From 9370a9c54ef7998c543ccafda9996dd3a741e914 Mon Sep 17 00:00:00 2001 From: Avinash Lingaloo Date: Tue, 14 Jun 2022 10:35:50 +0400 Subject: [PATCH] MM-39711 - Gekidou Settings Push Notification functionality (#6373) * adding nav hooks * added save button * capturing value from OptionItem * notification - saving in progress * tested API * corrections after review * Update en.json * Update notification_push.tsx * ts fixes * minor improvement Co-authored-by: Elias Nahum --- .../settings/notification_push/index.tsx | 4 +- .../notification_push/notification_push.tsx | 96 +++++++++++++++---- .../settings/notifications/notifications.tsx | 35 +++---- app/utils/user/index.ts | 5 +- types/api/users.d.ts | 1 + types/screens/settings.d.ts | 2 +- 6 files changed, 103 insertions(+), 40 deletions(-) diff --git a/app/screens/settings/notification_push/index.tsx b/app/screens/settings/notification_push/index.tsx index 9c2d921c94..1d2d4fbdac 100644 --- a/app/screens/settings/notification_push/index.tsx +++ b/app/screens/settings/notification_push/index.tsx @@ -6,14 +6,16 @@ import withObservables from '@nozbe/with-observables'; import {observeConfigBooleanValue} from '@queries/servers/system'; import {observeIsCRTEnabled} from '@queries/servers/thread'; +import {observeCurrentUser} from '@queries/servers/user'; import {WithDatabaseArgs} from '@typings/database/database'; import NotificationPush from './notification_push'; const enhanced = withObservables([], ({database}: WithDatabaseArgs) => { return { - sendPushNotifications: observeConfigBooleanValue(database, 'SendPushNotifications'), + currentUser: observeCurrentUser(database), isCRTEnabled: observeIsCRTEnabled(database), + sendPushNotifications: observeConfigBooleanValue(database, 'SendPushNotifications'), }; }); diff --git a/app/screens/settings/notification_push/notification_push.tsx b/app/screens/settings/notification_push/notification_push.tsx index d9b2916224..eb4661a08b 100644 --- a/app/screens/settings/notification_push/notification_push.tsx +++ b/app/screens/settings/notification_push/notification_push.tsx @@ -1,17 +1,26 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useState} from 'react'; +import React, {useCallback, useEffect, useMemo, useState} from 'react'; +import {useIntl} from 'react-intl'; import {ScrollView} from 'react-native'; import {Edge, SafeAreaView} from 'react-native-safe-area-context'; +import {updateMe} from '@actions/remote/user'; +import {useServerUrl} from '@context/server'; import {useTheme} from '@context/theme'; +import useAndroidHardwareBackHandler from '@hooks/android_back_handler'; +import useNavButtonPressed from '@hooks/navigation_button_pressed'; +import {popTopScreen, setButtons} from '@screens/navigation'; import {changeOpacity, makeStyleSheetFromTheme} from '@utils/theme'; +import {getNotificationProps} from '@utils/user'; import MobileSendPush from './push_send'; import MobilePushStatus from './push_status'; import MobilePushThread from './push_thread'; +import type UserModel from '@typings/database/models/servers/user'; + const getStyleSheet = makeStyleSheetFromTheme((theme) => { return { container: { @@ -27,31 +36,78 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => { }, }; }); + const edges: Edge[] = ['left', 'right']; +const SAVE_NOTIF_BUTTON_ID = 'SAVE_NOTIF_BUTTON_ID'; + type NotificationMobileProps = { + componentId: string; + currentUser: UserModel; isCRTEnabled: boolean; sendPushNotifications: boolean; }; -const NotificationPush = ({isCRTEnabled, sendPushNotifications}: NotificationMobileProps) => { - const theme = useTheme(); - const [pushStatus, setPushStatus] = useState('online'); - const [pushPref, setPushPref] = useState('online'); - const [pushThread, setPushThreadPref] = useState('online'); +const NotificationPush = ({componentId, currentUser, isCRTEnabled, sendPushNotifications}: NotificationMobileProps) => { + const serverUrl = useServerUrl(); + const notifyProps = useMemo(() => getNotificationProps(currentUser), [currentUser.notifyProps]); + + const [pushSend, setPushSend] = useState(notifyProps.push); + const [pushStatus, setPushStatus] = useState(notifyProps.push_status); + const [pushThread, setPushThreadPref] = useState(notifyProps?.push_threads || 'all'); + + const intl = useIntl(); + const theme = useTheme(); const styles = getStyleSheet(theme); - const setMobilePushStatus = (status: PushStatus) => { - setPushStatus(status); - }; + const onMobilePushThreadChanged = useCallback(() => { + setPushThreadPref(pushThread === 'all' ? 'mention' : 'all'); + }, [pushThread]); - const setMobilePushPref = (status: PushStatus) => { - setPushPref(status); - }; + const saveButton = useMemo(() => { + return { + id: SAVE_NOTIF_BUTTON_ID, + enabled: false, + showAsAction: 'always' as const, + testID: 'notification_settings.save.button', + color: theme.sidebarHeaderTextColor, + text: intl.formatMessage({id: 'settings.save', defaultMessage: 'Save'}), + }; + }, [theme.sidebarHeaderTextColor]); - const onMobilePushThreadChanged = (status: PushStatus) => { - setPushThreadPref(status); - }; + const close = useCallback(() => popTopScreen(componentId), [componentId]); + + const saveNotificationSettings = useCallback(() => { + const notify_props = {...notifyProps, push: pushSend, push_status: pushStatus, push_threads: pushThread}; + updateMe(serverUrl, {notify_props} as unknown as UserNotifyProps); + close(); + }, [serverUrl, notifyProps, pushSend, pushStatus, pushThread, close]); + + useEffect(() => { + const p = pushSend !== notifyProps.push; + const pT = pushThread !== notifyProps.push_threads; + const pS = pushStatus !== notifyProps.push_status; + + const enabled = p || pT || pS; + + const buttons = { + rightButtons: [{ + ...saveButton, + enabled, + }], + }; + setButtons(componentId, buttons); + }, [ + componentId, + notifyProps, + pushSend, + pushStatus, + pushThread, + ]); + + useNavButtonPressed(SAVE_NOTIF_BUTTON_ID, componentId, saveNotificationSettings, [saveNotificationSettings]); + + useAndroidHardwareBackHandler(componentId, close); return ( - {isCRTEnabled && pushPref === 'mention' && ( + {isCRTEnabled && pushSend === 'mention' && ( )} - {sendPushNotifications && pushPref !== 'none' && ( + {sendPushNotifications && pushSend !== 'none' && ( )} diff --git a/app/screens/settings/notifications/notifications.tsx b/app/screens/settings/notifications/notifications.tsx index 5899c6056c..ba49bd785a 100644 --- a/app/screens/settings/notifications/notifications.tsx +++ b/app/screens/settings/notifications/notifications.tsx @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React from 'react'; +import React, {useCallback} from 'react'; import {useIntl} from 'react-intl'; import {Platform, ScrollView, View} from 'react-native'; import {Edge, SafeAreaView} from 'react-native-safe-area-context'; @@ -37,6 +37,16 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => { }); const edges: Edge[] = ['left', 'right']; +const mentionTexts = { + crtOn: { + id: t('notification_settings.mentions'), + defaultMessage: 'Mentions', + }, + crtOff: { + id: t('notification_settings.mentions_replies'), + defaultMessage: 'Mentions and Replies', + }, +}; type NotificationsProps = { isCRTEnabled: boolean; enableAutoResponder: boolean; @@ -46,14 +56,7 @@ const Notifications = ({isCRTEnabled, enableAutoResponder}: NotificationsProps) const styles = getStyleSheet(theme); const intl = useIntl(); - let mentionsI18nId = t('notification_settings.mentions_replies'); - let mentionsI18nDefault = 'Mentions and Replies'; - if (isCRTEnabled) { - mentionsI18nId = t('notification_settings.mentions'); - mentionsI18nDefault = 'Mentions'; - } - - const goToNotificationSettingsMentions = () => { + const goToNotificationSettingsMentions = useCallback(() => { const screen = Screens.SETTINGS_NOTIFICATION_MENTION; const id = isCRTEnabled ? t('notification_settings.mentions') : t('notification_settings.mentions_replies'); @@ -61,9 +64,9 @@ const Notifications = ({isCRTEnabled, enableAutoResponder}: NotificationsProps) const title = intl.formatMessage({id, defaultMessage}); goToScreen(screen, title); - }; + }, [isCRTEnabled]); - const goToNotificationSettingsPush = () => { + const goToNotificationSettingsPush = useCallback(() => { const screen = Screens.SETTINGS_NOTIFICATION_PUSH; const title = intl.formatMessage({ id: 'notification_settings.push_notification', @@ -71,16 +74,16 @@ const Notifications = ({isCRTEnabled, enableAutoResponder}: NotificationsProps) }); goToScreen(screen, title); - }; + }, []); - const goToNotificationAutoResponder = () => { + const goToNotificationAutoResponder = useCallback(() => { const screen = Screens.SETTINGS_NOTIFICATION_AUTO_RESPONDER; const title = intl.formatMessage({ id: 'notification_settings.auto_responder', defaultMessage: 'Automatic Replies', }); goToScreen(screen, title); - }; + }, []); return ( diff --git a/app/utils/user/index.ts b/app/utils/user/index.ts index 0f72379273..44194b5451 100644 --- a/app/utils/user/index.ts +++ b/app/utils/user/index.ts @@ -307,16 +307,17 @@ export function getNotificationProps(user: UserModel) { } const props: UserNotifyProps = { - email: 'true', - mark_unread: 'all', channel: 'true', comments: 'any', desktop: 'all', desktop_sound: 'true', + email: 'true', first_name: (!user || !user.firstName) ? 'false' : 'true', + mark_unread: 'all', mention_keys: user ? `${user.username},@${user.username}` : '', push: 'mention', push_status: 'online', + push_threads: 'all', }; return props; diff --git a/types/api/users.d.ts b/types/api/users.d.ts index 94d5cee486..05201f0725 100644 --- a/types/api/users.d.ts +++ b/types/api/users.d.ts @@ -16,6 +16,7 @@ type UserNotifyProps = { push: 'default' | 'all' | 'mention' | 'none'; push_status: 'ooo' | 'offline' | 'away' | 'dnd' | 'online'; user_id?: string; + push_threads?: 'all' | 'mention'; }; type UserProfile = { diff --git a/types/screens/settings.d.ts b/types/screens/settings.d.ts index a0d7a43f89..500b68d5be 100644 --- a/types/screens/settings.d.ts +++ b/types/screens/settings.d.ts @@ -1,4 +1,4 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -type PushStatus = 'away' | 'online' | 'offline' | 'none' | 'mention' | 'all'; +type PushStatus = 'away' | 'online' | 'offline' | 'none' | 'mention' | 'all' | 'ooo' | 'dnd' | 'default' ;