@open-mercato/core 0.4.5-develop-636d33c995 → 0.4.5-develop-3d8e759e45

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 (211) hide show
  1. package/dist/modules/catalog/backend/catalog/categories/[id]/edit/page.js +17 -2
  2. package/dist/modules/catalog/backend/catalog/categories/[id]/edit/page.js.map +2 -2
  3. package/dist/modules/catalog/backend/catalog/products/[id]/page.js +15 -0
  4. package/dist/modules/catalog/backend/catalog/products/[id]/page.js.map +2 -2
  5. package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js +30 -0
  6. package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js.map +2 -2
  7. package/dist/modules/catalog/inbox-actions.js +51 -0
  8. package/dist/modules/catalog/inbox-actions.js.map +7 -0
  9. package/dist/modules/catalog/lib/messageObjectPreviews.js +146 -0
  10. package/dist/modules/catalog/lib/messageObjectPreviews.js.map +7 -0
  11. package/dist/modules/catalog/message-objects.js +95 -0
  12. package/dist/modules/catalog/message-objects.js.map +7 -0
  13. package/dist/modules/currencies/backend/currencies/[id]/page.js +21 -0
  14. package/dist/modules/currencies/backend/currencies/[id]/page.js.map +2 -2
  15. package/dist/modules/currencies/lib/messageObjectPreviews.js +51 -0
  16. package/dist/modules/currencies/lib/messageObjectPreviews.js.map +7 -0
  17. package/dist/modules/currencies/message-objects.js +41 -0
  18. package/dist/modules/currencies/message-objects.js.map +7 -0
  19. package/dist/modules/customers/backend/customers/companies/[id]/page.js +20 -0
  20. package/dist/modules/customers/backend/customers/companies/[id]/page.js.map +2 -2
  21. package/dist/modules/customers/backend/customers/deals/[id]/page.js +12 -1
  22. package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
  23. package/dist/modules/customers/backend/customers/people/[id]/page.js +20 -0
  24. package/dist/modules/customers/backend/customers/people/[id]/page.js.map +2 -2
  25. package/dist/modules/customers/components/detail/CompanyHighlights.js +18 -14
  26. package/dist/modules/customers/components/detail/CompanyHighlights.js.map +2 -2
  27. package/dist/modules/customers/components/detail/PersonHighlights.js +18 -14
  28. package/dist/modules/customers/components/detail/PersonHighlights.js.map +2 -2
  29. package/dist/modules/customers/inbox-actions.js +230 -0
  30. package/dist/modules/customers/inbox-actions.js.map +7 -0
  31. package/dist/modules/customers/lib/messageObjectPreviews.js +41 -5
  32. package/dist/modules/customers/lib/messageObjectPreviews.js.map +2 -2
  33. package/dist/modules/customers/message-objects.js +31 -11
  34. package/dist/modules/customers/message-objects.js.map +2 -2
  35. package/dist/modules/inbox_ops/api/emails/[id]/route.js +40 -1
  36. package/dist/modules/inbox_ops/api/emails/[id]/route.js.map +2 -2
  37. package/dist/modules/inbox_ops/api/extract/route.js +87 -0
  38. package/dist/modules/inbox_ops/api/extract/route.js.map +7 -0
  39. package/dist/modules/inbox_ops/api/proposals/[id]/translate/route.js +6 -1
  40. package/dist/modules/inbox_ops/api/proposals/[id]/translate/route.js.map +2 -2
  41. package/dist/modules/inbox_ops/api/proposals/counts/route.js.map +2 -2
  42. package/dist/modules/inbox_ops/backend/inbox-ops/log/page.js +40 -14
  43. package/dist/modules/inbox_ops/backend/inbox-ops/log/page.js.map +2 -2
  44. package/dist/modules/inbox_ops/backend/inbox-ops/log/page.meta.js +2 -2
  45. package/dist/modules/inbox_ops/backend/inbox-ops/log/page.meta.js.map +2 -2
  46. package/dist/modules/inbox_ops/backend/inbox-ops/page.js +161 -79
  47. package/dist/modules/inbox_ops/backend/inbox-ops/page.js.map +2 -2
  48. package/dist/modules/inbox_ops/backend/inbox-ops/page.meta.js +2 -2
  49. package/dist/modules/inbox_ops/backend/inbox-ops/page.meta.js.map +2 -2
  50. package/dist/modules/inbox_ops/backend/inbox-ops/proposals/[id]/page.js +109 -62
  51. package/dist/modules/inbox_ops/backend/inbox-ops/proposals/[id]/page.js.map +3 -3
  52. package/dist/modules/inbox_ops/backend/inbox-ops/proposals/[id]/page.meta.js +2 -2
  53. package/dist/modules/inbox_ops/backend/inbox-ops/proposals/[id]/page.meta.js.map +2 -2
  54. package/dist/modules/inbox_ops/backend/inbox-ops/settings/page.js +36 -14
  55. package/dist/modules/inbox_ops/backend/inbox-ops/settings/page.js.map +2 -2
  56. package/dist/modules/inbox_ops/backend/inbox-ops/settings/page.meta.js +2 -2
  57. package/dist/modules/inbox_ops/backend/inbox-ops/settings/page.meta.js.map +2 -2
  58. package/dist/modules/inbox_ops/components/proposals/ActionCard.js +65 -10
  59. package/dist/modules/inbox_ops/components/proposals/ActionCard.js.map +2 -2
  60. package/dist/modules/inbox_ops/components/proposals/EditActionDialog.js +58 -10
  61. package/dist/modules/inbox_ops/components/proposals/EditActionDialog.js.map +2 -2
  62. package/dist/modules/inbox_ops/lib/constants.js.map +2 -2
  63. package/dist/modules/inbox_ops/lib/contactValidation.js +40 -0
  64. package/dist/modules/inbox_ops/lib/contactValidation.js.map +7 -0
  65. package/dist/modules/inbox_ops/lib/executionEngine.js +31 -826
  66. package/dist/modules/inbox_ops/lib/executionEngine.js.map +3 -3
  67. package/dist/modules/inbox_ops/lib/executionHelpers.js +368 -0
  68. package/dist/modules/inbox_ops/lib/executionHelpers.js.map +7 -0
  69. package/dist/modules/inbox_ops/lib/extractionPrompt.js +28 -35
  70. package/dist/modules/inbox_ops/lib/extractionPrompt.js.map +3 -3
  71. package/dist/modules/inbox_ops/lib/inbox-actions-generated.d.js +1 -0
  72. package/dist/modules/inbox_ops/lib/inbox-actions-generated.d.js.map +7 -0
  73. package/dist/modules/inbox_ops/lib/translationProvider.js +15 -10
  74. package/dist/modules/inbox_ops/lib/translationProvider.js.map +2 -2
  75. package/dist/modules/inbox_ops/subscribers/extractionWorker.js +16 -16
  76. package/dist/modules/inbox_ops/subscribers/extractionWorker.js.map +2 -2
  77. package/dist/modules/messages/commands/messages.js +3 -0
  78. package/dist/modules/messages/commands/messages.js.map +2 -2
  79. package/dist/modules/messages/components/message-detail/panels/objects-panel.js +6 -1
  80. package/dist/modules/messages/components/message-detail/panels/objects-panel.js.map +2 -2
  81. package/dist/modules/messages/components/message-detail/panels/thread-panel.js +4 -1
  82. package/dist/modules/messages/components/message-detail/panels/thread-panel.js.map +2 -2
  83. package/dist/modules/messages/frontend/messages/view/[token]/page.js +1 -0
  84. package/dist/modules/messages/frontend/messages/view/[token]/page.js.map +2 -2
  85. package/dist/modules/resources/backend/resources/resources/[id]/page.js +24 -7
  86. package/dist/modules/resources/backend/resources/resources/[id]/page.js.map +2 -2
  87. package/dist/modules/resources/lib/messageObjectPreviews.js +43 -0
  88. package/dist/modules/resources/lib/messageObjectPreviews.js.map +7 -0
  89. package/dist/modules/resources/message-objects.js +37 -0
  90. package/dist/modules/resources/message-objects.js.map +7 -0
  91. package/dist/modules/sales/backend/sales/channels/[channelId]/edit/page.js +19 -0
  92. package/dist/modules/sales/backend/sales/channels/[channelId]/edit/page.js.map +2 -2
  93. package/dist/modules/sales/backend/sales/documents/[id]/page.js +23 -2
  94. package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
  95. package/dist/modules/sales/backend/sales/quotes/[id]/page.js +1 -1
  96. package/dist/modules/sales/backend/sales/quotes/[id]/page.js.map +2 -2
  97. package/dist/modules/sales/inbox-actions.js +278 -0
  98. package/dist/modules/sales/inbox-actions.js.map +7 -0
  99. package/dist/modules/sales/lib/messageObjectPreviews.js +49 -4
  100. package/dist/modules/sales/lib/messageObjectPreviews.js.map +2 -2
  101. package/dist/modules/sales/message-objects.js +44 -2
  102. package/dist/modules/sales/message-objects.js.map +2 -2
  103. package/dist/modules/sales/widgets/messages/SalesDocumentMessageDetail.js +59 -30
  104. package/dist/modules/sales/widgets/messages/SalesDocumentMessageDetail.js.map +2 -2
  105. package/dist/modules/sales/widgets/messages/SalesDocumentMessagePreview.js +1 -1
  106. package/dist/modules/sales/widgets/messages/SalesDocumentMessagePreview.js.map +1 -1
  107. package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js +8 -30
  108. package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js.map +2 -2
  109. package/dist/modules/staff/backend/staff/my-availability/page.js +13 -0
  110. package/dist/modules/staff/backend/staff/my-availability/page.js.map +2 -2
  111. package/dist/modules/staff/backend/staff/my-leave-requests/[id]/page.js +8 -31
  112. package/dist/modules/staff/backend/staff/my-leave-requests/[id]/page.js.map +2 -2
  113. package/dist/modules/staff/backend/staff/team-members/[id]/page.js +32 -10
  114. package/dist/modules/staff/backend/staff/team-members/[id]/page.js.map +2 -2
  115. package/dist/modules/staff/backend/staff/team-roles/[id]/edit/page.js +14 -1
  116. package/dist/modules/staff/backend/staff/team-roles/[id]/edit/page.js.map +2 -2
  117. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +14 -1
  118. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
  119. package/dist/modules/staff/components/TeamForm.js +4 -2
  120. package/dist/modules/staff/components/TeamForm.js.map +2 -2
  121. package/dist/modules/staff/components/TeamRoleForm.js +4 -2
  122. package/dist/modules/staff/components/TeamRoleForm.js.map +2 -2
  123. package/dist/modules/staff/lib/messageObjectPreviews.js +111 -2
  124. package/dist/modules/staff/lib/messageObjectPreviews.js.map +2 -2
  125. package/dist/modules/staff/message-objects.js +79 -8
  126. package/dist/modules/staff/message-objects.js.map +2 -2
  127. package/jest.config.cjs +1 -0
  128. package/jest.mocks/inbox-actions.generated.js +5 -0
  129. package/package.json +2 -2
  130. package/src/modules/catalog/backend/catalog/categories/[id]/edit/page.tsx +19 -5
  131. package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +14 -0
  132. package/src/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.tsx +40 -0
  133. package/src/modules/catalog/inbox-actions.ts +60 -0
  134. package/src/modules/catalog/lib/messageObjectPreviews.ts +176 -0
  135. package/src/modules/catalog/message-objects.ts +102 -0
  136. package/src/modules/currencies/backend/currencies/[id]/page.tsx +20 -0
  137. package/src/modules/currencies/lib/messageObjectPreviews.ts +65 -0
  138. package/src/modules/currencies/message-objects.ts +40 -0
  139. package/src/modules/customers/backend/customers/companies/[id]/page.tsx +19 -0
  140. package/src/modules/customers/backend/customers/deals/[id]/page.tsx +13 -0
  141. package/src/modules/customers/backend/customers/people/[id]/page.tsx +19 -0
  142. package/src/modules/customers/components/detail/CompanyHighlights.tsx +14 -9
  143. package/src/modules/customers/components/detail/PersonHighlights.tsx +14 -9
  144. package/src/modules/customers/inbox-actions.ts +285 -0
  145. package/src/modules/customers/lib/messageObjectPreviews.ts +43 -3
  146. package/src/modules/customers/message-objects.ts +31 -11
  147. package/src/modules/inbox_ops/api/emails/[id]/route.ts +44 -0
  148. package/src/modules/inbox_ops/api/extract/route.ts +94 -0
  149. package/src/modules/inbox_ops/api/proposals/[id]/translate/route.ts +6 -1
  150. package/src/modules/inbox_ops/api/proposals/counts/route.ts +2 -0
  151. package/src/modules/inbox_ops/backend/inbox-ops/log/page.meta.ts +2 -2
  152. package/src/modules/inbox_ops/backend/inbox-ops/log/page.tsx +43 -13
  153. package/src/modules/inbox_ops/backend/inbox-ops/page.meta.ts +2 -2
  154. package/src/modules/inbox_ops/backend/inbox-ops/page.tsx +176 -81
  155. package/src/modules/inbox_ops/backend/inbox-ops/proposals/[id]/page.meta.ts +2 -2
  156. package/src/modules/inbox_ops/backend/inbox-ops/proposals/[id]/page.tsx +122 -68
  157. package/src/modules/inbox_ops/backend/inbox-ops/settings/page.meta.ts +2 -2
  158. package/src/modules/inbox_ops/backend/inbox-ops/settings/page.tsx +36 -14
  159. package/src/modules/inbox_ops/components/proposals/ActionCard.tsx +91 -7
  160. package/src/modules/inbox_ops/components/proposals/EditActionDialog.tsx +64 -12
  161. package/src/modules/inbox_ops/lib/constants.ts +9 -0
  162. package/src/modules/inbox_ops/lib/contactValidation.ts +54 -0
  163. package/src/modules/inbox_ops/lib/executionEngine.ts +47 -1060
  164. package/src/modules/inbox_ops/lib/executionHelpers.ts +527 -0
  165. package/src/modules/inbox_ops/lib/extractionPrompt.ts +45 -34
  166. package/src/modules/inbox_ops/lib/inbox-actions-generated.d.ts +11 -0
  167. package/src/modules/inbox_ops/lib/translationProvider.ts +16 -10
  168. package/src/modules/inbox_ops/subscribers/extractionWorker.ts +16 -18
  169. package/src/modules/messages/commands/messages.ts +4 -0
  170. package/src/modules/messages/components/message-detail/panels/objects-panel.tsx +8 -1
  171. package/src/modules/messages/components/message-detail/panels/thread-panel.tsx +3 -0
  172. package/src/modules/messages/frontend/messages/view/[token]/page.tsx +1 -0
  173. package/src/modules/resources/backend/resources/resources/[id]/page.tsx +20 -4
  174. package/src/modules/resources/lib/messageObjectPreviews.ts +55 -0
  175. package/src/modules/resources/message-objects.ts +36 -0
  176. package/src/modules/sales/backend/sales/channels/[channelId]/edit/page.tsx +18 -0
  177. package/src/modules/sales/backend/sales/documents/[id]/page.tsx +23 -0
  178. package/src/modules/sales/backend/sales/quotes/[id]/page.tsx +1 -1
  179. package/src/modules/sales/inbox-actions.ts +359 -0
  180. package/src/modules/sales/lib/messageObjectPreviews.ts +54 -4
  181. package/src/modules/sales/message-objects.ts +44 -2
  182. package/src/modules/sales/widgets/messages/SalesDocumentMessageDetail.tsx +72 -34
  183. package/src/modules/sales/widgets/messages/SalesDocumentMessagePreview.tsx +1 -1
  184. package/src/modules/staff/backend/staff/leave-requests/[id]/page.tsx +7 -29
  185. package/src/modules/staff/backend/staff/my-availability/page.tsx +14 -0
  186. package/src/modules/staff/backend/staff/my-leave-requests/[id]/page.tsx +8 -30
  187. package/src/modules/staff/backend/staff/team-members/[id]/page.tsx +28 -7
  188. package/src/modules/staff/backend/staff/team-roles/[id]/edit/page.tsx +12 -0
  189. package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +12 -0
  190. package/src/modules/staff/components/TeamForm.tsx +3 -0
  191. package/src/modules/staff/components/TeamRoleForm.tsx +3 -0
  192. package/src/modules/staff/lib/messageObjectPreviews.ts +133 -2
  193. package/src/modules/staff/message-objects.ts +79 -8
  194. package/dist/modules/customers/widgets/messages/CustomerMessageObjectDetail.js +0 -51
  195. package/dist/modules/customers/widgets/messages/CustomerMessageObjectDetail.js.map +0 -7
  196. package/dist/modules/customers/widgets/messages/CustomerMessageObjectPreview.js +0 -35
  197. package/dist/modules/customers/widgets/messages/CustomerMessageObjectPreview.js.map +0 -7
  198. package/dist/modules/customers/widgets/messages/index.js +0 -7
  199. package/dist/modules/customers/widgets/messages/index.js.map +0 -7
  200. package/dist/modules/staff/widgets/messages/StaffMessageObjectDetail.js +0 -51
  201. package/dist/modules/staff/widgets/messages/StaffMessageObjectDetail.js.map +0 -7
  202. package/dist/modules/staff/widgets/messages/StaffMessageObjectPreview.js +0 -34
  203. package/dist/modules/staff/widgets/messages/StaffMessageObjectPreview.js.map +0 -7
  204. package/dist/modules/staff/widgets/messages/index.js +0 -7
  205. package/dist/modules/staff/widgets/messages/index.js.map +0 -7
  206. package/src/modules/customers/widgets/messages/CustomerMessageObjectDetail.tsx +0 -57
  207. package/src/modules/customers/widgets/messages/CustomerMessageObjectPreview.tsx +0 -49
  208. package/src/modules/customers/widgets/messages/index.ts +0 -2
  209. package/src/modules/staff/widgets/messages/StaffMessageObjectDetail.tsx +0 -57
  210. package/src/modules/staff/widgets/messages/StaffMessageObjectPreview.tsx +0 -44
  211. package/src/modules/staff/widgets/messages/index.ts +0 -2
@@ -38,7 +38,8 @@ function TeamRoleForm(props) {
38
38
  onSubmit,
39
39
  onDelete,
40
40
  isLoading,
41
- loadingMessage
41
+ loadingMessage,
42
+ extraActions
42
43
  } = props;
43
44
  const t = useT();
44
45
  const appearanceLabels = React.useMemo(() => ({
@@ -111,7 +112,8 @@ function TeamRoleForm(props) {
111
112
  onSubmit,
112
113
  onDelete,
113
114
  isLoading,
114
- loadingMessage
115
+ loadingMessage,
116
+ extraActions
115
117
  }
116
118
  );
117
119
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/staff/components/TeamRoleForm.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { CrudForm, type CrudField, type CrudFormGroup } from '@open-mercato/ui/backend/CrudForm'\nimport { collectCustomFieldValues } from '@open-mercato/ui/backend/utils/customFieldValues'\nimport { normalizeCustomFieldValues } from '@open-mercato/shared/lib/custom-fields/normalize'\nimport { AppearanceSelector } from '@open-mercato/core/modules/dictionaries/components/AppearanceSelector'\nimport { E } from '#generated/entities.ids.generated'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\n\nexport type TeamRoleFormValues = {\n id?: string\n teamId?: string | null\n name: string\n description?: string | null\n appearance?: { icon?: string | null; color?: string | null }\n} & Record<string, unknown>\n\nexport type TeamRoleOption = {\n id: string\n name: string\n}\n\nexport type TeamRoleFormProps = {\n title: string\n submitLabel?: string\n backHref: string\n cancelHref: string\n initialValues: TeamRoleFormValues\n teamOptions?: TeamRoleOption[]\n onSubmit: (values: TeamRoleFormValues) => Promise<void>\n onDelete?: () => Promise<void>\n isLoading?: boolean\n loadingMessage?: string\n}\n\nconst normalizeCustomFieldSubmitValue = (value: unknown): unknown => {\n const normalized = normalizeCustomFieldValues({ value })\n return normalized.value\n}\n\nexport const buildTeamRolePayload = (\n values: TeamRoleFormValues,\n options: { id?: string } = {},\n): Record<string, unknown> => {\n const name = typeof values.name === 'string' ? values.name.trim() : ''\n const description = typeof values.description === 'string' && values.description.trim().length\n ? values.description.trim()\n : null\n const teamId = typeof values.teamId === 'string' && values.teamId.trim().length ? values.teamId : null\n const appearance = values.appearance && typeof values.appearance === 'object'\n ? values.appearance as { icon?: string | null; color?: string | null }\n : {}\n const customFields = collectCustomFieldValues(values, { transform: normalizeCustomFieldSubmitValue })\n return {\n ...(options.id ? { id: options.id } : {}),\n teamId,\n name,\n description,\n appearanceIcon: appearance.icon ?? null,\n appearanceColor: appearance.color ?? null,\n ...(Object.keys(customFields).length ? { customFields } : {}),\n }\n}\n\nexport function TeamRoleForm(props: TeamRoleFormProps) {\n const {\n title,\n submitLabel,\n backHref,\n cancelHref,\n initialValues,\n teamOptions,\n onSubmit,\n onDelete,\n isLoading,\n loadingMessage,\n } = props\n const t = useT()\n\n const appearanceLabels = React.useMemo(() => ({\n colorLabel: t('staff.teamRoles.form.appearance.colorLabel', 'Color'),\n colorHelp: t('staff.teamRoles.form.appearance.colorHelp', 'Pick a color for this team role.'),\n colorClearLabel: t('staff.teamRoles.form.appearance.colorClear', 'Clear color'),\n iconLabel: t('staff.teamRoles.form.appearance.iconLabel', 'Icon'),\n iconPlaceholder: t('staff.teamRoles.form.appearance.iconPlaceholder', 'Type an emoji or icon name'),\n iconPickerTriggerLabel: t('staff.teamRoles.form.appearance.iconPicker', 'Browse icons'),\n iconSearchPlaceholder: t('staff.teamRoles.form.appearance.iconSearch', 'Search icons or emojis\u2026'),\n iconSearchEmptyLabel: t('staff.teamRoles.form.appearance.iconSearchEmpty', 'No icons match your search'),\n iconSuggestionsLabel: t('staff.teamRoles.form.appearance.iconSuggestions', 'Suggestions'),\n iconClearLabel: t('staff.teamRoles.form.appearance.iconClear', 'Clear icon'),\n previewEmptyLabel: t('staff.teamRoles.form.appearance.previewEmpty', 'No appearance selected'),\n }), [t])\n\n const fields = React.useMemo<CrudField[]>(() => {\n const base: CrudField[] = []\n if (teamOptions && teamOptions.length) {\n base.push({\n id: 'teamId',\n label: t('staff.teamRoles.form.fields.team', 'Team'),\n type: 'select',\n listbox: true,\n options: [\n { value: '', label: t('staff.teamRoles.form.fields.team.unassigned', 'Unassigned') },\n ...teamOptions.map((team) => ({ value: team.id, label: team.name })),\n ],\n })\n }\n base.push(\n { id: 'name', label: t('staff.teamRoles.form.fields.name', 'Name'), type: 'text', required: true },\n { id: 'description', label: t('staff.teamRoles.form.fields.description', 'Description'), type: 'richtext' },\n {\n id: 'appearance',\n label: t('staff.teamRoles.form.appearance.label', 'Appearance'),\n type: 'custom',\n component: ({ value, setValue }) => {\n const current = value && typeof value === 'object'\n ? (value as { icon?: string | null; color?: string | null })\n : {}\n return (\n <AppearanceSelector\n icon={current.icon ?? null}\n color={current.color ?? null}\n onIconChange={(next) => setValue({ ...current, icon: next })}\n onColorChange={(next) => setValue({ ...current, color: next })}\n labels={appearanceLabels}\n />\n )\n },\n },\n )\n return base\n }, [appearanceLabels, t, teamOptions])\n\n const groups = React.useMemo<CrudFormGroup[]>(() => [\n { id: 'details', fields: teamOptions && teamOptions.length ? ['teamId', 'name', 'description', 'appearance'] : ['name', 'description', 'appearance'] },\n { id: 'custom', title: t('entities.customFields.title', 'Custom Attributes'), column: 2, kind: 'customFields' },\n ], [t, teamOptions])\n\n return (\n <CrudForm<TeamRoleFormValues>\n title={title}\n backHref={backHref}\n cancelHref={cancelHref}\n versionHistory={initialValues.id\n ? { resourceKind: 'staff.teamRole', resourceId: String(initialValues.id) }\n : undefined}\n submitLabel={submitLabel}\n fields={fields}\n groups={groups}\n entityId={E.staff.staff_team_role}\n initialValues={initialValues}\n onSubmit={onSubmit}\n onDelete={onDelete}\n isLoading={isLoading}\n loadingMessage={loadingMessage}\n />\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { CrudForm, type CrudField, type CrudFormGroup } from '@open-mercato/ui/backend/CrudForm'\nimport { collectCustomFieldValues } from '@open-mercato/ui/backend/utils/customFieldValues'\nimport { normalizeCustomFieldValues } from '@open-mercato/shared/lib/custom-fields/normalize'\nimport { AppearanceSelector } from '@open-mercato/core/modules/dictionaries/components/AppearanceSelector'\nimport { E } from '#generated/entities.ids.generated'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\n\nexport type TeamRoleFormValues = {\n id?: string\n teamId?: string | null\n name: string\n description?: string | null\n appearance?: { icon?: string | null; color?: string | null }\n} & Record<string, unknown>\n\nexport type TeamRoleOption = {\n id: string\n name: string\n}\n\nexport type TeamRoleFormProps = {\n title: string\n submitLabel?: string\n backHref: string\n cancelHref: string\n initialValues: TeamRoleFormValues\n teamOptions?: TeamRoleOption[]\n onSubmit: (values: TeamRoleFormValues) => Promise<void>\n onDelete?: () => Promise<void>\n isLoading?: boolean\n loadingMessage?: string\n extraActions?: React.ReactNode\n}\n\nconst normalizeCustomFieldSubmitValue = (value: unknown): unknown => {\n const normalized = normalizeCustomFieldValues({ value })\n return normalized.value\n}\n\nexport const buildTeamRolePayload = (\n values: TeamRoleFormValues,\n options: { id?: string } = {},\n): Record<string, unknown> => {\n const name = typeof values.name === 'string' ? values.name.trim() : ''\n const description = typeof values.description === 'string' && values.description.trim().length\n ? values.description.trim()\n : null\n const teamId = typeof values.teamId === 'string' && values.teamId.trim().length ? values.teamId : null\n const appearance = values.appearance && typeof values.appearance === 'object'\n ? values.appearance as { icon?: string | null; color?: string | null }\n : {}\n const customFields = collectCustomFieldValues(values, { transform: normalizeCustomFieldSubmitValue })\n return {\n ...(options.id ? { id: options.id } : {}),\n teamId,\n name,\n description,\n appearanceIcon: appearance.icon ?? null,\n appearanceColor: appearance.color ?? null,\n ...(Object.keys(customFields).length ? { customFields } : {}),\n }\n}\n\nexport function TeamRoleForm(props: TeamRoleFormProps) {\n const {\n title,\n submitLabel,\n backHref,\n cancelHref,\n initialValues,\n teamOptions,\n onSubmit,\n onDelete,\n isLoading,\n loadingMessage,\n extraActions,\n } = props\n const t = useT()\n\n const appearanceLabels = React.useMemo(() => ({\n colorLabel: t('staff.teamRoles.form.appearance.colorLabel', 'Color'),\n colorHelp: t('staff.teamRoles.form.appearance.colorHelp', 'Pick a color for this team role.'),\n colorClearLabel: t('staff.teamRoles.form.appearance.colorClear', 'Clear color'),\n iconLabel: t('staff.teamRoles.form.appearance.iconLabel', 'Icon'),\n iconPlaceholder: t('staff.teamRoles.form.appearance.iconPlaceholder', 'Type an emoji or icon name'),\n iconPickerTriggerLabel: t('staff.teamRoles.form.appearance.iconPicker', 'Browse icons'),\n iconSearchPlaceholder: t('staff.teamRoles.form.appearance.iconSearch', 'Search icons or emojis\u2026'),\n iconSearchEmptyLabel: t('staff.teamRoles.form.appearance.iconSearchEmpty', 'No icons match your search'),\n iconSuggestionsLabel: t('staff.teamRoles.form.appearance.iconSuggestions', 'Suggestions'),\n iconClearLabel: t('staff.teamRoles.form.appearance.iconClear', 'Clear icon'),\n previewEmptyLabel: t('staff.teamRoles.form.appearance.previewEmpty', 'No appearance selected'),\n }), [t])\n\n const fields = React.useMemo<CrudField[]>(() => {\n const base: CrudField[] = []\n if (teamOptions && teamOptions.length) {\n base.push({\n id: 'teamId',\n label: t('staff.teamRoles.form.fields.team', 'Team'),\n type: 'select',\n listbox: true,\n options: [\n { value: '', label: t('staff.teamRoles.form.fields.team.unassigned', 'Unassigned') },\n ...teamOptions.map((team) => ({ value: team.id, label: team.name })),\n ],\n })\n }\n base.push(\n { id: 'name', label: t('staff.teamRoles.form.fields.name', 'Name'), type: 'text', required: true },\n { id: 'description', label: t('staff.teamRoles.form.fields.description', 'Description'), type: 'richtext' },\n {\n id: 'appearance',\n label: t('staff.teamRoles.form.appearance.label', 'Appearance'),\n type: 'custom',\n component: ({ value, setValue }) => {\n const current = value && typeof value === 'object'\n ? (value as { icon?: string | null; color?: string | null })\n : {}\n return (\n <AppearanceSelector\n icon={current.icon ?? null}\n color={current.color ?? null}\n onIconChange={(next) => setValue({ ...current, icon: next })}\n onColorChange={(next) => setValue({ ...current, color: next })}\n labels={appearanceLabels}\n />\n )\n },\n },\n )\n return base\n }, [appearanceLabels, t, teamOptions])\n\n const groups = React.useMemo<CrudFormGroup[]>(() => [\n { id: 'details', fields: teamOptions && teamOptions.length ? ['teamId', 'name', 'description', 'appearance'] : ['name', 'description', 'appearance'] },\n { id: 'custom', title: t('entities.customFields.title', 'Custom Attributes'), column: 2, kind: 'customFields' },\n ], [t, teamOptions])\n\n return (\n <CrudForm<TeamRoleFormValues>\n title={title}\n backHref={backHref}\n cancelHref={cancelHref}\n versionHistory={initialValues.id\n ? { resourceKind: 'staff.teamRole', resourceId: String(initialValues.id) }\n : undefined}\n submitLabel={submitLabel}\n fields={fields}\n groups={groups}\n entityId={E.staff.staff_team_role}\n initialValues={initialValues}\n onSubmit={onSubmit}\n onDelete={onDelete}\n isLoading={isLoading}\n loadingMessage={loadingMessage}\n extraActions={extraActions}\n />\n )\n}\n"],
5
+ "mappings": ";AA0HY;AAxHZ,YAAY,WAAW;AACvB,SAAS,gBAAoD;AAC7D,SAAS,gCAAgC;AACzC,SAAS,kCAAkC;AAC3C,SAAS,0BAA0B;AACnC,SAAS,SAAS;AAClB,SAAS,YAAY;AA6BrB,MAAM,kCAAkC,CAAC,UAA4B;AACnE,QAAM,aAAa,2BAA2B,EAAE,MAAM,CAAC;AACvD,SAAO,WAAW;AACpB;AAEO,MAAM,uBAAuB,CAClC,QACA,UAA2B,CAAC,MACA;AAC5B,QAAM,OAAO,OAAO,OAAO,SAAS,WAAW,OAAO,KAAK,KAAK,IAAI;AACpE,QAAM,cAAc,OAAO,OAAO,gBAAgB,YAAY,OAAO,YAAY,KAAK,EAAE,SACpF,OAAO,YAAY,KAAK,IACxB;AACJ,QAAM,SAAS,OAAO,OAAO,WAAW,YAAY,OAAO,OAAO,KAAK,EAAE,SAAS,OAAO,SAAS;AAClG,QAAM,aAAa,OAAO,cAAc,OAAO,OAAO,eAAe,WACjE,OAAO,aACP,CAAC;AACL,QAAM,eAAe,yBAAyB,QAAQ,EAAE,WAAW,gCAAgC,CAAC;AACpG,SAAO;AAAA,IACL,GAAI,QAAQ,KAAK,EAAE,IAAI,QAAQ,GAAG,IAAI,CAAC;AAAA,IACvC;AAAA,IACA;AAAA,IACA;AAAA,IACA,gBAAgB,WAAW,QAAQ;AAAA,IACnC,iBAAiB,WAAW,SAAS;AAAA,IACrC,GAAI,OAAO,KAAK,YAAY,EAAE,SAAS,EAAE,aAAa,IAAI,CAAC;AAAA,EAC7D;AACF;AAEO,SAAS,aAAa,OAA0B;AACrD,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AACJ,QAAM,IAAI,KAAK;AAEf,QAAM,mBAAmB,MAAM,QAAQ,OAAO;AAAA,IAC5C,YAAY,EAAE,8CAA8C,OAAO;AAAA,IACnE,WAAW,EAAE,6CAA6C,kCAAkC;AAAA,IAC5F,iBAAiB,EAAE,8CAA8C,aAAa;AAAA,IAC9E,WAAW,EAAE,6CAA6C,MAAM;AAAA,IAChE,iBAAiB,EAAE,mDAAmD,4BAA4B;AAAA,IAClG,wBAAwB,EAAE,8CAA8C,cAAc;AAAA,IACtF,uBAAuB,EAAE,8CAA8C,8BAAyB;AAAA,IAChG,sBAAsB,EAAE,mDAAmD,4BAA4B;AAAA,IACvG,sBAAsB,EAAE,mDAAmD,aAAa;AAAA,IACxF,gBAAgB,EAAE,6CAA6C,YAAY;AAAA,IAC3E,mBAAmB,EAAE,gDAAgD,wBAAwB;AAAA,EAC/F,IAAI,CAAC,CAAC,CAAC;AAEP,QAAM,SAAS,MAAM,QAAqB,MAAM;AAC9C,UAAM,OAAoB,CAAC;AAC3B,QAAI,eAAe,YAAY,QAAQ;AACrC,WAAK,KAAK;AAAA,QACR,IAAI;AAAA,QACJ,OAAO,EAAE,oCAAoC,MAAM;AAAA,QACnD,MAAM;AAAA,QACN,SAAS;AAAA,QACT,SAAS;AAAA,UACP,EAAE,OAAO,IAAI,OAAO,EAAE,+CAA+C,YAAY,EAAE;AAAA,UACnF,GAAG,YAAY,IAAI,CAAC,UAAU,EAAE,OAAO,KAAK,IAAI,OAAO,KAAK,KAAK,EAAE;AAAA,QACrE;AAAA,MACF,CAAC;AAAA,IACH;AACA,SAAK;AAAA,MACH,EAAE,IAAI,QAAQ,OAAO,EAAE,oCAAoC,MAAM,GAAG,MAAM,QAAQ,UAAU,KAAK;AAAA,MACjG,EAAE,IAAI,eAAe,OAAO,EAAE,2CAA2C,aAAa,GAAG,MAAM,WAAW;AAAA,MAC1G;AAAA,QACE,IAAI;AAAA,QACJ,OAAO,EAAE,yCAAyC,YAAY;AAAA,QAC9D,MAAM;AAAA,QACN,WAAW,CAAC,EAAE,OAAO,SAAS,MAAM;AAClC,gBAAM,UAAU,SAAS,OAAO,UAAU,WACrC,QACD,CAAC;AACL,iBACE;AAAA,YAAC;AAAA;AAAA,cACC,MAAM,QAAQ,QAAQ;AAAA,cACtB,OAAO,QAAQ,SAAS;AAAA,cACxB,cAAc,CAAC,SAAS,SAAS,EAAE,GAAG,SAAS,MAAM,KAAK,CAAC;AAAA,cAC3D,eAAe,CAAC,SAAS,SAAS,EAAE,GAAG,SAAS,OAAO,KAAK,CAAC;AAAA,cAC7D,QAAQ;AAAA;AAAA,UACV;AAAA,QAEJ;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT,GAAG,CAAC,kBAAkB,GAAG,WAAW,CAAC;AAErC,QAAM,SAAS,MAAM,QAAyB,MAAM;AAAA,IAClD,EAAE,IAAI,WAAW,QAAQ,eAAe,YAAY,SAAS,CAAC,UAAU,QAAQ,eAAe,YAAY,IAAI,CAAC,QAAQ,eAAe,YAAY,EAAE;AAAA,IACrJ,EAAE,IAAI,UAAU,OAAO,EAAE,+BAA+B,mBAAmB,GAAG,QAAQ,GAAG,MAAM,eAAe;AAAA,EAChH,GAAG,CAAC,GAAG,WAAW,CAAC;AAEnB,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACA,gBAAgB,cAAc,KAC1B,EAAE,cAAc,kBAAkB,YAAY,OAAO,cAAc,EAAE,EAAE,IACvE;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA,UAAU,EAAE,MAAM;AAAA,MAClB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA;AAAA,EACF;AAEJ;",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,9 @@
1
1
  import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
2
- import { findOneWithDecryption } from "@open-mercato/shared/lib/encryption/find";
2
+ import { findOneWithDecryption, findWithDecryption } from "@open-mercato/shared/lib/encryption/find";
3
3
  import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
4
- import { StaffLeaveRequest, StaffTeam, StaffTeamMember } from "../data/entities.js";
4
+ import { StaffLeaveRequest, StaffTeam, StaffTeamMember, StaffTeamRole } from "../data/entities.js";
5
+ import { PlannerAvailabilityRuleSet } from "../../planner/data/entities.js";
6
+ import { User } from "../../auth/data/entities.js";
5
7
  function mapStatus(status) {
6
8
  if (status === "approved") {
7
9
  return { label: "Approved", color: "green" };
@@ -131,6 +133,50 @@ async function loadTeamMemberPreview(entityId, ctx) {
131
133
  }
132
134
  const tags = Array.isArray(member.tags) ? member.tags : [];
133
135
  const metadata = {};
136
+ const teamLabel = t("staff.teamMembers.detail.fields.team");
137
+ const userLabel = t("staff.teamMembers.detail.fields.user");
138
+ const rolesLabel = t("staff.teamMembers.detail.fields.roles");
139
+ if (member.teamId) {
140
+ const team = await findOneWithDecryption(
141
+ em,
142
+ StaffTeam,
143
+ {
144
+ id: member.teamId,
145
+ tenantId: ctx.tenantId,
146
+ organizationId: ctx.organizationId,
147
+ deletedAt: null
148
+ },
149
+ void 0,
150
+ { tenantId: ctx.tenantId, organizationId: ctx.organizationId }
151
+ );
152
+ if (team?.name) metadata[teamLabel] = team.name;
153
+ }
154
+ if (member.userId) {
155
+ const user = await findOneWithDecryption(
156
+ em,
157
+ User,
158
+ { id: member.userId },
159
+ void 0,
160
+ { tenantId: ctx.tenantId, organizationId: ctx.organizationId }
161
+ );
162
+ if (user?.email) metadata[userLabel] = user.email;
163
+ }
164
+ if (Array.isArray(member.roleIds) && member.roleIds.length > 0) {
165
+ const roles = await findWithDecryption(
166
+ em,
167
+ StaffTeamRole,
168
+ {
169
+ id: { $in: member.roleIds },
170
+ tenantId: ctx.tenantId,
171
+ organizationId: ctx.organizationId,
172
+ deletedAt: null
173
+ },
174
+ { orderBy: { name: "ASC" } },
175
+ { tenantId: ctx.tenantId, organizationId: ctx.organizationId }
176
+ );
177
+ const roleNames = roles.map((role) => role.name?.trim()).filter((name) => Boolean(name && name.length > 0));
178
+ if (roleNames.length > 0) metadata[rolesLabel] = roleNames.join(", ");
179
+ }
134
180
  if (tags.length > 0) metadata.Tags = tags.slice(0, 5).join(", ");
135
181
  return {
136
182
  title: member.displayName,
@@ -140,8 +186,71 @@ async function loadTeamMemberPreview(entityId, ctx) {
140
186
  metadata: Object.keys(metadata).length > 0 ? metadata : void 0
141
187
  };
142
188
  }
189
+ async function loadStaffTeamRolePreview(entityId, ctx) {
190
+ const { t } = await resolveTranslations();
191
+ const defaultTitle = t("staff.messageObjects.teamRole.title");
192
+ if (!ctx.organizationId) {
193
+ return { title: defaultTitle, subtitle: entityId };
194
+ }
195
+ const { resolve } = await createRequestContainer();
196
+ const em = resolve("em");
197
+ const role = await findOneWithDecryption(
198
+ em,
199
+ StaffTeamRole,
200
+ {
201
+ id: entityId,
202
+ tenantId: ctx.tenantId,
203
+ organizationId: ctx.organizationId,
204
+ deletedAt: null
205
+ },
206
+ void 0,
207
+ { tenantId: ctx.tenantId, organizationId: ctx.organizationId }
208
+ );
209
+ if (!role) {
210
+ return {
211
+ title: defaultTitle,
212
+ subtitle: entityId,
213
+ status: t("staff.messageObjects.notFound"),
214
+ statusColor: "gray"
215
+ };
216
+ }
217
+ return {
218
+ title: role.name,
219
+ subtitle: role.description ?? void 0
220
+ };
221
+ }
222
+ async function loadStaffAvailabilityPreview(entityId, ctx) {
223
+ const { t } = await resolveTranslations();
224
+ const defaultTitle = t("staff.messageObjects.myAvailability.title");
225
+ if (!ctx.organizationId) {
226
+ return { title: defaultTitle, subtitle: entityId };
227
+ }
228
+ const { resolve } = await createRequestContainer();
229
+ const em = resolve("em");
230
+ const ruleSet = await findOneWithDecryption(
231
+ em,
232
+ PlannerAvailabilityRuleSet,
233
+ {
234
+ id: entityId,
235
+ tenantId: ctx.tenantId,
236
+ organizationId: ctx.organizationId,
237
+ deletedAt: null
238
+ },
239
+ void 0,
240
+ { tenantId: ctx.tenantId, organizationId: ctx.organizationId }
241
+ );
242
+ if (!ruleSet) {
243
+ return { title: defaultTitle, subtitle: entityId };
244
+ }
245
+ return {
246
+ title: ruleSet.name,
247
+ subtitle: ruleSet.description ?? void 0
248
+ };
249
+ }
143
250
  export {
144
251
  loadLeaveRequestPreview,
252
+ loadStaffAvailabilityPreview,
253
+ loadStaffTeamRolePreview,
145
254
  loadTeamMemberPreview,
146
255
  loadTeamPreview
147
256
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/modules/staff/lib/messageObjectPreviews.ts"],
4
- "sourcesContent": ["import { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport type { ObjectPreviewData } from '@open-mercato/shared/modules/messages/types'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { StaffLeaveRequest, StaffTeam, StaffTeamMember } from '../data/entities'\n\ntype PreviewContext = {\n tenantId: string\n organizationId?: string | null\n}\n\nfunction mapStatus(status: string): { label: string; color: string } {\n if (status === 'approved') {\n return { label: 'Approved', color: 'green' }\n }\n if (status === 'rejected') {\n return { label: 'Rejected', color: 'red' }\n }\n return { label: 'Pending', color: 'amber' }\n}\n\nfunction formatDate(value: Date): string {\n return value.toISOString().slice(0, 10)\n}\n\nexport async function loadLeaveRequestPreview(\n entityId: string,\n ctx: PreviewContext,\n): Promise<ObjectPreviewData> {\n const { t } = await resolveTranslations()\n const defaultTitle = t('staff.messageObjects.leaveRequest.title')\n\n if (!ctx.organizationId) {\n return {\n title: defaultTitle,\n subtitle: entityId,\n }\n }\n\n const { resolve } = await createRequestContainer()\n const em = resolve('em') as EntityManager\n\n const request = await findOneWithDecryption(\n em,\n StaffLeaveRequest,\n {\n id: entityId,\n tenantId: ctx.tenantId,\n organizationId: ctx.organizationId,\n deletedAt: null,\n },\n undefined,\n { tenantId: ctx.tenantId, organizationId: ctx.organizationId },\n )\n\n if (!request) {\n return {\n title: defaultTitle,\n subtitle: entityId,\n status: t('staff.messageObjects.notFound'),\n statusColor: 'gray',\n }\n }\n\n const status = mapStatus(request.status)\n const memberName = typeof request.member?.displayName === 'string' ? request.member.displayName : null\n const subtitle = memberName\n ? `${memberName} - ${formatDate(request.startDate)} to ${formatDate(request.endDate)}`\n : `${formatDate(request.startDate)} to ${formatDate(request.endDate)}`\n\n return {\n title: 'Leave request',\n subtitle,\n status: status.label,\n statusColor: status.color,\n metadata: {\n 'Start date': formatDate(request.startDate),\n 'End date': formatDate(request.endDate),\n Timezone: request.timezone,\n },\n }\n}\n\nexport async function loadTeamPreview(\n entityId: string,\n ctx: PreviewContext,\n): Promise<ObjectPreviewData> {\n const { t } = await resolveTranslations()\n const defaultTitle = t('staff.messageObjects.team.title')\n\n if (!ctx.organizationId) {\n return {\n title: defaultTitle,\n subtitle: entityId,\n }\n }\n\n const { resolve } = await createRequestContainer()\n const em = resolve('em') as EntityManager\n\n const team = await findOneWithDecryption(\n em,\n StaffTeam,\n {\n id: entityId,\n tenantId: ctx.tenantId,\n organizationId: ctx.organizationId,\n deletedAt: null,\n },\n undefined,\n { tenantId: ctx.tenantId, organizationId: ctx.organizationId },\n )\n\n if (!team) {\n return {\n title: defaultTitle,\n subtitle: entityId,\n status: t('staff.messageObjects.notFound'),\n statusColor: 'gray',\n }\n }\n\n return {\n title: team.name,\n subtitle: team.description ?? entityId,\n status: team.isActive ? 'Active' : 'Inactive',\n statusColor: team.isActive ? 'green' : 'gray',\n }\n}\n\nexport async function loadTeamMemberPreview(\n entityId: string,\n ctx: PreviewContext,\n): Promise<ObjectPreviewData> {\n const { t } = await resolveTranslations()\n const defaultTitle = t('staff.messageObjects.teamMember.title')\n\n if (!ctx.organizationId) {\n return {\n title: defaultTitle,\n subtitle: entityId,\n }\n }\n\n const { resolve } = await createRequestContainer()\n const em = resolve('em') as EntityManager\n\n const member = await findOneWithDecryption(\n em,\n StaffTeamMember,\n {\n id: entityId,\n tenantId: ctx.tenantId,\n organizationId: ctx.organizationId,\n deletedAt: null,\n },\n undefined,\n { tenantId: ctx.tenantId, organizationId: ctx.organizationId },\n )\n\n if (!member) {\n return {\n title: defaultTitle,\n subtitle: entityId,\n status: t('staff.messageObjects.notFound'),\n statusColor: 'gray',\n }\n }\n\n const tags = Array.isArray(member.tags) ? member.tags : []\n const metadata: Record<string, string> = {}\n if (tags.length > 0) metadata.Tags = tags.slice(0, 5).join(', ')\n\n return {\n title: member.displayName,\n subtitle: member.description ?? entityId,\n status: member.isActive ? 'Active' : 'Inactive',\n statusColor: member.isActive ? 'green' : 'gray',\n metadata: Object.keys(metadata).length > 0 ? metadata : undefined,\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { findOneWithDecryption, findWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport type { ObjectPreviewData } from '@open-mercato/shared/modules/messages/types'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { StaffLeaveRequest, StaffTeam, StaffTeamMember, StaffTeamRole } from '../data/entities'\nimport { PlannerAvailabilityRuleSet } from '../../planner/data/entities'\nimport { User } from '../../auth/data/entities'\n\ntype PreviewContext = {\n tenantId: string\n organizationId?: string | null\n}\n\nfunction mapStatus(status: string): { label: string; color: string } {\n if (status === 'approved') {\n return { label: 'Approved', color: 'green' }\n }\n if (status === 'rejected') {\n return { label: 'Rejected', color: 'red' }\n }\n return { label: 'Pending', color: 'amber' }\n}\n\nfunction formatDate(value: Date): string {\n return value.toISOString().slice(0, 10)\n}\n\nexport async function loadLeaveRequestPreview(\n entityId: string,\n ctx: PreviewContext,\n): Promise<ObjectPreviewData> {\n const { t } = await resolveTranslations()\n const defaultTitle = t('staff.messageObjects.leaveRequest.title')\n\n if (!ctx.organizationId) {\n return {\n title: defaultTitle,\n subtitle: entityId,\n }\n }\n\n const { resolve } = await createRequestContainer()\n const em = resolve('em') as EntityManager\n\n const request = await findOneWithDecryption(\n em,\n StaffLeaveRequest,\n {\n id: entityId,\n tenantId: ctx.tenantId,\n organizationId: ctx.organizationId,\n deletedAt: null,\n },\n undefined,\n { tenantId: ctx.tenantId, organizationId: ctx.organizationId },\n )\n\n if (!request) {\n return {\n title: defaultTitle,\n subtitle: entityId,\n status: t('staff.messageObjects.notFound'),\n statusColor: 'gray',\n }\n }\n\n const status = mapStatus(request.status)\n const memberName = typeof request.member?.displayName === 'string' ? request.member.displayName : null\n const subtitle = memberName\n ? `${memberName} - ${formatDate(request.startDate)} to ${formatDate(request.endDate)}`\n : `${formatDate(request.startDate)} to ${formatDate(request.endDate)}`\n\n return {\n title: 'Leave request',\n subtitle,\n status: status.label,\n statusColor: status.color,\n metadata: {\n 'Start date': formatDate(request.startDate),\n 'End date': formatDate(request.endDate),\n Timezone: request.timezone,\n },\n }\n}\n\nexport async function loadTeamPreview(\n entityId: string,\n ctx: PreviewContext,\n): Promise<ObjectPreviewData> {\n const { t } = await resolveTranslations()\n const defaultTitle = t('staff.messageObjects.team.title')\n\n if (!ctx.organizationId) {\n return {\n title: defaultTitle,\n subtitle: entityId,\n }\n }\n\n const { resolve } = await createRequestContainer()\n const em = resolve('em') as EntityManager\n\n const team = await findOneWithDecryption(\n em,\n StaffTeam,\n {\n id: entityId,\n tenantId: ctx.tenantId,\n organizationId: ctx.organizationId,\n deletedAt: null,\n },\n undefined,\n { tenantId: ctx.tenantId, organizationId: ctx.organizationId },\n )\n\n if (!team) {\n return {\n title: defaultTitle,\n subtitle: entityId,\n status: t('staff.messageObjects.notFound'),\n statusColor: 'gray',\n }\n }\n\n return {\n title: team.name,\n subtitle: team.description ?? entityId,\n status: team.isActive ? 'Active' : 'Inactive',\n statusColor: team.isActive ? 'green' : 'gray',\n }\n}\n\nexport async function loadTeamMemberPreview(\n entityId: string,\n ctx: PreviewContext,\n): Promise<ObjectPreviewData> {\n const { t } = await resolveTranslations()\n const defaultTitle = t('staff.messageObjects.teamMember.title')\n\n if (!ctx.organizationId) {\n return {\n title: defaultTitle,\n subtitle: entityId,\n }\n }\n\n const { resolve } = await createRequestContainer()\n const em = resolve('em') as EntityManager\n\n const member = await findOneWithDecryption(\n em,\n StaffTeamMember,\n {\n id: entityId,\n tenantId: ctx.tenantId,\n organizationId: ctx.organizationId,\n deletedAt: null,\n },\n undefined,\n { tenantId: ctx.tenantId, organizationId: ctx.organizationId },\n )\n\n if (!member) {\n return {\n title: defaultTitle,\n subtitle: entityId,\n status: t('staff.messageObjects.notFound'),\n statusColor: 'gray',\n }\n }\n\n const tags = Array.isArray(member.tags) ? member.tags : []\n const metadata: Record<string, string> = {}\n const teamLabel = t('staff.teamMembers.detail.fields.team')\n const userLabel = t('staff.teamMembers.detail.fields.user')\n const rolesLabel = t('staff.teamMembers.detail.fields.roles')\n\n if (member.teamId) {\n const team = await findOneWithDecryption(\n em,\n StaffTeam,\n {\n id: member.teamId,\n tenantId: ctx.tenantId,\n organizationId: ctx.organizationId,\n deletedAt: null,\n },\n undefined,\n { tenantId: ctx.tenantId, organizationId: ctx.organizationId },\n )\n if (team?.name) metadata[teamLabel] = team.name\n }\n\n if (member.userId) {\n const user = await findOneWithDecryption(\n em,\n User,\n { id: member.userId },\n undefined,\n { tenantId: ctx.tenantId, organizationId: ctx.organizationId },\n )\n if (user?.email) metadata[userLabel] = user.email\n }\n\n if (Array.isArray(member.roleIds) && member.roleIds.length > 0) {\n const roles = await findWithDecryption(\n em,\n StaffTeamRole,\n {\n id: { $in: member.roleIds },\n tenantId: ctx.tenantId,\n organizationId: ctx.organizationId,\n deletedAt: null,\n },\n { orderBy: { name: 'ASC' } },\n { tenantId: ctx.tenantId, organizationId: ctx.organizationId },\n )\n const roleNames = roles\n .map((role) => role.name?.trim())\n .filter((name): name is string => Boolean(name && name.length > 0))\n if (roleNames.length > 0) metadata[rolesLabel] = roleNames.join(', ')\n }\n\n if (tags.length > 0) metadata.Tags = tags.slice(0, 5).join(', ')\n\n return {\n title: member.displayName,\n subtitle: member.description ?? entityId,\n status: member.isActive ? 'Active' : 'Inactive',\n statusColor: member.isActive ? 'green' : 'gray',\n metadata: Object.keys(metadata).length > 0 ? metadata : undefined,\n }\n}\n\nexport async function loadStaffTeamRolePreview(\n entityId: string,\n ctx: PreviewContext,\n): Promise<ObjectPreviewData> {\n const { t } = await resolveTranslations()\n const defaultTitle = t('staff.messageObjects.teamRole.title')\n\n if (!ctx.organizationId) {\n return { title: defaultTitle, subtitle: entityId }\n }\n\n const { resolve } = await createRequestContainer()\n const em = resolve('em') as EntityManager\n\n const role = await findOneWithDecryption(\n em,\n StaffTeamRole,\n {\n id: entityId,\n tenantId: ctx.tenantId,\n organizationId: ctx.organizationId,\n deletedAt: null,\n },\n undefined,\n { tenantId: ctx.tenantId, organizationId: ctx.organizationId },\n )\n\n if (!role) {\n return {\n title: defaultTitle,\n subtitle: entityId,\n status: t('staff.messageObjects.notFound'),\n statusColor: 'gray',\n }\n }\n\n return {\n title: role.name,\n subtitle: role.description ?? undefined,\n }\n}\n\nexport async function loadStaffAvailabilityPreview(\n entityId: string,\n ctx: PreviewContext,\n): Promise<ObjectPreviewData> {\n const { t } = await resolveTranslations()\n const defaultTitle = t('staff.messageObjects.myAvailability.title')\n\n if (!ctx.organizationId) {\n return { title: defaultTitle, subtitle: entityId }\n }\n\n const { resolve } = await createRequestContainer()\n const em = resolve('em') as EntityManager\n\n const ruleSet = await findOneWithDecryption(\n em,\n PlannerAvailabilityRuleSet,\n {\n id: entityId,\n tenantId: ctx.tenantId,\n organizationId: ctx.organizationId,\n deletedAt: null,\n },\n undefined,\n { tenantId: ctx.tenantId, organizationId: ctx.organizationId },\n )\n\n if (!ruleSet) {\n return { title: defaultTitle, subtitle: entityId }\n }\n\n return {\n title: ruleSet.name,\n subtitle: ruleSet.description ?? undefined,\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,6 @@
1
+ import { MessageObjectDetail, MessageObjectPreview } from "@open-mercato/ui/backend/messages";
1
2
  import { LeaveRequestDetail } from "./components/LeaveRequestDetail.js";
2
3
  import { LeaveRequestPreview } from "./components/LeaveRequestPreview.js";
3
- import { StaffMessageObjectDetail } from "./widgets/messages/StaffMessageObjectDetail.js";
4
- import { StaffMessageObjectPreview } from "./widgets/messages/StaffMessageObjectPreview.js";
5
4
  const messageObjectTypes = [
6
5
  {
7
6
  module: "staff",
@@ -58,9 +57,18 @@ const messageObjectTypes = [
58
57
  optionSubtitleField: "description",
59
58
  labelKey: "staff.teams.page.title",
60
59
  icon: "users",
61
- PreviewComponent: StaffMessageObjectPreview,
62
- DetailComponent: StaffMessageObjectDetail,
63
- actions: [],
60
+ PreviewComponent: MessageObjectPreview,
61
+ DetailComponent: MessageObjectDetail,
62
+ actions: [
63
+ {
64
+ id: "view",
65
+ labelKey: "common.view",
66
+ variant: "outline",
67
+ href: "/backend/staff/teams/{entityId}/edit",
68
+ icon: "external-link",
69
+ isTerminal: false
70
+ }
71
+ ],
64
72
  loadPreview: async (entityId, ctx) => {
65
73
  if (typeof window !== "undefined") {
66
74
  return {
@@ -81,9 +89,18 @@ const messageObjectTypes = [
81
89
  optionSubtitleField: "email",
82
90
  labelKey: "staff.teamMembers.page.title",
83
91
  icon: "user-round",
84
- PreviewComponent: StaffMessageObjectPreview,
85
- DetailComponent: StaffMessageObjectDetail,
86
- actions: [],
92
+ PreviewComponent: MessageObjectPreview,
93
+ DetailComponent: MessageObjectDetail,
94
+ actions: [
95
+ {
96
+ id: "view",
97
+ labelKey: "common.view",
98
+ variant: "outline",
99
+ href: "/backend/staff/team-members/{entityId}",
100
+ icon: "external-link",
101
+ isTerminal: false
102
+ }
103
+ ],
87
104
  loadPreview: async (entityId, ctx) => {
88
105
  if (typeof window !== "undefined") {
89
106
  return {
@@ -94,6 +111,60 @@ const messageObjectTypes = [
94
111
  const { loadTeamMemberPreview } = await import("./lib/messageObjectPreviews.js");
95
112
  return loadTeamMemberPreview(entityId, ctx);
96
113
  }
114
+ },
115
+ {
116
+ module: "staff",
117
+ entityType: "team_role",
118
+ messageTypes: ["default", "messages.defaultWithObjects"],
119
+ entityId: "staff:staff_team_role",
120
+ optionLabelField: "name",
121
+ optionSubtitleField: "description",
122
+ labelKey: "staff.messageObjects.teamRole.title",
123
+ icon: "shield",
124
+ PreviewComponent: MessageObjectPreview,
125
+ DetailComponent: MessageObjectDetail,
126
+ actions: [
127
+ {
128
+ id: "view",
129
+ labelKey: "common.view",
130
+ variant: "outline",
131
+ href: "/backend/staff/team-roles/{entityId}/edit"
132
+ }
133
+ ],
134
+ loadPreview: async (entityId, ctx) => {
135
+ if (typeof window !== "undefined") {
136
+ return { title: "Team role", subtitle: entityId };
137
+ }
138
+ const { loadStaffTeamRolePreview } = await import("./lib/messageObjectPreviews.js");
139
+ return loadStaffTeamRolePreview(entityId, ctx);
140
+ }
141
+ },
142
+ {
143
+ module: "staff",
144
+ entityType: "my_availability",
145
+ messageTypes: ["default", "messages.defaultWithObjects"],
146
+ entityId: "planner:planner_availability_rule_set",
147
+ optionLabelField: "name",
148
+ optionSubtitleField: "description",
149
+ labelKey: "staff.messageObjects.myAvailability.title",
150
+ icon: "calendar-clock",
151
+ PreviewComponent: MessageObjectPreview,
152
+ DetailComponent: MessageObjectDetail,
153
+ actions: [
154
+ {
155
+ id: "view",
156
+ labelKey: "common.view",
157
+ variant: "outline",
158
+ href: "/backend/staff/my-availability"
159
+ }
160
+ ],
161
+ loadPreview: async (entityId, ctx) => {
162
+ if (typeof window !== "undefined") {
163
+ return { title: "My availability", subtitle: entityId };
164
+ }
165
+ const { loadStaffAvailabilityPreview } = await import("./lib/messageObjectPreviews.js");
166
+ return loadStaffAvailabilityPreview(entityId, ctx);
167
+ }
97
168
  }
98
169
  ];
99
170
  var message_objects_default = messageObjectTypes;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/modules/staff/message-objects.ts"],
4
- "sourcesContent": ["import type { MessageObjectTypeDefinition } from '@open-mercato/shared/modules/messages/types'\nimport { LeaveRequestDetail } from './components/LeaveRequestDetail'\nimport { LeaveRequestPreview } from './components/LeaveRequestPreview'\nimport { StaffMessageObjectDetail } from './widgets/messages/StaffMessageObjectDetail'\nimport { StaffMessageObjectPreview } from './widgets/messages/StaffMessageObjectPreview'\n\nexport const messageObjectTypes: MessageObjectTypeDefinition[] = [\n {\n module: 'staff',\n entityType: 'leave_request',\n messageTypes: ['default', 'messages.defaultWithObjects', 'staff.leave_request_approval', 'staff.leave_request_status'],\n entityId: 'staff:staff_leave_request',\n optionLabelField: 'id',\n optionSubtitleField: 'status',\n labelKey: 'staff.leaveRequests.page.title',\n icon: 'calendar-clock',\n PreviewComponent: LeaveRequestPreview,\n DetailComponent: LeaveRequestDetail,\n actions: [\n {\n id: 'approve',\n labelKey: 'staff.notifications.leaveRequest.actions.approve',\n variant: 'default',\n commandId: 'staff.leave-requests.accept',\n icon: 'check',\n },\n {\n id: 'reject',\n labelKey: 'staff.notifications.leaveRequest.actions.reject',\n variant: 'destructive',\n commandId: 'staff.leave-requests.reject',\n icon: 'x',\n },\n {\n id: 'view',\n labelKey: 'common.view',\n variant: 'outline',\n href: '/backend/staff/leave-requests/{entityId}',\n icon: 'external-link',\n isTerminal: false,\n },\n ],\n loadPreview: async (entityId, ctx) => {\n if (typeof window !== 'undefined') {\n return {\n title: 'Leave request',\n subtitle: entityId,\n }\n }\n const { loadLeaveRequestPreview } = await import('./lib/messageObjectPreviews')\n return loadLeaveRequestPreview(entityId, ctx)\n },\n },\n {\n module: 'staff',\n entityType: 'team',\n messageTypes: ['default', 'messages.defaultWithObjects'],\n entityId: 'staff:staff_team',\n optionLabelField: 'name',\n optionSubtitleField: 'description',\n labelKey: 'staff.teams.page.title',\n icon: 'users',\n PreviewComponent: StaffMessageObjectPreview,\n DetailComponent: StaffMessageObjectDetail,\n actions: [],\n loadPreview: async (entityId, ctx) => {\n if (typeof window !== 'undefined') {\n return {\n title: 'Team',\n subtitle: entityId,\n }\n }\n const { loadTeamPreview } = await import('./lib/messageObjectPreviews')\n return loadTeamPreview(entityId, ctx)\n },\n },\n {\n module: 'staff',\n entityType: 'team_member',\n messageTypes: ['default', 'messages.defaultWithObjects'],\n entityId: 'staff:staff_team_member',\n optionLabelField: 'displayName',\n optionSubtitleField: 'email',\n labelKey: 'staff.teamMembers.page.title',\n icon: 'user-round',\n PreviewComponent: StaffMessageObjectPreview,\n DetailComponent: StaffMessageObjectDetail,\n actions: [],\n loadPreview: async (entityId, ctx) => {\n if (typeof window !== 'undefined') {\n return {\n title: 'Team member',\n subtitle: entityId,\n }\n }\n const { loadTeamMemberPreview } = await import('./lib/messageObjectPreviews')\n return loadTeamMemberPreview(entityId, ctx)\n },\n },\n]\n\nexport default messageObjectTypes\n"],
5
- "mappings": "AACA,SAAS,0BAA0B;AACnC,SAAS,2BAA2B;AACpC,SAAS,gCAAgC;AACzC,SAAS,iCAAiC;AAEnC,MAAM,qBAAoD;AAAA,EAC/D;AAAA,IACE,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,cAAc,CAAC,WAAW,+BAA+B,gCAAgC,4BAA4B;AAAA,IACrH,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,qBAAqB;AAAA,IACrB,UAAU;AAAA,IACV,MAAM;AAAA,IACN,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,IACjB,SAAS;AAAA,MACP;AAAA,QACE,IAAI;AAAA,QACJ,UAAU;AAAA,QACV,SAAS;AAAA,QACT,WAAW;AAAA,QACX,MAAM;AAAA,MACR;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ,UAAU;AAAA,QACV,SAAS;AAAA,QACT,WAAW;AAAA,QACX,MAAM;AAAA,MACR;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ,UAAU;AAAA,QACV,SAAS;AAAA,QACT,MAAM;AAAA,QACN,MAAM;AAAA,QACN,YAAY;AAAA,MACd;AAAA,IACF;AAAA,IACA,aAAa,OAAO,UAAU,QAAQ;AACpC,UAAI,OAAO,WAAW,aAAa;AACjC,eAAO;AAAA,UACL,OAAO;AAAA,UACP,UAAU;AAAA,QACZ;AAAA,MACF;AACA,YAAM,EAAE,wBAAwB,IAAI,MAAM,OAAO,6BAA6B;AAC9E,aAAO,wBAAwB,UAAU,GAAG;AAAA,IAC9C;AAAA,EACF;AAAA,EACA;AAAA,IACE,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,cAAc,CAAC,WAAW,6BAA6B;AAAA,IACvD,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,qBAAqB;AAAA,IACrB,UAAU;AAAA,IACV,MAAM;AAAA,IACN,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,IACjB,SAAS,CAAC;AAAA,IACV,aAAa,OAAO,UAAU,QAAQ;AACpC,UAAI,OAAO,WAAW,aAAa;AACjC,eAAO;AAAA,UACL,OAAO;AAAA,UACP,UAAU;AAAA,QACZ;AAAA,MACF;AACA,YAAM,EAAE,gBAAgB,IAAI,MAAM,OAAO,6BAA6B;AACtE,aAAO,gBAAgB,UAAU,GAAG;AAAA,IACtC;AAAA,EACF;AAAA,EACA;AAAA,IACE,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,cAAc,CAAC,WAAW,6BAA6B;AAAA,IACvD,UAAU;AAAA,IACV,kBAAkB;AAAA,IAClB,qBAAqB;AAAA,IACrB,UAAU;AAAA,IACV,MAAM;AAAA,IACN,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,IACjB,SAAS,CAAC;AAAA,IACV,aAAa,OAAO,UAAU,QAAQ;AACpC,UAAI,OAAO,WAAW,aAAa;AACjC,eAAO;AAAA,UACL,OAAO;AAAA,UACP,UAAU;AAAA,QACZ;AAAA,MACF;AACA,YAAM,EAAE,sBAAsB,IAAI,MAAM,OAAO,6BAA6B;AAC5E,aAAO,sBAAsB,UAAU,GAAG;AAAA,IAC5C;AAAA,EACF;AACF;AAEA,IAAO,0BAAQ;",
4
+ "sourcesContent": ["import type { MessageObjectTypeDefinition } from '@open-mercato/shared/modules/messages/types'\nimport { MessageObjectDetail, MessageObjectPreview } from '@open-mercato/ui/backend/messages'\nimport { LeaveRequestDetail } from './components/LeaveRequestDetail'\nimport { LeaveRequestPreview } from './components/LeaveRequestPreview'\n\nexport const messageObjectTypes: MessageObjectTypeDefinition[] = [\n {\n module: 'staff',\n entityType: 'leave_request',\n messageTypes: ['default', 'messages.defaultWithObjects', 'staff.leave_request_approval', 'staff.leave_request_status'],\n entityId: 'staff:staff_leave_request',\n optionLabelField: 'id',\n optionSubtitleField: 'status',\n labelKey: 'staff.leaveRequests.page.title',\n icon: 'calendar-clock',\n PreviewComponent: LeaveRequestPreview,\n DetailComponent: LeaveRequestDetail,\n actions: [\n {\n id: 'approve',\n labelKey: 'staff.notifications.leaveRequest.actions.approve',\n variant: 'default',\n commandId: 'staff.leave-requests.accept',\n icon: 'check',\n },\n {\n id: 'reject',\n labelKey: 'staff.notifications.leaveRequest.actions.reject',\n variant: 'destructive',\n commandId: 'staff.leave-requests.reject',\n icon: 'x',\n },\n {\n id: 'view',\n labelKey: 'common.view',\n variant: 'outline',\n href: '/backend/staff/leave-requests/{entityId}',\n icon: 'external-link',\n isTerminal: false,\n },\n ],\n loadPreview: async (entityId, ctx) => {\n if (typeof window !== 'undefined') {\n return {\n title: 'Leave request',\n subtitle: entityId,\n }\n }\n const { loadLeaveRequestPreview } = await import('./lib/messageObjectPreviews')\n return loadLeaveRequestPreview(entityId, ctx)\n },\n },\n {\n module: 'staff',\n entityType: 'team',\n messageTypes: ['default', 'messages.defaultWithObjects'],\n entityId: 'staff:staff_team',\n optionLabelField: 'name',\n optionSubtitleField: 'description',\n labelKey: 'staff.teams.page.title',\n icon: 'users',\n PreviewComponent: MessageObjectPreview,\n DetailComponent: MessageObjectDetail,\n actions: [\n {\n id: 'view',\n labelKey: 'common.view',\n variant: 'outline',\n href: '/backend/staff/teams/{entityId}/edit',\n icon: 'external-link',\n isTerminal: false,\n },\n ],\n loadPreview: async (entityId, ctx) => {\n if (typeof window !== 'undefined') {\n return {\n title: 'Team',\n subtitle: entityId,\n }\n }\n const { loadTeamPreview } = await import('./lib/messageObjectPreviews')\n return loadTeamPreview(entityId, ctx)\n },\n },\n {\n module: 'staff',\n entityType: 'team_member',\n messageTypes: ['default', 'messages.defaultWithObjects'],\n entityId: 'staff:staff_team_member',\n optionLabelField: 'displayName',\n optionSubtitleField: 'email',\n labelKey: 'staff.teamMembers.page.title',\n icon: 'user-round',\n PreviewComponent: MessageObjectPreview,\n DetailComponent: MessageObjectDetail,\n actions: [\n {\n id: 'view',\n labelKey: 'common.view',\n variant: 'outline',\n href: '/backend/staff/team-members/{entityId}',\n icon: 'external-link',\n isTerminal: false,\n },\n ],\n loadPreview: async (entityId, ctx) => {\n if (typeof window !== 'undefined') {\n return {\n title: 'Team member',\n subtitle: entityId,\n }\n }\n const { loadTeamMemberPreview } = await import('./lib/messageObjectPreviews')\n return loadTeamMemberPreview(entityId, ctx)\n },\n },\n {\n module: 'staff',\n entityType: 'team_role',\n messageTypes: ['default', 'messages.defaultWithObjects'],\n entityId: 'staff:staff_team_role',\n optionLabelField: 'name',\n optionSubtitleField: 'description',\n labelKey: 'staff.messageObjects.teamRole.title',\n icon: 'shield',\n PreviewComponent: MessageObjectPreview,\n DetailComponent: MessageObjectDetail,\n actions: [\n {\n id: 'view',\n labelKey: 'common.view',\n variant: 'outline',\n href: '/backend/staff/team-roles/{entityId}/edit',\n },\n ],\n loadPreview: async (entityId, ctx) => {\n if (typeof window !== 'undefined') {\n return { title: 'Team role', subtitle: entityId }\n }\n const { loadStaffTeamRolePreview } = await import('./lib/messageObjectPreviews')\n return loadStaffTeamRolePreview(entityId, ctx)\n },\n },\n {\n module: 'staff',\n entityType: 'my_availability',\n messageTypes: ['default', 'messages.defaultWithObjects'],\n entityId: 'planner:planner_availability_rule_set',\n optionLabelField: 'name',\n optionSubtitleField: 'description',\n labelKey: 'staff.messageObjects.myAvailability.title',\n icon: 'calendar-clock',\n PreviewComponent: MessageObjectPreview,\n DetailComponent: MessageObjectDetail,\n actions: [\n {\n id: 'view',\n labelKey: 'common.view',\n variant: 'outline',\n href: '/backend/staff/my-availability',\n },\n ],\n loadPreview: async (entityId, ctx) => {\n if (typeof window !== 'undefined') {\n return { title: 'My availability', subtitle: entityId }\n }\n const { loadStaffAvailabilityPreview } = await import('./lib/messageObjectPreviews')\n return loadStaffAvailabilityPreview(entityId, ctx)\n },\n },\n]\n\nexport default messageObjectTypes\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/jest.config.cjs CHANGED
@@ -9,6 +9,7 @@ module.exports = {
9
9
  '^#generated/(.*)$': '<rootDir>/generated/$1',
10
10
  '^@open-mercato/core/generated/(.*)$': '<rootDir>/generated/$1',
11
11
  '^@open-mercato/core/(.*)$': '<rootDir>/src/$1',
12
+ '^@/\\.mercato/generated/inbox-actions\\.generated$': '<rootDir>/jest.mocks/inbox-actions.generated.js',
12
13
  '^react-markdown$': '<rootDir>/jest.mocks/react-markdown.js',
13
14
  '^remark-gfm$': '<rootDir>/jest.mocks/remark-gfm.js',
14
15
  },
@@ -0,0 +1,5 @@
1
+ module.exports = {
2
+ inboxActions: [],
3
+ getInboxAction: () => undefined,
4
+ getRegisteredActionTypes: () => [],
5
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/core",
3
- "version": "0.4.5-develop-636d33c995",
3
+ "version": "0.4.5-develop-3d8e759e45",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "scripts": {
@@ -207,7 +207,7 @@
207
207
  }
208
208
  },
209
209
  "dependencies": {
210
- "@open-mercato/shared": "0.4.5-develop-636d33c995",
210
+ "@open-mercato/shared": "0.4.5-develop-3d8e759e45",
211
211
  "@types/html-to-text": "^9.0.4",
212
212
  "@types/semver": "^7.5.8",
213
213
  "@xyflow/react": "^12.6.0",
@@ -11,6 +11,7 @@ import { useT } from '@open-mercato/shared/lib/i18n/context'
11
11
  import { E } from '#generated/entities.ids.generated'
12
12
  import { CategorySelect } from '../../../../../components/categories/CategorySelect'
13
13
  import { CategorySlugFieldSync } from '../../../../../components/categories/CategorySlugFieldSync'
14
+ import { SendObjectMessageDialog } from '@open-mercato/ui/backend/messages'
14
15
 
15
16
  type CategoryRow = {
16
17
  id: string
@@ -214,11 +215,24 @@ export default function EditCatalogCategoryPage({ params }: { params?: { id?: st
214
215
  submitLabel={t('catalog.categories.form.action.save', 'Save')}
215
216
  cancelHref="/backend/catalog/categories"
216
217
  successRedirect={`/backend/catalog/categories?flash=${encodeURIComponent(t('catalog.categories.flash.updated', 'Category updated'))}&type=success`}
217
- extraActions={pathLabel ? (
218
- <span className="text-xs text-muted-foreground">
219
- {t('catalog.categories.form.pathLabel', { path: pathLabel })}
220
- </span>
221
- ) : null}
218
+ extraActions={(
219
+ <>
220
+ <SendObjectMessageDialog
221
+ object={{
222
+ entityModule: 'catalog',
223
+ entityType: 'category',
224
+ entityId: categoryId,
225
+ previewData: { title: initialValues?.name ?? categoryId },
226
+ }}
227
+ viewHref={`/backend/catalog/categories/${categoryId}/edit`}
228
+ />
229
+ {pathLabel ? (
230
+ <span className="text-xs text-muted-foreground">
231
+ {t('catalog.categories.form.pathLabel', { path: pathLabel })}
232
+ </span>
233
+ ) : null}
234
+ </>
235
+ )}
222
236
  onSubmit={async (values) => {
223
237
  await submitCategoryUpdate(categoryId, values, t)
224
238
  }}
@@ -106,6 +106,7 @@ import {
106
106
  DialogHeader,
107
107
  DialogTitle,
108
108
  } from "@open-mercato/ui/primitives/dialog";
109
+ import { SendObjectMessageDialog } from "@open-mercato/ui/backend/messages/SendObjectMessageDialog.tsx";
109
110
 
110
111
  const MarkdownEditor = dynamic(() => import("@uiw/react-md-editor"), {
111
112
  ssr: false,
@@ -1204,6 +1205,19 @@ export default function EditCatalogProductPage({
1204
1205
  resourceKind: "catalog.product",
1205
1206
  resourceId: productId ? String(productId) : "",
1206
1207
  }}
1208
+ extraActions={productId ? (
1209
+ <SendObjectMessageDialog
1210
+ object={{
1211
+ entityModule: "catalog",
1212
+ entityType: "product",
1213
+ entityId: productId,
1214
+ previewData: {
1215
+ title: initialValues?.title ?? productId,
1216
+ }
1217
+ }}
1218
+ viewHref={`/backend/catalog/products/${productId}/edit`}
1219
+ />
1220
+ ) : undefined}
1207
1221
  fields={[]}
1208
1222
  groups={groups}
1209
1223
  injectionSpotId="crud-form:catalog.product"
@@ -11,6 +11,7 @@ import { apiCall, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/ap
11
11
  import { flash } from '@open-mercato/ui/backend/FlashMessages'
12
12
  import { useT } from '@open-mercato/shared/lib/i18n/context'
13
13
  import { E } from '#generated/entities.ids.generated'
14
+ import { SendObjectMessageDialog } from '@open-mercato/ui/backend/messages'
14
15
  import {
15
16
  type VariantFormValues,
16
17
  type VariantPriceDraft,
@@ -61,6 +62,21 @@ type AttachmentListResponse = {
61
62
  items?: ProductMediaItem[]
62
63
  }
63
64
 
65
+ function resolveVariantPriceLabel(prices: Record<string, VariantPriceDraft> | undefined): string | null {
66
+ if (!prices || typeof prices !== 'object') return null
67
+ const entries = Object.values(prices)
68
+ for (const entry of entries) {
69
+ const amount = typeof entry?.amount === 'string' ? entry.amount.trim() : ''
70
+ if (!amount) continue
71
+ const currencyCode =
72
+ typeof entry.currencyCode === 'string' && entry.currencyCode.trim().length
73
+ ? entry.currencyCode.trim().toUpperCase()
74
+ : null
75
+ return currencyCode ? `${currencyCode} ${amount}` : amount
76
+ }
77
+ return null
78
+ }
79
+
64
80
  export default function EditVariantPage({ params }: { params?: { productId?: string; variantId?: string } }) {
65
81
  const router = useRouter()
66
82
  const t = useT()
@@ -407,6 +423,30 @@ export default function EditVariantPage({ params }: { params?: { productId?: str
407
423
  title={formTitle}
408
424
  backHref={productVariantsHref}
409
425
  versionHistory={{ resourceKind: 'catalog.variant', resourceId: variantId ? String(variantId) : '' }}
426
+ extraActions={(
427
+ <SendObjectMessageDialog
428
+ object={{
429
+ entityModule: 'catalog',
430
+ entityType: 'variant',
431
+ entityId: variantId,
432
+ previewData: {
433
+ title:
434
+ (typeof initialValues?.name === 'string' && initialValues.name.trim().length
435
+ ? initialValues.name
436
+ : variantId),
437
+ metadata: {
438
+ [t('catalog.variants.form.skuLabel')]:
439
+ (typeof initialValues?.sku === 'string' && initialValues.sku.trim().length
440
+ ? initialValues.sku
441
+ : '-'),
442
+ [t('catalog.variants.form.pricesLabel')]:
443
+ resolveVariantPriceLabel(initialValues?.prices) ?? '-',
444
+ },
445
+ },
446
+ }}
447
+ viewHref={`/backend/catalog/products/${currentProductId}/variants/${variantId}`}
448
+ />
449
+ )}
410
450
  fields={[]}
411
451
  groups={groups}
412
452
  entityId={E.catalog.catalog_product_variant}
@@ -0,0 +1,60 @@
1
+ import type { InboxActionDefinition, InboxActionExecutionContext } from '@open-mercato/shared/modules/inbox-actions'
2
+ import { createProductPayloadSchema } from '../inbox_ops/data/validators'
3
+ import type { CreateProductPayload } from '../inbox_ops/data/validators'
4
+ import {
5
+ asHelperContext,
6
+ ExecutionError,
7
+ executeCommand,
8
+ resolveProductDiscrepanciesInProposal,
9
+ } from '../inbox_ops/lib/executionHelpers'
10
+
11
+ async function executeCreateProductAction(
12
+ action: { id: string; proposalId: string; payload: unknown },
13
+ ctx: InboxActionExecutionContext,
14
+ ): Promise<{ createdEntityId?: string | null; createdEntityType?: string | null }> {
15
+ const hCtx = asHelperContext(ctx)
16
+ const payload = action.payload as CreateProductPayload
17
+
18
+ const createInput: Record<string, unknown> = {
19
+ organizationId: hCtx.organizationId,
20
+ tenantId: hCtx.tenantId,
21
+ title: payload.title,
22
+ productType: 'simple',
23
+ isActive: true,
24
+ }
25
+
26
+ if (payload.sku) createInput.sku = payload.sku
27
+ if (payload.description) createInput.description = payload.description
28
+ if (payload.currencyCode) createInput.primaryCurrencyCode = payload.currencyCode
29
+
30
+ const result = await executeCommand<Record<string, unknown>, { productId?: string }>(
31
+ hCtx,
32
+ 'catalog.products.create',
33
+ createInput,
34
+ )
35
+
36
+ if (!result.productId) {
37
+ throw new ExecutionError('Product creation did not return a product ID', 500)
38
+ }
39
+
40
+ await resolveProductDiscrepanciesInProposal(hCtx.em, action.proposalId, payload.title, result.productId, {
41
+ tenantId: hCtx.tenantId,
42
+ organizationId: hCtx.organizationId,
43
+ })
44
+
45
+ return { createdEntityId: result.productId, createdEntityType: 'catalog_product' }
46
+ }
47
+
48
+ export const inboxActions: InboxActionDefinition[] = [
49
+ {
50
+ type: 'create_product',
51
+ requiredFeature: 'catalog.products.manage',
52
+ payloadSchema: createProductPayloadSchema,
53
+ label: 'Create Product',
54
+ promptSchema: `create_product payload:
55
+ { title: string, sku?: string, unitPrice?: string, currencyCode?: string (3-letter ISO), kind?: "product"|"service", description?: string }`,
56
+ execute: executeCreateProductAction,
57
+ },
58
+ ]
59
+
60
+ export default inboxActions