@voyantjs/availability-react 0.107.0 → 0.108.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.
@@ -41,24 +41,27 @@ export interface CreateAvailabilityAdminExtensionOptions {
41
41
  * If the base nav ever drops the availability item, this extension is where
42
42
  * the entry moves.
43
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},
44
+ * ROUTES: contributions carry the FULL route implementation (packaged-admin
45
+ * RFC §4.2/§4.8) lazy `page` module loaders, data loaders fed by the
46
+ * host-supplied {@link AdminRouteLoaderContext} (QueryClient + runtime +
47
+ * params), per-route SSR mode, and pending skeletons. Hosts bind them into
48
+ * their code-assembled admin route tree; no per-route host files needed.
49
+ * The pages stay code-split because each contribution's `page` dynamically
50
+ * imports the specific host/page module — never the admin barrel — so the
51
+ * heavy page chunks load on navigation, not with workspace chrome.
52
+ * {@link AvailabilityIndexHost} (the slots list + calendar landing page,
53
+ * with bulk update/delete running through the typed batch mutation hooks in
54
+ * `@voyantjs/availability-react`) mounts as a zero-prop page; the detail
55
+ * hosts {@link AvailabilitySlotDetailHost},
50
56
  * {@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.
57
+ * {@link AvailabilityStartTimeDetailHost} read their record id from
58
+ * `AdminRoutePageProps` via the default-exported wrappers in `./pages/`.
59
+ * The index host's SSR loader binding is no longer app-side:
60
+ * {@link ensureAvailabilityPageData} runs in the contribution's own loader
61
+ * against the host runtime's cookie-forwarding fetcher. The pages keep
62
+ * their filter state component-local, so there are no URL search contracts,
63
+ * and every cross-route link resolves through the semantic destinations
64
+ * declared above.
62
65
  *
63
66
  * WIDGETS: none. {@link OptionResourceTemplatesPanel} (the per-option
64
67
  * resource templates editor the product editor embeds) ships from this
@@ -1 +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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/admin/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,cAAc,EAKpB,MAAM,iBAAiB,CAAA;AAoBxB;;;;;;;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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAgB,gCAAgC,CAC9C,OAAO,GAAE,uCAA4C,GACpD,cAAc,CA6EhB"}
@@ -1,4 +1,7 @@
1
- import { defineAdminExtension } from "@voyantjs/admin";
1
+ import { adminRoutePageModule, defineAdminExtension, } from "@voyantjs/admin";
2
+ import { AvailabilityPageSkeleton, AvailabilityRuleDetailSkeleton, AvailabilitySlotDetailSkeleton, AvailabilityStartTimeDetailSkeleton, } from "../components/availability-skeletons.js";
3
+ import { defaultFetcher } from "../index.js";
4
+ import { ensureAvailabilityPageData } from "./availability-page-data.js";
2
5
  // Packaged admin hosts (packaged-admin RFC Phase 3): the operator-grade
3
6
  // availability pages bound to their data wiring + semantic-destination
4
7
  // navigation. Host route files only bind route params onto these.
@@ -18,24 +21,27 @@ export { AvailabilityStartTimeDetailHost, } from "./start-time-detail-host.js";
18
21
  * If the base nav ever drops the availability item, this extension is where
19
22
  * the entry moves.
20
23
  *
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},
24
+ * ROUTES: contributions carry the FULL route implementation (packaged-admin
25
+ * RFC §4.2/§4.8) lazy `page` module loaders, data loaders fed by the
26
+ * host-supplied {@link AdminRouteLoaderContext} (QueryClient + runtime +
27
+ * params), per-route SSR mode, and pending skeletons. Hosts bind them into
28
+ * their code-assembled admin route tree; no per-route host files needed.
29
+ * The pages stay code-split because each contribution's `page` dynamically
30
+ * imports the specific host/page module — never the admin barrel — so the
31
+ * heavy page chunks load on navigation, not with workspace chrome.
32
+ * {@link AvailabilityIndexHost} (the slots list + calendar landing page,
33
+ * with bulk update/delete running through the typed batch mutation hooks in
34
+ * `@voyantjs/availability-react`) mounts as a zero-prop page; the detail
35
+ * hosts {@link AvailabilitySlotDetailHost},
27
36
  * {@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.
37
+ * {@link AvailabilityStartTimeDetailHost} read their record id from
38
+ * `AdminRoutePageProps` via the default-exported wrappers in `./pages/`.
39
+ * The index host's SSR loader binding is no longer app-side:
40
+ * {@link ensureAvailabilityPageData} runs in the contribution's own loader
41
+ * against the host runtime's cookie-forwarding fetcher. The pages keep
42
+ * their filter state component-local, so there are no URL search contracts,
43
+ * and every cross-route link resolves through the semantic destinations
44
+ * declared above.
39
45
  *
40
46
  * WIDGETS: none. {@link OptionResourceTemplatesPanel} (the per-option
41
47
  * resource templates editor the product editor embeds) ships from this
@@ -52,22 +58,75 @@ export function createAvailabilityAdminExtension(options = {}) {
52
58
  id: "availability-index",
53
59
  path: basePath,
54
60
  title: availability,
61
+ ssr: "data-only",
62
+ page: () => import("./availability-index-host.js").then((module) => adminRoutePageModule(module.AvailabilityIndexHost)),
63
+ // Awaits only what the slots tab + the products picker need for
64
+ // first paint; the slot dialog's rules/start-times dimensions
65
+ // prefetch in the background.
66
+ loader: ({ queryClient, runtime }) => ensureAvailabilityPageData(queryClient, loaderClient(runtime)),
67
+ pendingComponent: AvailabilityPageSkeleton,
55
68
  },
56
69
  {
57
70
  id: "availability-slot-detail",
58
71
  path: `${basePath}/$id`,
59
72
  title: availability,
73
+ page: () => import("./pages/availability-slot-detail-page.js"),
74
+ loader: async ({ queryClient, runtime, params }) => {
75
+ const id = params.id;
76
+ if (!id)
77
+ return;
78
+ // Dynamic import on purpose: the loader helper lives in the slot
79
+ // detail page module, and a static import here would pin that
80
+ // module into the host's workspace-chrome chunk, defeating the
81
+ // route's code-split. The loader and the page resolve the same
82
+ // chunk, fetched once.
83
+ const { loadAvailabilitySlotDetailPage } = await import("../components/availability-slot-detail-page.js");
84
+ return loadAvailabilitySlotDetailPage(queryClient, loaderClient(runtime), id);
85
+ },
86
+ pendingComponent: AvailabilitySlotDetailSkeleton,
60
87
  },
61
88
  {
62
89
  id: "availability-rule-detail",
63
90
  path: `${basePath}/rules/$id`,
64
91
  title: availability,
92
+ page: () => import("./pages/availability-rule-detail-page.js"),
93
+ loader: async ({ queryClient, runtime, params }) => {
94
+ const id = params.id;
95
+ if (!id)
96
+ return;
97
+ // Dynamic import on purpose — see the slot detail loader above.
98
+ const { loadAvailabilityRuleDetailPage } = await import("../components/availability-rule-detail-page.js");
99
+ return loadAvailabilityRuleDetailPage(queryClient, loaderClient(runtime), id);
100
+ },
101
+ pendingComponent: AvailabilityRuleDetailSkeleton,
65
102
  },
66
103
  {
67
104
  id: "availability-start-time-detail",
68
105
  path: `${basePath}/start-times/$id`,
69
106
  title: availability,
107
+ page: () => import("./pages/availability-start-time-detail-page.js"),
108
+ loader: async ({ queryClient, runtime, params }) => {
109
+ const id = params.id;
110
+ if (!id)
111
+ return;
112
+ // Dynamic import on purpose — see the slot detail loader above.
113
+ const { loadAvailabilityStartTimeDetailPage } = await import("../components/availability-start-time-detail-page.js");
114
+ return loadAvailabilityStartTimeDetailPage(queryClient, loaderClient(runtime), id);
115
+ },
116
+ pendingComponent: AvailabilityStartTimeDetailSkeleton,
70
117
  },
71
118
  ],
72
119
  });
73
120
  }
121
+ /**
122
+ * Bridge the host-supplied {@link AdminRouteRuntime} (optional fetcher) to
123
+ * the required-fetcher client contract the availability loaders take.
124
+ *
125
+ * Note: the operator's detail route files built this client with the
126
+ * package `defaultFetcher` (a plain `credentials: "include"` fetch); the
127
+ * contribution uses the host runtime's cookie-forwarding fetcher instead,
128
+ * so detail SSR prefetches authenticate — an intentional improvement.
129
+ */
130
+ function loaderClient(runtime) {
131
+ return { baseUrl: runtime.baseUrl, fetcher: runtime.fetcher ?? defaultFetcher };
132
+ }
@@ -0,0 +1,9 @@
1
+ import type { AdminRoutePageProps } from "@voyantjs/admin";
2
+ /**
3
+ * Param-taking page for the `availability-rule-detail` contribution: reads
4
+ * the rule id off {@link AdminRoutePageProps} and binds it onto the packaged
5
+ * host. Resolved lazily through the contribution's `page` loader so the
6
+ * detail page lands in its own chunk.
7
+ */
8
+ export default function AvailabilityRuleDetailRoutePage({ params }: AdminRoutePageProps): import("react/jsx-runtime").JSX.Element;
9
+ //# sourceMappingURL=availability-rule-detail-page.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"availability-rule-detail-page.d.ts","sourceRoot":"","sources":["../../../src/admin/pages/availability-rule-detail-page.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AAI1D;;;;;GAKG;AACH,MAAM,CAAC,OAAO,UAAU,+BAA+B,CAAC,EAAE,MAAM,EAAE,EAAE,mBAAmB,2CAEtF"}
@@ -0,0 +1,11 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { AvailabilityRuleDetailHost } from "../rule-detail-host.js";
3
+ /**
4
+ * Param-taking page for the `availability-rule-detail` contribution: reads
5
+ * the rule id off {@link AdminRoutePageProps} and binds it onto the packaged
6
+ * host. Resolved lazily through the contribution's `page` loader so the
7
+ * detail page lands in its own chunk.
8
+ */
9
+ export default function AvailabilityRuleDetailRoutePage({ params }) {
10
+ return _jsx(AvailabilityRuleDetailHost, { ruleId: params.id ?? "" });
11
+ }
@@ -0,0 +1,9 @@
1
+ import type { AdminRoutePageProps } from "@voyantjs/admin";
2
+ /**
3
+ * Param-taking page for the `availability-slot-detail` contribution: reads
4
+ * the slot id off {@link AdminRoutePageProps} and binds it onto the packaged
5
+ * host. Resolved lazily through the contribution's `page` loader so the
6
+ * detail page lands in its own chunk.
7
+ */
8
+ export default function AvailabilitySlotDetailRoutePage({ params }: AdminRoutePageProps): import("react/jsx-runtime").JSX.Element;
9
+ //# sourceMappingURL=availability-slot-detail-page.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"availability-slot-detail-page.d.ts","sourceRoot":"","sources":["../../../src/admin/pages/availability-slot-detail-page.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AAI1D;;;;;GAKG;AACH,MAAM,CAAC,OAAO,UAAU,+BAA+B,CAAC,EAAE,MAAM,EAAE,EAAE,mBAAmB,2CAEtF"}
@@ -0,0 +1,11 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { AvailabilitySlotDetailHost } from "../slot-detail-host.js";
3
+ /**
4
+ * Param-taking page for the `availability-slot-detail` contribution: reads
5
+ * the slot id off {@link AdminRoutePageProps} and binds it onto the packaged
6
+ * host. Resolved lazily through the contribution's `page` loader so the
7
+ * detail page lands in its own chunk.
8
+ */
9
+ export default function AvailabilitySlotDetailRoutePage({ params }) {
10
+ return _jsx(AvailabilitySlotDetailHost, { slotId: params.id ?? "" });
11
+ }
@@ -0,0 +1,9 @@
1
+ import type { AdminRoutePageProps } from "@voyantjs/admin";
2
+ /**
3
+ * Param-taking page for the `availability-start-time-detail` contribution:
4
+ * reads the start time id off {@link AdminRoutePageProps} and binds it onto
5
+ * the packaged host. Resolved lazily through the contribution's `page`
6
+ * loader so the detail page lands in its own chunk.
7
+ */
8
+ export default function AvailabilityStartTimeDetailRoutePage({ params }: AdminRoutePageProps): import("react/jsx-runtime").JSX.Element;
9
+ //# sourceMappingURL=availability-start-time-detail-page.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"availability-start-time-detail-page.d.ts","sourceRoot":"","sources":["../../../src/admin/pages/availability-start-time-detail-page.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AAI1D;;;;;GAKG;AACH,MAAM,CAAC,OAAO,UAAU,oCAAoC,CAAC,EAAE,MAAM,EAAE,EAAE,mBAAmB,2CAE3F"}
@@ -0,0 +1,11 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { AvailabilityStartTimeDetailHost } from "../start-time-detail-host.js";
3
+ /**
4
+ * Param-taking page for the `availability-start-time-detail` contribution:
5
+ * reads the start time id off {@link AdminRoutePageProps} and binds it onto
6
+ * the packaged host. Resolved lazily through the contribution's `page`
7
+ * loader so the detail page lands in its own chunk.
8
+ */
9
+ export default function AvailabilityStartTimeDetailRoutePage({ params }) {
10
+ return _jsx(AvailabilityStartTimeDetailHost, { startTimeId: params.id ?? "" });
11
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voyantjs/availability-react",
3
- "version": "0.107.0",
3
+ "version": "0.108.0",
4
4
  "license": "Apache-2.0",
5
5
  "repository": {
6
6
  "type": "git",
@@ -73,12 +73,12 @@
73
73
  "react-hook-form": "^7.72.1",
74
74
  "sonner": "^2.0.7",
75
75
  "zod": "^4.0.0",
76
- "@voyantjs/admin": "^0.107.0",
77
- "@voyantjs/allocation-ui": "^0.108.0",
78
- "@voyantjs/availability": "^0.107.0",
79
- "@voyantjs/bookings-react": "^0.110.0",
80
- "@voyantjs/extras-react": "^0.110.0",
81
- "@voyantjs/products-react": "^0.110.0",
76
+ "@voyantjs/admin": "^0.108.0",
77
+ "@voyantjs/allocation-ui": "^0.109.0",
78
+ "@voyantjs/availability": "^0.108.0",
79
+ "@voyantjs/bookings-react": "^0.111.0",
80
+ "@voyantjs/extras-react": "^0.111.0",
81
+ "@voyantjs/products-react": "^0.111.0",
82
82
  "@voyantjs/ui": "^0.106.0"
83
83
  },
84
84
  "peerDependenciesMeta": {
@@ -130,13 +130,13 @@
130
130
  "typescript": "^6.0.2",
131
131
  "vitest": "^4.1.2",
132
132
  "zod": "^4.3.6",
133
- "@voyantjs/admin": "^0.107.0",
134
- "@voyantjs/allocation-ui": "^0.108.0",
135
- "@voyantjs/availability": "^0.107.0",
136
- "@voyantjs/bookings-react": "^0.110.0",
137
- "@voyantjs/extras-react": "^0.110.0",
133
+ "@voyantjs/admin": "^0.108.0",
134
+ "@voyantjs/allocation-ui": "^0.109.0",
135
+ "@voyantjs/availability": "^0.108.0",
136
+ "@voyantjs/bookings-react": "^0.111.0",
137
+ "@voyantjs/extras-react": "^0.111.0",
138
138
  "@voyantjs/i18n": "^0.106.0",
139
- "@voyantjs/products-react": "^0.110.0",
139
+ "@voyantjs/products-react": "^0.111.0",
140
140
  "@voyantjs/react": "^0.104.1",
141
141
  "@voyantjs/ui": "^0.106.0",
142
142
  "@voyantjs/voyant-typescript-config": "^0.1.0"