33import React , { RefObject , useEffect , useRef , useState } from 'react' ;
44
55import FeaturePrompt , { FeaturePromptProps } from '../../../internal/do-not-use/feature-prompt' ;
6+ import { metrics } from '../../../internal/metrics' ;
67import { persistSeenFeatureNotifications , retrieveSeenFeatureNotifications } from '../../../internal/persistence' ;
78import awsuiPlugins from '../../../internal/plugins' ;
89import { Feature , FeatureNotificationsPayload , WidgetMessage } from '../../../internal/plugins/widget/interfaces' ;
910import RuntimeFeaturesNotificationDrawer , { RuntimeContentPart } from '../drawer/feature-notifications-drawer-content' ;
11+
1012interface UseFeatureNotificationsProps {
1113 activeDrawersIds : Array < string > ;
1214}
@@ -34,30 +36,64 @@ function subtractDaysFromDate(currentDate: Date, daysToSubtract: number) {
3436 return pastDate ;
3537}
3638
39+ function filterOutdatedFeatures ( features : Record < string , string > ) : Record < string , string > {
40+ const cutoffDate = subtractDaysFromDate ( new Date ( ) , 180 ) ;
41+
42+ return Object . keys ( features ) . reduce ( ( acc , key ) => {
43+ const featureDate = new Date ( features [ key ] ) ;
44+
45+ if ( featureDate && featureDate >= cutoffDate ) {
46+ return {
47+ ...acc ,
48+ [ key ] : features [ key ] ,
49+ } ;
50+ }
51+
52+ return acc ;
53+ } , { } ) ;
54+ }
55+
3756export function useFeatureNotifications ( { activeDrawersIds } : UseFeatureNotificationsProps ) {
3857 const [ markAllAsRead , setMarkAllAsRead ] = useState ( false ) ;
3958 const [ featurePromptDismissed , setFeaturePromptDismissed ] = useState ( false ) ;
4059 const [ featureNotificationsData , setFeatureNotificationsData ] = useState < FeatureNotificationsPayload < unknown > | null > (
4160 null
4261 ) ;
43- const [ seenFeatureIds , setSeenFeatureIds ] = useState < Set < string > > ( new Set ( ) ) ;
62+ const [ seenFeatures , setSeenFeatures ] = useState < Record < string , string > > ( { } ) ;
4463 const featurePromptRef = useRef < FeaturePromptProps . Ref > ( null ) ;
4564
4665 useEffect ( ( ) => {
4766 if ( ! featureNotificationsData || markAllAsRead ) {
4867 return ;
4968 }
50- const id = featureNotificationsData . id ;
51- if ( activeDrawersIds . includes ( id ) && ! markAllAsRead ) {
52- const allFeaturesIds = [ ...seenFeatureIds , ...featureNotificationsData . features . map ( feature => feature . id ) ] ;
53- const uniqueAllFeatureIds = [ ...new Set ( allFeaturesIds ) ] ;
54- persistSeenFeatureNotifications ( persistenceConfig , uniqueAllFeatureIds ) . then ( ( ) => {
55- awsuiPlugins . appLayout . updateDrawer ( { id, badge : false } ) ;
56- setMarkAllAsRead ( true ) ;
57- } ) ;
69+ try {
70+ const id = featureNotificationsData ?. id ;
71+ if ( activeDrawersIds . includes ( id ) && ! markAllAsRead ) {
72+ const featuresMap = featureNotificationsData . features . reduce ( ( acc , feature ) => {
73+ return {
74+ ...acc ,
75+ [ feature . id ] : feature . releaseDate . toString ( ) ,
76+ } ;
77+ } , { } ) ;
78+ const filteredSeenFeaturesMap = filterOutdatedFeatures ( seenFeatures ) ;
79+ const allFeaturesMap = { ...featuresMap , ...filteredSeenFeaturesMap } ;
80+ persistSeenFeatureNotifications ( persistenceConfig , allFeaturesMap ) . then ( ( ) => {
81+ awsuiPlugins . appLayout . updateDrawer ( { id, badge : false } ) ;
82+ setMarkAllAsRead ( true ) ;
83+ } ) ;
84+ }
5885 return ;
86+ } catch ( error ) {
87+ let message = '' ;
88+ if ( error instanceof Error ) {
89+ message = error ?. message ?? '' ;
90+ }
91+ metrics . sendOpsMetricObject ( 'awsui-widget-feature-notifications-error' , {
92+ id : featureNotificationsData ?. id ,
93+ message,
94+ } ) ;
5995 }
60- } , [ featureNotificationsData , activeDrawersIds , markAllAsRead , featurePromptDismissed , seenFeatureIds ] ) ;
96+ } , [ featureNotificationsData , activeDrawersIds , markAllAsRead , featurePromptDismissed , seenFeatures ] ) ;
6197
6298 const defaultFeaturesFilter = ( feature : Feature < unknown > ) => {
6399 return feature . releaseDate >= subtractDaysFromDate ( new Date ( ) , 90 ) ;
@@ -103,9 +139,8 @@ export function useFeatureNotifications({ activeDrawersIds }: UseFeatureNotifica
103139 } ) ;
104140
105141 retrieveSeenFeatureNotifications ( persistenceConfig ) . then ( seenFeatureNotifications => {
106- const seenFeatureNotificationsSet = new Set ( seenFeatureNotifications ) ;
107- setSeenFeatureIds ( seenFeatureNotificationsSet ) ;
108- const hasUnseenFeatures = features . some ( feature => ! seenFeatureNotificationsSet . has ( feature . id ) ) ;
142+ setSeenFeatures ( seenFeatureNotifications ) ;
143+ const hasUnseenFeatures = features . some ( feature => ! seenFeatureNotifications [ feature . id ] ) ;
109144 if ( hasUnseenFeatures ) {
110145 if ( ! payload . suppressFeaturePrompt && ! featurePromptDismissed ) {
111146 featurePromptRef . current ?. show ( ) ;
@@ -117,7 +152,6 @@ export function useFeatureNotifications({ activeDrawersIds }: UseFeatureNotifica
117152 }
118153
119154 if ( event . type === 'showFeaturePromptIfPossible' ) {
120- console . log ( 'showFeaturePromptIfPossible markAllAsRead: ' , markAllAsRead ) ;
121155 if ( markAllAsRead ) {
122156 return ;
123157 }
@@ -134,12 +168,11 @@ export function useFeatureNotifications({ activeDrawersIds }: UseFeatureNotifica
134168 // Features array is already sorted in reverse chronological order (most recent first)
135169 // Find the first feature that hasn't been seen
136170 for ( const feature of featureNotificationsData . features ) {
137- if ( ! seenFeatureIds . has ( feature . id ) ) {
171+ if ( ! seenFeatures [ feature . id ] ) {
138172 return feature ;
139173 }
140174 }
141175
142- // No unseen features found
143176 return null ;
144177 }
145178
0 commit comments