@open-mercato/core 0.6.8-develop.7029.1.a1bb3363af → 0.6.8-develop.7031.1.005201cd70

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 (236) hide show
  1. package/dist/modules/api_keys/backend/api-keys/page.js +3 -1
  2. package/dist/modules/api_keys/backend/api-keys/page.js.map +2 -2
  3. package/dist/modules/attachments/components/AttachmentLibrary.js +2 -0
  4. package/dist/modules/attachments/components/AttachmentLibrary.js.map +2 -2
  5. package/dist/modules/audit_logs/backend/audit-logs/page.js +6 -0
  6. package/dist/modules/audit_logs/backend/audit-logs/page.js.map +2 -2
  7. package/dist/modules/auth/backend/roles/page.js +3 -1
  8. package/dist/modules/auth/backend/roles/page.js.map +2 -2
  9. package/dist/modules/auth/backend/users/page.js +2 -1
  10. package/dist/modules/auth/backend/users/page.js.map +2 -2
  11. package/dist/modules/business_rules/backend/logs/page.js +3 -1
  12. package/dist/modules/business_rules/backend/logs/page.js.map +2 -2
  13. package/dist/modules/business_rules/backend/rules/page.js +3 -1
  14. package/dist/modules/business_rules/backend/rules/page.js.map +2 -2
  15. package/dist/modules/business_rules/backend/sets/page.js +3 -1
  16. package/dist/modules/business_rules/backend/sets/page.js.map +2 -2
  17. package/dist/modules/catalog/ai-agents.js +1 -1
  18. package/dist/modules/catalog/ai-agents.js.map +1 -1
  19. package/dist/modules/catalog/ai-tools/merchandising-pack.js +2 -2
  20. package/dist/modules/catalog/ai-tools/merchandising-pack.js.map +2 -2
  21. package/dist/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.js +5 -2
  22. package/dist/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.js.map +2 -2
  23. package/dist/modules/catalog/components/categories/CategoriesDataTable.js +2 -0
  24. package/dist/modules/catalog/components/categories/CategoriesDataTable.js.map +2 -2
  25. package/dist/modules/catalog/components/products/ProductsDataTable.js +7 -1
  26. package/dist/modules/catalog/components/products/ProductsDataTable.js.map +2 -2
  27. package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.js +2 -0
  28. package/dist/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.js.map +2 -2
  29. package/dist/modules/communication_channels/backend/communication_channels/channels/page.js +3 -0
  30. package/dist/modules/communication_channels/backend/communication_channels/channels/page.js.map +2 -2
  31. package/dist/modules/configs/lib/system-status.js +9 -0
  32. package/dist/modules/configs/lib/system-status.js.map +2 -2
  33. package/dist/modules/currencies/backend/currencies/page.js +3 -1
  34. package/dist/modules/currencies/backend/currencies/page.js.map +2 -2
  35. package/dist/modules/currencies/backend/exchange-rates/page.js +3 -1
  36. package/dist/modules/currencies/backend/exchange-rates/page.js.map +2 -2
  37. package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js +3 -1
  38. package/dist/modules/customer_accounts/backend/customer_accounts/roles/page.js.map +2 -2
  39. package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js +3 -1
  40. package/dist/modules/customer_accounts/backend/customer_accounts/users/page.js.map +2 -2
  41. package/dist/modules/customers/ai-tools/companies-pack.js +4 -1
  42. package/dist/modules/customers/ai-tools/companies-pack.js.map +2 -2
  43. package/dist/modules/customers/ai-tools/deals-pack.js +4 -1
  44. package/dist/modules/customers/ai-tools/deals-pack.js.map +2 -2
  45. package/dist/modules/customers/ai-tools/people-pack.js +4 -1
  46. package/dist/modules/customers/ai-tools/people-pack.js.map +2 -2
  47. package/dist/modules/customers/api/deals/map/route.js +2 -1
  48. package/dist/modules/customers/api/deals/map/route.js.map +2 -2
  49. package/dist/modules/customers/backend/customers/companies/page.js +3 -1
  50. package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
  51. package/dist/modules/customers/backend/customers/deals/page.js +5 -2
  52. package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
  53. package/dist/modules/customers/backend/customers/people/page.js +3 -1
  54. package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
  55. package/dist/modules/customers/components/CustomerTodosTable.js +1 -0
  56. package/dist/modules/customers/components/CustomerTodosTable.js.map +2 -2
  57. package/dist/modules/data_sync/backend/data-sync/page.js +3 -1
  58. package/dist/modules/data_sync/backend/data-sync/page.js.map +2 -2
  59. package/dist/modules/devices/backend/devices/page.js +3 -1
  60. package/dist/modules/devices/backend/devices/page.js.map +2 -2
  61. package/dist/modules/directory/backend/directory/organizations/page.js +2 -1
  62. package/dist/modules/directory/backend/directory/organizations/page.js.map +2 -2
  63. package/dist/modules/directory/backend/directory/tenants/page.js +2 -1
  64. package/dist/modules/directory/backend/directory/tenants/page.js.map +2 -2
  65. package/dist/modules/entities/api/records.js +4 -2
  66. package/dist/modules/entities/api/records.js.map +2 -2
  67. package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js +3 -1
  68. package/dist/modules/entities/backend/entities/user/[entityId]/records/page.js.map +2 -2
  69. package/dist/modules/eudr/backend/eudr/evidence-submissions/page.js +3 -0
  70. package/dist/modules/eudr/backend/eudr/evidence-submissions/page.js.map +2 -2
  71. package/dist/modules/eudr/backend/eudr/plots/page.js +3 -0
  72. package/dist/modules/eudr/backend/eudr/plots/page.js.map +2 -2
  73. package/dist/modules/eudr/backend/eudr/product-mappings/page.js +3 -0
  74. package/dist/modules/eudr/backend/eudr/product-mappings/page.js.map +2 -2
  75. package/dist/modules/eudr/backend/eudr/risk-assessments/page.js +3 -0
  76. package/dist/modules/eudr/backend/eudr/risk-assessments/page.js.map +2 -2
  77. package/dist/modules/eudr/backend/eudr/statements/page.js +3 -0
  78. package/dist/modules/eudr/backend/eudr/statements/page.js.map +2 -2
  79. package/dist/modules/feature_toggles/components/FeatureTogglesTable.js +1 -0
  80. package/dist/modules/feature_toggles/components/FeatureTogglesTable.js.map +2 -2
  81. package/dist/modules/feature_toggles/components/OverridesTable.js +1 -0
  82. package/dist/modules/feature_toggles/components/OverridesTable.js.map +2 -2
  83. package/dist/modules/inbox_ops/backend/inbox-ops/log/page.js +3 -0
  84. package/dist/modules/inbox_ops/backend/inbox-ops/log/page.js.map +2 -2
  85. package/dist/modules/inbox_ops/backend/inbox-ops/page.js +3 -0
  86. package/dist/modules/inbox_ops/backend/inbox-ops/page.js.map +2 -2
  87. package/dist/modules/messages/components/MessagesInboxPageClient.js +4 -1
  88. package/dist/modules/messages/components/MessagesInboxPageClient.js.map +2 -2
  89. package/dist/modules/payment_gateways/backend/payment-gateways/page.js +3 -1
  90. package/dist/modules/payment_gateways/backend/payment-gateways/page.js.map +2 -2
  91. package/dist/modules/planner/backend/planner/availability-rulesets/page.js +3 -0
  92. package/dist/modules/planner/backend/planner/availability-rulesets/page.js.map +2 -2
  93. package/dist/modules/push_notifications/backend/push_notifications/page.js +3 -1
  94. package/dist/modules/push_notifications/backend/push_notifications/page.js.map +2 -2
  95. package/dist/modules/query_index/lib/engine.js +108 -48
  96. package/dist/modules/query_index/lib/engine.js.map +2 -2
  97. package/dist/modules/resources/backend/resources/resource-types/page.js +3 -1
  98. package/dist/modules/resources/backend/resources/resource-types/page.js.map +2 -2
  99. package/dist/modules/resources/backend/resources/resources/page.js +3 -1
  100. package/dist/modules/resources/backend/resources/resources/page.js.map +2 -2
  101. package/dist/modules/sales/backend/sales/channels/offers/page.js +3 -0
  102. package/dist/modules/sales/backend/sales/channels/offers/page.js.map +2 -2
  103. package/dist/modules/sales/backend/sales/channels/page.js +3 -0
  104. package/dist/modules/sales/backend/sales/channels/page.js.map +2 -2
  105. package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js +3 -0
  106. package/dist/modules/sales/components/channels/SalesChannelOffersPanel.js.map +2 -2
  107. package/dist/modules/sales/components/documents/SalesDocumentsTable.js +4 -0
  108. package/dist/modules/sales/components/documents/SalesDocumentsTable.js.map +2 -2
  109. package/dist/modules/staff/backend/staff/leave-requests/page.js +3 -0
  110. package/dist/modules/staff/backend/staff/leave-requests/page.js.map +2 -2
  111. package/dist/modules/staff/backend/staff/my-leave-requests/page.js +3 -0
  112. package/dist/modules/staff/backend/staff/my-leave-requests/page.js.map +2 -2
  113. package/dist/modules/staff/backend/staff/team-members/page.js +3 -0
  114. package/dist/modules/staff/backend/staff/team-members/page.js.map +2 -2
  115. package/dist/modules/staff/backend/staff/team-roles/page.js +3 -0
  116. package/dist/modules/staff/backend/staff/team-roles/page.js.map +2 -2
  117. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +3 -0
  118. package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
  119. package/dist/modules/staff/backend/staff/teams/page.js +3 -0
  120. package/dist/modules/staff/backend/staff/teams/page.js.map +2 -2
  121. package/dist/modules/staff/backend/staff/timesheets/projects/page.js +3 -0
  122. package/dist/modules/staff/backend/staff/timesheets/projects/page.js.map +2 -2
  123. package/dist/modules/warranty_claims/backend/page.js +3 -0
  124. package/dist/modules/warranty_claims/backend/page.js.map +2 -2
  125. package/dist/modules/warranty_claims/backend/warranty_claims/registrations/page.js +3 -0
  126. package/dist/modules/warranty_claims/backend/warranty_claims/registrations/page.js.map +2 -2
  127. package/dist/modules/warranty_claims/backend/warranty_claims/troubleshooting-guides/page.js +3 -0
  128. package/dist/modules/warranty_claims/backend/warranty_claims/troubleshooting-guides/page.js.map +2 -2
  129. package/dist/modules/warranty_claims/backend/warranty_claims/vendor-policies/page.js +3 -0
  130. package/dist/modules/warranty_claims/backend/warranty_claims/vendor-policies/page.js.map +2 -2
  131. package/dist/modules/warranty_claims/frontend/[orgSlug]/portal/claims/page.js +3 -0
  132. package/dist/modules/warranty_claims/frontend/[orgSlug]/portal/claims/page.js.map +2 -2
  133. package/dist/modules/wms/commands/inventory-actions.js +3 -0
  134. package/dist/modules/wms/commands/inventory-actions.js.map +2 -2
  135. package/dist/modules/wms/components/backend/WmsConfigurationPage.js +4 -0
  136. package/dist/modules/wms/components/backend/WmsConfigurationPage.js.map +2 -2
  137. package/dist/modules/wms/components/backend/WmsInventoryConsolePage.js +1 -0
  138. package/dist/modules/wms/components/backend/WmsInventoryConsolePage.js.map +2 -2
  139. package/dist/modules/wms/components/backend/WmsLotsListPage.js +1 -0
  140. package/dist/modules/wms/components/backend/WmsLotsListPage.js.map +2 -2
  141. package/dist/modules/wms/components/backend/inventoryMutationLoaders.js +27 -20
  142. package/dist/modules/wms/components/backend/inventoryMutationLoaders.js.map +2 -2
  143. package/dist/modules/workflows/backend/definitions/page.js +3 -1
  144. package/dist/modules/workflows/backend/definitions/page.js.map +2 -2
  145. package/dist/modules/workflows/backend/events/page.js +3 -1
  146. package/dist/modules/workflows/backend/events/page.js.map +2 -2
  147. package/dist/modules/workflows/backend/instances/page.js +3 -1
  148. package/dist/modules/workflows/backend/instances/page.js.map +2 -2
  149. package/dist/modules/workflows/backend/tasks/page.js +3 -1
  150. package/dist/modules/workflows/backend/tasks/page.js.map +2 -2
  151. package/package.json +7 -7
  152. package/src/modules/api_keys/backend/api-keys/page.tsx +4 -1
  153. package/src/modules/attachments/components/AttachmentLibrary.tsx +3 -0
  154. package/src/modules/audit_logs/backend/audit-logs/page.tsx +8 -0
  155. package/src/modules/auth/backend/roles/page.tsx +4 -2
  156. package/src/modules/auth/backend/users/page.tsx +3 -2
  157. package/src/modules/business_rules/backend/logs/page.tsx +4 -1
  158. package/src/modules/business_rules/backend/rules/page.tsx +4 -1
  159. package/src/modules/business_rules/backend/sets/page.tsx +4 -1
  160. package/src/modules/catalog/ai-agents.ts +1 -1
  161. package/src/modules/catalog/ai-tools/merchandising-pack.ts +2 -2
  162. package/src/modules/catalog/backend/catalog/products/MerchandisingAssistantSheet.tsx +12 -5
  163. package/src/modules/catalog/components/categories/CategoriesDataTable.tsx +3 -0
  164. package/src/modules/catalog/components/products/ProductsDataTable.tsx +7 -0
  165. package/src/modules/catalog/i18n/de.json +1 -0
  166. package/src/modules/catalog/i18n/en.json +1 -0
  167. package/src/modules/catalog/i18n/es.json +1 -0
  168. package/src/modules/catalog/i18n/ko.json +1 -0
  169. package/src/modules/catalog/i18n/pl.json +1 -0
  170. package/src/modules/catalog/widgets/injection/merchandising-assistant-trigger/widget.client.tsx +4 -0
  171. package/src/modules/communication_channels/backend/communication_channels/channels/page.tsx +4 -0
  172. package/src/modules/configs/i18n/de.json +2 -0
  173. package/src/modules/configs/i18n/en.json +2 -0
  174. package/src/modules/configs/i18n/es.json +2 -0
  175. package/src/modules/configs/i18n/ko.json +2 -0
  176. package/src/modules/configs/i18n/pl.json +2 -0
  177. package/src/modules/configs/lib/system-status.ts +9 -0
  178. package/src/modules/currencies/backend/currencies/page.tsx +4 -1
  179. package/src/modules/currencies/backend/exchange-rates/page.tsx +4 -1
  180. package/src/modules/customer_accounts/backend/customer_accounts/roles/page.tsx +4 -1
  181. package/src/modules/customer_accounts/backend/customer_accounts/users/page.tsx +4 -1
  182. package/src/modules/customers/ai-tools/companies-pack.ts +4 -1
  183. package/src/modules/customers/ai-tools/deals-pack.ts +4 -1
  184. package/src/modules/customers/ai-tools/people-pack.ts +4 -1
  185. package/src/modules/customers/api/deals/map/route.ts +1 -0
  186. package/src/modules/customers/backend/customers/companies/page.tsx +4 -1
  187. package/src/modules/customers/backend/customers/deals/page.tsx +8 -2
  188. package/src/modules/customers/backend/customers/people/page.tsx +4 -1
  189. package/src/modules/customers/components/CustomerTodosTable.tsx +2 -0
  190. package/src/modules/data_sync/backend/data-sync/page.tsx +4 -1
  191. package/src/modules/devices/backend/devices/page.tsx +4 -1
  192. package/src/modules/directory/backend/directory/organizations/page.tsx +3 -1
  193. package/src/modules/directory/backend/directory/tenants/page.tsx +3 -1
  194. package/src/modules/entities/api/records.ts +2 -0
  195. package/src/modules/entities/backend/entities/user/[entityId]/records/page.tsx +4 -1
  196. package/src/modules/eudr/backend/eudr/evidence-submissions/page.tsx +4 -0
  197. package/src/modules/eudr/backend/eudr/plots/page.tsx +4 -0
  198. package/src/modules/eudr/backend/eudr/product-mappings/page.tsx +4 -0
  199. package/src/modules/eudr/backend/eudr/risk-assessments/page.tsx +4 -0
  200. package/src/modules/eudr/backend/eudr/statements/page.tsx +4 -0
  201. package/src/modules/feature_toggles/components/FeatureTogglesTable.tsx +2 -1
  202. package/src/modules/feature_toggles/components/OverridesTable.tsx +2 -1
  203. package/src/modules/inbox_ops/backend/inbox-ops/log/page.tsx +4 -0
  204. package/src/modules/inbox_ops/backend/inbox-ops/page.tsx +4 -0
  205. package/src/modules/messages/components/MessagesInboxPageClient.tsx +4 -0
  206. package/src/modules/payment_gateways/backend/payment-gateways/page.tsx +4 -1
  207. package/src/modules/planner/backend/planner/availability-rulesets/page.tsx +4 -0
  208. package/src/modules/push_notifications/backend/push_notifications/page.tsx +4 -1
  209. package/src/modules/query_index/lib/engine.ts +156 -53
  210. package/src/modules/resources/backend/resources/resource-types/page.tsx +4 -1
  211. package/src/modules/resources/backend/resources/resources/page.tsx +4 -1
  212. package/src/modules/sales/backend/sales/channels/offers/page.tsx +4 -0
  213. package/src/modules/sales/backend/sales/channels/page.tsx +4 -0
  214. package/src/modules/sales/components/channels/SalesChannelOffersPanel.tsx +4 -0
  215. package/src/modules/sales/components/documents/SalesDocumentsTable.tsx +5 -0
  216. package/src/modules/staff/backend/staff/leave-requests/page.tsx +4 -0
  217. package/src/modules/staff/backend/staff/my-leave-requests/page.tsx +4 -0
  218. package/src/modules/staff/backend/staff/team-members/page.tsx +6 -0
  219. package/src/modules/staff/backend/staff/team-roles/page.tsx +4 -0
  220. package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +4 -0
  221. package/src/modules/staff/backend/staff/teams/page.tsx +4 -0
  222. package/src/modules/staff/backend/staff/timesheets/projects/page.tsx +4 -0
  223. package/src/modules/warranty_claims/backend/page.tsx +4 -0
  224. package/src/modules/warranty_claims/backend/warranty_claims/registrations/page.tsx +4 -0
  225. package/src/modules/warranty_claims/backend/warranty_claims/troubleshooting-guides/page.tsx +4 -0
  226. package/src/modules/warranty_claims/backend/warranty_claims/vendor-policies/page.tsx +4 -0
  227. package/src/modules/warranty_claims/frontend/[orgSlug]/portal/claims/page.tsx +4 -0
  228. package/src/modules/wms/commands/inventory-actions.ts +3 -0
  229. package/src/modules/wms/components/backend/WmsConfigurationPage.tsx +5 -0
  230. package/src/modules/wms/components/backend/WmsInventoryConsolePage.tsx +2 -0
  231. package/src/modules/wms/components/backend/WmsLotsListPage.tsx +2 -0
  232. package/src/modules/wms/components/backend/inventoryMutationLoaders.ts +36 -20
  233. package/src/modules/workflows/backend/definitions/page.tsx +4 -1
  234. package/src/modules/workflows/backend/events/page.tsx +4 -1
  235. package/src/modules/workflows/backend/instances/page.tsx +4 -1
  236. package/src/modules/workflows/backend/tasks/page.tsx +4 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../../../src/modules/staff/backend/staff/teams/%5Bid%5D/edit/page.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { usePathname, useRouter, useSearchParams } from 'next/navigation'\nimport type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'\nimport type { SortingState } from '@tanstack/react-table'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { ErrorMessage, RecordNotFoundState } from '@open-mercato/ui/backend/detail'\nimport { readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { updateCrud, deleteCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { DataTable, withDataTableNamespaces } from '@open-mercato/ui/backend/DataTable'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Tabs, TabsList, TabsTrigger } from '@open-mercato/ui/primitives/tabs'\nimport { BooleanIcon } from '@open-mercato/ui/backend/ValueIcons'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { TeamForm, type TeamFormValues, buildTeamPayload } from '@open-mercato/core/modules/staff/components/TeamForm'\nimport { buildRecordInjectionContext, useSetCurrentRecordInjectionContext } from '@open-mercato/ui/backend/injection/recordContext'\nimport { SendObjectMessageDialog } from '@open-mercato/ui/backend/messages'\nimport { extractCustomFieldEntries } from '@open-mercato/shared/lib/crud/custom-fields-client'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { Plus } from 'lucide-react'\nimport { formatDateTime } from '@open-mercato/shared/lib/time'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('staff')\n\nconst TEAM_MEMBERS_PAGE_SIZE = 50\n\ntype TeamRecord = {\n id: string\n name: string\n description?: string | null\n isActive?: boolean\n is_active?: boolean\n updatedAt?: string | null\n updated_at?: string | null\n} & Record<string, unknown>\n\ntype TeamResponse = {\n items?: TeamRecord[]\n}\n\ntype TeamMemberRow = {\n id: string\n displayName: string\n description: string | null\n userEmail: string | null\n roleNames: string[]\n tags: string[]\n isActive: boolean\n updatedAt: string | null\n teamId: string | null\n}\n\ntype TeamMembersResponse = {\n items?: Array<Record<string, unknown>>\n total?: number\n totalPages?: number\n}\n\nexport default function StaffTeamEditPage({ params }: { params?: { id?: string } }) {\n const teamId = params?.id\n const t = useT()\n const router = useRouter()\n const pathname = usePathname()\n const searchParams = useSearchParams()\n const scopeVersion = useOrganizationScopeVersion()\n const [initialValues, setInitialValues] = React.useState<TeamFormValues | null>(null)\n const [error, setError] = React.useState<string | null>(null)\n const [isNotFound, setIsNotFound] = React.useState(false)\n const [activeTab, setActiveTab] = React.useState<'details' | 'members'>('details')\n const [memberRows, setMemberRows] = React.useState<TeamMemberRow[]>([])\n const [memberPage, setMemberPage] = React.useState(1)\n const [memberTotal, setMemberTotal] = React.useState(0)\n const [memberTotalPages, setMemberTotalPages] = React.useState(1)\n const [memberSorting, setMemberSorting] = React.useState<SortingState>([{ id: 'displayName', desc: false }])\n const [memberSearch, setMemberSearch] = React.useState('')\n const [membersLoading, setMembersLoading] = React.useState(false)\n const [memberReloadToken, setMemberReloadToken] = React.useState(0)\n\n const memberLabels = React.useMemo(() => ({\n title: t('staff.teams.tabs.members', 'Team members'),\n description: t('staff.teamMembers.page.description', 'Manage employees and their team assignments.'),\n table: {\n name: t('staff.teamMembers.table.name', 'Name'),\n user: t('staff.teamMembers.table.user', 'User'),\n roles: t('staff.teamMembers.table.roles', 'Roles'),\n tags: t('staff.teamMembers.table.tags', 'Tags'),\n active: t('staff.teamMembers.table.active', 'Active'),\n updatedAt: t('staff.teamMembers.table.updatedAt', 'Updated'),\n empty: t('staff.teamMembers.table.empty', 'No team members yet.'),\n search: t('staff.teamMembers.table.search', 'Search team members...'),\n },\n actions: {\n add: t('staff.teamMembers.actions.add', 'Add team member'),\n edit: t('staff.teamMembers.actions.edit', 'Edit'),\n unassign: t('staff.teamMembers.actions.unassign', 'Unassign'),\n refresh: t('staff.teamMembers.actions.refresh', 'Refresh'),\n },\n messages: {\n unassigned: t('staff.teamMembers.messages.unassigned', 'Team member unassigned.'),\n },\n errors: {\n load: t('staff.teamMembers.errors.load', 'Failed to load team members.'),\n unassign: t('staff.teamMembers.errors.unassign', 'Failed to unassign team member.'),\n },\n tabs: {\n details: t('staff.teams.tabs.details', 'Details'),\n members: t('staff.teams.tabs.members', 'Team members'),\n label: t('staff.teams.tabs.label', 'Team sections'),\n },\n }), [t])\n\n const memberColumns = React.useMemo<ColumnDef<TeamMemberRow>[]>(() => [\n {\n accessorKey: 'displayName',\n header: memberLabels.table.name,\n meta: { priority: 1, sticky: true },\n cell: ({ row }) => (\n <div className=\"flex flex-col\">\n <span className=\"font-medium\">{row.original.displayName}</span>\n {row.original.description ? (\n <span className=\"text-xs text-muted-foreground line-clamp-2\">{row.original.description}</span>\n ) : null}\n </div>\n ),\n },\n {\n accessorKey: 'userEmail',\n header: memberLabels.table.user,\n meta: { priority: 2 },\n cell: ({ row }) => row.original.userEmail\n ? <span className=\"text-sm\">{row.original.userEmail}</span>\n : <span className=\"text-xs text-muted-foreground\">-</span>,\n },\n {\n accessorKey: 'roleNames',\n header: memberLabels.table.roles,\n meta: { priority: 3 },\n cell: ({ row }) => row.original.roleNames.length\n ? <span className=\"text-sm\">{row.original.roleNames.join(', ')}</span>\n : <span className=\"text-xs text-muted-foreground\">-</span>,\n },\n {\n accessorKey: 'tags',\n header: memberLabels.table.tags,\n meta: { priority: 4 },\n cell: ({ row }) => row.original.tags.length\n ? <span className=\"text-xs text-muted-foreground\">{row.original.tags.join(', ')}</span>\n : <span className=\"text-xs text-muted-foreground\">-</span>,\n },\n {\n accessorKey: 'isActive',\n header: memberLabels.table.active,\n meta: { priority: 5 },\n cell: ({ row }) => <BooleanIcon value={row.original.isActive} />,\n },\n {\n accessorKey: 'updatedAt',\n header: memberLabels.table.updatedAt,\n meta: { priority: 6 },\n cell: ({ row }) => row.original.updatedAt\n ? <span className=\"text-xs text-muted-foreground\">{formatDateTime(row.original.updatedAt)}</span>\n : <span className=\"text-xs text-muted-foreground\">-</span>,\n },\n ], [\n memberLabels.table.active,\n memberLabels.table.name,\n memberLabels.table.roles,\n memberLabels.table.tags,\n memberLabels.table.updatedAt,\n memberLabels.table.user,\n ])\n\n React.useEffect(() => {\n if (!teamId) return\n const teamIdValue = teamId\n let cancelled = false\n async function loadTeam() {\n if (!cancelled) {\n setError(null)\n setIsNotFound(false)\n }\n try {\n const params = new URLSearchParams({ page: '1', pageSize: '1', ids: teamIdValue })\n const payload = await readApiResultOrThrow<TeamResponse>(\n `/api/staff/teams?${params.toString()}`,\n undefined,\n { errorMessage: t('staff.teams.errors.load', 'Failed to load team.') },\n )\n const record = Array.isArray(payload.items) ? payload.items[0] : null\n if (!record) {\n if (!cancelled) setIsNotFound(true)\n return\n }\n const customFields = extractCustomFieldEntries(record)\n const isActive = typeof record.isActive === 'boolean'\n ? record.isActive\n : typeof record.is_active === 'boolean'\n ? record.is_active\n : true\n if (!cancelled) {\n setInitialValues({\n id: record.id,\n name: record.name ?? '',\n description: record.description ?? '',\n isActive,\n updatedAt: typeof record.updatedAt === 'string'\n ? record.updatedAt\n : typeof record.updated_at === 'string'\n ? record.updated_at\n : null,\n ...customFields,\n })\n }\n } catch (err) {\n if (!cancelled) {\n if ((err as { status?: number }).status === 404) {\n setIsNotFound(true)\n } else {\n const message = err instanceof Error ? err.message : t('staff.teams.errors.load', 'Failed to load team.')\n setError(message)\n }\n }\n }\n }\n loadTeam()\n return () => { cancelled = true }\n }, [teamId, t])\n\n React.useEffect(() => {\n if (!searchParams) return\n const tabParam = searchParams.get('tab')\n if (tabParam === 'members') {\n setActiveTab('members')\n }\n }, [searchParams])\n\n const loadTeamMembers = React.useCallback(async () => {\n if (!teamId) return\n setMembersLoading(true)\n try {\n const params = new URLSearchParams({\n page: String(memberPage),\n pageSize: String(TEAM_MEMBERS_PAGE_SIZE),\n teamId,\n })\n const sort = memberSorting[0]\n if (sort?.id) {\n params.set('sortField', sort.id)\n params.set('sortDir', sort.desc ? 'desc' : 'asc')\n }\n if (memberSearch.trim()) params.set('search', memberSearch.trim())\n const payload = await readApiResultOrThrow<TeamMembersResponse>(\n `/api/staff/team-members?${params.toString()}`,\n undefined,\n { errorMessage: memberLabels.errors.load, fallback: { items: [], total: 0, totalPages: 1 } },\n )\n const items = Array.isArray(payload.items) ? payload.items : []\n setMemberRows(items.map(mapApiTeamMember))\n setMemberTotal(typeof payload.total === 'number' ? payload.total : items.length)\n setMemberTotalPages(\n typeof payload.totalPages === 'number'\n ? payload.totalPages\n : Math.max(1, Math.ceil(items.length / TEAM_MEMBERS_PAGE_SIZE)),\n )\n } catch (error) {\n logger.error('staff.teams.team-members.list', { err: error })\n flash(memberLabels.errors.load, 'error')\n } finally {\n setMembersLoading(false)\n }\n }, [memberLabels.errors.load, memberPage, memberSearch, memberSorting, teamId])\n\n React.useEffect(() => {\n if (activeTab !== 'members') return\n void loadTeamMembers()\n }, [activeTab, loadTeamMembers, memberReloadToken, scopeVersion])\n\n const handleMemberSearchChange = React.useCallback((value: string) => {\n setMemberSearch(value)\n setMemberPage(1)\n }, [])\n\n const handleMemberRefresh = React.useCallback(() => {\n setMemberReloadToken((token) => token + 1)\n }, [])\n\n const handleUnassignMember = React.useCallback(async (entry: TeamMemberRow) => {\n if (!teamId || entry.teamId !== teamId) return\n try {\n const headers = buildOptimisticLockHeader(entry.updatedAt)\n await withScopedApiRequestHeaders(headers, () => (\n updateCrud('staff/team-members', { id: entry.id, teamId: null }, { errorMessage: memberLabels.errors.unassign })\n ))\n flash(memberLabels.messages.unassigned, 'success')\n handleMemberRefresh()\n } catch (error) {\n logger.error('staff.teams.team-members.unassign', { err: error })\n flash(memberLabels.errors.unassign, 'error')\n }\n }, [handleMemberRefresh, memberLabels.errors.unassign, memberLabels.messages.unassigned, teamId])\n\n const handleSubmit = React.useCallback(async (values: TeamFormValues) => {\n if (!teamId) return\n const payload = buildTeamPayload(values, { id: teamId })\n await updateCrud('staff/teams', payload, {\n errorMessage: t('staff.teams.errors.save', 'Failed to save team.'),\n })\n flash(t('staff.teams.messages.saved', 'Team saved.'), 'success')\n }, [teamId, t])\n\n const handleDelete = React.useCallback(async () => {\n if (!teamId) return\n await deleteCrud('staff/teams', teamId, {\n errorMessage: t('staff.teams.errors.delete', 'Failed to delete team.'),\n })\n router.push('/backend/staff/teams')\n }, [teamId, router, t])\n\n // Publish page-load record context to the AppShell-owned `backend:record:current`\n // mount so the enterprise record_locks widget resolves `staff.team` + id explicitly.\n // The resourceKind mirrors the TeamForm `versionHistory` so the held lock matches\n // the save-time conflict surface for the same team.\n useSetCurrentRecordInjectionContext(\n buildRecordInjectionContext({\n resourceKind: 'staff.team',\n resourceId: teamId || null,\n updatedAt: initialValues?.updatedAt ?? null,\n data: initialValues as Record<string, unknown> | null,\n path: pathname,\n }),\n )\n\n if (isNotFound) {\n return (\n <Page>\n <PageBody>\n <RecordNotFoundState\n label={t('staff.teams.errors.notFound', 'Team not found.')}\n backHref=\"/backend/staff/teams\"\n backLabel={t('staff.teams.actions.backToList', 'Back to teams')}\n />\n </PageBody>\n </Page>\n )\n }\n\n if (error && !initialValues) {\n return (\n <Page>\n <PageBody>\n <ErrorMessage label={error} />\n </PageBody>\n </Page>\n )\n }\n\n return (\n <Page>\n <PageBody>\n <div className=\"space-y-6\">\n <Tabs\n value={activeTab}\n onValueChange={(value) => setActiveTab(value as 'details' | 'members')}\n variant=\"underline\"\n >\n <TabsList className=\"w-full flex-wrap\" aria-label={memberLabels.tabs.label}>\n {[\n { id: 'details', label: memberLabels.tabs.details },\n { id: 'members', label: memberLabels.tabs.members },\n ].map((tab) => (\n <TabsTrigger key={tab.id} value={tab.id}>\n {tab.label}\n </TabsTrigger>\n ))}\n </TabsList>\n </Tabs>\n\n {activeTab === 'details' ? (\n <TeamForm\n title={t('staff.teams.form.editTitle', 'Edit team')}\n backHref=\"/backend/staff/teams\"\n cancelHref=\"/backend/staff/teams\"\n initialValues={initialValues ?? { name: '', description: '', isActive: true }}\n onSubmit={handleSubmit}\n onDelete={handleDelete}\n isLoading={!initialValues}\n loadingMessage={t('staff.teams.form.loading', 'Loading team...')}\n extraActions={teamId ? (\n <SendObjectMessageDialog\n object={{\n entityModule: 'staff',\n entityType: 'team',\n entityId: teamId,\n previewData: { title: initialValues?.name ?? ''},\n }}\n viewHref={`/backend/staff/teams/${teamId}/edit`}\n />\n ) : undefined}\n />\n ) : (\n <DataTable<TeamMemberRow>\n title={memberLabels.title}\n data={memberRows}\n columns={memberColumns}\n isLoading={membersLoading}\n searchValue={memberSearch}\n onSearchChange={handleMemberSearchChange}\n searchPlaceholder={memberLabels.table.search}\n emptyState={<p className=\"py-8 text-center text-sm text-muted-foreground\">{memberLabels.table.empty}</p>}\n actions={(\n <Button asChild size=\"sm\">\n <Link href={`/backend/staff/team-members/create?teamId=${encodeURIComponent(teamId ?? '')}`}>\n <Plus className=\"mr-2 h-4 w-4\" aria-hidden />\n {memberLabels.actions.add}\n </Link>\n </Button>\n )}\n refreshButton={{\n label: memberLabels.actions.refresh,\n onRefresh: handleMemberRefresh,\n isRefreshing: membersLoading,\n }}\n sortable\n sorting={memberSorting}\n onSortingChange={setMemberSorting}\n pagination={{\n page: memberPage,\n pageSize: TEAM_MEMBERS_PAGE_SIZE,\n total: memberTotal,\n totalPages: memberTotalPages,\n onPageChange: setMemberPage,\n }}\n rowActions={(row) => (\n <RowActions\n items={[\n { id: 'edit', label: memberLabels.actions.edit, onSelect: () => { router.push(`/backend/staff/team-members/${row.id}`) } },\n { id: 'unassign', label: memberLabels.actions.unassign, onSelect: () => { void handleUnassignMember(row) } },\n ]}\n />\n )}\n />\n )}\n </div>\n </PageBody>\n </Page>\n )\n}\n\nfunction mapApiTeamMember(item: Record<string, unknown>): TeamMemberRow {\n const id = typeof item.id === 'string' ? item.id : ''\n const displayName = typeof item.displayName === 'string'\n ? item.displayName\n : typeof item.display_name === 'string'\n ? item.display_name\n : id\n const description = typeof item.description === 'string' && item.description.trim().length\n ? item.description.trim()\n : null\n const user = item.user && typeof item.user === 'object' ? item.user as { email?: unknown } : null\n const userEmail = user && typeof user.email === 'string' && user.email.length ? user.email : null\n const roleNames = Array.isArray(item.roleNames) ? item.roleNames.filter((value): value is string => typeof value === 'string') : []\n const tags = Array.isArray(item.tags) ? item.tags.filter((value): value is string => typeof value === 'string') : []\n const updatedAt = typeof item.updatedAt === 'string'\n ? item.updatedAt\n : typeof item.updated_at === 'string'\n ? item.updated_at\n : null\n const isActive = typeof item.isActive === 'boolean'\n ? item.isActive\n : typeof item.is_active === 'boolean'\n ? item.is_active\n : true\n const teamId = typeof item.teamId === 'string'\n ? item.teamId\n : typeof item.team_id === 'string'\n ? item.team_id\n : null\n return withDataTableNamespaces({\n id,\n displayName,\n description,\n userEmail,\n roleNames,\n tags,\n isActive,\n updatedAt,\n teamId,\n }, item)\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { usePathname, useRouter, useSearchParams } from 'next/navigation'\nimport type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'\nimport type { SortingState } from '@tanstack/react-table'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { ErrorMessage, RecordNotFoundState } from '@open-mercato/ui/backend/detail'\nimport { readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { updateCrud, deleteCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { DataTable, withDataTableNamespaces } from '@open-mercato/ui/backend/DataTable'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { Tabs, TabsList, TabsTrigger } from '@open-mercato/ui/primitives/tabs'\nimport { BooleanIcon } from '@open-mercato/ui/backend/ValueIcons'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { TeamForm, type TeamFormValues, buildTeamPayload } from '@open-mercato/core/modules/staff/components/TeamForm'\nimport { buildRecordInjectionContext, useSetCurrentRecordInjectionContext } from '@open-mercato/ui/backend/injection/recordContext'\nimport { SendObjectMessageDialog } from '@open-mercato/ui/backend/messages'\nimport { extractCustomFieldEntries } from '@open-mercato/shared/lib/crud/custom-fields-client'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { Plus } from 'lucide-react'\nimport { formatDateTime } from '@open-mercato/shared/lib/time'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('staff')\n\nconst TEAM_MEMBERS_PAGE_SIZE = 50\n\ntype TeamRecord = {\n id: string\n name: string\n description?: string | null\n isActive?: boolean\n is_active?: boolean\n updatedAt?: string | null\n updated_at?: string | null\n} & Record<string, unknown>\n\ntype TeamResponse = {\n items?: TeamRecord[]\n}\n\ntype TeamMemberRow = {\n id: string\n displayName: string\n description: string | null\n userEmail: string | null\n roleNames: string[]\n tags: string[]\n isActive: boolean\n updatedAt: string | null\n teamId: string | null\n}\n\ntype TeamMembersResponse = {\n items?: Array<Record<string, unknown>>\n total?: number\n totalPages?: number\n totalIsCapped?: boolean\n}\n\nexport default function StaffTeamEditPage({ params }: { params?: { id?: string } }) {\n const teamId = params?.id\n const t = useT()\n const router = useRouter()\n const pathname = usePathname()\n const searchParams = useSearchParams()\n const scopeVersion = useOrganizationScopeVersion()\n const [initialValues, setInitialValues] = React.useState<TeamFormValues | null>(null)\n const [error, setError] = React.useState<string | null>(null)\n const [isNotFound, setIsNotFound] = React.useState(false)\n const [activeTab, setActiveTab] = React.useState<'details' | 'members'>('details')\n const [memberRows, setMemberRows] = React.useState<TeamMemberRow[]>([])\n const [memberPage, setMemberPage] = React.useState(1)\n const [memberTotal, setMemberTotal] = React.useState(0)\n const [memberTotalIsCapped, setMemberTotalIsCapped] = React.useState(false)\n const [memberTotalPages, setMemberTotalPages] = React.useState(1)\n const [memberSorting, setMemberSorting] = React.useState<SortingState>([{ id: 'displayName', desc: false }])\n const [memberSearch, setMemberSearch] = React.useState('')\n const [membersLoading, setMembersLoading] = React.useState(false)\n const [memberReloadToken, setMemberReloadToken] = React.useState(0)\n\n const memberLabels = React.useMemo(() => ({\n title: t('staff.teams.tabs.members', 'Team members'),\n description: t('staff.teamMembers.page.description', 'Manage employees and their team assignments.'),\n table: {\n name: t('staff.teamMembers.table.name', 'Name'),\n user: t('staff.teamMembers.table.user', 'User'),\n roles: t('staff.teamMembers.table.roles', 'Roles'),\n tags: t('staff.teamMembers.table.tags', 'Tags'),\n active: t('staff.teamMembers.table.active', 'Active'),\n updatedAt: t('staff.teamMembers.table.updatedAt', 'Updated'),\n empty: t('staff.teamMembers.table.empty', 'No team members yet.'),\n search: t('staff.teamMembers.table.search', 'Search team members...'),\n },\n actions: {\n add: t('staff.teamMembers.actions.add', 'Add team member'),\n edit: t('staff.teamMembers.actions.edit', 'Edit'),\n unassign: t('staff.teamMembers.actions.unassign', 'Unassign'),\n refresh: t('staff.teamMembers.actions.refresh', 'Refresh'),\n },\n messages: {\n unassigned: t('staff.teamMembers.messages.unassigned', 'Team member unassigned.'),\n },\n errors: {\n load: t('staff.teamMembers.errors.load', 'Failed to load team members.'),\n unassign: t('staff.teamMembers.errors.unassign', 'Failed to unassign team member.'),\n },\n tabs: {\n details: t('staff.teams.tabs.details', 'Details'),\n members: t('staff.teams.tabs.members', 'Team members'),\n label: t('staff.teams.tabs.label', 'Team sections'),\n },\n }), [t])\n\n const memberColumns = React.useMemo<ColumnDef<TeamMemberRow>[]>(() => [\n {\n accessorKey: 'displayName',\n header: memberLabels.table.name,\n meta: { priority: 1, sticky: true },\n cell: ({ row }) => (\n <div className=\"flex flex-col\">\n <span className=\"font-medium\">{row.original.displayName}</span>\n {row.original.description ? (\n <span className=\"text-xs text-muted-foreground line-clamp-2\">{row.original.description}</span>\n ) : null}\n </div>\n ),\n },\n {\n accessorKey: 'userEmail',\n header: memberLabels.table.user,\n meta: { priority: 2 },\n cell: ({ row }) => row.original.userEmail\n ? <span className=\"text-sm\">{row.original.userEmail}</span>\n : <span className=\"text-xs text-muted-foreground\">-</span>,\n },\n {\n accessorKey: 'roleNames',\n header: memberLabels.table.roles,\n meta: { priority: 3 },\n cell: ({ row }) => row.original.roleNames.length\n ? <span className=\"text-sm\">{row.original.roleNames.join(', ')}</span>\n : <span className=\"text-xs text-muted-foreground\">-</span>,\n },\n {\n accessorKey: 'tags',\n header: memberLabels.table.tags,\n meta: { priority: 4 },\n cell: ({ row }) => row.original.tags.length\n ? <span className=\"text-xs text-muted-foreground\">{row.original.tags.join(', ')}</span>\n : <span className=\"text-xs text-muted-foreground\">-</span>,\n },\n {\n accessorKey: 'isActive',\n header: memberLabels.table.active,\n meta: { priority: 5 },\n cell: ({ row }) => <BooleanIcon value={row.original.isActive} />,\n },\n {\n accessorKey: 'updatedAt',\n header: memberLabels.table.updatedAt,\n meta: { priority: 6 },\n cell: ({ row }) => row.original.updatedAt\n ? <span className=\"text-xs text-muted-foreground\">{formatDateTime(row.original.updatedAt)}</span>\n : <span className=\"text-xs text-muted-foreground\">-</span>,\n },\n ], [\n memberLabels.table.active,\n memberLabels.table.name,\n memberLabels.table.roles,\n memberLabels.table.tags,\n memberLabels.table.updatedAt,\n memberLabels.table.user,\n ])\n\n React.useEffect(() => {\n if (!teamId) return\n const teamIdValue = teamId\n let cancelled = false\n async function loadTeam() {\n if (!cancelled) {\n setError(null)\n setIsNotFound(false)\n }\n try {\n const params = new URLSearchParams({ page: '1', pageSize: '1', ids: teamIdValue })\n const payload = await readApiResultOrThrow<TeamResponse>(\n `/api/staff/teams?${params.toString()}`,\n undefined,\n { errorMessage: t('staff.teams.errors.load', 'Failed to load team.') },\n )\n const record = Array.isArray(payload.items) ? payload.items[0] : null\n if (!record) {\n if (!cancelled) setIsNotFound(true)\n return\n }\n const customFields = extractCustomFieldEntries(record)\n const isActive = typeof record.isActive === 'boolean'\n ? record.isActive\n : typeof record.is_active === 'boolean'\n ? record.is_active\n : true\n if (!cancelled) {\n setInitialValues({\n id: record.id,\n name: record.name ?? '',\n description: record.description ?? '',\n isActive,\n updatedAt: typeof record.updatedAt === 'string'\n ? record.updatedAt\n : typeof record.updated_at === 'string'\n ? record.updated_at\n : null,\n ...customFields,\n })\n }\n } catch (err) {\n if (!cancelled) {\n if ((err as { status?: number }).status === 404) {\n setIsNotFound(true)\n } else {\n const message = err instanceof Error ? err.message : t('staff.teams.errors.load', 'Failed to load team.')\n setError(message)\n }\n }\n }\n }\n loadTeam()\n return () => { cancelled = true }\n }, [teamId, t])\n\n React.useEffect(() => {\n if (!searchParams) return\n const tabParam = searchParams.get('tab')\n if (tabParam === 'members') {\n setActiveTab('members')\n }\n }, [searchParams])\n\n const loadTeamMembers = React.useCallback(async () => {\n if (!teamId) return\n setMembersLoading(true)\n try {\n const params = new URLSearchParams({\n page: String(memberPage),\n pageSize: String(TEAM_MEMBERS_PAGE_SIZE),\n teamId,\n })\n const sort = memberSorting[0]\n if (sort?.id) {\n params.set('sortField', sort.id)\n params.set('sortDir', sort.desc ? 'desc' : 'asc')\n }\n if (memberSearch.trim()) params.set('search', memberSearch.trim())\n const payload = await readApiResultOrThrow<TeamMembersResponse>(\n `/api/staff/team-members?${params.toString()}`,\n undefined,\n { errorMessage: memberLabels.errors.load, fallback: { items: [], total: 0, totalPages: 1 } },\n )\n const items = Array.isArray(payload.items) ? payload.items : []\n setMemberRows(items.map(mapApiTeamMember))\n setMemberTotal(typeof payload.total === 'number' ? payload.total : items.length)\n setMemberTotalIsCapped(payload.totalIsCapped === true)\n setMemberTotalPages(\n typeof payload.totalPages === 'number'\n ? payload.totalPages\n : Math.max(1, Math.ceil(items.length / TEAM_MEMBERS_PAGE_SIZE)),\n )\n } catch (error) {\n logger.error('staff.teams.team-members.list', { err: error })\n flash(memberLabels.errors.load, 'error')\n } finally {\n setMembersLoading(false)\n }\n }, [memberLabels.errors.load, memberPage, memberSearch, memberSorting, teamId])\n\n React.useEffect(() => {\n if (activeTab !== 'members') return\n void loadTeamMembers()\n }, [activeTab, loadTeamMembers, memberReloadToken, scopeVersion])\n\n const handleMemberSearchChange = React.useCallback((value: string) => {\n setMemberSearch(value)\n setMemberPage(1)\n }, [])\n\n const handleMemberRefresh = React.useCallback(() => {\n setMemberReloadToken((token) => token + 1)\n }, [])\n\n const handleUnassignMember = React.useCallback(async (entry: TeamMemberRow) => {\n if (!teamId || entry.teamId !== teamId) return\n try {\n const headers = buildOptimisticLockHeader(entry.updatedAt)\n await withScopedApiRequestHeaders(headers, () => (\n updateCrud('staff/team-members', { id: entry.id, teamId: null }, { errorMessage: memberLabels.errors.unassign })\n ))\n flash(memberLabels.messages.unassigned, 'success')\n handleMemberRefresh()\n } catch (error) {\n logger.error('staff.teams.team-members.unassign', { err: error })\n flash(memberLabels.errors.unassign, 'error')\n }\n }, [handleMemberRefresh, memberLabels.errors.unassign, memberLabels.messages.unassigned, teamId])\n\n const handleSubmit = React.useCallback(async (values: TeamFormValues) => {\n if (!teamId) return\n const payload = buildTeamPayload(values, { id: teamId })\n await updateCrud('staff/teams', payload, {\n errorMessage: t('staff.teams.errors.save', 'Failed to save team.'),\n })\n flash(t('staff.teams.messages.saved', 'Team saved.'), 'success')\n }, [teamId, t])\n\n const handleDelete = React.useCallback(async () => {\n if (!teamId) return\n await deleteCrud('staff/teams', teamId, {\n errorMessage: t('staff.teams.errors.delete', 'Failed to delete team.'),\n })\n router.push('/backend/staff/teams')\n }, [teamId, router, t])\n\n // Publish page-load record context to the AppShell-owned `backend:record:current`\n // mount so the enterprise record_locks widget resolves `staff.team` + id explicitly.\n // The resourceKind mirrors the TeamForm `versionHistory` so the held lock matches\n // the save-time conflict surface for the same team.\n useSetCurrentRecordInjectionContext(\n buildRecordInjectionContext({\n resourceKind: 'staff.team',\n resourceId: teamId || null,\n updatedAt: initialValues?.updatedAt ?? null,\n data: initialValues as Record<string, unknown> | null,\n path: pathname,\n }),\n )\n\n if (isNotFound) {\n return (\n <Page>\n <PageBody>\n <RecordNotFoundState\n label={t('staff.teams.errors.notFound', 'Team not found.')}\n backHref=\"/backend/staff/teams\"\n backLabel={t('staff.teams.actions.backToList', 'Back to teams')}\n />\n </PageBody>\n </Page>\n )\n }\n\n if (error && !initialValues) {\n return (\n <Page>\n <PageBody>\n <ErrorMessage label={error} />\n </PageBody>\n </Page>\n )\n }\n\n return (\n <Page>\n <PageBody>\n <div className=\"space-y-6\">\n <Tabs\n value={activeTab}\n onValueChange={(value) => setActiveTab(value as 'details' | 'members')}\n variant=\"underline\"\n >\n <TabsList className=\"w-full flex-wrap\" aria-label={memberLabels.tabs.label}>\n {[\n { id: 'details', label: memberLabels.tabs.details },\n { id: 'members', label: memberLabels.tabs.members },\n ].map((tab) => (\n <TabsTrigger key={tab.id} value={tab.id}>\n {tab.label}\n </TabsTrigger>\n ))}\n </TabsList>\n </Tabs>\n\n {activeTab === 'details' ? (\n <TeamForm\n title={t('staff.teams.form.editTitle', 'Edit team')}\n backHref=\"/backend/staff/teams\"\n cancelHref=\"/backend/staff/teams\"\n initialValues={initialValues ?? { name: '', description: '', isActive: true }}\n onSubmit={handleSubmit}\n onDelete={handleDelete}\n isLoading={!initialValues}\n loadingMessage={t('staff.teams.form.loading', 'Loading team...')}\n extraActions={teamId ? (\n <SendObjectMessageDialog\n object={{\n entityModule: 'staff',\n entityType: 'team',\n entityId: teamId,\n previewData: { title: initialValues?.name ?? ''},\n }}\n viewHref={`/backend/staff/teams/${teamId}/edit`}\n />\n ) : undefined}\n />\n ) : (\n <DataTable<TeamMemberRow>\n title={memberLabels.title}\n data={memberRows}\n columns={memberColumns}\n isLoading={membersLoading}\n searchValue={memberSearch}\n onSearchChange={handleMemberSearchChange}\n searchPlaceholder={memberLabels.table.search}\n emptyState={<p className=\"py-8 text-center text-sm text-muted-foreground\">{memberLabels.table.empty}</p>}\n actions={(\n <Button asChild size=\"sm\">\n <Link href={`/backend/staff/team-members/create?teamId=${encodeURIComponent(teamId ?? '')}`}>\n <Plus className=\"mr-2 h-4 w-4\" aria-hidden />\n {memberLabels.actions.add}\n </Link>\n </Button>\n )}\n refreshButton={{\n label: memberLabels.actions.refresh,\n onRefresh: handleMemberRefresh,\n isRefreshing: membersLoading,\n }}\n sortable\n sorting={memberSorting}\n onSortingChange={setMemberSorting}\n pagination={{\n page: memberPage,\n pageSize: TEAM_MEMBERS_PAGE_SIZE,\n total: memberTotal,\n totalPages: memberTotalPages,\n totalIsCapped: memberTotalIsCapped,\n onPageChange: setMemberPage,\n }}\n rowActions={(row) => (\n <RowActions\n items={[\n { id: 'edit', label: memberLabels.actions.edit, onSelect: () => { router.push(`/backend/staff/team-members/${row.id}`) } },\n { id: 'unassign', label: memberLabels.actions.unassign, onSelect: () => { void handleUnassignMember(row) } },\n ]}\n />\n )}\n />\n )}\n </div>\n </PageBody>\n </Page>\n )\n}\n\nfunction mapApiTeamMember(item: Record<string, unknown>): TeamMemberRow {\n const id = typeof item.id === 'string' ? item.id : ''\n const displayName = typeof item.displayName === 'string'\n ? item.displayName\n : typeof item.display_name === 'string'\n ? item.display_name\n : id\n const description = typeof item.description === 'string' && item.description.trim().length\n ? item.description.trim()\n : null\n const user = item.user && typeof item.user === 'object' ? item.user as { email?: unknown } : null\n const userEmail = user && typeof user.email === 'string' && user.email.length ? user.email : null\n const roleNames = Array.isArray(item.roleNames) ? item.roleNames.filter((value): value is string => typeof value === 'string') : []\n const tags = Array.isArray(item.tags) ? item.tags.filter((value): value is string => typeof value === 'string') : []\n const updatedAt = typeof item.updatedAt === 'string'\n ? item.updatedAt\n : typeof item.updated_at === 'string'\n ? item.updated_at\n : null\n const isActive = typeof item.isActive === 'boolean'\n ? item.isActive\n : typeof item.is_active === 'boolean'\n ? item.is_active\n : true\n const teamId = typeof item.teamId === 'string'\n ? item.teamId\n : typeof item.team_id === 'string'\n ? item.team_id\n : null\n return withDataTableNamespaces({\n id,\n displayName,\n description,\n userEmail,\n roleNames,\n tags,\n isActive,\n updatedAt,\n teamId,\n }, item)\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["params", "error"]
7
7
  }
@@ -32,6 +32,7 @@ function StaffTeamsPage() {
32
32
  const [page, setPage] = React.useState(1);
33
33
  const [total, setTotal] = React.useState(0);
34
34
  const [totalPages, setTotalPages] = React.useState(1);
35
+ const [totalIsCapped, setTotalIsCapped] = React.useState(false);
35
36
  const [sorting, setSorting] = React.useState([{ id: "name", desc: false }]);
36
37
  const [search, setSearch] = React.useState("");
37
38
  const [isLoading, setIsLoading] = React.useState(true);
@@ -141,6 +142,7 @@ function StaffTeamsPage() {
141
142
  setRows(items.map(mapApiTeam));
142
143
  setTotal(typeof payload.total === "number" ? payload.total : items.length);
143
144
  setTotalPages(typeof payload.totalPages === "number" ? payload.totalPages : Math.max(1, Math.ceil(items.length / PAGE_SIZE)));
145
+ setTotalIsCapped(payload?.totalIsCapped === true);
144
146
  } catch (error) {
145
147
  logger.error("staff.teams.list", { err: error });
146
148
  flash(labels.errors.load, "error");
@@ -219,6 +221,7 @@ function StaffTeamsPage() {
219
221
  pageSize: PAGE_SIZE,
220
222
  total,
221
223
  totalPages,
224
+ totalIsCapped,
222
225
  onPageChange: setPage
223
226
  },
224
227
  rowActions: (row) => /* @__PURE__ */ jsx(
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/modules/staff/backend/staff/teams/page.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useRouter } from 'next/navigation'\nimport type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'\nimport type { SortingState } from '@tanstack/react-table'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable, withDataTableNamespaces } from '@open-mercato/ui/backend/DataTable'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { markdownToPlainText } from '@open-mercato/ui/backend/markdown/markdownToPlainText'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { BooleanIcon } from '@open-mercato/ui/backend/ValueIcons'\nimport { readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'\nimport { deleteCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { ListEmptyState } from '@open-mercato/ui/backend/filters/ListEmptyState'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Users } from 'lucide-react'\nimport { formatDateTime } from '@open-mercato/shared/lib/time'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('staff')\n\nconst PAGE_SIZE = 50\n\ntype TeamRow = {\n id: string\n name: string\n description: string | null\n isActive: boolean\n updatedAt: string | null\n memberCount: number\n}\n\ntype TeamsResponse = {\n items?: Array<Record<string, unknown>>\n total?: number\n totalPages?: number\n}\n\nexport default function StaffTeamsPage() {\n const t = useT()\n const router = useRouter()\n const scopeVersion = useOrganizationScopeVersion()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const [rows, setRows] = React.useState<TeamRow[]>([])\n const [page, setPage] = React.useState(1)\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const [sorting, setSorting] = React.useState<SortingState>([{ id: 'name', desc: false }])\n const [search, setSearch] = React.useState('')\n const [isLoading, setIsLoading] = React.useState(true)\n const [reloadToken, setReloadToken] = React.useState(0)\n\n const labels = React.useMemo(() => ({\n title: t('staff.teams.page.title', 'Teams'),\n description: t('staff.teams.page.description', 'Group team members and roles.'),\n table: {\n name: t('staff.teams.table.name', 'Name'),\n description: t('staff.teams.table.description', 'Description'),\n active: t('staff.teams.table.active', 'Active'),\n members: t('staff.teams.table.members', 'Team members'),\n updatedAt: t('staff.teams.table.updatedAt', 'Updated'),\n empty: t('staff.teams.table.empty', 'No teams yet.'),\n search: t('staff.teams.table.search', 'Search teams...'),\n },\n actions: {\n add: t('staff.teams.actions.add', 'Add team'),\n edit: t('staff.teams.actions.edit', 'Edit'),\n delete: t('staff.teams.actions.delete', 'Delete'),\n deleteConfirm: t('staff.teams.actions.deleteConfirm', 'Delete team \"{{name}}\"?'),\n showMembers: t('staff.teams.actions.showMembers', 'Show team members ({{count}})'),\n refresh: t('staff.teams.actions.refresh', 'Refresh'),\n },\n messages: {\n deleted: t('staff.teams.messages.deleted', 'Team deleted.'),\n },\n errors: {\n load: t('staff.teams.errors.load', 'Failed to load teams.'),\n delete: t('staff.teams.errors.delete', 'Failed to delete team.'),\n deleteAssigned: t('staff.teams.errors.deleteAssigned', 'Team has assigned members and cannot be deleted.'),\n },\n }), [t])\n\n const columns = React.useMemo<ColumnDef<TeamRow>[]>(() => [\n {\n accessorKey: 'name',\n header: labels.table.name,\n meta: { priority: 1, sticky: true },\n cell: ({ row }) => (\n <div className=\"flex flex-col\">\n <span className=\"font-medium\">{row.original.name}</span>\n {row.original.description ? (\n <span className=\"text-xs text-muted-foreground line-clamp-2\">\n {markdownToPlainText(row.original.description)}\n </span>\n ) : null}\n </div>\n ),\n },\n {\n accessorKey: 'description',\n header: labels.table.description,\n meta: { priority: 4 },\n cell: ({ row }) => row.original.description\n ? (\n <span className=\"text-xs text-muted-foreground line-clamp-2\">\n {markdownToPlainText(row.original.description)}\n </span>\n )\n : <span className=\"text-xs text-muted-foreground\">-</span>,\n },\n {\n accessorKey: 'isActive',\n header: labels.table.active,\n meta: { priority: 2 },\n cell: ({ row }) => <BooleanIcon value={row.original.isActive} />,\n },\n {\n accessorKey: 'memberCount',\n header: () => <span className=\"inline-block min-w-[250px]\">{labels.table.members}</span>,\n meta: { priority: 3 },\n enableSorting: false,\n cell: ({ row }) => (\n <Link\n className=\"inline-flex min-w-[220px] items-center gap-2 text-sm text-muted-foreground hover:text-foreground\"\n href={`/backend/staff/team-members?teamId=${encodeURIComponent(row.original.id)}`}\n onClick={(event) => event.stopPropagation()}\n >\n <Users className=\"h-4 w-4\" aria-hidden />\n {labels.actions.showMembers.replace('{{count}}', String(row.original.memberCount))}\n </Link>\n ),\n },\n {\n accessorKey: 'updatedAt',\n header: labels.table.updatedAt,\n meta: { priority: 5 },\n cell: ({ row }) => row.original.updatedAt\n ? <span className=\"text-xs text-muted-foreground\">{formatDateTime(row.original.updatedAt)}</span>\n : <span className=\"text-xs text-muted-foreground\">-</span>,\n },\n ], [\n labels.actions.showMembers,\n labels.table.active,\n labels.table.description,\n labels.table.members,\n labels.table.name,\n labels.table.updatedAt,\n ])\n\n const loadTeams = React.useCallback(async () => {\n setIsLoading(true)\n try {\n const params = new URLSearchParams({\n page: String(page),\n pageSize: String(PAGE_SIZE),\n })\n const sort = sorting[0]\n if (sort?.id) {\n params.set('sortField', sort.id)\n params.set('sortDir', sort.desc ? 'desc' : 'asc')\n }\n if (search.trim()) params.set('search', search.trim())\n const payload = await readApiResultOrThrow<TeamsResponse>(\n `/api/staff/teams?${params.toString()}`,\n undefined,\n { errorMessage: labels.errors.load, fallback: { items: [], total: 0, totalPages: 1 } },\n )\n const items = Array.isArray(payload.items) ? payload.items : []\n setRows(items.map(mapApiTeam))\n setTotal(typeof payload.total === 'number' ? payload.total : items.length)\n setTotalPages(typeof payload.totalPages === 'number' ? payload.totalPages : Math.max(1, Math.ceil(items.length / PAGE_SIZE)))\n } catch (error) {\n logger.error('staff.teams.list', { err: error })\n flash(labels.errors.load, 'error')\n } finally {\n setIsLoading(false)\n }\n }, [labels.errors.load, page, search, sorting])\n\n React.useEffect(() => {\n void loadTeams()\n }, [loadTeams, scopeVersion, reloadToken])\n\n const handleSearchChange = React.useCallback((value: string) => {\n setSearch(value)\n setPage(1)\n }, [])\n\n const handleRefresh = React.useCallback(() => {\n setReloadToken((token) => token + 1)\n }, [])\n\n const handleDelete = React.useCallback(async (entry: TeamRow) => {\n if (entry.memberCount > 0) {\n flash(labels.errors.deleteAssigned, 'error')\n return\n }\n const message = labels.actions.deleteConfirm.replace('{{name}}', entry.name)\n const confirmed = await confirm({\n title: labels.actions.delete,\n text: message,\n variant: 'destructive',\n })\n if (!confirmed) return\n try {\n await withScopedApiRequestHeaders(\n buildOptimisticLockHeader(entry.updatedAt),\n () => deleteCrud('staff/teams', entry.id, { errorMessage: labels.errors.delete }),\n )\n flash(labels.messages.deleted, 'success')\n handleRefresh()\n } catch (error) {\n if (surfaceRecordConflict(error, t)) { handleRefresh(); return }\n logger.error('staff.teams.delete', { err: error })\n flash(labels.errors.delete, 'error')\n }\n }, [confirm, handleRefresh, labels.actions.deleteConfirm, labels.actions.delete, labels.errors.delete, labels.errors.deleteAssigned, labels.messages.deleted, t])\n\n return (\n <Page>\n <PageBody>\n <DataTable<TeamRow>\n title={labels.title}\n data={rows}\n columns={columns}\n isLoading={isLoading}\n searchValue={search}\n onSearchChange={handleSearchChange}\n searchPlaceholder={labels.table.search}\n emptyState={(\n <ListEmptyState\n entityName={labels.title}\n createHref=\"/backend/staff/teams/create\"\n createLabel={labels.actions.add}\n />\n )}\n actions={(\n <Button asChild size=\"sm\">\n <Link href=\"/backend/staff/teams/create\">\n {labels.actions.add}\n </Link>\n </Button>\n )}\n refreshButton={{\n label: labels.actions.refresh,\n onRefresh: handleRefresh,\n isRefreshing: isLoading,\n }}\n sortable\n sorting={sorting}\n onSortingChange={setSorting}\n pagination={{\n page,\n pageSize: PAGE_SIZE,\n total,\n totalPages,\n onPageChange: setPage,\n }}\n rowActions={(row) => (\n <RowActions\n items={[\n { id: 'edit', label: labels.actions.edit, href: `/backend/staff/teams/${row.id}/edit` },\n ...(row.memberCount > 0\n ? []\n : [{ id: 'delete', label: labels.actions.delete, destructive: true, onSelect: () => { void handleDelete(row) } }]),\n ]}\n />\n )}\n onRowClick={(row) => router.push(`/backend/staff/teams/${row.id}/edit`)}\n />\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n}\n\nfunction mapApiTeam(item: Record<string, unknown>): TeamRow {\n const id = typeof item.id === 'string' ? item.id : ''\n const name = typeof item.name === 'string' ? item.name : id\n const description = typeof item.description === 'string' && item.description.trim().length ? item.description.trim() : null\n const updatedAt = typeof item.updatedAt === 'string'\n ? item.updatedAt\n : typeof item.updated_at === 'string'\n ? item.updated_at\n : null\n const isActive = typeof item.isActive === 'boolean'\n ? item.isActive\n : typeof item.is_active === 'boolean'\n ? item.is_active\n : true\n const memberCount = typeof item.memberCount === 'number'\n ? item.memberCount\n : typeof item.member_count === 'number'\n ? item.member_count\n : 0\n return withDataTableNamespaces({ id, name, description, isActive, updatedAt, memberCount }, item)\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useRouter } from 'next/navigation'\nimport type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'\nimport type { SortingState } from '@tanstack/react-table'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable, withDataTableNamespaces } from '@open-mercato/ui/backend/DataTable'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { markdownToPlainText } from '@open-mercato/ui/backend/markdown/markdownToPlainText'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { BooleanIcon } from '@open-mercato/ui/backend/ValueIcons'\nimport { readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'\nimport { deleteCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { ListEmptyState } from '@open-mercato/ui/backend/filters/ListEmptyState'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Users } from 'lucide-react'\nimport { formatDateTime } from '@open-mercato/shared/lib/time'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('staff')\n\nconst PAGE_SIZE = 50\n\ntype TeamRow = {\n id: string\n name: string\n description: string | null\n isActive: boolean\n updatedAt: string | null\n memberCount: number\n}\n\ntype TeamsResponse = {\n items?: Array<Record<string, unknown>>\n total?: number\n totalPages?: number\n totalIsCapped?: boolean\n}\n\nexport default function StaffTeamsPage() {\n const t = useT()\n const router = useRouter()\n const scopeVersion = useOrganizationScopeVersion()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const [rows, setRows] = React.useState<TeamRow[]>([])\n const [page, setPage] = React.useState(1)\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const [totalIsCapped, setTotalIsCapped] = React.useState(false)\n const [sorting, setSorting] = React.useState<SortingState>([{ id: 'name', desc: false }])\n const [search, setSearch] = React.useState('')\n const [isLoading, setIsLoading] = React.useState(true)\n const [reloadToken, setReloadToken] = React.useState(0)\n\n const labels = React.useMemo(() => ({\n title: t('staff.teams.page.title', 'Teams'),\n description: t('staff.teams.page.description', 'Group team members and roles.'),\n table: {\n name: t('staff.teams.table.name', 'Name'),\n description: t('staff.teams.table.description', 'Description'),\n active: t('staff.teams.table.active', 'Active'),\n members: t('staff.teams.table.members', 'Team members'),\n updatedAt: t('staff.teams.table.updatedAt', 'Updated'),\n empty: t('staff.teams.table.empty', 'No teams yet.'),\n search: t('staff.teams.table.search', 'Search teams...'),\n },\n actions: {\n add: t('staff.teams.actions.add', 'Add team'),\n edit: t('staff.teams.actions.edit', 'Edit'),\n delete: t('staff.teams.actions.delete', 'Delete'),\n deleteConfirm: t('staff.teams.actions.deleteConfirm', 'Delete team \"{{name}}\"?'),\n showMembers: t('staff.teams.actions.showMembers', 'Show team members ({{count}})'),\n refresh: t('staff.teams.actions.refresh', 'Refresh'),\n },\n messages: {\n deleted: t('staff.teams.messages.deleted', 'Team deleted.'),\n },\n errors: {\n load: t('staff.teams.errors.load', 'Failed to load teams.'),\n delete: t('staff.teams.errors.delete', 'Failed to delete team.'),\n deleteAssigned: t('staff.teams.errors.deleteAssigned', 'Team has assigned members and cannot be deleted.'),\n },\n }), [t])\n\n const columns = React.useMemo<ColumnDef<TeamRow>[]>(() => [\n {\n accessorKey: 'name',\n header: labels.table.name,\n meta: { priority: 1, sticky: true },\n cell: ({ row }) => (\n <div className=\"flex flex-col\">\n <span className=\"font-medium\">{row.original.name}</span>\n {row.original.description ? (\n <span className=\"text-xs text-muted-foreground line-clamp-2\">\n {markdownToPlainText(row.original.description)}\n </span>\n ) : null}\n </div>\n ),\n },\n {\n accessorKey: 'description',\n header: labels.table.description,\n meta: { priority: 4 },\n cell: ({ row }) => row.original.description\n ? (\n <span className=\"text-xs text-muted-foreground line-clamp-2\">\n {markdownToPlainText(row.original.description)}\n </span>\n )\n : <span className=\"text-xs text-muted-foreground\">-</span>,\n },\n {\n accessorKey: 'isActive',\n header: labels.table.active,\n meta: { priority: 2 },\n cell: ({ row }) => <BooleanIcon value={row.original.isActive} />,\n },\n {\n accessorKey: 'memberCount',\n header: () => <span className=\"inline-block min-w-[250px]\">{labels.table.members}</span>,\n meta: { priority: 3 },\n enableSorting: false,\n cell: ({ row }) => (\n <Link\n className=\"inline-flex min-w-[220px] items-center gap-2 text-sm text-muted-foreground hover:text-foreground\"\n href={`/backend/staff/team-members?teamId=${encodeURIComponent(row.original.id)}`}\n onClick={(event) => event.stopPropagation()}\n >\n <Users className=\"h-4 w-4\" aria-hidden />\n {labels.actions.showMembers.replace('{{count}}', String(row.original.memberCount))}\n </Link>\n ),\n },\n {\n accessorKey: 'updatedAt',\n header: labels.table.updatedAt,\n meta: { priority: 5 },\n cell: ({ row }) => row.original.updatedAt\n ? <span className=\"text-xs text-muted-foreground\">{formatDateTime(row.original.updatedAt)}</span>\n : <span className=\"text-xs text-muted-foreground\">-</span>,\n },\n ], [\n labels.actions.showMembers,\n labels.table.active,\n labels.table.description,\n labels.table.members,\n labels.table.name,\n labels.table.updatedAt,\n ])\n\n const loadTeams = React.useCallback(async () => {\n setIsLoading(true)\n try {\n const params = new URLSearchParams({\n page: String(page),\n pageSize: String(PAGE_SIZE),\n })\n const sort = sorting[0]\n if (sort?.id) {\n params.set('sortField', sort.id)\n params.set('sortDir', sort.desc ? 'desc' : 'asc')\n }\n if (search.trim()) params.set('search', search.trim())\n const payload = await readApiResultOrThrow<TeamsResponse>(\n `/api/staff/teams?${params.toString()}`,\n undefined,\n { errorMessage: labels.errors.load, fallback: { items: [], total: 0, totalPages: 1 } },\n )\n const items = Array.isArray(payload.items) ? payload.items : []\n setRows(items.map(mapApiTeam))\n setTotal(typeof payload.total === 'number' ? payload.total : items.length)\n setTotalPages(typeof payload.totalPages === 'number' ? payload.totalPages : Math.max(1, Math.ceil(items.length / PAGE_SIZE)))\n setTotalIsCapped(payload?.totalIsCapped === true)\n } catch (error) {\n logger.error('staff.teams.list', { err: error })\n flash(labels.errors.load, 'error')\n } finally {\n setIsLoading(false)\n }\n }, [labels.errors.load, page, search, sorting])\n\n React.useEffect(() => {\n void loadTeams()\n }, [loadTeams, scopeVersion, reloadToken])\n\n const handleSearchChange = React.useCallback((value: string) => {\n setSearch(value)\n setPage(1)\n }, [])\n\n const handleRefresh = React.useCallback(() => {\n setReloadToken((token) => token + 1)\n }, [])\n\n const handleDelete = React.useCallback(async (entry: TeamRow) => {\n if (entry.memberCount > 0) {\n flash(labels.errors.deleteAssigned, 'error')\n return\n }\n const message = labels.actions.deleteConfirm.replace('{{name}}', entry.name)\n const confirmed = await confirm({\n title: labels.actions.delete,\n text: message,\n variant: 'destructive',\n })\n if (!confirmed) return\n try {\n await withScopedApiRequestHeaders(\n buildOptimisticLockHeader(entry.updatedAt),\n () => deleteCrud('staff/teams', entry.id, { errorMessage: labels.errors.delete }),\n )\n flash(labels.messages.deleted, 'success')\n handleRefresh()\n } catch (error) {\n if (surfaceRecordConflict(error, t)) { handleRefresh(); return }\n logger.error('staff.teams.delete', { err: error })\n flash(labels.errors.delete, 'error')\n }\n }, [confirm, handleRefresh, labels.actions.deleteConfirm, labels.actions.delete, labels.errors.delete, labels.errors.deleteAssigned, labels.messages.deleted, t])\n\n return (\n <Page>\n <PageBody>\n <DataTable<TeamRow>\n title={labels.title}\n data={rows}\n columns={columns}\n isLoading={isLoading}\n searchValue={search}\n onSearchChange={handleSearchChange}\n searchPlaceholder={labels.table.search}\n emptyState={(\n <ListEmptyState\n entityName={labels.title}\n createHref=\"/backend/staff/teams/create\"\n createLabel={labels.actions.add}\n />\n )}\n actions={(\n <Button asChild size=\"sm\">\n <Link href=\"/backend/staff/teams/create\">\n {labels.actions.add}\n </Link>\n </Button>\n )}\n refreshButton={{\n label: labels.actions.refresh,\n onRefresh: handleRefresh,\n isRefreshing: isLoading,\n }}\n sortable\n sorting={sorting}\n onSortingChange={setSorting}\n pagination={{\n page,\n pageSize: PAGE_SIZE,\n total,\n totalPages,\n totalIsCapped,\n onPageChange: setPage,\n }}\n rowActions={(row) => (\n <RowActions\n items={[\n { id: 'edit', label: labels.actions.edit, href: `/backend/staff/teams/${row.id}/edit` },\n ...(row.memberCount > 0\n ? []\n : [{ id: 'delete', label: labels.actions.delete, destructive: true, onSelect: () => { void handleDelete(row) } }]),\n ]}\n />\n )}\n onRowClick={(row) => router.push(`/backend/staff/teams/${row.id}/edit`)}\n />\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n}\n\nfunction mapApiTeam(item: Record<string, unknown>): TeamRow {\n const id = typeof item.id === 'string' ? item.id : ''\n const name = typeof item.name === 'string' ? item.name : id\n const description = typeof item.description === 'string' && item.description.trim().length ? item.description.trim() : null\n const updatedAt = typeof item.updatedAt === 'string'\n ? item.updatedAt\n : typeof item.updated_at === 'string'\n ? item.updated_at\n : null\n const isActive = typeof item.isActive === 'boolean'\n ? item.isActive\n : typeof item.is_active === 'boolean'\n ? item.is_active\n : true\n const memberCount = typeof item.memberCount === 'number'\n ? item.memberCount\n : typeof item.member_count === 'number'\n ? item.member_count\n : 0\n return withDataTableNamespaces({ id, name, description, isActive, updatedAt, memberCount }, item)\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -104,6 +104,7 @@ function TimesheetProjectsPage() {
104
104
  const [page, setPage] = React.useState(1);
105
105
  const [total, setTotal] = React.useState(0);
106
106
  const [totalPages, setTotalPages] = React.useState(1);
107
+ const [totalIsCapped, setTotalIsCapped] = React.useState(false);
107
108
  const [sorting, setSorting] = React.useState([{ id: "updatedAt", desc: true }]);
108
109
  const [search, setSearch] = React.useState("");
109
110
  const [filterValues, setFilterValues] = React.useState({});
@@ -309,6 +310,7 @@ function TimesheetProjectsPage() {
309
310
  setTotalPages(
310
311
  typeof payload.totalPages === "number" ? payload.totalPages : Math.max(1, Math.ceil(items.length / PAGE_SIZE))
311
312
  );
313
+ setTotalIsCapped(payload.totalIsCapped === true);
312
314
  } catch (error) {
313
315
  logger.error("staff.timesheets.projects.list", { err: error });
314
316
  flash(labels.errors.load, "error");
@@ -576,6 +578,7 @@ function TimesheetProjectsPage() {
576
578
  pageSize: PAGE_SIZE,
577
579
  total,
578
580
  totalPages,
581
+ totalIsCapped,
579
582
  onPageChange: setPage
580
583
  },
581
584
  rowActions: (row) => /* @__PURE__ */ jsx(
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../../src/modules/staff/backend/staff/timesheets/projects/page.tsx"],
4
- "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useRouter, useSearchParams } from 'next/navigation'\nimport type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'\nimport type { SortingState } from '@tanstack/react-table'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable, withDataTableNamespaces } from '@open-mercato/ui/backend/DataTable'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterOverlay'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'\nimport { deleteCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT, type TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport { formatDateTime } from '@open-mercato/shared/lib/time'\nimport { ProjectColorDot } from '../../../../lib/timesheets-ui/ProjectColorDot'\nimport { resolveProjectColorHex } from '../../../../lib/timesheets-ui/colors'\nimport {\n ProjectsKpiStrip,\n type PmKpis,\n type CollabKpis,\n} from '../../../../lib/timesheets-projects-ui/ProjectsKpiStrip'\nimport { SavedViewTabs } from '../../../../lib/timesheets-projects-ui/SavedViewTabs'\nimport { HoursSparkline } from '../../../../lib/timesheets-projects-ui/HoursSparkline'\nimport {\n ProjectMembersAvatarStack,\n type AvatarMember,\n} from '../../../../lib/timesheets-projects-ui/ProjectMembersAvatarStack'\nimport { ViewModeToggle } from '../../../../lib/timesheets-projects-ui/ViewModeToggle'\nimport {\n useProjectsViewMode,\n type ProjectsViewMode,\n} from '../../../../lib/timesheets-projects-ui/useProjectsViewMode'\nimport {\n ProjectCard,\n type ProjectCardData,\n type ProjectCardLabels,\n} from '../../../../lib/timesheets-projects-ui/ProjectCard'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('staff')\n\nconst PAGE_SIZE = 50\nconst INCLUDE_FIELDS = 'hoursWeek,hoursTrend,members,myRole'\n\ntype StaffEnrichment = {\n hoursWeek?: number\n hoursTrend?: number[]\n myRole?: string | null\n members?: AvatarMember[]\n memberCount?: number\n}\n\ntype ProjectRow = {\n id: string\n name: string\n code: string | null\n customerId: string | null\n customerName: string | null\n status: string\n projectType: string | null\n color: string | null\n startDate: string | null\n updatedAt: string | null\n hoursWeek: number\n hoursTrend: number[]\n myRole: string | null\n members: AvatarMember[]\n memberCount: number\n}\n\ntype ProjectsResponse = {\n items?: Array<Record<string, unknown>>\n total?: number\n totalPages?: number\n}\n\ntype KpisResponse = PmKpis | CollabKpis\n\nfunction formatRelativeTime(iso: string | null, fallback: string, t: TranslateFn): string {\n if (!iso) return fallback\n const parsed = new Date(iso)\n if (Number.isNaN(parsed.getTime())) return fallback\n const diffMs = Date.now() - parsed.getTime()\n const minutes = Math.round(diffMs / 60000)\n if (minutes < 1) return t('staff.timesheets.projects.portfolio.relativeTime.justNow', 'just now')\n if (minutes < 60) return t('staff.timesheets.projects.portfolio.relativeTime.minutesAgo', '{minutes}m ago', { minutes })\n const hours = Math.round(minutes / 60)\n if (hours < 24) return t('staff.timesheets.projects.portfolio.relativeTime.hoursAgo', '{hours}h ago', { hours })\n const days = Math.round(hours / 24)\n if (days < 14) return t('staff.timesheets.projects.portfolio.relativeTime.daysAgo', '{days}d ago', { days })\n return formatDateTime(iso) ?? fallback\n}\n\nfunction mapApiProject(item: Record<string, unknown>): ProjectRow {\n const id = typeof item.id === 'string' ? item.id : ''\n const name = typeof item.name === 'string' ? item.name : id\n const code = typeof item.code === 'string' && item.code.trim().length ? item.code.trim() : null\n const customerId =\n typeof item.customerId === 'string'\n ? item.customerId\n : typeof item.customer_id === 'string'\n ? item.customer_id\n : null\n const customerName =\n typeof item.customerName === 'string'\n ? item.customerName\n : typeof item.customer_name === 'string'\n ? item.customer_name\n : null\n const status = typeof item.status === 'string' ? item.status : 'active'\n const projectType =\n typeof item.projectType === 'string'\n ? item.projectType\n : typeof item.project_type === 'string'\n ? item.project_type\n : null\n const color = typeof item.color === 'string' ? item.color : null\n const startDate =\n typeof item.startDate === 'string'\n ? item.startDate\n : typeof item.start_date === 'string'\n ? item.start_date\n : null\n const updatedAt =\n typeof item.updatedAt === 'string'\n ? item.updatedAt\n : typeof item.updated_at === 'string'\n ? item.updated_at\n : null\n const enrichment =\n (item as { _staff?: StaffEnrichment })._staff ?? ({} as StaffEnrichment)\n const hoursWeek = typeof enrichment.hoursWeek === 'number' ? enrichment.hoursWeek : 0\n const hoursTrend = Array.isArray(enrichment.hoursTrend)\n ? enrichment.hoursTrend.filter((v): v is number => typeof v === 'number')\n : []\n const members = Array.isArray(enrichment.members)\n ? enrichment.members\n .filter((m): m is AvatarMember => !!m && typeof m === 'object' && typeof (m as AvatarMember).id === 'string')\n .map((m) => ({\n id: m.id,\n name: m.name ?? '',\n initials: m.initials ?? '',\n avatarUrl: m.avatarUrl ?? null,\n }))\n : []\n const memberCount = typeof enrichment.memberCount === 'number' ? enrichment.memberCount : members.length\n const myRole = typeof enrichment.myRole === 'string' ? enrichment.myRole : null\n\n return withDataTableNamespaces(\n {\n id,\n name,\n code,\n customerId,\n customerName,\n status,\n projectType,\n color,\n startDate,\n updatedAt,\n hoursWeek,\n hoursTrend,\n myRole,\n members,\n memberCount,\n },\n item,\n )\n}\n\nexport default function TimesheetProjectsPage() {\n const t = useT()\n const router = useRouter()\n const searchParams = useSearchParams()\n const scopeVersion = useOrganizationScopeVersion()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n\n const [rows, setRows] = React.useState<ProjectRow[]>([])\n const [page, setPage] = React.useState(1)\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const [sorting, setSorting] = React.useState<SortingState>([{ id: 'updatedAt', desc: true }])\n const [search, setSearch] = React.useState('')\n const [filterValues, setFilterValues] = React.useState<FilterValues>({})\n const [isLoading, setIsLoading] = React.useState(true)\n const [isRefreshing, setIsRefreshing] = React.useState(false)\n const hasLoadedOnceRef = React.useRef(false)\n const [reloadToken, setReloadToken] = React.useState(0)\n const [kpis, setKpis] = React.useState<KpisResponse | null>(null)\n const [isLoadingKpis, setIsLoadingKpis] = React.useState(true)\n\n const activeTab = searchParams.get('tab') ?? 'all'\n const urlViewMode = searchParams.get('view')\n const [viewMode, setViewMode] = useProjectsViewMode({\n userKey: null,\n urlOverride: urlViewMode,\n })\n\n const labels = React.useMemo(\n () => ({\n title: t('staff.timesheets.projects.page.title', 'Projects'),\n table: {\n name: t('staff.timesheets.projects.table.name', 'Project'),\n status: t('staff.timesheets.projects.table.status', 'Status'),\n type: t('staff.timesheets.projects.table.type', 'Type'),\n updatedAt: t('staff.timesheets.projects.table.updatedAt', 'Updated'),\n empty: t('staff.timesheets.projects.table.empty', 'No projects yet.'),\n search: t('staff.timesheets.projects.table.search', 'Search projects...'),\n team: t('staff.timesheets.projects.portfolio.team', 'Team'),\n myRole: t('staff.timesheets.projects.portfolio.myRole', 'My role'),\n hoursWeek: t('staff.timesheets.projects.portfolio.hoursWeek', 'Hours / week'),\n myHoursWeek: t('staff.timesheets.projects.portfolio.myHoursWeek', 'My hours / week'),\n },\n actions: {\n add: t('staff.timesheets.projects.actions.add', 'Add Project'),\n addFirst: t('staff.timesheets.projects.actions.addFirst', '+ Add first project'),\n viewDetails: t('staff.timesheets.projects.actions.viewDetails', 'View Details'),\n delete: t('staff.timesheets.projects.actions.delete', 'Delete'),\n deleteConfirm: t('staff.timesheets.projects.actions.deleteConfirm', 'Delete project \"{{name}}\"?'),\n refresh: t('staff.timesheets.projects.actions.refresh', 'Refresh'),\n },\n messages: {\n deleted: t('staff.timesheets.projects.messages.deleted', 'Project deleted.'),\n },\n errors: {\n load: t('staff.timesheets.projects.errors.load', 'Failed to load projects.'),\n delete: t('staff.timesheets.projects.errors.delete', 'Failed to delete project.'),\n },\n statuses: {\n all: t('staff.timesheets.projects.statuses.all', 'All'),\n active: t('staff.timesheets.projects.statuses.active', 'Active'),\n on_hold: t('staff.timesheets.projects.statuses.onHold', 'On Hold'),\n completed: t('staff.timesheets.projects.statuses.completed', 'Completed'),\n },\n tabs: {\n all: t('staff.timesheets.projects.portfolio.tabs.all', 'All'),\n active: t('staff.timesheets.projects.portfolio.tabs.active', 'Active'),\n onHold: t('staff.timesheets.projects.portfolio.tabs.onHold', 'On Hold'),\n completed: t('staff.timesheets.projects.portfolio.tabs.completed', 'Completed'),\n mine: t('staff.timesheets.projects.portfolio.tabs.mine', 'Mine'),\n },\n viewMode: {\n table: t('staff.timesheets.projects.portfolio.viewMode.table', 'Table'),\n cards: t('staff.timesheets.projects.portfolio.viewMode.cards', 'Cards'),\n },\n kpi: {\n totalProjects: t('staff.timesheets.projects.portfolio.kpi.totalProjects', 'Total Projects'),\n hoursWeek: t('staff.timesheets.projects.portfolio.kpi.hoursWeek', 'Hours this week'),\n hoursWeekSub: t('staff.timesheets.projects.portfolio.kpi.hoursWeekSub', 'vs previous week'),\n assignedToMe: t('staff.timesheets.projects.portfolio.kpi.assignedToMe', 'Assigned to me'),\n hoursMonth: t('staff.timesheets.projects.portfolio.kpi.hoursMonth', 'Hours this month'),\n hoursMonthSub: t('staff.timesheets.projects.portfolio.kpi.hoursMonthSub', 'vs previous month'),\n teamActive: t('staff.timesheets.projects.portfolio.kpi.teamActive', 'Active team'),\n teamActiveSub: t('staff.timesheets.projects.portfolio.kpi.teamActiveSub', 'Members with entries this month'),\n myProjects: t('staff.timesheets.projects.portfolio.kpi.myProjects', 'My projects'),\n myHoursWeek: t('staff.timesheets.projects.portfolio.kpi.myHoursWeek', 'My hours this week'),\n myHoursMonth: t('staff.timesheets.projects.portfolio.kpi.myHoursMonth', 'My hours this month'),\n deltaFlat: t('staff.timesheets.projects.portfolio.kpi.deltaFlat', 'no change'),\n noPrevious: t('staff.timesheets.projects.portfolio.kpi.noPrevious', 'no previous data'),\n },\n card: {\n hoursPanelPm: t('staff.timesheets.projects.portfolio.card.hoursPanelPm', 'Team hours \u00B7 last 7w'),\n hoursPanelCollab: t('staff.timesheets.projects.portfolio.card.hoursPanelCollab', 'My hours \u00B7 last 7w'),\n sparklineAria: t('staff.timesheets.projects.portfolio.sparkline.ariaLabel', 'Hours per week, last 7 weeks'),\n role: t('staff.timesheets.projects.portfolio.card.role', 'Role'),\n },\n emptyState: {\n noProjects: t('staff.timesheets.projects.portfolio.emptyState.noProjects', 'No projects yet.'),\n noAssignments: t(\n 'staff.timesheets.projects.portfolio.emptyState.noAssignments',\n \"You aren't assigned to any projects yet. Ask a PM to add you.\",\n ),\n noMatches: t('staff.timesheets.projects.portfolio.emptyState.noMatches', 'No projects match these filters.'),\n },\n }),\n [t],\n )\n\n const kpiLabels = React.useMemo(\n () => ({\n totalProjects: labels.kpi.totalProjects,\n totalProjectsSub: ({ active, onHold }: { active: number; onHold: number }) =>\n `${active} ${labels.statuses.active.toLowerCase()} \u00B7 ${onHold} ${labels.statuses.on_hold.toLowerCase()}`,\n hoursWeek: labels.kpi.hoursWeek,\n hoursWeekSub: labels.kpi.hoursWeekSub,\n assignedToMe: labels.kpi.assignedToMe,\n assignedToMeSub: (active: number) => `${active} ${labels.statuses.active.toLowerCase()}`,\n hoursMonth: labels.kpi.hoursMonth,\n hoursMonthSub: labels.kpi.hoursMonthSub,\n teamActive: labels.kpi.teamActive,\n teamActiveSub: labels.kpi.teamActiveSub,\n myProjects: labels.kpi.myProjects,\n myProjectsSub: (active: number) => `${active} ${labels.statuses.active.toLowerCase()}`,\n myHoursWeek: labels.kpi.myHoursWeek,\n myHoursMonth: labels.kpi.myHoursMonth,\n deltaUp: (pct: number) => `up ${pct}%`,\n deltaDown: (pct: number) => `down ${pct}%`,\n deltaFlat: labels.kpi.deltaFlat,\n noPrevious: labels.kpi.noPrevious,\n }),\n [labels],\n )\n\n const isPmRole = kpis?.role === 'pm'\n\n const filters = React.useMemo<FilterDef[]>(\n () => [\n {\n id: 'status',\n label: labels.table.status,\n type: 'select',\n options: [\n { value: 'active', label: labels.statuses.active },\n { value: 'on_hold', label: labels.statuses.on_hold },\n { value: 'completed', label: labels.statuses.completed },\n ],\n },\n ],\n [labels.table.status, labels.statuses],\n )\n\n const tabs = React.useMemo(() => {\n const base = [\n { id: 'all', label: labels.tabs.all },\n { id: 'active', label: labels.tabs.active },\n ]\n if (isPmRole) {\n base.push({ id: 'on_hold', label: labels.tabs.onHold })\n }\n base.push({ id: 'completed', label: labels.tabs.completed })\n if (isPmRole) {\n base.push({ id: 'mine', label: labels.tabs.mine })\n }\n return base\n }, [labels.tabs, isPmRole])\n\n const statusFromTab = (tabId: string): string | null => {\n if (tabId === 'active' || tabId === 'on_hold' || tabId === 'completed') return tabId\n return null\n }\n const mineFromTab = (tabId: string): boolean => tabId === 'mine' || !isPmRole\n\n const loadKpis = React.useCallback(async () => {\n setIsLoadingKpis(true)\n try {\n const payload = await readApiResultOrThrow<KpisResponse>(\n '/api/staff/timesheets/projects/kpis',\n undefined,\n {\n errorMessage: labels.errors.load,\n fallback: null as unknown as KpisResponse,\n },\n )\n setKpis(payload)\n } catch {\n setKpis(null)\n } finally {\n setIsLoadingKpis(false)\n }\n }, [labels.errors.load])\n\n const loadProjects = React.useCallback(async () => {\n if (hasLoadedOnceRef.current) {\n setIsRefreshing(true)\n } else {\n setIsLoading(true)\n }\n try {\n const params = new URLSearchParams({\n page: String(page),\n pageSize: String(PAGE_SIZE),\n include: INCLUDE_FIELDS,\n })\n const sort = sorting[0]\n if (sort?.id) {\n params.set('sortField', sort.id)\n params.set('sortDir', sort.desc ? 'desc' : 'asc')\n }\n if (search.trim()) params.set('q', search.trim())\n const tabStatus = statusFromTab(activeTab)\n if (tabStatus) params.set('status', tabStatus)\n else if (typeof filterValues.status === 'string' && filterValues.status.length > 0) {\n params.set('status', filterValues.status)\n }\n if (mineFromTab(activeTab)) params.set('mine', '1')\n\n const payload = await readApiResultOrThrow<ProjectsResponse>(\n `/api/staff/timesheets/time-projects?${params.toString()}`,\n undefined,\n { errorMessage: labels.errors.load, fallback: { items: [], total: 0, totalPages: 1 } },\n )\n const items = Array.isArray(payload.items) ? payload.items : []\n setRows(items.map(mapApiProject))\n setTotal(typeof payload.total === 'number' ? payload.total : items.length)\n setTotalPages(\n typeof payload.totalPages === 'number'\n ? payload.totalPages\n : Math.max(1, Math.ceil(items.length / PAGE_SIZE)),\n )\n } catch (error) {\n logger.error('staff.timesheets.projects.list', { err: error })\n flash(labels.errors.load, 'error')\n } finally {\n setIsLoading(false)\n setIsRefreshing(false)\n hasLoadedOnceRef.current = true\n }\n }, [labels.errors.load, page, search, sorting, filterValues.status, activeTab, isPmRole])\n\n React.useEffect(() => {\n void loadKpis()\n }, [loadKpis, scopeVersion, reloadToken])\n\n React.useEffect(() => {\n void loadProjects()\n }, [loadProjects, scopeVersion, reloadToken])\n\n const handleTabSelect = React.useCallback(\n (id: string) => {\n const params = new URLSearchParams(searchParams.toString())\n if (id === 'all') params.delete('tab')\n else params.set('tab', id)\n router.replace(`?${params.toString()}`)\n setPage(1)\n },\n [router, searchParams],\n )\n\n const handleViewModeChange = React.useCallback(\n (next: ProjectsViewMode) => {\n setViewMode(next)\n const params = new URLSearchParams(searchParams.toString())\n if (next === 'table') params.delete('view')\n else params.set('view', next)\n router.replace(`?${params.toString()}`)\n },\n [router, searchParams, setViewMode],\n )\n\n const handleSearchChange = React.useCallback((value: string) => {\n setSearch(value)\n setPage(1)\n }, [])\n\n const handleFiltersApply = React.useCallback((values: FilterValues) => {\n setFilterValues(values)\n setPage(1)\n }, [])\n\n const handleFiltersClear = React.useCallback(() => {\n setFilterValues({})\n setPage(1)\n }, [])\n\n const handleRefresh = React.useCallback(() => {\n setReloadToken((token) => token + 1)\n }, [])\n\n const handleDelete = React.useCallback(\n async (entry: ProjectRow) => {\n const message = labels.actions.deleteConfirm.replace('{{name}}', entry.name)\n const confirmed = await confirm({\n title: labels.actions.delete,\n text: message,\n variant: 'destructive',\n })\n if (!confirmed) return\n try {\n await withScopedApiRequestHeaders(\n buildOptimisticLockHeader(entry.updatedAt),\n () => deleteCrud('staff/timesheets/time-projects', entry.id, { errorMessage: labels.errors.delete }),\n )\n flash(labels.messages.deleted, 'success')\n handleRefresh()\n } catch (error) {\n if (surfaceRecordConflict(error, t)) { handleRefresh(); return }\n logger.error('staff.timesheets.projects.delete', { err: error })\n flash(labels.errors.delete, 'error')\n }\n },\n [confirm, handleRefresh, t, labels.actions.deleteConfirm, labels.actions.delete, labels.errors.delete, labels.messages.deleted],\n )\n\n const columns = React.useMemo<ColumnDef<ProjectRow>[]>(\n () => [\n {\n accessorKey: 'name',\n header: labels.table.name,\n meta: { priority: 1, sticky: true },\n cell: ({ row }) => (\n <div className=\"flex items-center gap-2.5\">\n <ProjectColorDot colorKey={row.original.color} projectName={row.original.name} size=\"sm\" />\n <div className=\"flex min-w-0 flex-col\">\n <span className=\"truncate text-sm font-medium text-foreground\">{row.original.name}</span>\n <span className=\"truncate font-mono text-[11px] text-muted-foreground\">\n {row.original.code ?? '\u2014'}\n {row.original.customerName ? ` \u00B7 ${row.original.customerName}` : ''}\n </span>\n </div>\n </div>\n ),\n },\n {\n accessorKey: 'status',\n header: labels.table.status,\n meta: { priority: 2 },\n cell: ({ row }) => {\n const badgeClass =\n row.original.status === 'active'\n ? 'bg-lime-100 text-lime-800 dark:bg-lime-900/30 dark:text-lime-300'\n : row.original.status === 'on_hold'\n ? 'bg-amber-100 text-amber-800 dark:bg-amber-900/30 dark:text-amber-300'\n : 'bg-muted text-muted-foreground'\n const statusLabel =\n labels.statuses[row.original.status as keyof typeof labels.statuses] ?? row.original.status\n return (\n <span\n className={`inline-flex items-center rounded-full px-2 py-0.5 text-[11px] font-medium ${badgeClass}`}\n >\n {statusLabel}\n </span>\n )\n },\n },\n {\n accessorKey: 'projectType',\n header: labels.table.type,\n meta: { priority: 3 },\n cell: ({ row }) =>\n row.original.projectType ? (\n <span className=\"text-sm text-foreground\">{row.original.projectType}</span>\n ) : (\n <span className=\"text-xs text-muted-foreground/70\">\u2014</span>\n ),\n },\n isPmRole\n ? {\n accessorKey: 'members',\n id: 'members',\n header: labels.table.team,\n enableSorting: false,\n meta: { priority: 4 },\n cell: ({ row }) => (\n <ProjectMembersAvatarStack\n members={row.original.members}\n total={row.original.memberCount}\n peopleCountLabel={`${row.original.memberCount}`}\n />\n ),\n }\n : {\n accessorKey: 'myRole',\n header: labels.table.myRole,\n enableSorting: false,\n meta: { priority: 4 },\n cell: ({ row }) =>\n row.original.myRole ? (\n <span className=\"text-sm text-foreground\">{row.original.myRole}</span>\n ) : (\n <span className=\"text-xs text-muted-foreground/70\">\u2014</span>\n ),\n },\n {\n accessorKey: 'hoursWeek',\n header: isPmRole ? labels.table.hoursWeek : labels.table.myHoursWeek,\n enableSorting: false,\n meta: { priority: 5 },\n cell: ({ row }) => {\n const stripe = resolveProjectColorHex(row.original.color, row.original.name)\n return (\n <div className=\"flex items-center justify-end gap-2\">\n <HoursSparkline\n values={row.original.hoursTrend}\n color={stripe}\n ariaLabel={labels.card.sparklineAria}\n />\n <span className=\"text-xs font-medium tabular-nums text-foreground\">\n {row.original.hoursWeek > 0 ? `${row.original.hoursWeek}h` : '\u2014'}\n </span>\n </div>\n )\n },\n },\n {\n accessorKey: 'updatedAt',\n header: labels.table.updatedAt,\n meta: { priority: 6 },\n cell: ({ row }) => (\n <span className=\"text-xs text-muted-foreground\">\n {formatRelativeTime(row.original.updatedAt, '\u2014', t)}\n </span>\n ),\n },\n ],\n [labels.table, labels.statuses, labels.card.sparklineAria, isPmRole],\n )\n\n const cardLabels = React.useMemo<ProjectCardLabels>(\n () => ({\n hoursPanelPm: labels.card.hoursPanelPm,\n hoursPanelCollab: labels.card.hoursPanelCollab,\n sparklineAria: labels.card.sparklineAria,\n peopleCount: (count: number) => `${count}`,\n role: labels.card.role,\n noCustomer: '\u2014',\n statuses: labels.statuses,\n }),\n [labels.card, labels.statuses],\n )\n\n const canManage = isPmRole\n\n const emptyStateCopy = React.useMemo(() => {\n const hasFiltersApplied = activeTab !== 'all' || search.trim().length > 0 || Object.values(filterValues).some(Boolean)\n if (hasFiltersApplied) return labels.emptyState.noMatches\n if (!canManage) return labels.emptyState.noAssignments\n return labels.emptyState.noProjects\n }, [activeTab, search, filterValues, canManage, labels.emptyState])\n\n const cardsData: ProjectCardData[] = rows.map((row) => ({\n id: row.id,\n name: row.name,\n code: row.code,\n customerName: row.customerName,\n color: row.color,\n status: row.status,\n hoursWeek: row.hoursWeek,\n hoursTrend: row.hoursTrend,\n members: row.members,\n memberCount: row.memberCount,\n myRole: row.myRole,\n updatedAt: row.updatedAt,\n }))\n\n return (\n <Page>\n <PageBody>\n <div className=\"mb-4\">\n <ProjectsKpiStrip kpis={kpis} labels={kpiLabels} isLoading={isLoadingKpis} />\n </div>\n\n <div className=\"mb-3 flex flex-wrap items-center justify-between gap-3\">\n <SavedViewTabs\n tabs={tabs}\n activeId={activeTab}\n onSelect={handleTabSelect}\n ariaLabel={t('staff.timesheets.projects.portfolio.savedViews.ariaLabel', 'Saved views')}\n />\n <ViewModeToggle\n mode={viewMode}\n onChange={handleViewModeChange}\n tableLabel={labels.viewMode.table}\n cardsLabel={labels.viewMode.cards}\n ariaLabel={t('staff.timesheets.projects.portfolio.viewMode.ariaLabel', 'View mode')}\n />\n </div>\n\n {viewMode === 'cards' ? (\n <div>\n {isLoading ? (\n <div className=\"grid grid-cols-1 gap-3 md:grid-cols-2 lg:grid-cols-3\">\n {Array.from({ length: 6 }).map((_, idx) => (\n <div key={idx} className=\"h-48 animate-pulse rounded-lg border border-border bg-muted/40\" />\n ))}\n </div>\n ) : rows.length === 0 ? (\n <div className=\"rounded-lg border border-dashed border-border bg-card p-10 text-center\">\n <p className=\"text-sm text-muted-foreground\">{emptyStateCopy}</p>\n {canManage ? (\n <div className=\"mt-3\">\n <Button asChild size=\"sm\">\n <Link href=\"/backend/staff/timesheets/projects/create\">\n {labels.actions.addFirst}\n </Link>\n </Button>\n </div>\n ) : null}\n </div>\n ) : (\n <div className=\"grid grid-cols-1 gap-3 md:grid-cols-2 lg:grid-cols-3\">\n {cardsData.map((card) => (\n <ProjectCard\n key={card.id}\n data={card}\n labels={cardLabels}\n showTeam={isPmRole}\n href={`/backend/staff/timesheets/projects/${card.id}`}\n />\n ))}\n </div>\n )}\n </div>\n ) : (\n <DataTable<ProjectRow>\n title={labels.title}\n data={rows}\n columns={columns}\n isLoading={isLoading}\n searchValue={search}\n onSearchChange={handleSearchChange}\n searchPlaceholder={labels.table.search}\n filters={filters}\n filterValues={filterValues}\n onFiltersApply={handleFiltersApply}\n onFiltersClear={handleFiltersClear}\n emptyState={\n <div className=\"py-12 text-center\">\n <p className=\"text-sm text-muted-foreground mb-4\">{emptyStateCopy}</p>\n {canManage ? (\n <Button asChild size=\"sm\">\n <Link href=\"/backend/staff/timesheets/projects/create\">{labels.actions.addFirst}</Link>\n </Button>\n ) : null}\n </div>\n }\n actions={\n canManage ? (\n <Button asChild size=\"sm\">\n <Link href=\"/backend/staff/timesheets/projects/create\">{labels.actions.add}</Link>\n </Button>\n ) : undefined\n }\n refreshButton={{\n label: labels.actions.refresh,\n onRefresh: handleRefresh,\n isRefreshing: isLoading || isRefreshing,\n }}\n sortable\n sorting={sorting}\n onSortingChange={setSorting}\n pagination={{\n page,\n pageSize: PAGE_SIZE,\n total,\n totalPages,\n onPageChange: setPage,\n }}\n rowActions={(row) => (\n <RowActions\n items={[\n {\n id: 'view',\n label: labels.actions.viewDetails,\n href: `/backend/staff/timesheets/projects/${row.id}`,\n },\n ...(canManage\n ? [\n {\n id: 'delete',\n label: labels.actions.delete,\n destructive: true,\n onSelect: () => {\n void handleDelete(row)\n },\n },\n ]\n : []),\n ]}\n />\n )}\n onRowClick={(row) => router.push(`/backend/staff/timesheets/projects/${row.id}`)}\n />\n )}\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useRouter, useSearchParams } from 'next/navigation'\nimport type { LegacyColumnDef as ColumnDef } from '@tanstack/react-table/legacy'\nimport type { SortingState } from '@tanstack/react-table'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable, withDataTableNamespaces } from '@open-mercato/ui/backend/DataTable'\nimport type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterOverlay'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { readApiResultOrThrow, withScopedApiRequestHeaders } from '@open-mercato/ui/backend/utils/apiCall'\nimport { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimisticLock'\nimport { surfaceRecordConflict } from '@open-mercato/ui/backend/conflicts'\nimport { deleteCrud } from '@open-mercato/ui/backend/utils/crud'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT, type TranslateFn } from '@open-mercato/shared/lib/i18n/context'\nimport { formatDateTime } from '@open-mercato/shared/lib/time'\nimport { ProjectColorDot } from '../../../../lib/timesheets-ui/ProjectColorDot'\nimport { resolveProjectColorHex } from '../../../../lib/timesheets-ui/colors'\nimport {\n ProjectsKpiStrip,\n type PmKpis,\n type CollabKpis,\n} from '../../../../lib/timesheets-projects-ui/ProjectsKpiStrip'\nimport { SavedViewTabs } from '../../../../lib/timesheets-projects-ui/SavedViewTabs'\nimport { HoursSparkline } from '../../../../lib/timesheets-projects-ui/HoursSparkline'\nimport {\n ProjectMembersAvatarStack,\n type AvatarMember,\n} from '../../../../lib/timesheets-projects-ui/ProjectMembersAvatarStack'\nimport { ViewModeToggle } from '../../../../lib/timesheets-projects-ui/ViewModeToggle'\nimport {\n useProjectsViewMode,\n type ProjectsViewMode,\n} from '../../../../lib/timesheets-projects-ui/useProjectsViewMode'\nimport {\n ProjectCard,\n type ProjectCardData,\n type ProjectCardLabels,\n} from '../../../../lib/timesheets-projects-ui/ProjectCard'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('staff')\n\nconst PAGE_SIZE = 50\nconst INCLUDE_FIELDS = 'hoursWeek,hoursTrend,members,myRole'\n\ntype StaffEnrichment = {\n hoursWeek?: number\n hoursTrend?: number[]\n myRole?: string | null\n members?: AvatarMember[]\n memberCount?: number\n}\n\ntype ProjectRow = {\n id: string\n name: string\n code: string | null\n customerId: string | null\n customerName: string | null\n status: string\n projectType: string | null\n color: string | null\n startDate: string | null\n updatedAt: string | null\n hoursWeek: number\n hoursTrend: number[]\n myRole: string | null\n members: AvatarMember[]\n memberCount: number\n}\n\ntype ProjectsResponse = {\n items?: Array<Record<string, unknown>>\n total?: number\n totalPages?: number\n totalIsCapped?: boolean\n}\n\ntype KpisResponse = PmKpis | CollabKpis\n\nfunction formatRelativeTime(iso: string | null, fallback: string, t: TranslateFn): string {\n if (!iso) return fallback\n const parsed = new Date(iso)\n if (Number.isNaN(parsed.getTime())) return fallback\n const diffMs = Date.now() - parsed.getTime()\n const minutes = Math.round(diffMs / 60000)\n if (minutes < 1) return t('staff.timesheets.projects.portfolio.relativeTime.justNow', 'just now')\n if (minutes < 60) return t('staff.timesheets.projects.portfolio.relativeTime.minutesAgo', '{minutes}m ago', { minutes })\n const hours = Math.round(minutes / 60)\n if (hours < 24) return t('staff.timesheets.projects.portfolio.relativeTime.hoursAgo', '{hours}h ago', { hours })\n const days = Math.round(hours / 24)\n if (days < 14) return t('staff.timesheets.projects.portfolio.relativeTime.daysAgo', '{days}d ago', { days })\n return formatDateTime(iso) ?? fallback\n}\n\nfunction mapApiProject(item: Record<string, unknown>): ProjectRow {\n const id = typeof item.id === 'string' ? item.id : ''\n const name = typeof item.name === 'string' ? item.name : id\n const code = typeof item.code === 'string' && item.code.trim().length ? item.code.trim() : null\n const customerId =\n typeof item.customerId === 'string'\n ? item.customerId\n : typeof item.customer_id === 'string'\n ? item.customer_id\n : null\n const customerName =\n typeof item.customerName === 'string'\n ? item.customerName\n : typeof item.customer_name === 'string'\n ? item.customer_name\n : null\n const status = typeof item.status === 'string' ? item.status : 'active'\n const projectType =\n typeof item.projectType === 'string'\n ? item.projectType\n : typeof item.project_type === 'string'\n ? item.project_type\n : null\n const color = typeof item.color === 'string' ? item.color : null\n const startDate =\n typeof item.startDate === 'string'\n ? item.startDate\n : typeof item.start_date === 'string'\n ? item.start_date\n : null\n const updatedAt =\n typeof item.updatedAt === 'string'\n ? item.updatedAt\n : typeof item.updated_at === 'string'\n ? item.updated_at\n : null\n const enrichment =\n (item as { _staff?: StaffEnrichment })._staff ?? ({} as StaffEnrichment)\n const hoursWeek = typeof enrichment.hoursWeek === 'number' ? enrichment.hoursWeek : 0\n const hoursTrend = Array.isArray(enrichment.hoursTrend)\n ? enrichment.hoursTrend.filter((v): v is number => typeof v === 'number')\n : []\n const members = Array.isArray(enrichment.members)\n ? enrichment.members\n .filter((m): m is AvatarMember => !!m && typeof m === 'object' && typeof (m as AvatarMember).id === 'string')\n .map((m) => ({\n id: m.id,\n name: m.name ?? '',\n initials: m.initials ?? '',\n avatarUrl: m.avatarUrl ?? null,\n }))\n : []\n const memberCount = typeof enrichment.memberCount === 'number' ? enrichment.memberCount : members.length\n const myRole = typeof enrichment.myRole === 'string' ? enrichment.myRole : null\n\n return withDataTableNamespaces(\n {\n id,\n name,\n code,\n customerId,\n customerName,\n status,\n projectType,\n color,\n startDate,\n updatedAt,\n hoursWeek,\n hoursTrend,\n myRole,\n members,\n memberCount,\n },\n item,\n )\n}\n\nexport default function TimesheetProjectsPage() {\n const t = useT()\n const router = useRouter()\n const searchParams = useSearchParams()\n const scopeVersion = useOrganizationScopeVersion()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n\n const [rows, setRows] = React.useState<ProjectRow[]>([])\n const [page, setPage] = React.useState(1)\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const [totalIsCapped, setTotalIsCapped] = React.useState(false)\n const [sorting, setSorting] = React.useState<SortingState>([{ id: 'updatedAt', desc: true }])\n const [search, setSearch] = React.useState('')\n const [filterValues, setFilterValues] = React.useState<FilterValues>({})\n const [isLoading, setIsLoading] = React.useState(true)\n const [isRefreshing, setIsRefreshing] = React.useState(false)\n const hasLoadedOnceRef = React.useRef(false)\n const [reloadToken, setReloadToken] = React.useState(0)\n const [kpis, setKpis] = React.useState<KpisResponse | null>(null)\n const [isLoadingKpis, setIsLoadingKpis] = React.useState(true)\n\n const activeTab = searchParams.get('tab') ?? 'all'\n const urlViewMode = searchParams.get('view')\n const [viewMode, setViewMode] = useProjectsViewMode({\n userKey: null,\n urlOverride: urlViewMode,\n })\n\n const labels = React.useMemo(\n () => ({\n title: t('staff.timesheets.projects.page.title', 'Projects'),\n table: {\n name: t('staff.timesheets.projects.table.name', 'Project'),\n status: t('staff.timesheets.projects.table.status', 'Status'),\n type: t('staff.timesheets.projects.table.type', 'Type'),\n updatedAt: t('staff.timesheets.projects.table.updatedAt', 'Updated'),\n empty: t('staff.timesheets.projects.table.empty', 'No projects yet.'),\n search: t('staff.timesheets.projects.table.search', 'Search projects...'),\n team: t('staff.timesheets.projects.portfolio.team', 'Team'),\n myRole: t('staff.timesheets.projects.portfolio.myRole', 'My role'),\n hoursWeek: t('staff.timesheets.projects.portfolio.hoursWeek', 'Hours / week'),\n myHoursWeek: t('staff.timesheets.projects.portfolio.myHoursWeek', 'My hours / week'),\n },\n actions: {\n add: t('staff.timesheets.projects.actions.add', 'Add Project'),\n addFirst: t('staff.timesheets.projects.actions.addFirst', '+ Add first project'),\n viewDetails: t('staff.timesheets.projects.actions.viewDetails', 'View Details'),\n delete: t('staff.timesheets.projects.actions.delete', 'Delete'),\n deleteConfirm: t('staff.timesheets.projects.actions.deleteConfirm', 'Delete project \"{{name}}\"?'),\n refresh: t('staff.timesheets.projects.actions.refresh', 'Refresh'),\n },\n messages: {\n deleted: t('staff.timesheets.projects.messages.deleted', 'Project deleted.'),\n },\n errors: {\n load: t('staff.timesheets.projects.errors.load', 'Failed to load projects.'),\n delete: t('staff.timesheets.projects.errors.delete', 'Failed to delete project.'),\n },\n statuses: {\n all: t('staff.timesheets.projects.statuses.all', 'All'),\n active: t('staff.timesheets.projects.statuses.active', 'Active'),\n on_hold: t('staff.timesheets.projects.statuses.onHold', 'On Hold'),\n completed: t('staff.timesheets.projects.statuses.completed', 'Completed'),\n },\n tabs: {\n all: t('staff.timesheets.projects.portfolio.tabs.all', 'All'),\n active: t('staff.timesheets.projects.portfolio.tabs.active', 'Active'),\n onHold: t('staff.timesheets.projects.portfolio.tabs.onHold', 'On Hold'),\n completed: t('staff.timesheets.projects.portfolio.tabs.completed', 'Completed'),\n mine: t('staff.timesheets.projects.portfolio.tabs.mine', 'Mine'),\n },\n viewMode: {\n table: t('staff.timesheets.projects.portfolio.viewMode.table', 'Table'),\n cards: t('staff.timesheets.projects.portfolio.viewMode.cards', 'Cards'),\n },\n kpi: {\n totalProjects: t('staff.timesheets.projects.portfolio.kpi.totalProjects', 'Total Projects'),\n hoursWeek: t('staff.timesheets.projects.portfolio.kpi.hoursWeek', 'Hours this week'),\n hoursWeekSub: t('staff.timesheets.projects.portfolio.kpi.hoursWeekSub', 'vs previous week'),\n assignedToMe: t('staff.timesheets.projects.portfolio.kpi.assignedToMe', 'Assigned to me'),\n hoursMonth: t('staff.timesheets.projects.portfolio.kpi.hoursMonth', 'Hours this month'),\n hoursMonthSub: t('staff.timesheets.projects.portfolio.kpi.hoursMonthSub', 'vs previous month'),\n teamActive: t('staff.timesheets.projects.portfolio.kpi.teamActive', 'Active team'),\n teamActiveSub: t('staff.timesheets.projects.portfolio.kpi.teamActiveSub', 'Members with entries this month'),\n myProjects: t('staff.timesheets.projects.portfolio.kpi.myProjects', 'My projects'),\n myHoursWeek: t('staff.timesheets.projects.portfolio.kpi.myHoursWeek', 'My hours this week'),\n myHoursMonth: t('staff.timesheets.projects.portfolio.kpi.myHoursMonth', 'My hours this month'),\n deltaFlat: t('staff.timesheets.projects.portfolio.kpi.deltaFlat', 'no change'),\n noPrevious: t('staff.timesheets.projects.portfolio.kpi.noPrevious', 'no previous data'),\n },\n card: {\n hoursPanelPm: t('staff.timesheets.projects.portfolio.card.hoursPanelPm', 'Team hours \u00B7 last 7w'),\n hoursPanelCollab: t('staff.timesheets.projects.portfolio.card.hoursPanelCollab', 'My hours \u00B7 last 7w'),\n sparklineAria: t('staff.timesheets.projects.portfolio.sparkline.ariaLabel', 'Hours per week, last 7 weeks'),\n role: t('staff.timesheets.projects.portfolio.card.role', 'Role'),\n },\n emptyState: {\n noProjects: t('staff.timesheets.projects.portfolio.emptyState.noProjects', 'No projects yet.'),\n noAssignments: t(\n 'staff.timesheets.projects.portfolio.emptyState.noAssignments',\n \"You aren't assigned to any projects yet. Ask a PM to add you.\",\n ),\n noMatches: t('staff.timesheets.projects.portfolio.emptyState.noMatches', 'No projects match these filters.'),\n },\n }),\n [t],\n )\n\n const kpiLabels = React.useMemo(\n () => ({\n totalProjects: labels.kpi.totalProjects,\n totalProjectsSub: ({ active, onHold }: { active: number; onHold: number }) =>\n `${active} ${labels.statuses.active.toLowerCase()} \u00B7 ${onHold} ${labels.statuses.on_hold.toLowerCase()}`,\n hoursWeek: labels.kpi.hoursWeek,\n hoursWeekSub: labels.kpi.hoursWeekSub,\n assignedToMe: labels.kpi.assignedToMe,\n assignedToMeSub: (active: number) => `${active} ${labels.statuses.active.toLowerCase()}`,\n hoursMonth: labels.kpi.hoursMonth,\n hoursMonthSub: labels.kpi.hoursMonthSub,\n teamActive: labels.kpi.teamActive,\n teamActiveSub: labels.kpi.teamActiveSub,\n myProjects: labels.kpi.myProjects,\n myProjectsSub: (active: number) => `${active} ${labels.statuses.active.toLowerCase()}`,\n myHoursWeek: labels.kpi.myHoursWeek,\n myHoursMonth: labels.kpi.myHoursMonth,\n deltaUp: (pct: number) => `up ${pct}%`,\n deltaDown: (pct: number) => `down ${pct}%`,\n deltaFlat: labels.kpi.deltaFlat,\n noPrevious: labels.kpi.noPrevious,\n }),\n [labels],\n )\n\n const isPmRole = kpis?.role === 'pm'\n\n const filters = React.useMemo<FilterDef[]>(\n () => [\n {\n id: 'status',\n label: labels.table.status,\n type: 'select',\n options: [\n { value: 'active', label: labels.statuses.active },\n { value: 'on_hold', label: labels.statuses.on_hold },\n { value: 'completed', label: labels.statuses.completed },\n ],\n },\n ],\n [labels.table.status, labels.statuses],\n )\n\n const tabs = React.useMemo(() => {\n const base = [\n { id: 'all', label: labels.tabs.all },\n { id: 'active', label: labels.tabs.active },\n ]\n if (isPmRole) {\n base.push({ id: 'on_hold', label: labels.tabs.onHold })\n }\n base.push({ id: 'completed', label: labels.tabs.completed })\n if (isPmRole) {\n base.push({ id: 'mine', label: labels.tabs.mine })\n }\n return base\n }, [labels.tabs, isPmRole])\n\n const statusFromTab = (tabId: string): string | null => {\n if (tabId === 'active' || tabId === 'on_hold' || tabId === 'completed') return tabId\n return null\n }\n const mineFromTab = (tabId: string): boolean => tabId === 'mine' || !isPmRole\n\n const loadKpis = React.useCallback(async () => {\n setIsLoadingKpis(true)\n try {\n const payload = await readApiResultOrThrow<KpisResponse>(\n '/api/staff/timesheets/projects/kpis',\n undefined,\n {\n errorMessage: labels.errors.load,\n fallback: null as unknown as KpisResponse,\n },\n )\n setKpis(payload)\n } catch {\n setKpis(null)\n } finally {\n setIsLoadingKpis(false)\n }\n }, [labels.errors.load])\n\n const loadProjects = React.useCallback(async () => {\n if (hasLoadedOnceRef.current) {\n setIsRefreshing(true)\n } else {\n setIsLoading(true)\n }\n try {\n const params = new URLSearchParams({\n page: String(page),\n pageSize: String(PAGE_SIZE),\n include: INCLUDE_FIELDS,\n })\n const sort = sorting[0]\n if (sort?.id) {\n params.set('sortField', sort.id)\n params.set('sortDir', sort.desc ? 'desc' : 'asc')\n }\n if (search.trim()) params.set('q', search.trim())\n const tabStatus = statusFromTab(activeTab)\n if (tabStatus) params.set('status', tabStatus)\n else if (typeof filterValues.status === 'string' && filterValues.status.length > 0) {\n params.set('status', filterValues.status)\n }\n if (mineFromTab(activeTab)) params.set('mine', '1')\n\n const payload = await readApiResultOrThrow<ProjectsResponse>(\n `/api/staff/timesheets/time-projects?${params.toString()}`,\n undefined,\n { errorMessage: labels.errors.load, fallback: { items: [], total: 0, totalPages: 1 } },\n )\n const items = Array.isArray(payload.items) ? payload.items : []\n setRows(items.map(mapApiProject))\n setTotal(typeof payload.total === 'number' ? payload.total : items.length)\n setTotalPages(\n typeof payload.totalPages === 'number'\n ? payload.totalPages\n : Math.max(1, Math.ceil(items.length / PAGE_SIZE)),\n )\n setTotalIsCapped(payload.totalIsCapped === true)\n } catch (error) {\n logger.error('staff.timesheets.projects.list', { err: error })\n flash(labels.errors.load, 'error')\n } finally {\n setIsLoading(false)\n setIsRefreshing(false)\n hasLoadedOnceRef.current = true\n }\n }, [labels.errors.load, page, search, sorting, filterValues.status, activeTab, isPmRole])\n\n React.useEffect(() => {\n void loadKpis()\n }, [loadKpis, scopeVersion, reloadToken])\n\n React.useEffect(() => {\n void loadProjects()\n }, [loadProjects, scopeVersion, reloadToken])\n\n const handleTabSelect = React.useCallback(\n (id: string) => {\n const params = new URLSearchParams(searchParams.toString())\n if (id === 'all') params.delete('tab')\n else params.set('tab', id)\n router.replace(`?${params.toString()}`)\n setPage(1)\n },\n [router, searchParams],\n )\n\n const handleViewModeChange = React.useCallback(\n (next: ProjectsViewMode) => {\n setViewMode(next)\n const params = new URLSearchParams(searchParams.toString())\n if (next === 'table') params.delete('view')\n else params.set('view', next)\n router.replace(`?${params.toString()}`)\n },\n [router, searchParams, setViewMode],\n )\n\n const handleSearchChange = React.useCallback((value: string) => {\n setSearch(value)\n setPage(1)\n }, [])\n\n const handleFiltersApply = React.useCallback((values: FilterValues) => {\n setFilterValues(values)\n setPage(1)\n }, [])\n\n const handleFiltersClear = React.useCallback(() => {\n setFilterValues({})\n setPage(1)\n }, [])\n\n const handleRefresh = React.useCallback(() => {\n setReloadToken((token) => token + 1)\n }, [])\n\n const handleDelete = React.useCallback(\n async (entry: ProjectRow) => {\n const message = labels.actions.deleteConfirm.replace('{{name}}', entry.name)\n const confirmed = await confirm({\n title: labels.actions.delete,\n text: message,\n variant: 'destructive',\n })\n if (!confirmed) return\n try {\n await withScopedApiRequestHeaders(\n buildOptimisticLockHeader(entry.updatedAt),\n () => deleteCrud('staff/timesheets/time-projects', entry.id, { errorMessage: labels.errors.delete }),\n )\n flash(labels.messages.deleted, 'success')\n handleRefresh()\n } catch (error) {\n if (surfaceRecordConflict(error, t)) { handleRefresh(); return }\n logger.error('staff.timesheets.projects.delete', { err: error })\n flash(labels.errors.delete, 'error')\n }\n },\n [confirm, handleRefresh, t, labels.actions.deleteConfirm, labels.actions.delete, labels.errors.delete, labels.messages.deleted],\n )\n\n const columns = React.useMemo<ColumnDef<ProjectRow>[]>(\n () => [\n {\n accessorKey: 'name',\n header: labels.table.name,\n meta: { priority: 1, sticky: true },\n cell: ({ row }) => (\n <div className=\"flex items-center gap-2.5\">\n <ProjectColorDot colorKey={row.original.color} projectName={row.original.name} size=\"sm\" />\n <div className=\"flex min-w-0 flex-col\">\n <span className=\"truncate text-sm font-medium text-foreground\">{row.original.name}</span>\n <span className=\"truncate font-mono text-[11px] text-muted-foreground\">\n {row.original.code ?? '\u2014'}\n {row.original.customerName ? ` \u00B7 ${row.original.customerName}` : ''}\n </span>\n </div>\n </div>\n ),\n },\n {\n accessorKey: 'status',\n header: labels.table.status,\n meta: { priority: 2 },\n cell: ({ row }) => {\n const badgeClass =\n row.original.status === 'active'\n ? 'bg-lime-100 text-lime-800 dark:bg-lime-900/30 dark:text-lime-300'\n : row.original.status === 'on_hold'\n ? 'bg-amber-100 text-amber-800 dark:bg-amber-900/30 dark:text-amber-300'\n : 'bg-muted text-muted-foreground'\n const statusLabel =\n labels.statuses[row.original.status as keyof typeof labels.statuses] ?? row.original.status\n return (\n <span\n className={`inline-flex items-center rounded-full px-2 py-0.5 text-[11px] font-medium ${badgeClass}`}\n >\n {statusLabel}\n </span>\n )\n },\n },\n {\n accessorKey: 'projectType',\n header: labels.table.type,\n meta: { priority: 3 },\n cell: ({ row }) =>\n row.original.projectType ? (\n <span className=\"text-sm text-foreground\">{row.original.projectType}</span>\n ) : (\n <span className=\"text-xs text-muted-foreground/70\">\u2014</span>\n ),\n },\n isPmRole\n ? {\n accessorKey: 'members',\n id: 'members',\n header: labels.table.team,\n enableSorting: false,\n meta: { priority: 4 },\n cell: ({ row }) => (\n <ProjectMembersAvatarStack\n members={row.original.members}\n total={row.original.memberCount}\n peopleCountLabel={`${row.original.memberCount}`}\n />\n ),\n }\n : {\n accessorKey: 'myRole',\n header: labels.table.myRole,\n enableSorting: false,\n meta: { priority: 4 },\n cell: ({ row }) =>\n row.original.myRole ? (\n <span className=\"text-sm text-foreground\">{row.original.myRole}</span>\n ) : (\n <span className=\"text-xs text-muted-foreground/70\">\u2014</span>\n ),\n },\n {\n accessorKey: 'hoursWeek',\n header: isPmRole ? labels.table.hoursWeek : labels.table.myHoursWeek,\n enableSorting: false,\n meta: { priority: 5 },\n cell: ({ row }) => {\n const stripe = resolveProjectColorHex(row.original.color, row.original.name)\n return (\n <div className=\"flex items-center justify-end gap-2\">\n <HoursSparkline\n values={row.original.hoursTrend}\n color={stripe}\n ariaLabel={labels.card.sparklineAria}\n />\n <span className=\"text-xs font-medium tabular-nums text-foreground\">\n {row.original.hoursWeek > 0 ? `${row.original.hoursWeek}h` : '\u2014'}\n </span>\n </div>\n )\n },\n },\n {\n accessorKey: 'updatedAt',\n header: labels.table.updatedAt,\n meta: { priority: 6 },\n cell: ({ row }) => (\n <span className=\"text-xs text-muted-foreground\">\n {formatRelativeTime(row.original.updatedAt, '\u2014', t)}\n </span>\n ),\n },\n ],\n [labels.table, labels.statuses, labels.card.sparklineAria, isPmRole],\n )\n\n const cardLabels = React.useMemo<ProjectCardLabels>(\n () => ({\n hoursPanelPm: labels.card.hoursPanelPm,\n hoursPanelCollab: labels.card.hoursPanelCollab,\n sparklineAria: labels.card.sparklineAria,\n peopleCount: (count: number) => `${count}`,\n role: labels.card.role,\n noCustomer: '\u2014',\n statuses: labels.statuses,\n }),\n [labels.card, labels.statuses],\n )\n\n const canManage = isPmRole\n\n const emptyStateCopy = React.useMemo(() => {\n const hasFiltersApplied = activeTab !== 'all' || search.trim().length > 0 || Object.values(filterValues).some(Boolean)\n if (hasFiltersApplied) return labels.emptyState.noMatches\n if (!canManage) return labels.emptyState.noAssignments\n return labels.emptyState.noProjects\n }, [activeTab, search, filterValues, canManage, labels.emptyState])\n\n const cardsData: ProjectCardData[] = rows.map((row) => ({\n id: row.id,\n name: row.name,\n code: row.code,\n customerName: row.customerName,\n color: row.color,\n status: row.status,\n hoursWeek: row.hoursWeek,\n hoursTrend: row.hoursTrend,\n members: row.members,\n memberCount: row.memberCount,\n myRole: row.myRole,\n updatedAt: row.updatedAt,\n }))\n\n return (\n <Page>\n <PageBody>\n <div className=\"mb-4\">\n <ProjectsKpiStrip kpis={kpis} labels={kpiLabels} isLoading={isLoadingKpis} />\n </div>\n\n <div className=\"mb-3 flex flex-wrap items-center justify-between gap-3\">\n <SavedViewTabs\n tabs={tabs}\n activeId={activeTab}\n onSelect={handleTabSelect}\n ariaLabel={t('staff.timesheets.projects.portfolio.savedViews.ariaLabel', 'Saved views')}\n />\n <ViewModeToggle\n mode={viewMode}\n onChange={handleViewModeChange}\n tableLabel={labels.viewMode.table}\n cardsLabel={labels.viewMode.cards}\n ariaLabel={t('staff.timesheets.projects.portfolio.viewMode.ariaLabel', 'View mode')}\n />\n </div>\n\n {viewMode === 'cards' ? (\n <div>\n {isLoading ? (\n <div className=\"grid grid-cols-1 gap-3 md:grid-cols-2 lg:grid-cols-3\">\n {Array.from({ length: 6 }).map((_, idx) => (\n <div key={idx} className=\"h-48 animate-pulse rounded-lg border border-border bg-muted/40\" />\n ))}\n </div>\n ) : rows.length === 0 ? (\n <div className=\"rounded-lg border border-dashed border-border bg-card p-10 text-center\">\n <p className=\"text-sm text-muted-foreground\">{emptyStateCopy}</p>\n {canManage ? (\n <div className=\"mt-3\">\n <Button asChild size=\"sm\">\n <Link href=\"/backend/staff/timesheets/projects/create\">\n {labels.actions.addFirst}\n </Link>\n </Button>\n </div>\n ) : null}\n </div>\n ) : (\n <div className=\"grid grid-cols-1 gap-3 md:grid-cols-2 lg:grid-cols-3\">\n {cardsData.map((card) => (\n <ProjectCard\n key={card.id}\n data={card}\n labels={cardLabels}\n showTeam={isPmRole}\n href={`/backend/staff/timesheets/projects/${card.id}`}\n />\n ))}\n </div>\n )}\n </div>\n ) : (\n <DataTable<ProjectRow>\n title={labels.title}\n data={rows}\n columns={columns}\n isLoading={isLoading}\n searchValue={search}\n onSearchChange={handleSearchChange}\n searchPlaceholder={labels.table.search}\n filters={filters}\n filterValues={filterValues}\n onFiltersApply={handleFiltersApply}\n onFiltersClear={handleFiltersClear}\n emptyState={\n <div className=\"py-12 text-center\">\n <p className=\"text-sm text-muted-foreground mb-4\">{emptyStateCopy}</p>\n {canManage ? (\n <Button asChild size=\"sm\">\n <Link href=\"/backend/staff/timesheets/projects/create\">{labels.actions.addFirst}</Link>\n </Button>\n ) : null}\n </div>\n }\n actions={\n canManage ? (\n <Button asChild size=\"sm\">\n <Link href=\"/backend/staff/timesheets/projects/create\">{labels.actions.add}</Link>\n </Button>\n ) : undefined\n }\n refreshButton={{\n label: labels.actions.refresh,\n onRefresh: handleRefresh,\n isRefreshing: isLoading || isRefreshing,\n }}\n sortable\n sorting={sorting}\n onSortingChange={setSorting}\n pagination={{\n page,\n pageSize: PAGE_SIZE,\n total,\n totalPages,\n totalIsCapped,\n onPageChange: setPage,\n }}\n rowActions={(row) => (\n <RowActions\n items={[\n {\n id: 'view',\n label: labels.actions.viewDetails,\n href: `/backend/staff/timesheets/projects/${row.id}`,\n },\n ...(canManage\n ? [\n {\n id: 'delete',\n label: labels.actions.delete,\n destructive: true,\n onSelect: () => {\n void handleDelete(row)\n },\n },\n ]\n : []),\n ]}\n />\n )}\n onRowClick={(row) => router.push(`/backend/staff/timesheets/projects/${row.id}`)}\n />\n )}\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -303,6 +303,7 @@ function WarrantyClaimsPage() {
303
303
  const [page, setPage] = React.useState(initialUrlState.page);
304
304
  const [total, setTotal] = React.useState(0);
305
305
  const [totalPages, setTotalPages] = React.useState(1);
306
+ const [totalIsCapped, setTotalIsCapped] = React.useState(false);
306
307
  const [tabCounts, setTabCounts] = React.useState({});
307
308
  const [search, setSearch] = React.useState(initialUrlState.search);
308
309
  const [filterValues, setFilterValues] = React.useState(initialUrlState.filterValues);
@@ -374,6 +375,7 @@ function WarrantyClaimsPage() {
374
375
  setRows(items.map(normalizeClaimRow).filter((row) => row !== null));
375
376
  setTotal(typeof call.result?.total === "number" ? call.result.total : items.length);
376
377
  setTotalPages(typeof call.result?.totalPages === "number" ? call.result.totalPages : 1);
378
+ setTotalIsCapped(call.result?.totalIsCapped === true);
377
379
  } catch (error) {
378
380
  if (!cancelled) {
379
381
  const message = error instanceof Error ? error.message : t("warranty_claims.list.error.load");
@@ -1036,6 +1038,7 @@ function WarrantyClaimsPage() {
1036
1038
  pageSize: PAGE_SIZE,
1037
1039
  total,
1038
1040
  totalPages,
1041
+ totalIsCapped,
1039
1042
  onPageChange: setPage
1040
1043
  }
1041
1044
  }