@open-mercato/core 0.10.1-develop.7716.1.cefe7975df → 0.10.1-develop.7721.1.b5c4a00a68
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.
- package/.turbo/turbo-build.log +2 -2
- package/dist/generated/entities/staff_support_routing_rule/index.js +21 -0
- package/dist/generated/entities/staff_support_routing_rule/index.js.map +7 -0
- package/dist/generated/entities/staff_support_ticket/index.js +37 -0
- package/dist/generated/entities/staff_support_ticket/index.js.map +7 -0
- package/dist/generated/entities/staff_time_project/index.js +2 -0
- package/dist/generated/entities/staff_time_project/index.js.map +2 -2
- package/dist/generated/entities/staff_time_project_member/index.js +2 -0
- package/dist/generated/entities/staff_time_project_member/index.js.map +2 -2
- package/dist/generated/entities/staff_time_task/index.js +4 -0
- package/dist/generated/entities/staff_time_task/index.js.map +2 -2
- package/dist/generated/entities/staff_time_task_comment/index.js +9 -1
- package/dist/generated/entities/staff_time_task_comment/index.js.map +2 -2
- package/dist/generated/entities.ids.generated.js +2 -0
- package/dist/generated/entities.ids.generated.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +38 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/helpers/integration/auth.js +1 -0
- package/dist/helpers/integration/auth.js.map +2 -2
- package/dist/helpers/integration/communicationChannelsFixtures.js +20 -0
- package/dist/helpers/integration/communicationChannelsFixtures.js.map +2 -2
- package/dist/modules/catalog/api/bulk-delete/route.js +12 -2
- package/dist/modules/catalog/api/bulk-delete/route.js.map +2 -2
- package/dist/modules/communication_channels/api/post/test-seed/route.js +17 -3
- package/dist/modules/communication_channels/api/post/test-seed/route.js.map +2 -2
- package/dist/modules/communication_channels/lib/test-seed.js +38 -5
- package/dist/modules/communication_channels/lib/test-seed.js.map +2 -2
- package/dist/modules/messages/commands/messages.js +2 -3
- package/dist/modules/messages/commands/messages.js.map +2 -2
- package/dist/modules/portal/frontend/[orgSlug]/portal/dashboard/page.js +2 -2
- package/dist/modules/portal/frontend/[orgSlug]/portal/dashboard/page.js.map +2 -2
- package/dist/modules/staff/api/portal/support-tickets/[id]/attachments/route.js +299 -0
- package/dist/modules/staff/api/portal/support-tickets/[id]/attachments/route.js.map +7 -0
- package/dist/modules/staff/api/portal/support-tickets/[id]/messages/route.js +91 -0
- package/dist/modules/staff/api/portal/support-tickets/[id]/messages/route.js.map +7 -0
- package/dist/modules/staff/api/portal/support-tickets/[id]/route.js +146 -0
- package/dist/modules/staff/api/portal/support-tickets/[id]/route.js.map +7 -0
- package/dist/modules/staff/api/portal/support-tickets/options/route.js +60 -0
- package/dist/modules/staff/api/portal/support-tickets/options/route.js.map +7 -0
- package/dist/modules/staff/api/portal/support-tickets/route.js +220 -0
- package/dist/modules/staff/api/portal/support-tickets/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/settings/route.js +7 -1
- package/dist/modules/staff/api/timesheets/settings/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/support-routing-rules/fallback-project/route.js +122 -0
- package/dist/modules/staff/api/timesheets/support-routing-rules/fallback-project/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/support-routing-rules/preview/route.js +180 -0
- package/dist/modules/staff/api/timesheets/support-routing-rules/preview/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/support-routing-rules/route.js +147 -0
- package/dist/modules/staff/api/timesheets/support-routing-rules/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/support-tickets/options/route.js +133 -0
- package/dist/modules/staff/api/timesheets/support-tickets/options/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/tasks/[id]/claim/route.js +33 -0
- package/dist/modules/staff/api/timesheets/tasks/[id]/claim/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/tasks/[id]/comments/route.js +25 -7
- package/dist/modules/staff/api/timesheets/tasks/[id]/comments/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/tasks/[id]/release/route.js +32 -0
- package/dist/modules/staff/api/timesheets/tasks/[id]/release/route.js.map +7 -0
- package/dist/modules/staff/api/timesheets/tasks/route.js +94 -47
- package/dist/modules/staff/api/timesheets/tasks/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-projects/[id]/employees/route.js +3 -0
- package/dist/modules/staff/api/timesheets/time-projects/[id]/employees/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-projects/route.js +3 -0
- package/dist/modules/staff/api/timesheets/time-projects/route.js.map +2 -2
- package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.js +1 -0
- package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.js +54 -4
- package/dist/modules/staff/backend/staff/time-tracking/projects/[id]/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/time-tracking/projects/projectFormConfig.js +21 -5
- package/dist/modules/staff/backend/staff/time-tracking/projects/projectFormConfig.js.map +2 -2
- package/dist/modules/staff/backend/staff/time-tracking/settings/page.js +319 -254
- package/dist/modules/staff/backend/staff/time-tracking/settings/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/time-tracking/support/page.js +363 -0
- package/dist/modules/staff/backend/staff/time-tracking/support/page.js.map +7 -0
- package/dist/modules/staff/backend/staff/time-tracking/support/page.meta.js +18 -0
- package/dist/modules/staff/backend/staff/time-tracking/support/page.meta.js.map +7 -0
- package/dist/modules/staff/cli.js +27 -0
- package/dist/modules/staff/cli.js.map +2 -2
- package/dist/modules/staff/commands/index.js +3 -0
- package/dist/modules/staff/commands/index.js.map +2 -2
- package/dist/modules/staff/commands/shared.js +10 -1
- package/dist/modules/staff/commands/shared.js.map +2 -2
- package/dist/modules/staff/commands/support-routing-rules.js +505 -0
- package/dist/modules/staff/commands/support-routing-rules.js.map +7 -0
- package/dist/modules/staff/commands/support-tickets.js +513 -0
- package/dist/modules/staff/commands/support-tickets.js.map +7 -0
- package/dist/modules/staff/commands/timesheets-projects.js +72 -14
- package/dist/modules/staff/commands/timesheets-projects.js.map +2 -2
- package/dist/modules/staff/commands/timesheets-task-assignment.js +270 -0
- package/dist/modules/staff/commands/timesheets-task-assignment.js.map +7 -0
- package/dist/modules/staff/commands/timesheets-task-comments.js +58 -12
- package/dist/modules/staff/commands/timesheets-task-comments.js.map +2 -2
- package/dist/modules/staff/commands/timesheets-tasks.js +91 -9
- package/dist/modules/staff/commands/timesheets-tasks.js.map +3 -3
- package/dist/modules/staff/data/enrichers.js +141 -0
- package/dist/modules/staff/data/enrichers.js.map +2 -2
- package/dist/modules/staff/data/entities.js +143 -2
- package/dist/modules/staff/data/entities.js.map +2 -2
- package/dist/modules/staff/data/extensions.js +8 -0
- package/dist/modules/staff/data/extensions.js.map +2 -2
- package/dist/modules/staff/data/validators.js +34 -5
- package/dist/modules/staff/data/validators.js.map +2 -2
- package/dist/modules/staff/encryption.js +6 -0
- package/dist/modules/staff/encryption.js.map +2 -2
- package/dist/modules/staff/events.js +25 -0
- package/dist/modules/staff/events.js.map +2 -2
- package/dist/modules/staff/events.payloads.js +54 -0
- package/dist/modules/staff/events.payloads.js.map +2 -2
- package/dist/modules/staff/extension-points.js +1 -0
- package/dist/modules/staff/extension-points.js.map +2 -2
- package/dist/modules/staff/frontend/[orgSlug]/portal/support/[id]/page.js +468 -0
- package/dist/modules/staff/frontend/[orgSlug]/portal/support/[id]/page.js.map +7 -0
- package/dist/modules/staff/frontend/[orgSlug]/portal/support/[id]/page.meta.js +12 -0
- package/dist/modules/staff/frontend/[orgSlug]/portal/support/[id]/page.meta.js.map +7 -0
- package/dist/modules/staff/frontend/[orgSlug]/portal/support/new/page.js +316 -0
- package/dist/modules/staff/frontend/[orgSlug]/portal/support/new/page.js.map +7 -0
- package/dist/modules/staff/frontend/[orgSlug]/portal/support/new/page.meta.js +12 -0
- package/dist/modules/staff/frontend/[orgSlug]/portal/support/new/page.meta.js.map +7 -0
- package/dist/modules/staff/frontend/[orgSlug]/portal/support/page.js +190 -0
- package/dist/modules/staff/frontend/[orgSlug]/portal/support/page.js.map +7 -0
- package/dist/modules/staff/frontend/[orgSlug]/portal/support/page.meta.js +19 -0
- package/dist/modules/staff/frontend/[orgSlug]/portal/support/page.meta.js.map +7 -0
- package/dist/modules/staff/index.js +1 -1
- package/dist/modules/staff/index.js.map +2 -2
- package/dist/modules/staff/lib/crud.js +2 -0
- package/dist/modules/staff/lib/crud.js.map +2 -2
- package/dist/modules/staff/lib/support/attachments.js +36 -0
- package/dist/modules/staff/lib/support/attachments.js.map +7 -0
- package/dist/modules/staff/lib/support/dictionaries.js +87 -0
- package/dist/modules/staff/lib/support/dictionaries.js.map +7 -0
- package/dist/modules/staff/lib/support/notifications.js +111 -0
- package/dist/modules/staff/lib/support/notifications.js.map +7 -0
- package/dist/modules/staff/lib/support/portalAttachments.js +100 -0
- package/dist/modules/staff/lib/support/portalAttachments.js.map +7 -0
- package/dist/modules/staff/lib/support/portalBroadcast.js +117 -0
- package/dist/modules/staff/lib/support/portalBroadcast.js.map +7 -0
- package/dist/modules/staff/lib/support/portalRoute.js +99 -0
- package/dist/modules/staff/lib/support/portalRoute.js.map +7 -0
- package/dist/modules/staff/lib/support/portalStatus.js +12 -0
- package/dist/modules/staff/lib/support/portalStatus.js.map +7 -0
- package/dist/modules/staff/lib/support/portalTickets.js +148 -0
- package/dist/modules/staff/lib/support/portalTickets.js.map +7 -0
- package/dist/modules/staff/lib/support/routing.js +81 -0
- package/dist/modules/staff/lib/support/routing.js.map +7 -0
- package/dist/modules/staff/lib/support/routingRuleDraft.js +25 -0
- package/dist/modules/staff/lib/support/routingRuleDraft.js.map +7 -0
- package/dist/modules/staff/lib/support/seedDefaults.js +114 -0
- package/dist/modules/staff/lib/support/seedDefaults.js.map +7 -0
- package/dist/modules/staff/lib/support/supportActivity.js +26 -0
- package/dist/modules/staff/lib/support/supportActivity.js.map +7 -0
- package/dist/modules/staff/lib/support-ui/PortalSupportNotLinked.js +23 -0
- package/dist/modules/staff/lib/support-ui/PortalSupportNotLinked.js.map +7 -0
- package/dist/modules/staff/lib/support-ui/portalAttachmentValidation.js +112 -0
- package/dist/modules/staff/lib/support-ui/portalAttachmentValidation.js.map +7 -0
- package/dist/modules/staff/lib/support-ui/portalPendingUploads.js +45 -0
- package/dist/modules/staff/lib/support-ui/portalPendingUploads.js.map +7 -0
- package/dist/modules/staff/lib/support-ui/portalSupport.js +51 -0
- package/dist/modules/staff/lib/support-ui/portalSupport.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/access.js +3 -39
- package/dist/modules/staff/lib/time-tracking/access.js.map +2 -2
- package/dist/modules/staff/lib/time-tracking/listProjectAccess.js +54 -0
- package/dist/modules/staff/lib/time-tracking/listProjectAccess.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/portalRecipients.js +92 -2
- package/dist/modules/staff/lib/time-tracking/portalRecipients.js.map +2 -2
- package/dist/modules/staff/lib/time-tracking/projectAssignment.js +112 -0
- package/dist/modules/staff/lib/time-tracking/projectAssignment.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/settingKeys.js +14 -0
- package/dist/modules/staff/lib/time-tracking/settingKeys.js.map +2 -2
- package/dist/modules/staff/lib/time-tracking/settings.js +28 -1
- package/dist/modules/staff/lib/time-tracking/settings.js.map +2 -2
- package/dist/modules/staff/lib/time-tracking/taskAssignmentRoute.js +143 -0
- package/dist/modules/staff/lib/time-tracking/taskAssignmentRoute.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking/workRecipients.js +92 -0
- package/dist/modules/staff/lib/time-tracking/workRecipients.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/BoardFilterChips.js +32 -3
- package/dist/modules/staff/lib/time-tracking-ui/BoardFilterChips.js.map +2 -2
- package/dist/modules/staff/lib/time-tracking-ui/KanbanBoard.js +29 -0
- package/dist/modules/staff/lib/time-tracking-ui/KanbanBoard.js.map +2 -2
- package/dist/modules/staff/lib/time-tracking-ui/KanbanCard.js +4 -0
- package/dist/modules/staff/lib/time-tracking-ui/KanbanCard.js.map +2 -2
- package/dist/modules/staff/lib/time-tracking-ui/ProjectFormSections.js +141 -1
- package/dist/modules/staff/lib/time-tracking-ui/ProjectFormSections.js.map +2 -2
- package/dist/modules/staff/lib/time-tracking-ui/SupportAttachmentsSection.js +153 -0
- package/dist/modules/staff/lib/time-tracking-ui/SupportAttachmentsSection.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/SupportRequestPanel.js +67 -0
- package/dist/modules/staff/lib/time-tracking-ui/SupportRequestPanel.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/TaskBoardScreen.js +3 -1
- package/dist/modules/staff/lib/time-tracking-ui/TaskBoardScreen.js.map +2 -2
- package/dist/modules/staff/lib/time-tracking-ui/TaskCommentThread.js +80 -17
- package/dist/modules/staff/lib/time-tracking-ui/TaskCommentThread.js.map +2 -2
- package/dist/modules/staff/lib/time-tracking-ui/TaskDrawer.js +230 -41
- package/dist/modules/staff/lib/time-tracking-ui/TaskDrawer.js.map +2 -2
- package/dist/modules/staff/lib/time-tracking-ui/boardDirectory.js +21 -1
- package/dist/modules/staff/lib/time-tracking-ui/boardDirectory.js.map +2 -2
- package/dist/modules/staff/lib/time-tracking-ui/boardFilters.js +16 -4
- package/dist/modules/staff/lib/time-tracking-ui/boardFilters.js.map +2 -2
- package/dist/modules/staff/lib/time-tracking-ui/kanbanBoardData.js +3 -1
- package/dist/modules/staff/lib/time-tracking-ui/kanbanBoardData.js.map +2 -2
- package/dist/modules/staff/lib/time-tracking-ui/projectDefaultAssignee.js +68 -0
- package/dist/modules/staff/lib/time-tracking-ui/projectDefaultAssignee.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/settingsTabs.js +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/settingsTabs.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/supportTicketData.js +50 -0
- package/dist/modules/staff/lib/time-tracking-ui/supportTicketData.js.map +7 -0
- package/dist/modules/staff/lib/time-tracking-ui/taskDrawerData.js +13 -1
- package/dist/modules/staff/lib/time-tracking-ui/taskDrawerData.js.map +2 -2
- package/dist/modules/staff/lib/time-tracking-ui/timeTrackingSettingsForm.js +36 -2
- package/dist/modules/staff/lib/time-tracking-ui/timeTrackingSettingsForm.js.map +2 -2
- package/dist/modules/staff/migrations/Migration20261009180543_staff.js +42 -0
- package/dist/modules/staff/migrations/Migration20261009180543_staff.js.map +7 -0
- package/dist/modules/staff/notifications.js +92 -0
- package/dist/modules/staff/notifications.js.map +2 -2
- package/dist/modules/staff/setup.js +6 -2
- package/dist/modules/staff/setup.js.map +2 -2
- package/dist/modules/staff/subscribers/support-portal-comment-created.js +26 -0
- package/dist/modules/staff/subscribers/support-portal-comment-created.js.map +7 -0
- package/dist/modules/staff/subscribers/support-portal-comment-deleted.js +26 -0
- package/dist/modules/staff/subscribers/support-portal-comment-deleted.js.map +7 -0
- package/dist/modules/staff/subscribers/support-portal-comment-updated.js +26 -0
- package/dist/modules/staff/subscribers/support-portal-comment-updated.js.map +7 -0
- package/dist/modules/staff/subscribers/support-portal-status-column-updated.js +24 -0
- package/dist/modules/staff/subscribers/support-portal-status-column-updated.js.map +7 -0
- package/dist/modules/staff/subscribers/support-portal-task-status-changed.js +25 -0
- package/dist/modules/staff/subscribers/support-portal-task-status-changed.js.map +7 -0
- package/dist/modules/staff/subscribers/support-portal-task-updated.js +25 -0
- package/dist/modules/staff/subscribers/support-portal-task-updated.js.map +7 -0
- package/dist/modules/staff/subscribers/support-ticket-created-notification.js +25 -0
- package/dist/modules/staff/subscribers/support-ticket-created-notification.js.map +7 -0
- package/dist/modules/staff/subscribers/support-ticket-customer-replied-notification.js +25 -0
- package/dist/modules/staff/subscribers/support-ticket-customer-replied-notification.js.map +7 -0
- package/dist/modules/staff/subscribers/support-ticket-unnotified-clear.js +26 -0
- package/dist/modules/staff/subscribers/support-ticket-unnotified-clear.js.map +7 -0
- package/dist/modules/staff/subscribers/time-task-assignee-notification.js +83 -0
- package/dist/modules/staff/subscribers/time-task-assignee-notification.js.map +7 -0
- package/dist/modules/staff/widgets/injection/portal-support-tickets/widget.client.js +112 -0
- package/dist/modules/staff/widgets/injection/portal-support-tickets/widget.client.js.map +7 -0
- package/dist/modules/staff/widgets/injection/portal-support-tickets/widget.js +17 -0
- package/dist/modules/staff/widgets/injection/portal-support-tickets/widget.js.map +7 -0
- package/dist/modules/staff/widgets/injection/time-tracking-settings-support/widget.client.js +870 -0
- package/dist/modules/staff/widgets/injection/time-tracking-settings-support/widget.client.js.map +7 -0
- package/dist/modules/staff/widgets/injection/time-tracking-settings-support/widget.js +17 -0
- package/dist/modules/staff/widgets/injection/time-tracking-settings-support/widget.js.map +7 -0
- package/dist/modules/staff/widgets/injection-table.js +16 -1
- package/dist/modules/staff/widgets/injection-table.js.map +2 -2
- package/dist/modules/wms/components/backend/WmsLocationDetailPage.js +4 -18
- package/dist/modules/wms/components/backend/WmsLocationDetailPage.js.map +2 -2
- package/dist/modules/wms/components/backend/WmsLotDetailPage.js +4 -18
- package/dist/modules/wms/components/backend/WmsLotDetailPage.js.map +2 -2
- package/dist/modules/wms/components/backend/WmsSkuDetailPage.js +4 -18
- package/dist/modules/wms/components/backend/WmsSkuDetailPage.js.map +2 -2
- package/dist/modules/wms/lib/inventoryCsvExport.js +19 -0
- package/dist/modules/wms/lib/inventoryCsvExport.js.map +7 -0
- package/generated/entities/staff_support_routing_rule/index.ts +9 -0
- package/generated/entities/staff_support_ticket/index.ts +17 -0
- package/generated/entities/staff_time_project/index.ts +1 -0
- package/generated/entities/staff_time_project_member/index.ts +1 -0
- package/generated/entities/staff_time_task/index.ts +2 -0
- package/generated/entities/staff_time_task_comment/index.ts +4 -0
- package/generated/entities.ids.generated.ts +2 -0
- package/generated/entity-fields-registry.ts +38 -0
- package/package.json +8 -8
- package/src/helpers/integration/auth.ts +1 -1
- package/src/helpers/integration/communicationChannelsFixtures.ts +60 -2
- package/src/modules/catalog/api/bulk-delete/route.ts +12 -2
- package/src/modules/communication_channels/api/post/test-seed/route.ts +29 -12
- package/src/modules/communication_channels/lib/test-seed.ts +49 -10
- package/src/modules/messages/commands/messages.ts +8 -10
- package/src/modules/portal/frontend/[orgSlug]/portal/dashboard/page.tsx +2 -2
- package/src/modules/staff/AGENTS.md +22 -6
- package/src/modules/staff/api/portal/support-tickets/[id]/attachments/route.ts +327 -0
- package/src/modules/staff/api/portal/support-tickets/[id]/messages/route.ts +94 -0
- package/src/modules/staff/api/portal/support-tickets/[id]/route.ts +160 -0
- package/src/modules/staff/api/portal/support-tickets/options/route.ts +60 -0
- package/src/modules/staff/api/portal/support-tickets/route.ts +253 -0
- package/src/modules/staff/api/timesheets/settings/route.ts +7 -1
- package/src/modules/staff/api/timesheets/support-routing-rules/fallback-project/route.ts +131 -0
- package/src/modules/staff/api/timesheets/support-routing-rules/preview/route.ts +248 -0
- package/src/modules/staff/api/timesheets/support-routing-rules/route.ts +150 -0
- package/src/modules/staff/api/timesheets/support-tickets/options/route.ts +181 -0
- package/src/modules/staff/api/timesheets/tasks/[id]/claim/route.ts +31 -0
- package/src/modules/staff/api/timesheets/tasks/[id]/comments/route.ts +25 -7
- package/src/modules/staff/api/timesheets/tasks/[id]/release/route.ts +30 -0
- package/src/modules/staff/api/timesheets/tasks/route.ts +119 -67
- package/src/modules/staff/api/timesheets/time-projects/[id]/employees/route.ts +3 -0
- package/src/modules/staff/api/timesheets/time-projects/route.ts +3 -0
- package/src/modules/staff/backend/staff/time-tracking/projects/[id]/edit/page.tsx +1 -0
- package/src/modules/staff/backend/staff/time-tracking/projects/[id]/page.tsx +67 -2
- package/src/modules/staff/backend/staff/time-tracking/projects/projectFormConfig.ts +22 -3
- package/src/modules/staff/backend/staff/time-tracking/settings/page.tsx +405 -308
- package/src/modules/staff/backend/staff/time-tracking/support/page.meta.ts +14 -0
- package/src/modules/staff/backend/staff/time-tracking/support/page.tsx +428 -0
- package/src/modules/staff/cli.ts +28 -0
- package/src/modules/staff/commands/index.ts +3 -0
- package/src/modules/staff/commands/shared.ts +22 -1
- package/src/modules/staff/commands/support-routing-rules.ts +595 -0
- package/src/modules/staff/commands/support-tickets.ts +580 -0
- package/src/modules/staff/commands/timesheets-projects.ts +84 -13
- package/src/modules/staff/commands/timesheets-task-assignment.ts +319 -0
- package/src/modules/staff/commands/timesheets-task-comments.ts +70 -15
- package/src/modules/staff/commands/timesheets-tasks.ts +106 -15
- package/src/modules/staff/data/enrichers.ts +203 -0
- package/src/modules/staff/data/entities.ts +133 -2
- package/src/modules/staff/data/extensions.ts +9 -1
- package/src/modules/staff/data/validators.ts +36 -0
- package/src/modules/staff/encryption.ts +6 -0
- package/src/modules/staff/events.payloads.ts +87 -1
- package/src/modules/staff/events.ts +26 -0
- package/src/modules/staff/extension-points.ts +1 -0
- package/src/modules/staff/frontend/[orgSlug]/portal/support/[id]/page.meta.ts +10 -0
- package/src/modules/staff/frontend/[orgSlug]/portal/support/[id]/page.tsx +553 -0
- package/src/modules/staff/frontend/[orgSlug]/portal/support/new/page.meta.ts +10 -0
- package/src/modules/staff/frontend/[orgSlug]/portal/support/new/page.tsx +346 -0
- package/src/modules/staff/frontend/[orgSlug]/portal/support/page.meta.ts +17 -0
- package/src/modules/staff/frontend/[orgSlug]/portal/support/page.tsx +253 -0
- package/src/modules/staff/i18n/de.json +291 -0
- package/src/modules/staff/i18n/en.json +291 -0
- package/src/modules/staff/i18n/es.json +291 -0
- package/src/modules/staff/i18n/ko.json +291 -0
- package/src/modules/staff/i18n/pl.json +291 -0
- package/src/modules/staff/index.ts +1 -1
- package/src/modules/staff/lib/crud.ts +2 -1
- package/src/modules/staff/lib/support/attachments.ts +43 -0
- package/src/modules/staff/lib/support/dictionaries.ts +120 -0
- package/src/modules/staff/lib/support/notifications.ts +138 -0
- package/src/modules/staff/lib/support/portalAttachments.ts +140 -0
- package/src/modules/staff/lib/support/portalBroadcast.ts +161 -0
- package/src/modules/staff/lib/support/portalRoute.ts +108 -0
- package/src/modules/staff/lib/support/portalStatus.ts +15 -0
- package/src/modules/staff/lib/support/portalTickets.ts +233 -0
- package/src/modules/staff/lib/support/routing.ts +117 -0
- package/src/modules/staff/lib/support/routingRuleDraft.ts +45 -0
- package/src/modules/staff/lib/support/seedDefaults.ts +151 -0
- package/src/modules/staff/lib/support/supportActivity.ts +39 -0
- package/src/modules/staff/lib/support-ui/PortalSupportNotLinked.tsx +20 -0
- package/src/modules/staff/lib/support-ui/portalAttachmentValidation.ts +125 -0
- package/src/modules/staff/lib/support-ui/portalPendingUploads.ts +49 -0
- package/src/modules/staff/lib/support-ui/portalSupport.ts +116 -0
- package/src/modules/staff/lib/time-tracking/access.ts +2 -62
- package/src/modules/staff/lib/time-tracking/listProjectAccess.ts +78 -0
- package/src/modules/staff/lib/time-tracking/portalRecipients.ts +173 -5
- package/src/modules/staff/lib/time-tracking/projectAssignment.ts +172 -0
- package/src/modules/staff/lib/time-tracking/settingKeys.ts +11 -0
- package/src/modules/staff/lib/time-tracking/settings.ts +46 -1
- package/src/modules/staff/lib/time-tracking/taskAssignmentRoute.ts +165 -0
- package/src/modules/staff/lib/time-tracking/workRecipients.ts +183 -0
- package/src/modules/staff/lib/time-tracking-ui/BoardFilterChips.tsx +36 -1
- package/src/modules/staff/lib/time-tracking-ui/KanbanBoard.tsx +30 -0
- package/src/modules/staff/lib/time-tracking-ui/KanbanCard.tsx +9 -0
- package/src/modules/staff/lib/time-tracking-ui/ProjectFormSections.tsx +185 -6
- package/src/modules/staff/lib/time-tracking-ui/SupportAttachmentsSection.tsx +188 -0
- package/src/modules/staff/lib/time-tracking-ui/SupportRequestPanel.tsx +102 -0
- package/src/modules/staff/lib/time-tracking-ui/TaskBoardScreen.tsx +2 -0
- package/src/modules/staff/lib/time-tracking-ui/TaskCommentThread.tsx +105 -22
- package/src/modules/staff/lib/time-tracking-ui/TaskDrawer.tsx +278 -43
- package/src/modules/staff/lib/time-tracking-ui/boardDirectory.ts +21 -0
- package/src/modules/staff/lib/time-tracking-ui/boardFilters.ts +16 -2
- package/src/modules/staff/lib/time-tracking-ui/kanbanBoardData.ts +4 -0
- package/src/modules/staff/lib/time-tracking-ui/projectDefaultAssignee.ts +117 -0
- package/src/modules/staff/lib/time-tracking-ui/settingsTabs.ts +17 -0
- package/src/modules/staff/lib/time-tracking-ui/supportTicketData.ts +71 -0
- package/src/modules/staff/lib/time-tracking-ui/taskDrawerData.ts +15 -0
- package/src/modules/staff/lib/time-tracking-ui/timeTrackingSettingsForm.ts +48 -1
- package/src/modules/staff/migrations/.snapshot-open-mercato.json +714 -0
- package/src/modules/staff/migrations/Migration20261009180543_staff.ts +50 -0
- package/src/modules/staff/notifications.ts +92 -0
- package/src/modules/staff/setup.ts +6 -2
- package/src/modules/staff/subscribers/support-portal-comment-created.ts +35 -0
- package/src/modules/staff/subscribers/support-portal-comment-deleted.ts +35 -0
- package/src/modules/staff/subscribers/support-portal-comment-updated.ts +35 -0
- package/src/modules/staff/subscribers/support-portal-status-column-updated.ts +36 -0
- package/src/modules/staff/subscribers/support-portal-task-status-changed.ts +34 -0
- package/src/modules/staff/subscribers/support-portal-task-updated.ts +34 -0
- package/src/modules/staff/subscribers/support-ticket-created-notification.ts +27 -0
- package/src/modules/staff/subscribers/support-ticket-customer-replied-notification.ts +27 -0
- package/src/modules/staff/subscribers/support-ticket-unnotified-clear.ts +29 -0
- package/src/modules/staff/subscribers/time-task-assignee-notification.ts +102 -0
- package/src/modules/staff/widgets/injection/portal-support-tickets/widget.client.tsx +151 -0
- package/src/modules/staff/widgets/injection/portal-support-tickets/widget.ts +16 -0
- package/src/modules/staff/widgets/injection/time-tracking-settings-support/widget.client.tsx +1058 -0
- package/src/modules/staff/widgets/injection/time-tracking-settings-support/widget.ts +17 -0
- package/src/modules/staff/widgets/injection-table.ts +15 -0
- package/src/modules/wms/components/backend/WmsLocationDetailPage.tsx +4 -20
- package/src/modules/wms/components/backend/WmsLotDetailPage.tsx +4 -20
- package/src/modules/wms/components/backend/WmsSkuDetailPage.tsx +4 -19
- package/src/modules/wms/lib/inventoryCsvExport.ts +18 -0
package/dist/modules/staff/widgets/injection/time-tracking-settings-support/widget.client.js.map
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../src/modules/staff/widgets/injection/time-tracking-settings-support/widget.client.tsx"],
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { Pencil, Plus, Save, Trash2 } from 'lucide-react'\nimport { Dialog, DialogContent, DialogHeader, DialogTitle } from '@open-mercato/ui/primitives/dialog'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { LoadingMessage, ErrorMessage } from '@open-mercato/ui/backend/detail'\nimport { apiCall, readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { createCrud, deleteCrud, updateCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'\nimport { raiseCrudError } from '@open-mercato/ui/backend/utils/serverErrors'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { Alert, AlertDescription, AlertTitle } from '@open-mercato/ui/primitives/alert'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { IconButton } from '@open-mercato/ui/primitives/icon-button'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Label } from '@open-mercato/ui/primitives/label'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@open-mercato/ui/primitives/select'\nimport { ComboboxInput, type ComboboxOption } from '@open-mercato/ui/backend/inputs/ComboboxInput'\nimport { useBackendChrome } from '@open-mercato/ui/backend/BackendChromeProvider'\nimport { hasFeature } from '@open-mercato/shared/security/features'\nimport { StatusBadge } from '@open-mercato/ui/primitives/status-badge'\nimport { Switch } from '@open-mercato/ui/primitives/switch'\nimport { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@open-mercato/ui/primitives/table'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useLocale, useT } from '@open-mercato/shared/lib/i18n/context'\nimport type { InjectionWidgetComponentProps } from '@open-mercato/shared/modules/widgets/injection'\nimport { ICON_SUGGESTIONS } from '@open-mercato/core/modules/dictionaries/components/dictionaryAppearance'\nimport {\n DictionaryForm,\n type DictionaryFormValues,\n} from '@open-mercato/core/modules/dictionaries/components/DictionaryForm'\nimport {\n DictionaryTable,\n type DictionaryTableEntry,\n} from '@open-mercato/core/modules/dictionaries/components/DictionaryTable'\nimport type { TimeTrackingSettings } from '../../../lib/time-tracking/settings'\nimport { DEFAULT_SUPPORT_REFERENCE_PREFIX } from '../../../lib/time-tracking/settingKeys'\nimport type { TimeTrackingSettingsTabContext } from '../../../lib/time-tracking-ui/settingsTabs'\nimport {\n buildRoutingRuleEditDraft,\n rebaseRoutingRuleDialog,\n routingRuleVersion,\n type RoutingRuleDialogState,\n} from '../../../lib/support/routingRuleDraft'\n\nconst CATEGORY_DICTIONARY_KEY = 'staff.support_ticket_category'\nconst ROUTING_API = 'staff/timesheets/support-routing-rules'\nconst PREVIEW_URL = '/api/staff/timesheets/support-routing-rules/preview'\nconst FALLBACK_PROJECT_URL = '/api/staff/timesheets/support-routing-rules/fallback-project'\nconst PROJECTS_URL = '/api/staff/timesheets/time-projects'\nconst SETTINGS_URL = '/api/staff/timesheets/settings'\nconst UNNOTIFIED_INBOX_URL = '/backend/staff/time-tracking/support?supportUnnotified=true'\nconst SAVE_CONTEXT_ID = 'staff.support.settings'\nconst DICTIONARIES_VIEW_FEATURE = 'dictionaries.view'\nconst DICTIONARIES_MANAGE_FEATURE = 'dictionaries.manage'\nconst PROJECT_SEARCH_PAGE_SIZE = 20\nconst PREFIX_PATTERN = /^[A-Z][A-Z0-9]{1,9}$/\n\ntype RuleProblem = 'paused' | 'project_unusable' | 'category_missing'\n\ntype PreviewProject = {\n id: string\n name: string | null\n code: string | null\n status: string\n usable: boolean\n nobodyNotified?: boolean\n}\n\ntype PreviewRule = {\n id: string\n categoryValue: string | null\n isActive: boolean\n isFallback: boolean\n project: PreviewProject\n problem: RuleProblem | null\n updatedAt?: string | null\n}\n\ntype PreviewCategory = {\n value: string\n label: string\n route: { via: 'category' | 'fallback'; project: PreviewProject } | null\n}\n\ntype RoutingPreview = {\n fallback: { ruleId: string; project: PreviewProject; updatedAt?: string | null } | null\n rules: PreviewRule[]\n categories: PreviewCategory[]\n unnotifiedTicketCount?: number\n}\n\ntype ProjectOption = {\n id: string\n name: string\n code: string | null\n}\n\ntype RuleDialogState = RoutingRuleDialogState\n\ntype CategoryDialogState =\n | { mode: 'create' }\n | { mode: 'edit'; entry: DictionaryTableEntry }\n\nconst EMPTY_PREVIEW: RoutingPreview = { fallback: null, rules: [], categories: [] }\n\nconst DEFAULT_CATEGORY_VALUES: DictionaryFormValues = {\n value: '',\n label: '',\n color: null,\n icon: null,\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction toStringOrNull(value: unknown): string | null {\n return typeof value === 'string' && value.length > 0 ? value : null\n}\n\nfunction normalizeEntry(item: unknown): DictionaryTableEntry | null {\n if (!isRecord(item)) return null\n const id = toStringOrNull(item.id)\n const value = toStringOrNull(item.value)\n if (!id || !value) return null\n return {\n id,\n value,\n label: toStringOrNull(item.label) ?? value,\n color: toStringOrNull(item.color),\n icon: toStringOrNull(item.icon),\n organizationId: toStringOrNull(item.organizationId),\n tenantId: toStringOrNull(item.tenantId),\n isInherited: item.isInherited === true,\n createdAt: toStringOrNull(item.createdAt),\n updatedAt: toStringOrNull(item.updatedAt),\n }\n}\n\nfunction normalizeProject(item: unknown): ProjectOption | null {\n if (!isRecord(item)) return null\n const id = toStringOrNull(item.id)\n if (!id) return null\n return { id, name: toStringOrNull(item.name) ?? id, code: toStringOrNull(item.code) }\n}\n\nfunction projectLabel(project: { name: string | null; code: string | null; id: string }): string {\n const name = project.name ?? project.id\n return project.code ? `${name} (${project.code})` : name\n}\n\nasync function searchProjects(query?: string): Promise<ComboboxOption[]> {\n const params = new URLSearchParams({\n page: '1',\n pageSize: String(PROJECT_SEARCH_PAGE_SIZE),\n sortField: 'name',\n sortDir: 'asc',\n })\n const term = query?.trim() ?? ''\n if (term) params.set('q', term)\n try {\n const call = await apiCall<{ items?: unknown[] }>(`${PROJECTS_URL}?${params.toString()}`)\n if (!call.ok) return []\n return (call.result?.items ?? [])\n .map(normalizeProject)\n .filter((project): project is ProjectOption => project !== null)\n .map((project) => ({ value: project.id, label: projectLabel(project) }))\n } catch {\n return []\n }\n}\n\ntype SupportProjectPickerProps = {\n labelId: string\n value: string\n knownProjects: ProjectOption[]\n placeholder: string\n disabled?: boolean\n testId: string\n onChange: (projectId: string) => void\n}\n\nfunction SupportProjectPicker({ labelId, value, knownProjects, placeholder, disabled, testId, onChange }: SupportProjectPickerProps) {\n const seedOptions = React.useMemo<ComboboxOption[]>(\n () => knownProjects.map((project) => ({ value: project.id, label: projectLabel(project) })),\n [knownProjects],\n )\n return (\n <div role=\"group\" aria-labelledby={labelId} data-testid={testId}>\n <ComboboxInput\n value={value}\n onChange={(next) => {\n if (next && next !== value) onChange(next)\n }}\n seedOptions={seedOptions}\n loadSuggestions={searchProjects}\n allowCustomValues={false}\n placeholder={placeholder}\n disabled={disabled}\n />\n </div>\n )\n}\n\nexport default function SupportSettingsTab({ context }: InjectionWidgetComponentProps<TimeTrackingSettingsTabContext>) {\n const t = useT()\n const locale = useLocale()\n const unnotifiedTicketsLabel = React.useCallback(\n (count: number): string => {\n let category: string\n try {\n category = new Intl.PluralRules(locale).select(count)\n } catch {\n category = count === 1 ? 'one' : 'other'\n }\n if (category === 'one') return t('staff.support.settings.routing.unnotifiedTickets.one', '{count} ticket was not notified to anyone.', { count })\n if (category === 'few') return t('staff.support.settings.routing.unnotifiedTickets.few', '{count} tickets were not notified to anyone.', { count })\n if (category === 'many') return t('staff.support.settings.routing.unnotifiedTickets.many', '{count} tickets were not notified to anyone.', { count })\n return t('staff.support.settings.routing.unnotifiedTickets.other', '{count} tickets were not notified to anyone.', { count })\n },\n [locale, t],\n )\n const scopeVersion = useOrganizationScopeVersion()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const { payload: chromePayload, isReady: chromeReady } = useBackendChrome()\n const grantedFeatures = chromePayload?.grantedFeatures\n const canManageSettings = context.canManage\n const canViewCategories = hasFeature(grantedFeatures, DICTIONARIES_VIEW_FEATURE)\n const canManageCategories = canManageSettings && hasFeature(grantedFeatures, DICTIONARIES_MANAGE_FEATURE)\n const { runMutation, retryLastMutation } = useGuardedMutation<{\n formId: string\n resourceKind: string\n retryLastMutation: () => Promise<boolean>\n }>({\n contextId: SAVE_CONTEXT_ID,\n blockedMessage: t('staff.support.settings.errors.saveBlocked', 'Save blocked by validation'),\n })\n const routingContext = React.useMemo(() => ({\n formId: SAVE_CONTEXT_ID,\n resourceKind: 'staff.support.routing_rule',\n retryLastMutation,\n }), [retryLastMutation])\n const categoryContext = React.useMemo(() => ({\n formId: SAVE_CONTEXT_ID,\n resourceKind: 'staff.support.categories',\n retryLastMutation,\n }), [retryLastMutation])\n const settingsContext = React.useMemo(() => ({\n formId: SAVE_CONTEXT_ID,\n resourceKind: 'staff.timesheets.settings',\n retryLastMutation,\n }), [retryLastMutation])\n\n const [categoryEntries, setCategoryEntries] = React.useState<DictionaryTableEntry[]>([])\n const [dictionaryId, setDictionaryId] = React.useState<string | null>(null)\n const [categoriesLoading, setCategoriesLoading] = React.useState(true)\n const [categoriesError, setCategoriesError] = React.useState<string | null>(null)\n const [categoryDialog, setCategoryDialog] = React.useState<CategoryDialogState | null>(null)\n const [categorySubmitting, setCategorySubmitting] = React.useState(false)\n\n const [preview, setPreview] = React.useState<RoutingPreview>(EMPTY_PREVIEW)\n const [routingLoading, setRoutingLoading] = React.useState(true)\n const [routingError, setRoutingError] = React.useState<string | null>(null)\n const [ruleDialog, setRuleDialog] = React.useState<RuleDialogState | null>(null)\n const [ruleSubmitting, setRuleSubmitting] = React.useState(false)\n const [creatingFallback, setCreatingFallback] = React.useState(false)\n\n const { settings, onSettingsSaved } = context\n const savedPrefix = settings.support?.referencePrefix ?? DEFAULT_SUPPORT_REFERENCE_PREFIX\n const [prefix, setPrefix] = React.useState(savedPrefix)\n const [prefixError, setPrefixError] = React.useState<string | null>(null)\n const [prefixSaving, setPrefixSaving] = React.useState(false)\n\n const loadCategories = React.useCallback(async () => {\n if (!chromeReady) return\n if (!canViewCategories) {\n setCategoryEntries([])\n setDictionaryId(null)\n setCategoriesError(null)\n setCategoriesLoading(false)\n return\n }\n setCategoriesLoading(true)\n setCategoriesError(null)\n try {\n const dictionaries = await readApiResultOrThrow<{ items?: Array<{ id?: string; key?: string }> }>(\n '/api/dictionaries',\n undefined,\n { fallback: { items: [] }, errorMessage: t('staff.support.settings.errors.load', 'Failed to load support settings.') },\n )\n const dictionary = (dictionaries.items ?? []).find((item) => item.key === CATEGORY_DICTIONARY_KEY)\n const id = dictionary?.id ?? null\n setDictionaryId(id)\n if (!id) {\n setCategoryEntries([])\n return\n }\n const entries = await readApiResultOrThrow<{ items?: unknown[] }>(\n `/api/dictionaries/${encodeURIComponent(id)}/entries`,\n undefined,\n { fallback: { items: [] }, errorMessage: t('staff.support.settings.errors.load', 'Failed to load support settings.') },\n )\n setCategoryEntries(\n (entries.items ?? []).map(normalizeEntry).filter((entry): entry is DictionaryTableEntry => entry !== null),\n )\n } catch (err) {\n setCategoriesError(err instanceof Error ? err.message : t('staff.support.settings.errors.load', 'Failed to load support settings.'))\n } finally {\n setCategoriesLoading(false)\n }\n }, [canViewCategories, chromeReady, t])\n\n const loadRouting = React.useCallback(async () => {\n setRoutingLoading(true)\n setRoutingError(null)\n try {\n const errorMessage = t('staff.support.settings.errors.load', 'Failed to load support settings.')\n const previewResult =\n (await readApiResultOrThrow<RoutingPreview>(PREVIEW_URL, undefined, { fallback: EMPTY_PREVIEW, errorMessage })) ??\n EMPTY_PREVIEW\n setPreview(previewResult)\n setRuleDialog((current) => rebaseRoutingRuleDialog(current, previewResult))\n } catch (err) {\n setRoutingError(err instanceof Error ? err.message : t('staff.support.settings.errors.load', 'Failed to load support settings.'))\n } finally {\n setRoutingLoading(false)\n }\n }, [t])\n\n React.useEffect(() => {\n setPrefix(savedPrefix)\n }, [savedPrefix])\n\n React.useEffect(() => {\n void loadCategories()\n }, [loadCategories, scopeVersion])\n\n React.useEffect(() => {\n void loadRouting()\n }, [loadRouting, scopeVersion])\n\n const reloadAll = React.useCallback(async () => {\n await Promise.all([loadCategories(), loadRouting()])\n }, [loadCategories, loadRouting])\n\n const surfaceMutationError = React.useCallback((err: unknown, fallbackKey: string, fallback: string, onRefresh?: () => void) => {\n if (surfaceRecordConflict(err, t, onRefresh ? { onRefresh } : undefined)) return\n flash(err instanceof Error ? err.message : t(fallbackKey, fallback), 'error')\n }, [t])\n\n const submitCategory = React.useCallback(async (values: DictionaryFormValues) => {\n if (!categoryDialog || !dictionaryId || categorySubmitting) return\n setCategorySubmitting(true)\n try {\n if (categoryDialog.mode === 'create') {\n await runMutation({\n operation: async () => {\n const call = await apiCall(`/api/dictionaries/${encodeURIComponent(dictionaryId)}/entries`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(values),\n })\n if (!call.ok) await raiseCrudError(call.response, t('staff.support.settings.errors.save', 'Failed to save.'))\n return call\n },\n context: categoryContext,\n mutationPayload: { action: 'create', ...values },\n })\n } else {\n const entry = categoryDialog.entry\n const payload: Record<string, unknown> = {}\n if (values.value !== entry.value) payload.value = values.value\n if (values.label !== entry.label) payload.label = values.label\n if ((values.color ?? null) !== (entry.color ?? null)) payload.color = values.color ?? null\n if ((values.icon ?? null) !== (entry.icon ?? null)) payload.icon = values.icon ?? null\n await runMutation({\n operation: async () => {\n const call = await withScopedApiRequestHeaders(\n buildOptimisticLockHeader(entry.updatedAt),\n () => apiCall(`/api/dictionaries/${encodeURIComponent(dictionaryId)}/entries/${encodeURIComponent(entry.id)}`, {\n method: 'PATCH',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n }),\n )\n if (!call.ok) await raiseCrudError(call.response, t('staff.support.settings.errors.save', 'Failed to save.'))\n return call\n },\n context: categoryContext,\n mutationPayload: { action: 'update', id: entry.id, ...payload },\n })\n }\n flash(t('staff.support.settings.categories.saved', 'Category saved.'), 'success')\n setCategoryDialog(null)\n await reloadAll()\n } catch (err) {\n surfaceMutationError(err, 'staff.support.settings.errors.save', 'Failed to save.', () => { void loadCategories() })\n } finally {\n setCategorySubmitting(false)\n }\n }, [categoryContext, categoryDialog, categorySubmitting, dictionaryId, loadCategories, reloadAll, surfaceMutationError, runMutation, t])\n\n const deleteCategory = React.useCallback(async (entry: DictionaryTableEntry) => {\n if (!dictionaryId) return\n const confirmed = await confirm({\n title: t('staff.support.settings.categories.confirmDelete', 'Delete category \"{value}\"?', { value: entry.label || entry.value }),\n variant: 'destructive',\n })\n if (!confirmed) return\n try {\n await runMutation({\n operation: async () => {\n const call = await withScopedApiRequestHeaders(\n buildOptimisticLockHeader(entry.updatedAt),\n () => apiCall(`/api/dictionaries/${encodeURIComponent(dictionaryId)}/entries/${encodeURIComponent(entry.id)}`, {\n method: 'DELETE',\n }),\n )\n if (!call.ok) await raiseCrudError(call.response, t('staff.support.settings.errors.delete', 'Failed to delete.'))\n return call\n },\n context: categoryContext,\n mutationPayload: { action: 'delete', id: entry.id },\n })\n flash(t('staff.support.settings.categories.deleted', 'Category deleted.'), 'success')\n await reloadAll()\n } catch (err) {\n surfaceMutationError(err, 'staff.support.settings.errors.delete', 'Failed to delete.', () => { void loadCategories() })\n }\n }, [categoryContext, confirm, dictionaryId, loadCategories, reloadAll, surfaceMutationError, runMutation, t])\n\n const createFallbackProject = React.useCallback(async () => {\n setCreatingFallback(true)\n try {\n await runMutation({\n operation: async () => {\n const call = await apiCall(FALLBACK_PROJECT_URL, { method: 'POST' })\n if (!call.ok) await raiseCrudError(call.response, t('staff.support.settings.errors.save', 'Failed to save.'))\n return call\n },\n context: routingContext,\n mutationPayload: { action: 'create_fallback_project' },\n })\n flash(t('staff.support.settings.routing.fallbackCreated', 'Fallback project created.'), 'success')\n await loadRouting()\n } catch (err) {\n surfaceMutationError(err, 'staff.support.settings.errors.save', 'Failed to save.')\n } finally {\n setCreatingFallback(false)\n }\n }, [loadRouting, surfaceMutationError, routingContext, runMutation, t])\n\n const updateRule = React.useCallback(async (\n ruleId: string,\n expectedUpdatedAt: string | null,\n patch: { timeProjectId?: string; isActive?: boolean },\n ) => {\n try {\n await runMutation({\n operation: () => updateCrud(ROUTING_API, { id: ruleId, ...patch }, {\n headers: buildOptimisticLockHeader(expectedUpdatedAt),\n errorMessage: t('staff.support.settings.errors.save', 'Failed to save.'),\n }),\n context: routingContext,\n mutationPayload: { action: 'update', id: ruleId, ...patch },\n })\n flash(t('staff.support.settings.routing.saved', 'Routing saved.'), 'success')\n await loadRouting()\n return true\n } catch (err) {\n surfaceMutationError(err, 'staff.support.settings.errors.save', 'Failed to save.', () => { void loadRouting() })\n return false\n }\n }, [loadRouting, surfaceMutationError, routingContext, runMutation, t])\n\n const deleteRule = React.useCallback(async (rule: PreviewRule) => {\n const confirmed = await confirm({\n title: t('staff.support.settings.routing.confirmDelete', 'Delete this rule? The category will use the fallback project.'),\n variant: 'destructive',\n })\n if (!confirmed) return\n try {\n await runMutation({\n operation: () => deleteCrud(ROUTING_API, rule.id, {\n headers: buildOptimisticLockHeader(routingRuleVersion(rule)),\n errorMessage: t('staff.support.settings.errors.delete', 'Failed to delete.'),\n }),\n context: routingContext,\n mutationPayload: { action: 'delete', id: rule.id },\n })\n flash(t('staff.support.settings.routing.deleted', 'Rule deleted.'), 'success')\n await loadRouting()\n } catch (err) {\n surfaceMutationError(err, 'staff.support.settings.errors.delete', 'Failed to delete.', () => { void loadRouting() })\n }\n }, [confirm, loadRouting, surfaceMutationError, routingContext, runMutation, t])\n\n const submitRuleDialog = React.useCallback(async () => {\n if (!ruleDialog || !ruleDialog.timeProjectId || ruleSubmitting) return\n if (ruleDialog.mode === 'create' && !ruleDialog.categoryValue) return\n setRuleSubmitting(true)\n try {\n if (ruleDialog.mode === 'create') {\n await runMutation({\n operation: () => createCrud(ROUTING_API, {\n categoryValue: ruleDialog.categoryValue,\n timeProjectId: ruleDialog.timeProjectId,\n }, { errorMessage: t('staff.support.settings.errors.save', 'Failed to save.') }),\n context: routingContext,\n mutationPayload: { action: 'create', categoryValue: ruleDialog.categoryValue, timeProjectId: ruleDialog.timeProjectId },\n })\n flash(t('staff.support.settings.routing.saved', 'Routing saved.'), 'success')\n setRuleDialog(null)\n await loadRouting()\n } else {\n const ok = await updateRule(ruleDialog.ruleId, ruleDialog.expectedUpdatedAt, { timeProjectId: ruleDialog.timeProjectId })\n if (ok) setRuleDialog(null)\n }\n } catch (err) {\n surfaceMutationError(err, 'staff.support.settings.errors.save', 'Failed to save.', () => { void loadRouting() })\n } finally {\n setRuleSubmitting(false)\n }\n }, [loadRouting, surfaceMutationError, routingContext, ruleDialog, ruleSubmitting, runMutation, t, updateRule])\n\n const savePrefix = React.useCallback(async () => {\n const value = prefix.trim().toUpperCase()\n if (!PREFIX_PATTERN.test(value)) {\n setPrefixError(t('staff.support.settings.prefix.invalid', 'Use 2\u201310 uppercase letters or digits, starting with a letter.'))\n return\n }\n setPrefixError(null)\n setPrefixSaving(true)\n try {\n const next: TimeTrackingSettings = { ...settings, support: { ...(settings.support ?? {}), referencePrefix: value } }\n const call = await runMutation({\n operation: async () => {\n const call = await apiCall<TimeTrackingSettings>(SETTINGS_URL, {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(next),\n })\n if (!call.ok) await raiseCrudError(call.response, t('staff.support.settings.errors.save', 'Failed to save.'))\n return call\n },\n context: settingsContext,\n mutationPayload: { support: { referencePrefix: value } },\n })\n if (call.result) onSettingsSaved(call.result)\n flash(t('staff.support.settings.prefix.saved', 'Reference prefix saved.'), 'success')\n } catch (err) {\n surfaceMutationError(err, 'staff.support.settings.errors.save', 'Failed to save.')\n } finally {\n setPrefixSaving(false)\n }\n }, [onSettingsSaved, prefix, surfaceMutationError, runMutation, settings, settingsContext, t])\n\n const categoryLabels = React.useMemo(() => {\n const map = new Map<string, string>()\n for (const category of preview.categories) map.set(category.value, category.label)\n for (const entry of categoryEntries) if (!map.has(entry.value)) map.set(entry.value, entry.label)\n return map\n }, [categoryEntries, preview.categories])\n\n const overrides = React.useMemo(() => preview.rules.filter((rule) => !rule.isFallback), [preview.rules])\n const categoriesWithoutRule = React.useMemo(() => {\n const ruled = new Set(overrides.map((rule) => rule.categoryValue))\n return preview.categories.filter((category) => !ruled.has(category.value))\n }, [overrides, preview.categories])\n\n const fallbackName = preview.fallback ? projectLabel(preview.fallback.project) : ''\n\n const knownProjects = React.useMemo<ProjectOption[]>(() => {\n const byId = new Map<string, ProjectOption>()\n const remember = (project: PreviewProject) => {\n if (!byId.has(project.id)) byId.set(project.id, { id: project.id, name: project.name ?? project.id, code: project.code })\n }\n if (preview.fallback) remember(preview.fallback.project)\n for (const rule of preview.rules) remember(rule.project)\n for (const category of preview.categories) if (category.route) remember(category.route.project)\n return [...byId.values()]\n }, [preview])\n\n const problemText = (problem: RuleProblem): string => {\n if (problem === 'paused') return t('staff.support.settings.routing.problem.paused', 'The rule is paused.')\n if (problem === 'category_missing') return t('staff.support.settings.routing.problem.categoryMissing', 'The category no longer exists.')\n return t('staff.support.settings.routing.problem.projectUnusable', 'The project is completed, deleted, or has no default status.')\n }\n\n const nobodyNotifiedText = t(\n 'staff.support.settings.routing.nobodyNotified',\n \"No one in this project will be notified about tickets routed here: it has no active assigner, no usable default assignee and no owner. New tickets go to the organization's project managers instead.\",\n )\n const unnotifiedTicketCount = typeof preview.unnotifiedTicketCount === 'number' ? preview.unnotifiedTicketCount : 0\n\n const tableTranslations = React.useMemo(() => ({\n title: t('staff.support.settings.categories.title', 'Categories'),\n valueColumn: t('staff.support.settings.categories.value', 'Value'),\n labelColumn: t('staff.support.settings.categories.label', 'Label'),\n appearanceColumn: t('staff.support.settings.categories.appearance', 'Appearance'),\n addLabel: t('staff.support.settings.categories.add', 'Add category'),\n editLabel: t('staff.support.settings.actions.edit', 'Edit'),\n deleteLabel: t('staff.support.settings.actions.delete', 'Delete'),\n refreshLabel: t('staff.support.settings.actions.refresh', 'Refresh'),\n inheritedLabel: t('staff.support.settings.categories.inherited', 'Inherited'),\n inheritedTooltip: t('staff.support.settings.categories.inheritedTooltip', 'Defined by a parent organization.'),\n emptyLabel: t('staff.support.settings.categories.empty', 'No categories yet.'),\n searchPlaceholder: t('staff.support.settings.categories.search', 'Search categories'),\n }), [t])\n\n const categoryFormValues = React.useMemo<DictionaryFormValues>(() => {\n if (categoryDialog?.mode === 'edit') {\n return {\n value: categoryDialog.entry.value,\n label: categoryDialog.entry.label,\n color: categoryDialog.entry.color,\n icon: categoryDialog.entry.icon,\n }\n }\n return DEFAULT_CATEGORY_VALUES\n }, [categoryDialog])\n\n const categoryDialogTitle = categoryDialog?.mode === 'edit'\n ? t('staff.support.settings.categories.editTitle', 'Edit category')\n : t('staff.support.settings.categories.createTitle', 'Add category')\n\n return (\n <>\n <div className=\"space-y-6\">\n <p className=\"text-sm text-muted-foreground\">\n {t('staff.support.settings.description', 'Configure support ticket categories, where each category is routed, and the ticket reference prefix.')}\n </p>\n\n <section className=\"rounded-xl border border-border bg-card text-card-foreground\">\n <div className=\"space-y-1 border-b border-border px-6 py-4\">\n <h2 className=\"text-lg font-medium\">{t('staff.support.settings.categories.title', 'Categories')}</h2>\n <p className=\"text-sm text-muted-foreground\">\n {t('staff.support.settings.categories.description', 'Categories customers pick when they file a ticket in the portal.')}\n </p>\n </div>\n <div className=\"px-2 py-4 sm:px-4\">\n {chromeReady && !canViewCategories ? (\n <Alert status=\"information\">\n <AlertDescription>\n {t('staff.support.settings.categories.noAccess', 'You do not have permission to view the support categories.')}\n </AlertDescription>\n </Alert>\n ) : categoriesError ? (\n <ErrorMessage\n label={categoriesError}\n action={(\n <Button type=\"button\" variant=\"outline\" onClick={() => { void loadCategories() }}>\n {t('staff.support.settings.actions.retry', 'Try again')}\n </Button>\n )}\n />\n ) : !categoriesLoading && !dictionaryId ? (\n <Alert status=\"warning\">\n <AlertDescription>\n {t('staff.support.settings.categories.missingDictionary', 'The support categories dictionary has not been seeded for this organization yet.')}\n </AlertDescription>\n </Alert>\n ) : (\n <DictionaryTable\n entries={categoryEntries}\n loading={categoriesLoading}\n canManage={canManageCategories}\n onCreate={() => setCategoryDialog({ mode: 'create' })}\n onEdit={(entry) => setCategoryDialog({ mode: 'edit', entry: categoryEntries.find((row) => row.id === entry.id) ?? entry })}\n onDelete={(entry) => { void deleteCategory(categoryEntries.find((row) => row.id === entry.id) ?? entry) }}\n onRefresh={() => { void loadCategories() }}\n translations={tableTranslations}\n />\n )}\n </div>\n </section>\n\n <section className=\"rounded-xl border border-border bg-card text-card-foreground\">\n <div className=\"space-y-1 border-b border-border px-6 py-4\">\n <h2 className=\"text-lg font-medium\">{t('staff.support.settings.routing.title', 'Routing')}</h2>\n <p className=\"text-sm text-muted-foreground\">\n {t('staff.support.settings.routing.description', 'Every category without a working rule goes to the fallback project. Add a rule to send a category to its own project.')}\n </p>\n </div>\n <div className=\"space-y-6 px-6 py-4\">\n {routingLoading ? (\n <LoadingMessage label={t('staff.support.settings.routing.loading', 'Loading routing\u2026')} />\n ) : routingError ? (\n <ErrorMessage\n label={routingError}\n action={(\n <Button type=\"button\" variant=\"outline\" onClick={() => { void loadRouting() }}>\n {t('staff.support.settings.actions.retry', 'Try again')}\n </Button>\n )}\n />\n ) : (\n <>\n {unnotifiedTicketCount > 0 ? (\n <Alert status=\"warning\" data-testid=\"support-unnotified-tickets\">\n <AlertDescription>\n {unnotifiedTicketsLabel(unnotifiedTicketCount)}{' '}\n <Link className=\"font-medium underline\" href={UNNOTIFIED_INBOX_URL}>\n {t('staff.support.settings.routing.unnotifiedTicketsLink', 'Open them in the Support Inbox')}\n </Link>\n </AlertDescription>\n </Alert>\n ) : null}\n {!preview.fallback ? (\n <Alert\n status=\"warning\"\n footer={(\n <Button type=\"button\" onClick={() => { void createFallbackProject() }} disabled={creatingFallback || !canManageSettings}>\n <Plus className=\"mr-2 h-4 w-4\" />\n {t('staff.support.settings.routing.createFallback', 'Create fallback project')}\n </Button>\n )}\n >\n <AlertTitle>{t('staff.support.settings.routing.noFallbackTitle', 'No fallback project')}</AlertTitle>\n <AlertDescription>\n {t('staff.support.settings.routing.noFallbackDescription', 'Customers cannot file tickets for categories without their own rule until a fallback project exists.')}\n </AlertDescription>\n </Alert>\n ) : (\n <div className=\"space-y-3\">\n {!preview.fallback.project.usable ? (\n <Alert status=\"error\">\n <AlertTitle>{t('staff.support.settings.routing.fallbackUnusableTitle', 'The fallback project cannot receive tickets')}</AlertTitle>\n <AlertDescription>\n {t('staff.support.settings.routing.fallbackUnusableDescription', 'It is completed, deleted, or has no default status. Point the fallback rule at another project.')}\n </AlertDescription>\n </Alert>\n ) : null}\n {preview.fallback.project.nobodyNotified === true ? (\n <Alert status=\"warning\" data-testid=\"support-fallback-nobody-notified\">\n <AlertDescription>{nobodyNotifiedText}</AlertDescription>\n </Alert>\n ) : null}\n <div className=\"max-w-md space-y-2\">\n <Label id=\"support-fallback-project-label\">\n {t('staff.support.settings.routing.fallbackProject', 'Fallback project')}\n </Label>\n <SupportProjectPicker\n labelId=\"support-fallback-project-label\"\n testId=\"support-fallback-project\"\n value={preview.fallback.project.id}\n knownProjects={knownProjects}\n placeholder={t('staff.support.settings.routing.searchProject', 'Search projects')}\n disabled={!canManageSettings}\n onChange={(projectId) => {\n if (preview.fallback) {\n void updateRule(preview.fallback.ruleId, routingRuleVersion(preview.fallback), { timeProjectId: projectId })\n }\n }}\n />\n </div>\n </div>\n )}\n\n <div className=\"space-y-3\">\n <div className=\"flex items-center justify-between gap-2\">\n <h3 className=\"text-base font-medium\">{t('staff.support.settings.routing.overrides', 'Category rules')}</h3>\n <Button\n type=\"button\"\n variant=\"outline\"\n disabled={categoriesWithoutRule.length === 0 || !canManageSettings}\n onClick={() => setRuleDialog({\n mode: 'create',\n categoryValue: categoriesWithoutRule[0]?.value ?? '',\n timeProjectId: '',\n })}\n >\n <Plus className=\"mr-2 h-4 w-4\" />\n {t('staff.support.settings.routing.addRule', 'Add rule')}\n </Button>\n </div>\n {overrides.length === 0 ? (\n <p className=\"text-sm text-muted-foreground\">\n {t('staff.support.settings.routing.noOverrides', 'No category rules. Every category goes to the fallback project.')}\n </p>\n ) : (\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead>{t('staff.support.settings.routing.category', 'Category')}</TableHead>\n <TableHead>{t('staff.support.settings.routing.project', 'Project')}</TableHead>\n <TableHead>{t('staff.support.settings.routing.active', 'Active')}</TableHead>\n <TableHead>{t('staff.support.settings.routing.state', 'State')}</TableHead>\n <TableHead className=\"w-24\" />\n </TableRow>\n </TableHeader>\n <TableBody>\n {overrides.map((rule) => (\n <TableRow key={rule.id}>\n <TableCell>{categoryLabels.get(rule.categoryValue ?? '') ?? rule.categoryValue}</TableCell>\n <TableCell>\n <div className=\"space-y-1\">\n <span>{projectLabel(rule.project)}</span>\n {rule.project.nobodyNotified === true ? (\n <Alert status=\"warning\" size=\"xs\" data-testid=\"support-rule-nobody-notified\">\n <AlertDescription>{nobodyNotifiedText}</AlertDescription>\n </Alert>\n ) : null}\n </div>\n </TableCell>\n <TableCell>\n <Switch\n checked={rule.isActive}\n disabled={!canManageSettings}\n aria-label={t('staff.support.settings.routing.active', 'Active')}\n onCheckedChange={(checked) => { void updateRule(rule.id, routingRuleVersion(rule), { isActive: checked }) }}\n />\n </TableCell>\n <TableCell>\n {rule.problem ? (\n <div className=\"space-y-1\">\n <StatusBadge variant=\"warning\" dot>\n {t('staff.support.settings.routing.fallingBack', 'Falling back to {project}', { project: fallbackName })}\n </StatusBadge>\n <p className=\"text-xs text-muted-foreground\">{problemText(rule.problem)}</p>\n </div>\n ) : (\n <StatusBadge variant=\"success\" dot>\n {t('staff.support.settings.routing.routing', 'Routing')}\n </StatusBadge>\n )}\n </TableCell>\n <TableCell>\n <div className=\"flex justify-end gap-1\">\n <IconButton\n type=\"button\"\n variant=\"ghost\"\n aria-label={t('staff.support.settings.actions.edit', 'Edit')}\n disabled={!canManageSettings}\n onClick={() => setRuleDialog(buildRoutingRuleEditDraft(rule))}\n >\n <Pencil className=\"h-4 w-4\" />\n </IconButton>\n <IconButton\n type=\"button\"\n variant=\"ghost\"\n aria-label={t('staff.support.settings.actions.delete', 'Delete')}\n disabled={!canManageSettings}\n onClick={() => { void deleteRule(rule) }}\n >\n <Trash2 className=\"h-4 w-4\" />\n </IconButton>\n </div>\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n )}\n </div>\n\n <div className=\"space-y-3\">\n <h3 className=\"text-base font-medium\">{t('staff.support.settings.preview.title', 'Where tickets go now')}</h3>\n {preview.categories.length === 0 ? (\n <p className=\"text-sm text-muted-foreground\">\n {t('staff.support.settings.preview.empty', 'No categories to route.')}\n </p>\n ) : (\n <Table>\n <TableHeader>\n <TableRow>\n <TableHead>{t('staff.support.settings.routing.category', 'Category')}</TableHead>\n <TableHead>{t('staff.support.settings.routing.project', 'Project')}</TableHead>\n <TableHead>{t('staff.support.settings.preview.via', 'Routed by')}</TableHead>\n </TableRow>\n </TableHeader>\n <TableBody>\n {preview.categories.map((category) => (\n <TableRow key={category.value}>\n <TableCell>{category.label}</TableCell>\n <TableCell>\n {category.route ? projectLabel(category.route.project) : (\n <StatusBadge variant=\"error\" dot>\n {t('staff.support.settings.preview.unavailable', 'Not available on portal')}\n </StatusBadge>\n )}\n </TableCell>\n <TableCell>\n {category.route\n ? category.route.via === 'category'\n ? t('staff.support.settings.preview.viaCategory', 'Category rule')\n : t('staff.support.settings.preview.viaFallback', 'Fallback rule')\n : '\u2014'}\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n )}\n </div>\n </>\n )}\n </div>\n </section>\n\n <section className=\"rounded-xl border border-border bg-card text-card-foreground\">\n <div className=\"space-y-1 border-b border-border px-6 py-4\">\n <h2 className=\"text-lg font-medium\">{t('staff.support.settings.prefix.title', 'Reference prefix')}</h2>\n <p className=\"text-sm text-muted-foreground\">\n {t('staff.support.settings.prefix.description', 'Customers see ticket references such as SUP-1042. The prefix applies to the whole tenant.')}\n </p>\n </div>\n <div className=\"px-6 py-4\">\n <div className=\"flex max-w-md items-end gap-2\">\n <div className=\"flex-1 space-y-2\">\n <Label htmlFor=\"support-reference-prefix\">{t('staff.support.settings.referencePrefix', 'Reference prefix')}</Label>\n <Input\n id=\"support-reference-prefix\"\n value={prefix}\n maxLength={10}\n disabled={!canManageSettings}\n onChange={(event) => setPrefix(event.target.value.toUpperCase())}\n aria-invalid={prefixError ? true : undefined}\n />\n {prefixError ? <p className=\"text-sm text-status-error-text\">{prefixError}</p> : null}\n </div>\n <Button type=\"button\" onClick={() => { void savePrefix() }} disabled={prefixSaving || !canManageSettings}>\n <Save className=\"mr-2 h-4 w-4\" />\n {t('staff.support.settings.actions.save', 'Save')}\n </Button>\n </div>\n </div>\n </section>\n </div>\n\n <Dialog open={categoryDialog !== null} onOpenChange={(open) => { if (!open) setCategoryDialog(null) }}>\n <DialogContent\n className=\"max-w-lg\"\n onKeyDown={(event) => {\n if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') {\n event.preventDefault()\n if (categorySubmitting) return\n event.currentTarget.querySelector('form')?.requestSubmit()\n }\n }}\n >\n <DialogHeader>\n <DialogTitle>{categoryDialogTitle}</DialogTitle>\n </DialogHeader>\n <DictionaryForm\n mode={categoryDialog?.mode === 'edit' ? 'edit' : 'create'}\n initialValues={categoryFormValues}\n onSubmit={submitCategory}\n onCancel={() => setCategoryDialog(null)}\n submitting={categorySubmitting}\n translations={{\n title: categoryDialogTitle,\n valueLabel: t('staff.support.settings.categories.value', 'Value'),\n labelLabel: t('staff.support.settings.categories.label', 'Label'),\n saveLabel: t('staff.support.settings.actions.save', 'Save'),\n cancelLabel: t('staff.support.settings.actions.cancel', 'Cancel'),\n appearance: {\n colorLabel: t('staff.support.settings.categories.colorLabel', 'Color'),\n colorHelp: t('staff.support.settings.categories.colorHelp', 'Shown as the category badge color.'),\n colorClearLabel: t('staff.support.settings.categories.colorClear', 'Clear color'),\n iconLabel: t('staff.support.settings.categories.iconLabel', 'Icon'),\n iconPlaceholder: t('staff.support.settings.categories.iconPlaceholder', 'Icon name'),\n iconPickerTriggerLabel: t('staff.support.settings.categories.iconBrowse', 'Browse icons'),\n iconSearchPlaceholder: t('staff.support.settings.categories.iconSearchPlaceholder', 'Search icons'),\n iconSearchEmptyLabel: t('staff.support.settings.categories.iconSearchEmpty', 'No icons found.'),\n iconSuggestionsLabel: t('staff.support.settings.categories.iconSuggestions', 'Suggestions'),\n iconClearLabel: t('staff.support.settings.categories.iconClear', 'Clear icon'),\n previewEmptyLabel: t('staff.support.settings.categories.previewEmpty', 'No appearance'),\n },\n }}\n iconSuggestions={ICON_SUGGESTIONS}\n />\n </DialogContent>\n </Dialog>\n\n <Dialog open={ruleDialog !== null} onOpenChange={(open) => { if (!open) setRuleDialog(null) }}>\n <DialogContent\n className=\"max-w-lg\"\n onKeyDown={(event) => {\n if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') {\n event.preventDefault()\n if (ruleSubmitting) return\n void submitRuleDialog()\n }\n }}\n >\n <DialogHeader>\n <DialogTitle>\n {ruleDialog?.mode === 'edit'\n ? t('staff.support.settings.routing.editRuleTitle', 'Edit rule')\n : t('staff.support.settings.routing.addRuleTitle', 'Add rule')}\n </DialogTitle>\n </DialogHeader>\n {ruleDialog ? (\n <form\n className=\"space-y-4\"\n onSubmit={(event) => {\n event.preventDefault()\n void submitRuleDialog()\n }}\n >\n <div className=\"space-y-2\">\n <Label htmlFor=\"support-rule-category\">{t('staff.support.settings.routing.category', 'Category')}</Label>\n {ruleDialog.mode === 'create' ? (\n <Select\n value={ruleDialog.categoryValue}\n onValueChange={(value) => setRuleDialog({ ...ruleDialog, categoryValue: value })}\n >\n <SelectTrigger id=\"support-rule-category\">\n <SelectValue placeholder={t('staff.support.settings.routing.selectCategory', 'Select a category')} />\n </SelectTrigger>\n <SelectContent>\n {categoriesWithoutRule.map((category) => (\n <SelectItem key={category.value} value={category.value}>{category.label}</SelectItem>\n ))}\n </SelectContent>\n </Select>\n ) : (\n <p id=\"support-rule-category\" className=\"text-sm\">\n {categoryLabels.get(ruleDialog.categoryValue) ?? ruleDialog.categoryValue}\n </p>\n )}\n </div>\n <div className=\"space-y-2\">\n <Label id=\"support-rule-project-label\">{t('staff.support.settings.routing.project', 'Project')}</Label>\n <SupportProjectPicker\n labelId=\"support-rule-project-label\"\n testId=\"support-rule-project\"\n value={ruleDialog.timeProjectId}\n knownProjects={knownProjects}\n placeholder={t('staff.support.settings.routing.selectProject', 'Select a project')}\n onChange={(projectId) => setRuleDialog({ ...ruleDialog, timeProjectId: projectId })}\n />\n </div>\n <div className=\"flex justify-end gap-2\">\n <Button type=\"button\" variant=\"outline\" onClick={() => setRuleDialog(null)}>\n {t('staff.support.settings.actions.cancel', 'Cancel')}\n </Button>\n <Button\n type=\"submit\"\n disabled={ruleSubmitting || !ruleDialog.timeProjectId || (ruleDialog.mode === 'create' && !ruleDialog.categoryValue)}\n >\n {t('staff.support.settings.actions.save', 'Save')}\n </Button>\n </div>\n </form>\n ) : null}\n </DialogContent>\n </Dialog>\n {ConfirmDialogElement}\n </>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["call"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import SupportSettingsTab from "./widget.client.js";
|
|
2
|
+
const widget = {
|
|
3
|
+
metadata: {
|
|
4
|
+
id: "staff.injection.time-tracking-settings-support",
|
|
5
|
+
title: "Support",
|
|
6
|
+
description: "Support ticket categories, routing to projects and the ticket reference prefix.",
|
|
7
|
+
features: ["staff.timesheets.settings.manage"],
|
|
8
|
+
priority: 50,
|
|
9
|
+
enabled: true
|
|
10
|
+
},
|
|
11
|
+
Widget: SupportSettingsTab
|
|
12
|
+
};
|
|
13
|
+
var widget_default = widget;
|
|
14
|
+
export {
|
|
15
|
+
widget_default as default
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=widget.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../src/modules/staff/widgets/injection/time-tracking-settings-support/widget.ts"],
|
|
4
|
+
"sourcesContent": ["import type { InjectionWidgetModule } from '@open-mercato/shared/modules/widgets/injection'\nimport type { TimeTrackingSettingsTabContext } from '../../../lib/time-tracking-ui/settingsTabs'\nimport SupportSettingsTab from './widget.client'\n\nconst widget: InjectionWidgetModule<TimeTrackingSettingsTabContext> = {\n metadata: {\n id: 'staff.injection.time-tracking-settings-support',\n title: 'Support',\n description: 'Support ticket categories, routing to projects and the ticket reference prefix.',\n features: ['staff.timesheets.settings.manage'],\n priority: 50,\n enabled: true,\n },\n Widget: SupportSettingsTab,\n}\n\nexport default widget\n"],
|
|
5
|
+
"mappings": "AAEA,OAAO,wBAAwB;AAE/B,MAAM,SAAgE;AAAA,EACpE,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,aAAa;AAAA,IACb,UAAU,CAAC,kCAAkC;AAAA,IAC7C,UAAU;AAAA,IACV,SAAS;AAAA,EACX;AAAA,EACA,QAAQ;AACV;AAEA,IAAO,iBAAQ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -2,7 +2,22 @@ const injectionTable = {
|
|
|
2
2
|
"backend:sidebar:nav:footer": {
|
|
3
3
|
widgetId: "staff.injection.timer-sidebar-indicator",
|
|
4
4
|
priority: 90
|
|
5
|
-
}
|
|
5
|
+
},
|
|
6
|
+
"staff.time_tracking.settings:tabs": [
|
|
7
|
+
{
|
|
8
|
+
widgetId: "staff.injection.time-tracking-settings-support",
|
|
9
|
+
kind: "tab",
|
|
10
|
+
groupId: "support",
|
|
11
|
+
groupLabel: "staff.support.settings.title",
|
|
12
|
+
priority: 50
|
|
13
|
+
}
|
|
14
|
+
],
|
|
15
|
+
"portal:dashboard:sections": [
|
|
16
|
+
{
|
|
17
|
+
widgetId: "staff.injection.portal-support-tickets",
|
|
18
|
+
priority: 20
|
|
19
|
+
}
|
|
20
|
+
]
|
|
6
21
|
};
|
|
7
22
|
var injection_table_default = injectionTable;
|
|
8
23
|
export {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/staff/widgets/injection-table.ts"],
|
|
4
|
-
"sourcesContent": ["import type { ModuleInjectionTable } from '@open-mercato/shared/modules/widgets/injection'\n\nexport const injectionTable: ModuleInjectionTable = {\n 'backend:sidebar:nav:footer': {\n widgetId: 'staff.injection.timer-sidebar-indicator',\n priority: 90,\n },\n}\n\nexport default injectionTable\n"],
|
|
5
|
-
"mappings": "AAEO,MAAM,iBAAuC;AAAA,EAClD,8BAA8B;AAAA,IAC5B,UAAU;AAAA,IACV,UAAU;AAAA,EACZ;AACF;AAEA,IAAO,0BAAQ;",
|
|
4
|
+
"sourcesContent": ["import type { ModuleInjectionTable } from '@open-mercato/shared/modules/widgets/injection'\n\nexport const injectionTable: ModuleInjectionTable = {\n 'backend:sidebar:nav:footer': {\n widgetId: 'staff.injection.timer-sidebar-indicator',\n priority: 90,\n },\n 'staff.time_tracking.settings:tabs': [\n {\n widgetId: 'staff.injection.time-tracking-settings-support',\n kind: 'tab',\n groupId: 'support',\n groupLabel: 'staff.support.settings.title',\n priority: 50,\n },\n ],\n 'portal:dashboard:sections': [\n {\n widgetId: 'staff.injection.portal-support-tickets',\n priority: 20,\n },\n ],\n}\n\nexport default injectionTable\n"],
|
|
5
|
+
"mappings": "AAEO,MAAM,iBAAuC;AAAA,EAClD,8BAA8B;AAAA,IAC5B,UAAU;AAAA,IACV,UAAU;AAAA,EACZ;AAAA,EACA,qCAAqC;AAAA,IACnC;AAAA,MACE,UAAU;AAAA,MACV,MAAM;AAAA,MACN,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,UAAU;AAAA,IACZ;AAAA,EACF;AAAA,EACA,6BAA6B;AAAA,IAC3B;AAAA,MACE,UAAU;AAAA,MACV,UAAU;AAAA,IACZ;AAAA,EACF;AACF;AAEA,IAAO,0BAAQ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -22,6 +22,7 @@ import { ErrorMessage, LoadingMessage, RecordNotFoundState } from "@open-mercato
|
|
|
22
22
|
import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
|
|
23
23
|
import { raiseCrudError } from "@open-mercato/ui/backend/utils/serverErrors";
|
|
24
24
|
import { useLocale, useT } from "@open-mercato/shared/lib/i18n/context";
|
|
25
|
+
import { downloadInventoryCsv } from "../../lib/inventoryCsvExport.js";
|
|
25
26
|
import { Button } from "@open-mercato/ui/primitives/button";
|
|
26
27
|
import { LinkButton } from "@open-mercato/ui/primitives/link-button";
|
|
27
28
|
import { Progress } from "@open-mercato/ui/primitives/progress";
|
|
@@ -45,21 +46,6 @@ import { LocationEditDialog } from "./LocationEditDialog.js";
|
|
|
45
46
|
import { useWmsInventoryMutationAccess } from "./useWmsInventoryMutationAccess.js";
|
|
46
47
|
const locationIdSchema = z.string().uuid();
|
|
47
48
|
const NEAR_EXPIRY_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
48
|
-
function escapeCsvCell(value) {
|
|
49
|
-
const str = String(value ?? "");
|
|
50
|
-
if (/[",\n]/.test(str)) return `"${str.replace(/"/g, '""')}"`;
|
|
51
|
-
return str;
|
|
52
|
-
}
|
|
53
|
-
function downloadCsvFile(filename, rows) {
|
|
54
|
-
const csv = rows.map((row) => row.map(escapeCsvCell).join(",")).join("\n");
|
|
55
|
-
const blob = new Blob([csv], { type: "text/csv;charset=utf-8;" });
|
|
56
|
-
const url = URL.createObjectURL(blob);
|
|
57
|
-
const anchor = document.createElement("a");
|
|
58
|
-
anchor.href = url;
|
|
59
|
-
anchor.download = filename;
|
|
60
|
-
anchor.click();
|
|
61
|
-
URL.revokeObjectURL(url);
|
|
62
|
-
}
|
|
63
49
|
function toNumber(value) {
|
|
64
50
|
const parsed = Number(value ?? 0);
|
|
65
51
|
return Number.isFinite(parsed) ? parsed : 0;
|
|
@@ -566,13 +552,13 @@ function WmsLocationDetailPage({ locationId }) {
|
|
|
566
552
|
formatSkuLabel(row),
|
|
567
553
|
formatVariantName(row),
|
|
568
554
|
formatLotLabel(lot, locale),
|
|
569
|
-
|
|
570
|
-
|
|
555
|
+
toNumber(row.quantity_on_hand),
|
|
556
|
+
toNumber(row.quantity_reserved),
|
|
571
557
|
t(status.labelKey, status.labelFallback)
|
|
572
558
|
];
|
|
573
559
|
});
|
|
574
560
|
const safeCode = pageTitle.replace(/[^\w.-]+/g, "-").replace(/^-+|-+$/g, "") || "location";
|
|
575
|
-
|
|
561
|
+
downloadInventoryCsv(`${safeCode}-items.csv`, [headers, ...rows]);
|
|
576
562
|
}, [filteredBalances, locale, lotById, nowMs, pageTitle, reorderPointByVariant, t]);
|
|
577
563
|
const warehouseLabel = formatWarehouseLabel(locationQuery.data ?? {});
|
|
578
564
|
const subtitleParts = [
|