From ba238cd653e9cead13fc8806e55d67ccba475aae Mon Sep 17 00:00:00 2001 From: BackSH00TER <18689469+BackSH00TER@users.noreply.github.com> Date: Thu, 13 Jul 2023 18:13:48 -0700 Subject: [PATCH 1/2] add sound notifications to generic usenotification hook --- .../hooks/useMarketplaceService.ts | 1 + .../src/apps/match/hooks/useMatchService.ts | 1 + .../apps/messages/hooks/useMessageService.ts | 1 + .../apps/twitter/hooks/useTwitterService.ts | 1 + .../os/new-notifications/useNotification.tsx | 25 ++++++++++++++++--- 5 files changed, 26 insertions(+), 3 deletions(-) diff --git a/apps/phone/src/apps/marketplace/hooks/useMarketplaceService.ts b/apps/phone/src/apps/marketplace/hooks/useMarketplaceService.ts index 51052d41a..7aceac757 100644 --- a/apps/phone/src/apps/marketplace/hooks/useMarketplaceService.ts +++ b/apps/phone/src/apps/marketplace/hooks/useMarketplaceService.ts @@ -18,6 +18,7 @@ export const useMarketplaceService = () => { notisId: 'npwd:marketplace:newListingBroadcast', content: resp.listing.description, secondaryTitle: t('MARKETPLACE.NEW_LISTING'), + playSound: true, }); }, [addListing, enqueueNotification], diff --git a/apps/phone/src/apps/match/hooks/useMatchService.ts b/apps/phone/src/apps/match/hooks/useMatchService.ts index 6dc86cfba..6cf56294d 100644 --- a/apps/phone/src/apps/match/hooks/useMatchService.ts +++ b/apps/phone/src/apps/match/hooks/useMatchService.ts @@ -42,6 +42,7 @@ export const useMatchService = () => { path: '/match', keepOpen: false, duration: 3000, + playSound: true, }); addMatchedAccount(); }; diff --git a/apps/phone/src/apps/messages/hooks/useMessageService.ts b/apps/phone/src/apps/messages/hooks/useMessageService.ts index 0ace4f5e2..f09d75838 100644 --- a/apps/phone/src/apps/messages/hooks/useMessageService.ts +++ b/apps/phone/src/apps/messages/hooks/useMessageService.ts @@ -32,6 +32,7 @@ export const useMessagesService = () => { onClick: () => goToConversation(group), secondaryTitle: getDisplayByNumber(convoName) ?? convoName, path: `/messages/conversations/${activeMessageConversation.id}`, + playSound: true, }); }, [enqueueNotification], diff --git a/apps/phone/src/apps/twitter/hooks/useTwitterService.ts b/apps/phone/src/apps/twitter/hooks/useTwitterService.ts index b95a28f56..f2a67ad49 100644 --- a/apps/phone/src/apps/twitter/hooks/useTwitterService.ts +++ b/apps/phone/src/apps/twitter/hooks/useTwitterService.ts @@ -43,6 +43,7 @@ export const useTwitterService = () => { notisId: 'npwd:tweetBroadcast', secondaryTitle: data.profile_name, path: '/twitter', + playSound: true, }); }, [enqueueNotification], diff --git a/apps/phone/src/os/new-notifications/useNotification.tsx b/apps/phone/src/os/new-notifications/useNotification.tsx index 54cc2c2c0..f36b8cd0e 100644 --- a/apps/phone/src/os/new-notifications/useNotification.tsx +++ b/apps/phone/src/os/new-notifications/useNotification.tsx @@ -1,7 +1,9 @@ import { useSnackbar } from 'notistack'; +import uuid from 'react-uuid'; import { useRecoilCallback } from 'recoil'; +import { AlertEvents } from '@typings/alerts'; +import fetchNui from '@utils/fetchNui'; import { useApps } from '../apps/hooks/useApps'; -import uuid from 'react-uuid'; import { notifications, @@ -11,6 +13,18 @@ import { unreadNotifications, } from './state'; +interface INotificationOptions { + appId: string, + content: string, + secondaryTitle: string, + notisId: string, + path: string, + keepOpen?: boolean, + onClick?: () => any, + duration?: number, + playSound?: boolean, +} + interface NotificationProps { enqueueNotification: (options: any) => void; removeAllActive: () => void; @@ -35,7 +49,8 @@ export const useNotification = (): NotificationProps => { keepOpen = false, onClick, duration, - }: any) => { + playSound, + }: INotificationOptions) => { const app = getApp(appId); const curNotis = await snapshot.getPromise(allNotificationIds); @@ -86,9 +101,13 @@ export const useNotification = (): NotificationProps => { secondaryTitle, path, app, - autoHideDuration: 3000 || duration, + autoHideDuration: duration || 3000, disableWindowBlurListener: true, }); + + if (playSound) { + fetchNui(AlertEvents.PLAY_ALERT); + } }, ); From c2fe451f4a7bbe1e4b8135856e2c865dfeebc453 Mon Sep 17 00:00:00 2001 From: BackSH00TER <18689469+BackSH00TER@users.noreply.github.com> Date: Thu, 13 Jul 2023 18:15:01 -0700 Subject: [PATCH 2/2] remove obsolete notification hooks --- .../hooks/useMarketplaceNotifications.ts | 34 -------- .../apps/match/hooks/useMatchNotifications.ts | 48 ----------- .../messages/hooks/useMessageNotifications.ts | 70 ---------------- .../twitter/hooks/useTwitterNotifications.ts | 81 ------------------- .../os/call/hooks/useCallNotifications.tsx | 68 ---------------- 5 files changed, 301 deletions(-) delete mode 100644 apps/phone/src/apps/marketplace/hooks/useMarketplaceNotifications.ts delete mode 100644 apps/phone/src/apps/match/hooks/useMatchNotifications.ts delete mode 100644 apps/phone/src/apps/messages/hooks/useMessageNotifications.ts delete mode 100644 apps/phone/src/apps/twitter/hooks/useTwitterNotifications.ts delete mode 100644 apps/phone/src/os/call/hooks/useCallNotifications.tsx diff --git a/apps/phone/src/apps/marketplace/hooks/useMarketplaceNotifications.ts b/apps/phone/src/apps/marketplace/hooks/useMarketplaceNotifications.ts deleted file mode 100644 index 2e4261b3f..000000000 --- a/apps/phone/src/apps/marketplace/hooks/useMarketplaceNotifications.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { useTranslation } from 'react-i18next'; -import { useSettings } from '../../settings/hooks/useSettings'; -import { useNotifications } from '@os/notifications/hooks/useNotifications'; -import { MarketplaceListing } from '@typings/marketplace'; -import { useApp } from '@os/apps/hooks/useApps'; -import { INotification } from '@os/notifications/providers/NotificationsProvider'; - -const NOTIFICATION_ID = 'marketplace:broadcast'; - -export const useMarketplaceNotifications = () => { - const [t] = useTranslation(); - const [settings] = useSettings(); - const { addNotificationAlert } = useNotifications(); - const { icon, notificationIcon } = useApp('MARKETPLACE'); - - const setNotification = (listing: MarketplaceListing) => { - if (!settings.MARKETPLACE_notifyNewListing) return; - - const id = `${NOTIFICATION_ID}:${listing.id}`; - - const notification: INotification = { - app: 'MARKETPLACE', - id, - title: t('MARKETPLACE.NEW_LISTING'), - content: listing.description, - icon, - notificationIcon, - }; - - addNotificationAlert(notification); - }; - - return { setNotification }; -}; diff --git a/apps/phone/src/apps/match/hooks/useMatchNotifications.ts b/apps/phone/src/apps/match/hooks/useMatchNotifications.ts deleted file mode 100644 index 4e0e9d347..000000000 --- a/apps/phone/src/apps/match/hooks/useMatchNotifications.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { useCallback, useEffect } from 'react'; -import { useTranslation } from 'react-i18next'; -import { matchPath, useHistory } from 'react-router-dom'; -import { useApp } from '@os/apps/hooks/useApps'; -import { useNotifications } from '@os/notifications/hooks/useNotifications'; - -const NOTIFICATION_ID = 'match:broadcast'; - -export const useMatchNotifications = () => { - const [t] = useTranslation(); - const { push, listen } = useHistory(); - const { removeId, addNotification, addNotificationAlert } = useNotifications(); - const { icon, notificationIcon } = useApp('MATCH'); - - useEffect(() => { - return listen((location) => { - if ( - matchPath(location.pathname, { - path: `/match/matches`, - exact: true, - }) - ) { - removeId(NOTIFICATION_ID); - } - }); - }, [listen, removeId]); - - const setNotification = useCallback( - ({ name }) => { - const notification = { - app: 'MATCH', - id: NOTIFICATION_ID, - sound: true, - title: t('MATCH.FEEDBACK.NEW_LIKE_FOUND'), - onClick: () => push(`/match/matches`), - content: name, - icon, - notificationIcon, - }; - - addNotificationAlert(notification); - addNotification(notification); - }, - [addNotification, addNotificationAlert, icon, notificationIcon, push, t], - ); - - return { setNotification }; -}; diff --git a/apps/phone/src/apps/messages/hooks/useMessageNotifications.ts b/apps/phone/src/apps/messages/hooks/useMessageNotifications.ts deleted file mode 100644 index 2fdeed9cc..000000000 --- a/apps/phone/src/apps/messages/hooks/useMessageNotifications.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { useTranslation } from 'react-i18next'; -import { matchPath, useHistory } from 'react-router-dom'; -import { useApp } from '@os/apps/hooks/useApps'; -import { useNotifications } from '@os/notifications/hooks/useNotifications'; -import useMessages from './useMessages'; -import { useRecoilValue } from 'recoil'; -import { messageState } from './state'; -import { MessageConversation } from '@typings/messages'; -import { useContactActions } from '@apps/contacts/hooks/useContactActions'; - -const NOTIFICATION_ID = 'messages:broadcast'; - -export const useMessageNotifications = () => { - const [t] = useTranslation(); - const history = useHistory(); - const { removeId, addNotification, addNotificationAlert } = useNotifications(); - const { icon, notificationIcon } = useApp('MESSAGES'); - const { getMessageConversationById, goToConversation } = useMessages(); - const activeMessageConversation = useRecoilValue(messageState.activeMessageConversation); - const { getDisplayByNumber } = useContactActions(); - - // Remove notifications from groups when opening them - history.listen((location) => { - if ( - activeMessageConversation?.id && - matchPath(location.pathname, { - path: `/messages/conversations/${activeMessageConversation.id}`, - exact: true, - }) - ) { - removeId(`${NOTIFICATION_ID}:${activeMessageConversation.id}`); - } - }); - - const setNotification = ({ conversationName, conversationId, message }) => { - let group: MessageConversation = null; - - group = getMessageConversationById(conversationId); - - const id = `${NOTIFICATION_ID}:${conversationId}`; - - const notification = { - app: 'MESSAGES', - id, - sound: true, - title: getDisplayByNumber(conversationName) ?? conversationName, - onClick: () => goToConversation(group), - content: message, - icon, - notificationIcon, - }; - - addNotificationAlert(notification, (n) => { - removeId(id); - if (group.unread > 1) { - addNotification({ - ...n, - title: group.participant, - content: t('MESSAGES.MESSAGES.UNREAD_MESSAGES', { - count: group.unread, - }), - }); - return; - } - addNotification(n); - }); - }; - - return { setNotification }; -}; diff --git a/apps/phone/src/apps/twitter/hooks/useTwitterNotifications.ts b/apps/phone/src/apps/twitter/hooks/useTwitterNotifications.ts deleted file mode 100644 index e33d8c4a8..000000000 --- a/apps/phone/src/apps/twitter/hooks/useTwitterNotifications.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { useTranslation } from 'react-i18next'; -import { useHistory } from 'react-router-dom'; -import { useRecoilState, useRecoilValueLoadable } from 'recoil'; -import { Tweet } from '@typings/twitter'; - -import { useApp } from '@os/apps/hooks/useApps'; -import { useNotifications } from '@os/notifications/hooks/useNotifications'; -import { useSettings } from '../../settings/hooks/useSettings'; -import { SETTING_MENTIONS } from '../utils/constants'; -import { twitterState } from './state'; - -const NOTIFICATION_ID = 'twitter:broadcast'; - -function isMentioned(profileName: string, message: string) { - return message.toLowerCase().includes(profileName.toLowerCase()); -} - -export const useTwitterNotifications = () => { - const [settings] = useSettings(); - const [t] = useTranslation(); - const history = useHistory(); - - const { addNotificationAlert, addNotification, hasNotification, removeId } = useNotifications(); - - const { icon, notificationIcon } = useApp('TWITTER'); - - const [unreadCount, setUnreadCount] = useRecoilState(twitterState.unreadTweetsCount); - const { state: profileLoading, contents: profile } = useRecoilValueLoadable(twitterState.profile); - - const setNotification = ({ profile_name, message, isRetweet }: Tweet) => { - if (profileLoading !== 'hasValue') return; - const titleStr = isRetweet - ? 'TWITTER.MESSAGES.NEW_RETWEET_BROADCAST' - : 'TWITTER.MESSAGES.NEW_BROADCAST'; - - // profile defaults to null, if for some reason it is not initialized - // defend against this case - if (!profile) return; - - // Prevents a crash if there is no current profile - // set and a Twitter broadcast occurs. - const currentProfileName = profile?.profile_name; - - // we don't want notifications of our own tweets - if (currentProfileName === profile_name) return; - - const profileMentioned = isMentioned(currentProfileName, message); - - // if the player only wants notifications on tweets they are - // mentioned in - if (settings.TWITTER_notiFilter.value === SETTING_MENTIONS && !profileMentioned) return; - - const notification = { - app: 'TWITTER', - id: NOTIFICATION_ID, - sound: profileMentioned, - title: t(titleStr, { profile_name }), - onClick: () => history.push('/twitter'), - content: message, - icon, - notificationIcon, - }; - const newCount = unreadCount + 1; - setUnreadCount(newCount); - addNotificationAlert(notification); - if (hasNotification(NOTIFICATION_ID)) { - removeId(NOTIFICATION_ID); - addNotification({ - ...notification, - title: t('TWITTER.MESSAGES.UNREAD_MESSAGES', { - count: newCount, - }), - content: null, - }); - return; - } - addNotification(notification); - }; - - return { setNotification, setUnreadCount, unreadCount }; -}; diff --git a/apps/phone/src/os/call/hooks/useCallNotifications.tsx b/apps/phone/src/os/call/hooks/useCallNotifications.tsx deleted file mode 100644 index f1ef91073..000000000 --- a/apps/phone/src/os/call/hooks/useCallNotifications.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import React, { useCallback } from 'react'; -import { useTranslation } from 'react-i18next'; -import { useHistory } from 'react-router-dom'; -import { ActiveCall } from '@typings/call'; -import { useApp } from '@os/apps/hooks/useApps'; -import { useNotifications } from '@os/notifications/hooks/useNotifications'; -import { CallNotification } from '../components/CallNotification'; -import { useContactActions } from '../../../apps/contacts/hooks/useContactActions'; -import { useContacts } from '../../../apps/contacts/hooks/state'; - -const NOTIFICATION_ID = 'call:current'; - -export const useCallNotifications = () => { - const [t] = useTranslation(); - const history = useHistory(); - const { addNotificationAlert, removeId } = useNotifications(); - const { getDisplayByNumber } = useContactActions(); - const contacts = useContacts(); - - const { icon, notificationIcon } = useApp('DIALER'); - - const contactDisplay = useCallback( - (number: string): string | null => { - return contacts.length ? getDisplayByNumber(number) : null; - }, - [contacts, getDisplayByNumber], - ); - - const callNotificationBase = { - app: 'CALL', - id: NOTIFICATION_ID, - cantClose: false, - icon, - onClick: () => history.push('/call'), - notificationIcon, - }; - - const clearNotification = (): void => { - removeId(NOTIFICATION_ID); - }; - - const setNotification = (call: ActiveCall) => { - if (!call) { - removeId(NOTIFICATION_ID); - return; - } - - if (!call.isTransmitter && !call.is_accepted) { - removeId(NOTIFICATION_ID); - addNotificationAlert({ - ...callNotificationBase, - title: t('DIALER.MESSAGES.INCOMING_CALL_TITLE', { - transmitter: contactDisplay(call.transmitter) || call.transmitter, - }), - keepWhenPhoneClosed: true, - content: ( - - {t('DIALER.MESSAGES.TRANSMITTER_IS_CALLING', { - transmitter: contactDisplay(call.transmitter) || call.transmitter, - })} - - ), - }); - } - }; - - return { setNotification, clearNotification }; -};