MM-50354 - do not show push disabled notification once acknowledged

This commit is contained in:
Pablo Andrés Vélez Vidal 2023-08-09 19:52:37 +02:00
parent 4f5b42abba
commit 0da1b5c6a4
11 changed files with 117 additions and 11 deletions

View file

@ -77,3 +77,11 @@ export const removeLastViewedChannelIdAndServer = async () => {
export const removeLastViewedThreadIdAndServer = async () => {
return storeGlobal(GLOBAL_IDENTIFIERS.LAST_VIEWED_THREAD, null, false);
};
export const storePushDisabledInServerAcknowledged = async (serverUrl: string) => {
return storeGlobal(`${GLOBAL_IDENTIFIERS.PUSH_DISABLED_ACK}${serverUrl}`, 'true', false);
};
export const removePushDisabledInServerAcknowledged = async (serverUrl: string) => {
return storeGlobal(`${GLOBAL_IDENTIFIERS.PUSH_DISABLED_ACK}${serverUrl}`, null, false);
};

View file

@ -82,6 +82,7 @@ export const GLOBAL_IDENTIFIERS = {
ONBOARDING: 'onboarding',
LAST_VIEWED_CHANNEL: 'lastViewedChannel',
LAST_VIEWED_THREAD: 'lastViewedThread',
PUSH_DISABLED_ACK: 'pushDisabledAck',
};
export enum OperationType {

View file

@ -5,7 +5,7 @@ import CookieManager, {type Cookie} from '@react-native-cookies/cookies';
import {AppState, type AppStateStatus, DeviceEventEmitter, Platform} from 'react-native';
import FastImage from 'react-native-fast-image';
import {storeOnboardingViewedValue} from '@actions/app/global';
import {removePushDisabledInServerAcknowledged, storeOnboardingViewedValue} from '@actions/app/global';
import {cancelSessionNotification, logout, scheduleSessionNotification} from '@actions/remote/session';
import {Events, Launch} from '@constants';
import DatabaseManager from '@database/manager';
@ -21,7 +21,7 @@ import {getCurrentUser} from '@queries/servers/user';
import {getThemeFromState} from '@screens/navigation';
import EphemeralStore from '@store/ephemeral_store';
import {deleteFileCache, deleteFileCacheByDir} from '@utils/file';
import {isMainActivity} from '@utils/helpers';
import {extractCleanDomain, isMainActivity} from '@utils/helpers';
import {addNewServer} from '@utils/server';
import type {LaunchType} from '@typings/launch';
@ -168,6 +168,8 @@ class SessionManager {
await this.terminateSession(serverUrl, removeServer);
await removePushDisabledInServerAcknowledged(extractCleanDomain(serverUrl));
if (activeServerUrl === serverUrl) {
let displayName = '';
let launchType: LaunchType = Launch.AddServer;

View file

@ -55,6 +55,22 @@ export const getDontAskForReview = async () => {
return Boolean(records?.[0]?.value);
};
export const getPushDisabledInServerAcknowledged = async (serverDomainString: string) => {
const records = await queryGlobalValue(`${GLOBAL_IDENTIFIERS.PUSH_DISABLED_ACK}${serverDomainString}`)?.fetch();
return Boolean(records?.[0]?.value);
};
export const observePushDisabledInServerAcknowledged = (serverDomainString: string) => {
const query = queryGlobalValue(`${GLOBAL_IDENTIFIERS.PUSH_DISABLED_ACK}${serverDomainString}`);
if (!query) {
return of$(false);
}
return query.observe().pipe(
switchMap((result) => (result.length ? result[0].observe() : of$(false))),
switchMap((v) => of$(Boolean(v))),
);
};
export const getFirstLaunch = async () => {
const records = await queryGlobalValue(GLOBAL_IDENTIFIERS.FIRST_LAUNCH)?.fetch();
if (!records?.[0]?.value) {

View file

@ -17,6 +17,7 @@ describe('components/channel_list/header', () => {
canJoinChannels={true}
canInvitePeople={true}
displayName={'Test!'}
pushDisabledAck={true}
/>,
);

View file

@ -38,6 +38,7 @@ type Props = {
iconPad?: boolean;
onHeaderPress?: () => void;
pushProxyStatus: string;
pushDisabledAck: boolean;
}
const getStyles = makeStyleSheetFromTheme((theme: Theme) => ({
@ -111,6 +112,7 @@ const ChannelListHeader = ({
iconPad,
onHeaderPress,
pushProxyStatus,
pushDisabledAck,
}: Props) => {
const theme = useTheme();
const isTablet = useIsTablet();
@ -166,7 +168,7 @@ const ChannelListHeader = ({
const onPushAlertPress = useCallback(() => {
if (pushProxyStatus === PUSH_PROXY_STATUS_NOT_AVAILABLE) {
alertPushProxyError(intl);
alertPushProxyError(intl, serverUrl);
} else {
alertPushProxyUnknown(intl);
}
@ -206,7 +208,7 @@ const ChannelListHeader = ({
>
{serverDisplayName}
</Text>
{(pushProxyStatus !== PUSH_PROXY_STATUS_VERIFIED) && (
{pushProxyStatus !== PUSH_PROXY_STATUS_VERIFIED && !pushDisabledAck && (
<TouchableWithFeedback
onPress={onPushAlertPress}
testID='channel_list_header.push_alert'

View file

@ -6,7 +6,10 @@ import withObservables from '@nozbe/with-observables';
import {combineLatest, of as of$} from 'rxjs';
import {distinctUntilChanged, switchMap} from 'rxjs/operators';
import {observePushDisabledInServerAcknowledged} from '@app/queries/app/global';
import {extractCleanDomain} from '@app/utils/helpers';
import {Permissions} from '@constants';
import {withServerUrl} from '@context/server';
import {observePermissionForTeam} from '@queries/servers/role';
import {observeConfigBooleanValue, observePushVerificationStatus} from '@queries/servers/system';
import {observeCurrentTeam} from '@queries/servers/team';
@ -16,7 +19,11 @@ import ChannelListHeader from './header';
import type {WithDatabaseArgs} from '@typings/database/database';
const enhanced = withObservables([], ({database}: WithDatabaseArgs) => {
type Props = WithDatabaseArgs & {
serverUrl: string;
}
const enhanced = withObservables([], ({serverUrl, database}: Props) => {
const team = observeCurrentTeam(database);
const currentUser = observeCurrentUser(database);
@ -57,7 +64,8 @@ const enhanced = withObservables([], ({database}: WithDatabaseArgs) => {
distinctUntilChanged(),
),
pushProxyStatus: observePushVerificationStatus(database),
pushDisabledAck: observePushDisabledInServerAcknowledged(extractCleanDomain(serverUrl)),
};
});
export default withDatabase(enhanced(ChannelListHeader));
export default withDatabase(withServerUrl(enhanced(ChannelListHeader)));

View file

@ -4,10 +4,11 @@
import withObservables from '@nozbe/with-observables';
import {of as of$} from 'rxjs';
import {extractCleanDomain} from '@app/utils/helpers';
import {Tutorial} from '@constants';
import {PUSH_PROXY_STATUS_UNKNOWN} from '@constants/push_proxy';
import DatabaseManager from '@database/manager';
import {observeTutorialWatched} from '@queries/app/global';
import {observePushDisabledInServerAcknowledged, observeTutorialWatched} from '@queries/app/global';
import {observePushVerificationStatus} from '@queries/servers/system';
import ServerItem from './server_item';
@ -26,6 +27,7 @@ const enhance = withObservables(['highlight'], ({highlight, server}: {highlight:
server: server.observe(),
tutorialWatched,
pushProxyStatus: serverDatabase ? observePushVerificationStatus(serverDatabase) : of$(PUSH_PROXY_STATUS_UNKNOWN),
pushDisabledAck: observePushDisabledInServerAcknowledged(extractCleanDomain(server.url)),
};
});

View file

@ -44,6 +44,7 @@ type Props = {
server: ServersModel;
tutorialWatched: boolean;
pushProxyStatus: string;
pushDisabledAck: boolean;
}
type BadgeValues = {
@ -147,6 +148,7 @@ const ServerItem = ({
server,
tutorialWatched,
pushProxyStatus,
pushDisabledAck,
}: Props) => {
const intl = useIntl();
const theme = useTheme();
@ -428,7 +430,7 @@ const ServerItem = ({
>
{displayName}
</Text>
{server.lastActiveAt > 0 && pushProxyStatus !== PUSH_PROXY_STATUS_VERIFIED && (
{server.lastActiveAt > 0 && pushProxyStatus !== PUSH_PROXY_STATUS_VERIFIED && !pushDisabledAck && (
<CompassIcon
name='alert-outline'
color={theme.errorTextColor}

View file

@ -162,3 +162,45 @@ export function isMainActivity() {
android: ShareModule?.getCurrentActivityName() === 'MainActivity',
});
}
/**
* Extracts the domain name or IP address from a serverUrl.
*
* @param {string} input - The serverUrl, potentially with a port and protocol.
* @returns {string} The extracted domain name or IP address,
* or empty if no match is found.
*
* // Output:
* // Input: https://example-something.com => Result: example-something
* // Input: http://192.168.1.1 => Result: 192.168.1.1
* // Input: https://127.0.0.1:3000 => Result: 127.0.0.1
*/
export function extractDomain(input: string) {
const regex = /^(https?:\/\/)?([\w.-]+)(:\d+)?$/;
const match = input.match(regex);
if (match && match[2]) {
return match[2].replace(/[\W.]/g, '');
}
return '';
}
/**
* Returns the domain name or IP address from a serverUrl without special characters.
*
* @param {string} domain - The extracted domain from a serverUrl.
* @returns {string} The extracted domain name or IP address, modified to remove special characters,
* or empty .
*
* // Output:
* // Input: example-something => Result: examplesomething
* // Input: 192.168.1.1 => Result: 19216811
* // Input: 127.0.0.1 => Result: 127001
*/
export function extractCleanDomain(domain: string) {
if (!domain) {
return '';
}
return extractDomain(domain).replace(/[\W.]/g, '');
}

View file

@ -3,16 +3,30 @@
import {Alert} from 'react-native';
import {storePushDisabledInServerAcknowledged} from '@actions/app/global';
import {getPushDisabledInServerAcknowledged} from '@app/queries/app/global';
import {PUSH_PROXY_RESPONSE_NOT_AVAILABLE, PUSH_PROXY_RESPONSE_UNKNOWN, PUSH_PROXY_STATUS_NOT_AVAILABLE, PUSH_PROXY_STATUS_UNKNOWN, PUSH_PROXY_STATUS_VERIFIED} from '@constants/push_proxy';
import EphemeralStore from '@store/ephemeral_store';
import {extractCleanDomain} from './helpers';
import type {IntlShape} from 'react-intl';
export function canReceiveNotifications(serverUrl: string, verification: string, intl: IntlShape) {
export async function pushDisabledInServerAck(serverUrl: string) {
const extractedDomain = extractCleanDomain(serverUrl);
const pushServerDisabledAck = await getPushDisabledInServerAcknowledged(extractedDomain);
return pushServerDisabledAck;
}
export async function canReceiveNotifications(serverUrl: string, verification: string, intl: IntlShape) {
const a = await pushDisabledInServerAck(serverUrl);
switch (verification) {
case PUSH_PROXY_RESPONSE_NOT_AVAILABLE:
EphemeralStore.setPushProxyVerificationState(serverUrl, PUSH_PROXY_STATUS_NOT_AVAILABLE);
alertPushProxyError(intl);
if (!a) {
alertPushProxyError(intl, serverUrl);
}
break;
case PUSH_PROXY_RESPONSE_UNKNOWN:
EphemeralStore.setPushProxyVerificationState(serverUrl, PUSH_PROXY_STATUS_UNKNOWN);
@ -23,7 +37,14 @@ export function canReceiveNotifications(serverUrl: string, verification: string,
}
}
export function alertPushProxyError(intl: IntlShape) {
const handleAlertResponse = async (buttonIndex: number, serverUrl: string) => {
if (buttonIndex === 0) {
// User clicked "Okay" acknowledging that the push notifications are disabled on that server
await storePushDisabledInServerAcknowledged(extractCleanDomain(serverUrl));
}
};
export function alertPushProxyError(intl: IntlShape, serverUrl: string) {
Alert.alert(
intl.formatMessage({
id: 'alert.push_proxy_error.title',
@ -35,6 +56,7 @@ export function alertPushProxyError(intl: IntlShape) {
}),
[{
text: intl.formatMessage({id: 'alert.push_proxy.button', defaultMessage: 'Okay'}),
onPress: () => handleAlertResponse(0, serverUrl),
}],
);
}