@open-mercato/core 0.5.1-develop.2663.2c29774b5b → 0.5.1-develop.2681.c559bb2bc3
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/action_log/index.js +8 -0
- package/dist/generated/entities/action_log/index.js.map +2 -2
- package/dist/generated/entities/customer_company_billing/index.js +23 -0
- package/dist/generated/entities/customer_company_billing/index.js.map +7 -0
- package/dist/generated/entities/customer_deal/index.js +8 -0
- package/dist/generated/entities/customer_deal/index.js.map +2 -2
- package/dist/generated/entities/customer_deal_stage_transition/index.js +31 -0
- package/dist/generated/entities/customer_deal_stage_transition/index.js.map +7 -0
- package/dist/generated/entities/customer_dictionary_kind_setting/index.js +21 -0
- package/dist/generated/entities/customer_dictionary_kind_setting/index.js.map +7 -0
- package/dist/generated/entities/customer_entity/index.js +8 -0
- package/dist/generated/entities/customer_entity/index.js.map +2 -2
- package/dist/generated/entities/customer_entity_role/index.js +23 -0
- package/dist/generated/entities/customer_entity_role/index.js.map +7 -0
- package/dist/generated/entities/customer_interaction/index.js +23 -1
- package/dist/generated/entities/customer_interaction/index.js.map +2 -2
- package/dist/generated/entities/customer_label/index.js +19 -0
- package/dist/generated/entities/customer_label/index.js.map +7 -0
- package/dist/generated/entities/customer_label_assignment/index.js +17 -0
- package/dist/generated/entities/customer_label_assignment/index.js.map +7 -0
- package/dist/generated/entities/customer_person_company_link/index.js +21 -0
- package/dist/generated/entities/customer_person_company_link/index.js.map +7 -0
- package/dist/generated/entities/customer_person_company_role/index.js +17 -0
- package/dist/generated/entities/customer_person_company_role/index.js.map +7 -0
- package/dist/generated/entities/dictionary_entry/index.js +4 -0
- package/dist/generated/entities/dictionary_entry/index.js.map +2 -2
- package/dist/generated/entities.ids.generated.js +9 -1
- package/dist/generated/entities.ids.generated.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +116 -1
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/modules/attachments/api/route.js +46 -8
- package/dist/modules/attachments/api/route.js.map +2 -2
- package/dist/modules/audit_logs/api/audit-logs/actions/export/route.js +208 -0
- package/dist/modules/audit_logs/api/audit-logs/actions/export/route.js.map +7 -0
- package/dist/modules/audit_logs/api/audit-logs/actions/route.js +52 -6
- package/dist/modules/audit_logs/api/audit-logs/actions/route.js.map +2 -2
- package/dist/modules/audit_logs/cli.js +62 -0
- package/dist/modules/audit_logs/cli.js.map +7 -0
- package/dist/modules/audit_logs/data/entities.js +21 -1
- package/dist/modules/audit_logs/data/entities.js.map +2 -2
- package/dist/modules/audit_logs/data/validators.js +9 -1
- package/dist/modules/audit_logs/data/validators.js.map +2 -2
- package/dist/modules/audit_logs/lib/changeRows.js +34 -0
- package/dist/modules/audit_logs/lib/changeRows.js.map +7 -0
- package/dist/modules/audit_logs/lib/display-helpers.js +2 -20
- package/dist/modules/audit_logs/lib/display-helpers.js.map +3 -3
- package/dist/modules/audit_logs/lib/projections.js +58 -0
- package/dist/modules/audit_logs/lib/projections.js.map +7 -0
- package/dist/modules/audit_logs/migrations/Migration20260412160533.js +21 -0
- package/dist/modules/audit_logs/migrations/Migration20260412160533.js.map +7 -0
- package/dist/modules/audit_logs/services/actionLogService.js +313 -79
- package/dist/modules/audit_logs/services/actionLogService.js.map +2 -2
- package/dist/modules/customers/acl.js +3 -1
- package/dist/modules/customers/acl.js.map +2 -2
- package/dist/modules/customers/api/activities/route.js +4 -0
- package/dist/modules/customers/api/activities/route.js.map +2 -2
- package/dist/modules/customers/api/assignable-staff/route.js +208 -0
- package/dist/modules/customers/api/assignable-staff/route.js.map +7 -0
- package/dist/modules/customers/api/companies/[id]/people/route.js +205 -0
- package/dist/modules/customers/api/companies/[id]/people/route.js.map +7 -0
- package/dist/modules/customers/api/companies/[id]/roles/route.js +22 -0
- package/dist/modules/customers/api/companies/[id]/roles/route.js.map +7 -0
- package/dist/modules/customers/api/companies/[id]/route.js +374 -32
- package/dist/modules/customers/api/companies/[id]/route.js.map +2 -2
- package/dist/modules/customers/api/companies/route.js +82 -7
- package/dist/modules/customers/api/companies/route.js.map +2 -2
- package/dist/modules/customers/api/deals/[id]/companies/route.js +172 -0
- package/dist/modules/customers/api/deals/[id]/companies/route.js.map +7 -0
- package/dist/modules/customers/api/deals/[id]/people/route.js +156 -0
- package/dist/modules/customers/api/deals/[id]/people/route.js.map +7 -0
- package/dist/modules/customers/api/deals/[id]/route.js +459 -53
- package/dist/modules/customers/api/deals/[id]/route.js.map +2 -2
- package/dist/modules/customers/api/deals/[id]/stats/route.js +195 -0
- package/dist/modules/customers/api/deals/[id]/stats/route.js.map +7 -0
- package/dist/modules/customers/api/deals/route.js +20 -10
- package/dist/modules/customers/api/deals/route.js.map +3 -3
- package/dist/modules/customers/api/dictionaries/[kind]/[id]/route.js +105 -4
- package/dist/modules/customers/api/dictionaries/[kind]/[id]/route.js.map +2 -2
- package/dist/modules/customers/api/dictionaries/[kind]/route.js +118 -42
- package/dist/modules/customers/api/dictionaries/[kind]/route.js.map +2 -2
- package/dist/modules/customers/api/dictionaries/context.js +30 -6
- package/dist/modules/customers/api/dictionaries/context.js.map +2 -2
- package/dist/modules/customers/api/dictionaries/kind-settings/route.js +207 -0
- package/dist/modules/customers/api/dictionaries/kind-settings/route.js.map +7 -0
- package/dist/modules/customers/api/entity-roles-factory.js +471 -0
- package/dist/modules/customers/api/entity-roles-factory.js.map +7 -0
- package/dist/modules/customers/api/interactions/conflicts/route.js +158 -0
- package/dist/modules/customers/api/interactions/conflicts/route.js.map +7 -0
- package/dist/modules/customers/api/interactions/counts/route.js +92 -0
- package/dist/modules/customers/api/interactions/counts/route.js.map +7 -0
- package/dist/modules/customers/api/interactions/route.js +83 -4
- package/dist/modules/customers/api/interactions/route.js.map +2 -2
- package/dist/modules/customers/api/labels/assign/route.js +189 -0
- package/dist/modules/customers/api/labels/assign/route.js.map +7 -0
- package/dist/modules/customers/api/labels/auth.js +17 -0
- package/dist/modules/customers/api/labels/auth.js.map +7 -0
- package/dist/modules/customers/api/labels/route.js +281 -0
- package/dist/modules/customers/api/labels/route.js.map +7 -0
- package/dist/modules/customers/api/labels/table-errors.js +38 -0
- package/dist/modules/customers/api/labels/table-errors.js.map +7 -0
- package/dist/modules/customers/api/labels/unassign/route.js +184 -0
- package/dist/modules/customers/api/labels/unassign/route.js.map +7 -0
- package/dist/modules/customers/api/people/[id]/companies/[linkId]/route.js +292 -0
- package/dist/modules/customers/api/people/[id]/companies/[linkId]/route.js.map +7 -0
- package/dist/modules/customers/api/people/[id]/companies/context.js +66 -0
- package/dist/modules/customers/api/people/[id]/companies/context.js.map +7 -0
- package/dist/modules/customers/api/people/[id]/companies/enriched/route.js +334 -0
- package/dist/modules/customers/api/people/[id]/companies/enriched/route.js.map +7 -0
- package/dist/modules/customers/api/people/[id]/companies/route.js +205 -0
- package/dist/modules/customers/api/people/[id]/companies/route.js.map +7 -0
- package/dist/modules/customers/api/people/[id]/roles/route.js +22 -0
- package/dist/modules/customers/api/people/[id]/roles/route.js.map +7 -0
- package/dist/modules/customers/api/people/[id]/route.js +134 -21
- package/dist/modules/customers/api/people/[id]/route.js.map +2 -2
- package/dist/modules/customers/api/people/route.js +122 -23
- package/dist/modules/customers/api/people/route.js.map +2 -2
- package/dist/modules/customers/api/todos/route.js +4 -0
- package/dist/modules/customers/api/todos/route.js.map +2 -2
- package/dist/modules/customers/api/utils.js +22 -0
- package/dist/modules/customers/api/utils.js.map +2 -2
- package/dist/modules/customers/backend/config/customers/page.js +2 -6
- package/dist/modules/customers/backend/config/customers/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies/page.js +37 -26
- package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js +265 -262
- package/dist/modules/customers/backend/customers/companies-v2/[id]/page.js.map +3 -3
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/formatters.js +23 -0
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/formatters.js.map +7 -0
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/types.js +1 -0
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/types.js.map +7 -0
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealActivities.js +43 -0
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealActivities.js.map +7 -0
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.js +264 -0
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.js.map +7 -0
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealClosure.js +88 -0
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealClosure.js.map +7 -0
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealData.js +41 -0
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealData.js.map +7 -0
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealFormHandlers.js +66 -0
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealFormHandlers.js.map +7 -0
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealInjectedTabs.js +39 -0
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealInjectedTabs.js.map +7 -0
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealMutationContext.js +49 -0
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealMutationContext.js.map +7 -0
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealPipeline.js +43 -0
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useDealPipeline.js.map +7 -0
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useScheduleDialog.js +28 -0
- package/dist/modules/customers/backend/customers/deals/[id]/hooks/useScheduleDialog.js.map +7 -0
- package/dist/modules/customers/backend/customers/deals/[id]/page.js +556 -503
- package/dist/modules/customers/backend/customers/deals/[id]/page.js.map +3 -3
- package/dist/modules/customers/backend/customers/deals/page.js +66 -21
- package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people/page.js +36 -28
- package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people-v2/[id]/page.js +318 -203
- package/dist/modules/customers/backend/customers/people-v2/[id]/page.js.map +3 -3
- package/dist/modules/customers/cli.js +105 -13
- package/dist/modules/customers/cli.js.map +2 -2
- package/dist/modules/customers/commands/activities.js +6 -0
- package/dist/modules/customers/commands/activities.js.map +2 -2
- package/dist/modules/customers/commands/deals.js +315 -107
- package/dist/modules/customers/commands/deals.js.map +2 -2
- package/dist/modules/customers/commands/dictionaries.js +166 -32
- package/dist/modules/customers/commands/dictionaries.js.map +2 -2
- package/dist/modules/customers/commands/dictionaryKindSettings.js +208 -0
- package/dist/modules/customers/commands/dictionaryKindSettings.js.map +7 -0
- package/dist/modules/customers/commands/entity-roles.js +415 -0
- package/dist/modules/customers/commands/entity-roles.js.map +7 -0
- package/dist/modules/customers/commands/index.js +4 -0
- package/dist/modules/customers/commands/index.js.map +2 -2
- package/dist/modules/customers/commands/interactions.js +108 -21
- package/dist/modules/customers/commands/interactions.js.map +2 -2
- package/dist/modules/customers/commands/labels.js +539 -0
- package/dist/modules/customers/commands/labels.js.map +7 -0
- package/dist/modules/customers/commands/people.js +560 -463
- package/dist/modules/customers/commands/people.js.map +3 -3
- package/dist/modules/customers/commands/personCompanyLinks.js +568 -0
- package/dist/modules/customers/commands/personCompanyLinks.js.map +7 -0
- package/dist/modules/customers/commands/shared.js +12 -4
- package/dist/modules/customers/commands/shared.js.map +2 -2
- package/dist/modules/customers/commands/todos.js +10 -1
- package/dist/modules/customers/commands/todos.js.map +2 -2
- package/dist/modules/customers/components/AddressEditor.js +1 -1
- package/dist/modules/customers/components/AddressEditor.js.map +2 -2
- package/dist/modules/customers/components/CustomersConfigurationSections.js +31 -0
- package/dist/modules/customers/components/CustomersConfigurationSections.js.map +7 -0
- package/dist/modules/customers/components/DictionarySettings.js +37 -2
- package/dist/modules/customers/components/DictionarySettings.js.map +2 -2
- package/dist/modules/customers/components/detail/ActiveDealCard.js +121 -0
- package/dist/modules/customers/components/detail/ActiveDealCard.js.map +7 -0
- package/dist/modules/customers/components/detail/ActivitiesSection.js +222 -331
- package/dist/modules/customers/components/detail/ActivitiesSection.js.map +3 -3
- package/dist/modules/customers/components/detail/ActivityAiActions.js +36 -0
- package/dist/modules/customers/components/detail/ActivityAiActions.js.map +7 -0
- package/dist/modules/customers/components/detail/ActivityCard.js +126 -0
- package/dist/modules/customers/components/detail/ActivityCard.js.map +7 -0
- package/dist/modules/customers/components/detail/ActivityHistorySection.js +340 -0
- package/dist/modules/customers/components/detail/ActivityHistorySection.js.map +7 -0
- package/dist/modules/customers/components/detail/ActivityLogTab.js +56 -0
- package/dist/modules/customers/components/detail/ActivityLogTab.js.map +7 -0
- package/dist/modules/customers/components/detail/ActivityTimeline.js +108 -0
- package/dist/modules/customers/components/detail/ActivityTimeline.js.map +7 -0
- package/dist/modules/customers/components/detail/ActivityTimelineFilters.js +139 -0
- package/dist/modules/customers/components/detail/ActivityTimelineFilters.js.map +7 -0
- package/dist/modules/customers/components/detail/ActivityTypeSelector.js +42 -0
- package/dist/modules/customers/components/detail/ActivityTypeSelector.js.map +7 -0
- package/dist/modules/customers/components/detail/AiActionChips.js +38 -0
- package/dist/modules/customers/components/detail/AiActionChips.js.map +7 -0
- package/dist/modules/customers/components/detail/AssignRoleDialog.js +534 -0
- package/dist/modules/customers/components/detail/AssignRoleDialog.js.map +7 -0
- package/dist/modules/customers/components/detail/ChangelogEntryRow.js +79 -0
- package/dist/modules/customers/components/detail/ChangelogEntryRow.js.map +7 -0
- package/dist/modules/customers/components/detail/ChangelogFilters.js +176 -0
- package/dist/modules/customers/components/detail/ChangelogFilters.js.map +7 -0
- package/dist/modules/customers/components/detail/ChangelogKpiCards.js +88 -0
- package/dist/modules/customers/components/detail/ChangelogKpiCards.js.map +7 -0
- package/dist/modules/customers/components/detail/ChangelogTab.js +470 -0
- package/dist/modules/customers/components/detail/ChangelogTab.js.map +7 -0
- package/dist/modules/customers/components/detail/ComingSoonPlaceholder.js +16 -0
- package/dist/modules/customers/components/detail/ComingSoonPlaceholder.js.map +7 -0
- package/dist/modules/customers/components/detail/CompanyCard.js +283 -0
- package/dist/modules/customers/components/detail/CompanyCard.js.map +7 -0
- package/dist/modules/customers/components/detail/CompanyDashboardTab.js +133 -0
- package/dist/modules/customers/components/detail/CompanyDashboardTab.js.map +7 -0
- package/dist/modules/customers/components/detail/CompanyDetailHeader.js +191 -0
- package/dist/modules/customers/components/detail/CompanyDetailHeader.js.map +7 -0
- package/dist/modules/customers/components/detail/CompanyDetailTabs.js +123 -0
- package/dist/modules/customers/components/detail/CompanyDetailTabs.js.map +7 -0
- package/dist/modules/customers/components/detail/CompanyKpiBar.js +174 -0
- package/dist/modules/customers/components/detail/CompanyKpiBar.js.map +7 -0
- package/dist/modules/customers/components/detail/CompanyPeopleSection.js +514 -230
- package/dist/modules/customers/components/detail/CompanyPeopleSection.js.map +2 -2
- package/dist/modules/customers/components/detail/CompanyTagsDialog.js +22 -0
- package/dist/modules/customers/components/detail/CompanyTagsDialog.js.map +7 -0
- package/dist/modules/customers/components/detail/ConfirmDealLostDialog.js +159 -0
- package/dist/modules/customers/components/detail/ConfirmDealLostDialog.js.map +7 -0
- package/dist/modules/customers/components/detail/CreatePersonDialog.js +135 -0
- package/dist/modules/customers/components/detail/CreatePersonDialog.js.map +7 -0
- package/dist/modules/customers/components/detail/DealClosureActionBar.js +59 -0
- package/dist/modules/customers/components/detail/DealClosureActionBar.js.map +7 -0
- package/dist/modules/customers/components/detail/DealDetailHeader.js +237 -0
- package/dist/modules/customers/components/detail/DealDetailHeader.js.map +7 -0
- package/dist/modules/customers/components/detail/DealDetailTabs.js +109 -0
- package/dist/modules/customers/components/detail/DealDetailTabs.js.map +7 -0
- package/dist/modules/customers/components/detail/DealForm.js +219 -92
- package/dist/modules/customers/components/detail/DealForm.js.map +2 -2
- package/dist/modules/customers/components/detail/DealLinkedEntitiesTab.js +295 -0
- package/dist/modules/customers/components/detail/DealLinkedEntitiesTab.js.map +7 -0
- package/dist/modules/customers/components/detail/DealLostSummaryDialog.js +107 -0
- package/dist/modules/customers/components/detail/DealLostSummaryDialog.js.map +7 -0
- package/dist/modules/customers/components/detail/DealWonPopup.js +113 -0
- package/dist/modules/customers/components/detail/DealWonPopup.js.map +7 -0
- package/dist/modules/customers/components/detail/DealsSection.js +206 -193
- package/dist/modules/customers/components/detail/DealsSection.js.map +2 -2
- package/dist/modules/customers/components/detail/DecisionMakersFooter.js +39 -0
- package/dist/modules/customers/components/detail/DecisionMakersFooter.js.map +7 -0
- package/dist/modules/customers/components/detail/EntityTagsDialog.js +1096 -0
- package/dist/modules/customers/components/detail/EntityTagsDialog.js.map +7 -0
- package/dist/modules/customers/components/detail/InlineActivityComposer.js +197 -0
- package/dist/modules/customers/components/detail/InlineActivityComposer.js.map +7 -0
- package/dist/modules/customers/components/detail/ManageTagsDialog.js +1091 -0
- package/dist/modules/customers/components/detail/ManageTagsDialog.js.map +7 -0
- package/dist/modules/customers/components/detail/MiniWeekCalendar.js +272 -0
- package/dist/modules/customers/components/detail/MiniWeekCalendar.js.map +7 -0
- package/dist/modules/customers/components/detail/MobilePersonDetail.js +106 -0
- package/dist/modules/customers/components/detail/MobilePersonDetail.js.map +7 -0
- package/dist/modules/customers/components/detail/NextStepCard.js +72 -0
- package/dist/modules/customers/components/detail/NextStepCard.js.map +7 -0
- package/dist/modules/customers/components/detail/PersonCard.js +192 -0
- package/dist/modules/customers/components/detail/PersonCard.js.map +7 -0
- package/dist/modules/customers/components/detail/PersonCompaniesSection.js +345 -0
- package/dist/modules/customers/components/detail/PersonCompaniesSection.js.map +7 -0
- package/dist/modules/customers/components/detail/PersonDetailHeader.js +220 -0
- package/dist/modules/customers/components/detail/PersonDetailHeader.js.map +7 -0
- package/dist/modules/customers/components/detail/PersonDetailTabs.js +122 -0
- package/dist/modules/customers/components/detail/PersonDetailTabs.js.map +7 -0
- package/dist/modules/customers/components/detail/PersonTagsDialog.js +24 -0
- package/dist/modules/customers/components/detail/PersonTagsDialog.js.map +7 -0
- package/dist/modules/customers/components/detail/PipelineStepper.js +191 -0
- package/dist/modules/customers/components/detail/PipelineStepper.js.map +7 -0
- package/dist/modules/customers/components/detail/PlannedActivitiesSection.js +222 -0
- package/dist/modules/customers/components/detail/PlannedActivitiesSection.js.map +7 -0
- package/dist/modules/customers/components/detail/RelationshipHealthCard.js +49 -0
- package/dist/modules/customers/components/detail/RelationshipHealthCard.js.map +7 -0
- package/dist/modules/customers/components/detail/RoleAssignmentRow.js +189 -0
- package/dist/modules/customers/components/detail/RoleAssignmentRow.js.map +7 -0
- package/dist/modules/customers/components/detail/RolesSection.js +234 -0
- package/dist/modules/customers/components/detail/RolesSection.js.map +7 -0
- package/dist/modules/customers/components/detail/ScheduleActivityDialog.js +410 -0
- package/dist/modules/customers/components/detail/ScheduleActivityDialog.js.map +7 -0
- package/dist/modules/customers/components/detail/aiActionCatalog.js +41 -0
- package/dist/modules/customers/components/detail/aiActionCatalog.js.map +7 -0
- package/dist/modules/customers/components/detail/assignableStaff.js +48 -0
- package/dist/modules/customers/components/detail/assignableStaff.js.map +7 -0
- package/dist/modules/customers/components/detail/dashboard/ActiveDealWidget.js +48 -0
- package/dist/modules/customers/components/detail/dashboard/ActiveDealWidget.js.map +7 -0
- package/dist/modules/customers/components/detail/dashboard/OpenTasksWidget.js +86 -0
- package/dist/modules/customers/components/detail/dashboard/OpenTasksWidget.js.map +7 -0
- package/dist/modules/customers/components/detail/dashboard/RecentActivityWidget.js +53 -0
- package/dist/modules/customers/components/detail/dashboard/RecentActivityWidget.js.map +7 -0
- package/dist/modules/customers/components/detail/dashboard/RelationshipHealthWidget.js +30 -0
- package/dist/modules/customers/components/detail/dashboard/RelationshipHealthWidget.js.map +7 -0
- package/dist/modules/customers/components/detail/dashboard/UpcomingMeetingsWidget.js +43 -0
- package/dist/modules/customers/components/detail/dashboard/UpcomingMeetingsWidget.js.map +7 -0
- package/dist/modules/customers/components/detail/dashboard/helpers.js +71 -0
- package/dist/modules/customers/components/detail/dashboard/helpers.js.map +7 -0
- package/dist/modules/customers/components/detail/healthScoreUtils.js +69 -0
- package/dist/modules/customers/components/detail/healthScoreUtils.js.map +7 -0
- package/dist/modules/customers/components/detail/hooks/useCurrencyDictionary.js +5 -5
- package/dist/modules/customers/components/detail/hooks/useCurrencyDictionary.js.map +2 -2
- package/dist/modules/customers/components/detail/hooks/useCustomerDictionary.js +9 -8
- package/dist/modules/customers/components/detail/hooks/useCustomerDictionary.js.map +3 -3
- package/dist/modules/customers/components/detail/hooks/useInteractionMutations.js +65 -0
- package/dist/modules/customers/components/detail/hooks/useInteractionMutations.js.map +7 -0
- package/dist/modules/customers/components/detail/notesAdapter.js +70 -30
- package/dist/modules/customers/components/detail/notesAdapter.js.map +2 -2
- package/dist/modules/customers/components/detail/pipelineStageUtils.js +26 -0
- package/dist/modules/customers/components/detail/pipelineStageUtils.js.map +7 -0
- package/dist/modules/customers/components/detail/schedule/DateTimeFields.js +144 -0
- package/dist/modules/customers/components/detail/schedule/DateTimeFields.js.map +7 -0
- package/dist/modules/customers/components/detail/schedule/FooterFields.js +60 -0
- package/dist/modules/customers/components/detail/schedule/FooterFields.js.map +7 -0
- package/dist/modules/customers/components/detail/schedule/LinkedEntitiesField.js +216 -0
- package/dist/modules/customers/components/detail/schedule/LinkedEntitiesField.js.map +7 -0
- package/dist/modules/customers/components/detail/schedule/LocationField.js +34 -0
- package/dist/modules/customers/components/detail/schedule/LocationField.js.map +7 -0
- package/dist/modules/customers/components/detail/schedule/ParticipantsField.js +226 -0
- package/dist/modules/customers/components/detail/schedule/ParticipantsField.js.map +7 -0
- package/dist/modules/customers/components/detail/schedule/fieldConfig.js +69 -0
- package/dist/modules/customers/components/detail/schedule/fieldConfig.js.map +7 -0
- package/dist/modules/customers/components/detail/schedule/index.js +21 -0
- package/dist/modules/customers/components/detail/schedule/index.js.map +7 -0
- package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js +172 -0
- package/dist/modules/customers/components/detail/schedule/useScheduleFormState.js.map +7 -0
- package/dist/modules/customers/components/detail/utils.js +23 -0
- package/dist/modules/customers/components/detail/utils.js.map +2 -2
- package/dist/modules/customers/components/formConfig.js +144 -22
- package/dist/modules/customers/components/formConfig.js.map +2 -2
- package/dist/modules/customers/components/linking/LinkEntityDialog.js +661 -0
- package/dist/modules/customers/components/linking/LinkEntityDialog.js.map +7 -0
- package/dist/modules/customers/components/linking/adapters/companyAdapter.js +252 -0
- package/dist/modules/customers/components/linking/adapters/companyAdapter.js.map +7 -0
- package/dist/modules/customers/components/linking/adapters/dealAdapter.js +384 -0
- package/dist/modules/customers/components/linking/adapters/dealAdapter.js.map +7 -0
- package/dist/modules/customers/components/linking/adapters/personAdapter.js +324 -0
- package/dist/modules/customers/components/linking/adapters/personAdapter.js.map +7 -0
- package/dist/modules/customers/components/list/CollectionPreviewCell.js +53 -0
- package/dist/modules/customers/components/list/CollectionPreviewCell.js.map +7 -0
- package/dist/modules/customers/data/entities.js +407 -1
- package/dist/modules/customers/data/entities.js.map +2 -2
- package/dist/modules/customers/data/validators.js +139 -21
- package/dist/modules/customers/data/validators.js.map +2 -2
- package/dist/modules/customers/events.js +19 -1
- package/dist/modules/customers/events.js.map +2 -2
- package/dist/modules/customers/lib/customerRoleTypes.js +19 -0
- package/dist/modules/customers/lib/customerRoleTypes.js.map +7 -0
- package/dist/modules/customers/lib/dealClosureNotification.js +39 -0
- package/dist/modules/customers/lib/dealClosureNotification.js.map +7 -0
- package/dist/modules/customers/lib/dealStageTransitionTable.js +29 -0
- package/dist/modules/customers/lib/dealStageTransitionTable.js.map +7 -0
- package/dist/modules/customers/lib/dictionaries.js +25 -0
- package/dist/modules/customers/lib/dictionaries.js.map +2 -2
- package/dist/modules/customers/lib/interactionReadModel.js +10 -0
- package/dist/modules/customers/lib/interactionReadModel.js.map +2 -2
- package/dist/modules/customers/lib/personCompanies.js +235 -0
- package/dist/modules/customers/lib/personCompanies.js.map +7 -0
- package/dist/modules/customers/lib/personCompanyLinkTable.js +42 -0
- package/dist/modules/customers/lib/personCompanyLinkTable.js.map +7 -0
- package/dist/modules/customers/lib/roleTypeUsage.js +104 -0
- package/dist/modules/customers/lib/roleTypeUsage.js.map +7 -0
- package/dist/modules/customers/migrations/Migration20260406214502.js +18 -0
- package/dist/modules/customers/migrations/Migration20260406214502.js.map +7 -0
- package/dist/modules/customers/migrations/Migration20260408135736.js +17 -0
- package/dist/modules/customers/migrations/Migration20260408135736.js.map +7 -0
- package/dist/modules/customers/migrations/Migration20260408225345.js +21 -0
- package/dist/modules/customers/migrations/Migration20260408225345.js.map +7 -0
- package/dist/modules/customers/migrations/Migration20260411075533.js +27 -0
- package/dist/modules/customers/migrations/Migration20260411075533.js.map +7 -0
- package/dist/modules/customers/migrations/Migration20260411103551.js +13 -0
- package/dist/modules/customers/migrations/Migration20260411103551.js.map +7 -0
- package/dist/modules/customers/migrations/Migration20260411130944.js +26 -0
- package/dist/modules/customers/migrations/Migration20260411130944.js.map +7 -0
- package/dist/modules/customers/migrations/Migration20260415095203.js +13 -0
- package/dist/modules/customers/migrations/Migration20260415095203.js.map +7 -0
- package/dist/modules/customers/migrations/Migration20260415135056.js +20 -0
- package/dist/modules/customers/migrations/Migration20260415135056.js.map +7 -0
- package/dist/modules/customers/migrations/Migration20260417140000.js +15 -0
- package/dist/modules/customers/migrations/Migration20260417140000.js.map +7 -0
- package/dist/modules/customers/migrations/Migration20260417160000.js +17 -0
- package/dist/modules/customers/migrations/Migration20260417160000.js.map +7 -0
- package/dist/modules/customers/migrations/Migration20260417235407.js +13 -0
- package/dist/modules/customers/migrations/Migration20260417235407.js.map +7 -0
- package/dist/modules/customers/setup.js +16 -1
- package/dist/modules/customers/setup.js.map +2 -2
- package/dist/modules/customers/subscribers/deal-closure-notification.js +16 -0
- package/dist/modules/customers/subscribers/deal-closure-notification.js.map +7 -0
- package/dist/modules/customers/subscribers/deal-lost-notification.js +16 -0
- package/dist/modules/customers/subscribers/deal-lost-notification.js.map +7 -0
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js +2 -0
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.js.map +2 -2
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/reorder/route.js +154 -0
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/reorder/route.js.map +7 -0
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/route.js +6 -2
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/route.js.map +2 -2
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/set-default/route.js +154 -0
- package/dist/modules/dictionaries/api/[dictionaryId]/entries/set-default/route.js.map +7 -0
- package/dist/modules/dictionaries/api/context.js +8 -1
- package/dist/modules/dictionaries/api/context.js.map +2 -2
- package/dist/modules/dictionaries/api/openapi.js +18 -1
- package/dist/modules/dictionaries/api/openapi.js.map +2 -2
- package/dist/modules/dictionaries/commands/entry-operations.js +388 -0
- package/dist/modules/dictionaries/commands/entry-operations.js.map +7 -0
- package/dist/modules/dictionaries/commands/factory.js +24 -3
- package/dist/modules/dictionaries/commands/factory.js.map +2 -2
- package/dist/modules/dictionaries/commands/index.js +1 -0
- package/dist/modules/dictionaries/commands/index.js.map +2 -2
- package/dist/modules/dictionaries/components/DictionaryTable.js +6 -3
- package/dist/modules/dictionaries/components/DictionaryTable.js.map +2 -2
- package/dist/modules/dictionaries/data/entities.js +11 -1
- package/dist/modules/dictionaries/data/entities.js.map +2 -2
- package/dist/modules/dictionaries/data/validators.js +28 -2
- package/dist/modules/dictionaries/data/validators.js.map +2 -2
- package/dist/modules/dictionaries/events.js +18 -0
- package/dist/modules/dictionaries/events.js.map +7 -0
- package/dist/modules/dictionaries/lib/clientEntries.js +43 -0
- package/dist/modules/dictionaries/lib/clientEntries.js.map +7 -0
- package/dist/modules/dictionaries/migrations/Migration20260410171544.js +45 -0
- package/dist/modules/dictionaries/migrations/Migration20260410171544.js.map +7 -0
- package/dist/modules/inbox_ops/api/proposals/[id]/route.js +4 -1
- package/dist/modules/inbox_ops/api/proposals/[id]/route.js.map +2 -2
- package/dist/modules/query_index/lib/engine.js +1 -1
- package/dist/modules/query_index/lib/engine.js.map +2 -2
- package/dist/modules/sales/components/documents/AddressesSection.js +82 -42
- package/dist/modules/sales/components/documents/AddressesSection.js.map +2 -2
- package/dist/modules/sales/lib/dictionaries.js +16 -0
- package/dist/modules/sales/lib/dictionaries.js.map +2 -2
- package/dist/modules/sales/widgets/injection-table.js +5 -1
- package/dist/modules/sales/widgets/injection-table.js.map +2 -2
- package/generated/entities/action_log/index.ts +4 -0
- package/generated/entities/customer_company_billing/index.ts +10 -0
- package/generated/entities/customer_deal/index.ts +4 -0
- package/generated/entities/customer_deal_stage_transition/index.ts +14 -0
- package/generated/entities/customer_dictionary_kind_setting/index.ts +9 -0
- package/generated/entities/customer_entity/index.ts +4 -0
- package/generated/entities/customer_entity_role/index.ts +10 -0
- package/generated/entities/customer_interaction/index.ts +11 -0
- package/generated/entities/customer_label/index.ts +8 -0
- package/generated/entities/customer_label_assignment/index.ts +7 -0
- package/generated/entities/customer_person_company_link/index.ts +9 -0
- package/generated/entities/customer_person_company_role/index.ts +7 -0
- package/generated/entities/dictionary_entry/index.ts +2 -0
- package/generated/entities.ids.generated.ts +9 -1
- package/generated/entity-fields-registry.ts +116 -1
- package/package.json +3 -3
- package/src/modules/attachments/api/route.ts +48 -6
- package/src/modules/attachments/i18n/de.json +4 -0
- package/src/modules/attachments/i18n/en.json +4 -0
- package/src/modules/attachments/i18n/es.json +4 -0
- package/src/modules/attachments/i18n/pl.json +4 -0
- package/src/modules/audit_logs/api/audit-logs/actions/export/route.ts +260 -0
- package/src/modules/audit_logs/api/audit-logs/actions/route.ts +81 -6
- package/src/modules/audit_logs/cli.ts +79 -0
- package/src/modules/audit_logs/data/entities.ts +17 -0
- package/src/modules/audit_logs/data/validators.ts +9 -1
- package/src/modules/audit_logs/lib/changeRows.ts +47 -0
- package/src/modules/audit_logs/lib/display-helpers.tsx +4 -30
- package/src/modules/audit_logs/lib/projections.ts +110 -0
- package/src/modules/audit_logs/migrations/.snapshot-open-mercato.json +325 -2
- package/src/modules/audit_logs/migrations/Migration20260412160533.ts +21 -0
- package/src/modules/audit_logs/services/actionLogService.ts +455 -85
- package/src/modules/catalog/i18n/de.json +1 -0
- package/src/modules/catalog/i18n/en.json +1 -0
- package/src/modules/catalog/i18n/es.json +1 -0
- package/src/modules/catalog/i18n/pl.json +1 -0
- package/src/modules/customer_accounts/i18n/de.json +2 -0
- package/src/modules/customer_accounts/i18n/en.json +2 -0
- package/src/modules/customer_accounts/i18n/es.json +2 -0
- package/src/modules/customer_accounts/i18n/pl.json +2 -0
- package/src/modules/customers/acl.ts +2 -0
- package/src/modules/customers/api/activities/route.ts +4 -0
- package/src/modules/customers/api/assignable-staff/route.ts +250 -0
- package/src/modules/customers/api/companies/[id]/people/route.ts +244 -0
- package/src/modules/customers/api/companies/[id]/roles/route.ts +15 -0
- package/src/modules/customers/api/companies/[id]/route.ts +458 -40
- package/src/modules/customers/api/companies/route.ts +93 -15
- package/src/modules/customers/api/deals/[id]/companies/route.ts +203 -0
- package/src/modules/customers/api/deals/[id]/people/route.ts +182 -0
- package/src/modules/customers/api/deals/[id]/route.ts +554 -57
- package/src/modules/customers/api/deals/[id]/stats/route.ts +221 -0
- package/src/modules/customers/api/deals/route.ts +35 -46
- package/src/modules/customers/api/dictionaries/[kind]/[id]/route.ts +105 -3
- package/src/modules/customers/api/dictionaries/[kind]/route.ts +143 -44
- package/src/modules/customers/api/dictionaries/context.ts +45 -16
- package/src/modules/customers/api/dictionaries/kind-settings/route.ts +232 -0
- package/src/modules/customers/api/entity-roles-factory.ts +520 -0
- package/src/modules/customers/api/interactions/conflicts/route.ts +196 -0
- package/src/modules/customers/api/interactions/counts/route.ts +112 -0
- package/src/modules/customers/api/interactions/route.ts +95 -2
- package/src/modules/customers/api/labels/assign/route.ts +202 -0
- package/src/modules/customers/api/labels/auth.ts +19 -0
- package/src/modules/customers/api/labels/route.ts +310 -0
- package/src/modules/customers/api/labels/table-errors.ts +36 -0
- package/src/modules/customers/api/labels/unassign/route.ts +197 -0
- package/src/modules/customers/api/people/[id]/companies/[linkId]/route.ts +331 -0
- package/src/modules/customers/api/people/[id]/companies/context.ts +70 -0
- package/src/modules/customers/api/people/[id]/companies/enriched/route.ts +384 -0
- package/src/modules/customers/api/people/[id]/companies/route.ts +215 -0
- package/src/modules/customers/api/people/[id]/roles/route.ts +15 -0
- package/src/modules/customers/api/people/[id]/route.ts +153 -26
- package/src/modules/customers/api/people/route.ts +134 -31
- package/src/modules/customers/api/todos/route.ts +4 -0
- package/src/modules/customers/api/utils.ts +36 -0
- package/src/modules/customers/backend/config/customers/page.tsx +2 -6
- package/src/modules/customers/backend/customers/companies/page.tsx +36 -26
- package/src/modules/customers/backend/customers/companies-v2/[id]/page.tsx +277 -262
- package/src/modules/customers/backend/customers/deals/[id]/hooks/formatters.ts +19 -0
- package/src/modules/customers/backend/customers/deals/[id]/hooks/types.ts +104 -0
- package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealActivities.ts +60 -0
- package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealAssociations.ts +362 -0
- package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealClosure.ts +113 -0
- package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealData.ts +52 -0
- package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealFormHandlers.ts +86 -0
- package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealInjectedTabs.tsx +60 -0
- package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealMutationContext.ts +76 -0
- package/src/modules/customers/backend/customers/deals/[id]/hooks/useDealPipeline.ts +56 -0
- package/src/modules/customers/backend/customers/deals/[id]/hooks/useScheduleDialog.ts +38 -0
- package/src/modules/customers/backend/customers/deals/[id]/page.tsx +587 -624
- package/src/modules/customers/backend/customers/deals/page.tsx +71 -28
- package/src/modules/customers/backend/customers/people/page.tsx +35 -29
- package/src/modules/customers/backend/customers/people-v2/[id]/page.tsx +343 -209
- package/src/modules/customers/cli.ts +107 -12
- package/src/modules/customers/commands/activities.ts +13 -0
- package/src/modules/customers/commands/deals.ts +386 -114
- package/src/modules/customers/commands/dictionaries.ts +175 -32
- package/src/modules/customers/commands/dictionaryKindSettings.ts +268 -0
- package/src/modules/customers/commands/entity-roles.ts +494 -0
- package/src/modules/customers/commands/index.ts +4 -0
- package/src/modules/customers/commands/interactions.ts +125 -21
- package/src/modules/customers/commands/labels.ts +626 -0
- package/src/modules/customers/commands/people.ts +373 -259
- package/src/modules/customers/commands/personCompanyLinks.ts +654 -0
- package/src/modules/customers/commands/shared.ts +16 -15
- package/src/modules/customers/commands/todos.ts +17 -1
- package/src/modules/customers/components/AddressEditor.tsx +1 -1
- package/src/modules/customers/components/CustomersConfigurationSections.tsx +36 -0
- package/src/modules/customers/components/DictionarySettings.tsx +43 -2
- package/src/modules/customers/components/detail/ActiveDealCard.tsx +175 -0
- package/src/modules/customers/components/detail/ActivitiesSection.tsx +267 -361
- package/src/modules/customers/components/detail/ActivityAiActions.tsx +49 -0
- package/src/modules/customers/components/detail/ActivityCard.tsx +154 -0
- package/src/modules/customers/components/detail/ActivityHistorySection.tsx +412 -0
- package/src/modules/customers/components/detail/ActivityLogTab.tsx +67 -0
- package/src/modules/customers/components/detail/ActivityTimeline.tsx +158 -0
- package/src/modules/customers/components/detail/ActivityTimelineFilters.tsx +163 -0
- package/src/modules/customers/components/detail/ActivityTypeSelector.tsx +53 -0
- package/src/modules/customers/components/detail/AiActionChips.tsx +48 -0
- package/src/modules/customers/components/detail/AssignRoleDialog.tsx +672 -0
- package/src/modules/customers/components/detail/ChangelogEntryRow.tsx +132 -0
- package/src/modules/customers/components/detail/ChangelogFilters.tsx +193 -0
- package/src/modules/customers/components/detail/ChangelogKpiCards.tsx +107 -0
- package/src/modules/customers/components/detail/ChangelogTab.tsx +629 -0
- package/src/modules/customers/components/detail/ComingSoonPlaceholder.tsx +21 -0
- package/src/modules/customers/components/detail/CompanyCard.tsx +419 -0
- package/src/modules/customers/components/detail/CompanyDashboardTab.tsx +161 -0
- package/src/modules/customers/components/detail/CompanyDetailHeader.tsx +243 -0
- package/src/modules/customers/components/detail/CompanyDetailTabs.tsx +172 -0
- package/src/modules/customers/components/detail/CompanyKpiBar.tsx +206 -0
- package/src/modules/customers/components/detail/CompanyPeopleSection.tsx +582 -288
- package/src/modules/customers/components/detail/CompanyTagsDialog.tsx +23 -0
- package/src/modules/customers/components/detail/ConfirmDealLostDialog.tsx +210 -0
- package/src/modules/customers/components/detail/CreatePersonDialog.tsx +178 -0
- package/src/modules/customers/components/detail/DealClosureActionBar.tsx +63 -0
- package/src/modules/customers/components/detail/DealDetailHeader.tsx +335 -0
- package/src/modules/customers/components/detail/DealDetailTabs.tsx +154 -0
- package/src/modules/customers/components/detail/DealForm.tsx +253 -101
- package/src/modules/customers/components/detail/DealLinkedEntitiesTab.tsx +349 -0
- package/src/modules/customers/components/detail/DealLostSummaryDialog.tsx +156 -0
- package/src/modules/customers/components/detail/DealWonPopup.tsx +164 -0
- package/src/modules/customers/components/detail/DealsSection.tsx +276 -221
- package/src/modules/customers/components/detail/DecisionMakersFooter.tsx +56 -0
- package/src/modules/customers/components/detail/EntityTagsDialog.tsx +1372 -0
- package/src/modules/customers/components/detail/InlineActivityComposer.tsx +239 -0
- package/src/modules/customers/components/detail/ManageTagsDialog.tsx +1331 -0
- package/src/modules/customers/components/detail/MiniWeekCalendar.tsx +338 -0
- package/src/modules/customers/components/detail/MobilePersonDetail.tsx +124 -0
- package/src/modules/customers/components/detail/NextStepCard.tsx +104 -0
- package/src/modules/customers/components/detail/PersonCard.tsx +238 -0
- package/src/modules/customers/components/detail/PersonCompaniesSection.tsx +426 -0
- package/src/modules/customers/components/detail/PersonDetailHeader.tsx +294 -0
- package/src/modules/customers/components/detail/PersonDetailTabs.tsx +172 -0
- package/src/modules/customers/components/detail/PersonTagsDialog.tsx +26 -0
- package/src/modules/customers/components/detail/PipelineStepper.tsx +245 -0
- package/src/modules/customers/components/detail/PlannedActivitiesSection.tsx +255 -0
- package/src/modules/customers/components/detail/RelationshipHealthCard.tsx +63 -0
- package/src/modules/customers/components/detail/RoleAssignmentRow.tsx +248 -0
- package/src/modules/customers/components/detail/RolesSection.tsx +311 -0
- package/src/modules/customers/components/detail/ScheduleActivityDialog.tsx +481 -0
- package/src/modules/customers/components/detail/aiActionCatalog.ts +77 -0
- package/src/modules/customers/components/detail/assignableStaff.ts +124 -0
- package/src/modules/customers/components/detail/dashboard/ActiveDealWidget.tsx +63 -0
- package/src/modules/customers/components/detail/dashboard/OpenTasksWidget.tsx +114 -0
- package/src/modules/customers/components/detail/dashboard/RecentActivityWidget.tsx +69 -0
- package/src/modules/customers/components/detail/dashboard/RelationshipHealthWidget.tsx +40 -0
- package/src/modules/customers/components/detail/dashboard/UpcomingMeetingsWidget.tsx +64 -0
- package/src/modules/customers/components/detail/dashboard/helpers.ts +78 -0
- package/src/modules/customers/components/detail/healthScoreUtils.ts +91 -0
- package/src/modules/customers/components/detail/hooks/useCurrencyDictionary.ts +8 -8
- package/src/modules/customers/components/detail/hooks/useCustomerDictionary.ts +10 -6
- package/src/modules/customers/components/detail/hooks/useInteractionMutations.ts +91 -0
- package/src/modules/customers/components/detail/notesAdapter.ts +91 -30
- package/src/modules/customers/components/detail/pipelineStageUtils.ts +29 -0
- package/src/modules/customers/components/detail/schedule/DateTimeFields.tsx +187 -0
- package/src/modules/customers/components/detail/schedule/FooterFields.tsx +79 -0
- package/src/modules/customers/components/detail/schedule/LinkedEntitiesField.tsx +277 -0
- package/src/modules/customers/components/detail/schedule/LocationField.tsx +42 -0
- package/src/modules/customers/components/detail/schedule/ParticipantsField.tsx +255 -0
- package/src/modules/customers/components/detail/schedule/fieldConfig.ts +70 -0
- package/src/modules/customers/components/detail/schedule/index.ts +9 -0
- package/src/modules/customers/components/detail/schedule/useScheduleFormState.ts +221 -0
- package/src/modules/customers/components/detail/types.ts +16 -0
- package/src/modules/customers/components/detail/utils.ts +25 -0
- package/src/modules/customers/components/formConfig.tsx +223 -28
- package/src/modules/customers/components/linking/LinkEntityDialog.tsx +920 -0
- package/src/modules/customers/components/linking/adapters/companyAdapter.tsx +398 -0
- package/src/modules/customers/components/linking/adapters/dealAdapter.tsx +578 -0
- package/src/modules/customers/components/linking/adapters/personAdapter.tsx +512 -0
- package/src/modules/customers/components/list/CollectionPreviewCell.tsx +66 -0
- package/src/modules/customers/data/entities.ts +353 -1
- package/src/modules/customers/data/validators.ts +170 -19
- package/src/modules/customers/events.ts +22 -0
- package/src/modules/customers/i18n/de.json +841 -2
- package/src/modules/customers/i18n/en.json +841 -2
- package/src/modules/customers/i18n/es.json +840 -1
- package/src/modules/customers/i18n/pl.json +841 -2
- package/src/modules/customers/lib/customerRoleTypes.ts +24 -0
- package/src/modules/customers/lib/dealClosureNotification.ts +64 -0
- package/src/modules/customers/lib/dealStageTransitionTable.ts +32 -0
- package/src/modules/customers/lib/dictionaries.ts +26 -10
- package/src/modules/customers/lib/interactionReadModel.ts +10 -0
- package/src/modules/customers/lib/personCompanies.ts +317 -0
- package/src/modules/customers/lib/personCompanyLinkTable.ts +58 -0
- package/src/modules/customers/lib/roleTypeUsage.ts +146 -0
- package/src/modules/customers/migrations/.snapshot-open-mercato.json +2747 -798
- package/src/modules/customers/migrations/Migration20260406214502.ts +19 -0
- package/src/modules/customers/migrations/Migration20260408135736.ts +15 -0
- package/src/modules/customers/migrations/Migration20260408225345.ts +23 -0
- package/src/modules/customers/migrations/Migration20260411075533.ts +30 -0
- package/src/modules/customers/migrations/Migration20260411103551.ts +13 -0
- package/src/modules/customers/migrations/Migration20260411130944.ts +30 -0
- package/src/modules/customers/migrations/Migration20260415095203.ts +13 -0
- package/src/modules/customers/migrations/Migration20260415135056.ts +22 -0
- package/src/modules/customers/migrations/Migration20260417140000.ts +15 -0
- package/src/modules/customers/migrations/Migration20260417160000.ts +17 -0
- package/src/modules/customers/migrations/Migration20260417235407.ts +13 -0
- package/src/modules/customers/setup.ts +15 -0
- package/src/modules/customers/subscribers/deal-closure-notification.ts +22 -0
- package/src/modules/customers/subscribers/deal-lost-notification.ts +22 -0
- package/src/modules/dictionaries/api/[dictionaryId]/entries/[entryId]/route.ts +2 -0
- package/src/modules/dictionaries/api/[dictionaryId]/entries/reorder/route.ts +162 -0
- package/src/modules/dictionaries/api/[dictionaryId]/entries/route.ts +6 -2
- package/src/modules/dictionaries/api/[dictionaryId]/entries/set-default/route.ts +162 -0
- package/src/modules/dictionaries/api/context.ts +9 -0
- package/src/modules/dictionaries/api/openapi.ts +17 -0
- package/src/modules/dictionaries/commands/entry-operations.ts +457 -0
- package/src/modules/dictionaries/commands/factory.ts +31 -3
- package/src/modules/dictionaries/commands/index.ts +1 -0
- package/src/modules/dictionaries/components/DictionaryTable.tsx +15 -6
- package/src/modules/dictionaries/data/entities.ts +9 -0
- package/src/modules/dictionaries/data/validators.ts +34 -0
- package/src/modules/dictionaries/events.ts +20 -0
- package/src/modules/dictionaries/i18n/de.json +2 -0
- package/src/modules/dictionaries/i18n/en.json +2 -0
- package/src/modules/dictionaries/i18n/es.json +2 -0
- package/src/modules/dictionaries/i18n/pl.json +2 -0
- package/src/modules/dictionaries/lib/clientEntries.ts +66 -0
- package/src/modules/dictionaries/migrations/.snapshot-open-mercato.json +185 -3
- package/src/modules/dictionaries/migrations/Migration20260410171544.ts +49 -0
- package/src/modules/inbox_ops/api/proposals/[id]/route.ts +4 -1
- package/src/modules/query_index/lib/engine.ts +9 -1
- package/src/modules/sales/components/documents/AddressesSection.tsx +92 -42
- package/src/modules/sales/i18n/de.json +28 -0
- package/src/modules/sales/i18n/en.json +28 -0
- package/src/modules/sales/i18n/es.json +28 -0
- package/src/modules/sales/i18n/pl.json +28 -0
- package/src/modules/sales/lib/dictionaries.ts +18 -0
- package/src/modules/sales/widgets/injection-table.ts +4 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Users, ArrowUpRight } from "lucide-react";
|
|
4
|
+
import { Badge } from "@open-mercato/ui/primitives/badge";
|
|
5
|
+
import { formatCurrency } from "../utils.js";
|
|
6
|
+
function ActiveDealWidget({ deals, t }) {
|
|
7
|
+
const topDeal = deals.sort((a, b) => {
|
|
8
|
+
const va = typeof a.valueAmount === "number" ? a.valueAmount : parseFloat(String(a.valueAmount ?? "0"));
|
|
9
|
+
const vb = typeof b.valueAmount === "number" ? b.valueAmount : parseFloat(String(b.valueAmount ?? "0"));
|
|
10
|
+
return vb - va;
|
|
11
|
+
})[0];
|
|
12
|
+
if (!topDeal) {
|
|
13
|
+
return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-card p-5", children: [
|
|
14
|
+
/* @__PURE__ */ jsxs("h3", { className: "flex items-center gap-2 text-sm font-semibold text-foreground", children: [
|
|
15
|
+
/* @__PURE__ */ jsx(Users, { className: "size-4" }),
|
|
16
|
+
t("customers.companies.dashboard.activeDeal", "Active deal")
|
|
17
|
+
] }),
|
|
18
|
+
/* @__PURE__ */ jsx("p", { className: "mt-3 text-sm text-muted-foreground", children: t("customers.companies.dashboard.noDeals", "No active deals") })
|
|
19
|
+
] });
|
|
20
|
+
}
|
|
21
|
+
const amount = typeof topDeal.valueAmount === "number" ? topDeal.valueAmount : parseFloat(String(topDeal.valueAmount ?? "0"));
|
|
22
|
+
return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-card p-5", children: [
|
|
23
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
24
|
+
/* @__PURE__ */ jsxs("h3", { className: "flex items-center gap-2 text-sm font-semibold text-foreground", children: [
|
|
25
|
+
/* @__PURE__ */ jsx(Users, { className: "size-4" }),
|
|
26
|
+
t("customers.companies.dashboard.activeDeal", "Active deal")
|
|
27
|
+
] }),
|
|
28
|
+
/* @__PURE__ */ jsx(ArrowUpRight, { className: "size-4 text-muted-foreground" })
|
|
29
|
+
] }),
|
|
30
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-3", children: [
|
|
31
|
+
/* @__PURE__ */ jsx("p", { className: "font-semibold text-foreground", children: topDeal.title }),
|
|
32
|
+
topDeal.createdAt && /* @__PURE__ */ jsxs("p", { className: "mt-0.5 text-xs text-muted-foreground", children: [
|
|
33
|
+
t("customers.companies.dashboard.created", "Created"),
|
|
34
|
+
" ",
|
|
35
|
+
new Date(topDeal.createdAt).toLocaleDateString()
|
|
36
|
+
] }),
|
|
37
|
+
topDeal.pipelineStage && /* @__PURE__ */ jsx("div", { className: "mt-2", children: /* @__PURE__ */ jsx(Badge, { variant: "outline", className: "text-xs", children: topDeal.pipelineStage }) }),
|
|
38
|
+
Number.isFinite(amount) && amount > 0 && /* @__PURE__ */ jsxs("p", { className: "mt-2 text-lg font-bold text-foreground", children: [
|
|
39
|
+
formatCurrency(amount, topDeal.valueCurrency),
|
|
40
|
+
/* @__PURE__ */ jsx("span", { className: "ml-1.5 text-xs font-normal text-muted-foreground", children: t("customers.companies.dashboard.potentialValue", "potential value") })
|
|
41
|
+
] })
|
|
42
|
+
] })
|
|
43
|
+
] });
|
|
44
|
+
}
|
|
45
|
+
export {
|
|
46
|
+
ActiveDealWidget
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=ActiveDealWidget.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../src/modules/customers/components/detail/dashboard/ActiveDealWidget.tsx"],
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Users, ArrowUpRight } from 'lucide-react'\nimport { Badge } from '@open-mercato/ui/primitives/badge'\nimport type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport type { DealSummary } from '../../formConfig'\nimport { formatCurrency } from '../utils'\n\nexport function ActiveDealWidget({ deals, t }: { deals: DealSummary[]; t: TranslateFn }) {\n const topDeal = deals.sort((a, b) => {\n const va = typeof a.valueAmount === 'number' ? a.valueAmount : parseFloat(String(a.valueAmount ?? '0'))\n const vb = typeof b.valueAmount === 'number' ? b.valueAmount : parseFloat(String(b.valueAmount ?? '0'))\n return vb - va\n })[0]\n\n if (!topDeal) {\n return (\n <div className=\"rounded-lg border bg-card p-5\">\n <h3 className=\"flex items-center gap-2 text-sm font-semibold text-foreground\">\n <Users className=\"size-4\" />\n {t('customers.companies.dashboard.activeDeal', 'Active deal')}\n </h3>\n <p className=\"mt-3 text-sm text-muted-foreground\">{t('customers.companies.dashboard.noDeals', 'No active deals')}</p>\n </div>\n )\n }\n\n const amount = typeof topDeal.valueAmount === 'number' ? topDeal.valueAmount : parseFloat(String(topDeal.valueAmount ?? '0'))\n\n return (\n <div className=\"rounded-lg border bg-card p-5\">\n <div className=\"flex items-center justify-between\">\n <h3 className=\"flex items-center gap-2 text-sm font-semibold text-foreground\">\n <Users className=\"size-4\" />\n {t('customers.companies.dashboard.activeDeal', 'Active deal')}\n </h3>\n <ArrowUpRight className=\"size-4 text-muted-foreground\" />\n </div>\n <div className=\"mt-3\">\n <p className=\"font-semibold text-foreground\">{topDeal.title}</p>\n {topDeal.createdAt && (\n <p className=\"mt-0.5 text-xs text-muted-foreground\">\n {t('customers.companies.dashboard.created', 'Created')} {new Date(topDeal.createdAt).toLocaleDateString()}\n </p>\n )}\n {topDeal.pipelineStage && (\n <div className=\"mt-2\">\n <Badge variant=\"outline\" className=\"text-xs\">{topDeal.pipelineStage}</Badge>\n </div>\n )}\n {Number.isFinite(amount) && amount > 0 && (\n <p className=\"mt-2 text-lg font-bold text-foreground\">\n {formatCurrency(amount, topDeal.valueCurrency)}\n <span className=\"ml-1.5 text-xs font-normal text-muted-foreground\">\n {t('customers.companies.dashboard.potentialValue', 'potential value')}\n </span>\n </p>\n )}\n </div>\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": ";AAmBQ,SACE,KADF;AAhBR,SAAS,OAAO,oBAAoB;AACpC,SAAS,aAAa;AAGtB,SAAS,sBAAsB;AAExB,SAAS,iBAAiB,EAAE,OAAO,EAAE,GAA6C;AACvF,QAAM,UAAU,MAAM,KAAK,CAAC,GAAG,MAAM;AACnC,UAAM,KAAK,OAAO,EAAE,gBAAgB,WAAW,EAAE,cAAc,WAAW,OAAO,EAAE,eAAe,GAAG,CAAC;AACtG,UAAM,KAAK,OAAO,EAAE,gBAAgB,WAAW,EAAE,cAAc,WAAW,OAAO,EAAE,eAAe,GAAG,CAAC;AACtG,WAAO,KAAK;AAAA,EACd,CAAC,EAAE,CAAC;AAEJ,MAAI,CAAC,SAAS;AACZ,WACE,qBAAC,SAAI,WAAU,iCACb;AAAA,2BAAC,QAAG,WAAU,iEACZ;AAAA,4BAAC,SAAM,WAAU,UAAS;AAAA,QACzB,EAAE,4CAA4C,aAAa;AAAA,SAC9D;AAAA,MACA,oBAAC,OAAE,WAAU,sCAAsC,YAAE,yCAAyC,iBAAiB,GAAE;AAAA,OACnH;AAAA,EAEJ;AAEA,QAAM,SAAS,OAAO,QAAQ,gBAAgB,WAAW,QAAQ,cAAc,WAAW,OAAO,QAAQ,eAAe,GAAG,CAAC;AAE5H,SACE,qBAAC,SAAI,WAAU,iCACb;AAAA,yBAAC,SAAI,WAAU,qCACb;AAAA,2BAAC,QAAG,WAAU,iEACZ;AAAA,4BAAC,SAAM,WAAU,UAAS;AAAA,QACzB,EAAE,4CAA4C,aAAa;AAAA,SAC9D;AAAA,MACA,oBAAC,gBAAa,WAAU,gCAA+B;AAAA,OACzD;AAAA,IACA,qBAAC,SAAI,WAAU,QACb;AAAA,0BAAC,OAAE,WAAU,iCAAiC,kBAAQ,OAAM;AAAA,MAC3D,QAAQ,aACP,qBAAC,OAAE,WAAU,wCACV;AAAA,UAAE,yCAAyC,SAAS;AAAA,QAAE;AAAA,QAAE,IAAI,KAAK,QAAQ,SAAS,EAAE,mBAAmB;AAAA,SAC1G;AAAA,MAED,QAAQ,iBACP,oBAAC,SAAI,WAAU,QACb,8BAAC,SAAM,SAAQ,WAAU,WAAU,WAAW,kBAAQ,eAAc,GACtE;AAAA,MAED,OAAO,SAAS,MAAM,KAAK,SAAS,KACnC,qBAAC,OAAE,WAAU,0CACV;AAAA,uBAAe,QAAQ,QAAQ,aAAa;AAAA,QAC7C,oBAAC,UAAK,WAAU,oDACb,YAAE,gDAAgD,iBAAiB,GACtE;AAAA,SACF;AAAA,OAEJ;AAAA,KACF;AAEJ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { CheckCircle2, AlertCircle, ArrowUpRight } from "lucide-react";
|
|
5
|
+
import { cn } from "@open-mercato/shared/lib/utils";
|
|
6
|
+
import { Button } from "@open-mercato/ui/primitives/button";
|
|
7
|
+
import { Badge } from "@open-mercato/ui/primitives/badge";
|
|
8
|
+
function isOverdue(dueAt) {
|
|
9
|
+
if (!dueAt) return false;
|
|
10
|
+
return new Date(dueAt) < /* @__PURE__ */ new Date();
|
|
11
|
+
}
|
|
12
|
+
function priorityLabel(priority) {
|
|
13
|
+
if (priority === null || priority === void 0) return { label: "None", variant: "muted" };
|
|
14
|
+
if (priority >= 3) return { label: "High", variant: "destructive" };
|
|
15
|
+
if (priority === 2) return { label: "Medium", variant: "default" };
|
|
16
|
+
return { label: "Low", variant: "secondary" };
|
|
17
|
+
}
|
|
18
|
+
function OpenTasksWidget({
|
|
19
|
+
tasks,
|
|
20
|
+
currentUserId,
|
|
21
|
+
t,
|
|
22
|
+
onViewAll
|
|
23
|
+
}) {
|
|
24
|
+
const [taskFilter, setTaskFilter] = React.useState("all");
|
|
25
|
+
const overdueTasks = tasks.filter((task) => isOverdue(task.dueAt));
|
|
26
|
+
const mineTasks = currentUserId ? tasks.filter((task) => {
|
|
27
|
+
const assignee = task.assignedToUserId ?? task.createdByUserId;
|
|
28
|
+
return assignee === currentUserId;
|
|
29
|
+
}) : tasks;
|
|
30
|
+
const filteredTasks = taskFilter === "overdue" ? overdueTasks : taskFilter === "mine" ? mineTasks : tasks;
|
|
31
|
+
const filterTabs = [
|
|
32
|
+
{ key: "all", label: t("customers.tasks.filters.all", "All"), count: tasks.length },
|
|
33
|
+
{ key: "mine", label: t("customers.tasks.filters.mine", "Mine"), count: mineTasks.length },
|
|
34
|
+
{ key: "overdue", label: t("customers.tasks.filters.overdue", "Overdue"), count: overdueTasks.length }
|
|
35
|
+
];
|
|
36
|
+
return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-card p-5", children: [
|
|
37
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
38
|
+
/* @__PURE__ */ jsxs("h3", { className: "flex items-center gap-2 text-sm font-semibold text-foreground", children: [
|
|
39
|
+
/* @__PURE__ */ jsx(CheckCircle2, { className: "size-4" }),
|
|
40
|
+
t("customers.companies.dashboard.openTasks", "Open tasks"),
|
|
41
|
+
/* @__PURE__ */ jsx("span", { className: "rounded-full bg-muted px-1.5 py-0.5 text-xs font-medium text-muted-foreground", children: tasks.length })
|
|
42
|
+
] }),
|
|
43
|
+
/* @__PURE__ */ jsxs(Button, { type: "button", variant: "outline", size: "sm", className: "h-7 text-xs", onClick: onViewAll, children: [
|
|
44
|
+
"+ ",
|
|
45
|
+
t("customers.companies.dashboard.newTask", "New task")
|
|
46
|
+
] })
|
|
47
|
+
] }),
|
|
48
|
+
/* @__PURE__ */ jsx("div", { className: "mt-2 flex items-center gap-1", children: filterTabs.map((tab) => /* @__PURE__ */ jsxs(
|
|
49
|
+
Button,
|
|
50
|
+
{
|
|
51
|
+
type: "button",
|
|
52
|
+
variant: taskFilter === tab.key ? "default" : "outline",
|
|
53
|
+
size: "sm",
|
|
54
|
+
className: "h-6 px-2 text-xs",
|
|
55
|
+
onClick: () => setTaskFilter(tab.key),
|
|
56
|
+
children: [
|
|
57
|
+
tab.label,
|
|
58
|
+
/* @__PURE__ */ jsx("span", { className: "ml-1 rounded-full bg-muted/50 px-1 text-overline", children: tab.count })
|
|
59
|
+
]
|
|
60
|
+
},
|
|
61
|
+
tab.key
|
|
62
|
+
)) }),
|
|
63
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-3 divide-y", children: [
|
|
64
|
+
filteredTasks.slice(0, 4).map((task) => {
|
|
65
|
+
const overdue = isOverdue(task.dueAt);
|
|
66
|
+
const prio = priorityLabel(task.priority);
|
|
67
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 py-2.5 first:pt-0 last:pb-0", children: [
|
|
68
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
69
|
+
/* @__PURE__ */ jsx("p", { className: "truncate text-sm text-foreground", children: task.title || "\u2014" }),
|
|
70
|
+
task.dueAt && /* @__PURE__ */ jsxs("p", { className: cn("mt-0.5 text-xs", overdue ? "text-destructive" : "text-muted-foreground"), children: [
|
|
71
|
+
overdue && /* @__PURE__ */ jsx(AlertCircle, { className: "mr-1 inline size-3" }),
|
|
72
|
+
overdue ? t("customers.companies.dashboard.overdueBy", "Overdue by {{days}} days", { days: Math.ceil((Date.now() - new Date(task.dueAt).getTime()) / 864e5) }) : t("customers.companies.dashboard.dueOn", "Due: {{date}}", { date: new Date(task.dueAt).toLocaleDateString() })
|
|
73
|
+
] })
|
|
74
|
+
] }),
|
|
75
|
+
/* @__PURE__ */ jsx(Badge, { variant: prio.variant, className: "shrink-0 text-xs", children: prio.label }),
|
|
76
|
+
/* @__PURE__ */ jsx(ArrowUpRight, { className: "size-3.5 shrink-0 text-muted-foreground" })
|
|
77
|
+
] }, task.id);
|
|
78
|
+
}),
|
|
79
|
+
filteredTasks.length === 0 && /* @__PURE__ */ jsx("p", { className: "py-3 text-sm text-muted-foreground", children: t("customers.companies.dashboard.noTasks", "No open tasks") })
|
|
80
|
+
] })
|
|
81
|
+
] });
|
|
82
|
+
}
|
|
83
|
+
export {
|
|
84
|
+
OpenTasksWidget
|
|
85
|
+
};
|
|
86
|
+
//# sourceMappingURL=OpenTasksWidget.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../src/modules/customers/components/detail/dashboard/OpenTasksWidget.tsx"],
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { CheckCircle2, AlertCircle, ArrowUpRight } from 'lucide-react'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Badge } from '@open-mercato/ui/primitives/badge'\nimport type { TodoLinkSummary } from '../../formConfig'\n\nfunction isOverdue(dueAt: string | null | undefined): boolean {\n if (!dueAt) return false\n return new Date(dueAt) < new Date()\n}\n\nfunction priorityLabel(priority: number | null | undefined): { label: string; variant: 'destructive' | 'default' | 'secondary' | 'muted' } {\n if (priority === null || priority === undefined) return { label: 'None', variant: 'muted' }\n if (priority >= 3) return { label: 'High', variant: 'destructive' }\n if (priority === 2) return { label: 'Medium', variant: 'default' }\n return { label: 'Low', variant: 'secondary' }\n}\n\ntype TranslateFnWithParams = (key: string, fallback?: string, params?: Record<string, string | number>) => string\n\nexport function OpenTasksWidget({\n tasks,\n currentUserId,\n t,\n onViewAll,\n}: {\n tasks: TodoLinkSummary[]\n currentUserId?: string | null\n t: TranslateFnWithParams\n onViewAll: () => void\n}) {\n const [taskFilter, setTaskFilter] = React.useState<'all' | 'mine' | 'overdue'>('all')\n const overdueTasks = tasks.filter((task) => isOverdue(task.dueAt))\n const mineTasks = currentUserId\n ? tasks.filter((task) => {\n const assignee = (task as Record<string, unknown>).assignedToUserId ?? (task as Record<string, unknown>).createdByUserId\n return assignee === currentUserId\n })\n : tasks\n\n const filteredTasks = taskFilter === 'overdue'\n ? overdueTasks\n : taskFilter === 'mine'\n ? mineTasks\n : tasks\n\n const filterTabs: Array<{ key: 'all' | 'mine' | 'overdue'; label: string; count: number }> = [\n { key: 'all', label: t('customers.tasks.filters.all', 'All'), count: tasks.length },\n { key: 'mine', label: t('customers.tasks.filters.mine', 'Mine'), count: mineTasks.length },\n { key: 'overdue', label: t('customers.tasks.filters.overdue', 'Overdue'), count: overdueTasks.length },\n ]\n\n return (\n <div className=\"rounded-lg border bg-card p-5\">\n <div className=\"flex items-center justify-between\">\n <h3 className=\"flex items-center gap-2 text-sm font-semibold text-foreground\">\n <CheckCircle2 className=\"size-4\" />\n {t('customers.companies.dashboard.openTasks', 'Open tasks')}\n <span className=\"rounded-full bg-muted px-1.5 py-0.5 text-xs font-medium text-muted-foreground\">\n {tasks.length}\n </span>\n </h3>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" className=\"h-7 text-xs\" onClick={onViewAll}>\n + {t('customers.companies.dashboard.newTask', 'New task')}\n </Button>\n </div>\n <div className=\"mt-2 flex items-center gap-1\">\n {filterTabs.map((tab) => (\n <Button\n key={tab.key}\n type=\"button\"\n variant={taskFilter === tab.key ? 'default' : 'outline'}\n size=\"sm\"\n className=\"h-6 px-2 text-xs\"\n onClick={() => setTaskFilter(tab.key)}\n >\n {tab.label}\n <span className=\"ml-1 rounded-full bg-muted/50 px-1 text-overline\">{tab.count}</span>\n </Button>\n ))}\n </div>\n <div className=\"mt-3 divide-y\">\n {filteredTasks.slice(0, 4).map((task) => {\n const overdue = isOverdue(task.dueAt)\n const prio = priorityLabel(task.priority)\n return (\n <div key={task.id} className=\"flex items-center gap-3 py-2.5 first:pt-0 last:pb-0\">\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm text-foreground\">{task.title || '\u2014'}</p>\n {task.dueAt && (\n <p className={cn('mt-0.5 text-xs', overdue ? 'text-destructive' : 'text-muted-foreground')}>\n {overdue && <AlertCircle className=\"mr-1 inline size-3\" />}\n {overdue\n ? t('customers.companies.dashboard.overdueBy', 'Overdue by {{days}} days', { days: Math.ceil((Date.now() - new Date(task.dueAt).getTime()) / 86_400_000) })\n : t('customers.companies.dashboard.dueOn', 'Due: {{date}}', { date: new Date(task.dueAt).toLocaleDateString() })\n }\n </p>\n )}\n </div>\n <Badge variant={prio.variant} className=\"shrink-0 text-xs\">{prio.label}</Badge>\n <ArrowUpRight className=\"size-3.5 shrink-0 text-muted-foreground\" />\n </div>\n )\n })}\n {filteredTasks.length === 0 && (\n <p className=\"py-3 text-sm text-muted-foreground\">{t('customers.companies.dashboard.noTasks', 'No open tasks')}</p>\n )}\n </div>\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Phone, Mail, Users, StickyNote, Clock, ArrowUpRight, ChevronRight } from "lucide-react";
|
|
4
|
+
import { Button } from "@open-mercato/ui/primitives/button";
|
|
5
|
+
import { formatRelativeTime } from "@open-mercato/shared/lib/time";
|
|
6
|
+
function interactionIcon(type) {
|
|
7
|
+
switch (type) {
|
|
8
|
+
case "call":
|
|
9
|
+
return /* @__PURE__ */ jsx(Phone, { className: "size-4" });
|
|
10
|
+
case "email":
|
|
11
|
+
return /* @__PURE__ */ jsx(Mail, { className: "size-4" });
|
|
12
|
+
case "meeting":
|
|
13
|
+
return /* @__PURE__ */ jsx(Users, { className: "size-4" });
|
|
14
|
+
case "note":
|
|
15
|
+
return /* @__PURE__ */ jsx(StickyNote, { className: "size-4" });
|
|
16
|
+
default:
|
|
17
|
+
return /* @__PURE__ */ jsx(Clock, { className: "size-4" });
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function RecentActivityWidget({ interactions, t }) {
|
|
21
|
+
return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-card p-5", children: [
|
|
22
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center justify-between", children: /* @__PURE__ */ jsxs("h3", { className: "flex items-center gap-2 text-sm font-semibold text-foreground", children: [
|
|
23
|
+
/* @__PURE__ */ jsx(Clock, { className: "size-4" }),
|
|
24
|
+
t("customers.companies.dashboard.recentActivity", "Recent activity"),
|
|
25
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-normal text-muted-foreground", children: t("customers.companies.dashboard.last7days", "last 7 days") })
|
|
26
|
+
] }) }),
|
|
27
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-3 divide-y", children: [
|
|
28
|
+
interactions.map((interaction) => {
|
|
29
|
+
const date = interaction.occurredAt ?? interaction.scheduledAt;
|
|
30
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3 py-3 first:pt-0 last:pb-0", children: [
|
|
31
|
+
/* @__PURE__ */ jsx("div", { className: "mt-0.5 flex size-8 shrink-0 items-center justify-center rounded-full bg-muted text-muted-foreground", children: interactionIcon(interaction.interactionType) }),
|
|
32
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
33
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-foreground", children: interaction.title || interaction.interactionType }),
|
|
34
|
+
/* @__PURE__ */ jsx("p", { className: "mt-0.5 text-xs text-muted-foreground", children: interaction.authorName && /* @__PURE__ */ jsx("span", { children: interaction.authorName }) })
|
|
35
|
+
] }),
|
|
36
|
+
/* @__PURE__ */ jsxs("div", { className: "shrink-0 text-right", children: [
|
|
37
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: date ? formatRelativeTime(date) : "\u2014" }),
|
|
38
|
+
/* @__PURE__ */ jsx(ArrowUpRight, { className: "ml-auto mt-1 size-3.5 text-muted-foreground" })
|
|
39
|
+
] })
|
|
40
|
+
] }, interaction.id);
|
|
41
|
+
}),
|
|
42
|
+
interactions.length === 0 && /* @__PURE__ */ jsx("p", { className: "py-3 text-sm text-muted-foreground", children: t("customers.companies.dashboard.noActivity", "No recent activity") })
|
|
43
|
+
] }),
|
|
44
|
+
interactions.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-3 border-t pt-3", children: /* @__PURE__ */ jsxs(Button, { type: "button", variant: "link", size: "sm", className: "h-auto p-0 text-xs", children: [
|
|
45
|
+
t("customers.companies.dashboard.seeAllActivity", "See all {{count}} activities", { count: String(interactions.length) }),
|
|
46
|
+
/* @__PURE__ */ jsx(ChevronRight, { className: "ml-0.5 size-3" })
|
|
47
|
+
] }) })
|
|
48
|
+
] });
|
|
49
|
+
}
|
|
50
|
+
export {
|
|
51
|
+
RecentActivityWidget
|
|
52
|
+
};
|
|
53
|
+
//# sourceMappingURL=RecentActivityWidget.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../src/modules/customers/components/detail/dashboard/RecentActivityWidget.tsx"],
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Phone, Mail, Users, StickyNote, Clock, ArrowUpRight, ChevronRight } from 'lucide-react'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { formatRelativeTime } from '@open-mercato/shared/lib/time'\nimport type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport type { InteractionSummary } from '../../formConfig'\n\nfunction interactionIcon(type: string) {\n switch (type) {\n case 'call': return <Phone className=\"size-4\" />\n case 'email': return <Mail className=\"size-4\" />\n case 'meeting': return <Users className=\"size-4\" />\n case 'note': return <StickyNote className=\"size-4\" />\n default: return <Clock className=\"size-4\" />\n }\n}\n\nexport function RecentActivityWidget({ interactions, t }: { interactions: InteractionSummary[]; t: TranslateFn }) {\n return (\n <div className=\"rounded-lg border bg-card p-5\">\n <div className=\"flex items-center justify-between\">\n <h3 className=\"flex items-center gap-2 text-sm font-semibold text-foreground\">\n <Clock className=\"size-4\" />\n {t('customers.companies.dashboard.recentActivity', 'Recent activity')}\n <span className=\"text-xs font-normal text-muted-foreground\">\n {t('customers.companies.dashboard.last7days', 'last 7 days')}\n </span>\n </h3>\n </div>\n <div className=\"mt-3 divide-y\">\n {interactions.map((interaction) => {\n const date = interaction.occurredAt ?? interaction.scheduledAt\n return (\n <div key={interaction.id} className=\"flex items-start gap-3 py-3 first:pt-0 last:pb-0\">\n <div className=\"mt-0.5 flex size-8 shrink-0 items-center justify-center rounded-full bg-muted text-muted-foreground\">\n {interactionIcon(interaction.interactionType)}\n </div>\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-sm text-foreground\">{interaction.title || interaction.interactionType}</p>\n <p className=\"mt-0.5 text-xs text-muted-foreground\">\n {interaction.authorName && <span>{interaction.authorName}</span>}\n </p>\n </div>\n <div className=\"shrink-0 text-right\">\n <p className=\"text-xs text-muted-foreground\">\n {date ? formatRelativeTime(date) : '\u2014'}\n </p>\n <ArrowUpRight className=\"ml-auto mt-1 size-3.5 text-muted-foreground\" />\n </div>\n </div>\n )\n })}\n {interactions.length === 0 && (\n <p className=\"py-3 text-sm text-muted-foreground\">{t('customers.companies.dashboard.noActivity', 'No recent activity')}</p>\n )}\n </div>\n {interactions.length > 0 && (\n <div className=\"mt-3 border-t pt-3\">\n <Button type=\"button\" variant=\"link\" size=\"sm\" className=\"h-auto p-0 text-xs\">\n {t('customers.companies.dashboard.seeAllActivity', 'See all {{count}} activities', { count: String(interactions.length) })}\n <ChevronRight className=\"ml-0.5 size-3\" />\n </Button>\n </div>\n )}\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": ";AAWwB,cAYhB,YAZgB;AARxB,SAAS,OAAO,MAAM,OAAO,YAAY,OAAO,cAAc,oBAAoB;AAClF,SAAS,cAAc;AACvB,SAAS,0BAA0B;AAInC,SAAS,gBAAgB,MAAc;AACrC,UAAQ,MAAM;AAAA,IACZ,KAAK;AAAQ,aAAO,oBAAC,SAAM,WAAU,UAAS;AAAA,IAC9C,KAAK;AAAS,aAAO,oBAAC,QAAK,WAAU,UAAS;AAAA,IAC9C,KAAK;AAAW,aAAO,oBAAC,SAAM,WAAU,UAAS;AAAA,IACjD,KAAK;AAAQ,aAAO,oBAAC,cAAW,WAAU,UAAS;AAAA,IACnD;AAAS,aAAO,oBAAC,SAAM,WAAU,UAAS;AAAA,EAC5C;AACF;AAEO,SAAS,qBAAqB,EAAE,cAAc,EAAE,GAA2D;AAChH,SACE,qBAAC,SAAI,WAAU,iCACb;AAAA,wBAAC,SAAI,WAAU,qCACb,+BAAC,QAAG,WAAU,iEACZ;AAAA,0BAAC,SAAM,WAAU,UAAS;AAAA,MACzB,EAAE,gDAAgD,iBAAiB;AAAA,MACpE,oBAAC,UAAK,WAAU,6CACb,YAAE,2CAA2C,aAAa,GAC7D;AAAA,OACF,GACF;AAAA,IACA,qBAAC,SAAI,WAAU,iBACZ;AAAA,mBAAa,IAAI,CAAC,gBAAgB;AACjC,cAAM,OAAO,YAAY,cAAc,YAAY;AACnD,eACE,qBAAC,SAAyB,WAAU,oDAClC;AAAA,8BAAC,SAAI,WAAU,uGACZ,0BAAgB,YAAY,eAAe,GAC9C;AAAA,UACA,qBAAC,SAAI,WAAU,kBACb;AAAA,gCAAC,OAAE,WAAU,2BAA2B,sBAAY,SAAS,YAAY,iBAAgB;AAAA,YACzF,oBAAC,OAAE,WAAU,wCACV,sBAAY,cAAc,oBAAC,UAAM,sBAAY,YAAW,GAC3D;AAAA,aACF;AAAA,UACA,qBAAC,SAAI,WAAU,uBACb;AAAA,gCAAC,OAAE,WAAU,iCACV,iBAAO,mBAAmB,IAAI,IAAI,UACrC;AAAA,YACA,oBAAC,gBAAa,WAAU,+CAA8C;AAAA,aACxE;AAAA,aAfQ,YAAY,EAgBtB;AAAA,MAEJ,CAAC;AAAA,MACA,aAAa,WAAW,KACvB,oBAAC,OAAE,WAAU,sCAAsC,YAAE,4CAA4C,oBAAoB,GAAE;AAAA,OAE3H;AAAA,IACC,aAAa,SAAS,KACrB,oBAAC,SAAI,WAAU,sBACb,+BAAC,UAAO,MAAK,UAAS,SAAQ,QAAO,MAAK,MAAK,WAAU,sBACtD;AAAA,QAAE,gDAAgD,gCAAgC,EAAE,OAAO,OAAO,aAAa,MAAM,EAAE,CAAC;AAAA,MACzH,oBAAC,gBAAa,WAAU,iBAAgB;AAAA,OAC1C,GACF;AAAA,KAEJ;AAEJ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Heart } from "lucide-react";
|
|
4
|
+
import { cn } from "@open-mercato/shared/lib/utils";
|
|
5
|
+
import { Badge } from "@open-mercato/ui/primitives/badge";
|
|
6
|
+
import { HEALTH_BADGE_CLASSES, HEALTH_ICON_CLASSES } from "../healthScoreUtils.js";
|
|
7
|
+
function RelationshipHealthWidget({ health, t }) {
|
|
8
|
+
return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-card p-5", children: [
|
|
9
|
+
/* @__PURE__ */ jsxs("h3", { className: "flex items-center gap-2 text-sm font-semibold text-foreground", children: [
|
|
10
|
+
/* @__PURE__ */ jsx(Heart, { className: cn("size-4", HEALTH_ICON_CLASSES[health.variant]) }),
|
|
11
|
+
t("customers.companies.dashboard.relationshipHealth", "Relationship health")
|
|
12
|
+
] }),
|
|
13
|
+
/* @__PURE__ */ jsx("div", { className: "mt-4 flex items-center justify-center", children: /* @__PURE__ */ jsxs("div", { className: "text-center space-y-2", children: [
|
|
14
|
+
/* @__PURE__ */ jsxs("div", { className: "relative inline-flex items-center justify-center", children: [
|
|
15
|
+
/* @__PURE__ */ jsx("span", { className: cn("text-4xl font-bold", HEALTH_ICON_CLASSES[health.variant]), children: health.score }),
|
|
16
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm text-muted-foreground", children: "/100" })
|
|
17
|
+
] }),
|
|
18
|
+
/* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Badge, { className: cn("text-xs", HEALTH_BADGE_CLASSES[health.variant]), children: t(`customers.health.${health.label}`, health.label) }) }),
|
|
19
|
+
health.lastContactDays !== null && /* @__PURE__ */ jsxs("p", { className: "text-xs text-muted-foreground", children: [
|
|
20
|
+
t("customers.health.lastContact", "Last contact"),
|
|
21
|
+
": ",
|
|
22
|
+
health.lastContactDays === 0 ? t("customers.health.today", "today") : t("customers.health.daysAgo", "{{days}} days ago", { days: health.lastContactDays })
|
|
23
|
+
] })
|
|
24
|
+
] }) })
|
|
25
|
+
] });
|
|
26
|
+
}
|
|
27
|
+
export {
|
|
28
|
+
RelationshipHealthWidget
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=RelationshipHealthWidget.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../src/modules/customers/components/detail/dashboard/RelationshipHealthWidget.tsx"],
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Heart } from 'lucide-react'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { Badge } from '@open-mercato/ui/primitives/badge'\nimport { HEALTH_BADGE_CLASSES, HEALTH_ICON_CLASSES, type HealthScore } from '../healthScoreUtils'\n\ntype TranslateFnWithParams = (key: string, fallback?: string, params?: Record<string, string | number>) => string\n\nexport function RelationshipHealthWidget({ health, t }: { health: HealthScore; t: TranslateFnWithParams }) {\n return (\n <div className=\"rounded-lg border bg-card p-5\">\n <h3 className=\"flex items-center gap-2 text-sm font-semibold text-foreground\">\n <Heart className={cn('size-4', HEALTH_ICON_CLASSES[health.variant])} />\n {t('customers.companies.dashboard.relationshipHealth', 'Relationship health')}\n </h3>\n <div className=\"mt-4 flex items-center justify-center\">\n <div className=\"text-center space-y-2\">\n <div className=\"relative inline-flex items-center justify-center\">\n <span className={cn('text-4xl font-bold', HEALTH_ICON_CLASSES[health.variant])}>{health.score}</span>\n <span className=\"text-sm text-muted-foreground\">/100</span>\n </div>\n <div>\n <Badge className={cn('text-xs', HEALTH_BADGE_CLASSES[health.variant])}>\n {t(`customers.health.${health.label}`, health.label)}\n </Badge>\n </div>\n {health.lastContactDays !== null && (\n <p className=\"text-xs text-muted-foreground\">\n {t('customers.health.lastContact', 'Last contact')}: {health.lastContactDays === 0\n ? t('customers.health.today', 'today')\n : t('customers.health.daysAgo', '{{days}} days ago', { days: health.lastContactDays })}\n </p>\n )}\n </div>\n </div>\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": ";AAaM,SACE,KADF;AAVN,SAAS,aAAa;AACtB,SAAS,UAAU;AACnB,SAAS,aAAa;AACtB,SAAS,sBAAsB,2BAA6C;AAIrE,SAAS,yBAAyB,EAAE,QAAQ,EAAE,GAAsD;AACzG,SACE,qBAAC,SAAI,WAAU,iCACb;AAAA,yBAAC,QAAG,WAAU,iEACZ;AAAA,0BAAC,SAAM,WAAW,GAAG,UAAU,oBAAoB,OAAO,OAAO,CAAC,GAAG;AAAA,MACpE,EAAE,oDAAoD,qBAAqB;AAAA,OAC9E;AAAA,IACA,oBAAC,SAAI,WAAU,yCACb,+BAAC,SAAI,WAAU,yBACb;AAAA,2BAAC,SAAI,WAAU,oDACb;AAAA,4BAAC,UAAK,WAAW,GAAG,sBAAsB,oBAAoB,OAAO,OAAO,CAAC,GAAI,iBAAO,OAAM;AAAA,QAC9F,oBAAC,UAAK,WAAU,iCAAgC,kBAAI;AAAA,SACtD;AAAA,MACA,oBAAC,SACC,8BAAC,SAAM,WAAW,GAAG,WAAW,qBAAqB,OAAO,OAAO,CAAC,GACjE,YAAE,oBAAoB,OAAO,KAAK,IAAI,OAAO,KAAK,GACrD,GACF;AAAA,MACC,OAAO,oBAAoB,QAC1B,qBAAC,OAAE,WAAU,iCACV;AAAA,UAAE,gCAAgC,cAAc;AAAA,QAAE;AAAA,QAAG,OAAO,oBAAoB,IAC7E,EAAE,0BAA0B,OAAO,IACnC,EAAE,4BAA4B,qBAAqB,EAAE,MAAM,OAAO,gBAAgB,CAAC;AAAA,SACzF;AAAA,OAEJ,GACF;AAAA,KACF;AAEJ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Calendar, ChevronRight } from "lucide-react";
|
|
4
|
+
import { Button } from "@open-mercato/ui/primitives/button";
|
|
5
|
+
function UpcomingMeetingsWidget({ meetings, t }) {
|
|
6
|
+
if (meetings.length === 0) {
|
|
7
|
+
return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-card p-5", children: [
|
|
8
|
+
/* @__PURE__ */ jsxs("h3", { className: "flex items-center gap-2 text-sm font-semibold text-foreground", children: [
|
|
9
|
+
/* @__PURE__ */ jsx(Calendar, { className: "size-4" }),
|
|
10
|
+
t("customers.companies.dashboard.upcomingMeetings", "Upcoming meetings")
|
|
11
|
+
] }),
|
|
12
|
+
/* @__PURE__ */ jsx("p", { className: "mt-3 text-sm text-muted-foreground", children: t("customers.companies.dashboard.noMeetings", "No upcoming meetings") })
|
|
13
|
+
] });
|
|
14
|
+
}
|
|
15
|
+
return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border bg-card p-5", children: [
|
|
16
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
|
|
17
|
+
/* @__PURE__ */ jsxs("h3", { className: "flex items-center gap-2 text-sm font-semibold text-foreground", children: [
|
|
18
|
+
/* @__PURE__ */ jsx(Calendar, { className: "size-4" }),
|
|
19
|
+
t("customers.companies.dashboard.upcomingMeetings", "Upcoming meetings"),
|
|
20
|
+
/* @__PURE__ */ jsx("span", { className: "rounded-full bg-muted px-1.5 py-0.5 text-xs font-medium text-muted-foreground", children: meetings.length })
|
|
21
|
+
] }),
|
|
22
|
+
/* @__PURE__ */ jsxs(Button, { type: "button", variant: "link", size: "sm", className: "h-auto p-0 text-xs", children: [
|
|
23
|
+
t("customers.companies.dashboard.seeAll", "See all"),
|
|
24
|
+
/* @__PURE__ */ jsx(ChevronRight, { className: "ml-0.5 size-3" })
|
|
25
|
+
] })
|
|
26
|
+
] }),
|
|
27
|
+
/* @__PURE__ */ jsx("div", { className: "mt-3 divide-y", children: meetings.map((meeting) => {
|
|
28
|
+
const date = meeting.scheduledAt ? new Date(meeting.scheduledAt) : null;
|
|
29
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-4 py-3 first:pt-0 last:pb-0", children: [
|
|
30
|
+
/* @__PURE__ */ jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
31
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: date ? date.toLocaleDateString(void 0, { weekday: "short", month: "short", day: "numeric" }) : "\u2014" }) }),
|
|
32
|
+
/* @__PURE__ */ jsx("p", { className: "mt-0.5 truncate text-sm font-medium text-foreground", children: meeting.title || meeting.interactionType }),
|
|
33
|
+
meeting.authorName && /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground", children: meeting.authorName })
|
|
34
|
+
] }),
|
|
35
|
+
/* @__PURE__ */ jsx("div", { className: "flex shrink-0 items-center gap-2", children: /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", size: "sm", className: "h-7 text-xs", children: t("customers.companies.dashboard.details", "Details") }) })
|
|
36
|
+
] }, meeting.id);
|
|
37
|
+
}) })
|
|
38
|
+
] });
|
|
39
|
+
}
|
|
40
|
+
export {
|
|
41
|
+
UpcomingMeetingsWidget
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=UpcomingMeetingsWidget.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../src/modules/customers/components/detail/dashboard/UpcomingMeetingsWidget.tsx"],
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Calendar, ChevronRight } from 'lucide-react'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport type { TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport type { InteractionSummary } from '../../formConfig'\n\nexport function UpcomingMeetingsWidget({ meetings, t }: { meetings: InteractionSummary[]; t: TranslateFn }) {\n if (meetings.length === 0) {\n return (\n <div className=\"rounded-lg border bg-card p-5\">\n <h3 className=\"flex items-center gap-2 text-sm font-semibold text-foreground\">\n <Calendar className=\"size-4\" />\n {t('customers.companies.dashboard.upcomingMeetings', 'Upcoming meetings')}\n </h3>\n <p className=\"mt-3 text-sm text-muted-foreground\">{t('customers.companies.dashboard.noMeetings', 'No upcoming meetings')}</p>\n </div>\n )\n }\n\n return (\n <div className=\"rounded-lg border bg-card p-5\">\n <div className=\"flex items-center justify-between\">\n <h3 className=\"flex items-center gap-2 text-sm font-semibold text-foreground\">\n <Calendar className=\"size-4\" />\n {t('customers.companies.dashboard.upcomingMeetings', 'Upcoming meetings')}\n <span className=\"rounded-full bg-muted px-1.5 py-0.5 text-xs font-medium text-muted-foreground\">\n {meetings.length}\n </span>\n </h3>\n <Button type=\"button\" variant=\"link\" size=\"sm\" className=\"h-auto p-0 text-xs\">\n {t('customers.companies.dashboard.seeAll', 'See all')}\n <ChevronRight className=\"ml-0.5 size-3\" />\n </Button>\n </div>\n <div className=\"mt-3 divide-y\">\n {meetings.map((meeting) => {\n const date = meeting.scheduledAt ? new Date(meeting.scheduledAt) : null\n return (\n <div key={meeting.id} className=\"flex items-center justify-between gap-4 py-3 first:pt-0 last:pb-0\">\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center gap-2\">\n <span className=\"text-xs text-muted-foreground\">\n {date ? date.toLocaleDateString(undefined, { weekday: 'short', month: 'short', day: 'numeric' }) : '\u2014'}\n </span>\n </div>\n <p className=\"mt-0.5 truncate text-sm font-medium text-foreground\">{meeting.title || meeting.interactionType}</p>\n {meeting.authorName && (\n <p className=\"text-xs text-muted-foreground\">{meeting.authorName}</p>\n )}\n </div>\n <div className=\"flex shrink-0 items-center gap-2\">\n <Button type=\"button\" variant=\"outline\" size=\"sm\" className=\"h-7 text-xs\">\n {t('customers.companies.dashboard.details', 'Details')}\n </Button>\n </div>\n </div>\n )\n })}\n </div>\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": ";AAYQ,SACE,KADF;AATR,SAAS,UAAU,oBAAoB;AACvC,SAAS,cAAc;AAIhB,SAAS,uBAAuB,EAAE,UAAU,EAAE,GAAuD;AAC1G,MAAI,SAAS,WAAW,GAAG;AACzB,WACE,qBAAC,SAAI,WAAU,iCACb;AAAA,2BAAC,QAAG,WAAU,iEACZ;AAAA,4BAAC,YAAS,WAAU,UAAS;AAAA,QAC5B,EAAE,kDAAkD,mBAAmB;AAAA,SAC1E;AAAA,MACA,oBAAC,OAAE,WAAU,sCAAsC,YAAE,4CAA4C,sBAAsB,GAAE;AAAA,OAC3H;AAAA,EAEJ;AAEA,SACE,qBAAC,SAAI,WAAU,iCACb;AAAA,yBAAC,SAAI,WAAU,qCACb;AAAA,2BAAC,QAAG,WAAU,iEACZ;AAAA,4BAAC,YAAS,WAAU,UAAS;AAAA,QAC5B,EAAE,kDAAkD,mBAAmB;AAAA,QACxE,oBAAC,UAAK,WAAU,iFACb,mBAAS,QACZ;AAAA,SACF;AAAA,MACA,qBAAC,UAAO,MAAK,UAAS,SAAQ,QAAO,MAAK,MAAK,WAAU,sBACtD;AAAA,UAAE,wCAAwC,SAAS;AAAA,QACpD,oBAAC,gBAAa,WAAU,iBAAgB;AAAA,SAC1C;AAAA,OACF;AAAA,IACA,oBAAC,SAAI,WAAU,iBACZ,mBAAS,IAAI,CAAC,YAAY;AACzB,YAAM,OAAO,QAAQ,cAAc,IAAI,KAAK,QAAQ,WAAW,IAAI;AACnE,aACE,qBAAC,SAAqB,WAAU,qEAC9B;AAAA,6BAAC,SAAI,WAAU,kBACb;AAAA,8BAAC,SAAI,WAAU,2BACb,8BAAC,UAAK,WAAU,iCACb,iBAAO,KAAK,mBAAmB,QAAW,EAAE,SAAS,SAAS,OAAO,SAAS,KAAK,UAAU,CAAC,IAAI,UACrG,GACF;AAAA,UACA,oBAAC,OAAE,WAAU,uDAAuD,kBAAQ,SAAS,QAAQ,iBAAgB;AAAA,UAC5G,QAAQ,cACP,oBAAC,OAAE,WAAU,iCAAiC,kBAAQ,YAAW;AAAA,WAErE;AAAA,QACA,oBAAC,SAAI,WAAU,oCACb,8BAAC,UAAO,MAAK,UAAS,SAAQ,WAAU,MAAK,MAAK,WAAU,eACzD,YAAE,yCAAyC,SAAS,GACvD,GACF;AAAA,WAhBQ,QAAQ,EAiBlB;AAAA,IAEJ,CAAC,GACH;AAAA,KACF;AAEJ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
function sumActiveDeals(deals) {
|
|
2
|
+
return deals.filter((d) => d.status !== "won" && d.status !== "lost" && d.status !== "closed").reduce((sum, d) => {
|
|
3
|
+
const amount = typeof d.valueAmount === "number" ? d.valueAmount : parseFloat(String(d.valueAmount ?? "0"));
|
|
4
|
+
return sum + (Number.isFinite(amount) ? amount : 0);
|
|
5
|
+
}, 0);
|
|
6
|
+
}
|
|
7
|
+
function getActiveDeals(deals) {
|
|
8
|
+
return deals.filter((d) => d.status !== "won" && d.status !== "lost" && d.status !== "closed");
|
|
9
|
+
}
|
|
10
|
+
function getOpenTasks(todos) {
|
|
11
|
+
return todos.filter((t) => !t.isDone).sort((a, b) => {
|
|
12
|
+
if (!a.dueAt && !b.dueAt) return 0;
|
|
13
|
+
if (!a.dueAt) return 1;
|
|
14
|
+
if (!b.dueAt) return -1;
|
|
15
|
+
return new Date(a.dueAt).getTime() - new Date(b.dueAt).getTime();
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
function getUpcomingMeetings(interactions) {
|
|
19
|
+
const now = /* @__PURE__ */ new Date();
|
|
20
|
+
return interactions.filter((i) => i.scheduledAt && new Date(i.scheduledAt) > now).sort((a, b) => new Date(a.scheduledAt).getTime() - new Date(b.scheduledAt).getTime()).slice(0, 3);
|
|
21
|
+
}
|
|
22
|
+
function getRecentActivity(interactions) {
|
|
23
|
+
const weekAgo = /* @__PURE__ */ new Date();
|
|
24
|
+
weekAgo.setDate(weekAgo.getDate() - 7);
|
|
25
|
+
return interactions.filter((i) => {
|
|
26
|
+
const date = i.occurredAt ?? i.scheduledAt;
|
|
27
|
+
return date && new Date(date) >= weekAgo;
|
|
28
|
+
}).sort((a, b) => {
|
|
29
|
+
const da = a.occurredAt ?? a.scheduledAt ?? "";
|
|
30
|
+
const db = b.occurredAt ?? b.scheduledAt ?? "";
|
|
31
|
+
return new Date(db).getTime() - new Date(da).getTime();
|
|
32
|
+
}).slice(0, 4);
|
|
33
|
+
}
|
|
34
|
+
function computeActivityTrend(interactions) {
|
|
35
|
+
const now = Date.now();
|
|
36
|
+
const weekMs = 7 * 864e5;
|
|
37
|
+
const thisWeek = interactions.filter((i) => {
|
|
38
|
+
const d = i.occurredAt ?? i.scheduledAt;
|
|
39
|
+
return d && now - new Date(d).getTime() < weekMs;
|
|
40
|
+
}).length;
|
|
41
|
+
const lastWeek = interactions.filter((i) => {
|
|
42
|
+
const d = i.occurredAt ?? i.scheduledAt;
|
|
43
|
+
if (!d) return false;
|
|
44
|
+
const diff = now - new Date(d).getTime();
|
|
45
|
+
return diff >= weekMs && diff < weekMs * 2;
|
|
46
|
+
}).length;
|
|
47
|
+
if (lastWeek === 0 && thisWeek === 0) return void 0;
|
|
48
|
+
if (lastWeek === 0) return { value: 100, direction: "up" };
|
|
49
|
+
const pct = (thisWeek - lastWeek) / lastWeek * 100;
|
|
50
|
+
if (Math.abs(pct) < 0.5) return { value: 0, direction: "unchanged" };
|
|
51
|
+
return { value: Math.abs(pct), direction: pct > 0 ? "up" : "down" };
|
|
52
|
+
}
|
|
53
|
+
function computeDealTrend(deals) {
|
|
54
|
+
const active = deals.filter((d) => d.status !== "won" && d.status !== "lost" && d.status !== "closed");
|
|
55
|
+
if (active.length === 0) return void 0;
|
|
56
|
+
const now = Date.now();
|
|
57
|
+
const monthMs = 30 * 864e5;
|
|
58
|
+
const recentDeals = active.filter((d) => d.createdAt && now - new Date(d.createdAt).getTime() < monthMs).length;
|
|
59
|
+
if (recentDeals > 0) return { value: recentDeals * 10, direction: "up" };
|
|
60
|
+
return { value: 0, direction: "unchanged" };
|
|
61
|
+
}
|
|
62
|
+
export {
|
|
63
|
+
computeActivityTrend,
|
|
64
|
+
computeDealTrend,
|
|
65
|
+
getActiveDeals,
|
|
66
|
+
getOpenTasks,
|
|
67
|
+
getRecentActivity,
|
|
68
|
+
getUpcomingMeetings,
|
|
69
|
+
sumActiveDeals
|
|
70
|
+
};
|
|
71
|
+
//# sourceMappingURL=helpers.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../src/modules/customers/components/detail/dashboard/helpers.ts"],
|
|
4
|
+
"sourcesContent": ["import type { KpiTrend } from '@open-mercato/ui/backend/charts/KpiCard'\nimport type { DealSummary, InteractionSummary, TodoLinkSummary } from '../../formConfig'\n\nexport function sumActiveDeals(deals: DealSummary[]): number {\n return deals\n .filter((d) => d.status !== 'won' && d.status !== 'lost' && d.status !== 'closed')\n .reduce((sum, d) => {\n const amount = typeof d.valueAmount === 'number' ? d.valueAmount : parseFloat(String(d.valueAmount ?? '0'))\n return sum + (Number.isFinite(amount) ? amount : 0)\n }, 0)\n}\n\nexport function getActiveDeals(deals: DealSummary[]): DealSummary[] {\n return deals.filter((d) => d.status !== 'won' && d.status !== 'lost' && d.status !== 'closed')\n}\n\nexport function getOpenTasks(todos: TodoLinkSummary[]): TodoLinkSummary[] {\n return todos.filter((t) => !t.isDone).sort((a, b) => {\n if (!a.dueAt && !b.dueAt) return 0\n if (!a.dueAt) return 1\n if (!b.dueAt) return -1\n return new Date(a.dueAt).getTime() - new Date(b.dueAt).getTime()\n })\n}\n\nexport function getUpcomingMeetings(interactions: InteractionSummary[]): InteractionSummary[] {\n const now = new Date()\n return interactions\n .filter((i) => i.scheduledAt && new Date(i.scheduledAt) > now)\n .sort((a, b) => new Date(a.scheduledAt!).getTime() - new Date(b.scheduledAt!).getTime())\n .slice(0, 3)\n}\n\nexport function getRecentActivity(interactions: InteractionSummary[]): InteractionSummary[] {\n const weekAgo = new Date()\n weekAgo.setDate(weekAgo.getDate() - 7)\n return interactions\n .filter((i) => {\n const date = i.occurredAt ?? i.scheduledAt\n return date && new Date(date) >= weekAgo\n })\n .sort((a, b) => {\n const da = a.occurredAt ?? a.scheduledAt ?? ''\n const db = b.occurredAt ?? b.scheduledAt ?? ''\n return new Date(db).getTime() - new Date(da).getTime()\n })\n .slice(0, 4)\n}\n\nexport function computeActivityTrend(interactions: InteractionSummary[]): KpiTrend | undefined {\n const now = Date.now()\n const weekMs = 7 * 86_400_000\n const thisWeek = interactions.filter((i) => {\n const d = i.occurredAt ?? i.scheduledAt\n return d && now - new Date(d).getTime() < weekMs\n }).length\n const lastWeek = interactions.filter((i) => {\n const d = i.occurredAt ?? i.scheduledAt\n if (!d) return false\n const diff = now - new Date(d).getTime()\n return diff >= weekMs && diff < weekMs * 2\n }).length\n if (lastWeek === 0 && thisWeek === 0) return undefined\n if (lastWeek === 0) return { value: 100, direction: 'up' }\n const pct = ((thisWeek - lastWeek) / lastWeek) * 100\n if (Math.abs(pct) < 0.5) return { value: 0, direction: 'unchanged' }\n return { value: Math.abs(pct), direction: pct > 0 ? 'up' : 'down' }\n}\n\nexport function computeDealTrend(deals: DealSummary[]): KpiTrend | undefined {\n const active = deals.filter((d) => d.status !== 'won' && d.status !== 'lost' && d.status !== 'closed')\n if (active.length === 0) return undefined\n const now = Date.now()\n const monthMs = 30 * 86_400_000\n const recentDeals = active.filter((d) => d.createdAt && now - new Date(d.createdAt).getTime() < monthMs).length\n if (recentDeals > 0) return { value: recentDeals * 10, direction: 'up' }\n return { value: 0, direction: 'unchanged' }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
function computeHealthScore(interactions) {
|
|
2
|
+
const now = Date.now();
|
|
3
|
+
const dayMs = 864e5;
|
|
4
|
+
const dates = interactions.map((i) => i.occurredAt ?? i.scheduledAt).filter(Boolean).map((d) => new Date(d).getTime());
|
|
5
|
+
const lastContactMs = dates.length > 0 ? Math.max(...dates) : 0;
|
|
6
|
+
const daysSinceContact = lastContactMs > 0 ? Math.floor((now - lastContactMs) / dayMs) : 999;
|
|
7
|
+
let recencyScore;
|
|
8
|
+
if (daysSinceContact <= 7) recencyScore = 100;
|
|
9
|
+
else if (daysSinceContact <= 30) recencyScore = 75;
|
|
10
|
+
else if (daysSinceContact <= 60) recencyScore = 50;
|
|
11
|
+
else if (daysSinceContact <= 90) recencyScore = 25;
|
|
12
|
+
else recencyScore = 0;
|
|
13
|
+
const last30 = interactions.filter((i) => {
|
|
14
|
+
const d = i.occurredAt ?? i.scheduledAt;
|
|
15
|
+
return d && now - new Date(d).getTime() < 30 * dayMs;
|
|
16
|
+
}).length;
|
|
17
|
+
let frequencyScore;
|
|
18
|
+
if (last30 >= 5) frequencyScore = 100;
|
|
19
|
+
else if (last30 >= 3) frequencyScore = 75;
|
|
20
|
+
else if (last30 >= 1) frequencyScore = 50;
|
|
21
|
+
else frequencyScore = 0;
|
|
22
|
+
const types = new Set(interactions.map((i) => i.interactionType));
|
|
23
|
+
let diversityScore;
|
|
24
|
+
if (types.size >= 4) diversityScore = 100;
|
|
25
|
+
else if (types.size >= 3) diversityScore = 75;
|
|
26
|
+
else if (types.size >= 2) diversityScore = 50;
|
|
27
|
+
else if (types.size >= 1) diversityScore = 25;
|
|
28
|
+
else diversityScore = 0;
|
|
29
|
+
const weekBuckets = new Set(
|
|
30
|
+
interactions.map((i) => i.occurredAt ?? i.scheduledAt).filter(Boolean).map((d) => Math.floor(new Date(d).getTime() / (7 * dayMs)))
|
|
31
|
+
);
|
|
32
|
+
let consistencyScore;
|
|
33
|
+
if (weekBuckets.size >= 8) consistencyScore = 100;
|
|
34
|
+
else if (weekBuckets.size >= 4) consistencyScore = 75;
|
|
35
|
+
else if (weekBuckets.size >= 2) consistencyScore = 50;
|
|
36
|
+
else consistencyScore = 25;
|
|
37
|
+
const score = Math.round(
|
|
38
|
+
recencyScore * 0.4 + frequencyScore * 0.3 + diversityScore * 0.15 + consistencyScore * 0.15
|
|
39
|
+
);
|
|
40
|
+
let label;
|
|
41
|
+
let variant;
|
|
42
|
+
if (score >= 70) {
|
|
43
|
+
label = "healthy";
|
|
44
|
+
variant = "success";
|
|
45
|
+
} else if (score >= 40) {
|
|
46
|
+
label = "watchful";
|
|
47
|
+
variant = "warning";
|
|
48
|
+
} else {
|
|
49
|
+
label = "at risk";
|
|
50
|
+
variant = "error";
|
|
51
|
+
}
|
|
52
|
+
return { score, label, variant, lastContactDays: daysSinceContact < 999 ? daysSinceContact : null };
|
|
53
|
+
}
|
|
54
|
+
const HEALTH_ICON_CLASSES = {
|
|
55
|
+
success: "text-status-success-icon",
|
|
56
|
+
warning: "text-status-warning-icon",
|
|
57
|
+
error: "text-status-error-icon"
|
|
58
|
+
};
|
|
59
|
+
const HEALTH_BADGE_CLASSES = {
|
|
60
|
+
success: "bg-status-success-bg text-status-success-text",
|
|
61
|
+
warning: "bg-status-warning-bg text-status-warning-text",
|
|
62
|
+
error: "bg-status-error-bg text-status-error-text"
|
|
63
|
+
};
|
|
64
|
+
export {
|
|
65
|
+
HEALTH_BADGE_CLASSES,
|
|
66
|
+
HEALTH_ICON_CLASSES,
|
|
67
|
+
computeHealthScore
|
|
68
|
+
};
|
|
69
|
+
//# sourceMappingURL=healthScoreUtils.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/modules/customers/components/detail/healthScoreUtils.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Shared health score computation for CRM relationship health widgets.\n */\nimport type { InteractionSummary } from '../formConfig'\n\nexport type HealthVariant = 'success' | 'warning' | 'error'\n\nexport type HealthScore = {\n score: number\n label: string\n variant: HealthVariant\n lastContactDays: number | null\n}\n\nexport function computeHealthScore(interactions: InteractionSummary[]): HealthScore {\n const now = Date.now()\n const dayMs = 86_400_000\n\n const dates = interactions\n .map((i) => i.occurredAt ?? i.scheduledAt)\n .filter(Boolean)\n .map((d) => new Date(d!).getTime())\n const lastContactMs = dates.length > 0 ? Math.max(...dates) : 0\n const daysSinceContact = lastContactMs > 0 ? Math.floor((now - lastContactMs) / dayMs) : 999\n\n let recencyScore: number\n if (daysSinceContact <= 7) recencyScore = 100\n else if (daysSinceContact <= 30) recencyScore = 75\n else if (daysSinceContact <= 60) recencyScore = 50\n else if (daysSinceContact <= 90) recencyScore = 25\n else recencyScore = 0\n\n const last30 = interactions.filter((i) => {\n const d = i.occurredAt ?? i.scheduledAt\n return d && now - new Date(d).getTime() < 30 * dayMs\n }).length\n\n let frequencyScore: number\n if (last30 >= 5) frequencyScore = 100\n else if (last30 >= 3) frequencyScore = 75\n else if (last30 >= 1) frequencyScore = 50\n else frequencyScore = 0\n\n const types = new Set(interactions.map((i) => i.interactionType))\n let diversityScore: number\n if (types.size >= 4) diversityScore = 100\n else if (types.size >= 3) diversityScore = 75\n else if (types.size >= 2) diversityScore = 50\n else if (types.size >= 1) diversityScore = 25\n else diversityScore = 0\n\n const weekBuckets = new Set(\n interactions\n .map((i) => i.occurredAt ?? i.scheduledAt)\n .filter(Boolean)\n .map((d) => Math.floor(new Date(d!).getTime() / (7 * dayMs))),\n )\n let consistencyScore: number\n if (weekBuckets.size >= 8) consistencyScore = 100\n else if (weekBuckets.size >= 4) consistencyScore = 75\n else if (weekBuckets.size >= 2) consistencyScore = 50\n else consistencyScore = 25\n\n const score = Math.round(\n recencyScore * 0.4 + frequencyScore * 0.3 + diversityScore * 0.15 + consistencyScore * 0.15,\n )\n\n let label: string\n let variant: HealthVariant\n if (score >= 70) { label = 'healthy'; variant = 'success' }\n else if (score >= 40) { label = 'watchful'; variant = 'warning' }\n else { label = 'at risk'; variant = 'error' }\n\n return { score, label, variant, lastContactDays: daysSinceContact < 999 ? daysSinceContact : null }\n}\n\n/**\n * Shared health variant \u2192 semantic status token mappings.\n * Used by RelationshipHealthCard and RelationshipHealthWidget.\n */\nexport const HEALTH_ICON_CLASSES: Record<HealthVariant, string> = {\n success: 'text-status-success-icon',\n warning: 'text-status-warning-icon',\n error: 'text-status-error-icon',\n}\n\nexport const HEALTH_BADGE_CLASSES: Record<HealthVariant, string> = {\n success: 'bg-status-success-bg text-status-success-text',\n warning: 'bg-status-warning-bg text-status-warning-text',\n error: 'bg-status-error-bg text-status-error-text',\n}\n"],
|
|
5
|
+
"mappings": "AAcO,SAAS,mBAAmB,cAAiD;AAClF,QAAM,MAAM,KAAK,IAAI;AACrB,QAAM,QAAQ;AAEd,QAAM,QAAQ,aACX,IAAI,CAAC,MAAM,EAAE,cAAc,EAAE,WAAW,EACxC,OAAO,OAAO,EACd,IAAI,CAAC,MAAM,IAAI,KAAK,CAAE,EAAE,QAAQ,CAAC;AACpC,QAAM,gBAAgB,MAAM,SAAS,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI;AAC9D,QAAM,mBAAmB,gBAAgB,IAAI,KAAK,OAAO,MAAM,iBAAiB,KAAK,IAAI;AAEzF,MAAI;AACJ,MAAI,oBAAoB,EAAG,gBAAe;AAAA,WACjC,oBAAoB,GAAI,gBAAe;AAAA,WACvC,oBAAoB,GAAI,gBAAe;AAAA,WACvC,oBAAoB,GAAI,gBAAe;AAAA,MAC3C,gBAAe;AAEpB,QAAM,SAAS,aAAa,OAAO,CAAC,MAAM;AACxC,UAAM,IAAI,EAAE,cAAc,EAAE;AAC5B,WAAO,KAAK,MAAM,IAAI,KAAK,CAAC,EAAE,QAAQ,IAAI,KAAK;AAAA,EACjD,CAAC,EAAE;AAEH,MAAI;AACJ,MAAI,UAAU,EAAG,kBAAiB;AAAA,WACzB,UAAU,EAAG,kBAAiB;AAAA,WAC9B,UAAU,EAAG,kBAAiB;AAAA,MAClC,kBAAiB;AAEtB,QAAM,QAAQ,IAAI,IAAI,aAAa,IAAI,CAAC,MAAM,EAAE,eAAe,CAAC;AAChE,MAAI;AACJ,MAAI,MAAM,QAAQ,EAAG,kBAAiB;AAAA,WAC7B,MAAM,QAAQ,EAAG,kBAAiB;AAAA,WAClC,MAAM,QAAQ,EAAG,kBAAiB;AAAA,WAClC,MAAM,QAAQ,EAAG,kBAAiB;AAAA,MACtC,kBAAiB;AAEtB,QAAM,cAAc,IAAI;AAAA,IACtB,aACG,IAAI,CAAC,MAAM,EAAE,cAAc,EAAE,WAAW,EACxC,OAAO,OAAO,EACd,IAAI,CAAC,MAAM,KAAK,MAAM,IAAI,KAAK,CAAE,EAAE,QAAQ,KAAK,IAAI,MAAM,CAAC;AAAA,EAChE;AACA,MAAI;AACJ,MAAI,YAAY,QAAQ,EAAG,oBAAmB;AAAA,WACrC,YAAY,QAAQ,EAAG,oBAAmB;AAAA,WAC1C,YAAY,QAAQ,EAAG,oBAAmB;AAAA,MAC9C,oBAAmB;AAExB,QAAM,QAAQ,KAAK;AAAA,IACjB,eAAe,MAAM,iBAAiB,MAAM,iBAAiB,OAAO,mBAAmB;AAAA,EACzF;AAEA,MAAI;AACJ,MAAI;AACJ,MAAI,SAAS,IAAI;AAAE,YAAQ;AAAW,cAAU;AAAA,EAAU,WACjD,SAAS,IAAI;AAAE,YAAQ;AAAY,cAAU;AAAA,EAAU,OAC3D;AAAE,YAAQ;AAAW,cAAU;AAAA,EAAQ;AAE5C,SAAO,EAAE,OAAO,OAAO,SAAS,iBAAiB,mBAAmB,MAAM,mBAAmB,KAAK;AACpG;AAMO,MAAM,sBAAqD;AAAA,EAChE,SAAS;AAAA,EACT,SAAS;AAAA,EACT,OAAO;AACT;AAEO,MAAM,uBAAsD;AAAA,EACjE,SAAS;AAAA,EACT,SAAS;AAAA,EACT,OAAO;AACT;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -18,12 +18,12 @@ async function fetchCurrencyDictionary() {
|
|
|
18
18
|
}
|
|
19
19
|
const entriesRaw = Array.isArray(payload?.entries) ? payload.entries : [];
|
|
20
20
|
const entries = entriesRaw.map((entry) => {
|
|
21
|
-
const value = typeof entry
|
|
22
|
-
const label = typeof entry
|
|
23
|
-
const entryId = typeof entry
|
|
21
|
+
const value = typeof entry.value === "string" ? entry.value.trim().toUpperCase() : "";
|
|
22
|
+
const label = typeof entry.label === "string" && entry.label.trim().length ? entry.label.trim() : value;
|
|
23
|
+
const entryId = typeof entry.id === "string" ? entry.id : value;
|
|
24
24
|
if (!value) return null;
|
|
25
|
-
const color = typeof entry
|
|
26
|
-
const icon = typeof entry
|
|
25
|
+
const color = typeof entry.color === "string" && entry.color.trim().length ? entry.color.trim() : null;
|
|
26
|
+
const icon = typeof entry.icon === "string" && entry.icon.trim().length ? entry.icon.trim() : null;
|
|
27
27
|
return { id: entryId, value, label, color, icon };
|
|
28
28
|
}).filter((entry) => entry !== null);
|
|
29
29
|
return { id, entries };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/modules/customers/components/detail/hooks/useCurrencyDictionary.ts"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { QueryClient } from '@tanstack/react-query'\nimport * as React from 'react'\n\nexport type CurrencyDictionaryEntry = {\n id: string\n value: string\n label: string\n color?: string | null\n icon?: string | null\n}\n\nexport type CurrencyDictionaryPayload = {\n id: string\n entries: CurrencyDictionaryEntry[]\n}\n\nconst QUERY_KEY = ['customers', 'dictionaries', 'currency'] as const\nconst STALE_TIME = 5 * 60 * 1000\n\nconst cache = new Map<string, { promise: Promise<CurrencyDictionaryPayload>; client: QueryClient }>()\nconst CACHE_KEY = JSON.stringify(QUERY_KEY)\n\nasync function fetchCurrencyDictionary(): Promise<CurrencyDictionaryPayload> {\n const payload = await readApiResultOrThrow<Record<string, unknown>>(\n '/api/customers/dictionaries/currency',\n undefined,\n { errorMessage: 'Failed to load currency dictionary.' },\n )\n const id = typeof payload?.id === 'string' ? payload.id : ''\n if (!id) {\n throw new Error('Currency dictionary is not configured yet.')\n }\n const entriesRaw = Array.isArray(payload?.entries) ? payload.entries : []\n const entries: CurrencyDictionaryEntry[] = entriesRaw\n .map((entry:
|
|
5
|
-
"mappings": ";AAEA,SAAS,4BAA4B;AACrC,SAAS,mBAAmB;AAC5B,YAAY,WAAW;AAevB,MAAM,YAAY,CAAC,aAAa,gBAAgB,UAAU;AAC1D,MAAM,aAAa,IAAI,KAAK;AAE5B,MAAM,QAAQ,oBAAI,IAAkF;AACpG,MAAM,YAAY,KAAK,UAAU,SAAS;AAE1C,eAAe,0BAA8D;AAC3E,QAAM,UAAU,MAAM;AAAA,IACpB;AAAA,IACA;AAAA,IACA,EAAE,cAAc,sCAAsC;AAAA,EACxD;AACA,QAAM,KAAK,OAAO,SAAS,OAAO,WAAW,QAAQ,KAAK;AAC1D,MAAI,CAAC,IAAI;AACP,UAAM,IAAI,MAAM,4CAA4C;AAAA,EAC9D;AACA,QAAM,aAAa,MAAM,QAAQ,SAAS,OAAO,IAAI,QAAQ,UAAU,CAAC;AACxE,QAAM,UAAqC,WACxC,IAAI,CAAC,
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { QueryClient } from '@tanstack/react-query'\nimport * as React from 'react'\n\nexport type CurrencyDictionaryEntry = {\n id: string\n value: string\n label: string\n color?: string | null\n icon?: string | null\n}\n\nexport type CurrencyDictionaryPayload = {\n id: string\n entries: CurrencyDictionaryEntry[]\n}\n\nconst QUERY_KEY = ['customers', 'dictionaries', 'currency'] as const\nconst STALE_TIME = 5 * 60 * 1000\n\nconst cache = new Map<string, { promise: Promise<CurrencyDictionaryPayload>; client: QueryClient }>()\nconst CACHE_KEY = JSON.stringify(QUERY_KEY)\n\nasync function fetchCurrencyDictionary(): Promise<CurrencyDictionaryPayload> {\n const payload = await readApiResultOrThrow<Record<string, unknown>>(\n '/api/customers/dictionaries/currency',\n undefined,\n { errorMessage: 'Failed to load currency dictionary.' },\n )\n const id = typeof payload?.id === 'string' ? payload.id : ''\n if (!id) {\n throw new Error('Currency dictionary is not configured yet.')\n }\n const entriesRaw = Array.isArray(payload?.entries) ? payload.entries : []\n const entries: CurrencyDictionaryEntry[] = entriesRaw\n .map((entry: Record<string, unknown>): CurrencyDictionaryEntry | null => {\n const value = typeof entry.value === 'string' ? entry.value.trim().toUpperCase() : ''\n const label =\n typeof entry.label === 'string' && entry.label.trim().length\n ? entry.label.trim()\n : value\n const entryId = typeof entry.id === 'string' ? entry.id : value\n if (!value) return null\n const color = typeof entry.color === 'string' && entry.color.trim().length ? entry.color.trim() : null\n const icon = typeof entry.icon === 'string' && entry.icon.trim().length ? entry.icon.trim() : null\n return { id: entryId, value, label, color, icon }\n })\n .filter((entry: CurrencyDictionaryEntry | null): entry is CurrencyDictionaryEntry => entry !== null)\n return { id, entries }\n}\n\nexport function useCurrencyDictionary() {\n const [, forceRender] = React.useReducer((c) => c + 1, 0)\n const entry = cache.get(CACHE_KEY)\n const result = entry?.client.getQueryState<CurrencyDictionaryPayload>(QUERY_KEY)\n\n React.useEffect(() => {\n if (entry?.client.getQueryData(QUERY_KEY)) {\n forceRender()\n return\n }\n const client = entry?.client ?? new QueryClient()\n const promise = entry?.promise ?? client.fetchQuery({ queryKey: QUERY_KEY, queryFn: fetchCurrencyDictionary, staleTime: STALE_TIME, gcTime: STALE_TIME })\n if (!entry) cache.set(CACHE_KEY, { promise, client })\n promise.finally(() => { forceRender() })\n }, [])\n\n const data = entry?.client.getQueryData<CurrencyDictionaryPayload>(QUERY_KEY) ?? null\n const isLoading = !data && !(result && result.status === 'error')\n const error = (result && result.status === 'error') ? result.error ?? null : null\n const refetch = React.useCallback(async () => {\n const current = cache.get(CACHE_KEY)\n const client = current?.client ?? new QueryClient()\n const promise = client.fetchQuery({ queryKey: QUERY_KEY, queryFn: fetchCurrencyDictionary, staleTime: STALE_TIME, gcTime: STALE_TIME })\n cache.set(CACHE_KEY, { promise, client })\n const payload = await promise\n forceRender()\n return payload\n }, [])\n return { data, error, isLoading, isError: Boolean(error), refetch }\n}\n\nexport async function ensureCurrencyDictionary(queryClient: QueryClient) {\n const key = JSON.stringify(QUERY_KEY)\n const existing = cache.get(key)\n if (existing) return existing.promise\n const promise = queryClient.fetchQuery({ queryKey: QUERY_KEY, queryFn: fetchCurrencyDictionary, staleTime: STALE_TIME, gcTime: STALE_TIME })\n cache.set(key, { promise, client: queryClient })\n return promise\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|