@open-mercato/core 0.5.1-develop.2953.6647bb2c43 → 0.5.1-develop.2964.d5ac4a6ebb

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 (226) hide show
  1. package/dist/helpers/integration/salesUi.js +25 -23
  2. package/dist/helpers/integration/salesUi.js.map +2 -2
  3. package/dist/modules/api_docs/frontend/docs/api/Explorer.js +24 -24
  4. package/dist/modules/api_docs/frontend/docs/api/Explorer.js.map +2 -2
  5. package/dist/modules/attachments/components/AttachmentPartitionSettings.js +15 -7
  6. package/dist/modules/attachments/components/AttachmentPartitionSettings.js.map +2 -2
  7. package/dist/modules/attachments/fields/attachment.js +4 -6
  8. package/dist/modules/attachments/fields/attachment.js.map +2 -2
  9. package/dist/modules/auth/backend/users/create/page.js +26 -26
  10. package/dist/modules/auth/backend/users/create/page.js.map +2 -2
  11. package/dist/modules/business_rules/components/ActionRow.js +36 -25
  12. package/dist/modules/business_rules/components/ActionRow.js.map +2 -2
  13. package/dist/modules/business_rules/components/ConditionGroup.js +14 -5
  14. package/dist/modules/business_rules/components/ConditionGroup.js.map +2 -2
  15. package/dist/modules/business_rules/components/ConditionRow.js +19 -10
  16. package/dist/modules/business_rules/components/ConditionRow.js.map +2 -2
  17. package/dist/modules/business_rules/components/RuleSetMembers.js +16 -10
  18. package/dist/modules/business_rules/components/RuleSetMembers.js.map +2 -2
  19. package/dist/modules/catalog/backend/catalog/products/[id]/page.js +30 -34
  20. package/dist/modules/catalog/backend/catalog/products/[id]/page.js.map +2 -2
  21. package/dist/modules/catalog/backend/catalog/products/create/page.js +220 -223
  22. package/dist/modules/catalog/backend/catalog/products/create/page.js.map +2 -2
  23. package/dist/modules/catalog/components/PriceKindSettings.js +20 -19
  24. package/dist/modules/catalog/components/PriceKindSettings.js.map +2 -2
  25. package/dist/modules/catalog/components/products/ProductUomSection.js +42 -37
  26. package/dist/modules/catalog/components/products/ProductUomSection.js.map +2 -2
  27. package/dist/modules/catalog/components/products/VariantBuilder.js +22 -18
  28. package/dist/modules/catalog/components/products/VariantBuilder.js.map +2 -2
  29. package/dist/modules/customer_accounts/backend/customer_accounts/users/[id]/page.js +18 -26
  30. package/dist/modules/customer_accounts/backend/customer_accounts/users/[id]/page.js.map +2 -2
  31. package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js +4 -6
  32. package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js.map +2 -2
  33. package/dist/modules/customer_accounts/widgets/injection/account-status/widget.client.js +5 -4
  34. package/dist/modules/customer_accounts/widgets/injection/account-status/widget.client.js.map +2 -2
  35. package/dist/modules/customers/backend/config/customers/pipeline-stages/page.js +19 -7
  36. package/dist/modules/customers/backend/config/customers/pipeline-stages/page.js.map +2 -2
  37. package/dist/modules/customers/backend/customers/deals/pipeline/page.js +24 -21
  38. package/dist/modules/customers/backend/customers/deals/pipeline/page.js.map +2 -2
  39. package/dist/modules/customers/components/AddressEditor.js +24 -7
  40. package/dist/modules/customers/components/AddressEditor.js.map +2 -2
  41. package/dist/modules/customers/components/AddressFormatSettings.js +35 -25
  42. package/dist/modules/customers/components/AddressFormatSettings.js.map +2 -2
  43. package/dist/modules/customers/components/detail/ActivityForm.js +20 -12
  44. package/dist/modules/customers/components/detail/ActivityForm.js.map +2 -2
  45. package/dist/modules/customers/components/detail/AnnualRevenueField.js +2 -2
  46. package/dist/modules/customers/components/detail/AnnualRevenueField.js.map +2 -2
  47. package/dist/modules/customers/components/detail/DealForm.js +19 -14
  48. package/dist/modules/customers/components/detail/DealForm.js.map +2 -2
  49. package/dist/modules/customers/components/formConfig.js +16 -12
  50. package/dist/modules/customers/components/formConfig.js.map +2 -2
  51. package/dist/modules/customers/widgets/dashboard/customer-todos/widget.client.js +3 -2
  52. package/dist/modules/customers/widgets/dashboard/customer-todos/widget.client.js.map +2 -2
  53. package/dist/modules/customers/widgets/dashboard/new-customers/widget.client.js +18 -10
  54. package/dist/modules/customers/widgets/dashboard/new-customers/widget.client.js.map +2 -2
  55. package/dist/modules/customers/widgets/dashboard/new-deals/widget.client.js +3 -2
  56. package/dist/modules/customers/widgets/dashboard/new-deals/widget.client.js.map +2 -2
  57. package/dist/modules/customers/widgets/dashboard/next-interactions/widget.client.js +3 -2
  58. package/dist/modules/customers/widgets/dashboard/next-interactions/widget.client.js.map +2 -2
  59. package/dist/modules/dashboards/components/WidgetVisibilityEditor.js +27 -28
  60. package/dist/modules/dashboards/components/WidgetVisibilityEditor.js.map +2 -2
  61. package/dist/modules/dashboards/widgets/dashboard/orders-by-status/widget.client.js +14 -6
  62. package/dist/modules/dashboards/widgets/dashboard/orders-by-status/widget.client.js.map +2 -2
  63. package/dist/modules/dashboards/widgets/dashboard/revenue-trend/widget.client.js +14 -6
  64. package/dist/modules/dashboards/widgets/dashboard/revenue-trend/widget.client.js.map +2 -2
  65. package/dist/modules/dashboards/widgets/dashboard/sales-by-region/widget.client.js +3 -2
  66. package/dist/modules/dashboards/widgets/dashboard/sales-by-region/widget.client.js.map +2 -2
  67. package/dist/modules/dashboards/widgets/dashboard/top-customers/widget.client.js +3 -2
  68. package/dist/modules/dashboards/widgets/dashboard/top-customers/widget.client.js.map +2 -2
  69. package/dist/modules/dashboards/widgets/dashboard/top-products/widget.client.js +17 -8
  70. package/dist/modules/dashboards/widgets/dashboard/top-products/widget.client.js.map +2 -2
  71. package/dist/modules/data_sync/backend/data-sync/page.js +40 -23
  72. package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
  73. package/dist/modules/data_sync/components/IntegrationScheduleTab.js +15 -6
  74. package/dist/modules/data_sync/components/IntegrationScheduleTab.js.map +2 -2
  75. package/dist/modules/dictionaries/components/AppearanceSelector.js +4 -4
  76. package/dist/modules/dictionaries/components/AppearanceSelector.js.map +2 -2
  77. package/dist/modules/dictionaries/components/DictionaryEntriesEditor.js +4 -5
  78. package/dist/modules/dictionaries/components/DictionaryEntriesEditor.js.map +2 -2
  79. package/dist/modules/dictionaries/components/DictionaryEntrySelect.js +22 -14
  80. package/dist/modules/dictionaries/components/DictionaryEntrySelect.js.map +2 -2
  81. package/dist/modules/dictionaries/fields/dictionary.js +18 -13
  82. package/dist/modules/dictionaries/fields/dictionary.js.map +2 -2
  83. package/dist/modules/entities/components/EncryptionManager.js +23 -19
  84. package/dist/modules/entities/components/EncryptionManager.js.map +2 -2
  85. package/dist/modules/feature_toggles/components/formConfig.js +17 -9
  86. package/dist/modules/feature_toggles/components/formConfig.js.map +2 -2
  87. package/dist/modules/feature_toggles/components/overrideFormConfig.js +17 -9
  88. package/dist/modules/feature_toggles/components/overrideFormConfig.js.map +2 -2
  89. package/dist/modules/inbox_ops/backend/inbox-ops/settings/page.js +15 -8
  90. package/dist/modules/inbox_ops/backend/inbox-ops/settings/page.js.map +2 -2
  91. package/dist/modules/inbox_ops/components/proposals/EditActionDialog.js +37 -22
  92. package/dist/modules/inbox_ops/components/proposals/EditActionDialog.js.map +2 -2
  93. package/dist/modules/integrations/backend/integrations/[id]/page.js +22 -17
  94. package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
  95. package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js +12 -6
  96. package/dist/modules/integrations/backend/integrations/bundle/[id]/page.js.map +2 -2
  97. package/dist/modules/planner/components/AvailabilityRulesEditor.js +19 -12
  98. package/dist/modules/planner/components/AvailabilityRulesEditor.js.map +2 -2
  99. package/dist/modules/resources/components/ResourceCrudForm.js +15 -10
  100. package/dist/modules/resources/components/ResourceCrudForm.js.map +3 -3
  101. package/dist/modules/sales/backend/sales/documents/[id]/page.js +15 -18
  102. package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
  103. package/dist/modules/sales/components/ProviderFieldInput.js +23 -20
  104. package/dist/modules/sales/components/ProviderFieldInput.js.map +2 -2
  105. package/dist/modules/sales/components/ShippingMethodsSettings.js +25 -17
  106. package/dist/modules/sales/components/ShippingMethodsSettings.js.map +3 -3
  107. package/dist/modules/sales/components/channels/ChannelOfferForm.js +35 -42
  108. package/dist/modules/sales/components/channels/ChannelOfferForm.js.map +2 -2
  109. package/dist/modules/sales/components/documents/AddressesSection.js +87 -90
  110. package/dist/modules/sales/components/documents/AddressesSection.js.map +2 -2
  111. package/dist/modules/sales/components/documents/AdjustmentDialog.js +17 -6
  112. package/dist/modules/sales/components/documents/AdjustmentDialog.js.map +3 -3
  113. package/dist/modules/sales/components/documents/LineItemDialog.js +42 -25
  114. package/dist/modules/sales/components/documents/LineItemDialog.js.map +2 -2
  115. package/dist/modules/sales/components/documents/SalesDocumentForm.js +96 -87
  116. package/dist/modules/sales/components/documents/SalesDocumentForm.js.map +2 -2
  117. package/dist/modules/sales/widgets/dashboard/new-orders/widget.client.js +20 -11
  118. package/dist/modules/sales/widgets/dashboard/new-orders/widget.client.js.map +2 -2
  119. package/dist/modules/sales/widgets/dashboard/new-quotes/widget.client.js +20 -11
  120. package/dist/modules/sales/widgets/dashboard/new-quotes/widget.client.js.map +2 -2
  121. package/dist/modules/shipping_carriers/lib/shipment-wizard/components/ConfigureStep.js +36 -22
  122. package/dist/modules/shipping_carriers/lib/shipment-wizard/components/ConfigureStep.js.map +2 -2
  123. package/dist/modules/staff/components/TeamMemberForm.js +14 -9
  124. package/dist/modules/staff/components/TeamMemberForm.js.map +3 -3
  125. package/dist/modules/workflows/backend/tasks/[id]/page.js +42 -21
  126. package/dist/modules/workflows/backend/tasks/[id]/page.js.map +2 -2
  127. package/dist/modules/workflows/components/ActivitiesEditor.js +14 -6
  128. package/dist/modules/workflows/components/ActivitiesEditor.js.map +3 -3
  129. package/dist/modules/workflows/components/DefinitionTriggersEditor.js +25 -17
  130. package/dist/modules/workflows/components/DefinitionTriggersEditor.js.map +3 -3
  131. package/dist/modules/workflows/components/EdgeEditDialog.js +48 -45
  132. package/dist/modules/workflows/components/EdgeEditDialog.js.map +2 -2
  133. package/dist/modules/workflows/components/NodeEditDialog.js +90 -90
  134. package/dist/modules/workflows/components/NodeEditDialog.js.map +2 -2
  135. package/dist/modules/workflows/components/StepsEditor.js +14 -6
  136. package/dist/modules/workflows/components/StepsEditor.js.map +3 -3
  137. package/dist/modules/workflows/components/TransitionsEditor.js +31 -26
  138. package/dist/modules/workflows/components/TransitionsEditor.js.map +3 -3
  139. package/dist/modules/workflows/components/fields/ActivityArrayEditor.js +19 -11
  140. package/dist/modules/workflows/components/fields/ActivityArrayEditor.js.map +3 -3
  141. package/dist/modules/workflows/components/fields/BusinessRuleConditionsEditor.js +12 -14
  142. package/dist/modules/workflows/components/fields/BusinessRuleConditionsEditor.js.map +2 -2
  143. package/dist/modules/workflows/components/fields/FormFieldArrayEditor.js +24 -16
  144. package/dist/modules/workflows/components/fields/FormFieldArrayEditor.js.map +3 -3
  145. package/dist/modules/workflows/components/fields/StartPreConditionsEditor.js +12 -13
  146. package/dist/modules/workflows/components/fields/StartPreConditionsEditor.js.map +2 -2
  147. package/dist/modules/workflows/components/mobile/MobileTaskForm.js +12 -8
  148. package/dist/modules/workflows/components/mobile/MobileTaskForm.js.map +2 -2
  149. package/dist/modules/workflows/frontend/checkout-demo/page.js +43 -46
  150. package/dist/modules/workflows/frontend/checkout-demo/page.js.map +2 -2
  151. package/package.json +3 -3
  152. package/src/helpers/integration/salesUi.ts +40 -30
  153. package/src/modules/api_docs/frontend/docs/api/Explorer.tsx +25 -19
  154. package/src/modules/attachments/components/AttachmentPartitionSettings.tsx +21 -11
  155. package/src/modules/attachments/fields/attachment.tsx +4 -6
  156. package/src/modules/auth/backend/users/create/page.tsx +16 -20
  157. package/src/modules/business_rules/components/ActionRow.tsx +51 -32
  158. package/src/modules/business_rules/components/ConditionGroup.tsx +20 -9
  159. package/src/modules/business_rules/components/ConditionRow.tsx +24 -15
  160. package/src/modules/business_rules/components/RuleSetMembers.tsx +23 -13
  161. package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +47 -53
  162. package/src/modules/catalog/backend/catalog/products/create/page.tsx +84 -87
  163. package/src/modules/catalog/components/PriceKindSettings.tsx +9 -9
  164. package/src/modules/catalog/components/products/ProductUomSection.tsx +85 -83
  165. package/src/modules/catalog/components/products/VariantBuilder.tsx +49 -33
  166. package/src/modules/customer_accounts/backend/customer_accounts/users/[id]/page.tsx +12 -27
  167. package/src/modules/customer_accounts/backend/customer_accounts/users/page.tsx +4 -6
  168. package/src/modules/customer_accounts/widgets/injection/account-status/widget.client.tsx +5 -4
  169. package/src/modules/customers/backend/config/customers/pipeline-stages/page.tsx +28 -15
  170. package/src/modules/customers/backend/customers/deals/pipeline/page.tsx +37 -26
  171. package/src/modules/customers/components/AddressEditor.tsx +30 -16
  172. package/src/modules/customers/components/AddressFormatSettings.tsx +25 -19
  173. package/src/modules/customers/components/detail/ActivityForm.tsx +35 -23
  174. package/src/modules/customers/components/detail/AnnualRevenueField.tsx +2 -2
  175. package/src/modules/customers/components/detail/DealForm.tsx +33 -20
  176. package/src/modules/customers/components/formConfig.tsx +25 -17
  177. package/src/modules/customers/widgets/dashboard/customer-todos/widget.client.tsx +3 -2
  178. package/src/modules/customers/widgets/dashboard/new-customers/widget.client.tsx +21 -11
  179. package/src/modules/customers/widgets/dashboard/new-deals/widget.client.tsx +3 -2
  180. package/src/modules/customers/widgets/dashboard/next-interactions/widget.client.tsx +3 -2
  181. package/src/modules/dashboards/components/WidgetVisibilityEditor.tsx +17 -22
  182. package/src/modules/dashboards/widgets/dashboard/orders-by-status/widget.client.tsx +17 -7
  183. package/src/modules/dashboards/widgets/dashboard/revenue-trend/widget.client.tsx +20 -10
  184. package/src/modules/dashboards/widgets/dashboard/sales-by-region/widget.client.tsx +3 -2
  185. package/src/modules/dashboards/widgets/dashboard/top-customers/widget.client.tsx +3 -2
  186. package/src/modules/dashboards/widgets/dashboard/top-products/widget.client.tsx +20 -9
  187. package/src/modules/data_sync/backend/data-sync/page.tsx +64 -38
  188. package/src/modules/data_sync/components/IntegrationScheduleTab.tsx +18 -7
  189. package/src/modules/dictionaries/components/AppearanceSelector.tsx +4 -4
  190. package/src/modules/dictionaries/components/DictionaryEntriesEditor.tsx +3 -4
  191. package/src/modules/dictionaries/components/DictionaryEntrySelect.tsx +27 -21
  192. package/src/modules/dictionaries/fields/dictionary.tsx +36 -23
  193. package/src/modules/entities/components/EncryptionManager.tsx +49 -33
  194. package/src/modules/feature_toggles/components/formConfig.tsx +20 -10
  195. package/src/modules/feature_toggles/components/overrideFormConfig.tsx +20 -10
  196. package/src/modules/inbox_ops/backend/inbox-ops/settings/page.tsx +19 -10
  197. package/src/modules/inbox_ops/components/proposals/EditActionDialog.tsx +49 -26
  198. package/src/modules/integrations/backend/integrations/[id]/page.tsx +20 -11
  199. package/src/modules/integrations/backend/integrations/bundle/[id]/page.tsx +19 -9
  200. package/src/modules/planner/components/AvailabilityRulesEditor.tsx +34 -21
  201. package/src/modules/resources/components/ResourceCrudForm.tsx +24 -15
  202. package/src/modules/sales/backend/sales/documents/[id]/page.tsx +12 -15
  203. package/src/modules/sales/components/ProviderFieldInput.tsx +26 -17
  204. package/src/modules/sales/components/ShippingMethodsSettings.tsx +28 -20
  205. package/src/modules/sales/components/channels/ChannelOfferForm.tsx +51 -46
  206. package/src/modules/sales/components/documents/AddressesSection.tsx +78 -76
  207. package/src/modules/sales/components/documents/AdjustmentDialog.tsx +27 -15
  208. package/src/modules/sales/components/documents/LineItemDialog.tsx +69 -51
  209. package/src/modules/sales/components/documents/SalesDocumentForm.tsx +98 -87
  210. package/src/modules/sales/widgets/dashboard/new-orders/widget.client.tsx +23 -12
  211. package/src/modules/sales/widgets/dashboard/new-quotes/widget.client.tsx +23 -12
  212. package/src/modules/shipping_carriers/lib/shipment-wizard/components/ConfigureStep.tsx +35 -19
  213. package/src/modules/staff/components/TeamMemberForm.tsx +23 -14
  214. package/src/modules/workflows/backend/tasks/[id]/page.tsx +51 -23
  215. package/src/modules/workflows/components/ActivitiesEditor.tsx +20 -10
  216. package/src/modules/workflows/components/DefinitionTriggersEditor.tsx +28 -18
  217. package/src/modules/workflows/components/EdgeEditDialog.tsx +51 -40
  218. package/src/modules/workflows/components/NodeEditDialog.tsx +81 -77
  219. package/src/modules/workflows/components/StepsEditor.tsx +20 -10
  220. package/src/modules/workflows/components/TransitionsEditor.tsx +61 -44
  221. package/src/modules/workflows/components/fields/ActivityArrayEditor.tsx +22 -12
  222. package/src/modules/workflows/components/fields/BusinessRuleConditionsEditor.tsx +9 -13
  223. package/src/modules/workflows/components/fields/FormFieldArrayEditor.tsx +27 -17
  224. package/src/modules/workflows/components/fields/StartPreConditionsEditor.tsx +9 -12
  225. package/src/modules/workflows/components/mobile/MobileTaskForm.tsx +19 -11
  226. package/src/modules/workflows/frontend/checkout-demo/page.tsx +71 -60
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/customers/widgets/dashboard/customer-todos/widget.client.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport type { DashboardWidgetComponentProps } from '@open-mercato/shared/modules/dashboard/widgets'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { DEFAULT_SETTINGS, hydrateCustomerTodoSettings, type CustomerTodoWidgetSettings } from './config'\nimport { resolveExampleIntegrationHref } from '../../../lib/interactionCompatibility'\nimport { resolveTodoHref } from '../../../components/detail/utils'\n\ntype TodoLinkSummary = {\n id: string\n todoId: string\n todoSource: string\n todoTitle: string | null\n createdAt: string\n _integrations?: {\n example?: {\n href?: string | null\n }\n [key: string]: unknown\n }\n entity: {\n id: string | null\n displayName: string | null\n kind: string | null\n }\n}\n\nasync function loadTodos(settings: CustomerTodoWidgetSettings): Promise<TodoLinkSummary[]> {\n const params = new URLSearchParams({\n limit: String(settings.pageSize),\n })\n const call = await apiCall<{ items?: unknown[]; error?: string }>(\n `/api/customers/dashboard/widgets/customer-todos?${params.toString()}`,\n )\n if (!call.ok) {\n const message =\n typeof (call.result as Record<string, unknown> | null)?.error === 'string'\n ? ((call.result as Record<string, unknown>).error as string)\n : `Request failed with status ${call.status}`\n throw new Error(message)\n }\n const payload = call.result ?? {}\n const rawItems = Array.isArray((payload as { items?: unknown }).items)\n ? ((payload as { items: unknown[] }).items)\n : []\n return rawItems\n .map((item): TodoLinkSummary | null => {\n if (!item || typeof item !== 'object') return null\n const data = item as any\n const entity = data.entity ?? {}\n return {\n id: typeof data.id === 'string' ? data.id : null,\n todoId: typeof data.todoId === 'string' ? data.todoId : '',\n todoSource: typeof data.todoSource === 'string' ? data.todoSource : '',\n todoTitle: typeof data.todoTitle === 'string' ? data.todoTitle : null,\n createdAt: typeof data.createdAt === 'string' ? data.createdAt : '',\n _integrations: data._integrations && typeof data._integrations === 'object'\n ? (data._integrations as TodoLinkSummary['_integrations'])\n : undefined,\n entity: {\n id: typeof entity.id === 'string' ? entity.id : null,\n displayName: typeof entity.displayName === 'string' ? entity.displayName : null,\n kind: typeof entity.kind === 'string' ? entity.kind : null,\n },\n }\n })\n .filter((item): item is TodoLinkSummary => !!item && !!item.id)\n}\n\nfunction formatDate(value: string | null, locale?: string): string {\n if (!value) return ''\n const date = new Date(value)\n if (Number.isNaN(date.getTime())) return ''\n return date.toLocaleString(locale ?? undefined)\n}\n\nfunction resolveDetailHref(entity: { id: string | null; kind: string | null } | null | undefined): string | null {\n if (!entity?.id) return null\n if (entity.kind === 'company') return `/backend/customers/companies-v2/${encodeURIComponent(entity.id)}`\n if (entity.kind === 'person') return `/backend/customers/people-v2/${encodeURIComponent(entity.id)}`\n return `/backend/customers/people-v2/${encodeURIComponent(entity.id)}`\n}\n\nconst CustomerTodosWidget: React.FC<DashboardWidgetComponentProps<CustomerTodoWidgetSettings>> = ({\n mode,\n settings = DEFAULT_SETTINGS,\n onSettingsChange,\n refreshToken,\n onRefreshStateChange,\n}) => {\n const t = useT()\n const hydrated = React.useMemo(() => hydrateCustomerTodoSettings(settings), [settings])\n const [items, setItems] = React.useState<TodoLinkSummary[]>([])\n const [loading, setLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [locale, setLocale] = React.useState<string | undefined>(undefined)\n\n React.useEffect(() => {\n if (typeof navigator !== 'undefined') {\n setLocale(navigator.language)\n }\n }, [])\n\n const refresh = React.useCallback(async () => {\n onRefreshStateChange?.(true)\n setLoading(true)\n setError(null)\n try {\n const data = await loadTodos(hydrated)\n setItems(data)\n } catch (err) {\n console.error('Failed to load customer todos widget data', err)\n setError(t('customers.widgets.todos.error'))\n } finally {\n setLoading(false)\n onRefreshStateChange?.(false)\n }\n }, [hydrated, onRefreshStateChange, t])\n\n React.useEffect(() => {\n refresh().catch(() => {})\n }, [refresh, refreshToken])\n\n if (mode === 'settings') {\n return (\n <div className=\"space-y-4 text-sm\">\n <div className=\"space-y-1.5\">\n <label htmlFor=\"customer-todos-page-size\" className=\"text-xs font-semibold uppercase text-muted-foreground\">\n {t('customers.widgets.todos.settings.pageSize')}\n </label>\n <input\n id=\"customer-todos-page-size\"\n type=\"number\"\n min={1}\n max={20}\n className=\"w-24 rounded-md border px-2 py-1 text-sm focus-visible:border-ring focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n value={hydrated.pageSize}\n onChange={(event) => {\n const next = Number(event.target.value)\n onSettingsChange({ ...hydrated, pageSize: Number.isFinite(next) ? next : hydrated.pageSize })\n }}\n />\n </div>\n <p className=\"text-xs text-muted-foreground\">{t('customers.widgets.todos.settings.help')}</p>\n </div>\n )\n }\n\n return (\n <div className=\"space-y-4\">\n {error ? (\n <p className=\"text-sm text-destructive\">{error}</p>\n ) : loading ? (\n <div className=\"flex h-32 items-center justify-center\">\n <Spinner className=\"h-6 w-6 text-muted-foreground\" />\n </div>\n ) : items.length === 0 ? (\n <p className=\"text-sm text-muted-foreground\">{t('customers.widgets.todos.empty')}</p>\n ) : (\n <ul className=\"space-y-3\">\n {items.map((item) => {\n const createdLabel = formatDate(item.createdAt, locale)\n const href = resolveDetailHref(item.entity)\n const exampleHref = resolveExampleIntegrationHref(item)\n const taskHref = exampleHref ?? resolveTodoHref(item.todoSource, item.todoId)\n return (\n <li key={item.id} className=\"rounded-md border p-3\">\n <div className=\"flex items-start justify-between gap-3 text-sm font-medium\">\n <span>{item.entity.displayName ?? t('customers.widgets.common.unknown')}</span>\n <span className=\"text-xs text-muted-foreground\">{createdLabel || t('customers.widgets.common.unknownDate')}</span>\n </div>\n <div className=\"mt-1 space-y-0.5\">\n <p className=\"text-sm font-medium text-foreground\">\n {item.todoTitle ?? t('customers.widgets.todos.untitled')}\n </p>\n {item.todoSource ? (\n <p className=\"text-xs text-muted-foreground\">{item.todoSource}</p>\n ) : null}\n </div>\n <div className=\"mt-2 flex flex-wrap gap-3 text-xs\">\n {href ? (\n <Link className=\"text-primary hover:underline\" href={href}>\n {t('customers.widgets.common.viewRecord')}\n </Link>\n ) : null}\n {taskHref ? (\n <Link className=\"text-primary hover:underline\" href={taskHref}>\n {t('customers.workPlan.customerTodos.table.actions.openTask')}\n </Link>\n ) : null}\n </div>\n </li>\n )\n })}\n </ul>\n )}\n </div>\n )\n}\n\nexport default CustomerTodosWidget\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport type { DashboardWidgetComponentProps } from '@open-mercato/shared/modules/dashboard/widgets'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { DEFAULT_SETTINGS, hydrateCustomerTodoSettings, type CustomerTodoWidgetSettings } from './config'\nimport { resolveExampleIntegrationHref } from '../../../lib/interactionCompatibility'\nimport { resolveTodoHref } from '../../../components/detail/utils'\n\ntype TodoLinkSummary = {\n id: string\n todoId: string\n todoSource: string\n todoTitle: string | null\n createdAt: string\n _integrations?: {\n example?: {\n href?: string | null\n }\n [key: string]: unknown\n }\n entity: {\n id: string | null\n displayName: string | null\n kind: string | null\n }\n}\n\nasync function loadTodos(settings: CustomerTodoWidgetSettings): Promise<TodoLinkSummary[]> {\n const params = new URLSearchParams({\n limit: String(settings.pageSize),\n })\n const call = await apiCall<{ items?: unknown[]; error?: string }>(\n `/api/customers/dashboard/widgets/customer-todos?${params.toString()}`,\n )\n if (!call.ok) {\n const message =\n typeof (call.result as Record<string, unknown> | null)?.error === 'string'\n ? ((call.result as Record<string, unknown>).error as string)\n : `Request failed with status ${call.status}`\n throw new Error(message)\n }\n const payload = call.result ?? {}\n const rawItems = Array.isArray((payload as { items?: unknown }).items)\n ? ((payload as { items: unknown[] }).items)\n : []\n return rawItems\n .map((item): TodoLinkSummary | null => {\n if (!item || typeof item !== 'object') return null\n const data = item as any\n const entity = data.entity ?? {}\n return {\n id: typeof data.id === 'string' ? data.id : null,\n todoId: typeof data.todoId === 'string' ? data.todoId : '',\n todoSource: typeof data.todoSource === 'string' ? data.todoSource : '',\n todoTitle: typeof data.todoTitle === 'string' ? data.todoTitle : null,\n createdAt: typeof data.createdAt === 'string' ? data.createdAt : '',\n _integrations: data._integrations && typeof data._integrations === 'object'\n ? (data._integrations as TodoLinkSummary['_integrations'])\n : undefined,\n entity: {\n id: typeof entity.id === 'string' ? entity.id : null,\n displayName: typeof entity.displayName === 'string' ? entity.displayName : null,\n kind: typeof entity.kind === 'string' ? entity.kind : null,\n },\n }\n })\n .filter((item): item is TodoLinkSummary => !!item && !!item.id)\n}\n\nfunction formatDate(value: string | null, locale?: string): string {\n if (!value) return ''\n const date = new Date(value)\n if (Number.isNaN(date.getTime())) return ''\n return date.toLocaleString(locale ?? undefined)\n}\n\nfunction resolveDetailHref(entity: { id: string | null; kind: string | null } | null | undefined): string | null {\n if (!entity?.id) return null\n if (entity.kind === 'company') return `/backend/customers/companies-v2/${encodeURIComponent(entity.id)}`\n if (entity.kind === 'person') return `/backend/customers/people-v2/${encodeURIComponent(entity.id)}`\n return `/backend/customers/people-v2/${encodeURIComponent(entity.id)}`\n}\n\nconst CustomerTodosWidget: React.FC<DashboardWidgetComponentProps<CustomerTodoWidgetSettings>> = ({\n mode,\n settings = DEFAULT_SETTINGS,\n onSettingsChange,\n refreshToken,\n onRefreshStateChange,\n}) => {\n const t = useT()\n const hydrated = React.useMemo(() => hydrateCustomerTodoSettings(settings), [settings])\n const [items, setItems] = React.useState<TodoLinkSummary[]>([])\n const [loading, setLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [locale, setLocale] = React.useState<string | undefined>(undefined)\n\n React.useEffect(() => {\n if (typeof navigator !== 'undefined') {\n setLocale(navigator.language)\n }\n }, [])\n\n const refresh = React.useCallback(async () => {\n onRefreshStateChange?.(true)\n setLoading(true)\n setError(null)\n try {\n const data = await loadTodos(hydrated)\n setItems(data)\n } catch (err) {\n console.error('Failed to load customer todos widget data', err)\n setError(t('customers.widgets.todos.error'))\n } finally {\n setLoading(false)\n onRefreshStateChange?.(false)\n }\n }, [hydrated, onRefreshStateChange, t])\n\n React.useEffect(() => {\n refresh().catch(() => {})\n }, [refresh, refreshToken])\n\n if (mode === 'settings') {\n return (\n <div className=\"space-y-4 text-sm\">\n <div className=\"space-y-1.5\">\n <label htmlFor=\"customer-todos-page-size\" className=\"text-xs font-semibold uppercase text-muted-foreground\">\n {t('customers.widgets.todos.settings.pageSize')}\n </label>\n <Input\n id=\"customer-todos-page-size\"\n type=\"number\"\n min={1}\n max={20}\n className=\"w-24\"\n value={hydrated.pageSize}\n onChange={(event) => {\n const next = Number(event.target.value)\n onSettingsChange({ ...hydrated, pageSize: Number.isFinite(next) ? next : hydrated.pageSize })\n }}\n />\n </div>\n <p className=\"text-xs text-muted-foreground\">{t('customers.widgets.todos.settings.help')}</p>\n </div>\n )\n }\n\n return (\n <div className=\"space-y-4\">\n {error ? (\n <p className=\"text-sm text-destructive\">{error}</p>\n ) : loading ? (\n <div className=\"flex h-32 items-center justify-center\">\n <Spinner className=\"h-6 w-6 text-muted-foreground\" />\n </div>\n ) : items.length === 0 ? (\n <p className=\"text-sm text-muted-foreground\">{t('customers.widgets.todos.empty')}</p>\n ) : (\n <ul className=\"space-y-3\">\n {items.map((item) => {\n const createdLabel = formatDate(item.createdAt, locale)\n const href = resolveDetailHref(item.entity)\n const exampleHref = resolveExampleIntegrationHref(item)\n const taskHref = exampleHref ?? resolveTodoHref(item.todoSource, item.todoId)\n return (\n <li key={item.id} className=\"rounded-md border p-3\">\n <div className=\"flex items-start justify-between gap-3 text-sm font-medium\">\n <span>{item.entity.displayName ?? t('customers.widgets.common.unknown')}</span>\n <span className=\"text-xs text-muted-foreground\">{createdLabel || t('customers.widgets.common.unknownDate')}</span>\n </div>\n <div className=\"mt-1 space-y-0.5\">\n <p className=\"text-sm font-medium text-foreground\">\n {item.todoTitle ?? t('customers.widgets.todos.untitled')}\n </p>\n {item.todoSource ? (\n <p className=\"text-xs text-muted-foreground\">{item.todoSource}</p>\n ) : null}\n </div>\n <div className=\"mt-2 flex flex-wrap gap-3 text-xs\">\n {href ? (\n <Link className=\"text-primary hover:underline\" href={href}>\n {t('customers.widgets.common.viewRecord')}\n </Link>\n ) : null}\n {taskHref ? (\n <Link className=\"text-primary hover:underline\" href={taskHref}>\n {t('customers.workPlan.customerTodos.table.actions.openTask')}\n </Link>\n ) : null}\n </div>\n </li>\n )\n })}\n </ul>\n )}\n </div>\n )\n}\n\nexport default CustomerTodosWidget\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -3,6 +3,14 @@ import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import Link from "next/link";
5
5
  import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
6
+ import { Input } from "@open-mercato/ui/primitives/input";
7
+ import {
8
+ Select,
9
+ SelectContent,
10
+ SelectItem,
11
+ SelectTrigger,
12
+ SelectValue
13
+ } from "@open-mercato/ui/primitives/select";
6
14
  import { Spinner } from "@open-mercato/ui/primitives/spinner";
7
15
  import { useT } from "@open-mercato/shared/lib/i18n/context";
8
16
  import {
@@ -95,13 +103,13 @@ const CustomerNewCustomersWidget = ({
95
103
  /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
96
104
  /* @__PURE__ */ jsx("label", { htmlFor: "customer-new-customers-page-size", className: "text-xs font-semibold uppercase text-muted-foreground", children: t("customers.widgets.newCustomers.settings.pageSize") }),
97
105
  /* @__PURE__ */ jsx(
98
- "input",
106
+ Input,
99
107
  {
100
108
  id: "customer-new-customers-page-size",
101
109
  type: "number",
102
110
  min: 1,
103
111
  max: 20,
104
- className: "w-24 rounded-md border px-2 py-1 text-sm focus-visible:border-ring focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
112
+ className: "w-24",
105
113
  value: hydrated.pageSize,
106
114
  onChange: (event) => {
107
115
  const next = Number(event.target.value);
@@ -113,21 +121,21 @@ const CustomerNewCustomersWidget = ({
113
121
  /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
114
122
  /* @__PURE__ */ jsx("label", { htmlFor: "customer-new-customers-kind", className: "text-xs font-semibold uppercase text-muted-foreground", children: t("customers.widgets.newCustomers.settings.kind") }),
115
123
  /* @__PURE__ */ jsxs(
116
- "select",
124
+ Select,
117
125
  {
118
- id: "customer-new-customers-kind",
119
- className: "w-full rounded-md border px-2 py-1 text-sm focus-visible:border-ring focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
120
126
  value: hydrated.kind,
121
- onChange: (event) => {
122
- const value = event.target.value;
127
+ onValueChange: (value) => {
123
128
  if (value === "person" || value === "company" || value === "all") {
124
129
  onSettingsChange({ ...hydrated, kind: value });
125
130
  }
126
131
  },
127
132
  children: [
128
- /* @__PURE__ */ jsx("option", { value: "all", children: t("customers.widgets.newCustomers.filters.all") }),
129
- /* @__PURE__ */ jsx("option", { value: "person", children: t("customers.widgets.newCustomers.filters.person") }),
130
- /* @__PURE__ */ jsx("option", { value: "company", children: t("customers.widgets.newCustomers.filters.company") })
133
+ /* @__PURE__ */ jsx(SelectTrigger, { id: "customer-new-customers-kind", size: "sm", children: /* @__PURE__ */ jsx(SelectValue, {}) }),
134
+ /* @__PURE__ */ jsxs(SelectContent, { children: [
135
+ /* @__PURE__ */ jsx(SelectItem, { value: "all", children: t("customers.widgets.newCustomers.filters.all") }),
136
+ /* @__PURE__ */ jsx(SelectItem, { value: "person", children: t("customers.widgets.newCustomers.filters.person") }),
137
+ /* @__PURE__ */ jsx(SelectItem, { value: "company", children: t("customers.widgets.newCustomers.filters.company") })
138
+ ] })
131
139
  ]
132
140
  }
133
141
  )
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/customers/widgets/dashboard/new-customers/widget.client.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport type { DashboardWidgetComponentProps } from '@open-mercato/shared/modules/dashboard/widgets'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport {\n DEFAULT_SETTINGS,\n hydrateNewCustomersSettings,\n type CustomerNewCustomersSettings,\n} from './config'\n\ntype NewCustomerItem = {\n id: string\n displayName: string | null\n kind: string | null\n createdAt: string\n}\n\nasync function loadNewCustomers(settings: CustomerNewCustomersSettings): Promise<NewCustomerItem[]> {\n const params = new URLSearchParams({\n limit: String(settings.pageSize),\n })\n if (settings.kind !== 'all') {\n params.set('kind', settings.kind)\n }\n const call = await apiCall<{ items?: unknown[]; error?: string }>(\n `/api/customers/dashboard/widgets/new-customers?${params.toString()}`,\n )\n if (!call.ok) {\n const message =\n typeof (call.result as Record<string, unknown> | null)?.error === 'string'\n ? ((call.result as Record<string, unknown>).error as string)\n : `Request failed with status ${call.status}`\n throw new Error(message)\n }\n const payload = call.result ?? {}\n const rawItems = Array.isArray((payload as { items?: unknown[] }).items)\n ? (payload as { items: unknown[] }).items\n : []\n return rawItems\n .map((item: unknown): NewCustomerItem | null => {\n if (!item || typeof item !== 'object') return null\n const data = item as any\n return {\n id: typeof data.id === 'string' ? data.id : null,\n displayName: typeof data.displayName === 'string' ? data.displayName : null,\n kind: typeof data.kind === 'string' ? data.kind : null,\n createdAt: typeof data.createdAt === 'string' ? data.createdAt : '',\n }\n })\n .filter((item: NewCustomerItem | null): item is NewCustomerItem => !!item && !!item.id && !!item.createdAt)\n}\n\nfunction resolveDetailHref(item: NewCustomerItem): string | null {\n if (!item.id || !item.kind) return null\n if (item.kind === 'company') return `/backend/customers/companies-v2/${encodeURIComponent(item.id)}`\n if (item.kind === 'person') return `/backend/customers/people-v2/${encodeURIComponent(item.id)}`\n return null\n}\n\nfunction formatDate(value: string | null, locale?: string): string {\n if (!value) return ''\n const date = new Date(value)\n if (Number.isNaN(date.getTime())) return ''\n return date.toLocaleString(locale ?? undefined, { dateStyle: 'medium', timeStyle: 'short' })\n}\n\nfunction formatKind(kind: string | null, t: (key: string) => string): string {\n if (kind === 'person') return t('customers.widgets.newCustomers.kind.person')\n if (kind === 'company') return t('customers.widgets.newCustomers.kind.company')\n return t('customers.widgets.newCustomers.kind.unknown')\n}\n\nconst CustomerNewCustomersWidget: React.FC<DashboardWidgetComponentProps<CustomerNewCustomersSettings>> = ({\n mode,\n settings = DEFAULT_SETTINGS,\n onSettingsChange,\n refreshToken,\n onRefreshStateChange,\n}) => {\n const t = useT()\n const hydrated = React.useMemo(() => hydrateNewCustomersSettings(settings), [settings])\n const [items, setItems] = React.useState<NewCustomerItem[]>([])\n const [loading, setLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [locale, setLocale] = React.useState<string | undefined>(undefined)\n\n React.useEffect(() => {\n if (typeof navigator !== 'undefined') {\n setLocale(navigator.language)\n }\n }, [])\n\n const refresh = React.useCallback(async () => {\n onRefreshStateChange?.(true)\n setLoading(true)\n setError(null)\n try {\n const data = await loadNewCustomers(hydrated)\n setItems(data)\n } catch (err) {\n console.error('Failed to load new customers widget data', err)\n setError(t('customers.widgets.newCustomers.error'))\n } finally {\n setLoading(false)\n onRefreshStateChange?.(false)\n }\n }, [hydrated, onRefreshStateChange, t])\n\n React.useEffect(() => {\n refresh().catch(() => {})\n }, [refresh, refreshToken])\n\n if (mode === 'settings') {\n return (\n <div className=\"space-y-4 text-sm\">\n <div className=\"space-y-1.5\">\n <label htmlFor=\"customer-new-customers-page-size\" className=\"text-xs font-semibold uppercase text-muted-foreground\">\n {t('customers.widgets.newCustomers.settings.pageSize')}\n </label>\n <input\n id=\"customer-new-customers-page-size\"\n type=\"number\"\n min={1}\n max={20}\n className=\"w-24 rounded-md border px-2 py-1 text-sm focus-visible:border-ring focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n value={hydrated.pageSize}\n onChange={(event) => {\n const next = Number(event.target.value)\n onSettingsChange({ ...hydrated, pageSize: Number.isFinite(next) ? next : hydrated.pageSize })\n }}\n />\n </div>\n <div className=\"space-y-1.5\">\n <label htmlFor=\"customer-new-customers-kind\" className=\"text-xs font-semibold uppercase text-muted-foreground\">\n {t('customers.widgets.newCustomers.settings.kind')}\n </label>\n <select\n id=\"customer-new-customers-kind\"\n className=\"w-full rounded-md border px-2 py-1 text-sm focus-visible:border-ring focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n value={hydrated.kind}\n onChange={(event) => {\n const value = event.target.value\n if (value === 'person' || value === 'company' || value === 'all') {\n onSettingsChange({ ...hydrated, kind: value })\n }\n }}\n >\n <option value=\"all\">{t('customers.widgets.newCustomers.filters.all')}</option>\n <option value=\"person\">{t('customers.widgets.newCustomers.filters.person')}</option>\n <option value=\"company\">{t('customers.widgets.newCustomers.filters.company')}</option>\n </select>\n </div>\n </div>\n )\n }\n\n return (\n <div className=\"space-y-4\">\n {error ? (\n <p className=\"text-sm text-destructive\">{error}</p>\n ) : loading ? (\n <div className=\"flex h-32 items-center justify-center\">\n <Spinner className=\"h-6 w-6 text-muted-foreground\" />\n </div>\n ) : items.length === 0 ? (\n <p className=\"text-sm text-muted-foreground\">{t('customers.widgets.newCustomers.empty')}</p>\n ) : (\n <ul className=\"space-y-3\">\n {items.map((item) => {\n const href = resolveDetailHref(item)\n const createdLabel = formatDate(item.createdAt, locale)\n return (\n <li key={item.id} className=\"rounded-md border p-3\">\n <div className=\"flex items-start justify-between gap-3\">\n <div>\n <p className=\"text-sm font-medium\">{item.displayName ?? t('customers.widgets.common.unknown')}</p>\n <p className=\"text-xs text-muted-foreground\">{formatKind(item.kind, t)}</p>\n </div>\n <p className=\"text-xs text-muted-foreground\">{createdLabel || t('customers.widgets.common.unknownDate')}</p>\n </div>\n {href ? (\n <div className=\"mt-2 text-xs\">\n <Link className=\"text-primary hover:underline\" href={href}>\n {t('customers.widgets.common.viewRecord')}\n </Link>\n </div>\n ) : null}\n </li>\n )\n })}\n </ul>\n )}\n </div>\n )\n}\n\nexport default CustomerNewCustomersWidget\n"],
5
- "mappings": ";AAuHQ,SACE,KADF;AArHR,YAAY,WAAW;AACvB,OAAO,UAAU;AAEjB,SAAS,eAAe;AACxB,SAAS,eAAe;AACxB,SAAS,YAAY;AACrB;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AASP,eAAe,iBAAiB,UAAoE;AAClG,QAAM,SAAS,IAAI,gBAAgB;AAAA,IACjC,OAAO,OAAO,SAAS,QAAQ;AAAA,EACjC,CAAC;AACD,MAAI,SAAS,SAAS,OAAO;AAC3B,WAAO,IAAI,QAAQ,SAAS,IAAI;AAAA,EAClC;AACA,QAAM,OAAO,MAAM;AAAA,IACjB,kDAAkD,OAAO,SAAS,CAAC;AAAA,EACrE;AACA,MAAI,CAAC,KAAK,IAAI;AACZ,UAAM,UACJ,OAAQ,KAAK,QAA2C,UAAU,WAC5D,KAAK,OAAmC,QAC1C,8BAA8B,KAAK,MAAM;AAC/C,UAAM,IAAI,MAAM,OAAO;AAAA,EACzB;AACA,QAAM,UAAU,KAAK,UAAU,CAAC;AAChC,QAAM,WAAW,MAAM,QAAS,QAAkC,KAAK,IAClE,QAAiC,QAClC,CAAC;AACL,SAAO,SACJ,IAAI,CAAC,SAA0C;AAC9C,QAAI,CAAC,QAAQ,OAAO,SAAS,SAAU,QAAO;AAC9C,UAAM,OAAO;AACb,WAAO;AAAA,MACL,IAAI,OAAO,KAAK,OAAO,WAAW,KAAK,KAAK;AAAA,MAC5C,aAAa,OAAO,KAAK,gBAAgB,WAAW,KAAK,cAAc;AAAA,MACvE,MAAM,OAAO,KAAK,SAAS,WAAW,KAAK,OAAO;AAAA,MAClD,WAAW,OAAO,KAAK,cAAc,WAAW,KAAK,YAAY;AAAA,IACnE;AAAA,EACF,CAAC,EACA,OAAO,CAAC,SAA0D,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,KAAK,SAAS;AAC9G;AAEA,SAAS,kBAAkB,MAAsC;AAC/D,MAAI,CAAC,KAAK,MAAM,CAAC,KAAK,KAAM,QAAO;AACnC,MAAI,KAAK,SAAS,UAAW,QAAO,mCAAmC,mBAAmB,KAAK,EAAE,CAAC;AAClG,MAAI,KAAK,SAAS,SAAU,QAAO,gCAAgC,mBAAmB,KAAK,EAAE,CAAC;AAC9F,SAAO;AACT;AAEA,SAAS,WAAW,OAAsB,QAAyB;AACjE,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,OAAO,IAAI,KAAK,KAAK;AAC3B,MAAI,OAAO,MAAM,KAAK,QAAQ,CAAC,EAAG,QAAO;AACzC,SAAO,KAAK,eAAe,UAAU,QAAW,EAAE,WAAW,UAAU,WAAW,QAAQ,CAAC;AAC7F;AAEA,SAAS,WAAW,MAAqB,GAAoC;AAC3E,MAAI,SAAS,SAAU,QAAO,EAAE,4CAA4C;AAC5E,MAAI,SAAS,UAAW,QAAO,EAAE,6CAA6C;AAC9E,SAAO,EAAE,6CAA6C;AACxD;AAEA,MAAM,6BAAoG,CAAC;AAAA,EACzG;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AACF,MAAM;AACJ,QAAM,IAAI,KAAK;AACf,QAAM,WAAW,MAAM,QAAQ,MAAM,4BAA4B,QAAQ,GAAG,CAAC,QAAQ,CAAC;AACtF,QAAM,CAAC,OAAO,QAAQ,IAAI,MAAM,SAA4B,CAAC,CAAC;AAC9D,QAAM,CAAC,SAAS,UAAU,IAAI,MAAM,SAAS,IAAI;AACjD,QAAM,CAAC,OAAO,QAAQ,IAAI,MAAM,SAAwB,IAAI;AAC5D,QAAM,CAAC,QAAQ,SAAS,IAAI,MAAM,SAA6B,MAAS;AAExE,QAAM,UAAU,MAAM;AACpB,QAAI,OAAO,cAAc,aAAa;AACpC,gBAAU,UAAU,QAAQ;AAAA,IAC9B;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,UAAU,MAAM,YAAY,YAAY;AAC5C,2BAAuB,IAAI;AAC3B,eAAW,IAAI;AACf,aAAS,IAAI;AACb,QAAI;AACF,YAAM,OAAO,MAAM,iBAAiB,QAAQ;AAC5C,eAAS,IAAI;AAAA,IACf,SAAS,KAAK;AACZ,cAAQ,MAAM,4CAA4C,GAAG;AAC7D,eAAS,EAAE,sCAAsC,CAAC;AAAA,IACpD,UAAE;AACA,iBAAW,KAAK;AAChB,6BAAuB,KAAK;AAAA,IAC9B;AAAA,EACF,GAAG,CAAC,UAAU,sBAAsB,CAAC,CAAC;AAEtC,QAAM,UAAU,MAAM;AACpB,YAAQ,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AAAA,EAC1B,GAAG,CAAC,SAAS,YAAY,CAAC;AAE1B,MAAI,SAAS,YAAY;AACvB,WACE,qBAAC,SAAI,WAAU,qBACb;AAAA,2BAAC,SAAI,WAAU,eACb;AAAA,4BAAC,WAAM,SAAQ,oCAAmC,WAAU,yDACzD,YAAE,kDAAkD,GACvD;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,IAAG;AAAA,YACH,MAAK;AAAA,YACL,KAAK;AAAA,YACL,KAAK;AAAA,YACL,WAAU;AAAA,YACV,OAAO,SAAS;AAAA,YAChB,UAAU,CAAC,UAAU;AACnB,oBAAM,OAAO,OAAO,MAAM,OAAO,KAAK;AACtC,+BAAiB,EAAE,GAAG,UAAU,UAAU,OAAO,SAAS,IAAI,IAAI,OAAO,SAAS,SAAS,CAAC;AAAA,YAC9F;AAAA;AAAA,QACF;AAAA,SACF;AAAA,MACA,qBAAC,SAAI,WAAU,eACb;AAAA,4BAAC,WAAM,SAAQ,+BAA8B,WAAU,yDACpD,YAAE,8CAA8C,GACnD;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,IAAG;AAAA,YACH,WAAU;AAAA,YACV,OAAO,SAAS;AAAA,YAChB,UAAU,CAAC,UAAU;AACnB,oBAAM,QAAQ,MAAM,OAAO;AAC3B,kBAAI,UAAU,YAAY,UAAU,aAAa,UAAU,OAAO;AAChE,iCAAiB,EAAE,GAAG,UAAU,MAAM,MAAM,CAAC;AAAA,cAC/C;AAAA,YACF;AAAA,YAEA;AAAA,kCAAC,YAAO,OAAM,OAAO,YAAE,4CAA4C,GAAE;AAAA,cACrE,oBAAC,YAAO,OAAM,UAAU,YAAE,+CAA+C,GAAE;AAAA,cAC3E,oBAAC,YAAO,OAAM,WAAW,YAAE,gDAAgD,GAAE;AAAA;AAAA;AAAA,QAC/E;AAAA,SACF;AAAA,OACF;AAAA,EAEJ;AAEA,SACE,oBAAC,SAAI,WAAU,aACZ,kBACC,oBAAC,OAAE,WAAU,4BAA4B,iBAAM,IAC7C,UACF,oBAAC,SAAI,WAAU,yCACb,8BAAC,WAAQ,WAAU,iCAAgC,GACrD,IACE,MAAM,WAAW,IACnB,oBAAC,OAAE,WAAU,iCAAiC,YAAE,sCAAsC,GAAE,IAExF,oBAAC,QAAG,WAAU,aACX,gBAAM,IAAI,CAAC,SAAS;AACnB,UAAM,OAAO,kBAAkB,IAAI;AACnC,UAAM,eAAe,WAAW,KAAK,WAAW,MAAM;AACtD,WACE,qBAAC,QAAiB,WAAU,yBAC1B;AAAA,2BAAC,SAAI,WAAU,0CACb;AAAA,6BAAC,SACC;AAAA,8BAAC,OAAE,WAAU,uBAAuB,eAAK,eAAe,EAAE,kCAAkC,GAAE;AAAA,UAC9F,oBAAC,OAAE,WAAU,iCAAiC,qBAAW,KAAK,MAAM,CAAC,GAAE;AAAA,WACzE;AAAA,QACA,oBAAC,OAAE,WAAU,iCAAiC,0BAAgB,EAAE,sCAAsC,GAAE;AAAA,SAC1G;AAAA,MACC,OACC,oBAAC,SAAI,WAAU,gBACb,8BAAC,QAAK,WAAU,gCAA+B,MAC5C,YAAE,qCAAqC,GAC1C,GACF,IACE;AAAA,SAdG,KAAK,EAed;AAAA,EAEJ,CAAC,GACH,GAEJ;AAEJ;AAEA,IAAO,wBAAQ;",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport type { DashboardWidgetComponentProps } from '@open-mercato/shared/modules/dashboard/widgets'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport {\n Select,\n SelectContent,\n SelectItem,\n SelectTrigger,\n SelectValue,\n} from '@open-mercato/ui/primitives/select'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport {\n DEFAULT_SETTINGS,\n hydrateNewCustomersSettings,\n type CustomerNewCustomersSettings,\n} from './config'\n\ntype NewCustomerItem = {\n id: string\n displayName: string | null\n kind: string | null\n createdAt: string\n}\n\nasync function loadNewCustomers(settings: CustomerNewCustomersSettings): Promise<NewCustomerItem[]> {\n const params = new URLSearchParams({\n limit: String(settings.pageSize),\n })\n if (settings.kind !== 'all') {\n params.set('kind', settings.kind)\n }\n const call = await apiCall<{ items?: unknown[]; error?: string }>(\n `/api/customers/dashboard/widgets/new-customers?${params.toString()}`,\n )\n if (!call.ok) {\n const message =\n typeof (call.result as Record<string, unknown> | null)?.error === 'string'\n ? ((call.result as Record<string, unknown>).error as string)\n : `Request failed with status ${call.status}`\n throw new Error(message)\n }\n const payload = call.result ?? {}\n const rawItems = Array.isArray((payload as { items?: unknown[] }).items)\n ? (payload as { items: unknown[] }).items\n : []\n return rawItems\n .map((item: unknown): NewCustomerItem | null => {\n if (!item || typeof item !== 'object') return null\n const data = item as any\n return {\n id: typeof data.id === 'string' ? data.id : null,\n displayName: typeof data.displayName === 'string' ? data.displayName : null,\n kind: typeof data.kind === 'string' ? data.kind : null,\n createdAt: typeof data.createdAt === 'string' ? data.createdAt : '',\n }\n })\n .filter((item: NewCustomerItem | null): item is NewCustomerItem => !!item && !!item.id && !!item.createdAt)\n}\n\nfunction resolveDetailHref(item: NewCustomerItem): string | null {\n if (!item.id || !item.kind) return null\n if (item.kind === 'company') return `/backend/customers/companies-v2/${encodeURIComponent(item.id)}`\n if (item.kind === 'person') return `/backend/customers/people-v2/${encodeURIComponent(item.id)}`\n return null\n}\n\nfunction formatDate(value: string | null, locale?: string): string {\n if (!value) return ''\n const date = new Date(value)\n if (Number.isNaN(date.getTime())) return ''\n return date.toLocaleString(locale ?? undefined, { dateStyle: 'medium', timeStyle: 'short' })\n}\n\nfunction formatKind(kind: string | null, t: (key: string) => string): string {\n if (kind === 'person') return t('customers.widgets.newCustomers.kind.person')\n if (kind === 'company') return t('customers.widgets.newCustomers.kind.company')\n return t('customers.widgets.newCustomers.kind.unknown')\n}\n\nconst CustomerNewCustomersWidget: React.FC<DashboardWidgetComponentProps<CustomerNewCustomersSettings>> = ({\n mode,\n settings = DEFAULT_SETTINGS,\n onSettingsChange,\n refreshToken,\n onRefreshStateChange,\n}) => {\n const t = useT()\n const hydrated = React.useMemo(() => hydrateNewCustomersSettings(settings), [settings])\n const [items, setItems] = React.useState<NewCustomerItem[]>([])\n const [loading, setLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [locale, setLocale] = React.useState<string | undefined>(undefined)\n\n React.useEffect(() => {\n if (typeof navigator !== 'undefined') {\n setLocale(navigator.language)\n }\n }, [])\n\n const refresh = React.useCallback(async () => {\n onRefreshStateChange?.(true)\n setLoading(true)\n setError(null)\n try {\n const data = await loadNewCustomers(hydrated)\n setItems(data)\n } catch (err) {\n console.error('Failed to load new customers widget data', err)\n setError(t('customers.widgets.newCustomers.error'))\n } finally {\n setLoading(false)\n onRefreshStateChange?.(false)\n }\n }, [hydrated, onRefreshStateChange, t])\n\n React.useEffect(() => {\n refresh().catch(() => {})\n }, [refresh, refreshToken])\n\n if (mode === 'settings') {\n return (\n <div className=\"space-y-4 text-sm\">\n <div className=\"space-y-1.5\">\n <label htmlFor=\"customer-new-customers-page-size\" className=\"text-xs font-semibold uppercase text-muted-foreground\">\n {t('customers.widgets.newCustomers.settings.pageSize')}\n </label>\n <Input\n id=\"customer-new-customers-page-size\"\n type=\"number\"\n min={1}\n max={20}\n className=\"w-24\"\n value={hydrated.pageSize}\n onChange={(event) => {\n const next = Number(event.target.value)\n onSettingsChange({ ...hydrated, pageSize: Number.isFinite(next) ? next : hydrated.pageSize })\n }}\n />\n </div>\n <div className=\"space-y-1.5\">\n <label htmlFor=\"customer-new-customers-kind\" className=\"text-xs font-semibold uppercase text-muted-foreground\">\n {t('customers.widgets.newCustomers.settings.kind')}\n </label>\n <Select\n value={hydrated.kind}\n onValueChange={(value) => {\n if (value === 'person' || value === 'company' || value === 'all') {\n onSettingsChange({ ...hydrated, kind: value })\n }\n }}\n >\n <SelectTrigger id=\"customer-new-customers-kind\" size=\"sm\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent>\n <SelectItem value=\"all\">{t('customers.widgets.newCustomers.filters.all')}</SelectItem>\n <SelectItem value=\"person\">{t('customers.widgets.newCustomers.filters.person')}</SelectItem>\n <SelectItem value=\"company\">{t('customers.widgets.newCustomers.filters.company')}</SelectItem>\n </SelectContent>\n </Select>\n </div>\n </div>\n )\n }\n\n return (\n <div className=\"space-y-4\">\n {error ? (\n <p className=\"text-sm text-destructive\">{error}</p>\n ) : loading ? (\n <div className=\"flex h-32 items-center justify-center\">\n <Spinner className=\"h-6 w-6 text-muted-foreground\" />\n </div>\n ) : items.length === 0 ? (\n <p className=\"text-sm text-muted-foreground\">{t('customers.widgets.newCustomers.empty')}</p>\n ) : (\n <ul className=\"space-y-3\">\n {items.map((item) => {\n const href = resolveDetailHref(item)\n const createdLabel = formatDate(item.createdAt, locale)\n return (\n <li key={item.id} className=\"rounded-md border p-3\">\n <div className=\"flex items-start justify-between gap-3\">\n <div>\n <p className=\"text-sm font-medium\">{item.displayName ?? t('customers.widgets.common.unknown')}</p>\n <p className=\"text-xs text-muted-foreground\">{formatKind(item.kind, t)}</p>\n </div>\n <p className=\"text-xs text-muted-foreground\">{createdLabel || t('customers.widgets.common.unknownDate')}</p>\n </div>\n {href ? (\n <div className=\"mt-2 text-xs\">\n <Link className=\"text-primary hover:underline\" href={href}>\n {t('customers.widgets.common.viewRecord')}\n </Link>\n </div>\n ) : null}\n </li>\n )\n })}\n </ul>\n )}\n </div>\n )\n}\n\nexport default CustomerNewCustomersWidget\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -3,6 +3,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import Link from "next/link";
5
5
  import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
6
+ import { Input } from "@open-mercato/ui/primitives/input";
6
7
  import { Spinner } from "@open-mercato/ui/primitives/spinner";
7
8
  import { useT } from "@open-mercato/shared/lib/i18n/context";
8
9
  import { DEFAULT_SETTINGS, hydrateNewDealsSettings } from "./config.js";
@@ -79,13 +80,13 @@ const CustomerNewDealsWidget = ({
79
80
  return /* @__PURE__ */ jsx("div", { className: "space-y-4 text-sm", children: /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
80
81
  /* @__PURE__ */ jsx("label", { htmlFor: "customer-new-deals-page-size", className: "text-xs font-semibold uppercase text-muted-foreground", children: t("customers.widgets.newDeals.settings.pageSize") }),
81
82
  /* @__PURE__ */ jsx(
82
- "input",
83
+ Input,
83
84
  {
84
85
  id: "customer-new-deals-page-size",
85
86
  type: "number",
86
87
  min: 1,
87
88
  max: 20,
88
- className: "w-24 rounded-md border px-2 py-1 text-sm focus-visible:border-ring focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
89
+ className: "w-24",
89
90
  value: hydrated.pageSize,
90
91
  onChange: (event) => {
91
92
  const next = Number(event.target.value);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/customers/widgets/dashboard/new-deals/widget.client.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport type { DashboardWidgetComponentProps } from '@open-mercato/shared/modules/dashboard/widgets'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { DEFAULT_SETTINGS, hydrateNewDealsSettings, type CustomerNewDealsSettings } from './config'\n\ntype NewDealItem = {\n id: string\n title: string | null\n status: string | null\n createdAt: string\n}\n\nasync function loadNewDeals(settings: CustomerNewDealsSettings): Promise<NewDealItem[]> {\n const params = new URLSearchParams({ limit: String(settings.pageSize) })\n const call = await apiCall<{ items?: unknown[]; error?: string }>(\n `/api/customers/dashboard/widgets/new-deals?${params.toString()}`,\n )\n if (!call.ok) {\n const message =\n typeof (call.result as Record<string, unknown> | null)?.error === 'string'\n ? ((call.result as Record<string, unknown>).error as string)\n : `Request failed with status ${call.status}`\n throw new Error(message)\n }\n const payload = call.result ?? {}\n const rawItems = Array.isArray((payload as { items?: unknown[] }).items)\n ? (payload as { items: unknown[] }).items\n : []\n return rawItems\n .map((item: unknown): NewDealItem | null => {\n if (!item || typeof item !== 'object') return null\n const data = item as any\n return {\n id: typeof data.id === 'string' ? data.id : null,\n title: typeof data.title === 'string' ? data.title : null,\n status: typeof data.status === 'string' ? data.status : null,\n createdAt: typeof data.createdAt === 'string' ? data.createdAt : '',\n }\n })\n .filter((item: NewDealItem | null): item is NewDealItem => !!item && !!item.id && !!item.createdAt)\n}\n\nfunction resolveDetailHref(item: NewDealItem): string | null {\n if (!item.id) return null\n return `/backend/customers/deals/${encodeURIComponent(item.id)}`\n}\n\nfunction formatDate(value: string | null, locale?: string): string {\n if (!value) return ''\n const date = new Date(value)\n if (Number.isNaN(date.getTime())) return ''\n return date.toLocaleString(locale ?? undefined, { dateStyle: 'medium', timeStyle: 'short' })\n}\n\nconst CustomerNewDealsWidget: React.FC<DashboardWidgetComponentProps<CustomerNewDealsSettings>> = ({\n mode,\n settings = DEFAULT_SETTINGS,\n onSettingsChange,\n refreshToken,\n onRefreshStateChange,\n}) => {\n const t = useT()\n const hydrated = React.useMemo(() => hydrateNewDealsSettings(settings), [settings])\n const [items, setItems] = React.useState<NewDealItem[]>([])\n const [loading, setLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [locale, setLocale] = React.useState<string | undefined>(undefined)\n\n React.useEffect(() => {\n if (typeof navigator !== 'undefined') {\n setLocale(navigator.language)\n }\n }, [])\n\n const refresh = React.useCallback(async () => {\n onRefreshStateChange?.(true)\n setLoading(true)\n setError(null)\n try {\n const data = await loadNewDeals(hydrated)\n setItems(data)\n } catch (err) {\n console.error('Failed to load new deals widget data', err)\n setError(t('customers.widgets.newDeals.error'))\n } finally {\n setLoading(false)\n onRefreshStateChange?.(false)\n }\n }, [hydrated, onRefreshStateChange, t])\n\n React.useEffect(() => {\n refresh().catch(() => {})\n }, [refresh, refreshToken])\n\n if (mode === 'settings') {\n return (\n <div className=\"space-y-4 text-sm\">\n <div className=\"space-y-1.5\">\n <label htmlFor=\"customer-new-deals-page-size\" className=\"text-xs font-semibold uppercase text-muted-foreground\">\n {t('customers.widgets.newDeals.settings.pageSize')}\n </label>\n <input\n id=\"customer-new-deals-page-size\"\n type=\"number\"\n min={1}\n max={20}\n className=\"w-24 rounded-md border px-2 py-1 text-sm focus-visible:border-ring focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n value={hydrated.pageSize}\n onChange={(event) => {\n const next = Number(event.target.value)\n onSettingsChange({ ...hydrated, pageSize: Number.isFinite(next) ? next : hydrated.pageSize })\n }}\n />\n </div>\n </div>\n )\n }\n\n return (\n <div className=\"space-y-4\">\n {error ? (\n <p className=\"text-sm text-destructive\">{error}</p>\n ) : loading ? (\n <div className=\"flex h-32 items-center justify-center\">\n <Spinner className=\"h-6 w-6 text-muted-foreground\" />\n </div>\n ) : items.length === 0 ? (\n <p className=\"text-sm text-muted-foreground\">{t('customers.widgets.newDeals.empty')}</p>\n ) : (\n <ul className=\"space-y-3\">\n {items.map((item) => {\n const href = resolveDetailHref(item)\n const createdLabel = formatDate(item.createdAt, locale)\n return (\n <li key={item.id} className=\"rounded-md border p-3\">\n <div className=\"flex items-start justify-between gap-3\">\n <div>\n <p className=\"text-sm font-medium\">{item.title ?? t('customers.widgets.newDeals.untitled')}</p>\n <p className=\"text-xs text-muted-foreground\">{item.status ?? t('customers.widgets.common.unknown')}</p>\n </div>\n <p className=\"text-xs text-muted-foreground\">{createdLabel || t('customers.widgets.common.unknownDate')}</p>\n </div>\n {href ? (\n <div className=\"mt-2 text-xs\">\n <Link className=\"text-primary hover:underline\" href={href}>\n {t('customers.widgets.common.viewRecord')}\n </Link>\n </div>\n ) : null}\n </li>\n )\n })}\n </ul>\n )}\n </div>\n )\n}\n\nexport default CustomerNewDealsWidget\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport type { DashboardWidgetComponentProps } from '@open-mercato/shared/modules/dashboard/widgets'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { DEFAULT_SETTINGS, hydrateNewDealsSettings, type CustomerNewDealsSettings } from './config'\n\ntype NewDealItem = {\n id: string\n title: string | null\n status: string | null\n createdAt: string\n}\n\nasync function loadNewDeals(settings: CustomerNewDealsSettings): Promise<NewDealItem[]> {\n const params = new URLSearchParams({ limit: String(settings.pageSize) })\n const call = await apiCall<{ items?: unknown[]; error?: string }>(\n `/api/customers/dashboard/widgets/new-deals?${params.toString()}`,\n )\n if (!call.ok) {\n const message =\n typeof (call.result as Record<string, unknown> | null)?.error === 'string'\n ? ((call.result as Record<string, unknown>).error as string)\n : `Request failed with status ${call.status}`\n throw new Error(message)\n }\n const payload = call.result ?? {}\n const rawItems = Array.isArray((payload as { items?: unknown[] }).items)\n ? (payload as { items: unknown[] }).items\n : []\n return rawItems\n .map((item: unknown): NewDealItem | null => {\n if (!item || typeof item !== 'object') return null\n const data = item as any\n return {\n id: typeof data.id === 'string' ? data.id : null,\n title: typeof data.title === 'string' ? data.title : null,\n status: typeof data.status === 'string' ? data.status : null,\n createdAt: typeof data.createdAt === 'string' ? data.createdAt : '',\n }\n })\n .filter((item: NewDealItem | null): item is NewDealItem => !!item && !!item.id && !!item.createdAt)\n}\n\nfunction resolveDetailHref(item: NewDealItem): string | null {\n if (!item.id) return null\n return `/backend/customers/deals/${encodeURIComponent(item.id)}`\n}\n\nfunction formatDate(value: string | null, locale?: string): string {\n if (!value) return ''\n const date = new Date(value)\n if (Number.isNaN(date.getTime())) return ''\n return date.toLocaleString(locale ?? undefined, { dateStyle: 'medium', timeStyle: 'short' })\n}\n\nconst CustomerNewDealsWidget: React.FC<DashboardWidgetComponentProps<CustomerNewDealsSettings>> = ({\n mode,\n settings = DEFAULT_SETTINGS,\n onSettingsChange,\n refreshToken,\n onRefreshStateChange,\n}) => {\n const t = useT()\n const hydrated = React.useMemo(() => hydrateNewDealsSettings(settings), [settings])\n const [items, setItems] = React.useState<NewDealItem[]>([])\n const [loading, setLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [locale, setLocale] = React.useState<string | undefined>(undefined)\n\n React.useEffect(() => {\n if (typeof navigator !== 'undefined') {\n setLocale(navigator.language)\n }\n }, [])\n\n const refresh = React.useCallback(async () => {\n onRefreshStateChange?.(true)\n setLoading(true)\n setError(null)\n try {\n const data = await loadNewDeals(hydrated)\n setItems(data)\n } catch (err) {\n console.error('Failed to load new deals widget data', err)\n setError(t('customers.widgets.newDeals.error'))\n } finally {\n setLoading(false)\n onRefreshStateChange?.(false)\n }\n }, [hydrated, onRefreshStateChange, t])\n\n React.useEffect(() => {\n refresh().catch(() => {})\n }, [refresh, refreshToken])\n\n if (mode === 'settings') {\n return (\n <div className=\"space-y-4 text-sm\">\n <div className=\"space-y-1.5\">\n <label htmlFor=\"customer-new-deals-page-size\" className=\"text-xs font-semibold uppercase text-muted-foreground\">\n {t('customers.widgets.newDeals.settings.pageSize')}\n </label>\n <Input\n id=\"customer-new-deals-page-size\"\n type=\"number\"\n min={1}\n max={20}\n className=\"w-24\"\n value={hydrated.pageSize}\n onChange={(event) => {\n const next = Number(event.target.value)\n onSettingsChange({ ...hydrated, pageSize: Number.isFinite(next) ? next : hydrated.pageSize })\n }}\n />\n </div>\n </div>\n )\n }\n\n return (\n <div className=\"space-y-4\">\n {error ? (\n <p className=\"text-sm text-destructive\">{error}</p>\n ) : loading ? (\n <div className=\"flex h-32 items-center justify-center\">\n <Spinner className=\"h-6 w-6 text-muted-foreground\" />\n </div>\n ) : items.length === 0 ? (\n <p className=\"text-sm text-muted-foreground\">{t('customers.widgets.newDeals.empty')}</p>\n ) : (\n <ul className=\"space-y-3\">\n {items.map((item) => {\n const href = resolveDetailHref(item)\n const createdLabel = formatDate(item.createdAt, locale)\n return (\n <li key={item.id} className=\"rounded-md border p-3\">\n <div className=\"flex items-start justify-between gap-3\">\n <div>\n <p className=\"text-sm font-medium\">{item.title ?? t('customers.widgets.newDeals.untitled')}</p>\n <p className=\"text-xs text-muted-foreground\">{item.status ?? t('customers.widgets.common.unknown')}</p>\n </div>\n <p className=\"text-xs text-muted-foreground\">{createdLabel || t('customers.widgets.common.unknownDate')}</p>\n </div>\n {href ? (\n <div className=\"mt-2 text-xs\">\n <Link className=\"text-primary hover:underline\" href={href}>\n {t('customers.widgets.common.viewRecord')}\n </Link>\n </div>\n ) : null}\n </li>\n )\n })}\n </ul>\n )}\n </div>\n )\n}\n\nexport default CustomerNewDealsWidget\n"],
5
+ "mappings": ";AAuGQ,SACE,KADF;AArGR,YAAY,WAAW;AACvB,OAAO,UAAU;AAEjB,SAAS,eAAe;AACxB,SAAS,aAAa;AACtB,SAAS,eAAe;AACxB,SAAS,YAAY;AACrB,SAAS,kBAAkB,+BAA8D;AASzF,eAAe,aAAa,UAA4D;AACtF,QAAM,SAAS,IAAI,gBAAgB,EAAE,OAAO,OAAO,SAAS,QAAQ,EAAE,CAAC;AACvE,QAAM,OAAO,MAAM;AAAA,IACjB,8CAA8C,OAAO,SAAS,CAAC;AAAA,EACjE;AACA,MAAI,CAAC,KAAK,IAAI;AACZ,UAAM,UACJ,OAAQ,KAAK,QAA2C,UAAU,WAC5D,KAAK,OAAmC,QAC1C,8BAA8B,KAAK,MAAM;AAC/C,UAAM,IAAI,MAAM,OAAO;AAAA,EACzB;AACA,QAAM,UAAU,KAAK,UAAU,CAAC;AAChC,QAAM,WAAW,MAAM,QAAS,QAAkC,KAAK,IAClE,QAAiC,QAClC,CAAC;AACL,SAAO,SACJ,IAAI,CAAC,SAAsC;AAC1C,QAAI,CAAC,QAAQ,OAAO,SAAS,SAAU,QAAO;AAC9C,UAAM,OAAO;AACb,WAAO;AAAA,MACL,IAAI,OAAO,KAAK,OAAO,WAAW,KAAK,KAAK;AAAA,MAC5C,OAAO,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ;AAAA,MACrD,QAAQ,OAAO,KAAK,WAAW,WAAW,KAAK,SAAS;AAAA,MACxD,WAAW,OAAO,KAAK,cAAc,WAAW,KAAK,YAAY;AAAA,IACnE;AAAA,EACF,CAAC,EACA,OAAO,CAAC,SAAkD,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,KAAK,SAAS;AACtG;AAEA,SAAS,kBAAkB,MAAkC;AAC3D,MAAI,CAAC,KAAK,GAAI,QAAO;AACrB,SAAO,4BAA4B,mBAAmB,KAAK,EAAE,CAAC;AAChE;AAEA,SAAS,WAAW,OAAsB,QAAyB;AACjE,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,OAAO,IAAI,KAAK,KAAK;AAC3B,MAAI,OAAO,MAAM,KAAK,QAAQ,CAAC,EAAG,QAAO;AACzC,SAAO,KAAK,eAAe,UAAU,QAAW,EAAE,WAAW,UAAU,WAAW,QAAQ,CAAC;AAC7F;AAEA,MAAM,yBAA4F,CAAC;AAAA,EACjG;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AACF,MAAM;AACJ,QAAM,IAAI,KAAK;AACf,QAAM,WAAW,MAAM,QAAQ,MAAM,wBAAwB,QAAQ,GAAG,CAAC,QAAQ,CAAC;AAClF,QAAM,CAAC,OAAO,QAAQ,IAAI,MAAM,SAAwB,CAAC,CAAC;AAC1D,QAAM,CAAC,SAAS,UAAU,IAAI,MAAM,SAAS,IAAI;AACjD,QAAM,CAAC,OAAO,QAAQ,IAAI,MAAM,SAAwB,IAAI;AAC5D,QAAM,CAAC,QAAQ,SAAS,IAAI,MAAM,SAA6B,MAAS;AAExE,QAAM,UAAU,MAAM;AACpB,QAAI,OAAO,cAAc,aAAa;AACpC,gBAAU,UAAU,QAAQ;AAAA,IAC9B;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,UAAU,MAAM,YAAY,YAAY;AAC5C,2BAAuB,IAAI;AAC3B,eAAW,IAAI;AACf,aAAS,IAAI;AACb,QAAI;AACF,YAAM,OAAO,MAAM,aAAa,QAAQ;AACxC,eAAS,IAAI;AAAA,IACf,SAAS,KAAK;AACZ,cAAQ,MAAM,wCAAwC,GAAG;AACzD,eAAS,EAAE,kCAAkC,CAAC;AAAA,IAChD,UAAE;AACA,iBAAW,KAAK;AAChB,6BAAuB,KAAK;AAAA,IAC9B;AAAA,EACF,GAAG,CAAC,UAAU,sBAAsB,CAAC,CAAC;AAEtC,QAAM,UAAU,MAAM;AACpB,YAAQ,EAAE,MAAM,MAAM;AAAA,IAAC,CAAC;AAAA,EAC1B,GAAG,CAAC,SAAS,YAAY,CAAC;AAE1B,MAAI,SAAS,YAAY;AACvB,WACE,oBAAC,SAAI,WAAU,qBACb,+BAAC,SAAI,WAAU,eACb;AAAA,0BAAC,WAAM,SAAQ,gCAA+B,WAAU,yDACrD,YAAE,8CAA8C,GACnD;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,IAAG;AAAA,UACH,MAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK;AAAA,UACL,WAAU;AAAA,UACV,OAAO,SAAS;AAAA,UAChB,UAAU,CAAC,UAAU;AACnB,kBAAM,OAAO,OAAO,MAAM,OAAO,KAAK;AACtC,6BAAiB,EAAE,GAAG,UAAU,UAAU,OAAO,SAAS,IAAI,IAAI,OAAO,SAAS,SAAS,CAAC;AAAA,UAC9F;AAAA;AAAA,MACF;AAAA,OACF,GACF;AAAA,EAEJ;AAEA,SACE,oBAAC,SAAI,WAAU,aACZ,kBACC,oBAAC,OAAE,WAAU,4BAA4B,iBAAM,IAC7C,UACF,oBAAC,SAAI,WAAU,yCACb,8BAAC,WAAQ,WAAU,iCAAgC,GACrD,IACE,MAAM,WAAW,IACnB,oBAAC,OAAE,WAAU,iCAAiC,YAAE,kCAAkC,GAAE,IAEpF,oBAAC,QAAG,WAAU,aACX,gBAAM,IAAI,CAAC,SAAS;AACnB,UAAM,OAAO,kBAAkB,IAAI;AACnC,UAAM,eAAe,WAAW,KAAK,WAAW,MAAM;AACtD,WACE,qBAAC,QAAiB,WAAU,yBAC1B;AAAA,2BAAC,SAAI,WAAU,0CACb;AAAA,6BAAC,SACC;AAAA,8BAAC,OAAE,WAAU,uBAAuB,eAAK,SAAS,EAAE,qCAAqC,GAAE;AAAA,UAC3F,oBAAC,OAAE,WAAU,iCAAiC,eAAK,UAAU,EAAE,kCAAkC,GAAE;AAAA,WACrG;AAAA,QACA,oBAAC,OAAE,WAAU,iCAAiC,0BAAgB,EAAE,sCAAsC,GAAE;AAAA,SAC1G;AAAA,MACC,OACC,oBAAC,SAAI,WAAU,gBACb,8BAAC,QAAK,WAAU,gCAA+B,MAC5C,YAAE,qCAAqC,GAC1C,GACF,IACE;AAAA,SAdG,KAAK,EAed;AAAA,EAEJ,CAAC,GACH,GAEJ;AAEJ;AAEA,IAAO,wBAAQ;",
6
6
  "names": []
7
7
  }
@@ -4,6 +4,7 @@ import * as React from "react";
4
4
  import Link from "next/link";
5
5
  import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
6
6
  import { formatRelativeTime } from "@open-mercato/shared/lib/time";
7
+ import { Input } from "@open-mercato/ui/primitives/input";
7
8
  import { Spinner } from "@open-mercato/ui/primitives/spinner";
8
9
  import { useT } from "@open-mercato/shared/lib/i18n/context";
9
10
  import {
@@ -100,13 +101,13 @@ const CustomerNextInteractionsWidget = ({
100
101
  /* @__PURE__ */ jsxs("div", { className: "space-y-1.5", children: [
101
102
  /* @__PURE__ */ jsx("label", { htmlFor: "customer-next-interactions-page-size", className: "text-xs font-semibold uppercase text-muted-foreground", children: t("customers.widgets.nextInteractions.settings.pageSize") }),
102
103
  /* @__PURE__ */ jsx(
103
- "input",
104
+ Input,
104
105
  {
105
106
  id: "customer-next-interactions-page-size",
106
107
  type: "number",
107
108
  min: 1,
108
109
  max: 20,
109
- className: "w-24 rounded-md border px-2 py-1 text-sm focus-visible:border-ring focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
110
+ className: "w-24",
110
111
  value: hydrated.pageSize,
111
112
  onChange: (event) => {
112
113
  const next = Number(event.target.value);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/customers/widgets/dashboard/next-interactions/widget.client.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport type { DashboardWidgetComponentProps } from '@open-mercato/shared/modules/dashboard/widgets'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { formatRelativeTime } from '@open-mercato/shared/lib/time'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport {\n DEFAULT_SETTINGS,\n hydrateNextInteractionsSettings,\n type CustomerNextInteractionsSettings,\n} from './config'\nimport { renderDictionaryColor, renderDictionaryIcon } from '../../../lib/dictionaries'\n\ntype NextInteractionItem = {\n id: string\n displayName: string | null\n kind: string | null\n nextInteractionAt: string | null\n nextInteractionName: string | null\n nextInteractionIcon: string | null\n nextInteractionColor: string | null\n organizationId: string | null\n}\n\ntype ApiResponse = {\n items: NextInteractionItem[]\n now?: string\n}\n\n// NOTE(SPEC-046b): This widget reads from next_interaction_* projection fields\n// on CustomerEntity. These fields are now maintained by the interaction\n// projection recompute service (lib/interactionProjection.ts).\nasync function loadNextInteractions(settings: CustomerNextInteractionsSettings): Promise<ApiResponse> {\n const params = new URLSearchParams({\n limit: String(settings.pageSize),\n includePast: settings.includePast ? 'true' : 'false',\n })\n const call = await apiCall<ApiResponse>(`/api/customers/dashboard/widgets/next-interactions?${params.toString()}`)\n if (!call.ok) {\n const rawError = (call.result as Record<string, unknown> | null)?.error\n const message =\n typeof rawError === 'string'\n ? rawError\n : `Request failed with status ${call.status}`\n throw new Error(message)\n }\n const payloadData = (call.result ?? {}) as Record<string, unknown>\n const now = typeof payloadData.now === 'string' ? payloadData.now : undefined\n const rawItems = Array.isArray(payloadData.items) ? payloadData.items : []\n const items = rawItems\n .map((item): NextInteractionItem | null => {\n if (!item || typeof item !== 'object') return null\n const data = item as Record<string, unknown>\n const id = typeof data.id === 'string' ? data.id : null\n if (!id) return null\n return {\n id,\n displayName: typeof data.displayName === 'string' ? data.displayName : null,\n kind: typeof data.kind === 'string' ? data.kind : null,\n nextInteractionAt: typeof data.nextInteractionAt === 'string' ? data.nextInteractionAt : null,\n nextInteractionName: typeof data.nextInteractionName === 'string' ? data.nextInteractionName : null,\n nextInteractionIcon: typeof data.nextInteractionIcon === 'string' ? data.nextInteractionIcon : null,\n nextInteractionColor: typeof data.nextInteractionColor === 'string' ? data.nextInteractionColor : null,\n organizationId: typeof data.organizationId === 'string' ? data.organizationId : null,\n }\n })\n .filter((item): item is NextInteractionItem => !!item && !!item.id)\n\n return { items, now }\n}\n\nfunction resolveDetailHref(item: NextInteractionItem): string | null {\n if (!item.id || !item.kind) return null\n if (item.kind === 'company') return `/backend/customers/companies-v2/${encodeURIComponent(item.id)}`\n if (item.kind === 'person') return `/backend/customers/people-v2/${encodeURIComponent(item.id)}`\n return null\n}\n\nfunction formatAbsolute(value: string | null, locale?: string): string {\n if (!value) return ''\n const date = new Date(value)\n if (Number.isNaN(date.getTime())) return ''\n return date.toLocaleString(locale ?? undefined, {\n dateStyle: 'medium',\n timeStyle: 'short',\n })\n}\n\nconst CustomerNextInteractionsWidget: React.FC<DashboardWidgetComponentProps<CustomerNextInteractionsSettings>> = ({\n mode,\n settings = DEFAULT_SETTINGS,\n onSettingsChange,\n refreshToken,\n onRefreshStateChange,\n}) => {\n const t = useT()\n const hydrated = React.useMemo(() => hydrateNextInteractionsSettings(settings), [settings])\n const [data, setData] = React.useState<NextInteractionItem[]>([])\n const [loading, setLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [locale, setLocale] = React.useState<string | undefined>(undefined)\n\n React.useEffect(() => {\n if (typeof navigator !== 'undefined') {\n setLocale(navigator.language)\n }\n }, [])\n\n const refresh = React.useCallback(async () => {\n onRefreshStateChange?.(true)\n setLoading(true)\n setError(null)\n try {\n const response = await loadNextInteractions(hydrated)\n setData(response.items)\n } catch (err) {\n console.error('Failed to load next interactions widget data', err)\n setError(t('customers.widgets.nextInteractions.error'))\n } finally {\n setLoading(false)\n onRefreshStateChange?.(false)\n }\n }, [hydrated, onRefreshStateChange, t])\n\n React.useEffect(() => {\n refresh().catch(() => {})\n }, [refresh, refreshToken])\n\n if (mode === 'settings') {\n return (\n <div className=\"space-y-4 text-sm\">\n <div className=\"space-y-1.5\">\n <label htmlFor=\"customer-next-interactions-page-size\" className=\"text-xs font-semibold uppercase text-muted-foreground\">\n {t('customers.widgets.nextInteractions.settings.pageSize')}\n </label>\n <input\n id=\"customer-next-interactions-page-size\"\n type=\"number\"\n min={1}\n max={20}\n className=\"w-24 rounded-md border px-2 py-1 text-sm focus-visible:border-ring focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\"\n value={hydrated.pageSize}\n onChange={(event) => {\n const next = Number(event.target.value)\n onSettingsChange({ ...hydrated, pageSize: Number.isFinite(next) ? next : hydrated.pageSize })\n }}\n />\n </div>\n <label className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n <input\n type=\"checkbox\"\n checked={hydrated.includePast}\n onChange={(event) => onSettingsChange({ ...hydrated, includePast: event.target.checked })}\n />\n {t('customers.widgets.nextInteractions.settings.includePast')}\n </label>\n </div>\n )\n }\n\n return (\n <div className=\"space-y-4\">\n {error ? (\n <p className=\"text-sm text-destructive\">{error}</p>\n ) : loading ? (\n <div className=\"flex h-32 items-center justify-center\">\n <Spinner className=\"h-6 w-6 text-muted-foreground\" />\n </div>\n ) : data.length === 0 ? (\n <p className=\"text-sm text-muted-foreground\">{t('customers.widgets.nextInteractions.empty')}</p>\n ) : (\n <ul className=\"space-y-3\">\n {data.map((item) => {\n const href = resolveDetailHref(item)\n const absolute = formatAbsolute(item.nextInteractionAt, locale)\n const relative = formatRelativeTime(item.nextInteractionAt, { locale }) ?? ''\n return (\n <li key={item.id} className=\"rounded-md border p-3\">\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"flex items-start gap-3\">\n {item.nextInteractionIcon ? (\n <span className=\"mt-0.5 inline-flex h-7 w-7 items-center justify-center rounded border border-border bg-card\">\n {renderDictionaryIcon(item.nextInteractionIcon, 'h-4 w-4')}\n </span>\n ) : null}\n <div>\n <p className=\"text-sm font-medium\">{item.displayName ?? t('customers.widgets.common.unknown')}</p>\n {item.nextInteractionName ? (\n <p className=\"text-xs text-muted-foreground\">{item.nextInteractionName}</p>\n ) : null}\n </div>\n </div>\n <div className=\"flex items-center gap-2 text-right text-xs text-muted-foreground\">\n <div>\n <p>{absolute || t('customers.widgets.common.unknownDate')}</p>\n {relative ? <p>{relative}</p> : null}\n </div>\n {item.nextInteractionColor\n ? renderDictionaryColor(item.nextInteractionColor, 'h-3 w-3 rounded-full border border-border')\n : null}\n </div>\n </div>\n {href ? (\n <div className=\"mt-2 text-xs\">\n <Link className=\"text-primary hover:underline\" href={href}>\n {t('customers.widgets.common.viewRecord')}\n </Link>\n </div>\n ) : null}\n </li>\n )\n })}\n </ul>\n )}\n </div>\n )\n}\n\nexport default CustomerNextInteractionsWidget\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport type { DashboardWidgetComponentProps } from '@open-mercato/shared/modules/dashboard/widgets'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { formatRelativeTime } from '@open-mercato/shared/lib/time'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport {\n DEFAULT_SETTINGS,\n hydrateNextInteractionsSettings,\n type CustomerNextInteractionsSettings,\n} from './config'\nimport { renderDictionaryColor, renderDictionaryIcon } from '../../../lib/dictionaries'\n\ntype NextInteractionItem = {\n id: string\n displayName: string | null\n kind: string | null\n nextInteractionAt: string | null\n nextInteractionName: string | null\n nextInteractionIcon: string | null\n nextInteractionColor: string | null\n organizationId: string | null\n}\n\ntype ApiResponse = {\n items: NextInteractionItem[]\n now?: string\n}\n\n// NOTE(SPEC-046b): This widget reads from next_interaction_* projection fields\n// on CustomerEntity. These fields are now maintained by the interaction\n// projection recompute service (lib/interactionProjection.ts).\nasync function loadNextInteractions(settings: CustomerNextInteractionsSettings): Promise<ApiResponse> {\n const params = new URLSearchParams({\n limit: String(settings.pageSize),\n includePast: settings.includePast ? 'true' : 'false',\n })\n const call = await apiCall<ApiResponse>(`/api/customers/dashboard/widgets/next-interactions?${params.toString()}`)\n if (!call.ok) {\n const rawError = (call.result as Record<string, unknown> | null)?.error\n const message =\n typeof rawError === 'string'\n ? rawError\n : `Request failed with status ${call.status}`\n throw new Error(message)\n }\n const payloadData = (call.result ?? {}) as Record<string, unknown>\n const now = typeof payloadData.now === 'string' ? payloadData.now : undefined\n const rawItems = Array.isArray(payloadData.items) ? payloadData.items : []\n const items = rawItems\n .map((item): NextInteractionItem | null => {\n if (!item || typeof item !== 'object') return null\n const data = item as Record<string, unknown>\n const id = typeof data.id === 'string' ? data.id : null\n if (!id) return null\n return {\n id,\n displayName: typeof data.displayName === 'string' ? data.displayName : null,\n kind: typeof data.kind === 'string' ? data.kind : null,\n nextInteractionAt: typeof data.nextInteractionAt === 'string' ? data.nextInteractionAt : null,\n nextInteractionName: typeof data.nextInteractionName === 'string' ? data.nextInteractionName : null,\n nextInteractionIcon: typeof data.nextInteractionIcon === 'string' ? data.nextInteractionIcon : null,\n nextInteractionColor: typeof data.nextInteractionColor === 'string' ? data.nextInteractionColor : null,\n organizationId: typeof data.organizationId === 'string' ? data.organizationId : null,\n }\n })\n .filter((item): item is NextInteractionItem => !!item && !!item.id)\n\n return { items, now }\n}\n\nfunction resolveDetailHref(item: NextInteractionItem): string | null {\n if (!item.id || !item.kind) return null\n if (item.kind === 'company') return `/backend/customers/companies-v2/${encodeURIComponent(item.id)}`\n if (item.kind === 'person') return `/backend/customers/people-v2/${encodeURIComponent(item.id)}`\n return null\n}\n\nfunction formatAbsolute(value: string | null, locale?: string): string {\n if (!value) return ''\n const date = new Date(value)\n if (Number.isNaN(date.getTime())) return ''\n return date.toLocaleString(locale ?? undefined, {\n dateStyle: 'medium',\n timeStyle: 'short',\n })\n}\n\nconst CustomerNextInteractionsWidget: React.FC<DashboardWidgetComponentProps<CustomerNextInteractionsSettings>> = ({\n mode,\n settings = DEFAULT_SETTINGS,\n onSettingsChange,\n refreshToken,\n onRefreshStateChange,\n}) => {\n const t = useT()\n const hydrated = React.useMemo(() => hydrateNextInteractionsSettings(settings), [settings])\n const [data, setData] = React.useState<NextInteractionItem[]>([])\n const [loading, setLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [locale, setLocale] = React.useState<string | undefined>(undefined)\n\n React.useEffect(() => {\n if (typeof navigator !== 'undefined') {\n setLocale(navigator.language)\n }\n }, [])\n\n const refresh = React.useCallback(async () => {\n onRefreshStateChange?.(true)\n setLoading(true)\n setError(null)\n try {\n const response = await loadNextInteractions(hydrated)\n setData(response.items)\n } catch (err) {\n console.error('Failed to load next interactions widget data', err)\n setError(t('customers.widgets.nextInteractions.error'))\n } finally {\n setLoading(false)\n onRefreshStateChange?.(false)\n }\n }, [hydrated, onRefreshStateChange, t])\n\n React.useEffect(() => {\n refresh().catch(() => {})\n }, [refresh, refreshToken])\n\n if (mode === 'settings') {\n return (\n <div className=\"space-y-4 text-sm\">\n <div className=\"space-y-1.5\">\n <label htmlFor=\"customer-next-interactions-page-size\" className=\"text-xs font-semibold uppercase text-muted-foreground\">\n {t('customers.widgets.nextInteractions.settings.pageSize')}\n </label>\n <Input\n id=\"customer-next-interactions-page-size\"\n type=\"number\"\n min={1}\n max={20}\n className=\"w-24\"\n value={hydrated.pageSize}\n onChange={(event) => {\n const next = Number(event.target.value)\n onSettingsChange({ ...hydrated, pageSize: Number.isFinite(next) ? next : hydrated.pageSize })\n }}\n />\n </div>\n <label className=\"flex items-center gap-2 text-xs text-muted-foreground\">\n <input\n type=\"checkbox\"\n checked={hydrated.includePast}\n onChange={(event) => onSettingsChange({ ...hydrated, includePast: event.target.checked })}\n />\n {t('customers.widgets.nextInteractions.settings.includePast')}\n </label>\n </div>\n )\n }\n\n return (\n <div className=\"space-y-4\">\n {error ? (\n <p className=\"text-sm text-destructive\">{error}</p>\n ) : loading ? (\n <div className=\"flex h-32 items-center justify-center\">\n <Spinner className=\"h-6 w-6 text-muted-foreground\" />\n </div>\n ) : data.length === 0 ? (\n <p className=\"text-sm text-muted-foreground\">{t('customers.widgets.nextInteractions.empty')}</p>\n ) : (\n <ul className=\"space-y-3\">\n {data.map((item) => {\n const href = resolveDetailHref(item)\n const absolute = formatAbsolute(item.nextInteractionAt, locale)\n const relative = formatRelativeTime(item.nextInteractionAt, { locale }) ?? ''\n return (\n <li key={item.id} className=\"rounded-md border p-3\">\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"flex items-start gap-3\">\n {item.nextInteractionIcon ? (\n <span className=\"mt-0.5 inline-flex h-7 w-7 items-center justify-center rounded border border-border bg-card\">\n {renderDictionaryIcon(item.nextInteractionIcon, 'h-4 w-4')}\n </span>\n ) : null}\n <div>\n <p className=\"text-sm font-medium\">{item.displayName ?? t('customers.widgets.common.unknown')}</p>\n {item.nextInteractionName ? (\n <p className=\"text-xs text-muted-foreground\">{item.nextInteractionName}</p>\n ) : null}\n </div>\n </div>\n <div className=\"flex items-center gap-2 text-right text-xs text-muted-foreground\">\n <div>\n <p>{absolute || t('customers.widgets.common.unknownDate')}</p>\n {relative ? <p>{relative}</p> : null}\n </div>\n {item.nextInteractionColor\n ? renderDictionaryColor(item.nextInteractionColor, 'h-3 w-3 rounded-full border border-border')\n : null}\n </div>\n </div>\n {href ? (\n <div className=\"mt-2 text-xs\">\n <Link className=\"text-primary hover:underline\" href={href}>\n {t('customers.widgets.common.viewRecord')}\n </Link>\n </div>\n ) : null}\n </li>\n )\n })}\n </ul>\n )}\n </div>\n )\n}\n\nexport default CustomerNextInteractionsWidget\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -3,6 +3,8 @@ import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import { Button } from "@open-mercato/ui/primitives/button";
5
5
  import { Spinner } from "@open-mercato/ui/primitives/spinner";
6
+ import { RadioGroup } from "@open-mercato/ui/primitives/radio";
7
+ import { RadioField } from "@open-mercato/ui/primitives/radio-field";
6
8
  import { apiCallOrThrow, readApiResultOrThrow } from "@open-mercato/ui/backend/utils/apiCall";
7
9
  import { flash } from "@open-mercato/ui/backend/FlashMessages";
8
10
  import { useT } from "@open-mercato/shared/lib/i18n/context";
@@ -208,34 +210,31 @@ const WidgetVisibilityEditor = React.forwardRef(function WidgetVisibilityEditor2
208
210
  }
209
211
  return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
210
212
  error && /* @__PURE__ */ jsx("div", { className: "rounded-md border border-destructive/40 bg-destructive/10 p-3 text-sm text-destructive", children: error }),
211
- kind === "user" && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 rounded-md border bg-muted/30 px-3 py-2", children: [
212
- /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-sm", children: [
213
- /* @__PURE__ */ jsx(
214
- "input",
215
- {
216
- type: "radio",
217
- name: "widgetOverride",
218
- value: "inherit",
219
- checked: mode === "inherit",
220
- onChange: () => setMode("inherit")
221
- }
222
- ),
223
- t("dashboards.widgets.mode.inherit", "Inherit from roles")
224
- ] }),
225
- /* @__PURE__ */ jsxs("label", { className: "flex items-center gap-2 text-sm", children: [
226
- /* @__PURE__ */ jsx(
227
- "input",
228
- {
229
- type: "radio",
230
- name: "widgetOverride",
231
- value: "override",
232
- checked: mode === "override",
233
- onChange: () => setMode("override")
234
- }
235
- ),
236
- t("dashboards.widgets.mode.override", "Override for this user")
237
- ] })
238
- ] }),
213
+ kind === "user" && /* @__PURE__ */ jsxs(
214
+ RadioGroup,
215
+ {
216
+ className: "flex flex-row items-center gap-3 rounded-md border bg-muted/30 px-3 py-2",
217
+ name: "widgetOverride",
218
+ value: mode,
219
+ onValueChange: (next) => setMode(next),
220
+ children: [
221
+ /* @__PURE__ */ jsx(
222
+ RadioField,
223
+ {
224
+ value: "inherit",
225
+ label: t("dashboards.widgets.mode.inherit", "Inherit from roles")
226
+ }
227
+ ),
228
+ /* @__PURE__ */ jsx(
229
+ RadioField,
230
+ {
231
+ value: "override",
232
+ label: t("dashboards.widgets.mode.override", "Override for this user")
233
+ }
234
+ )
235
+ ]
236
+ }
237
+ ),
239
238
  kind === "user" && mode === "inherit" && /* @__PURE__ */ jsx("div", { className: "rounded-md border border-muted bg-muted/30 px-3 py-2 text-xs text-muted-foreground", children: t("dashboards.widgets.mode.hint", "This user currently inherits widgets from their assigned roles. Switch to override to customize.") }),
240
239
  (kind === "role" || mode === "override") && /* @__PURE__ */ jsx("div", { className: "space-y-3", children: catalog.map((widget) => /* @__PURE__ */ jsxs("label", { className: "flex items-start gap-3 rounded-md border px-3 py-2 hover:border-primary/40", children: [
241
240
  /* @__PURE__ */ jsx(
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/dashboards/components/WidgetVisibilityEditor.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { apiCallOrThrow, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\n\ntype WidgetCatalogItem = {\n id: string\n title: string\n description: string | null\n}\n\ntype RoleResponse = {\n widgetIds: string[]\n hasCustom: boolean\n scope: { tenantId: string | null; organizationId: string | null }\n}\n\ntype UserResponse = {\n mode: 'inherit' | 'override'\n widgetIds: string[]\n hasCustom: boolean\n effectiveWidgetIds: string[]\n scope: { tenantId: string | null; organizationId: string | null }\n}\n\ntype BaseProps = {\n tenantId?: string | null\n organizationId?: string | null\n}\n\ntype RoleProps = BaseProps & {\n kind: 'role'\n targetId: string\n}\n\ntype UserProps = BaseProps & {\n kind: 'user'\n targetId: string\n}\n\ntype WidgetVisibilityEditorProps = RoleProps | UserProps\n\nexport type WidgetVisibilityEditorHandle = {\n save: () => Promise<void>\n}\n\nconst EMPTY: string[] = []\n\nfunction resolveWidgetText(\n t: (key: string, fallback: string) => string,\n id: string,\n field: 'title' | 'description',\n fallback: string,\n): string {\n const key1 = `${id}.${field}`\n const result1 = t(key1, '')\n if (result1 && result1 !== key1) return result1\n\n const key2 = `dashboard.widgets.${id}.${field}`\n const result2 = t(key2, '')\n if (result2 && result2 !== key2) return result2\n\n const dotIndex = id.lastIndexOf('.')\n if (dotIndex > 0) {\n const prefix = id.slice(0, dotIndex)\n const lastPart = id.slice(dotIndex + 1)\n const key3 = `${prefix}.widgets.${lastPart}.${field}`\n const result3 = t(key3, '')\n if (result3 && result3 !== key3) return result3\n }\n\n return fallback\n}\n\nexport const WidgetVisibilityEditor = React.forwardRef<WidgetVisibilityEditorHandle, WidgetVisibilityEditorProps>(function WidgetVisibilityEditor(props, ref) {\n const t = useT()\n const tRef = React.useRef(t)\n tRef.current = t\n\n const resolveTitle = React.useCallback(\n (widget: WidgetCatalogItem) => resolveWidgetText(t, widget.id, 'title', widget.title),\n [t],\n )\n\n const resolveDescription = React.useCallback(\n (widget: WidgetCatalogItem) => resolveWidgetText(t, widget.id, 'description', widget.description || ''),\n [t],\n )\n const { kind, targetId, tenantId, organizationId } = props\n const [catalog, setCatalog] = React.useState<WidgetCatalogItem[]>([])\n const [loading, setLoading] = React.useState(true)\n const [saving, setSaving] = React.useState(false)\n const [error, setError] = React.useState<string | null>(null)\n\n const [selected, setSelected] = React.useState<string[]>(EMPTY)\n const [original, setOriginal] = React.useState<string[]>(EMPTY)\n const [mode, setMode] = React.useState<'inherit' | 'override'>('inherit')\n const [originalMode, setOriginalMode] = React.useState<'inherit' | 'override'>('inherit')\n const [effective, setEffective] = React.useState<string[]>(EMPTY)\n\n const dirty = React.useMemo(() => {\n if (kind === 'user') {\n if (mode !== originalMode) return true\n if (mode === 'override') return selected.join('|') !== original.join('|')\n return false\n }\n return selected.join('|') !== original.join('|')\n }, [kind, mode, original, originalMode, selected])\n\n const loadCatalog = React.useCallback(async () => {\n const data = await readApiResultOrThrow<{ items?: unknown[] }>(\n '/api/dashboards/widgets/catalog',\n undefined,\n { errorMessage: tRef.current('dashboards.widgets.error.load', 'Unable to load widget configuration.') },\n )\n const items = Array.isArray(data?.items) ? data.items : []\n const mapped = items\n .map((item: unknown): WidgetCatalogItem | null => {\n if (!item || typeof item !== 'object') return null\n const entry = item as Record<string, unknown>\n const id = typeof entry.id === 'string' ? entry.id : null\n if (!id || !id.length) return null\n const title =\n typeof entry.title === 'string' && entry.title.length ? entry.title : id\n const description =\n typeof entry.description === 'string' && entry.description.length ? entry.description : null\n return { id, title, description }\n })\n .filter((item: WidgetCatalogItem | null): item is WidgetCatalogItem => item !== null)\n setCatalog(mapped)\n }, [])\n\n const loadRoleData = React.useCallback(async () => {\n const params = new URLSearchParams({ roleId: targetId })\n if (tenantId) params.set('tenantId', tenantId)\n if (organizationId) params.set('organizationId', organizationId)\n const data = await readApiResultOrThrow<RoleResponse>(\n `/api/dashboards/roles/widgets?${params.toString()}`,\n undefined,\n { errorMessage: tRef.current('dashboards.widgets.error.load', 'Unable to load widget configuration.') },\n )\n const ids = Array.isArray(data.widgetIds) ? data.widgetIds : []\n setSelected(ids)\n setOriginal(ids)\n setMode('override')\n setOriginalMode('override')\n setEffective(ids)\n }, [organizationId, targetId, tenantId])\n\n const loadUserData = React.useCallback(async () => {\n const params = new URLSearchParams({ userId: targetId })\n if (tenantId) params.set('tenantId', tenantId)\n if (organizationId) params.set('organizationId', organizationId)\n const data = await readApiResultOrThrow<UserResponse>(\n `/api/dashboards/users/widgets?${params.toString()}`,\n undefined,\n { errorMessage: tRef.current('dashboards.widgets.error.load', 'Unable to load widget configuration.') },\n )\n const ids = Array.isArray(data.widgetIds) ? data.widgetIds : []\n setSelected(ids)\n setOriginal(ids)\n setMode(data.mode || 'inherit')\n setOriginalMode(data.mode || 'inherit')\n setEffective(Array.isArray(data.effectiveWidgetIds) ? data.effectiveWidgetIds : [])\n }, [organizationId, targetId, tenantId])\n\n React.useEffect(() => {\n let cancelled = false\n async function load() {\n setLoading(true)\n setError(null)\n try {\n await loadCatalog()\n if (kind === 'role') await loadRoleData()\n else await loadUserData()\n } catch (err) {\n console.error('Failed to load widget visibility data', err)\n if (!cancelled) {\n setError(tRef.current('dashboards.widgets.error.load', 'Unable to load widget configuration.'))\n }\n } finally {\n if (!cancelled) setLoading(false)\n }\n }\n load()\n return () => { cancelled = true }\n }, [kind, loadCatalog, loadRoleData, loadUserData])\n\n const toggle = React.useCallback((id: string) => {\n setSelected((prev) => (prev.includes(id) ? prev.filter((value) => value !== id) : [...prev, id]))\n }, [])\n\n const resetSelections = React.useCallback(() => {\n setSelected(original)\n setMode(originalMode)\n }, [original, originalMode])\n\n const save = React.useCallback(async () => {\n if (loading) return\n if (error && catalog.length === 0) return\n if (!dirty) return\n setSaving(true)\n setError(null)\n try {\n const saveError = t('dashboards.widgets.error.save', 'Unable to save dashboard widget preferences.')\n if (kind === 'role') {\n const payload = {\n roleId: targetId,\n tenantId: tenantId ?? null,\n organizationId: organizationId ?? null,\n widgetIds: selected,\n }\n await apiCallOrThrow('/api/dashboards/roles/widgets', {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n }, { errorMessage: saveError })\n setOriginal(selected)\n setOriginalMode('override')\n setEffective(selected)\n } else {\n const payload = {\n userId: targetId,\n tenantId: tenantId ?? null,\n organizationId: organizationId ?? null,\n mode,\n widgetIds: selected,\n }\n await apiCallOrThrow('/api/dashboards/users/widgets', {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n }, { errorMessage: saveError })\n setOriginal(selected)\n if (mode === 'inherit') {\n const refreshed = await readApiResultOrThrow<UserResponse>(\n `/api/dashboards/users/widgets?userId=${encodeURIComponent(targetId)}`,\n undefined,\n { errorMessage: saveError },\n )\n setEffective(Array.isArray(refreshed.effectiveWidgetIds) ? refreshed.effectiveWidgetIds : [])\n } else {\n setEffective(selected)\n }\n setOriginal(selected)\n setOriginalMode(mode)\n }\n try { flash(t('dashboards.widgets.flash.saved', 'Dashboard widgets updated'), 'success') } catch {}\n } catch (err) {\n console.error('Failed to save widget visibility', err)\n setError(t('dashboards.widgets.error.save', 'Unable to save dashboard widget preferences.'))\n } finally {\n setSaving(false)\n }\n }, [catalog.length, dirty, error, kind, loading, mode, organizationId, selected, t, targetId, tenantId])\n\n React.useImperativeHandle(ref, () => ({ save }), [save])\n\n if (loading) {\n return (\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <Spinner size=\"sm\" /> {t('dashboards.widgets.loading', 'Loading widget options\u2026')}\n </div>\n )\n }\n\n if (error && catalog.length === 0) {\n return <div className=\"rounded-md border border-destructive/40 bg-destructive/10 p-3 text-sm text-destructive\">{error}</div>\n }\n\n return (\n <div className=\"space-y-4\">\n {error && (\n <div className=\"rounded-md border border-destructive/40 bg-destructive/10 p-3 text-sm text-destructive\">{error}</div>\n )}\n\n {kind === 'user' && (\n <div className=\"flex items-center gap-3 rounded-md border bg-muted/30 px-3 py-2\">\n <label className=\"flex items-center gap-2 text-sm\">\n <input\n type=\"radio\"\n name=\"widgetOverride\"\n value=\"inherit\"\n checked={mode === 'inherit'}\n onChange={() => setMode('inherit')}\n />\n {t('dashboards.widgets.mode.inherit', 'Inherit from roles')}\n </label>\n <label className=\"flex items-center gap-2 text-sm\">\n <input\n type=\"radio\"\n name=\"widgetOverride\"\n value=\"override\"\n checked={mode === 'override'}\n onChange={() => setMode('override')}\n />\n {t('dashboards.widgets.mode.override', 'Override for this user')}\n </label>\n </div>\n )}\n\n {kind === 'user' && mode === 'inherit' && (\n <div className=\"rounded-md border border-muted bg-muted/30 px-3 py-2 text-xs text-muted-foreground\">\n {t('dashboards.widgets.mode.hint', 'This user currently inherits widgets from their assigned roles. Switch to override to customize.')}\n </div>\n )}\n\n {(kind === 'role' || mode === 'override') && (\n <div className=\"space-y-3\">\n {catalog.map((widget) => (\n <label key={widget.id} className=\"flex items-start gap-3 rounded-md border px-3 py-2 hover:border-primary/40\">\n <input\n type=\"checkbox\"\n className=\"mt-1 size-4\"\n checked={selected.includes(widget.id)}\n onChange={() => toggle(widget.id)}\n />\n <div>\n <div className=\"text-sm font-medium leading-none\">{resolveTitle(widget)}</div>\n {widget.description ? <div className=\"mt-1 text-xs text-muted-foreground\">{resolveDescription(widget)}</div> : null}\n </div>\n </label>\n ))}\n </div>\n )}\n\n {kind === 'user' && effective.length > 0 && (\n <div className=\"rounded-md border bg-muted/30 px-3 py-2 text-xs text-muted-foreground\">\n {t('dashboards.widgets.effective', 'Effective widgets:')} {effective.map((id) => { const meta = catalog.find((m) => m.id === id); return meta ? resolveTitle(meta) : id }).join(', ')}\n </div>\n )}\n\n <div className=\"flex items-center gap-2\">\n <Button type=\"button\" onClick={save} disabled={saving || !dirty}>\n {saving ? t('dashboards.widgets.saving', 'Saving\u2026') : t('dashboards.widgets.save', 'Save widgets')}\n </Button>\n <Button type=\"button\" variant=\"ghost\" onClick={resetSelections} disabled={!dirty}>\n {t('dashboards.widgets.reset', 'Reset')}\n </Button>\n </div>\n </div>\n )\n})\n\nWidgetVisibilityEditor.displayName = 'WidgetVisibilityEditor'\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport { RadioGroup } from '@open-mercato/ui/primitives/radio'\nimport { RadioField } from '@open-mercato/ui/primitives/radio-field'\nimport { apiCallOrThrow, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\n\ntype WidgetCatalogItem = {\n id: string\n title: string\n description: string | null\n}\n\ntype RoleResponse = {\n widgetIds: string[]\n hasCustom: boolean\n scope: { tenantId: string | null; organizationId: string | null }\n}\n\ntype UserResponse = {\n mode: 'inherit' | 'override'\n widgetIds: string[]\n hasCustom: boolean\n effectiveWidgetIds: string[]\n scope: { tenantId: string | null; organizationId: string | null }\n}\n\ntype BaseProps = {\n tenantId?: string | null\n organizationId?: string | null\n}\n\ntype RoleProps = BaseProps & {\n kind: 'role'\n targetId: string\n}\n\ntype UserProps = BaseProps & {\n kind: 'user'\n targetId: string\n}\n\ntype WidgetVisibilityEditorProps = RoleProps | UserProps\n\nexport type WidgetVisibilityEditorHandle = {\n save: () => Promise<void>\n}\n\nconst EMPTY: string[] = []\n\nfunction resolveWidgetText(\n t: (key: string, fallback: string) => string,\n id: string,\n field: 'title' | 'description',\n fallback: string,\n): string {\n const key1 = `${id}.${field}`\n const result1 = t(key1, '')\n if (result1 && result1 !== key1) return result1\n\n const key2 = `dashboard.widgets.${id}.${field}`\n const result2 = t(key2, '')\n if (result2 && result2 !== key2) return result2\n\n const dotIndex = id.lastIndexOf('.')\n if (dotIndex > 0) {\n const prefix = id.slice(0, dotIndex)\n const lastPart = id.slice(dotIndex + 1)\n const key3 = `${prefix}.widgets.${lastPart}.${field}`\n const result3 = t(key3, '')\n if (result3 && result3 !== key3) return result3\n }\n\n return fallback\n}\n\nexport const WidgetVisibilityEditor = React.forwardRef<WidgetVisibilityEditorHandle, WidgetVisibilityEditorProps>(function WidgetVisibilityEditor(props, ref) {\n const t = useT()\n const tRef = React.useRef(t)\n tRef.current = t\n\n const resolveTitle = React.useCallback(\n (widget: WidgetCatalogItem) => resolveWidgetText(t, widget.id, 'title', widget.title),\n [t],\n )\n\n const resolveDescription = React.useCallback(\n (widget: WidgetCatalogItem) => resolveWidgetText(t, widget.id, 'description', widget.description || ''),\n [t],\n )\n const { kind, targetId, tenantId, organizationId } = props\n const [catalog, setCatalog] = React.useState<WidgetCatalogItem[]>([])\n const [loading, setLoading] = React.useState(true)\n const [saving, setSaving] = React.useState(false)\n const [error, setError] = React.useState<string | null>(null)\n\n const [selected, setSelected] = React.useState<string[]>(EMPTY)\n const [original, setOriginal] = React.useState<string[]>(EMPTY)\n const [mode, setMode] = React.useState<'inherit' | 'override'>('inherit')\n const [originalMode, setOriginalMode] = React.useState<'inherit' | 'override'>('inherit')\n const [effective, setEffective] = React.useState<string[]>(EMPTY)\n\n const dirty = React.useMemo(() => {\n if (kind === 'user') {\n if (mode !== originalMode) return true\n if (mode === 'override') return selected.join('|') !== original.join('|')\n return false\n }\n return selected.join('|') !== original.join('|')\n }, [kind, mode, original, originalMode, selected])\n\n const loadCatalog = React.useCallback(async () => {\n const data = await readApiResultOrThrow<{ items?: unknown[] }>(\n '/api/dashboards/widgets/catalog',\n undefined,\n { errorMessage: tRef.current('dashboards.widgets.error.load', 'Unable to load widget configuration.') },\n )\n const items = Array.isArray(data?.items) ? data.items : []\n const mapped = items\n .map((item: unknown): WidgetCatalogItem | null => {\n if (!item || typeof item !== 'object') return null\n const entry = item as Record<string, unknown>\n const id = typeof entry.id === 'string' ? entry.id : null\n if (!id || !id.length) return null\n const title =\n typeof entry.title === 'string' && entry.title.length ? entry.title : id\n const description =\n typeof entry.description === 'string' && entry.description.length ? entry.description : null\n return { id, title, description }\n })\n .filter((item: WidgetCatalogItem | null): item is WidgetCatalogItem => item !== null)\n setCatalog(mapped)\n }, [])\n\n const loadRoleData = React.useCallback(async () => {\n const params = new URLSearchParams({ roleId: targetId })\n if (tenantId) params.set('tenantId', tenantId)\n if (organizationId) params.set('organizationId', organizationId)\n const data = await readApiResultOrThrow<RoleResponse>(\n `/api/dashboards/roles/widgets?${params.toString()}`,\n undefined,\n { errorMessage: tRef.current('dashboards.widgets.error.load', 'Unable to load widget configuration.') },\n )\n const ids = Array.isArray(data.widgetIds) ? data.widgetIds : []\n setSelected(ids)\n setOriginal(ids)\n setMode('override')\n setOriginalMode('override')\n setEffective(ids)\n }, [organizationId, targetId, tenantId])\n\n const loadUserData = React.useCallback(async () => {\n const params = new URLSearchParams({ userId: targetId })\n if (tenantId) params.set('tenantId', tenantId)\n if (organizationId) params.set('organizationId', organizationId)\n const data = await readApiResultOrThrow<UserResponse>(\n `/api/dashboards/users/widgets?${params.toString()}`,\n undefined,\n { errorMessage: tRef.current('dashboards.widgets.error.load', 'Unable to load widget configuration.') },\n )\n const ids = Array.isArray(data.widgetIds) ? data.widgetIds : []\n setSelected(ids)\n setOriginal(ids)\n setMode(data.mode || 'inherit')\n setOriginalMode(data.mode || 'inherit')\n setEffective(Array.isArray(data.effectiveWidgetIds) ? data.effectiveWidgetIds : [])\n }, [organizationId, targetId, tenantId])\n\n React.useEffect(() => {\n let cancelled = false\n async function load() {\n setLoading(true)\n setError(null)\n try {\n await loadCatalog()\n if (kind === 'role') await loadRoleData()\n else await loadUserData()\n } catch (err) {\n console.error('Failed to load widget visibility data', err)\n if (!cancelled) {\n setError(tRef.current('dashboards.widgets.error.load', 'Unable to load widget configuration.'))\n }\n } finally {\n if (!cancelled) setLoading(false)\n }\n }\n load()\n return () => { cancelled = true }\n }, [kind, loadCatalog, loadRoleData, loadUserData])\n\n const toggle = React.useCallback((id: string) => {\n setSelected((prev) => (prev.includes(id) ? prev.filter((value) => value !== id) : [...prev, id]))\n }, [])\n\n const resetSelections = React.useCallback(() => {\n setSelected(original)\n setMode(originalMode)\n }, [original, originalMode])\n\n const save = React.useCallback(async () => {\n if (loading) return\n if (error && catalog.length === 0) return\n if (!dirty) return\n setSaving(true)\n setError(null)\n try {\n const saveError = t('dashboards.widgets.error.save', 'Unable to save dashboard widget preferences.')\n if (kind === 'role') {\n const payload = {\n roleId: targetId,\n tenantId: tenantId ?? null,\n organizationId: organizationId ?? null,\n widgetIds: selected,\n }\n await apiCallOrThrow('/api/dashboards/roles/widgets', {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n }, { errorMessage: saveError })\n setOriginal(selected)\n setOriginalMode('override')\n setEffective(selected)\n } else {\n const payload = {\n userId: targetId,\n tenantId: tenantId ?? null,\n organizationId: organizationId ?? null,\n mode,\n widgetIds: selected,\n }\n await apiCallOrThrow('/api/dashboards/users/widgets', {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n }, { errorMessage: saveError })\n setOriginal(selected)\n if (mode === 'inherit') {\n const refreshed = await readApiResultOrThrow<UserResponse>(\n `/api/dashboards/users/widgets?userId=${encodeURIComponent(targetId)}`,\n undefined,\n { errorMessage: saveError },\n )\n setEffective(Array.isArray(refreshed.effectiveWidgetIds) ? refreshed.effectiveWidgetIds : [])\n } else {\n setEffective(selected)\n }\n setOriginal(selected)\n setOriginalMode(mode)\n }\n try { flash(t('dashboards.widgets.flash.saved', 'Dashboard widgets updated'), 'success') } catch {}\n } catch (err) {\n console.error('Failed to save widget visibility', err)\n setError(t('dashboards.widgets.error.save', 'Unable to save dashboard widget preferences.'))\n } finally {\n setSaving(false)\n }\n }, [catalog.length, dirty, error, kind, loading, mode, organizationId, selected, t, targetId, tenantId])\n\n React.useImperativeHandle(ref, () => ({ save }), [save])\n\n if (loading) {\n return (\n <div className=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <Spinner size=\"sm\" /> {t('dashboards.widgets.loading', 'Loading widget options\u2026')}\n </div>\n )\n }\n\n if (error && catalog.length === 0) {\n return <div className=\"rounded-md border border-destructive/40 bg-destructive/10 p-3 text-sm text-destructive\">{error}</div>\n }\n\n return (\n <div className=\"space-y-4\">\n {error && (\n <div className=\"rounded-md border border-destructive/40 bg-destructive/10 p-3 text-sm text-destructive\">{error}</div>\n )}\n\n {kind === 'user' && (\n <RadioGroup\n className=\"flex flex-row items-center gap-3 rounded-md border bg-muted/30 px-3 py-2\"\n name=\"widgetOverride\"\n value={mode}\n onValueChange={(next) => setMode(next as 'inherit' | 'override')}\n >\n <RadioField\n value=\"inherit\"\n label={t('dashboards.widgets.mode.inherit', 'Inherit from roles')}\n />\n <RadioField\n value=\"override\"\n label={t('dashboards.widgets.mode.override', 'Override for this user')}\n />\n </RadioGroup>\n )}\n\n {kind === 'user' && mode === 'inherit' && (\n <div className=\"rounded-md border border-muted bg-muted/30 px-3 py-2 text-xs text-muted-foreground\">\n {t('dashboards.widgets.mode.hint', 'This user currently inherits widgets from their assigned roles. Switch to override to customize.')}\n </div>\n )}\n\n {(kind === 'role' || mode === 'override') && (\n <div className=\"space-y-3\">\n {catalog.map((widget) => (\n <label key={widget.id} className=\"flex items-start gap-3 rounded-md border px-3 py-2 hover:border-primary/40\">\n <input\n type=\"checkbox\"\n className=\"mt-1 size-4\"\n checked={selected.includes(widget.id)}\n onChange={() => toggle(widget.id)}\n />\n <div>\n <div className=\"text-sm font-medium leading-none\">{resolveTitle(widget)}</div>\n {widget.description ? <div className=\"mt-1 text-xs text-muted-foreground\">{resolveDescription(widget)}</div> : null}\n </div>\n </label>\n ))}\n </div>\n )}\n\n {kind === 'user' && effective.length > 0 && (\n <div className=\"rounded-md border bg-muted/30 px-3 py-2 text-xs text-muted-foreground\">\n {t('dashboards.widgets.effective', 'Effective widgets:')} {effective.map((id) => { const meta = catalog.find((m) => m.id === id); return meta ? resolveTitle(meta) : id }).join(', ')}\n </div>\n )}\n\n <div className=\"flex items-center gap-2\">\n <Button type=\"button\" onClick={save} disabled={saving || !dirty}>\n {saving ? t('dashboards.widgets.saving', 'Saving\u2026') : t('dashboards.widgets.save', 'Save widgets')}\n </Button>\n <Button type=\"button\" variant=\"ghost\" onClick={resetSelections} disabled={!dirty}>\n {t('dashboards.widgets.reset', 'Reset')}\n </Button>\n </div>\n </div>\n )\n})\n\nWidgetVisibilityEditor.displayName = 'WidgetVisibilityEditor'\n"],
5
+ "mappings": "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",
6
6
  "names": ["WidgetVisibilityEditor"]
7
7
  }