@endora-commerce/mod-sales-channels 0.100.0
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/LICENSE +21 -0
- package/README.md +67 -0
- package/dist/admin/api/sales-channels-client.d.ts +69 -0
- package/dist/admin/api/sales-channels-client.d.ts.map +1 -0
- package/dist/admin/api/sales-channels-client.js +74 -0
- package/dist/admin/api/sales-channels-client.js.map +1 -0
- package/dist/admin/components/ChannelIdentityForm.d.ts +24 -0
- package/dist/admin/components/ChannelIdentityForm.d.ts.map +1 -0
- package/dist/admin/components/ChannelIdentityForm.js +147 -0
- package/dist/admin/components/ChannelIdentityForm.js.map +1 -0
- package/dist/admin/components/DefaultChannelBadge.d.ts +21 -0
- package/dist/admin/components/DefaultChannelBadge.d.ts.map +1 -0
- package/dist/admin/components/DefaultChannelBadge.js +26 -0
- package/dist/admin/components/DefaultChannelBadge.js.map +1 -0
- package/dist/admin/components/EntityChannelMembership.d.ts +52 -0
- package/dist/admin/components/EntityChannelMembership.d.ts.map +1 -0
- package/dist/admin/components/EntityChannelMembership.js +98 -0
- package/dist/admin/components/EntityChannelMembership.js.map +1 -0
- package/dist/admin/index.d.ts +44 -0
- package/dist/admin/index.d.ts.map +1 -0
- package/dist/admin/index.js +148 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/admin/pages/SalesChannelEditPage.d.ts +25 -0
- package/dist/admin/pages/SalesChannelEditPage.d.ts.map +1 -0
- package/dist/admin/pages/SalesChannelEditPage.js +185 -0
- package/dist/admin/pages/SalesChannelEditPage.js.map +1 -0
- package/dist/admin/pages/SalesChannelsListPage.d.ts +25 -0
- package/dist/admin/pages/SalesChannelsListPage.d.ts.map +1 -0
- package/dist/admin/pages/SalesChannelsListPage.js +91 -0
- package/dist/admin/pages/SalesChannelsListPage.js.map +1 -0
- package/dist/admin/zones/OrganizationChannelMembership.d.ts +34 -0
- package/dist/admin/zones/OrganizationChannelMembership.d.ts.map +1 -0
- package/dist/admin/zones/OrganizationChannelMembership.js +11 -0
- package/dist/admin/zones/OrganizationChannelMembership.js.map +1 -0
- package/dist/admin/zones/ProductChannelMembership.d.ts +23 -0
- package/dist/admin/zones/ProductChannelMembership.d.ts.map +1 -0
- package/dist/admin/zones/ProductChannelMembership.js +11 -0
- package/dist/admin/zones/ProductChannelMembership.js.map +1 -0
- package/dist/backend/commands/set-default.command.d.ts +53 -0
- package/dist/backend/commands/set-default.command.d.ts.map +1 -0
- package/dist/backend/commands/set-default.command.js +87 -0
- package/dist/backend/commands/set-default.command.js.map +1 -0
- package/dist/backend/index.d.ts +71 -0
- package/dist/backend/index.d.ts.map +1 -0
- package/dist/backend/index.js +81 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/backend/routes.admin.d.ts +12 -0
- package/dist/backend/routes.admin.d.ts.map +1 -0
- package/dist/backend/routes.admin.js +302 -0
- package/dist/backend/routes.admin.js.map +1 -0
- package/dist/backend/routes.storefront.d.ts +36 -0
- package/dist/backend/routes.storefront.d.ts.map +1 -0
- package/dist/backend/routes.storefront.js +58 -0
- package/dist/backend/routes.storefront.js.map +1 -0
- package/dist/backend/services/index.d.ts +2 -0
- package/dist/backend/services/index.d.ts.map +1 -0
- package/dist/backend/services/index.js +2 -0
- package/dist/backend/services/index.js.map +1 -0
- package/dist/backend/services/sales-channel-attribution-registry.d.ts +28 -0
- package/dist/backend/services/sales-channel-attribution-registry.d.ts.map +1 -0
- package/dist/backend/services/sales-channel-attribution-registry.js +50 -0
- package/dist/backend/services/sales-channel-attribution-registry.js.map +1 -0
- package/dist/backend/services/sales-channels.service.d.ts +247 -0
- package/dist/backend/services/sales-channels.service.d.ts.map +1 -0
- package/dist/backend/services/sales-channels.service.js +535 -0
- package/dist/backend/services/sales-channels.service.js.map +1 -0
- package/dist/manifest.d.ts +185 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +204 -0
- package/dist/manifest.js.map +1 -0
- package/docs/sales_channels/admin-usage.md +77 -0
- package/docs/sales_channels/developer-guide.md +107 -0
- package/docs/sales_channels/index.md +95 -0
- package/i18n/en.json +75 -0
- package/i18n/pl.json +75 -0
- package/package.json +88 -0
- package/tailwind.css +14 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
3
|
+
import { ApiError, apiClient } from '@endora-commerce/admin-kit/lib';
|
|
4
|
+
import { Alert, AlertDescription, Badge, Button, Card, CardContent, CardHeader, CardTitle, Select, } from '@endora-commerce/admin-kit/ui';
|
|
5
|
+
import { useTranslation } from '@endora-commerce/admin-kit/i18n';
|
|
6
|
+
import { DefaultChannelBadge } from './DefaultChannelBadge.js';
|
|
7
|
+
const BASE = '/api/v1/admin/sales-channels';
|
|
8
|
+
export function EntityChannelMembership({ entityType, entityId, onChanged, }) {
|
|
9
|
+
const t = useTranslation('sales_channels');
|
|
10
|
+
const [channels, setChannels] = useState([]);
|
|
11
|
+
const [allChannels, setAllChannels] = useState([]);
|
|
12
|
+
const [loading, setLoading] = useState(false);
|
|
13
|
+
const [busy, setBusy] = useState(false);
|
|
14
|
+
const [error, setError] = useState(null);
|
|
15
|
+
const [pickerCode, setPickerCode] = useState('');
|
|
16
|
+
const refresh = useCallback(async () => {
|
|
17
|
+
if (!entityId)
|
|
18
|
+
return;
|
|
19
|
+
setLoading(true);
|
|
20
|
+
setError(null);
|
|
21
|
+
try {
|
|
22
|
+
const [forEntity, all] = await Promise.all([
|
|
23
|
+
apiClient.get(`${BASE}/by-entity/${entityType}/${encodeURIComponent(entityId)}`),
|
|
24
|
+
apiClient.get(`${BASE}?activeOnly=true`),
|
|
25
|
+
]);
|
|
26
|
+
setChannels(forEntity.channels);
|
|
27
|
+
setAllChannels(all.items);
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
setError(err instanceof ApiError
|
|
31
|
+
? err.envelope.error.message
|
|
32
|
+
: 'Failed to load channel memberships.');
|
|
33
|
+
}
|
|
34
|
+
finally {
|
|
35
|
+
setLoading(false);
|
|
36
|
+
}
|
|
37
|
+
}, [entityType, entityId]);
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
void refresh();
|
|
40
|
+
}, [refresh]);
|
|
41
|
+
const candidates = useMemo(() => allChannels.filter((c) => !channels.some((m) => m.id === c.id)), [allChannels, channels]);
|
|
42
|
+
const handleAdd = useCallback(async () => {
|
|
43
|
+
if (!entityId || !pickerCode)
|
|
44
|
+
return;
|
|
45
|
+
setBusy(true);
|
|
46
|
+
setError(null);
|
|
47
|
+
try {
|
|
48
|
+
await apiClient.put(`${BASE}/${encodeURIComponent(pickerCode)}/${entityType}/${encodeURIComponent(entityId)}`, {});
|
|
49
|
+
setPickerCode('');
|
|
50
|
+
await refresh();
|
|
51
|
+
onChanged?.();
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
setError(err instanceof ApiError ? err.envelope.error.message : 'Add failed.');
|
|
55
|
+
}
|
|
56
|
+
finally {
|
|
57
|
+
setBusy(false);
|
|
58
|
+
}
|
|
59
|
+
}, [pickerCode, entityType, entityId, refresh, onChanged]);
|
|
60
|
+
const handleRemove = useCallback(async (code) => {
|
|
61
|
+
if (!entityId)
|
|
62
|
+
return;
|
|
63
|
+
const path = `${BASE}/${encodeURIComponent(code)}/${entityType}/${encodeURIComponent(entityId)}`;
|
|
64
|
+
setBusy(true);
|
|
65
|
+
setError(null);
|
|
66
|
+
try {
|
|
67
|
+
try {
|
|
68
|
+
await apiClient.delete(path);
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
if (err instanceof ApiError &&
|
|
72
|
+
err.envelope.error.code === 'ENTITY_WOULD_HAVE_ZERO_CHANNELS') {
|
|
73
|
+
if (window.confirm(`${err.envelope.error.message}\n\nRebind this ${entityType} to the system default channel and continue?`)) {
|
|
74
|
+
await apiClient.delete(`${path}?fallbackToDefault=true`);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
throw err;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
await refresh();
|
|
85
|
+
onChanged?.();
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
setError(err instanceof ApiError ? err.envelope.error.message : 'Remove failed.');
|
|
89
|
+
}
|
|
90
|
+
finally {
|
|
91
|
+
setBusy(false);
|
|
92
|
+
}
|
|
93
|
+
}, [entityType, entityId, refresh, onChanged]);
|
|
94
|
+
if (!entityId)
|
|
95
|
+
return null;
|
|
96
|
+
return (_jsxs(Card, { className: "mb-4", children: [_jsx(CardHeader, { children: _jsx(CardTitle, { className: "text-base", children: t('membership.title') }) }), _jsxs(CardContent, { children: [error && (_jsx(Alert, { variant: "destructive", className: "mb-4", children: _jsx(AlertDescription, { children: error }) })), loading ? (_jsx("p", { className: "text-sm text-muted-foreground", children: t('membership.loading') })) : (_jsxs(_Fragment, { children: [channels.length === 0 ? (_jsx("p", { className: "text-sm text-muted-foreground", children: t('membership.empty', { entityType }) })) : (_jsx("ul", { className: "grid gap-2", children: channels.map((c) => (_jsxs("li", { className: "flex items-center justify-between rounded-md border border-input p-2", children: [_jsxs("span", { className: "flex items-center gap-2", children: [_jsx("span", { className: "font-mono text-xs", children: c.code }), _jsx(DefaultChannelBadge, { systemDefault: c.systemDefault }), !c.active && (_jsx(Badge, { variant: "outline", className: "text-[10px]", children: t('status.inactive') })), _jsx("span", { className: "text-xs text-muted-foreground", children: c.name['en-US'] ?? c.name['en'] ?? Object.values(c.name)[0] ?? '' })] }), _jsx(Button, { variant: "ghost", size: "sm", disabled: busy, onClick: () => void handleRemove(c.code), children: t('membership.action.remove') })] }, c.id))) })), candidates.length > 0 && (_jsxs("div", { className: "mt-4 grid grid-cols-[1fr_auto] gap-2", children: [_jsxs(Select, { value: pickerCode, onChange: (e) => setPickerCode(e.target.value), disabled: busy, children: [_jsx("option", { value: "", children: t('membership.action.pickChannel') }), candidates.map((c) => (_jsxs("option", { value: c.code, children: [c.code, c.systemDefault ? t('membership.defaultSuffix') : ''] }, c.id)))] }), _jsx(Button, { onClick: () => void handleAdd(), disabled: busy || !pickerCode, children: t('membership.action.add') })] }))] }))] })] }));
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=EntityChannelMembership.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EntityChannelMembership.js","sourceRoot":"","sources":["../../../src/admin/components/EntityChannelMembership.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `sales_channels`' admin surface — three routes, one sidebar entry and two
|
|
3
|
+
* zone contributions (feature 091, P7a and P7b for the zones, Phase 4 batch 14
|
|
4
|
+
* for the registrations;
|
|
5
|
+
* `specs/091-module-owned-admin-surfaces/contracts/admin-component-contribution.md`
|
|
6
|
+
* §10).
|
|
7
|
+
*
|
|
8
|
+
* **Batch 14 added the three routes and the sidebar entry**, and it is the
|
|
9
|
+
* paragraph that used to stand here arriving as a fact: this entry said its
|
|
10
|
+
* screens *"are still under `admin/src/modules/sales_channels/` and move in
|
|
11
|
+
* Phase 4's batch 14"*. They are this package's now. The property that let the
|
|
12
|
+
* zones land first is unchanged and is what schedules both halves —
|
|
13
|
+
* `check:admin-registrations` counts routes and nav entries and a zone is
|
|
14
|
+
* neither, so a contributor and a host may each move without the other.
|
|
15
|
+
*
|
|
16
|
+
* **This module is also a zone *host*, which is the other half of batch 14.**
|
|
17
|
+
* `SalesChannelEditPage.tsx` renders `sales_channel.editor.after`, the member
|
|
18
|
+
* P7c published for it, and `inventory` contributes its warehouse routing panel
|
|
19
|
+
* there.
|
|
20
|
+
*
|
|
21
|
+
* **What it drains**: the third admin key in
|
|
22
|
+
* `backend/scripts/ledgers/cross-module-imports/catalog.ts` —
|
|
23
|
+
* `ProductEditor.tsx` importing `EntityChannelMembership` from this module's
|
|
24
|
+
* admin directory and rendering it as the whole body of its Channels tab. The
|
|
25
|
+
* host keeps the tab and its label, which is its own vocabulary (Z14), and
|
|
26
|
+
* counts this contribution to decide whether to show the button (Z15).
|
|
27
|
+
*
|
|
28
|
+
* **Zone and not a published component**, decided from the signature read off
|
|
29
|
+
* the file in this merge request (§9.3): `(entityType, entityId, onChanged?)` —
|
|
30
|
+
* identifiers in, a change notification back and no `value`/`onChange` pair, so
|
|
31
|
+
* the component owns its own persistence. That is Z1 question 2.
|
|
32
|
+
*
|
|
33
|
+
* **P7b added the second contribution**, over the same component: it drains the
|
|
34
|
+
* `EntityChannelMembership` key of
|
|
35
|
+
* `backend/scripts/ledgers/cross-module-imports/organizations.ts`, and it is a
|
|
36
|
+
* contribution to a *different* member rather than a `match` on this one,
|
|
37
|
+
* because two hosts with a place each are two members (Z13).
|
|
38
|
+
*
|
|
39
|
+
* **This entry exports data and nothing else** (R2); every component is a
|
|
40
|
+
* dynamic-import factory (R6).
|
|
41
|
+
*/
|
|
42
|
+
import { type AdminContributions } from '@endora-commerce/admin-kit/contributions';
|
|
43
|
+
export declare const contributions: AdminContributions;
|
|
44
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/admin/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,OAAO,EAEL,KAAK,kBAAkB,EACxB,MAAM,0CAA0C,CAAC;AA2ClD,eAAO,MAAM,aAAa,EAAE,kBA0E3B,CAAC"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `sales_channels`' admin surface — three routes, one sidebar entry and two
|
|
3
|
+
* zone contributions (feature 091, P7a and P7b for the zones, Phase 4 batch 14
|
|
4
|
+
* for the registrations;
|
|
5
|
+
* `specs/091-module-owned-admin-surfaces/contracts/admin-component-contribution.md`
|
|
6
|
+
* §10).
|
|
7
|
+
*
|
|
8
|
+
* **Batch 14 added the three routes and the sidebar entry**, and it is the
|
|
9
|
+
* paragraph that used to stand here arriving as a fact: this entry said its
|
|
10
|
+
* screens *"are still under `admin/src/modules/sales_channels/` and move in
|
|
11
|
+
* Phase 4's batch 14"*. They are this package's now. The property that let the
|
|
12
|
+
* zones land first is unchanged and is what schedules both halves —
|
|
13
|
+
* `check:admin-registrations` counts routes and nav entries and a zone is
|
|
14
|
+
* neither, so a contributor and a host may each move without the other.
|
|
15
|
+
*
|
|
16
|
+
* **This module is also a zone *host*, which is the other half of batch 14.**
|
|
17
|
+
* `SalesChannelEditPage.tsx` renders `sales_channel.editor.after`, the member
|
|
18
|
+
* P7c published for it, and `inventory` contributes its warehouse routing panel
|
|
19
|
+
* there.
|
|
20
|
+
*
|
|
21
|
+
* **What it drains**: the third admin key in
|
|
22
|
+
* `backend/scripts/ledgers/cross-module-imports/catalog.ts` —
|
|
23
|
+
* `ProductEditor.tsx` importing `EntityChannelMembership` from this module's
|
|
24
|
+
* admin directory and rendering it as the whole body of its Channels tab. The
|
|
25
|
+
* host keeps the tab and its label, which is its own vocabulary (Z14), and
|
|
26
|
+
* counts this contribution to decide whether to show the button (Z15).
|
|
27
|
+
*
|
|
28
|
+
* **Zone and not a published component**, decided from the signature read off
|
|
29
|
+
* the file in this merge request (§9.3): `(entityType, entityId, onChanged?)` —
|
|
30
|
+
* identifiers in, a change notification back and no `value`/`onChange` pair, so
|
|
31
|
+
* the component owns its own persistence. That is Z1 question 2.
|
|
32
|
+
*
|
|
33
|
+
* **P7b added the second contribution**, over the same component: it drains the
|
|
34
|
+
* `EntityChannelMembership` key of
|
|
35
|
+
* `backend/scripts/ledgers/cross-module-imports/organizations.ts`, and it is a
|
|
36
|
+
* contribution to a *different* member rather than a `match` on this one,
|
|
37
|
+
* because two hosts with a place each are two members (Z13).
|
|
38
|
+
*
|
|
39
|
+
* **This entry exports data and nothing else** (R2); every component is a
|
|
40
|
+
* dynamic-import factory (R6).
|
|
41
|
+
*/
|
|
42
|
+
import { zoneComponent, } from '@endora-commerce/admin-kit/contributions';
|
|
43
|
+
/**
|
|
44
|
+
* The one code that opens every surface below — the three screens and the two
|
|
45
|
+
* contributions alike.
|
|
46
|
+
*
|
|
47
|
+
* `packages/modules/sales_channels/src/backend/routes.admin.ts` gates the
|
|
48
|
+
* channel roster and one channel with `sales_channels:read` and every write
|
|
49
|
+
* with `sales_channels:write`, which each screen checks for itself through
|
|
50
|
+
* `useAuth().hasPermission`. It also gates
|
|
51
|
+
* `GET /api/v1/admin/sales-channels/by-entity/:entityType/:entityId` and
|
|
52
|
+
* `GET /api/v1/admin/sales-channels` with `sales_channels:read`; the add and
|
|
53
|
+
* remove behind the panel's two controls take `sales_channels:write`, which a
|
|
54
|
+
* contribution cannot declare a second time. The read code is what makes the
|
|
55
|
+
* surface appear, and it is the honest one: an operator holding it can see the
|
|
56
|
+
* memberships even if the buttons then refuse.
|
|
57
|
+
*/
|
|
58
|
+
const READ_PERMISSION = 'sales_channels:read';
|
|
59
|
+
/**
|
|
60
|
+
* The code the create route enforces.
|
|
61
|
+
*
|
|
62
|
+
* `POST /api/v1/admin/sales-channels` is `requireAdmin('sales_channels:write')`
|
|
63
|
+
* and `/sales-channels/new` lands straight on the form — a screen whose only
|
|
64
|
+
* purpose is a write. The codes are opaque strings, so an operator holding the
|
|
65
|
+
* read code alone must not reach it; this module's own `new-sales-channel`
|
|
66
|
+
* palette action declares the same code, which is what
|
|
67
|
+
* `check:action-route-permissions` holds the pair to. Batch 10 settled the
|
|
68
|
+
* shape for `credentials`' `/credentials/new`, and this is the same screen one
|
|
69
|
+
* module over.
|
|
70
|
+
*
|
|
71
|
+
* **One operator-visible tightening, recorded rather than glossed.** The route
|
|
72
|
+
* was `App.tsx`'s and therefore ungated, so a read-only operator could open a
|
|
73
|
+
* create form whose save button would then refuse. The roster's *+ New channel*
|
|
74
|
+
* button was ungated too and is gated on this code in the same merge request,
|
|
75
|
+
* so the dead end is closed at both ends rather than moved from one to the
|
|
76
|
+
* other.
|
|
77
|
+
*/
|
|
78
|
+
const WRITE_PERMISSION = 'sales_channels:write';
|
|
79
|
+
/** The module's landing route: the channel roster. */
|
|
80
|
+
const ROUTE_PATH = '/sales-channels';
|
|
81
|
+
export const contributions = {
|
|
82
|
+
routes: [
|
|
83
|
+
{
|
|
84
|
+
path: ROUTE_PATH,
|
|
85
|
+
component: () => import('./pages/SalesChannelsListPage.js'),
|
|
86
|
+
requiredPermission: READ_PERMISSION,
|
|
87
|
+
index: true,
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
// The create form and the editor are one component, told apart by the
|
|
91
|
+
// `:code` parameter — `App.tsx` declared them as two routes over one
|
|
92
|
+
// element and this declaration keeps that shape. `/sales-channels/new` is
|
|
93
|
+
// declared first, and `<Routes>` ranks by specificity rather than by
|
|
94
|
+
// declaration order, so the static segment wins whatever the order; the
|
|
95
|
+
// ordering is kept anyway, so a reader does not have to know that to see
|
|
96
|
+
// why the parametric route is safe here.
|
|
97
|
+
//
|
|
98
|
+
// **The create route carries the write code and the editor carries the
|
|
99
|
+
// read one**, which is the split `credentials` already ships: a screen
|
|
100
|
+
// whose only purpose is a write is opened by the code that write demands,
|
|
101
|
+
// and an existing channel is opened by the code that reads it.
|
|
102
|
+
path: `${ROUTE_PATH}/new`,
|
|
103
|
+
component: () => import('./pages/SalesChannelEditPage.js'),
|
|
104
|
+
requiredPermission: WRITE_PERMISSION,
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
path: `${ROUTE_PATH}/:code`,
|
|
108
|
+
component: () => import('./pages/SalesChannelEditPage.js'),
|
|
109
|
+
requiredPermission: READ_PERMISSION,
|
|
110
|
+
},
|
|
111
|
+
],
|
|
112
|
+
nav: [
|
|
113
|
+
{
|
|
114
|
+
to: ROUTE_PATH,
|
|
115
|
+
// Module-relative (R8), resolved in this module's own namespace out of
|
|
116
|
+
// `packages/modules/sales_channels/i18n/`. It was
|
|
117
|
+
// `appShell.nav.salesChannels` in the shared `_i18n` bundle, one of the
|
|
118
|
+
// four shared files a module author had to edit.
|
|
119
|
+
labelKey: 'nav.salesChannels.label',
|
|
120
|
+
// The glyph `AppShell.tsx` rendered by hand, and already on
|
|
121
|
+
// `KnownIconNameSchema`.
|
|
122
|
+
icon: 'Store',
|
|
123
|
+
section: 'channels',
|
|
124
|
+
// First in *Channels*, which is where the hand-written table put it and
|
|
125
|
+
// where the operator has always seen it. `dictionaries` declares 200 and
|
|
126
|
+
// 300 and `seo` 400, and the host declares no row in this section once
|
|
127
|
+
// this one leaves, so 100 is the whole of what keeps this row on top.
|
|
128
|
+
weight: 100,
|
|
129
|
+
requiredPermission: READ_PERMISSION,
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
zones: [
|
|
133
|
+
zoneComponent('product.editor.channels', () => import('./zones/ProductChannelMembership.js'), {
|
|
134
|
+
// The only contribution to this place, so the weight orders nothing
|
|
135
|
+
// today. Declared rather than defaulted so a second contributor arrives
|
|
136
|
+
// beside it rather than ahead of it by accident.
|
|
137
|
+
weight: 100,
|
|
138
|
+
requiredPermission: READ_PERMISSION,
|
|
139
|
+
}),
|
|
140
|
+
// Weight 100 of four contributors to the organization detail's zone
|
|
141
|
+
// (feature 091, P7b): this panel first, then `price_lists` at 200,
|
|
142
|
+
// `quick_order` at 300 and `carts` at 400. That is the order the operator
|
|
143
|
+
// saw when the panels were scattered through `OrganizationDetail.tsx`,
|
|
144
|
+
// preserved rather than re-chosen.
|
|
145
|
+
zoneComponent('organization.detail.after', () => import('./zones/OrganizationChannelMembership.js'), { weight: 100, requiredPermission: READ_PERMISSION }),
|
|
146
|
+
],
|
|
147
|
+
};
|
|
148
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/admin/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,OAAO,EACL,aAAa,GAEd,MAAM,0CAA0C,CAAC;AAElD;;;;;;;;;;;;;;GAcG;AACH,MAAM,eAAe,GAAG,qBAAqB,CAAC;AAE9C;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,gBAAgB,GAAG,sBAAsB,CAAC;AAEhD,sDAAsD;AACtD,MAAM,UAAU,GAAG,iBAAiB,CAAC;AAErC,MAAM,CAAC,MAAM,aAAa,GAAuB;IAC/C,MAAM,EAAE;QACN;YACE,IAAI,EAAE,UAAU;YAChB,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,kCAAkC,CAAC;YAC3D,kBAAkB,EAAE,eAAe;YACnC,KAAK,EAAE,IAAI;SACZ;QACD;YACE,sEAAsE;YACtE,qEAAqE;YACrE,0EAA0E;YAC1E,qEAAqE;YACrE,wEAAwE;YACxE,yEAAyE;YACzE,yCAAyC;YACzC,EAAE;YACF,uEAAuE;YACvE,uEAAuE;YACvE,0EAA0E;YAC1E,+DAA+D;YAC/D,IAAI,EAAE,GAAG,UAAU,MAAM;YACzB,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,iCAAiC,CAAC;YAC1D,kBAAkB,EAAE,gBAAgB;SACrC;QACD;YACE,IAAI,EAAE,GAAG,UAAU,QAAQ;YAC3B,SAAS,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,iCAAiC,CAAC;YAC1D,kBAAkB,EAAE,eAAe;SACpC;KACF;IACD,GAAG,EAAE;QACH;YACE,EAAE,EAAE,UAAU;YACd,uEAAuE;YACvE,kDAAkD;YAClD,wEAAwE;YACxE,iDAAiD;YACjD,QAAQ,EAAE,yBAAyB;YACnC,4DAA4D;YAC5D,yBAAyB;YACzB,IAAI,EAAE,OAAO;YACb,OAAO,EAAE,UAAU;YACnB,wEAAwE;YACxE,yEAAyE;YACzE,uEAAuE;YACvE,sEAAsE;YACtE,MAAM,EAAE,GAAG;YACX,kBAAkB,EAAE,eAAe;SACpC;KACF;IACD,KAAK,EAAE;QACL,aAAa,CACX,yBAAyB,EACzB,GAAG,EAAE,CAAC,MAAM,CAAC,qCAAqC,CAAC,EACnD;YACE,oEAAoE;YACpE,wEAAwE;YACxE,iDAAiD;YACjD,MAAM,EAAE,GAAG;YACX,kBAAkB,EAAE,eAAe;SACpC,CACF;QACD,oEAAoE;QACpE,mEAAmE;QACnE,0EAA0E;QAC1E,uEAAuE;QACvE,mCAAmC;QACnC,aAAa,CACX,2BAA2B,EAC3B,GAAG,EAAE,CAAC,MAAM,CAAC,0CAA0C,CAAC,EACxD,EAAE,MAAM,EAAE,GAAG,EAAE,kBAAkB,EAAE,eAAe,EAAE,CACrD;KACF;CACF,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* SalesChannelEditPage — feature 005 / T042.
|
|
4
|
+
*
|
|
5
|
+
* Two roles in one component, distinguished by the `:code` path
|
|
6
|
+
* parameter:
|
|
7
|
+
* - `code === 'new'` → create form (POST).
|
|
8
|
+
* - any other value → edit form (GET → PATCH).
|
|
9
|
+
*
|
|
10
|
+
* The form surfaces 409 / 412 / 422 errors from the backend as a
|
|
11
|
+
* conflict banner so the operator can choose to refresh and retry
|
|
12
|
+
* (412) or rename / re-pick a code (409).
|
|
13
|
+
*
|
|
14
|
+
* Membership tabs (US3 / T064) are NOT rendered here yet; the page
|
|
15
|
+
* deliberately scopes itself to identity + lifecycle so US2 ships
|
|
16
|
+
* standalone.
|
|
17
|
+
*/
|
|
18
|
+
export declare function SalesChannelEditPage(): ReactNode;
|
|
19
|
+
/**
|
|
20
|
+
* The registry loads a route component through a dynamic-import factory and
|
|
21
|
+
* reads its default export (feature 091, FR-013). The named export stays: it is
|
|
22
|
+
* the spelling this module's own code and its tests use.
|
|
23
|
+
*/
|
|
24
|
+
export default SalesChannelEditPage;
|
|
25
|
+
//# sourceMappingURL=SalesChannelEditPage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SalesChannelEditPage.d.ts","sourceRoot":"","sources":["../../../src/admin/pages/SalesChannelEditPage.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAoC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAczE;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,oBAAoB,IAAI,SAAS,CAuOhD;AAED;;;;GAIG;AACH,eAAe,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useEffect, useState } from 'react';
|
|
3
|
+
import { useNavigate, useParams } from 'react-router-dom';
|
|
4
|
+
import { ApiError } from '@endora-commerce/admin-kit/lib';
|
|
5
|
+
import { Alert, AlertDescription, Badge, Button, PageHeader } from '@endora-commerce/admin-kit/ui';
|
|
6
|
+
import { salesChannelsClient } from '../api/sales-channels-client.js';
|
|
7
|
+
import { ChannelIdentityForm, } from '../components/ChannelIdentityForm.js';
|
|
8
|
+
import { DefaultChannelBadge } from '../components/DefaultChannelBadge.js';
|
|
9
|
+
import { AdminZone } from '@endora-commerce/admin-kit/zones';
|
|
10
|
+
import { useTranslation } from '@endora-commerce/admin-kit/i18n';
|
|
11
|
+
/**
|
|
12
|
+
* SalesChannelEditPage — feature 005 / T042.
|
|
13
|
+
*
|
|
14
|
+
* Two roles in one component, distinguished by the `:code` path
|
|
15
|
+
* parameter:
|
|
16
|
+
* - `code === 'new'` → create form (POST).
|
|
17
|
+
* - any other value → edit form (GET → PATCH).
|
|
18
|
+
*
|
|
19
|
+
* The form surfaces 409 / 412 / 422 errors from the backend as a
|
|
20
|
+
* conflict banner so the operator can choose to refresh and retry
|
|
21
|
+
* (412) or rename / re-pick a code (409).
|
|
22
|
+
*
|
|
23
|
+
* Membership tabs (US3 / T064) are NOT rendered here yet; the page
|
|
24
|
+
* deliberately scopes itself to identity + lifecycle so US2 ships
|
|
25
|
+
* standalone.
|
|
26
|
+
*/
|
|
27
|
+
export function SalesChannelEditPage() {
|
|
28
|
+
const t = useTranslation('sales_channels');
|
|
29
|
+
const { code: routeCode } = useParams();
|
|
30
|
+
const navigate = useNavigate();
|
|
31
|
+
const isCreate = routeCode === 'new' || routeCode === undefined;
|
|
32
|
+
const [channel, setChannel] = useState(null);
|
|
33
|
+
const [loading, setLoading] = useState(!isCreate);
|
|
34
|
+
const [saving, setSaving] = useState(false);
|
|
35
|
+
const [error, setError] = useState(null);
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
if (isCreate)
|
|
38
|
+
return;
|
|
39
|
+
let cancelled = false;
|
|
40
|
+
(async () => {
|
|
41
|
+
setLoading(true);
|
|
42
|
+
setError(null);
|
|
43
|
+
try {
|
|
44
|
+
const detail = await salesChannelsClient.getByCode(routeCode);
|
|
45
|
+
if (!cancelled)
|
|
46
|
+
setChannel(detail);
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
if (!cancelled) {
|
|
50
|
+
setError(err instanceof ApiError ? err.envelope.error.message : 'Failed to load channel.');
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
finally {
|
|
54
|
+
if (!cancelled)
|
|
55
|
+
setLoading(false);
|
|
56
|
+
}
|
|
57
|
+
})();
|
|
58
|
+
return () => {
|
|
59
|
+
cancelled = true;
|
|
60
|
+
};
|
|
61
|
+
}, [isCreate, routeCode]);
|
|
62
|
+
const handleSubmit = useCallback(async (value) => {
|
|
63
|
+
setSaving(true);
|
|
64
|
+
setError(null);
|
|
65
|
+
try {
|
|
66
|
+
if (isCreate) {
|
|
67
|
+
const created = await salesChannelsClient.create({
|
|
68
|
+
code: value.code,
|
|
69
|
+
name: { 'en-US': value.name },
|
|
70
|
+
...(value.themeCode ? { themeCode: value.themeCode } : {}),
|
|
71
|
+
languages: value.languages,
|
|
72
|
+
defaultLanguage: value.defaultLanguage,
|
|
73
|
+
currencies: value.currencies,
|
|
74
|
+
defaultCurrency: value.defaultCurrency,
|
|
75
|
+
active: value.active,
|
|
76
|
+
});
|
|
77
|
+
navigate(`/sales-channels/${encodeURIComponent(created.code)}`, { replace: true });
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
if (!channel)
|
|
81
|
+
return;
|
|
82
|
+
const updated = await salesChannelsClient.update(channel.code, {
|
|
83
|
+
expectedVersion: channel.version,
|
|
84
|
+
name: { 'en-US': value.name },
|
|
85
|
+
...(value.themeCode !== undefined ? { themeCode: value.themeCode || null } : {}),
|
|
86
|
+
languages: value.languages,
|
|
87
|
+
defaultLanguage: value.defaultLanguage,
|
|
88
|
+
currencies: value.currencies,
|
|
89
|
+
defaultCurrency: value.defaultCurrency,
|
|
90
|
+
active: value.active,
|
|
91
|
+
});
|
|
92
|
+
setChannel(updated);
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
setError(err instanceof ApiError ? err.envelope.error.message : 'Save failed.');
|
|
96
|
+
}
|
|
97
|
+
finally {
|
|
98
|
+
setSaving(false);
|
|
99
|
+
}
|
|
100
|
+
}, [channel, isCreate, navigate]);
|
|
101
|
+
const handleDeactivate = useCallback(async () => {
|
|
102
|
+
if (!channel || channel.systemDefault)
|
|
103
|
+
return;
|
|
104
|
+
setSaving(true);
|
|
105
|
+
setError(null);
|
|
106
|
+
try {
|
|
107
|
+
const updated = await salesChannelsClient.deactivate(channel.code);
|
|
108
|
+
setChannel(updated);
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
setError(err instanceof ApiError ? err.envelope.error.message : 'Deactivate failed.');
|
|
112
|
+
}
|
|
113
|
+
finally {
|
|
114
|
+
setSaving(false);
|
|
115
|
+
}
|
|
116
|
+
}, [channel]);
|
|
117
|
+
const handleActivate = useCallback(async () => {
|
|
118
|
+
if (!channel)
|
|
119
|
+
return;
|
|
120
|
+
setSaving(true);
|
|
121
|
+
setError(null);
|
|
122
|
+
try {
|
|
123
|
+
const updated = await salesChannelsClient.activate(channel.code);
|
|
124
|
+
setChannel(updated);
|
|
125
|
+
}
|
|
126
|
+
catch (err) {
|
|
127
|
+
setError(err instanceof ApiError ? err.envelope.error.message : 'Activate failed.');
|
|
128
|
+
}
|
|
129
|
+
finally {
|
|
130
|
+
setSaving(false);
|
|
131
|
+
}
|
|
132
|
+
}, [channel]);
|
|
133
|
+
const handleDelete = useCallback(async () => {
|
|
134
|
+
if (!channel || channel.systemDefault)
|
|
135
|
+
return;
|
|
136
|
+
if (!window.confirm(`Delete sales channel "${channel.code}"? This is irreversible. ` +
|
|
137
|
+
`If any product / customer / category would be left with zero channels, ` +
|
|
138
|
+
`the platform will refuse — you can opt to rebind them to the system default instead.`))
|
|
139
|
+
return;
|
|
140
|
+
setSaving(true);
|
|
141
|
+
setError(null);
|
|
142
|
+
try {
|
|
143
|
+
try {
|
|
144
|
+
await salesChannelsClient.delete(channel.code, { fallbackToDefault: false });
|
|
145
|
+
}
|
|
146
|
+
catch (err) {
|
|
147
|
+
if (err instanceof ApiError &&
|
|
148
|
+
err.envelope.error.code === 'ENTITY_WOULD_HAVE_ZERO_CHANNELS') {
|
|
149
|
+
if (window.confirm(`${err.envelope.error.message}\n\nRebind those entities to the system default and delete?`)) {
|
|
150
|
+
await salesChannelsClient.delete(channel.code, { fallbackToDefault: true });
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
throw err;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
navigate('/sales-channels');
|
|
161
|
+
}
|
|
162
|
+
catch (err) {
|
|
163
|
+
setError(err instanceof ApiError ? err.envelope.error.message : 'Delete failed.');
|
|
164
|
+
}
|
|
165
|
+
finally {
|
|
166
|
+
setSaving(false);
|
|
167
|
+
}
|
|
168
|
+
}, [channel, navigate]);
|
|
169
|
+
if (loading) {
|
|
170
|
+
return _jsx("p", { className: "text-sm text-muted-foreground", children: t('edit.loading') });
|
|
171
|
+
}
|
|
172
|
+
if (!isCreate && !channel) {
|
|
173
|
+
return (_jsx(Alert, { variant: "destructive", children: _jsx(AlertDescription, { children: error ?? 'Channel not found.' }) }));
|
|
174
|
+
}
|
|
175
|
+
return (_jsxs(_Fragment, { children: [_jsx(PageHeader, { title: isCreate ? ('New Sales Channel') : (_jsxs("span", { className: "flex items-center gap-2", children: [_jsx("span", { className: "font-mono text-base", children: channel.code }), _jsx(DefaultChannelBadge, { systemDefault: channel.systemDefault }), !channel.active && (_jsx(Badge, { variant: "outline", className: "text-[10px]", children: "Inactive" }))] })), description: isCreate
|
|
176
|
+
? 'Create a new place of sale. After saving, manage its product / customer / price-list memberships from the channel detail page or from the entity edit screens.'
|
|
177
|
+
: 'Edit the channel’s identity. Lifecycle actions live in the toolbar; membership tabs land in a follow-up.', actions: channel ? (_jsxs("div", { className: "flex gap-2", children: [channel.active ? (_jsx(Button, { variant: "outline", onClick: () => void handleDeactivate(), disabled: saving || channel.systemDefault, children: "Deactivate" })) : (_jsx(Button, { variant: "outline", onClick: () => void handleActivate(), disabled: saving, children: "Re-activate" })), _jsx(Button, { variant: "destructive", onClick: () => void handleDelete(), disabled: saving || channel.systemDefault, children: "Delete" })] })) : null }), _jsx(ChannelIdentityForm, { mode: isCreate ? 'create' : 'edit', initial: channel, lockCode: !isCreate, errorMessage: error, saving: saving, onSubmit: (v) => void handleSubmit(v), onCancel: () => navigate('/sales-channels') }), channel && !isCreate ? (_jsx("div", { style: { marginTop: 24 }, children: _jsx(AdminZone, { name: "sales_channel.editor.after", props: { channelId: channel.id } }) })) : null] }));
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* The registry loads a route component through a dynamic-import factory and
|
|
181
|
+
* reads its default export (feature 091, FR-013). The named export stays: it is
|
|
182
|
+
* the spelling this module's own code and its tests use.
|
|
183
|
+
*/
|
|
184
|
+
export default SalesChannelEditPage;
|
|
185
|
+
//# sourceMappingURL=SalesChannelEditPage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SalesChannelEditPage.js","sourceRoot":"","sources":["../../../src/admin/pages/SalesChannelEditPage.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* SalesChannelsListPage — feature 005 / T041.
|
|
4
|
+
*
|
|
5
|
+
* Top-level list view. The system-default channel always lives in
|
|
6
|
+
* the list; the activeOnly filter toggles whether deactivated
|
|
7
|
+
* channels are hidden. The "+ New channel" CTA sends the operator
|
|
8
|
+
* to the create form (`/sales-channels/new`).
|
|
9
|
+
*
|
|
10
|
+
* The system-default column is where the flag moves (feature 072 / D-51). The
|
|
11
|
+
* list is the right surface for it because the decision is comparative — which
|
|
12
|
+
* of these channels should be the fallback — and because the current default
|
|
13
|
+
* has to be visible while another one is promoted. The current default's cell
|
|
14
|
+
* is deliberately inert: the flag is moved by promoting a different channel,
|
|
15
|
+
* never by clearing it here, which is what keeps "exactly one default" true at
|
|
16
|
+
* every moment.
|
|
17
|
+
*/
|
|
18
|
+
export declare function SalesChannelsListPage(): ReactNode;
|
|
19
|
+
/**
|
|
20
|
+
* The registry loads a route component through a dynamic-import factory and
|
|
21
|
+
* reads its default export (feature 091, FR-013). The named export stays: it is
|
|
22
|
+
* the spelling this module's own code and its tests use.
|
|
23
|
+
*/
|
|
24
|
+
export default SalesChannelsListPage;
|
|
25
|
+
//# sourceMappingURL=SalesChannelsListPage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SalesChannelsListPage.d.ts","sourceRoot":"","sources":["../../../src/admin/pages/SalesChannelsListPage.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAoC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AASzE;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,qBAAqB,IAAI,SAAS,CAmLjD;AAED;;;;GAIG;AACH,eAAe,qBAAqB,CAAC"}
|