Skip to content

Commit

Permalink
feat: ajout de la gestion de l'état lu/pas lu des notifications (#168)
Browse files Browse the repository at this point in the history
Signed-off-by: fc-santos <[email protected]>
  • Loading branch information
fc-santos authored Dec 4, 2024
1 parent ebfc31d commit 88fe552
Show file tree
Hide file tree
Showing 7 changed files with 179 additions and 90 deletions.
4 changes: 4 additions & 0 deletions app/container-imp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import {
IASEnvironment,
getInitialState,
QCPreferences,
ActivityState,
} from './src/store'

export interface AppState {
Expand Down Expand Up @@ -217,6 +218,7 @@ export class AppContainer implements Container {
let tours = initialState.tours
let onboarding = initialState.onboarding
let attestationAuthentificationDissmissed = initialState.attestationAuthentification
let activities = initialState.activities
let { environment } = initialState.developer

await Promise.all([
Expand All @@ -233,6 +235,7 @@ export class AppContainer implements Container {
BCLocalStorageKeys.AttestationAuthentification,
(val) => (attestationAuthentificationDissmissed = val)
),
loadState<ActivityState>(BCLocalStorageKeys.Activities, (val) => (activities = val)),
loadState<IASEnvironment>(BCLocalStorageKeys.Environment, (val) => (environment = val)),
])
const state: BCState = {
Expand All @@ -246,6 +249,7 @@ export class AppContainer implements Container {
...initialState.attestationAuthentification,
...attestationAuthentificationDissmissed,
},
activities,
developer: {
...initialState.developer,
environment,
Expand Down
31 changes: 26 additions & 5 deletions app/src/components/EventItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ const iconSize = 20
interface EventItemProps {
action?: GenericFn
handleDelete?: () => Promise<void>
isRead?: boolean
isHome?: boolean
event: {
id: string
title?: string
Expand All @@ -37,6 +39,8 @@ const EventItem = ({
onOpenSwipeable,
activateSelection,
setSelected,
isRead = true,
isHome,
}: EventItemProps): React.JSX.Element => {
const { t } = useTranslation()
const { ColorPallet, TextTheme } = useTheme()
Expand All @@ -51,8 +55,11 @@ const EventItem = ({
flex: 1,
flexDirection: 'row',
justifyContent: 'space-between',
backgroundColor: ColorPallet.grayscale.white,
backgroundColor: !isHome && !isRead ? ColorPallet.notification.info : ColorPallet.grayscale.white,
zIndex: 9999,
...(!isHome && {
padding: 16,
}),
gap: 8,
},
infoContainer: {
Expand Down Expand Up @@ -164,8 +171,15 @@ const EventItem = ({
text1: t('Activities.NotificationsDeleted', { count: 1 }),
onShow() {
dispatch({
type: BCDispatchAction.NOTIFICATIONS_TEMPORARILY_DELETED_IDS,
payload: [event.id],
type: BCDispatchAction.ACTIVITY_TEMPORARILY_DELETED_IDS,
payload: [
{
[event.id]: {
isRead,
isTempDeleted: true,
},
},
],
})
},
onHide: () => {
Expand All @@ -179,8 +193,15 @@ const EventItem = ({
onCancel: () => {
hasCanceledRef.current = true
dispatch({
type: BCDispatchAction.NOTIFICATIONS_TEMPORARILY_DELETED_IDS,
payload: [],
type: BCDispatchAction.ACTIVITY_TEMPORARILY_DELETED_IDS,
payload: [
{
[event.id]: {
isRead,
isTempDeleted: false,
},
},
],
})
},
},
Expand Down
67 changes: 19 additions & 48 deletions app/src/components/NotificationListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
W3cCredentialRecord,
} from '@credo-ts/core'
import { useAgent, useConnectionById } from '@credo-ts/react-hooks'
import { BifoldError, EventTypes, Screens, Stacks, useStore, useTheme } from '@hyperledger/aries-bifold-core'
import { BifoldError, EventTypes, Screens, Stacks, useStore } from '@hyperledger/aries-bifold-core'
import { BasicMessageMetadata, basicMessageCustomMetadata } from '@hyperledger/aries-bifold-core/App/types/metadata'
import { HomeStackParams } from '@hyperledger/aries-bifold-core/App/types/navigators'
import { CustomNotification, CustomNotificationRecord } from '@hyperledger/aries-bifold-core/App/types/notification'
Expand All @@ -27,6 +27,7 @@ import FleurLysImg from '../assets/img/FleurLys.svg'
import MessageImg from '../assets/img/Message.svg'
import ProofRequestImg from '../assets/img/ProofRequest.svg'
import RevocationImg from '../assets/img/Revocation.svg'
import { BCDispatchAction, BCState } from '../store'

import CustomCheckBox from './CustomCheckBox'
import EventItem from './EventItem'
Expand Down Expand Up @@ -55,6 +56,7 @@ interface NotificationListItemProps {
selected?: boolean
setSelected?: ({ id, deleteAction }: { id: string; deleteAction?: () => Promise<void> }) => void
activateSelection?: boolean
isHome?: boolean
}

type DisplayDetails = {
Expand All @@ -79,11 +81,12 @@ const NotificationListItem: React.FC<NotificationListItemProps> = ({
selected,
setSelected,
activateSelection,
isHome = true,
}) => {
const navigation = useNavigation<StackNavigationProp<HomeStackParams>>()
const [store, dispatch] = useStore()
const [store, dispatch] = useStore<BCState>()
const storeNofication = store.activities[notification.id]
const { t } = useTranslation()
const { ColorPallet, TextTheme } = useTheme()
const { agent } = useAgent()
const isNotCustomNotification =
notification instanceof BasicMessageRecord ||
Expand All @@ -98,55 +101,10 @@ const NotificationListItem: React.FC<NotificationListItemProps> = ({
})

const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'row',
justifyContent: 'space-between',
backgroundColor: ColorPallet.grayscale.white,
zIndex: 9999,
gap: 8,
},
infoContainer: {
flex: 2,
},
arrowContainer: {
justifyContent: 'center',
},
headerText: {
...TextTheme.labelTitle,
flexGrow: 1,
flex: 1,
},
bodyText: {
...TextTheme.labelSubtitle,
marginVertical: 8,
},
bodyEventTime: {
...TextTheme.labelSubtitle,
color: ColorPallet.grayscale.mediumGrey,
fontSize: 12,
},
icon: {
width: 24,
height: 24,
},
rightAction: {
padding: 8,
backgroundColor: ColorPallet.semantic.error,
minWidth: 120,
justifyContent: 'center',
flex: 1,
marginVertical: 'auto',
alignItems: 'center',
},
rightActionIcon: {
color: ColorPallet.brand.secondary,
},
rightActionText: {
color: ColorPallet.brand.secondary,
fontSize: 14,
fontWeight: '600',
},
})

const handleSwipeClose = () => {
Expand Down Expand Up @@ -303,6 +261,17 @@ const NotificationListItem: React.FC<NotificationListItemProps> = ({
| W3cCredentialRecord,
notificationType: NotificationTypeEnum
) => {
dispatch({
type: BCDispatchAction.NOTIFICATIONS_UPDATED,
payload: [
{
[notification.id]: {
isRead: true,
isTempDeleted: false,
},
},
],
})
switch (notificationType) {
case NotificationTypeEnum.BasicMessage:
navigation.getParent()?.navigate(Stacks.ContactStack, {
Expand Down Expand Up @@ -374,6 +343,8 @@ const NotificationListItem: React.FC<NotificationListItemProps> = ({
return (
<EventItem
action={action}
isRead={!!storeNofication?.isRead}
isHome={isHome}
handleDelete={removeCurrentNotification}
event={{
id: notification.id,
Expand Down
18 changes: 5 additions & 13 deletions app/src/hooks/notifications.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ import {
} from '@credo-ts/core'
import { useCredentialByState, useProofByState, useBasicMessages, useAgent } from '@credo-ts/react-hooks'
import { BifoldAgent, useStore } from '@hyperledger/aries-bifold-core'
import { useOpenID } from '@hyperledger/aries-bifold-core/App/modules/openid/hooks/openid'
import { OpenId4VPRequestRecord } from '@hyperledger/aries-bifold-core/App/modules/openid/types'
import {
BasicMessageMetadata,
CredentialMetadata,
Expand Down Expand Up @@ -60,16 +58,15 @@ export type NotificationType =

export type NotificationReturnType = Array<NotificationType>

export const useNotifications = ({ openIDUri, isHome = true }: NotificationsInputProps): NotificationReturnType => {
export const useNotifications = ({ isHome = true }: NotificationsInputProps): NotificationReturnType => {
const { records: basicMessages } = useBasicMessages()
const [notifications, setNotifications] = useState([])
const [notifications, setNotifications] = useState<NotificationReturnType>([])

const credsReceived = useCredentialByState(CredentialState.CredentialReceived)
const credsDone = useCredentialByState(CredentialState.Done)
const proofsDone = useProofByState([ProofState.Done, ProofState.PresentationReceived])
const offers = useCredentialByState(CredentialState.OfferReceived)
const proofsRequested = useProofByState(ProofState.RequestReceived)
const openIDCredReceived = useOpenID({ openIDUri })

const { agent } = useAgent()
const [store] = useStore<BCState>()
Expand Down Expand Up @@ -139,16 +136,11 @@ export const useNotifications = ({ openIDUri, isHome = true }: NotificationsInpu
)
})

const openIDCreds: Array<SdJwtVcRecord | W3cCredentialRecord | OpenId4VPRequestRecord> = []
if (openIDCredReceived) {
openIDCreds.push(openIDCredReceived)
}

let notif = [...messagesToShow, ...custom, ...receivedOffers, ...proofs, ...revoked, ...openIDCreds].sort(
let notif = [...messagesToShow, ...custom, ...receivedOffers, ...proofs, ...revoked].sort(
(a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()
)

notif = notif.filter((n) => !store.notificationsTempDeletedIds.includes((n as NotificationType).id))
notif = notif.filter((n) => !store.activities[n.id]?.isTempDeleted)

setNotifications(isHome ? (notif.splice(0, 5) as never[]) : (notif as never[]))
}, [
Expand All @@ -159,7 +151,7 @@ export const useNotifications = ({ openIDUri, isHome = true }: NotificationsInpu
nonAttestationProofs,
store.attestationAuthentification.isDismissed,
store.attestationAuthentification.isSeenOnHome,
store.notificationsTempDeletedIds,
store.activities,
])

useEffect(() => {
Expand Down
23 changes: 21 additions & 2 deletions app/src/navigators/TabStack.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ import AtestationTabIcon from '../assets/img/icons/atestation.svg'
import HomeTabIcon from '../assets/img/icons/home.svg'
import NotificationTabIcon from '../assets/img/icons/notification.svg'
import PlusTabIcon from '../assets/img/icons/plus.svg'
import { NotificationReturnType, NotificationsInputProps } from '../hooks/notifications'
import { NotificationReturnType, NotificationsInputProps, NotificationType } from '../hooks/notifications'
import { BCDispatchAction, BCState, ActivityState } from '../store'
import { notificationsSeenOnHome } from '../utils/notificationsSeenOnHome'

import ActivitiesStack from './ActivitiesStack'
Expand All @@ -37,7 +38,7 @@ import { TabStackParams, TabStacks } from './navigators'
const TabStack: React.FC = () => {
const { fontScale } = useWindowDimensions()
const { agent } = useAgent()
const [store, dispatch] = useStore()
const [store, dispatch] = useStore<BCState>()
const navigation = useNavigation<StackNavigationProp<TabStackParams>>()

const [{ useNotifications }, { enableImplicitInvitations, enableReuseConnections }, logger] = useServices([
Expand Down Expand Up @@ -148,6 +149,24 @@ const TabStack: React.FC = () => {
}
}, [agent, notifications])

useEffect(() => {
const notificationsToAdd = {} as ActivityState
for (const n of notifications) {
if (!store.activities[(n as NotificationType).id]) {
notificationsToAdd[(n as NotificationType).id] = {
isRead: false,
isTempDeleted: false,
}
}
}
if (Object.keys(notificationsToAdd).length > 0) {
dispatch({
type: BCDispatchAction.NOTIFICATIONS_UPDATED,
payload: [notificationsToAdd],
})
}
}, [notifications])

const TabBarIcon = (props: {
focused: boolean
color: string
Expand Down
Loading

0 comments on commit 88fe552

Please sign in to comment.