From 6525dfbd7f30282e9eb3c40771ab30f58f06305c Mon Sep 17 00:00:00 2001 From: Aman Chaturvedi Date: Wed, 31 Jan 2024 20:41:12 +0530 Subject: [PATCH] TP-52572 | push notification changes --- .../drawable-hdpi/ic_notification_icon.png | Bin 514 -> 371 bytes .../drawable-mdpi/ic_notification_icon.png | Bin 373 -> 238 bytes .../drawable-xhdpi/ic_notification_icon.png | Bin 782 -> 423 bytes .../drawable-xxhdpi/ic_notification_icon.png | Bin 1243 -> 466 bytes .../drawable-xxxhdpi/ic_notification_icon.png | Bin 1840 -> 0 bytes src/components/utlis/deeplinkingUtils.ts | 36 +++++++++++++++++- src/constants/Global.ts | 18 +++++++-- .../useFCM/notificationHelperFunctions.ts | 13 ++++++- src/hooks/useFCM/useFCM.ts | 5 ++- src/screens/auth/ProtectedRouter.tsx | 3 +- .../foregroundServices/foreground.service.ts | 4 +- 11 files changed, 67 insertions(+), 12 deletions(-) delete mode 100644 android/app/src/main/res/drawable-xxxhdpi/ic_notification_icon.png diff --git a/android/app/src/main/res/drawable-hdpi/ic_notification_icon.png b/android/app/src/main/res/drawable-hdpi/ic_notification_icon.png index 87e254d052dcd252f7348eb71f85c6516944b89d..4392a91c200170fdcd246a1d1eaec609721ecc28 100644 GIT binary patch delta 344 zcmZo-`OGvyrQXWZ#WAEJ?(Ou0g@*!oSTz+@1Dw1Th)kcrw@B!P!crI6B`Qz%JNnFd zYFzfDLBBq|#6c%}u7rgQTl3t`j+JNA3(vjDUFNF$%A$I9XW<1VL%yg5uKl@w+@H(# zGFVjmE9$v_E!gF+xJ^c6y8f>3_GdbImDGP(+?7`O7_9vxA-&%3O~Hg8S)UKh>zKaNbq zx(fwPcU}~|73?!7kFzzxFR*9bg?UMjO1w3W6eX3kBANZ@qP@Q;NZ+Ej@gVbDxaW$# oKI8Je>)z`h|Nom;8blm4uQ$EF?n$oiGX@~=boFyt=akR{0GEuNssI20 delta 488 zcmVqOReu){xVS9 zGMNU>9huFUFbDpIJ6Nn)sLkt1Ad?Mk-kb;8hXsa3a82uRHBihlP(VE&E=!L$fpA<3 z>tVHg&VyUGtU@x2|4)e&vKF_JIhi&3ZrglpO8z;WJ=hA1vNg!7V0@>mFK)!po_uaoA e{`!B&FMI&D!y9`4IPhEm0000%cOJNv?GQ1J*bc#0b`aYk_{t7qJ46fb#XY*mjo7}$YvjuV z{t;5fg`J552h5hVhYpx6x{oP7Fko(7J2#Lx delta 347 zcmV-h0i^!!0rdiqBYy!rNkl@bL?~<$o9_%^`^tFoWafG=AFk z5s4Hqnism-G5nC20a(UoT(J5be8E@0u$}(|4BPnkA#<#I^FanCAjL%+U*i;B{7r}H zHlSxZ1)SnNzT*LY;Tb;SrMRtnhc|d`=ZE;Mi!(w2`*?(VxQti0iWB0RRB=<>`>}$% zIFC!>0&_wECsep$YU6Diuj8D!Mq9XsvsP0R_pBP?5eiUrf9q{gbpI>5@AX=C8+5EM toPGe6Cp+eJ3W!2q0}B6T7W>mLk{|AfKtS4vhm8OL002ovPDHLkV1l2}rK11< diff --git a/android/app/src/main/res/drawable-xhdpi/ic_notification_icon.png b/android/app/src/main/res/drawable-xhdpi/ic_notification_icon.png index d02aacbe31a9a37ec088c1ea23566eb2d6c75dd7..a4906bbec9cecfafc55deac6675969e0f213748b 100644 GIT binary patch literal 423 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA1|-9oezr3(Fy?u>IEGZjy}fqPm)TIDCDF@+ zQ?pTM9gCNT`proiin2>sUNBfm*f4dz*k3&7h+T=$Z_nS`9`CI6nl~@VE3p`n(tCut(#|R=^OuDP&`xie*B`cbc5ihsmrYIl(gKMd(da< z^qKFj*f_mCm$2;AX&?TAuN+YIwjKR9HlM%pjwfx^o-x@%^-X1cl}B|=07;4mDK^1+&h;DD{W1{=%)Wu`uaXn(q@Fl_5*fHF>-G)8Rw z3{WX-{V_n%*!p9DqOtXND!?6hbqt^V>zWT+f2RWU*l|M8zTO_tEcRS6Knj%)@Du(p z_6B2?BETE?w1Lmz-=LqTFBr2F0s8H^JZPH+-<$r`2|&<3Mf5Itsuh5s&m{QD^)GJ# zZ1;$MIe8}sZGRhF|JOnLJGU=4{=5mcLk_|KGfZ3ZF)D3d@%i&6*bX^}0mg$rZ-VWR zgBV~u`12;%4mnr>Cpc%Cw(W4DYg=vFTEf=fN&v!NG`yCy{VieZZ#6*S*!p9DqOtWi z6W|Km3Xj9zZr@$F6CQ$}-M(vZ3q0#ypMVeC_FH%aet(Bw;9-?1k4w$G8B` z!-KUWQn2-B1y}$-1h4swze)6$13I>E9l`>=3U{h++2|@h8INxFle`Efy-RKg|(xUbE0>L zcY#yqBwQM_*J10=3h-F;ONw)wx0~~ucVsTyD0)>nmpS+>xLfpUbM7+$`6{}^WB@L3 z_K1e$on&9WKemZZPr6qRYmBWwD**W=`W^_Eh;S_EK70}E<3gVOKDyWb&F%3)$V<_w z6|SBAntDuZ{mld@6}J8uplEFUF+kDS`Wc|@kGvhE;h%i`gS#pW+4>ovtxLWRQ~yUd pVT0(SKpCeKYvL?vTzup|F$xW$eS42evQ_{9002ovPDHLkV1l>_csc+8 diff --git a/android/app/src/main/res/drawable-xxhdpi/ic_notification_icon.png b/android/app/src/main/res/drawable-xxhdpi/ic_notification_icon.png index d6afed77bcd33d1eb5cfdebcfa063f54b9a94515..bb9666beb0f7c6914abf59d2fdefcc8738eb9371 100644 GIT binary patch literal 466 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@Zgyv2V4Ugc;uum9_x5&R?qdg$)`w0J z9IXKyjR72O0c@r%tto7+0vx){^|jZ#Lguy`&oeva^6}@AO0Q?nUe%v)USnhH>f+*Z z#Nfb|dEXhIFWG%(Y3apQ!?e3k^(H#VaX!IDtnJ>n=6Ol$XSey0<&_yZ6RXZxJzj`V zXs8sxdvRrWS={;Eb?^K?ENIlTyY|`Lem^_E+=@S1LhKwN=U!J{wEgx#q4AWueaDeT zrm62dWOM>vb{%14o_cqpMaF`liE*XoM;n=AeRkb1SGiEHe)r>|xXb3|XRH=S1I^}* z&#_YYdO5bh#vM28gdsK;=_uY$%yl3App8e2{`K(p)j3~G5*%46T z?sF1tET23S`iUiOv;11^EG0JAkY_t*NPl*fj#aWmp1_I?e?M2g|Gd%lJ^$fvTQ(`Z xwVizKM)uy{XTFs)&0U#(X}2H{6vqB%m>}4(Kyl;zY+zh5c)I$ztaD0e0stL=%k}^O literal 1243 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@Zgyv2U|Hnp;uum9_jXR?in}2at=e52 zVQa+JUVCWaaFFv#(}Io*b}JM*m^JwLw>2fK|a8G4OUn-}e5$vV>o6g0#wsQFp<%LB7l%6b-=Ces~ygVPr0 z`O803^p%PAUvNw_nCaC*mMhMjE86`RhRR0W*|c{h)2rmr)8D2wNS(RWAlK$6>8!oL ze^u(O8Cx0eu6R9@v*LT>z3WU`UJfk(Y!{es70_nnJ!rJs@%7R@4i&+2V??hB4_UKG1A|fCPdEy%Un)_P(+T*g${FdHz`_In)qZeGwe%+VY^Pp6#M5ILVOR4GKq72C| z&R^&5VUA6Ri#yBwO#EKox@WZ)W_*_`Syp-TdGzaQ<2Sw!3_}4bz;}eYQ-j?)bDHkxe#6WrX(2Ew-!w>XH2<=~=lNouKaI!t?wtHH^^zJ- zQ}u7}3~TAQ8UJ~IUDzYU{DSL+!so9wjAvW*O!+(Rmv32{&;LYeY|Ud+z=bzslxPw$g2lwR0*!S@;C z#z*X7_tefibFV&MK687(HkoZ^ZB}NWq{e4qmy>@lcGiYTug_>7Oj~#Mm!EW*>L>0m zJwNBAmp|EIYOsIy!C<~V#W&O5w3RyKl=6Jzmu`*yx#8IN`)7CGx4f|L!usCIxuAHe zwm4j)uqOPEaEVaK*2<&bjn}8hUON8l@iE(H$wKVkem$I7es(wOX{j0PM zqnPi&9&ROeOLEsK8-uVnI-jG@sykOZUH_dVI3bAL#UgIwR-Ofq&%9swaX~=8u}zYm zf&T2fee4|@F9Kt>kCXqP|BV-k+uH6nq<{90{%!F=?2F2lm4>~{7Q5RIUAwl2|Cm9X z>HBlJ?S*o$(r>Nv17)d5kk&NUV$LfwL_sbJ!z-w*FQzb8U+lrxId4k#&1zDgU)8B3 zyr%klcF~$Wa?9mEUw^V;cdEo>P`U8z`Xdpp*8ko0j6UV7kEOateFPR-44$rjF6*2U FngHciR$c%A diff --git a/android/app/src/main/res/drawable-xxxhdpi/ic_notification_icon.png b/android/app/src/main/res/drawable-xxxhdpi/ic_notification_icon.png deleted file mode 100644 index f552b0c83346c058e9807cd2afef45ed99993484..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1840 zcmbVNYgEz+7XM30DImTQ3lti)v{af*awgv;qD}|`Y2_;Fj*e#LD?^JSL`6d@on5WL zk#QW;zve3)okB%vvgyJ2qMY$D5?g9&N{aYcb#cGopai z@O?^nVCQSvdi2#1q`|;IJy|`SGA*x}N*{Gg5Gq{?lyux@0}L4b93B0*8rI|;y})>s zT-QQT#>?j{M!#I=z++N6q>yczH-eH3pIe7!m!IO1hf8JYXzLeeWy}zX))Bf2yBe|= z2>kjq=xrO`xjenc9KxpW)gH4=g zX41^G1<+3wm`hzNA4c<5!_H{?H$=dliZtzZfA*}6OoVDp2$^4fU@}xy!^`mTpJPTfQbDSWwgt}SDR^`q{CTyP#yRA zCC4z%_ojA0ZwJBX>~?M5Lo?6T(%KC0M#0-9&$+USRlAFISArBLR~^p1))#j|3C)s3 z-8MctCY9|#YHfd--=izo!r)aFF&sP2Em+knw z6sX7kFmH~V^oS{q+adp4rO6K-^qaW7Q2jnqUh@Y#-`xKpEdCow;pAKz|0-_pe3^~l zBkb7G&EE$av0q_JG)DIB-qYu!ZM_sd(&{RtwhqCWjDfZCB zvD@*J3equewP4Y`SRQFR<=F6pPKxzRB7^irjZ!)C1pV2xa%oyQchCm2I*BeWkK#r8 zlPVxrY$H~ssoY;MJ{@Fr;tWzZ1aqMi)&8QX%?(j*1IDV{;XEh$g~})EhC!B4!V#u& zdcl}m1sQ-DteMWYG`p#YBQo9Y5y8SULEHK(*0lqG3$@#|pvb*aJXi4m2vE)@;Dhmk z;e~1=nq{T1#u`Iq(RP-di_6@|$wDAP92E2SGZ0vs9=S3kma|U39H3qk%Zd(Vcm%mQ zM#x?kS6vGzDeMm|MKOJrT>E|JCv+u+CIf?~lg=7cn%5?$6&tRe1k)`Xy4@8dVSwg! z^nYjHJK=BJjgiL~6W0U4Oq*KPt6$SXa>q~Z^7RifF1M&e@bdSw{Ngovybamy25$FV z49$3BD*0-B5egV?6t9P7=lv4}yvXmAcAo0SNt%u~m`~8En8Rrzz7+tzN2JxQ8Gn%PwsD9eooOLmQs**GZSd zI0xDQ+kQECzdx#{Y`Eq_-gyAx+c|{CIG1E3q7OP?ve-sjyI#~IdVCKjB8kWF0Vd`v zfg~19m$>T`mcd-PbdUFTGNu2tsKuDbKAJd|9z2tp;{jKV9d;#bbV$NKFvce(E0bw* zPI`tGjF)$^p*?K>mO#r6jE)H(YMQT4G N;O9d=QRmI%{s*c1Z>|6U diff --git a/src/components/utlis/deeplinkingUtils.ts b/src/components/utlis/deeplinkingUtils.ts index 947687b7..eecba8b1 100644 --- a/src/components/utlis/deeplinkingUtils.ts +++ b/src/components/utlis/deeplinkingUtils.ts @@ -4,9 +4,13 @@ import { } from '@react-navigation/native'; import { CaseDetailStackEnum } from '@screens/caseDetails/CaseDetailStack'; import { Linking } from 'react-native'; -import notifee from '@notifee/react-native'; +import notifee, { InitialNotification } from '@notifee/react-native'; import { GenericType } from '@common/GenericTypes'; import { NotificationAction } from '@hooks/useFCM/useFCM'; +import store from '@store'; +import AsyncStorage from '@react-native-async-storage/async-storage'; + +const LAST_INITIAL_NOTIFICATION_ID = 'LAST_INITIAL_NOTIFICATION_ID'; // Define a type for the Route object for better type checking type Route = { @@ -49,6 +53,29 @@ const findRouteByName = (routes: Route[], name: string): Route | null => { return null; }; +const needToHandleInitialNotification = async ( + initialNotification: InitialNotification | null +): Promise => { + if (initialNotification !== null) { + try { + const lastInitialNotificationId = await AsyncStorage.getItem(LAST_INITIAL_NOTIFICATION_ID); + const notificationId = initialNotification.notification.data?.notificationId; + + if (lastInitialNotificationId !== null) { + if (lastInitialNotificationId === notificationId) { + return false; + } + } + + await AsyncStorage.setItem(LAST_INITIAL_NOTIFICATION_ID, String(notificationId)); + return true; + } catch (e) { + return false; + } + } + return false; +}; + // Linking configuration with types for better type safety export const linkingConf: LinkingOptions = { prefixes: ['cosmosapp://'], @@ -58,13 +85,18 @@ export const linkingConf: LinkingOptions = { if (url) { return url; } + // Access Redux store from the imported store instance const message = await notifee.getInitialNotification(); + const shouldHandleInitialNotification = await needToHandleInitialNotification(message); + if (!shouldHandleInitialNotification) return null; if (message?.pressAction?.id === NotificationAction.DEFAULT) { return null; } const caseId = message?.notification?.data?.caseId as string; + const reduxState = store.getState(); + const caseDetails = reduxState?.allCases?.caseDetails?.[caseId]; const notificationId = message?.notification?.data?.notificationId as string; - if (!caseId || !notificationId) return null; + if (!caseId || !notificationId || !caseDetails) return null; const deepLink = `${ message?.notification?.data?.deepLinks?.[message?.pressAction?.id] }¬ificationId=${notificationId}` as string; diff --git a/src/constants/Global.ts b/src/constants/Global.ts index 55874907..705f8fc7 100644 --- a/src/constants/Global.ts +++ b/src/constants/Global.ts @@ -1,5 +1,6 @@ import { buildFlavour } from '@reducers/metadataSlice'; import { isNullOrUndefined } from '../components/utlis/commonFunctions'; +import { setItem } from '@components/utlis/storageHelper'; export enum DEVICE_TYPE_ENUM { MOBILE = 'MOBILE', @@ -13,7 +14,7 @@ export const GLOBAL = { DEVICE_TYPE: DEVICE_TYPE_ENUM.MOBILE, IS_IMPERSONATED: false, SELECTED_AGENT_ID: '', - BUILD_FLAVOUR: '' + BUILD_FLAVOUR: '', }; interface IGlobalUserData { @@ -27,9 +28,18 @@ interface IGlobalUserData { export const setGlobalUserData = (userData: IGlobalUserData) => { const { token, deviceId, agentId, deviceType, isImpersonated, selectedAgentId } = userData; - if (!isNullOrUndefined(token)) GLOBAL.SESSION_TOKEN = `${token}`; - if (!isNullOrUndefined(deviceId)) GLOBAL.DEVICE_ID = `${deviceId}`; - if (!isNullOrUndefined(agentId)) GLOBAL.AGENT_ID = `${agentId}`; + if (!isNullOrUndefined(token)) { + GLOBAL.SESSION_TOKEN = `${token}`; + setItem('sessionToken', String(token)); + } + if (!isNullOrUndefined(deviceId)) { + GLOBAL.DEVICE_ID = `${deviceId}`; + setItem('deviceId', String(deviceId)); + } + if (!isNullOrUndefined(agentId)) { + GLOBAL.AGENT_ID = `${agentId}`; + setItem('agentId', String(agentId)); + } if (!isNullOrUndefined(deviceType)) GLOBAL.DEVICE_TYPE = deviceType as DEVICE_TYPE_ENUM; if (!isNullOrUndefined(isImpersonated)) GLOBAL.IS_IMPERSONATED = isImpersonated ?? false; if (!isNullOrUndefined(selectedAgentId)) GLOBAL.SELECTED_AGENT_ID = `${selectedAgentId}`; diff --git a/src/hooks/useFCM/notificationHelperFunctions.ts b/src/hooks/useFCM/notificationHelperFunctions.ts index 2322de71..e6c0ad0b 100644 --- a/src/hooks/useFCM/notificationHelperFunctions.ts +++ b/src/hooks/useFCM/notificationHelperFunctions.ts @@ -1,11 +1,13 @@ import { CLICKSTREAM_EVENT_NAMES } from '@common/Constants'; import { navigateToScreen } from '@components/utlis/navigationUtlis'; import { AndroidAction, Event, EventType } from '@notifee/react-native'; +import { formatAmount } from '@rn-ui-lib/utils/amount'; import { CaseDetailStackEnum } from '@screens/caseDetails/CaseDetailStack'; import { EmiScheduleTabs } from '@screens/emiSchedule'; import { EmiSelectedTab } from '@screens/emiSchedule/EmiScheduleTab'; import { INotification } from '@screens/notifications/NotificationItem'; import { addClickstreamEvent } from '@services/clickstreamEventService'; +import store from '@store'; // Actions that can be performed on notification export enum NotificationAction { @@ -34,7 +36,9 @@ const getPaymentMadeNotificationContent = (notification: INotification) => { const { params } = notification || {}; const { amount, customerName } = params || {}; const title = `Payment success`; - const body = `${customerName} made a payment of ₹${amount}`; + const body = `${customerName} made a payment of ${formatAmount( + amount + )}`; const actions = [ { title: `VIEW DETAILS`, @@ -57,7 +61,9 @@ const getPaymentFailedNotificationContent = (notification: INotification) => { const { params } = notification || {}; const { amount, customerName } = params || {}; const title = 'Payment failure'; - const body = `${customerName} failed to make a payment of ₹${amount}`; + const body = `${customerName} failed to make a payment of ${formatAmount( + amount + )}`; const actions = [ { title: `VIEW DETAILS`, @@ -112,6 +118,9 @@ export const handleNotificationNavigation = ( caseId: string, notificationId: string ) => { + const reduxState = store.getState(); + const caseDetails = reduxState?.allCases?.caseDetails?.[caseId]; + if(!caseDetails) return; switch (action) { case NotificationAction.VIEW_PAID_SCHEDULE: navigateToScreen('caseDetailStack', { diff --git a/src/hooks/useFCM/useFCM.ts b/src/hooks/useFCM/useFCM.ts index a3a716a3..9413ae6d 100644 --- a/src/hooks/useFCM/useFCM.ts +++ b/src/hooks/useFCM/useFCM.ts @@ -64,6 +64,7 @@ export const sendPushNotification = async (notification: any) => { name: 'Default Channel', importance: AndroidImportance.HIGH, bypassDnd: true, + sound: 'default', }); const notificationContent = getNotificationContent(notification); @@ -77,13 +78,15 @@ export const sendPushNotification = async (notification: any) => { android: { channelId, smallIcon: 'ic_notification_icon', - color: '#1D2678', + color: '#22d081', + largeIcon: 'ic_launcher', showTimestamp: true, actions, style: { type: AndroidStyle.BIGTEXT, text: body }, pressAction: actions[0].pressAction, groupSummary: true, importance: AndroidImportance.HIGH, + sound: 'default', }, data, }); diff --git a/src/screens/auth/ProtectedRouter.tsx b/src/screens/auth/ProtectedRouter.tsx index 4e632c38..de4446da 100644 --- a/src/screens/auth/ProtectedRouter.tsx +++ b/src/screens/auth/ProtectedRouter.tsx @@ -26,6 +26,7 @@ import CaseDetailStack from '@screens/caseDetails/CaseDetailStack'; import FullScreenLoader from '@rn-ui-lib/components/FullScreenLoader'; import { getFirestoreResyncIntervalInMinutes } from '@common/AgentActivityConfigurableConstants'; import AgentIdCard from '@screens/Profile/AgentIdCard'; +import SuspenseLoader from '@rn-ui-lib/components/suspense_loader/SuspenseLoader'; const Stack = createNativeStackNavigator(); @@ -110,7 +111,7 @@ const ProtectedRouter = () => { }; }, []); - if (isLoading) return ; + // if (isLoading) return ; return (