@open-mercato/core 0.6.6-develop.6465.1.019f0fb26f → 0.6.6-develop.6471.1.9ab5bdd79a
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/dist/bootstrap.js +13 -11
- package/dist/bootstrap.js.map +2 -2
- package/dist/helpers/integration/queue-runner.js +4 -2
- package/dist/helpers/integration/queue-runner.js.map +2 -2
- package/dist/modules/api_keys/services/apiKeyService.js +5 -3
- package/dist/modules/api_keys/services/apiKeyService.js.map +2 -2
- package/dist/modules/attachments/api/image/[id]/[[...slug]]/route.js +4 -2
- package/dist/modules/attachments/api/image/[id]/[[...slug]]/route.js.map +2 -2
- package/dist/modules/attachments/api/library/[id]/route.js +3 -1
- package/dist/modules/attachments/api/library/[id]/route.js.map +2 -2
- package/dist/modules/attachments/api/route.js +8 -6
- package/dist/modules/attachments/api/route.js.map +2 -2
- package/dist/modules/attachments/components/AttachmentPartitionSettings.js +5 -3
- package/dist/modules/attachments/components/AttachmentPartitionSettings.js.map +2 -2
- package/dist/modules/attachments/lib/assignmentDetails.js +3 -1
- package/dist/modules/attachments/lib/assignmentDetails.js.map +2 -2
- package/dist/modules/attachments/lib/drivers/driverFactory.js +3 -1
- package/dist/modules/attachments/lib/drivers/driverFactory.js.map +2 -2
- package/dist/modules/attachments/lib/ocrQueue.js +10 -11
- package/dist/modules/attachments/lib/ocrQueue.js.map +2 -2
- package/dist/modules/attachments/lib/ocrService.js +6 -4
- package/dist/modules/attachments/lib/ocrService.js.map +2 -2
- package/dist/modules/audit_logs/api/audit-logs/actions/redo/route.js +3 -1
- package/dist/modules/audit_logs/api/audit-logs/actions/redo/route.js.map +2 -2
- package/dist/modules/audit_logs/api/audit-logs/actions/undo/route.js +3 -1
- package/dist/modules/audit_logs/api/audit-logs/actions/undo/route.js.map +2 -2
- package/dist/modules/audit_logs/backend/audit-logs/page.js +3 -1
- package/dist/modules/audit_logs/backend/audit-logs/page.js.map +2 -2
- package/dist/modules/audit_logs/components/AuditLogsActions.js +4 -2
- package/dist/modules/audit_logs/components/AuditLogsActions.js.map +2 -2
- package/dist/modules/audit_logs/services/accessLogService.js +4 -2
- package/dist/modules/audit_logs/services/accessLogService.js.map +2 -2
- package/dist/modules/audit_logs/services/actionLogService.js +7 -5
- package/dist/modules/audit_logs/services/actionLogService.js.map +3 -3
- package/dist/modules/auth/api/profile/route.js +4 -2
- package/dist/modules/auth/api/profile/route.js.map +2 -2
- package/dist/modules/auth/api/reset/confirm.js +3 -1
- package/dist/modules/auth/api/reset/confirm.js.map +2 -2
- package/dist/modules/auth/api/reset.js +4 -2
- package/dist/modules/auth/api/reset.js.map +2 -2
- package/dist/modules/auth/api/roles/route.js +3 -1
- package/dist/modules/auth/api/roles/route.js.map +2 -2
- package/dist/modules/auth/api/sidebar/variants/route.js +3 -1
- package/dist/modules/auth/api/sidebar/variants/route.js.map +2 -2
- package/dist/modules/auth/api/users/resend-invite/route.js +4 -2
- package/dist/modules/auth/api/users/resend-invite/route.js.map +2 -2
- package/dist/modules/auth/api/users/route.js +3 -1
- package/dist/modules/auth/api/users/route.js.map +2 -2
- package/dist/modules/auth/backend/auth/profile/page.js +3 -1
- package/dist/modules/auth/backend/auth/profile/page.js.map +2 -2
- package/dist/modules/auth/backend/profile/change-password/page.js +3 -1
- package/dist/modules/auth/backend/profile/change-password/page.js.map +2 -2
- package/dist/modules/auth/backend/users/[id]/edit/page.js +5 -3
- package/dist/modules/auth/backend/users/[id]/edit/page.js.map +2 -2
- package/dist/modules/auth/backend/users/create/page.js +4 -2
- package/dist/modules/auth/backend/users/create/page.js.map +2 -2
- package/dist/modules/auth/cli.js +10 -0
- package/dist/modules/auth/cli.js.map +2 -2
- package/dist/modules/auth/commands/users.js +4 -2
- package/dist/modules/auth/commands/users.js.map +2 -2
- package/dist/modules/auth/lib/consentIntegrity.js +3 -3
- package/dist/modules/auth/lib/consentIntegrity.js.map +2 -2
- package/dist/modules/auth/lib/setup-app.js +9 -10
- package/dist/modules/auth/lib/setup-app.js.map +2 -2
- package/dist/modules/auth/lib/tenantAccess.js +3 -1
- package/dist/modules/auth/lib/tenantAccess.js.map +2 -2
- package/dist/modules/auth/lib/tokenHash.js +3 -3
- package/dist/modules/auth/lib/tokenHash.js.map +2 -2
- package/dist/modules/business_rules/api/rules/route.js +4 -2
- package/dist/modules/business_rules/api/rules/route.js.map +2 -2
- package/dist/modules/business_rules/lib/expression-evaluator.js +7 -5
- package/dist/modules/business_rules/lib/expression-evaluator.js.map +2 -2
- package/dist/modules/business_rules/lib/rule-engine.js +5 -3
- package/dist/modules/business_rules/lib/rule-engine.js.map +2 -2
- package/dist/modules/business_rules/lib/rule-evaluator.js +11 -12
- package/dist/modules/business_rules/lib/rule-evaluator.js.map +2 -2
- package/dist/modules/business_rules/subscribers/crud-rule-trigger.js +3 -1
- package/dist/modules/business_rules/subscribers/crud-rule-trigger.js.map +2 -2
- package/dist/modules/business_rules/subscribers/rule-execution-failed-notification.js +3 -1
- package/dist/modules/business_rules/subscribers/rule-execution-failed-notification.js.map +2 -2
- package/dist/modules/catalog/ai-agents-context.js +4 -5
- package/dist/modules/catalog/ai-agents-context.js.map +2 -2
- package/dist/modules/catalog/ai-tools/_shared.js +3 -1
- package/dist/modules/catalog/ai-tools/_shared.js.map +2 -2
- package/dist/modules/catalog/ai-tools/authoring-pack.js +3 -1
- package/dist/modules/catalog/ai-tools/authoring-pack.js.map +2 -2
- package/dist/modules/catalog/ai-tools/merchandising-pack.js +3 -1
- package/dist/modules/catalog/ai-tools/merchandising-pack.js.map +2 -2
- package/dist/modules/catalog/api/dictionaries/[key]/route.js +3 -1
- package/dist/modules/catalog/api/dictionaries/[key]/route.js.map +2 -2
- package/dist/modules/catalog/api/prices/route.js +3 -1
- package/dist/modules/catalog/api/prices/route.js.map +2 -2
- package/dist/modules/catalog/api/products/route.js +5 -3
- package/dist/modules/catalog/api/products/route.js.map +2 -2
- package/dist/modules/catalog/api/settings/route.js +4 -2
- package/dist/modules/catalog/api/settings/route.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/[id]/page.js +14 -12
- package/dist/modules/catalog/backend/catalog/products/[id]/page.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js +8 -6
- package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/[productId]/variants/create/page.js +5 -3
- package/dist/modules/catalog/backend/catalog/products/[productId]/variants/create/page.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/create/page.js +5 -6
- package/dist/modules/catalog/backend/catalog/products/create/page.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/optionSchemaClient.js +3 -1
- package/dist/modules/catalog/backend/catalog/products/optionSchemaClient.js.map +2 -2
- package/dist/modules/catalog/components/PriceKindSettings.js +5 -3
- package/dist/modules/catalog/components/PriceKindSettings.js.map +2 -2
- package/dist/modules/catalog/components/UnitPriceDisplaySettings.js +4 -2
- package/dist/modules/catalog/components/UnitPriceDisplaySettings.js.map +2 -2
- package/dist/modules/catalog/inbox-actions.js +4 -2
- package/dist/modules/catalog/inbox-actions.js.map +2 -2
- package/dist/modules/catalog/seed/examples.js +4 -5
- package/dist/modules/catalog/seed/examples.js.map +2 -2
- package/dist/modules/catalog/subscribers/low-stock-notification.js +3 -1
- package/dist/modules/catalog/subscribers/low-stock-notification.js.map +2 -2
- package/dist/modules/catalog/widgets/injection/product-seo/state.js +3 -1
- package/dist/modules/catalog/widgets/injection/product-seo/state.js.map +2 -2
- package/dist/modules/communication_channels/api/get/oauth/[provider]/callback/route.js +12 -11
- package/dist/modules/communication_channels/api/get/oauth/[provider]/callback/route.js.map +2 -2
- package/dist/modules/communication_channels/api/post/channels/[id]/import-history/route.js +3 -1
- package/dist/modules/communication_channels/api/post/channels/[id]/import-history/route.js.map +2 -2
- package/dist/modules/communication_channels/api/post/channels/[id]/push/register/route.js +3 -1
- package/dist/modules/communication_channels/api/post/channels/[id]/push/register/route.js.map +2 -2
- package/dist/modules/communication_channels/api/post/webhook/[provider]/route.js +5 -3
- package/dist/modules/communication_channels/api/post/webhook/[provider]/route.js.map +2 -2
- package/dist/modules/communication_channels/api/post/webhooks/gmail/route.js +6 -6
- package/dist/modules/communication_channels/api/post/webhooks/gmail/route.js.map +2 -2
- package/dist/modules/communication_channels/commands/connect-credential-channel.js +4 -6
- package/dist/modules/communication_channels/commands/connect-credential-channel.js.map +2 -2
- package/dist/modules/communication_channels/commands/delete-channel.js +3 -3
- package/dist/modules/communication_channels/commands/delete-channel.js.map +2 -2
- package/dist/modules/communication_channels/commands/deliver-outbound-message.js +4 -5
- package/dist/modules/communication_channels/commands/deliver-outbound-message.js.map +2 -2
- package/dist/modules/communication_channels/commands/disconnect-channel.js +3 -3
- package/dist/modules/communication_channels/commands/disconnect-channel.js.map +2 -2
- package/dist/modules/communication_channels/commands/ingest-inbound-message.js +5 -12
- package/dist/modules/communication_channels/commands/ingest-inbound-message.js.map +2 -2
- package/dist/modules/communication_channels/commands/push-unregister.js +3 -3
- package/dist/modules/communication_channels/commands/push-unregister.js.map +2 -2
- package/dist/modules/communication_channels/commands/reassign-conversation.js +5 -3
- package/dist/modules/communication_channels/commands/reassign-conversation.js.map +2 -2
- package/dist/modules/communication_channels/lib/dead-letter.js +3 -3
- package/dist/modules/communication_channels/lib/dead-letter.js.map +2 -2
- package/dist/modules/communication_channels/lib/email-mime.js +4 -6
- package/dist/modules/communication_channels/lib/email-mime.js.map +2 -2
- package/dist/modules/communication_channels/lib/oauth-client-config.js +5 -3
- package/dist/modules/communication_channels/lib/oauth-client-config.js.map +2 -2
- package/dist/modules/communication_channels/lib/send-as-user.js +3 -1
- package/dist/modules/communication_channels/lib/send-as-user.js.map +2 -2
- package/dist/modules/communication_channels/lib/thread-token.js +4 -2
- package/dist/modules/communication_channels/lib/thread-token.js.map +2 -2
- package/dist/modules/communication_channels/setup.js +3 -4
- package/dist/modules/communication_channels/setup.js.map +2 -2
- package/dist/modules/communication_channels/workers/channel-import-history.js +4 -6
- package/dist/modules/communication_channels/workers/channel-import-history.js.map +2 -2
- package/dist/modules/communication_channels/workers/gmail-history-sync.js +8 -16
- package/dist/modules/communication_channels/workers/gmail-history-sync.js.map +2 -2
- package/dist/modules/communication_channels/workers/gmail-renew-watch.js +5 -7
- package/dist/modules/communication_channels/workers/gmail-renew-watch.js.map +2 -2
- package/dist/modules/communication_channels/workers/outbound-delivery.js +6 -12
- package/dist/modules/communication_channels/workers/outbound-delivery.js.map +2 -2
- package/dist/modules/communication_channels/workers/poll-channel.js +7 -15
- package/dist/modules/communication_channels/workers/poll-channel.js.map +2 -2
- package/dist/modules/communication_channels/workers/poll-tick.js +5 -6
- package/dist/modules/communication_channels/workers/poll-tick.js.map +2 -2
- package/dist/modules/communication_channels/workers/reaction-processor.js +5 -9
- package/dist/modules/communication_channels/workers/reaction-processor.js.map +2 -2
- package/dist/modules/configs/api/cache/route.js +4 -2
- package/dist/modules/configs/api/cache/route.js.map +2 -2
- package/dist/modules/configs/api/system-status/route.js +4 -2
- package/dist/modules/configs/api/system-status/route.js.map +2 -2
- package/dist/modules/configs/api/upgrade-actions/route.js +4 -2
- package/dist/modules/configs/api/upgrade-actions/route.js.map +2 -2
- package/dist/modules/configs/components/ModuleTelemetryPanel.js +3 -1
- package/dist/modules/configs/components/ModuleTelemetryPanel.js.map +2 -2
- package/dist/modules/configs/lib/touchGeneratedBarrels.js +2 -1
- package/dist/modules/configs/lib/touchGeneratedBarrels.js.map +2 -2
- package/dist/modules/configs/services/upgradeActionsService.js +6 -3
- package/dist/modules/configs/services/upgradeActionsService.js.map +2 -2
- package/dist/modules/currencies/components/CurrencyFetchingConfig.js +3 -1
- package/dist/modules/currencies/components/CurrencyFetchingConfig.js.map +2 -2
- package/dist/modules/currencies/lib/exchangeRateFormConfig.js +3 -1
- package/dist/modules/currencies/lib/exchangeRateFormConfig.js.map +2 -2
- package/dist/modules/currencies/services/providers/nbp.js +6 -4
- package/dist/modules/currencies/services/providers/nbp.js.map +2 -2
- package/dist/modules/currencies/services/providers/raiffeisen.js +7 -7
- package/dist/modules/currencies/services/providers/raiffeisen.js.map +2 -2
- package/dist/modules/customer_accounts/api/domain-resolve/all.js +6 -5
- package/dist/modules/customer_accounts/api/domain-resolve/all.js.map +2 -2
- package/dist/modules/customer_accounts/api/signup.js +4 -2
- package/dist/modules/customer_accounts/api/signup.js.map +2 -2
- package/dist/modules/customer_accounts/lib/customerAuthServer.js +3 -1
- package/dist/modules/customer_accounts/lib/customerAuthServer.js.map +2 -2
- package/dist/modules/customer_accounts/subscribers/autoLinkCrm.js +3 -1
- package/dist/modules/customer_accounts/subscribers/autoLinkCrm.js.map +2 -2
- package/dist/modules/customer_accounts/subscribers/autoLinkCrmReverse.js +3 -1
- package/dist/modules/customer_accounts/subscribers/autoLinkCrmReverse.js.map +2 -2
- package/dist/modules/customer_accounts/subscribers/unlinkOnCompanyDelete.js +3 -1
- package/dist/modules/customer_accounts/subscribers/unlinkOnCompanyDelete.js.map +2 -2
- package/dist/modules/customer_accounts/subscribers/unlinkOnPersonDelete.js +3 -1
- package/dist/modules/customer_accounts/subscribers/unlinkOnPersonDelete.js.map +2 -2
- package/dist/modules/customers/ai-agents-context.js +4 -5
- package/dist/modules/customers/ai-agents-context.js.map +2 -2
- package/dist/modules/customers/api/activities/route.js +6 -4
- package/dist/modules/customers/api/activities/route.js.map +2 -2
- package/dist/modules/customers/api/comments/route.js +3 -1
- package/dist/modules/customers/api/comments/route.js.map +2 -2
- package/dist/modules/customers/api/companies/[id]/people/route.js +3 -1
- package/dist/modules/customers/api/companies/[id]/people/route.js.map +2 -2
- package/dist/modules/customers/api/companies/[id]/route.js +5 -3
- package/dist/modules/customers/api/companies/[id]/route.js.map +2 -2
- package/dist/modules/customers/api/companies/route.js +5 -3
- package/dist/modules/customers/api/companies/route.js.map +2 -2
- package/dist/modules/customers/api/dashboard/widgets/customer-todos/route.js +3 -1
- package/dist/modules/customers/api/dashboard/widgets/customer-todos/route.js.map +2 -2
- package/dist/modules/customers/api/dashboard/widgets/new-customers/route.js +3 -1
- package/dist/modules/customers/api/dashboard/widgets/new-customers/route.js.map +2 -2
- package/dist/modules/customers/api/dashboard/widgets/new-deals/route.js +3 -1
- package/dist/modules/customers/api/dashboard/widgets/new-deals/route.js.map +2 -2
- package/dist/modules/customers/api/dashboard/widgets/next-interactions/route.js +3 -1
- package/dist/modules/customers/api/dashboard/widgets/next-interactions/route.js.map +2 -2
- package/dist/modules/customers/api/deals/[id]/companies/route.js +3 -1
- package/dist/modules/customers/api/deals/[id]/companies/route.js.map +2 -2
- package/dist/modules/customers/api/deals/[id]/people/route.js +3 -1
- package/dist/modules/customers/api/deals/[id]/people/route.js.map +2 -2
- package/dist/modules/customers/api/deals/aggregate/route.js +3 -1
- package/dist/modules/customers/api/deals/aggregate/route.js.map +2 -2
- package/dist/modules/customers/api/deals/bulk-update-owner/route.js +7 -5
- package/dist/modules/customers/api/deals/bulk-update-owner/route.js.map +2 -2
- package/dist/modules/customers/api/deals/bulk-update-stage/route.js +7 -5
- package/dist/modules/customers/api/deals/bulk-update-stage/route.js.map +2 -2
- package/dist/modules/customers/api/deals/route.js +3 -1
- package/dist/modules/customers/api/deals/route.js.map +2 -2
- package/dist/modules/customers/api/deals/summary/route.js +3 -1
- package/dist/modules/customers/api/deals/summary/route.js.map +2 -2
- package/dist/modules/customers/api/dictionaries/[kind]/[id]/route.js +4 -2
- package/dist/modules/customers/api/dictionaries/[kind]/[id]/route.js.map +2 -2
- package/dist/modules/customers/api/dictionaries/[kind]/route.js +5 -3
- package/dist/modules/customers/api/dictionaries/[kind]/route.js.map +2 -2
- package/dist/modules/customers/api/dictionaries/cache.js +3 -1
- package/dist/modules/customers/api/dictionaries/cache.js.map +2 -2
- package/dist/modules/customers/api/dictionaries/context.js +3 -1
- package/dist/modules/customers/api/dictionaries/context.js.map +2 -2
- package/dist/modules/customers/api/dictionaries/currency/route.js +3 -1
- package/dist/modules/customers/api/dictionaries/currency/route.js.map +2 -2
- package/dist/modules/customers/api/dictionaries/kind-settings/route.js +4 -2
- package/dist/modules/customers/api/dictionaries/kind-settings/route.js.map +2 -2
- package/dist/modules/customers/api/entity-roles-factory.js +7 -5
- package/dist/modules/customers/api/entity-roles-factory.js.map +2 -2
- package/dist/modules/customers/api/interactions/cancel/route.js +3 -1
- package/dist/modules/customers/api/interactions/cancel/route.js.map +2 -2
- package/dist/modules/customers/api/interactions/complete/route.js +3 -1
- package/dist/modules/customers/api/interactions/complete/route.js.map +2 -2
- package/dist/modules/customers/api/interactions/conflicts/route.js +3 -1
- package/dist/modules/customers/api/interactions/conflicts/route.js.map +2 -2
- package/dist/modules/customers/api/interactions/counts/route.js +3 -1
- package/dist/modules/customers/api/interactions/counts/route.js.map +2 -2
- package/dist/modules/customers/api/interactions/route.js +7 -4
- package/dist/modules/customers/api/interactions/route.js.map +2 -2
- package/dist/modules/customers/api/interactions/tasks/route.js +3 -1
- package/dist/modules/customers/api/interactions/tasks/route.js.map +2 -2
- package/dist/modules/customers/api/labels/assign/route.js +3 -1
- package/dist/modules/customers/api/labels/assign/route.js.map +2 -2
- package/dist/modules/customers/api/labels/route.js +6 -3
- package/dist/modules/customers/api/labels/route.js.map +2 -2
- package/dist/modules/customers/api/labels/unassign/route.js +3 -1
- package/dist/modules/customers/api/labels/unassign/route.js.map +2 -2
- package/dist/modules/customers/api/people/[id]/companies/enriched/route.js +3 -1
- package/dist/modules/customers/api/people/[id]/companies/enriched/route.js.map +2 -2
- package/dist/modules/customers/api/people/[id]/route.js +5 -3
- package/dist/modules/customers/api/people/[id]/route.js.map +2 -2
- package/dist/modules/customers/api/people/route.js +5 -3
- package/dist/modules/customers/api/people/route.js.map +2 -2
- package/dist/modules/customers/api/pipeline-stages/reorder/route.js +3 -1
- package/dist/modules/customers/api/pipeline-stages/reorder/route.js.map +2 -2
- package/dist/modules/customers/api/pipeline-stages/route.js +6 -4
- package/dist/modules/customers/api/pipeline-stages/route.js.map +2 -2
- package/dist/modules/customers/api/pipelines/route.js +6 -4
- package/dist/modules/customers/api/pipelines/route.js.map +2 -2
- package/dist/modules/customers/api/settings/address-format/route.js +4 -2
- package/dist/modules/customers/api/settings/address-format/route.js.map +2 -2
- package/dist/modules/customers/api/settings/dictionary-sort-modes/route.js +4 -2
- package/dist/modules/customers/api/settings/dictionary-sort-modes/route.js.map +2 -2
- package/dist/modules/customers/api/settings/stuck-threshold/route.js +4 -2
- package/dist/modules/customers/api/settings/stuck-threshold/route.js.map +2 -2
- package/dist/modules/customers/api/tags/assign/route.js +3 -1
- package/dist/modules/customers/api/tags/assign/route.js.map +2 -2
- package/dist/modules/customers/api/tags/unassign/route.js +3 -1
- package/dist/modules/customers/api/tags/unassign/route.js.map +2 -2
- package/dist/modules/customers/api/todos/route.js +6 -4
- package/dist/modules/customers/api/todos/route.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +5 -3
- package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealActivities.js +3 -1
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealActivities.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealClosure.js +3 -1
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealClosure.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/map/components/DealsMapCanvasImpl.js +4 -2
- package/dist/modules/customers/backend/customers/deals/map/components/DealsMapCanvasImpl.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/page.js +4 -2
- package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +5 -3
- package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +2 -2
- package/dist/modules/customers/commands/deals.js +3 -1
- package/dist/modules/customers/commands/deals.js.map +2 -2
- package/dist/modules/customers/commands/dictionaries.js +3 -1
- package/dist/modules/customers/commands/dictionaries.js.map +2 -2
- package/dist/modules/customers/commands/interactions.js +4 -2
- package/dist/modules/customers/commands/interactions.js.map +2 -2
- package/dist/modules/customers/commands/shared.js +4 -2
- package/dist/modules/customers/commands/shared.js.map +2 -2
- package/dist/modules/customers/commands/todos.js +3 -1
- package/dist/modules/customers/commands/todos.js.map +2 -2
- package/dist/modules/customers/components/DictionarySettings.js +5 -3
- package/dist/modules/customers/components/DictionarySettings.js.map +2 -2
- package/dist/modules/customers/components/DictionarySortSettings.js +3 -1
- package/dist/modules/customers/components/DictionarySortSettings.js.map +2 -2
- package/dist/modules/customers/components/detail/ActivitiesCard.js +3 -1
- package/dist/modules/customers/components/detail/ActivitiesCard.js.map +2 -2
- package/dist/modules/customers/components/detail/ActivitiesDayStrip.js +3 -1
- package/dist/modules/customers/components/detail/ActivitiesDayStrip.js.map +2 -2
- package/dist/modules/customers/components/detail/ActivitiesSection.js +6 -4
- package/dist/modules/customers/components/detail/ActivitiesSection.js.map +2 -2
- package/dist/modules/customers/components/detail/ActivityCard.js +3 -1
- package/dist/modules/customers/components/detail/ActivityCard.js.map +2 -2
- package/dist/modules/customers/components/detail/ChangelogTab.js +3 -1
- package/dist/modules/customers/components/detail/ChangelogTab.js.map +2 -2
- package/dist/modules/customers/components/detail/CompanyCard.js +3 -1
- package/dist/modules/customers/components/detail/CompanyCard.js.map +2 -2
- package/dist/modules/customers/components/detail/ConfirmDealLostDialog.js +3 -1
- package/dist/modules/customers/components/detail/ConfirmDealLostDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/EntityTagsDialog.js +3 -1
- package/dist/modules/customers/components/detail/EntityTagsDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/InlineActivityComposer.js +3 -1
- package/dist/modules/customers/components/detail/InlineActivityComposer.js.map +2 -2
- package/dist/modules/customers/components/detail/ManageTagsDialog.js +3 -1
- package/dist/modules/customers/components/detail/ManageTagsDialog.js.map +2 -2
- package/dist/modules/customers/components/detail/RoleAssignmentRow.js +5 -3
- package/dist/modules/customers/components/detail/RoleAssignmentRow.js.map +2 -2
- package/dist/modules/customers/components/detail/RolesSection.js +4 -2
- package/dist/modules/customers/components/detail/RolesSection.js.map +2 -2
- package/dist/modules/customers/components/detail/hooks/useInteractionMutations.js +5 -3
- package/dist/modules/customers/components/detail/hooks/useInteractionMutations.js.map +2 -2
- package/dist/modules/customers/components/linking/LinkEntityDialog.js +4 -2
- package/dist/modules/customers/components/linking/LinkEntityDialog.js.map +2 -2
- package/dist/modules/customers/inbox-actions.js +3 -1
- package/dist/modules/customers/inbox-actions.js.map +2 -2
- package/dist/modules/customers/lib/bulkDeals.js +3 -1
- package/dist/modules/customers/lib/bulkDeals.js.map +2 -2
- package/dist/modules/customers/lib/dealClosureNotification.js +4 -2
- package/dist/modules/customers/lib/dealClosureNotification.js.map +2 -2
- package/dist/modules/customers/lib/dealStageTransitionTable.js +3 -1
- package/dist/modules/customers/lib/dealStageTransitionTable.js.map +2 -2
- package/dist/modules/customers/lib/interactionFeatureFlags.js +3 -1
- package/dist/modules/customers/lib/interactionFeatureFlags.js.map +2 -2
- package/dist/modules/customers/lib/todoCompatibility.js +3 -1
- package/dist/modules/customers/lib/todoCompatibility.js.map +2 -2
- package/dist/modules/customers/search.js +14 -7
- package/dist/modules/customers/search.js.map +2 -2
- package/dist/modules/customers/widgets/dashboard/customer-todos/widget.client.js +3 -1
- package/dist/modules/customers/widgets/dashboard/customer-todos/widget.client.js.map +2 -2
- package/dist/modules/customers/widgets/dashboard/new-customers/widget.client.js +3 -1
- package/dist/modules/customers/widgets/dashboard/new-customers/widget.client.js.map +2 -2
- package/dist/modules/customers/widgets/dashboard/new-deals/widget.client.js +3 -1
- package/dist/modules/customers/widgets/dashboard/new-deals/widget.client.js.map +2 -2
- package/dist/modules/customers/widgets/dashboard/next-interactions/widget.client.js +3 -1
- package/dist/modules/customers/widgets/dashboard/next-interactions/widget.client.js.map +2 -2
- package/dist/modules/dashboards/api/widgets/data/batch/route.js +3 -1
- package/dist/modules/dashboards/api/widgets/data/batch/route.js.map +2 -2
- package/dist/modules/dashboards/api/widgets/data/route.js +3 -1
- package/dist/modules/dashboards/api/widgets/data/route.js.map +2 -2
- package/dist/modules/dashboards/components/WidgetVisibilityEditor.js +5 -3
- package/dist/modules/dashboards/components/WidgetVisibilityEditor.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/aov-kpi/widget.client.js +3 -1
- package/dist/modules/dashboards/widgets/dashboard/aov-kpi/widget.client.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/new-customers-kpi/widget.client.js +3 -1
- package/dist/modules/dashboards/widgets/dashboard/new-customers-kpi/widget.client.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/orders-by-status/widget.client.js +3 -1
- package/dist/modules/dashboards/widgets/dashboard/orders-by-status/widget.client.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/orders-kpi/widget.client.js +3 -1
- package/dist/modules/dashboards/widgets/dashboard/orders-kpi/widget.client.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/pipeline-summary/widget.client.js +3 -1
- package/dist/modules/dashboards/widgets/dashboard/pipeline-summary/widget.client.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/revenue-kpi/widget.client.js +3 -1
- package/dist/modules/dashboards/widgets/dashboard/revenue-kpi/widget.client.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/revenue-trend/widget.client.js +3 -1
- package/dist/modules/dashboards/widgets/dashboard/revenue-trend/widget.client.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/sales-by-region/widget.client.js +3 -1
- package/dist/modules/dashboards/widgets/dashboard/sales-by-region/widget.client.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/top-customers/widget.client.js +3 -1
- package/dist/modules/dashboards/widgets/dashboard/top-customers/widget.client.js.map +2 -2
- package/dist/modules/dashboards/widgets/dashboard/top-products/widget.client.js +3 -1
- package/dist/modules/dashboards/widgets/dashboard/top-products/widget.client.js.map +2 -2
- package/dist/modules/data_sync/api/run.js +3 -1
- package/dist/modules/data_sync/api/run.js.map +2 -2
- package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.js +1 -1
- package/dist/modules/data_sync/backend/data-sync/runs/[id]/page.js.map +2 -2
- package/dist/modules/data_sync/lib/adapter-registry.js +11 -4
- package/dist/modules/data_sync/lib/adapter-registry.js.map +2 -2
- package/dist/modules/data_sync/lib/sync-engine.js +23 -2
- package/dist/modules/data_sync/lib/sync-engine.js.map +2 -2
- package/dist/modules/data_sync/workers/sync-export.js +3 -1
- package/dist/modules/data_sync/workers/sync-export.js.map +2 -2
- package/dist/modules/data_sync/workers/sync-import.js +3 -1
- package/dist/modules/data_sync/workers/sync-import.js.map +2 -2
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js +4 -2
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js.map +2 -2
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/reorder/route.js +3 -1
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/reorder/route.js.map +2 -2
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/route.js +4 -2
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/route.js.map +2 -2
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/set-default/route.js +3 -1
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/set-default/route.js.map +2 -2
- package/dist/modules/dictionaries/api/[dictionaryId]/route.js +5 -3
- package/dist/modules/dictionaries/api/[dictionaryId]/route.js.map +2 -2
- package/dist/modules/dictionaries/api/context.js +3 -1
- package/dist/modules/dictionaries/api/context.js.map +2 -2
- package/dist/modules/dictionaries/api/route.js +4 -2
- package/dist/modules/dictionaries/api/route.js.map +2 -2
- package/dist/modules/dictionaries/components/DictionariesManager.js +5 -3
- package/dist/modules/dictionaries/components/DictionariesManager.js.map +2 -2
- package/dist/modules/dictionaries/components/DictionaryEntriesEditor.js +4 -2
- package/dist/modules/dictionaries/components/DictionaryEntriesEditor.js.map +2 -2
- package/dist/modules/dictionaries/components/DictionaryEntrySelect.js +4 -2
- package/dist/modules/dictionaries/components/DictionaryEntrySelect.js.map +2 -2
- package/dist/modules/dictionaries/components/DictionarySelectControl.js +3 -1
- package/dist/modules/dictionaries/components/DictionarySelectControl.js.map +2 -2
- package/dist/modules/dictionaries/fields/dictionary.js +3 -1
- package/dist/modules/dictionaries/fields/dictionary.js.map +2 -2
- package/dist/modules/directory/api/organization-branding/route.js +3 -1
- package/dist/modules/directory/api/organization-branding/route.js.map +2 -2
- package/dist/modules/directory/api/organization-switcher/route.js +3 -1
- package/dist/modules/directory/api/organization-switcher/route.js.map +2 -2
- package/dist/modules/directory/commands/tenants.js +5 -3
- package/dist/modules/directory/commands/tenants.js.map +2 -2
- package/dist/modules/directory/utils/organizationScope.js +6 -4
- package/dist/modules/directory/utils/organizationScope.js.map +2 -2
- package/dist/modules/entities/api/definitions.cache.js +3 -1
- package/dist/modules/entities/api/definitions.cache.js.map +2 -2
- package/dist/modules/entities/api/definitions.js +7 -5
- package/dist/modules/entities/api/definitions.js.map +2 -2
- package/dist/modules/entities/api/records.js +4 -8
- package/dist/modules/entities/api/records.js.map +2 -2
- package/dist/modules/entities/components/EncryptionManager.js +3 -1
- package/dist/modules/entities/components/EncryptionManager.js.map +2 -2
- package/dist/modules/entities/lib/makeActivityRoute.js +3 -1
- package/dist/modules/entities/lib/makeActivityRoute.js.map +2 -2
- package/dist/modules/feature_toggles/api/overrides/route.js +3 -1
- package/dist/modules/feature_toggles/api/overrides/route.js.map +2 -2
- package/dist/modules/feature_toggles/lib/feature-flag-check.js +5 -9
- package/dist/modules/feature_toggles/lib/feature-flag-check.js.map +2 -2
- package/dist/modules/inbox_ops/api/emails/[id]/reprocess/route.js +4 -2
- package/dist/modules/inbox_ops/api/emails/[id]/reprocess/route.js.map +2 -2
- package/dist/modules/inbox_ops/api/emails/[id]/route.js +4 -2
- package/dist/modules/inbox_ops/api/emails/[id]/route.js.map +2 -2
- package/dist/modules/inbox_ops/api/emails/route.js +3 -1
- package/dist/modules/inbox_ops/api/emails/route.js.map +2 -2
- package/dist/modules/inbox_ops/api/extract/route.js +3 -1
- package/dist/modules/inbox_ops/api/extract/route.js.map +2 -2
- package/dist/modules/inbox_ops/api/proposals/[id]/actions/[actionId]/route.js +3 -1
- package/dist/modules/inbox_ops/api/proposals/[id]/actions/[actionId]/route.js.map +2 -2
- package/dist/modules/inbox_ops/api/proposals/[id]/replies/[replyId]/send/route.js +4 -2
- package/dist/modules/inbox_ops/api/proposals/[id]/replies/[replyId]/send/route.js.map +2 -2
- package/dist/modules/inbox_ops/api/proposals/counts/route.js +4 -2
- package/dist/modules/inbox_ops/api/proposals/counts/route.js.map +2 -2
- package/dist/modules/inbox_ops/api/proposals/route.js +3 -1
- package/dist/modules/inbox_ops/api/proposals/route.js.map +2 -2
- package/dist/modules/inbox_ops/api/routeHelpers.js +3 -1
- package/dist/modules/inbox_ops/api/routeHelpers.js.map +2 -2
- package/dist/modules/inbox_ops/api/settings/route.js +3 -1
- package/dist/modules/inbox_ops/api/settings/route.js.map +2 -2
- package/dist/modules/inbox_ops/api/webhook/inbound.js +7 -5
- package/dist/modules/inbox_ops/api/webhook/inbound.js.map +2 -2
- package/dist/modules/inbox_ops/lib/cache.js +4 -2
- package/dist/modules/inbox_ops/lib/cache.js.map +2 -2
- package/dist/modules/inbox_ops/lib/catalogLookup.js +3 -1
- package/dist/modules/inbox_ops/lib/catalogLookup.js.map +2 -2
- package/dist/modules/inbox_ops/lib/eventBus.js +3 -4
- package/dist/modules/inbox_ops/lib/eventBus.js.map +2 -2
- package/dist/modules/inbox_ops/lib/messagesIntegration.js +4 -8
- package/dist/modules/inbox_ops/lib/messagesIntegration.js.map +2 -2
- package/dist/modules/inbox_ops/subscribers/executionAuditor.js +3 -1
- package/dist/modules/inbox_ops/subscribers/executionAuditor.js.map +2 -2
- package/dist/modules/inbox_ops/subscribers/extractionWorker.js +10 -8
- package/dist/modules/inbox_ops/subscribers/extractionWorker.js.map +2 -2
- package/dist/modules/inbox_ops/subscribers/proposalNotifier.js +3 -1
- package/dist/modules/inbox_ops/subscribers/proposalNotifier.js.map +2 -2
- package/dist/modules/messages/api/[id]/route.js +3 -4
- package/dist/modules/messages/api/[id]/route.js.map +2 -2
- package/dist/modules/messages/commands/actions.js +3 -1
- package/dist/modules/messages/commands/actions.js.map +2 -2
- package/dist/modules/messages/components/MessagesInboxPageClient.js +3 -1
- package/dist/modules/messages/components/MessagesInboxPageClient.js.map +2 -2
- package/dist/modules/messages/lib/email-sender.js +3 -7
- package/dist/modules/messages/lib/email-sender.js.map +2 -2
- package/dist/modules/messages/lib/message-objects-registry.js +3 -1
- package/dist/modules/messages/lib/message-objects-registry.js.map +2 -2
- package/dist/modules/messages/lib/message-types-registry.js +3 -1
- package/dist/modules/messages/lib/message-types-registry.js.map +2 -2
- package/dist/modules/messages/workers/send-email.worker.js +6 -4
- package/dist/modules/messages/workers/send-email.worker.js.map +2 -2
- package/dist/modules/notifications/lib/notificationMapper.js +3 -4
- package/dist/modules/notifications/lib/notificationMapper.js.map +2 -2
- package/dist/modules/notifications/lib/notificationService.js +4 -5
- package/dist/modules/notifications/lib/notificationService.js.map +2 -2
- package/dist/modules/notifications/subscribers/deliver-notification.js +8 -13
- package/dist/modules/notifications/subscribers/deliver-notification.js.map +2 -2
- package/dist/modules/payment_gateways/api/webhook/[provider]/route.js +3 -1
- package/dist/modules/payment_gateways/api/webhook/[provider]/route.js.map +2 -2
- package/dist/modules/perspectives/services/perspectiveService.js +3 -3
- package/dist/modules/perspectives/services/perspectiveService.js.map +2 -2
- package/dist/modules/planner/api/access.js +3 -3
- package/dist/modules/planner/api/access.js.map +2 -2
- package/dist/modules/planner/api/availability-date-specific.js +3 -1
- package/dist/modules/planner/api/availability-date-specific.js.map +2 -2
- package/dist/modules/planner/api/availability-weekly.js +3 -1
- package/dist/modules/planner/api/availability-weekly.js.map +2 -2
- package/dist/modules/planner/backend/planner/availability-rulesets/page.js +4 -2
- package/dist/modules/planner/backend/planner/availability-rulesets/page.js.map +2 -2
- package/dist/modules/planner/components/AvailabilityRulesEditor.js +3 -1
- package/dist/modules/planner/components/AvailabilityRulesEditor.js.map +2 -2
- package/dist/modules/progress/api/jobs/route.js +3 -1
- package/dist/modules/progress/api/jobs/route.js.map +2 -2
- package/dist/modules/query_index/components/QueryIndexesTable.js +5 -3
- package/dist/modules/query_index/components/QueryIndexesTable.js.map +2 -2
- package/dist/modules/query_index/lib/batch.js +4 -2
- package/dist/modules/query_index/lib/batch.js.map +2 -2
- package/dist/modules/query_index/lib/coverage.js +3 -1
- package/dist/modules/query_index/lib/coverage.js.map +2 -2
- package/dist/modules/query_index/lib/engine.js +13 -18
- package/dist/modules/query_index/lib/engine.js.map +2 -2
- package/dist/modules/query_index/lib/reindexer.js +8 -6
- package/dist/modules/query_index/lib/reindexer.js.map +2 -2
- package/dist/modules/query_index/lib/search-tokens.js +3 -1
- package/dist/modules/query_index/lib/search-tokens.js.map +2 -2
- package/dist/modules/query_index/subscribers/coverage_refresh.js +3 -1
- package/dist/modules/query_index/subscribers/coverage_refresh.js.map +2 -2
- package/dist/modules/resources/api/comments.js +3 -1
- package/dist/modules/resources/api/comments.js.map +2 -2
- package/dist/modules/resources/api/resources/tags/assign/route.js +3 -1
- package/dist/modules/resources/api/resources/tags/assign/route.js.map +2 -2
- package/dist/modules/resources/api/resources/tags/unassign/route.js +3 -1
- package/dist/modules/resources/api/resources/tags/unassign/route.js.map +2 -2
- package/dist/modules/resources/backend/resources/resource-types/[id]/edit/page.js +3 -1
- package/dist/modules/resources/backend/resources/resource-types/[id]/edit/page.js.map +2 -2
- package/dist/modules/resources/backend/resources/resource-types/page.js +4 -2
- package/dist/modules/resources/backend/resources/resource-types/page.js.map +2 -2
- package/dist/modules/resources/commands/activities.js +6 -5
- package/dist/modules/resources/commands/activities.js.map +2 -2
- package/dist/modules/resources/commands/comments.js +6 -4
- package/dist/modules/resources/commands/comments.js.map +2 -2
- package/dist/modules/resources/commands/shared.js +24 -1
- package/dist/modules/resources/commands/shared.js.map +2 -2
- package/dist/modules/sales/api/channels/route.js +3 -1
- package/dist/modules/sales/api/channels/route.js.map +2 -2
- package/dist/modules/sales/api/document-history/route.js +3 -1
- package/dist/modules/sales/api/document-history/route.js.map +2 -2
- package/dist/modules/sales/api/document-numbers/route.js +3 -1
- package/dist/modules/sales/api/document-numbers/route.js.map +2 -2
- package/dist/modules/sales/api/quotes/accept/route.js +4 -2
- package/dist/modules/sales/api/quotes/accept/route.js.map +2 -2
- package/dist/modules/sales/api/quotes/convert/route.js +3 -1
- package/dist/modules/sales/api/quotes/convert/route.js.map +2 -2
- package/dist/modules/sales/api/quotes/public/[token]/route.js +3 -1
- package/dist/modules/sales/api/quotes/public/[token]/route.js.map +2 -2
- package/dist/modules/sales/api/quotes/send/route.js +3 -1
- package/dist/modules/sales/api/quotes/send/route.js.map +2 -2
- package/dist/modules/sales/api/returns/[id]/route.js +3 -1
- package/dist/modules/sales/api/returns/[id]/route.js.map +2 -2
- package/dist/modules/sales/api/settings/document-numbers/route.js +4 -2
- package/dist/modules/sales/api/settings/document-numbers/route.js.map +2 -2
- package/dist/modules/sales/api/settings/order-editing/route.js +4 -2
- package/dist/modules/sales/api/settings/order-editing/route.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/[channelId]/edit/page.js +3 -1
- package/dist/modules/sales/backend/sales/channels/[channelId]/edit/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/offers/page.js +6 -4
- package/dist/modules/sales/backend/sales/channels/offers/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/page.js +4 -2
- package/dist/modules/sales/backend/sales/channels/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/documents/[id]/page.js +20 -18
- package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
- package/dist/modules/sales/commands/documents.js +4 -8
- package/dist/modules/sales/commands/documents.js.map +2 -2
- package/dist/modules/sales/commands/payments.js +3 -1
- package/dist/modules/sales/commands/payments.js.map +2 -2
- package/dist/modules/sales/commands/shipments.js +3 -1
- package/dist/modules/sales/commands/shipments.js.map +2 -2
- package/dist/modules/sales/components/AdjustmentKindSettings.js +5 -3
- package/dist/modules/sales/components/AdjustmentKindSettings.js.map +2 -2
- package/dist/modules/sales/components/DocumentNumberSettings.js +4 -2
- package/dist/modules/sales/components/DocumentNumberSettings.js.map +2 -2
- package/dist/modules/sales/components/OrderEditingSettings.js +4 -2
- package/dist/modules/sales/components/OrderEditingSettings.js.map +2 -2
- package/dist/modules/sales/components/PaymentMethodsSettings.js +5 -3
- package/dist/modules/sales/components/PaymentMethodsSettings.js.map +2 -2
- package/dist/modules/sales/components/ShippingMethodsSettings.js +5 -3
- package/dist/modules/sales/components/ShippingMethodsSettings.js.map +2 -2
- package/dist/modules/sales/components/StatusSettings.js +5 -3
- package/dist/modules/sales/components/StatusSettings.js.map +2 -2
- package/dist/modules/sales/components/TaxRatesSettings.js +5 -3
- package/dist/modules/sales/components/TaxRatesSettings.js.map +2 -2
- package/dist/modules/sales/components/channels/ChannelOfferForm.js +16 -14
- package/dist/modules/sales/components/channels/ChannelOfferForm.js.map +2 -2
- package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js +4 -2
- package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js.map +2 -2
- package/dist/modules/sales/components/documents/AddressesSection.js +5 -3
- package/dist/modules/sales/components/documents/AddressesSection.js.map +2 -2
- package/dist/modules/sales/components/documents/AdjustmentDialog.js +3 -1
- package/dist/modules/sales/components/documents/AdjustmentDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/AdjustmentsSection.js +5 -3
- package/dist/modules/sales/components/documents/AdjustmentsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/ItemsSection.js +6 -4
- package/dist/modules/sales/components/documents/ItemsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/LineItemDialog.js +8 -6
- package/dist/modules/sales/components/documents/LineItemDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/PaymentDialog.js +5 -3
- package/dist/modules/sales/components/documents/PaymentDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/PaymentsSection.js +4 -2
- package/dist/modules/sales/components/documents/PaymentsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/SalesDocumentForm.js +14 -12
- package/dist/modules/sales/components/documents/SalesDocumentForm.js.map +2 -2
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js +5 -3
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js.map +2 -2
- package/dist/modules/sales/components/documents/ShipmentDialog.js +9 -7
- package/dist/modules/sales/components/documents/ShipmentDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/ShipmentsSection.js +4 -2
- package/dist/modules/sales/components/documents/ShipmentsSection.js.map +2 -2
- package/dist/modules/sales/frontend/quote/[token]/page.js +4 -2
- package/dist/modules/sales/frontend/quote/[token]/page.js.map +2 -2
- package/dist/modules/sales/seed/examples.js +7 -9
- package/dist/modules/sales/seed/examples.js.map +2 -2
- package/dist/modules/sales/subscribers/quote-expiring-notification.js +3 -1
- package/dist/modules/sales/subscribers/quote-expiring-notification.js.map +2 -2
- package/dist/modules/sales/subscribers/reconcileOnAddressDelete.js +3 -1
- package/dist/modules/sales/subscribers/reconcileOnAddressDelete.js.map +2 -2
- package/dist/modules/sales/subscribers/reconcileOnCompanyDelete.js +3 -1
- package/dist/modules/sales/subscribers/reconcileOnCompanyDelete.js.map +2 -2
- package/dist/modules/sales/subscribers/reconcileOnCustomerDelete.js +3 -1
- package/dist/modules/sales/subscribers/reconcileOnCustomerDelete.js.map +2 -2
- package/dist/modules/sales/widgets/dashboard/makeDashboardWidgetRoute.js +5 -3
- package/dist/modules/sales/widgets/dashboard/makeDashboardWidgetRoute.js.map +2 -2
- package/dist/modules/sales/widgets/dashboard/new-orders/widget.client.js +3 -1
- package/dist/modules/sales/widgets/dashboard/new-orders/widget.client.js.map +2 -2
- package/dist/modules/sales/widgets/dashboard/new-quotes/widget.client.js +3 -1
- package/dist/modules/sales/widgets/dashboard/new-quotes/widget.client.js.map +2 -2
- package/dist/modules/shipping_carriers/api/tracking/route.js +5 -0
- package/dist/modules/shipping_carriers/api/tracking/route.js.map +2 -2
- package/dist/modules/shipping_carriers/api/webhook/[provider]/route.js +3 -1
- package/dist/modules/shipping_carriers/api/webhook/[provider]/route.js.map +2 -2
- package/dist/modules/shipping_carriers/lib/shipping-service.js +41 -19
- package/dist/modules/shipping_carriers/lib/shipping-service.js.map +2 -2
- package/dist/modules/shipping_carriers/lib/upstream-error-response.js +3 -1
- package/dist/modules/shipping_carriers/lib/upstream-error-response.js.map +2 -2
- package/dist/modules/shipping_carriers/workers/webhook-processor.js +3 -5
- package/dist/modules/shipping_carriers/workers/webhook-processor.js.map +2 -2
- package/dist/modules/staff/api/comments.js +3 -1
- package/dist/modules/staff/api/comments.js.map +2 -2
- package/dist/modules/staff/api/leave-requests/accept/route.js +3 -1
- package/dist/modules/staff/api/leave-requests/accept/route.js.map +2 -2
- package/dist/modules/staff/api/leave-requests/reject/route.js +3 -1
- package/dist/modules/staff/api/leave-requests/reject/route.js.map +2 -2
- package/dist/modules/staff/api/team-members/assignable/route.js +3 -1
- package/dist/modules/staff/api/team-members/assignable/route.js.map +2 -2
- package/dist/modules/staff/api/team-members/self/route.js +4 -2
- package/dist/modules/staff/api/team-members/self/route.js.map +2 -2
- package/dist/modules/staff/api/team-members/tags/assign/route.js +3 -1
- package/dist/modules/staff/api/team-members/tags/assign/route.js.map +2 -2
- package/dist/modules/staff/api/team-members/tags/unassign/route.js +3 -1
- package/dist/modules/staff/api/team-members/tags/unassign/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/my-projects/[projectId]/route.js +3 -1
- package/dist/modules/staff/api/timesheets/my-projects/[projectId]/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/my-projects/route.js +3 -1
- package/dist/modules/staff/api/timesheets/my-projects/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/projects/kpis/route.js +3 -1
- package/dist/modules/staff/api/timesheets/projects/kpis/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/route.js +3 -1
- package/dist/modules/staff/api/timesheets/time-entries/[id]/segments/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.js +4 -2
- package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.js +4 -2
- package/dist/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-entries/bulk/route.js +3 -1
- package/dist/modules/staff/api/timesheets/time-entries/bulk/route.js.map +2 -2
- package/dist/modules/staff/api/timesheets/time-entries/start-timer/route.js +3 -1
- package/dist/modules/staff/api/timesheets/time-entries/start-timer/route.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-members/page.js +4 -2
- package/dist/modules/staff/backend/staff/team-members/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-roles/page.js +4 -2
- package/dist/modules/staff/backend/staff/team-roles/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +4 -2
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/teams/page.js +4 -2
- package/dist/modules/staff/backend/staff/teams/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/page.js +7 -5
- package/dist/modules/staff/backend/staff/timesheets/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.js +3 -1
- package/dist/modules/staff/backend/staff/timesheets/projects/[id]/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/timesheets/projects/page.js +4 -2
- package/dist/modules/staff/backend/staff/timesheets/projects/page.js.map +2 -2
- package/dist/modules/staff/commands/timesheets-entries.js +3 -1
- package/dist/modules/staff/commands/timesheets-entries.js.map +2 -2
- package/dist/modules/staff/widgets/dashboard/timesheets-hours-by-project/widget.client.js +3 -1
- package/dist/modules/staff/widgets/dashboard/timesheets-hours-by-project/widget.client.js.map +2 -2
- package/dist/modules/staff/widgets/dashboard/timesheets-time-reporting/widget.client.js +5 -3
- package/dist/modules/staff/widgets/dashboard/timesheets-time-reporting/widget.client.js.map +2 -2
- package/dist/modules/sync_excel/api/import/route.js +3 -1
- package/dist/modules/sync_excel/api/import/route.js.map +2 -2
- package/dist/modules/translations/api/[entityType]/[entityId]/route.js +5 -3
- package/dist/modules/translations/api/[entityType]/[entityId]/route.js.map +2 -2
- package/dist/modules/translations/api/get/locales.js +3 -1
- package/dist/modules/translations/api/get/locales.js.map +2 -2
- package/dist/modules/translations/api/put/locales.js +3 -1
- package/dist/modules/translations/api/put/locales.js.map +2 -2
- package/dist/modules/translations/components/TranslationManager.js +3 -1
- package/dist/modules/translations/components/TranslationManager.js.map +2 -2
- package/dist/modules/translations/subscribers/cleanup.js +3 -1
- package/dist/modules/translations/subscribers/cleanup.js.map +2 -2
- package/dist/modules/workflows/api/definitions/[id]/customize/route.js +4 -2
- package/dist/modules/workflows/api/definitions/[id]/customize/route.js.map +2 -2
- package/dist/modules/workflows/api/definitions/[id]/reset-to-code/route.js +4 -2
- package/dist/modules/workflows/api/definitions/[id]/reset-to-code/route.js.map +2 -2
- package/dist/modules/workflows/api/definitions/[id]/route.js +6 -4
- package/dist/modules/workflows/api/definitions/[id]/route.js.map +2 -2
- package/dist/modules/workflows/api/definitions/route.js +4 -2
- package/dist/modules/workflows/api/definitions/route.js.map +2 -2
- package/dist/modules/workflows/api/events/[id]/route.js +3 -1
- package/dist/modules/workflows/api/events/[id]/route.js.map +2 -2
- package/dist/modules/workflows/api/events/route.js +3 -1
- package/dist/modules/workflows/api/events/route.js.map +2 -2
- package/dist/modules/workflows/api/instances/[id]/advance/route.js +3 -1
- package/dist/modules/workflows/api/instances/[id]/advance/route.js.map +2 -2
- package/dist/modules/workflows/api/instances/[id]/cancel/route.js +3 -1
- package/dist/modules/workflows/api/instances/[id]/cancel/route.js.map +2 -2
- package/dist/modules/workflows/api/instances/[id]/events/route.js +3 -1
- package/dist/modules/workflows/api/instances/[id]/events/route.js.map +2 -2
- package/dist/modules/workflows/api/instances/[id]/retry/route.js +3 -1
- package/dist/modules/workflows/api/instances/[id]/retry/route.js.map +2 -2
- package/dist/modules/workflows/api/instances/[id]/route.js +3 -1
- package/dist/modules/workflows/api/instances/[id]/route.js.map +2 -2
- package/dist/modules/workflows/api/instances/[id]/signal/route.js +5 -7
- package/dist/modules/workflows/api/instances/[id]/signal/route.js.map +2 -2
- package/dist/modules/workflows/api/instances/route.js +5 -3
- package/dist/modules/workflows/api/instances/route.js.map +2 -2
- package/dist/modules/workflows/api/instances/validate-start/route.js +3 -1
- package/dist/modules/workflows/api/instances/validate-start/route.js.map +2 -2
- package/dist/modules/workflows/api/signals/route.js +3 -1
- package/dist/modules/workflows/api/signals/route.js.map +2 -2
- package/dist/modules/workflows/api/tasks/[id]/claim/route.js +3 -1
- package/dist/modules/workflows/api/tasks/[id]/claim/route.js.map +2 -2
- package/dist/modules/workflows/api/tasks/[id]/complete/route.js +3 -1
- package/dist/modules/workflows/api/tasks/[id]/complete/route.js.map +2 -2
- package/dist/modules/workflows/api/tasks/[id]/route.js +3 -1
- package/dist/modules/workflows/api/tasks/[id]/route.js.map +2 -2
- package/dist/modules/workflows/api/tasks/route.js +3 -1
- package/dist/modules/workflows/api/tasks/route.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/visual-editor/page.js +4 -2
- package/dist/modules/workflows/backend/definitions/visual-editor/page.js.map +2 -2
- package/dist/modules/workflows/backend/instances/[id]/page.js +5 -3
- package/dist/modules/workflows/backend/instances/[id]/page.js.map +2 -2
- package/dist/modules/workflows/backend/tasks/[id]/page.js +3 -1
- package/dist/modules/workflows/backend/tasks/[id]/page.js.map +2 -2
- package/dist/modules/workflows/components/BusinessRulesSelector.js +5 -3
- package/dist/modules/workflows/components/BusinessRulesSelector.js.map +2 -2
- package/dist/modules/workflows/components/WorkflowSelector.js +5 -3
- package/dist/modules/workflows/components/WorkflowSelector.js.map +2 -2
- package/dist/modules/workflows/components/fields/BusinessRuleConditionsEditor.js +3 -1
- package/dist/modules/workflows/components/fields/BusinessRuleConditionsEditor.js.map +2 -2
- package/dist/modules/workflows/components/fields/StartPreConditionsEditor.js +3 -1
- package/dist/modules/workflows/components/fields/StartPreConditionsEditor.js.map +2 -2
- package/dist/modules/workflows/components/fields/WorkflowSelectorField.js +3 -1
- package/dist/modules/workflows/components/fields/WorkflowSelectorField.js.map +2 -2
- package/dist/modules/workflows/frontend/checkout-demo/page.js +8 -7
- package/dist/modules/workflows/frontend/checkout-demo/page.js.map +2 -2
- package/dist/modules/workflows/lib/activity-executor.js +25 -21
- package/dist/modules/workflows/lib/activity-executor.js.map +2 -2
- package/dist/modules/workflows/lib/activity-worker-handler.js +8 -15
- package/dist/modules/workflows/lib/activity-worker-handler.js.map +2 -2
- package/dist/modules/workflows/lib/code-registry.js +7 -7
- package/dist/modules/workflows/lib/code-registry.js.map +2 -2
- package/dist/modules/workflows/lib/compensation-handler.js +4 -2
- package/dist/modules/workflows/lib/compensation-handler.js.map +2 -2
- package/dist/modules/workflows/lib/edgeFormTransforms.js +3 -1
- package/dist/modules/workflows/lib/edgeFormTransforms.js.map +2 -2
- package/dist/modules/workflows/lib/event-trigger-service.js +5 -3
- package/dist/modules/workflows/lib/event-trigger-service.js.map +2 -2
- package/dist/modules/workflows/lib/nodeFormTransforms.js +3 -1
- package/dist/modules/workflows/lib/nodeFormTransforms.js.map +2 -2
- package/dist/modules/workflows/lib/seeds.js +16 -2
- package/dist/modules/workflows/lib/seeds.js.map +2 -2
- package/dist/modules/workflows/lib/signal-handler.js +3 -1
- package/dist/modules/workflows/lib/signal-handler.js.map +2 -2
- package/dist/modules/workflows/lib/start-validator.js +9 -3
- package/dist/modules/workflows/lib/start-validator.js.map +2 -2
- package/dist/modules/workflows/lib/step-handler.js +3 -1
- package/dist/modules/workflows/lib/step-handler.js.map +2 -2
- package/dist/modules/workflows/lib/task-handler.js +3 -1
- package/dist/modules/workflows/lib/task-handler.js.map +2 -2
- package/dist/modules/workflows/lib/transition-handler.js +5 -3
- package/dist/modules/workflows/lib/transition-handler.js.map +2 -2
- package/dist/modules/workflows/lib/workflow-executor.js +27 -15
- package/dist/modules/workflows/lib/workflow-executor.js.map +2 -2
- package/dist/modules/workflows/subscribers/event-trigger.js +21 -18
- package/dist/modules/workflows/subscribers/event-trigger.js.map +2 -2
- package/dist/modules/workflows/subscribers/task-assigned-notification.js +3 -1
- package/dist/modules/workflows/subscribers/task-assigned-notification.js.map +2 -2
- package/dist/modules/workflows/workers/workflow-activities.worker.js +30 -20
- package/dist/modules/workflows/workers/workflow-activities.worker.js.map +2 -2
- package/package.json +7 -7
- package/src/bootstrap.ts +14 -11
- package/src/helpers/integration/queue-runner.ts +2 -2
- package/src/modules/api_keys/services/apiKeyService.ts +6 -3
- package/src/modules/attachments/api/image/[id]/[[...slug]]/route.ts +5 -2
- package/src/modules/attachments/api/library/[id]/route.ts +4 -1
- package/src/modules/attachments/api/route.ts +9 -6
- package/src/modules/attachments/components/AttachmentPartitionSettings.tsx +6 -3
- package/src/modules/attachments/lib/assignmentDetails.ts +4 -1
- package/src/modules/attachments/lib/drivers/driverFactory.ts +4 -1
- package/src/modules/attachments/lib/ocrQueue.ts +11 -11
- package/src/modules/attachments/lib/ocrService.ts +7 -4
- package/src/modules/audit_logs/api/audit-logs/actions/redo/route.ts +4 -1
- package/src/modules/audit_logs/api/audit-logs/actions/undo/route.ts +4 -1
- package/src/modules/audit_logs/backend/audit-logs/page.tsx +4 -1
- package/src/modules/audit_logs/components/AuditLogsActions.tsx +5 -2
- package/src/modules/audit_logs/services/accessLogService.ts +5 -4
- package/src/modules/audit_logs/services/actionLogService.ts +5 -2
- package/src/modules/auth/api/profile/route.ts +5 -2
- package/src/modules/auth/api/reset/confirm.ts +4 -1
- package/src/modules/auth/api/reset.ts +5 -2
- package/src/modules/auth/api/roles/route.ts +4 -1
- package/src/modules/auth/api/sidebar/variants/route.ts +4 -2
- package/src/modules/auth/api/users/resend-invite/route.ts +5 -2
- package/src/modules/auth/api/users/route.ts +4 -1
- package/src/modules/auth/backend/auth/profile/page.tsx +4 -1
- package/src/modules/auth/backend/profile/change-password/page.tsx +4 -1
- package/src/modules/auth/backend/users/[id]/edit/page.tsx +6 -3
- package/src/modules/auth/backend/users/create/page.tsx +5 -2
- package/src/modules/auth/cli.ts +10 -0
- package/src/modules/auth/commands/users.ts +5 -2
- package/src/modules/auth/lib/consentIntegrity.ts +4 -4
- package/src/modules/auth/lib/setup-app.ts +10 -10
- package/src/modules/auth/lib/tenantAccess.ts +4 -1
- package/src/modules/auth/lib/tokenHash.ts +4 -4
- package/src/modules/business_rules/api/rules/route.ts +5 -2
- package/src/modules/business_rules/lib/expression-evaluator.ts +8 -6
- package/src/modules/business_rules/lib/rule-engine.ts +6 -3
- package/src/modules/business_rules/lib/rule-evaluator.ts +11 -11
- package/src/modules/business_rules/subscribers/crud-rule-trigger.ts +4 -1
- package/src/modules/business_rules/subscribers/rule-execution-failed-notification.ts +4 -1
- package/src/modules/catalog/ai-agents-context.ts +5 -5
- package/src/modules/catalog/ai-tools/_shared.ts +4 -1
- package/src/modules/catalog/ai-tools/authoring-pack.ts +4 -1
- package/src/modules/catalog/ai-tools/merchandising-pack.ts +4 -1
- package/src/modules/catalog/api/dictionaries/[key]/route.ts +4 -1
- package/src/modules/catalog/api/prices/route.ts +4 -1
- package/src/modules/catalog/api/products/route.ts +6 -3
- package/src/modules/catalog/api/settings/route.ts +5 -2
- package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +15 -12
- package/src/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.tsx +9 -6
- package/src/modules/catalog/backend/catalog/products/[productId]/variants/create/page.tsx +6 -3
- package/src/modules/catalog/backend/catalog/products/create/page.tsx +6 -6
- package/src/modules/catalog/backend/catalog/products/optionSchemaClient.ts +4 -1
- package/src/modules/catalog/components/PriceKindSettings.tsx +6 -3
- package/src/modules/catalog/components/UnitPriceDisplaySettings.tsx +5 -2
- package/src/modules/catalog/inbox-actions.ts +5 -2
- package/src/modules/catalog/seed/examples.ts +5 -5
- package/src/modules/catalog/subscribers/low-stock-notification.ts +4 -1
- package/src/modules/catalog/widgets/injection/product-seo/state.ts +4 -1
- package/src/modules/communication_channels/api/get/oauth/[provider]/callback/route.ts +13 -13
- package/src/modules/communication_channels/api/post/channels/[id]/import-history/route.ts +4 -1
- package/src/modules/communication_channels/api/post/channels/[id]/push/register/route.ts +4 -1
- package/src/modules/communication_channels/api/post/webhook/[provider]/route.ts +6 -3
- package/src/modules/communication_channels/api/post/webhooks/gmail/route.ts +7 -6
- package/src/modules/communication_channels/commands/connect-credential-channel.ts +5 -10
- package/src/modules/communication_channels/commands/delete-channel.ts +4 -5
- package/src/modules/communication_channels/commands/deliver-outbound-message.ts +5 -5
- package/src/modules/communication_channels/commands/disconnect-channel.ts +4 -5
- package/src/modules/communication_channels/commands/ingest-inbound-message.ts +6 -12
- package/src/modules/communication_channels/commands/push-unregister.ts +4 -3
- package/src/modules/communication_channels/commands/reassign-conversation.ts +6 -3
- package/src/modules/communication_channels/lib/dead-letter.ts +4 -5
- package/src/modules/communication_channels/lib/email-mime.ts +5 -6
- package/src/modules/communication_channels/lib/oauth-client-config.ts +7 -3
- package/src/modules/communication_channels/lib/send-as-user.ts +4 -1
- package/src/modules/communication_channels/lib/thread-token.ts +5 -2
- package/src/modules/communication_channels/setup.ts +4 -4
- package/src/modules/communication_channels/workers/channel-import-history.ts +5 -8
- package/src/modules/communication_channels/workers/gmail-history-sync.ts +9 -18
- package/src/modules/communication_channels/workers/gmail-renew-watch.ts +6 -9
- package/src/modules/communication_channels/workers/outbound-delivery.ts +7 -12
- package/src/modules/communication_channels/workers/poll-channel.ts +8 -15
- package/src/modules/communication_channels/workers/poll-tick.ts +6 -6
- package/src/modules/communication_channels/workers/reaction-processor.ts +6 -9
- package/src/modules/configs/api/cache/route.ts +5 -2
- package/src/modules/configs/api/system-status/route.ts +5 -2
- package/src/modules/configs/api/upgrade-actions/route.ts +5 -2
- package/src/modules/configs/components/ModuleTelemetryPanel.tsx +4 -1
- package/src/modules/configs/lib/touchGeneratedBarrels.ts +1 -1
- package/src/modules/configs/services/upgradeActionsService.ts +7 -3
- package/src/modules/currencies/components/CurrencyFetchingConfig.tsx +4 -1
- package/src/modules/currencies/lib/exchangeRateFormConfig.ts +4 -1
- package/src/modules/currencies/services/providers/nbp.ts +7 -4
- package/src/modules/currencies/services/providers/raiffeisen.ts +8 -7
- package/src/modules/customer_accounts/api/domain-resolve/all.ts +7 -5
- package/src/modules/customer_accounts/api/signup.ts +5 -2
- package/src/modules/customer_accounts/lib/customerAuthServer.ts +4 -1
- package/src/modules/customer_accounts/subscribers/autoLinkCrm.ts +4 -1
- package/src/modules/customer_accounts/subscribers/autoLinkCrmReverse.ts +4 -1
- package/src/modules/customer_accounts/subscribers/unlinkOnCompanyDelete.ts +4 -1
- package/src/modules/customer_accounts/subscribers/unlinkOnPersonDelete.ts +4 -1
- package/src/modules/customers/ai-agents-context.ts +5 -5
- package/src/modules/customers/api/activities/route.ts +7 -4
- package/src/modules/customers/api/comments/route.ts +4 -1
- package/src/modules/customers/api/companies/[id]/people/route.ts +4 -1
- package/src/modules/customers/api/companies/[id]/route.ts +6 -3
- package/src/modules/customers/api/companies/route.ts +6 -3
- package/src/modules/customers/api/dashboard/widgets/customer-todos/route.ts +4 -1
- package/src/modules/customers/api/dashboard/widgets/new-customers/route.ts +4 -1
- package/src/modules/customers/api/dashboard/widgets/new-deals/route.ts +4 -1
- package/src/modules/customers/api/dashboard/widgets/next-interactions/route.ts +4 -1
- package/src/modules/customers/api/deals/[id]/companies/route.ts +4 -1
- package/src/modules/customers/api/deals/[id]/people/route.ts +4 -1
- package/src/modules/customers/api/deals/aggregate/route.ts +4 -1
- package/src/modules/customers/api/deals/bulk-update-owner/route.ts +8 -5
- package/src/modules/customers/api/deals/bulk-update-stage/route.ts +8 -5
- package/src/modules/customers/api/deals/route.ts +4 -1
- package/src/modules/customers/api/deals/summary/route.ts +4 -1
- package/src/modules/customers/api/dictionaries/[kind]/[id]/route.ts +5 -2
- package/src/modules/customers/api/dictionaries/[kind]/route.ts +6 -3
- package/src/modules/customers/api/dictionaries/cache.ts +4 -1
- package/src/modules/customers/api/dictionaries/context.ts +4 -1
- package/src/modules/customers/api/dictionaries/currency/route.ts +4 -1
- package/src/modules/customers/api/dictionaries/kind-settings/route.ts +5 -2
- package/src/modules/customers/api/entity-roles-factory.ts +8 -5
- package/src/modules/customers/api/interactions/cancel/route.ts +4 -1
- package/src/modules/customers/api/interactions/complete/route.ts +4 -1
- package/src/modules/customers/api/interactions/conflicts/route.ts +4 -1
- package/src/modules/customers/api/interactions/counts/route.ts +4 -1
- package/src/modules/customers/api/interactions/route.ts +8 -4
- package/src/modules/customers/api/interactions/tasks/route.ts +4 -1
- package/src/modules/customers/api/labels/assign/route.ts +4 -1
- package/src/modules/customers/api/labels/route.ts +7 -3
- package/src/modules/customers/api/labels/unassign/route.ts +4 -1
- package/src/modules/customers/api/people/[id]/companies/enriched/route.ts +4 -1
- package/src/modules/customers/api/people/[id]/route.ts +6 -3
- package/src/modules/customers/api/people/route.ts +6 -3
- package/src/modules/customers/api/pipeline-stages/reorder/route.ts +4 -1
- package/src/modules/customers/api/pipeline-stages/route.ts +7 -4
- package/src/modules/customers/api/pipelines/route.ts +7 -4
- package/src/modules/customers/api/settings/address-format/route.ts +5 -2
- package/src/modules/customers/api/settings/dictionary-sort-modes/route.ts +5 -2
- package/src/modules/customers/api/settings/stuck-threshold/route.ts +5 -2
- package/src/modules/customers/api/tags/assign/route.ts +4 -1
- package/src/modules/customers/api/tags/unassign/route.ts +4 -1
- package/src/modules/customers/api/todos/route.ts +7 -4
- package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +6 -3
- package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealActivities.ts +4 -1
- package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealClosure.ts +4 -1
- package/src/modules/customers/backend/customers/deals/map/components/DealsMapCanvasImpl.tsx +5 -3
- package/src/modules/customers/backend/customers/deals/page.tsx +5 -2
- package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +6 -3
- package/src/modules/customers/commands/deals.ts +4 -1
- package/src/modules/customers/commands/dictionaries.ts +4 -1
- package/src/modules/customers/commands/interactions.ts +5 -2
- package/src/modules/customers/commands/shared.ts +5 -2
- package/src/modules/customers/commands/todos.ts +4 -1
- package/src/modules/customers/components/DictionarySettings.tsx +6 -3
- package/src/modules/customers/components/DictionarySortSettings.tsx +4 -1
- package/src/modules/customers/components/detail/ActivitiesCard.tsx +4 -1
- package/src/modules/customers/components/detail/ActivitiesDayStrip.tsx +4 -1
- package/src/modules/customers/components/detail/ActivitiesSection.tsx +7 -4
- package/src/modules/customers/components/detail/ActivityCard.tsx +4 -1
- package/src/modules/customers/components/detail/ChangelogTab.tsx +4 -1
- package/src/modules/customers/components/detail/CompanyCard.tsx +4 -1
- package/src/modules/customers/components/detail/ConfirmDealLostDialog.tsx +4 -1
- package/src/modules/customers/components/detail/EntityTagsDialog.tsx +4 -1
- package/src/modules/customers/components/detail/InlineActivityComposer.tsx +4 -1
- package/src/modules/customers/components/detail/ManageTagsDialog.tsx +4 -1
- package/src/modules/customers/components/detail/RoleAssignmentRow.tsx +6 -3
- package/src/modules/customers/components/detail/RolesSection.tsx +5 -2
- package/src/modules/customers/components/detail/hooks/useInteractionMutations.ts +6 -3
- package/src/modules/customers/components/linking/LinkEntityDialog.tsx +5 -2
- package/src/modules/customers/inbox-actions.ts +4 -1
- package/src/modules/customers/lib/bulkDeals.ts +4 -1
- package/src/modules/customers/lib/dealClosureNotification.ts +5 -2
- package/src/modules/customers/lib/dealStageTransitionTable.ts +4 -1
- package/src/modules/customers/lib/interactionFeatureFlags.ts +5 -1
- package/src/modules/customers/lib/todoCompatibility.ts +4 -1
- package/src/modules/customers/search.ts +15 -7
- package/src/modules/customers/widgets/dashboard/customer-todos/widget.client.tsx +4 -1
- package/src/modules/customers/widgets/dashboard/new-customers/widget.client.tsx +4 -1
- package/src/modules/customers/widgets/dashboard/new-deals/widget.client.tsx +4 -1
- package/src/modules/customers/widgets/dashboard/next-interactions/widget.client.tsx +4 -1
- package/src/modules/dashboards/api/widgets/data/batch/route.ts +4 -1
- package/src/modules/dashboards/api/widgets/data/route.ts +4 -1
- package/src/modules/dashboards/components/WidgetVisibilityEditor.tsx +6 -3
- package/src/modules/dashboards/widgets/dashboard/aov-kpi/widget.client.tsx +4 -1
- package/src/modules/dashboards/widgets/dashboard/new-customers-kpi/widget.client.tsx +4 -1
- package/src/modules/dashboards/widgets/dashboard/orders-by-status/widget.client.tsx +4 -1
- package/src/modules/dashboards/widgets/dashboard/orders-kpi/widget.client.tsx +4 -1
- package/src/modules/dashboards/widgets/dashboard/pipeline-summary/widget.client.tsx +4 -1
- package/src/modules/dashboards/widgets/dashboard/revenue-kpi/widget.client.tsx +4 -1
- package/src/modules/dashboards/widgets/dashboard/revenue-trend/widget.client.tsx +4 -1
- package/src/modules/dashboards/widgets/dashboard/sales-by-region/widget.client.tsx +4 -1
- package/src/modules/dashboards/widgets/dashboard/top-customers/widget.client.tsx +4 -1
- package/src/modules/dashboards/widgets/dashboard/top-products/widget.client.tsx +4 -1
- package/src/modules/data_sync/api/run.ts +4 -1
- package/src/modules/data_sync/backend/data-sync/runs/[id]/page.tsx +3 -1
- package/src/modules/data_sync/lib/adapter-registry.ts +16 -4
- package/src/modules/data_sync/lib/sync-engine.ts +31 -2
- package/src/modules/data_sync/workers/sync-export.ts +4 -1
- package/src/modules/data_sync/workers/sync-import.ts +4 -1
- package/src/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.ts +5 -2
- package/src/modules/dictionaries/api/[dictionaryId]/entries/reorder/route.ts +4 -1
- package/src/modules/dictionaries/api/[dictionaryId]/entries/route.ts +5 -2
- package/src/modules/dictionaries/api/[dictionaryId]/entries/set-default/route.ts +4 -1
- package/src/modules/dictionaries/api/[dictionaryId]/route.ts +6 -3
- package/src/modules/dictionaries/api/context.ts +4 -1
- package/src/modules/dictionaries/api/route.ts +5 -2
- package/src/modules/dictionaries/components/DictionariesManager.tsx +6 -3
- package/src/modules/dictionaries/components/DictionaryEntriesEditor.tsx +5 -2
- package/src/modules/dictionaries/components/DictionaryEntrySelect.tsx +5 -2
- package/src/modules/dictionaries/components/DictionarySelectControl.tsx +4 -1
- package/src/modules/dictionaries/fields/dictionary.tsx +4 -1
- package/src/modules/directory/api/organization-branding/route.ts +4 -1
- package/src/modules/directory/api/organization-switcher/route.ts +4 -1
- package/src/modules/directory/commands/tenants.ts +6 -3
- package/src/modules/directory/utils/organizationScope.ts +7 -4
- package/src/modules/entities/api/definitions.cache.ts +4 -1
- package/src/modules/entities/api/definitions.ts +8 -5
- package/src/modules/entities/api/records.ts +5 -2
- package/src/modules/entities/components/EncryptionManager.tsx +4 -1
- package/src/modules/entities/lib/makeActivityRoute.ts +4 -1
- package/src/modules/feature_toggles/api/overrides/route.ts +4 -1
- package/src/modules/feature_toggles/lib/feature-flag-check.ts +6 -9
- package/src/modules/inbox_ops/api/emails/[id]/reprocess/route.ts +5 -2
- package/src/modules/inbox_ops/api/emails/[id]/route.ts +5 -2
- package/src/modules/inbox_ops/api/emails/route.ts +4 -1
- package/src/modules/inbox_ops/api/extract/route.ts +4 -1
- package/src/modules/inbox_ops/api/proposals/[id]/actions/[actionId]/route.ts +4 -1
- package/src/modules/inbox_ops/api/proposals/[id]/replies/[replyId]/send/route.ts +5 -2
- package/src/modules/inbox_ops/api/proposals/counts/route.ts +5 -2
- package/src/modules/inbox_ops/api/proposals/route.ts +4 -1
- package/src/modules/inbox_ops/api/routeHelpers.ts +4 -1
- package/src/modules/inbox_ops/api/settings/route.ts +4 -1
- package/src/modules/inbox_ops/api/webhook/inbound.ts +8 -5
- package/src/modules/inbox_ops/lib/cache.ts +5 -2
- package/src/modules/inbox_ops/lib/catalogLookup.ts +4 -1
- package/src/modules/inbox_ops/lib/eventBus.ts +4 -4
- package/src/modules/inbox_ops/lib/messagesIntegration.ts +5 -8
- package/src/modules/inbox_ops/subscribers/executionAuditor.ts +5 -1
- package/src/modules/inbox_ops/subscribers/extractionWorker.ts +11 -8
- package/src/modules/inbox_ops/subscribers/proposalNotifier.ts +4 -1
- package/src/modules/messages/api/[id]/route.ts +4 -4
- package/src/modules/messages/commands/actions.ts +4 -1
- package/src/modules/messages/components/MessagesInboxPageClient.tsx +4 -1
- package/src/modules/messages/lib/email-sender.ts +4 -7
- package/src/modules/messages/lib/message-objects-registry.ts +4 -1
- package/src/modules/messages/lib/message-types-registry.ts +4 -1
- package/src/modules/messages/workers/send-email.worker.ts +7 -4
- package/src/modules/notifications/lib/notificationMapper.ts +4 -4
- package/src/modules/notifications/lib/notificationService.ts +4 -5
- package/src/modules/notifications/subscribers/deliver-notification.ts +9 -14
- package/src/modules/payment_gateways/api/webhook/[provider]/route.ts +4 -1
- package/src/modules/perspectives/services/perspectiveService.ts +4 -3
- package/src/modules/planner/api/access.ts +4 -3
- package/src/modules/planner/api/availability-date-specific.ts +4 -1
- package/src/modules/planner/api/availability-weekly.ts +4 -1
- package/src/modules/planner/backend/planner/availability-rulesets/page.tsx +5 -2
- package/src/modules/planner/components/AvailabilityRulesEditor.tsx +4 -1
- package/src/modules/progress/api/jobs/route.ts +4 -1
- package/src/modules/query_index/components/QueryIndexesTable.tsx +6 -3
- package/src/modules/query_index/lib/batch.ts +5 -2
- package/src/modules/query_index/lib/coverage.ts +4 -1
- package/src/modules/query_index/lib/engine.ts +14 -17
- package/src/modules/query_index/lib/reindexer.ts +9 -6
- package/src/modules/query_index/lib/search-tokens.ts +4 -2
- package/src/modules/query_index/subscribers/coverage_refresh.ts +4 -1
- package/src/modules/resources/api/comments.ts +4 -1
- package/src/modules/resources/api/resources/tags/assign/route.ts +4 -1
- package/src/modules/resources/api/resources/tags/unassign/route.ts +4 -1
- package/src/modules/resources/backend/resources/resource-types/[id]/edit/page.tsx +4 -1
- package/src/modules/resources/backend/resources/resource-types/page.tsx +5 -2
- package/src/modules/resources/commands/activities.ts +5 -4
- package/src/modules/resources/commands/comments.ts +6 -4
- package/src/modules/resources/commands/shared.ts +36 -0
- package/src/modules/sales/api/channels/route.ts +4 -1
- package/src/modules/sales/api/document-history/route.ts +4 -1
- package/src/modules/sales/api/document-numbers/route.ts +4 -1
- package/src/modules/sales/api/quotes/accept/route.ts +5 -2
- package/src/modules/sales/api/quotes/convert/route.ts +4 -1
- package/src/modules/sales/api/quotes/public/[token]/route.ts +4 -1
- package/src/modules/sales/api/quotes/send/route.ts +4 -1
- package/src/modules/sales/api/returns/[id]/route.ts +4 -1
- package/src/modules/sales/api/settings/document-numbers/route.ts +5 -2
- package/src/modules/sales/api/settings/order-editing/route.ts +5 -2
- package/src/modules/sales/backend/sales/channels/[channelId]/edit/page.tsx +4 -1
- package/src/modules/sales/backend/sales/channels/offers/page.tsx +7 -4
- package/src/modules/sales/backend/sales/channels/page.tsx +5 -2
- package/src/modules/sales/backend/sales/documents/[id]/page.tsx +21 -18
- package/src/modules/sales/commands/documents.ts +5 -8
- package/src/modules/sales/commands/payments.ts +4 -1
- package/src/modules/sales/commands/shipments.ts +4 -2
- package/src/modules/sales/components/AdjustmentKindSettings.tsx +6 -3
- package/src/modules/sales/components/DocumentNumberSettings.tsx +5 -2
- package/src/modules/sales/components/OrderEditingSettings.tsx +5 -2
- package/src/modules/sales/components/PaymentMethodsSettings.tsx +6 -3
- package/src/modules/sales/components/ShippingMethodsSettings.tsx +6 -3
- package/src/modules/sales/components/StatusSettings.tsx +6 -3
- package/src/modules/sales/components/TaxRatesSettings.tsx +6 -3
- package/src/modules/sales/components/channels/ChannelOfferForm.tsx +17 -14
- package/src/modules/sales/components/channels/SalesChannelOffersPanel.tsx +5 -2
- package/src/modules/sales/components/documents/AddressesSection.tsx +6 -3
- package/src/modules/sales/components/documents/AdjustmentDialog.tsx +4 -1
- package/src/modules/sales/components/documents/AdjustmentsSection.tsx +6 -3
- package/src/modules/sales/components/documents/ItemsSection.tsx +7 -4
- package/src/modules/sales/components/documents/LineItemDialog.tsx +9 -6
- package/src/modules/sales/components/documents/PaymentDialog.tsx +6 -3
- package/src/modules/sales/components/documents/PaymentsSection.tsx +5 -2
- package/src/modules/sales/components/documents/SalesDocumentForm.tsx +15 -12
- package/src/modules/sales/components/documents/SalesDocumentsTable.tsx +6 -3
- package/src/modules/sales/components/documents/ShipmentDialog.tsx +10 -7
- package/src/modules/sales/components/documents/ShipmentsSection.tsx +5 -2
- package/src/modules/sales/frontend/quote/[token]/page.tsx +5 -2
- package/src/modules/sales/seed/examples.ts +8 -9
- package/src/modules/sales/subscribers/quote-expiring-notification.ts +4 -1
- package/src/modules/sales/subscribers/reconcileOnAddressDelete.ts +4 -1
- package/src/modules/sales/subscribers/reconcileOnCompanyDelete.ts +4 -1
- package/src/modules/sales/subscribers/reconcileOnCustomerDelete.ts +4 -1
- package/src/modules/sales/widgets/dashboard/makeDashboardWidgetRoute.ts +6 -3
- package/src/modules/sales/widgets/dashboard/new-orders/widget.client.tsx +274 -271
- package/src/modules/sales/widgets/dashboard/new-quotes/widget.client.tsx +280 -277
- package/src/modules/shipping_carriers/api/tracking/route.ts +5 -1
- package/src/modules/shipping_carriers/api/webhook/[provider]/route.ts +4 -1
- package/src/modules/shipping_carriers/lib/shipping-service.ts +47 -22
- package/src/modules/shipping_carriers/lib/upstream-error-response.ts +4 -1
- package/src/modules/shipping_carriers/workers/webhook-processor.ts +4 -5
- package/src/modules/staff/api/comments.ts +4 -1
- package/src/modules/staff/api/leave-requests/accept/route.ts +4 -1
- package/src/modules/staff/api/leave-requests/reject/route.ts +4 -1
- package/src/modules/staff/api/team-members/assignable/route.ts +4 -1
- package/src/modules/staff/api/team-members/self/route.ts +5 -2
- package/src/modules/staff/api/team-members/tags/assign/route.ts +4 -1
- package/src/modules/staff/api/team-members/tags/unassign/route.ts +4 -1
- package/src/modules/staff/api/timesheets/my-projects/[projectId]/route.ts +4 -1
- package/src/modules/staff/api/timesheets/my-projects/route.ts +4 -1
- package/src/modules/staff/api/timesheets/projects/kpis/route.ts +4 -1
- package/src/modules/staff/api/timesheets/time-entries/[id]/segments/route.ts +4 -1
- package/src/modules/staff/api/timesheets/time-entries/[id]/timer-start/route.ts +5 -2
- package/src/modules/staff/api/timesheets/time-entries/[id]/timer-stop/route.ts +5 -2
- package/src/modules/staff/api/timesheets/time-entries/bulk/route.ts +4 -1
- package/src/modules/staff/api/timesheets/time-entries/start-timer/route.ts +4 -1
- package/src/modules/staff/backend/staff/team-members/page.tsx +5 -2
- package/src/modules/staff/backend/staff/team-roles/page.tsx +5 -2
- package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +5 -2
- package/src/modules/staff/backend/staff/teams/page.tsx +5 -2
- package/src/modules/staff/backend/staff/timesheets/page.tsx +8 -5
- package/src/modules/staff/backend/staff/timesheets/projects/[id]/page.tsx +4 -1
- package/src/modules/staff/backend/staff/timesheets/projects/page.tsx +5 -2
- package/src/modules/staff/commands/timesheets-entries.ts +4 -1
- package/src/modules/staff/widgets/dashboard/timesheets-hours-by-project/widget.client.tsx +4 -1
- package/src/modules/staff/widgets/dashboard/timesheets-time-reporting/widget.client.tsx +6 -3
- package/src/modules/sync_excel/api/import/route.ts +4 -1
- package/src/modules/translations/api/[entityType]/[entityId]/route.ts +6 -3
- package/src/modules/translations/api/get/locales.ts +4 -1
- package/src/modules/translations/api/put/locales.ts +4 -1
- package/src/modules/translations/components/TranslationManager.tsx +4 -1
- package/src/modules/translations/subscribers/cleanup.ts +4 -1
- package/src/modules/workflows/api/definitions/[id]/customize/route.ts +5 -2
- package/src/modules/workflows/api/definitions/[id]/reset-to-code/route.ts +5 -2
- package/src/modules/workflows/api/definitions/[id]/route.ts +7 -4
- package/src/modules/workflows/api/definitions/route.ts +5 -2
- package/src/modules/workflows/api/events/[id]/route.ts +4 -1
- package/src/modules/workflows/api/events/route.ts +4 -1
- package/src/modules/workflows/api/instances/[id]/advance/route.ts +4 -1
- package/src/modules/workflows/api/instances/[id]/cancel/route.ts +4 -1
- package/src/modules/workflows/api/instances/[id]/events/route.ts +4 -1
- package/src/modules/workflows/api/instances/[id]/retry/route.ts +4 -1
- package/src/modules/workflows/api/instances/[id]/route.ts +4 -1
- package/src/modules/workflows/api/instances/[id]/signal/route.ts +6 -7
- package/src/modules/workflows/api/instances/route.ts +6 -3
- package/src/modules/workflows/api/instances/validate-start/route.ts +4 -1
- package/src/modules/workflows/api/signals/route.ts +4 -1
- package/src/modules/workflows/api/tasks/[id]/claim/route.ts +4 -1
- package/src/modules/workflows/api/tasks/[id]/complete/route.ts +4 -1
- package/src/modules/workflows/api/tasks/[id]/route.ts +4 -1
- package/src/modules/workflows/api/tasks/route.ts +4 -1
- package/src/modules/workflows/backend/definitions/visual-editor/page.tsx +5 -2
- package/src/modules/workflows/backend/instances/[id]/page.tsx +6 -3
- package/src/modules/workflows/backend/tasks/[id]/page.tsx +4 -1
- package/src/modules/workflows/components/BusinessRulesSelector.tsx +6 -3
- package/src/modules/workflows/components/WorkflowSelector.tsx +6 -3
- package/src/modules/workflows/components/fields/BusinessRuleConditionsEditor.tsx +4 -1
- package/src/modules/workflows/components/fields/StartPreConditionsEditor.tsx +4 -1
- package/src/modules/workflows/components/fields/WorkflowSelectorField.tsx +4 -1
- package/src/modules/workflows/frontend/checkout-demo/page.tsx +9 -7
- package/src/modules/workflows/lib/activity-executor.ts +26 -21
- package/src/modules/workflows/lib/activity-worker-handler.ts +9 -15
- package/src/modules/workflows/lib/code-registry.ts +8 -7
- package/src/modules/workflows/lib/compensation-handler.ts +5 -2
- package/src/modules/workflows/lib/edgeFormTransforms.ts +4 -1
- package/src/modules/workflows/lib/event-trigger-service.ts +6 -3
- package/src/modules/workflows/lib/nodeFormTransforms.ts +4 -1
- package/src/modules/workflows/lib/seeds.ts +17 -2
- package/src/modules/workflows/lib/signal-handler.ts +4 -1
- package/src/modules/workflows/lib/start-validator.ts +10 -3
- package/src/modules/workflows/lib/step-handler.ts +4 -1
- package/src/modules/workflows/lib/task-handler.ts +4 -1
- package/src/modules/workflows/lib/transition-handler.ts +6 -3
- package/src/modules/workflows/lib/workflow-executor.ts +28 -15
- package/src/modules/workflows/subscribers/event-trigger.ts +22 -24
- package/src/modules/workflows/subscribers/task-assigned-notification.ts +4 -1
- package/src/modules/workflows/workers/workflow-activities.worker.ts +31 -20
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../../src/modules/staff/backend/staff/timesheets/projects/page.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useRouter, useSearchParams } from 'next/navigation'\nimport type { ColumnDef, SortingState } from '@tanstack/react-table'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable, withDataTableNamespaces } from '@open-mercato/ui/backend/DataTable'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterOverlay'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'\nimport { deleteCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT, type TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport { formatDateTime } from '@open-mercato/shared/lib/time'\nimport { ProjectColorDot } from '../../../../lib/timesheets-ui/ProjectColorDot'\nimport { resolveProjectColorHex } from '../../../../lib/timesheets-ui/colors'\nimport {\n ProjectsKpiStrip,\n type PmKpis,\n type CollabKpis,\n} from '../../../../lib/timesheets-projects-ui/ProjectsKpiStrip'\nimport { SavedViewTabs } from '../../../../lib/timesheets-projects-ui/SavedViewTabs'\nimport { HoursSparkline } from '../../../../lib/timesheets-projects-ui/HoursSparkline'\nimport {\n ProjectMembersAvatarStack,\n type AvatarMember,\n} from '../../../../lib/timesheets-projects-ui/ProjectMembersAvatarStack'\nimport { ViewModeToggle } from '../../../../lib/timesheets-projects-ui/ViewModeToggle'\nimport {\n useProjectsViewMode,\n type ProjectsViewMode,\n} from '../../../../lib/timesheets-projects-ui/useProjectsViewMode'\nimport {\n ProjectCard,\n type ProjectCardData,\n type ProjectCardLabels,\n} from '../../../../lib/timesheets-projects-ui/ProjectCard'\n\nconst PAGE_SIZE = 50\nconst INCLUDE_FIELDS = 'hoursWeek,hoursTrend,members,myRole'\n\ntype StaffEnrichment = {\n hoursWeek?: number\n hoursTrend?: number[]\n myRole?: string | null\n members?: AvatarMember[]\n memberCount?: number\n}\n\ntype ProjectRow = {\n id: string\n name: string\n code: string | null\n customerId: string | null\n customerName: string | null\n status: string\n projectType: string | null\n color: string | null\n startDate: string | null\n updatedAt: string | null\n hoursWeek: number\n hoursTrend: number[]\n myRole: string | null\n members: AvatarMember[]\n memberCount: number\n}\n\ntype ProjectsResponse = {\n items?: Array<Record<string, unknown>>\n total?: number\n totalPages?: number\n}\n\ntype KpisResponse = PmKpis | CollabKpis\n\nfunction formatRelativeTime(iso: string | null, fallback: string, t: TranslateFn): string {\n if (!iso) return fallback\n const parsed = new Date(iso)\n if (Number.isNaN(parsed.getTime())) return fallback\n const diffMs = Date.now() - parsed.getTime()\n const minutes = Math.round(diffMs / 60000)\n if (minutes < 1) return t('staff.timesheets.projects.portfolio.relativeTime.justNow', 'just now')\n if (minutes < 60) return t('staff.timesheets.projects.portfolio.relativeTime.minutesAgo', '{minutes}m ago', { minutes })\n const hours = Math.round(minutes / 60)\n if (hours < 24) return t('staff.timesheets.projects.portfolio.relativeTime.hoursAgo', '{hours}h ago', { hours })\n const days = Math.round(hours / 24)\n if (days < 14) return t('staff.timesheets.projects.portfolio.relativeTime.daysAgo', '{days}d ago', { days })\n return formatDateTime(iso) ?? fallback\n}\n\nfunction mapApiProject(item: Record<string, unknown>): ProjectRow {\n const id = typeof item.id === 'string' ? item.id : ''\n const name = typeof item.name === 'string' ? item.name : id\n const code = typeof item.code === 'string' && item.code.trim().length ? item.code.trim() : null\n const customerId =\n typeof item.customerId === 'string'\n ? item.customerId\n : typeof item.customer_id === 'string'\n ? item.customer_id\n : null\n const customerName =\n typeof item.customerName === 'string'\n ? item.customerName\n : typeof item.customer_name === 'string'\n ? item.customer_name\n : null\n const status = typeof item.status === 'string' ? item.status : 'active'\n const projectType =\n typeof item.projectType === 'string'\n ? item.projectType\n : typeof item.project_type === 'string'\n ? item.project_type\n : null\n const color = typeof item.color === 'string' ? item.color : null\n const startDate =\n typeof item.startDate === 'string'\n ? item.startDate\n : typeof item.start_date === 'string'\n ? item.start_date\n : null\n const updatedAt =\n typeof item.updatedAt === 'string'\n ? item.updatedAt\n : typeof item.updated_at === 'string'\n ? item.updated_at\n : null\n const enrichment =\n (item as { _staff?: StaffEnrichment })._staff ?? ({} as StaffEnrichment)\n const hoursWeek = typeof enrichment.hoursWeek === 'number' ? enrichment.hoursWeek : 0\n const hoursTrend = Array.isArray(enrichment.hoursTrend)\n ? enrichment.hoursTrend.filter((v): v is number => typeof v === 'number')\n : []\n const members = Array.isArray(enrichment.members)\n ? enrichment.members\n .filter((m): m is AvatarMember => !!m && typeof m === 'object' && typeof (m as AvatarMember).id === 'string')\n .map((m) => ({\n id: m.id,\n name: m.name ?? '',\n initials: m.initials ?? '',\n avatarUrl: m.avatarUrl ?? null,\n }))\n : []\n const memberCount = typeof enrichment.memberCount === 'number' ? enrichment.memberCount : members.length\n const myRole = typeof enrichment.myRole === 'string' ? enrichment.myRole : null\n\n return withDataTableNamespaces(\n {\n id,\n name,\n code,\n customerId,\n customerName,\n status,\n projectType,\n color,\n startDate,\n updatedAt,\n hoursWeek,\n hoursTrend,\n myRole,\n members,\n memberCount,\n },\n item,\n )\n}\n\nexport default function TimesheetProjectsPage() {\n const t = useT()\n const router = useRouter()\n const searchParams = useSearchParams()\n const scopeVersion = useOrganizationScopeVersion()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n\n const [rows, setRows] = React.useState<ProjectRow[]>([])\n const [page, setPage] = React.useState(1)\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const [sorting, setSorting] = React.useState<SortingState>([{ id: 'updatedAt', desc: true }])\n const [search, setSearch] = React.useState('')\n const [filterValues, setFilterValues] = React.useState<FilterValues>({})\n const [isLoading, setIsLoading] = React.useState(true)\n const [isRefreshing, setIsRefreshing] = React.useState(false)\n const hasLoadedOnceRef = React.useRef(false)\n const [reloadToken, setReloadToken] = React.useState(0)\n const [kpis, setKpis] = React.useState<KpisResponse | null>(null)\n const [isLoadingKpis, setIsLoadingKpis] = React.useState(true)\n\n const activeTab = searchParams.get('tab') ?? 'all'\n const urlViewMode = searchParams.get('view')\n const [viewMode, setViewMode] = useProjectsViewMode({\n userKey: null,\n urlOverride: urlViewMode,\n })\n\n const labels = React.useMemo(\n () => ({\n title: t('staff.timesheets.projects.page.title', 'Projects'),\n table: {\n name: t('staff.timesheets.projects.table.name', 'Project'),\n status: t('staff.timesheets.projects.table.status', 'Status'),\n type: t('staff.timesheets.projects.table.type', 'Type'),\n updatedAt: t('staff.timesheets.projects.table.updatedAt', 'Updated'),\n empty: t('staff.timesheets.projects.table.empty', 'No projects yet.'),\n search: t('staff.timesheets.projects.table.search', 'Search projects...'),\n team: t('staff.timesheets.projects.portfolio.team', 'Team'),\n myRole: t('staff.timesheets.projects.portfolio.myRole', 'My role'),\n hoursWeek: t('staff.timesheets.projects.portfolio.hoursWeek', 'Hours / week'),\n myHoursWeek: t('staff.timesheets.projects.portfolio.myHoursWeek', 'My hours / week'),\n },\n actions: {\n add: t('staff.timesheets.projects.actions.add', 'Add Project'),\n addFirst: t('staff.timesheets.projects.actions.addFirst', '+ Add first project'),\n viewDetails: t('staff.timesheets.projects.actions.viewDetails', 'View Details'),\n delete: t('staff.timesheets.projects.actions.delete', 'Delete'),\n deleteConfirm: t('staff.timesheets.projects.actions.deleteConfirm', 'Delete project \"{{name}}\"?'),\n refresh: t('staff.timesheets.projects.actions.refresh', 'Refresh'),\n },\n messages: {\n deleted: t('staff.timesheets.projects.messages.deleted', 'Project deleted.'),\n },\n errors: {\n load: t('staff.timesheets.projects.errors.load', 'Failed to load projects.'),\n delete: t('staff.timesheets.projects.errors.delete', 'Failed to delete project.'),\n },\n statuses: {\n all: t('staff.timesheets.projects.statuses.all', 'All'),\n active: t('staff.timesheets.projects.statuses.active', 'Active'),\n on_hold: t('staff.timesheets.projects.statuses.onHold', 'On Hold'),\n completed: t('staff.timesheets.projects.statuses.completed', 'Completed'),\n },\n tabs: {\n all: t('staff.timesheets.projects.portfolio.tabs.all', 'All'),\n active: t('staff.timesheets.projects.portfolio.tabs.active', 'Active'),\n onHold: t('staff.timesheets.projects.portfolio.tabs.onHold', 'On Hold'),\n completed: t('staff.timesheets.projects.portfolio.tabs.completed', 'Completed'),\n mine: t('staff.timesheets.projects.portfolio.tabs.mine', 'Mine'),\n },\n viewMode: {\n table: t('staff.timesheets.projects.portfolio.viewMode.table', 'Table'),\n cards: t('staff.timesheets.projects.portfolio.viewMode.cards', 'Cards'),\n },\n kpi: {\n totalProjects: t('staff.timesheets.projects.portfolio.kpi.totalProjects', 'Total Projects'),\n hoursWeek: t('staff.timesheets.projects.portfolio.kpi.hoursWeek', 'Hours this week'),\n hoursWeekSub: t('staff.timesheets.projects.portfolio.kpi.hoursWeekSub', 'vs previous week'),\n assignedToMe: t('staff.timesheets.projects.portfolio.kpi.assignedToMe', 'Assigned to me'),\n hoursMonth: t('staff.timesheets.projects.portfolio.kpi.hoursMonth', 'Hours this month'),\n hoursMonthSub: t('staff.timesheets.projects.portfolio.kpi.hoursMonthSub', 'vs previous month'),\n teamActive: t('staff.timesheets.projects.portfolio.kpi.teamActive', 'Active team'),\n teamActiveSub: t('staff.timesheets.projects.portfolio.kpi.teamActiveSub', 'Members with entries this month'),\n myProjects: t('staff.timesheets.projects.portfolio.kpi.myProjects', 'My projects'),\n myHoursWeek: t('staff.timesheets.projects.portfolio.kpi.myHoursWeek', 'My hours this week'),\n myHoursMonth: t('staff.timesheets.projects.portfolio.kpi.myHoursMonth', 'My hours this month'),\n deltaFlat: t('staff.timesheets.projects.portfolio.kpi.deltaFlat', 'no change'),\n noPrevious: t('staff.timesheets.projects.portfolio.kpi.noPrevious', 'no previous data'),\n },\n card: {\n hoursPanelPm: t('staff.timesheets.projects.portfolio.card.hoursPanelPm', 'Team hours \u00B7 last 7w'),\n hoursPanelCollab: t('staff.timesheets.projects.portfolio.card.hoursPanelCollab', 'My hours \u00B7 last 7w'),\n sparklineAria: t('staff.timesheets.projects.portfolio.sparkline.ariaLabel', 'Hours per week, last 7 weeks'),\n role: t('staff.timesheets.projects.portfolio.card.role', 'Role'),\n },\n emptyState: {\n noProjects: t('staff.timesheets.projects.portfolio.emptyState.noProjects', 'No projects yet.'),\n noAssignments: t(\n 'staff.timesheets.projects.portfolio.emptyState.noAssignments',\n \"You aren't assigned to any projects yet. Ask a PM to add you.\",\n ),\n noMatches: t('staff.timesheets.projects.portfolio.emptyState.noMatches', 'No projects match these filters.'),\n },\n }),\n [t],\n )\n\n const kpiLabels = React.useMemo(\n () => ({\n totalProjects: labels.kpi.totalProjects,\n totalProjectsSub: ({ active, onHold }: { active: number; onHold: number }) =>\n `${active} ${labels.statuses.active.toLowerCase()} \u00B7 ${onHold} ${labels.statuses.on_hold.toLowerCase()}`,\n hoursWeek: labels.kpi.hoursWeek,\n hoursWeekSub: labels.kpi.hoursWeekSub,\n assignedToMe: labels.kpi.assignedToMe,\n assignedToMeSub: (active: number) => `${active} ${labels.statuses.active.toLowerCase()}`,\n hoursMonth: labels.kpi.hoursMonth,\n hoursMonthSub: labels.kpi.hoursMonthSub,\n teamActive: labels.kpi.teamActive,\n teamActiveSub: labels.kpi.teamActiveSub,\n myProjects: labels.kpi.myProjects,\n myProjectsSub: (active: number) => `${active} ${labels.statuses.active.toLowerCase()}`,\n myHoursWeek: labels.kpi.myHoursWeek,\n myHoursMonth: labels.kpi.myHoursMonth,\n deltaUp: (pct: number) => `up ${pct}%`,\n deltaDown: (pct: number) => `down ${pct}%`,\n deltaFlat: labels.kpi.deltaFlat,\n noPrevious: labels.kpi.noPrevious,\n }),\n [labels],\n )\n\n const isPmRole = kpis?.role === 'pm'\n\n const filters = React.useMemo<FilterDef[]>(\n () => [\n {\n id: 'status',\n label: labels.table.status,\n type: 'select',\n options: [\n { value: 'active', label: labels.statuses.active },\n { value: 'on_hold', label: labels.statuses.on_hold },\n { value: 'completed', label: labels.statuses.completed },\n ],\n },\n ],\n [labels.table.status, labels.statuses],\n )\n\n const tabs = React.useMemo(() => {\n const base = [\n { id: 'all', label: labels.tabs.all },\n { id: 'active', label: labels.tabs.active },\n ]\n if (isPmRole) {\n base.push({ id: 'on_hold', label: labels.tabs.onHold })\n }\n base.push({ id: 'completed', label: labels.tabs.completed })\n if (isPmRole) {\n base.push({ id: 'mine', label: labels.tabs.mine })\n }\n return base\n }, [labels.tabs, isPmRole])\n\n const statusFromTab = (tabId: string): string | null => {\n if (tabId === 'active' || tabId === 'on_hold' || tabId === 'completed') return tabId\n return null\n }\n const mineFromTab = (tabId: string): boolean => tabId === 'mine' || !isPmRole\n\n const loadKpis = React.useCallback(async () => {\n setIsLoadingKpis(true)\n try {\n const payload = await readApiResultOrThrow<KpisResponse>(\n '/api/staff/timesheets/projects/kpis',\n undefined,\n {\n errorMessage: labels.errors.load,\n fallback: null as unknown as KpisResponse,\n },\n )\n setKpis(payload)\n } catch {\n setKpis(null)\n } finally {\n setIsLoadingKpis(false)\n }\n }, [labels.errors.load])\n\n const loadProjects = React.useCallback(async () => {\n if (hasLoadedOnceRef.current) {\n setIsRefreshing(true)\n } else {\n setIsLoading(true)\n }\n try {\n const params = new URLSearchParams({\n page: String(page),\n pageSize: String(PAGE_SIZE),\n include: INCLUDE_FIELDS,\n })\n const sort = sorting[0]\n if (sort?.id) {\n params.set('sortField', sort.id)\n params.set('sortDir', sort.desc ? 'desc' : 'asc')\n }\n if (search.trim()) params.set('q', search.trim())\n const tabStatus = statusFromTab(activeTab)\n if (tabStatus) params.set('status', tabStatus)\n else if (typeof filterValues.status === 'string' && filterValues.status.length > 0) {\n params.set('status', filterValues.status)\n }\n if (mineFromTab(activeTab)) params.set('mine', '1')\n\n const payload = await readApiResultOrThrow<ProjectsResponse>(\n `/api/staff/timesheets/time-projects?${params.toString()}`,\n undefined,\n { errorMessage: labels.errors.load, fallback: { items: [], total: 0, totalPages: 1 } },\n )\n const items = Array.isArray(payload.items) ? payload.items : []\n setRows(items.map(mapApiProject))\n setTotal(typeof payload.total === 'number' ? payload.total : items.length)\n setTotalPages(\n typeof payload.totalPages === 'number'\n ? payload.totalPages\n : Math.max(1, Math.ceil(items.length / PAGE_SIZE)),\n )\n } catch (error) {\n console.error('staff.timesheets.projects.list', error)\n flash(labels.errors.load, 'error')\n } finally {\n setIsLoading(false)\n setIsRefreshing(false)\n hasLoadedOnceRef.current = true\n }\n }, [labels.errors.load, page, search, sorting, filterValues.status, activeTab, isPmRole])\n\n React.useEffect(() => {\n void loadKpis()\n }, [loadKpis, scopeVersion, reloadToken])\n\n React.useEffect(() => {\n void loadProjects()\n }, [loadProjects, scopeVersion, reloadToken])\n\n const handleTabSelect = React.useCallback(\n (id: string) => {\n const params = new URLSearchParams(searchParams.toString())\n if (id === 'all') params.delete('tab')\n else params.set('tab', id)\n router.replace(`?${params.toString()}`)\n setPage(1)\n },\n [router, searchParams],\n )\n\n const handleViewModeChange = React.useCallback(\n (next: ProjectsViewMode) => {\n setViewMode(next)\n const params = new URLSearchParams(searchParams.toString())\n if (next === 'table') params.delete('view')\n else params.set('view', next)\n router.replace(`?${params.toString()}`)\n },\n [router, searchParams, setViewMode],\n )\n\n const handleSearchChange = React.useCallback((value: string) => {\n setSearch(value)\n setPage(1)\n }, [])\n\n const handleFiltersApply = React.useCallback((values: FilterValues) => {\n setFilterValues(values)\n setPage(1)\n }, [])\n\n const handleFiltersClear = React.useCallback(() => {\n setFilterValues({})\n setPage(1)\n }, [])\n\n const handleRefresh = React.useCallback(() => {\n setReloadToken((token) => token + 1)\n }, [])\n\n const handleDelete = React.useCallback(\n async (entry: ProjectRow) => {\n const message = labels.actions.deleteConfirm.replace('{{name}}', entry.name)\n const confirmed = await confirm({\n title: labels.actions.delete,\n text: message,\n variant: 'destructive',\n })\n if (!confirmed) return\n try {\n await withScopedApiRequestHeaders(\n buildOptimisticLockHeader(entry.updatedAt),\n () => deleteCrud('staff/timesheets/time-projects', entry.id, { errorMessage: labels.errors.delete }),\n )\n flash(labels.messages.deleted, 'success')\n handleRefresh()\n } catch (error) {\n if (surfaceRecordConflict(error, t)) { handleRefresh(); return }\n console.error('staff.timesheets.projects.delete', error)\n flash(labels.errors.delete, 'error')\n }\n },\n [confirm, handleRefresh, t, labels.actions.deleteConfirm, labels.actions.delete, labels.errors.delete, labels.messages.deleted],\n )\n\n const columns = React.useMemo<ColumnDef<ProjectRow>[]>(\n () => [\n {\n accessorKey: 'name',\n header: labels.table.name,\n meta: { priority: 1, sticky: true },\n cell: ({ row }) => (\n <div className=\"flex items-center gap-2.5\">\n <ProjectColorDot colorKey={row.original.color} projectName={row.original.name} size=\"sm\" />\n <div className=\"flex min-w-0 flex-col\">\n <span className=\"truncate text-sm font-medium text-foreground\">{row.original.name}</span>\n <span className=\"truncate font-mono text-[11px] text-muted-foreground\">\n {row.original.code ?? '\u2014'}\n {row.original.customerName ? ` \u00B7 ${row.original.customerName}` : ''}\n </span>\n </div>\n </div>\n ),\n },\n {\n accessorKey: 'status',\n header: labels.table.status,\n meta: { priority: 2 },\n cell: ({ row }) => {\n const badgeClass =\n row.original.status === 'active'\n ? 'bg-lime-100 text-lime-800 dark:bg-lime-900/30 dark:text-lime-300'\n : row.original.status === 'on_hold'\n ? 'bg-amber-100 text-amber-800 dark:bg-amber-900/30 dark:text-amber-300'\n : 'bg-muted text-muted-foreground'\n const statusLabel =\n labels.statuses[row.original.status as keyof typeof labels.statuses] ?? row.original.status\n return (\n <span\n className={`inline-flex items-center rounded-full px-2 py-0.5 text-[11px] font-medium ${badgeClass}`}\n >\n {statusLabel}\n </span>\n )\n },\n },\n {\n accessorKey: 'projectType',\n header: labels.table.type,\n meta: { priority: 3 },\n cell: ({ row }) =>\n row.original.projectType ? (\n <span className=\"text-sm text-foreground\">{row.original.projectType}</span>\n ) : (\n <span className=\"text-xs text-muted-foreground/70\">\u2014</span>\n ),\n },\n isPmRole\n ? {\n accessorKey: 'members',\n id: 'members',\n header: labels.table.team,\n enableSorting: false,\n meta: { priority: 4 },\n cell: ({ row }) => (\n <ProjectMembersAvatarStack\n members={row.original.members}\n total={row.original.memberCount}\n peopleCountLabel={`${row.original.memberCount}`}\n />\n ),\n }\n : {\n accessorKey: 'myRole',\n header: labels.table.myRole,\n enableSorting: false,\n meta: { priority: 4 },\n cell: ({ row }) =>\n row.original.myRole ? (\n <span className=\"text-sm text-foreground\">{row.original.myRole}</span>\n ) : (\n <span className=\"text-xs text-muted-foreground/70\">\u2014</span>\n ),\n },\n {\n accessorKey: 'hoursWeek',\n header: isPmRole ? labels.table.hoursWeek : labels.table.myHoursWeek,\n enableSorting: false,\n meta: { priority: 5 },\n cell: ({ row }) => {\n const stripe = resolveProjectColorHex(row.original.color, row.original.name)\n return (\n <div className=\"flex items-center justify-end gap-2\">\n <HoursSparkline\n values={row.original.hoursTrend}\n color={stripe}\n ariaLabel={labels.card.sparklineAria}\n />\n <span className=\"text-xs font-medium tabular-nums text-foreground\">\n {row.original.hoursWeek > 0 ? `${row.original.hoursWeek}h` : '\u2014'}\n </span>\n </div>\n )\n },\n },\n {\n accessorKey: 'updatedAt',\n header: labels.table.updatedAt,\n meta: { priority: 6 },\n cell: ({ row }) => (\n <span className=\"text-xs text-muted-foreground\">\n {formatRelativeTime(row.original.updatedAt, '\u2014', t)}\n </span>\n ),\n },\n ],\n [labels.table, labels.statuses, labels.card.sparklineAria, isPmRole],\n )\n\n const cardLabels = React.useMemo<ProjectCardLabels>(\n () => ({\n hoursPanelPm: labels.card.hoursPanelPm,\n hoursPanelCollab: labels.card.hoursPanelCollab,\n sparklineAria: labels.card.sparklineAria,\n peopleCount: (count: number) => `${count}`,\n role: labels.card.role,\n noCustomer: '\u2014',\n statuses: labels.statuses,\n }),\n [labels.card, labels.statuses],\n )\n\n const canManage = isPmRole\n\n const emptyStateCopy = React.useMemo(() => {\n const hasFiltersApplied = activeTab !== 'all' || search.trim().length > 0 || Object.values(filterValues).some(Boolean)\n if (hasFiltersApplied) return labels.emptyState.noMatches\n if (!canManage) return labels.emptyState.noAssignments\n return labels.emptyState.noProjects\n }, [activeTab, search, filterValues, canManage, labels.emptyState])\n\n const cardsData: ProjectCardData[] = rows.map((row) => ({\n id: row.id,\n name: row.name,\n code: row.code,\n customerName: row.customerName,\n color: row.color,\n status: row.status,\n hoursWeek: row.hoursWeek,\n hoursTrend: row.hoursTrend,\n members: row.members,\n memberCount: row.memberCount,\n myRole: row.myRole,\n updatedAt: row.updatedAt,\n }))\n\n return (\n <Page>\n <PageBody>\n <div className=\"mb-4\">\n <ProjectsKpiStrip kpis={kpis} labels={kpiLabels} isLoading={isLoadingKpis} />\n </div>\n\n <div className=\"mb-3 flex flex-wrap items-center justify-between gap-3\">\n <SavedViewTabs\n tabs={tabs}\n activeId={activeTab}\n onSelect={handleTabSelect}\n ariaLabel={t('staff.timesheets.projects.portfolio.savedViews.ariaLabel', 'Saved views')}\n />\n <ViewModeToggle\n mode={viewMode}\n onChange={handleViewModeChange}\n tableLabel={labels.viewMode.table}\n cardsLabel={labels.viewMode.cards}\n ariaLabel={t('staff.timesheets.projects.portfolio.viewMode.ariaLabel', 'View mode')}\n />\n </div>\n\n {viewMode === 'cards' ? (\n <div>\n {isLoading ? (\n <div className=\"grid grid-cols-1 gap-3 md:grid-cols-2 lg:grid-cols-3\">\n {Array.from({ length: 6 }).map((_, idx) => (\n <div key={idx} className=\"h-48 animate-pulse rounded-lg border border-border bg-muted/40\" />\n ))}\n </div>\n ) : rows.length === 0 ? (\n <div className=\"rounded-lg border border-dashed border-border bg-card p-10 text-center\">\n <p className=\"text-sm text-muted-foreground\">{emptyStateCopy}</p>\n {canManage ? (\n <div className=\"mt-3\">\n <Button asChild size=\"sm\">\n <Link href=\"/backend/staff/timesheets/projects/create\">\n {labels.actions.addFirst}\n </Link>\n </Button>\n </div>\n ) : null}\n </div>\n ) : (\n <div className=\"grid grid-cols-1 gap-3 md:grid-cols-2 lg:grid-cols-3\">\n {cardsData.map((card) => (\n <ProjectCard\n key={card.id}\n data={card}\n labels={cardLabels}\n showTeam={isPmRole}\n href={`/backend/staff/timesheets/projects/${card.id}`}\n />\n ))}\n </div>\n )}\n </div>\n ) : (\n <DataTable<ProjectRow>\n title={labels.title}\n data={rows}\n columns={columns}\n isLoading={isLoading}\n searchValue={search}\n onSearchChange={handleSearchChange}\n searchPlaceholder={labels.table.search}\n filters={filters}\n filterValues={filterValues}\n onFiltersApply={handleFiltersApply}\n onFiltersClear={handleFiltersClear}\n emptyState={\n <div className=\"py-12 text-center\">\n <p className=\"text-sm text-muted-foreground mb-4\">{emptyStateCopy}</p>\n {canManage ? (\n <Button asChild size=\"sm\">\n <Link href=\"/backend/staff/timesheets/projects/create\">{labels.actions.addFirst}</Link>\n </Button>\n ) : null}\n </div>\n }\n actions={\n canManage ? (\n <Button asChild size=\"sm\">\n <Link href=\"/backend/staff/timesheets/projects/create\">{labels.actions.add}</Link>\n </Button>\n ) : undefined\n }\n refreshButton={{\n label: labels.actions.refresh,\n onRefresh: handleRefresh,\n isRefreshing: isLoading || isRefreshing,\n }}\n sortable\n sorting={sorting}\n onSortingChange={setSorting}\n pagination={{\n page,\n pageSize: PAGE_SIZE,\n total,\n totalPages,\n onPageChange: setPage,\n }}\n rowActions={(row) => (\n <RowActions\n items={[\n {\n id: 'view',\n label: labels.actions.viewDetails,\n href: `/backend/staff/timesheets/projects/${row.id}`,\n },\n ...(canManage\n ? [\n {\n id: 'delete',\n label: labels.actions.delete,\n destructive: true,\n onSelect: () => {\n void handleDelete(row)\n },\n },\n ]\n : []),\n ]}\n />\n )}\n onRowClick={(row) => router.push(`/backend/staff/timesheets/projects/${row.id}`)}\n />\n )}\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useRouter, useSearchParams } from 'next/navigation'\nimport type { ColumnDef, SortingState } from '@tanstack/react-table'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable, withDataTableNamespaces } from '@open-mercato/ui/backend/DataTable'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterOverlay'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'\nimport { deleteCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT, type TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport { formatDateTime } from '@open-mercato/shared/lib/time'\nimport { ProjectColorDot } from '../../../../lib/timesheets-ui/ProjectColorDot'\nimport { resolveProjectColorHex } from '../../../../lib/timesheets-ui/colors'\nimport {\n ProjectsKpiStrip,\n type PmKpis,\n type CollabKpis,\n} from '../../../../lib/timesheets-projects-ui/ProjectsKpiStrip'\nimport { SavedViewTabs } from '../../../../lib/timesheets-projects-ui/SavedViewTabs'\nimport { HoursSparkline } from '../../../../lib/timesheets-projects-ui/HoursSparkline'\nimport {\n ProjectMembersAvatarStack,\n type AvatarMember,\n} from '../../../../lib/timesheets-projects-ui/ProjectMembersAvatarStack'\nimport { ViewModeToggle } from '../../../../lib/timesheets-projects-ui/ViewModeToggle'\nimport {\n useProjectsViewMode,\n type ProjectsViewMode,\n} from '../../../../lib/timesheets-projects-ui/useProjectsViewMode'\nimport {\n ProjectCard,\n type ProjectCardData,\n type ProjectCardLabels,\n} from '../../../../lib/timesheets-projects-ui/ProjectCard'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('staff')\n\nconst PAGE_SIZE = 50\nconst INCLUDE_FIELDS = 'hoursWeek,hoursTrend,members,myRole'\n\ntype StaffEnrichment = {\n hoursWeek?: number\n hoursTrend?: number[]\n myRole?: string | null\n members?: AvatarMember[]\n memberCount?: number\n}\n\ntype ProjectRow = {\n id: string\n name: string\n code: string | null\n customerId: string | null\n customerName: string | null\n status: string\n projectType: string | null\n color: string | null\n startDate: string | null\n updatedAt: string | null\n hoursWeek: number\n hoursTrend: number[]\n myRole: string | null\n members: AvatarMember[]\n memberCount: number\n}\n\ntype ProjectsResponse = {\n items?: Array<Record<string, unknown>>\n total?: number\n totalPages?: number\n}\n\ntype KpisResponse = PmKpis | CollabKpis\n\nfunction formatRelativeTime(iso: string | null, fallback: string, t: TranslateFn): string {\n if (!iso) return fallback\n const parsed = new Date(iso)\n if (Number.isNaN(parsed.getTime())) return fallback\n const diffMs = Date.now() - parsed.getTime()\n const minutes = Math.round(diffMs / 60000)\n if (minutes < 1) return t('staff.timesheets.projects.portfolio.relativeTime.justNow', 'just now')\n if (minutes < 60) return t('staff.timesheets.projects.portfolio.relativeTime.minutesAgo', '{minutes}m ago', { minutes })\n const hours = Math.round(minutes / 60)\n if (hours < 24) return t('staff.timesheets.projects.portfolio.relativeTime.hoursAgo', '{hours}h ago', { hours })\n const days = Math.round(hours / 24)\n if (days < 14) return t('staff.timesheets.projects.portfolio.relativeTime.daysAgo', '{days}d ago', { days })\n return formatDateTime(iso) ?? fallback\n}\n\nfunction mapApiProject(item: Record<string, unknown>): ProjectRow {\n const id = typeof item.id === 'string' ? item.id : ''\n const name = typeof item.name === 'string' ? item.name : id\n const code = typeof item.code === 'string' && item.code.trim().length ? item.code.trim() : null\n const customerId =\n typeof item.customerId === 'string'\n ? item.customerId\n : typeof item.customer_id === 'string'\n ? item.customer_id\n : null\n const customerName =\n typeof item.customerName === 'string'\n ? item.customerName\n : typeof item.customer_name === 'string'\n ? item.customer_name\n : null\n const status = typeof item.status === 'string' ? item.status : 'active'\n const projectType =\n typeof item.projectType === 'string'\n ? item.projectType\n : typeof item.project_type === 'string'\n ? item.project_type\n : null\n const color = typeof item.color === 'string' ? item.color : null\n const startDate =\n typeof item.startDate === 'string'\n ? item.startDate\n : typeof item.start_date === 'string'\n ? item.start_date\n : null\n const updatedAt =\n typeof item.updatedAt === 'string'\n ? item.updatedAt\n : typeof item.updated_at === 'string'\n ? item.updated_at\n : null\n const enrichment =\n (item as { _staff?: StaffEnrichment })._staff ?? ({} as StaffEnrichment)\n const hoursWeek = typeof enrichment.hoursWeek === 'number' ? enrichment.hoursWeek : 0\n const hoursTrend = Array.isArray(enrichment.hoursTrend)\n ? enrichment.hoursTrend.filter((v): v is number => typeof v === 'number')\n : []\n const members = Array.isArray(enrichment.members)\n ? enrichment.members\n .filter((m): m is AvatarMember => !!m && typeof m === 'object' && typeof (m as AvatarMember).id === 'string')\n .map((m) => ({\n id: m.id,\n name: m.name ?? '',\n initials: m.initials ?? '',\n avatarUrl: m.avatarUrl ?? null,\n }))\n : []\n const memberCount = typeof enrichment.memberCount === 'number' ? enrichment.memberCount : members.length\n const myRole = typeof enrichment.myRole === 'string' ? enrichment.myRole : null\n\n return withDataTableNamespaces(\n {\n id,\n name,\n code,\n customerId,\n customerName,\n status,\n projectType,\n color,\n startDate,\n updatedAt,\n hoursWeek,\n hoursTrend,\n myRole,\n members,\n memberCount,\n },\n item,\n )\n}\n\nexport default function TimesheetProjectsPage() {\n const t = useT()\n const router = useRouter()\n const searchParams = useSearchParams()\n const scopeVersion = useOrganizationScopeVersion()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n\n const [rows, setRows] = React.useState<ProjectRow[]>([])\n const [page, setPage] = React.useState(1)\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const [sorting, setSorting] = React.useState<SortingState>([{ id: 'updatedAt', desc: true }])\n const [search, setSearch] = React.useState('')\n const [filterValues, setFilterValues] = React.useState<FilterValues>({})\n const [isLoading, setIsLoading] = React.useState(true)\n const [isRefreshing, setIsRefreshing] = React.useState(false)\n const hasLoadedOnceRef = React.useRef(false)\n const [reloadToken, setReloadToken] = React.useState(0)\n const [kpis, setKpis] = React.useState<KpisResponse | null>(null)\n const [isLoadingKpis, setIsLoadingKpis] = React.useState(true)\n\n const activeTab = searchParams.get('tab') ?? 'all'\n const urlViewMode = searchParams.get('view')\n const [viewMode, setViewMode] = useProjectsViewMode({\n userKey: null,\n urlOverride: urlViewMode,\n })\n\n const labels = React.useMemo(\n () => ({\n title: t('staff.timesheets.projects.page.title', 'Projects'),\n table: {\n name: t('staff.timesheets.projects.table.name', 'Project'),\n status: t('staff.timesheets.projects.table.status', 'Status'),\n type: t('staff.timesheets.projects.table.type', 'Type'),\n updatedAt: t('staff.timesheets.projects.table.updatedAt', 'Updated'),\n empty: t('staff.timesheets.projects.table.empty', 'No projects yet.'),\n search: t('staff.timesheets.projects.table.search', 'Search projects...'),\n team: t('staff.timesheets.projects.portfolio.team', 'Team'),\n myRole: t('staff.timesheets.projects.portfolio.myRole', 'My role'),\n hoursWeek: t('staff.timesheets.projects.portfolio.hoursWeek', 'Hours / week'),\n myHoursWeek: t('staff.timesheets.projects.portfolio.myHoursWeek', 'My hours / week'),\n },\n actions: {\n add: t('staff.timesheets.projects.actions.add', 'Add Project'),\n addFirst: t('staff.timesheets.projects.actions.addFirst', '+ Add first project'),\n viewDetails: t('staff.timesheets.projects.actions.viewDetails', 'View Details'),\n delete: t('staff.timesheets.projects.actions.delete', 'Delete'),\n deleteConfirm: t('staff.timesheets.projects.actions.deleteConfirm', 'Delete project \"{{name}}\"?'),\n refresh: t('staff.timesheets.projects.actions.refresh', 'Refresh'),\n },\n messages: {\n deleted: t('staff.timesheets.projects.messages.deleted', 'Project deleted.'),\n },\n errors: {\n load: t('staff.timesheets.projects.errors.load', 'Failed to load projects.'),\n delete: t('staff.timesheets.projects.errors.delete', 'Failed to delete project.'),\n },\n statuses: {\n all: t('staff.timesheets.projects.statuses.all', 'All'),\n active: t('staff.timesheets.projects.statuses.active', 'Active'),\n on_hold: t('staff.timesheets.projects.statuses.onHold', 'On Hold'),\n completed: t('staff.timesheets.projects.statuses.completed', 'Completed'),\n },\n tabs: {\n all: t('staff.timesheets.projects.portfolio.tabs.all', 'All'),\n active: t('staff.timesheets.projects.portfolio.tabs.active', 'Active'),\n onHold: t('staff.timesheets.projects.portfolio.tabs.onHold', 'On Hold'),\n completed: t('staff.timesheets.projects.portfolio.tabs.completed', 'Completed'),\n mine: t('staff.timesheets.projects.portfolio.tabs.mine', 'Mine'),\n },\n viewMode: {\n table: t('staff.timesheets.projects.portfolio.viewMode.table', 'Table'),\n cards: t('staff.timesheets.projects.portfolio.viewMode.cards', 'Cards'),\n },\n kpi: {\n totalProjects: t('staff.timesheets.projects.portfolio.kpi.totalProjects', 'Total Projects'),\n hoursWeek: t('staff.timesheets.projects.portfolio.kpi.hoursWeek', 'Hours this week'),\n hoursWeekSub: t('staff.timesheets.projects.portfolio.kpi.hoursWeekSub', 'vs previous week'),\n assignedToMe: t('staff.timesheets.projects.portfolio.kpi.assignedToMe', 'Assigned to me'),\n hoursMonth: t('staff.timesheets.projects.portfolio.kpi.hoursMonth', 'Hours this month'),\n hoursMonthSub: t('staff.timesheets.projects.portfolio.kpi.hoursMonthSub', 'vs previous month'),\n teamActive: t('staff.timesheets.projects.portfolio.kpi.teamActive', 'Active team'),\n teamActiveSub: t('staff.timesheets.projects.portfolio.kpi.teamActiveSub', 'Members with entries this month'),\n myProjects: t('staff.timesheets.projects.portfolio.kpi.myProjects', 'My projects'),\n myHoursWeek: t('staff.timesheets.projects.portfolio.kpi.myHoursWeek', 'My hours this week'),\n myHoursMonth: t('staff.timesheets.projects.portfolio.kpi.myHoursMonth', 'My hours this month'),\n deltaFlat: t('staff.timesheets.projects.portfolio.kpi.deltaFlat', 'no change'),\n noPrevious: t('staff.timesheets.projects.portfolio.kpi.noPrevious', 'no previous data'),\n },\n card: {\n hoursPanelPm: t('staff.timesheets.projects.portfolio.card.hoursPanelPm', 'Team hours \u00B7 last 7w'),\n hoursPanelCollab: t('staff.timesheets.projects.portfolio.card.hoursPanelCollab', 'My hours \u00B7 last 7w'),\n sparklineAria: t('staff.timesheets.projects.portfolio.sparkline.ariaLabel', 'Hours per week, last 7 weeks'),\n role: t('staff.timesheets.projects.portfolio.card.role', 'Role'),\n },\n emptyState: {\n noProjects: t('staff.timesheets.projects.portfolio.emptyState.noProjects', 'No projects yet.'),\n noAssignments: t(\n 'staff.timesheets.projects.portfolio.emptyState.noAssignments',\n \"You aren't assigned to any projects yet. Ask a PM to add you.\",\n ),\n noMatches: t('staff.timesheets.projects.portfolio.emptyState.noMatches', 'No projects match these filters.'),\n },\n }),\n [t],\n )\n\n const kpiLabels = React.useMemo(\n () => ({\n totalProjects: labels.kpi.totalProjects,\n totalProjectsSub: ({ active, onHold }: { active: number; onHold: number }) =>\n `${active} ${labels.statuses.active.toLowerCase()} \u00B7 ${onHold} ${labels.statuses.on_hold.toLowerCase()}`,\n hoursWeek: labels.kpi.hoursWeek,\n hoursWeekSub: labels.kpi.hoursWeekSub,\n assignedToMe: labels.kpi.assignedToMe,\n assignedToMeSub: (active: number) => `${active} ${labels.statuses.active.toLowerCase()}`,\n hoursMonth: labels.kpi.hoursMonth,\n hoursMonthSub: labels.kpi.hoursMonthSub,\n teamActive: labels.kpi.teamActive,\n teamActiveSub: labels.kpi.teamActiveSub,\n myProjects: labels.kpi.myProjects,\n myProjectsSub: (active: number) => `${active} ${labels.statuses.active.toLowerCase()}`,\n myHoursWeek: labels.kpi.myHoursWeek,\n myHoursMonth: labels.kpi.myHoursMonth,\n deltaUp: (pct: number) => `up ${pct}%`,\n deltaDown: (pct: number) => `down ${pct}%`,\n deltaFlat: labels.kpi.deltaFlat,\n noPrevious: labels.kpi.noPrevious,\n }),\n [labels],\n )\n\n const isPmRole = kpis?.role === 'pm'\n\n const filters = React.useMemo<FilterDef[]>(\n () => [\n {\n id: 'status',\n label: labels.table.status,\n type: 'select',\n options: [\n { value: 'active', label: labels.statuses.active },\n { value: 'on_hold', label: labels.statuses.on_hold },\n { value: 'completed', label: labels.statuses.completed },\n ],\n },\n ],\n [labels.table.status, labels.statuses],\n )\n\n const tabs = React.useMemo(() => {\n const base = [\n { id: 'all', label: labels.tabs.all },\n { id: 'active', label: labels.tabs.active },\n ]\n if (isPmRole) {\n base.push({ id: 'on_hold', label: labels.tabs.onHold })\n }\n base.push({ id: 'completed', label: labels.tabs.completed })\n if (isPmRole) {\n base.push({ id: 'mine', label: labels.tabs.mine })\n }\n return base\n }, [labels.tabs, isPmRole])\n\n const statusFromTab = (tabId: string): string | null => {\n if (tabId === 'active' || tabId === 'on_hold' || tabId === 'completed') return tabId\n return null\n }\n const mineFromTab = (tabId: string): boolean => tabId === 'mine' || !isPmRole\n\n const loadKpis = React.useCallback(async () => {\n setIsLoadingKpis(true)\n try {\n const payload = await readApiResultOrThrow<KpisResponse>(\n '/api/staff/timesheets/projects/kpis',\n undefined,\n {\n errorMessage: labels.errors.load,\n fallback: null as unknown as KpisResponse,\n },\n )\n setKpis(payload)\n } catch {\n setKpis(null)\n } finally {\n setIsLoadingKpis(false)\n }\n }, [labels.errors.load])\n\n const loadProjects = React.useCallback(async () => {\n if (hasLoadedOnceRef.current) {\n setIsRefreshing(true)\n } else {\n setIsLoading(true)\n }\n try {\n const params = new URLSearchParams({\n page: String(page),\n pageSize: String(PAGE_SIZE),\n include: INCLUDE_FIELDS,\n })\n const sort = sorting[0]\n if (sort?.id) {\n params.set('sortField', sort.id)\n params.set('sortDir', sort.desc ? 'desc' : 'asc')\n }\n if (search.trim()) params.set('q', search.trim())\n const tabStatus = statusFromTab(activeTab)\n if (tabStatus) params.set('status', tabStatus)\n else if (typeof filterValues.status === 'string' && filterValues.status.length > 0) {\n params.set('status', filterValues.status)\n }\n if (mineFromTab(activeTab)) params.set('mine', '1')\n\n const payload = await readApiResultOrThrow<ProjectsResponse>(\n `/api/staff/timesheets/time-projects?${params.toString()}`,\n undefined,\n { errorMessage: labels.errors.load, fallback: { items: [], total: 0, totalPages: 1 } },\n )\n const items = Array.isArray(payload.items) ? payload.items : []\n setRows(items.map(mapApiProject))\n setTotal(typeof payload.total === 'number' ? payload.total : items.length)\n setTotalPages(\n typeof payload.totalPages === 'number'\n ? payload.totalPages\n : Math.max(1, Math.ceil(items.length / PAGE_SIZE)),\n )\n } catch (error) {\n logger.error('staff.timesheets.projects.list', { err: error })\n flash(labels.errors.load, 'error')\n } finally {\n setIsLoading(false)\n setIsRefreshing(false)\n hasLoadedOnceRef.current = true\n }\n }, [labels.errors.load, page, search, sorting, filterValues.status, activeTab, isPmRole])\n\n React.useEffect(() => {\n void loadKpis()\n }, [loadKpis, scopeVersion, reloadToken])\n\n React.useEffect(() => {\n void loadProjects()\n }, [loadProjects, scopeVersion, reloadToken])\n\n const handleTabSelect = React.useCallback(\n (id: string) => {\n const params = new URLSearchParams(searchParams.toString())\n if (id === 'all') params.delete('tab')\n else params.set('tab', id)\n router.replace(`?${params.toString()}`)\n setPage(1)\n },\n [router, searchParams],\n )\n\n const handleViewModeChange = React.useCallback(\n (next: ProjectsViewMode) => {\n setViewMode(next)\n const params = new URLSearchParams(searchParams.toString())\n if (next === 'table') params.delete('view')\n else params.set('view', next)\n router.replace(`?${params.toString()}`)\n },\n [router, searchParams, setViewMode],\n )\n\n const handleSearchChange = React.useCallback((value: string) => {\n setSearch(value)\n setPage(1)\n }, [])\n\n const handleFiltersApply = React.useCallback((values: FilterValues) => {\n setFilterValues(values)\n setPage(1)\n }, [])\n\n const handleFiltersClear = React.useCallback(() => {\n setFilterValues({})\n setPage(1)\n }, [])\n\n const handleRefresh = React.useCallback(() => {\n setReloadToken((token) => token + 1)\n }, [])\n\n const handleDelete = React.useCallback(\n async (entry: ProjectRow) => {\n const message = labels.actions.deleteConfirm.replace('{{name}}', entry.name)\n const confirmed = await confirm({\n title: labels.actions.delete,\n text: message,\n variant: 'destructive',\n })\n if (!confirmed) return\n try {\n await withScopedApiRequestHeaders(\n buildOptimisticLockHeader(entry.updatedAt),\n () => deleteCrud('staff/timesheets/time-projects', entry.id, { errorMessage: labels.errors.delete }),\n )\n flash(labels.messages.deleted, 'success')\n handleRefresh()\n } catch (error) {\n if (surfaceRecordConflict(error, t)) { handleRefresh(); return }\n logger.error('staff.timesheets.projects.delete', { err: error })\n flash(labels.errors.delete, 'error')\n }\n },\n [confirm, handleRefresh, t, labels.actions.deleteConfirm, labels.actions.delete, labels.errors.delete, labels.messages.deleted],\n )\n\n const columns = React.useMemo<ColumnDef<ProjectRow>[]>(\n () => [\n {\n accessorKey: 'name',\n header: labels.table.name,\n meta: { priority: 1, sticky: true },\n cell: ({ row }) => (\n <div className=\"flex items-center gap-2.5\">\n <ProjectColorDot colorKey={row.original.color} projectName={row.original.name} size=\"sm\" />\n <div className=\"flex min-w-0 flex-col\">\n <span className=\"truncate text-sm font-medium text-foreground\">{row.original.name}</span>\n <span className=\"truncate font-mono text-[11px] text-muted-foreground\">\n {row.original.code ?? '\u2014'}\n {row.original.customerName ? ` \u00B7 ${row.original.customerName}` : ''}\n </span>\n </div>\n </div>\n ),\n },\n {\n accessorKey: 'status',\n header: labels.table.status,\n meta: { priority: 2 },\n cell: ({ row }) => {\n const badgeClass =\n row.original.status === 'active'\n ? 'bg-lime-100 text-lime-800 dark:bg-lime-900/30 dark:text-lime-300'\n : row.original.status === 'on_hold'\n ? 'bg-amber-100 text-amber-800 dark:bg-amber-900/30 dark:text-amber-300'\n : 'bg-muted text-muted-foreground'\n const statusLabel =\n labels.statuses[row.original.status as keyof typeof labels.statuses] ?? row.original.status\n return (\n <span\n className={`inline-flex items-center rounded-full px-2 py-0.5 text-[11px] font-medium ${badgeClass}`}\n >\n {statusLabel}\n </span>\n )\n },\n },\n {\n accessorKey: 'projectType',\n header: labels.table.type,\n meta: { priority: 3 },\n cell: ({ row }) =>\n row.original.projectType ? (\n <span className=\"text-sm text-foreground\">{row.original.projectType}</span>\n ) : (\n <span className=\"text-xs text-muted-foreground/70\">\u2014</span>\n ),\n },\n isPmRole\n ? {\n accessorKey: 'members',\n id: 'members',\n header: labels.table.team,\n enableSorting: false,\n meta: { priority: 4 },\n cell: ({ row }) => (\n <ProjectMembersAvatarStack\n members={row.original.members}\n total={row.original.memberCount}\n peopleCountLabel={`${row.original.memberCount}`}\n />\n ),\n }\n : {\n accessorKey: 'myRole',\n header: labels.table.myRole,\n enableSorting: false,\n meta: { priority: 4 },\n cell: ({ row }) =>\n row.original.myRole ? (\n <span className=\"text-sm text-foreground\">{row.original.myRole}</span>\n ) : (\n <span className=\"text-xs text-muted-foreground/70\">\u2014</span>\n ),\n },\n {\n accessorKey: 'hoursWeek',\n header: isPmRole ? labels.table.hoursWeek : labels.table.myHoursWeek,\n enableSorting: false,\n meta: { priority: 5 },\n cell: ({ row }) => {\n const stripe = resolveProjectColorHex(row.original.color, row.original.name)\n return (\n <div className=\"flex items-center justify-end gap-2\">\n <HoursSparkline\n values={row.original.hoursTrend}\n color={stripe}\n ariaLabel={labels.card.sparklineAria}\n />\n <span className=\"text-xs font-medium tabular-nums text-foreground\">\n {row.original.hoursWeek > 0 ? `${row.original.hoursWeek}h` : '\u2014'}\n </span>\n </div>\n )\n },\n },\n {\n accessorKey: 'updatedAt',\n header: labels.table.updatedAt,\n meta: { priority: 6 },\n cell: ({ row }) => (\n <span className=\"text-xs text-muted-foreground\">\n {formatRelativeTime(row.original.updatedAt, '\u2014', t)}\n </span>\n ),\n },\n ],\n [labels.table, labels.statuses, labels.card.sparklineAria, isPmRole],\n )\n\n const cardLabels = React.useMemo<ProjectCardLabels>(\n () => ({\n hoursPanelPm: labels.card.hoursPanelPm,\n hoursPanelCollab: labels.card.hoursPanelCollab,\n sparklineAria: labels.card.sparklineAria,\n peopleCount: (count: number) => `${count}`,\n role: labels.card.role,\n noCustomer: '\u2014',\n statuses: labels.statuses,\n }),\n [labels.card, labels.statuses],\n )\n\n const canManage = isPmRole\n\n const emptyStateCopy = React.useMemo(() => {\n const hasFiltersApplied = activeTab !== 'all' || search.trim().length > 0 || Object.values(filterValues).some(Boolean)\n if (hasFiltersApplied) return labels.emptyState.noMatches\n if (!canManage) return labels.emptyState.noAssignments\n return labels.emptyState.noProjects\n }, [activeTab, search, filterValues, canManage, labels.emptyState])\n\n const cardsData: ProjectCardData[] = rows.map((row) => ({\n id: row.id,\n name: row.name,\n code: row.code,\n customerName: row.customerName,\n color: row.color,\n status: row.status,\n hoursWeek: row.hoursWeek,\n hoursTrend: row.hoursTrend,\n members: row.members,\n memberCount: row.memberCount,\n myRole: row.myRole,\n updatedAt: row.updatedAt,\n }))\n\n return (\n <Page>\n <PageBody>\n <div className=\"mb-4\">\n <ProjectsKpiStrip kpis={kpis} labels={kpiLabels} isLoading={isLoadingKpis} />\n </div>\n\n <div className=\"mb-3 flex flex-wrap items-center justify-between gap-3\">\n <SavedViewTabs\n tabs={tabs}\n activeId={activeTab}\n onSelect={handleTabSelect}\n ariaLabel={t('staff.timesheets.projects.portfolio.savedViews.ariaLabel', 'Saved views')}\n />\n <ViewModeToggle\n mode={viewMode}\n onChange={handleViewModeChange}\n tableLabel={labels.viewMode.table}\n cardsLabel={labels.viewMode.cards}\n ariaLabel={t('staff.timesheets.projects.portfolio.viewMode.ariaLabel', 'View mode')}\n />\n </div>\n\n {viewMode === 'cards' ? (\n <div>\n {isLoading ? (\n <div className=\"grid grid-cols-1 gap-3 md:grid-cols-2 lg:grid-cols-3\">\n {Array.from({ length: 6 }).map((_, idx) => (\n <div key={idx} className=\"h-48 animate-pulse rounded-lg border border-border bg-muted/40\" />\n ))}\n </div>\n ) : rows.length === 0 ? (\n <div className=\"rounded-lg border border-dashed border-border bg-card p-10 text-center\">\n <p className=\"text-sm text-muted-foreground\">{emptyStateCopy}</p>\n {canManage ? (\n <div className=\"mt-3\">\n <Button asChild size=\"sm\">\n <Link href=\"/backend/staff/timesheets/projects/create\">\n {labels.actions.addFirst}\n </Link>\n </Button>\n </div>\n ) : null}\n </div>\n ) : (\n <div className=\"grid grid-cols-1 gap-3 md:grid-cols-2 lg:grid-cols-3\">\n {cardsData.map((card) => (\n <ProjectCard\n key={card.id}\n data={card}\n labels={cardLabels}\n showTeam={isPmRole}\n href={`/backend/staff/timesheets/projects/${card.id}`}\n />\n ))}\n </div>\n )}\n </div>\n ) : (\n <DataTable<ProjectRow>\n title={labels.title}\n data={rows}\n columns={columns}\n isLoading={isLoading}\n searchValue={search}\n onSearchChange={handleSearchChange}\n searchPlaceholder={labels.table.search}\n filters={filters}\n filterValues={filterValues}\n onFiltersApply={handleFiltersApply}\n onFiltersClear={handleFiltersClear}\n emptyState={\n <div className=\"py-12 text-center\">\n <p className=\"text-sm text-muted-foreground mb-4\">{emptyStateCopy}</p>\n {canManage ? (\n <Button asChild size=\"sm\">\n <Link href=\"/backend/staff/timesheets/projects/create\">{labels.actions.addFirst}</Link>\n </Button>\n ) : null}\n </div>\n }\n actions={\n canManage ? (\n <Button asChild size=\"sm\">\n <Link href=\"/backend/staff/timesheets/projects/create\">{labels.actions.add}</Link>\n </Button>\n ) : undefined\n }\n refreshButton={{\n label: labels.actions.refresh,\n onRefresh: handleRefresh,\n isRefreshing: isLoading || isRefreshing,\n }}\n sortable\n sorting={sorting}\n onSortingChange={setSorting}\n pagination={{\n page,\n pageSize: PAGE_SIZE,\n total,\n totalPages,\n onPageChange: setPage,\n }}\n rowActions={(row) => (\n <RowActions\n items={[\n {\n id: 'view',\n label: labels.actions.viewDetails,\n href: `/backend/staff/timesheets/projects/${row.id}`,\n },\n ...(canManage\n ? [\n {\n id: 'delete',\n label: labels.actions.delete,\n destructive: true,\n onSelect: () => {\n void handleDelete(row)\n },\n },\n ]\n : []),\n ]}\n />\n )}\n onRowClick={(row) => router.push(`/backend/staff/timesheets/projects/${row.id}`)}\n />\n )}\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -29,6 +29,8 @@ import {
|
|
|
29
29
|
staffSnapshotScopeFromSnapshot
|
|
30
30
|
} from "./shared.js";
|
|
31
31
|
import { getStaffMemberByUserId } from "../lib/staffMemberResolver.js";
|
|
32
|
+
import { createLogger } from "@open-mercato/shared/lib/logger";
|
|
33
|
+
const logger = createLogger("staff");
|
|
32
34
|
async function callerHasManageAll(ctx) {
|
|
33
35
|
const userId = ctx.auth?.sub;
|
|
34
36
|
if (!userId) return false;
|
|
@@ -314,7 +316,7 @@ const startTimerCommand = {
|
|
|
314
316
|
organizationId: parsed.organizationId,
|
|
315
317
|
startedAt: startedAt.toISOString()
|
|
316
318
|
}, { persistent: true }).catch((err) => {
|
|
317
|
-
|
|
319
|
+
logger.error("staff.timesheets emit timer_started failed", { err });
|
|
318
320
|
});
|
|
319
321
|
return { timeEntryId: entry.id };
|
|
320
322
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/staff/commands/timesheets-entries.ts"],
|
|
4
|
-
"sourcesContent": ["import type { CommandHandler } from '@open-mercato/shared/lib/commands'\nimport { registerCommand } from '@open-mercato/shared/lib/commands'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { buildChanges, emitCrudSideEffects, emitCrudUndoSideEffects } from '@open-mercato/shared/lib/commands/helpers'\nimport { makeCreateRedo } from '@open-mercato/shared/lib/commands/redo'\nimport type { CrudIndexerConfig } from '@open-mercato/shared/lib/crud/types'\nimport { StaffTimeEntry, StaffTimeEntrySegment, StaffTimeProject, type StaffTimeEntrySource } from '../data/entities'\nimport { emitStaffEvent } from '../events'\n\nconst timeEntryCrudIndexer: CrudIndexerConfig<StaffTimeEntry> = {\n entityType: 'staff:staff_time_entry',\n}\nimport {\n staffTimeEntryCreateSchema,\n staffTimeEntryStartTimerSchema,\n staffTimeEntryUpdateSchema,\n type StaffTimeEntryCreateInput,\n type StaffTimeEntryStartTimerInput,\n type StaffTimeEntryUpdateInput,\n} from '../data/validators'\nimport { staffTimeEntryCrudEvents } from '../lib/crud'\nimport {\n applyScopeToWhere,\n commandActorScope,\n commandInputScope,\n ensureOrganizationScope,\n ensureTenantScope,\n extractUndoPayload,\n scopeForDecryption,\n scopedStaffSnapshotWhere,\n staffSnapshotDecryptionScope,\n staffSnapshotScopeFromContext,\n staffSnapshotScopeFromSnapshot,\n type StaffSnapshotScope,\n} from './shared'\nimport { getStaffMemberByUserId } from '../lib/staffMemberResolver'\n\ntype RbacServiceLike = {\n userHasAllFeatures: (\n userId: string,\n required: string[],\n scope: { tenantId: string | null; organizationId: string | null },\n ) => Promise<boolean>\n}\n\n/**\n * Returns true when the caller holds `staff.timesheets.manage_all`, honoring\n * wildcard ACL grants (`staff.*`, `*`) and the super-admin flag via the cached\n * rbacService. Returns false when no auth context (e.g. system/CLI ctx) so\n * write paths that lack a caller identity are NOT silently elevated.\n */\nasync function callerHasManageAll(ctx: {\n auth?: { sub?: string | null; tenantId?: string | null; orgId?: string | null } | null\n container: { resolve: (token: string) => unknown }\n}): Promise<boolean> {\n const userId = ctx.auth?.sub\n if (!userId) return false\n try {\n const rbac = ctx.container.resolve('rbacService') as RbacServiceLike | undefined\n if (!rbac?.userHasAllFeatures) return false\n return await rbac.userHasAllFeatures(\n userId,\n ['staff.timesheets.manage_all'],\n { tenantId: ctx.auth?.tenantId ?? null, organizationId: ctx.auth?.orgId ?? null },\n )\n } catch {\n return false\n }\n}\n\nasync function resolveCallerStaffMemberId(\n em: EntityManager,\n ctx: { auth?: { sub?: string | null; tenantId?: string | null; orgId?: string | null } | null },\n): Promise<string | null> {\n const userId = ctx.auth?.sub\n if (!userId) return null\n const member = await getStaffMemberByUserId(\n em,\n userId,\n ctx.auth?.tenantId ?? null,\n ctx.auth?.orgId ?? null,\n )\n return member?.id ?? null\n}\n\n/**\n * Verifies the referenced time project exists and is in-scope (same tenant + org,\n * not soft-deleted). Throws 422 if the ID is provided but unresolvable.\n * No-op when projectId is null/undefined (timeProjectId is optional on entries).\n */\nasync function assertTimeProjectInScope(\n em: EntityManager,\n projectId: string | null | undefined,\n tenantId: string,\n organizationId: string,\n): Promise<void> {\n if (!projectId) return\n const exists = await em.findOne(\n StaffTimeProject,\n { id: projectId, tenantId, organizationId, deletedAt: null },\n { fields: ['id'] },\n )\n if (!exists) {\n const { translate } = await resolveTranslations()\n throw new CrudHttpError(422, {\n error: translate('staff.timesheets.errors.projectNotFound', 'Time project not found or not accessible.'),\n fieldErrors: {\n timeProjectId: translate('staff.timesheets.errors.projectNotFound', 'Time project not found or not accessible.'),\n },\n })\n }\n}\n\ntype TimeEntrySnapshot = {\n id: string\n tenantId: string\n organizationId: string\n staffMemberId: string\n date: string\n durationMinutes: number\n startedAt: string | null\n endedAt: string | null\n notes: string | null\n timeProjectId: string | null\n customerId: string | null\n dealId: string | null\n orderId: string | null\n source: string\n deletedAt: string | null\n}\n\ntype TimeEntryUndoPayload = {\n before?: TimeEntrySnapshot | null\n after?: TimeEntrySnapshot | null\n}\n\nasync function loadTimeEntrySnapshot(em: EntityManager, id: string, scope?: StaffSnapshotScope | null): Promise<TimeEntrySnapshot | null> {\n const entry = await findOneWithDecryption(\n em,\n StaffTimeEntry,\n scopedStaffSnapshotWhere(id, scope),\n undefined,\n staffSnapshotDecryptionScope(scope),\n )\n if (!entry) return null\n return {\n id: entry.id,\n tenantId: entry.tenantId,\n organizationId: entry.organizationId,\n staffMemberId: entry.staffMemberId,\n date: entry.date instanceof Date ? entry.date.toISOString().split('T')[0] : String(entry.date),\n durationMinutes: entry.durationMinutes,\n startedAt: entry.startedAt ? entry.startedAt.toISOString() : null,\n endedAt: entry.endedAt ? entry.endedAt.toISOString() : null,\n notes: entry.notes ?? null,\n timeProjectId: entry.timeProjectId ?? null,\n customerId: entry.customerId ?? null,\n dealId: entry.dealId ?? null,\n orderId: entry.orderId ?? null,\n source: entry.source,\n deletedAt: entry.deletedAt ? entry.deletedAt.toISOString() : null,\n }\n}\n\nfunction timeEntrySeedFromSnapshot(snapshot: TimeEntrySnapshot): Record<string, unknown> {\n return {\n id: snapshot.id,\n tenantId: snapshot.tenantId,\n organizationId: snapshot.organizationId,\n staffMemberId: snapshot.staffMemberId,\n date: snapshot.date,\n durationMinutes: snapshot.durationMinutes,\n startedAt: snapshot.startedAt ? new Date(snapshot.startedAt) : null,\n endedAt: snapshot.endedAt ? new Date(snapshot.endedAt) : null,\n notes: snapshot.notes ?? null,\n timeProjectId: snapshot.timeProjectId ?? null,\n customerId: snapshot.customerId ?? null,\n dealId: snapshot.dealId ?? null,\n orderId: snapshot.orderId ?? null,\n source: (snapshot.source ?? 'manual') as StaffTimeEntrySource,\n createdAt: new Date(),\n updatedAt: new Date(),\n deletedAt: null,\n }\n}\n\nconst createTimeEntryCommand: CommandHandler<StaffTimeEntryCreateInput, { timeEntryId: string }> = {\n id: 'staff.timesheets.time_entries.create',\n async execute(rawInput, ctx) {\n const parsed = staffTimeEntryCreateSchema.parse(rawInput)\n ensureTenantScope(ctx, parsed.tenantId)\n ensureOrganizationScope(ctx, parsed.organizationId)\n commandInputScope(ctx, parsed.tenantId, parsed.organizationId)\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n\n // Ownership enforcement: callers without `staff.timesheets.manage_all`\n // can only create entries attributed to themselves. Silent override\n // (mirrors `bulk/route.ts` behavior) so the request body's staffMemberId\n // can't forge an entry under a colleague's identity.\n let effectiveStaffMemberId = parsed.staffMemberId\n if (!(await callerHasManageAll(ctx))) {\n const callerStaffMemberId = await resolveCallerStaffMemberId(em, ctx)\n if (!callerStaffMemberId) {\n const { translate } = await resolveTranslations()\n throw new CrudHttpError(403, {\n error: translate('staff.timesheets.errors.noStaffMember', 'No staff member linked to your account.'),\n })\n }\n effectiveStaffMemberId = callerStaffMemberId\n }\n\n // Validate referenced timeProjectId is in-scope before persisting.\n // Without this check a foreign or stale UUID would produce a dangling reference.\n await assertTimeProjectInScope(em, parsed.timeProjectId ?? null, parsed.tenantId, parsed.organizationId)\n\n const now = new Date()\n const entry = em.create(StaffTimeEntry, {\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n staffMemberId: effectiveStaffMemberId,\n date: parsed.date,\n durationMinutes: parsed.durationMinutes,\n startedAt: parsed.startedAt ?? null,\n endedAt: parsed.endedAt ?? null,\n notes: parsed.notes ?? null,\n timeProjectId: parsed.timeProjectId ?? null,\n customerId: parsed.customerId ?? null,\n dealId: parsed.dealId ?? null,\n orderId: parsed.orderId ?? null,\n source: parsed.source ?? 'manual',\n createdAt: now,\n updatedAt: now,\n deletedAt: null,\n })\n em.persist(entry)\n await em.flush()\n\n await emitCrudSideEffects({\n dataEngine: ctx.container.resolve('dataEngine'),\n action: 'created',\n entity: entry,\n identifiers: { id: entry.id, organizationId: entry.organizationId, tenantId: entry.tenantId },\n events: staffTimeEntryCrudEvents,\n indexer: timeEntryCrudIndexer,\n })\n\n return { timeEntryId: entry.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const snapshot = await loadTimeEntrySnapshot(em, result.timeEntryId, staffSnapshotScopeFromContext(ctx))\n if (!snapshot) return null\n return { snapshot }\n },\n buildLog: async ({ result, ctx }) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const snapshot = await loadTimeEntrySnapshot(em, result.timeEntryId, staffSnapshotScopeFromContext(ctx))\n if (!snapshot) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('staff.audit.timesheets.time_entries.create', 'Create time entry'),\n resourceKind: 'staff.timesheets.time_entry',\n resourceId: snapshot.id,\n tenantId: snapshot.tenantId,\n organizationId: snapshot.organizationId,\n snapshotAfter: snapshot,\n payload: {\n undo: {\n after: snapshot,\n } satisfies TimeEntryUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<TimeEntryUndoPayload>(logEntry)\n const after = payload?.after\n if (!after) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const entry = await em.findOne(StaffTimeEntry, scopedStaffSnapshotWhere(after.id, staffSnapshotScopeFromSnapshot(after)))\n if (entry) {\n entry.deletedAt = new Date()\n await em.flush()\n\n await emitCrudUndoSideEffects({\n dataEngine: ctx.container.resolve('dataEngine'),\n action: 'deleted',\n entity: entry,\n identifiers: { id: entry.id, organizationId: entry.organizationId, tenantId: entry.tenantId },\n events: staffTimeEntryCrudEvents,\n })\n }\n },\n redo: makeCreateRedo<StaffTimeEntry, TimeEntrySnapshot, StaffTimeEntryCreateInput, { timeEntryId: string }>({\n entityClass: StaffTimeEntry,\n getSnapshotId: (snapshot) => snapshot.id,\n seedFromSnapshot: timeEntrySeedFromSnapshot,\n buildResult: (entity) => ({ timeEntryId: entity.id }),\n events: staffTimeEntryCrudEvents,\n indexer: timeEntryCrudIndexer,\n }),\n}\n\nconst startTimerCommand: CommandHandler<StaffTimeEntryStartTimerInput, { timeEntryId: string }> = {\n id: 'staff.timesheets.time_entries.start_timer',\n async execute(rawInput, ctx) {\n const parsed = staffTimeEntryStartTimerSchema.parse(rawInput)\n ensureTenantScope(ctx, parsed.tenantId)\n ensureOrganizationScope(ctx, parsed.organizationId)\n commandInputScope(ctx, parsed.tenantId, parsed.organizationId)\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n\n // Ownership enforcement mirrors createTimeEntryCommand: callers without\n // `staff.timesheets.manage_all` can only start their own timer, so the\n // request body's staffMemberId can't start a timer under a colleague's id.\n let effectiveStaffMemberId = parsed.staffMemberId\n if (!(await callerHasManageAll(ctx))) {\n const callerStaffMemberId = await resolveCallerStaffMemberId(em, ctx)\n if (!callerStaffMemberId) {\n const { translate } = await resolveTranslations()\n throw new CrudHttpError(403, {\n error: translate('staff.timesheets.errors.noStaffMember', 'No staff member linked to your account.'),\n })\n }\n effectiveStaffMemberId = callerStaffMemberId\n }\n\n await assertTimeProjectInScope(em, parsed.timeProjectId ?? null, parsed.tenantId, parsed.organizationId)\n\n const scopeCtx = { tenantId: parsed.tenantId, organizationId: parsed.organizationId }\n\n // Create the timer entry AND start it inside a single transaction so a\n // partial failure can never leave an orphaned, never-started timer entry\n // (issue #3311 \u2014 the legacy two-request create-then-start flow). The\n // single-active-timer invariant (#2855) is re-checked here so a second\n // surface cannot create a parallel running timer for the same staff member.\n const { entry, startedAt } = await em.transactional(async (trx) => {\n const otherRunningEntry = await findOneWithDecryption(\n trx,\n StaffTimeEntry,\n {\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n staffMemberId: effectiveStaffMemberId,\n startedAt: { $ne: null },\n endedAt: null,\n deletedAt: null,\n },\n {},\n scopeCtx,\n )\n if (otherRunningEntry) {\n const { translate } = await resolveTranslations()\n throw new CrudHttpError(409, {\n error: translate(\n 'staff.timesheets.errors.timerAlreadyRunning',\n 'Another timer is already running. Stop it before starting a new one.',\n ),\n })\n }\n\n const startedAt = new Date()\n const entry = trx.create(StaffTimeEntry, {\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n staffMemberId: effectiveStaffMemberId,\n date: parsed.date,\n durationMinutes: 0,\n startedAt,\n endedAt: null,\n notes: parsed.notes ?? null,\n timeProjectId: parsed.timeProjectId ?? null,\n customerId: null,\n dealId: null,\n orderId: null,\n source: 'timer',\n createdAt: startedAt,\n updatedAt: startedAt,\n deletedAt: null,\n })\n // Flush so the DB-generated id is populated before the work segment\n // references it; both writes commit together when the transaction closes.\n await trx.flush()\n\n const segmentData = {\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n timeEntryId: entry.id,\n startedAt,\n segmentType: 'work' as const,\n }\n trx.create(StaffTimeEntrySegment, segmentData as never)\n await trx.flush()\n\n return { entry, startedAt }\n })\n\n await emitCrudSideEffects({\n dataEngine: ctx.container.resolve('dataEngine'),\n action: 'created',\n entity: entry,\n identifiers: { id: entry.id, organizationId: entry.organizationId, tenantId: entry.tenantId },\n events: staffTimeEntryCrudEvents,\n indexer: timeEntryCrudIndexer,\n })\n\n void emitStaffEvent('staff.timesheets.time_entry.timer_started', {\n id: entry.id,\n staffMemberId: effectiveStaffMemberId,\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n startedAt: startedAt.toISOString(),\n }, { persistent: true }).catch((err) => {\n console.error('[staff.timesheets] emit timer_started failed', err)\n })\n\n return { timeEntryId: entry.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const snapshot = await loadTimeEntrySnapshot(em, result.timeEntryId, staffSnapshotScopeFromContext(ctx))\n if (!snapshot) return null\n return { snapshot }\n },\n buildLog: async ({ result, ctx }) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const snapshot = await loadTimeEntrySnapshot(em, result.timeEntryId, staffSnapshotScopeFromContext(ctx))\n if (!snapshot) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('staff.audit.timesheets.time_entries.startTimer', 'Start timer'),\n resourceKind: 'staff.timesheets.time_entry',\n resourceId: snapshot.id,\n tenantId: snapshot.tenantId,\n organizationId: snapshot.organizationId,\n snapshotAfter: snapshot,\n payload: {\n undo: {\n after: snapshot,\n } satisfies TimeEntryUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<TimeEntryUndoPayload>(logEntry)\n const after = payload?.after\n if (!after) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const entry = await em.findOne(StaffTimeEntry, scopedStaffSnapshotWhere(after.id, staffSnapshotScopeFromSnapshot(after)))\n if (entry) {\n entry.deletedAt = new Date()\n await em.flush()\n\n await emitCrudUndoSideEffects({\n dataEngine: ctx.container.resolve('dataEngine'),\n action: 'deleted',\n entity: entry,\n identifiers: { id: entry.id, organizationId: entry.organizationId, tenantId: entry.tenantId },\n events: staffTimeEntryCrudEvents,\n })\n }\n },\n}\n\nconst updateTimeEntryCommand: CommandHandler<StaffTimeEntryUpdateInput, { timeEntryId: string }> = {\n id: 'staff.timesheets.time_entries.update',\n async prepare(rawInput, ctx) {\n const parsed = staffTimeEntryUpdateSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadTimeEntrySnapshot(em, parsed.id, staffSnapshotScopeFromContext(ctx))\n if (!snapshot) return {}\n return { before: snapshot }\n },\n async execute(rawInput, ctx) {\n const parsed = staffTimeEntryUpdateSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const scope = commandActorScope(ctx)\n const entry = await findOneWithDecryption(\n em,\n StaffTimeEntry,\n applyScopeToWhere<StaffTimeEntry>({ id: parsed.id, deletedAt: null }, scope),\n undefined,\n scopeForDecryption(scope),\n )\n if (!entry) throw new CrudHttpError(404, { error: 'Time entry not found.' })\n ensureTenantScope(ctx, entry.tenantId)\n ensureOrganizationScope(ctx, entry.organizationId)\n\n // Ownership enforcement: callers without `staff.timesheets.manage_all`\n // can only update entries they own.\n if (!(await callerHasManageAll(ctx))) {\n const callerStaffMemberId = await resolveCallerStaffMemberId(em, ctx)\n if (!callerStaffMemberId || entry.staffMemberId !== callerStaffMemberId) {\n const { translate } = await resolveTranslations()\n throw new CrudHttpError(403, {\n error: translate('staff.timesheets.errors.notOwner', 'You can only manage your own time entries.'),\n })\n }\n }\n\n // Validate referenced timeProjectId is in-scope when it's being changed to a non-null value.\n if (parsed.timeProjectId !== undefined && parsed.timeProjectId !== null) {\n await assertTimeProjectInScope(em, parsed.timeProjectId, entry.tenantId, entry.organizationId)\n }\n\n if (parsed.date !== undefined) entry.date = parsed.date\n if (parsed.durationMinutes !== undefined) entry.durationMinutes = parsed.durationMinutes\n if (parsed.timeProjectId !== undefined) entry.timeProjectId = parsed.timeProjectId ?? null\n if (parsed.customerId !== undefined) entry.customerId = parsed.customerId ?? null\n if (parsed.dealId !== undefined) entry.dealId = parsed.dealId ?? null\n if (parsed.orderId !== undefined) entry.orderId = parsed.orderId ?? null\n if (parsed.notes !== undefined) entry.notes = parsed.notes ?? null\n entry.updatedAt = new Date()\n await em.flush()\n\n await emitCrudSideEffects({\n dataEngine: ctx.container.resolve('dataEngine'),\n action: 'updated',\n entity: entry,\n identifiers: { id: entry.id, organizationId: entry.organizationId, tenantId: entry.tenantId },\n events: staffTimeEntryCrudEvents,\n indexer: timeEntryCrudIndexer,\n })\n\n return { timeEntryId: entry.id }\n },\n buildLog: async ({ snapshots, ctx }) => {\n const before = snapshots.before as TimeEntrySnapshot | undefined\n if (!before) return null\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const after = await loadTimeEntrySnapshot(em, before.id, staffSnapshotScopeFromSnapshot(before))\n if (!after) return null\n const changes = buildChanges(before as unknown as Record<string, unknown>, after as unknown as Record<string, unknown>, [\n 'date',\n 'durationMinutes',\n 'timeProjectId',\n 'customerId',\n 'dealId',\n 'orderId',\n 'notes',\n 'deletedAt',\n ])\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('staff.audit.timesheets.time_entries.update', 'Update time entry'),\n resourceKind: 'staff.timesheets.time_entry',\n resourceId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n snapshotBefore: before,\n snapshotAfter: after,\n changes,\n payload: {\n undo: {\n before,\n after,\n } satisfies TimeEntryUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<TimeEntryUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const entry = await em.findOne(StaffTimeEntry, scopedStaffSnapshotWhere(before.id, staffSnapshotScopeFromSnapshot(before)))\n if (!entry) return\n entry.date = before.date as unknown as Date\n entry.durationMinutes = before.durationMinutes\n entry.timeProjectId = before.timeProjectId ?? null\n entry.customerId = before.customerId ?? null\n entry.dealId = before.dealId ?? null\n entry.orderId = before.orderId ?? null\n entry.notes = before.notes ?? null\n entry.deletedAt = before.deletedAt ? new Date(before.deletedAt) : null\n entry.updatedAt = new Date()\n await em.flush()\n\n await emitCrudUndoSideEffects({\n dataEngine: ctx.container.resolve('dataEngine'),\n action: 'updated',\n entity: entry,\n identifiers: { id: entry.id, organizationId: entry.organizationId, tenantId: entry.tenantId },\n events: staffTimeEntryCrudEvents,\n indexer: timeEntryCrudIndexer,\n })\n },\n}\n\nconst deleteTimeEntryCommand: CommandHandler<{ id?: string }, { timeEntryId: string }> = {\n id: 'staff.timesheets.time_entries.delete',\n async prepare(input, ctx) {\n const id = input?.id\n if (!id) throw new CrudHttpError(400, { error: 'Time entry id is required.' })\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadTimeEntrySnapshot(em, id, staffSnapshotScopeFromContext(ctx))\n if (!snapshot) return {}\n return { before: snapshot }\n },\n async execute(input, ctx) {\n const id = input?.id\n if (!id) throw new CrudHttpError(400, { error: 'Time entry id is required.' })\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const scope = commandActorScope(ctx)\n const entry = await findOneWithDecryption(\n em,\n StaffTimeEntry,\n applyScopeToWhere<StaffTimeEntry>({ id, deletedAt: null }, scope),\n undefined,\n scopeForDecryption(scope),\n )\n if (!entry) throw new CrudHttpError(404, { error: 'Time entry not found.' })\n ensureTenantScope(ctx, entry.tenantId)\n ensureOrganizationScope(ctx, entry.organizationId)\n\n // Ownership enforcement: callers without `staff.timesheets.manage_all`\n // can only delete entries they own.\n if (!(await callerHasManageAll(ctx))) {\n const callerStaffMemberId = await resolveCallerStaffMemberId(em, ctx)\n if (!callerStaffMemberId || entry.staffMemberId !== callerStaffMemberId) {\n const { translate } = await resolveTranslations()\n throw new CrudHttpError(403, {\n error: translate('staff.timesheets.errors.notOwner', 'You can only manage your own time entries.'),\n })\n }\n }\n\n entry.deletedAt = new Date()\n entry.updatedAt = new Date()\n await em.flush()\n\n await emitCrudSideEffects({\n dataEngine: ctx.container.resolve('dataEngine'),\n action: 'deleted',\n entity: entry,\n identifiers: { id: entry.id, organizationId: entry.organizationId, tenantId: entry.tenantId },\n events: staffTimeEntryCrudEvents,\n indexer: timeEntryCrudIndexer,\n })\n\n return { timeEntryId: entry.id }\n },\n buildLog: async ({ snapshots }) => {\n const before = snapshots.before as TimeEntrySnapshot | undefined\n if (!before) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('staff.audit.timesheets.time_entries.delete', 'Delete time entry'),\n resourceKind: 'staff.timesheets.time_entry',\n resourceId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n snapshotBefore: before,\n payload: {\n undo: {\n before,\n } satisfies TimeEntryUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<TimeEntryUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n let entry = await em.findOne(StaffTimeEntry, scopedStaffSnapshotWhere(before.id, staffSnapshotScopeFromSnapshot(before)))\n if (!entry) {\n entry = em.create(StaffTimeEntry, {\n id: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n staffMemberId: before.staffMemberId,\n date: before.date as unknown as Date,\n durationMinutes: before.durationMinutes,\n startedAt: before.startedAt ? new Date(before.startedAt) : null,\n endedAt: before.endedAt ? new Date(before.endedAt) : null,\n notes: before.notes ?? null,\n timeProjectId: before.timeProjectId ?? null,\n customerId: before.customerId ?? null,\n dealId: before.dealId ?? null,\n orderId: before.orderId ?? null,\n source: (before.source ?? 'manual') as StaffTimeEntrySource,\n deletedAt: null,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n em.persist(entry)\n } else {\n entry.staffMemberId = before.staffMemberId\n entry.date = before.date as unknown as Date\n entry.durationMinutes = before.durationMinutes\n entry.startedAt = before.startedAt ? new Date(before.startedAt) : null\n entry.endedAt = before.endedAt ? new Date(before.endedAt) : null\n entry.notes = before.notes ?? null\n entry.timeProjectId = before.timeProjectId ?? null\n entry.customerId = before.customerId ?? null\n entry.dealId = before.dealId ?? null\n entry.orderId = before.orderId ?? null\n entry.source = (before.source ?? 'manual') as StaffTimeEntrySource\n entry.deletedAt = null\n entry.updatedAt = new Date()\n }\n await em.flush()\n\n await emitCrudUndoSideEffects({\n dataEngine: ctx.container.resolve('dataEngine'),\n action: 'created',\n entity: entry,\n identifiers: { id: entry.id, organizationId: entry.organizationId, tenantId: entry.tenantId },\n events: staffTimeEntryCrudEvents,\n indexer: timeEntryCrudIndexer,\n })\n },\n}\n\nregisterCommand(createTimeEntryCommand)\nregisterCommand(startTimerCommand)\nregisterCommand(updateTimeEntryCommand)\nregisterCommand(deleteTimeEntryCommand)\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import type { CommandHandler } from '@open-mercato/shared/lib/commands'\nimport { registerCommand } from '@open-mercato/shared/lib/commands'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { findOneWithDecryption } from '@open-mercato/shared/lib/encryption/find'\nimport { buildChanges, emitCrudSideEffects, emitCrudUndoSideEffects } from '@open-mercato/shared/lib/commands/helpers'\nimport { makeCreateRedo } from '@open-mercato/shared/lib/commands/redo'\nimport type { CrudIndexerConfig } from '@open-mercato/shared/lib/crud/types'\nimport { StaffTimeEntry, StaffTimeEntrySegment, StaffTimeProject, type StaffTimeEntrySource } from '../data/entities'\nimport { emitStaffEvent } from '../events'\n\nconst timeEntryCrudIndexer: CrudIndexerConfig<StaffTimeEntry> = {\n entityType: 'staff:staff_time_entry',\n}\nimport {\n staffTimeEntryCreateSchema,\n staffTimeEntryStartTimerSchema,\n staffTimeEntryUpdateSchema,\n type StaffTimeEntryCreateInput,\n type StaffTimeEntryStartTimerInput,\n type StaffTimeEntryUpdateInput,\n} from '../data/validators'\nimport { staffTimeEntryCrudEvents } from '../lib/crud'\nimport {\n applyScopeToWhere,\n commandActorScope,\n commandInputScope,\n ensureOrganizationScope,\n ensureTenantScope,\n extractUndoPayload,\n scopeForDecryption,\n scopedStaffSnapshotWhere,\n staffSnapshotDecryptionScope,\n staffSnapshotScopeFromContext,\n staffSnapshotScopeFromSnapshot,\n type StaffSnapshotScope,\n} from './shared'\nimport { getStaffMemberByUserId } from '../lib/staffMemberResolver'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('staff')\n\ntype RbacServiceLike = {\n userHasAllFeatures: (\n userId: string,\n required: string[],\n scope: { tenantId: string | null; organizationId: string | null },\n ) => Promise<boolean>\n}\n\n/**\n * Returns true when the caller holds `staff.timesheets.manage_all`, honoring\n * wildcard ACL grants (`staff.*`, `*`) and the super-admin flag via the cached\n * rbacService. Returns false when no auth context (e.g. system/CLI ctx) so\n * write paths that lack a caller identity are NOT silently elevated.\n */\nasync function callerHasManageAll(ctx: {\n auth?: { sub?: string | null; tenantId?: string | null; orgId?: string | null } | null\n container: { resolve: (token: string) => unknown }\n}): Promise<boolean> {\n const userId = ctx.auth?.sub\n if (!userId) return false\n try {\n const rbac = ctx.container.resolve('rbacService') as RbacServiceLike | undefined\n if (!rbac?.userHasAllFeatures) return false\n return await rbac.userHasAllFeatures(\n userId,\n ['staff.timesheets.manage_all'],\n { tenantId: ctx.auth?.tenantId ?? null, organizationId: ctx.auth?.orgId ?? null },\n )\n } catch {\n return false\n }\n}\n\nasync function resolveCallerStaffMemberId(\n em: EntityManager,\n ctx: { auth?: { sub?: string | null; tenantId?: string | null; orgId?: string | null } | null },\n): Promise<string | null> {\n const userId = ctx.auth?.sub\n if (!userId) return null\n const member = await getStaffMemberByUserId(\n em,\n userId,\n ctx.auth?.tenantId ?? null,\n ctx.auth?.orgId ?? null,\n )\n return member?.id ?? null\n}\n\n/**\n * Verifies the referenced time project exists and is in-scope (same tenant + org,\n * not soft-deleted). Throws 422 if the ID is provided but unresolvable.\n * No-op when projectId is null/undefined (timeProjectId is optional on entries).\n */\nasync function assertTimeProjectInScope(\n em: EntityManager,\n projectId: string | null | undefined,\n tenantId: string,\n organizationId: string,\n): Promise<void> {\n if (!projectId) return\n const exists = await em.findOne(\n StaffTimeProject,\n { id: projectId, tenantId, organizationId, deletedAt: null },\n { fields: ['id'] },\n )\n if (!exists) {\n const { translate } = await resolveTranslations()\n throw new CrudHttpError(422, {\n error: translate('staff.timesheets.errors.projectNotFound', 'Time project not found or not accessible.'),\n fieldErrors: {\n timeProjectId: translate('staff.timesheets.errors.projectNotFound', 'Time project not found or not accessible.'),\n },\n })\n }\n}\n\ntype TimeEntrySnapshot = {\n id: string\n tenantId: string\n organizationId: string\n staffMemberId: string\n date: string\n durationMinutes: number\n startedAt: string | null\n endedAt: string | null\n notes: string | null\n timeProjectId: string | null\n customerId: string | null\n dealId: string | null\n orderId: string | null\n source: string\n deletedAt: string | null\n}\n\ntype TimeEntryUndoPayload = {\n before?: TimeEntrySnapshot | null\n after?: TimeEntrySnapshot | null\n}\n\nasync function loadTimeEntrySnapshot(em: EntityManager, id: string, scope?: StaffSnapshotScope | null): Promise<TimeEntrySnapshot | null> {\n const entry = await findOneWithDecryption(\n em,\n StaffTimeEntry,\n scopedStaffSnapshotWhere(id, scope),\n undefined,\n staffSnapshotDecryptionScope(scope),\n )\n if (!entry) return null\n return {\n id: entry.id,\n tenantId: entry.tenantId,\n organizationId: entry.organizationId,\n staffMemberId: entry.staffMemberId,\n date: entry.date instanceof Date ? entry.date.toISOString().split('T')[0] : String(entry.date),\n durationMinutes: entry.durationMinutes,\n startedAt: entry.startedAt ? entry.startedAt.toISOString() : null,\n endedAt: entry.endedAt ? entry.endedAt.toISOString() : null,\n notes: entry.notes ?? null,\n timeProjectId: entry.timeProjectId ?? null,\n customerId: entry.customerId ?? null,\n dealId: entry.dealId ?? null,\n orderId: entry.orderId ?? null,\n source: entry.source,\n deletedAt: entry.deletedAt ? entry.deletedAt.toISOString() : null,\n }\n}\n\nfunction timeEntrySeedFromSnapshot(snapshot: TimeEntrySnapshot): Record<string, unknown> {\n return {\n id: snapshot.id,\n tenantId: snapshot.tenantId,\n organizationId: snapshot.organizationId,\n staffMemberId: snapshot.staffMemberId,\n date: snapshot.date,\n durationMinutes: snapshot.durationMinutes,\n startedAt: snapshot.startedAt ? new Date(snapshot.startedAt) : null,\n endedAt: snapshot.endedAt ? new Date(snapshot.endedAt) : null,\n notes: snapshot.notes ?? null,\n timeProjectId: snapshot.timeProjectId ?? null,\n customerId: snapshot.customerId ?? null,\n dealId: snapshot.dealId ?? null,\n orderId: snapshot.orderId ?? null,\n source: (snapshot.source ?? 'manual') as StaffTimeEntrySource,\n createdAt: new Date(),\n updatedAt: new Date(),\n deletedAt: null,\n }\n}\n\nconst createTimeEntryCommand: CommandHandler<StaffTimeEntryCreateInput, { timeEntryId: string }> = {\n id: 'staff.timesheets.time_entries.create',\n async execute(rawInput, ctx) {\n const parsed = staffTimeEntryCreateSchema.parse(rawInput)\n ensureTenantScope(ctx, parsed.tenantId)\n ensureOrganizationScope(ctx, parsed.organizationId)\n commandInputScope(ctx, parsed.tenantId, parsed.organizationId)\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n\n // Ownership enforcement: callers without `staff.timesheets.manage_all`\n // can only create entries attributed to themselves. Silent override\n // (mirrors `bulk/route.ts` behavior) so the request body's staffMemberId\n // can't forge an entry under a colleague's identity.\n let effectiveStaffMemberId = parsed.staffMemberId\n if (!(await callerHasManageAll(ctx))) {\n const callerStaffMemberId = await resolveCallerStaffMemberId(em, ctx)\n if (!callerStaffMemberId) {\n const { translate } = await resolveTranslations()\n throw new CrudHttpError(403, {\n error: translate('staff.timesheets.errors.noStaffMember', 'No staff member linked to your account.'),\n })\n }\n effectiveStaffMemberId = callerStaffMemberId\n }\n\n // Validate referenced timeProjectId is in-scope before persisting.\n // Without this check a foreign or stale UUID would produce a dangling reference.\n await assertTimeProjectInScope(em, parsed.timeProjectId ?? null, parsed.tenantId, parsed.organizationId)\n\n const now = new Date()\n const entry = em.create(StaffTimeEntry, {\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n staffMemberId: effectiveStaffMemberId,\n date: parsed.date,\n durationMinutes: parsed.durationMinutes,\n startedAt: parsed.startedAt ?? null,\n endedAt: parsed.endedAt ?? null,\n notes: parsed.notes ?? null,\n timeProjectId: parsed.timeProjectId ?? null,\n customerId: parsed.customerId ?? null,\n dealId: parsed.dealId ?? null,\n orderId: parsed.orderId ?? null,\n source: parsed.source ?? 'manual',\n createdAt: now,\n updatedAt: now,\n deletedAt: null,\n })\n em.persist(entry)\n await em.flush()\n\n await emitCrudSideEffects({\n dataEngine: ctx.container.resolve('dataEngine'),\n action: 'created',\n entity: entry,\n identifiers: { id: entry.id, organizationId: entry.organizationId, tenantId: entry.tenantId },\n events: staffTimeEntryCrudEvents,\n indexer: timeEntryCrudIndexer,\n })\n\n return { timeEntryId: entry.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const snapshot = await loadTimeEntrySnapshot(em, result.timeEntryId, staffSnapshotScopeFromContext(ctx))\n if (!snapshot) return null\n return { snapshot }\n },\n buildLog: async ({ result, ctx }) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const snapshot = await loadTimeEntrySnapshot(em, result.timeEntryId, staffSnapshotScopeFromContext(ctx))\n if (!snapshot) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('staff.audit.timesheets.time_entries.create', 'Create time entry'),\n resourceKind: 'staff.timesheets.time_entry',\n resourceId: snapshot.id,\n tenantId: snapshot.tenantId,\n organizationId: snapshot.organizationId,\n snapshotAfter: snapshot,\n payload: {\n undo: {\n after: snapshot,\n } satisfies TimeEntryUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<TimeEntryUndoPayload>(logEntry)\n const after = payload?.after\n if (!after) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const entry = await em.findOne(StaffTimeEntry, scopedStaffSnapshotWhere(after.id, staffSnapshotScopeFromSnapshot(after)))\n if (entry) {\n entry.deletedAt = new Date()\n await em.flush()\n\n await emitCrudUndoSideEffects({\n dataEngine: ctx.container.resolve('dataEngine'),\n action: 'deleted',\n entity: entry,\n identifiers: { id: entry.id, organizationId: entry.organizationId, tenantId: entry.tenantId },\n events: staffTimeEntryCrudEvents,\n })\n }\n },\n redo: makeCreateRedo<StaffTimeEntry, TimeEntrySnapshot, StaffTimeEntryCreateInput, { timeEntryId: string }>({\n entityClass: StaffTimeEntry,\n getSnapshotId: (snapshot) => snapshot.id,\n seedFromSnapshot: timeEntrySeedFromSnapshot,\n buildResult: (entity) => ({ timeEntryId: entity.id }),\n events: staffTimeEntryCrudEvents,\n indexer: timeEntryCrudIndexer,\n }),\n}\n\nconst startTimerCommand: CommandHandler<StaffTimeEntryStartTimerInput, { timeEntryId: string }> = {\n id: 'staff.timesheets.time_entries.start_timer',\n async execute(rawInput, ctx) {\n const parsed = staffTimeEntryStartTimerSchema.parse(rawInput)\n ensureTenantScope(ctx, parsed.tenantId)\n ensureOrganizationScope(ctx, parsed.organizationId)\n commandInputScope(ctx, parsed.tenantId, parsed.organizationId)\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n\n // Ownership enforcement mirrors createTimeEntryCommand: callers without\n // `staff.timesheets.manage_all` can only start their own timer, so the\n // request body's staffMemberId can't start a timer under a colleague's id.\n let effectiveStaffMemberId = parsed.staffMemberId\n if (!(await callerHasManageAll(ctx))) {\n const callerStaffMemberId = await resolveCallerStaffMemberId(em, ctx)\n if (!callerStaffMemberId) {\n const { translate } = await resolveTranslations()\n throw new CrudHttpError(403, {\n error: translate('staff.timesheets.errors.noStaffMember', 'No staff member linked to your account.'),\n })\n }\n effectiveStaffMemberId = callerStaffMemberId\n }\n\n await assertTimeProjectInScope(em, parsed.timeProjectId ?? null, parsed.tenantId, parsed.organizationId)\n\n const scopeCtx = { tenantId: parsed.tenantId, organizationId: parsed.organizationId }\n\n // Create the timer entry AND start it inside a single transaction so a\n // partial failure can never leave an orphaned, never-started timer entry\n // (issue #3311 \u2014 the legacy two-request create-then-start flow). The\n // single-active-timer invariant (#2855) is re-checked here so a second\n // surface cannot create a parallel running timer for the same staff member.\n const { entry, startedAt } = await em.transactional(async (trx) => {\n const otherRunningEntry = await findOneWithDecryption(\n trx,\n StaffTimeEntry,\n {\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n staffMemberId: effectiveStaffMemberId,\n startedAt: { $ne: null },\n endedAt: null,\n deletedAt: null,\n },\n {},\n scopeCtx,\n )\n if (otherRunningEntry) {\n const { translate } = await resolveTranslations()\n throw new CrudHttpError(409, {\n error: translate(\n 'staff.timesheets.errors.timerAlreadyRunning',\n 'Another timer is already running. Stop it before starting a new one.',\n ),\n })\n }\n\n const startedAt = new Date()\n const entry = trx.create(StaffTimeEntry, {\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n staffMemberId: effectiveStaffMemberId,\n date: parsed.date,\n durationMinutes: 0,\n startedAt,\n endedAt: null,\n notes: parsed.notes ?? null,\n timeProjectId: parsed.timeProjectId ?? null,\n customerId: null,\n dealId: null,\n orderId: null,\n source: 'timer',\n createdAt: startedAt,\n updatedAt: startedAt,\n deletedAt: null,\n })\n // Flush so the DB-generated id is populated before the work segment\n // references it; both writes commit together when the transaction closes.\n await trx.flush()\n\n const segmentData = {\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n timeEntryId: entry.id,\n startedAt,\n segmentType: 'work' as const,\n }\n trx.create(StaffTimeEntrySegment, segmentData as never)\n await trx.flush()\n\n return { entry, startedAt }\n })\n\n await emitCrudSideEffects({\n dataEngine: ctx.container.resolve('dataEngine'),\n action: 'created',\n entity: entry,\n identifiers: { id: entry.id, organizationId: entry.organizationId, tenantId: entry.tenantId },\n events: staffTimeEntryCrudEvents,\n indexer: timeEntryCrudIndexer,\n })\n\n void emitStaffEvent('staff.timesheets.time_entry.timer_started', {\n id: entry.id,\n staffMemberId: effectiveStaffMemberId,\n tenantId: parsed.tenantId,\n organizationId: parsed.organizationId,\n startedAt: startedAt.toISOString(),\n }, { persistent: true }).catch((err) => {\n logger.error('staff.timesheets emit timer_started failed', { err })\n })\n\n return { timeEntryId: entry.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const snapshot = await loadTimeEntrySnapshot(em, result.timeEntryId, staffSnapshotScopeFromContext(ctx))\n if (!snapshot) return null\n return { snapshot }\n },\n buildLog: async ({ result, ctx }) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const snapshot = await loadTimeEntrySnapshot(em, result.timeEntryId, staffSnapshotScopeFromContext(ctx))\n if (!snapshot) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('staff.audit.timesheets.time_entries.startTimer', 'Start timer'),\n resourceKind: 'staff.timesheets.time_entry',\n resourceId: snapshot.id,\n tenantId: snapshot.tenantId,\n organizationId: snapshot.organizationId,\n snapshotAfter: snapshot,\n payload: {\n undo: {\n after: snapshot,\n } satisfies TimeEntryUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<TimeEntryUndoPayload>(logEntry)\n const after = payload?.after\n if (!after) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const entry = await em.findOne(StaffTimeEntry, scopedStaffSnapshotWhere(after.id, staffSnapshotScopeFromSnapshot(after)))\n if (entry) {\n entry.deletedAt = new Date()\n await em.flush()\n\n await emitCrudUndoSideEffects({\n dataEngine: ctx.container.resolve('dataEngine'),\n action: 'deleted',\n entity: entry,\n identifiers: { id: entry.id, organizationId: entry.organizationId, tenantId: entry.tenantId },\n events: staffTimeEntryCrudEvents,\n })\n }\n },\n}\n\nconst updateTimeEntryCommand: CommandHandler<StaffTimeEntryUpdateInput, { timeEntryId: string }> = {\n id: 'staff.timesheets.time_entries.update',\n async prepare(rawInput, ctx) {\n const parsed = staffTimeEntryUpdateSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadTimeEntrySnapshot(em, parsed.id, staffSnapshotScopeFromContext(ctx))\n if (!snapshot) return {}\n return { before: snapshot }\n },\n async execute(rawInput, ctx) {\n const parsed = staffTimeEntryUpdateSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const scope = commandActorScope(ctx)\n const entry = await findOneWithDecryption(\n em,\n StaffTimeEntry,\n applyScopeToWhere<StaffTimeEntry>({ id: parsed.id, deletedAt: null }, scope),\n undefined,\n scopeForDecryption(scope),\n )\n if (!entry) throw new CrudHttpError(404, { error: 'Time entry not found.' })\n ensureTenantScope(ctx, entry.tenantId)\n ensureOrganizationScope(ctx, entry.organizationId)\n\n // Ownership enforcement: callers without `staff.timesheets.manage_all`\n // can only update entries they own.\n if (!(await callerHasManageAll(ctx))) {\n const callerStaffMemberId = await resolveCallerStaffMemberId(em, ctx)\n if (!callerStaffMemberId || entry.staffMemberId !== callerStaffMemberId) {\n const { translate } = await resolveTranslations()\n throw new CrudHttpError(403, {\n error: translate('staff.timesheets.errors.notOwner', 'You can only manage your own time entries.'),\n })\n }\n }\n\n // Validate referenced timeProjectId is in-scope when it's being changed to a non-null value.\n if (parsed.timeProjectId !== undefined && parsed.timeProjectId !== null) {\n await assertTimeProjectInScope(em, parsed.timeProjectId, entry.tenantId, entry.organizationId)\n }\n\n if (parsed.date !== undefined) entry.date = parsed.date\n if (parsed.durationMinutes !== undefined) entry.durationMinutes = parsed.durationMinutes\n if (parsed.timeProjectId !== undefined) entry.timeProjectId = parsed.timeProjectId ?? null\n if (parsed.customerId !== undefined) entry.customerId = parsed.customerId ?? null\n if (parsed.dealId !== undefined) entry.dealId = parsed.dealId ?? null\n if (parsed.orderId !== undefined) entry.orderId = parsed.orderId ?? null\n if (parsed.notes !== undefined) entry.notes = parsed.notes ?? null\n entry.updatedAt = new Date()\n await em.flush()\n\n await emitCrudSideEffects({\n dataEngine: ctx.container.resolve('dataEngine'),\n action: 'updated',\n entity: entry,\n identifiers: { id: entry.id, organizationId: entry.organizationId, tenantId: entry.tenantId },\n events: staffTimeEntryCrudEvents,\n indexer: timeEntryCrudIndexer,\n })\n\n return { timeEntryId: entry.id }\n },\n buildLog: async ({ snapshots, ctx }) => {\n const before = snapshots.before as TimeEntrySnapshot | undefined\n if (!before) return null\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const after = await loadTimeEntrySnapshot(em, before.id, staffSnapshotScopeFromSnapshot(before))\n if (!after) return null\n const changes = buildChanges(before as unknown as Record<string, unknown>, after as unknown as Record<string, unknown>, [\n 'date',\n 'durationMinutes',\n 'timeProjectId',\n 'customerId',\n 'dealId',\n 'orderId',\n 'notes',\n 'deletedAt',\n ])\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('staff.audit.timesheets.time_entries.update', 'Update time entry'),\n resourceKind: 'staff.timesheets.time_entry',\n resourceId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n snapshotBefore: before,\n snapshotAfter: after,\n changes,\n payload: {\n undo: {\n before,\n after,\n } satisfies TimeEntryUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<TimeEntryUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const entry = await em.findOne(StaffTimeEntry, scopedStaffSnapshotWhere(before.id, staffSnapshotScopeFromSnapshot(before)))\n if (!entry) return\n entry.date = before.date as unknown as Date\n entry.durationMinutes = before.durationMinutes\n entry.timeProjectId = before.timeProjectId ?? null\n entry.customerId = before.customerId ?? null\n entry.dealId = before.dealId ?? null\n entry.orderId = before.orderId ?? null\n entry.notes = before.notes ?? null\n entry.deletedAt = before.deletedAt ? new Date(before.deletedAt) : null\n entry.updatedAt = new Date()\n await em.flush()\n\n await emitCrudUndoSideEffects({\n dataEngine: ctx.container.resolve('dataEngine'),\n action: 'updated',\n entity: entry,\n identifiers: { id: entry.id, organizationId: entry.organizationId, tenantId: entry.tenantId },\n events: staffTimeEntryCrudEvents,\n indexer: timeEntryCrudIndexer,\n })\n },\n}\n\nconst deleteTimeEntryCommand: CommandHandler<{ id?: string }, { timeEntryId: string }> = {\n id: 'staff.timesheets.time_entries.delete',\n async prepare(input, ctx) {\n const id = input?.id\n if (!id) throw new CrudHttpError(400, { error: 'Time entry id is required.' })\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadTimeEntrySnapshot(em, id, staffSnapshotScopeFromContext(ctx))\n if (!snapshot) return {}\n return { before: snapshot }\n },\n async execute(input, ctx) {\n const id = input?.id\n if (!id) throw new CrudHttpError(400, { error: 'Time entry id is required.' })\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const scope = commandActorScope(ctx)\n const entry = await findOneWithDecryption(\n em,\n StaffTimeEntry,\n applyScopeToWhere<StaffTimeEntry>({ id, deletedAt: null }, scope),\n undefined,\n scopeForDecryption(scope),\n )\n if (!entry) throw new CrudHttpError(404, { error: 'Time entry not found.' })\n ensureTenantScope(ctx, entry.tenantId)\n ensureOrganizationScope(ctx, entry.organizationId)\n\n // Ownership enforcement: callers without `staff.timesheets.manage_all`\n // can only delete entries they own.\n if (!(await callerHasManageAll(ctx))) {\n const callerStaffMemberId = await resolveCallerStaffMemberId(em, ctx)\n if (!callerStaffMemberId || entry.staffMemberId !== callerStaffMemberId) {\n const { translate } = await resolveTranslations()\n throw new CrudHttpError(403, {\n error: translate('staff.timesheets.errors.notOwner', 'You can only manage your own time entries.'),\n })\n }\n }\n\n entry.deletedAt = new Date()\n entry.updatedAt = new Date()\n await em.flush()\n\n await emitCrudSideEffects({\n dataEngine: ctx.container.resolve('dataEngine'),\n action: 'deleted',\n entity: entry,\n identifiers: { id: entry.id, organizationId: entry.organizationId, tenantId: entry.tenantId },\n events: staffTimeEntryCrudEvents,\n indexer: timeEntryCrudIndexer,\n })\n\n return { timeEntryId: entry.id }\n },\n buildLog: async ({ snapshots }) => {\n const before = snapshots.before as TimeEntrySnapshot | undefined\n if (!before) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('staff.audit.timesheets.time_entries.delete', 'Delete time entry'),\n resourceKind: 'staff.timesheets.time_entry',\n resourceId: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n snapshotBefore: before,\n payload: {\n undo: {\n before,\n } satisfies TimeEntryUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<TimeEntryUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n let entry = await em.findOne(StaffTimeEntry, scopedStaffSnapshotWhere(before.id, staffSnapshotScopeFromSnapshot(before)))\n if (!entry) {\n entry = em.create(StaffTimeEntry, {\n id: before.id,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n staffMemberId: before.staffMemberId,\n date: before.date as unknown as Date,\n durationMinutes: before.durationMinutes,\n startedAt: before.startedAt ? new Date(before.startedAt) : null,\n endedAt: before.endedAt ? new Date(before.endedAt) : null,\n notes: before.notes ?? null,\n timeProjectId: before.timeProjectId ?? null,\n customerId: before.customerId ?? null,\n dealId: before.dealId ?? null,\n orderId: before.orderId ?? null,\n source: (before.source ?? 'manual') as StaffTimeEntrySource,\n deletedAt: null,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n em.persist(entry)\n } else {\n entry.staffMemberId = before.staffMemberId\n entry.date = before.date as unknown as Date\n entry.durationMinutes = before.durationMinutes\n entry.startedAt = before.startedAt ? new Date(before.startedAt) : null\n entry.endedAt = before.endedAt ? new Date(before.endedAt) : null\n entry.notes = before.notes ?? null\n entry.timeProjectId = before.timeProjectId ?? null\n entry.customerId = before.customerId ?? null\n entry.dealId = before.dealId ?? null\n entry.orderId = before.orderId ?? null\n entry.source = (before.source ?? 'manual') as StaffTimeEntrySource\n entry.deletedAt = null\n entry.updatedAt = new Date()\n }\n await em.flush()\n\n await emitCrudUndoSideEffects({\n dataEngine: ctx.container.resolve('dataEngine'),\n action: 'created',\n entity: entry,\n identifiers: { id: entry.id, organizationId: entry.organizationId, tenantId: entry.tenantId },\n events: staffTimeEntryCrudEvents,\n indexer: timeEntryCrudIndexer,\n })\n },\n}\n\nregisterCommand(createTimeEntryCommand)\nregisterCommand(startTimerCommand)\nregisterCommand(updateTimeEntryCommand)\nregisterCommand(deleteTimeEntryCommand)\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["startedAt", "entry"]
|
|
7
7
|
}
|
|
@@ -8,6 +8,8 @@ import {
|
|
|
8
8
|
InlineDateRangeSelect
|
|
9
9
|
} from "@open-mercato/ui/backend/date-range";
|
|
10
10
|
import { DEFAULT_SETTINGS, hydrateSettings } from "./config.js";
|
|
11
|
+
import { createLogger } from "@open-mercato/shared/lib/logger";
|
|
12
|
+
const logger = createLogger("staff");
|
|
11
13
|
function minutesToHours(minutes) {
|
|
12
14
|
const hours = minutes / 60;
|
|
13
15
|
return hours % 1 === 0 ? String(hours) : hours.toFixed(1);
|
|
@@ -53,7 +55,7 @@ const HoursByProjectWidget = ({
|
|
|
53
55
|
setData(sorted);
|
|
54
56
|
setTotalMinutes(sorted.reduce((sum, item) => sum + (item.value ?? 0), 0));
|
|
55
57
|
} catch (err) {
|
|
56
|
-
|
|
58
|
+
logger.error("staff.timesheets.hoursByProject", { err });
|
|
57
59
|
setError(t("staff.timesheets.widgets.hoursByProject.error", "Failed to load data"));
|
|
58
60
|
} finally {
|
|
59
61
|
setLoading(false);
|
package/dist/modules/staff/widgets/dashboard/timesheets-hours-by-project/widget.client.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/modules/staff/widgets/dashboard/timesheets-hours-by-project/widget.client.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport type { DashboardWidgetComponentProps } from '@open-mercato/shared/modules/dashboard/widgets'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport {\n DateRangeSelect,\n InlineDateRangeSelect,\n type DateRangePreset,\n} from '@open-mercato/ui/backend/date-range'\nimport { DEFAULT_SETTINGS, hydrateSettings, type HoursByProjectSettings } from './config'\n\ntype WidgetDataItem = { groupKey: string; groupLabel?: string; value: number | null }\ntype WidgetDataResponse = {\n value: number | null\n data: WidgetDataItem[]\n metadata: { fetchedAt: string; recordCount: number }\n}\n\nfunction minutesToHours(minutes: number): string {\n const hours = minutes / 60\n return hours % 1 === 0 ? String(hours) : hours.toFixed(1)\n}\n\nasync function fetchData(settings: HoursByProjectSettings): Promise<WidgetDataResponse> {\n const body = {\n entityType: 'staff:staff_time_entries',\n metric: { field: 'durationMinutes', aggregate: 'sum' },\n groupBy: { field: 'timeProjectId', limit: 20, resolveLabels: true },\n dateRange: { field: 'date', preset: settings.dateRange },\n }\n\n const res = await apiCall<WidgetDataResponse>('/api/dashboards/widgets/data', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n })\n\n if (!res.ok) {\n const err = (res.result as Record<string, unknown>)?.error\n throw new Error(typeof err === 'string' ? err : 'Failed to fetch data')\n }\n\n return res.result as WidgetDataResponse\n}\n\nconst HoursByProjectWidget: React.FC<DashboardWidgetComponentProps<HoursByProjectSettings>> = ({\n mode,\n settings = DEFAULT_SETTINGS,\n onSettingsChange,\n refreshToken,\n onRefreshStateChange,\n}) => {\n const t = useT()\n const hydrated = React.useMemo(() => hydrateSettings(settings), [settings])\n const [data, setData] = React.useState<WidgetDataItem[]>([])\n const [totalMinutes, setTotalMinutes] = React.useState(0)\n const [loading, setLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n\n const refresh = React.useCallback(async () => {\n onRefreshStateChange?.(true)\n setLoading(true)\n setError(null)\n try {\n const result = await fetchData(hydrated)\n const sorted = [...result.data].sort((a, b) => (b.value ?? 0) - (a.value ?? 0))\n setData(sorted)\n setTotalMinutes(sorted.reduce((sum, item) => sum + (item.value ?? 0), 0))\n } catch (err) {\n
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport type { DashboardWidgetComponentProps } from '@open-mercato/shared/modules/dashboard/widgets'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport {\n DateRangeSelect,\n InlineDateRangeSelect,\n type DateRangePreset,\n} from '@open-mercato/ui/backend/date-range'\nimport { DEFAULT_SETTINGS, hydrateSettings, type HoursByProjectSettings } from './config'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('staff')\n\ntype WidgetDataItem = { groupKey: string; groupLabel?: string; value: number | null }\ntype WidgetDataResponse = {\n value: number | null\n data: WidgetDataItem[]\n metadata: { fetchedAt: string; recordCount: number }\n}\n\nfunction minutesToHours(minutes: number): string {\n const hours = minutes / 60\n return hours % 1 === 0 ? String(hours) : hours.toFixed(1)\n}\n\nasync function fetchData(settings: HoursByProjectSettings): Promise<WidgetDataResponse> {\n const body = {\n entityType: 'staff:staff_time_entries',\n metric: { field: 'durationMinutes', aggregate: 'sum' },\n groupBy: { field: 'timeProjectId', limit: 20, resolveLabels: true },\n dateRange: { field: 'date', preset: settings.dateRange },\n }\n\n const res = await apiCall<WidgetDataResponse>('/api/dashboards/widgets/data', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(body),\n })\n\n if (!res.ok) {\n const err = (res.result as Record<string, unknown>)?.error\n throw new Error(typeof err === 'string' ? err : 'Failed to fetch data')\n }\n\n return res.result as WidgetDataResponse\n}\n\nconst HoursByProjectWidget: React.FC<DashboardWidgetComponentProps<HoursByProjectSettings>> = ({\n mode,\n settings = DEFAULT_SETTINGS,\n onSettingsChange,\n refreshToken,\n onRefreshStateChange,\n}) => {\n const t = useT()\n const hydrated = React.useMemo(() => hydrateSettings(settings), [settings])\n const [data, setData] = React.useState<WidgetDataItem[]>([])\n const [totalMinutes, setTotalMinutes] = React.useState(0)\n const [loading, setLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n\n const refresh = React.useCallback(async () => {\n onRefreshStateChange?.(true)\n setLoading(true)\n setError(null)\n try {\n const result = await fetchData(hydrated)\n const sorted = [...result.data].sort((a, b) => (b.value ?? 0) - (a.value ?? 0))\n setData(sorted)\n setTotalMinutes(sorted.reduce((sum, item) => sum + (item.value ?? 0), 0))\n } catch (err) {\n logger.error('staff.timesheets.hoursByProject', { err })\n setError(t('staff.timesheets.widgets.hoursByProject.error', 'Failed to load data'))\n } finally {\n setLoading(false)\n onRefreshStateChange?.(false)\n }\n }, [hydrated, onRefreshStateChange, t])\n\n React.useEffect(() => {\n void refresh()\n }, [refresh, refreshToken])\n\n if (mode === 'settings') {\n return (\n <div className=\"space-y-4 text-sm\">\n <DateRangeSelect\n id=\"hours-by-project-date-range\"\n label={t('staff.timesheets.widgets.hoursByProject.settings.dateRange', 'Date Range')}\n value={hydrated.dateRange}\n onChange={(dateRange: DateRangePreset) => onSettingsChange({ ...hydrated, dateRange })}\n />\n </div>\n )\n }\n\n if (loading) {\n return (\n <div className=\"flex h-full items-center justify-center py-8\">\n <p className=\"text-sm text-muted-foreground\">{t('staff.timesheets.widgets.hoursByProject.loading', 'Loading...')}</p>\n </div>\n )\n }\n\n if (error) {\n return (\n <div className=\"flex h-full items-center justify-center py-8\">\n <p className=\"text-sm text-destructive\">{error}</p>\n </div>\n )\n }\n\n const maxValue = data.length > 0 ? Math.max(...data.map((d) => d.value ?? 0)) : 0\n\n return (\n <div className=\"space-y-3\">\n <div className=\"flex items-center justify-end\">\n <InlineDateRangeSelect\n value={hydrated.dateRange}\n onChange={(dateRange) => onSettingsChange({ ...hydrated, dateRange })}\n />\n </div>\n\n {data.length === 0 ? (\n <p className=\"py-4 text-center text-sm text-muted-foreground\">\n {t('staff.timesheets.widgets.hoursByProject.empty', 'No hours tracked in this period.')}\n </p>\n ) : (\n <div className=\"space-y-2.5\">\n {data.map((item) => {\n const barWidth = maxValue > 0 ? ((item.value ?? 0) / maxValue) * 100 : 0\n return (\n <div key={item.groupKey} className=\"space-y-1\">\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"truncate font-medium\">{item.groupLabel || item.groupKey}</span>\n <span className=\"shrink-0 tabular-nums text-muted-foreground\">{minutesToHours(item.value ?? 0)} h</span>\n </div>\n <div className=\"h-2 w-full rounded-full bg-muted\">\n <div\n className=\"h-2 rounded-full bg-primary transition-all\"\n style={{ width: `${barWidth}%` }}\n />\n </div>\n </div>\n )\n })}\n\n <div className=\"flex items-center justify-between border-t pt-2 text-sm font-semibold\">\n <span>{t('staff.timesheets.widgets.hoursByProject.total', 'Total')}</span>\n <span className=\"tabular-nums\">{minutesToHours(totalMinutes)} h</span>\n </div>\n </div>\n )}\n </div>\n )\n}\n\nexport default HoursByProjectWidget\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -10,6 +10,8 @@ import { useGuardedMutation } from "@open-mercato/ui/backend/injection/useGuarde
|
|
|
10
10
|
import { startTimerEntry } from "../../../lib/timesheets-ui/startTimer.js";
|
|
11
11
|
import { resolveTimerActionError } from "../../../lib/timesheets-ui/timerErrors.js";
|
|
12
12
|
import { DEFAULT_SETTINGS, hydrateSettings } from "./config.js";
|
|
13
|
+
import { createLogger } from "@open-mercato/shared/lib/logger";
|
|
14
|
+
const logger = createLogger("staff");
|
|
13
15
|
const TIMER_WIDGET_MUTATION_CONTEXT_ID = "staff-timesheets-time-reporting-widget";
|
|
14
16
|
function formatElapsed(startedAt) {
|
|
15
17
|
const elapsed = Math.max(0, Date.now() - new Date(startedAt).getTime());
|
|
@@ -80,7 +82,7 @@ const TimeReportingWidget = ({
|
|
|
80
82
|
setProjects([]);
|
|
81
83
|
}
|
|
82
84
|
} catch (err) {
|
|
83
|
-
|
|
85
|
+
logger.error("staff.timesheets.timeReporting.load", { err });
|
|
84
86
|
setError(t("staff.timesheets.widgets.timeReporting.error", "Failed to load timer state"));
|
|
85
87
|
} finally {
|
|
86
88
|
setLoading(false);
|
|
@@ -132,7 +134,7 @@ const TimeReportingWidget = ({
|
|
|
132
134
|
onSettingsChange({ ...hydrated, lastProjectId: selectedProjectId });
|
|
133
135
|
await refreshActiveTimer();
|
|
134
136
|
} catch (err) {
|
|
135
|
-
|
|
137
|
+
logger.error("staff.timesheets.timeReporting.start", { err });
|
|
136
138
|
setError(resolveTimerActionError(err, t("staff.timesheets.widgets.timeReporting.startError", "Failed to start timer")));
|
|
137
139
|
} finally {
|
|
138
140
|
setActionLoading(false);
|
|
@@ -161,7 +163,7 @@ const TimeReportingWidget = ({
|
|
|
161
163
|
});
|
|
162
164
|
await refreshActiveTimer();
|
|
163
165
|
} catch (err) {
|
|
164
|
-
|
|
166
|
+
logger.error("staff.timesheets.timeReporting.stop", { err });
|
|
165
167
|
setError(resolveTimerActionError(err, t("staff.timesheets.widgets.timeReporting.stopError", "Failed to stop timer")));
|
|
166
168
|
} finally {
|
|
167
169
|
setActionLoading(false);
|