@open-mercato/core 0.6.6-develop.6089.1.a7ed560528 → 0.6.6-develop.6121.1.5797a901b3
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/generated/entities/catalog_product/index.js +52 -0
- package/dist/generated/entities/catalog_product/index.js.map +2 -2
- package/dist/generated/entities/catalog_product_variant/index.js +4 -0
- package/dist/generated/entities/catalog_product_variant/index.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +28 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/modules/catalog/api/products/route.js +103 -33
- package/dist/modules/catalog/api/products/route.js.map +2 -2
- package/dist/modules/catalog/api/variants/route.js +4 -0
- package/dist/modules/catalog/api/variants/route.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/[id]/page.js +46 -2
- 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 +4 -0
- package/dist/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/[productId]/variants/create/page.js +2 -0
- package/dist/modules/catalog/backend/catalog/products/[productId]/variants/create/page.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/create/page.js +42 -2
- package/dist/modules/catalog/backend/catalog/products/create/page.js.map +2 -2
- package/dist/modules/catalog/commands/products.js +251 -14
- package/dist/modules/catalog/commands/products.js.map +2 -2
- package/dist/modules/catalog/commands/variants.js +72 -1
- package/dist/modules/catalog/commands/variants.js.map +2 -2
- package/dist/modules/catalog/components/products/ProductComplianceSection.js +500 -0
- package/dist/modules/catalog/components/products/ProductComplianceSection.js.map +7 -0
- package/dist/modules/catalog/components/products/VariantBuilder.js +39 -1
- package/dist/modules/catalog/components/products/VariantBuilder.js.map +2 -2
- package/dist/modules/catalog/components/products/productForm.js +164 -2
- package/dist/modules/catalog/components/products/productForm.js.map +2 -2
- package/dist/modules/catalog/components/products/variantForm.js +2 -0
- package/dist/modules/catalog/components/products/variantForm.js.map +2 -2
- package/dist/modules/catalog/data/entities.js +93 -0
- package/dist/modules/catalog/data/entities.js.map +2 -2
- package/dist/modules/catalog/data/types.js +28 -0
- package/dist/modules/catalog/data/types.js.map +2 -2
- package/dist/modules/catalog/data/validators.js +100 -5
- package/dist/modules/catalog/data/validators.js.map +2 -2
- package/dist/modules/catalog/lib/gtin.js +61 -0
- package/dist/modules/catalog/lib/gtin.js.map +7 -0
- package/dist/modules/catalog/migrations/Migration20260611090000.js +17 -0
- package/dist/modules/catalog/migrations/Migration20260611090000.js.map +7 -0
- package/dist/modules/catalog/translations.js +1 -1
- package/dist/modules/catalog/translations.js.map +2 -2
- package/dist/modules/configs/api/cache/route.js +60 -10
- package/dist/modules/configs/api/cache/route.js.map +3 -3
- package/dist/modules/configs/components/CachePanel.js +52 -29
- package/dist/modules/configs/components/CachePanel.js.map +2 -2
- package/dist/modules/currencies/api/currencies/options/route.js +18 -4
- package/dist/modules/currencies/api/currencies/options/route.js.map +2 -2
- package/dist/modules/currencies/services/rateFetchingService.js +35 -18
- package/dist/modules/currencies/services/rateFetchingService.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/users/[id]/page.js +16 -16
- package/dist/modules/customer_accounts/backend/customer_accounts/users/[id]/page.js.map +2 -2
- package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js +1 -1
- package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js.map +2 -2
- package/dist/modules/customers/backend/calendar/page.js +10 -0
- package/dist/modules/customers/backend/calendar/page.js.map +7 -0
- package/dist/modules/customers/backend/calendar/page.meta.js +25 -0
- package/dist/modules/customers/backend/calendar/page.meta.js.map +7 -0
- package/dist/modules/customers/cli.js +1 -0
- package/dist/modules/customers/cli.js.map +2 -2
- package/dist/modules/customers/components/calendar/AgendaList.js +182 -0
- package/dist/modules/customers/components/calendar/AgendaList.js.map +7 -0
- package/dist/modules/customers/components/calendar/CalendarEventEditor.js +331 -0
- package/dist/modules/customers/components/calendar/CalendarEventEditor.js.map +7 -0
- package/dist/modules/customers/components/calendar/CalendarFooter.js +48 -0
- package/dist/modules/customers/components/calendar/CalendarFooter.js.map +7 -0
- package/dist/modules/customers/components/calendar/CalendarHeader.js +36 -0
- package/dist/modules/customers/components/calendar/CalendarHeader.js.map +7 -0
- package/dist/modules/customers/components/calendar/CalendarScreen.js +516 -0
- package/dist/modules/customers/components/calendar/CalendarScreen.js.map +7 -0
- package/dist/modules/customers/components/calendar/CalendarSettingsModal.js +163 -0
- package/dist/modules/customers/components/calendar/CalendarSettingsModal.js.map +7 -0
- package/dist/modules/customers/components/calendar/CalendarTabs.js +60 -0
- package/dist/modules/customers/components/calendar/CalendarTabs.js.map +7 -0
- package/dist/modules/customers/components/calendar/CalendarToolbar.js +262 -0
- package/dist/modules/customers/components/calendar/CalendarToolbar.js.map +7 -0
- package/dist/modules/customers/components/calendar/EventBlock.js +149 -0
- package/dist/modules/customers/components/calendar/EventBlock.js.map +7 -0
- package/dist/modules/customers/components/calendar/EventPeekPopover.js +72 -0
- package/dist/modules/customers/components/calendar/EventPeekPopover.js.map +7 -0
- package/dist/modules/customers/components/calendar/MonthGrid.js +214 -0
- package/dist/modules/customers/components/calendar/MonthGrid.js.map +7 -0
- package/dist/modules/customers/components/calendar/ShortcutsDialog.js +44 -0
- package/dist/modules/customers/components/calendar/ShortcutsDialog.js.map +7 -0
- package/dist/modules/customers/components/calendar/TimeGrid.js +410 -0
- package/dist/modules/customers/components/calendar/TimeGrid.js.map +7 -0
- package/dist/modules/customers/components/calendar/UpcomingCards.js +175 -0
- package/dist/modules/customers/components/calendar/UpcomingCards.js.map +7 -0
- package/dist/modules/customers/components/calendar/editor/CategoryField.js +75 -0
- package/dist/modules/customers/components/calendar/editor/CategoryField.js.map +7 -0
- package/dist/modules/customers/components/calendar/editor/LocationField.js +30 -0
- package/dist/modules/customers/components/calendar/editor/LocationField.js.map +7 -0
- package/dist/modules/customers/components/calendar/editor/PeopleField.js +135 -0
- package/dist/modules/customers/components/calendar/editor/PeopleField.js.map +7 -0
- package/dist/modules/customers/components/calendar/editor/RelatedToField.js +218 -0
- package/dist/modules/customers/components/calendar/editor/RelatedToField.js.map +7 -0
- package/dist/modules/customers/components/calendar/editor/RepeatField.js +119 -0
- package/dist/modules/customers/components/calendar/editor/RepeatField.js.map +7 -0
- package/dist/modules/customers/components/calendar/editor/ScheduleSection.js +83 -0
- package/dist/modules/customers/components/calendar/editor/ScheduleSection.js.map +7 -0
- package/dist/modules/customers/components/calendar/editor/SegmentGroup.js +44 -0
- package/dist/modules/customers/components/calendar/editor/SegmentGroup.js.map +7 -0
- package/dist/modules/customers/components/calendar/editor/hooks.js +132 -0
- package/dist/modules/customers/components/calendar/editor/hooks.js.map +7 -0
- package/dist/modules/customers/components/calendar/editor/inputs.js +160 -0
- package/dist/modules/customers/components/calendar/editor/inputs.js.map +7 -0
- package/dist/modules/customers/components/calendar/editor/lookups.js +107 -0
- package/dist/modules/customers/components/calendar/editor/lookups.js.map +7 -0
- package/dist/modules/customers/components/calendar/types.js +30 -0
- package/dist/modules/customers/components/calendar/types.js.map +7 -0
- package/dist/modules/customers/components/calendar/useCalendarItems.js +131 -0
- package/dist/modules/customers/components/calendar/useCalendarItems.js.map +7 -0
- package/dist/modules/customers/components/calendar/useCalendarPreferences.js +41 -0
- package/dist/modules/customers/components/calendar/useCalendarPreferences.js.map +7 -0
- package/dist/modules/customers/lib/calendar/categories.js +28 -0
- package/dist/modules/customers/lib/calendar/categories.js.map +7 -0
- package/dist/modules/customers/lib/calendar/conflicts.js +72 -0
- package/dist/modules/customers/lib/calendar/conflicts.js.map +7 -0
- package/dist/modules/customers/lib/calendar/editorPayload.js +271 -0
- package/dist/modules/customers/lib/calendar/editorPayload.js.map +7 -0
- package/dist/modules/customers/lib/calendar/grid.js +48 -0
- package/dist/modules/customers/lib/calendar/grid.js.map +7 -0
- package/dist/modules/customers/lib/calendar/layout.js +39 -0
- package/dist/modules/customers/lib/calendar/layout.js.map +7 -0
- package/dist/modules/customers/lib/calendar/mapItem.js +79 -0
- package/dist/modules/customers/lib/calendar/mapItem.js.map +7 -0
- package/dist/modules/customers/lib/calendar/preferences.js +71 -0
- package/dist/modules/customers/lib/calendar/preferences.js.map +7 -0
- package/dist/modules/customers/lib/calendar/range.js +46 -0
- package/dist/modules/customers/lib/calendar/range.js.map +7 -0
- package/dist/modules/customers/lib/calendar/recurrence.js +113 -0
- package/dist/modules/customers/lib/calendar/recurrence.js.map +7 -0
- package/dist/modules/dashboards/services/widgetDataService.js +5 -5
- package/dist/modules/dashboards/services/widgetDataService.js.map +2 -2
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js +61 -1
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js.map +2 -2
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/route.js +33 -1
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/route.js.map +2 -2
- package/dist/modules/dictionaries/api/[dictionaryId]/route.js +61 -1
- package/dist/modules/dictionaries/api/[dictionaryId]/route.js.map +2 -2
- package/dist/modules/dictionaries/api/route.js +33 -1
- package/dist/modules/dictionaries/api/route.js.map +2 -2
- package/dist/modules/feature_toggles/lib/queries.js +36 -52
- package/dist/modules/feature_toggles/lib/queries.js.map +2 -2
- package/dist/modules/messages/commands/actions.js +81 -9
- package/dist/modules/messages/commands/actions.js.map +2 -2
- package/dist/modules/perspectives/api/[tableId]/[perspectiveId]/route.js +32 -1
- package/dist/modules/perspectives/api/[tableId]/[perspectiveId]/route.js.map +2 -2
- package/dist/modules/perspectives/api/[tableId]/roles/[roleId]/route.js +32 -1
- package/dist/modules/perspectives/api/[tableId]/roles/[roleId]/route.js.map +2 -2
- package/dist/modules/perspectives/api/[tableId]/route.js +73 -2
- package/dist/modules/perspectives/api/[tableId]/route.js.map +2 -2
- package/dist/modules/perspectives/services/perspectiveService.js +5 -3
- package/dist/modules/perspectives/services/perspectiveService.js.map +2 -2
- package/dist/modules/planner/api/access.js +9 -0
- package/dist/modules/planner/api/access.js.map +2 -2
- package/dist/modules/planner/api/availability-date-specific.js +22 -1
- package/dist/modules/planner/api/availability-date-specific.js.map +2 -2
- package/dist/modules/planner/api/availability-weekly.js +22 -1
- package/dist/modules/planner/api/availability-weekly.js.map +2 -2
- package/dist/modules/resources/api/resources/tags/assign/route.js +39 -0
- package/dist/modules/resources/api/resources/tags/assign/route.js.map +2 -2
- package/dist/modules/resources/api/resources/tags/unassign/route.js +39 -0
- package/dist/modules/resources/api/resources/tags/unassign/route.js.map +2 -2
- package/dist/modules/sales/api/settings/document-numbers/route.js +33 -1
- package/dist/modules/sales/api/settings/document-numbers/route.js.map +2 -2
- package/dist/modules/sales/api/settings/order-editing/route.js +35 -3
- package/dist/modules/sales/api/settings/order-editing/route.js.map +2 -2
- package/dist/modules/staff/api/leave-requests/accept/route.js +41 -0
- package/dist/modules/staff/api/leave-requests/accept/route.js.map +2 -2
- package/dist/modules/staff/api/leave-requests/reject/route.js +41 -0
- package/dist/modules/staff/api/leave-requests/reject/route.js.map +2 -2
- package/dist/modules/staff/api/team-members/self/route.js +40 -0
- package/dist/modules/staff/api/team-members/self/route.js.map +2 -2
- package/dist/modules/staff/api/team-members/tags/assign/route.js +41 -0
- package/dist/modules/staff/api/team-members/tags/assign/route.js.map +2 -2
- package/dist/modules/staff/api/team-members/tags/unassign/route.js +41 -0
- package/dist/modules/staff/api/team-members/tags/unassign/route.js.map +2 -2
- package/dist/modules/translations/api/[entityType]/[entityId]/route.js +61 -1
- package/dist/modules/translations/api/[entityType]/[entityId]/route.js.map +2 -2
- package/dist/modules/translations/api/context.js +7 -0
- package/dist/modules/translations/api/context.js.map +2 -2
- package/dist/modules/translations/api/put/locales.js +33 -1
- package/dist/modules/translations/api/put/locales.js.map +2 -2
- package/dist/modules/workflows/backend/definitions/visual-editor/page.js +6 -7
- package/dist/modules/workflows/backend/definitions/visual-editor/page.js.map +2 -2
- package/dist/modules/workflows/backend/instances/[id]/page.js.map +1 -1
- package/dist/modules/workflows/components/EdgeEditDialog.js.map +1 -1
- package/dist/modules/workflows/components/EdgeEditDialogCrudForm.js.map +1 -1
- package/dist/modules/workflows/components/NodeEditDialog.js.map +1 -1
- package/dist/modules/workflows/components/NodeEditDialogCrudForm.js.map +1 -1
- package/dist/modules/workflows/components/WorkflowGraph.js.map +1 -1
- package/dist/modules/workflows/components/WorkflowGraphImpl.js +17 -9
- package/dist/modules/workflows/components/WorkflowGraphImpl.js.map +2 -2
- package/dist/modules/workflows/components/mobile/MobileVisualEditor.js.map +1 -1
- package/dist/modules/workflows/frontend/checkout-demo/deriveCurrentStep.js +8 -0
- package/dist/modules/workflows/frontend/checkout-demo/deriveCurrentStep.js.map +7 -0
- package/dist/modules/workflows/frontend/checkout-demo/page.js +2 -20
- package/dist/modules/workflows/frontend/checkout-demo/page.js.map +2 -2
- package/dist/modules/workflows/lib/graph-utils.js +8 -0
- package/dist/modules/workflows/lib/graph-utils.js.map +2 -2
- package/generated/entities/catalog_product/index.ts +26 -0
- package/generated/entities/catalog_product_variant/index.ts +2 -0
- package/generated/entity-fields-registry.ts +28 -0
- package/package.json +7 -7
- package/src/modules/catalog/api/products/route.ts +123 -39
- package/src/modules/catalog/api/variants/route.ts +4 -0
- package/src/modules/catalog/backend/catalog/products/[id]/page.tsx +43 -0
- package/src/modules/catalog/backend/catalog/products/[productId]/variants/[variantId]/page.tsx +14 -0
- package/src/modules/catalog/backend/catalog/products/[productId]/variants/create/page.tsx +2 -0
- package/src/modules/catalog/backend/catalog/products/create/page.tsx +41 -0
- package/src/modules/catalog/commands/products.ts +307 -2
- package/src/modules/catalog/commands/variants.ts +90 -1
- package/src/modules/catalog/components/products/ProductComplianceSection.tsx +497 -0
- package/src/modules/catalog/components/products/VariantBuilder.tsx +43 -0
- package/src/modules/catalog/components/products/productForm.ts +262 -0
- package/src/modules/catalog/components/products/variantForm.ts +4 -0
- package/src/modules/catalog/data/entities.ts +97 -0
- package/src/modules/catalog/data/types.ts +36 -0
- package/src/modules/catalog/data/validators.ts +159 -3
- package/src/modules/catalog/i18n/de.json +64 -0
- package/src/modules/catalog/i18n/en.json +64 -0
- package/src/modules/catalog/i18n/es.json +64 -0
- package/src/modules/catalog/i18n/pl.json +64 -0
- package/src/modules/catalog/lib/gtin.ts +66 -0
- package/src/modules/catalog/migrations/.snapshot-open-mercato.json +457 -0
- package/src/modules/catalog/migrations/Migration20260611090000.ts +17 -0
- package/src/modules/catalog/translations.ts +1 -1
- package/src/modules/configs/api/cache/route.ts +72 -10
- package/src/modules/configs/components/CachePanel.tsx +59 -29
- package/src/modules/currencies/api/currencies/options/route.ts +22 -4
- package/src/modules/currencies/services/rateFetchingService.ts +63 -26
- package/src/modules/customer_accounts/backend/customer_accounts/users/[id]/page.tsx +18 -18
- package/src/modules/customer_accounts/backend/customer_accounts/users/page.tsx +1 -1
- package/src/modules/customer_accounts/i18n/de.json +1 -1
- package/src/modules/customer_accounts/i18n/en.json +1 -1
- package/src/modules/customer_accounts/i18n/es.json +1 -1
- package/src/modules/customer_accounts/i18n/pl.json +1 -1
- package/src/modules/customers/backend/calendar/page.meta.ts +23 -0
- package/src/modules/customers/backend/calendar/page.tsx +12 -0
- package/src/modules/customers/cli.ts +1 -0
- package/src/modules/customers/components/calendar/AgendaList.tsx +219 -0
- package/src/modules/customers/components/calendar/CalendarEventEditor.tsx +386 -0
- package/src/modules/customers/components/calendar/CalendarFooter.tsx +61 -0
- package/src/modules/customers/components/calendar/CalendarHeader.tsx +40 -0
- package/src/modules/customers/components/calendar/CalendarScreen.tsx +590 -0
- package/src/modules/customers/components/calendar/CalendarSettingsModal.tsx +207 -0
- package/src/modules/customers/components/calendar/CalendarTabs.tsx +63 -0
- package/src/modules/customers/components/calendar/CalendarToolbar.tsx +295 -0
- package/src/modules/customers/components/calendar/EventBlock.tsx +205 -0
- package/src/modules/customers/components/calendar/EventPeekPopover.tsx +100 -0
- package/src/modules/customers/components/calendar/MonthGrid.tsx +236 -0
- package/src/modules/customers/components/calendar/ShortcutsDialog.tsx +57 -0
- package/src/modules/customers/components/calendar/TimeGrid.tsx +510 -0
- package/src/modules/customers/components/calendar/UpcomingCards.tsx +220 -0
- package/src/modules/customers/components/calendar/editor/CategoryField.tsx +79 -0
- package/src/modules/customers/components/calendar/editor/LocationField.tsx +37 -0
- package/src/modules/customers/components/calendar/editor/PeopleField.tsx +148 -0
- package/src/modules/customers/components/calendar/editor/RelatedToField.tsx +242 -0
- package/src/modules/customers/components/calendar/editor/RepeatField.tsx +132 -0
- package/src/modules/customers/components/calendar/editor/ScheduleSection.tsx +110 -0
- package/src/modules/customers/components/calendar/editor/SegmentGroup.tsx +50 -0
- package/src/modules/customers/components/calendar/editor/hooks.ts +162 -0
- package/src/modules/customers/components/calendar/editor/inputs.tsx +158 -0
- package/src/modules/customers/components/calendar/editor/lookups.ts +160 -0
- package/src/modules/customers/components/calendar/types.ts +163 -0
- package/src/modules/customers/components/calendar/useCalendarItems.ts +162 -0
- package/src/modules/customers/components/calendar/useCalendarPreferences.ts +52 -0
- package/src/modules/customers/i18n/de.json +195 -0
- package/src/modules/customers/i18n/en.json +195 -0
- package/src/modules/customers/i18n/es.json +195 -0
- package/src/modules/customers/i18n/pl.json +195 -0
- package/src/modules/customers/lib/calendar/categories.ts +26 -0
- package/src/modules/customers/lib/calendar/conflicts.ts +117 -0
- package/src/modules/customers/lib/calendar/editorPayload.ts +388 -0
- package/src/modules/customers/lib/calendar/grid.ts +50 -0
- package/src/modules/customers/lib/calendar/layout.ts +47 -0
- package/src/modules/customers/lib/calendar/mapItem.ts +94 -0
- package/src/modules/customers/lib/calendar/preferences.ts +95 -0
- package/src/modules/customers/lib/calendar/range.ts +45 -0
- package/src/modules/customers/lib/calendar/recurrence.ts +137 -0
- package/src/modules/dashboards/services/widgetDataService.ts +8 -6
- package/src/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.ts +61 -1
- package/src/modules/dictionaries/api/[dictionaryId]/entries/route.ts +33 -1
- package/src/modules/dictionaries/api/[dictionaryId]/route.ts +65 -1
- package/src/modules/dictionaries/api/route.ts +36 -1
- package/src/modules/feature_toggles/lib/queries.ts +41 -60
- package/src/modules/messages/commands/actions.ts +100 -7
- package/src/modules/perspectives/api/[tableId]/[perspectiveId]/route.ts +34 -1
- package/src/modules/perspectives/api/[tableId]/roles/[roleId]/route.ts +34 -1
- package/src/modules/perspectives/api/[tableId]/route.ts +107 -32
- package/src/modules/perspectives/services/perspectiveService.ts +9 -5
- package/src/modules/planner/api/access.ts +9 -0
- package/src/modules/planner/api/availability-date-specific.ts +22 -1
- package/src/modules/planner/api/availability-weekly.ts +22 -1
- package/src/modules/resources/api/resources/tags/assign/route.ts +42 -0
- package/src/modules/resources/api/resources/tags/unassign/route.ts +42 -0
- package/src/modules/sales/api/settings/document-numbers/route.ts +35 -1
- package/src/modules/sales/api/settings/order-editing/route.ts +37 -3
- package/src/modules/staff/api/leave-requests/accept/route.ts +45 -0
- package/src/modules/staff/api/leave-requests/reject/route.ts +45 -0
- package/src/modules/staff/api/team-members/self/route.ts +43 -0
- package/src/modules/staff/api/team-members/tags/assign/route.ts +45 -0
- package/src/modules/staff/api/team-members/tags/unassign/route.ts +45 -0
- package/src/modules/translations/api/[entityType]/[entityId]/route.ts +65 -1
- package/src/modules/translations/api/context.ts +7 -0
- package/src/modules/translations/api/put/locales.ts +35 -1
- package/src/modules/workflows/backend/definitions/visual-editor/page.tsx +11 -9
- package/src/modules/workflows/backend/instances/[id]/page.tsx +1 -1
- package/src/modules/workflows/components/EdgeEditDialog.tsx +1 -1
- package/src/modules/workflows/components/EdgeEditDialogCrudForm.tsx +1 -1
- package/src/modules/workflows/components/NodeEditDialog.tsx +1 -1
- package/src/modules/workflows/components/NodeEditDialogCrudForm.tsx +1 -1
- package/src/modules/workflows/components/WorkflowGraph.tsx +2 -2
- package/src/modules/workflows/components/WorkflowGraphImpl.tsx +27 -13
- package/src/modules/workflows/components/mobile/MobileVisualEditor.tsx +3 -3
- package/src/modules/workflows/frontend/checkout-demo/deriveCurrentStep.ts +12 -0
- package/src/modules/workflows/frontend/checkout-demo/page.tsx +3 -23
- package/src/modules/workflows/lib/graph-utils.ts +21 -1
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Button } from "@open-mercato/ui/primitives/button";
|
|
4
|
+
import { Kbd } from "@open-mercato/ui/primitives/kbd";
|
|
5
|
+
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
6
|
+
const CALENDAR_SHORTCUTS = [
|
|
7
|
+
{ key: "T", labelKey: "customers.calendar.shortcuts.today", fallback: "Today" },
|
|
8
|
+
{ key: "D", labelKey: "customers.calendar.shortcuts.dayView", fallback: "Day view" },
|
|
9
|
+
{ key: "W", labelKey: "customers.calendar.shortcuts.week", fallback: "Week" },
|
|
10
|
+
{ key: "M", labelKey: "customers.calendar.shortcuts.month", fallback: "Month" },
|
|
11
|
+
{ key: "A", labelKey: "customers.calendar.shortcuts.agenda", fallback: "Agenda" },
|
|
12
|
+
{ key: "N", labelKey: "customers.calendar.shortcuts.newEvent", fallback: "New event" },
|
|
13
|
+
{ key: "/", labelKey: "customers.calendar.shortcuts.search", fallback: "Search" },
|
|
14
|
+
{ key: "?", labelKey: "customers.calendar.shortcuts.help", fallback: "Shortcuts" }
|
|
15
|
+
];
|
|
16
|
+
function CalendarFooter({ timezoneLabel, onOpenShortcuts }) {
|
|
17
|
+
const t = useT();
|
|
18
|
+
return /* @__PURE__ */ jsxs("footer", { className: "flex flex-wrap items-center gap-x-4 gap-y-1.5 border-t bg-muted/40 px-4 py-2", children: [
|
|
19
|
+
CALENDAR_SHORTCUTS.map((shortcut) => {
|
|
20
|
+
const legend = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
21
|
+
/* @__PURE__ */ jsx(Kbd, { children: shortcut.key }),
|
|
22
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: t(shortcut.labelKey, shortcut.fallback) })
|
|
23
|
+
] });
|
|
24
|
+
if (shortcut.key === "?" && onOpenShortcuts) {
|
|
25
|
+
return /* @__PURE__ */ jsx(
|
|
26
|
+
Button,
|
|
27
|
+
{
|
|
28
|
+
type: "button",
|
|
29
|
+
variant: "ghost",
|
|
30
|
+
size: "sm",
|
|
31
|
+
className: "h-auto gap-1.5 p-0 font-normal hover:bg-transparent",
|
|
32
|
+
"aria-label": t("customers.calendar.shortcuts.title", "Keyboard shortcuts"),
|
|
33
|
+
onClick: onOpenShortcuts,
|
|
34
|
+
children: legend
|
|
35
|
+
},
|
|
36
|
+
shortcut.key
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
return /* @__PURE__ */ jsx("span", { className: "inline-flex items-center gap-1.5", children: legend }, shortcut.key);
|
|
40
|
+
}),
|
|
41
|
+
/* @__PURE__ */ jsx("span", { className: "ml-auto text-xs text-muted-foreground", children: timezoneLabel })
|
|
42
|
+
] });
|
|
43
|
+
}
|
|
44
|
+
export {
|
|
45
|
+
CALENDAR_SHORTCUTS,
|
|
46
|
+
CalendarFooter
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=CalendarFooter.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/modules/customers/components/calendar/CalendarFooter.tsx"],
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Kbd } from '@open-mercato/ui/primitives/kbd'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport type { CalendarFooterProps } from './types'\n\nexport const CALENDAR_SHORTCUTS: ReadonlyArray<{\n key: string\n labelKey: string\n fallback: string\n}> = [\n { key: 'T', labelKey: 'customers.calendar.shortcuts.today', fallback: 'Today' },\n { key: 'D', labelKey: 'customers.calendar.shortcuts.dayView', fallback: 'Day view' },\n { key: 'W', labelKey: 'customers.calendar.shortcuts.week', fallback: 'Week' },\n { key: 'M', labelKey: 'customers.calendar.shortcuts.month', fallback: 'Month' },\n { key: 'A', labelKey: 'customers.calendar.shortcuts.agenda', fallback: 'Agenda' },\n { key: 'N', labelKey: 'customers.calendar.shortcuts.newEvent', fallback: 'New event' },\n { key: '/', labelKey: 'customers.calendar.shortcuts.search', fallback: 'Search' },\n { key: '?', labelKey: 'customers.calendar.shortcuts.help', fallback: 'Shortcuts' },\n]\n\nexport function CalendarFooter({ timezoneLabel, onOpenShortcuts }: CalendarFooterProps) {\n const t = useT()\n return (\n <footer className=\"flex flex-wrap items-center gap-x-4 gap-y-1.5 border-t bg-muted/40 px-4 py-2\">\n {CALENDAR_SHORTCUTS.map((shortcut) => {\n const legend = (\n <>\n <Kbd>{shortcut.key}</Kbd>\n <span className=\"text-xs text-muted-foreground\">\n {t(shortcut.labelKey, shortcut.fallback)}\n </span>\n </>\n )\n if (shortcut.key === '?' && onOpenShortcuts) {\n return (\n <Button\n key={shortcut.key}\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-auto gap-1.5 p-0 font-normal hover:bg-transparent\"\n aria-label={t('customers.calendar.shortcuts.title', 'Keyboard shortcuts')}\n onClick={onOpenShortcuts}\n >\n {legend}\n </Button>\n )\n }\n return (\n <span key={shortcut.key} className=\"inline-flex items-center gap-1.5\">\n {legend}\n </span>\n )\n })}\n <span className=\"ml-auto text-xs text-muted-foreground\">{timezoneLabel}</span>\n </footer>\n )\n}\n"],
|
|
5
|
+
"mappings": ";AA6BU,mBACE,KADF;AA1BV,SAAS,cAAc;AACvB,SAAS,WAAW;AACpB,SAAS,YAAY;AAGd,MAAM,qBAIR;AAAA,EACH,EAAE,KAAK,KAAK,UAAU,sCAAsC,UAAU,QAAQ;AAAA,EAC9E,EAAE,KAAK,KAAK,UAAU,wCAAwC,UAAU,WAAW;AAAA,EACnF,EAAE,KAAK,KAAK,UAAU,qCAAqC,UAAU,OAAO;AAAA,EAC5E,EAAE,KAAK,KAAK,UAAU,sCAAsC,UAAU,QAAQ;AAAA,EAC9E,EAAE,KAAK,KAAK,UAAU,uCAAuC,UAAU,SAAS;AAAA,EAChF,EAAE,KAAK,KAAK,UAAU,yCAAyC,UAAU,YAAY;AAAA,EACrF,EAAE,KAAK,KAAK,UAAU,uCAAuC,UAAU,SAAS;AAAA,EAChF,EAAE,KAAK,KAAK,UAAU,qCAAqC,UAAU,YAAY;AACnF;AAEO,SAAS,eAAe,EAAE,eAAe,gBAAgB,GAAwB;AACtF,QAAM,IAAI,KAAK;AACf,SACE,qBAAC,YAAO,WAAU,gFACf;AAAA,uBAAmB,IAAI,CAAC,aAAa;AACpC,YAAM,SACJ,iCACE;AAAA,4BAAC,OAAK,mBAAS,KAAI;AAAA,QACnB,oBAAC,UAAK,WAAU,iCACb,YAAE,SAAS,UAAU,SAAS,QAAQ,GACzC;AAAA,SACF;AAEF,UAAI,SAAS,QAAQ,OAAO,iBAAiB;AAC3C,eACE;AAAA,UAAC;AAAA;AAAA,YAEC,MAAK;AAAA,YACL,SAAQ;AAAA,YACR,MAAK;AAAA,YACL,WAAU;AAAA,YACV,cAAY,EAAE,sCAAsC,oBAAoB;AAAA,YACxE,SAAS;AAAA,YAER;AAAA;AAAA,UARI,SAAS;AAAA,QAShB;AAAA,MAEJ;AACA,aACE,oBAAC,UAAwB,WAAU,oCAChC,oBADQ,SAAS,GAEpB;AAAA,IAEJ,CAAC;AAAA,IACD,oBAAC,UAAK,WAAU,yCAAyC,yBAAc;AAAA,KACzE;AAEJ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { Plus } from "lucide-react";
|
|
5
|
+
import { Button } from "@open-mercato/ui/primitives/button";
|
|
6
|
+
import { useLocale, useT } from "@open-mercato/shared/lib/i18n/context";
|
|
7
|
+
function CalendarHeader({ view, anchor, onNewEvent }) {
|
|
8
|
+
const t = useT();
|
|
9
|
+
const locale = useLocale();
|
|
10
|
+
const title = React.useMemo(() => {
|
|
11
|
+
if (view === "agenda") return t("customers.calendar.header.titleAgenda", "Upcoming");
|
|
12
|
+
if (view === "month") {
|
|
13
|
+
return new Intl.DateTimeFormat(locale, { month: "long", year: "numeric" }).format(anchor);
|
|
14
|
+
}
|
|
15
|
+
return new Intl.DateTimeFormat(locale, { month: "short", day: "2-digit", year: "numeric" }).format(anchor);
|
|
16
|
+
}, [view, anchor, locale, t]);
|
|
17
|
+
return /* @__PURE__ */ jsxs("header", { className: "flex items-center gap-3 border-b py-4", children: [
|
|
18
|
+
/* @__PURE__ */ jsx("h1", { className: "min-w-0 truncate text-xl font-semibold text-foreground", children: title }),
|
|
19
|
+
onNewEvent ? /* @__PURE__ */ jsx("div", { className: "ml-auto flex shrink-0 items-center", children: /* @__PURE__ */ jsxs(
|
|
20
|
+
Button,
|
|
21
|
+
{
|
|
22
|
+
type: "button",
|
|
23
|
+
onClick: onNewEvent,
|
|
24
|
+
"aria-label": t("customers.calendar.actions.newEvent", "New event"),
|
|
25
|
+
children: [
|
|
26
|
+
/* @__PURE__ */ jsx(Plus, { "aria-hidden": "true" }),
|
|
27
|
+
/* @__PURE__ */ jsx("span", { className: "hidden sm:inline", children: t("customers.calendar.actions.newEvent", "New event") })
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
) }) : null
|
|
31
|
+
] });
|
|
32
|
+
}
|
|
33
|
+
export {
|
|
34
|
+
CalendarHeader
|
|
35
|
+
};
|
|
36
|
+
//# sourceMappingURL=CalendarHeader.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/modules/customers/components/calendar/CalendarHeader.tsx"],
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Plus } from 'lucide-react'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { useLocale, useT } from '@open-mercato/shared/lib/i18n/context'\nimport type { CalendarHeaderProps } from './types'\n\nexport function CalendarHeader({ view, anchor, onNewEvent }: CalendarHeaderProps) {\n const t = useT()\n const locale = useLocale()\n\n const title = React.useMemo(() => {\n if (view === 'agenda') return t('customers.calendar.header.titleAgenda', 'Upcoming')\n if (view === 'month') {\n return new Intl.DateTimeFormat(locale, { month: 'long', year: 'numeric' }).format(anchor)\n }\n return new Intl.DateTimeFormat(locale, { month: 'short', day: '2-digit', year: 'numeric' }).format(anchor)\n }, [view, anchor, locale, t])\n\n return (\n <header className=\"flex items-center gap-3 border-b py-4\">\n <h1 className=\"min-w-0 truncate text-xl font-semibold text-foreground\">{title}</h1>\n {onNewEvent ? (\n <div className=\"ml-auto flex shrink-0 items-center\">\n <Button\n type=\"button\"\n onClick={onNewEvent}\n aria-label={t('customers.calendar.actions.newEvent', 'New event')}\n >\n <Plus aria-hidden=\"true\" />\n <span className=\"hidden sm:inline\">\n {t('customers.calendar.actions.newEvent', 'New event')}\n </span>\n </Button>\n </div>\n ) : null}\n </header>\n )\n}\n"],
|
|
5
|
+
"mappings": ";AAsBM,cAGI,YAHJ;AApBN,YAAY,WAAW;AACvB,SAAS,YAAY;AACrB,SAAS,cAAc;AACvB,SAAS,WAAW,YAAY;AAGzB,SAAS,eAAe,EAAE,MAAM,QAAQ,WAAW,GAAwB;AAChF,QAAM,IAAI,KAAK;AACf,QAAM,SAAS,UAAU;AAEzB,QAAM,QAAQ,MAAM,QAAQ,MAAM;AAChC,QAAI,SAAS,SAAU,QAAO,EAAE,yCAAyC,UAAU;AACnF,QAAI,SAAS,SAAS;AACpB,aAAO,IAAI,KAAK,eAAe,QAAQ,EAAE,OAAO,QAAQ,MAAM,UAAU,CAAC,EAAE,OAAO,MAAM;AAAA,IAC1F;AACA,WAAO,IAAI,KAAK,eAAe,QAAQ,EAAE,OAAO,SAAS,KAAK,WAAW,MAAM,UAAU,CAAC,EAAE,OAAO,MAAM;AAAA,EAC3G,GAAG,CAAC,MAAM,QAAQ,QAAQ,CAAC,CAAC;AAE5B,SACE,qBAAC,YAAO,WAAU,yCAChB;AAAA,wBAAC,QAAG,WAAU,0DAA0D,iBAAM;AAAA,IAC7E,aACC,oBAAC,SAAI,WAAU,sCACb;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS;AAAA,QACT,cAAY,EAAE,uCAAuC,WAAW;AAAA,QAEhE;AAAA,8BAAC,QAAK,eAAY,QAAO;AAAA,UACzB,oBAAC,UAAK,WAAU,oBACb,YAAE,uCAAuC,WAAW,GACvD;AAAA;AAAA;AAAA,IACF,GACF,IACE;AAAA,KACN;AAEJ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,516 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import dynamic from "next/dynamic";
|
|
5
|
+
import { addDays } from "date-fns/addDays";
|
|
6
|
+
import { isSameDay } from "date-fns/isSameDay";
|
|
7
|
+
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
8
|
+
import { apiCall, apiCallOrThrow, withScopedApiRequestHeaders } from "@open-mercato/ui/backend/utils/apiCall";
|
|
9
|
+
import { matchFeature } from "@open-mercato/shared/lib/auth/featureMatch";
|
|
10
|
+
import {
|
|
11
|
+
buildOptimisticLockHeader,
|
|
12
|
+
extractOptimisticLockConflict
|
|
13
|
+
} from "@open-mercato/ui/backend/utils/optimisticLock";
|
|
14
|
+
import { flash } from "@open-mercato/ui/backend/FlashMessages";
|
|
15
|
+
import { useGuardedMutation } from "@open-mercato/ui/backend/injection/useGuardedMutation";
|
|
16
|
+
import { ErrorMessage, LoadingMessage } from "@open-mercato/ui/backend/detail";
|
|
17
|
+
import { Button } from "@open-mercato/ui/primitives/button";
|
|
18
|
+
import { countByCategory } from "../../lib/calendar/categories.js";
|
|
19
|
+
import { findConflicts } from "../../lib/calendar/conflicts.js";
|
|
20
|
+
import { getVisibleRange } from "../../lib/calendar/range.js";
|
|
21
|
+
import { AgendaList } from "./AgendaList.js";
|
|
22
|
+
import { CalendarFooter } from "./CalendarFooter.js";
|
|
23
|
+
import { CalendarHeader } from "./CalendarHeader.js";
|
|
24
|
+
import { CalendarTabs } from "./CalendarTabs.js";
|
|
25
|
+
import { CalendarToolbar } from "./CalendarToolbar.js";
|
|
26
|
+
import { MonthGrid } from "./MonthGrid.js";
|
|
27
|
+
import { ShortcutsDialog } from "./ShortcutsDialog.js";
|
|
28
|
+
import { TimeGrid } from "./TimeGrid.js";
|
|
29
|
+
import { UpcomingCards } from "./UpcomingCards.js";
|
|
30
|
+
import { CalendarSettingsModal } from "./CalendarSettingsModal.js";
|
|
31
|
+
import { useCalendarPreferences } from "./useCalendarPreferences.js";
|
|
32
|
+
import { MAX_WINDOW_ITEMS, useCalendarItems } from "./useCalendarItems.js";
|
|
33
|
+
const CalendarEventEditor = dynamic(
|
|
34
|
+
() => import("./CalendarEventEditor.js").then((mod) => mod.CalendarEventEditor),
|
|
35
|
+
{ ssr: false }
|
|
36
|
+
);
|
|
37
|
+
const SEARCH_DEBOUNCE_MS = 200;
|
|
38
|
+
const PHONE_BREAKPOINT_PX = 640;
|
|
39
|
+
const HIGHLIGHT_CLEAR_MS = 3e3;
|
|
40
|
+
const DEFAULT_AGENDA_HORIZON_DAYS = 7;
|
|
41
|
+
const UPCOMING_CARDS_COUNT = 4;
|
|
42
|
+
const EMPTY_FILTERS = { types: [], status: null, ownerUserId: null };
|
|
43
|
+
const MANAGE_FEATURE = "customers.interactions.manage";
|
|
44
|
+
function useCanManageInteractions() {
|
|
45
|
+
const [canManage, setCanManage] = React.useState(false);
|
|
46
|
+
React.useEffect(() => {
|
|
47
|
+
const controller = new AbortController();
|
|
48
|
+
let cancelled = false;
|
|
49
|
+
apiCall("/api/auth/feature-check", {
|
|
50
|
+
method: "POST",
|
|
51
|
+
headers: { "Content-Type": "application/json" },
|
|
52
|
+
signal: controller.signal,
|
|
53
|
+
body: JSON.stringify({ features: [MANAGE_FEATURE] })
|
|
54
|
+
}).then((call) => {
|
|
55
|
+
if (cancelled || !call.ok) return;
|
|
56
|
+
const granted = Array.isArray(call.result?.granted) ? call.result.granted.map((feature) => String(feature)) : [];
|
|
57
|
+
setCanManage(granted.some((grantedFeature) => matchFeature(MANAGE_FEATURE, grantedFeature)));
|
|
58
|
+
}).catch(() => {
|
|
59
|
+
if (!cancelled && !controller.signal.aborted) setCanManage(false);
|
|
60
|
+
});
|
|
61
|
+
return () => {
|
|
62
|
+
cancelled = true;
|
|
63
|
+
controller.abort();
|
|
64
|
+
};
|
|
65
|
+
}, []);
|
|
66
|
+
return canManage;
|
|
67
|
+
}
|
|
68
|
+
function buildTimezoneLabel() {
|
|
69
|
+
const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
70
|
+
const offsetMinutes = -(/* @__PURE__ */ new Date()).getTimezoneOffset();
|
|
71
|
+
const sign = offsetMinutes >= 0 ? "+" : "-";
|
|
72
|
+
const absolute = Math.abs(offsetMinutes);
|
|
73
|
+
const hours = Math.floor(absolute / 60);
|
|
74
|
+
const minutes = absolute % 60;
|
|
75
|
+
const offset = minutes > 0 ? `${sign}${hours}:${String(minutes).padStart(2, "0")}` : `${sign}${hours}`;
|
|
76
|
+
return `${timeZone} (GMT${offset})`;
|
|
77
|
+
}
|
|
78
|
+
function resolveJoinUrl(location) {
|
|
79
|
+
const trimmed = location?.trim() ?? "";
|
|
80
|
+
if (!trimmed) return null;
|
|
81
|
+
if (/^https?:\/\//i.test(trimmed)) return trimmed;
|
|
82
|
+
if (/^www\./i.test(trimmed)) return `https://${trimmed}`;
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
function asEditableItem(item) {
|
|
86
|
+
return item.isRecurringOccurrence ? { ...item, id: item.raw.id } : item;
|
|
87
|
+
}
|
|
88
|
+
function CalendarScreen() {
|
|
89
|
+
const t = useT();
|
|
90
|
+
const [view, setView] = React.useState("week");
|
|
91
|
+
const [anchor, setAnchor] = React.useState(() => /* @__PURE__ */ new Date());
|
|
92
|
+
const [agendaHorizonDays, setAgendaHorizonDays] = React.useState(DEFAULT_AGENDA_HORIZON_DAYS);
|
|
93
|
+
const [preset, setPreset] = React.useState("thisWeek");
|
|
94
|
+
React.useEffect(() => {
|
|
95
|
+
if (window.innerWidth >= PHONE_BREAKPOINT_PX) return;
|
|
96
|
+
setView("day");
|
|
97
|
+
setPreset(null);
|
|
98
|
+
}, []);
|
|
99
|
+
const [tab, setTab] = React.useState("all");
|
|
100
|
+
const [searchText, setSearchText] = React.useState("");
|
|
101
|
+
const [debouncedSearch, setDebouncedSearch] = React.useState("");
|
|
102
|
+
const [filters, setFilters] = React.useState(EMPTY_FILTERS);
|
|
103
|
+
const [editor, setEditor] = React.useState({ open: false, mode: "create", item: null });
|
|
104
|
+
const [editorMounted, setEditorMounted] = React.useState(false);
|
|
105
|
+
const [createRange, setCreateRange] = React.useState(null);
|
|
106
|
+
const [shortcutsOpen, setShortcutsOpen] = React.useState(false);
|
|
107
|
+
const [settingsOpen, setSettingsOpen] = React.useState(false);
|
|
108
|
+
const [highlightItemId, setHighlightItemId] = React.useState(null);
|
|
109
|
+
const [hasLoadedOnce, setHasLoadedOnce] = React.useState(false);
|
|
110
|
+
const { preferences, setPreferences, hydrated: preferencesHydrated, userId: currentUserId } = useCalendarPreferences();
|
|
111
|
+
const range = React.useMemo(
|
|
112
|
+
() => getVisibleRange(view, anchor, agendaHorizonDays),
|
|
113
|
+
[view, anchor, agendaHorizonDays]
|
|
114
|
+
);
|
|
115
|
+
const { items, isLoading, error, truncated, typeLabels, typeColors, refetch } = useCalendarItems(range);
|
|
116
|
+
React.useEffect(() => {
|
|
117
|
+
if (!isLoading) setHasLoadedOnce(true);
|
|
118
|
+
}, [isLoading]);
|
|
119
|
+
React.useEffect(() => {
|
|
120
|
+
const timer = window.setTimeout(() => setDebouncedSearch(searchText), SEARCH_DEBOUNCE_MS);
|
|
121
|
+
return () => window.clearTimeout(timer);
|
|
122
|
+
}, [searchText]);
|
|
123
|
+
React.useEffect(() => {
|
|
124
|
+
if (!highlightItemId) return;
|
|
125
|
+
const timer = window.setTimeout(() => setHighlightItemId(null), HIGHLIGHT_CLEAR_MS);
|
|
126
|
+
return () => window.clearTimeout(timer);
|
|
127
|
+
}, [highlightItemId]);
|
|
128
|
+
const visibleItems = React.useMemo(
|
|
129
|
+
() => items.filter((item) => item.end > range.from && item.start < range.to),
|
|
130
|
+
[items, range]
|
|
131
|
+
);
|
|
132
|
+
const searchedItems = React.useMemo(() => {
|
|
133
|
+
const query = debouncedSearch.trim().toLowerCase();
|
|
134
|
+
if (!query) return visibleItems;
|
|
135
|
+
return visibleItems.filter((item) => {
|
|
136
|
+
if (item.title.toLowerCase().includes(query)) return true;
|
|
137
|
+
if (item.location && item.location.toLowerCase().includes(query)) return true;
|
|
138
|
+
const rawBody = item.raw.body;
|
|
139
|
+
if (typeof rawBody === "string" && rawBody.toLowerCase().includes(query)) return true;
|
|
140
|
+
return item.participants.some(
|
|
141
|
+
(participant) => (participant.name ?? "").toLowerCase().includes(query)
|
|
142
|
+
);
|
|
143
|
+
});
|
|
144
|
+
}, [visibleItems, debouncedSearch]);
|
|
145
|
+
const baseItems = React.useMemo(
|
|
146
|
+
() => searchedItems.filter((item) => {
|
|
147
|
+
if (filters.types.length > 0 && !filters.types.includes(item.interactionType)) return false;
|
|
148
|
+
if (filters.status && item.status !== filters.status) return false;
|
|
149
|
+
if (filters.ownerUserId && item.ownerUserId !== filters.ownerUserId) return false;
|
|
150
|
+
if (!preferences.showCrmActivities && item.category !== "meeting" && item.category !== "event") return false;
|
|
151
|
+
return true;
|
|
152
|
+
}),
|
|
153
|
+
[searchedItems, filters, preferences.showCrmActivities]
|
|
154
|
+
);
|
|
155
|
+
const tabCounts = React.useMemo(() => countByCategory(baseItems), [baseItems]);
|
|
156
|
+
const viewItems = React.useMemo(() => {
|
|
157
|
+
if (tab === "meetings") return baseItems.filter((item) => item.category === "meeting");
|
|
158
|
+
if (tab === "events") return baseItems.filter((item) => item.category === "event");
|
|
159
|
+
return baseItems;
|
|
160
|
+
}, [baseItems, tab]);
|
|
161
|
+
const conflictMap = React.useMemo(
|
|
162
|
+
() => findConflicts(baseItems, { scope: preferences.conflictScope, currentUserId }),
|
|
163
|
+
[baseItems, preferences.conflictScope, currentUserId]
|
|
164
|
+
);
|
|
165
|
+
const conflictIds = React.useMemo(() => new Set(conflictMap.keys()), [conflictMap]);
|
|
166
|
+
const upcomingCards = React.useMemo(() => {
|
|
167
|
+
const now = /* @__PURE__ */ new Date();
|
|
168
|
+
const nowMs = now.getTime();
|
|
169
|
+
return baseItems.filter((item) => item.start.getTime() >= nowMs).sort((first, second) => first.start.getTime() - second.start.getTime()).slice(0, UPCOMING_CARDS_COUNT).map((item) => {
|
|
170
|
+
const conflictCount = preferences.conflictWarnings ? conflictMap.get(item.id)?.length ?? 0 : 0;
|
|
171
|
+
const kind = item.status === "canceled" ? "cancelled" : conflictCount > 0 ? "conflicted" : isSameDay(item.start, now) ? "today" : "future";
|
|
172
|
+
return { item, kind, conflictCount };
|
|
173
|
+
});
|
|
174
|
+
}, [baseItems, conflictMap, preferences.conflictWarnings]);
|
|
175
|
+
const typeOptions = React.useMemo(() => {
|
|
176
|
+
const values = new Set(Object.keys(typeLabels));
|
|
177
|
+
for (const item of items) values.add(item.interactionType);
|
|
178
|
+
return [...values].sort().map((value) => ({ value, label: typeLabels[value] ?? value }));
|
|
179
|
+
}, [items, typeLabels]);
|
|
180
|
+
const ownerOptions = React.useMemo(() => {
|
|
181
|
+
const participantNames = /* @__PURE__ */ new Map();
|
|
182
|
+
for (const item of items) {
|
|
183
|
+
for (const participant of item.participants) {
|
|
184
|
+
if (participant.name && !participantNames.has(participant.userId)) {
|
|
185
|
+
participantNames.set(participant.userId, participant.name);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
const owners = /* @__PURE__ */ new Map();
|
|
190
|
+
for (const item of items) {
|
|
191
|
+
if (!item.ownerUserId || owners.has(item.ownerUserId)) continue;
|
|
192
|
+
owners.set(item.ownerUserId, participantNames.get(item.ownerUserId) ?? item.ownerUserId);
|
|
193
|
+
}
|
|
194
|
+
return [...owners.entries()].map(([value, label]) => ({ value, label })).sort((first, second) => first.label.localeCompare(second.label));
|
|
195
|
+
}, [items]);
|
|
196
|
+
const timezoneLabel = React.useMemo(() => buildTimezoneLabel(), []);
|
|
197
|
+
const canManage = useCanManageInteractions();
|
|
198
|
+
const openCreateEditor = React.useCallback(() => {
|
|
199
|
+
if (!canManage) return;
|
|
200
|
+
setCreateRange(null);
|
|
201
|
+
setEditorMounted(true);
|
|
202
|
+
setEditor({ open: true, mode: "create", item: null });
|
|
203
|
+
}, [canManage]);
|
|
204
|
+
const openEditEditor = React.useCallback(
|
|
205
|
+
(item) => {
|
|
206
|
+
if (!canManage) return;
|
|
207
|
+
setCreateRange(null);
|
|
208
|
+
setEditorMounted(true);
|
|
209
|
+
setEditor({ open: true, mode: "edit", item: asEditableItem(item) });
|
|
210
|
+
},
|
|
211
|
+
[canManage]
|
|
212
|
+
);
|
|
213
|
+
const handleCreateRange = React.useCallback(
|
|
214
|
+
(start, end) => {
|
|
215
|
+
if (!canManage) return;
|
|
216
|
+
setCreateRange({ start, end });
|
|
217
|
+
setEditorMounted(true);
|
|
218
|
+
setEditor({ open: true, mode: "create", item: null });
|
|
219
|
+
},
|
|
220
|
+
[canManage]
|
|
221
|
+
);
|
|
222
|
+
const seedActivityTypes = React.useMemo(() => {
|
|
223
|
+
const seen = /* @__PURE__ */ new Set();
|
|
224
|
+
const labels = [];
|
|
225
|
+
for (const value of Object.keys(typeLabels)) {
|
|
226
|
+
const label = typeLabels[value] ?? value;
|
|
227
|
+
if (seen.has(label)) continue;
|
|
228
|
+
seen.add(label);
|
|
229
|
+
labels.push(label);
|
|
230
|
+
}
|
|
231
|
+
return labels;
|
|
232
|
+
}, [typeLabels]);
|
|
233
|
+
const handleToday = React.useCallback(() => {
|
|
234
|
+
setAnchor(/* @__PURE__ */ new Date());
|
|
235
|
+
setPreset(null);
|
|
236
|
+
}, []);
|
|
237
|
+
const handlePresetChange = React.useCallback((next) => {
|
|
238
|
+
setPreset(next);
|
|
239
|
+
setAnchor(/* @__PURE__ */ new Date());
|
|
240
|
+
if (next === "thisWeek") {
|
|
241
|
+
setView("week");
|
|
242
|
+
} else if (next === "thisMonth") {
|
|
243
|
+
setView("month");
|
|
244
|
+
} else {
|
|
245
|
+
setView("agenda");
|
|
246
|
+
setAgendaHorizonDays(next === "next30" ? 30 : DEFAULT_AGENDA_HORIZON_DAYS);
|
|
247
|
+
}
|
|
248
|
+
}, []);
|
|
249
|
+
const handleAnchorChange = React.useCallback((date) => {
|
|
250
|
+
setAnchor(date);
|
|
251
|
+
setPreset(null);
|
|
252
|
+
}, []);
|
|
253
|
+
const handleViewChange = React.useCallback((next) => {
|
|
254
|
+
setView(next);
|
|
255
|
+
setPreset(null);
|
|
256
|
+
}, []);
|
|
257
|
+
const handleTimeGridNavigate = React.useCallback((deltaDays) => {
|
|
258
|
+
setAnchor((current) => addDays(current, deltaDays));
|
|
259
|
+
setPreset(null);
|
|
260
|
+
}, []);
|
|
261
|
+
const handleDayOpen = React.useCallback((date) => {
|
|
262
|
+
setView("day");
|
|
263
|
+
setAnchor(date);
|
|
264
|
+
setPreset(null);
|
|
265
|
+
}, []);
|
|
266
|
+
const handleSeeConflict = React.useCallback((item) => {
|
|
267
|
+
setView("week");
|
|
268
|
+
setAnchor(item.start);
|
|
269
|
+
setPreset(null);
|
|
270
|
+
setHighlightItemId(item.id);
|
|
271
|
+
}, []);
|
|
272
|
+
const handleJoin = React.useCallback((item) => {
|
|
273
|
+
const url = resolveJoinUrl(item.location);
|
|
274
|
+
if (url) window.open(url, "_blank", "noopener");
|
|
275
|
+
}, []);
|
|
276
|
+
const { runMutation, retryLastMutation } = useGuardedMutation({
|
|
277
|
+
contextId: "customers-calendar-cancel",
|
|
278
|
+
blockedMessage: t("ui.forms.flash.saveBlocked", "Save blocked by validation")
|
|
279
|
+
});
|
|
280
|
+
const handleCancelItem = React.useCallback(
|
|
281
|
+
async (item) => {
|
|
282
|
+
const interactionId = item.raw.id;
|
|
283
|
+
try {
|
|
284
|
+
await runMutation({
|
|
285
|
+
operation: () => withScopedApiRequestHeaders(
|
|
286
|
+
buildOptimisticLockHeader(item.updatedAt),
|
|
287
|
+
() => apiCallOrThrow("/api/customers/interactions", {
|
|
288
|
+
method: "PUT",
|
|
289
|
+
headers: { "content-type": "application/json" },
|
|
290
|
+
body: JSON.stringify({ id: interactionId, status: "canceled" })
|
|
291
|
+
})
|
|
292
|
+
),
|
|
293
|
+
mutationPayload: {
|
|
294
|
+
operation: "cancelCalendarEvent",
|
|
295
|
+
interactionId,
|
|
296
|
+
interactionType: item.interactionType
|
|
297
|
+
},
|
|
298
|
+
context: {
|
|
299
|
+
formId: "customers-calendar-cancel",
|
|
300
|
+
resourceKind: "customers.interaction",
|
|
301
|
+
resourceId: interactionId,
|
|
302
|
+
retryLastMutation
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
flash(t("customers.calendar.cards.cancelSuccess", "Event cancelled"), "success");
|
|
306
|
+
refetch();
|
|
307
|
+
} catch (err) {
|
|
308
|
+
if (extractOptimisticLockConflict(err)) return;
|
|
309
|
+
flash(t("customers.calendar.cards.cancelError", "Failed to cancel event"), "error");
|
|
310
|
+
}
|
|
311
|
+
},
|
|
312
|
+
[refetch, retryLastMutation, runMutation, t]
|
|
313
|
+
);
|
|
314
|
+
const focusSearch = React.useCallback(() => {
|
|
315
|
+
const node = document.querySelector("[data-calendar-search]");
|
|
316
|
+
if (node instanceof HTMLInputElement) node.focus();
|
|
317
|
+
else if (node instanceof HTMLElement) node.querySelector("input")?.focus();
|
|
318
|
+
}, []);
|
|
319
|
+
const editorOpen = editor.open;
|
|
320
|
+
React.useEffect(() => {
|
|
321
|
+
const handleKeyDown = (event) => {
|
|
322
|
+
if (event.defaultPrevented) return;
|
|
323
|
+
if (event.metaKey || event.ctrlKey || event.altKey) return;
|
|
324
|
+
const target = event.target;
|
|
325
|
+
if (target instanceof HTMLElement) {
|
|
326
|
+
const tag = target.tagName;
|
|
327
|
+
if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT" || target.isContentEditable) return;
|
|
328
|
+
}
|
|
329
|
+
if (editorOpen) return;
|
|
330
|
+
switch (event.key) {
|
|
331
|
+
case "t":
|
|
332
|
+
case "T":
|
|
333
|
+
event.preventDefault();
|
|
334
|
+
setAnchor(/* @__PURE__ */ new Date());
|
|
335
|
+
setPreset(null);
|
|
336
|
+
break;
|
|
337
|
+
case "d":
|
|
338
|
+
case "D":
|
|
339
|
+
event.preventDefault();
|
|
340
|
+
setView("day");
|
|
341
|
+
setPreset(null);
|
|
342
|
+
break;
|
|
343
|
+
case "w":
|
|
344
|
+
case "W":
|
|
345
|
+
event.preventDefault();
|
|
346
|
+
setView("week");
|
|
347
|
+
setPreset(null);
|
|
348
|
+
break;
|
|
349
|
+
case "m":
|
|
350
|
+
case "M":
|
|
351
|
+
event.preventDefault();
|
|
352
|
+
setView("month");
|
|
353
|
+
setPreset(null);
|
|
354
|
+
break;
|
|
355
|
+
case "a":
|
|
356
|
+
case "A":
|
|
357
|
+
event.preventDefault();
|
|
358
|
+
setView("agenda");
|
|
359
|
+
setPreset(null);
|
|
360
|
+
break;
|
|
361
|
+
case "n":
|
|
362
|
+
case "N":
|
|
363
|
+
event.preventDefault();
|
|
364
|
+
openCreateEditor();
|
|
365
|
+
break;
|
|
366
|
+
case "/":
|
|
367
|
+
event.preventDefault();
|
|
368
|
+
focusSearch();
|
|
369
|
+
break;
|
|
370
|
+
case "?":
|
|
371
|
+
event.preventDefault();
|
|
372
|
+
setShortcutsOpen((open) => !open);
|
|
373
|
+
break;
|
|
374
|
+
case "Escape":
|
|
375
|
+
setHighlightItemId(null);
|
|
376
|
+
break;
|
|
377
|
+
default:
|
|
378
|
+
break;
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
382
|
+
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
383
|
+
}, [editorOpen, focusSearch, openCreateEditor]);
|
|
384
|
+
const showInitialLoading = isLoading && !hasLoadedOnce || !preferencesHydrated;
|
|
385
|
+
let viewArea;
|
|
386
|
+
if (error) {
|
|
387
|
+
viewArea = /* @__PURE__ */ jsx(
|
|
388
|
+
ErrorMessage,
|
|
389
|
+
{
|
|
390
|
+
label: t("customers.calendar.errors.loadFailed", "Failed to load calendar events."),
|
|
391
|
+
action: /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: refetch, children: t("customers.calendar.errors.retry", "Retry") })
|
|
392
|
+
}
|
|
393
|
+
);
|
|
394
|
+
} else if (showInitialLoading) {
|
|
395
|
+
viewArea = /* @__PURE__ */ jsx(LoadingMessage, { label: t("customers.calendar.loading", "Loading calendar\u2026") });
|
|
396
|
+
} else if (view === "month") {
|
|
397
|
+
viewArea = /* @__PURE__ */ jsx(MonthGrid, { anchor, items: viewItems, onItemClick: openEditEditor, onDayOpen: handleDayOpen });
|
|
398
|
+
} else if (view === "agenda") {
|
|
399
|
+
viewArea = /* @__PURE__ */ jsx(
|
|
400
|
+
AgendaList,
|
|
401
|
+
{
|
|
402
|
+
anchor,
|
|
403
|
+
horizonDays: agendaHorizonDays,
|
|
404
|
+
items: viewItems,
|
|
405
|
+
typeLabels,
|
|
406
|
+
onItemClick: openEditEditor
|
|
407
|
+
}
|
|
408
|
+
);
|
|
409
|
+
} else {
|
|
410
|
+
viewArea = /* @__PURE__ */ jsx(
|
|
411
|
+
TimeGrid,
|
|
412
|
+
{
|
|
413
|
+
days: view === "day" ? 1 : 7,
|
|
414
|
+
anchor,
|
|
415
|
+
items: viewItems,
|
|
416
|
+
conflictIds,
|
|
417
|
+
showWeekends: preferences.showWeekends,
|
|
418
|
+
showConflicts: preferences.conflictWarnings,
|
|
419
|
+
aiSummaries: preferences.aiSummaries,
|
|
420
|
+
highlightItemId,
|
|
421
|
+
onItemClick: openEditEditor,
|
|
422
|
+
onJoin: handleJoin,
|
|
423
|
+
onNavigate: handleTimeGridNavigate,
|
|
424
|
+
onCreate: canManage ? openCreateEditor : void 0,
|
|
425
|
+
onCreateRange: canManage ? handleCreateRange : void 0
|
|
426
|
+
}
|
|
427
|
+
);
|
|
428
|
+
}
|
|
429
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex min-h-0 flex-1 flex-col gap-4", children: [
|
|
430
|
+
/* @__PURE__ */ jsx(CalendarHeader, { view, anchor, onNewEvent: canManage ? openCreateEditor : void 0 }),
|
|
431
|
+
/* @__PURE__ */ jsx(
|
|
432
|
+
CalendarToolbar,
|
|
433
|
+
{
|
|
434
|
+
view,
|
|
435
|
+
anchor,
|
|
436
|
+
range,
|
|
437
|
+
preset,
|
|
438
|
+
search: searchText,
|
|
439
|
+
filters,
|
|
440
|
+
typeOptions,
|
|
441
|
+
ownerOptions,
|
|
442
|
+
onToday: handleToday,
|
|
443
|
+
onPresetChange: handlePresetChange,
|
|
444
|
+
onAnchorChange: handleAnchorChange,
|
|
445
|
+
onSearchChange: setSearchText,
|
|
446
|
+
onFiltersChange: setFilters,
|
|
447
|
+
onOpenSettings: () => setSettingsOpen(true)
|
|
448
|
+
}
|
|
449
|
+
),
|
|
450
|
+
/* @__PURE__ */ jsx(
|
|
451
|
+
UpcomingCards,
|
|
452
|
+
{
|
|
453
|
+
cards: upcomingCards,
|
|
454
|
+
canManage,
|
|
455
|
+
onJoin: handleJoin,
|
|
456
|
+
onSeeConflict: handleSeeConflict,
|
|
457
|
+
onOpen: openEditEditor,
|
|
458
|
+
onEdit: openEditEditor,
|
|
459
|
+
onCancel: handleCancelItem
|
|
460
|
+
}
|
|
461
|
+
),
|
|
462
|
+
/* @__PURE__ */ jsxs("div", { className: "flex min-h-0 flex-1 flex-col gap-3", children: [
|
|
463
|
+
/* @__PURE__ */ jsx(
|
|
464
|
+
CalendarTabs,
|
|
465
|
+
{
|
|
466
|
+
tab,
|
|
467
|
+
counts: tabCounts,
|
|
468
|
+
view,
|
|
469
|
+
onTabChange: setTab,
|
|
470
|
+
onViewChange: handleViewChange
|
|
471
|
+
}
|
|
472
|
+
),
|
|
473
|
+
truncated ? /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", role: "status", children: t("customers.calendar.notice.truncated", "Showing first {count} items for this range.", {
|
|
474
|
+
count: MAX_WINDOW_ITEMS
|
|
475
|
+
}) }) : null,
|
|
476
|
+
/* @__PURE__ */ jsx("div", { className: "flex min-h-[560px] flex-1 flex-col [&>*]:flex-1", children: viewArea })
|
|
477
|
+
] }),
|
|
478
|
+
/* @__PURE__ */ jsx("div", { className: "hidden md:block", children: /* @__PURE__ */ jsx(CalendarFooter, { timezoneLabel, onOpenShortcuts: () => setShortcutsOpen(true) }) }),
|
|
479
|
+
/* @__PURE__ */ jsx(ShortcutsDialog, { open: shortcutsOpen, onOpenChange: setShortcutsOpen }),
|
|
480
|
+
/* @__PURE__ */ jsx(
|
|
481
|
+
CalendarSettingsModal,
|
|
482
|
+
{
|
|
483
|
+
open: settingsOpen,
|
|
484
|
+
preferences,
|
|
485
|
+
seedActivityTypes,
|
|
486
|
+
onOpenChange: setSettingsOpen,
|
|
487
|
+
onSave: (next) => {
|
|
488
|
+
setPreferences(next);
|
|
489
|
+
flash(t("customers.calendar.settings.saved", "Calendar settings saved"), "success");
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
),
|
|
493
|
+
editorMounted ? /* @__PURE__ */ jsx(
|
|
494
|
+
CalendarEventEditor,
|
|
495
|
+
{
|
|
496
|
+
open: editor.open,
|
|
497
|
+
mode: editor.mode,
|
|
498
|
+
item: editor.item,
|
|
499
|
+
defaultDate: anchor,
|
|
500
|
+
defaultRange: createRange,
|
|
501
|
+
typeLabels,
|
|
502
|
+
typeColors,
|
|
503
|
+
surfacedTypes: preferences.activityTypes,
|
|
504
|
+
eventCategories: preferences.eventCategories,
|
|
505
|
+
conflictScope: preferences.conflictScope,
|
|
506
|
+
currentUserId,
|
|
507
|
+
onOpenChange: (open) => setEditor((current) => ({ ...current, open })),
|
|
508
|
+
onSaved: refetch
|
|
509
|
+
}
|
|
510
|
+
) : null
|
|
511
|
+
] });
|
|
512
|
+
}
|
|
513
|
+
export {
|
|
514
|
+
CalendarScreen
|
|
515
|
+
};
|
|
516
|
+
//# sourceMappingURL=CalendarScreen.js.map
|