@voyantjs/availability-react 0.105.2 → 0.107.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/README.md +161 -1
- package/dist/admin/availability-index-host.d.ts +12 -0
- package/dist/admin/availability-index-host.d.ts.map +1 -0
- package/dist/admin/availability-index-host.js +125 -0
- package/dist/admin/availability-page-data.d.ts +9 -0
- package/dist/admin/availability-page-data.d.ts.map +1 -0
- package/dist/admin/availability-page-data.js +25 -0
- package/dist/admin/index.d.ts +69 -0
- package/dist/admin/index.d.ts.map +1 -0
- package/dist/admin/index.js +73 -0
- package/dist/admin/option-resource-templates-panel.d.ts +22 -0
- package/dist/admin/option-resource-templates-panel.d.ts.map +1 -0
- package/dist/admin/option-resource-templates-panel.js +251 -0
- package/dist/admin/rule-detail-host.d.ts +14 -0
- package/dist/admin/rule-detail-host.d.ts.map +1 -0
- package/dist/admin/rule-detail-host.js +27 -0
- package/dist/admin/slot-detail-host.d.ts +29 -0
- package/dist/admin/slot-detail-host.d.ts.map +1 -0
- package/dist/admin/slot-detail-host.js +110 -0
- package/dist/admin/start-time-detail-host.d.ts +15 -0
- package/dist/admin/start-time-detail-host.d.ts.map +1 -0
- package/dist/admin/start-time-detail-host.js +37 -0
- package/dist/components/availability-columns.d.ts +42 -0
- package/dist/components/availability-columns.d.ts.map +1 -0
- package/dist/components/availability-columns.js +182 -0
- package/dist/components/availability-dialogs.d.ts +236 -0
- package/dist/components/availability-dialogs.d.ts.map +1 -0
- package/dist/components/availability-dialogs.js +369 -0
- package/dist/components/availability-overview.d.ts +54 -0
- package/dist/components/availability-overview.d.ts.map +1 -0
- package/dist/components/availability-overview.js +50 -0
- package/dist/components/availability-page.d.ts +32 -0
- package/dist/components/availability-page.d.ts.map +1 -0
- package/dist/components/availability-page.js +128 -0
- package/dist/components/availability-rule-detail-page.d.ts +251 -0
- package/dist/components/availability-rule-detail-page.d.ts.map +1 -0
- package/dist/components/availability-rule-detail-page.js +74 -0
- package/dist/components/availability-section-header.d.ts +8 -0
- package/dist/components/availability-section-header.d.ts.map +1 -0
- package/dist/components/availability-section-header.js +7 -0
- package/dist/components/availability-skeletons.d.ts +6 -0
- package/dist/components/availability-skeletons.d.ts.map +1 -0
- package/dist/components/availability-skeletons.js +34 -0
- package/dist/components/availability-slot-detail-page.d.ts +974 -0
- package/dist/components/availability-slot-detail-page.d.ts.map +1 -0
- package/dist/components/availability-slot-detail-page.js +383 -0
- package/dist/components/availability-start-time-detail-page.d.ts +246 -0
- package/dist/components/availability-start-time-detail-page.d.ts.map +1 -0
- package/dist/components/availability-start-time-detail-page.js +83 -0
- package/dist/components/availability-tabs.d.ts +152 -0
- package/dist/components/availability-tabs.d.ts.map +1 -0
- package/dist/components/availability-tabs.js +192 -0
- package/dist/components/slot-status-tone.d.ts +15 -0
- package/dist/components/slot-status-tone.d.ts.map +1 -0
- package/dist/components/slot-status-tone.js +18 -0
- package/dist/form-resolver.d.ts +4 -0
- package/dist/form-resolver.d.ts.map +1 -0
- package/dist/form-resolver.js +40 -0
- package/dist/hooks/index.d.ts +4 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +3 -0
- package/dist/hooks/use-availability-batch-mutations.d.ts +193 -0
- package/dist/hooks/use-availability-batch-mutations.d.ts.map +1 -0
- package/dist/hooks/use-availability-batch-mutations.js +53 -0
- package/dist/hooks/use-availability-closeout-mutation.d.ts +34 -0
- package/dist/hooks/use-availability-closeout-mutation.d.ts.map +1 -0
- package/dist/hooks/use-availability-closeout-mutation.js +38 -0
- package/dist/hooks/use-availability-pickup-point-mutation.d.ts +35 -0
- package/dist/hooks/use-availability-pickup-point-mutation.d.ts.map +1 -0
- package/dist/hooks/use-availability-pickup-point-mutation.js +38 -0
- package/dist/i18n/index.d.ts +2 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/i18n/index.js +1 -0
- package/dist/i18n/provider.d.ts +2003 -0
- package/dist/i18n/provider.d.ts.map +1 -0
- package/dist/i18n/provider.js +102 -0
- package/dist/schemas.d.ts +63 -2
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +22 -2
- package/dist/ui.d.ts +13 -0
- package/dist/ui.d.ts.map +1 -0
- package/dist/ui.js +12 -0
- package/dist/utils.d.ts +1 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +3 -0
- package/package.json +92 -9
- package/src/styles.css +11 -0
package/README.md
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
# @voyantjs/availability-react
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The availability client tier: headless data hooks/clients plus the styled UI
|
|
4
|
+
primitives and page-level compositions (formerly `@voyantjs/availability-ui`).
|
|
5
|
+
|
|
6
|
+
Headless consumers (storefronts, portals) import from the root, `./hooks`,
|
|
7
|
+
`./client`, or `./query-keys` — these pull no styling peers. Styled surfaces
|
|
8
|
+
live under `./ui`, `./components/*`, `./admin`, `./i18n`, `./utils`, and
|
|
9
|
+
`./styles.css`, whose heavier peers (`@voyantjs/ui`, `@voyantjs/admin`,
|
|
10
|
+
`@tanstack/react-table`, `sonner`, `lucide-react`) are optional and only
|
|
11
|
+
needed when you import those subpaths.
|
|
4
12
|
|
|
5
13
|
## Install
|
|
6
14
|
|
|
@@ -27,6 +35,158 @@ function SlotsList() {
|
|
|
27
35
|
}
|
|
28
36
|
```
|
|
29
37
|
|
|
38
|
+
## UI components
|
|
39
|
+
|
|
40
|
+
Reusable availability UI primitives and page compositions for Voyant
|
|
41
|
+
operator/admin apps.
|
|
42
|
+
|
|
43
|
+
### Exports
|
|
44
|
+
|
|
45
|
+
| Entry | Description |
|
|
46
|
+
| --- | --- |
|
|
47
|
+
| `./ui` | Barrel re-exports |
|
|
48
|
+
| `./i18n` | Availability UI message provider, defaults, and helpers |
|
|
49
|
+
| `./components/*` | Availability UI components |
|
|
50
|
+
| `./utils` | Small formatting helpers |
|
|
51
|
+
|
|
52
|
+
### Surface
|
|
53
|
+
|
|
54
|
+
The package exports reusable pieces that keep app-owned routing and the
|
|
55
|
+
availability batch mutations injected through props:
|
|
56
|
+
|
|
57
|
+
- `AvailabilityPage`
|
|
58
|
+
- `AvailabilityRuleDetailPage`, `AvailabilitySlotDetailPage`,
|
|
59
|
+
`AvailabilityStartTimeDetailPage`
|
|
60
|
+
- `AvailabilityOverview`
|
|
61
|
+
- `AvailabilitySlotsTab`, `AvailabilityRulesTab`, `AvailabilityStartTimesTab`
|
|
62
|
+
- `AvailabilityCloseoutsTab`, `AvailabilityPickupPointsTab`
|
|
63
|
+
- `AvailabilityRuleDialog`, `AvailabilityStartTimeDialog`, `AvailabilitySlotDialog`
|
|
64
|
+
- `AvailabilityCloseoutDialog`, `AvailabilityPickupPointDialog`
|
|
65
|
+
- `AvailabilityPageSkeleton`, `AvailabilityBodySkeleton`, detail skeletons
|
|
66
|
+
- `availability*Columns` table column builders
|
|
67
|
+
- `AvailabilitySectionHeader`
|
|
68
|
+
- `AvailabilityUiMessagesProvider` and i18n helpers from `./i18n`
|
|
69
|
+
- `formatLocalizedSelectionLabel`
|
|
70
|
+
|
|
71
|
+
### Usage
|
|
72
|
+
|
|
73
|
+
`AvailabilityPage` owns the common operator availability shell, data hooks,
|
|
74
|
+
filters, overview metrics, table tabs, calendar tab, and rule/slot/start-time
|
|
75
|
+
dialogs. Route navigation and batch mutations stay app-specific:
|
|
76
|
+
|
|
77
|
+
```tsx
|
|
78
|
+
import { AvailabilityPage } from "@voyantjs/availability-react/ui"
|
|
79
|
+
|
|
80
|
+
<AvailabilityPage
|
|
81
|
+
onSlotOpen={(id) => navigate({ to: "/availability/$id", params: { id } })}
|
|
82
|
+
onRuleOpen={(id) => navigate({ to: "/availability/rules/$id", params: { id } })}
|
|
83
|
+
onStartTimeOpen={(id) =>
|
|
84
|
+
navigate({ to: "/availability/start-times/$id", params: { id } })
|
|
85
|
+
}
|
|
86
|
+
onProductOpen={(id) => navigate({ to: "/products/$id", params: { id } })}
|
|
87
|
+
onBulkUpdate={handleAvailabilityBulkUpdate}
|
|
88
|
+
onBulkDelete={handleAvailabilityBulkDelete}
|
|
89
|
+
/>
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Closeout and pickup-point mutations are not owned by the headless tier yet.
|
|
93
|
+
Pass `onCloseoutSubmit` and `onPickupPointSubmit` to use the package dialogs, or
|
|
94
|
+
use the `slots.dialogs` escape hatch to render app-owned dialogs.
|
|
95
|
+
|
|
96
|
+
Detail pages expose query/loader helpers that accept the app's API client:
|
|
97
|
+
|
|
98
|
+
```tsx
|
|
99
|
+
import { defaultFetcher } from "@voyantjs/availability-react"
|
|
100
|
+
import {
|
|
101
|
+
AvailabilitySlotDetailPage,
|
|
102
|
+
loadAvailabilitySlotDetailPage,
|
|
103
|
+
} from "@voyantjs/availability-react/ui"
|
|
104
|
+
|
|
105
|
+
const client = { baseUrl: getApiUrl(), fetcher: defaultFetcher }
|
|
106
|
+
|
|
107
|
+
export const Route = createFileRoute("/_workspace/availability/$id")({
|
|
108
|
+
loader: ({ context, params }) =>
|
|
109
|
+
loadAvailabilitySlotDetailPage(context.queryClient, client, params.id),
|
|
110
|
+
component: () => {
|
|
111
|
+
const { id } = Route.useParams()
|
|
112
|
+
return (
|
|
113
|
+
<AvailabilitySlotDetailPage
|
|
114
|
+
id={id}
|
|
115
|
+
onBack={() => navigate({ to: "/availability" })}
|
|
116
|
+
onOpenProduct={(productId) =>
|
|
117
|
+
navigate({ to: "/products/$id", params: { id: productId } })
|
|
118
|
+
}
|
|
119
|
+
onOpenStartTime={(startTimeId) =>
|
|
120
|
+
navigate({ to: "/availability/start-times/$id", params: { id: startTimeId } })
|
|
121
|
+
}
|
|
122
|
+
/>
|
|
123
|
+
)
|
|
124
|
+
},
|
|
125
|
+
})
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Wrap consumers in `AvailabilityUiMessagesProvider` for package-level copy and
|
|
129
|
+
locale-aware formatting. Without a provider the package falls back to English.
|
|
130
|
+
|
|
131
|
+
```tsx
|
|
132
|
+
import { AvailabilityUiMessagesProvider } from "@voyantjs/availability-react/i18n"
|
|
133
|
+
|
|
134
|
+
<AvailabilityUiMessagesProvider locale={resolvedLocale}>
|
|
135
|
+
<AvailabilityPage onBulkUpdate={handleBulkUpdate} onBulkDelete={handleBulkDelete} />
|
|
136
|
+
</AvailabilityUiMessagesProvider>
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Leaf components remain available for custom page shells:
|
|
140
|
+
|
|
141
|
+
```tsx
|
|
142
|
+
import { AvailabilitySectionHeader } from "@voyantjs/availability-react/ui"
|
|
143
|
+
|
|
144
|
+
function SlotsHeader() {
|
|
145
|
+
return (
|
|
146
|
+
<AvailabilitySectionHeader
|
|
147
|
+
title="Slots"
|
|
148
|
+
description="Manage generated capacity."
|
|
149
|
+
actionLabel="Create slot"
|
|
150
|
+
onAction={() => setOpen(true)}
|
|
151
|
+
/>
|
|
152
|
+
)
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Table column builders are available for apps that use `@voyantjs/ui`'s
|
|
157
|
+
`DataTable` and keep routing behavior app-owned:
|
|
158
|
+
|
|
159
|
+
```tsx
|
|
160
|
+
import { availabilitySlotColumns } from "@voyantjs/availability-react/ui"
|
|
161
|
+
|
|
162
|
+
<DataTable
|
|
163
|
+
columns={availabilitySlotColumns(products, openSlotRoute, messages.availability)}
|
|
164
|
+
data={slots}
|
|
165
|
+
/>
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Dialogs expose the reusable form UI and validation while the app decides how
|
|
169
|
+
to persist the payload:
|
|
170
|
+
|
|
171
|
+
```tsx
|
|
172
|
+
import { AvailabilitySlotDialog } from "@voyantjs/availability-react/ui"
|
|
173
|
+
|
|
174
|
+
<AvailabilitySlotDialog
|
|
175
|
+
messages={messages.availability}
|
|
176
|
+
open={open}
|
|
177
|
+
onOpenChange={setOpen}
|
|
178
|
+
products={products}
|
|
179
|
+
rules={rules}
|
|
180
|
+
startTimes={startTimes}
|
|
181
|
+
onSubmit={(payload, context) =>
|
|
182
|
+
context.isEditing
|
|
183
|
+
? api.patch(`/v1/availability/slots/${context.id}`, payload)
|
|
184
|
+
: api.post("/v1/availability/slots", payload)
|
|
185
|
+
}
|
|
186
|
+
onSuccess={refresh}
|
|
187
|
+
/>
|
|
188
|
+
```
|
|
189
|
+
|
|
30
190
|
## License
|
|
31
191
|
|
|
32
192
|
Apache-2.0
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Packaged admin host for the availability index page (packaged-admin RFC
|
|
3
|
+
* Phase 3). Zero-prop: list/filter state stays component-local (no URL
|
|
4
|
+
* search contract), opening a slot resolves through the
|
|
5
|
+
* `availabilitySlot.detail` semantic destination, and the bulk
|
|
6
|
+
* update/delete handlers run through the typed batch mutation pairs from
|
|
7
|
+
* `@voyantjs/availability-react` (the `batch-update`/`batch-delete`
|
|
8
|
+
* endpoints) instead of an app RPC client. Slot create/edit submits through
|
|
9
|
+
* the package default (`useAvailabilitySlotMutation`).
|
|
10
|
+
*/
|
|
11
|
+
export declare function AvailabilityIndexHost(): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
//# sourceMappingURL=availability-index-host.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"availability-index-host.d.ts","sourceRoot":"","sources":["../../src/admin/availability-index-host.tsx"],"names":[],"mappings":"AA0BA;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,4CA2KpC"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useQueryClient } from "@tanstack/react-query";
|
|
4
|
+
import { formatMessage, useAdminNavigate, useOperatorAdminMessages } from "@voyantjs/admin";
|
|
5
|
+
import { useState } from "react";
|
|
6
|
+
import { toast } from "sonner";
|
|
7
|
+
import { AvailabilityPage, } from "../components/availability-page.js";
|
|
8
|
+
import { availabilityQueryKeys, useAvailabilityCloseoutBatchMutation, useAvailabilityPickupPointBatchMutation, useAvailabilityRuleBatchMutation, useAvailabilitySlotBatchMutation, useAvailabilityStartTimeBatchMutation, } from "../index.js";
|
|
9
|
+
import { formatLocalizedSelectionLabel } from "../utils.js";
|
|
10
|
+
/**
|
|
11
|
+
* Packaged admin host for the availability index page (packaged-admin RFC
|
|
12
|
+
* Phase 3). Zero-prop: list/filter state stays component-local (no URL
|
|
13
|
+
* search contract), opening a slot resolves through the
|
|
14
|
+
* `availabilitySlot.detail` semantic destination, and the bulk
|
|
15
|
+
* update/delete handlers run through the typed batch mutation pairs from
|
|
16
|
+
* `@voyantjs/availability-react` (the `batch-update`/`batch-delete`
|
|
17
|
+
* endpoints) instead of an app RPC client. Slot create/edit submits through
|
|
18
|
+
* the package default (`useAvailabilitySlotMutation`).
|
|
19
|
+
*/
|
|
20
|
+
export function AvailabilityIndexHost() {
|
|
21
|
+
const messages = useOperatorAdminMessages();
|
|
22
|
+
const navigateTo = useAdminNavigate();
|
|
23
|
+
const queryClient = useQueryClient();
|
|
24
|
+
const [bulkActionTarget, setBulkActionTarget] = useState(null);
|
|
25
|
+
const ruleBatch = useAvailabilityRuleBatchMutation();
|
|
26
|
+
const startTimeBatch = useAvailabilityStartTimeBatchMutation();
|
|
27
|
+
const slotBatch = useAvailabilitySlotBatchMutation();
|
|
28
|
+
const closeoutBatch = useAvailabilityCloseoutBatchMutation();
|
|
29
|
+
const pickupPointBatch = useAvailabilityPickupPointBatchMutation();
|
|
30
|
+
const refreshAvailability = () => queryClient.invalidateQueries({ queryKey: availabilityQueryKeys.all });
|
|
31
|
+
// The tabs identify their batch endpoints by REST path; resolve each to
|
|
32
|
+
// the matching typed batch mutation pair. The page currently only emits
|
|
33
|
+
// the slots endpoint, but every availability list entity is covered so
|
|
34
|
+
// additional tabs slot in without touching the host.
|
|
35
|
+
const runBatchUpdate = (endpoint, ids, payload) => {
|
|
36
|
+
switch (endpoint) {
|
|
37
|
+
case "/v1/availability/rules":
|
|
38
|
+
return ruleBatch.batchUpdate.mutateAsync({
|
|
39
|
+
ids,
|
|
40
|
+
patch: payload,
|
|
41
|
+
});
|
|
42
|
+
case "/v1/availability/start-times":
|
|
43
|
+
return startTimeBatch.batchUpdate.mutateAsync({
|
|
44
|
+
ids,
|
|
45
|
+
patch: payload,
|
|
46
|
+
});
|
|
47
|
+
case "/v1/availability/closeouts":
|
|
48
|
+
return closeoutBatch.batchUpdate.mutateAsync({
|
|
49
|
+
ids,
|
|
50
|
+
patch: payload,
|
|
51
|
+
});
|
|
52
|
+
case "/v1/availability/pickup-points":
|
|
53
|
+
return pickupPointBatch.batchUpdate.mutateAsync({
|
|
54
|
+
ids,
|
|
55
|
+
patch: payload,
|
|
56
|
+
});
|
|
57
|
+
default:
|
|
58
|
+
return slotBatch.batchUpdate.mutateAsync({
|
|
59
|
+
ids,
|
|
60
|
+
patch: payload,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
const runBatchDelete = (endpoint, ids) => {
|
|
65
|
+
switch (endpoint) {
|
|
66
|
+
case "/v1/availability/rules":
|
|
67
|
+
return ruleBatch.batchDelete.mutateAsync({ ids });
|
|
68
|
+
case "/v1/availability/start-times":
|
|
69
|
+
return startTimeBatch.batchDelete.mutateAsync({ ids });
|
|
70
|
+
case "/v1/availability/closeouts":
|
|
71
|
+
return closeoutBatch.batchDelete.mutateAsync({ ids });
|
|
72
|
+
case "/v1/availability/pickup-points":
|
|
73
|
+
return pickupPointBatch.batchDelete.mutateAsync({ ids });
|
|
74
|
+
default:
|
|
75
|
+
return slotBatch.batchDelete.mutateAsync({ ids });
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
const slotsNounSingular = messages.availability.tabs.slots.title;
|
|
79
|
+
const slotsNounPlural = messages.availability.tabs.slots.title;
|
|
80
|
+
const handleBulkUpdate = async ({ ids, endpoint, target, nounSingular, nounPlural, payload, successVerb, clearSelection, }) => {
|
|
81
|
+
if (ids.length === 0)
|
|
82
|
+
return;
|
|
83
|
+
setBulkActionTarget(target);
|
|
84
|
+
const result = await runBatchUpdate(endpoint, ids, payload);
|
|
85
|
+
await refreshAvailability();
|
|
86
|
+
clearSelection();
|
|
87
|
+
setBulkActionTarget(null);
|
|
88
|
+
const succeededSelection = formatLocalizedSelectionLabel(result.succeeded, nounSingular ?? slotsNounSingular, nounPlural ?? slotsNounPlural);
|
|
89
|
+
const totalSelection = formatLocalizedSelectionLabel(result.total, nounSingular ?? slotsNounSingular, nounPlural ?? slotsNounPlural);
|
|
90
|
+
if (result.failed.length === 0) {
|
|
91
|
+
toast.success(formatMessage(messages.availability.toasts.bulkUpdated, {
|
|
92
|
+
verb: successVerb,
|
|
93
|
+
selection: succeededSelection,
|
|
94
|
+
}));
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
toast.error(formatMessage(messages.availability.toasts.bulkUpdatedPartial, {
|
|
98
|
+
verb: successVerb,
|
|
99
|
+
succeeded: result.succeeded,
|
|
100
|
+
selection: totalSelection,
|
|
101
|
+
}));
|
|
102
|
+
};
|
|
103
|
+
const handleBulkDelete = async ({ ids, endpoint, target, nounSingular, nounPlural, clearSelection, }) => {
|
|
104
|
+
if (ids.length === 0)
|
|
105
|
+
return;
|
|
106
|
+
setBulkActionTarget(target);
|
|
107
|
+
const result = await runBatchDelete(endpoint, ids);
|
|
108
|
+
await refreshAvailability();
|
|
109
|
+
clearSelection();
|
|
110
|
+
setBulkActionTarget(null);
|
|
111
|
+
const succeededSelection = formatLocalizedSelectionLabel(result.succeeded, nounSingular ?? slotsNounSingular, nounPlural ?? slotsNounPlural);
|
|
112
|
+
const totalSelection = formatLocalizedSelectionLabel(result.total, nounSingular ?? slotsNounSingular, nounPlural ?? slotsNounPlural);
|
|
113
|
+
if (result.failed.length === 0) {
|
|
114
|
+
toast.success(formatMessage(messages.availability.toasts.bulkDeleted, {
|
|
115
|
+
selection: succeededSelection,
|
|
116
|
+
}));
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
toast.error(formatMessage(messages.availability.toasts.bulkDeletedPartial, {
|
|
120
|
+
succeeded: result.succeeded,
|
|
121
|
+
selection: totalSelection,
|
|
122
|
+
}));
|
|
123
|
+
};
|
|
124
|
+
return (_jsx(AvailabilityPage, { bulkActionTarget: bulkActionTarget, onBulkUpdate: handleBulkUpdate, onBulkDelete: handleBulkDelete, onSlotOpen: (slotId) => navigateTo("availabilitySlot.detail", { slotId }) }));
|
|
125
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { QueryClient } from "@tanstack/react-query";
|
|
2
|
+
import { type VoyantAvailabilityContextValue } from "../index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Index page loader: await only what the slots tab + the products picker
|
|
5
|
+
* (top of page) need for first paint; the rules/start-times dimensions that
|
|
6
|
+
* back the slot create/edit dialog prefetch in the background.
|
|
7
|
+
*/
|
|
8
|
+
export declare function ensureAvailabilityPageData(queryClient: QueryClient, client: VoyantAvailabilityContextValue): Promise<void>;
|
|
9
|
+
//# sourceMappingURL=availability-page-data.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"availability-page-data.d.ts","sourceRoot":"","sources":["../../src/admin/availability-page-data.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACxD,OAAO,EAKL,KAAK,8BAA8B,EACpC,MAAM,aAAa,CAAA;AAcpB;;;;GAIG;AACH,wBAAsB,0BAA0B,CAC9C,WAAW,EAAE,WAAW,EACxB,MAAM,EAAE,8BAA8B,GACrC,OAAO,CAAC,IAAI,CAAC,CAYf"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { getProductsQueryOptions, getRulesQueryOptions, getSlotsQueryOptions, getStartTimesQueryOptions, } from "../index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Canonical first-page list filters for the availability index page.
|
|
4
|
+
* `AvailabilityPage` hard-codes the same filters in its hooks, so the
|
|
5
|
+
* loader-seeded cache entries line up with the page's query keys.
|
|
6
|
+
*/
|
|
7
|
+
const availabilityPageQueryFilters = {
|
|
8
|
+
products: { limit: 25, offset: 0 },
|
|
9
|
+
slots: { limit: 25, offset: 0 },
|
|
10
|
+
rules: { limit: 25, offset: 0 },
|
|
11
|
+
startTimes: { limit: 25, offset: 0 },
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Index page loader: await only what the slots tab + the products picker
|
|
15
|
+
* (top of page) need for first paint; the rules/start-times dimensions that
|
|
16
|
+
* back the slot create/edit dialog prefetch in the background.
|
|
17
|
+
*/
|
|
18
|
+
export async function ensureAvailabilityPageData(queryClient, client) {
|
|
19
|
+
await Promise.all([
|
|
20
|
+
queryClient.ensureQueryData(getSlotsQueryOptions(client, availabilityPageQueryFilters.slots)),
|
|
21
|
+
queryClient.ensureQueryData(getProductsQueryOptions(client, availabilityPageQueryFilters.products)),
|
|
22
|
+
]);
|
|
23
|
+
void queryClient.prefetchQuery(getRulesQueryOptions(client, availabilityPageQueryFilters.rules));
|
|
24
|
+
void queryClient.prefetchQuery(getStartTimesQueryOptions(client, availabilityPageQueryFilters.startTimes));
|
|
25
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { type AdminExtension } from "@voyantjs/admin";
|
|
2
|
+
/**
|
|
3
|
+
* Semantic destinations the availability admin surfaces navigate to
|
|
4
|
+
* (packaged-admin RFC §4.7). Keys shared with other domains
|
|
5
|
+
* (`availabilitySlot.detail`, `booking.detail`, `product.detail`) come from
|
|
6
|
+
* the bookings-ui augmentation bound above; declared here are the
|
|
7
|
+
* availability-owned targets the packaged pages and breadcrumbs resolve
|
|
8
|
+
* through `useAdminHref`/`useAdminNavigate`.
|
|
9
|
+
*/
|
|
10
|
+
declare module "@voyantjs/admin" {
|
|
11
|
+
interface AdminDestinations {
|
|
12
|
+
/** The availability landing page (slots list + calendar). */
|
|
13
|
+
"availabilitySlot.list": Record<string, never>;
|
|
14
|
+
/** An availability start time's detail page. */
|
|
15
|
+
"availabilityStartTime.detail": {
|
|
16
|
+
startTimeId: string;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export { AvailabilityIndexHost } from "./availability-index-host.js";
|
|
21
|
+
export { ensureAvailabilityPageData } from "./availability-page-data.js";
|
|
22
|
+
export { OptionResourceTemplatesPanel, type OptionResourceTemplatesPanelProps, } from "./option-resource-templates-panel.js";
|
|
23
|
+
export { AvailabilityRuleDetailHost, type AvailabilityRuleDetailHostProps, } from "./rule-detail-host.js";
|
|
24
|
+
export { AvailabilitySlotDetailHost, type AvailabilitySlotDetailHostProps, } from "./slot-detail-host.js";
|
|
25
|
+
export { AvailabilityStartTimeDetailHost, type AvailabilityStartTimeDetailHostProps, } from "./start-time-detail-host.js";
|
|
26
|
+
export interface CreateAvailabilityAdminExtensionOptions {
|
|
27
|
+
/** Mount path of the availability pages inside the admin workspace. Default `/availability`. */
|
|
28
|
+
basePath?: string;
|
|
29
|
+
/** Localized page titles. Defaults are the English operator nav labels. */
|
|
30
|
+
labels?: {
|
|
31
|
+
availability?: string;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The availability admin contribution (packaged-admin RFC Phase 3,
|
|
36
|
+
* `@voyantjs/<domain>-ui/admin` convention).
|
|
37
|
+
*
|
|
38
|
+
* NAVIGATION: deliberately none. The Availability nav item is part of the
|
|
39
|
+
* BASE operator navigation — see `createOperatorAdminNavigation` in
|
|
40
|
+
* `@voyantjs/admin` — so contributing a nav entry here would duplicate it.
|
|
41
|
+
* If the base nav ever drops the availability item, this extension is where
|
|
42
|
+
* the entry moves.
|
|
43
|
+
*
|
|
44
|
+
* ROUTES: contributions are metadata only — the availability pages keep
|
|
45
|
+
* their filter state component-local, so there are no URL search contracts.
|
|
46
|
+
* The PAGES are package-owned: {@link AvailabilityIndexHost} (the slots
|
|
47
|
+
* list + calendar landing page, with bulk update/delete running through
|
|
48
|
+
* the typed batch mutation hooks in `@voyantjs/availability-react`) plus
|
|
49
|
+
* the detail hosts {@link AvailabilitySlotDetailHost},
|
|
50
|
+
* {@link AvailabilityRuleDetailHost} and
|
|
51
|
+
* {@link AvailabilityStartTimeDetailHost} bind the operator-grade pages to
|
|
52
|
+
* their data wiring (the shared availability provider context) and resolve
|
|
53
|
+
* every cross-route link through the semantic destinations declared above.
|
|
54
|
+
* `component:` is intentionally NOT attached to these contributions: the
|
|
55
|
+
* contribution contract renders zero-prop pages (route components read
|
|
56
|
+
* params via the router, per RFC §4.2), while the detail hosts take the
|
|
57
|
+
* record id as a prop — host route files stay the thin binding layer
|
|
58
|
+
* (`Route.useParams()` → host props) until the §4.2 code-based route
|
|
59
|
+
* assembly lands. The index host's SSR loader binding stays app-side
|
|
60
|
+
* ({@link ensureAvailabilityPageData} takes the app's cookie-forwarding
|
|
61
|
+
* client), per the packaged-host recipe.
|
|
62
|
+
*
|
|
63
|
+
* WIDGETS: none. {@link OptionResourceTemplatesPanel} (the per-option
|
|
64
|
+
* resource templates editor the product editor embeds) ships from this
|
|
65
|
+
* entry as a directly importable component — the products admin host owns
|
|
66
|
+
* where it mounts.
|
|
67
|
+
*/
|
|
68
|
+
export declare function createAvailabilityAdminExtension(options?: CreateAvailabilityAdminExtensionOptions): AdminExtension;
|
|
69
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/admin/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAwB,MAAM,iBAAiB,CAAA;AAW3E;;;;;;;GAOG;AACH,OAAO,QAAQ,iBAAiB,CAAC;IAC/B,UAAU,iBAAiB;QACzB,6DAA6D;QAC7D,uBAAuB,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;QAC9C,gDAAgD;QAChD,8BAA8B,EAAE;YAAE,WAAW,EAAE,MAAM,CAAA;SAAE,CAAA;KACxD;CACF;AAKD,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAA;AACpE,OAAO,EAAE,0BAA0B,EAAE,MAAM,6BAA6B,CAAA;AACxE,OAAO,EACL,4BAA4B,EAC5B,KAAK,iCAAiC,GACvC,MAAM,sCAAsC,CAAA;AAC7C,OAAO,EACL,0BAA0B,EAC1B,KAAK,+BAA+B,GACrC,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EACL,0BAA0B,EAC1B,KAAK,+BAA+B,GACrC,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EACL,+BAA+B,EAC/B,KAAK,oCAAoC,GAC1C,MAAM,6BAA6B,CAAA;AAEpC,MAAM,WAAW,uCAAuC;IACtD,gGAAgG;IAChG,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,2EAA2E;IAC3E,MAAM,CAAC,EAAE;QACP,YAAY,CAAC,EAAE,MAAM,CAAA;KACtB,CAAA;CACF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,gCAAgC,CAC9C,OAAO,GAAE,uCAA4C,GACpD,cAAc,CA6BhB"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { defineAdminExtension } from "@voyantjs/admin";
|
|
2
|
+
// Packaged admin hosts (packaged-admin RFC Phase 3): the operator-grade
|
|
3
|
+
// availability pages bound to their data wiring + semantic-destination
|
|
4
|
+
// navigation. Host route files only bind route params onto these.
|
|
5
|
+
export { AvailabilityIndexHost } from "./availability-index-host.js";
|
|
6
|
+
export { ensureAvailabilityPageData } from "./availability-page-data.js";
|
|
7
|
+
export { OptionResourceTemplatesPanel, } from "./option-resource-templates-panel.js";
|
|
8
|
+
export { AvailabilityRuleDetailHost, } from "./rule-detail-host.js";
|
|
9
|
+
export { AvailabilitySlotDetailHost, } from "./slot-detail-host.js";
|
|
10
|
+
export { AvailabilityStartTimeDetailHost, } from "./start-time-detail-host.js";
|
|
11
|
+
/**
|
|
12
|
+
* The availability admin contribution (packaged-admin RFC Phase 3,
|
|
13
|
+
* `@voyantjs/<domain>-ui/admin` convention).
|
|
14
|
+
*
|
|
15
|
+
* NAVIGATION: deliberately none. The Availability nav item is part of the
|
|
16
|
+
* BASE operator navigation — see `createOperatorAdminNavigation` in
|
|
17
|
+
* `@voyantjs/admin` — so contributing a nav entry here would duplicate it.
|
|
18
|
+
* If the base nav ever drops the availability item, this extension is where
|
|
19
|
+
* the entry moves.
|
|
20
|
+
*
|
|
21
|
+
* ROUTES: contributions are metadata only — the availability pages keep
|
|
22
|
+
* their filter state component-local, so there are no URL search contracts.
|
|
23
|
+
* The PAGES are package-owned: {@link AvailabilityIndexHost} (the slots
|
|
24
|
+
* list + calendar landing page, with bulk update/delete running through
|
|
25
|
+
* the typed batch mutation hooks in `@voyantjs/availability-react`) plus
|
|
26
|
+
* the detail hosts {@link AvailabilitySlotDetailHost},
|
|
27
|
+
* {@link AvailabilityRuleDetailHost} and
|
|
28
|
+
* {@link AvailabilityStartTimeDetailHost} bind the operator-grade pages to
|
|
29
|
+
* their data wiring (the shared availability provider context) and resolve
|
|
30
|
+
* every cross-route link through the semantic destinations declared above.
|
|
31
|
+
* `component:` is intentionally NOT attached to these contributions: the
|
|
32
|
+
* contribution contract renders zero-prop pages (route components read
|
|
33
|
+
* params via the router, per RFC §4.2), while the detail hosts take the
|
|
34
|
+
* record id as a prop — host route files stay the thin binding layer
|
|
35
|
+
* (`Route.useParams()` → host props) until the §4.2 code-based route
|
|
36
|
+
* assembly lands. The index host's SSR loader binding stays app-side
|
|
37
|
+
* ({@link ensureAvailabilityPageData} takes the app's cookie-forwarding
|
|
38
|
+
* client), per the packaged-host recipe.
|
|
39
|
+
*
|
|
40
|
+
* WIDGETS: none. {@link OptionResourceTemplatesPanel} (the per-option
|
|
41
|
+
* resource templates editor the product editor embeds) ships from this
|
|
42
|
+
* entry as a directly importable component — the products admin host owns
|
|
43
|
+
* where it mounts.
|
|
44
|
+
*/
|
|
45
|
+
export function createAvailabilityAdminExtension(options = {}) {
|
|
46
|
+
const { basePath = "/availability", labels = {} } = options;
|
|
47
|
+
const { availability = "Availability" } = labels;
|
|
48
|
+
return defineAdminExtension({
|
|
49
|
+
id: "availability",
|
|
50
|
+
routes: [
|
|
51
|
+
{
|
|
52
|
+
id: "availability-index",
|
|
53
|
+
path: basePath,
|
|
54
|
+
title: availability,
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
id: "availability-slot-detail",
|
|
58
|
+
path: `${basePath}/$id`,
|
|
59
|
+
title: availability,
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
id: "availability-rule-detail",
|
|
63
|
+
path: `${basePath}/rules/$id`,
|
|
64
|
+
title: availability,
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
id: "availability-start-time-detail",
|
|
68
|
+
path: `${basePath}/start-times/$id`,
|
|
69
|
+
title: availability,
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
});
|
|
73
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-option Resource templates editor. Templates drive the Allocation
|
|
3
|
+
* tab's "Generate resources" automation — without a template configured
|
|
4
|
+
* for an option, no rooms/seats/etc. are materialized when bookings hit
|
|
5
|
+
* a slot.
|
|
6
|
+
*
|
|
7
|
+
* Each template is identified by `(optionId, kind, refId)` — an option can
|
|
8
|
+
* hold several templates of the same kind, one per `option_unit` (e.g. a
|
|
9
|
+
* "room" template per room type), distinguished by `refId`. Common kinds:
|
|
10
|
+
* - `room` — accommodation rooms (default capacity 2)
|
|
11
|
+
* - `vehicle_seat` — coach/van seats (capacity 1)
|
|
12
|
+
* - `cabin` — cruise cabins
|
|
13
|
+
*
|
|
14
|
+
* The kind field is a free-form string on the server; we constrain the
|
|
15
|
+
* picker to the known set for UX, but operators can extend by typing.
|
|
16
|
+
*/
|
|
17
|
+
export interface OptionResourceTemplatesPanelProps {
|
|
18
|
+
productId: string;
|
|
19
|
+
optionId: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function OptionResourceTemplatesPanel({ productId, optionId, }: OptionResourceTemplatesPanelProps): import("react/jsx-runtime").JSX.Element;
|
|
22
|
+
//# sourceMappingURL=option-resource-templates-panel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"option-resource-templates-panel.d.ts","sourceRoot":"","sources":["../../src/admin/option-resource-templates-panel.tsx"],"names":[],"mappings":"AA+CA;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,iCAAiC;IAChD,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;CACjB;AAiBD,wBAAgB,4BAA4B,CAAC,EAC3C,SAAS,EACT,QAAQ,GACT,EAAE,iCAAiC,2CAqenC"}
|