@open-mercato/core 0.6.6-develop.6317.1.b3be10ab84 → 0.6.6-develop.6331.1.a33b8e99b7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -1
- package/dist/modules/attachments/components/AttachmentPartitionSettings.js +3 -0
- package/dist/modules/attachments/components/AttachmentPartitionSettings.js.map +2 -2
- package/dist/modules/auth/api/roles/acl/route.js +2 -2
- package/dist/modules/auth/api/roles/acl/route.js.map +2 -2
- package/dist/modules/auth/api/users/acl/route.js +2 -2
- package/dist/modules/auth/api/users/acl/route.js.map +2 -2
- package/dist/modules/auth/backend/roles/[id]/edit/page.js +12 -0
- package/dist/modules/auth/backend/roles/[id]/edit/page.js.map +2 -2
- package/dist/modules/auth/backend/users/[id]/edit/page.js +12 -0
- package/dist/modules/auth/backend/users/[id]/edit/page.js.map +2 -2
- package/dist/modules/auth/data/entities.js +2 -2
- package/dist/modules/auth/data/entities.js.map +2 -2
- package/dist/modules/business_rules/api/rules/route.js +3 -3
- package/dist/modules/business_rules/api/rules/route.js.map +2 -2
- package/dist/modules/business_rules/api/sets/route.js +3 -3
- package/dist/modules/business_rules/api/sets/route.js.map +2 -2
- package/dist/modules/business_rules/backend/rules/[id]/page.js +12 -1
- package/dist/modules/business_rules/backend/rules/[id]/page.js.map +2 -2
- package/dist/modules/business_rules/backend/sets/[id]/page.js +12 -1
- package/dist/modules/business_rules/backend/sets/[id]/page.js.map +2 -2
- package/dist/modules/catalog/api/product-media/route.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/categories/[id]/edit/page.js +12 -0
- package/dist/modules/catalog/backend/catalog/categories/[id]/edit/page.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/[id]/page.js +15 -0
- 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 +12 -1
- package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js.map +2 -2
- package/dist/modules/catalog/components/PriceKindSettings.js +13 -3
- package/dist/modules/catalog/components/PriceKindSettings.js.map +2 -2
- package/dist/modules/catalog/lib/bulkDelete.js.map +2 -2
- package/dist/modules/currencies/backend/currencies/[id]/page.js +15 -3
- package/dist/modules/currencies/backend/currencies/[id]/page.js.map +2 -2
- package/dist/modules/currencies/backend/currencies/page.js +2 -1
- package/dist/modules/currencies/backend/currencies/page.js.map +2 -2
- package/dist/modules/currencies/backend/exchange-rates/[id]/page.js +12 -1
- package/dist/modules/currencies/backend/exchange-rates/[id]/page.js.map +2 -2
- package/dist/modules/currencies/backend/exchange-rates/page.js +3 -2
- package/dist/modules/currencies/backend/exchange-rates/page.js.map +2 -2
- package/dist/modules/customer_accounts/api/admin/roles/[id].js +3 -3
- package/dist/modules/customer_accounts/api/admin/roles/[id].js.map +2 -2
- package/dist/modules/customer_accounts/api/admin/users/[id].js +3 -3
- package/dist/modules/customer_accounts/api/admin/users/[id].js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.js +7 -12
- package/dist/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js +5 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js.map +2 -2
- package/dist/modules/customer_accounts/widgets/injection/account-status/widget.client.js +2 -1
- package/dist/modules/customer_accounts/widgets/injection/account-status/widget.client.js.map +2 -2
- package/dist/modules/customer_accounts/widgets/injection/company-users/widget.client.js +2 -1
- package/dist/modules/customer_accounts/widgets/injection/company-users/widget.client.js.map +2 -2
- package/dist/modules/customers/api/addresses/route.js +4 -2
- package/dist/modules/customers/api/addresses/route.js.map +2 -2
- package/dist/modules/customers/api/tags/route.js +8 -3
- package/dist/modules/customers/api/tags/route.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +13 -2
- package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.js +24 -9
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealClosure.js +53 -23
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealClosure.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealPipeline.js +13 -3
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealPipeline.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/[id]/page.js +19 -2
- package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +13 -2
- package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +2 -2
- package/dist/modules/customers/commands/interactions.js +5 -5
- package/dist/modules/customers/commands/interactions.js.map +2 -2
- package/dist/modules/customers/commands/pipeline-stages.js +24 -2
- package/dist/modules/customers/commands/pipeline-stages.js.map +2 -2
- package/dist/modules/customers/commands/pipelines.js +24 -2
- package/dist/modules/customers/commands/pipelines.js.map +2 -2
- package/dist/modules/customers/components/detail/AddressesSection.js +46 -29
- package/dist/modules/customers/components/detail/AddressesSection.js.map +2 -2
- package/dist/modules/customers/components/detail/DealForm.js +5 -1
- package/dist/modules/customers/components/detail/DealForm.js.map +2 -2
- package/dist/modules/customers/components/detail/EntityTagsDialog.js +76 -67
- package/dist/modules/customers/components/detail/EntityTagsDialog.js.map +3 -3
- package/dist/modules/customers/components/detail/notesAdapter.js +25 -18
- package/dist/modules/customers/components/detail/notesAdapter.js.map +2 -2
- package/dist/modules/dashboards/components/WidgetVisibilityEditor.js +4 -3
- package/dist/modules/dashboards/components/WidgetVisibilityEditor.js.map +2 -2
- package/dist/modules/data_sync/api/runs.js +1 -0
- package/dist/modules/data_sync/api/runs.js.map +2 -2
- package/dist/modules/data_sync/api/schedules/[id]/route.js +38 -19
- package/dist/modules/data_sync/api/schedules/[id]/route.js.map +2 -2
- package/dist/modules/data_sync/api/schedules/route.js +1 -1
- package/dist/modules/data_sync/api/schedules/route.js.map +2 -2
- package/dist/modules/data_sync/backend/data-sync/page.js +35 -16
- package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
- package/dist/modules/data_sync/data/validators.js +1 -0
- package/dist/modules/data_sync/data/validators.js.map +2 -2
- package/dist/modules/data_sync/lib/sync-run-service.js +20 -0
- package/dist/modules/data_sync/lib/sync-run-service.js.map +2 -2
- package/dist/modules/data_sync/lib/sync-schedule-service.js +19 -5
- package/dist/modules/data_sync/lib/sync-schedule-service.js.map +2 -2
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js +3 -3
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js.map +2 -2
- package/dist/modules/dictionaries/api/[dictionaryId]/route.js +3 -3
- package/dist/modules/dictionaries/api/[dictionaryId]/route.js.map +2 -2
- package/dist/modules/dictionaries/components/DictionariesManager.js +12 -1
- package/dist/modules/dictionaries/components/DictionariesManager.js.map +2 -2
- package/dist/modules/dictionaries/components/DictionaryEntriesEditor.js.map +2 -2
- package/dist/modules/directory/backend/directory/organizations/[id]/edit/page.js +12 -0
- package/dist/modules/directory/backend/directory/organizations/[id]/edit/page.js.map +2 -2
- package/dist/modules/directory/backend/directory/tenants/[id]/edit/page.js +12 -0
- package/dist/modules/directory/backend/directory/tenants/[id]/edit/page.js.map +2 -2
- package/dist/modules/entities/api/entities.js +2 -2
- package/dist/modules/entities/api/entities.js.map +2 -2
- package/dist/modules/entities/api/records.js +18 -6
- package/dist/modules/entities/api/records.js.map +2 -2
- package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js +17 -10
- package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js.map +2 -2
- package/dist/modules/feature_toggles/api/overrides/route.js +2 -2
- package/dist/modules/feature_toggles/api/overrides/route.js.map +2 -2
- package/dist/modules/feature_toggles/backend/feature-toggles/global/[id]/edit/page.js.map +2 -2
- package/dist/modules/feature_toggles/data/entities.js +1 -1
- package/dist/modules/feature_toggles/data/entities.js.map +2 -2
- package/dist/modules/feature_toggles/data/validators.js +2 -1
- package/dist/modules/feature_toggles/data/validators.js.map +2 -2
- package/dist/modules/feature_toggles/lib/queries.js +2 -1
- package/dist/modules/feature_toggles/lib/queries.js.map +2 -2
- package/dist/modules/inbox_ops/api/settings/route.js +2 -2
- package/dist/modules/inbox_ops/api/settings/route.js.map +2 -2
- package/dist/modules/messages/api/unread-count/route.js +32 -0
- package/dist/modules/messages/api/unread-count/route.js.map +2 -2
- package/dist/modules/query_index/components/QueryIndexesTable.js +13 -5
- package/dist/modules/query_index/components/QueryIndexesTable.js.map +2 -2
- package/dist/modules/resources/backend/resources/resource-types/[id]/edit/page.js +12 -1
- package/dist/modules/resources/backend/resources/resource-types/[id]/edit/page.js.map +2 -2
- package/dist/modules/resources/backend/resources/resources/[id]/page.js +12 -1
- package/dist/modules/resources/backend/resources/resources/[id]/page.js.map +2 -2
- package/dist/modules/resources/components/detail/notesAdapter.js +25 -18
- package/dist/modules/resources/components/detail/notesAdapter.js.map +2 -2
- package/dist/modules/sales/backend/sales/documents/[id]/page.js +14 -1
- package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
- package/dist/modules/sales/commands/documents.js +11 -10
- package/dist/modules/sales/commands/documents.js.map +2 -2
- package/dist/modules/sales/commands/payments.js +6 -1
- package/dist/modules/sales/commands/payments.js.map +2 -2
- package/dist/modules/sales/commands/returns.js +3 -3
- package/dist/modules/sales/commands/returns.js.map +2 -2
- package/dist/modules/sales/commands/shared.js +3 -3
- package/dist/modules/sales/commands/shared.js.map +2 -2
- package/dist/modules/sales/commands/shipments.js +6 -1
- package/dist/modules/sales/commands/shipments.js.map +2 -2
- package/dist/modules/sales/components/documents/PaymentDialog.js +6 -3
- package/dist/modules/sales/components/documents/PaymentDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/PaymentsSection.js +7 -3
- package/dist/modules/sales/components/documents/PaymentsSection.js.map +2 -2
- package/dist/modules/sales/components/documents/ShipmentDialog.js +6 -3
- package/dist/modules/sales/components/documents/ShipmentDialog.js.map +2 -2
- package/dist/modules/sales/components/documents/ShipmentsSection.js +7 -3
- package/dist/modules/sales/components/documents/ShipmentsSection.js.map +2 -2
- package/dist/modules/sales/di.js +39 -3
- package/dist/modules/sales/di.js.map +2 -2
- package/dist/modules/sales/setup.js +2 -0
- package/dist/modules/sales/setup.js.map +2 -2
- package/dist/modules/shipping_carriers/i18n/en.js +11 -1
- package/dist/modules/shipping_carriers/i18n/en.js.map +2 -2
- package/dist/modules/shipping_carriers/i18n/pl.js +11 -1
- package/dist/modules/shipping_carriers/i18n/pl.js.map +2 -2
- package/dist/modules/shipping_carriers/widgets/injection/tracking-status-badge/widget.client.js +25 -0
- package/dist/modules/shipping_carriers/widgets/injection/tracking-status-badge/widget.client.js.map +7 -0
- package/dist/modules/shipping_carriers/widgets/injection/tracking-status-badge/widget.js +3 -17
- package/dist/modules/shipping_carriers/widgets/injection/tracking-status-badge/widget.js.map +2 -2
- package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js +12 -1
- package/dist/modules/staff/backend/staff/leave-requests/[id]/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-members/[id]/page.js +12 -1
- package/dist/modules/staff/backend/staff/team-members/[id]/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-roles/[id]/edit/page.js +12 -1
- package/dist/modules/staff/backend/staff/team-roles/[id]/edit/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +12 -1
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
- package/dist/modules/staff/commands/job-histories.js +3 -3
- package/dist/modules/staff/commands/job-histories.js.map +2 -2
- package/dist/modules/staff/components/detail/addressesAdapter.js +33 -24
- package/dist/modules/staff/components/detail/addressesAdapter.js.map +2 -2
- package/dist/modules/staff/components/detail/notesAdapter.js +25 -18
- package/dist/modules/staff/components/detail/notesAdapter.js.map +2 -2
- package/dist/modules/translations/api/[entityType]/[entityId]/route.js +37 -0
- package/dist/modules/translations/api/[entityType]/[entityId]/route.js.map +2 -2
- package/dist/modules/translations/components/TranslationManager.js +7 -1
- package/dist/modules/translations/components/TranslationManager.js.map +2 -2
- package/dist/modules/translations/widgets/injection/translation-manager/widget.client.js +19 -14
- package/dist/modules/translations/widgets/injection/translation-manager/widget.client.js.map +2 -2
- package/dist/modules/workflows/api/definitions/[id]/route.js +3 -3
- package/dist/modules/workflows/api/definitions/[id]/route.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/[id]/page.js +12 -1
- package/dist/modules/workflows/backend/definitions/[id]/page.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/visual-editor/page.js +11 -1
- package/dist/modules/workflows/backend/definitions/visual-editor/page.js.map +2 -2
- package/package.json +7 -7
- package/src/modules/attachments/components/AttachmentPartitionSettings.tsx +3 -0
- package/src/modules/auth/api/roles/acl/route.ts +2 -2
- package/src/modules/auth/api/users/acl/route.ts +2 -2
- package/src/modules/auth/backend/roles/[id]/edit/page.tsx +17 -0
- package/src/modules/auth/backend/users/[id]/edit/page.tsx +17 -0
- package/src/modules/auth/data/entities.ts +2 -2
- package/src/modules/business_rules/api/rules/route.ts +3 -3
- package/src/modules/business_rules/api/sets/route.ts +3 -3
- package/src/modules/business_rules/backend/rules/[id]/page.tsx +17 -1
- package/src/modules/business_rules/backend/sets/[id]/page.tsx +18 -1
- package/src/modules/catalog/api/product-media/route.ts +4 -0
- package/src/modules/catalog/backend/catalog/categories/[id]/edit/page.tsx +17 -0
- package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +21 -0
- package/src/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.tsx +16 -1
- package/src/modules/catalog/components/PriceKindSettings.tsx +15 -7
- package/src/modules/catalog/lib/bulkDelete.ts +6 -0
- package/src/modules/currencies/backend/currencies/[id]/page.tsx +20 -3
- package/src/modules/currencies/backend/currencies/page.tsx +2 -1
- package/src/modules/currencies/backend/exchange-rates/[id]/page.tsx +17 -1
- package/src/modules/currencies/backend/exchange-rates/page.tsx +3 -2
- package/src/modules/customer_accounts/api/admin/roles/[id].ts +3 -3
- package/src/modules/customer_accounts/api/admin/users/[id].ts +3 -3
- package/src/modules/customer_accounts/backend/customer_accounts/roles/[id]/page.tsx +7 -10
- package/src/modules/customer_accounts/backend/customer_accounts/users/page.tsx +6 -7
- package/src/modules/customer_accounts/widgets/injection/account-status/widget.client.tsx +3 -2
- package/src/modules/customer_accounts/widgets/injection/company-users/widget.client.tsx +3 -2
- package/src/modules/customers/api/addresses/route.ts +2 -0
- package/src/modules/customers/api/tags/route.ts +6 -1
- package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +19 -2
- package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.ts +29 -8
- package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealClosure.ts +47 -20
- package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealPipeline.ts +13 -3
- package/src/modules/customers/backend/customers/deals/[id]/page.tsx +21 -1
- package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +18 -2
- package/src/modules/customers/commands/interactions.ts +5 -5
- package/src/modules/customers/commands/pipeline-stages.ts +26 -2
- package/src/modules/customers/commands/pipelines.ts +26 -2
- package/src/modules/customers/components/detail/AddressesSection.tsx +50 -28
- package/src/modules/customers/components/detail/DealForm.tsx +12 -0
- package/src/modules/customers/components/detail/EntityTagsDialog.tsx +89 -71
- package/src/modules/customers/components/detail/notesAdapter.ts +29 -18
- package/src/modules/customers/i18n/de.json +2 -0
- package/src/modules/customers/i18n/en.json +2 -0
- package/src/modules/customers/i18n/es.json +2 -0
- package/src/modules/customers/i18n/pl.json +2 -0
- package/src/modules/dashboards/components/WidgetVisibilityEditor.tsx +6 -3
- package/src/modules/data_sync/api/runs.ts +1 -0
- package/src/modules/data_sync/api/schedules/[id]/route.ts +38 -20
- package/src/modules/data_sync/api/schedules/route.ts +1 -1
- package/src/modules/data_sync/backend/data-sync/page.tsx +35 -16
- package/src/modules/data_sync/data/validators.ts +1 -0
- package/src/modules/data_sync/i18n/de.json +1 -0
- package/src/modules/data_sync/i18n/en.json +1 -0
- package/src/modules/data_sync/i18n/es.json +1 -0
- package/src/modules/data_sync/i18n/pl.json +1 -0
- package/src/modules/data_sync/lib/sync-run-service.ts +23 -0
- package/src/modules/data_sync/lib/sync-schedule-service.ts +30 -5
- package/src/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.ts +3 -3
- package/src/modules/dictionaries/api/[dictionaryId]/route.ts +3 -3
- package/src/modules/dictionaries/components/DictionariesManager.tsx +21 -1
- package/src/modules/dictionaries/components/DictionaryEntriesEditor.tsx +2 -0
- package/src/modules/directory/backend/directory/organizations/[id]/edit/page.tsx +17 -0
- package/src/modules/directory/backend/directory/tenants/[id]/edit/page.tsx +17 -0
- package/src/modules/entities/api/entities.ts +2 -2
- package/src/modules/entities/api/records.ts +24 -6
- package/src/modules/entities/backend/entities/user/[entityId]/records/page.tsx +25 -12
- package/src/modules/feature_toggles/api/overrides/route.ts +2 -2
- package/src/modules/feature_toggles/backend/feature-toggles/global/[id]/edit/page.tsx +12 -0
- package/src/modules/feature_toggles/data/entities.ts +1 -1
- package/src/modules/feature_toggles/data/validators.ts +1 -0
- package/src/modules/feature_toggles/lib/queries.ts +1 -0
- package/src/modules/inbox_ops/api/settings/route.ts +2 -2
- package/src/modules/messages/api/unread-count/route.ts +40 -0
- package/src/modules/query_index/components/QueryIndexesTable.tsx +17 -15
- package/src/modules/resources/backend/resources/resource-types/[id]/edit/page.tsx +17 -1
- package/src/modules/resources/backend/resources/resources/[id]/page.tsx +17 -1
- package/src/modules/resources/components/detail/notesAdapter.ts +29 -18
- package/src/modules/sales/backend/sales/documents/[id]/page.tsx +17 -1
- package/src/modules/sales/commands/documents.ts +11 -10
- package/src/modules/sales/commands/payments.ts +11 -0
- package/src/modules/sales/commands/returns.ts +3 -3
- package/src/modules/sales/commands/shared.ts +10 -4
- package/src/modules/sales/commands/shipments.ts +14 -0
- package/src/modules/sales/components/documents/PaymentDialog.tsx +7 -3
- package/src/modules/sales/components/documents/PaymentsSection.tsx +8 -3
- package/src/modules/sales/components/documents/ShipmentDialog.tsx +7 -3
- package/src/modules/sales/components/documents/ShipmentsSection.tsx +8 -3
- package/src/modules/sales/di.ts +68 -9
- package/src/modules/sales/setup.ts +2 -0
- package/src/modules/shipping_carriers/i18n/de.json +11 -1
- package/src/modules/shipping_carriers/i18n/en.json +11 -1
- package/src/modules/shipping_carriers/i18n/en.ts +10 -0
- package/src/modules/shipping_carriers/i18n/es.json +11 -1
- package/src/modules/shipping_carriers/i18n/pl.json +11 -1
- package/src/modules/shipping_carriers/i18n/pl.ts +10 -0
- package/src/modules/shipping_carriers/widgets/injection/tracking-status-badge/widget.client.tsx +35 -0
- package/src/modules/shipping_carriers/widgets/injection/tracking-status-badge/widget.tsx +3 -22
- package/src/modules/staff/backend/staff/leave-requests/[id]/page.tsx +17 -1
- package/src/modules/staff/backend/staff/team-members/[id]/page.tsx +17 -1
- package/src/modules/staff/backend/staff/team-roles/[id]/edit/page.tsx +17 -1
- package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +17 -1
- package/src/modules/staff/commands/job-histories.ts +3 -3
- package/src/modules/staff/components/detail/addressesAdapter.ts +40 -23
- package/src/modules/staff/components/detail/notesAdapter.ts +28 -18
- package/src/modules/translations/api/[entityType]/[entityId]/route.ts +74 -0
- package/src/modules/translations/components/TranslationManager.tsx +14 -1
- package/src/modules/translations/widgets/injection/translation-manager/widget.client.tsx +30 -13
- package/src/modules/workflows/api/definitions/[id]/route.ts +3 -3
- package/src/modules/workflows/backend/definitions/[id]/page.tsx +18 -1
- package/src/modules/workflows/backend/definitions/visual-editor/page.tsx +19 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../../../src/modules/staff/backend/staff/teams/%5Bid%5D/edit/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 { ErrorMessage, RecordNotFoundState } from '@open-mercato/ui/backend/detail'\nimport { readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { updateCrud, deleteCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { DataTable, withDataTableNamespaces } from '@open-mercato/ui/backend/DataTable'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { BooleanIcon } from '@open-mercato/ui/backend/ValueIcons'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { TeamForm, type TeamFormValues, buildTeamPayload } from '@open-mercato/core/modules/staff/components/TeamForm'\nimport { SendObjectMessageDialog } from '@open-mercato/ui/backend/messages'\nimport { extractCustomFieldEntries } from '@open-mercato/shared/lib/crud/custom-fields-client'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { Plus } from 'lucide-react'\nimport { formatDateTime } from '@open-mercato/shared/lib/time'\n\nconst TEAM_MEMBERS_PAGE_SIZE = 50\n\ntype TeamRecord = {\n id: string\n name: string\n description?: string | null\n isActive?: boolean\n is_active?: boolean\n updatedAt?: string | null\n updated_at?: string | null\n} & Record<string, unknown>\n\ntype TeamResponse = {\n items?: TeamRecord[]\n}\n\ntype TeamMemberRow = {\n id: string\n displayName: string\n description: string | null\n userEmail: string | null\n roleNames: string[]\n tags: string[]\n isActive: boolean\n updatedAt: string | null\n teamId: string | null\n}\n\ntype TeamMembersResponse = {\n items?: Array<Record<string, unknown>>\n total?: number\n totalPages?: number\n}\n\nexport default function StaffTeamEditPage({ params }: { params?: { id?: string } }) {\n const teamId = params?.id\n const t = useT()\n const router = useRouter()\n const searchParams = useSearchParams()\n const scopeVersion = useOrganizationScopeVersion()\n const [initialValues, setInitialValues] = React.useState<TeamFormValues | null>(null)\n const [error, setError] = React.useState<string | null>(null)\n const [isNotFound, setIsNotFound] = React.useState(false)\n const [activeTab, setActiveTab] = React.useState<'details' | 'members'>('details')\n const [memberRows, setMemberRows] = React.useState<TeamMemberRow[]>([])\n const [memberPage, setMemberPage] = React.useState(1)\n const [memberTotal, setMemberTotal] = React.useState(0)\n const [memberTotalPages, setMemberTotalPages] = React.useState(1)\n const [memberSorting, setMemberSorting] = React.useState<SortingState>([{ id: 'displayName', desc: false }])\n const [memberSearch, setMemberSearch] = React.useState('')\n const [membersLoading, setMembersLoading] = React.useState(false)\n const [memberReloadToken, setMemberReloadToken] = React.useState(0)\n\n const memberLabels = React.useMemo(() => ({\n title: t('staff.teams.tabs.members', 'Team members'),\n description: t('staff.teamMembers.page.description', 'Manage employees and their team assignments.'),\n table: {\n name: t('staff.teamMembers.table.name', 'Name'),\n user: t('staff.teamMembers.table.user', 'User'),\n roles: t('staff.teamMembers.table.roles', 'Roles'),\n tags: t('staff.teamMembers.table.tags', 'Tags'),\n active: t('staff.teamMembers.table.active', 'Active'),\n updatedAt: t('staff.teamMembers.table.updatedAt', 'Updated'),\n empty: t('staff.teamMembers.table.empty', 'No team members yet.'),\n search: t('staff.teamMembers.table.search', 'Search team members...'),\n },\n actions: {\n add: t('staff.teamMembers.actions.add', 'Add team member'),\n edit: t('staff.teamMembers.actions.edit', 'Edit'),\n unassign: t('staff.teamMembers.actions.unassign', 'Unassign'),\n refresh: t('staff.teamMembers.actions.refresh', 'Refresh'),\n },\n messages: {\n unassigned: t('staff.teamMembers.messages.unassigned', 'Team member unassigned.'),\n },\n errors: {\n load: t('staff.teamMembers.errors.load', 'Failed to load team members.'),\n unassign: t('staff.teamMembers.errors.unassign', 'Failed to unassign team member.'),\n },\n tabs: {\n details: t('staff.teams.tabs.details', 'Details'),\n members: t('staff.teams.tabs.members', 'Team members'),\n label: t('staff.teams.tabs.label', 'Team sections'),\n },\n }), [t])\n\n const memberColumns = React.useMemo<ColumnDef<TeamMemberRow>[]>(() => [\n {\n accessorKey: 'displayName',\n header: memberLabels.table.name,\n meta: { priority: 1, sticky: true },\n cell: ({ row }) => (\n <div className=\"flex flex-col\">\n <span className=\"font-medium\">{row.original.displayName}</span>\n {row.original.description ? (\n <span className=\"text-xs text-muted-foreground line-clamp-2\">{row.original.description}</span>\n ) : null}\n </div>\n ),\n },\n {\n accessorKey: 'userEmail',\n header: memberLabels.table.user,\n meta: { priority: 2 },\n cell: ({ row }) => row.original.userEmail\n ? <span className=\"text-sm\">{row.original.userEmail}</span>\n : <span className=\"text-xs text-muted-foreground\">-</span>,\n },\n {\n accessorKey: 'roleNames',\n header: memberLabels.table.roles,\n meta: { priority: 3 },\n cell: ({ row }) => row.original.roleNames.length\n ? <span className=\"text-sm\">{row.original.roleNames.join(', ')}</span>\n : <span className=\"text-xs text-muted-foreground\">-</span>,\n },\n {\n accessorKey: 'tags',\n header: memberLabels.table.tags,\n meta: { priority: 4 },\n cell: ({ row }) => row.original.tags.length\n ? <span className=\"text-xs text-muted-foreground\">{row.original.tags.join(', ')}</span>\n : <span className=\"text-xs text-muted-foreground\">-</span>,\n },\n {\n accessorKey: 'isActive',\n header: memberLabels.table.active,\n meta: { priority: 5 },\n cell: ({ row }) => <BooleanIcon value={row.original.isActive} />,\n },\n {\n accessorKey: 'updatedAt',\n header: memberLabels.table.updatedAt,\n meta: { priority: 6 },\n cell: ({ row }) => row.original.updatedAt\n ? <span className=\"text-xs text-muted-foreground\">{formatDateTime(row.original.updatedAt)}</span>\n : <span className=\"text-xs text-muted-foreground\">-</span>,\n },\n ], [\n memberLabels.table.active,\n memberLabels.table.name,\n memberLabels.table.roles,\n memberLabels.table.tags,\n memberLabels.table.updatedAt,\n memberLabels.table.user,\n ])\n\n React.useEffect(() => {\n if (!teamId) return\n const teamIdValue = teamId\n let cancelled = false\n async function loadTeam() {\n if (!cancelled) {\n setError(null)\n setIsNotFound(false)\n }\n try {\n const params = new URLSearchParams({ page: '1', pageSize: '1', ids: teamIdValue })\n const payload = await readApiResultOrThrow<TeamResponse>(\n `/api/staff/teams?${params.toString()}`,\n undefined,\n { errorMessage: t('staff.teams.errors.load', 'Failed to load team.') },\n )\n const record = Array.isArray(payload.items) ? payload.items[0] : null\n if (!record) {\n if (!cancelled) setIsNotFound(true)\n return\n }\n const customFields = extractCustomFieldEntries(record)\n const isActive = typeof record.isActive === 'boolean'\n ? record.isActive\n : typeof record.is_active === 'boolean'\n ? record.is_active\n : true\n if (!cancelled) {\n setInitialValues({\n id: record.id,\n name: record.name ?? '',\n description: record.description ?? '',\n isActive,\n updatedAt: typeof record.updatedAt === 'string'\n ? record.updatedAt\n : typeof record.updated_at === 'string'\n ? record.updated_at\n : null,\n ...customFields,\n })\n }\n } catch (err) {\n if (!cancelled) {\n if ((err as { status?: number }).status === 404) {\n setIsNotFound(true)\n } else {\n const message = err instanceof Error ? err.message : t('staff.teams.errors.load', 'Failed to load team.')\n setError(message)\n }\n }\n }\n }\n loadTeam()\n return () => { cancelled = true }\n }, [teamId, t])\n\n React.useEffect(() => {\n if (!searchParams) return\n const tabParam = searchParams.get('tab')\n if (tabParam === 'members') {\n setActiveTab('members')\n }\n }, [searchParams])\n\n const loadTeamMembers = React.useCallback(async () => {\n if (!teamId) return\n setMembersLoading(true)\n try {\n const params = new URLSearchParams({\n page: String(memberPage),\n pageSize: String(TEAM_MEMBERS_PAGE_SIZE),\n teamId,\n })\n const sort = memberSorting[0]\n if (sort?.id) {\n params.set('sortField', sort.id)\n params.set('sortDir', sort.desc ? 'desc' : 'asc')\n }\n if (memberSearch.trim()) params.set('search', memberSearch.trim())\n const payload = await readApiResultOrThrow<TeamMembersResponse>(\n `/api/staff/team-members?${params.toString()}`,\n undefined,\n { errorMessage: memberLabels.errors.load, fallback: { items: [], total: 0, totalPages: 1 } },\n )\n const items = Array.isArray(payload.items) ? payload.items : []\n setMemberRows(items.map(mapApiTeamMember))\n setMemberTotal(typeof payload.total === 'number' ? payload.total : items.length)\n setMemberTotalPages(\n typeof payload.totalPages === 'number'\n ? payload.totalPages\n : Math.max(1, Math.ceil(items.length / TEAM_MEMBERS_PAGE_SIZE)),\n )\n } catch (error) {\n console.error('staff.teams.team-members.list', error)\n flash(memberLabels.errors.load, 'error')\n } finally {\n setMembersLoading(false)\n }\n }, [memberLabels.errors.load, memberPage, memberSearch, memberSorting, teamId])\n\n React.useEffect(() => {\n if (activeTab !== 'members') return\n void loadTeamMembers()\n }, [activeTab, loadTeamMembers, memberReloadToken, scopeVersion])\n\n const handleMemberSearchChange = React.useCallback((value: string) => {\n setMemberSearch(value)\n setMemberPage(1)\n }, [])\n\n const handleMemberRefresh = React.useCallback(() => {\n setMemberReloadToken((token) => token + 1)\n }, [])\n\n const handleUnassignMember = React.useCallback(async (entry: TeamMemberRow) => {\n if (!teamId || entry.teamId !== teamId) return\n try {\n const headers = buildOptimisticLockHeader(entry.updatedAt)\n await withScopedApiRequestHeaders(headers, () => (\n updateCrud('staff/team-members', { id: entry.id, teamId: null }, { errorMessage: memberLabels.errors.unassign })\n ))\n flash(memberLabels.messages.unassigned, 'success')\n handleMemberRefresh()\n } catch (error) {\n console.error('staff.teams.team-members.unassign', error)\n flash(memberLabels.errors.unassign, 'error')\n }\n }, [handleMemberRefresh, memberLabels.errors.unassign, memberLabels.messages.unassigned, teamId])\n\n const handleSubmit = React.useCallback(async (values: TeamFormValues) => {\n if (!teamId) return\n const payload = buildTeamPayload(values, { id: teamId })\n await updateCrud('staff/teams', payload, {\n errorMessage: t('staff.teams.errors.save', 'Failed to save team.'),\n })\n flash(t('staff.teams.messages.saved', 'Team saved.'), 'success')\n }, [teamId, t])\n\n const handleDelete = React.useCallback(async () => {\n if (!teamId) return\n await deleteCrud('staff/teams', teamId, {\n errorMessage: t('staff.teams.errors.delete', 'Failed to delete team.'),\n })\n router.push('/backend/staff/teams')\n }, [teamId, router, t])\n\n if (isNotFound) {\n return (\n <Page>\n <PageBody>\n <RecordNotFoundState\n label={t('staff.teams.errors.notFound', 'Team not found.')}\n backHref=\"/backend/staff/teams\"\n backLabel={t('staff.teams.actions.backToList', 'Back to teams')}\n />\n </PageBody>\n </Page>\n )\n }\n\n if (error && !initialValues) {\n return (\n <Page>\n <PageBody>\n <ErrorMessage label={error} />\n </PageBody>\n </Page>\n )\n }\n\n return (\n <Page>\n <PageBody>\n <div className=\"space-y-6\">\n <div className=\"border-b\">\n <nav className=\"flex flex-wrap items-center gap-5 text-sm\" aria-label={memberLabels.tabs.label}>\n {[\n { id: 'details', label: memberLabels.tabs.details },\n { id: 'members', label: memberLabels.tabs.members },\n ].map((tab) => (\n <button\n key={tab.id}\n type=\"button\"\n role=\"tab\"\n aria-selected={activeTab === tab.id}\n onClick={() => setActiveTab(tab.id as 'details' | 'members')}\n className={`relative -mb-px border-b-2 px-0 py-2 text-sm font-medium transition-colors ${\n activeTab === tab.id\n ? 'border-accent-indigo text-foreground'\n : 'border-transparent text-muted-foreground hover:text-foreground'\n }`}\n >\n {tab.label}\n </button>\n ))}\n </nav>\n </div>\n\n {activeTab === 'details' ? (\n <TeamForm\n title={t('staff.teams.form.editTitle', 'Edit team')}\n backHref=\"/backend/staff/teams\"\n cancelHref=\"/backend/staff/teams\"\n initialValues={initialValues ?? { name: '', description: '', isActive: true }}\n onSubmit={handleSubmit}\n onDelete={handleDelete}\n isLoading={!initialValues}\n loadingMessage={t('staff.teams.form.loading', 'Loading team...')}\n extraActions={teamId ? (\n <SendObjectMessageDialog\n object={{\n entityModule: 'staff',\n entityType: 'team',\n entityId: teamId,\n previewData: { title: initialValues?.name ?? ''},\n }}\n viewHref={`/backend/staff/teams/${teamId}/edit`}\n />\n ) : undefined}\n />\n ) : (\n <DataTable<TeamMemberRow>\n title={memberLabels.title}\n data={memberRows}\n columns={memberColumns}\n isLoading={membersLoading}\n searchValue={memberSearch}\n onSearchChange={handleMemberSearchChange}\n searchPlaceholder={memberLabels.table.search}\n emptyState={<p className=\"py-8 text-center text-sm text-muted-foreground\">{memberLabels.table.empty}</p>}\n actions={(\n <Button asChild size=\"sm\">\n <Link href={`/backend/staff/team-members/create?teamId=${encodeURIComponent(teamId ?? '')}`}>\n <Plus className=\"mr-2 h-4 w-4\" aria-hidden />\n {memberLabels.actions.add}\n </Link>\n </Button>\n )}\n refreshButton={{\n label: memberLabels.actions.refresh,\n onRefresh: handleMemberRefresh,\n isRefreshing: membersLoading,\n }}\n sortable\n sorting={memberSorting}\n onSortingChange={setMemberSorting}\n pagination={{\n page: memberPage,\n pageSize: TEAM_MEMBERS_PAGE_SIZE,\n total: memberTotal,\n totalPages: memberTotalPages,\n onPageChange: setMemberPage,\n }}\n rowActions={(row) => (\n <RowActions\n items={[\n { id: 'edit', label: memberLabels.actions.edit, onSelect: () => { router.push(`/backend/staff/team-members/${row.id}`) } },\n { id: 'unassign', label: memberLabels.actions.unassign, onSelect: () => { void handleUnassignMember(row) } },\n ]}\n />\n )}\n />\n )}\n </div>\n </PageBody>\n </Page>\n )\n}\n\nfunction mapApiTeamMember(item: Record<string, unknown>): TeamMemberRow {\n const id = typeof item.id === 'string' ? item.id : ''\n const displayName = typeof item.displayName === 'string'\n ? item.displayName\n : typeof item.display_name === 'string'\n ? item.display_name\n : id\n const description = typeof item.description === 'string' && item.description.trim().length\n ? item.description.trim()\n : null\n const user = item.user && typeof item.user === 'object' ? item.user as { email?: unknown } : null\n const userEmail = user && typeof user.email === 'string' && user.email.length ? user.email : null\n const roleNames = Array.isArray(item.roleNames) ? item.roleNames.filter((value): value is string => typeof value === 'string') : []\n const tags = Array.isArray(item.tags) ? item.tags.filter((value): value is string => typeof value === 'string') : []\n const updatedAt = typeof item.updatedAt === 'string'\n ? item.updatedAt\n : typeof item.updated_at === 'string'\n ? item.updated_at\n : null\n const isActive = typeof item.isActive === 'boolean'\n ? item.isActive\n : typeof item.is_active === 'boolean'\n ? item.is_active\n : true\n const teamId = typeof item.teamId === 'string'\n ? item.teamId\n : typeof item.team_id === 'string'\n ? item.team_id\n : null\n return withDataTableNamespaces({\n id,\n displayName,\n description,\n userEmail,\n roleNames,\n tags,\n isActive,\n updatedAt,\n teamId,\n }, item)\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { usePathname, useRouter, useSearchParams } from 'next/navigation'\nimport type { ColumnDef, SortingState } from '@tanstack/react-table'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { ErrorMessage, RecordNotFoundState } from '@open-mercato/ui/backend/detail'\nimport { readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { updateCrud, deleteCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { DataTable, withDataTableNamespaces } from '@open-mercato/ui/backend/DataTable'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { BooleanIcon } from '@open-mercato/ui/backend/ValueIcons'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { TeamForm, type TeamFormValues, buildTeamPayload } from '@open-mercato/core/modules/staff/components/TeamForm'\nimport { buildRecordInjectionContext, useSetCurrentRecordInjectionContext } from '@open-mercato/ui/backend/injection/recordContext'\nimport { SendObjectMessageDialog } from '@open-mercato/ui/backend/messages'\nimport { extractCustomFieldEntries } from '@open-mercato/shared/lib/crud/custom-fields-client'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { Plus } from 'lucide-react'\nimport { formatDateTime } from '@open-mercato/shared/lib/time'\n\nconst TEAM_MEMBERS_PAGE_SIZE = 50\n\ntype TeamRecord = {\n id: string\n name: string\n description?: string | null\n isActive?: boolean\n is_active?: boolean\n updatedAt?: string | null\n updated_at?: string | null\n} & Record<string, unknown>\n\ntype TeamResponse = {\n items?: TeamRecord[]\n}\n\ntype TeamMemberRow = {\n id: string\n displayName: string\n description: string | null\n userEmail: string | null\n roleNames: string[]\n tags: string[]\n isActive: boolean\n updatedAt: string | null\n teamId: string | null\n}\n\ntype TeamMembersResponse = {\n items?: Array<Record<string, unknown>>\n total?: number\n totalPages?: number\n}\n\nexport default function StaffTeamEditPage({ params }: { params?: { id?: string } }) {\n const teamId = params?.id\n const t = useT()\n const router = useRouter()\n const pathname = usePathname()\n const searchParams = useSearchParams()\n const scopeVersion = useOrganizationScopeVersion()\n const [initialValues, setInitialValues] = React.useState<TeamFormValues | null>(null)\n const [error, setError] = React.useState<string | null>(null)\n const [isNotFound, setIsNotFound] = React.useState(false)\n const [activeTab, setActiveTab] = React.useState<'details' | 'members'>('details')\n const [memberRows, setMemberRows] = React.useState<TeamMemberRow[]>([])\n const [memberPage, setMemberPage] = React.useState(1)\n const [memberTotal, setMemberTotal] = React.useState(0)\n const [memberTotalPages, setMemberTotalPages] = React.useState(1)\n const [memberSorting, setMemberSorting] = React.useState<SortingState>([{ id: 'displayName', desc: false }])\n const [memberSearch, setMemberSearch] = React.useState('')\n const [membersLoading, setMembersLoading] = React.useState(false)\n const [memberReloadToken, setMemberReloadToken] = React.useState(0)\n\n const memberLabels = React.useMemo(() => ({\n title: t('staff.teams.tabs.members', 'Team members'),\n description: t('staff.teamMembers.page.description', 'Manage employees and their team assignments.'),\n table: {\n name: t('staff.teamMembers.table.name', 'Name'),\n user: t('staff.teamMembers.table.user', 'User'),\n roles: t('staff.teamMembers.table.roles', 'Roles'),\n tags: t('staff.teamMembers.table.tags', 'Tags'),\n active: t('staff.teamMembers.table.active', 'Active'),\n updatedAt: t('staff.teamMembers.table.updatedAt', 'Updated'),\n empty: t('staff.teamMembers.table.empty', 'No team members yet.'),\n search: t('staff.teamMembers.table.search', 'Search team members...'),\n },\n actions: {\n add: t('staff.teamMembers.actions.add', 'Add team member'),\n edit: t('staff.teamMembers.actions.edit', 'Edit'),\n unassign: t('staff.teamMembers.actions.unassign', 'Unassign'),\n refresh: t('staff.teamMembers.actions.refresh', 'Refresh'),\n },\n messages: {\n unassigned: t('staff.teamMembers.messages.unassigned', 'Team member unassigned.'),\n },\n errors: {\n load: t('staff.teamMembers.errors.load', 'Failed to load team members.'),\n unassign: t('staff.teamMembers.errors.unassign', 'Failed to unassign team member.'),\n },\n tabs: {\n details: t('staff.teams.tabs.details', 'Details'),\n members: t('staff.teams.tabs.members', 'Team members'),\n label: t('staff.teams.tabs.label', 'Team sections'),\n },\n }), [t])\n\n const memberColumns = React.useMemo<ColumnDef<TeamMemberRow>[]>(() => [\n {\n accessorKey: 'displayName',\n header: memberLabels.table.name,\n meta: { priority: 1, sticky: true },\n cell: ({ row }) => (\n <div className=\"flex flex-col\">\n <span className=\"font-medium\">{row.original.displayName}</span>\n {row.original.description ? (\n <span className=\"text-xs text-muted-foreground line-clamp-2\">{row.original.description}</span>\n ) : null}\n </div>\n ),\n },\n {\n accessorKey: 'userEmail',\n header: memberLabels.table.user,\n meta: { priority: 2 },\n cell: ({ row }) => row.original.userEmail\n ? <span className=\"text-sm\">{row.original.userEmail}</span>\n : <span className=\"text-xs text-muted-foreground\">-</span>,\n },\n {\n accessorKey: 'roleNames',\n header: memberLabels.table.roles,\n meta: { priority: 3 },\n cell: ({ row }) => row.original.roleNames.length\n ? <span className=\"text-sm\">{row.original.roleNames.join(', ')}</span>\n : <span className=\"text-xs text-muted-foreground\">-</span>,\n },\n {\n accessorKey: 'tags',\n header: memberLabels.table.tags,\n meta: { priority: 4 },\n cell: ({ row }) => row.original.tags.length\n ? <span className=\"text-xs text-muted-foreground\">{row.original.tags.join(', ')}</span>\n : <span className=\"text-xs text-muted-foreground\">-</span>,\n },\n {\n accessorKey: 'isActive',\n header: memberLabels.table.active,\n meta: { priority: 5 },\n cell: ({ row }) => <BooleanIcon value={row.original.isActive} />,\n },\n {\n accessorKey: 'updatedAt',\n header: memberLabels.table.updatedAt,\n meta: { priority: 6 },\n cell: ({ row }) => row.original.updatedAt\n ? <span className=\"text-xs text-muted-foreground\">{formatDateTime(row.original.updatedAt)}</span>\n : <span className=\"text-xs text-muted-foreground\">-</span>,\n },\n ], [\n memberLabels.table.active,\n memberLabels.table.name,\n memberLabels.table.roles,\n memberLabels.table.tags,\n memberLabels.table.updatedAt,\n memberLabels.table.user,\n ])\n\n React.useEffect(() => {\n if (!teamId) return\n const teamIdValue = teamId\n let cancelled = false\n async function loadTeam() {\n if (!cancelled) {\n setError(null)\n setIsNotFound(false)\n }\n try {\n const params = new URLSearchParams({ page: '1', pageSize: '1', ids: teamIdValue })\n const payload = await readApiResultOrThrow<TeamResponse>(\n `/api/staff/teams?${params.toString()}`,\n undefined,\n { errorMessage: t('staff.teams.errors.load', 'Failed to load team.') },\n )\n const record = Array.isArray(payload.items) ? payload.items[0] : null\n if (!record) {\n if (!cancelled) setIsNotFound(true)\n return\n }\n const customFields = extractCustomFieldEntries(record)\n const isActive = typeof record.isActive === 'boolean'\n ? record.isActive\n : typeof record.is_active === 'boolean'\n ? record.is_active\n : true\n if (!cancelled) {\n setInitialValues({\n id: record.id,\n name: record.name ?? '',\n description: record.description ?? '',\n isActive,\n updatedAt: typeof record.updatedAt === 'string'\n ? record.updatedAt\n : typeof record.updated_at === 'string'\n ? record.updated_at\n : null,\n ...customFields,\n })\n }\n } catch (err) {\n if (!cancelled) {\n if ((err as { status?: number }).status === 404) {\n setIsNotFound(true)\n } else {\n const message = err instanceof Error ? err.message : t('staff.teams.errors.load', 'Failed to load team.')\n setError(message)\n }\n }\n }\n }\n loadTeam()\n return () => { cancelled = true }\n }, [teamId, t])\n\n React.useEffect(() => {\n if (!searchParams) return\n const tabParam = searchParams.get('tab')\n if (tabParam === 'members') {\n setActiveTab('members')\n }\n }, [searchParams])\n\n const loadTeamMembers = React.useCallback(async () => {\n if (!teamId) return\n setMembersLoading(true)\n try {\n const params = new URLSearchParams({\n page: String(memberPage),\n pageSize: String(TEAM_MEMBERS_PAGE_SIZE),\n teamId,\n })\n const sort = memberSorting[0]\n if (sort?.id) {\n params.set('sortField', sort.id)\n params.set('sortDir', sort.desc ? 'desc' : 'asc')\n }\n if (memberSearch.trim()) params.set('search', memberSearch.trim())\n const payload = await readApiResultOrThrow<TeamMembersResponse>(\n `/api/staff/team-members?${params.toString()}`,\n undefined,\n { errorMessage: memberLabels.errors.load, fallback: { items: [], total: 0, totalPages: 1 } },\n )\n const items = Array.isArray(payload.items) ? payload.items : []\n setMemberRows(items.map(mapApiTeamMember))\n setMemberTotal(typeof payload.total === 'number' ? payload.total : items.length)\n setMemberTotalPages(\n typeof payload.totalPages === 'number'\n ? payload.totalPages\n : Math.max(1, Math.ceil(items.length / TEAM_MEMBERS_PAGE_SIZE)),\n )\n } catch (error) {\n console.error('staff.teams.team-members.list', error)\n flash(memberLabels.errors.load, 'error')\n } finally {\n setMembersLoading(false)\n }\n }, [memberLabels.errors.load, memberPage, memberSearch, memberSorting, teamId])\n\n React.useEffect(() => {\n if (activeTab !== 'members') return\n void loadTeamMembers()\n }, [activeTab, loadTeamMembers, memberReloadToken, scopeVersion])\n\n const handleMemberSearchChange = React.useCallback((value: string) => {\n setMemberSearch(value)\n setMemberPage(1)\n }, [])\n\n const handleMemberRefresh = React.useCallback(() => {\n setMemberReloadToken((token) => token + 1)\n }, [])\n\n const handleUnassignMember = React.useCallback(async (entry: TeamMemberRow) => {\n if (!teamId || entry.teamId !== teamId) return\n try {\n const headers = buildOptimisticLockHeader(entry.updatedAt)\n await withScopedApiRequestHeaders(headers, () => (\n updateCrud('staff/team-members', { id: entry.id, teamId: null }, { errorMessage: memberLabels.errors.unassign })\n ))\n flash(memberLabels.messages.unassigned, 'success')\n handleMemberRefresh()\n } catch (error) {\n console.error('staff.teams.team-members.unassign', error)\n flash(memberLabels.errors.unassign, 'error')\n }\n }, [handleMemberRefresh, memberLabels.errors.unassign, memberLabels.messages.unassigned, teamId])\n\n const handleSubmit = React.useCallback(async (values: TeamFormValues) => {\n if (!teamId) return\n const payload = buildTeamPayload(values, { id: teamId })\n await updateCrud('staff/teams', payload, {\n errorMessage: t('staff.teams.errors.save', 'Failed to save team.'),\n })\n flash(t('staff.teams.messages.saved', 'Team saved.'), 'success')\n }, [teamId, t])\n\n const handleDelete = React.useCallback(async () => {\n if (!teamId) return\n await deleteCrud('staff/teams', teamId, {\n errorMessage: t('staff.teams.errors.delete', 'Failed to delete team.'),\n })\n router.push('/backend/staff/teams')\n }, [teamId, router, t])\n\n // Publish page-load record context to the AppShell-owned `backend:record:current`\n // mount so the enterprise record_locks widget resolves `staff.team` + id explicitly.\n // The resourceKind mirrors the TeamForm `versionHistory` so the held lock matches\n // the save-time conflict surface for the same team.\n useSetCurrentRecordInjectionContext(\n buildRecordInjectionContext({\n resourceKind: 'staff.team',\n resourceId: teamId || null,\n updatedAt: initialValues?.updatedAt ?? null,\n data: initialValues as Record<string, unknown> | null,\n path: pathname,\n }),\n )\n\n if (isNotFound) {\n return (\n <Page>\n <PageBody>\n <RecordNotFoundState\n label={t('staff.teams.errors.notFound', 'Team not found.')}\n backHref=\"/backend/staff/teams\"\n backLabel={t('staff.teams.actions.backToList', 'Back to teams')}\n />\n </PageBody>\n </Page>\n )\n }\n\n if (error && !initialValues) {\n return (\n <Page>\n <PageBody>\n <ErrorMessage label={error} />\n </PageBody>\n </Page>\n )\n }\n\n return (\n <Page>\n <PageBody>\n <div className=\"space-y-6\">\n <div className=\"border-b\">\n <nav className=\"flex flex-wrap items-center gap-5 text-sm\" aria-label={memberLabels.tabs.label}>\n {[\n { id: 'details', label: memberLabels.tabs.details },\n { id: 'members', label: memberLabels.tabs.members },\n ].map((tab) => (\n <button\n key={tab.id}\n type=\"button\"\n role=\"tab\"\n aria-selected={activeTab === tab.id}\n onClick={() => setActiveTab(tab.id as 'details' | 'members')}\n className={`relative -mb-px border-b-2 px-0 py-2 text-sm font-medium transition-colors ${\n activeTab === tab.id\n ? 'border-accent-indigo text-foreground'\n : 'border-transparent text-muted-foreground hover:text-foreground'\n }`}\n >\n {tab.label}\n </button>\n ))}\n </nav>\n </div>\n\n {activeTab === 'details' ? (\n <TeamForm\n title={t('staff.teams.form.editTitle', 'Edit team')}\n backHref=\"/backend/staff/teams\"\n cancelHref=\"/backend/staff/teams\"\n initialValues={initialValues ?? { name: '', description: '', isActive: true }}\n onSubmit={handleSubmit}\n onDelete={handleDelete}\n isLoading={!initialValues}\n loadingMessage={t('staff.teams.form.loading', 'Loading team...')}\n extraActions={teamId ? (\n <SendObjectMessageDialog\n object={{\n entityModule: 'staff',\n entityType: 'team',\n entityId: teamId,\n previewData: { title: initialValues?.name ?? ''},\n }}\n viewHref={`/backend/staff/teams/${teamId}/edit`}\n />\n ) : undefined}\n />\n ) : (\n <DataTable<TeamMemberRow>\n title={memberLabels.title}\n data={memberRows}\n columns={memberColumns}\n isLoading={membersLoading}\n searchValue={memberSearch}\n onSearchChange={handleMemberSearchChange}\n searchPlaceholder={memberLabels.table.search}\n emptyState={<p className=\"py-8 text-center text-sm text-muted-foreground\">{memberLabels.table.empty}</p>}\n actions={(\n <Button asChild size=\"sm\">\n <Link href={`/backend/staff/team-members/create?teamId=${encodeURIComponent(teamId ?? '')}`}>\n <Plus className=\"mr-2 h-4 w-4\" aria-hidden />\n {memberLabels.actions.add}\n </Link>\n </Button>\n )}\n refreshButton={{\n label: memberLabels.actions.refresh,\n onRefresh: handleMemberRefresh,\n isRefreshing: membersLoading,\n }}\n sortable\n sorting={memberSorting}\n onSortingChange={setMemberSorting}\n pagination={{\n page: memberPage,\n pageSize: TEAM_MEMBERS_PAGE_SIZE,\n total: memberTotal,\n totalPages: memberTotalPages,\n onPageChange: setMemberPage,\n }}\n rowActions={(row) => (\n <RowActions\n items={[\n { id: 'edit', label: memberLabels.actions.edit, onSelect: () => { router.push(`/backend/staff/team-members/${row.id}`) } },\n { id: 'unassign', label: memberLabels.actions.unassign, onSelect: () => { void handleUnassignMember(row) } },\n ]}\n />\n )}\n />\n )}\n </div>\n </PageBody>\n </Page>\n )\n}\n\nfunction mapApiTeamMember(item: Record<string, unknown>): TeamMemberRow {\n const id = typeof item.id === 'string' ? item.id : ''\n const displayName = typeof item.displayName === 'string'\n ? item.displayName\n : typeof item.display_name === 'string'\n ? item.display_name\n : id\n const description = typeof item.description === 'string' && item.description.trim().length\n ? item.description.trim()\n : null\n const user = item.user && typeof item.user === 'object' ? item.user as { email?: unknown } : null\n const userEmail = user && typeof user.email === 'string' && user.email.length ? user.email : null\n const roleNames = Array.isArray(item.roleNames) ? item.roleNames.filter((value): value is string => typeof value === 'string') : []\n const tags = Array.isArray(item.tags) ? item.tags.filter((value): value is string => typeof value === 'string') : []\n const updatedAt = typeof item.updatedAt === 'string'\n ? item.updatedAt\n : typeof item.updated_at === 'string'\n ? item.updated_at\n : null\n const isActive = typeof item.isActive === 'boolean'\n ? item.isActive\n : typeof item.is_active === 'boolean'\n ? item.is_active\n : true\n const teamId = typeof item.teamId === 'string'\n ? item.teamId\n : typeof item.team_id === 'string'\n ? item.team_id\n : null\n return withDataTableNamespaces({\n id,\n displayName,\n description,\n userEmail,\n roleNames,\n tags,\n isActive,\n updatedAt,\n teamId,\n }, item)\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["params", "error"]
|
|
7
7
|
}
|
|
@@ -16,7 +16,7 @@ import { resolveTranslations } from "@open-mercato/shared/lib/i18n/server";
|
|
|
16
16
|
import { resolveRedoSnapshot } from "@open-mercato/shared/lib/commands/redo";
|
|
17
17
|
import { CrudHttpError } from "@open-mercato/shared/lib/crud/errors";
|
|
18
18
|
import {
|
|
19
|
-
|
|
19
|
+
enforceCommandOptimisticLockWithGuards,
|
|
20
20
|
enforceRecordGoneIsConflict
|
|
21
21
|
} from "@open-mercato/shared/lib/crud/optimistic-lock-command";
|
|
22
22
|
import { E } from "../../../generated/entities.ids.generated.js";
|
|
@@ -183,7 +183,7 @@ const updateJobHistoryCommand = {
|
|
|
183
183
|
}
|
|
184
184
|
ensureTenantScope(ctx, record.tenantId);
|
|
185
185
|
ensureOrganizationScope(ctx, record.organizationId);
|
|
186
|
-
|
|
186
|
+
await enforceCommandOptimisticLockWithGuards(ctx.container, {
|
|
187
187
|
resourceKind: JOB_HISTORY_LOCK_RESOURCE_KIND,
|
|
188
188
|
resourceId: record.id,
|
|
189
189
|
current: record.updatedAt ?? null,
|
|
@@ -320,7 +320,7 @@ const deleteJobHistoryCommand = {
|
|
|
320
320
|
}
|
|
321
321
|
ensureTenantScope(ctx, record.tenantId);
|
|
322
322
|
ensureOrganizationScope(ctx, record.organizationId);
|
|
323
|
-
|
|
323
|
+
await enforceCommandOptimisticLockWithGuards(ctx.container, {
|
|
324
324
|
resourceKind: JOB_HISTORY_LOCK_RESOURCE_KIND,
|
|
325
325
|
resourceId: record.id,
|
|
326
326
|
current: record.updatedAt ?? null,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../src/modules/staff/commands/job-histories.ts"],
|
|
4
|
-
"sourcesContent": ["import { registerCommand } from '@open-mercato/shared/lib/commands'\nimport type { CommandHandler } from '@open-mercato/shared/lib/commands'\nimport { emitCrudSideEffects, emitCrudUndoSideEffects, buildChanges, requireId } from '@open-mercato/shared/lib/commands/helpers'\nimport type { DataEngine } from '@open-mercato/shared/lib/data/engine'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { StaffTeamMemberJobHistory } from '../data/entities'\nimport {\n staffTeamMemberJobHistoryCreateSchema,\n staffTeamMemberJobHistoryUpdateSchema,\n type StaffTeamMemberJobHistoryCreateInput,\n type StaffTeamMemberJobHistoryUpdateInput,\n} from '../data/validators'\nimport { staffTeamMemberJobHistoryCrudEvents } from '../lib/crud'\nimport {\n ensureOrganizationScope,\n ensureTenantScope,\n extractUndoPayload,\n requireTeamMember,\n} from './shared'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { resolveRedoSnapshot } from '@open-mercato/shared/lib/commands/redo'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport {\n enforceCommandOptimisticLock,\n enforceRecordGoneIsConflict,\n} from '@open-mercato/shared/lib/crud/optimistic-lock-command'\nimport type { CrudIndexerConfig } from '@open-mercato/shared/lib/crud/types'\nimport { E } from '#generated/entities.ids.generated'\n\nconst JOB_HISTORY_LOCK_RESOURCE_KIND = 'staff.jobHistory'\n\nconst jobHistoryCrudIndexer: CrudIndexerConfig<StaffTeamMemberJobHistory> = {\n entityType: E.staff.staff_team_member_job_history,\n}\n\ntype JobHistorySnapshot = {\n id: string\n organizationId: string\n tenantId: string\n memberId: string\n name: string\n companyName: string | null\n description: string | null\n startDate: string\n endDate: string | null\n updatedAt: string\n}\n\ntype JobHistoryUndoPayload = {\n before?: JobHistorySnapshot | null\n after?: JobHistorySnapshot | null\n}\n\nasync function loadJobHistorySnapshot(em: EntityManager, id: string): Promise<JobHistorySnapshot | null> {\n const record = await em.findOne(StaffTeamMemberJobHistory, { id })\n if (!record) return null\n return {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n memberId: typeof record.member === 'string' ? record.member : record.member.id,\n name: record.name,\n companyName: record.companyName ?? null,\n description: record.description ?? null,\n startDate: record.startDate.toISOString(),\n endDate: record.endDate ? record.endDate.toISOString() : null,\n updatedAt: record.updatedAt.toISOString(),\n }\n}\n\nconst createJobHistoryCommand: CommandHandler<StaffTeamMemberJobHistoryCreateInput, { jobHistoryId: string }> = {\n id: 'staff.team-member-job-histories.create',\n async execute(rawInput, ctx) {\n const parsed = staffTeamMemberJobHistoryCreateSchema.parse(rawInput)\n ensureTenantScope(ctx, parsed.tenantId)\n ensureOrganizationScope(ctx, parsed.organizationId)\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const member = await requireTeamMember(em, parsed.entityId, 'Team member not found')\n ensureTenantScope(ctx, member.tenantId)\n ensureOrganizationScope(ctx, member.organizationId)\n\n const record = em.create(StaffTeamMemberJobHistory, {\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n member,\n name: parsed.name,\n companyName: parsed.companyName ?? null,\n description: parsed.description ?? null,\n startDate: parsed.startDate,\n endDate: parsed.endDate ?? null,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n em.persist(record)\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'created',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n events: staffTeamMemberJobHistoryCrudEvents,\n indexer: jobHistoryCrudIndexer,\n })\n\n return { jobHistoryId: record.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return await loadJobHistorySnapshot(em, result.jobHistoryId)\n },\n buildLog: async ({ result, snapshots }) => {\n const { translate } = await resolveTranslations()\n const snapshot = snapshots.after as JobHistorySnapshot | undefined\n return {\n actionLabel: translate('staff.audit.teamMemberJobHistories.create', 'Create job history entry'),\n resourceKind: 'staff.team_member_job_history',\n resourceId: result.jobHistoryId,\n parentResourceKind: 'staff.teamMember',\n parentResourceId: snapshot?.memberId ?? null,\n tenantId: snapshot?.tenantId ?? null,\n organizationId: snapshot?.organizationId ?? null,\n snapshotAfter: snapshot ?? null,\n payload: {\n undo: {\n after: snapshot ?? null,\n } satisfies JobHistoryUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const jobHistoryId = logEntry?.resourceId ?? null\n if (!jobHistoryId) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const record = await em.findOne(StaffTeamMemberJobHistory, { id: jobHistoryId })\n if (record) {\n em.remove(record)\n await em.flush()\n }\n },\n redo: async ({ logEntry, ctx }) => {\n const after = resolveRedoSnapshot<JobHistorySnapshot>(logEntry)\n if (!after) {\n throw new CrudHttpError(400, { error: '[internal] redo snapshot unavailable for job history create' })\n }\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const member = await requireTeamMember(em, after.memberId, 'Team member not found')\n let record = await em.findOne(StaffTeamMemberJobHistory, { id: after.id })\n if (!record) {\n record = em.create(StaffTeamMemberJobHistory, {\n id: after.id,\n organizationId: after.organizationId,\n tenantId: after.tenantId,\n member,\n name: after.name,\n companyName: after.companyName,\n description: after.description,\n startDate: new Date(after.startDate),\n endDate: after.endDate ? new Date(after.endDate) : null,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n em.persist(record)\n } else {\n record.member = member\n record.name = after.name\n record.companyName = after.companyName\n record.description = after.description\n record.startDate = new Date(after.startDate)\n record.endDate = after.endDate ? new Date(after.endDate) : null\n }\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'created',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n events: staffTeamMemberJobHistoryCrudEvents,\n indexer: jobHistoryCrudIndexer,\n })\n\n return { jobHistoryId: record.id }\n },\n}\n\nconst updateJobHistoryCommand: CommandHandler<StaffTeamMemberJobHistoryUpdateInput, { jobHistoryId: string }> = {\n id: 'staff.team-member-job-histories.update',\n async prepare(rawInput, ctx) {\n const parsed = staffTeamMemberJobHistoryUpdateSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadJobHistorySnapshot(em, parsed.id)\n return snapshot ? { before: snapshot } : {}\n },\n async execute(rawInput, ctx) {\n const parsed = staffTeamMemberJobHistoryUpdateSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const record = await em.findOne(StaffTeamMemberJobHistory, { id: parsed.id })\n if (!record) {\n enforceRecordGoneIsConflict({\n resourceKind: JOB_HISTORY_LOCK_RESOURCE_KIND,\n resourceId: parsed.id,\n expected: parsed.updatedAt ?? null,\n request: ctx.request ?? null,\n })\n throw new CrudHttpError(404, { error: 'Job history entry not found' })\n }\n ensureTenantScope(ctx, record.tenantId)\n ensureOrganizationScope(ctx, record.organizationId)\n enforceCommandOptimisticLock({\n resourceKind: JOB_HISTORY_LOCK_RESOURCE_KIND,\n resourceId: record.id,\n current: record.updatedAt ?? null,\n expected: parsed.updatedAt ?? null,\n request: ctx.request ?? null,\n })\n\n if (parsed.entityId !== undefined) {\n const member = await requireTeamMember(em, parsed.entityId, 'Team member not found')\n ensureTenantScope(ctx, member.tenantId)\n ensureOrganizationScope(ctx, member.organizationId)\n record.member = member\n }\n if (parsed.name !== undefined) record.name = parsed.name\n if (parsed.companyName !== undefined) record.companyName = parsed.companyName ?? null\n if (parsed.description !== undefined) record.description = parsed.description ?? null\n if (parsed.startDate !== undefined) record.startDate = parsed.startDate\n if (parsed.endDate !== undefined) record.endDate = parsed.endDate ?? null\n\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n events: staffTeamMemberJobHistoryCrudEvents,\n indexer: jobHistoryCrudIndexer,\n })\n\n return { jobHistoryId: record.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return await loadJobHistorySnapshot(em, result.jobHistoryId)\n },\n buildLog: async ({ snapshots }) => {\n const { translate } = await resolveTranslations()\n const before = snapshots.before as JobHistorySnapshot | undefined\n if (!before) return null\n const afterSnapshot = snapshots.after as JobHistorySnapshot | undefined\n const changes =\n afterSnapshot && before\n ? buildChanges(\n before as unknown as Record<string, unknown>,\n afterSnapshot as unknown as Record<string, unknown>,\n ['memberId', 'name', 'companyName', 'description', 'startDate', 'endDate'],\n )\n : {}\n return {\n actionLabel: translate('staff.audit.teamMemberJobHistories.update', 'Update job history entry'),\n resourceKind: 'staff.team_member_job_history',\n resourceId: before.id,\n parentResourceKind: 'staff.teamMember',\n parentResourceId: before.memberId ?? null,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n snapshotBefore: before,\n snapshotAfter: afterSnapshot ?? null,\n changes,\n payload: {\n undo: {\n before,\n after: afterSnapshot ?? null,\n } satisfies JobHistoryUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<JobHistoryUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n let record = await em.findOne(StaffTeamMemberJobHistory, { id: before.id })\n const member = await requireTeamMember(em, before.memberId, 'Team member not found')\n\n if (!record) {\n record = em.create(StaffTeamMemberJobHistory, {\n id: before.id,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n member,\n name: before.name,\n companyName: before.companyName,\n description: before.description,\n startDate: new Date(before.startDate),\n endDate: before.endDate ? new Date(before.endDate) : null,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n em.persist(record)\n } else {\n record.member = member\n record.name = before.name\n record.companyName = before.companyName\n record.description = before.description\n record.startDate = new Date(before.startDate)\n record.endDate = before.endDate ? new Date(before.endDate) : null\n }\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n events: staffTeamMemberJobHistoryCrudEvents,\n indexer: jobHistoryCrudIndexer,\n })\n },\n}\n\nconst deleteJobHistoryCommand: CommandHandler<{ id?: string; updatedAt?: string; body?: Record<string, unknown>; query?: Record<string, unknown> }, { jobHistoryId: string }> =\n {\n id: 'staff.team-member-job-histories.delete',\n async prepare(input, ctx) {\n const id = requireId(input, 'Job history id required')\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadJobHistorySnapshot(em, id)\n return snapshot ? { before: snapshot } : {}\n },\n async execute(input, ctx) {\n const id = requireId(input, 'Job history id required')\n const expectedUpdatedAt = typeof input.updatedAt === 'string' ? input.updatedAt : undefined\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const record = await em.findOne(StaffTeamMemberJobHistory, { id })\n if (!record) {\n enforceRecordGoneIsConflict({\n resourceKind: JOB_HISTORY_LOCK_RESOURCE_KIND,\n resourceId: id,\n expected: expectedUpdatedAt ?? null,\n request: ctx.request ?? null,\n })\n throw new CrudHttpError(404, { error: 'Job history entry not found' })\n }\n ensureTenantScope(ctx, record.tenantId)\n ensureOrganizationScope(ctx, record.organizationId)\n enforceCommandOptimisticLock({\n resourceKind: JOB_HISTORY_LOCK_RESOURCE_KIND,\n resourceId: record.id,\n current: record.updatedAt ?? null,\n expected: expectedUpdatedAt ?? null,\n request: ctx.request ?? null,\n })\n em.remove(record)\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'deleted',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n events: staffTeamMemberJobHistoryCrudEvents,\n indexer: jobHistoryCrudIndexer,\n })\n return { jobHistoryId: record.id }\n },\n buildLog: async ({ snapshots }) => {\n const before = snapshots.before as JobHistorySnapshot | undefined\n if (!before) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('staff.audit.teamMemberJobHistories.delete', 'Delete job history entry'),\n resourceKind: 'staff.team_member_job_history',\n resourceId: before.id,\n parentResourceKind: 'staff.teamMember',\n parentResourceId: before.memberId ?? null,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n snapshotBefore: before,\n payload: {\n undo: {\n before,\n } satisfies JobHistoryUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<JobHistoryUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const member = await requireTeamMember(em, before.memberId, 'Team member not found')\n let record = await em.findOne(StaffTeamMemberJobHistory, { id: before.id })\n if (!record) {\n record = em.create(StaffTeamMemberJobHistory, {\n id: before.id,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n member,\n name: before.name,\n companyName: before.companyName,\n description: before.description,\n startDate: new Date(before.startDate),\n endDate: before.endDate ? new Date(before.endDate) : null,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n em.persist(record)\n } else {\n record.member = member\n record.name = before.name\n record.companyName = before.companyName\n record.description = before.description\n record.startDate = new Date(before.startDate)\n record.endDate = before.endDate ? new Date(before.endDate) : null\n }\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'created',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n events: staffTeamMemberJobHistoryCrudEvents,\n indexer: jobHistoryCrudIndexer,\n })\n },\n }\n\nregisterCommand(createJobHistoryCommand)\nregisterCommand(updateJobHistoryCommand)\nregisterCommand(deleteJobHistoryCommand)\n"],
|
|
5
|
-
"mappings": "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
|
|
4
|
+
"sourcesContent": ["import { registerCommand } from '@open-mercato/shared/lib/commands'\nimport type { CommandHandler } from '@open-mercato/shared/lib/commands'\nimport { emitCrudSideEffects, emitCrudUndoSideEffects, buildChanges, requireId } from '@open-mercato/shared/lib/commands/helpers'\nimport type { DataEngine } from '@open-mercato/shared/lib/data/engine'\nimport type { EntityManager } from '@mikro-orm/postgresql'\nimport { StaffTeamMemberJobHistory } from '../data/entities'\nimport {\n staffTeamMemberJobHistoryCreateSchema,\n staffTeamMemberJobHistoryUpdateSchema,\n type StaffTeamMemberJobHistoryCreateInput,\n type StaffTeamMemberJobHistoryUpdateInput,\n} from '../data/validators'\nimport { staffTeamMemberJobHistoryCrudEvents } from '../lib/crud'\nimport {\n ensureOrganizationScope,\n ensureTenantScope,\n extractUndoPayload,\n requireTeamMember,\n} from './shared'\nimport { resolveTranslations } from '@open-mercato/shared/lib/i18n/server'\nimport { resolveRedoSnapshot } from '@open-mercato/shared/lib/commands/redo'\nimport { CrudHttpError } from '@open-mercato/shared/lib/crud/errors'\nimport {\n enforceCommandOptimisticLockWithGuards,\n enforceRecordGoneIsConflict,\n} from '@open-mercato/shared/lib/crud/optimistic-lock-command'\nimport type { CrudIndexerConfig } from '@open-mercato/shared/lib/crud/types'\nimport { E } from '#generated/entities.ids.generated'\n\nconst JOB_HISTORY_LOCK_RESOURCE_KIND = 'staff.jobHistory'\n\nconst jobHistoryCrudIndexer: CrudIndexerConfig<StaffTeamMemberJobHistory> = {\n entityType: E.staff.staff_team_member_job_history,\n}\n\ntype JobHistorySnapshot = {\n id: string\n organizationId: string\n tenantId: string\n memberId: string\n name: string\n companyName: string | null\n description: string | null\n startDate: string\n endDate: string | null\n updatedAt: string\n}\n\ntype JobHistoryUndoPayload = {\n before?: JobHistorySnapshot | null\n after?: JobHistorySnapshot | null\n}\n\nasync function loadJobHistorySnapshot(em: EntityManager, id: string): Promise<JobHistorySnapshot | null> {\n const record = await em.findOne(StaffTeamMemberJobHistory, { id })\n if (!record) return null\n return {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n memberId: typeof record.member === 'string' ? record.member : record.member.id,\n name: record.name,\n companyName: record.companyName ?? null,\n description: record.description ?? null,\n startDate: record.startDate.toISOString(),\n endDate: record.endDate ? record.endDate.toISOString() : null,\n updatedAt: record.updatedAt.toISOString(),\n }\n}\n\nconst createJobHistoryCommand: CommandHandler<StaffTeamMemberJobHistoryCreateInput, { jobHistoryId: string }> = {\n id: 'staff.team-member-job-histories.create',\n async execute(rawInput, ctx) {\n const parsed = staffTeamMemberJobHistoryCreateSchema.parse(rawInput)\n ensureTenantScope(ctx, parsed.tenantId)\n ensureOrganizationScope(ctx, parsed.organizationId)\n\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const member = await requireTeamMember(em, parsed.entityId, 'Team member not found')\n ensureTenantScope(ctx, member.tenantId)\n ensureOrganizationScope(ctx, member.organizationId)\n\n const record = em.create(StaffTeamMemberJobHistory, {\n organizationId: parsed.organizationId,\n tenantId: parsed.tenantId,\n member,\n name: parsed.name,\n companyName: parsed.companyName ?? null,\n description: parsed.description ?? null,\n startDate: parsed.startDate,\n endDate: parsed.endDate ?? null,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n em.persist(record)\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'created',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n events: staffTeamMemberJobHistoryCrudEvents,\n indexer: jobHistoryCrudIndexer,\n })\n\n return { jobHistoryId: record.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return await loadJobHistorySnapshot(em, result.jobHistoryId)\n },\n buildLog: async ({ result, snapshots }) => {\n const { translate } = await resolveTranslations()\n const snapshot = snapshots.after as JobHistorySnapshot | undefined\n return {\n actionLabel: translate('staff.audit.teamMemberJobHistories.create', 'Create job history entry'),\n resourceKind: 'staff.team_member_job_history',\n resourceId: result.jobHistoryId,\n parentResourceKind: 'staff.teamMember',\n parentResourceId: snapshot?.memberId ?? null,\n tenantId: snapshot?.tenantId ?? null,\n organizationId: snapshot?.organizationId ?? null,\n snapshotAfter: snapshot ?? null,\n payload: {\n undo: {\n after: snapshot ?? null,\n } satisfies JobHistoryUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const jobHistoryId = logEntry?.resourceId ?? null\n if (!jobHistoryId) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const record = await em.findOne(StaffTeamMemberJobHistory, { id: jobHistoryId })\n if (record) {\n em.remove(record)\n await em.flush()\n }\n },\n redo: async ({ logEntry, ctx }) => {\n const after = resolveRedoSnapshot<JobHistorySnapshot>(logEntry)\n if (!after) {\n throw new CrudHttpError(400, { error: '[internal] redo snapshot unavailable for job history create' })\n }\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const member = await requireTeamMember(em, after.memberId, 'Team member not found')\n let record = await em.findOne(StaffTeamMemberJobHistory, { id: after.id })\n if (!record) {\n record = em.create(StaffTeamMemberJobHistory, {\n id: after.id,\n organizationId: after.organizationId,\n tenantId: after.tenantId,\n member,\n name: after.name,\n companyName: after.companyName,\n description: after.description,\n startDate: new Date(after.startDate),\n endDate: after.endDate ? new Date(after.endDate) : null,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n em.persist(record)\n } else {\n record.member = member\n record.name = after.name\n record.companyName = after.companyName\n record.description = after.description\n record.startDate = new Date(after.startDate)\n record.endDate = after.endDate ? new Date(after.endDate) : null\n }\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'created',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n events: staffTeamMemberJobHistoryCrudEvents,\n indexer: jobHistoryCrudIndexer,\n })\n\n return { jobHistoryId: record.id }\n },\n}\n\nconst updateJobHistoryCommand: CommandHandler<StaffTeamMemberJobHistoryUpdateInput, { jobHistoryId: string }> = {\n id: 'staff.team-member-job-histories.update',\n async prepare(rawInput, ctx) {\n const parsed = staffTeamMemberJobHistoryUpdateSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadJobHistorySnapshot(em, parsed.id)\n return snapshot ? { before: snapshot } : {}\n },\n async execute(rawInput, ctx) {\n const parsed = staffTeamMemberJobHistoryUpdateSchema.parse(rawInput)\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const record = await em.findOne(StaffTeamMemberJobHistory, { id: parsed.id })\n if (!record) {\n enforceRecordGoneIsConflict({\n resourceKind: JOB_HISTORY_LOCK_RESOURCE_KIND,\n resourceId: parsed.id,\n expected: parsed.updatedAt ?? null,\n request: ctx.request ?? null,\n })\n throw new CrudHttpError(404, { error: 'Job history entry not found' })\n }\n ensureTenantScope(ctx, record.tenantId)\n ensureOrganizationScope(ctx, record.organizationId)\n await enforceCommandOptimisticLockWithGuards(ctx.container, {\n resourceKind: JOB_HISTORY_LOCK_RESOURCE_KIND,\n resourceId: record.id,\n current: record.updatedAt ?? null,\n expected: parsed.updatedAt ?? null,\n request: ctx.request ?? null,\n })\n\n if (parsed.entityId !== undefined) {\n const member = await requireTeamMember(em, parsed.entityId, 'Team member not found')\n ensureTenantScope(ctx, member.tenantId)\n ensureOrganizationScope(ctx, member.organizationId)\n record.member = member\n }\n if (parsed.name !== undefined) record.name = parsed.name\n if (parsed.companyName !== undefined) record.companyName = parsed.companyName ?? null\n if (parsed.description !== undefined) record.description = parsed.description ?? null\n if (parsed.startDate !== undefined) record.startDate = parsed.startDate\n if (parsed.endDate !== undefined) record.endDate = parsed.endDate ?? null\n\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n events: staffTeamMemberJobHistoryCrudEvents,\n indexer: jobHistoryCrudIndexer,\n })\n\n return { jobHistoryId: record.id }\n },\n captureAfter: async (_input, result, ctx) => {\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n return await loadJobHistorySnapshot(em, result.jobHistoryId)\n },\n buildLog: async ({ snapshots }) => {\n const { translate } = await resolveTranslations()\n const before = snapshots.before as JobHistorySnapshot | undefined\n if (!before) return null\n const afterSnapshot = snapshots.after as JobHistorySnapshot | undefined\n const changes =\n afterSnapshot && before\n ? buildChanges(\n before as unknown as Record<string, unknown>,\n afterSnapshot as unknown as Record<string, unknown>,\n ['memberId', 'name', 'companyName', 'description', 'startDate', 'endDate'],\n )\n : {}\n return {\n actionLabel: translate('staff.audit.teamMemberJobHistories.update', 'Update job history entry'),\n resourceKind: 'staff.team_member_job_history',\n resourceId: before.id,\n parentResourceKind: 'staff.teamMember',\n parentResourceId: before.memberId ?? null,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n snapshotBefore: before,\n snapshotAfter: afterSnapshot ?? null,\n changes,\n payload: {\n undo: {\n before,\n after: afterSnapshot ?? null,\n } satisfies JobHistoryUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<JobHistoryUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n let record = await em.findOne(StaffTeamMemberJobHistory, { id: before.id })\n const member = await requireTeamMember(em, before.memberId, 'Team member not found')\n\n if (!record) {\n record = em.create(StaffTeamMemberJobHistory, {\n id: before.id,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n member,\n name: before.name,\n companyName: before.companyName,\n description: before.description,\n startDate: new Date(before.startDate),\n endDate: before.endDate ? new Date(before.endDate) : null,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n em.persist(record)\n } else {\n record.member = member\n record.name = before.name\n record.companyName = before.companyName\n record.description = before.description\n record.startDate = new Date(before.startDate)\n record.endDate = before.endDate ? new Date(before.endDate) : null\n }\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'updated',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n events: staffTeamMemberJobHistoryCrudEvents,\n indexer: jobHistoryCrudIndexer,\n })\n },\n}\n\nconst deleteJobHistoryCommand: CommandHandler<{ id?: string; updatedAt?: string; body?: Record<string, unknown>; query?: Record<string, unknown> }, { jobHistoryId: string }> =\n {\n id: 'staff.team-member-job-histories.delete',\n async prepare(input, ctx) {\n const id = requireId(input, 'Job history id required')\n const em = (ctx.container.resolve('em') as EntityManager)\n const snapshot = await loadJobHistorySnapshot(em, id)\n return snapshot ? { before: snapshot } : {}\n },\n async execute(input, ctx) {\n const id = requireId(input, 'Job history id required')\n const expectedUpdatedAt = typeof input.updatedAt === 'string' ? input.updatedAt : undefined\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const record = await em.findOne(StaffTeamMemberJobHistory, { id })\n if (!record) {\n enforceRecordGoneIsConflict({\n resourceKind: JOB_HISTORY_LOCK_RESOURCE_KIND,\n resourceId: id,\n expected: expectedUpdatedAt ?? null,\n request: ctx.request ?? null,\n })\n throw new CrudHttpError(404, { error: 'Job history entry not found' })\n }\n ensureTenantScope(ctx, record.tenantId)\n ensureOrganizationScope(ctx, record.organizationId)\n await enforceCommandOptimisticLockWithGuards(ctx.container, {\n resourceKind: JOB_HISTORY_LOCK_RESOURCE_KIND,\n resourceId: record.id,\n current: record.updatedAt ?? null,\n expected: expectedUpdatedAt ?? null,\n request: ctx.request ?? null,\n })\n em.remove(record)\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudSideEffects({\n dataEngine: de,\n action: 'deleted',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n events: staffTeamMemberJobHistoryCrudEvents,\n indexer: jobHistoryCrudIndexer,\n })\n return { jobHistoryId: record.id }\n },\n buildLog: async ({ snapshots }) => {\n const before = snapshots.before as JobHistorySnapshot | undefined\n if (!before) return null\n const { translate } = await resolveTranslations()\n return {\n actionLabel: translate('staff.audit.teamMemberJobHistories.delete', 'Delete job history entry'),\n resourceKind: 'staff.team_member_job_history',\n resourceId: before.id,\n parentResourceKind: 'staff.teamMember',\n parentResourceId: before.memberId ?? null,\n tenantId: before.tenantId,\n organizationId: before.organizationId,\n snapshotBefore: before,\n payload: {\n undo: {\n before,\n } satisfies JobHistoryUndoPayload,\n },\n }\n },\n undo: async ({ logEntry, ctx }) => {\n const payload = extractUndoPayload<JobHistoryUndoPayload>(logEntry)\n const before = payload?.before\n if (!before) return\n const em = (ctx.container.resolve('em') as EntityManager).fork()\n const member = await requireTeamMember(em, before.memberId, 'Team member not found')\n let record = await em.findOne(StaffTeamMemberJobHistory, { id: before.id })\n if (!record) {\n record = em.create(StaffTeamMemberJobHistory, {\n id: before.id,\n organizationId: before.organizationId,\n tenantId: before.tenantId,\n member,\n name: before.name,\n companyName: before.companyName,\n description: before.description,\n startDate: new Date(before.startDate),\n endDate: before.endDate ? new Date(before.endDate) : null,\n createdAt: new Date(),\n updatedAt: new Date(),\n })\n em.persist(record)\n } else {\n record.member = member\n record.name = before.name\n record.companyName = before.companyName\n record.description = before.description\n record.startDate = new Date(before.startDate)\n record.endDate = before.endDate ? new Date(before.endDate) : null\n }\n await em.flush()\n\n const de = (ctx.container.resolve('dataEngine') as DataEngine)\n await emitCrudUndoSideEffects({\n dataEngine: de,\n action: 'created',\n entity: record,\n identifiers: {\n id: record.id,\n organizationId: record.organizationId,\n tenantId: record.tenantId,\n },\n events: staffTeamMemberJobHistoryCrudEvents,\n indexer: jobHistoryCrudIndexer,\n })\n },\n }\n\nregisterCommand(createJobHistoryCommand)\nregisterCommand(updateJobHistoryCommand)\nregisterCommand(deleteJobHistoryCommand)\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { apiCallOrThrow, readApiResultOrThrow } from "@open-mercato/ui/backend/utils/apiCall";
|
|
2
|
+
import { apiCallOrThrow, readApiResultOrThrow, withScopedApiRequestHeaders } from "@open-mercato/ui/backend/utils/apiCall";
|
|
3
|
+
import { buildOptimisticLockHeader } from "@open-mercato/ui/backend/utils/optimisticLock";
|
|
3
4
|
import { loadStaffDictionaryEntries, createStaffDictionaryEntry } from "./dictionaries.js";
|
|
4
5
|
function createStaffAddressAdapter(translator) {
|
|
5
6
|
return {
|
|
@@ -33,7 +34,8 @@ function createStaffAddressAdapter(translator) {
|
|
|
33
34
|
region: typeof record.region === "string" ? record.region : null,
|
|
34
35
|
postalCode: typeof record.postal_code === "string" ? record.postal_code : typeof record.postalCode === "string" ? record.postalCode : null,
|
|
35
36
|
country: typeof record.country === "string" ? record.country : null,
|
|
36
|
-
isPrimary: typeof record.is_primary === "boolean" ? record.is_primary : typeof record.isPrimary === "boolean" ? record.isPrimary : false
|
|
37
|
+
isPrimary: typeof record.is_primary === "boolean" ? record.is_primary : typeof record.isPrimary === "boolean" ? record.isPrimary : false,
|
|
38
|
+
updatedAt: typeof record.updated_at === "string" ? record.updated_at : typeof record.updatedAt === "string" ? record.updatedAt : null
|
|
37
39
|
};
|
|
38
40
|
}).filter((value) => value !== null);
|
|
39
41
|
},
|
|
@@ -41,6 +43,7 @@ function createStaffAddressAdapter(translator) {
|
|
|
41
43
|
const response = await apiCallOrThrow(
|
|
42
44
|
"/api/staff/addresses",
|
|
43
45
|
{
|
|
46
|
+
// optimistic-lock-exempt: address create-only (no prior version to compare)
|
|
44
47
|
method: "POST",
|
|
45
48
|
headers: { "content-type": "application/json" },
|
|
46
49
|
body: JSON.stringify({
|
|
@@ -53,30 +56,36 @@ function createStaffAddressAdapter(translator) {
|
|
|
53
56
|
);
|
|
54
57
|
return response.result ?? {};
|
|
55
58
|
},
|
|
56
|
-
update: async ({ id, payload }) => {
|
|
57
|
-
await
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
59
|
+
update: async ({ id, payload, updatedAt }) => {
|
|
60
|
+
await withScopedApiRequestHeaders(
|
|
61
|
+
buildOptimisticLockHeader(updatedAt ?? null),
|
|
62
|
+
() => apiCallOrThrow(
|
|
63
|
+
"/api/staff/addresses",
|
|
64
|
+
{
|
|
65
|
+
method: "PUT",
|
|
66
|
+
headers: { "content-type": "application/json" },
|
|
67
|
+
body: JSON.stringify({
|
|
68
|
+
id,
|
|
69
|
+
...payload,
|
|
70
|
+
country: payload.country ? payload.country.toUpperCase() : void 0
|
|
71
|
+
})
|
|
72
|
+
},
|
|
73
|
+
{ errorMessage: translator("staff.teamMembers.detail.addresses.error", "Failed to save address.") }
|
|
74
|
+
)
|
|
69
75
|
);
|
|
70
76
|
},
|
|
71
|
-
delete: async ({ id }) => {
|
|
72
|
-
await
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
delete: async ({ id, updatedAt }) => {
|
|
78
|
+
await withScopedApiRequestHeaders(
|
|
79
|
+
buildOptimisticLockHeader(updatedAt ?? null),
|
|
80
|
+
() => apiCallOrThrow(
|
|
81
|
+
"/api/staff/addresses",
|
|
82
|
+
{
|
|
83
|
+
method: "DELETE",
|
|
84
|
+
headers: { "content-type": "application/json" },
|
|
85
|
+
body: JSON.stringify({ id })
|
|
86
|
+
},
|
|
87
|
+
{ errorMessage: translator("staff.teamMembers.detail.addresses.error", "Failed to delete address.") }
|
|
88
|
+
)
|
|
80
89
|
);
|
|
81
90
|
}
|
|
82
91
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/staff/components/detail/addressesAdapter.ts"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport { apiCallOrThrow, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport type { AddressDataAdapter } from '@open-mercato/ui/backend/detail'\nimport type { AddressTypesAdapter } from '@open-mercato/ui/backend/detail'\nimport { loadStaffDictionaryEntries, createStaffDictionaryEntry } from './dictionaries'\n\ntype Translator = (key: string, fallback?: string, params?: Record<string, string | number>) => string\n\ntype ApiAddressPayload = Record<string, unknown>\n\nexport function createStaffAddressAdapter(translator: Translator): AddressDataAdapter {\n return {\n list: async ({ entityId }) => {\n if (!entityId) return []\n const params = new URLSearchParams({ entityId, pageSize: '100' })\n const payload = await readApiResultOrThrow<ApiAddressPayload>(\n `/api/staff/addresses?${params.toString()}`,\n undefined,\n { errorMessage: translator('staff.teamMembers.detail.addresses.error', 'Failed to load addresses.') },\n )\n const items = Array.isArray(payload?.items) ? payload.items : []\n return items\n .map((item) => {\n if (!item || typeof item !== 'object') return null\n const record = item as Record<string, unknown>\n const rawId = record.id ?? record.address_id ?? null\n const id =\n typeof rawId === 'string'\n ? rawId\n : typeof rawId === 'number' || typeof rawId === 'bigint'\n ? String(rawId)\n : null\n if (!id) return null\n const addressLine1 = typeof record.address_line1 === 'string'\n ? record.address_line1\n : typeof record.addressLine1 === 'string'\n ? record.addressLine1\n : null\n if (!addressLine1) return null\n return {\n id,\n name: typeof record.name === 'string' ? record.name : null,\n purpose: typeof record.purpose === 'string' ? record.purpose : null,\n companyName: typeof record.company_name === 'string'\n ? record.company_name\n : typeof record.companyName === 'string'\n ? record.companyName\n : null,\n addressLine1,\n addressLine2: typeof record.address_line2 === 'string'\n ? record.address_line2\n : typeof record.addressLine2 === 'string'\n ? record.addressLine2\n : null,\n buildingNumber: typeof record.building_number === 'string'\n ? record.building_number\n : typeof record.buildingNumber === 'string'\n ? record.buildingNumber\n : null,\n flatNumber: typeof record.flat_number === 'string'\n ? record.flat_number\n : typeof record.flatNumber === 'string'\n ? record.flatNumber\n : null,\n city: typeof record.city === 'string' ? record.city : null,\n region: typeof record.region === 'string' ? record.region : null,\n postalCode: typeof record.postal_code === 'string'\n ? record.postal_code\n : typeof record.postalCode === 'string'\n ? record.postalCode\n : null,\n country: typeof record.country === 'string' ? record.country : null,\n isPrimary:\n typeof record.is_primary === 'boolean'\n ? record.is_primary\n : typeof record.isPrimary === 'boolean'\n ? record.isPrimary\n : false,\n }\n })\n .filter((value): value is NonNullable<typeof value> => value !== null)\n },\n create: async ({ entityId, payload }) => {\n const response = await apiCallOrThrow<Record<string, unknown>>(\n '/api/staff/addresses',\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({\n entityId,\n ...payload,\n country: payload.country ? payload.country.toUpperCase() : undefined,\n }),\n },\n { errorMessage: translator('staff.teamMembers.detail.addresses.error', 'Failed to save address.') },\n )\n return response.result ?? {}\n },\n update: async ({ id, payload }) => {\n await apiCallOrThrow(\n
|
|
5
|
-
"mappings": ";AAEA,SAAS,gBAAgB,
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport { apiCallOrThrow, readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport type { AddressDataAdapter } from '@open-mercato/ui/backend/detail'\nimport type { AddressTypesAdapter } from '@open-mercato/ui/backend/detail'\nimport { loadStaffDictionaryEntries, createStaffDictionaryEntry } from './dictionaries'\n\ntype Translator = (key: string, fallback?: string, params?: Record<string, string | number>) => string\n\ntype ApiAddressPayload = Record<string, unknown>\n\nexport function createStaffAddressAdapter(translator: Translator): AddressDataAdapter {\n return {\n list: async ({ entityId }) => {\n if (!entityId) return []\n const params = new URLSearchParams({ entityId, pageSize: '100' })\n const payload = await readApiResultOrThrow<ApiAddressPayload>(\n `/api/staff/addresses?${params.toString()}`,\n undefined,\n { errorMessage: translator('staff.teamMembers.detail.addresses.error', 'Failed to load addresses.') },\n )\n const items = Array.isArray(payload?.items) ? payload.items : []\n return items\n .map((item) => {\n if (!item || typeof item !== 'object') return null\n const record = item as Record<string, unknown>\n const rawId = record.id ?? record.address_id ?? null\n const id =\n typeof rawId === 'string'\n ? rawId\n : typeof rawId === 'number' || typeof rawId === 'bigint'\n ? String(rawId)\n : null\n if (!id) return null\n const addressLine1 = typeof record.address_line1 === 'string'\n ? record.address_line1\n : typeof record.addressLine1 === 'string'\n ? record.addressLine1\n : null\n if (!addressLine1) return null\n return {\n id,\n name: typeof record.name === 'string' ? record.name : null,\n purpose: typeof record.purpose === 'string' ? record.purpose : null,\n companyName: typeof record.company_name === 'string'\n ? record.company_name\n : typeof record.companyName === 'string'\n ? record.companyName\n : null,\n addressLine1,\n addressLine2: typeof record.address_line2 === 'string'\n ? record.address_line2\n : typeof record.addressLine2 === 'string'\n ? record.addressLine2\n : null,\n buildingNumber: typeof record.building_number === 'string'\n ? record.building_number\n : typeof record.buildingNumber === 'string'\n ? record.buildingNumber\n : null,\n flatNumber: typeof record.flat_number === 'string'\n ? record.flat_number\n : typeof record.flatNumber === 'string'\n ? record.flatNumber\n : null,\n city: typeof record.city === 'string' ? record.city : null,\n region: typeof record.region === 'string' ? record.region : null,\n postalCode: typeof record.postal_code === 'string'\n ? record.postal_code\n : typeof record.postalCode === 'string'\n ? record.postalCode\n : null,\n country: typeof record.country === 'string' ? record.country : null,\n isPrimary:\n typeof record.is_primary === 'boolean'\n ? record.is_primary\n : typeof record.isPrimary === 'boolean'\n ? record.isPrimary\n : false,\n updatedAt:\n typeof record.updated_at === 'string'\n ? record.updated_at\n : typeof record.updatedAt === 'string'\n ? record.updatedAt\n : null,\n }\n })\n .filter((value): value is NonNullable<typeof value> => value !== null)\n },\n create: async ({ entityId, payload }) => {\n const response = await apiCallOrThrow<Record<string, unknown>>(\n '/api/staff/addresses',\n {\n // optimistic-lock-exempt: address create-only (no prior version to compare)\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({\n entityId,\n ...payload,\n country: payload.country ? payload.country.toUpperCase() : undefined,\n }),\n },\n { errorMessage: translator('staff.teamMembers.detail.addresses.error', 'Failed to save address.') },\n )\n return response.result ?? {}\n },\n update: async ({ id, payload, updatedAt }) => {\n // Send the optimistic-lock header (address's loaded updatedAt) so a stale\n // edit fails with a 409; the shared AddressesSection host surfaces it through\n // surfaceRecordConflict instead of silently overwriting.\n await withScopedApiRequestHeaders(\n buildOptimisticLockHeader(updatedAt ?? null),\n () => apiCallOrThrow(\n '/api/staff/addresses',\n {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({\n id,\n ...payload,\n country: payload.country ? payload.country.toUpperCase() : undefined,\n }),\n },\n { errorMessage: translator('staff.teamMembers.detail.addresses.error', 'Failed to save address.') },\n ),\n )\n },\n delete: async ({ id, updatedAt }) => {\n await withScopedApiRequestHeaders(\n buildOptimisticLockHeader(updatedAt ?? null),\n () => apiCallOrThrow(\n '/api/staff/addresses',\n {\n method: 'DELETE',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ id }),\n },\n { errorMessage: translator('staff.teamMembers.detail.addresses.error', 'Failed to delete address.') },\n ),\n )\n },\n }\n}\n\nexport function createStaffAddressTypesAdapter(translator: Translator): AddressTypesAdapter {\n return {\n list: async () => {\n const entries = await loadStaffDictionaryEntries('addressTypes')\n return entries.map((entry) => ({ value: entry.value, label: entry.label }))\n },\n create: async (value: string) => {\n const entry = await createStaffDictionaryEntry('addressTypes', { value })\n if (!entry) return null\n return { value: entry.value, label: entry.label }\n },\n manageHref: '/backend/config/dictionaries',\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { apiCallOrThrow, readApiResultOrThrow } from "@open-mercato/ui/backend/utils/apiCall";
|
|
2
|
+
import { apiCallOrThrow, readApiResultOrThrow, withScopedApiRequestHeaders } from "@open-mercato/ui/backend/utils/apiCall";
|
|
3
|
+
import { buildOptimisticLockHeader } from "@open-mercato/ui/backend/utils/optimisticLock";
|
|
3
4
|
import { mapCommentSummary } from "@open-mercato/ui/backend/detail/NotesSection";
|
|
4
5
|
function createStaffNotesAdapter(translator) {
|
|
5
6
|
return {
|
|
@@ -31,29 +32,35 @@ function createStaffNotesAdapter(translator) {
|
|
|
31
32
|
);
|
|
32
33
|
return response.result ?? {};
|
|
33
34
|
},
|
|
34
|
-
update: async ({ id, patch }) => {
|
|
35
|
+
update: async ({ id, patch, updatedAt }) => {
|
|
35
36
|
const payload = { id };
|
|
36
37
|
if (patch.body !== void 0) payload.body = patch.body;
|
|
37
38
|
if (patch.appearanceIcon !== void 0) payload.appearanceIcon = patch.appearanceIcon;
|
|
38
39
|
if (patch.appearanceColor !== void 0) payload.appearanceColor = patch.appearanceColor;
|
|
39
|
-
await
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
40
|
+
await withScopedApiRequestHeaders(
|
|
41
|
+
buildOptimisticLockHeader(updatedAt ?? null),
|
|
42
|
+
() => apiCallOrThrow(
|
|
43
|
+
"/api/staff/comments",
|
|
44
|
+
{
|
|
45
|
+
method: "PUT",
|
|
46
|
+
headers: { "content-type": "application/json" },
|
|
47
|
+
body: JSON.stringify(payload)
|
|
48
|
+
},
|
|
49
|
+
{ errorMessage: translator("staff.teamMembers.detail.notes.updateError", "Failed to update note.") }
|
|
50
|
+
)
|
|
47
51
|
);
|
|
48
52
|
},
|
|
49
|
-
delete: async ({ id }) => {
|
|
50
|
-
await
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
53
|
+
delete: async ({ id, updatedAt }) => {
|
|
54
|
+
await withScopedApiRequestHeaders(
|
|
55
|
+
buildOptimisticLockHeader(updatedAt ?? null),
|
|
56
|
+
() => apiCallOrThrow(
|
|
57
|
+
`/api/staff/comments?id=${encodeURIComponent(id)}`,
|
|
58
|
+
{
|
|
59
|
+
method: "DELETE",
|
|
60
|
+
headers: { "content-type": "application/json" }
|
|
61
|
+
},
|
|
62
|
+
{ errorMessage: translator("staff.teamMembers.detail.notes.deleteError", "Failed to delete note") }
|
|
63
|
+
)
|
|
57
64
|
);
|
|
58
65
|
}
|
|
59
66
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/staff/components/detail/notesAdapter.ts"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport { apiCallOrThrow, readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { mapCommentSummary, type NotesDataAdapter } from '@open-mercato/ui/backend/detail/NotesSection'\n\ntype Translator = (key: string, fallback?: string, params?: Record<string, string | number>) => string\n\nexport function createStaffNotesAdapter(translator: Translator): NotesDataAdapter {\n return {\n list: async ({ entityId }) => {\n const params = new URLSearchParams()\n if (entityId) params.set('entityId', entityId)\n const payload = await readApiResultOrThrow<Record<string, unknown>>(\n `/api/staff/comments?${params.toString()}`,\n undefined,\n { errorMessage: translator('staff.teamMembers.detail.notes.loadError', 'Failed to load notes.') },\n )\n const items = Array.isArray(payload?.items) ? payload.items : []\n return items.map(mapCommentSummary)\n },\n create: async ({ entityId, body, appearanceIcon, appearanceColor }) => {\n const response = await apiCallOrThrow<Record<string, unknown>>(\n '/api/staff/comments',\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({\n entityId,\n body,\n appearanceIcon: appearanceIcon ?? undefined,\n appearanceColor: appearanceColor ?? undefined,\n }),\n },\n { errorMessage: translator('staff.teamMembers.detail.notes.error', 'Failed to save note.') },\n )\n return response.result ?? {}\n },\n update: async ({ id, patch }) => {\n const payload: Record<string, unknown> = { id }\n if (patch.body !== undefined) payload.body = patch.body\n if (patch.appearanceIcon !== undefined) payload.appearanceIcon = patch.appearanceIcon\n if (patch.appearanceColor !== undefined) payload.appearanceColor = patch.appearanceColor\n await apiCallOrThrow(\n
|
|
5
|
-
"mappings": ";AAEA,SAAS,gBAAgB,
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport { apiCallOrThrow, readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { mapCommentSummary, type NotesDataAdapter } from '@open-mercato/ui/backend/detail/NotesSection'\n\ntype Translator = (key: string, fallback?: string, params?: Record<string, string | number>) => string\n\nexport function createStaffNotesAdapter(translator: Translator): NotesDataAdapter {\n return {\n list: async ({ entityId }) => {\n const params = new URLSearchParams()\n if (entityId) params.set('entityId', entityId)\n const payload = await readApiResultOrThrow<Record<string, unknown>>(\n `/api/staff/comments?${params.toString()}`,\n undefined,\n { errorMessage: translator('staff.teamMembers.detail.notes.loadError', 'Failed to load notes.') },\n )\n const items = Array.isArray(payload?.items) ? payload.items : []\n return items.map(mapCommentSummary)\n },\n create: async ({ entityId, body, appearanceIcon, appearanceColor }) => {\n const response = await apiCallOrThrow<Record<string, unknown>>(\n '/api/staff/comments',\n {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({\n entityId,\n body,\n appearanceIcon: appearanceIcon ?? undefined,\n appearanceColor: appearanceColor ?? undefined,\n }),\n },\n { errorMessage: translator('staff.teamMembers.detail.notes.error', 'Failed to save note.') },\n )\n return response.result ?? {}\n },\n update: async ({ id, patch, updatedAt }) => {\n const payload: Record<string, unknown> = { id }\n if (patch.body !== undefined) payload.body = patch.body\n if (patch.appearanceIcon !== undefined) payload.appearanceIcon = patch.appearanceIcon\n if (patch.appearanceColor !== undefined) payload.appearanceColor = patch.appearanceColor\n // Send the optimistic-lock header (note's loaded updatedAt) so a stale edit\n // fails with a 409; the shared NotesSection host surfaces it through\n // surfaceRecordConflict instead of silently overwriting.\n await withScopedApiRequestHeaders(\n buildOptimisticLockHeader(updatedAt ?? null),\n () => apiCallOrThrow(\n '/api/staff/comments',\n {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(payload),\n },\n { errorMessage: translator('staff.teamMembers.detail.notes.updateError', 'Failed to update note.') },\n ),\n )\n },\n delete: async ({ id, updatedAt }) => {\n await withScopedApiRequestHeaders(\n buildOptimisticLockHeader(updatedAt ?? null),\n () => apiCallOrThrow(\n `/api/staff/comments?id=${encodeURIComponent(id)}`,\n {\n method: 'DELETE',\n headers: { 'content-type': 'application/json' },\n },\n { errorMessage: translator('staff.teamMembers.detail.notes.deleteError', 'Failed to delete note') },\n ),\n )\n },\n }\n}\n"],
|
|
5
|
+
"mappings": ";AAEA,SAAS,gBAAgB,sBAAsB,mCAAmC;AAClF,SAAS,iCAAiC;AAC1C,SAAS,yBAAgD;AAIlD,SAAS,wBAAwB,YAA0C;AAChF,SAAO;AAAA,IACL,MAAM,OAAO,EAAE,SAAS,MAAM;AAC5B,YAAM,SAAS,IAAI,gBAAgB;AACnC,UAAI,SAAU,QAAO,IAAI,YAAY,QAAQ;AAC7C,YAAM,UAAU,MAAM;AAAA,QACpB,uBAAuB,OAAO,SAAS,CAAC;AAAA,QACxC;AAAA,QACA,EAAE,cAAc,WAAW,4CAA4C,uBAAuB,EAAE;AAAA,MAClG;AACA,YAAM,QAAQ,MAAM,QAAQ,SAAS,KAAK,IAAI,QAAQ,QAAQ,CAAC;AAC/D,aAAO,MAAM,IAAI,iBAAiB;AAAA,IACpC;AAAA,IACA,QAAQ,OAAO,EAAE,UAAU,MAAM,gBAAgB,gBAAgB,MAAM;AACrE,YAAM,WAAW,MAAM;AAAA,QACrB;AAAA,QACA;AAAA,UACE,QAAQ;AAAA,UACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,UAC9C,MAAM,KAAK,UAAU;AAAA,YACnB;AAAA,YACA;AAAA,YACA,gBAAgB,kBAAkB;AAAA,YAClC,iBAAiB,mBAAmB;AAAA,UACtC,CAAC;AAAA,QACH;AAAA,QACA,EAAE,cAAc,WAAW,wCAAwC,sBAAsB,EAAE;AAAA,MAC7F;AACA,aAAO,SAAS,UAAU,CAAC;AAAA,IAC7B;AAAA,IACA,QAAQ,OAAO,EAAE,IAAI,OAAO,UAAU,MAAM;AAC1C,YAAM,UAAmC,EAAE,GAAG;AAC9C,UAAI,MAAM,SAAS,OAAW,SAAQ,OAAO,MAAM;AACnD,UAAI,MAAM,mBAAmB,OAAW,SAAQ,iBAAiB,MAAM;AACvE,UAAI,MAAM,oBAAoB,OAAW,SAAQ,kBAAkB,MAAM;AAIzE,YAAM;AAAA,QACJ,0BAA0B,aAAa,IAAI;AAAA,QAC3C,MAAM;AAAA,UACJ;AAAA,UACA;AAAA,YACE,QAAQ;AAAA,YACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,YAC9C,MAAM,KAAK,UAAU,OAAO;AAAA,UAC9B;AAAA,UACA,EAAE,cAAc,WAAW,8CAA8C,wBAAwB,EAAE;AAAA,QACrG;AAAA,MACF;AAAA,IACF;AAAA,IACA,QAAQ,OAAO,EAAE,IAAI,UAAU,MAAM;AACnC,YAAM;AAAA,QACJ,0BAA0B,aAAa,IAAI;AAAA,QAC3C,MAAM;AAAA,UACJ,0BAA0B,mBAAmB,EAAE,CAAC;AAAA,UAChD;AAAA,YACE,QAAQ;AAAA,YACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,UAChD;AAAA,UACA,EAAE,cAAc,WAAW,8CAA8C,uBAAuB,EAAE;AAAA,QACpG;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|