From 57bab7cc773bc36ae638d460745577e6652cbe7c Mon Sep 17 00:00:00 2001 From: cballevre Date: Fri, 13 Sep 2024 15:21:54 +0200 Subject: [PATCH 1/3] feat: Only user action mark a announcement seen Previously, announcements was considered to have been seen when it appeared. Now, it's when the user decides to move on to the next announcement that the one displayed is considered to have been seen. --- .../Announcements/Announcements.tsx | 3 --- .../Announcements/AnnouncementsDialog.tsx | 20 +++++++++++++++++-- .../AnnouncementsDialogContent.tsx | 8 ++++---- src/hooks/useAnnouncements.tsx | 4 ---- 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/src/components/Announcements/Announcements.tsx b/src/components/Announcements/Announcements.tsx index b13c997800..4c5ccd08e4 100644 --- a/src/components/Announcements/Announcements.tsx +++ b/src/components/Announcements/Announcements.tsx @@ -14,9 +14,6 @@ const Announcements: FC = () => { const { values, save } = useAnnouncementsSettings() const handleDismiss = (): void => { - save({ - dismissedAt: new Date().toISOString() - }) setBeenDismissed(true) } diff --git a/src/components/Announcements/AnnouncementsDialog.tsx b/src/components/Announcements/AnnouncementsDialog.tsx index 36e7f4d3c7..a97d3acc3f 100644 --- a/src/components/Announcements/AnnouncementsDialog.tsx +++ b/src/components/Announcements/AnnouncementsDialog.tsx @@ -46,13 +46,29 @@ const AnnouncementsDialog: FC = ({ setActiveStep(index) } + const handleLast = (): void => { + const uuid = announcements[activeStep].attributes.uuid + save({ + dismissedAt: new Date().toISOString(), + seen: [...(values?.seen ?? []), uuid] + }) + onDismiss() + } + + const handleDismiss = (): void => { + save({ + dismissedAt: new Date().toISOString() + }) + onDismiss() + } + const maxSteps = announcements.length return ( = ({ key={index} isLast={index === maxSteps - 1} announcement={announcement} - onDismiss={onDismiss} onNext={handleNext} + onLast={handleLast} /> ))} diff --git a/src/components/Announcements/AnnouncementsDialogContent.tsx b/src/components/Announcements/AnnouncementsDialogContent.tsx index 27ad8298fa..e20349bba4 100644 --- a/src/components/Announcements/AnnouncementsDialogContent.tsx +++ b/src/components/Announcements/AnnouncementsDialogContent.tsx @@ -11,15 +11,15 @@ import { useAnnouncementsImage } from 'hooks/useAnnouncementsImage' interface AnnouncementsDialogContentProps { isLast: boolean announcement: Announcement - onDismiss: () => void onNext: () => void + onLast: () => void } const AnnouncementsDialogContent: FC = ({ isLast, announcement, - onDismiss, - onNext + onNext, + onLast }) => { const { t, f } = useI18n() const primaryImage = useAnnouncementsImage( @@ -87,7 +87,7 @@ const AnnouncementsDialogContent: FC = ({ : 'AnnouncementsDialogContent.next' )} variant="secondary" - onClick={isLast ? onDismiss : onNext} + onClick={isLast ? onLast : onNext} /> {secondaryImage ? ( 0) { - uuidsInCommon.push(unseenData[0].attributes.uuid) - } save({ seen: uuidsInCommon }) setUnseenData(unseenData) From c02808713eade53d9dcacc477fa3935351342701 Mon Sep 17 00:00:00 2001 From: cballevre Date: Fri, 13 Sep 2024 15:22:16 +0200 Subject: [PATCH 2/3] feat: Limit to 5 the number of announcement shown Before the API was limiting the number of response. This limit has been removed so that users can go 5 by 5 through the announcement they haven't seen yet. --- src/hooks/useAnnouncements.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/useAnnouncements.tsx b/src/hooks/useAnnouncements.tsx index 0de05664c2..8f0acdf09b 100644 --- a/src/hooks/useAnnouncements.tsx +++ b/src/hooks/useAnnouncements.tsx @@ -79,7 +79,7 @@ const useAnnouncements = ({ save({ seen: uuidsInCommon }) - setUnseenData(unseenData) + setUnseenData(unseenData.slice(0, 5)) } }, [hasStartedFiltering, rawData, values, save]) From 2d4948b91ef9e399ea21f86bbe8653e6542c26f0 Mon Sep 17 00:00:00 2001 From: cballevre Date: Fri, 13 Sep 2024 15:22:57 +0200 Subject: [PATCH 3/3] feat: Show announcement 1h after the feature has been activated To avoid spamming the interface with new users, we're putting a delay between the first opening of the Home and the appearance of the announcements dialog. --- .../Announcements/Announcements.tsx | 26 ++++++++++++++++--- src/hooks/useAnnouncementsSettings.tsx | 20 +++++++++++--- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/src/components/Announcements/Announcements.tsx b/src/components/Announcements/Announcements.tsx index 4c5ccd08e4..184979cc92 100644 --- a/src/components/Announcements/Announcements.tsx +++ b/src/components/Announcements/Announcements.tsx @@ -1,4 +1,4 @@ -import React, { FC, useState } from 'react' +import React, { FC, useEffect, useState } from 'react' import { differenceInHours } from 'date-fns' import flag from 'cozy-flags' @@ -11,17 +11,37 @@ import { useAnnouncementsSettings } from 'hooks/useAnnouncementsSettings' const Announcements: FC = () => { const config = flag('home.announcements') const [hasBeenDismissed, setBeenDismissed] = useState(false) - const { values, save } = useAnnouncementsSettings() + const { fetchStatus, values, save } = useAnnouncementsSettings() + const [hasBeenActivated, setBeenActivated] = useState(false) + + useEffect(() => { + if ( + !values.firstActivatedAt && + !hasBeenActivated && + fetchStatus === 'loaded' + ) { + save({ + firstActivatedAt: new Date().toISOString() + }) + setBeenActivated(true) + } + }, [hasBeenActivated, save, values.firstActivatedAt, fetchStatus]) const handleDismiss = (): void => { setBeenDismissed(true) } + const hasBeenActivatedForMoreThanAHour = values.firstActivatedAt + ? differenceInHours(new Date(), Date.parse(values.firstActivatedAt)) >= 1 + : false const moreThan = config?.delayAfterDismiss ?? 24 const hasBeenDismissedForMoreThan = values.dismissedAt ? differenceInHours(new Date(), Date.parse(values.dismissedAt)) >= moreThan : true - const canBeDisplayed = !hasBeenDismissed && hasBeenDismissedForMoreThan + const canBeDisplayed = + !hasBeenDismissed && + hasBeenDismissedForMoreThan && + hasBeenActivatedForMoreThanAHour const announcements = useAnnouncements({ canBeDisplayed }) diff --git a/src/hooks/useAnnouncementsSettings.tsx b/src/hooks/useAnnouncementsSettings.tsx index 1e9d474d9d..18d40ea383 100644 --- a/src/hooks/useAnnouncementsSettings.tsx +++ b/src/hooks/useAnnouncementsSettings.tsx @@ -2,23 +2,31 @@ import { useSettings } from 'cozy-client' const defaultAnnouncements = { dismissedAt: undefined, - seen: [] + seen: [], + firstActivatedAt: undefined } const useAnnouncementsSettings = (): { + fetchStatus: string values: { dismissedAt?: string seen: string[] + firstActivatedAt?: string } - save: (data: { dismissedAt?: string; seen?: string[] }) => void + save: (data: { + dismissedAt?: string + seen?: string[] + firstActivatedAt?: string + }) => void } => { - const { values, save } = useSettings('home', [ + const { query, values, save } = useSettings('home', [ 'announcements' ]) as unknown as UseSettingsType const saveAnnouncement = (data: { dismissedAt?: string seen?: string[] + firstActivatedAt?: string }): void => { const announcements = { ...(values?.announcements ?? defaultAnnouncements), @@ -30,22 +38,28 @@ const useAnnouncementsSettings = (): { } return { + fetchStatus: query.fetchStatus, values: values?.announcements ?? defaultAnnouncements, save: saveAnnouncement } } interface UseSettingsType { + query: { + fetchStatus: string + } values?: { announcements: { dismissedAt: string seen: string[] + firstActivatedAt: string } } save: (data: { announcements: { dismissedAt?: string seen: string[] + firstActivatedAt?: string } }) => void }