@@ -4,81 +4,18 @@ import type { Notification } from '../../../notifications';
4
4
import { ActionTypeEnum } from '../../../types' ;
5
5
import { useInboxContext , useLocalization } from '../../context' ;
6
6
import { cn , formatToRelativeTime , useStyle } from '../../helpers' ;
7
- import { MarkAsUnarchived } from '../../icons' ;
8
7
import { Clock } from '../../icons/Clock' ;
9
- import { MarkAsArchived } from '../../icons/MarkAsArchived' ;
10
- import { MarkAsRead } from '../../icons/MarkAsRead' ;
11
- import { MarkAsUnread } from '../../icons/MarkAsUnread' ;
12
- import { Snooze } from '../../icons/Snooze' ;
13
- import { Unsnooze } from '../../icons/Unsnooze' ;
14
8
import {
15
- LocalizationKey ,
16
- NotificationStatus ,
17
9
type BodyRenderer ,
18
10
type NotificationActionClickHandler ,
19
11
type NotificationClickHandler ,
20
12
type SubjectRenderer ,
21
13
} from '../../types' ;
22
14
import Markdown from '../elements/Markdown' ;
23
15
import { ExternalElementRenderer } from '../ExternalElementRenderer' ;
24
- import { Button , Dropdown , dropdownItemVariants , Popover } from '../primitives' ;
16
+ import { Button } from '../primitives' ;
25
17
import { Badge } from '../primitives/Badge' ;
26
- import { Tooltip } from '../primitives/Tooltip' ;
27
- import { SnoozeDateTimePicker } from './SnoozeDateTimePicker' ;
28
-
29
- const SNOOZE_PRESETS = [
30
- {
31
- key : 'snooze.options.anHourFromNow' ,
32
- hours : 1 ,
33
- getDate : ( ) => new Date ( Date . now ( ) + 1 * 60 * 60 * 1000 ) ,
34
- } ,
35
- {
36
- key : 'snooze.options.inTwelveHours' ,
37
- hours : 12 ,
38
- getDate : ( ) => new Date ( Date . now ( ) + 12 * 60 * 60 * 1000 ) ,
39
- } ,
40
- {
41
- key : 'snooze.options.inOneDay' ,
42
- hours : 24 ,
43
- getDate : ( ) => new Date ( Date . now ( ) + 1 * 24 * 60 * 60 * 1000 ) ,
44
- } ,
45
- {
46
- key : 'snooze.options.inOneWeek' ,
47
- hours : 168 ,
48
- getDate : ( ) => new Date ( Date . now ( ) + 7 * 24 * 60 * 60 * 1000 ) ,
49
- } ,
50
- ] satisfies {
51
- key : LocalizationKey ;
52
- hours : number ;
53
- getDate : ( ) => Date ;
54
- } [ ] ;
55
-
56
- const formatSnoozeOption = (
57
- preset : ( typeof SNOOZE_PRESETS ) [ number ] ,
58
- t : ( key : LocalizationKey ) => string ,
59
- locale : string
60
- ) : string => {
61
- const date = preset . getDate ( ) ;
62
-
63
- // For hour-based presets (1 hour, 12 hours), just show the translation without time
64
- if ( preset . hours <= 12 ) {
65
- return t ( preset . key ) ;
66
- }
67
-
68
- // Format time (e.g., "9:00 AM")
69
- const timeString = new Intl . DateTimeFormat ( locale , { hour : 'numeric' , minute : 'numeric' } ) . format ( date ) ;
70
-
71
- // For weekly option, show "Next Monday" etc.
72
- if ( preset . key === 'snooze.options.inOneWeek' ) {
73
- // Get the day name (e.g., "Monday")
74
- const dayName = new Intl . DateTimeFormat ( locale , { weekday : 'long' } ) . format ( date ) ;
75
-
76
- return `${ t ( preset . key ) } ${ dayName } , ${ timeString } ` ;
77
- }
78
-
79
- // Fallback to original translation
80
- return `${ t ( preset . key ) } , ${ timeString } ` ;
81
- } ;
18
+ import { renderNotificationActions } from './NotificationActions' ;
82
19
83
20
type DefaultNotificationProps = {
84
21
notification : Notification ;
@@ -92,8 +29,7 @@ type DefaultNotificationProps = {
92
29
export const DefaultNotification = ( props : DefaultNotificationProps ) => {
93
30
const style = useStyle ( ) ;
94
31
const { t, locale } = useLocalization ( ) ;
95
- const { navigate, status, maxSnoozeDurationHours } = useInboxContext ( ) ;
96
- const [ isSnoozeDateTimePickerOpen , setIsSnoozeDateTimePickerOpen ] = createSignal ( false ) ;
32
+ const { navigate, status } = useInboxContext ( ) ;
97
33
const [ minutesPassed , setMinutesPassed ] = createSignal ( 0 ) ;
98
34
const createdAt = createMemo ( ( ) => {
99
35
minutesPassed ( ) ; // register as dep
@@ -120,12 +56,6 @@ export const DefaultNotification = (props: DefaultNotificationProps) => {
120
56
) ;
121
57
} ) ;
122
58
123
- const availableSnoozePresets = createMemo ( ( ) => {
124
- if ( ! maxSnoozeDurationHours ( ) ) return SNOOZE_PRESETS ;
125
-
126
- return SNOOZE_PRESETS . filter ( ( preset ) => preset . hours <= maxSnoozeDurationHours ( ) ) ;
127
- } ) ;
128
-
129
59
createEffect ( ( ) => {
130
60
const interval = setInterval ( ( ) => {
131
61
setMinutesPassed ( ( prev ) => prev + 1 ) ;
@@ -228,214 +158,10 @@ export const DefaultNotification = (props: DefaultNotificationProps) => {
228
158
< div
229
159
class = { style (
230
160
'notificationDefaultActions' ,
231
- ' nt-absolute nt-transition nt-duration-100 nt-ease-out nt-gap-0.5 nt-flex nt-shrink-0 nt-opacity-0 group-hover:nt-opacity-100 group-focus-within:nt-opacity-100 nt-justify-center nt-items-center nt-bg-background/90 nt-right-3 nt-top-3 nt-border nt-border-neutral-alpha-100 nt-rounded-lg nt-backdrop-blur-lg nt-p-0.5'
161
+ ` nt-absolute nt-transition nt-duration-100 nt-ease-out nt-gap-0.5 nt-flex nt-shrink-0 nt-opacity-0 group-hover:nt-opacity-100 group-focus-within:nt-opacity-100 nt-justify-center nt-items-center nt-bg-background/90 nt-right-3 nt-top-3 nt-border nt-border-neutral-alpha-100 nt-rounded-lg nt-backdrop-blur-lg nt-p-0.5`
232
162
) }
233
163
>
234
- < Show when = { status ( ) !== NotificationStatus . ARCHIVED } >
235
- < Show
236
- when = { props . notification . isRead }
237
- fallback = {
238
- < Tooltip . Root >
239
- < Tooltip . Trigger
240
- asChild = { ( childProps ) => (
241
- < Button
242
- appearanceKey = "notificationRead__button"
243
- size = "iconSm"
244
- variant = "ghost"
245
- { ...childProps }
246
- onClick = { async ( e ) => {
247
- e . stopPropagation ( ) ;
248
- await props . notification . read ( ) ;
249
- } }
250
- >
251
- < MarkAsRead class = { style ( 'notificationRead__icon' , 'nt-size-3' ) } />
252
- </ Button >
253
- ) }
254
- />
255
- < Tooltip . Content data-localization = "notification.actions.read.tooltip" >
256
- { t ( 'notification.actions.read.tooltip' ) }
257
- </ Tooltip . Content >
258
- </ Tooltip . Root >
259
- }
260
- >
261
- < Tooltip . Root >
262
- < Tooltip . Trigger
263
- asChild = { ( childProps ) => (
264
- < Button
265
- appearanceKey = "notificationUnread__button"
266
- size = "iconSm"
267
- variant = "ghost"
268
- { ...childProps }
269
- onClick = { async ( e ) => {
270
- e . stopPropagation ( ) ;
271
- await props . notification . unread ( ) ;
272
- } }
273
- >
274
- < MarkAsUnread class = { style ( 'notificationUnread__icon' , 'nt-size-3' ) } />
275
- </ Button >
276
- ) }
277
- />
278
- < Tooltip . Content data-localization = "notification.actions.unread.tooltip" >
279
- { t ( 'notification.actions.unread.tooltip' ) }
280
- </ Tooltip . Content >
281
- </ Tooltip . Root >
282
- </ Show >
283
- </ Show >
284
-
285
- < Show
286
- when = { props . notification . isSnoozed }
287
- fallback = {
288
- < Tooltip . Root >
289
- < Tooltip . Trigger
290
- asChild = { ( tooltipProps ) => (
291
- < Dropdown . Root >
292
- < Dropdown . Trigger
293
- { ...tooltipProps }
294
- asChild = { ( popoverProps ) => (
295
- < Button
296
- appearanceKey = "notificationSnooze__button"
297
- size = "iconSm"
298
- variant = "ghost"
299
- { ...popoverProps }
300
- >
301
- < Snooze class = { style ( 'notificationSnooze__icon' , 'nt-size-3' ) } />
302
- </ Button >
303
- ) }
304
- />
305
- < Dropdown . Content appearanceKey = "notificationSnooze__dropdownContent" >
306
- < For each = { availableSnoozePresets ( ) } >
307
- { ( preset ) => (
308
- < Dropdown . Item
309
- appearanceKey = "notificationSnooze__dropdownItem"
310
- onClick = { async ( e ) => {
311
- e . stopPropagation ( ) ;
312
- await props . notification . snooze ( preset . getDate ( ) . toISOString ( ) ) ;
313
- } }
314
- >
315
- < Clock
316
- class = { style (
317
- 'notificationSnooze__dropdownItem__icon' ,
318
- 'nt-size-3 nt-text-foreground-alpha-400'
319
- ) }
320
- />
321
- { formatSnoozeOption ( preset , t , locale ( ) ) }
322
- </ Dropdown . Item >
323
- ) }
324
- </ For >
325
-
326
- < Popover . Root open = { isSnoozeDateTimePickerOpen ( ) } onOpenChange = { setIsSnoozeDateTimePickerOpen } >
327
- < Dropdown . Item
328
- asChild = { ( props ) => (
329
- < Popover . Trigger
330
- class = { style ( 'notificationSnooze__dropdownItem' , dropdownItemVariants ( ) ) }
331
- { ...props }
332
- >
333
- < Clock
334
- class = { style (
335
- 'notificationSnooze__dropdownItem__icon' ,
336
- 'nt-size-3 nt-text-foreground-alpha-400'
337
- ) }
338
- />
339
- { t ( 'snooze.options.customTime' ) }
340
- </ Popover . Trigger >
341
- ) }
342
- />
343
- < Popover . Content
344
- portal
345
- class = { style ( 'notificationSnoozeCustomTime_popoverContent' , 'nt-size-fit' ) }
346
- >
347
- < SnoozeDateTimePicker
348
- maxDurationHours = { maxSnoozeDurationHours ( ) }
349
- onSelect = { async ( date ) => {
350
- await props . notification . snooze ( date . toISOString ( ) ) ;
351
- } }
352
- onCancel = { ( ) => {
353
- setIsSnoozeDateTimePickerOpen ( false ) ;
354
- } }
355
- />
356
- </ Popover . Content >
357
- </ Popover . Root >
358
- </ Dropdown . Content >
359
- </ Dropdown . Root >
360
- ) }
361
- />
362
- < Tooltip . Content data-localization = "notification.actions.read.tooltip" >
363
- { t ( 'notification.actions.snooze.tooltip' ) }
364
- </ Tooltip . Content >
365
- </ Tooltip . Root >
366
- }
367
- >
368
- < Tooltip . Root >
369
- < Tooltip . Trigger
370
- asChild = { ( childProps ) => (
371
- < Button
372
- appearanceKey = "notificationUnsnooze__button"
373
- size = "iconSm"
374
- variant = "ghost"
375
- { ...childProps }
376
- onClick = { async ( e ) => {
377
- e . stopPropagation ( ) ;
378
- await props . notification . unsnooze ( ) ;
379
- } }
380
- >
381
- < Unsnooze class = { style ( 'notificationUnsnooze__icon' , 'nt-size-3' ) } />
382
- </ Button >
383
- ) }
384
- />
385
- < Tooltip . Content data-localization = "notification.actions.unsnooze.tooltip" >
386
- { t ( 'notification.actions.unsnooze.tooltip' ) }
387
- </ Tooltip . Content >
388
- </ Tooltip . Root >
389
- </ Show >
390
-
391
- < Show
392
- when = { props . notification . isArchived }
393
- fallback = {
394
- < Tooltip . Root >
395
- < Tooltip . Trigger
396
- asChild = { ( childProps ) => (
397
- < Button
398
- appearanceKey = "notificationArchive__button"
399
- size = "iconSm"
400
- variant = "ghost"
401
- { ...childProps }
402
- onClick = { async ( e ) => {
403
- e . stopPropagation ( ) ;
404
- await props . notification . archive ( ) ;
405
- } }
406
- >
407
- < MarkAsArchived class = { style ( 'notificationArchive__icon' , 'nt-size-3' ) } />
408
- </ Button >
409
- ) }
410
- />
411
- < Tooltip . Content data-localization = "notification.actions.archive.tooltip" >
412
- { t ( 'notification.actions.archive.tooltip' ) }
413
- </ Tooltip . Content >
414
- </ Tooltip . Root >
415
- }
416
- >
417
- < Tooltip . Root >
418
- < Tooltip . Trigger
419
- asChild = { ( childProps ) => (
420
- < Button
421
- appearanceKey = "notificationUnarchive__button"
422
- size = "iconSm"
423
- variant = "ghost"
424
- { ...childProps }
425
- onClick = { async ( e ) => {
426
- e . stopPropagation ( ) ;
427
- await props . notification . unarchive ( ) ;
428
- } }
429
- >
430
- < MarkAsUnarchived class = { style ( 'notificationArchive__icon' , 'nt-size-3' ) } />
431
- </ Button >
432
- ) }
433
- />
434
- < Tooltip . Content data-localization = "notification.actions.unarchive.tooltip" >
435
- { t ( 'notification.actions.unarchive.tooltip' ) }
436
- </ Tooltip . Content >
437
- </ Tooltip . Root >
438
- </ Show >
164
+ { renderNotificationActions ( props . notification , status ) }
439
165
</ div >
440
166
< Show when = { props . notification . primaryAction || props . notification . secondaryAction } >
441
167
< div class = { style ( 'notificationCustomActions' , 'nt-flex nt-flex-wrap nt-gap-2' ) } >
0 commit comments