@open-mercato/core 0.6.6-develop.6542.1.fee3e68aa6 → 0.6.6-develop.6551.1.1511bfa890

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.
Files changed (162) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/dist/generated/entities/gateway_session_initialization/index.js +23 -0
  3. package/dist/generated/entities/gateway_session_initialization/index.js.map +7 -0
  4. package/dist/generated/entities.ids.generated.js +1 -0
  5. package/dist/generated/entities.ids.generated.js.map +2 -2
  6. package/dist/generated/entity-fields-registry.js +12 -0
  7. package/dist/generated/entity-fields-registry.js.map +2 -2
  8. package/dist/modules/api_keys/api/keys/route.js +7 -4
  9. package/dist/modules/api_keys/api/keys/route.js.map +2 -2
  10. package/dist/modules/attachments/components/AttachmentContentPreview.js +6 -35
  11. package/dist/modules/attachments/components/AttachmentContentPreview.js.map +2 -2
  12. package/dist/modules/audit_logs/backend/audit-logs/page.js +14 -24
  13. package/dist/modules/audit_logs/backend/audit-logs/page.js.map +2 -2
  14. package/dist/modules/auth/api/autologin.js +85 -0
  15. package/dist/modules/auth/api/autologin.js.map +7 -0
  16. package/dist/modules/auth/lib/autologin.js +19 -0
  17. package/dist/modules/auth/lib/autologin.js.map +7 -0
  18. package/dist/modules/customer_accounts/api/admin/roles/[id]/acl.js +1 -0
  19. package/dist/modules/customer_accounts/api/admin/roles/[id]/acl.js.map +2 -2
  20. package/dist/modules/customer_accounts/api/admin/roles/[id].js +17 -3
  21. package/dist/modules/customer_accounts/api/admin/roles/[id].js.map +2 -2
  22. package/dist/modules/customer_accounts/api/portal/users/[id]/roles.js +6 -1
  23. package/dist/modules/customer_accounts/api/portal/users/[id]/roles.js.map +2 -2
  24. package/dist/modules/customer_accounts/api/portal/users-invite.js +6 -1
  25. package/dist/modules/customer_accounts/api/portal/users-invite.js.map +2 -2
  26. package/dist/modules/customer_accounts/services/customerInvitationService.js +1 -0
  27. package/dist/modules/customer_accounts/services/customerInvitationService.js.map +2 -2
  28. package/dist/modules/customer_accounts/services/customerRbacService.js +6 -1
  29. package/dist/modules/customer_accounts/services/customerRbacService.js.map +2 -2
  30. package/dist/modules/customers/backend/customers/deals/pipeline/components/ViewTabsRow.js +2 -2
  31. package/dist/modules/customers/backend/customers/deals/pipeline/components/ViewTabsRow.js.map +2 -2
  32. package/dist/modules/customers/components/detail/CompanyDetailTabs.js +27 -37
  33. package/dist/modules/customers/components/detail/CompanyDetailTabs.js.map +2 -2
  34. package/dist/modules/customers/components/detail/DealDetailTabs.js +23 -35
  35. package/dist/modules/customers/components/detail/DealDetailTabs.js.map +2 -2
  36. package/dist/modules/customers/components/detail/DetailTabsLayout.js +6 -21
  37. package/dist/modules/customers/components/detail/DetailTabsLayout.js.map +2 -2
  38. package/dist/modules/customers/components/detail/MobilePersonDetail.js +26 -32
  39. package/dist/modules/customers/components/detail/MobilePersonDetail.js.map +2 -2
  40. package/dist/modules/customers/components/detail/PersonDetailTabs.js +29 -39
  41. package/dist/modules/customers/components/detail/PersonDetailTabs.js.map +2 -2
  42. package/dist/modules/dictionaries/commands/entries.js +7 -14
  43. package/dist/modules/dictionaries/commands/entries.js.map +2 -2
  44. package/dist/modules/dictionaries/commands/entry-operations.js +7 -16
  45. package/dist/modules/dictionaries/commands/entry-operations.js.map +2 -2
  46. package/dist/modules/dictionaries/commands/factory.js +9 -3
  47. package/dist/modules/dictionaries/commands/factory.js.map +2 -2
  48. package/dist/modules/feature_toggles/api/check/boolean/route.js +0 -14
  49. package/dist/modules/feature_toggles/api/check/boolean/route.js.map +2 -2
  50. package/dist/modules/feature_toggles/defaults.json +8 -0
  51. package/dist/modules/integrations/backend/integrations/[id]/page.js +9 -80
  52. package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
  53. package/dist/modules/payment_gateways/data/entities.js +45 -0
  54. package/dist/modules/payment_gateways/data/entities.js.map +2 -2
  55. package/dist/modules/payment_gateways/lib/gateway-service.js +173 -38
  56. package/dist/modules/payment_gateways/lib/gateway-service.js.map +3 -3
  57. package/dist/modules/payment_gateways/lib/session-idempotency.js +104 -0
  58. package/dist/modules/payment_gateways/lib/session-idempotency.js.map +7 -0
  59. package/dist/modules/payment_gateways/migrations/Migration20260709220938_payment_gateways.js +11 -0
  60. package/dist/modules/payment_gateways/migrations/Migration20260709220938_payment_gateways.js.map +7 -0
  61. package/dist/modules/planner/backend/planner/availability-rulesets/[id]/page.js +16 -14
  62. package/dist/modules/planner/backend/planner/availability-rulesets/[id]/page.js.map +2 -2
  63. package/dist/modules/planner/components/AvailabilityRulesEditor.js +18 -30
  64. package/dist/modules/planner/components/AvailabilityRulesEditor.js.map +2 -2
  65. package/dist/modules/resources/backend/resources/resources/[id]/page.js +24 -24
  66. package/dist/modules/resources/backend/resources/resources/[id]/page.js.map +2 -2
  67. package/dist/modules/sales/backend/sales/channels/create/page.js +6 -0
  68. package/dist/modules/sales/backend/sales/channels/create/page.js.map +2 -2
  69. package/dist/modules/sales/backend/sales/channels/create/page.meta.js +2 -0
  70. package/dist/modules/sales/backend/sales/channels/create/page.meta.js.map +2 -2
  71. package/dist/modules/sales/backend/sales/channels/offers/page.js +6 -0
  72. package/dist/modules/sales/backend/sales/channels/offers/page.js.map +2 -2
  73. package/dist/modules/sales/backend/sales/channels/offers/page.meta.js +2 -0
  74. package/dist/modules/sales/backend/sales/channels/offers/page.meta.js.map +2 -2
  75. package/dist/modules/sales/backend/sales/channels/page.js +6 -0
  76. package/dist/modules/sales/backend/sales/channels/page.js.map +2 -2
  77. package/dist/modules/sales/backend/sales/channels/page.meta.js +2 -0
  78. package/dist/modules/sales/backend/sales/channels/page.meta.js.map +2 -2
  79. package/dist/modules/sales/backend/sales/documents/[id]/page.js +6 -4
  80. package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
  81. package/dist/modules/sales/components/SalesChannelsDisabledNotice.js +15 -0
  82. package/dist/modules/sales/components/SalesChannelsDisabledNotice.js.map +7 -0
  83. package/dist/modules/sales/components/documents/SalesDocumentForm.js +7 -3
  84. package/dist/modules/sales/components/documents/SalesDocumentForm.js.map +2 -2
  85. package/dist/modules/sales/components/documents/SalesDocumentsTable.js +10 -8
  86. package/dist/modules/sales/components/documents/SalesDocumentsTable.js.map +2 -2
  87. package/dist/modules/sales/components/useSalesChannelsEnabled.js +44 -0
  88. package/dist/modules/sales/components/useSalesChannelsEnabled.js.map +7 -0
  89. package/dist/modules/sales/lib/salesChannelsToggle.js +18 -0
  90. package/dist/modules/sales/lib/salesChannelsToggle.js.map +7 -0
  91. package/dist/modules/sales/lib/salesChannelsToggleId.js +5 -0
  92. package/dist/modules/sales/lib/salesChannelsToggleId.js.map +7 -0
  93. package/dist/modules/staff/backend/staff/team-members/[id]/page.js +22 -25
  94. package/dist/modules/staff/backend/staff/team-members/[id]/page.js.map +2 -2
  95. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +12 -14
  96. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
  97. package/dist/modules/staff/lib/timesheets-projects-ui/SavedViewTabs.js +10 -29
  98. package/dist/modules/staff/lib/timesheets-projects-ui/SavedViewTabs.js.map +2 -2
  99. package/dist/modules/sync_excel/lib/adapters/customers.js +19 -20
  100. package/dist/modules/sync_excel/lib/adapters/customers.js.map +2 -2
  101. package/dist/modules/sync_excel/lib/parser.js +185 -0
  102. package/dist/modules/sync_excel/lib/parser.js.map +2 -2
  103. package/dist/modules/sync_excel/lib/upload-storage.js +20 -1
  104. package/dist/modules/sync_excel/lib/upload-storage.js.map +2 -2
  105. package/generated/entities/gateway_session_initialization/index.ts +10 -0
  106. package/generated/entities.ids.generated.ts +1 -0
  107. package/generated/entity-fields-registry.ts +12 -0
  108. package/package.json +7 -7
  109. package/src/modules/api_keys/api/keys/route.ts +9 -4
  110. package/src/modules/attachments/components/AttachmentContentPreview.tsx +9 -44
  111. package/src/modules/audit_logs/backend/audit-logs/page.tsx +12 -22
  112. package/src/modules/auth/api/autologin.ts +100 -0
  113. package/src/modules/auth/lib/autologin.ts +36 -0
  114. package/src/modules/customer_accounts/api/admin/roles/[id]/acl.ts +1 -0
  115. package/src/modules/customer_accounts/api/admin/roles/[id].ts +17 -3
  116. package/src/modules/customer_accounts/api/portal/users/[id]/roles.ts +6 -1
  117. package/src/modules/customer_accounts/api/portal/users-invite.ts +6 -1
  118. package/src/modules/customer_accounts/services/customerInvitationService.ts +1 -0
  119. package/src/modules/customer_accounts/services/customerRbacService.ts +9 -2
  120. package/src/modules/customers/backend/customers/deals/pipeline/components/ViewTabsRow.tsx +6 -2
  121. package/src/modules/customers/components/detail/CompanyDetailTabs.tsx +27 -49
  122. package/src/modules/customers/components/detail/DealDetailTabs.tsx +24 -49
  123. package/src/modules/customers/components/detail/DetailTabsLayout.tsx +13 -24
  124. package/src/modules/customers/components/detail/MobilePersonDetail.tsx +25 -31
  125. package/src/modules/customers/components/detail/PersonDetailTabs.tsx +29 -50
  126. package/src/modules/dictionaries/commands/entries.ts +7 -16
  127. package/src/modules/dictionaries/commands/entry-operations.ts +8 -18
  128. package/src/modules/dictionaries/commands/factory.ts +8 -2
  129. package/src/modules/feature_toggles/api/check/boolean/route.ts +0 -15
  130. package/src/modules/feature_toggles/defaults.json +8 -0
  131. package/src/modules/integrations/backend/integrations/[id]/page.tsx +16 -59
  132. package/src/modules/payment_gateways/data/entities.ts +39 -0
  133. package/src/modules/payment_gateways/lib/gateway-service.ts +211 -40
  134. package/src/modules/payment_gateways/lib/session-idempotency.ts +142 -0
  135. package/src/modules/payment_gateways/migrations/.snapshot-open-mercato.json +236 -0
  136. package/src/modules/payment_gateways/migrations/Migration20260709220938_payment_gateways.ts +10 -0
  137. package/src/modules/planner/backend/planner/availability-rulesets/[id]/page.tsx +14 -20
  138. package/src/modules/planner/components/AvailabilityRulesEditor.tsx +16 -34
  139. package/src/modules/resources/backend/resources/resources/[id]/page.tsx +27 -37
  140. package/src/modules/sales/backend/sales/channels/create/page.meta.ts +3 -0
  141. package/src/modules/sales/backend/sales/channels/create/page.tsx +7 -0
  142. package/src/modules/sales/backend/sales/channels/offers/page.meta.ts +3 -0
  143. package/src/modules/sales/backend/sales/channels/offers/page.tsx +7 -0
  144. package/src/modules/sales/backend/sales/channels/page.meta.ts +4 -0
  145. package/src/modules/sales/backend/sales/channels/page.tsx +7 -0
  146. package/src/modules/sales/backend/sales/documents/[id]/page.tsx +7 -5
  147. package/src/modules/sales/components/SalesChannelsDisabledNotice.tsx +21 -0
  148. package/src/modules/sales/components/documents/SalesDocumentForm.tsx +7 -3
  149. package/src/modules/sales/components/documents/SalesDocumentsTable.tsx +10 -8
  150. package/src/modules/sales/components/useSalesChannelsEnabled.ts +59 -0
  151. package/src/modules/sales/i18n/de.json +1 -0
  152. package/src/modules/sales/i18n/en.json +1 -0
  153. package/src/modules/sales/i18n/es.json +1 -0
  154. package/src/modules/sales/i18n/pl.json +1 -0
  155. package/src/modules/sales/lib/salesChannelsToggle.ts +26 -0
  156. package/src/modules/sales/lib/salesChannelsToggleId.ts +1 -0
  157. package/src/modules/staff/backend/staff/team-members/[id]/page.tsx +25 -34
  158. package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +11 -17
  159. package/src/modules/staff/lib/timesheets-projects-ui/SavedViewTabs.tsx +11 -28
  160. package/src/modules/sync_excel/lib/adapters/customers.ts +20 -22
  161. package/src/modules/sync_excel/lib/parser.ts +245 -0
  162. package/src/modules/sync_excel/lib/upload-storage.ts +23 -1
@@ -1,9 +1,9 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
- import { cn } from "@open-mercato/shared/lib/utils";
5
4
  import { useT } from "@open-mercato/shared/lib/i18n/context";
6
5
  import { Button } from "@open-mercato/ui/primitives/button";
6
+ import { Tabs, TabsList, TabsTrigger } from "@open-mercato/ui/primitives/tabs";
7
7
  import {
8
8
  Users,
9
9
  Handshake,
@@ -27,12 +27,9 @@ function resolveLegacyTab(tab) {
27
27
  if (LEGACY_TAB_MAP[tab]) return LEGACY_TAB_MAP[tab];
28
28
  return tab;
29
29
  }
30
- function NewBadge() {
31
- return /* @__PURE__ */ jsx("span", { className: "ml-1.5 rounded bg-foreground px-1.5 py-0.5 text-overline font-semibold leading-none text-background", children: "NEW" });
32
- }
33
- function CountBadge({ count }) {
34
- if (count <= 0) return null;
35
- return /* @__PURE__ */ jsx("span", { className: "ml-1.5 rounded-full bg-muted px-1.5 py-0.5 text-xs font-medium leading-none text-muted-foreground", children: count > 999 ? "999+" : count });
30
+ function formatTabCount(count) {
31
+ if (count <= 0) return void 0;
32
+ return count > 999 ? "999+" : count;
36
33
  }
37
34
  function CompanyDetailTabs({
38
35
  activeTab,
@@ -53,33 +50,33 @@ function CompanyDetailTabs({
53
50
  id: "people",
54
51
  label: t("customers.companies.detail.tabs.people", "People"),
55
52
  icon: /* @__PURE__ */ jsx(Users, { className: "size-4" }),
56
- badge: /* @__PURE__ */ jsx(CountBadge, { count: peopleCount })
53
+ count: formatTabCount(peopleCount)
57
54
  },
58
55
  ...canViewDeals ? [
59
56
  {
60
57
  id: "deals",
61
58
  label: t("customers.companies.detail.tabs.deals", "Deals"),
62
59
  icon: /* @__PURE__ */ jsx(Handshake, { className: "size-4" }),
63
- badge: /* @__PURE__ */ jsx(CountBadge, { count: dealsCount })
60
+ count: formatTabCount(dealsCount)
64
61
  }
65
62
  ] : [],
66
63
  {
67
64
  id: "activity-log",
68
65
  label: t("customers.companies.detail.tabs.activityLog", "Activity log"),
69
66
  icon: /* @__PURE__ */ jsx(Clock, { className: "size-4" }),
70
- badge: /* @__PURE__ */ jsx(CountBadge, { count: activitiesCount })
67
+ count: formatTabCount(activitiesCount)
71
68
  },
72
69
  {
73
70
  id: "changelog",
74
71
  label: t("customers.companies.detail.tabs.changelog", "Changelog"),
75
72
  icon: /* @__PURE__ */ jsx(History, { className: "size-4" }),
76
- badge: /* @__PURE__ */ jsx(NewBadge, {})
73
+ count: "NEW"
77
74
  },
78
75
  {
79
76
  id: "files",
80
77
  label: t("customers.companies.detail.tabs.files", "Files"),
81
78
  icon: /* @__PURE__ */ jsx(Paperclip, { className: "size-4" }),
82
- badge: /* @__PURE__ */ jsx(CountBadge, { count: filesCount })
79
+ count: formatTabCount(filesCount)
83
80
  }
84
81
  ],
85
82
  [t, canViewDeals, peopleCount, dealsCount, activitiesCount, filesCount]
@@ -95,31 +92,24 @@ function CompanyDetailTabs({
95
92
  [builtInTabs, injectedTabs]
96
93
  );
97
94
  return /* @__PURE__ */ jsxs("div", { children: [
98
- /* @__PURE__ */ jsxs("div", { className: "flex items-end justify-between gap-2 border-b", role: "tablist", "aria-label": t("customers.companies.detail.tabs.label", "Company detail sections"), children: [
99
- /* @__PURE__ */ jsx("nav", { className: "-mb-px flex flex-1 gap-1 overflow-x-auto px-1", children: allTabs.map((tab) => {
100
- const isActive = activeTab === tab.id;
101
- return /* @__PURE__ */ jsxs(
102
- Button,
103
- {
104
- type: "button",
105
- variant: "ghost",
106
- size: "sm",
107
- role: "tab",
108
- "aria-selected": isActive,
109
- onClick: () => onTabChange(tab.id),
110
- className: cn(
111
- "h-auto shrink-0 rounded-none border-b-2 px-3 py-2.5 hover:bg-transparent",
112
- isActive ? "border-foreground text-foreground font-semibold" : "border-transparent text-muted-foreground hover:text-foreground"
113
- ),
114
- children: [
115
- tab.icon && /* @__PURE__ */ jsx("span", { className: "mr-1.5", children: tab.icon }),
116
- tab.label,
117
- tab.badge
118
- ]
119
- },
120
- tab.id
121
- );
122
- }) }),
95
+ /* @__PURE__ */ jsxs("div", { className: "flex items-end justify-between gap-2 border-b", children: [
96
+ /* @__PURE__ */ jsx(
97
+ Tabs,
98
+ {
99
+ value: activeTab,
100
+ onValueChange: (value) => onTabChange(value),
101
+ variant: "underline",
102
+ className: "min-w-0 flex-1",
103
+ children: /* @__PURE__ */ jsx(
104
+ TabsList,
105
+ {
106
+ "aria-label": t("customers.companies.detail.tabs.label", "Company detail sections"),
107
+ className: "-mb-px w-full overflow-x-auto border-b-0 px-1",
108
+ children: allTabs.map((tab) => /* @__PURE__ */ jsx(TabsTrigger, { value: tab.id, leading: tab.icon, count: tab.count, children: tab.label }, tab.id))
109
+ }
110
+ )
111
+ }
112
+ ),
123
113
  sectionAction ? /* @__PURE__ */ jsxs(
124
114
  Button,
125
115
  {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/customers/components/detail/CompanyDetailTabs.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Badge } from '@open-mercato/ui/primitives/badge'\nimport {\n Users,\n Handshake,\n Clock,\n History,\n Paperclip,\n Plus,\n} from 'lucide-react'\nimport type { SectionAction } from '@open-mercato/ui/backend/detail'\nimport { useDealsAccess } from './useDealsAccess'\n\nexport type CompanyTabId =\n | 'people'\n | 'deals'\n | 'activity-log'\n | 'changelog'\n | 'files'\n | string\n\ntype TabDef = {\n id: CompanyTabId\n label: string\n icon?: React.ReactNode\n badge?: React.ReactNode\n}\n\ntype CompanyDetailTabsProps = {\n activeTab: CompanyTabId\n onTabChange: (tab: CompanyTabId) => void\n injectedTabs?: Array<{ id: string; label: string; priority?: number }>\n peopleCount?: number\n dealsCount?: number\n activitiesCount?: number\n filesCount?: number\n sectionAction?: SectionAction | null\n children: React.ReactNode\n}\n\nconst LEGACY_TAB_MAP: Record<string, CompanyTabId> = {\n notes: 'people',\n activities: 'activity-log',\n addresses: 'people',\n tasks: 'people',\n dashboard: 'people',\n 'dane-firmy': 'people',\n analysis: 'people',\n}\n\nexport function resolveLegacyTab(tab: string | null | undefined): CompanyTabId {\n if (!tab) return 'people'\n if (LEGACY_TAB_MAP[tab]) return LEGACY_TAB_MAP[tab]\n return tab as CompanyTabId\n}\n\nfunction NewBadge() {\n return (\n <span className=\"ml-1.5 rounded bg-foreground px-1.5 py-0.5 text-overline font-semibold leading-none text-background\">\n NEW\n </span>\n )\n}\n\nfunction CountBadge({ count }: { count: number }) {\n if (count <= 0) return null\n return (\n <span className=\"ml-1.5 rounded-full bg-muted px-1.5 py-0.5 text-xs font-medium leading-none text-muted-foreground\">\n {count > 999 ? '999+' : count}\n </span>\n )\n}\n\nexport function CompanyDetailTabs({\n activeTab,\n onTabChange,\n injectedTabs = [],\n peopleCount = 0,\n dealsCount = 0,\n activitiesCount = 0,\n filesCount = 0,\n sectionAction = null,\n children,\n}: CompanyDetailTabsProps) {\n const t = useT()\n const { canViewDeals } = useDealsAccess()\n\n const builtInTabs: TabDef[] = React.useMemo(\n () => [\n {\n id: 'people',\n label: t('customers.companies.detail.tabs.people', 'People'),\n icon: <Users className=\"size-4\" />,\n badge: <CountBadge count={peopleCount} />,\n },\n ...(canViewDeals\n ? [\n {\n id: 'deals' as CompanyTabId,\n label: t('customers.companies.detail.tabs.deals', 'Deals'),\n icon: <Handshake className=\"size-4\" />,\n badge: <CountBadge count={dealsCount} />,\n },\n ]\n : []),\n {\n id: 'activity-log',\n label: t('customers.companies.detail.tabs.activityLog', 'Activity log'),\n icon: <Clock className=\"size-4\" />,\n badge: <CountBadge count={activitiesCount} />,\n },\n {\n id: 'changelog',\n label: t('customers.companies.detail.tabs.changelog', 'Changelog'),\n icon: <History className=\"size-4\" />,\n badge: <NewBadge />,\n },\n {\n id: 'files',\n label: t('customers.companies.detail.tabs.files', 'Files'),\n icon: <Paperclip className=\"size-4\" />,\n badge: <CountBadge count={filesCount} />,\n },\n ],\n [t, canViewDeals, peopleCount, dealsCount, activitiesCount, filesCount],\n )\n\n const allTabs: TabDef[] = React.useMemo(\n () => [\n ...builtInTabs,\n ...injectedTabs.map((tab) => ({\n id: tab.id as CompanyTabId,\n label: tab.label,\n })),\n ],\n [builtInTabs, injectedTabs],\n )\n\n return (\n <div>\n {/* Tab navigation */}\n <div className=\"flex items-end justify-between gap-2 border-b\" role=\"tablist\" aria-label={t('customers.companies.detail.tabs.label', 'Company detail sections')}>\n <nav className=\"-mb-px flex flex-1 gap-1 overflow-x-auto px-1\">\n {allTabs.map((tab) => {\n const isActive = activeTab === tab.id\n return (\n <Button\n key={tab.id}\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n role=\"tab\"\n aria-selected={isActive}\n onClick={() => onTabChange(tab.id)}\n className={cn(\n 'h-auto shrink-0 rounded-none border-b-2 px-3 py-2.5 hover:bg-transparent',\n isActive\n ? 'border-foreground text-foreground font-semibold'\n : 'border-transparent text-muted-foreground hover:text-foreground',\n )}\n >\n {tab.icon && <span className=\"mr-1.5\">{tab.icon}</span>}\n {tab.label}\n {tab.badge}\n </Button>\n )\n })}\n </nav>\n {sectionAction ? (\n <Button\n type=\"button\"\n size=\"sm\"\n onClick={sectionAction.onClick}\n disabled={sectionAction.disabled}\n className=\"mb-1.5 mr-1 shrink-0\"\n >\n <Plus className=\"mr-1.5 h-4 w-4\" />\n {sectionAction.label}\n </Button>\n ) : null}\n </div>\n\n {/* Tab content */}\n <div className=\"pt-6\" role=\"tabpanel\">\n {children}\n </div>\n </div>\n )\n}\n"],
5
- "mappings": ";AA+DI,cAwFU,YAxFV;AA7DJ,YAAY,WAAW;AACvB,SAAS,UAAU;AACnB,SAAS,YAAY;AACrB,SAAS,cAAc;AAEvB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,SAAS,sBAAsB;AA6B/B,MAAM,iBAA+C;AAAA,EACnD,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,OAAO;AAAA,EACP,WAAW;AAAA,EACX,cAAc;AAAA,EACd,UAAU;AACZ;AAEO,SAAS,iBAAiB,KAA8C;AAC7E,MAAI,CAAC,IAAK,QAAO;AACjB,MAAI,eAAe,GAAG,EAAG,QAAO,eAAe,GAAG;AAClD,SAAO;AACT;AAEA,SAAS,WAAW;AAClB,SACE,oBAAC,UAAK,WAAU,uGAAsG,iBAEtH;AAEJ;AAEA,SAAS,WAAW,EAAE,MAAM,GAAsB;AAChD,MAAI,SAAS,EAAG,QAAO;AACvB,SACE,oBAAC,UAAK,WAAU,qGACb,kBAAQ,MAAM,SAAS,OAC1B;AAEJ;AAEO,SAAS,kBAAkB;AAAA,EAChC;AAAA,EACA;AAAA,EACA,eAAe,CAAC;AAAA,EAChB,cAAc;AAAA,EACd,aAAa;AAAA,EACb,kBAAkB;AAAA,EAClB,aAAa;AAAA,EACb,gBAAgB;AAAA,EAChB;AACF,GAA2B;AACzB,QAAM,IAAI,KAAK;AACf,QAAM,EAAE,aAAa,IAAI,eAAe;AAExC,QAAM,cAAwB,MAAM;AAAA,IAClC,MAAM;AAAA,MACJ;AAAA,QACE,IAAI;AAAA,QACJ,OAAO,EAAE,0CAA0C,QAAQ;AAAA,QAC3D,MAAM,oBAAC,SAAM,WAAU,UAAS;AAAA,QAChC,OAAO,oBAAC,cAAW,OAAO,aAAa;AAAA,MACzC;AAAA,MACA,GAAI,eACA;AAAA,QACE;AAAA,UACE,IAAI;AAAA,UACJ,OAAO,EAAE,yCAAyC,OAAO;AAAA,UACzD,MAAM,oBAAC,aAAU,WAAU,UAAS;AAAA,UACpC,OAAO,oBAAC,cAAW,OAAO,YAAY;AAAA,QACxC;AAAA,MACF,IACA,CAAC;AAAA,MACL;AAAA,QACE,IAAI;AAAA,QACJ,OAAO,EAAE,+CAA+C,cAAc;AAAA,QACtE,MAAM,oBAAC,SAAM,WAAU,UAAS;AAAA,QAChC,OAAO,oBAAC,cAAW,OAAO,iBAAiB;AAAA,MAC7C;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ,OAAO,EAAE,6CAA6C,WAAW;AAAA,QACjE,MAAM,oBAAC,WAAQ,WAAU,UAAS;AAAA,QAClC,OAAO,oBAAC,YAAS;AAAA,MACnB;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ,OAAO,EAAE,yCAAyC,OAAO;AAAA,QACzD,MAAM,oBAAC,aAAU,WAAU,UAAS;AAAA,QACpC,OAAO,oBAAC,cAAW,OAAO,YAAY;AAAA,MACxC;AAAA,IACF;AAAA,IACA,CAAC,GAAG,cAAc,aAAa,YAAY,iBAAiB,UAAU;AAAA,EACxE;AAEA,QAAM,UAAoB,MAAM;AAAA,IAC9B,MAAM;AAAA,MACJ,GAAG;AAAA,MACH,GAAG,aAAa,IAAI,CAAC,SAAS;AAAA,QAC5B,IAAI,IAAI;AAAA,QACR,OAAO,IAAI;AAAA,MACb,EAAE;AAAA,IACJ;AAAA,IACA,CAAC,aAAa,YAAY;AAAA,EAC5B;AAEA,SACE,qBAAC,SAEC;AAAA,yBAAC,SAAI,WAAU,iDAAgD,MAAK,WAAU,cAAY,EAAE,yCAAyC,yBAAyB,GAC5J;AAAA,0BAAC,SAAI,WAAU,iDACZ,kBAAQ,IAAI,CAAC,QAAQ;AACpB,cAAM,WAAW,cAAc,IAAI;AACnC,eACE;AAAA,UAAC;AAAA;AAAA,YAEC,MAAK;AAAA,YACL,SAAQ;AAAA,YACR,MAAK;AAAA,YACL,MAAK;AAAA,YACL,iBAAe;AAAA,YACf,SAAS,MAAM,YAAY,IAAI,EAAE;AAAA,YACjC,WAAW;AAAA,cACT;AAAA,cACA,WACI,oDACA;AAAA,YACN;AAAA,YAEC;AAAA,kBAAI,QAAQ,oBAAC,UAAK,WAAU,UAAU,cAAI,MAAK;AAAA,cAC/C,IAAI;AAAA,cACJ,IAAI;AAAA;AAAA;AAAA,UAhBA,IAAI;AAAA,QAiBX;AAAA,MAEJ,CAAC,GACH;AAAA,MACC,gBACC;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,MAAK;AAAA,UACL,SAAS,cAAc;AAAA,UACvB,UAAU,cAAc;AAAA,UACxB,WAAU;AAAA,UAEV;AAAA,gCAAC,QAAK,WAAU,kBAAiB;AAAA,YAChC,cAAc;AAAA;AAAA;AAAA,MACjB,IACE;AAAA,OACN;AAAA,IAGA,oBAAC,SAAI,WAAU,QAAO,MAAK,YACxB,UACH;AAAA,KACF;AAEJ;",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Tabs, TabsList, TabsTrigger } from '@open-mercato/ui/primitives/tabs'\nimport {\n Users,\n Handshake,\n Clock,\n History,\n Paperclip,\n Plus,\n} from 'lucide-react'\nimport type { SectionAction } from '@open-mercato/ui/backend/detail'\nimport { useDealsAccess } from './useDealsAccess'\n\nexport type CompanyTabId =\n | 'people'\n | 'deals'\n | 'activity-log'\n | 'changelog'\n | 'files'\n | string\n\ntype TabDef = {\n id: CompanyTabId\n label: string\n icon?: React.ReactNode\n count?: React.ReactNode\n}\n\ntype CompanyDetailTabsProps = {\n activeTab: CompanyTabId\n onTabChange: (tab: CompanyTabId) => void\n injectedTabs?: Array<{ id: string; label: string; priority?: number }>\n peopleCount?: number\n dealsCount?: number\n activitiesCount?: number\n filesCount?: number\n sectionAction?: SectionAction | null\n children: React.ReactNode\n}\n\nconst LEGACY_TAB_MAP: Record<string, CompanyTabId> = {\n notes: 'people',\n activities: 'activity-log',\n addresses: 'people',\n tasks: 'people',\n dashboard: 'people',\n 'dane-firmy': 'people',\n analysis: 'people',\n}\n\nexport function resolveLegacyTab(tab: string | null | undefined): CompanyTabId {\n if (!tab) return 'people'\n if (LEGACY_TAB_MAP[tab]) return LEGACY_TAB_MAP[tab]\n return tab as CompanyTabId\n}\n\nfunction formatTabCount(count: number): string | number | undefined {\n if (count <= 0) return undefined\n return count > 999 ? '999+' : count\n}\n\nexport function CompanyDetailTabs({\n activeTab,\n onTabChange,\n injectedTabs = [],\n peopleCount = 0,\n dealsCount = 0,\n activitiesCount = 0,\n filesCount = 0,\n sectionAction = null,\n children,\n}: CompanyDetailTabsProps) {\n const t = useT()\n const { canViewDeals } = useDealsAccess()\n\n const builtInTabs: TabDef[] = React.useMemo(\n () => [\n {\n id: 'people',\n label: t('customers.companies.detail.tabs.people', 'People'),\n icon: <Users className=\"size-4\" />,\n count: formatTabCount(peopleCount),\n },\n ...(canViewDeals\n ? [\n {\n id: 'deals' as CompanyTabId,\n label: t('customers.companies.detail.tabs.deals', 'Deals'),\n icon: <Handshake className=\"size-4\" />,\n count: formatTabCount(dealsCount),\n },\n ]\n : []),\n {\n id: 'activity-log',\n label: t('customers.companies.detail.tabs.activityLog', 'Activity log'),\n icon: <Clock className=\"size-4\" />,\n count: formatTabCount(activitiesCount),\n },\n {\n id: 'changelog',\n label: t('customers.companies.detail.tabs.changelog', 'Changelog'),\n icon: <History className=\"size-4\" />,\n count: 'NEW',\n },\n {\n id: 'files',\n label: t('customers.companies.detail.tabs.files', 'Files'),\n icon: <Paperclip className=\"size-4\" />,\n count: formatTabCount(filesCount),\n },\n ],\n [t, canViewDeals, peopleCount, dealsCount, activitiesCount, filesCount],\n )\n\n const allTabs: TabDef[] = React.useMemo(\n () => [\n ...builtInTabs,\n ...injectedTabs.map((tab) => ({\n id: tab.id as CompanyTabId,\n label: tab.label,\n })),\n ],\n [builtInTabs, injectedTabs],\n )\n\n return (\n <div>\n {/* Tab navigation */}\n <div className=\"flex items-end justify-between gap-2 border-b\">\n <Tabs\n value={activeTab}\n onValueChange={(value) => onTabChange(value as CompanyTabId)}\n variant=\"underline\"\n className=\"min-w-0 flex-1\"\n >\n <TabsList\n aria-label={t('customers.companies.detail.tabs.label', 'Company detail sections')}\n className=\"-mb-px w-full overflow-x-auto border-b-0 px-1\"\n >\n {allTabs.map((tab) => (\n <TabsTrigger key={tab.id} value={tab.id} leading={tab.icon} count={tab.count}>\n {tab.label}\n </TabsTrigger>\n ))}\n </TabsList>\n </Tabs>\n {sectionAction ? (\n <Button\n type=\"button\"\n size=\"sm\"\n onClick={sectionAction.onClick}\n disabled={sectionAction.disabled}\n className=\"mb-1.5 mr-1 shrink-0\"\n >\n <Plus className=\"mr-1.5 h-4 w-4\" />\n {sectionAction.label}\n </Button>\n ) : null}\n </div>\n\n {/* Tab content */}\n <div className=\"pt-6\" role=\"tabpanel\">\n {children}\n </div>\n </div>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -2,20 +2,16 @@
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import { Activity, Building2, History, NotebookPen, Paperclip, Users } from "lucide-react";
5
- import { cn } from "@open-mercato/shared/lib/utils";
6
5
  import { useT } from "@open-mercato/shared/lib/i18n/context";
7
- import { Button } from "@open-mercato/ui/primitives/button";
6
+ import { Tabs, TabsList, TabsTrigger } from "@open-mercato/ui/primitives/tabs";
8
7
  const SUPPORTED_TAB_IDS = /* @__PURE__ */ new Set(["activities", "people", "companies", "notes", "files", "changelog"]);
9
8
  function resolveLegacyTab(tab) {
10
9
  if (!tab) return "activities";
11
10
  return SUPPORTED_TAB_IDS.has(tab) ? tab : "activities";
12
11
  }
13
- function CountBadge({ count }) {
14
- if (count <= 0) return null;
15
- return /* @__PURE__ */ jsx("span", { className: "ml-1.5 rounded-sm bg-muted px-1.5 py-px text-xs font-semibold leading-none text-muted-foreground", children: count > 999 ? "999+" : count });
16
- }
17
- function NewBadge() {
18
- return /* @__PURE__ */ jsx("span", { className: "ml-1.5 rounded-sm bg-muted px-1.5 py-px text-xs font-semibold leading-none text-muted-foreground", children: "NEW" });
12
+ function formatTabCount(count) {
13
+ if (count <= 0) return void 0;
14
+ return count > 999 ? "999+" : count;
19
15
  }
20
16
  function DealDetailTabs({
21
17
  activeTab,
@@ -37,13 +33,13 @@ function DealDetailTabs({
37
33
  id: "people",
38
34
  label: t("customers.deals.detail.tabs.people", "People"),
39
35
  icon: /* @__PURE__ */ jsx(Users, { className: "size-4" }),
40
- badge: /* @__PURE__ */ jsx(CountBadge, { count: peopleCount })
36
+ count: formatTabCount(peopleCount)
41
37
  },
42
38
  {
43
39
  id: "companies",
44
40
  label: t("customers.deals.detail.tabs.companies", "Companies"),
45
41
  icon: /* @__PURE__ */ jsx(Building2, { className: "size-4" }),
46
- badge: /* @__PURE__ */ jsx(CountBadge, { count: companiesCount })
42
+ count: formatTabCount(companiesCount)
47
43
  },
48
44
  {
49
45
  id: "notes",
@@ -59,7 +55,7 @@ function DealDetailTabs({
59
55
  id: "changelog",
60
56
  label: t("customers.deals.detail.tabs.changelog", "Changelog"),
61
57
  icon: /* @__PURE__ */ jsx(History, { className: "size-4" }),
62
- badge: /* @__PURE__ */ jsx(NewBadge, {})
58
+ count: "NEW"
63
59
  }
64
60
  ],
65
61
  [companiesCount, peopleCount, t]
@@ -75,30 +71,22 @@ function DealDetailTabs({
75
71
  [builtInTabs, injectedTabs]
76
72
  );
77
73
  return /* @__PURE__ */ jsxs("div", { children: [
78
- /* @__PURE__ */ jsx("div", { className: "border-b border-border", role: "tablist", "aria-label": t("customers.deals.detail.tabs.label", "Deal detail sections"), children: /* @__PURE__ */ jsx("nav", { className: "-mb-px flex gap-7 overflow-x-auto", role: "presentation", children: allTabs.map((tab) => {
79
- const isActive = activeTab === tab.id;
80
- return /* @__PURE__ */ jsxs(
81
- Button,
82
- {
83
- type: "button",
84
- variant: "ghost",
85
- size: "sm",
86
- role: "tab",
87
- "aria-selected": isActive,
88
- onClick: () => onTabChange(tab.id),
89
- className: cn(
90
- "h-auto shrink-0 rounded-none border-b-2 px-3 py-2.5 hover:bg-transparent",
91
- isActive ? "border-foreground text-foreground font-semibold" : "border-transparent text-muted-foreground hover:text-foreground"
92
- ),
93
- children: [
94
- tab.icon ? /* @__PURE__ */ jsx("span", { className: "mr-1.5", children: tab.icon }) : null,
95
- tab.label,
96
- tab.badge
97
- ]
98
- },
99
- tab.id
100
- );
101
- }) }) }),
74
+ /* @__PURE__ */ jsx(
75
+ Tabs,
76
+ {
77
+ value: activeTab,
78
+ onValueChange: (value) => onTabChange(value),
79
+ variant: "underline",
80
+ children: /* @__PURE__ */ jsx(
81
+ TabsList,
82
+ {
83
+ "aria-label": t("customers.deals.detail.tabs.label", "Deal detail sections"),
84
+ className: "w-full overflow-x-auto",
85
+ children: allTabs.map((tab) => /* @__PURE__ */ jsx(TabsTrigger, { value: tab.id, leading: tab.icon, count: tab.count, children: tab.label }, tab.id))
86
+ }
87
+ )
88
+ }
89
+ ),
102
90
  /* @__PURE__ */ jsx("div", { className: "pt-5", role: "tabpanel", children })
103
91
  ] });
104
92
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/customers/components/detail/DealDetailTabs.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Activity, Building2, History, NotebookPen, Paperclip, Users } from 'lucide-react'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Button } from '@open-mercato/ui/primitives/button'\n\nexport type DealTabId =\n | 'activities'\n | 'people'\n | 'companies'\n | 'notes'\n | 'files'\n | 'changelog'\n | string\n\ntype TabDef = {\n id: DealTabId\n label: string\n icon?: React.ReactNode\n badge?: React.ReactNode\n}\n\ntype DealDetailTabsProps = {\n activeTab: DealTabId\n onTabChange: (tab: DealTabId) => void\n injectedTabs?: Array<{ id: string; label: string }>\n peopleCount?: number\n companiesCount?: number\n children: React.ReactNode\n}\n\nconst SUPPORTED_TAB_IDS = new Set<DealTabId>(['activities', 'people', 'companies', 'notes', 'files', 'changelog'])\n\nexport function resolveLegacyTab(tab: string | null | undefined): DealTabId {\n if (!tab) return 'activities'\n return SUPPORTED_TAB_IDS.has(tab as DealTabId) ? (tab as DealTabId) : 'activities'\n}\n\nfunction CountBadge({ count }: { count: number }) {\n if (count <= 0) return null\n return (\n <span className=\"ml-1.5 rounded-sm bg-muted px-1.5 py-px text-xs font-semibold leading-none text-muted-foreground\">\n {count > 999 ? '999+' : count}\n </span>\n )\n}\n\nfunction NewBadge() {\n return (\n <span className=\"ml-1.5 rounded-sm bg-muted px-1.5 py-px text-xs font-semibold leading-none text-muted-foreground\">\n NEW\n </span>\n )\n}\n\nexport function DealDetailTabs({\n activeTab,\n onTabChange,\n injectedTabs = [],\n peopleCount = 0,\n companiesCount = 0,\n children,\n}: DealDetailTabsProps) {\n const t = useT()\n\n const builtInTabs = React.useMemo<TabDef[]>(\n () => [\n {\n id: 'activities',\n label: t('customers.deals.detail.tabs.activities', 'Activities'),\n icon: <Activity className=\"size-4\" />,\n },\n {\n id: 'people',\n label: t('customers.deals.detail.tabs.people', 'People'),\n icon: <Users className=\"size-4\" />,\n badge: <CountBadge count={peopleCount} />,\n },\n {\n id: 'companies',\n label: t('customers.deals.detail.tabs.companies', 'Companies'),\n icon: <Building2 className=\"size-4\" />,\n badge: <CountBadge count={companiesCount} />,\n },\n {\n id: 'notes',\n label: t('customers.deals.detail.tabs.notes', 'Notes'),\n icon: <NotebookPen className=\"size-4\" />,\n },\n {\n id: 'files',\n label: t('customers.deals.detail.tabs.files', 'Files'),\n icon: <Paperclip className=\"size-4\" />,\n },\n {\n id: 'changelog',\n label: t('customers.deals.detail.tabs.changelog', 'Changelog'),\n icon: <History className=\"size-4\" />,\n badge: <NewBadge />,\n },\n ],\n [companiesCount, peopleCount, t],\n )\n\n const allTabs = React.useMemo<TabDef[]>(\n () => [\n ...builtInTabs,\n ...injectedTabs.map((tab) => ({\n id: tab.id as DealTabId,\n label: tab.label,\n })),\n ],\n [builtInTabs, injectedTabs],\n )\n\n return (\n <div>\n <div className=\"border-b border-border\" role=\"tablist\" aria-label={t('customers.deals.detail.tabs.label', 'Deal detail sections')}>\n <nav className=\"-mb-px flex gap-7 overflow-x-auto\" role=\"presentation\">\n {allTabs.map((tab) => {\n const isActive = activeTab === tab.id\n return (\n <Button\n key={tab.id}\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n role=\"tab\"\n aria-selected={isActive}\n onClick={() => onTabChange(tab.id)}\n className={cn(\n 'h-auto shrink-0 rounded-none border-b-2 px-3 py-2.5 hover:bg-transparent',\n isActive\n ? 'border-foreground text-foreground font-semibold'\n : 'border-transparent text-muted-foreground hover:text-foreground',\n )}\n >\n {tab.icon ? <span className=\"mr-1.5\">{tab.icon}</span> : null}\n {tab.label}\n {tab.badge}\n </Button>\n )\n })}\n </nav>\n </div>\n\n <div className=\"pt-5\" role=\"tabpanel\">\n {children}\n </div>\n </div>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { Activity, Building2, History, NotebookPen, Paperclip, Users } from 'lucide-react'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Tabs, TabsList, TabsTrigger } from '@open-mercato/ui/primitives/tabs'\n\nexport type DealTabId =\n | 'activities'\n | 'people'\n | 'companies'\n | 'notes'\n | 'files'\n | 'changelog'\n | string\n\ntype TabDef = {\n id: DealTabId\n label: string\n icon?: React.ReactNode\n count?: React.ReactNode\n}\n\ntype DealDetailTabsProps = {\n activeTab: DealTabId\n onTabChange: (tab: DealTabId) => void\n injectedTabs?: Array<{ id: string; label: string }>\n peopleCount?: number\n companiesCount?: number\n children: React.ReactNode\n}\n\nconst SUPPORTED_TAB_IDS = new Set<DealTabId>(['activities', 'people', 'companies', 'notes', 'files', 'changelog'])\n\nexport function resolveLegacyTab(tab: string | null | undefined): DealTabId {\n if (!tab) return 'activities'\n return SUPPORTED_TAB_IDS.has(tab as DealTabId) ? (tab as DealTabId) : 'activities'\n}\n\nfunction formatTabCount(count: number): string | number | undefined {\n if (count <= 0) return undefined\n return count > 999 ? '999+' : count\n}\n\nexport function DealDetailTabs({\n activeTab,\n onTabChange,\n injectedTabs = [],\n peopleCount = 0,\n companiesCount = 0,\n children,\n}: DealDetailTabsProps) {\n const t = useT()\n\n const builtInTabs = React.useMemo<TabDef[]>(\n () => [\n {\n id: 'activities',\n label: t('customers.deals.detail.tabs.activities', 'Activities'),\n icon: <Activity className=\"size-4\" />,\n },\n {\n id: 'people',\n label: t('customers.deals.detail.tabs.people', 'People'),\n icon: <Users className=\"size-4\" />,\n count: formatTabCount(peopleCount),\n },\n {\n id: 'companies',\n label: t('customers.deals.detail.tabs.companies', 'Companies'),\n icon: <Building2 className=\"size-4\" />,\n count: formatTabCount(companiesCount),\n },\n {\n id: 'notes',\n label: t('customers.deals.detail.tabs.notes', 'Notes'),\n icon: <NotebookPen className=\"size-4\" />,\n },\n {\n id: 'files',\n label: t('customers.deals.detail.tabs.files', 'Files'),\n icon: <Paperclip className=\"size-4\" />,\n },\n {\n id: 'changelog',\n label: t('customers.deals.detail.tabs.changelog', 'Changelog'),\n icon: <History className=\"size-4\" />,\n count: 'NEW',\n },\n ],\n [companiesCount, peopleCount, t],\n )\n\n const allTabs = React.useMemo<TabDef[]>(\n () => [\n ...builtInTabs,\n ...injectedTabs.map((tab) => ({\n id: tab.id as DealTabId,\n label: tab.label,\n })),\n ],\n [builtInTabs, injectedTabs],\n )\n\n return (\n <div>\n <Tabs\n value={activeTab}\n onValueChange={(value) => onTabChange(value as DealTabId)}\n variant=\"underline\"\n >\n <TabsList\n aria-label={t('customers.deals.detail.tabs.label', 'Deal detail sections')}\n className=\"w-full overflow-x-auto\"\n >\n {allTabs.map((tab) => (\n <TabsTrigger key={tab.id} value={tab.id} leading={tab.icon} count={tab.count}>\n {tab.label}\n </TabsTrigger>\n ))}\n </TabsList>\n </Tabs>\n\n <div className=\"pt-5\" role=\"tabpanel\">\n {children}\n </div>\n </div>\n )\n}\n"],
5
+ "mappings": ";AA2Dc,cA8CV,YA9CU;AAzDd,YAAY,WAAW;AACvB,SAAS,UAAU,WAAW,SAAS,aAAa,WAAW,aAAa;AAC5E,SAAS,YAAY;AACrB,SAAS,MAAM,UAAU,mBAAmB;AA2B5C,MAAM,oBAAoB,oBAAI,IAAe,CAAC,cAAc,UAAU,aAAa,SAAS,SAAS,WAAW,CAAC;AAE1G,SAAS,iBAAiB,KAA2C;AAC1E,MAAI,CAAC,IAAK,QAAO;AACjB,SAAO,kBAAkB,IAAI,GAAgB,IAAK,MAAoB;AACxE;AAEA,SAAS,eAAe,OAA4C;AAClE,MAAI,SAAS,EAAG,QAAO;AACvB,SAAO,QAAQ,MAAM,SAAS;AAChC;AAEO,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA,eAAe,CAAC;AAAA,EAChB,cAAc;AAAA,EACd,iBAAiB;AAAA,EACjB;AACF,GAAwB;AACtB,QAAM,IAAI,KAAK;AAEf,QAAM,cAAc,MAAM;AAAA,IACxB,MAAM;AAAA,MACJ;AAAA,QACE,IAAI;AAAA,QACJ,OAAO,EAAE,0CAA0C,YAAY;AAAA,QAC/D,MAAM,oBAAC,YAAS,WAAU,UAAS;AAAA,MACrC;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ,OAAO,EAAE,sCAAsC,QAAQ;AAAA,QACvD,MAAM,oBAAC,SAAM,WAAU,UAAS;AAAA,QAChC,OAAO,eAAe,WAAW;AAAA,MACnC;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ,OAAO,EAAE,yCAAyC,WAAW;AAAA,QAC7D,MAAM,oBAAC,aAAU,WAAU,UAAS;AAAA,QACpC,OAAO,eAAe,cAAc;AAAA,MACtC;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ,OAAO,EAAE,qCAAqC,OAAO;AAAA,QACrD,MAAM,oBAAC,eAAY,WAAU,UAAS;AAAA,MACxC;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ,OAAO,EAAE,qCAAqC,OAAO;AAAA,QACrD,MAAM,oBAAC,aAAU,WAAU,UAAS;AAAA,MACtC;AAAA,MACA;AAAA,QACE,IAAI;AAAA,QACJ,OAAO,EAAE,yCAAyC,WAAW;AAAA,QAC7D,MAAM,oBAAC,WAAQ,WAAU,UAAS;AAAA,QAClC,OAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA,CAAC,gBAAgB,aAAa,CAAC;AAAA,EACjC;AAEA,QAAM,UAAU,MAAM;AAAA,IACpB,MAAM;AAAA,MACJ,GAAG;AAAA,MACH,GAAG,aAAa,IAAI,CAAC,SAAS;AAAA,QAC5B,IAAI,IAAI;AAAA,QACR,OAAO,IAAI;AAAA,MACb,EAAE;AAAA,IACJ;AAAA,IACA,CAAC,aAAa,YAAY;AAAA,EAC5B;AAEA,SACE,qBAAC,SACC;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,OAAO;AAAA,QACP,eAAe,CAAC,UAAU,YAAY,KAAkB;AAAA,QACxD,SAAQ;AAAA,QAER;AAAA,UAAC;AAAA;AAAA,YACC,cAAY,EAAE,qCAAqC,sBAAsB;AAAA,YACzE,WAAU;AAAA,YAET,kBAAQ,IAAI,CAAC,QACZ,oBAAC,eAAyB,OAAO,IAAI,IAAI,SAAS,IAAI,MAAM,OAAO,IAAI,OACpE,cAAI,SADW,IAAI,EAEtB,CACD;AAAA;AAAA,QACH;AAAA;AAAA,IACF;AAAA,IAEA,oBAAC,SAAI,WAAU,QAAO,MAAK,YACxB,UACH;AAAA,KACF;AAEJ;",
6
6
  "names": []
7
7
  }
@@ -2,6 +2,7 @@
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import { Button } from "@open-mercato/ui/primitives/button";
5
+ import { Tabs, TabsList, TabsTrigger } from "@open-mercato/ui/primitives/tabs";
5
6
  import { cn } from "@open-mercato/shared/lib/utils";
6
7
  import { Plus } from "lucide-react";
7
8
  function DetailTabsLayout({
@@ -25,28 +26,12 @@ function DetailTabsLayout({
25
26
  return /* @__PURE__ */ jsxs("div", { className: cn("space-y-4", className), children: [
26
27
  /* @__PURE__ */ jsxs("div", { className: cn("flex flex-wrap items-center justify-between gap-3", headerClassName), children: [
27
28
  /* @__PURE__ */ jsx(
28
- "nav",
29
+ Tabs,
29
30
  {
30
- className: cn("flex flex-wrap items-center gap-3 text-sm", navClassName),
31
- role: "tablist",
32
- "aria-label": navAriaLabel,
33
- children: tabs.map((tab) => /* @__PURE__ */ jsx(
34
- Button,
35
- {
36
- type: "button",
37
- variant: "ghost",
38
- size: "sm",
39
- role: "tab",
40
- "aria-selected": activeTab === tab.id,
41
- onClick: () => handleTabChange(tab.id),
42
- className: cn(
43
- "h-auto rounded-none border-b-2 px-0 py-1",
44
- activeTab === tab.id ? "border-accent-indigo text-foreground hover:bg-transparent" : "border-transparent text-muted-foreground hover:text-foreground hover:bg-transparent"
45
- ),
46
- children: tab.label
47
- },
48
- tab.id
49
- ))
31
+ value: activeTab,
32
+ onValueChange: (value) => handleTabChange(value),
33
+ variant: "underline",
34
+ children: /* @__PURE__ */ jsx(TabsList, { className: cn("h-auto flex-wrap border-b-0", navClassName), "aria-label": navAriaLabel, children: tabs.map((tab) => /* @__PURE__ */ jsx(TabsTrigger, { value: tab.id, children: tab.label }, tab.id)) })
50
35
  }
51
36
  ),
52
37
  sectionAction ? /* @__PURE__ */ jsxs(
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/customers/components/detail/DetailTabsLayout.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport type { SectionAction } from '@open-mercato/ui/backend/detail'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { Plus } from 'lucide-react'\n\nexport type DetailTabDefinition<TId extends string = string> = {\n id: TId\n label: React.ReactNode\n}\n\ntype DetailTabsLayoutProps<TId extends string = string> = {\n tabs: DetailTabDefinition<TId>[]\n activeTab: TId\n onTabChange: (id: TId) => void\n sectionAction: SectionAction | null\n onSectionAction: () => void\n navAriaLabel: string\n className?: string\n headerClassName?: string\n navClassName?: string\n children: React.ReactNode\n}\n\nexport function DetailTabsLayout<TId extends string = string>({\n tabs,\n activeTab,\n onTabChange,\n sectionAction,\n onSectionAction,\n navAriaLabel,\n className,\n headerClassName,\n navClassName,\n children,\n}: DetailTabsLayoutProps<TId>) {\n const handleTabChange = React.useCallback(\n (id: TId) => {\n onTabChange(id)\n },\n [onTabChange],\n )\n\n return (\n <div className={cn('space-y-4', className)}>\n <div className={cn('flex flex-wrap items-center justify-between gap-3', headerClassName)}>\n <nav\n className={cn('flex flex-wrap items-center gap-3 text-sm', navClassName)}\n role=\"tablist\"\n aria-label={navAriaLabel}\n >\n {tabs.map((tab) => (\n <Button\n key={tab.id}\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n role=\"tab\"\n aria-selected={activeTab === tab.id}\n onClick={() => handleTabChange(tab.id)}\n className={cn(\n 'h-auto rounded-none border-b-2 px-0 py-1',\n activeTab === tab.id\n ? 'border-accent-indigo text-foreground hover:bg-transparent'\n : 'border-transparent text-muted-foreground hover:text-foreground hover:bg-transparent'\n )}\n >\n {tab.label}\n </Button>\n ))}\n </nav>\n {sectionAction ? (\n <Button\n type=\"button\"\n size=\"sm\"\n onClick={onSectionAction}\n disabled={sectionAction.disabled}\n >\n {sectionAction.icon ?? (typeof sectionAction.label === 'string' || typeof sectionAction.label === 'number' ? (\n <Plus className=\"mr-2 h-4 w-4\" />\n ) : null)}\n {sectionAction.label}\n </Button>\n ) : null}\n </div>\n <div>{children}</div>\n </div>\n )\n}\n"],
5
- "mappings": ";AAsDY,cAoBF,YApBE;AApDZ,YAAY,WAAW;AAEvB,SAAS,cAAc;AACvB,SAAS,UAAU;AACnB,SAAS,YAAY;AAoBd,SAAS,iBAA8C;AAAA,EAC5D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA+B;AAC7B,QAAM,kBAAkB,MAAM;AAAA,IAC5B,CAAC,OAAY;AACX,kBAAY,EAAE;AAAA,IAChB;AAAA,IACA,CAAC,WAAW;AAAA,EACd;AAEA,SACE,qBAAC,SAAI,WAAW,GAAG,aAAa,SAAS,GACvC;AAAA,yBAAC,SAAI,WAAW,GAAG,qDAAqD,eAAe,GACrF;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,WAAW,GAAG,6CAA6C,YAAY;AAAA,UACvE,MAAK;AAAA,UACL,cAAY;AAAA,UAEX,eAAK,IAAI,CAAC,QACT;AAAA,YAAC;AAAA;AAAA,cAEC,MAAK;AAAA,cACL,SAAQ;AAAA,cACR,MAAK;AAAA,cACL,MAAK;AAAA,cACL,iBAAe,cAAc,IAAI;AAAA,cACjC,SAAS,MAAM,gBAAgB,IAAI,EAAE;AAAA,cACrC,WAAW;AAAA,gBACT;AAAA,gBACA,cAAc,IAAI,KACd,8DACA;AAAA,cACN;AAAA,cAEC,cAAI;AAAA;AAAA,YAdA,IAAI;AAAA,UAeX,CACD;AAAA;AAAA,MACH;AAAA,MACC,gBACC;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,MAAK;AAAA,UACL,SAAS;AAAA,UACT,UAAU,cAAc;AAAA,UAEvB;AAAA,0BAAc,SAAS,OAAO,cAAc,UAAU,YAAY,OAAO,cAAc,UAAU,WAChG,oBAAC,QAAK,WAAU,gBAAe,IAC7B;AAAA,YACH,cAAc;AAAA;AAAA;AAAA,MACjB,IACE;AAAA,OACN;AAAA,IACA,oBAAC,SAAK,UAAS;AAAA,KACjB;AAEJ;",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport type { SectionAction } from '@open-mercato/ui/backend/detail'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Tabs, TabsList, TabsTrigger } from '@open-mercato/ui/primitives/tabs'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { Plus } from 'lucide-react'\n\nexport type DetailTabDefinition<TId extends string = string> = {\n id: TId\n label: React.ReactNode\n}\n\ntype DetailTabsLayoutProps<TId extends string = string> = {\n tabs: DetailTabDefinition<TId>[]\n activeTab: TId\n onTabChange: (id: TId) => void\n sectionAction: SectionAction | null\n onSectionAction: () => void\n navAriaLabel: string\n className?: string\n headerClassName?: string\n navClassName?: string\n children: React.ReactNode\n}\n\nexport function DetailTabsLayout<TId extends string = string>({\n tabs,\n activeTab,\n onTabChange,\n sectionAction,\n onSectionAction,\n navAriaLabel,\n className,\n headerClassName,\n navClassName,\n children,\n}: DetailTabsLayoutProps<TId>) {\n const handleTabChange = React.useCallback(\n (id: TId) => {\n onTabChange(id)\n },\n [onTabChange],\n )\n\n return (\n <div className={cn('space-y-4', className)}>\n <div className={cn('flex flex-wrap items-center justify-between gap-3', headerClassName)}>\n <Tabs\n value={activeTab}\n onValueChange={(value) => handleTabChange(value as TId)}\n variant=\"underline\"\n >\n <TabsList className={cn('h-auto flex-wrap border-b-0', navClassName)} aria-label={navAriaLabel}>\n {tabs.map((tab) => (\n <TabsTrigger key={tab.id} value={tab.id}>\n {tab.label}\n </TabsTrigger>\n ))}\n </TabsList>\n </Tabs>\n {sectionAction ? (\n <Button\n type=\"button\"\n size=\"sm\"\n onClick={onSectionAction}\n disabled={sectionAction.disabled}\n >\n {sectionAction.icon ?? (typeof sectionAction.label === 'string' || typeof sectionAction.label === 'number' ? (\n <Plus className=\"mr-2 h-4 w-4\" />\n ) : null)}\n {sectionAction.label}\n </Button>\n ) : null}\n </div>\n <div>{children}</div>\n </div>\n )\n}\n"],
5
+ "mappings": ";AAwDc,cAOJ,YAPI;AAtDd,YAAY,WAAW;AAEvB,SAAS,cAAc;AACvB,SAAS,MAAM,UAAU,mBAAmB;AAC5C,SAAS,UAAU;AACnB,SAAS,YAAY;AAoBd,SAAS,iBAA8C;AAAA,EAC5D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA+B;AAC7B,QAAM,kBAAkB,MAAM;AAAA,IAC5B,CAAC,OAAY;AACX,kBAAY,EAAE;AAAA,IAChB;AAAA,IACA,CAAC,WAAW;AAAA,EACd;AAEA,SACE,qBAAC,SAAI,WAAW,GAAG,aAAa,SAAS,GACvC;AAAA,yBAAC,SAAI,WAAW,GAAG,qDAAqD,eAAe,GACrF;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO;AAAA,UACP,eAAe,CAAC,UAAU,gBAAgB,KAAY;AAAA,UACtD,SAAQ;AAAA,UAER,8BAAC,YAAS,WAAW,GAAG,+BAA+B,YAAY,GAAG,cAAY,cAC/E,eAAK,IAAI,CAAC,QACT,oBAAC,eAAyB,OAAO,IAAI,IAClC,cAAI,SADW,IAAI,EAEtB,CACD,GACH;AAAA;AAAA,MACF;AAAA,MACC,gBACC;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,MAAK;AAAA,UACL,SAAS;AAAA,UACT,UAAU,cAAc;AAAA,UAEvB;AAAA,0BAAc,SAAS,OAAO,cAAc,UAAU,YAAY,OAAO,cAAc,UAAU,WAChG,oBAAC,QAAK,WAAU,gBAAe,IAC7B;AAAA,YACH,cAAc;AAAA;AAAA;AAAA,MACjB,IACE;AAAA,OACN;AAAA,IACA,oBAAC,SAAK,UAAS;AAAA,KACjB;AAEJ;",
6
6
  "names": []
7
7
  }
@@ -3,8 +3,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import { useRouter, useSearchParams } from "next/navigation";
5
5
  import { useT } from "@open-mercato/shared/lib/i18n/context";
6
- import { cn } from "@open-mercato/shared/lib/utils";
7
- import { Button } from "@open-mercato/ui/primitives/button";
6
+ import { Tabs, TabsList, TabsTrigger } from "@open-mercato/ui/primitives/tabs";
8
7
  const ZONES = [
9
8
  { id: "details", labelKey: "customers.people.mobile.zoneSwitcher.details", fallback: "Details" },
10
9
  { id: "activity", labelKey: "customers.people.mobile.zoneSwitcher.activity", fallback: "Activity" }
@@ -55,38 +54,33 @@ function MobilePersonDetail({
55
54
  [handleZoneChange, zone]
56
55
  );
57
56
  return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
58
- /* @__PURE__ */ jsx(
59
- "div",
57
+ /* @__PURE__ */ jsx("div", { onKeyDown: handleKeyDown, children: /* @__PURE__ */ jsx(
58
+ Tabs,
60
59
  {
61
- role: "tablist",
62
- "aria-label": t(
63
- "customers.people.mobile.zoneSwitcher.ariaLabel",
64
- "Zone selector"
65
- ),
66
- className: "grid grid-cols-2 gap-1 rounded-lg border border-border/70 bg-muted/20 p-1",
67
- onKeyDown: handleKeyDown,
68
- children: ZONES.map((entry) => {
69
- const isActive = zone === entry.id;
70
- return /* @__PURE__ */ jsx(
71
- Button,
72
- {
73
- type: "button",
74
- role: "tab",
75
- "aria-selected": isActive,
76
- "aria-controls": `mobile-person-zone-${entry.id}`,
77
- variant: isActive ? "default" : "ghost",
78
- className: cn(
79
- "h-11 rounded-lg text-sm font-semibold",
80
- isActive ? "" : "text-muted-foreground"
81
- ),
82
- onClick: () => handleZoneChange(entry.id),
83
- children: t(entry.labelKey, entry.fallback)
84
- },
85
- entry.id
86
- );
87
- })
60
+ value: zone,
61
+ onValueChange: (value) => handleZoneChange(value),
62
+ variant: "underline",
63
+ children: /* @__PURE__ */ jsx(
64
+ TabsList,
65
+ {
66
+ "aria-label": t(
67
+ "customers.people.mobile.zoneSwitcher.ariaLabel",
68
+ "Zone selector"
69
+ ),
70
+ className: "w-full",
71
+ children: ZONES.map((entry) => /* @__PURE__ */ jsx(
72
+ TabsTrigger,
73
+ {
74
+ value: entry.id,
75
+ className: "flex-1 justify-center",
76
+ children: t(entry.labelKey, entry.fallback)
77
+ },
78
+ entry.id
79
+ ))
80
+ }
81
+ )
88
82
  }
89
- ),
83
+ ) }),
90
84
  /* @__PURE__ */ jsx(
91
85
  "div",
92
86
  {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/modules/customers/components/detail/MobilePersonDetail.tsx"],
4
- "sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { useRouter, useSearchParams } from 'next/navigation'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { Button } from '@open-mercato/ui/primitives/button'\n\nexport type MobilePersonZone = 'details' | 'activity'\n\nexport type MobilePersonDetailProps = {\n zone1: React.ReactNode\n zone2: React.ReactNode\n defaultZone?: MobilePersonZone\n /**\n * Controls whether zone state is synced to the URL `?zone=` query param.\n * Defaults to true on the page route so deep links round-trip.\n */\n syncToUrl?: boolean\n}\n\nconst ZONES: Array<{ id: MobilePersonZone; labelKey: string; fallback: string }> = [\n { id: 'details', labelKey: 'customers.people.mobile.zoneSwitcher.details', fallback: 'Details' },\n { id: 'activity', labelKey: 'customers.people.mobile.zoneSwitcher.activity', fallback: 'Activity' },\n]\n\nexport function MobilePersonDetail({\n zone1,\n zone2,\n defaultZone = 'details',\n syncToUrl = true,\n}: MobilePersonDetailProps) {\n const t = useT()\n const router = useRouter()\n const searchParams = useSearchParams()\n\n const initialZone = React.useMemo<MobilePersonZone>(() => {\n if (!syncToUrl) return defaultZone\n const raw = searchParams?.get('zone')\n if (raw === 'activity' || raw === 'details') return raw\n return defaultZone\n // Intentionally compute only from the initial searchParams snapshot; external URL updates\n // (browser back, manual edit) are acceptable to be out of sync on mobile \u2014 local clicks\n // own the zone state thereafter.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n const [zone, setZone] = React.useState<MobilePersonZone>(initialZone)\n const lastWrittenZoneRef = React.useRef<MobilePersonZone | null>(null)\n\n const handleZoneChange = React.useCallback(\n (next: MobilePersonZone) => {\n setZone(next)\n lastWrittenZoneRef.current = next\n if (!syncToUrl) return\n const params = new URLSearchParams(searchParams?.toString() ?? '')\n if (next === defaultZone) {\n params.delete('zone')\n } else {\n params.set('zone', next)\n }\n const query = params.toString()\n router.replace(query.length ? `?${query}` : '?', { scroll: false })\n },\n [defaultZone, router, searchParams, syncToUrl],\n )\n\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (event.key !== 'ArrowLeft' && event.key !== 'ArrowRight') return\n event.preventDefault()\n const currentIndex = ZONES.findIndex((entry) => entry.id === zone)\n if (currentIndex < 0) return\n const offset = event.key === 'ArrowRight' ? 1 : -1\n const nextIndex = (currentIndex + offset + ZONES.length) % ZONES.length\n handleZoneChange(ZONES[nextIndex].id)\n },\n [handleZoneChange, zone],\n )\n\n return (\n <div className=\"space-y-4\">\n <div\n role=\"tablist\"\n aria-label={t(\n 'customers.people.mobile.zoneSwitcher.ariaLabel',\n 'Zone selector',\n )}\n className=\"grid grid-cols-2 gap-1 rounded-lg border border-border/70 bg-muted/20 p-1\"\n onKeyDown={handleKeyDown}\n >\n {ZONES.map((entry) => {\n const isActive = zone === entry.id\n return (\n <Button\n key={entry.id}\n type=\"button\"\n role=\"tab\"\n aria-selected={isActive}\n aria-controls={`mobile-person-zone-${entry.id}`}\n variant={isActive ? 'default' : 'ghost'}\n className={cn(\n 'h-11 rounded-lg text-sm font-semibold',\n isActive ? '' : 'text-muted-foreground',\n )}\n onClick={() => handleZoneChange(entry.id)}\n >\n {t(entry.labelKey, entry.fallback)}\n </Button>\n )\n })}\n </div>\n <div\n id={`mobile-person-zone-${zone}`}\n role=\"tabpanel\"\n aria-labelledby={`mobile-person-zone-${zone}-tab`}\n >\n {zone === 'details' ? zone1 : zone2}\n </div>\n </div>\n )\n}\n\nexport default MobilePersonDetail\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { useRouter, useSearchParams } from 'next/navigation'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Tabs, TabsList, TabsTrigger } from '@open-mercato/ui/primitives/tabs'\n\nexport type MobilePersonZone = 'details' | 'activity'\n\nexport type MobilePersonDetailProps = {\n zone1: React.ReactNode\n zone2: React.ReactNode\n defaultZone?: MobilePersonZone\n /**\n * Controls whether zone state is synced to the URL `?zone=` query param.\n * Defaults to true on the page route so deep links round-trip.\n */\n syncToUrl?: boolean\n}\n\nconst ZONES: Array<{ id: MobilePersonZone; labelKey: string; fallback: string }> = [\n { id: 'details', labelKey: 'customers.people.mobile.zoneSwitcher.details', fallback: 'Details' },\n { id: 'activity', labelKey: 'customers.people.mobile.zoneSwitcher.activity', fallback: 'Activity' },\n]\n\nexport function MobilePersonDetail({\n zone1,\n zone2,\n defaultZone = 'details',\n syncToUrl = true,\n}: MobilePersonDetailProps) {\n const t = useT()\n const router = useRouter()\n const searchParams = useSearchParams()\n\n const initialZone = React.useMemo<MobilePersonZone>(() => {\n if (!syncToUrl) return defaultZone\n const raw = searchParams?.get('zone')\n if (raw === 'activity' || raw === 'details') return raw\n return defaultZone\n // Intentionally compute only from the initial searchParams snapshot; external URL updates\n // (browser back, manual edit) are acceptable to be out of sync on mobile \u2014 local clicks\n // own the zone state thereafter.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n const [zone, setZone] = React.useState<MobilePersonZone>(initialZone)\n const lastWrittenZoneRef = React.useRef<MobilePersonZone | null>(null)\n\n const handleZoneChange = React.useCallback(\n (next: MobilePersonZone) => {\n setZone(next)\n lastWrittenZoneRef.current = next\n if (!syncToUrl) return\n const params = new URLSearchParams(searchParams?.toString() ?? '')\n if (next === defaultZone) {\n params.delete('zone')\n } else {\n params.set('zone', next)\n }\n const query = params.toString()\n router.replace(query.length ? `?${query}` : '?', { scroll: false })\n },\n [defaultZone, router, searchParams, syncToUrl],\n )\n\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (event.key !== 'ArrowLeft' && event.key !== 'ArrowRight') return\n event.preventDefault()\n const currentIndex = ZONES.findIndex((entry) => entry.id === zone)\n if (currentIndex < 0) return\n const offset = event.key === 'ArrowRight' ? 1 : -1\n const nextIndex = (currentIndex + offset + ZONES.length) % ZONES.length\n handleZoneChange(ZONES[nextIndex].id)\n },\n [handleZoneChange, zone],\n )\n\n return (\n <div className=\"space-y-4\">\n <div onKeyDown={handleKeyDown}>\n <Tabs\n value={zone}\n onValueChange={(value) => handleZoneChange(value as MobilePersonZone)}\n variant=\"underline\"\n >\n <TabsList\n aria-label={t(\n 'customers.people.mobile.zoneSwitcher.ariaLabel',\n 'Zone selector',\n )}\n className=\"w-full\"\n >\n {ZONES.map((entry) => (\n <TabsTrigger\n key={entry.id}\n value={entry.id}\n className=\"flex-1 justify-center\"\n >\n {t(entry.labelKey, entry.fallback)}\n </TabsTrigger>\n ))}\n </TabsList>\n </Tabs>\n </div>\n <div\n id={`mobile-person-zone-${zone}`}\n role=\"tabpanel\"\n aria-labelledby={`mobile-person-zone-${zone}-tab`}\n >\n {zone === 'details' ? zone1 : zone2}\n </div>\n </div>\n )\n}\n\nexport default MobilePersonDetail\n"],
5
+ "mappings": ";AAgFI,SAeU,KAfV;AA9EJ,YAAY,WAAW;AACvB,SAAS,WAAW,uBAAuB;AAC3C,SAAS,YAAY;AACrB,SAAS,MAAM,UAAU,mBAAmB;AAe5C,MAAM,QAA6E;AAAA,EACjF,EAAE,IAAI,WAAW,UAAU,gDAAgD,UAAU,UAAU;AAAA,EAC/F,EAAE,IAAI,YAAY,UAAU,iDAAiD,UAAU,WAAW;AACpG;AAEO,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd,YAAY;AACd,GAA4B;AAC1B,QAAM,IAAI,KAAK;AACf,QAAM,SAAS,UAAU;AACzB,QAAM,eAAe,gBAAgB;AAErC,QAAM,cAAc,MAAM,QAA0B,MAAM;AACxD,QAAI,CAAC,UAAW,QAAO;AACvB,UAAM,MAAM,cAAc,IAAI,MAAM;AACpC,QAAI,QAAQ,cAAc,QAAQ,UAAW,QAAO;AACpD,WAAO;AAAA,EAKT,GAAG,CAAC,CAAC;AAEL,QAAM,CAAC,MAAM,OAAO,IAAI,MAAM,SAA2B,WAAW;AACpE,QAAM,qBAAqB,MAAM,OAAgC,IAAI;AAErE,QAAM,mBAAmB,MAAM;AAAA,IAC7B,CAAC,SAA2B;AAC1B,cAAQ,IAAI;AACZ,yBAAmB,UAAU;AAC7B,UAAI,CAAC,UAAW;AAChB,YAAM,SAAS,IAAI,gBAAgB,cAAc,SAAS,KAAK,EAAE;AACjE,UAAI,SAAS,aAAa;AACxB,eAAO,OAAO,MAAM;AAAA,MACtB,OAAO;AACL,eAAO,IAAI,QAAQ,IAAI;AAAA,MACzB;AACA,YAAM,QAAQ,OAAO,SAAS;AAC9B,aAAO,QAAQ,MAAM,SAAS,IAAI,KAAK,KAAK,KAAK,EAAE,QAAQ,MAAM,CAAC;AAAA,IACpE;AAAA,IACA,CAAC,aAAa,QAAQ,cAAc,SAAS;AAAA,EAC/C;AAEA,QAAM,gBAAgB,MAAM;AAAA,IAC1B,CAAC,UAA+C;AAC9C,UAAI,MAAM,QAAQ,eAAe,MAAM,QAAQ,aAAc;AAC7D,YAAM,eAAe;AACrB,YAAM,eAAe,MAAM,UAAU,CAAC,UAAU,MAAM,OAAO,IAAI;AACjE,UAAI,eAAe,EAAG;AACtB,YAAM,SAAS,MAAM,QAAQ,eAAe,IAAI;AAChD,YAAM,aAAa,eAAe,SAAS,MAAM,UAAU,MAAM;AACjE,uBAAiB,MAAM,SAAS,EAAE,EAAE;AAAA,IACtC;AAAA,IACA,CAAC,kBAAkB,IAAI;AAAA,EACzB;AAEA,SACE,qBAAC,SAAI,WAAU,aACb;AAAA,wBAAC,SAAI,WAAW,eACd;AAAA,MAAC;AAAA;AAAA,QACC,OAAO;AAAA,QACP,eAAe,CAAC,UAAU,iBAAiB,KAAyB;AAAA,QACpE,SAAQ;AAAA,QAER;AAAA,UAAC;AAAA;AAAA,YACC,cAAY;AAAA,cACV;AAAA,cACA;AAAA,YACF;AAAA,YACA,WAAU;AAAA,YAET,gBAAM,IAAI,CAAC,UACV;AAAA,cAAC;AAAA;AAAA,gBAEC,OAAO,MAAM;AAAA,gBACb,WAAU;AAAA,gBAET,YAAE,MAAM,UAAU,MAAM,QAAQ;AAAA;AAAA,cAJ5B,MAAM;AAAA,YAKb,CACD;AAAA;AAAA,QACH;AAAA;AAAA,IACF,GACF;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,IAAI,sBAAsB,IAAI;AAAA,QAC9B,MAAK;AAAA,QACL,mBAAiB,sBAAsB,IAAI;AAAA,QAE1C,mBAAS,YAAY,QAAQ;AAAA;AAAA,IAChC;AAAA,KACF;AAEJ;AAEA,IAAO,6BAAQ;",
6
6
  "names": []
7
7
  }