@open-mercato/core 0.4.6-develop-e321a4e2a1 → 0.4.6-main-24e64eef39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +0 -22
- package/dist/modules/api_docs/frontend/docs/api/page.js +1 -1
- package/dist/modules/api_docs/frontend/docs/api/page.js.map +2 -2
- package/dist/modules/attachments/api/library/[id]/route.js +1 -0
- package/dist/modules/attachments/api/library/[id]/route.js.map +2 -2
- package/dist/modules/attachments/components/AttachmentLibrary.js +1 -1
- package/dist/modules/attachments/components/AttachmentLibrary.js.map +2 -2
- package/dist/modules/attachments/lib/partitionEnv.js +1 -1
- package/dist/modules/attachments/lib/partitionEnv.js.map +2 -2
- package/dist/modules/auth/backend/users/page.js +1 -1
- package/dist/modules/auth/backend/users/page.js.map +2 -2
- package/dist/modules/auth/cli.js +1 -1
- package/dist/modules/auth/cli.js.map +2 -2
- package/dist/modules/auth/commands/users.js +1 -1
- package/dist/modules/auth/commands/users.js.map +2 -2
- package/dist/modules/business_rules/components/utils/formHelpers.js +1 -1
- package/dist/modules/business_rules/components/utils/formHelpers.js.map +2 -2
- package/dist/modules/catalog/backend/catalog/products/create/page.js +1 -1
- package/dist/modules/catalog/backend/catalog/products/create/page.js.map +2 -2
- package/dist/modules/catalog/commands/products.js +1 -1
- package/dist/modules/catalog/commands/products.js.map +2 -2
- package/dist/modules/catalog/commands/shared.js +1 -1
- package/dist/modules/catalog/commands/shared.js.map +2 -2
- package/dist/modules/catalog/components/PriceKindSettings.js +1 -1
- package/dist/modules/catalog/components/PriceKindSettings.js.map +2 -2
- package/dist/modules/catalog/components/products/productForm.js +1 -1
- package/dist/modules/catalog/components/products/productForm.js.map +2 -2
- package/dist/modules/configs/lib/upgrade-actions.js.map +1 -1
- package/dist/modules/currencies/services/providers/raiffeisen.js +1 -1
- package/dist/modules/currencies/services/providers/raiffeisen.js.map +2 -2
- package/dist/modules/customers/backend/customers/companies/page.js +3 -3
- package/dist/modules/customers/backend/customers/companies/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/page.js +3 -3
- package/dist/modules/customers/backend/customers/deals/page.js.map +2 -2
- package/dist/modules/customers/backend/customers/people/page.js +3 -3
- package/dist/modules/customers/backend/customers/people/page.js.map +2 -2
- package/dist/modules/customers/cli.js +2 -2
- package/dist/modules/customers/cli.js.map +2 -2
- package/dist/modules/customers/lib/detailHelpers.js +1 -1
- package/dist/modules/customers/lib/detailHelpers.js.map +2 -2
- package/dist/modules/entities/cli.js +1 -1
- package/dist/modules/entities/cli.js.map +2 -2
- package/dist/modules/entities/lib/field-definitions.js +1 -1
- package/dist/modules/entities/lib/field-definitions.js.map +2 -2
- package/dist/modules/entities/lib/install-from-ce.js +1 -1
- package/dist/modules/entities/lib/install-from-ce.js.map +2 -2
- package/dist/modules/inbox_ops/lib/emailParser.js +1 -1
- package/dist/modules/inbox_ops/lib/emailParser.js.map +2 -2
- package/dist/modules/inbox_ops/widgets/notifications/ProposalCreatedRenderer.js +0 -8
- package/dist/modules/inbox_ops/widgets/notifications/ProposalCreatedRenderer.js.map +2 -2
- package/dist/modules/perspectives/services/perspectiveService.js +1 -1
- package/dist/modules/perspectives/services/perspectiveService.js.map +2 -2
- package/dist/modules/planner/backend/planner/availability-rulesets/page.js +3 -3
- package/dist/modules/planner/backend/planner/availability-rulesets/page.js.map +2 -2
- package/dist/modules/query_index/components/QueryIndexesTable.js +7 -7
- package/dist/modules/query_index/components/QueryIndexesTable.js.map +2 -2
- package/dist/modules/query_index/lib/engine.js +1 -1
- package/dist/modules/query_index/lib/engine.js.map +2 -2
- package/dist/modules/resources/backend/resources/resource-types/page.js +2 -2
- package/dist/modules/resources/backend/resources/resource-types/page.js.map +2 -2
- package/dist/modules/resources/backend/resources/resources/page.js +3 -3
- package/dist/modules/resources/backend/resources/resources/page.js.map +2 -2
- package/dist/modules/resources/commands/resources.js +1 -1
- package/dist/modules/resources/commands/resources.js.map +2 -2
- package/dist/modules/resources/lib/seeds.js +1 -1
- package/dist/modules/resources/lib/seeds.js.map +2 -2
- package/dist/modules/sales/api/dashboard/widgets/new-orders/route.js +1 -1
- package/dist/modules/sales/api/dashboard/widgets/new-orders/route.js.map +2 -2
- package/dist/modules/sales/api/dashboard/widgets/new-quotes/route.js +1 -1
- package/dist/modules/sales/api/dashboard/widgets/new-quotes/route.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/page.js +3 -3
- package/dist/modules/sales/backend/sales/channels/page.js.map +2 -2
- package/dist/modules/sales/commands/documents.js +2 -2
- package/dist/modules/sales/commands/documents.js.map +2 -2
- package/dist/modules/sales/components/channels/offerTableUtils.js +2 -3
- package/dist/modules/sales/components/channels/offerTableUtils.js.map +2 -2
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js +4 -4
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js.map +2 -2
- package/dist/modules/sales/components/documents/ShipmentDialog.js +1 -1
- package/dist/modules/sales/components/documents/ShipmentDialog.js.map +2 -2
- package/dist/modules/sales/lib/shipments/snapshots.js.map +1 -1
- package/dist/modules/sales/widgets/notifications/SalesOrderCreatedRenderer.js +0 -8
- package/dist/modules/sales/widgets/notifications/SalesOrderCreatedRenderer.js.map +2 -2
- package/dist/modules/sales/widgets/notifications/SalesQuoteCreatedRenderer.js +0 -8
- package/dist/modules/sales/widgets/notifications/SalesQuoteCreatedRenderer.js.map +2 -2
- package/dist/modules/staff/backend/staff/leave-requests/page.js +3 -3
- package/dist/modules/staff/backend/staff/leave-requests/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/my-leave-requests/page.js +3 -3
- package/dist/modules/staff/backend/staff/my-leave-requests/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-members/page.js +3 -3
- package/dist/modules/staff/backend/staff/team-members/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/team-roles/page.js +2 -2
- package/dist/modules/staff/backend/staff/team-roles/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +3 -3
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/teams/page.js +2 -2
- package/dist/modules/staff/backend/staff/teams/page.js.map +2 -2
- package/dist/modules/workflows/backend/instances/page.js +2 -2
- package/dist/modules/workflows/backend/instances/page.js.map +2 -2
- package/dist/modules/workflows/backend/tasks/page.js +1 -1
- package/dist/modules/workflows/backend/tasks/page.js.map +2 -2
- package/dist/modules/workflows/components/DefinitionTriggersEditor.js +1 -1
- package/dist/modules/workflows/components/DefinitionTriggersEditor.js.map +2 -2
- package/dist/modules/workflows/lib/graph-utils.js +1 -1
- package/dist/modules/workflows/lib/graph-utils.js.map +2 -2
- package/package.json +2 -2
- package/src/modules/api_docs/frontend/docs/api/page.tsx +1 -1
- package/src/modules/attachments/api/library/[id]/route.ts +1 -0
- package/src/modules/attachments/components/AttachmentLibrary.tsx +1 -1
- package/src/modules/attachments/lib/partitionEnv.ts +1 -1
- package/src/modules/auth/backend/users/page.tsx +1 -1
- package/src/modules/auth/cli.ts +1 -1
- package/src/modules/auth/commands/users.ts +1 -1
- package/src/modules/business_rules/components/utils/formHelpers.ts +1 -1
- package/src/modules/catalog/backend/catalog/products/create/page.tsx +1 -1
- package/src/modules/catalog/commands/products.ts +1 -1
- package/src/modules/catalog/commands/shared.ts +1 -1
- package/src/modules/catalog/components/PriceKindSettings.tsx +1 -1
- package/src/modules/catalog/components/products/productForm.ts +1 -1
- package/src/modules/configs/lib/upgrade-actions.ts +1 -1
- package/src/modules/currencies/services/providers/raiffeisen.ts +1 -1
- package/src/modules/customers/backend/customers/companies/page.tsx +3 -3
- package/src/modules/customers/backend/customers/deals/page.tsx +3 -3
- package/src/modules/customers/backend/customers/people/page.tsx +3 -3
- package/src/modules/customers/cli.ts +2 -2
- package/src/modules/customers/lib/detailHelpers.ts +1 -1
- package/src/modules/entities/cli.ts +1 -1
- package/src/modules/entities/lib/field-definitions.ts +1 -1
- package/src/modules/entities/lib/install-from-ce.ts +1 -1
- package/src/modules/inbox_ops/lib/emailParser.ts +1 -1
- package/src/modules/inbox_ops/widgets/notifications/ProposalCreatedRenderer.tsx +0 -8
- package/src/modules/perspectives/services/perspectiveService.ts +1 -1
- package/src/modules/planner/backend/planner/availability-rulesets/page.tsx +4 -3
- package/src/modules/query_index/components/QueryIndexesTable.tsx +7 -7
- package/src/modules/query_index/lib/engine.ts +1 -1
- package/src/modules/resources/backend/resources/resource-types/page.tsx +3 -2
- package/src/modules/resources/backend/resources/resources/page.tsx +3 -3
- package/src/modules/resources/commands/resources.ts +1 -1
- package/src/modules/resources/lib/seeds.ts +1 -1
- package/src/modules/sales/api/dashboard/widgets/new-orders/route.ts +1 -1
- package/src/modules/sales/api/dashboard/widgets/new-quotes/route.ts +1 -1
- package/src/modules/sales/backend/sales/channels/page.tsx +3 -3
- package/src/modules/sales/commands/documents.ts +2 -2
- package/src/modules/sales/components/channels/offerTableUtils.tsx +2 -3
- package/src/modules/sales/components/documents/SalesDocumentsTable.tsx +4 -4
- package/src/modules/sales/components/documents/ShipmentDialog.tsx +1 -1
- package/src/modules/sales/lib/shipments/snapshots.ts +1 -1
- package/src/modules/sales/widgets/notifications/SalesOrderCreatedRenderer.tsx +0 -8
- package/src/modules/sales/widgets/notifications/SalesQuoteCreatedRenderer.tsx +0 -8
- package/src/modules/staff/backend/staff/leave-requests/page.tsx +3 -3
- package/src/modules/staff/backend/staff/my-leave-requests/page.tsx +3 -3
- package/src/modules/staff/backend/staff/team-members/page.tsx +3 -3
- package/src/modules/staff/backend/staff/team-roles/page.tsx +2 -2
- package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +4 -3
- package/src/modules/staff/backend/staff/teams/page.tsx +3 -2
- package/src/modules/workflows/backend/instances/page.tsx +2 -2
- package/src/modules/workflows/backend/tasks/page.tsx +1 -1
- package/src/modules/workflows/components/DefinitionTriggersEditor.tsx +1 -1
- package/src/modules/workflows/lib/graph-utils.ts +1 -1
- package/dist/modules/integrations/acl.js +0 -8
- package/dist/modules/integrations/acl.js.map +0 -7
- package/dist/modules/integrations/data/enrichers.js +0 -72
- package/dist/modules/integrations/data/enrichers.js.map +0 -7
- package/dist/modules/integrations/data/entities.js +0 -63
- package/dist/modules/integrations/data/entities.js.map +0 -7
- package/dist/modules/integrations/index.js +0 -9
- package/dist/modules/integrations/index.js.map +0 -7
- package/dist/modules/integrations/setup.js +0 -13
- package/dist/modules/integrations/setup.js.map +0 -7
- package/dist/modules/integrations/widgets/injection/external-ids/widget.client.js +0 -69
- package/dist/modules/integrations/widgets/injection/external-ids/widget.client.js.map +0 -7
- package/dist/modules/integrations/widgets/injection-table.js +0 -13
- package/dist/modules/integrations/widgets/injection-table.js.map +0 -7
- package/src/modules/integrations/acl.ts +0 -4
- package/src/modules/integrations/data/enrichers.ts +0 -98
- package/src/modules/integrations/data/entities.ts +0 -46
- package/src/modules/integrations/index.ts +0 -5
- package/src/modules/integrations/setup.ts +0 -11
- package/src/modules/integrations/widgets/injection/external-ids/widget.client.tsx +0 -94
- package/src/modules/integrations/widgets/injection-table.ts +0 -17
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/modules/sales/widgets/notifications/SalesQuoteCreatedRenderer.tsx"],
|
|
4
|
-
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { FileText, ExternalLink, DollarSign, User, Calendar } from 'lucide-react'\nimport { useRouter } from 'next/navigation'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { formatRelativeTime } from '@open-mercato/shared/lib/time'\nimport type { NotificationRendererProps } from '@open-mercato/shared/modules/notifications/types'\nimport { formatMoney } from '../../components/documents/lineItemUtils'\nimport { useSalesDocumentTotals } from './useSalesDocumentTotals'\n\nfunction normalizeTotal(value?: string | null): string | null {\n if (!value) return null\n let trimmed = value.trim()\n if (trimmed.startsWith('(') && trimmed.endsWith(')')) {\n trimmed = trimmed.slice(1, -1).trim()\n }\n return trimmed.length ? trimmed : null\n}\n\nexport function SalesQuoteCreatedRenderer({\n notification,\n onAction,\n onDismiss,\n actions = [],\n}: NotificationRendererProps) {\n const t = useT()\n const router = useRouter()\n const [executing, setExecuting] = React.useState(false)\n const isUnread = notification.status === 'unread'\n const quoteNumber = notification.bodyVariables?.quoteNumber ?? notification.titleVariables?.quoteNumber\n const fallbackTotal =\n normalizeTotal(notification.bodyVariables?.totalAmount ?? null) ??\n normalizeTotal(notification.bodyVariables?.total ?? null)\n const { totals } = useSalesDocumentTotals('quote', notification.sourceEntityId)\n\n const currentTotal =\n totals && typeof totals.grandTotalGrossAmount === 'number'\n ? formatMoney(totals.grandTotalGrossAmount, totals.currencyCode)\n : fallbackTotal\n\n const viewAction = actions.find((action) => action.id === 'view') ?? actions[0] ?? null\n\n const handleView = async () => {\n if (!viewAction) {\n if (notification.linkHref) router.push(notification.linkHref)\n return\n }\n setExecuting(true)\n try {\n await onAction(viewAction.id)\n } finally {\n setExecuting(false)\n }\n }\n\n return (\n <div\n className={cn(\n 'group relative px-4 py-3 hover:bg-muted/50 cursor-pointer transition-colors border-l-4 border-l-amber-500',\n isUnread && 'bg-amber-50/50 dark:bg-amber-950/20'\n )}\n onClick={handleView}\n
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport { FileText, ExternalLink, DollarSign, User, Calendar } from 'lucide-react'\nimport { useRouter } from 'next/navigation'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { cn } from '@open-mercato/shared/lib/utils'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { formatRelativeTime } from '@open-mercato/shared/lib/time'\nimport type { NotificationRendererProps } from '@open-mercato/shared/modules/notifications/types'\nimport { formatMoney } from '../../components/documents/lineItemUtils'\nimport { useSalesDocumentTotals } from './useSalesDocumentTotals'\n\nfunction normalizeTotal(value?: string | null): string | null {\n if (!value) return null\n let trimmed = value.trim()\n if (trimmed.startsWith('(') && trimmed.endsWith(')')) {\n trimmed = trimmed.slice(1, -1).trim()\n }\n return trimmed.length ? trimmed : null\n}\n\nexport function SalesQuoteCreatedRenderer({\n notification,\n onAction,\n onDismiss,\n actions = [],\n}: NotificationRendererProps) {\n const t = useT()\n const router = useRouter()\n const [executing, setExecuting] = React.useState(false)\n const isUnread = notification.status === 'unread'\n const quoteNumber = notification.bodyVariables?.quoteNumber ?? notification.titleVariables?.quoteNumber\n const fallbackTotal =\n normalizeTotal(notification.bodyVariables?.totalAmount ?? null) ??\n normalizeTotal(notification.bodyVariables?.total ?? null)\n const { totals } = useSalesDocumentTotals('quote', notification.sourceEntityId)\n\n const currentTotal =\n totals && typeof totals.grandTotalGrossAmount === 'number'\n ? formatMoney(totals.grandTotalGrossAmount, totals.currencyCode)\n : fallbackTotal\n\n const viewAction = actions.find((action) => action.id === 'view') ?? actions[0] ?? null\n\n const handleView = async () => {\n if (!viewAction) {\n if (notification.linkHref) router.push(notification.linkHref)\n return\n }\n setExecuting(true)\n try {\n await onAction(viewAction.id)\n } finally {\n setExecuting(false)\n }\n }\n\n return (\n <div\n className={cn(\n 'group relative px-4 py-3 hover:bg-muted/50 cursor-pointer transition-colors border-l-4 border-l-amber-500',\n isUnread && 'bg-amber-50/50 dark:bg-amber-950/20'\n )}\n onClick={handleView}\n >\n {isUnread && (\n <div className=\"absolute left-1.5 top-1/2 -translate-y-1/2 h-2 w-2 rounded-full bg-primary\" />\n )}\n\n <div className=\"flex gap-3\">\n <div className=\"flex-shrink-0 mt-0.5\">\n <div className=\"h-10 w-10 rounded-lg bg-amber-100 dark:bg-amber-900/40 flex items-center justify-center\">\n <FileText className=\"h-5 w-5 text-amber-600 dark:text-amber-400\" />\n </div>\n </div>\n\n <div className=\"flex-1 min-w-0\">\n <div className=\"flex items-start justify-between gap-2\">\n <div>\n <h4 className={cn('text-sm font-medium', isUnread && 'font-semibold')}>\n {notification.title}\n </h4>\n {quoteNumber && (\n <div className=\"flex items-center gap-1 mt-0.5\">\n <span className=\"text-xs font-mono text-muted-foreground bg-muted px-1.5 py-0.5 rounded\">\n #{quoteNumber}\n </span>\n </div>\n )}\n </div>\n <span className=\"flex-shrink-0 text-xs text-muted-foreground flex items-center gap-1\">\n <Calendar className=\"h-3 w-3\" />\n {formatRelativeTime(notification.createdAt, { translate: t }) ?? ''}\n </span>\n </div>\n\n <div className=\"mt-2 flex items-center gap-4 text-xs text-muted-foreground\">\n {currentTotal && (\n <div className=\"flex items-center gap-1\">\n <DollarSign className=\"h-3 w-3\" />\n <span className=\"font-medium text-foreground\">{currentTotal}</span>\n </div>\n )}\n <div className=\"flex items-center gap-1\">\n <User className=\"h-3 w-3\" />\n <span>{t('sales.notifications.renderer.pendingReview', 'Pending review')}</span>\n </div>\n </div>\n\n <div className=\"mt-3 flex gap-2\">\n <Button\n variant=\"default\"\n size=\"sm\"\n onClick={(e) => {\n e.stopPropagation()\n handleView()\n }}\n disabled={executing || (!viewAction && !notification.linkHref)}\n className=\"gap-1\"\n >\n <ExternalLink className=\"h-3 w-3\" />\n {t('sales.notifications.renderer.viewQuote', 'View Quote')}\n </Button>\n <Button\n variant=\"ghost\"\n size=\"sm\"\n onClick={(e) => {\n e.stopPropagation()\n onDismiss()\n }}\n >\n {t('notifications.actions.dismiss', 'Dismiss')}\n </Button>\n </div>\n </div>\n </div>\n </div>\n )\n}\n\nexport default SalesQuoteCreatedRenderer\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -4,7 +4,7 @@ import * as React from "react";
|
|
|
4
4
|
import Link from "next/link";
|
|
5
5
|
import { useRouter } from "next/navigation";
|
|
6
6
|
import { Page, PageBody } from "@open-mercato/ui/backend/Page";
|
|
7
|
-
import { DataTable
|
|
7
|
+
import { DataTable } from "@open-mercato/ui/backend/DataTable";
|
|
8
8
|
import { Badge } from "@open-mercato/ui/primitives/badge";
|
|
9
9
|
import { Button } from "@open-mercato/ui/primitives/button";
|
|
10
10
|
import { readApiResultOrThrow } from "@open-mercato/ui/backend/utils/apiCall";
|
|
@@ -152,7 +152,7 @@ function mapLeaveRequest(item) {
|
|
|
152
152
|
const status = item.status === "approved" || item.status === "rejected" ? item.status : "pending";
|
|
153
153
|
const reason = typeof item.unavailabilityReasonValue === "string" ? item.unavailabilityReasonValue : typeof item.unavailability_reason_value === "string" ? item.unavailability_reason_value : null;
|
|
154
154
|
const updatedAt = typeof item.updatedAt === "string" ? item.updatedAt : typeof item.updated_at === "string" ? item.updated_at : null;
|
|
155
|
-
return
|
|
155
|
+
return {
|
|
156
156
|
id,
|
|
157
157
|
memberName,
|
|
158
158
|
startDate,
|
|
@@ -160,7 +160,7 @@ function mapLeaveRequest(item) {
|
|
|
160
160
|
status,
|
|
161
161
|
reason,
|
|
162
162
|
updatedAt
|
|
163
|
-
}
|
|
163
|
+
};
|
|
164
164
|
}
|
|
165
165
|
function formatDateRange(start, end) {
|
|
166
166
|
const startLabel = formatDateLabel(start);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/modules/staff/backend/staff/leave-requests/page.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useRouter } from 'next/navigation'\nimport type { ColumnDef, SortingState } from '@tanstack/react-table'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable
|
|
5
|
-
"mappings": ";AAkFQ;AAhFR,YAAY,WAAW;AACvB,OAAO,UAAU;AACjB,SAAS,iBAAiB;AAE1B,SAAS,MAAM,gBAAgB;AAC/B,SAAS,
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useRouter } from 'next/navigation'\nimport type { ColumnDef, SortingState } from '@tanstack/react-table'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport { Badge } from '@open-mercato/ui/primitives/badge'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\n\nconst PAGE_SIZE = 50\n\ntype LeaveRequestRow = {\n id: string\n memberName: string | null\n startDate: string | null\n endDate: string | null\n status: 'pending' | 'approved' | 'rejected'\n reason: string | null\n updatedAt: string | null\n}\n\ntype LeaveRequestsResponse = {\n items?: Array<Record<string, unknown>>\n total?: number\n totalPages?: number\n}\n\nexport default function StaffLeaveRequestsPage() {\n const t = useT()\n const router = useRouter()\n const scopeVersion = useOrganizationScopeVersion()\n const [rows, setRows] = React.useState<LeaveRequestRow[]>([])\n const [page, setPage] = React.useState(1)\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const [search, setSearch] = React.useState('')\n const [isLoading, setIsLoading] = React.useState(true)\n const [sorting, setSorting] = React.useState<SortingState>([{ id: 'startDate', desc: true }])\n\n const labels = React.useMemo(() => ({\n title: t('staff.leaveRequests.page.title', 'Leave requests'),\n table: {\n member: t('staff.leaveRequests.table.member', 'Team member'),\n dates: t('staff.leaveRequests.table.dates', 'Dates'),\n status: t('staff.leaveRequests.table.status', 'Status'),\n reason: t('staff.leaveRequests.table.reason', 'Reason'),\n updatedAt: t('staff.leaveRequests.table.updatedAt', 'Updated'),\n empty: t('staff.leaveRequests.table.empty', 'No leave requests yet.'),\n search: t('staff.leaveRequests.table.search', 'Search leave requests...'),\n },\n actions: {\n add: t('staff.leaveRequests.actions.add', 'New request'),\n refresh: t('staff.leaveRequests.actions.refresh', 'Refresh'),\n },\n errors: {\n load: t('staff.leaveRequests.errors.load', 'Failed to load leave requests.'),\n },\n }), [t])\n\n const columns = React.useMemo<ColumnDef<LeaveRequestRow>[]>(() => [\n {\n accessorKey: 'memberName',\n header: labels.table.member,\n meta: { priority: 1, sticky: true },\n cell: ({ row }) => row.original.memberName ?? '-',\n },\n {\n accessorKey: 'startDate',\n header: labels.table.dates,\n meta: { priority: 2 },\n cell: ({ row }) => formatDateRange(row.original.startDate, row.original.endDate),\n },\n {\n accessorKey: 'status',\n header: labels.table.status,\n meta: { priority: 3 },\n cell: ({ row }) => (\n <Badge variant={resolveStatusVariant(row.original.status)}>\n {t(`staff.leaveRequests.status.${row.original.status}`, row.original.status)}\n </Badge>\n ),\n },\n {\n accessorKey: 'reason',\n header: labels.table.reason,\n meta: { priority: 4, truncate: true, maxWidth: '240px' },\n cell: ({ row }) => row.original.reason ?? '-',\n },\n {\n accessorKey: 'updatedAt',\n header: labels.table.updatedAt,\n meta: { priority: 5 },\n cell: ({ row }) => formatDateLabel(row.original.updatedAt),\n },\n ], [labels, t])\n\n const loadRows = React.useCallback(async () => {\n setIsLoading(true)\n try {\n const params = new URLSearchParams({\n page: String(page),\n pageSize: String(PAGE_SIZE),\n })\n if (search.trim().length) params.set('search', search.trim())\n const activeSort = sorting[0]\n if (activeSort?.id) {\n params.set('sortField', activeSort.id)\n params.set('sortDir', activeSort.desc ? 'desc' : 'asc')\n }\n const payload = await readApiResultOrThrow<LeaveRequestsResponse>(\n `/api/staff/leave-requests?${params.toString()}`,\n undefined,\n { errorMessage: labels.errors.load },\n )\n const items = Array.isArray(payload.items) ? payload.items : []\n setRows(items.map(mapLeaveRequest))\n setTotal(typeof payload.total === 'number' ? payload.total : items.length)\n setTotalPages(typeof payload.totalPages === 'number' ? payload.totalPages : 1)\n } catch {\n setRows([])\n setTotal(0)\n setTotalPages(1)\n } finally {\n setIsLoading(false)\n }\n }, [labels.errors.load, page, search, sorting])\n\n React.useEffect(() => {\n void loadRows()\n }, [loadRows, scopeVersion])\n\n const handleSearchChange = React.useCallback((value: string) => {\n setSearch(value)\n setPage(1)\n }, [])\n\n return (\n <Page>\n <PageBody>\n <DataTable<LeaveRequestRow>\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={<p className=\"py-8 text-center text-sm text-muted-foreground\">{labels.table.empty}</p>}\n actions={(\n <Button asChild size=\"sm\">\n <Link href=\"/backend/staff/leave-requests/create\">{labels.actions.add}</Link>\n </Button>\n )}\n refreshButton={{\n label: labels.actions.refresh,\n onRefresh: loadRows,\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 onRowClick={(row) => {\n router.push(`/backend/staff/leave-requests/${encodeURIComponent(row.id)}`)\n }}\n />\n </PageBody>\n </Page>\n )\n}\n\nfunction mapLeaveRequest(item: Record<string, unknown>): LeaveRequestRow {\n const id = typeof item.id === 'string' ? item.id : ''\n const member = item.member && typeof item.member === 'object'\n ? item.member as { displayName?: unknown }\n : null\n const memberName = typeof member?.displayName === 'string'\n ? member.displayName\n : null\n const startDate = typeof item.startDate === 'string'\n ? item.startDate\n : typeof item.start_date === 'string'\n ? item.start_date\n : null\n const endDate = typeof item.endDate === 'string'\n ? item.endDate\n : typeof item.end_date === 'string'\n ? item.end_date\n : null\n const status = item.status === 'approved' || item.status === 'rejected' ? item.status : 'pending'\n const reason = typeof item.unavailabilityReasonValue === 'string'\n ? item.unavailabilityReasonValue\n : typeof item.unavailability_reason_value === 'string'\n ? item.unavailability_reason_value\n : null\n const updatedAt = typeof item.updatedAt === 'string'\n ? item.updatedAt\n : typeof item.updated_at === 'string'\n ? item.updated_at\n : null\n return {\n id,\n memberName,\n startDate,\n endDate,\n status,\n reason,\n updatedAt,\n }\n}\n\nfunction formatDateRange(start?: string | null, end?: string | null): string {\n const startLabel = formatDateLabel(start)\n const endLabel = formatDateLabel(end)\n if (startLabel && endLabel) return `${startLabel} -> ${endLabel}`\n return startLabel || endLabel || '-'\n}\n\nfunction formatDateLabel(value?: string | null): string {\n if (!value) return ''\n const date = new Date(value)\n if (Number.isNaN(date.getTime())) return value\n return date.toLocaleDateString()\n}\n\nfunction resolveStatusVariant(status: 'pending' | 'approved' | 'rejected') {\n if (status === 'approved') return 'default'\n if (status === 'rejected') return 'destructive'\n return 'secondary'\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -4,7 +4,7 @@ import * as React from "react";
|
|
|
4
4
|
import Link from "next/link";
|
|
5
5
|
import { useRouter } from "next/navigation";
|
|
6
6
|
import { Page, PageBody } from "@open-mercato/ui/backend/Page";
|
|
7
|
-
import { DataTable
|
|
7
|
+
import { DataTable } from "@open-mercato/ui/backend/DataTable";
|
|
8
8
|
import { Badge } from "@open-mercato/ui/primitives/badge";
|
|
9
9
|
import { Button } from "@open-mercato/ui/primitives/button";
|
|
10
10
|
import { readApiResultOrThrow } from "@open-mercato/ui/backend/utils/apiCall";
|
|
@@ -155,14 +155,14 @@ function mapLeaveRequest(item) {
|
|
|
155
155
|
const status = item.status === "approved" || item.status === "rejected" ? item.status : "pending";
|
|
156
156
|
const reason = typeof item.unavailabilityReasonValue === "string" ? item.unavailabilityReasonValue : typeof item.unavailability_reason_value === "string" ? item.unavailability_reason_value : null;
|
|
157
157
|
const updatedAt = typeof item.updatedAt === "string" ? item.updatedAt : typeof item.updated_at === "string" ? item.updated_at : null;
|
|
158
|
-
return
|
|
158
|
+
return {
|
|
159
159
|
id,
|
|
160
160
|
startDate,
|
|
161
161
|
endDate,
|
|
162
162
|
status,
|
|
163
163
|
reason,
|
|
164
164
|
updatedAt
|
|
165
|
-
}
|
|
165
|
+
};
|
|
166
166
|
}
|
|
167
167
|
function formatDateRange(start, end) {
|
|
168
168
|
const startLabel = formatDateLabel(start);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/modules/staff/backend/staff/my-leave-requests/page.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useRouter } from 'next/navigation'\nimport type { ColumnDef, SortingState } from '@tanstack/react-table'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable
|
|
5
|
-
"mappings": ";AA8EQ,cAmEF,YAnEE;AA5ER,YAAY,WAAW;AACvB,OAAO,UAAU;AACjB,SAAS,iBAAiB;AAE1B,SAAS,MAAM,gBAAgB;AAC/B,SAAS,
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport Link from 'next/link'\nimport { useRouter } from 'next/navigation'\nimport type { ColumnDef, SortingState } from '@tanstack/react-table'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport { Badge } from '@open-mercato/ui/primitives/badge'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\n\nconst PAGE_SIZE = 50\n\ntype LeaveRequestRow = {\n id: string\n startDate: string | null\n endDate: string | null\n status: 'pending' | 'approved' | 'rejected'\n reason: string | null\n updatedAt: string | null\n}\n\ntype LeaveRequestsResponse = {\n items?: Array<Record<string, unknown>>\n total?: number\n totalPages?: number\n viewer?: { memberId?: string | null; canSend?: boolean }\n}\n\nexport default function StaffMyLeaveRequestsPage() {\n const t = useT()\n const router = useRouter()\n const scopeVersion = useOrganizationScopeVersion()\n const [rows, setRows] = React.useState<LeaveRequestRow[]>([])\n const [page, setPage] = React.useState(1)\n const [total, setTotal] = React.useState(0)\n const [totalPages, setTotalPages] = React.useState(1)\n const [search, setSearch] = React.useState('')\n const [isLoading, setIsLoading] = React.useState(true)\n const [sorting, setSorting] = React.useState<SortingState>([{ id: 'startDate', desc: true }])\n const [memberId, setMemberId] = React.useState<string | null>(null)\n const [canSend, setCanSend] = React.useState(false)\n\n const labels = React.useMemo(() => ({\n title: t('staff.leaveRequests.my.title', 'My leave requests'),\n table: {\n dates: t('staff.leaveRequests.table.dates', 'Dates'),\n status: t('staff.leaveRequests.table.status', 'Status'),\n reason: t('staff.leaveRequests.table.reason', 'Reason'),\n updatedAt: t('staff.leaveRequests.table.updatedAt', 'Updated'),\n empty: t('staff.leaveRequests.table.empty', 'No leave requests yet.'),\n search: t('staff.leaveRequests.table.search', 'Search leave requests...'),\n },\n actions: {\n add: t('staff.leaveRequests.actions.add', 'New request'),\n refresh: t('staff.leaveRequests.actions.refresh', 'Refresh'),\n createProfile: t('staff.leaveRequests.actions.createProfile', 'Create my profile'),\n },\n errors: {\n load: t('staff.leaveRequests.errors.load', 'Failed to load leave requests.'),\n },\n }), [t])\n\n const columns = React.useMemo<ColumnDef<LeaveRequestRow>[]>(() => [\n {\n accessorKey: 'startDate',\n header: labels.table.dates,\n meta: { priority: 1, sticky: true },\n cell: ({ row }) => formatDateRange(row.original.startDate, row.original.endDate),\n },\n {\n accessorKey: 'status',\n header: labels.table.status,\n meta: { priority: 2 },\n cell: ({ row }) => (\n <Badge variant={resolveStatusVariant(row.original.status)}>\n {t(`staff.leaveRequests.status.${row.original.status}`, row.original.status)}\n </Badge>\n ),\n },\n {\n accessorKey: 'reason',\n header: labels.table.reason,\n meta: { priority: 3, truncate: true, maxWidth: '240px' },\n cell: ({ row }) => row.original.reason ?? '-',\n },\n {\n accessorKey: 'updatedAt',\n header: labels.table.updatedAt,\n meta: { priority: 4 },\n cell: ({ row }) => formatDateLabel(row.original.updatedAt),\n },\n ], [labels.table, t])\n\n const loadRows = React.useCallback(async () => {\n setIsLoading(true)\n try {\n const params = new URLSearchParams({\n page: String(page),\n pageSize: String(PAGE_SIZE),\n })\n if (search.trim().length) params.set('search', search.trim())\n const activeSort = sorting[0]\n if (activeSort?.id) {\n params.set('sortField', activeSort.id)\n params.set('sortDir', activeSort.desc ? 'desc' : 'asc')\n }\n const payload = await readApiResultOrThrow<LeaveRequestsResponse>(\n `/api/staff/leave-requests?${params.toString()}`,\n undefined,\n { errorMessage: labels.errors.load },\n )\n const items = Array.isArray(payload.items) ? payload.items : []\n setRows(items.map(mapLeaveRequest))\n setTotal(typeof payload.total === 'number' ? payload.total : items.length)\n setTotalPages(typeof payload.totalPages === 'number' ? payload.totalPages : 1)\n const viewerMemberId = typeof payload.viewer?.memberId === 'string' ? payload.viewer.memberId : null\n setMemberId(viewerMemberId)\n setCanSend(payload.viewer?.canSend === true)\n } catch {\n setRows([])\n setTotal(0)\n setTotalPages(1)\n setMemberId(null)\n setCanSend(false)\n } finally {\n setIsLoading(false)\n }\n }, [labels.errors.load, page, search, sorting])\n\n React.useEffect(() => {\n void loadRows()\n }, [loadRows, scopeVersion])\n\n const handleSearchChange = React.useCallback((value: string) => {\n setSearch(value)\n setPage(1)\n }, [])\n\n const emptyState = memberId\n ? <p className=\"py-8 text-center text-sm text-muted-foreground\">{labels.table.empty}</p>\n : (\n <div className=\"py-8 text-center text-sm text-muted-foreground space-y-3\">\n <p>{t('staff.leaveRequests.empty.profileRequired', 'Create your team member profile to submit leave requests.')}</p>\n <Button asChild size=\"sm\" variant=\"outline\">\n <Link href=\"/backend/staff/profile/create\">{labels.actions.createProfile}</Link>\n </Button>\n </div>\n )\n\n return (\n <Page>\n <PageBody>\n <DataTable<LeaveRequestRow>\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={emptyState}\n actions={memberId && canSend ? (\n <Button asChild size=\"sm\">\n <Link href=\"/backend/staff/my-leave-requests/create\">{labels.actions.add}</Link>\n </Button>\n ) : null}\n refreshButton={{\n label: labels.actions.refresh,\n onRefresh: loadRows,\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 onRowClick={(row) => {\n router.push(`/backend/staff/my-leave-requests/${encodeURIComponent(row.id)}`)\n }}\n />\n </PageBody>\n </Page>\n )\n}\n\nfunction mapLeaveRequest(item: Record<string, unknown>): LeaveRequestRow {\n const id = typeof item.id === 'string' ? item.id : ''\n const startDate = typeof item.startDate === 'string'\n ? item.startDate\n : typeof item.start_date === 'string'\n ? item.start_date\n : null\n const endDate = typeof item.endDate === 'string'\n ? item.endDate\n : typeof item.end_date === 'string'\n ? item.end_date\n : null\n const status = item.status === 'approved' || item.status === 'rejected' ? item.status : 'pending'\n const reason = typeof item.unavailabilityReasonValue === 'string'\n ? item.unavailabilityReasonValue\n : typeof item.unavailability_reason_value === 'string'\n ? item.unavailability_reason_value\n : null\n const updatedAt = typeof item.updatedAt === 'string'\n ? item.updatedAt\n : typeof item.updated_at === 'string'\n ? item.updated_at\n : null\n return {\n id,\n startDate,\n endDate,\n status,\n reason,\n updatedAt,\n }\n}\n\nfunction formatDateRange(start?: string | null, end?: string | null): string {\n const startLabel = formatDateLabel(start)\n const endLabel = formatDateLabel(end)\n if (startLabel && endLabel) return `${startLabel} -> ${endLabel}`\n return startLabel || endLabel || '-'\n}\n\nfunction formatDateLabel(value?: string | null): string {\n if (!value) return ''\n const date = new Date(value)\n if (Number.isNaN(date.getTime())) return value\n return date.toLocaleDateString()\n}\n\nfunction resolveStatusVariant(status: 'pending' | 'approved' | 'rejected') {\n if (status === 'approved') return 'default'\n if (status === 'rejected') return 'destructive'\n return 'secondary'\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -4,7 +4,7 @@ import * as React from "react";
|
|
|
4
4
|
import Link from "next/link";
|
|
5
5
|
import { usePathname, useRouter, useSearchParams } from "next/navigation";
|
|
6
6
|
import { Page, PageBody } from "@open-mercato/ui/backend/Page";
|
|
7
|
-
import { DataTable
|
|
7
|
+
import { DataTable } from "@open-mercato/ui/backend/DataTable";
|
|
8
8
|
import { RowActions } from "@open-mercato/ui/backend/RowActions";
|
|
9
9
|
import { Button } from "@open-mercato/ui/primitives/button";
|
|
10
10
|
import { BooleanIcon } from "@open-mercato/ui/backend/ValueIcons";
|
|
@@ -375,7 +375,7 @@ function mapApiTeamMember(item) {
|
|
|
375
375
|
const teamId = typeof item.teamId === "string" ? item.teamId : typeof item.team_id === "string" ? item.team_id : null;
|
|
376
376
|
const team = item.team && typeof item.team === "object" ? item.team : null;
|
|
377
377
|
const teamName = typeof team?.name === "string" ? team.name : null;
|
|
378
|
-
return
|
|
378
|
+
return {
|
|
379
379
|
id,
|
|
380
380
|
displayName,
|
|
381
381
|
description,
|
|
@@ -387,7 +387,7 @@ function mapApiTeamMember(item) {
|
|
|
387
387
|
updatedAt,
|
|
388
388
|
teamId,
|
|
389
389
|
teamName
|
|
390
|
-
}
|
|
390
|
+
};
|
|
391
391
|
}
|
|
392
392
|
function compareGroupedRows(field, labels, left, right) {
|
|
393
393
|
const leftTeam = (left.teamName ?? labels.unassignedTeam).toLocaleLowerCase();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/modules/staff/backend/staff/team-members/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 { ColumnDef, SortingFn, 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 { Button } from '@open-mercato/ui/primitives/button'\nimport { BooleanIcon } from '@open-mercato/ui/backend/ValueIcons'\nimport { readApiResultOrThrow, apiCall } from '@open-mercato/ui/backend/utils/apiCall'\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 type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Pencil } from 'lucide-react'\nimport { formatDateTime } from '@open-mercato/shared/lib/time'\n\nconst PAGE_SIZE = 50\n\ntype TeamMemberRow = {\n kind: 'team' | 'member'\n id: string\n teamId: string | null\n teamName: string | null\n roleLabel: string | null\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}\n\ntype TeamMembersResponse = {\n items?: Array<Record<string, unknown>>\n total?: number\n totalPages?: number\n}\n\ntype TeamsResponse = {\n items?: Array<{ id?: string; name?: string }>\n}\n\ntype TeamRolesResponse = {\n items?: Array<{ id?: string; name?: string; team?: { name?: string } | null }>\n}\n\nexport default function StaffTeamMembersPage() {\n const t = useT()\n const router = useRouter()\n const pathname = usePathname()\n const scopeVersion = useOrganizationScopeVersion()\n const searchParams = useSearchParams()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const [rows, setRows] = React.useState<TeamMemberRow[]>([])\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: 'displayName', desc: false }])\n const [search, setSearch] = React.useState('')\n const [isLoading, setIsLoading] = React.useState(true)\n const [reloadToken, setReloadToken] = React.useState(0)\n const [filterValues, setFilterValues] = React.useState<FilterValues>({})\n const [teamFilterOptions, setTeamFilterOptions] = React.useState<Array<{ value: string; label: string }>>([])\n const [roleFilterOptions, setRoleFilterOptions] = React.useState<Array<{ value: string; label: string }>>([])\n const teamFilterParam = searchParams?.get('teamId')\n const roleFilterParam = searchParams?.get('roleId')\n const resolvedTeamId = typeof filterValues.teamId === 'string' && filterValues.teamId.length\n ? filterValues.teamId\n : teamFilterParam\n\n React.useEffect(() => {\n setPage(1)\n }, [teamFilterParam, roleFilterParam])\n\n React.useEffect(() => {\n if (!teamFilterParam) return\n setFilterValues((prev) => {\n if (prev.teamId === teamFilterParam) return prev\n if (typeof prev.teamId === 'string' && prev.teamId.length > 0) return prev\n return { ...prev, teamId: teamFilterParam }\n })\n }, [teamFilterParam])\n\n React.useEffect(() => {\n if (!roleFilterParam) return\n setFilterValues((prev) => {\n if (prev.roleId === roleFilterParam) return prev\n if (typeof prev.roleId === 'string' && prev.roleId.length > 0) return prev\n return { ...prev, roleId: roleFilterParam }\n })\n }, [roleFilterParam])\n\n const labels = React.useMemo(() => ({\n title: t('staff.teamMembers.page.title', '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 groups: {\n unassignedTeam: t('staff.teamMembers.group.unassignedTeam', 'Unassigned team'),\n unassignedRole: t('staff.teamMembers.group.unassignedRole', 'Unassigned role'),\n multipleRoles: t('staff.teamMembers.group.multipleRoles', 'Multiple roles'),\n },\n filters: {\n team: t('staff.teamMembers.filters.team', 'Team'),\n role: t('staff.teamMembers.filters.role', 'Role'),\n },\n actions: {\n add: t('staff.teamMembers.actions.add', 'Add team member'),\n edit: t('staff.teamMembers.actions.edit', 'Edit'),\n delete: t('staff.teamMembers.actions.delete', 'Delete'),\n deleteConfirm: t('staff.teamMembers.actions.deleteConfirm', 'Delete team member \"{{name}}\"?'),\n refresh: t('staff.teamMembers.actions.refresh', 'Refresh'),\n editTeam: t('staff.teams.actions.edit', 'Edit'),\n },\n messages: {\n deleted: t('staff.teamMembers.messages.deleted', 'Team member deleted.'),\n },\n errors: {\n load: t('staff.teamMembers.errors.load', 'Failed to load team members.'),\n delete: t('staff.teamMembers.errors.delete', 'Failed to delete team member.'),\n },\n }), [t])\n\n const groupedSortingFn = React.useCallback((field: GroupedSortField): SortingFn<TeamMemberRow> => {\n return (rowA, rowB) => compareGroupedRows(field, labels.groups, rowA.original, rowB.original)\n }, [labels.groups])\n\n const columns = React.useMemo<ColumnDef<TeamMemberRow>[]>(() => [\n {\n accessorKey: 'displayName',\n header: labels.table.name,\n meta: { priority: 1, sticky: true },\n sortingFn: groupedSortingFn('displayName'),\n cell: ({ row }) => (\n row.original.kind === 'team'\n ? (\n <div className=\"flex items-center justify-between gap-3\">\n <div className=\"flex items-center gap-2\">\n {row.original.teamId ? <TeamsIcon className=\"h-4 w-4 text-muted-foreground\" /> : null}\n <span className=\"font-semibold\">{row.original.displayName}</span>\n </div>\n {row.original.teamId ? (\n <Button\n asChild\n size=\"icon\"\n variant=\"ghost\"\n className=\"h-7 w-7\"\n title={labels.actions.editTeam}\n aria-label={labels.actions.editTeam}\n >\n <Link href={`/backend/staff/teams/${encodeURIComponent(row.original.teamId)}/edit`}>\n <Pencil className=\"h-4 w-4\" />\n </Link>\n </Button>\n ) : null}\n </div>\n )\n : (\n <div className=\"flex flex-col\">\n <span className=\"font-medium pl-6\">{row.original.displayName}</span>\n {row.original.description ? (\n <span className=\"text-xs text-muted-foreground line-clamp-2 pl-6\">{row.original.description}</span>\n ) : null}\n </div>\n )\n ),\n },\n {\n accessorKey: 'userEmail',\n header: labels.table.user,\n meta: { priority: 2 },\n sortingFn: groupedSortingFn('userEmail'),\n cell: ({ row }) => row.original.kind === 'member' && 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: labels.table.roles,\n meta: { priority: 3 },\n sortingFn: groupedSortingFn('roleNames'),\n cell: ({ row }) => row.original.kind === 'member'\n ? renderLabelPills(row.original.roleNames)\n : <span className=\"text-xs text-muted-foreground\">-</span>,\n },\n {\n accessorKey: 'tags',\n header: labels.table.tags,\n meta: { priority: 4 },\n sortingFn: groupedSortingFn('tags'),\n cell: ({ row }) => row.original.kind === 'member'\n ? renderLabelPills(row.original.tags)\n : <span className=\"text-xs text-muted-foreground\">-</span>,\n },\n {\n accessorKey: 'isActive',\n header: labels.table.active,\n meta: { priority: 5 },\n sortingFn: groupedSortingFn('isActive'),\n cell: ({ row }) => row.original.kind === 'member'\n ? <BooleanIcon value={row.original.isActive} />\n : <span className=\"text-xs text-muted-foreground\">-</span>,\n },\n {\n accessorKey: 'updatedAt',\n header: labels.table.updatedAt,\n meta: { priority: 6 },\n sortingFn: groupedSortingFn('updatedAt'),\n cell: ({ row }) => row.original.kind === 'member' && 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 ], [groupedSortingFn, labels.table.active, labels.table.name, labels.table.roles, labels.table.tags, labels.table.updatedAt, labels.table.user])\n\n const loadTeamMembers = 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 if (resolvedTeamId) params.set('teamId', String(resolvedTeamId))\n if (filterValues.roleId) params.set('roleId', String(filterValues.roleId))\n const payload = await readApiResultOrThrow<TeamMembersResponse>(\n `/api/staff/team-members?${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 const mappedItems = items.map(mapApiTeamMember)\n const roleFilterId = typeof filterValues.roleId === 'string' ? filterValues.roleId : null\n const filteredItems = roleFilterId\n ? mappedItems.filter((member) => member.roleIds.includes(roleFilterId))\n : mappedItems\n const roleFilterApplied = roleFilterId != null && filteredItems.length !== mappedItems.length\n setRows(buildTeamMemberRows(filteredItems, labels.groups))\n const resolvedTotal = roleFilterApplied\n ? filteredItems.length\n : typeof payload.total === 'number'\n ? payload.total\n : items.length\n setTotal(resolvedTotal)\n setTotalPages(roleFilterApplied\n ? 1\n : typeof payload.totalPages === 'number'\n ? payload.totalPages\n : Math.max(1, Math.ceil(items.length / PAGE_SIZE)))\n } catch (error) {\n console.error('staff.team-members.list', error)\n flash(labels.errors.load, 'error')\n } finally {\n setIsLoading(false)\n }\n }, [filterValues.roleId, labels.errors.load, labels.groups, page, resolvedTeamId, search, sorting])\n\n React.useEffect(() => {\n void loadTeamMembers()\n }, [loadTeamMembers, scopeVersion, reloadToken])\n\n React.useEffect(() => {\n let cancelled = false\n async function loadFilters() {\n try {\n const teamParams = new URLSearchParams({ page: '1', pageSize: '100' })\n const roleParams = new URLSearchParams({ page: '1', pageSize: '100' })\n const [teamsCall, rolesCall] = await Promise.all([\n apiCall<TeamsResponse>(`/api/staff/teams?${teamParams.toString()}`),\n apiCall<TeamRolesResponse>(`/api/staff/team-roles?${roleParams.toString()}`),\n ])\n const teamItems = Array.isArray(teamsCall.result?.items) ? teamsCall.result.items : []\n const roleItems = Array.isArray(rolesCall.result?.items) ? rolesCall.result.items : []\n const teams = teamItems\n .map((team) => {\n const id = typeof team.id === 'string' ? team.id : null\n const name = typeof team.name === 'string' ? team.name : null\n if (!id || !name) return null\n return { value: id, label: name }\n })\n .filter((entry): entry is { value: string; label: string } => entry !== null)\n const roles = roleItems\n .map((role) => {\n const id = typeof role.id === 'string' ? role.id : null\n const name = typeof role.name === 'string' ? role.name : null\n const teamName = role.team && typeof role.team === 'object' && typeof role.team.name === 'string'\n ? role.team.name\n : labels.groups.unassignedTeam\n if (!id || !name) return null\n return { value: id, label: `${teamName} - ${name}` }\n })\n .filter((entry): entry is { value: string; label: string } => entry !== null)\n if (!cancelled) {\n setTeamFilterOptions(teams)\n setRoleFilterOptions(roles)\n }\n } catch {\n if (!cancelled) {\n setTeamFilterOptions([])\n setRoleFilterOptions([])\n }\n }\n }\n loadFilters()\n return () => { cancelled = true }\n }, [scopeVersion])\n\n const filters = React.useMemo<FilterDef[]>(() => [\n {\n id: 'teamId',\n label: labels.filters.team,\n type: 'select',\n options: teamFilterOptions,\n placeholder: labels.filters.team,\n },\n {\n id: 'roleId',\n label: labels.filters.role,\n type: 'select',\n options: roleFilterOptions,\n placeholder: labels.filters.role,\n },\n ], [labels.filters.role, labels.filters.team, roleFilterOptions, teamFilterOptions])\n\n const handleSearchChange = React.useCallback((value: string) => {\n setSearch(value)\n setPage(1)\n }, [pathname, router, searchParams])\n\n const handleFiltersApply = React.useCallback((values: FilterValues) => {\n setFilterValues(values)\n setPage(1)\n\n const params = new URLSearchParams(searchParams?.toString())\n const hasTeamId = typeof values.teamId === 'string' && values.teamId.length > 0\n if (!hasTeamId && params.has('teamId')) {\n params.delete('teamId')\n }\n const hasRoleId = typeof values.roleId === 'string' && values.roleId.length > 0\n if (!hasRoleId && params.has('roleId')) {\n params.delete('roleId')\n }\n const query = params.toString()\n router.replace(query ? `${pathname}?${query}` : pathname)\n }, [pathname, router, searchParams])\n\n const handleFiltersClear = React.useCallback(() => {\n setFilterValues({})\n setPage(1)\n\n const params = new URLSearchParams(searchParams?.toString())\n if (params.has('teamId')) {\n params.delete('teamId')\n }\n if (params.has('roleId')) {\n params.delete('roleId')\n }\n const query = params.toString()\n router.replace(query ? `${pathname}?${query}` : pathname)\n }, [])\n\n const handleRefresh = React.useCallback(() => {\n setReloadToken((token) => token + 1)\n }, [])\n\n const handleDelete = React.useCallback(async (entry: TeamMemberRow) => {\n if (entry.kind !== 'member') return\n const message = labels.actions.deleteConfirm.replace('{{name}}', entry.displayName)\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 deleteCrud('staff/team-members', entry.id, { errorMessage: labels.errors.delete })\n flash(labels.messages.deleted, 'success')\n handleRefresh()\n } catch (error) {\n console.error('staff.team-members.delete', error)\n flash(labels.errors.delete, 'error')\n }\n }, [confirm, handleRefresh, labels.actions.deleteConfirm, labels.actions.delete, labels.errors.delete, labels.messages.deleted])\n\n return (\n <Page>\n <PageBody>\n <DataTable<TeamMemberRow>\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={<p className=\"py-8 text-center text-sm text-muted-foreground\">{labels.table.empty}</p>}\n actions={(\n <Button asChild size=\"sm\">\n <Link href=\"/backend/staff/team-members/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) => row.kind === 'member' ? (\n <RowActions\n items={[\n { id: 'edit', label: labels.actions.edit, onSelect: () => { router.push(`/backend/staff/team-members/${row.id}`) } },\n { id: 'delete', label: labels.actions.delete, destructive: true, onSelect: () => { void handleDelete(row) } },\n ]}\n />\n ) : null}\n />\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n}\n\ntype TeamMemberApiRow = {\n id: string\n displayName: string\n description: string | null\n userEmail: string | null\n roleNames: string[]\n roleIds: string[]\n tags: string[]\n isActive: boolean\n updatedAt: string | null\n teamId: string | null\n teamName: string | null\n}\n\ntype GroupedSortField = 'displayName' | 'userEmail' | 'roleNames' | 'tags' | 'isActive' | 'updatedAt'\n\nfunction mapApiTeamMember(item: Record<string, unknown>): TeamMemberApiRow {\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 roleIds = Array.isArray(item.roleIds)\n ? item.roleIds.filter((value): value is string => typeof value === 'string')\n : Array.isArray(item.role_ids)\n ? item.role_ids.filter((value): value is string => typeof value === 'string')\n : []\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 const team = item.team && typeof item.team === 'object' ? item.team as { name?: unknown } : null\n const teamName = typeof team?.name === 'string' ? team.name : null\n return withDataTableNamespaces({\n id,\n displayName,\n description,\n userEmail,\n roleNames,\n roleIds,\n tags,\n isActive,\n updatedAt,\n teamId,\n teamName,\n }, item)\n}\n\nfunction compareGroupedRows(\n field: GroupedSortField,\n labels: { unassignedTeam: string },\n left: TeamMemberRow,\n right: TeamMemberRow,\n): number {\n const leftTeam = (left.teamName ?? labels.unassignedTeam).toLocaleLowerCase()\n const rightTeam = (right.teamName ?? labels.unassignedTeam).toLocaleLowerCase()\n const teamComparison = leftTeam.localeCompare(rightTeam)\n if (teamComparison !== 0) return teamComparison\n if (left.kind !== right.kind) return left.kind === 'team' ? -1 : 1\n if (left.kind === 'team' && right.kind === 'team') return 0\n switch (field) {\n case 'displayName':\n return left.displayName.localeCompare(right.displayName)\n case 'userEmail':\n return (left.userEmail ?? '').localeCompare(right.userEmail ?? '')\n case 'roleNames':\n return left.roleNames.join(', ').localeCompare(right.roleNames.join(', '))\n case 'tags':\n return left.tags.join(', ').localeCompare(right.tags.join(', '))\n case 'isActive':\n return Number(left.isActive) - Number(right.isActive)\n case 'updatedAt':\n return compareDateStrings(left.updatedAt, right.updatedAt)\n }\n}\n\nfunction compareDateStrings(left: string | null, right: string | null): number {\n if (!left && !right) return 0\n if (!left) return -1\n if (!right) return 1\n const leftTime = Date.parse(left)\n const rightTime = Date.parse(right)\n if (Number.isNaN(leftTime) || Number.isNaN(rightTime)) {\n return left.localeCompare(right)\n }\n return leftTime - rightTime\n}\n\nfunction buildTeamMemberRows(\n items: TeamMemberApiRow[],\n labels: { unassignedTeam: string; unassignedRole: string; multipleRoles: string },\n): TeamMemberRow[] {\n const teamGroups = new Map<string, { teamId: string | null; name: string; members: TeamMemberApiRow[] }>()\n for (const member of items) {\n const key = member.teamId ?? 'unassigned'\n const name = member.teamName ?? labels.unassignedTeam\n const group = teamGroups.get(key) ?? { teamId: member.teamId ?? null, name, members: [] }\n group.members.push(member)\n teamGroups.set(key, group)\n }\n const sortedTeams = Array.from(teamGroups.values()).sort((a, b) => a.name.localeCompare(b.name))\n const rows: TeamMemberRow[] = []\n for (const team of sortedTeams) {\n rows.push({\n kind: 'team',\n id: `team:${team.teamId ?? 'unassigned'}`,\n teamId: team.teamId,\n teamName: team.name,\n roleLabel: null,\n displayName: team.name,\n description: null,\n userEmail: null,\n roleNames: [],\n tags: [],\n isActive: true,\n updatedAt: null,\n })\n const sortedMembers = [...team.members].sort((a, b) => a.displayName.localeCompare(b.displayName))\n for (const member of sortedMembers) {\n rows.push({\n kind: 'member',\n id: member.id,\n teamId: member.teamId,\n teamName: member.teamName,\n roleLabel: member.roleNames.length\n ? member.roleNames.join(', ')\n : labels.unassignedRole,\n displayName: member.displayName,\n description: member.description,\n userEmail: member.userEmail,\n roleNames: member.roleNames,\n tags: member.tags,\n isActive: member.isActive,\n updatedAt: member.updatedAt,\n })\n }\n }\n return rows\n}\n\n\n\nfunction renderLabelPills(values: string[]): React.ReactNode {\n if (!values.length) return <span className=\"text-xs text-muted-foreground\">-</span>\n return (\n <div className=\"flex flex-wrap gap-2\">\n {values.map((value) => (\n <span key={value} className=\"inline-flex items-center rounded-full border px-3 py-1 text-xs font-medium\">\n {value}\n </span>\n ))}\n </div>\n )\n}\n\nfunction TeamsIcon({ className }: { className?: string }) {\n return (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n className={className}\n aria-hidden=\"true\"\n >\n <circle cx=\"8\" cy=\"8\" r=\"3\" />\n <circle cx=\"16\" cy=\"8\" r=\"3\" />\n <path d=\"M3 20c0-3 3-5 5-5\" />\n <path d=\"M21 20c0-3-3-5-5-5\" />\n </svg>\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 { usePathname, useRouter, useSearchParams } from 'next/navigation'\nimport type { ColumnDef, SortingFn, SortingState } from '@tanstack/react-table'\nimport { Page, PageBody } from '@open-mercato/ui/backend/Page'\nimport { DataTable } from '@open-mercato/ui/backend/DataTable'\nimport { RowActions } from '@open-mercato/ui/backend/RowActions'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { BooleanIcon } from '@open-mercato/ui/backend/ValueIcons'\nimport { readApiResultOrThrow, apiCall } from '@open-mercato/ui/backend/utils/apiCall'\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 type { FilterDef, FilterValues } from '@open-mercato/ui/backend/FilterBar'\nimport { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { Pencil } from 'lucide-react'\nimport { formatDateTime } from '@open-mercato/shared/lib/time'\n\nconst PAGE_SIZE = 50\n\ntype TeamMemberRow = {\n kind: 'team' | 'member'\n id: string\n teamId: string | null\n teamName: string | null\n roleLabel: string | null\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}\n\ntype TeamMembersResponse = {\n items?: Array<Record<string, unknown>>\n total?: number\n totalPages?: number\n}\n\ntype TeamsResponse = {\n items?: Array<{ id?: string; name?: string }>\n}\n\ntype TeamRolesResponse = {\n items?: Array<{ id?: string; name?: string; team?: { name?: string } | null }>\n}\n\nexport default function StaffTeamMembersPage() {\n const t = useT()\n const router = useRouter()\n const pathname = usePathname()\n const scopeVersion = useOrganizationScopeVersion()\n const searchParams = useSearchParams()\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n const [rows, setRows] = React.useState<TeamMemberRow[]>([])\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: 'displayName', desc: false }])\n const [search, setSearch] = React.useState('')\n const [isLoading, setIsLoading] = React.useState(true)\n const [reloadToken, setReloadToken] = React.useState(0)\n const [filterValues, setFilterValues] = React.useState<FilterValues>({})\n const [teamFilterOptions, setTeamFilterOptions] = React.useState<Array<{ value: string; label: string }>>([])\n const [roleFilterOptions, setRoleFilterOptions] = React.useState<Array<{ value: string; label: string }>>([])\n const teamFilterParam = searchParams?.get('teamId')\n const roleFilterParam = searchParams?.get('roleId')\n const resolvedTeamId = typeof filterValues.teamId === 'string' && filterValues.teamId.length\n ? filterValues.teamId\n : teamFilterParam\n\n React.useEffect(() => {\n setPage(1)\n }, [teamFilterParam, roleFilterParam])\n\n React.useEffect(() => {\n if (!teamFilterParam) return\n setFilterValues((prev) => {\n if (prev.teamId === teamFilterParam) return prev\n if (typeof prev.teamId === 'string' && prev.teamId.length > 0) return prev\n return { ...prev, teamId: teamFilterParam }\n })\n }, [teamFilterParam])\n\n React.useEffect(() => {\n if (!roleFilterParam) return\n setFilterValues((prev) => {\n if (prev.roleId === roleFilterParam) return prev\n if (typeof prev.roleId === 'string' && prev.roleId.length > 0) return prev\n return { ...prev, roleId: roleFilterParam }\n })\n }, [roleFilterParam])\n\n const labels = React.useMemo(() => ({\n title: t('staff.teamMembers.page.title', '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 groups: {\n unassignedTeam: t('staff.teamMembers.group.unassignedTeam', 'Unassigned team'),\n unassignedRole: t('staff.teamMembers.group.unassignedRole', 'Unassigned role'),\n multipleRoles: t('staff.teamMembers.group.multipleRoles', 'Multiple roles'),\n },\n filters: {\n team: t('staff.teamMembers.filters.team', 'Team'),\n role: t('staff.teamMembers.filters.role', 'Role'),\n },\n actions: {\n add: t('staff.teamMembers.actions.add', 'Add team member'),\n edit: t('staff.teamMembers.actions.edit', 'Edit'),\n delete: t('staff.teamMembers.actions.delete', 'Delete'),\n deleteConfirm: t('staff.teamMembers.actions.deleteConfirm', 'Delete team member \"{{name}}\"?'),\n refresh: t('staff.teamMembers.actions.refresh', 'Refresh'),\n editTeam: t('staff.teams.actions.edit', 'Edit'),\n },\n messages: {\n deleted: t('staff.teamMembers.messages.deleted', 'Team member deleted.'),\n },\n errors: {\n load: t('staff.teamMembers.errors.load', 'Failed to load team members.'),\n delete: t('staff.teamMembers.errors.delete', 'Failed to delete team member.'),\n },\n }), [t])\n\n const groupedSortingFn = React.useCallback((field: GroupedSortField): SortingFn<TeamMemberRow> => {\n return (rowA, rowB) => compareGroupedRows(field, labels.groups, rowA.original, rowB.original)\n }, [labels.groups])\n\n const columns = React.useMemo<ColumnDef<TeamMemberRow>[]>(() => [\n {\n accessorKey: 'displayName',\n header: labels.table.name,\n meta: { priority: 1, sticky: true },\n sortingFn: groupedSortingFn('displayName'),\n cell: ({ row }) => (\n row.original.kind === 'team'\n ? (\n <div className=\"flex items-center justify-between gap-3\">\n <div className=\"flex items-center gap-2\">\n {row.original.teamId ? <TeamsIcon className=\"h-4 w-4 text-muted-foreground\" /> : null}\n <span className=\"font-semibold\">{row.original.displayName}</span>\n </div>\n {row.original.teamId ? (\n <Button\n asChild\n size=\"icon\"\n variant=\"ghost\"\n className=\"h-7 w-7\"\n title={labels.actions.editTeam}\n aria-label={labels.actions.editTeam}\n >\n <Link href={`/backend/staff/teams/${encodeURIComponent(row.original.teamId)}/edit`}>\n <Pencil className=\"h-4 w-4\" />\n </Link>\n </Button>\n ) : null}\n </div>\n )\n : (\n <div className=\"flex flex-col\">\n <span className=\"font-medium pl-6\">{row.original.displayName}</span>\n {row.original.description ? (\n <span className=\"text-xs text-muted-foreground line-clamp-2 pl-6\">{row.original.description}</span>\n ) : null}\n </div>\n )\n ),\n },\n {\n accessorKey: 'userEmail',\n header: labels.table.user,\n meta: { priority: 2 },\n sortingFn: groupedSortingFn('userEmail'),\n cell: ({ row }) => row.original.kind === 'member' && 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: labels.table.roles,\n meta: { priority: 3 },\n sortingFn: groupedSortingFn('roleNames'),\n cell: ({ row }) => row.original.kind === 'member'\n ? renderLabelPills(row.original.roleNames)\n : <span className=\"text-xs text-muted-foreground\">-</span>,\n },\n {\n accessorKey: 'tags',\n header: labels.table.tags,\n meta: { priority: 4 },\n sortingFn: groupedSortingFn('tags'),\n cell: ({ row }) => row.original.kind === 'member'\n ? renderLabelPills(row.original.tags)\n : <span className=\"text-xs text-muted-foreground\">-</span>,\n },\n {\n accessorKey: 'isActive',\n header: labels.table.active,\n meta: { priority: 5 },\n sortingFn: groupedSortingFn('isActive'),\n cell: ({ row }) => row.original.kind === 'member'\n ? <BooleanIcon value={row.original.isActive} />\n : <span className=\"text-xs text-muted-foreground\">-</span>,\n },\n {\n accessorKey: 'updatedAt',\n header: labels.table.updatedAt,\n meta: { priority: 6 },\n sortingFn: groupedSortingFn('updatedAt'),\n cell: ({ row }) => row.original.kind === 'member' && 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 ], [groupedSortingFn, labels.table.active, labels.table.name, labels.table.roles, labels.table.tags, labels.table.updatedAt, labels.table.user])\n\n const loadTeamMembers = 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 if (resolvedTeamId) params.set('teamId', String(resolvedTeamId))\n if (filterValues.roleId) params.set('roleId', String(filterValues.roleId))\n const payload = await readApiResultOrThrow<TeamMembersResponse>(\n `/api/staff/team-members?${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 const mappedItems = items.map(mapApiTeamMember)\n const roleFilterId = typeof filterValues.roleId === 'string' ? filterValues.roleId : null\n const filteredItems = roleFilterId\n ? mappedItems.filter((member) => member.roleIds.includes(roleFilterId))\n : mappedItems\n const roleFilterApplied = roleFilterId != null && filteredItems.length !== mappedItems.length\n setRows(buildTeamMemberRows(filteredItems, labels.groups))\n const resolvedTotal = roleFilterApplied\n ? filteredItems.length\n : typeof payload.total === 'number'\n ? payload.total\n : items.length\n setTotal(resolvedTotal)\n setTotalPages(roleFilterApplied\n ? 1\n : typeof payload.totalPages === 'number'\n ? payload.totalPages\n : Math.max(1, Math.ceil(items.length / PAGE_SIZE)))\n } catch (error) {\n console.error('staff.team-members.list', error)\n flash(labels.errors.load, 'error')\n } finally {\n setIsLoading(false)\n }\n }, [filterValues.roleId, labels.errors.load, labels.groups, page, resolvedTeamId, search, sorting])\n\n React.useEffect(() => {\n void loadTeamMembers()\n }, [loadTeamMembers, scopeVersion, reloadToken])\n\n React.useEffect(() => {\n let cancelled = false\n async function loadFilters() {\n try {\n const teamParams = new URLSearchParams({ page: '1', pageSize: '100' })\n const roleParams = new URLSearchParams({ page: '1', pageSize: '100' })\n const [teamsCall, rolesCall] = await Promise.all([\n apiCall<TeamsResponse>(`/api/staff/teams?${teamParams.toString()}`),\n apiCall<TeamRolesResponse>(`/api/staff/team-roles?${roleParams.toString()}`),\n ])\n const teamItems = Array.isArray(teamsCall.result?.items) ? teamsCall.result.items : []\n const roleItems = Array.isArray(rolesCall.result?.items) ? rolesCall.result.items : []\n const teams = teamItems\n .map((team) => {\n const id = typeof team.id === 'string' ? team.id : null\n const name = typeof team.name === 'string' ? team.name : null\n if (!id || !name) return null\n return { value: id, label: name }\n })\n .filter((entry): entry is { value: string; label: string } => entry !== null)\n const roles = roleItems\n .map((role) => {\n const id = typeof role.id === 'string' ? role.id : null\n const name = typeof role.name === 'string' ? role.name : null\n const teamName = role.team && typeof role.team === 'object' && typeof role.team.name === 'string'\n ? role.team.name\n : labels.groups.unassignedTeam\n if (!id || !name) return null\n return { value: id, label: `${teamName} - ${name}` }\n })\n .filter((entry): entry is { value: string; label: string } => entry !== null)\n if (!cancelled) {\n setTeamFilterOptions(teams)\n setRoleFilterOptions(roles)\n }\n } catch {\n if (!cancelled) {\n setTeamFilterOptions([])\n setRoleFilterOptions([])\n }\n }\n }\n loadFilters()\n return () => { cancelled = true }\n }, [scopeVersion])\n\n const filters = React.useMemo<FilterDef[]>(() => [\n {\n id: 'teamId',\n label: labels.filters.team,\n type: 'select',\n options: teamFilterOptions,\n placeholder: labels.filters.team,\n },\n {\n id: 'roleId',\n label: labels.filters.role,\n type: 'select',\n options: roleFilterOptions,\n placeholder: labels.filters.role,\n },\n ], [labels.filters.role, labels.filters.team, roleFilterOptions, teamFilterOptions])\n\n const handleSearchChange = React.useCallback((value: string) => {\n setSearch(value)\n setPage(1)\n }, [pathname, router, searchParams])\n\n const handleFiltersApply = React.useCallback((values: FilterValues) => {\n setFilterValues(values)\n setPage(1)\n\n const params = new URLSearchParams(searchParams?.toString())\n const hasTeamId = typeof values.teamId === 'string' && values.teamId.length > 0\n if (!hasTeamId && params.has('teamId')) {\n params.delete('teamId')\n }\n const hasRoleId = typeof values.roleId === 'string' && values.roleId.length > 0\n if (!hasRoleId && params.has('roleId')) {\n params.delete('roleId')\n }\n const query = params.toString()\n router.replace(query ? `${pathname}?${query}` : pathname)\n }, [pathname, router, searchParams])\n\n const handleFiltersClear = React.useCallback(() => {\n setFilterValues({})\n setPage(1)\n\n const params = new URLSearchParams(searchParams?.toString())\n if (params.has('teamId')) {\n params.delete('teamId')\n }\n if (params.has('roleId')) {\n params.delete('roleId')\n }\n const query = params.toString()\n router.replace(query ? `${pathname}?${query}` : pathname)\n }, [])\n\n const handleRefresh = React.useCallback(() => {\n setReloadToken((token) => token + 1)\n }, [])\n\n const handleDelete = React.useCallback(async (entry: TeamMemberRow) => {\n if (entry.kind !== 'member') return\n const message = labels.actions.deleteConfirm.replace('{{name}}', entry.displayName)\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 deleteCrud('staff/team-members', entry.id, { errorMessage: labels.errors.delete })\n flash(labels.messages.deleted, 'success')\n handleRefresh()\n } catch (error) {\n console.error('staff.team-members.delete', error)\n flash(labels.errors.delete, 'error')\n }\n }, [confirm, handleRefresh, labels.actions.deleteConfirm, labels.actions.delete, labels.errors.delete, labels.messages.deleted])\n\n return (\n <Page>\n <PageBody>\n <DataTable<TeamMemberRow>\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={<p className=\"py-8 text-center text-sm text-muted-foreground\">{labels.table.empty}</p>}\n actions={(\n <Button asChild size=\"sm\">\n <Link href=\"/backend/staff/team-members/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) => row.kind === 'member' ? (\n <RowActions\n items={[\n { id: 'edit', label: labels.actions.edit, onSelect: () => { router.push(`/backend/staff/team-members/${row.id}`) } },\n { id: 'delete', label: labels.actions.delete, destructive: true, onSelect: () => { void handleDelete(row) } },\n ]}\n />\n ) : null}\n />\n </PageBody>\n {ConfirmDialogElement}\n </Page>\n )\n}\n\ntype TeamMemberApiRow = {\n id: string\n displayName: string\n description: string | null\n userEmail: string | null\n roleNames: string[]\n roleIds: string[]\n tags: string[]\n isActive: boolean\n updatedAt: string | null\n teamId: string | null\n teamName: string | null\n}\n\ntype GroupedSortField = 'displayName' | 'userEmail' | 'roleNames' | 'tags' | 'isActive' | 'updatedAt'\n\nfunction mapApiTeamMember(item: Record<string, unknown>): TeamMemberApiRow {\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 roleIds = Array.isArray(item.roleIds)\n ? item.roleIds.filter((value): value is string => typeof value === 'string')\n : Array.isArray(item.role_ids)\n ? item.role_ids.filter((value): value is string => typeof value === 'string')\n : []\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 const team = item.team && typeof item.team === 'object' ? item.team as { name?: unknown } : null\n const teamName = typeof team?.name === 'string' ? team.name : null\n return {\n id,\n displayName,\n description,\n userEmail,\n roleNames,\n roleIds,\n tags,\n isActive,\n updatedAt,\n teamId,\n teamName,\n }\n}\n\nfunction compareGroupedRows(\n field: GroupedSortField,\n labels: { unassignedTeam: string },\n left: TeamMemberRow,\n right: TeamMemberRow,\n): number {\n const leftTeam = (left.teamName ?? labels.unassignedTeam).toLocaleLowerCase()\n const rightTeam = (right.teamName ?? labels.unassignedTeam).toLocaleLowerCase()\n const teamComparison = leftTeam.localeCompare(rightTeam)\n if (teamComparison !== 0) return teamComparison\n if (left.kind !== right.kind) return left.kind === 'team' ? -1 : 1\n if (left.kind === 'team' && right.kind === 'team') return 0\n switch (field) {\n case 'displayName':\n return left.displayName.localeCompare(right.displayName)\n case 'userEmail':\n return (left.userEmail ?? '').localeCompare(right.userEmail ?? '')\n case 'roleNames':\n return left.roleNames.join(', ').localeCompare(right.roleNames.join(', '))\n case 'tags':\n return left.tags.join(', ').localeCompare(right.tags.join(', '))\n case 'isActive':\n return Number(left.isActive) - Number(right.isActive)\n case 'updatedAt':\n return compareDateStrings(left.updatedAt, right.updatedAt)\n }\n}\n\nfunction compareDateStrings(left: string | null, right: string | null): number {\n if (!left && !right) return 0\n if (!left) return -1\n if (!right) return 1\n const leftTime = Date.parse(left)\n const rightTime = Date.parse(right)\n if (Number.isNaN(leftTime) || Number.isNaN(rightTime)) {\n return left.localeCompare(right)\n }\n return leftTime - rightTime\n}\n\nfunction buildTeamMemberRows(\n items: TeamMemberApiRow[],\n labels: { unassignedTeam: string; unassignedRole: string; multipleRoles: string },\n): TeamMemberRow[] {\n const teamGroups = new Map<string, { teamId: string | null; name: string; members: TeamMemberApiRow[] }>()\n for (const member of items) {\n const key = member.teamId ?? 'unassigned'\n const name = member.teamName ?? labels.unassignedTeam\n const group = teamGroups.get(key) ?? { teamId: member.teamId ?? null, name, members: [] }\n group.members.push(member)\n teamGroups.set(key, group)\n }\n const sortedTeams = Array.from(teamGroups.values()).sort((a, b) => a.name.localeCompare(b.name))\n const rows: TeamMemberRow[] = []\n for (const team of sortedTeams) {\n rows.push({\n kind: 'team',\n id: `team:${team.teamId ?? 'unassigned'}`,\n teamId: team.teamId,\n teamName: team.name,\n roleLabel: null,\n displayName: team.name,\n description: null,\n userEmail: null,\n roleNames: [],\n tags: [],\n isActive: true,\n updatedAt: null,\n })\n const sortedMembers = [...team.members].sort((a, b) => a.displayName.localeCompare(b.displayName))\n for (const member of sortedMembers) {\n rows.push({\n kind: 'member',\n id: member.id,\n teamId: member.teamId,\n teamName: member.teamName,\n roleLabel: member.roleNames.length\n ? member.roleNames.join(', ')\n : labels.unassignedRole,\n displayName: member.displayName,\n description: member.description,\n userEmail: member.userEmail,\n roleNames: member.roleNames,\n tags: member.tags,\n isActive: member.isActive,\n updatedAt: member.updatedAt,\n })\n }\n }\n return rows\n}\n\n\n\nfunction renderLabelPills(values: string[]): React.ReactNode {\n if (!values.length) return <span className=\"text-xs text-muted-foreground\">-</span>\n return (\n <div className=\"flex flex-wrap gap-2\">\n {values.map((value) => (\n <span key={value} className=\"inline-flex items-center rounded-full border px-3 py-1 text-xs font-medium\">\n {value}\n </span>\n ))}\n </div>\n )\n}\n\nfunction TeamsIcon({ className }: { className?: string }) {\n return (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n className={className}\n aria-hidden=\"true\"\n >\n <circle cx=\"8\" cy=\"8\" r=\"3\" />\n <circle cx=\"16\" cy=\"8\" r=\"3\" />\n <path d=\"M3 20c0-3 3-5 5-5\" />\n <path d=\"M21 20c0-3-3-5-5-5\" />\n </svg>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -5,7 +5,7 @@ import Link from "next/link";
|
|
|
5
5
|
import dynamic from "next/dynamic";
|
|
6
6
|
import { useRouter } from "next/navigation";
|
|
7
7
|
import { Page, PageBody } from "@open-mercato/ui/backend/Page";
|
|
8
|
-
import { DataTable
|
|
8
|
+
import { DataTable } from "@open-mercato/ui/backend/DataTable";
|
|
9
9
|
import { RowActions } from "@open-mercato/ui/backend/RowActions";
|
|
10
10
|
import { Button } from "@open-mercato/ui/primitives/button";
|
|
11
11
|
import { readApiResultOrThrow, apiCall } from "@open-mercato/ui/backend/utils/apiCall";
|
|
@@ -304,7 +304,7 @@ function mapApiTeamRole(item) {
|
|
|
304
304
|
const team = item.team && typeof item.team === "object" ? item.team : null;
|
|
305
305
|
const teamName = typeof team?.name === "string" ? team.name : null;
|
|
306
306
|
const memberCount = typeof item.memberCount === "number" ? item.memberCount : 0;
|
|
307
|
-
return
|
|
307
|
+
return { id, name, description, updatedAt, teamId, teamName, memberCount };
|
|
308
308
|
}
|
|
309
309
|
function buildTeamRoleRows(items, unassignedLabel) {
|
|
310
310
|
const groups = /* @__PURE__ */ new Map();
|