@open-mercato/core 0.6.6-develop.6542.1.fee3e68aa6 → 0.6.6-develop.6551.1.1511bfa890
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +2 -2
- package/dist/generated/entities/gateway_session_initialization/index.js +23 -0
- package/dist/generated/entities/gateway_session_initialization/index.js.map +7 -0
- package/dist/generated/entities.ids.generated.js +1 -0
- package/dist/generated/entities.ids.generated.js.map +2 -2
- package/dist/generated/entity-fields-registry.js +12 -0
- package/dist/generated/entity-fields-registry.js.map +2 -2
- package/dist/modules/api_keys/api/keys/route.js +7 -4
- package/dist/modules/api_keys/api/keys/route.js.map +2 -2
- package/dist/modules/attachments/components/AttachmentContentPreview.js +6 -35
- package/dist/modules/attachments/components/AttachmentContentPreview.js.map +2 -2
- package/dist/modules/audit_logs/backend/audit-logs/page.js +14 -24
- package/dist/modules/audit_logs/backend/audit-logs/page.js.map +2 -2
- package/dist/modules/auth/api/autologin.js +85 -0
- package/dist/modules/auth/api/autologin.js.map +7 -0
- package/dist/modules/auth/lib/autologin.js +19 -0
- package/dist/modules/auth/lib/autologin.js.map +7 -0
- package/dist/modules/customer_accounts/api/admin/roles/[id]/acl.js +1 -0
- package/dist/modules/customer_accounts/api/admin/roles/[id]/acl.js.map +2 -2
- package/dist/modules/customer_accounts/api/admin/roles/[id].js +17 -3
- package/dist/modules/customer_accounts/api/admin/roles/[id].js.map +2 -2
- package/dist/modules/customer_accounts/api/portal/users/[id]/roles.js +6 -1
- package/dist/modules/customer_accounts/api/portal/users/[id]/roles.js.map +2 -2
- package/dist/modules/customer_accounts/api/portal/users-invite.js +6 -1
- package/dist/modules/customer_accounts/api/portal/users-invite.js.map +2 -2
- package/dist/modules/customer_accounts/services/customerInvitationService.js +1 -0
- package/dist/modules/customer_accounts/services/customerInvitationService.js.map +2 -2
- package/dist/modules/customer_accounts/services/customerRbacService.js +6 -1
- package/dist/modules/customer_accounts/services/customerRbacService.js.map +2 -2
- package/dist/modules/customers/backend/customers/deals/pipeline/components/ViewTabsRow.js +2 -2
- package/dist/modules/customers/backend/customers/deals/pipeline/components/ViewTabsRow.js.map +2 -2
- package/dist/modules/customers/components/detail/CompanyDetailTabs.js +27 -37
- package/dist/modules/customers/components/detail/CompanyDetailTabs.js.map +2 -2
- package/dist/modules/customers/components/detail/DealDetailTabs.js +23 -35
- package/dist/modules/customers/components/detail/DealDetailTabs.js.map +2 -2
- package/dist/modules/customers/components/detail/DetailTabsLayout.js +6 -21
- package/dist/modules/customers/components/detail/DetailTabsLayout.js.map +2 -2
- package/dist/modules/customers/components/detail/MobilePersonDetail.js +26 -32
- package/dist/modules/customers/components/detail/MobilePersonDetail.js.map +2 -2
- package/dist/modules/customers/components/detail/PersonDetailTabs.js +29 -39
- package/dist/modules/customers/components/detail/PersonDetailTabs.js.map +2 -2
- package/dist/modules/dictionaries/commands/entries.js +7 -14
- package/dist/modules/dictionaries/commands/entries.js.map +2 -2
- package/dist/modules/dictionaries/commands/entry-operations.js +7 -16
- package/dist/modules/dictionaries/commands/entry-operations.js.map +2 -2
- package/dist/modules/dictionaries/commands/factory.js +9 -3
- package/dist/modules/dictionaries/commands/factory.js.map +2 -2
- package/dist/modules/feature_toggles/api/check/boolean/route.js +0 -14
- package/dist/modules/feature_toggles/api/check/boolean/route.js.map +2 -2
- package/dist/modules/feature_toggles/defaults.json +8 -0
- package/dist/modules/integrations/backend/integrations/[id]/page.js +9 -80
- package/dist/modules/integrations/backend/integrations/[id]/page.js.map +2 -2
- package/dist/modules/payment_gateways/data/entities.js +45 -0
- package/dist/modules/payment_gateways/data/entities.js.map +2 -2
- package/dist/modules/payment_gateways/lib/gateway-service.js +173 -38
- package/dist/modules/payment_gateways/lib/gateway-service.js.map +3 -3
- package/dist/modules/payment_gateways/lib/session-idempotency.js +104 -0
- package/dist/modules/payment_gateways/lib/session-idempotency.js.map +7 -0
- package/dist/modules/payment_gateways/migrations/Migration20260709220938_payment_gateways.js +11 -0
- package/dist/modules/payment_gateways/migrations/Migration20260709220938_payment_gateways.js.map +7 -0
- package/dist/modules/planner/backend/planner/availability-rulesets/[id]/page.js +16 -14
- package/dist/modules/planner/backend/planner/availability-rulesets/[id]/page.js.map +2 -2
- package/dist/modules/planner/components/AvailabilityRulesEditor.js +18 -30
- package/dist/modules/planner/components/AvailabilityRulesEditor.js.map +2 -2
- package/dist/modules/resources/backend/resources/resources/[id]/page.js +24 -24
- package/dist/modules/resources/backend/resources/resources/[id]/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/create/page.js +6 -0
- package/dist/modules/sales/backend/sales/channels/create/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/create/page.meta.js +2 -0
- package/dist/modules/sales/backend/sales/channels/create/page.meta.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/offers/page.js +6 -0
- package/dist/modules/sales/backend/sales/channels/offers/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/offers/page.meta.js +2 -0
- package/dist/modules/sales/backend/sales/channels/offers/page.meta.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/page.js +6 -0
- package/dist/modules/sales/backend/sales/channels/page.js.map +2 -2
- package/dist/modules/sales/backend/sales/channels/page.meta.js +2 -0
- package/dist/modules/sales/backend/sales/channels/page.meta.js.map +2 -2
- package/dist/modules/sales/backend/sales/documents/[id]/page.js +6 -4
- package/dist/modules/sales/backend/sales/documents/[id]/page.js.map +2 -2
- package/dist/modules/sales/components/SalesChannelsDisabledNotice.js +15 -0
- package/dist/modules/sales/components/SalesChannelsDisabledNotice.js.map +7 -0
- package/dist/modules/sales/components/documents/SalesDocumentForm.js +7 -3
- package/dist/modules/sales/components/documents/SalesDocumentForm.js.map +2 -2
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js +10 -8
- package/dist/modules/sales/components/documents/SalesDocumentsTable.js.map +2 -2
- package/dist/modules/sales/components/useSalesChannelsEnabled.js +44 -0
- package/dist/modules/sales/components/useSalesChannelsEnabled.js.map +7 -0
- package/dist/modules/sales/lib/salesChannelsToggle.js +18 -0
- package/dist/modules/sales/lib/salesChannelsToggle.js.map +7 -0
- package/dist/modules/sales/lib/salesChannelsToggleId.js +5 -0
- package/dist/modules/sales/lib/salesChannelsToggleId.js.map +7 -0
- package/dist/modules/staff/backend/staff/team-members/[id]/page.js +22 -25
- package/dist/modules/staff/backend/staff/team-members/[id]/page.js.map +2 -2
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js +12 -14
- package/dist/modules/staff/backend/staff/teams/[id]/edit/page.js.map +2 -2
- package/dist/modules/staff/lib/timesheets-projects-ui/SavedViewTabs.js +10 -29
- package/dist/modules/staff/lib/timesheets-projects-ui/SavedViewTabs.js.map +2 -2
- package/dist/modules/sync_excel/lib/adapters/customers.js +19 -20
- package/dist/modules/sync_excel/lib/adapters/customers.js.map +2 -2
- package/dist/modules/sync_excel/lib/parser.js +185 -0
- package/dist/modules/sync_excel/lib/parser.js.map +2 -2
- package/dist/modules/sync_excel/lib/upload-storage.js +20 -1
- package/dist/modules/sync_excel/lib/upload-storage.js.map +2 -2
- package/generated/entities/gateway_session_initialization/index.ts +10 -0
- package/generated/entities.ids.generated.ts +1 -0
- package/generated/entity-fields-registry.ts +12 -0
- package/package.json +7 -7
- package/src/modules/api_keys/api/keys/route.ts +9 -4
- package/src/modules/attachments/components/AttachmentContentPreview.tsx +9 -44
- package/src/modules/audit_logs/backend/audit-logs/page.tsx +12 -22
- package/src/modules/auth/api/autologin.ts +100 -0
- package/src/modules/auth/lib/autologin.ts +36 -0
- package/src/modules/customer_accounts/api/admin/roles/[id]/acl.ts +1 -0
- package/src/modules/customer_accounts/api/admin/roles/[id].ts +17 -3
- package/src/modules/customer_accounts/api/portal/users/[id]/roles.ts +6 -1
- package/src/modules/customer_accounts/api/portal/users-invite.ts +6 -1
- package/src/modules/customer_accounts/services/customerInvitationService.ts +1 -0
- package/src/modules/customer_accounts/services/customerRbacService.ts +9 -2
- package/src/modules/customers/backend/customers/deals/pipeline/components/ViewTabsRow.tsx +6 -2
- package/src/modules/customers/components/detail/CompanyDetailTabs.tsx +27 -49
- package/src/modules/customers/components/detail/DealDetailTabs.tsx +24 -49
- package/src/modules/customers/components/detail/DetailTabsLayout.tsx +13 -24
- package/src/modules/customers/components/detail/MobilePersonDetail.tsx +25 -31
- package/src/modules/customers/components/detail/PersonDetailTabs.tsx +29 -50
- package/src/modules/dictionaries/commands/entries.ts +7 -16
- package/src/modules/dictionaries/commands/entry-operations.ts +8 -18
- package/src/modules/dictionaries/commands/factory.ts +8 -2
- package/src/modules/feature_toggles/api/check/boolean/route.ts +0 -15
- package/src/modules/feature_toggles/defaults.json +8 -0
- package/src/modules/integrations/backend/integrations/[id]/page.tsx +16 -59
- package/src/modules/payment_gateways/data/entities.ts +39 -0
- package/src/modules/payment_gateways/lib/gateway-service.ts +211 -40
- package/src/modules/payment_gateways/lib/session-idempotency.ts +142 -0
- package/src/modules/payment_gateways/migrations/.snapshot-open-mercato.json +236 -0
- package/src/modules/payment_gateways/migrations/Migration20260709220938_payment_gateways.ts +10 -0
- package/src/modules/planner/backend/planner/availability-rulesets/[id]/page.tsx +14 -20
- package/src/modules/planner/components/AvailabilityRulesEditor.tsx +16 -34
- package/src/modules/resources/backend/resources/resources/[id]/page.tsx +27 -37
- package/src/modules/sales/backend/sales/channels/create/page.meta.ts +3 -0
- package/src/modules/sales/backend/sales/channels/create/page.tsx +7 -0
- package/src/modules/sales/backend/sales/channels/offers/page.meta.ts +3 -0
- package/src/modules/sales/backend/sales/channels/offers/page.tsx +7 -0
- package/src/modules/sales/backend/sales/channels/page.meta.ts +4 -0
- package/src/modules/sales/backend/sales/channels/page.tsx +7 -0
- package/src/modules/sales/backend/sales/documents/[id]/page.tsx +7 -5
- package/src/modules/sales/components/SalesChannelsDisabledNotice.tsx +21 -0
- package/src/modules/sales/components/documents/SalesDocumentForm.tsx +7 -3
- package/src/modules/sales/components/documents/SalesDocumentsTable.tsx +10 -8
- package/src/modules/sales/components/useSalesChannelsEnabled.ts +59 -0
- package/src/modules/sales/i18n/de.json +1 -0
- package/src/modules/sales/i18n/en.json +1 -0
- package/src/modules/sales/i18n/es.json +1 -0
- package/src/modules/sales/i18n/pl.json +1 -0
- package/src/modules/sales/lib/salesChannelsToggle.ts +26 -0
- package/src/modules/sales/lib/salesChannelsToggleId.ts +1 -0
- package/src/modules/staff/backend/staff/team-members/[id]/page.tsx +25 -34
- package/src/modules/staff/backend/staff/teams/[id]/edit/page.tsx +11 -17
- package/src/modules/staff/lib/timesheets-projects-ui/SavedViewTabs.tsx +11 -28
- package/src/modules/sync_excel/lib/adapters/customers.ts +20 -22
- package/src/modules/sync_excel/lib/parser.ts +245 -0
- package/src/modules/sync_excel/lib/upload-storage.ts +23 -1
|
@@ -9,13 +9,20 @@ import { collectCustomFieldValues } from '@open-mercato/ui/backend/utils/customF
|
|
|
9
9
|
import { flash } from '@open-mercato/ui/backend/FlashMessages'
|
|
10
10
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
11
11
|
import { useChannelFields, buildChannelPayload, type ChannelFormValues } from '@open-mercato/core/modules/sales/components/channels/channelFormFields'
|
|
12
|
+
import { useSalesChannelsEnabled } from '@open-mercato/core/modules/sales/components/useSalesChannelsEnabled'
|
|
13
|
+
import { SalesChannelsDisabledNotice } from '@open-mercato/core/modules/sales/components/SalesChannelsDisabledNotice'
|
|
12
14
|
import { E } from '#generated/entities.ids.generated'
|
|
13
15
|
|
|
14
16
|
export default function CreateChannelPage() {
|
|
15
17
|
const t = useT()
|
|
16
18
|
const { fields, groups } = useChannelFields()
|
|
19
|
+
const { enabled: channelsEnabled, isLoading: channelsEnabledLoading } = useSalesChannelsEnabled()
|
|
17
20
|
const router = useRouter()
|
|
18
21
|
|
|
22
|
+
if (!channelsEnabled && !channelsEnabledLoading) {
|
|
23
|
+
return <SalesChannelsDisabledNotice />
|
|
24
|
+
}
|
|
25
|
+
|
|
19
26
|
return (
|
|
20
27
|
<Page>
|
|
21
28
|
<PageBody>
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import React from 'react'
|
|
2
|
+
import type { RouteVisibilityContext } from '@open-mercato/shared/modules/registry'
|
|
3
|
+
import { isSalesChannelsEnabledForTenant } from '../../../../lib/salesChannelsToggle'
|
|
2
4
|
|
|
3
5
|
const globeIcon = React.createElement(
|
|
4
6
|
'svg',
|
|
@@ -12,6 +14,7 @@ const globeIcon = React.createElement(
|
|
|
12
14
|
export const metadata = {
|
|
13
15
|
requireAuth: true,
|
|
14
16
|
requireFeatures: ['sales.channels.manage'],
|
|
17
|
+
visible: (ctx: RouteVisibilityContext) => isSalesChannelsEnabledForTenant(ctx.auth?.tenantId ?? null),
|
|
15
18
|
pageTitle: 'Sales channel offers',
|
|
16
19
|
pageTitleKey: 'sales.channels.offers.listTitle',
|
|
17
20
|
pageGroup: 'Sales',
|
|
@@ -18,6 +18,8 @@ import { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuarde
|
|
|
18
18
|
import { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'
|
|
19
19
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
20
20
|
import { mapOfferRow, renderOfferPriceSummary, type OfferRow } from '@open-mercato/core/modules/sales/components/channels/offerTableUtils'
|
|
21
|
+
import { useSalesChannelsEnabled } from '@open-mercato/core/modules/sales/components/useSalesChannelsEnabled'
|
|
22
|
+
import { SalesChannelsDisabledNotice } from '@open-mercato/core/modules/sales/components/SalesChannelsDisabledNotice'
|
|
21
23
|
import { createLogger } from '@open-mercato/shared/lib/logger'
|
|
22
24
|
|
|
23
25
|
const logger = createLogger('sales')
|
|
@@ -34,6 +36,7 @@ const SAVE_CONTEXT_ID = 'sales-channel-offers-list'
|
|
|
34
36
|
|
|
35
37
|
export default function SalesChannelOffersListPage() {
|
|
36
38
|
const t = useT()
|
|
39
|
+
const { enabled: channelsEnabled, isLoading: channelsEnabledLoading } = useSalesChannelsEnabled()
|
|
37
40
|
const router = useRouter()
|
|
38
41
|
const { runMutation, retryLastMutation } = useGuardedMutation<{
|
|
39
42
|
formId: string
|
|
@@ -332,6 +335,10 @@ export default function SalesChannelOffersListPage() {
|
|
|
332
335
|
</div>
|
|
333
336
|
)
|
|
334
337
|
|
|
338
|
+
if (!channelsEnabled && !channelsEnabledLoading) {
|
|
339
|
+
return <SalesChannelsDisabledNotice />
|
|
340
|
+
}
|
|
341
|
+
|
|
335
342
|
return (
|
|
336
343
|
<Page>
|
|
337
344
|
<PageBody>
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
import type { RouteVisibilityContext } from '@open-mercato/shared/modules/registry'
|
|
2
|
+
import { isSalesChannelsEnabledForTenant } from '../../../lib/salesChannelsToggle'
|
|
3
|
+
|
|
1
4
|
export const metadata = {
|
|
2
5
|
requireAuth: true,
|
|
3
6
|
requireFeatures: ['sales.channels.manage'],
|
|
7
|
+
visible: (ctx: RouteVisibilityContext) => isSalesChannelsEnabledForTenant(ctx.auth?.tenantId ?? null),
|
|
4
8
|
pageTitle: 'Sales channels',
|
|
5
9
|
pageTitleKey: 'sales.channels.nav.title',
|
|
6
10
|
pageGroup: 'Sales',
|
|
@@ -16,6 +16,8 @@ import { buildOptimisticLockHeader, extractOptimisticLockConflict } from '@open-
|
|
|
16
16
|
import { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'
|
|
17
17
|
import { useOrganizationScopeVersion } from '@open-mercato/shared/lib/frontend/useOrganizationScope'
|
|
18
18
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
19
|
+
import { useSalesChannelsEnabled } from '../../../components/useSalesChannelsEnabled'
|
|
20
|
+
import { SalesChannelsDisabledNotice } from '../../../components/SalesChannelsDisabledNotice'
|
|
19
21
|
import { createLogger } from '@open-mercato/shared/lib/logger'
|
|
20
22
|
|
|
21
23
|
const logger = createLogger('sales')
|
|
@@ -42,6 +44,7 @@ const SAVE_CONTEXT_ID = 'sales-channels-list'
|
|
|
42
44
|
|
|
43
45
|
export default function SalesChannelsPage() {
|
|
44
46
|
const t = useT()
|
|
47
|
+
const { enabled: channelsEnabled, isLoading: channelsEnabledLoading } = useSalesChannelsEnabled()
|
|
45
48
|
const router = useRouter()
|
|
46
49
|
const { runMutation, retryLastMutation } = useGuardedMutation<{
|
|
47
50
|
formId: string
|
|
@@ -190,6 +193,10 @@ export default function SalesChannelsPage() {
|
|
|
190
193
|
}
|
|
191
194
|
}, [handleRefresh, mutationContext, runMutation, t])
|
|
192
195
|
|
|
196
|
+
if (!channelsEnabled && !channelsEnabledLoading) {
|
|
197
|
+
return <SalesChannelsDisabledNotice />
|
|
198
|
+
}
|
|
199
|
+
|
|
193
200
|
return (
|
|
194
201
|
<Page>
|
|
195
202
|
<PageBody>
|
|
@@ -69,6 +69,7 @@ import { readMarkdownPreferenceCookie, writeMarkdownPreferenceCookie } from '@op
|
|
|
69
69
|
import { InjectionSpot, useInjectionWidgets } from '@open-mercato/ui/backend/injection/InjectionSpot'
|
|
70
70
|
import { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'
|
|
71
71
|
import { buildRecordInjectionContext, useSetCurrentRecordInjectionContext } from '@open-mercato/ui/backend/injection/recordContext'
|
|
72
|
+
import { useSalesChannelsEnabled } from '@open-mercato/core/modules/sales/components/useSalesChannelsEnabled'
|
|
72
73
|
import { createLogger } from '@open-mercato/shared/lib/logger'
|
|
73
74
|
|
|
74
75
|
const logger = createLogger('sales')
|
|
@@ -1894,6 +1895,7 @@ export default function SalesDocumentDetailPage({
|
|
|
1894
1895
|
includeAmountInMessageMetadata?: boolean
|
|
1895
1896
|
}) {
|
|
1896
1897
|
const t = useT()
|
|
1898
|
+
const { enabled: channelsEnabled } = useSalesChannelsEnabled()
|
|
1897
1899
|
const router = useRouter()
|
|
1898
1900
|
const searchParams = useSearchParams()
|
|
1899
1901
|
const pathname = usePathname()
|
|
@@ -2578,11 +2580,11 @@ export default function SalesDocumentDetailPage({
|
|
|
2578
2580
|
}, [record])
|
|
2579
2581
|
|
|
2580
2582
|
React.useEffect(() => {
|
|
2581
|
-
loadChannels().catch(() => {})
|
|
2583
|
+
if (channelsEnabled) loadChannels().catch(() => {})
|
|
2582
2584
|
loadStatuses().catch(() => {})
|
|
2583
2585
|
loadShippingMethods().catch(() => {})
|
|
2584
2586
|
loadPaymentMethods().catch(() => {})
|
|
2585
|
-
}, [loadChannels, loadPaymentMethods, loadShippingMethods, loadStatuses, scopeVersion])
|
|
2587
|
+
}, [channelsEnabled, loadChannels, loadPaymentMethods, loadShippingMethods, loadStatuses, scopeVersion])
|
|
2586
2588
|
|
|
2587
2589
|
React.useEffect(() => {
|
|
2588
2590
|
void refreshPaymentPresence()
|
|
@@ -3955,11 +3957,11 @@ export default function SalesDocumentDetailPage({
|
|
|
3955
3957
|
emptyLabel: t('sales.documents.detail.empty', 'Not set'),
|
|
3956
3958
|
type: 'email' as const,
|
|
3957
3959
|
},
|
|
3958
|
-
{
|
|
3959
|
-
key: 'channel',
|
|
3960
|
+
...(channelsEnabled ? [{
|
|
3961
|
+
key: 'channel' as const,
|
|
3960
3962
|
title: t('sales.documents.detail.channel', 'Channel'),
|
|
3961
3963
|
value: record?.channelId ?? null,
|
|
3962
|
-
},
|
|
3964
|
+
}] : []),
|
|
3963
3965
|
{
|
|
3964
3966
|
key: 'status',
|
|
3965
3967
|
title: t('sales.documents.detail.status', 'Status'),
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import { Page, PageBody } from '@open-mercato/ui/backend/Page'
|
|
5
|
+
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
6
|
+
|
|
7
|
+
export function SalesChannelsDisabledNotice() {
|
|
8
|
+
const t = useT()
|
|
9
|
+
return (
|
|
10
|
+
<Page>
|
|
11
|
+
<PageBody>
|
|
12
|
+
<div className="rounded-lg border bg-muted/50 p-6 text-sm text-muted-foreground">
|
|
13
|
+
{t(
|
|
14
|
+
'sales.channels.disabledNotice',
|
|
15
|
+
'Sales channels are disabled for this tenant. Enable the "Sales Channels" feature toggle to manage them.',
|
|
16
|
+
)}
|
|
17
|
+
</div>
|
|
18
|
+
</PageBody>
|
|
19
|
+
</Page>
|
|
20
|
+
)
|
|
21
|
+
}
|
|
@@ -57,6 +57,7 @@ import {
|
|
|
57
57
|
type AddressValue,
|
|
58
58
|
} from '@open-mercato/core/modules/customers/utils/addressFormat'
|
|
59
59
|
import { AddressEditor, type AddressEditorDraft } from '@open-mercato/core/modules/customers/components/AddressEditor'
|
|
60
|
+
import { useSalesChannelsEnabled } from '../useSalesChannelsEnabled'
|
|
60
61
|
import { createLogger } from '@open-mercato/shared/lib/logger'
|
|
61
62
|
|
|
62
63
|
const logger = createLogger('sales')
|
|
@@ -804,6 +805,7 @@ function CustomerGroupComponent({ values, setValue, t, customers, setCustomers,
|
|
|
804
805
|
|
|
805
806
|
export function SalesDocumentForm({ onCreated, isSubmitting = false, initialKind, inboxPreFill }: SalesDocumentFormProps) {
|
|
806
807
|
const t = useT()
|
|
808
|
+
const { enabled: channelsEnabled } = useSalesChannelsEnabled()
|
|
807
809
|
const [customers, setCustomers] = React.useState<CustomerOption[]>([])
|
|
808
810
|
const [customerLoading, setCustomerLoading] = React.useState(false)
|
|
809
811
|
const [channels, setChannels] = React.useState<ChannelOption[]>([])
|
|
@@ -1174,7 +1176,7 @@ export function SalesDocumentForm({ onCreated, isSubmitting = false, initialKind
|
|
|
1174
1176
|
/>
|
|
1175
1177
|
),
|
|
1176
1178
|
},
|
|
1177
|
-
{
|
|
1179
|
+
...(channelsEnabled ? [{
|
|
1178
1180
|
id: 'channelId',
|
|
1179
1181
|
label: t('sales.documents.form.channel', 'Sales channel'),
|
|
1180
1182
|
type: 'custom',
|
|
@@ -1196,7 +1198,7 @@ export function SalesDocumentForm({ onCreated, isSubmitting = false, initialKind
|
|
|
1196
1198
|
selectedHintLabel={(id) => t('sales.documents.form.channel.selected', 'Selected channel: {{id}}', { id })}
|
|
1197
1199
|
/>
|
|
1198
1200
|
),
|
|
1199
|
-
},
|
|
1201
|
+
} satisfies CrudField] : []),
|
|
1200
1202
|
{
|
|
1201
1203
|
id: 'shippingAddressSection',
|
|
1202
1204
|
label: '',
|
|
@@ -1317,6 +1319,7 @@ export function SalesDocumentForm({ onCreated, isSubmitting = false, initialKind
|
|
|
1317
1319
|
addressOptions,
|
|
1318
1320
|
addressesError,
|
|
1319
1321
|
addressesLoading,
|
|
1322
|
+
channelsEnabled,
|
|
1320
1323
|
currencyLabels,
|
|
1321
1324
|
fetchCurrencyOptions,
|
|
1322
1325
|
loadAddresses,
|
|
@@ -1335,12 +1338,13 @@ export function SalesDocumentForm({ onCreated, isSubmitting = false, initialKind
|
|
|
1335
1338
|
fields: [],
|
|
1336
1339
|
component: (ctx) => <CustomerGroupComponent {...ctx} t={t} customers={customers} setCustomers={setCustomers} customerQuerySetter={customerQuerySetter} loadAddresses={loadAddresses} loadCustomers={loadCustomers} fetchCustomerEmail={fetchCustomerEmail} resetAddressFormState={resetAddressFormState} />,
|
|
1337
1340
|
},
|
|
1338
|
-
{ id: 'channels-comments', title: '', column: 1, fields: ['channelId', 'comments'] },
|
|
1341
|
+
{ id: 'channels-comments', title: '', column: 1, fields: channelsEnabled ? ['channelId', 'comments'] : ['comments'] },
|
|
1339
1342
|
{ id: 'currency', title: '', column: 2, fields: ['currencyCode'] },
|
|
1340
1343
|
{ id: 'shipping', title: '', column: 2, fields: ['shippingAddressSection'] },
|
|
1341
1344
|
{ id: 'billing', title: '', column: 2, fields: ['billingAddressSection'] },
|
|
1342
1345
|
{ id: 'custom', title: t('sales.documents.form.customFields', 'Custom fields'), column: 2, kind: 'customFields' },
|
|
1343
1346
|
], [
|
|
1347
|
+
channelsEnabled,
|
|
1344
1348
|
customers,
|
|
1345
1349
|
fetchCustomerEmail,
|
|
1346
1350
|
loadAddresses,
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
normalizeDictionaryEntries,
|
|
25
25
|
} from '@open-mercato/core/modules/dictionaries/components/dictionaryAppearance'
|
|
26
26
|
import { SALES_DOCUMENT_NUMBER_COLUMN_META } from './salesDocumentsColumns'
|
|
27
|
+
import { useSalesChannelsEnabled } from '../useSalesChannelsEnabled'
|
|
27
28
|
import { createLogger } from '@open-mercato/shared/lib/logger'
|
|
28
29
|
|
|
29
30
|
const logger = createLogger('sales')
|
|
@@ -146,6 +147,7 @@ function normalizeNumberInput(value: unknown): number | null {
|
|
|
146
147
|
|
|
147
148
|
export function SalesDocumentsTable({ kind }: { kind: SalesDocumentKind }) {
|
|
148
149
|
const t = useT()
|
|
150
|
+
const { enabled: channelsEnabled } = useSalesChannelsEnabled()
|
|
149
151
|
const router = useRouter()
|
|
150
152
|
const scopeVersion = useOrganizationScopeVersion()
|
|
151
153
|
const { confirm, ConfirmDialogElement } = useConfirmDialog()
|
|
@@ -293,20 +295,20 @@ export function SalesDocumentsTable({ kind }: { kind: SalesDocumentKind }) {
|
|
|
293
295
|
)
|
|
294
296
|
|
|
295
297
|
React.useEffect(() => {
|
|
296
|
-
loadChannelOptions().catch(() => {})
|
|
298
|
+
if (channelsEnabled) loadChannelOptions().catch(() => {})
|
|
297
299
|
loadTagOptions().catch(() => {})
|
|
298
300
|
loadCustomerOptions().catch(() => {})
|
|
299
301
|
loadStatusMap().catch(() => setStatusMap({}))
|
|
300
|
-
}, [loadChannelOptions, loadCustomerOptions, loadStatusMap, loadTagOptions, scopeVersion])
|
|
302
|
+
}, [channelsEnabled, loadChannelOptions, loadCustomerOptions, loadStatusMap, loadTagOptions, scopeVersion])
|
|
301
303
|
|
|
302
304
|
const filters = React.useMemo<FilterDef[]>(() => [
|
|
303
|
-
{
|
|
305
|
+
...(channelsEnabled ? [{
|
|
304
306
|
id: 'channelId',
|
|
305
307
|
label: t('sales.documents.list.filters.channel', 'Channel'),
|
|
306
308
|
type: 'select',
|
|
307
309
|
options: channelOptions,
|
|
308
310
|
loadOptions: loadChannelOptions,
|
|
309
|
-
},
|
|
311
|
+
} satisfies FilterDef] : []),
|
|
310
312
|
{
|
|
311
313
|
id: 'date',
|
|
312
314
|
label: t('sales.documents.list.filters.date', 'Date'),
|
|
@@ -363,7 +365,7 @@ export function SalesDocumentsTable({ kind }: { kind: SalesDocumentKind }) {
|
|
|
363
365
|
formatValue: (val: string) => tagOptions.find((o) => o.value === val)?.label ?? val,
|
|
364
366
|
formatDescription: (val: string) => tagOptions.find((o) => o.value === val)?.description ?? null,
|
|
365
367
|
},
|
|
366
|
-
], [channelOptions, loadChannelOptions, customerOptions, loadCustomerOptions, loadTagOptions, tagOptions, t])
|
|
368
|
+
], [channelsEnabled, channelOptions, loadChannelOptions, customerOptions, loadCustomerOptions, loadTagOptions, tagOptions, t])
|
|
367
369
|
|
|
368
370
|
const queryParams = React.useMemo(() => {
|
|
369
371
|
const params = new URLSearchParams()
|
|
@@ -615,7 +617,7 @@ export function SalesDocumentsTable({ kind }: { kind: SalesDocumentKind }) {
|
|
|
615
617
|
),
|
|
616
618
|
enableSorting: false,
|
|
617
619
|
},
|
|
618
|
-
{
|
|
620
|
+
...(channelsEnabled ? [{
|
|
619
621
|
accessorKey: 'channelId',
|
|
620
622
|
header: t('sales.documents.list.table.channel', 'Channel'),
|
|
621
623
|
cell: ({ row }) => {
|
|
@@ -627,7 +629,7 @@ export function SalesDocumentsTable({ kind }: { kind: SalesDocumentKind }) {
|
|
|
627
629
|
)
|
|
628
630
|
},
|
|
629
631
|
enableSorting: false,
|
|
630
|
-
},
|
|
632
|
+
} satisfies ColumnDef<SalesDocumentRow>] : []),
|
|
631
633
|
{
|
|
632
634
|
id: 'lineItemCount',
|
|
633
635
|
accessorKey: 'lineItemCount',
|
|
@@ -661,7 +663,7 @@ export function SalesDocumentsTable({ kind }: { kind: SalesDocumentKind }) {
|
|
|
661
663
|
? <span className="text-xs text-muted-foreground">{new Date(row.original.date).toLocaleString()}</span>
|
|
662
664
|
: <span className="text-xs text-muted-foreground">—</span>,
|
|
663
665
|
},
|
|
664
|
-
], [channelOptions, kind, statusMap, t])
|
|
666
|
+
], [channelsEnabled, channelOptions, kind, statusMap, t])
|
|
665
667
|
|
|
666
668
|
const emptyLabel = kind === 'order'
|
|
667
669
|
? t('sales.documents.list.table.emptyOrders', 'No orders yet.')
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import { apiCall } from '@open-mercato/ui/backend/utils/apiCall'
|
|
5
|
+
import { SALES_CHANNELS_TOGGLE_ID } from '../lib/salesChannelsToggleId'
|
|
6
|
+
|
|
7
|
+
export { SALES_CHANNELS_TOGGLE_ID }
|
|
8
|
+
|
|
9
|
+
const CACHE_TTL_MS = 60_000
|
|
10
|
+
|
|
11
|
+
type FeatureToggleCheckResponse = {
|
|
12
|
+
ok?: boolean
|
|
13
|
+
value?: unknown
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Fails open: channels stay visible unless the toggle explicitly resolves to
|
|
17
|
+
// false. A missing toggle definition (404) or an absent feature_toggles module
|
|
18
|
+
// must not hide sales channel UI.
|
|
19
|
+
async function fetchSalesChannelsEnabled(): Promise<boolean> {
|
|
20
|
+
try {
|
|
21
|
+
const call = await apiCall<FeatureToggleCheckResponse>(
|
|
22
|
+
`/api/feature_toggles/check/boolean?identifier=${SALES_CHANNELS_TOGGLE_ID}`,
|
|
23
|
+
)
|
|
24
|
+
if (!call.ok) return true
|
|
25
|
+
return !(call.result?.ok === true && call.result.value === false)
|
|
26
|
+
} catch {
|
|
27
|
+
return true
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
let cache: { value: Promise<boolean>; at: number } | null = null
|
|
32
|
+
|
|
33
|
+
function getSalesChannelsEnabled(): Promise<boolean> {
|
|
34
|
+
const now = Date.now()
|
|
35
|
+
if (!cache || now - cache.at > CACHE_TTL_MS) {
|
|
36
|
+
cache = { value: fetchSalesChannelsEnabled(), at: now }
|
|
37
|
+
}
|
|
38
|
+
return cache.value
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function useSalesChannelsEnabled(): { enabled: boolean; isLoading: boolean } {
|
|
42
|
+
const [resolved, setResolved] = React.useState<boolean | null>(null)
|
|
43
|
+
|
|
44
|
+
React.useEffect(() => {
|
|
45
|
+
let active = true
|
|
46
|
+
getSalesChannelsEnabled()
|
|
47
|
+
.then((value) => {
|
|
48
|
+
if (active) setResolved(value)
|
|
49
|
+
})
|
|
50
|
+
.catch(() => {
|
|
51
|
+
if (active) setResolved(true)
|
|
52
|
+
})
|
|
53
|
+
return () => {
|
|
54
|
+
active = false
|
|
55
|
+
}
|
|
56
|
+
}, [])
|
|
57
|
+
|
|
58
|
+
return { enabled: resolved !== false, isLoading: resolved === null }
|
|
59
|
+
}
|
|
@@ -60,6 +60,7 @@
|
|
|
60
60
|
"sales.channels.actions.backToList": "Zurück zu Kanälen",
|
|
61
61
|
"sales.channels.actions.create": "Kanal hinzufügen",
|
|
62
62
|
"sales.channels.create": "Vertriebskanal erstellen",
|
|
63
|
+
"sales.channels.disabledNotice": "Vertriebskanäle sind für diesen Mandanten deaktiviert. Aktivieren Sie das Feature-Toggle \"Sales Channels\", um sie zu verwalten.",
|
|
63
64
|
"sales.channels.form.address1": "Adresszeile 1",
|
|
64
65
|
"sales.channels.form.address2": "Adresszeile 2",
|
|
65
66
|
"sales.channels.form.city": "Stadt",
|
|
@@ -60,6 +60,7 @@
|
|
|
60
60
|
"sales.channels.actions.backToList": "Back to channels",
|
|
61
61
|
"sales.channels.actions.create": "Add channel",
|
|
62
62
|
"sales.channels.create": "Create sales channel",
|
|
63
|
+
"sales.channels.disabledNotice": "Sales channels are disabled for this tenant. Enable the \"Sales Channels\" feature toggle to manage them.",
|
|
63
64
|
"sales.channels.form.address1": "Address line 1",
|
|
64
65
|
"sales.channels.form.address2": "Address line 2",
|
|
65
66
|
"sales.channels.form.city": "City",
|
|
@@ -60,6 +60,7 @@
|
|
|
60
60
|
"sales.channels.actions.backToList": "Volver a canales",
|
|
61
61
|
"sales.channels.actions.create": "Añadir canal",
|
|
62
62
|
"sales.channels.create": "Crear canal de ventas",
|
|
63
|
+
"sales.channels.disabledNotice": "Los canales de venta están desactivados para este inquilino. Active el conmutador de función \"Sales Channels\" para gestionarlos.",
|
|
63
64
|
"sales.channels.form.address1": "Línea de dirección 1",
|
|
64
65
|
"sales.channels.form.address2": "Línea de dirección 2",
|
|
65
66
|
"sales.channels.form.city": "Ciudad",
|
|
@@ -60,6 +60,7 @@
|
|
|
60
60
|
"sales.channels.actions.backToList": "Powrót do kanałów",
|
|
61
61
|
"sales.channels.actions.create": "Dodaj kanał",
|
|
62
62
|
"sales.channels.create": "Utwórz kanał sprzedaży",
|
|
63
|
+
"sales.channels.disabledNotice": "Kanały sprzedaży są wyłączone dla tego najemcy. Włącz przełącznik funkcji \"Sales Channels\", aby nimi zarządzać.",
|
|
63
64
|
"sales.channels.form.address1": "Adres linia 1",
|
|
64
65
|
"sales.channels.form.address2": "Adres linia 2",
|
|
65
66
|
"sales.channels.form.city": "Miasto",
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { SALES_CHANNELS_TOGGLE_ID } from './salesChannelsToggleId'
|
|
2
|
+
|
|
3
|
+
export { SALES_CHANNELS_TOGGLE_ID }
|
|
4
|
+
|
|
5
|
+
type BoolConfigResult = { ok: boolean; value?: unknown }
|
|
6
|
+
|
|
7
|
+
type FeatureTogglesServiceLike = {
|
|
8
|
+
getBoolConfig: (identifier: string, tenantId: string) => Promise<BoolConfigResult>
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// Server-side counterpart of useSalesChannelsEnabled with the same fail-open
|
|
12
|
+
// contract: channels stay enabled unless the toggle explicitly resolves to
|
|
13
|
+
// false. The DI container and feature_toggles service are optional peers, so
|
|
14
|
+
// they are loaded lazily and any failure keeps channels visible.
|
|
15
|
+
export async function isSalesChannelsEnabledForTenant(tenantId: string | null | undefined): Promise<boolean> {
|
|
16
|
+
if (!tenantId) return true
|
|
17
|
+
try {
|
|
18
|
+
const { createRequestContainer } = await import('@open-mercato/shared/lib/di/container')
|
|
19
|
+
const container = await createRequestContainer()
|
|
20
|
+
const service = container.resolve('featureTogglesService') as FeatureTogglesServiceLike
|
|
21
|
+
const result = await service.getBoolConfig(SALES_CHANNELS_TOGGLE_ID, tenantId)
|
|
22
|
+
return !(result.ok === true && result.value === false)
|
|
23
|
+
} catch {
|
|
24
|
+
return true
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const SALES_CHANNELS_TOGGLE_ID = 'sales_channels_enabled'
|
|
@@ -5,6 +5,7 @@ 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
7
|
import { Button } from '@open-mercato/ui/primitives/button'
|
|
8
|
+
import { Tabs, TabsList, TabsTrigger } from '@open-mercato/ui/primitives/tabs'
|
|
8
9
|
import { readApiResultOrThrow } from '@open-mercato/ui/backend/utils/apiCall'
|
|
9
10
|
import { extractCustomFieldEntries } from '@open-mercato/shared/lib/crud/custom-fields-client'
|
|
10
11
|
import { updateCrud, deleteCrud } from '@open-mercato/ui/backend/utils/crud'
|
|
@@ -432,29 +433,22 @@ export default function StaffTeamMemberDetailPage({ params }: { params?: { id?:
|
|
|
432
433
|
</div>
|
|
433
434
|
</div>
|
|
434
435
|
|
|
435
|
-
<
|
|
436
|
-
|
|
437
|
-
|
|
436
|
+
<Tabs
|
|
437
|
+
value={activePanel}
|
|
438
|
+
onValueChange={(value) => setActivePanel(value as 'details' | 'availability' | 'jobHistory')}
|
|
439
|
+
variant="underline"
|
|
440
|
+
>
|
|
441
|
+
<TabsList
|
|
442
|
+
className="w-full flex-wrap"
|
|
438
443
|
aria-label={t('staff.teamMembers.detail.tabs.label', 'Team member sections')}
|
|
439
444
|
>
|
|
440
445
|
{panelTabs.map((tab) => (
|
|
441
|
-
<
|
|
442
|
-
key={tab.id}
|
|
443
|
-
type="button"
|
|
444
|
-
role="tab"
|
|
445
|
-
aria-selected={activePanel === tab.id}
|
|
446
|
-
onClick={() => setActivePanel(tab.id)}
|
|
447
|
-
className={`relative -mb-px border-b-2 px-0 py-2 text-sm font-medium transition-colors ${
|
|
448
|
-
activePanel === tab.id
|
|
449
|
-
? 'border-accent-indigo text-foreground'
|
|
450
|
-
: 'border-transparent text-muted-foreground hover:text-foreground'
|
|
451
|
-
}`}
|
|
452
|
-
>
|
|
446
|
+
<TabsTrigger key={tab.id} value={tab.id}>
|
|
453
447
|
{tab.label}
|
|
454
|
-
</
|
|
448
|
+
</TabsTrigger>
|
|
455
449
|
))}
|
|
456
|
-
</
|
|
457
|
-
</
|
|
450
|
+
</TabsList>
|
|
451
|
+
</Tabs>
|
|
458
452
|
|
|
459
453
|
{activePanel === 'details' ? (
|
|
460
454
|
<>
|
|
@@ -500,22 +494,19 @@ export default function StaffTeamMemberDetailPage({ params }: { params?: { id?:
|
|
|
500
494
|
|
|
501
495
|
<div className="rounded-lg border bg-card p-4">
|
|
502
496
|
<div className="flex flex-wrap items-center justify-between gap-3">
|
|
503
|
-
<
|
|
504
|
-
{
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
</button>
|
|
517
|
-
))}
|
|
518
|
-
</div>
|
|
497
|
+
<Tabs
|
|
498
|
+
value={activeTab}
|
|
499
|
+
onValueChange={(value) => setActiveTab(value as 'notes' | 'activities' | 'addresses')}
|
|
500
|
+
variant="underline"
|
|
501
|
+
>
|
|
502
|
+
<TabsList className="h-auto flex-wrap border-b-0">
|
|
503
|
+
{tabs.map((tab) => (
|
|
504
|
+
<TabsTrigger key={tab.id} value={tab.id}>
|
|
505
|
+
{tab.label}
|
|
506
|
+
</TabsTrigger>
|
|
507
|
+
))}
|
|
508
|
+
</TabsList>
|
|
509
|
+
</Tabs>
|
|
519
510
|
{sectionAction ? (
|
|
520
511
|
<Button
|
|
521
512
|
type="button"
|
|
@@ -12,6 +12,7 @@ import { buildOptimisticLockHeader } from '@open-mercato/ui/backend/utils/optimi
|
|
|
12
12
|
import { DataTable, withDataTableNamespaces } from '@open-mercato/ui/backend/DataTable'
|
|
13
13
|
import { RowActions } from '@open-mercato/ui/backend/RowActions'
|
|
14
14
|
import { Button } from '@open-mercato/ui/primitives/button'
|
|
15
|
+
import { Tabs, TabsList, TabsTrigger } from '@open-mercato/ui/primitives/tabs'
|
|
15
16
|
import { BooleanIcon } from '@open-mercato/ui/backend/ValueIcons'
|
|
16
17
|
import { flash } from '@open-mercato/ui/backend/FlashMessages'
|
|
17
18
|
import { useT } from '@open-mercato/shared/lib/i18n/context'
|
|
@@ -362,29 +363,22 @@ export default function StaffTeamEditPage({ params }: { params?: { id?: string }
|
|
|
362
363
|
<Page>
|
|
363
364
|
<PageBody>
|
|
364
365
|
<div className="space-y-6">
|
|
365
|
-
<
|
|
366
|
-
|
|
366
|
+
<Tabs
|
|
367
|
+
value={activeTab}
|
|
368
|
+
onValueChange={(value) => setActiveTab(value as 'details' | 'members')}
|
|
369
|
+
variant="underline"
|
|
370
|
+
>
|
|
371
|
+
<TabsList className="w-full flex-wrap" aria-label={memberLabels.tabs.label}>
|
|
367
372
|
{[
|
|
368
373
|
{ id: 'details', label: memberLabels.tabs.details },
|
|
369
374
|
{ id: 'members', label: memberLabels.tabs.members },
|
|
370
375
|
].map((tab) => (
|
|
371
|
-
<
|
|
372
|
-
key={tab.id}
|
|
373
|
-
type="button"
|
|
374
|
-
role="tab"
|
|
375
|
-
aria-selected={activeTab === tab.id}
|
|
376
|
-
onClick={() => setActiveTab(tab.id as 'details' | 'members')}
|
|
377
|
-
className={`relative -mb-px border-b-2 px-0 py-2 text-sm font-medium transition-colors ${
|
|
378
|
-
activeTab === tab.id
|
|
379
|
-
? 'border-accent-indigo text-foreground'
|
|
380
|
-
: 'border-transparent text-muted-foreground hover:text-foreground'
|
|
381
|
-
}`}
|
|
382
|
-
>
|
|
376
|
+
<TabsTrigger key={tab.id} value={tab.id}>
|
|
383
377
|
{tab.label}
|
|
384
|
-
</
|
|
378
|
+
</TabsTrigger>
|
|
385
379
|
))}
|
|
386
|
-
</
|
|
387
|
-
</
|
|
380
|
+
</TabsList>
|
|
381
|
+
</Tabs>
|
|
388
382
|
|
|
389
383
|
{activeTab === 'details' ? (
|
|
390
384
|
<TeamForm
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
3
|
import * as React from 'react'
|
|
4
|
-
import {
|
|
4
|
+
import { Tabs, TabsList, TabsTrigger } from '@open-mercato/ui/primitives/tabs'
|
|
5
5
|
|
|
6
6
|
export type SavedViewTab = {
|
|
7
7
|
id: string
|
|
@@ -19,35 +19,18 @@ export type SavedViewTabsProps = {
|
|
|
19
19
|
|
|
20
20
|
export function SavedViewTabs({ tabs, activeId, onSelect, className, ariaLabel }: SavedViewTabsProps) {
|
|
21
21
|
return (
|
|
22
|
-
<
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
>
|
|
27
|
-
{tabs.map((tab) => {
|
|
28
|
-
const isActive = tab.id === activeId
|
|
29
|
-
return (
|
|
30
|
-
<Button
|
|
22
|
+
<Tabs value={activeId} onValueChange={onSelect} variant="underline" className={className}>
|
|
23
|
+
<TabsList className="w-full flex-wrap" aria-label={ariaLabel ?? 'Saved views'}>
|
|
24
|
+
{tabs.map((tab) => (
|
|
25
|
+
<TabsTrigger
|
|
31
26
|
key={tab.id}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
size="sm"
|
|
35
|
-
role="tab"
|
|
36
|
-
aria-selected={isActive}
|
|
37
|
-
className={`h-auto rounded-none px-3 py-2 text-sm hover:bg-transparent ${
|
|
38
|
-
isActive
|
|
39
|
-
? 'border-b-2 border-foreground font-medium text-foreground'
|
|
40
|
-
: 'border-b-2 border-transparent text-muted-foreground hover:text-foreground'
|
|
41
|
-
}`}
|
|
42
|
-
onClick={() => onSelect(tab.id)}
|
|
27
|
+
value={tab.id}
|
|
28
|
+
count={typeof tab.count === 'number' ? tab.count : undefined}
|
|
43
29
|
>
|
|
44
30
|
{tab.label}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
)
|
|
50
|
-
})}
|
|
51
|
-
</div>
|
|
31
|
+
</TabsTrigger>
|
|
32
|
+
))}
|
|
33
|
+
</TabsList>
|
|
34
|
+
</Tabs>
|
|
52
35
|
)
|
|
53
36
|
}
|