@open-mercato/core 0.6.7-develop.6785.1.1dd7cfac55 → 0.6.7-develop.6795.1.8a3f27921c

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (196) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/generated/entities.ids.generated.js +1 -0
  3. package/dist/generated/entities.ids.generated.js.map +2 -2
  4. package/dist/modules/auth/backend/settings/page.js +14 -9
  5. package/dist/modules/auth/backend/settings/page.js.map +2 -2
  6. package/dist/modules/customers/cli.js +17 -7
  7. package/dist/modules/customers/cli.js.map +2 -2
  8. package/dist/modules/customers/components/detail/ScheduleActivityDialog.js +229 -216
  9. package/dist/modules/customers/components/detail/ScheduleActivityDialog.js.map +2 -2
  10. package/dist/modules/customers/search.js +50 -29
  11. package/dist/modules/customers/search.js.map +2 -2
  12. package/dist/modules/data_sync/api/mappings/[id]/route.js +22 -9
  13. package/dist/modules/data_sync/api/mappings/[id]/route.js.map +2 -2
  14. package/dist/modules/data_sync/api/mappings/route.js +13 -4
  15. package/dist/modules/data_sync/api/mappings/route.js.map +2 -2
  16. package/dist/modules/data_sync/api/options.js +7 -2
  17. package/dist/modules/data_sync/api/options.js.map +2 -2
  18. package/dist/modules/data_sync/api/run.js +7 -2
  19. package/dist/modules/data_sync/api/run.js.map +2 -2
  20. package/dist/modules/data_sync/api/runs/[id]/cancel.js +8 -3
  21. package/dist/modules/data_sync/api/runs/[id]/cancel.js.map +2 -2
  22. package/dist/modules/data_sync/api/runs/[id]/retry.js +7 -2
  23. package/dist/modules/data_sync/api/runs/[id]/retry.js.map +2 -2
  24. package/dist/modules/data_sync/api/runs/[id]/route.js +8 -3
  25. package/dist/modules/data_sync/api/runs/[id]/route.js.map +2 -2
  26. package/dist/modules/data_sync/api/runs.js +7 -2
  27. package/dist/modules/data_sync/api/runs.js.map +2 -2
  28. package/dist/modules/data_sync/api/schedules/[id]/route.js +19 -6
  29. package/dist/modules/data_sync/api/schedules/[id]/route.js.map +2 -2
  30. package/dist/modules/data_sync/api/schedules/route.js +13 -4
  31. package/dist/modules/data_sync/api/schedules/route.js.map +2 -2
  32. package/dist/modules/data_sync/api/validate.js +9 -4
  33. package/dist/modules/data_sync/api/validate.js.map +2 -2
  34. package/dist/modules/design_system/acl.js +9 -0
  35. package/dist/modules/design_system/acl.js.map +7 -0
  36. package/dist/modules/design_system/backend/design-system/page.js +11 -0
  37. package/dist/modules/design_system/backend/design-system/page.js.map +7 -0
  38. package/dist/modules/design_system/backend/design-system/page.meta.js +15 -0
  39. package/dist/modules/design_system/backend/design-system/page.meta.js.map +7 -0
  40. package/dist/modules/design_system/gallery/components/CodeSnippet.js +52 -0
  41. package/dist/modules/design_system/gallery/components/CodeSnippet.js.map +7 -0
  42. package/dist/modules/design_system/gallery/components/EntryCard.js +63 -0
  43. package/dist/modules/design_system/gallery/components/EntryCard.js.map +7 -0
  44. package/dist/modules/design_system/gallery/components/GalleryShell.js +163 -0
  45. package/dist/modules/design_system/gallery/components/GalleryShell.js.map +7 -0
  46. package/dist/modules/design_system/gallery/components/VariantPreview.js +9 -0
  47. package/dist/modules/design_system/gallery/components/VariantPreview.js.map +7 -0
  48. package/dist/modules/design_system/gallery/entries/banners.js +186 -0
  49. package/dist/modules/design_system/gallery/entries/banners.js.map +7 -0
  50. package/dist/modules/design_system/gallery/entries/buttons.js +361 -0
  51. package/dist/modules/design_system/gallery/entries/buttons.js.map +7 -0
  52. package/dist/modules/design_system/gallery/entries/charts.js +457 -0
  53. package/dist/modules/design_system/gallery/entries/charts.js.map +7 -0
  54. package/dist/modules/design_system/gallery/entries/dates.js +306 -0
  55. package/dist/modules/design_system/gallery/entries/dates.js.map +7 -0
  56. package/dist/modules/design_system/gallery/entries/detail.js +358 -0
  57. package/dist/modules/design_system/gallery/entries/detail.js.map +7 -0
  58. package/dist/modules/design_system/gallery/entries/display.js +785 -0
  59. package/dist/modules/design_system/gallery/entries/display.js.map +7 -0
  60. package/dist/modules/design_system/gallery/entries/feedback.js +658 -0
  61. package/dist/modules/design_system/gallery/entries/feedback.js.map +7 -0
  62. package/dist/modules/design_system/gallery/entries/filters.js +505 -0
  63. package/dist/modules/design_system/gallery/entries/filters.js.map +7 -0
  64. package/dist/modules/design_system/gallery/entries/foundations.js +453 -0
  65. package/dist/modules/design_system/gallery/entries/foundations.js.map +7 -0
  66. package/dist/modules/design_system/gallery/entries/icons.js +140 -0
  67. package/dist/modules/design_system/gallery/entries/icons.js.map +7 -0
  68. package/dist/modules/design_system/gallery/entries/inputs.js +1217 -0
  69. package/dist/modules/design_system/gallery/entries/inputs.js.map +7 -0
  70. package/dist/modules/design_system/gallery/entries/messages.js +334 -0
  71. package/dist/modules/design_system/gallery/entries/messages.js.map +7 -0
  72. package/dist/modules/design_system/gallery/entries/navigation.js +475 -0
  73. package/dist/modules/design_system/gallery/entries/navigation.js.map +7 -0
  74. package/dist/modules/design_system/gallery/entries/notifications.js +257 -0
  75. package/dist/modules/design_system/gallery/entries/notifications.js.map +7 -0
  76. package/dist/modules/design_system/gallery/entries/overlays.js +576 -0
  77. package/dist/modules/design_system/gallery/entries/overlays.js.map +7 -0
  78. package/dist/modules/design_system/gallery/entries/scaffolding.js +378 -0
  79. package/dist/modules/design_system/gallery/entries/scaffolding.js.map +7 -0
  80. package/dist/modules/design_system/gallery/entries/schedule.js +297 -0
  81. package/dist/modules/design_system/gallery/entries/schedule.js.map +7 -0
  82. package/dist/modules/design_system/gallery/registry.js +139 -0
  83. package/dist/modules/design_system/gallery/registry.js.map +7 -0
  84. package/dist/modules/design_system/gallery/types.js +1 -0
  85. package/dist/modules/design_system/gallery/types.js.map +7 -0
  86. package/dist/modules/design_system/index.js +9 -0
  87. package/dist/modules/design_system/index.js.map +7 -0
  88. package/dist/modules/design_system/setup.js +14 -0
  89. package/dist/modules/design_system/setup.js.map +7 -0
  90. package/dist/modules/inbox_ops/search.js +15 -4
  91. package/dist/modules/inbox_ops/search.js.map +2 -2
  92. package/dist/modules/integrations/api/[id]/credentials/route.js +11 -5
  93. package/dist/modules/integrations/api/[id]/credentials/route.js.map +2 -2
  94. package/dist/modules/integrations/api/[id]/health/route.js +6 -3
  95. package/dist/modules/integrations/api/[id]/health/route.js.map +2 -2
  96. package/dist/modules/integrations/api/[id]/route.js +6 -3
  97. package/dist/modules/integrations/api/[id]/route.js.map +2 -2
  98. package/dist/modules/integrations/api/[id]/state/route.js +6 -3
  99. package/dist/modules/integrations/api/[id]/state/route.js.map +2 -2
  100. package/dist/modules/integrations/api/[id]/version/route.js +6 -3
  101. package/dist/modules/integrations/api/[id]/version/route.js.map +2 -2
  102. package/dist/modules/integrations/api/logs/route.js +6 -3
  103. package/dist/modules/integrations/api/logs/route.js.map +2 -2
  104. package/dist/modules/integrations/api/route.js +6 -3
  105. package/dist/modules/integrations/api/route.js.map +2 -2
  106. package/dist/modules/integrations/api/umes-read.js +2 -2
  107. package/dist/modules/integrations/api/umes-read.js.map +2 -2
  108. package/dist/modules/integrations/lib/organization-scope.js +2 -9
  109. package/dist/modules/integrations/lib/organization-scope.js.map +2 -2
  110. package/dist/modules/messages/search.js +10 -5
  111. package/dist/modules/messages/search.js.map +2 -2
  112. package/dist/modules/query_index/data/entities.js +2 -1
  113. package/dist/modules/query_index/data/entities.js.map +2 -2
  114. package/dist/modules/query_index/lib/engine.js +32 -50
  115. package/dist/modules/query_index/lib/engine.js.map +2 -2
  116. package/dist/modules/query_index/migrations/Migration20260731105052_query_index.js +17 -0
  117. package/dist/modules/query_index/migrations/Migration20260731105052_query_index.js.map +7 -0
  118. package/generated/entities.ids.generated.ts +1 -0
  119. package/package.json +16 -16
  120. package/src/modules/auth/backend/settings/page.tsx +17 -8
  121. package/src/modules/customers/cli.ts +17 -7
  122. package/src/modules/customers/components/detail/ScheduleActivityDialog.tsx +24 -13
  123. package/src/modules/customers/i18n/de.json +17 -0
  124. package/src/modules/customers/i18n/en.json +17 -0
  125. package/src/modules/customers/i18n/es.json +17 -0
  126. package/src/modules/customers/i18n/pl.json +17 -0
  127. package/src/modules/customers/search.ts +59 -27
  128. package/src/modules/data_sync/AGENTS.md +1 -0
  129. package/src/modules/data_sync/api/mappings/[id]/route.ts +22 -9
  130. package/src/modules/data_sync/api/mappings/route.ts +13 -4
  131. package/src/modules/data_sync/api/options.ts +7 -2
  132. package/src/modules/data_sync/api/run.ts +7 -2
  133. package/src/modules/data_sync/api/runs/[id]/cancel.ts +8 -3
  134. package/src/modules/data_sync/api/runs/[id]/retry.ts +7 -2
  135. package/src/modules/data_sync/api/runs/[id]/route.ts +8 -3
  136. package/src/modules/data_sync/api/runs.ts +7 -2
  137. package/src/modules/data_sync/api/schedules/[id]/route.ts +19 -6
  138. package/src/modules/data_sync/api/schedules/route.ts +13 -4
  139. package/src/modules/data_sync/api/validate.ts +9 -4
  140. package/src/modules/design_system/AGENTS.md +34 -0
  141. package/src/modules/design_system/acl.ts +5 -0
  142. package/src/modules/design_system/backend/design-system/page.meta.ts +11 -0
  143. package/src/modules/design_system/backend/design-system/page.tsx +14 -0
  144. package/src/modules/design_system/gallery/components/CodeSnippet.tsx +55 -0
  145. package/src/modules/design_system/gallery/components/EntryCard.tsx +95 -0
  146. package/src/modules/design_system/gallery/components/GalleryShell.tsx +206 -0
  147. package/src/modules/design_system/gallery/components/VariantPreview.tsx +15 -0
  148. package/src/modules/design_system/gallery/entries/banners.tsx +226 -0
  149. package/src/modules/design_system/gallery/entries/buttons.tsx +422 -0
  150. package/src/modules/design_system/gallery/entries/charts.tsx +518 -0
  151. package/src/modules/design_system/gallery/entries/dates.tsx +325 -0
  152. package/src/modules/design_system/gallery/entries/detail.tsx +403 -0
  153. package/src/modules/design_system/gallery/entries/display.tsx +893 -0
  154. package/src/modules/design_system/gallery/entries/feedback.tsx +746 -0
  155. package/src/modules/design_system/gallery/entries/filters.tsx +570 -0
  156. package/src/modules/design_system/gallery/entries/foundations.tsx +529 -0
  157. package/src/modules/design_system/gallery/entries/icons.tsx +168 -0
  158. package/src/modules/design_system/gallery/entries/inputs.tsx +1516 -0
  159. package/src/modules/design_system/gallery/entries/messages.tsx +339 -0
  160. package/src/modules/design_system/gallery/entries/navigation.tsx +573 -0
  161. package/src/modules/design_system/gallery/entries/notifications.tsx +285 -0
  162. package/src/modules/design_system/gallery/entries/overlays.tsx +677 -0
  163. package/src/modules/design_system/gallery/entries/scaffolding.tsx +430 -0
  164. package/src/modules/design_system/gallery/entries/schedule.tsx +307 -0
  165. package/src/modules/design_system/gallery/registry.ts +152 -0
  166. package/src/modules/design_system/gallery/types.ts +32 -0
  167. package/src/modules/design_system/i18n/.hardcoded-allowlist.json +71 -0
  168. package/src/modules/design_system/i18n/de.json +46 -0
  169. package/src/modules/design_system/i18n/en.json +46 -0
  170. package/src/modules/design_system/i18n/es.json +46 -0
  171. package/src/modules/design_system/i18n/pl.json +46 -0
  172. package/src/modules/design_system/index.ts +7 -0
  173. package/src/modules/design_system/setup.ts +12 -0
  174. package/src/modules/inbox_ops/i18n/de.json +3 -0
  175. package/src/modules/inbox_ops/i18n/en.json +3 -0
  176. package/src/modules/inbox_ops/i18n/es.json +3 -0
  177. package/src/modules/inbox_ops/i18n/pl.json +3 -0
  178. package/src/modules/inbox_ops/search.ts +20 -4
  179. package/src/modules/integrations/api/[id]/credentials/route.ts +11 -5
  180. package/src/modules/integrations/api/[id]/health/route.ts +6 -3
  181. package/src/modules/integrations/api/[id]/route.ts +6 -3
  182. package/src/modules/integrations/api/[id]/state/route.ts +6 -3
  183. package/src/modules/integrations/api/[id]/version/route.ts +6 -3
  184. package/src/modules/integrations/api/logs/route.ts +6 -3
  185. package/src/modules/integrations/api/route.ts +6 -3
  186. package/src/modules/integrations/api/umes-read.ts +2 -2
  187. package/src/modules/integrations/lib/organization-scope.ts +5 -25
  188. package/src/modules/messages/i18n/de.json +2 -0
  189. package/src/modules/messages/i18n/en.json +2 -0
  190. package/src/modules/messages/i18n/es.json +2 -0
  191. package/src/modules/messages/i18n/pl.json +2 -0
  192. package/src/modules/messages/search.ts +11 -5
  193. package/src/modules/query_index/data/entities.ts +7 -0
  194. package/src/modules/query_index/lib/engine.ts +40 -63
  195. package/src/modules/query_index/migrations/.snapshot-open-mercato.json +12 -0
  196. package/src/modules/query_index/migrations/Migration20260731105052_query_index.ts +35 -0
@@ -0,0 +1,285 @@
1
+ import * as React from 'react'
2
+ import { Bell } from 'lucide-react'
3
+ import { Button } from '@open-mercato/ui/primitives/button'
4
+ import { IconButton } from '@open-mercato/ui/primitives/icon-button'
5
+ import {
6
+ NotificationCountBadge,
7
+ NotificationItem,
8
+ NotificationPanel,
9
+ } from '@open-mercato/ui/backend/notifications'
10
+ import type { NotificationDto } from '@open-mercato/shared/modules/notifications/types'
11
+ import type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'
12
+ import type { GalleryEntry } from '../types'
13
+
14
+ // Component titles and variant names are proper nouns from the codebase and
15
+ // are deliberately not translated. `code` MUST contain the entry's importPath
16
+ // (enforced by the registry-integrity test) and is always reviewed alongside
17
+ // its sibling `render`.
18
+
19
+ // All previews below run on inline mocked data — no API calls, no SSE.
20
+ // `NotificationBell` itself is wired to `useNotifications` (SSE + API) and
21
+ // cannot be severed from it, so its entry shows the presentational chrome
22
+ // (bell trigger + `NotificationCountBadge`) instead of mounting the live bell.
23
+
24
+ const galleryT: TranslateFn = (key, fallbackOrParams, params) => {
25
+ const fallback = typeof fallbackOrParams === 'string' ? fallbackOrParams : key
26
+ const variables = (typeof fallbackOrParams === 'object' ? fallbackOrParams : params) ?? {}
27
+ return Object.entries(variables).reduce(
28
+ (text, [name, value]) => text.replaceAll(`{${name}}`, String(value)),
29
+ fallback,
30
+ )
31
+ }
32
+
33
+ const minutesAgo = (minutes: number) => new Date(Date.now() - minutes * 60_000).toISOString()
34
+
35
+ const noopMarkAsRead = async () => {}
36
+ const noopDismiss = async () => {}
37
+ const noopExecuteAction = async () => ({})
38
+
39
+ function mockNotification(overrides: Partial<NotificationDto>): NotificationDto {
40
+ return {
41
+ id: 'gallery-notification',
42
+ type: 'gallery.demo',
43
+ title: 'Notification',
44
+ severity: 'info',
45
+ status: 'unread',
46
+ actions: [],
47
+ createdAt: minutesAgo(5),
48
+ ...overrides,
49
+ }
50
+ }
51
+
52
+ const unreadInfoNotification = mockNotification({
53
+ id: 'gallery-unread-info',
54
+ title: 'Nightly import finished',
55
+ severity: 'info',
56
+ status: 'unread',
57
+ sourceModule: 'catalog',
58
+ createdAt: minutesAgo(4),
59
+ })
60
+
61
+ const successWithBodyNotification = mockNotification({
62
+ id: 'gallery-success-body',
63
+ title: 'Order #10023 shipped',
64
+ body: 'Carrier picked up 3 parcels. Tracking numbers were emailed to the customer.',
65
+ severity: 'success',
66
+ status: 'read',
67
+ sourceModule: 'sales',
68
+ createdAt: minutesAgo(35),
69
+ })
70
+
71
+ const actionRequiredNotification = mockNotification({
72
+ id: 'gallery-action-required',
73
+ title: 'Price list awaiting approval',
74
+ body: 'Wholesale EU price list changes 214 products.',
75
+ severity: 'warning',
76
+ status: 'unread',
77
+ sourceModule: 'pricing',
78
+ actions: [
79
+ { id: 'review', label: 'Review changes', variant: 'outline' },
80
+ { id: 'approve', label: 'Approve', variant: 'default' },
81
+ ],
82
+ createdAt: minutesAgo(90),
83
+ })
84
+
85
+ const panelNotifications: NotificationDto[] = [
86
+ unreadInfoNotification,
87
+ actionRequiredNotification,
88
+ successWithBodyNotification,
89
+ ]
90
+
91
+ function DemoNotificationPanel() {
92
+ const [open, setOpen] = React.useState(false)
93
+ return (
94
+ <>
95
+ <Button variant="outline" onClick={() => setOpen(true)}>
96
+ Open notification panel
97
+ </Button>
98
+ <NotificationPanel
99
+ open={open}
100
+ onOpenChange={setOpen}
101
+ notifications={panelNotifications}
102
+ unreadCount={2}
103
+ onMarkAsRead={noopMarkAsRead}
104
+ onExecuteAction={noopExecuteAction}
105
+ onDismiss={noopDismiss}
106
+ onMarkAllRead={noopMarkAsRead}
107
+ t={galleryT}
108
+ />
109
+ </>
110
+ )
111
+ }
112
+
113
+ const notificationBellEntry: GalleryEntry = {
114
+ id: 'notification-bell',
115
+ title: 'NotificationBell',
116
+ importPath: '@open-mercato/ui/backend/notifications',
117
+ variants: [
118
+ {
119
+ id: 'presentational-mock',
120
+ title: 'Presentational mock (live bell is SSE-wired)',
121
+ render: () => (
122
+ <IconButton variant="ghost" size="sm" className="relative" aria-label="3 unread notifications">
123
+ <Bell className="h-5 w-5" />
124
+ <NotificationCountBadge count={3} />
125
+ </IconButton>
126
+ ),
127
+ code: `import { NotificationBell } from '@open-mercato/ui/backend/notifications'
128
+
129
+ // Wired to the notifications API + SSE — AppShell renders one in the topbar.
130
+ <NotificationBell t={t} />`,
131
+ },
132
+ ],
133
+ }
134
+
135
+ const notificationCountBadgeEntry: GalleryEntry = {
136
+ id: 'notification-count-badge',
137
+ title: 'NotificationCountBadge',
138
+ importPath: '@open-mercato/ui/backend/notifications',
139
+ variants: [
140
+ {
141
+ id: 'counts',
142
+ title: 'Counts (caps at 99+)',
143
+ render: () => (
144
+ <>
145
+ <IconButton variant="ghost" size="sm" className="relative" aria-label="3 unread notifications">
146
+ <Bell className="h-5 w-5" />
147
+ <NotificationCountBadge count={3} />
148
+ </IconButton>
149
+ <IconButton variant="ghost" size="sm" className="relative" aria-label="12 unread notifications">
150
+ <Bell className="h-5 w-5" />
151
+ <NotificationCountBadge count={12} />
152
+ </IconButton>
153
+ <IconButton variant="ghost" size="sm" className="relative" aria-label="120 unread notifications">
154
+ <Bell className="h-5 w-5" />
155
+ <NotificationCountBadge count={120} />
156
+ </IconButton>
157
+ </>
158
+ ),
159
+ code: `import { NotificationCountBadge } from '@open-mercato/ui/backend/notifications'
160
+
161
+ // Renders nothing for count <= 0; anchors to the nearest relative parent.
162
+ <IconButton variant="ghost" size="sm" className="relative" aria-label="3 unread notifications">
163
+ <Bell className="h-5 w-5" />
164
+ <NotificationCountBadge count={3} />
165
+ </IconButton>`,
166
+ },
167
+ ],
168
+ }
169
+
170
+ const notificationItemEntry: GalleryEntry = {
171
+ id: 'notification-item',
172
+ title: 'NotificationItem',
173
+ importPath: '@open-mercato/ui/backend/notifications',
174
+ variants: [
175
+ {
176
+ id: 'unread-info',
177
+ title: 'Unread (mocked data)',
178
+ render: () => (
179
+ <div className="w-full max-w-md">
180
+ <NotificationItem
181
+ notification={unreadInfoNotification}
182
+ onMarkAsRead={noopMarkAsRead}
183
+ onExecuteAction={noopExecuteAction}
184
+ onDismiss={noopDismiss}
185
+ t={galleryT}
186
+ />
187
+ </div>
188
+ ),
189
+ code: `import { NotificationItem } from '@open-mercato/ui/backend/notifications'
190
+
191
+ <NotificationItem
192
+ notification={notification} // NotificationDto with status: 'unread'
193
+ onMarkAsRead={() => markAsRead(notification.id)}
194
+ onExecuteAction={(actionId) => executeAction(notification.id, actionId)}
195
+ onDismiss={() => dismiss(notification.id)}
196
+ t={t}
197
+ />`,
198
+ },
199
+ {
200
+ id: 'with-body',
201
+ title: 'Read with body bubble (mocked data)',
202
+ render: () => (
203
+ <div className="w-full max-w-md">
204
+ <NotificationItem
205
+ notification={successWithBodyNotification}
206
+ onMarkAsRead={noopMarkAsRead}
207
+ onExecuteAction={noopExecuteAction}
208
+ onDismiss={noopDismiss}
209
+ t={galleryT}
210
+ />
211
+ </div>
212
+ ),
213
+ code: `import { NotificationItem } from '@open-mercato/ui/backend/notifications'
214
+
215
+ // A notification with a body renders it as a speech-bubble under the title.
216
+ <NotificationItem
217
+ notification={notification} // NotificationDto with body text
218
+ onMarkAsRead={() => markAsRead(notification.id)}
219
+ onExecuteAction={(actionId) => executeAction(notification.id, actionId)}
220
+ onDismiss={() => dismiss(notification.id)}
221
+ t={t}
222
+ />`,
223
+ },
224
+ {
225
+ id: 'with-actions',
226
+ title: 'Action required (mocked data)',
227
+ render: () => (
228
+ <div className="w-full max-w-md">
229
+ <NotificationItem
230
+ notification={actionRequiredNotification}
231
+ onMarkAsRead={noopMarkAsRead}
232
+ onExecuteAction={noopExecuteAction}
233
+ onDismiss={noopDismiss}
234
+ t={galleryT}
235
+ />
236
+ </div>
237
+ ),
238
+ code: `import { NotificationItem } from '@open-mercato/ui/backend/notifications'
239
+
240
+ // Actions come from notification.actions; the last one renders as primary.
241
+ <NotificationItem
242
+ notification={notification} // NotificationDto with actions[]
243
+ onMarkAsRead={() => markAsRead(notification.id)}
244
+ onExecuteAction={(actionId) => executeAction(notification.id, actionId)}
245
+ onDismiss={() => dismiss(notification.id)}
246
+ t={t}
247
+ />`,
248
+ },
249
+ ],
250
+ }
251
+
252
+ const notificationPanelEntry: GalleryEntry = {
253
+ id: 'notification-panel',
254
+ title: 'NotificationPanel',
255
+ importPath: '@open-mercato/ui/backend/notifications',
256
+ variants: [
257
+ {
258
+ id: 'mocked-inbox',
259
+ title: 'Mocked inbox (opens in a sheet)',
260
+ render: () => <DemoNotificationPanel />,
261
+ code: `import { NotificationPanel } from '@open-mercato/ui/backend/notifications'
262
+
263
+ const [open, setOpen] = React.useState(false)
264
+
265
+ <NotificationPanel
266
+ open={open}
267
+ onOpenChange={setOpen}
268
+ notifications={notifications} // NotificationDto[]
269
+ unreadCount={unreadCount}
270
+ onMarkAsRead={markAsRead}
271
+ onExecuteAction={executeAction}
272
+ onDismiss={dismiss}
273
+ onMarkAllRead={markAllRead}
274
+ t={t}
275
+ />`,
276
+ },
277
+ ],
278
+ }
279
+
280
+ export const entries: GalleryEntry[] = [
281
+ notificationBellEntry,
282
+ notificationCountBadgeEntry,
283
+ notificationItemEntry,
284
+ notificationPanelEntry,
285
+ ]