@open-mercato/core 0.5.1-develop.2638.59e6e26f46 → 0.5.1-develop.2657.a01847a9fa

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 (58) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/AGENTS.md +26 -0
  3. package/dist/modules/auth/lib/backendChrome.js +3 -1
  4. package/dist/modules/auth/lib/backendChrome.js.map +2 -2
  5. package/dist/modules/auth/services/rbacService.js +8 -2
  6. package/dist/modules/auth/services/rbacService.js.map +2 -2
  7. package/dist/modules/customer_accounts/api/password/reset-confirm.js +7 -0
  8. package/dist/modules/customer_accounts/api/password/reset-confirm.js.map +2 -2
  9. package/dist/modules/customer_accounts/api/portal/nav.js +77 -0
  10. package/dist/modules/customer_accounts/api/portal/nav.js.map +7 -0
  11. package/dist/modules/customer_accounts/api/signup.js +20 -8
  12. package/dist/modules/customer_accounts/api/signup.js.map +2 -2
  13. package/dist/modules/customer_accounts/services/customerSessionService.js +32 -0
  14. package/dist/modules/customer_accounts/services/customerSessionService.js.map +2 -2
  15. package/dist/modules/directory/api/organizations/route.js +10 -0
  16. package/dist/modules/directory/api/organizations/route.js.map +3 -3
  17. package/dist/modules/directory/backend/directory/organizations/[id]/edit/page.js +13 -2
  18. package/dist/modules/directory/backend/directory/organizations/[id]/edit/page.js.map +2 -2
  19. package/dist/modules/directory/backend/directory/organizations/create/page.js +12 -2
  20. package/dist/modules/directory/backend/directory/organizations/create/page.js.map +2 -2
  21. package/dist/modules/messages/components/message-detail/hooks/useMessageDetails.js +4 -3
  22. package/dist/modules/messages/components/message-detail/hooks/useMessageDetails.js.map +2 -2
  23. package/dist/modules/portal/frontend/[orgSlug]/portal/dashboard/page.meta.js +17 -0
  24. package/dist/modules/portal/frontend/[orgSlug]/portal/dashboard/page.meta.js.map +7 -0
  25. package/dist/modules/portal/frontend/[orgSlug]/portal/login/page.meta.js +11 -0
  26. package/dist/modules/portal/frontend/[orgSlug]/portal/login/page.meta.js.map +7 -0
  27. package/dist/modules/portal/frontend/[orgSlug]/portal/page.meta.js +11 -0
  28. package/dist/modules/portal/frontend/[orgSlug]/portal/page.meta.js.map +7 -0
  29. package/dist/modules/portal/frontend/[orgSlug]/portal/profile/page.meta.js +17 -0
  30. package/dist/modules/portal/frontend/[orgSlug]/portal/profile/page.meta.js.map +7 -0
  31. package/dist/modules/portal/frontend/[orgSlug]/portal/signup/page.meta.js +11 -0
  32. package/dist/modules/portal/frontend/[orgSlug]/portal/signup/page.meta.js.map +7 -0
  33. package/dist/modules/portal/frontend/[orgSlug]/portal/verify/page.meta.js +11 -0
  34. package/dist/modules/portal/frontend/[orgSlug]/portal/verify/page.meta.js.map +7 -0
  35. package/dist/modules/workflows/lib/activity-executor.js +25 -16
  36. package/dist/modules/workflows/lib/activity-executor.js.map +2 -2
  37. package/package.json +3 -3
  38. package/src/modules/auth/lib/backendChrome.tsx +3 -1
  39. package/src/modules/auth/services/rbacService.ts +8 -2
  40. package/src/modules/customer_accounts/api/password/reset-confirm.ts +9 -0
  41. package/src/modules/customer_accounts/api/portal/nav.ts +87 -0
  42. package/src/modules/customer_accounts/api/signup.ts +23 -7
  43. package/src/modules/customer_accounts/services/customerSessionService.ts +39 -0
  44. package/src/modules/directory/api/organizations/route.ts +11 -0
  45. package/src/modules/directory/backend/directory/organizations/[id]/edit/page.tsx +17 -3
  46. package/src/modules/directory/backend/directory/organizations/create/page.tsx +15 -3
  47. package/src/modules/directory/i18n/de.json +2 -0
  48. package/src/modules/directory/i18n/en.json +2 -0
  49. package/src/modules/directory/i18n/es.json +2 -0
  50. package/src/modules/directory/i18n/pl.json +2 -0
  51. package/src/modules/messages/components/message-detail/hooks/useMessageDetails.ts +4 -3
  52. package/src/modules/portal/frontend/[orgSlug]/portal/dashboard/page.meta.ts +15 -0
  53. package/src/modules/portal/frontend/[orgSlug]/portal/login/page.meta.ts +9 -0
  54. package/src/modules/portal/frontend/[orgSlug]/portal/page.meta.ts +9 -0
  55. package/src/modules/portal/frontend/[orgSlug]/portal/profile/page.meta.ts +15 -0
  56. package/src/modules/portal/frontend/[orgSlug]/portal/signup/page.meta.ts +9 -0
  57. package/src/modules/portal/frontend/[orgSlug]/portal/verify/page.meta.ts +9 -0
  58. package/src/modules/workflows/lib/activity-executor.ts +52 -24
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../../src/modules/directory/backend/directory/organizations/create/page.tsx"],
4
- "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { E } from '#generated/entities.ids.generated'\nimport { OrganizationSelect } from '@open-mercato/core/modules/directory/components/OrganizationSelect'\nimport { TenantSelect } from '@open-mercato/core/modules/directory/components/TenantSelect'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { CrudForm, type CrudField, type CrudFormGroup } from '@open-mercato/ui/backend/CrudForm'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { collectCustomFieldValues } from '@open-mercato/ui/backend/utils/customFieldValues'\nimport { createCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { createCrudFormError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { type OrganizationTreeNode } from '@open-mercato/core/modules/directory/lib/tree'\n\ntype TreeResponse = {\n items: OrganizationTreeNode[]\n}\n\ntype ChildTreeSelectProps = {\n nodes: OrganizationTreeNode[]\n value: string[]\n onChange: (vals: string[]) => void\n}\n\nfunction ChildTreeSelect({ nodes, value, onChange }: ChildTreeSelectProps) {\n const t = useT()\n const selected = React.useMemo(() => new Set(value), [value])\n const handleToggle = React.useCallback((id: string) => {\n const next = new Set(value)\n if (next.has(id)) next.delete(id)\n else next.add(id)\n onChange(Array.from(next))\n }, [value, onChange])\n\n if (!nodes.length) {\n return (\n <div className=\"text-sm text-muted-foreground\">\n {t('directory.organizations.form.children.empty', 'No organizations available to assign.')}\n </div>\n )\n }\n\n return (\n <div className=\"rounded border px-3 py-2 max-h-64 overflow-auto space-y-2\">\n <TreeCheckboxGroup nodes={nodes} selected={selected} onToggle={handleToggle} level={0} />\n </div>\n )\n}\n\nfunction TreeCheckboxGroup({ nodes, selected, onToggle, level }: { nodes: OrganizationTreeNode[]; selected: Set<string>; onToggle: (id: string) => void; level: number }) {\n return (\n <div className={level === 0 ? 'space-y-1' : 'space-y-1 pl-5'}>\n {nodes.map((node) => (\n <div key={node.id} className=\"space-y-1\">\n <label className=\"inline-flex items-start gap-2 text-sm\">\n <input\n type=\"checkbox\"\n className=\"size-4 mt-0.5\"\n checked={selected.has(node.id)}\n onChange={() => onToggle(node.id)}\n />\n <span>{node.name}</span>\n </label>\n {node.children?.length ? (\n <TreeCheckboxGroup nodes={node.children} selected={selected} onToggle={onToggle} level={level + 1} />\n ) : null}\n </div>\n ))}\n </div>\n )\n}\n\nexport default function CreateOrganizationPage() {\n const [tree, setTree] = React.useState<OrganizationTreeNode[]>([])\n const [actorIsSuperAdmin, setActorIsSuperAdmin] = React.useState(false)\n const [selectedTenantId, setSelectedTenantId] = React.useState<string | null>(null)\n const t = useT()\n\n const loadTree = React.useCallback(async (tenantId: string | null) => {\n const params = new URLSearchParams({ view: 'tree', includeInactive: 'true' })\n if (tenantId) params.set('tenantId', tenantId)\n try {\n const call = await apiCall<TreeResponse>(`/api/directory/organizations?${params.toString()}`)\n const items = Array.isArray(call.result?.items) ? call.result.items : []\n setTree(items)\n } catch {\n setTree([])\n }\n }, [])\n\n React.useEffect(() => {\n let cancelled = false\n async function bootstrap() {\n try {\n const call = await apiCall<{ isSuperAdmin?: boolean }>('/api/auth/roles?page=1&pageSize=1')\n if (!cancelled) setActorIsSuperAdmin(Boolean(call.result?.isSuperAdmin))\n } catch {\n if (!cancelled) setActorIsSuperAdmin(false)\n }\n if (!cancelled) await loadTree(null)\n }\n bootstrap()\n return () => { cancelled = true }\n }, [loadTree])\n\n React.useEffect(() => {\n if (!actorIsSuperAdmin) return\n void loadTree(selectedTenantId)\n }, [actorIsSuperAdmin, loadTree, selectedTenantId])\n\n const fields = React.useMemo<CrudField[]>(() => [\n ...(actorIsSuperAdmin ? [\n {\n id: 'tenantId',\n label: t('directory.organizations.form.field.tenant', 'Tenant'),\n type: 'custom',\n required: true,\n component: ({ value, setValue }) => (\n <TenantSelect\n id=\"tenantId\"\n value={typeof value === 'string' ? value : selectedTenantId}\n onChange={(next) => {\n const normalized = next ?? null\n setSelectedTenantId(normalized)\n setValue(normalized)\n }}\n includeEmptyOption\n emptyOptionLabel={t('directory.organizations.form.tenant.select', 'Select tenant')}\n className=\"w-full h-9 rounded border px-2 text-sm\"\n />\n ),\n } as CrudField,\n ] : []),\n { id: 'name', label: t('directory.organizations.form.field.name', 'Name'), type: 'text', required: true },\n {\n id: 'parentId',\n label: t('directory.organizations.form.field.parent', 'Parent'),\n type: 'custom',\n component: ({ id, value, setValue }) => (\n <OrganizationSelect\n id={id}\n value={value ? String(value) : null}\n onChange={(next) => setValue(next ?? '')}\n tenantId={selectedTenantId}\n fetchOnMount={true}\n includeEmptyOption\n emptyOptionLabel={t('directory.organizations.form.rootOption', '\u2014 Root level \u2014')}\n className=\"w-full h-9 rounded border px-2 text-sm\"\n />\n ),\n },\n {\n id: 'childIds',\n label: t('directory.organizations.form.field.children', 'Children'),\n type: 'custom',\n component: ({ value, setValue }) => (\n <ChildTreeSelect\n nodes={tree}\n value={Array.isArray(value) ? value : []}\n onChange={(vals) => setValue(vals)}\n />\n ),\n },\n { id: 'isActive', label: t('directory.organizations.form.field.isActive', 'Active'), type: 'checkbox' },\n ], [actorIsSuperAdmin, selectedTenantId, t, tree])\n\n const detailFields = React.useMemo(() => (\n actorIsSuperAdmin\n ? ['tenantId', 'name', 'parentId', 'childIds', 'isActive']\n : ['name', 'parentId', 'childIds', 'isActive']\n ), [actorIsSuperAdmin])\n\n const groups: CrudFormGroup[] = React.useMemo(() => ([\n { id: 'details', title: t('directory.organizations.form.group.details', 'Details'), column: 1, fields: detailFields },\n { id: 'custom', title: t('directory.organizations.form.group.customFields', 'Custom Data'), column: 2, kind: 'customFields' },\n ]), [detailFields, t])\n const formTitle = t('directory.nav.organizations.create', 'Create Organization')\n const successMessage = encodeURIComponent(t('directory.organizations.flash.created', 'Organization created'))\n\n return (\n <Page>\n <PageBody>\n <CrudForm\n title={formTitle}\n backHref=\"/backend/directory/organizations\"\n fields={fields}\n groups={groups}\n entityId={E.directory.organization}\n initialValues={{ tenantId: selectedTenantId ?? null, name: '', parentId: '', childIds: [], isActive: true }}\n submitLabel={t('directory.organizations.form.action.create', 'Create')}\n cancelHref=\"/backend/directory/organizations\"\n successRedirect={`/backend/directory/organizations?flash=${successMessage}&type=success`}\n onSubmit={async (values) => {\n await submitCreateOrganization({\n values: values as Record<string, unknown>,\n actorIsSuperAdmin,\n selectedTenantId,\n messages: {\n tenantRequired: t('directory.organizations.errors.tenantRequired', 'Tenant selection is required for super administrators'),\n },\n })\n }}\n />\n </PageBody>\n </Page>\n )\n}\n\ntype CreateOrganizationPayload = {\n name: string\n isActive: boolean\n parentId: string | null\n childIds: string[]\n tenantId?: string\n customFields?: Record<string, unknown>\n}\n\ntype CreateOrganizationRequest = (payload: CreateOrganizationPayload) => Promise<void>\n\nasync function defaultCreateOrganizationRequest(payload: CreateOrganizationPayload) {\n await createCrud('directory/organizations', payload)\n}\n\nexport async function submitCreateOrganization(options: {\n values: Record<string, unknown>\n actorIsSuperAdmin: boolean\n selectedTenantId: string | null\n createOrganization?: CreateOrganizationRequest\n messages?: {\n tenantRequired?: string\n }\n}): Promise<void> {\n const {\n values,\n actorIsSuperAdmin,\n selectedTenantId,\n createOrganization = defaultCreateOrganizationRequest,\n messages,\n } = options\n\n const customFields = collectCustomFieldValues(values)\n\n const tenantValue =\n typeof values.tenantId === 'string' && values.tenantId.trim().length\n ? values.tenantId.trim()\n : selectedTenantId\n\n if (actorIsSuperAdmin && !tenantValue) {\n const message = messages?.tenantRequired ?? 'Tenant selection is required for super administrators'\n throw createCrudFormError(message, {\n tenantId: message,\n })\n }\n\n const payload: CreateOrganizationPayload = {\n name: typeof values.name === 'string' ? values.name : '',\n isActive: values.isActive !== false,\n parentId: typeof values.parentId === 'string' && values.parentId.length\n ? values.parentId\n : null,\n childIds: Array.isArray(values.childIds) ? values.childIds.filter((id): id is string => typeof id === 'string') : [],\n }\n\n if (tenantValue) payload.tenantId = tenantValue\n if (Object.keys(customFields).length > 0) payload.customFields = customFields\n\n await createOrganization(payload)\n}\n"],
5
- "mappings": ";AAoCM,cAkBI,YAlBJ;AAnCN,YAAY,WAAW;AACvB,SAAS,YAAY;AACrB,SAAS,SAAS;AAClB,SAAS,0BAA0B;AACnC,SAAS,oBAAoB;AAC7B,SAAS,MAAM,gBAAgB;AAC/B,SAAS,gBAAoD;AAC7D,SAAS,eAAe;AACxB,SAAS,gCAAgC;AACzC,SAAS,kBAAkB;AAC3B,SAAS,2BAA2B;AAapC,SAAS,gBAAgB,EAAE,OAAO,OAAO,SAAS,GAAyB;AACzE,QAAM,IAAI,KAAK;AACf,QAAM,WAAW,MAAM,QAAQ,MAAM,IAAI,IAAI,KAAK,GAAG,CAAC,KAAK,CAAC;AAC5D,QAAM,eAAe,MAAM,YAAY,CAAC,OAAe;AACrD,UAAM,OAAO,IAAI,IAAI,KAAK;AAC1B,QAAI,KAAK,IAAI,EAAE,EAAG,MAAK,OAAO,EAAE;AAAA,QAC3B,MAAK,IAAI,EAAE;AAChB,aAAS,MAAM,KAAK,IAAI,CAAC;AAAA,EAC3B,GAAG,CAAC,OAAO,QAAQ,CAAC;AAEpB,MAAI,CAAC,MAAM,QAAQ;AACjB,WACE,oBAAC,SAAI,WAAU,iCACZ,YAAE,+CAA+C,uCAAuC,GAC3F;AAAA,EAEJ;AAEA,SACE,oBAAC,SAAI,WAAU,6DACb,8BAAC,qBAAkB,OAAc,UAAoB,UAAU,cAAc,OAAO,GAAG,GACzF;AAEJ;AAEA,SAAS,kBAAkB,EAAE,OAAO,UAAU,UAAU,MAAM,GAA4G;AACxK,SACE,oBAAC,SAAI,WAAW,UAAU,IAAI,cAAc,kBACzC,gBAAM,IAAI,CAAC,SACV,qBAAC,SAAkB,WAAU,aAC3B;AAAA,yBAAC,WAAM,WAAU,yCACf;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,WAAU;AAAA,UACV,SAAS,SAAS,IAAI,KAAK,EAAE;AAAA,UAC7B,UAAU,MAAM,SAAS,KAAK,EAAE;AAAA;AAAA,MAClC;AAAA,MACA,oBAAC,UAAM,eAAK,MAAK;AAAA,OACnB;AAAA,IACC,KAAK,UAAU,SACd,oBAAC,qBAAkB,OAAO,KAAK,UAAU,UAAoB,UAAoB,OAAO,QAAQ,GAAG,IACjG;AAAA,OAZI,KAAK,EAaf,CACD,GACH;AAEJ;AAEe,SAAR,yBAA0C;AAC/C,QAAM,CAAC,MAAM,OAAO,IAAI,MAAM,SAAiC,CAAC,CAAC;AACjE,QAAM,CAAC,mBAAmB,oBAAoB,IAAI,MAAM,SAAS,KAAK;AACtE,QAAM,CAAC,kBAAkB,mBAAmB,IAAI,MAAM,SAAwB,IAAI;AAClF,QAAM,IAAI,KAAK;AAEf,QAAM,WAAW,MAAM,YAAY,OAAO,aAA4B;AACpE,UAAM,SAAS,IAAI,gBAAgB,EAAE,MAAM,QAAQ,iBAAiB,OAAO,CAAC;AAC5E,QAAI,SAAU,QAAO,IAAI,YAAY,QAAQ;AAC7C,QAAI;AACF,YAAM,OAAO,MAAM,QAAsB,gCAAgC,OAAO,SAAS,CAAC,EAAE;AAC5F,YAAM,QAAQ,MAAM,QAAQ,KAAK,QAAQ,KAAK,IAAI,KAAK,OAAO,QAAQ,CAAC;AACvE,cAAQ,KAAK;AAAA,IACf,QAAQ;AACN,cAAQ,CAAC,CAAC;AAAA,IACZ;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,UAAU,MAAM;AACpB,QAAI,YAAY;AAChB,mBAAe,YAAY;AACzB,UAAI;AACF,cAAM,OAAO,MAAM,QAAoC,mCAAmC;AAC1F,YAAI,CAAC,UAAW,sBAAqB,QAAQ,KAAK,QAAQ,YAAY,CAAC;AAAA,MACzE,QAAQ;AACN,YAAI,CAAC,UAAW,sBAAqB,KAAK;AAAA,MAC5C;AACA,UAAI,CAAC,UAAW,OAAM,SAAS,IAAI;AAAA,IACrC;AACA,cAAU;AACV,WAAO,MAAM;AAAE,kBAAY;AAAA,IAAK;AAAA,EAClC,GAAG,CAAC,QAAQ,CAAC;AAEb,QAAM,UAAU,MAAM;AACpB,QAAI,CAAC,kBAAmB;AACxB,SAAK,SAAS,gBAAgB;AAAA,EAChC,GAAG,CAAC,mBAAmB,UAAU,gBAAgB,CAAC;AAElD,QAAM,SAAS,MAAM,QAAqB,MAAM;AAAA,IAC9C,GAAI,oBAAoB;AAAA,MACtB;AAAA,QACE,IAAI;AAAA,QACJ,OAAO,EAAE,6CAA6C,QAAQ;AAAA,QAC9D,MAAM;AAAA,QACN,UAAU;AAAA,QACV,WAAW,CAAC,EAAE,OAAO,SAAS,MAC5B;AAAA,UAAC;AAAA;AAAA,YACC,IAAG;AAAA,YACH,OAAO,OAAO,UAAU,WAAW,QAAQ;AAAA,YAC3C,UAAU,CAAC,SAAS;AAClB,oBAAM,aAAa,QAAQ;AAC3B,kCAAoB,UAAU;AAC9B,uBAAS,UAAU;AAAA,YACrB;AAAA,YACA,oBAAkB;AAAA,YAClB,kBAAkB,EAAE,8CAA8C,eAAe;AAAA,YACjF,WAAU;AAAA;AAAA,QACZ;AAAA,MAEJ;AAAA,IACF,IAAI,CAAC;AAAA,IACL,EAAE,IAAI,QAAQ,OAAO,EAAE,2CAA2C,MAAM,GAAG,MAAM,QAAQ,UAAU,KAAK;AAAA,IACxG;AAAA,MACE,IAAI;AAAA,MACJ,OAAO,EAAE,6CAA6C,QAAQ;AAAA,MAC9D,MAAM;AAAA,MACN,WAAW,CAAC,EAAE,IAAI,OAAO,SAAS,MAChC;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA,OAAO,QAAQ,OAAO,KAAK,IAAI;AAAA,UAC/B,UAAU,CAAC,SAAS,SAAS,QAAQ,EAAE;AAAA,UACvC,UAAU;AAAA,UACV,cAAc;AAAA,UACd,oBAAkB;AAAA,UAClB,kBAAkB,EAAE,2CAA2C,0BAAgB;AAAA,UAC/E,WAAU;AAAA;AAAA,MACZ;AAAA,IAEJ;AAAA,IACA;AAAA,MACE,IAAI;AAAA,MACJ,OAAO,EAAE,+CAA+C,UAAU;AAAA,MAClE,MAAM;AAAA,MACN,WAAW,CAAC,EAAE,OAAO,SAAS,MAC5B;AAAA,QAAC;AAAA;AAAA,UACC,OAAO;AAAA,UACP,OAAO,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC;AAAA,UACvC,UAAU,CAAC,SAAS,SAAS,IAAI;AAAA;AAAA,MACnC;AAAA,IAEJ;AAAA,IACA,EAAE,IAAI,YAAY,OAAO,EAAE,+CAA+C,QAAQ,GAAG,MAAM,WAAW;AAAA,EACxG,GAAG,CAAC,mBAAmB,kBAAkB,GAAG,IAAI,CAAC;AAEjD,QAAM,eAAe,MAAM,QAAQ,MACjC,oBACI,CAAC,YAAY,QAAQ,YAAY,YAAY,UAAU,IACvD,CAAC,QAAQ,YAAY,YAAY,UAAU,GAC9C,CAAC,iBAAiB,CAAC;AAEtB,QAAM,SAA0B,MAAM,QAAQ,MAAO;AAAA,IACnD,EAAE,IAAI,WAAW,OAAO,EAAE,8CAA8C,SAAS,GAAG,QAAQ,GAAG,QAAQ,aAAa;AAAA,IACpH,EAAE,IAAI,UAAU,OAAO,EAAE,mDAAmD,aAAa,GAAG,QAAQ,GAAG,MAAM,eAAe;AAAA,EAC9H,GAAI,CAAC,cAAc,CAAC,CAAC;AACrB,QAAM,YAAY,EAAE,sCAAsC,qBAAqB;AAC/E,QAAM,iBAAiB,mBAAmB,EAAE,yCAAyC,sBAAsB,CAAC;AAE5G,SACE,oBAAC,QACC,8BAAC,YACC;AAAA,IAAC;AAAA;AAAA,MACC,OAAO;AAAA,MACP,UAAS;AAAA,MACT;AAAA,MACA;AAAA,MACA,UAAU,EAAE,UAAU;AAAA,MACtB,eAAe,EAAE,UAAU,oBAAoB,MAAM,MAAM,IAAI,UAAU,IAAI,UAAU,CAAC,GAAG,UAAU,KAAK;AAAA,MAC1G,aAAa,EAAE,8CAA8C,QAAQ;AAAA,MACrE,YAAW;AAAA,MACX,iBAAiB,0CAA0C,cAAc;AAAA,MACzE,UAAU,OAAO,WAAW;AAC1B,cAAM,yBAAyB;AAAA,UAC7B;AAAA,UACA;AAAA,UACA;AAAA,UACA,UAAU;AAAA,YACR,gBAAgB,EAAE,iDAAiD,uDAAuD;AAAA,UAC5H;AAAA,QACF,CAAC;AAAA,MACH;AAAA;AAAA,EACF,GACF,GACF;AAEJ;AAaA,eAAe,iCAAiC,SAAoC;AAClF,QAAM,WAAW,2BAA2B,OAAO;AACrD;AAEA,eAAsB,yBAAyB,SAQ7B;AAChB,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA,qBAAqB;AAAA,IACrB;AAAA,EACF,IAAI;AAEJ,QAAM,eAAe,yBAAyB,MAAM;AAEpD,QAAM,cACJ,OAAO,OAAO,aAAa,YAAY,OAAO,SAAS,KAAK,EAAE,SAC1D,OAAO,SAAS,KAAK,IACrB;AAEN,MAAI,qBAAqB,CAAC,aAAa;AACrC,UAAM,UAAU,UAAU,kBAAkB;AAC5C,UAAM,oBAAoB,SAAS;AAAA,MACjC,UAAU;AAAA,IACZ,CAAC;AAAA,EACH;AAEA,QAAM,UAAqC;AAAA,IACzC,MAAM,OAAO,OAAO,SAAS,WAAW,OAAO,OAAO;AAAA,IACtD,UAAU,OAAO,aAAa;AAAA,IAC9B,UAAU,OAAO,OAAO,aAAa,YAAY,OAAO,SAAS,SAC7D,OAAO,WACP;AAAA,IACJ,UAAU,MAAM,QAAQ,OAAO,QAAQ,IAAI,OAAO,SAAS,OAAO,CAAC,OAAqB,OAAO,OAAO,QAAQ,IAAI,CAAC;AAAA,EACrH;AAEA,MAAI,YAAa,SAAQ,WAAW;AACpC,MAAI,OAAO,KAAK,YAAY,EAAE,SAAS,EAAG,SAAQ,eAAe;AAEjE,QAAM,mBAAmB,OAAO;AAClC;",
4
+ "sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { E } from '#generated/entities.ids.generated'\nimport { OrganizationSelect } from '@open-mercato/core/modules/directory/components/OrganizationSelect'\nimport { TenantSelect } from '@open-mercato/core/modules/directory/components/TenantSelect'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { CrudForm, type CrudField, type CrudFormGroup } from '@open-mercato/ui/backend/CrudForm'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { collectCustomFieldValues } from '@open-mercato/ui/backend/utils/customFieldValues'\nimport { createCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { createCrudFormError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { type OrganizationTreeNode } from '@open-mercato/core/modules/directory/lib/tree'\n\ntype TreeResponse = {\n items: OrganizationTreeNode[]\n}\n\ntype ChildTreeSelectProps = {\n nodes: OrganizationTreeNode[]\n value: string[]\n onChange: (vals: string[]) => void\n}\n\nfunction ChildTreeSelect({ nodes, value, onChange }: ChildTreeSelectProps) {\n const t = useT()\n const selected = React.useMemo(() => new Set(value), [value])\n const handleToggle = React.useCallback((id: string) => {\n const next = new Set(value)\n if (next.has(id)) next.delete(id)\n else next.add(id)\n onChange(Array.from(next))\n }, [value, onChange])\n\n if (!nodes.length) {\n return (\n <div className=\"text-sm text-muted-foreground\">\n {t('directory.organizations.form.children.empty', 'No organizations available to assign.')}\n </div>\n )\n }\n\n return (\n <div className=\"rounded border px-3 py-2 max-h-64 overflow-auto space-y-2\">\n <TreeCheckboxGroup nodes={nodes} selected={selected} onToggle={handleToggle} level={0} />\n </div>\n )\n}\n\nfunction TreeCheckboxGroup({ nodes, selected, onToggle, level }: { nodes: OrganizationTreeNode[]; selected: Set<string>; onToggle: (id: string) => void; level: number }) {\n return (\n <div className={level === 0 ? 'space-y-1' : 'space-y-1 pl-5'}>\n {nodes.map((node) => (\n <div key={node.id} className=\"space-y-1\">\n <label className=\"inline-flex items-start gap-2 text-sm\">\n <input\n type=\"checkbox\"\n className=\"size-4 mt-0.5\"\n checked={selected.has(node.id)}\n onChange={() => onToggle(node.id)}\n />\n <span>{node.name}</span>\n </label>\n {node.children?.length ? (\n <TreeCheckboxGroup nodes={node.children} selected={selected} onToggle={onToggle} level={level + 1} />\n ) : null}\n </div>\n ))}\n </div>\n )\n}\n\nexport default function CreateOrganizationPage() {\n const [tree, setTree] = React.useState<OrganizationTreeNode[]>([])\n const [actorIsSuperAdmin, setActorIsSuperAdmin] = React.useState(false)\n const [selectedTenantId, setSelectedTenantId] = React.useState<string | null>(null)\n const t = useT()\n\n const loadTree = React.useCallback(async (tenantId: string | null) => {\n const params = new URLSearchParams({ view: 'tree', includeInactive: 'true' })\n if (tenantId) params.set('tenantId', tenantId)\n try {\n const call = await apiCall<TreeResponse>(`/api/directory/organizations?${params.toString()}`)\n const items = Array.isArray(call.result?.items) ? call.result.items : []\n setTree(items)\n } catch {\n setTree([])\n }\n }, [])\n\n React.useEffect(() => {\n let cancelled = false\n async function bootstrap() {\n try {\n const call = await apiCall<{ isSuperAdmin?: boolean }>('/api/auth/roles?page=1&pageSize=1')\n if (!cancelled) setActorIsSuperAdmin(Boolean(call.result?.isSuperAdmin))\n } catch {\n if (!cancelled) setActorIsSuperAdmin(false)\n }\n if (!cancelled) await loadTree(null)\n }\n bootstrap()\n return () => { cancelled = true }\n }, [loadTree])\n\n React.useEffect(() => {\n if (!actorIsSuperAdmin) return\n void loadTree(selectedTenantId)\n }, [actorIsSuperAdmin, loadTree, selectedTenantId])\n\n const fields = React.useMemo<CrudField[]>(() => [\n ...(actorIsSuperAdmin ? [\n {\n id: 'tenantId',\n label: t('directory.organizations.form.field.tenant', 'Tenant'),\n type: 'custom',\n required: true,\n component: ({ value, setValue }) => (\n <TenantSelect\n id=\"tenantId\"\n value={typeof value === 'string' ? value : selectedTenantId}\n onChange={(next) => {\n const normalized = next ?? null\n setSelectedTenantId(normalized)\n setValue(normalized)\n }}\n includeEmptyOption\n emptyOptionLabel={t('directory.organizations.form.tenant.select', 'Select tenant')}\n className=\"w-full h-9 rounded border px-2 text-sm\"\n />\n ),\n } as CrudField,\n ] : []),\n { id: 'name', label: t('directory.organizations.form.field.name', 'Name'), type: 'text', required: true },\n {\n id: 'slug',\n label: t('directory.organizations.form.field.slug', 'Slug'),\n type: 'text',\n description: t('directory.organizations.form.field.slug.description', 'URL-safe identifier used for the customer portal (lowercase letters, numbers, hyphens, underscores). Generated from the name when left blank.'),\n },\n {\n id: 'parentId',\n label: t('directory.organizations.form.field.parent', 'Parent'),\n type: 'custom',\n component: ({ id, value, setValue }) => (\n <OrganizationSelect\n id={id}\n value={value ? String(value) : null}\n onChange={(next) => setValue(next ?? '')}\n tenantId={selectedTenantId}\n fetchOnMount={true}\n includeEmptyOption\n emptyOptionLabel={t('directory.organizations.form.rootOption', '\u2014 Root level \u2014')}\n className=\"w-full h-9 rounded border px-2 text-sm\"\n />\n ),\n },\n {\n id: 'childIds',\n label: t('directory.organizations.form.field.children', 'Children'),\n type: 'custom',\n component: ({ value, setValue }) => (\n <ChildTreeSelect\n nodes={tree}\n value={Array.isArray(value) ? value : []}\n onChange={(vals) => setValue(vals)}\n />\n ),\n },\n { id: 'isActive', label: t('directory.organizations.form.field.isActive', 'Active'), type: 'checkbox' },\n ], [actorIsSuperAdmin, selectedTenantId, t, tree])\n\n const detailFields = React.useMemo(() => (\n actorIsSuperAdmin\n ? ['tenantId', 'name', 'slug', 'parentId', 'childIds', 'isActive']\n : ['name', 'slug', 'parentId', 'childIds', 'isActive']\n ), [actorIsSuperAdmin])\n\n const groups: CrudFormGroup[] = React.useMemo(() => ([\n { id: 'details', title: t('directory.organizations.form.group.details', 'Details'), column: 1, fields: detailFields },\n { id: 'custom', title: t('directory.organizations.form.group.customFields', 'Custom Data'), column: 2, kind: 'customFields' },\n ]), [detailFields, t])\n const formTitle = t('directory.nav.organizations.create', 'Create Organization')\n const successMessage = encodeURIComponent(t('directory.organizations.flash.created', 'Organization created'))\n\n return (\n <Page>\n <PageBody>\n <CrudForm\n title={formTitle}\n backHref=\"/backend/directory/organizations\"\n fields={fields}\n groups={groups}\n entityId={E.directory.organization}\n initialValues={{ tenantId: selectedTenantId ?? null, name: '', slug: '', parentId: '', childIds: [], isActive: true }}\n submitLabel={t('directory.organizations.form.action.create', 'Create')}\n cancelHref=\"/backend/directory/organizations\"\n successRedirect={`/backend/directory/organizations?flash=${successMessage}&type=success`}\n onSubmit={async (values) => {\n await submitCreateOrganization({\n values: values as Record<string, unknown>,\n actorIsSuperAdmin,\n selectedTenantId,\n messages: {\n tenantRequired: t('directory.organizations.errors.tenantRequired', 'Tenant selection is required for super administrators'),\n },\n })\n }}\n />\n </PageBody>\n </Page>\n )\n}\n\ntype CreateOrganizationPayload = {\n name: string\n slug?: string | null\n isActive: boolean\n parentId: string | null\n childIds: string[]\n tenantId?: string\n customFields?: Record<string, unknown>\n}\n\ntype CreateOrganizationRequest = (payload: CreateOrganizationPayload) => Promise<void>\n\nasync function defaultCreateOrganizationRequest(payload: CreateOrganizationPayload) {\n await createCrud('directory/organizations', payload)\n}\n\nexport async function submitCreateOrganization(options: {\n values: Record<string, unknown>\n actorIsSuperAdmin: boolean\n selectedTenantId: string | null\n createOrganization?: CreateOrganizationRequest\n messages?: {\n tenantRequired?: string\n }\n}): Promise<void> {\n const {\n values,\n actorIsSuperAdmin,\n selectedTenantId,\n createOrganization = defaultCreateOrganizationRequest,\n messages,\n } = options\n\n const customFields = collectCustomFieldValues(values)\n\n const tenantValue =\n typeof values.tenantId === 'string' && values.tenantId.trim().length\n ? values.tenantId.trim()\n : selectedTenantId\n\n if (actorIsSuperAdmin && !tenantValue) {\n const message = messages?.tenantRequired ?? 'Tenant selection is required for super administrators'\n throw createCrudFormError(message, {\n tenantId: message,\n })\n }\n\n const payload: CreateOrganizationPayload = {\n name: typeof values.name === 'string' ? values.name : '',\n isActive: values.isActive !== false,\n parentId: typeof values.parentId === 'string' && values.parentId.length\n ? values.parentId\n : null,\n childIds: Array.isArray(values.childIds) ? values.childIds.filter((id): id is string => typeof id === 'string') : [],\n }\n\n if (typeof values.slug === 'string') {\n const trimmedSlug = values.slug.trim()\n if (trimmedSlug.length) payload.slug = trimmedSlug\n }\n\n if (tenantValue) payload.tenantId = tenantValue\n if (Object.keys(customFields).length > 0) payload.customFields = customFields\n\n await createOrganization(payload)\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -19,8 +19,9 @@ function useMessageDetails(id) {
19
19
  scopeVersion,
20
20
  queryClient
21
21
  });
22
- const invalidateDetailQueries = React.useCallback(
22
+ const invalidateMessageQueries = React.useCallback(
23
23
  (payload) => {
24
+ void queryClient.invalidateQueries({ queryKey: ["messages", "list"] });
24
25
  void queryClient.invalidateQueries({ queryKey: ["messages", "detail", id] });
25
26
  const messageId = typeof payload.messageId === "string" ? payload.messageId : null;
26
27
  if (messageId && messageId !== id) {
@@ -32,9 +33,9 @@ function useMessageDetails(id) {
32
33
  useAppEvent(
33
34
  "messages.message.*",
34
35
  (evt) => {
35
- invalidateDetailQueries(evt.payload ?? {});
36
+ invalidateMessageQueries(evt.payload ?? {});
36
37
  },
37
- [invalidateDetailQueries]
38
+ [invalidateMessageQueries]
38
39
  );
39
40
  useAppEvent(
40
41
  "om:bridge:reconnected",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/messages/components/message-detail/hooks/useMessageDetails.ts"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { useRouter } from 'next/navigation'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useAppEvent } from '@open-mercato/ui/backend/injection/useAppEvent'\nimport { useMessageDetailsQueries } from './useMessageDetailsQueries'\nimport { useMessageDetailsActions } from './useMessageDetailsActions'\nimport { useMessageDetailsConversation } from './useMessageDetailsConversation'\n\nexport function useMessageDetails(id: string) {\n const t = useT()\n const router = useRouter()\n const scopeVersion = useOrganizationScopeVersion()\n const queryClient = useQueryClient()\n\n const queryState = useMessageDetailsQueries({\n id,\n t,\n scopeVersion,\n queryClient,\n })\n\n const invalidateDetailQueries = React.useCallback(\n (payload: Record<string, unknown>) => {\n void queryClient.invalidateQueries({ queryKey: ['messages', 'detail', id] })\n const messageId = typeof payload.messageId === 'string' ? payload.messageId : null\n if (messageId && messageId !== id) {\n void queryClient.invalidateQueries({ queryKey: ['messages', 'detail', messageId] })\n }\n },\n [id, queryClient],\n )\n\n useAppEvent(\n 'messages.message.*',\n (evt) => {\n invalidateDetailQueries((evt.payload ?? {}) as Record<string, unknown>)\n },\n [invalidateDetailQueries],\n )\n\n useAppEvent(\n 'om:bridge:reconnected',\n () => {\n void queryClient.invalidateQueries({ queryKey: ['messages', 'detail', id] })\n },\n [id, queryClient],\n )\n\n const isArchived = (queryState.detail?.recipients ?? []).some((item) => item.status === 'archived')\n\n const actionState = useMessageDetailsActions({\n id,\n t,\n detail: queryState.detail,\n detailQuery: queryState.detailQuery,\n attachments: queryState.attachments,\n isArchived,\n onDeleted: () => router.push('/backend/messages'),\n refreshDetailWithoutAutoMarkRead: queryState.refreshDetailWithoutAutoMarkRead,\n })\n\n const conversationState = useMessageDetailsConversation({\n detail: queryState.detail,\n t,\n })\n\n const backToList = React.useCallback(() => {\n router.push('/backend/messages')\n }, [router])\n\n return {\n t,\n router,\n backToList,\n ...queryState,\n ...conversationState,\n ...actionState,\n isArchived,\n }\n}\n"],
5
- "mappings": ";AAEA,YAAY,WAAW;AACvB,SAAS,iBAAiB;AAC1B,SAAS,sBAAsB;AAC/B,SAAS,YAAY;AACrB,SAAS,mCAAmC;AAC5C,SAAS,mBAAmB;AAC5B,SAAS,gCAAgC;AACzC,SAAS,gCAAgC;AACzC,SAAS,qCAAqC;AAEvC,SAAS,kBAAkB,IAAY;AAC5C,QAAM,IAAI,KAAK;AACf,QAAM,SAAS,UAAU;AACzB,QAAM,eAAe,4BAA4B;AACjD,QAAM,cAAc,eAAe;AAEnC,QAAM,aAAa,yBAAyB;AAAA,IAC1C;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,0BAA0B,MAAM;AAAA,IACpC,CAAC,YAAqC;AACpC,WAAK,YAAY,kBAAkB,EAAE,UAAU,CAAC,YAAY,UAAU,EAAE,EAAE,CAAC;AAC3E,YAAM,YAAY,OAAO,QAAQ,cAAc,WAAW,QAAQ,YAAY;AAC9E,UAAI,aAAa,cAAc,IAAI;AACjC,aAAK,YAAY,kBAAkB,EAAE,UAAU,CAAC,YAAY,UAAU,SAAS,EAAE,CAAC;AAAA,MACpF;AAAA,IACF;AAAA,IACA,CAAC,IAAI,WAAW;AAAA,EAClB;AAEA;AAAA,IACE;AAAA,IACA,CAAC,QAAQ;AACP,8BAAyB,IAAI,WAAW,CAAC,CAA6B;AAAA,IACxE;AAAA,IACA,CAAC,uBAAuB;AAAA,EAC1B;AAEA;AAAA,IACE;AAAA,IACA,MAAM;AACJ,WAAK,YAAY,kBAAkB,EAAE,UAAU,CAAC,YAAY,UAAU,EAAE,EAAE,CAAC;AAAA,IAC7E;AAAA,IACA,CAAC,IAAI,WAAW;AAAA,EAClB;AAEA,QAAM,cAAc,WAAW,QAAQ,cAAc,CAAC,GAAG,KAAK,CAAC,SAAS,KAAK,WAAW,UAAU;AAElG,QAAM,cAAc,yBAAyB;AAAA,IAC3C;AAAA,IACA;AAAA,IACA,QAAQ,WAAW;AAAA,IACnB,aAAa,WAAW;AAAA,IACxB,aAAa,WAAW;AAAA,IACxB;AAAA,IACA,WAAW,MAAM,OAAO,KAAK,mBAAmB;AAAA,IAChD,kCAAkC,WAAW;AAAA,EAC/C,CAAC;AAED,QAAM,oBAAoB,8BAA8B;AAAA,IACtD,QAAQ,WAAW;AAAA,IACnB;AAAA,EACF,CAAC;AAED,QAAM,aAAa,MAAM,YAAY,MAAM;AACzC,WAAO,KAAK,mBAAmB;AAAA,EACjC,GAAG,CAAC,MAAM,CAAC;AAEX,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,IACH,GAAG;AAAA,IACH,GAAG;AAAA,IACH;AAAA,EACF;AACF;",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { useRouter } from 'next/navigation'\nimport { useQueryClient } from '@tanstack/react-query'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useAppEvent } from '@open-mercato/ui/backend/injection/useAppEvent'\nimport { useMessageDetailsQueries } from './useMessageDetailsQueries'\nimport { useMessageDetailsActions } from './useMessageDetailsActions'\nimport { useMessageDetailsConversation } from './useMessageDetailsConversation'\n\nexport function useMessageDetails(id: string) {\n const t = useT()\n const router = useRouter()\n const scopeVersion = useOrganizationScopeVersion()\n const queryClient = useQueryClient()\n\n const queryState = useMessageDetailsQueries({\n id,\n t,\n scopeVersion,\n queryClient,\n })\n\n const invalidateMessageQueries = React.useCallback(\n (payload: Record<string, unknown>) => {\n void queryClient.invalidateQueries({ queryKey: ['messages', 'list'] })\n void queryClient.invalidateQueries({ queryKey: ['messages', 'detail', id] })\n const messageId = typeof payload.messageId === 'string' ? payload.messageId : null\n if (messageId && messageId !== id) {\n void queryClient.invalidateQueries({ queryKey: ['messages', 'detail', messageId] })\n }\n },\n [id, queryClient],\n )\n\n useAppEvent(\n 'messages.message.*',\n (evt) => {\n invalidateMessageQueries((evt.payload ?? {}) as Record<string, unknown>)\n },\n [invalidateMessageQueries],\n )\n\n useAppEvent(\n 'om:bridge:reconnected',\n () => {\n void queryClient.invalidateQueries({ queryKey: ['messages', 'detail', id] })\n },\n [id, queryClient],\n )\n\n const isArchived = (queryState.detail?.recipients ?? []).some((item) => item.status === 'archived')\n\n const actionState = useMessageDetailsActions({\n id,\n t,\n detail: queryState.detail,\n detailQuery: queryState.detailQuery,\n attachments: queryState.attachments,\n isArchived,\n onDeleted: () => router.push('/backend/messages'),\n refreshDetailWithoutAutoMarkRead: queryState.refreshDetailWithoutAutoMarkRead,\n })\n\n const conversationState = useMessageDetailsConversation({\n detail: queryState.detail,\n t,\n })\n\n const backToList = React.useCallback(() => {\n router.push('/backend/messages')\n }, [router])\n\n return {\n t,\n router,\n backToList,\n ...queryState,\n ...conversationState,\n ...actionState,\n isArchived,\n }\n}\n"],
5
+ "mappings": ";AAEA,YAAY,WAAW;AACvB,SAAS,iBAAiB;AAC1B,SAAS,sBAAsB;AAC/B,SAAS,YAAY;AACrB,SAAS,mCAAmC;AAC5C,SAAS,mBAAmB;AAC5B,SAAS,gCAAgC;AACzC,SAAS,gCAAgC;AACzC,SAAS,qCAAqC;AAEvC,SAAS,kBAAkB,IAAY;AAC5C,QAAM,IAAI,KAAK;AACf,QAAM,SAAS,UAAU;AACzB,QAAM,eAAe,4BAA4B;AACjD,QAAM,cAAc,eAAe;AAEnC,QAAM,aAAa,yBAAyB;AAAA,IAC1C;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,2BAA2B,MAAM;AAAA,IACrC,CAAC,YAAqC;AACpC,WAAK,YAAY,kBAAkB,EAAE,UAAU,CAAC,YAAY,MAAM,EAAE,CAAC;AACrE,WAAK,YAAY,kBAAkB,EAAE,UAAU,CAAC,YAAY,UAAU,EAAE,EAAE,CAAC;AAC3E,YAAM,YAAY,OAAO,QAAQ,cAAc,WAAW,QAAQ,YAAY;AAC9E,UAAI,aAAa,cAAc,IAAI;AACjC,aAAK,YAAY,kBAAkB,EAAE,UAAU,CAAC,YAAY,UAAU,SAAS,EAAE,CAAC;AAAA,MACpF;AAAA,IACF;AAAA,IACA,CAAC,IAAI,WAAW;AAAA,EAClB;AAEA;AAAA,IACE;AAAA,IACA,CAAC,QAAQ;AACP,+BAA0B,IAAI,WAAW,CAAC,CAA6B;AAAA,IACzE;AAAA,IACA,CAAC,wBAAwB;AAAA,EAC3B;AAEA;AAAA,IACE;AAAA,IACA,MAAM;AACJ,WAAK,YAAY,kBAAkB,EAAE,UAAU,CAAC,YAAY,UAAU,EAAE,EAAE,CAAC;AAAA,IAC7E;AAAA,IACA,CAAC,IAAI,WAAW;AAAA,EAClB;AAEA,QAAM,cAAc,WAAW,QAAQ,cAAc,CAAC,GAAG,KAAK,CAAC,SAAS,KAAK,WAAW,UAAU;AAElG,QAAM,cAAc,yBAAyB;AAAA,IAC3C;AAAA,IACA;AAAA,IACA,QAAQ,WAAW;AAAA,IACnB,aAAa,WAAW;AAAA,IACxB,aAAa,WAAW;AAAA,IACxB;AAAA,IACA,WAAW,MAAM,OAAO,KAAK,mBAAmB;AAAA,IAChD,kCAAkC,WAAW;AAAA,EAC/C,CAAC;AAED,QAAM,oBAAoB,8BAA8B;AAAA,IACtD,QAAQ,WAAW;AAAA,IACnB;AAAA,EACF,CAAC;AAED,QAAM,aAAa,MAAM,YAAY,MAAM;AACzC,WAAO,KAAK,mBAAmB;AAAA,EACjC,GAAG,CAAC,MAAM,CAAC;AAEX,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,IACH,GAAG;AAAA,IACH,GAAG;AAAA,IACH;AAAA,EACF;AACF;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,17 @@
1
+ const metadata = {
2
+ requireCustomerAuth: true,
3
+ titleKey: "portal.dashboard.title",
4
+ title: "Dashboard",
5
+ nav: {
6
+ label: "Dashboard",
7
+ labelKey: "portal.nav.dashboard",
8
+ group: "main",
9
+ order: 10
10
+ }
11
+ };
12
+ var page_meta_default = metadata;
13
+ export {
14
+ page_meta_default as default,
15
+ metadata
16
+ };
17
+ //# sourceMappingURL=page.meta.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../../src/modules/portal/frontend/%5BorgSlug%5D/portal/dashboard/page.meta.ts"],
4
+ "sourcesContent": ["import type { PageMetadata } from '@open-mercato/shared/modules/registry'\n\nexport const metadata: PageMetadata = {\n requireCustomerAuth: true,\n titleKey: 'portal.dashboard.title',\n title: 'Dashboard',\n nav: {\n label: 'Dashboard',\n labelKey: 'portal.nav.dashboard',\n group: 'main',\n order: 10,\n },\n}\n\nexport default metadata\n"],
5
+ "mappings": "AAEO,MAAM,WAAyB;AAAA,EACpC,qBAAqB;AAAA,EACrB,UAAU;AAAA,EACV,OAAO;AAAA,EACP,KAAK;AAAA,IACH,OAAO;AAAA,IACP,UAAU;AAAA,IACV,OAAO;AAAA,IACP,OAAO;AAAA,EACT;AACF;AAEA,IAAO,oBAAQ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,11 @@
1
+ const metadata = {
2
+ titleKey: "portal.nav.login",
3
+ title: "Log In",
4
+ navHidden: true
5
+ };
6
+ var page_meta_default = metadata;
7
+ export {
8
+ page_meta_default as default,
9
+ metadata
10
+ };
11
+ //# sourceMappingURL=page.meta.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../../src/modules/portal/frontend/%5BorgSlug%5D/portal/login/page.meta.ts"],
4
+ "sourcesContent": ["import type { PageMetadata } from '@open-mercato/shared/modules/registry'\n\nexport const metadata: PageMetadata = {\n titleKey: 'portal.nav.login',\n title: 'Log In',\n navHidden: true,\n}\n\nexport default metadata\n"],
5
+ "mappings": "AAEO,MAAM,WAAyB;AAAA,EACpC,UAAU;AAAA,EACV,OAAO;AAAA,EACP,WAAW;AACb;AAEA,IAAO,oBAAQ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,11 @@
1
+ const metadata = {
2
+ titleKey: "portal.title",
3
+ title: "Customer Portal",
4
+ navHidden: true
5
+ };
6
+ var page_meta_default = metadata;
7
+ export {
8
+ page_meta_default as default,
9
+ metadata
10
+ };
11
+ //# sourceMappingURL=page.meta.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../src/modules/portal/frontend/%5BorgSlug%5D/portal/page.meta.ts"],
4
+ "sourcesContent": ["import type { PageMetadata } from '@open-mercato/shared/modules/registry'\n\nexport const metadata: PageMetadata = {\n titleKey: 'portal.title',\n title: 'Customer Portal',\n navHidden: true,\n}\n\nexport default metadata\n"],
5
+ "mappings": "AAEO,MAAM,WAAyB;AAAA,EACpC,UAAU;AAAA,EACV,OAAO;AAAA,EACP,WAAW;AACb;AAEA,IAAO,oBAAQ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,17 @@
1
+ const metadata = {
2
+ requireCustomerAuth: true,
3
+ titleKey: "portal.nav.profile",
4
+ title: "Profile",
5
+ nav: {
6
+ label: "Profile",
7
+ labelKey: "portal.nav.profile",
8
+ group: "account",
9
+ order: 10
10
+ }
11
+ };
12
+ var page_meta_default = metadata;
13
+ export {
14
+ page_meta_default as default,
15
+ metadata
16
+ };
17
+ //# sourceMappingURL=page.meta.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../../src/modules/portal/frontend/%5BorgSlug%5D/portal/profile/page.meta.ts"],
4
+ "sourcesContent": ["import type { PageMetadata } from '@open-mercato/shared/modules/registry'\n\nexport const metadata: PageMetadata = {\n requireCustomerAuth: true,\n titleKey: 'portal.nav.profile',\n title: 'Profile',\n nav: {\n label: 'Profile',\n labelKey: 'portal.nav.profile',\n group: 'account',\n order: 10,\n },\n}\n\nexport default metadata\n"],
5
+ "mappings": "AAEO,MAAM,WAAyB;AAAA,EACpC,qBAAqB;AAAA,EACrB,UAAU;AAAA,EACV,OAAO;AAAA,EACP,KAAK;AAAA,IACH,OAAO;AAAA,IACP,UAAU;AAAA,IACV,OAAO;AAAA,IACP,OAAO;AAAA,EACT;AACF;AAEA,IAAO,oBAAQ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,11 @@
1
+ const metadata = {
2
+ titleKey: "portal.nav.signup",
3
+ title: "Sign Up",
4
+ navHidden: true
5
+ };
6
+ var page_meta_default = metadata;
7
+ export {
8
+ page_meta_default as default,
9
+ metadata
10
+ };
11
+ //# sourceMappingURL=page.meta.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../../src/modules/portal/frontend/%5BorgSlug%5D/portal/signup/page.meta.ts"],
4
+ "sourcesContent": ["import type { PageMetadata } from '@open-mercato/shared/modules/registry'\n\nexport const metadata: PageMetadata = {\n titleKey: 'portal.nav.signup',\n title: 'Sign Up',\n navHidden: true,\n}\n\nexport default metadata\n"],
5
+ "mappings": "AAEO,MAAM,WAAyB;AAAA,EACpC,UAAU;AAAA,EACV,OAAO;AAAA,EACP,WAAW;AACb;AAEA,IAAO,oBAAQ;",
6
+ "names": []
7
+ }
@@ -0,0 +1,11 @@
1
+ const metadata = {
2
+ titleKey: "portal.title",
3
+ title: "Verify Email",
4
+ navHidden: true
5
+ };
6
+ var page_meta_default = metadata;
7
+ export {
8
+ page_meta_default as default,
9
+ metadata
10
+ };
11
+ //# sourceMappingURL=page.meta.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../../src/modules/portal/frontend/%5BorgSlug%5D/portal/verify/page.meta.ts"],
4
+ "sourcesContent": ["import type { PageMetadata } from '@open-mercato/shared/modules/registry'\n\nexport const metadata: PageMetadata = {\n titleKey: 'portal.title',\n title: 'Verify Email',\n navHidden: true,\n}\n\nexport default metadata\n"],
5
+ "mappings": "AAEO,MAAM,WAAyB;AAAA,EACpC,UAAU;AAAA,EACV,OAAO;AAAA,EACP,WAAW;AACb;AAEA,IAAO,oBAAQ;",
6
+ "names": []
7
+ }
@@ -469,28 +469,19 @@ async function executeCallApi(em, config, context, container, signal) {
469
469
  }
470
470
  );
471
471
  }
472
- async function resolveCallApiRoleIds(em, instance) {
473
- if (!instance.definitionId) return [];
472
+ async function resolveActiveRoleIdsForUser(em, userId, scope) {
474
473
  const { findOneWithDecryption, findWithDecryption } = await import("@open-mercato/shared/lib/encryption/find");
475
474
  const { User, UserRole, Role } = await import("../../auth/data/entities.js");
476
- const { WorkflowDefinition } = await import("../data/entities.js");
477
- const scope = { tenantId: instance.tenantId, organizationId: instance.organizationId };
478
- const definition = await findOneWithDecryption(em, WorkflowDefinition, {
479
- id: instance.definitionId,
480
- tenantId: instance.tenantId
481
- }, {}, scope);
482
- const authorUserId = definition?.createdBy;
483
- if (!authorUserId) return [];
484
- const author = await findOneWithDecryption(em, User, {
485
- id: authorUserId,
486
- tenantId: instance.tenantId,
475
+ const user = await findOneWithDecryption(em, User, {
476
+ id: userId,
477
+ tenantId: scope.tenantId,
487
478
  deletedAt: null
488
479
  }, {}, scope);
489
- if (!author) return [];
480
+ if (!user) return [];
490
481
  const userRoles = await findWithDecryption(
491
482
  em,
492
483
  UserRole,
493
- { user: author.id, deletedAt: null },
484
+ { user: user.id, deletedAt: null },
494
485
  { populate: ["role"] },
495
486
  scope
496
487
  );
@@ -498,11 +489,29 @@ async function resolveCallApiRoleIds(em, instance) {
498
489
  if (roleIds.length === 0) return [];
499
490
  const scopedRoles = await findWithDecryption(em, Role, {
500
491
  id: { $in: roleIds },
501
- tenantId: instance.tenantId,
492
+ tenantId: scope.tenantId,
502
493
  deletedAt: null
503
494
  }, {}, scope);
504
495
  return scopedRoles.map((r) => r.id);
505
496
  }
497
+ async function resolveCallApiRoleIds(em, instance) {
498
+ if (!instance.definitionId) return [];
499
+ const { findOneWithDecryption } = await import("@open-mercato/shared/lib/encryption/find");
500
+ const { WorkflowDefinition } = await import("../data/entities.js");
501
+ const scope = { tenantId: instance.tenantId, organizationId: instance.organizationId };
502
+ const initiatorUserId = instance.metadata?.initiatedBy ?? null;
503
+ if (initiatorUserId) {
504
+ return resolveActiveRoleIdsForUser(em, initiatorUserId, scope);
505
+ }
506
+ const definition = await findOneWithDecryption(em, WorkflowDefinition, {
507
+ id: instance.definitionId,
508
+ tenantId: instance.tenantId,
509
+ deletedAt: null
510
+ }, {}, scope);
511
+ const authorUserId = definition?.createdBy;
512
+ if (!authorUserId) return [];
513
+ return resolveActiveRoleIdsForUser(em, authorUserId, scope);
514
+ }
506
515
  function buildApiUrl(endpoint) {
507
516
  const appUrl = process.env.APP_URL || "http://localhost:3000";
508
517
  if (endpoint.startsWith("/")) {