@voyant-travel/legal-react 0.119.2
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 +201 -0
- package/README.md +66 -0
- package/dist/admin/contract-detail-host.d.ts +21 -0
- package/dist/admin/contract-detail-host.d.ts.map +1 -0
- package/dist/admin/contract-detail-host.js +118 -0
- package/dist/admin/contract-dialog-fields.d.ts +79 -0
- package/dist/admin/contract-dialog-fields.d.ts.map +1 -0
- package/dist/admin/contract-dialog-fields.js +178 -0
- package/dist/admin/contract-dialog.d.ts +4 -0
- package/dist/admin/contract-dialog.d.ts.map +1 -0
- package/dist/admin/contract-dialog.js +479 -0
- package/dist/admin/contract-upload-field.d.ts +12 -0
- package/dist/admin/contract-upload-field.d.ts.map +1 -0
- package/dist/admin/contract-upload-field.js +31 -0
- package/dist/admin/contracts-host.d.ts +10 -0
- package/dist/admin/contracts-host.d.ts.map +1 -0
- package/dist/admin/contracts-host.js +32 -0
- package/dist/admin/index.d.ts +78 -0
- package/dist/admin/index.d.ts.map +1 -0
- package/dist/admin/index.js +193 -0
- package/dist/admin/legal-admin-shared.d.ts +31 -0
- package/dist/admin/legal-admin-shared.d.ts.map +1 -0
- package/dist/admin/legal-admin-shared.js +48 -0
- package/dist/admin/number-series-dialog.d.ts +11 -0
- package/dist/admin/number-series-dialog.d.ts.map +1 -0
- package/dist/admin/number-series-dialog.js +110 -0
- package/dist/admin/number-series-host.d.ts +7 -0
- package/dist/admin/number-series-host.d.ts.map +1 -0
- package/dist/admin/number-series-host.js +12 -0
- package/dist/admin/pages/contract-detail-page.d.ts +7 -0
- package/dist/admin/pages/contract-detail-page.d.ts.map +1 -0
- package/dist/admin/pages/contract-detail-page.js +9 -0
- package/dist/admin/pages/policy-detail-page.d.ts +7 -0
- package/dist/admin/pages/policy-detail-page.d.ts.map +1 -0
- package/dist/admin/pages/policy-detail-page.js +9 -0
- package/dist/admin/pages/template-detail-page.d.ts +7 -0
- package/dist/admin/pages/template-detail-page.d.ts.map +1 -0
- package/dist/admin/pages/template-detail-page.js +9 -0
- package/dist/admin/policies-host.d.ts +9 -0
- package/dist/admin/policies-host.d.ts.map +1 -0
- package/dist/admin/policies-host.js +16 -0
- package/dist/admin/policy-assignment-dialog.d.ts +11 -0
- package/dist/admin/policy-assignment-dialog.d.ts.map +1 -0
- package/dist/admin/policy-assignment-dialog.js +234 -0
- package/dist/admin/policy-detail-host.d.ts +12 -0
- package/dist/admin/policy-detail-host.d.ts.map +1 -0
- package/dist/admin/policy-detail-host.js +17 -0
- package/dist/admin/policy-dialog.d.ts +10 -0
- package/dist/admin/policy-dialog.d.ts.map +1 -0
- package/dist/admin/policy-dialog.js +81 -0
- package/dist/admin/template-detail-host.d.ts +11 -0
- package/dist/admin/template-detail-host.d.ts.map +1 -0
- package/dist/admin/template-detail-host.js +20 -0
- package/dist/admin/template-dialog.d.ts +10 -0
- package/dist/admin/template-dialog.d.ts.map +1 -0
- package/dist/admin/template-dialog.js +117 -0
- package/dist/admin/template-version-dialog.d.ts +9 -0
- package/dist/admin/template-version-dialog.d.ts.map +1 -0
- package/dist/admin/template-version-dialog.js +67 -0
- package/dist/admin/templates-host.d.ts +9 -0
- package/dist/admin/templates-host.d.ts.map +1 -0
- package/dist/admin/templates-host.js +20 -0
- package/dist/client.d.ts +14 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +69 -0
- package/dist/components/attachment-dialog.d.ts +11 -0
- package/dist/components/attachment-dialog.d.ts.map +1 -0
- package/dist/components/attachment-dialog.js +154 -0
- package/dist/components/booking-contract-card.d.ts +37 -0
- package/dist/components/booking-contract-card.d.ts.map +1 -0
- package/dist/components/booking-contract-card.js +101 -0
- package/dist/components/contract-detail-page.d.ts +36 -0
- package/dist/components/contract-detail-page.d.ts.map +1 -0
- package/dist/components/contract-detail-page.js +156 -0
- package/dist/components/contract-dialog-fields.d.ts +114 -0
- package/dist/components/contract-dialog-fields.d.ts.map +1 -0
- package/dist/components/contract-dialog-fields.js +233 -0
- package/dist/components/contract-dialog.d.ts +5 -0
- package/dist/components/contract-dialog.d.ts.map +1 -0
- package/dist/components/contract-dialog.js +345 -0
- package/dist/components/contract-send-dialog.d.ts +37 -0
- package/dist/components/contract-send-dialog.d.ts.map +1 -0
- package/dist/components/contract-send-dialog.js +56 -0
- package/dist/components/contracts-page.d.ts +30 -0
- package/dist/components/contracts-page.d.ts.map +1 -0
- package/dist/components/contracts-page.js +192 -0
- package/dist/components/number-series-page.d.ts +13 -0
- package/dist/components/number-series-page.d.ts.map +1 -0
- package/dist/components/number-series-page.js +37 -0
- package/dist/components/policies-page.d.ts +13 -0
- package/dist/components/policies-page.d.ts.map +1 -0
- package/dist/components/policies-page.js +70 -0
- package/dist/components/policy-detail-page.d.ts +23 -0
- package/dist/components/policy-detail-page.d.ts.map +1 -0
- package/dist/components/policy-detail-page.js +171 -0
- package/dist/components/policy-rule-dialog.d.ts +12 -0
- package/dist/components/policy-rule-dialog.d.ts.map +1 -0
- package/dist/components/policy-rule-dialog.js +101 -0
- package/dist/components/policy-version-dialog.d.ts +11 -0
- package/dist/components/policy-version-dialog.d.ts.map +1 -0
- package/dist/components/policy-version-dialog.js +62 -0
- package/dist/components/signature-dialog.d.ts +9 -0
- package/dist/components/signature-dialog.d.ts.map +1 -0
- package/dist/components/signature-dialog.js +64 -0
- package/dist/components/template-detail-page.d.ts +10 -0
- package/dist/components/template-detail-page.d.ts.map +1 -0
- package/dist/components/template-detail-page.js +84 -0
- package/dist/components/templates-page.d.ts +27 -0
- package/dist/components/templates-page.d.ts.map +1 -0
- package/dist/components/templates-page.js +65 -0
- package/dist/hooks/index.d.ts +31 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +30 -0
- package/dist/hooks/use-contract-attachment-mutation.d.ts +119 -0
- package/dist/hooks/use-contract-attachment-mutation.d.ts.map +1 -0
- package/dist/hooks/use-contract-attachment-mutation.js +72 -0
- package/dist/hooks/use-contract-attachments.d.ts +23 -0
- package/dist/hooks/use-contract-attachments.d.ts.map +1 -0
- package/dist/hooks/use-contract-attachments.js +12 -0
- package/dist/hooks/use-contract-mutation.d.ts +427 -0
- package/dist/hooks/use-contract-mutation.d.ts.map +1 -0
- package/dist/hooks/use-contract-mutation.js +151 -0
- package/dist/hooks/use-contract-signature-mutation.d.ts +35 -0
- package/dist/hooks/use-contract-signature-mutation.d.ts.map +1 -0
- package/dist/hooks/use-contract-signature-mutation.js +23 -0
- package/dist/hooks/use-contract-signatures.d.ts +28 -0
- package/dist/hooks/use-contract-signatures.d.ts.map +1 -0
- package/dist/hooks/use-contract-signatures.js +12 -0
- package/dist/hooks/use-contract-template-authoring.d.ts +5 -0
- package/dist/hooks/use-contract-template-authoring.d.ts.map +1 -0
- package/dist/hooks/use-contract-template-authoring.js +7 -0
- package/dist/hooks/use-contract-template-mutation.d.ts +56 -0
- package/dist/hooks/use-contract-template-mutation.d.ts.map +1 -0
- package/dist/hooks/use-contract-template-mutation.js +39 -0
- package/dist/hooks/use-contract-template-version-mutation.d.ts +22 -0
- package/dist/hooks/use-contract-template-version-mutation.d.ts.map +1 -0
- package/dist/hooks/use-contract-template-version-mutation.js +22 -0
- package/dist/hooks/use-contract-template-versions.d.ts +15 -0
- package/dist/hooks/use-contract-template-versions.d.ts.map +1 -0
- package/dist/hooks/use-contract-template-versions.js +12 -0
- package/dist/hooks/use-contract-template.d.ts +20 -0
- package/dist/hooks/use-contract-template.d.ts.map +1 -0
- package/dist/hooks/use-contract-template.js +12 -0
- package/dist/hooks/use-contract-templates.d.ts +26 -0
- package/dist/hooks/use-contract-templates.d.ts.map +1 -0
- package/dist/hooks/use-contract-templates.js +12 -0
- package/dist/hooks/use-contract.d.ts +47 -0
- package/dist/hooks/use-contract.d.ts.map +1 -0
- package/dist/hooks/use-contract.js +12 -0
- package/dist/hooks/use-contracts.d.ts +53 -0
- package/dist/hooks/use-contracts.d.ts.map +1 -0
- package/dist/hooks/use-contracts.js +12 -0
- package/dist/hooks/use-default-contract-template.d.ts +21 -0
- package/dist/hooks/use-default-contract-template.d.ts.map +1 -0
- package/dist/hooks/use-default-contract-template.js +12 -0
- package/dist/hooks/use-evaluate-cancellation.d.ts +46 -0
- package/dist/hooks/use-evaluate-cancellation.d.ts.map +1 -0
- package/dist/hooks/use-evaluate-cancellation.js +43 -0
- package/dist/hooks/use-number-series-mutation.d.ts +58 -0
- package/dist/hooks/use-number-series-mutation.d.ts.map +1 -0
- package/dist/hooks/use-number-series-mutation.js +38 -0
- package/dist/hooks/use-number-series.d.ts +24 -0
- package/dist/hooks/use-number-series.d.ts.map +1 -0
- package/dist/hooks/use-number-series.js +12 -0
- package/dist/hooks/use-policies.d.ts +22 -0
- package/dist/hooks/use-policies.d.ts.map +1 -0
- package/dist/hooks/use-policies.js +12 -0
- package/dist/hooks/use-policy-acceptances.d.ts +26 -0
- package/dist/hooks/use-policy-acceptances.d.ts.map +1 -0
- package/dist/hooks/use-policy-acceptances.js +12 -0
- package/dist/hooks/use-policy-assignment-mutation.d.ts +63 -0
- package/dist/hooks/use-policy-assignment-mutation.d.ts.map +1 -0
- package/dist/hooks/use-policy-assignment-mutation.js +41 -0
- package/dist/hooks/use-policy-assignments.d.ts +23 -0
- package/dist/hooks/use-policy-assignments.d.ts.map +1 -0
- package/dist/hooks/use-policy-assignments.js +12 -0
- package/dist/hooks/use-policy-mutation.d.ts +44 -0
- package/dist/hooks/use-policy-mutation.d.ts.map +1 -0
- package/dist/hooks/use-policy-mutation.js +40 -0
- package/dist/hooks/use-policy-rule-mutation.d.ts +56 -0
- package/dist/hooks/use-policy-rule-mutation.d.ts.map +1 -0
- package/dist/hooks/use-policy-rule-mutation.js +39 -0
- package/dist/hooks/use-policy-rules.d.ts +22 -0
- package/dist/hooks/use-policy-rules.d.ts.map +1 -0
- package/dist/hooks/use-policy-rules.js +12 -0
- package/dist/hooks/use-policy-version-mutation.d.ts +69 -0
- package/dist/hooks/use-policy-version-mutation.d.ts.map +1 -0
- package/dist/hooks/use-policy-version-mutation.js +50 -0
- package/dist/hooks/use-policy-versions.d.ts +19 -0
- package/dist/hooks/use-policy-versions.d.ts.map +1 -0
- package/dist/hooks/use-policy-versions.js +12 -0
- package/dist/hooks/use-policy.d.ts +16 -0
- package/dist/hooks/use-policy.d.ts.map +1 -0
- package/dist/hooks/use-policy.js +12 -0
- package/dist/hooks/use-resolve-policy.d.ts +72 -0
- package/dist/hooks/use-resolve-policy.d.ts.map +1 -0
- package/dist/hooks/use-resolve-policy.js +16 -0
- package/dist/hooks/use-term.d.ts +27 -0
- package/dist/hooks/use-term.d.ts.map +1 -0
- package/dist/hooks/use-term.js +12 -0
- package/dist/hooks/use-terms.d.ts +33 -0
- package/dist/hooks/use-terms.d.ts.map +1 -0
- package/dist/hooks/use-terms.js +12 -0
- package/dist/i18n/en.d.ts +548 -0
- package/dist/i18n/en.d.ts.map +1 -0
- package/dist/i18n/en.js +547 -0
- package/dist/i18n/index.d.ts +6 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/i18n/index.js +4 -0
- package/dist/i18n/messages.d.ts +504 -0
- package/dist/i18n/messages.d.ts.map +1 -0
- package/dist/i18n/messages.js +29 -0
- package/dist/i18n/provider.d.ts +1118 -0
- package/dist/i18n/provider.d.ts.map +1 -0
- package/dist/i18n/provider.js +44 -0
- package/dist/i18n/ro.d.ts +548 -0
- package/dist/i18n/ro.d.ts.map +1 -0
- package/dist/i18n/ro.js +547 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/provider.d.ts +2 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +1 -0
- package/dist/query-keys.d.ts +120 -0
- package/dist/query-keys.d.ts.map +1 -0
- package/dist/query-keys.js +27 -0
- package/dist/query-options.d.ts +1929 -0
- package/dist/query-options.d.ts.map +1 -0
- package/dist/query-options.js +183 -0
- package/dist/schemas.d.ts +1547 -0
- package/dist/schemas.d.ts.map +1 -0
- package/dist/schemas.js +269 -0
- package/dist/ui.d.ts +16 -0
- package/dist/ui.d.ts.map +1 -0
- package/dist/ui.js +15 -0
- package/package.json +159 -0
- package/src/styles.css +11 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { type AdminExtension } from "@voyant-travel/admin";
|
|
2
|
+
/**
|
|
3
|
+
* Semantic destinations the legal admin surfaces navigate to
|
|
4
|
+
* (packaged-admin RFC §4.7). Keys shared with other domains
|
|
5
|
+
* (`person.detail`, `booking.detail`) come from the bookings-ui
|
|
6
|
+
* augmentation bound above; declared here are the legal-owned targets the
|
|
7
|
+
* packaged pages and breadcrumbs resolve through
|
|
8
|
+
* `useAdminHref`/`useAdminNavigate`.
|
|
9
|
+
*/
|
|
10
|
+
declare module "@voyant-travel/admin" {
|
|
11
|
+
interface AdminDestinations {
|
|
12
|
+
/** The legal area's landing surface (redirects to contracts). */
|
|
13
|
+
"legal.home": Record<string, never>;
|
|
14
|
+
/** The contracts list page. */
|
|
15
|
+
"contract.list": Record<string, never>;
|
|
16
|
+
/** A contract's detail page. */
|
|
17
|
+
"contract.detail": {
|
|
18
|
+
contractId: string;
|
|
19
|
+
};
|
|
20
|
+
/** The contract templates list page. */
|
|
21
|
+
"contractTemplate.list": Record<string, never>;
|
|
22
|
+
/** A contract template's detail page. */
|
|
23
|
+
"contractTemplate.detail": {
|
|
24
|
+
templateId: string;
|
|
25
|
+
};
|
|
26
|
+
/** The policies list page. */
|
|
27
|
+
"policy.list": Record<string, never>;
|
|
28
|
+
/** A policy's detail page. */
|
|
29
|
+
"policy.detail": {
|
|
30
|
+
policyId: string;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export type { ContractDetailHostProps } from "./contract-detail-host.js";
|
|
35
|
+
export type { ContractDialogProps } from "./contract-dialog.js";
|
|
36
|
+
export type { AssignmentData, PolicyAssignmentDialogProps } from "./policy-assignment-dialog.js";
|
|
37
|
+
export type { PolicyDetailHostProps } from "./policy-detail-host.js";
|
|
38
|
+
export type { TemplateDetailHostProps } from "./template-detail-host.js";
|
|
39
|
+
export interface CreateLegalAdminExtensionOptions {
|
|
40
|
+
/** Mount path of the legal pages inside the admin workspace. Default `/legal`. */
|
|
41
|
+
basePath?: string;
|
|
42
|
+
/** Localized page titles. Defaults are the English operator nav labels. */
|
|
43
|
+
labels?: {
|
|
44
|
+
contracts?: string;
|
|
45
|
+
contractTemplates?: string;
|
|
46
|
+
policies?: string;
|
|
47
|
+
numberSeries?: string;
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The legal admin contribution (packaged-admin RFC Phase 3,
|
|
52
|
+
* `@voyant-travel/<domain>-ui/admin` convention).
|
|
53
|
+
*
|
|
54
|
+
* NAVIGATION: deliberately none. The Legal nav group (contracts, contract
|
|
55
|
+
* templates, policies, number series) is part of the BASE operator
|
|
56
|
+
* navigation — see `createOperatorAdminNavigation` in `@voyant-travel/admin` —
|
|
57
|
+
* so contributing nav entries here would duplicate them. If the base nav
|
|
58
|
+
* ever drops the legal group, this extension is where the entries move.
|
|
59
|
+
*
|
|
60
|
+
* ROUTES: full implementations (packaged-admin RFC §4.8 endgame) — each
|
|
61
|
+
* contribution carries the lazy `page` module loader, the data loader and
|
|
62
|
+
* the per-route SSR mode, so hosts bind them through their code-assembled
|
|
63
|
+
* admin route tree with no per-route files. List pages
|
|
64
|
+
* ({@link ContractsHost}, {@link TemplatesHost}, {@link PoliciesHost},
|
|
65
|
+
* {@link NumberSeriesHost}) are zero-prop; the detail contributions resolve
|
|
66
|
+
* wrapper pages (`./pages/*`) that bind the matched `$id` param onto
|
|
67
|
+
* {@link ContractDetailHost}, {@link TemplateDetailHost} and
|
|
68
|
+
* {@link PolicyDetailHost}. Pages stay code-split because every `page` is a
|
|
69
|
+
* dynamic import of the specific host module, never a static reference from
|
|
70
|
+
* this factory.
|
|
71
|
+
*
|
|
72
|
+
* WIDGETS: none today. The legal-owned `BookingContractCard` ships from the
|
|
73
|
+
* package root, but no operator surface currently mounts it through a
|
|
74
|
+
* widget slot — the booking detail page's documents/contract wiring is an
|
|
75
|
+
* operator bookings-domain concern and stays with that host.
|
|
76
|
+
*/
|
|
77
|
+
export declare function createLegalAdminExtension(options?: CreateLegalAdminExtensionOptions): AdminExtension;
|
|
78
|
+
//# 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,EACL,KAAK,cAAc,EAKpB,MAAM,sBAAsB,CAAA;AAc7B;;;;;;;GAOG;AACH,OAAO,QAAQ,sBAAsB,CAAC;IACpC,UAAU,iBAAiB;QACzB,iEAAiE;QACjE,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;QACnC,+BAA+B;QAC/B,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;QACtC,gCAAgC;QAChC,iBAAiB,EAAE;YAAE,UAAU,EAAE,MAAM,CAAA;SAAE,CAAA;QACzC,wCAAwC;QACxC,uBAAuB,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;QAC9C,yCAAyC;QACzC,yBAAyB,EAAE;YAAE,UAAU,EAAE,MAAM,CAAA;SAAE,CAAA;QACjD,8BAA8B;QAC9B,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;QACpC,8BAA8B;QAC9B,eAAe,EAAE;YAAE,QAAQ,EAAE,MAAM,CAAA;SAAE,CAAA;KACtC;CACF;AAWD,YAAY,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAA;AACxE,YAAY,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAA;AAC/D,YAAY,EAAE,cAAc,EAAE,2BAA2B,EAAE,MAAM,+BAA+B,CAAA;AAChG,YAAY,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAA;AACpE,YAAY,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAA;AAWxE,MAAM,WAAW,gCAAgC;IAC/C,kFAAkF;IAClF,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,2EAA2E;IAC3E,MAAM,CAAC,EAAE;QACP,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,iBAAiB,CAAC,EAAE,MAAM,CAAA;QAC1B,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,YAAY,CAAC,EAAE,MAAM,CAAA;KACtB,CAAA;CACF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,GAAE,gCAAqC,GAC7C,cAAc,CA0MhB"}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { adminRoutePageModule, defineAdminExtension, } from "@voyant-travel/admin";
|
|
2
|
+
// Lean static only: the client module (fetcher + client contract type).
|
|
3
|
+
// Query options resolve via dynamic import inside the loaders so the legal
|
|
4
|
+
// data layer (client + response schemas) stays out of the workspace-chrome
|
|
5
|
+
// chunk that evaluates this factory.
|
|
6
|
+
import { defaultFetcher } from "../client.js";
|
|
7
|
+
/**
|
|
8
|
+
* Bind the host-supplied route runtime to the legal data-client shape the
|
|
9
|
+
* query-option factories take. Hosts that don't inject a fetcher (no SSR
|
|
10
|
+
* cookie forwarding) fall back to the package's `defaultFetcher`.
|
|
11
|
+
*/
|
|
12
|
+
function toLegalClient(runtime) {
|
|
13
|
+
return { baseUrl: runtime.baseUrl, fetcher: runtime.fetcher ?? defaultFetcher };
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* The legal admin contribution (packaged-admin RFC Phase 3,
|
|
17
|
+
* `@voyant-travel/<domain>-ui/admin` convention).
|
|
18
|
+
*
|
|
19
|
+
* NAVIGATION: deliberately none. The Legal nav group (contracts, contract
|
|
20
|
+
* templates, policies, number series) is part of the BASE operator
|
|
21
|
+
* navigation — see `createOperatorAdminNavigation` in `@voyant-travel/admin` —
|
|
22
|
+
* so contributing nav entries here would duplicate them. If the base nav
|
|
23
|
+
* ever drops the legal group, this extension is where the entries move.
|
|
24
|
+
*
|
|
25
|
+
* ROUTES: full implementations (packaged-admin RFC §4.8 endgame) — each
|
|
26
|
+
* contribution carries the lazy `page` module loader, the data loader and
|
|
27
|
+
* the per-route SSR mode, so hosts bind them through their code-assembled
|
|
28
|
+
* admin route tree with no per-route files. List pages
|
|
29
|
+
* ({@link ContractsHost}, {@link TemplatesHost}, {@link PoliciesHost},
|
|
30
|
+
* {@link NumberSeriesHost}) are zero-prop; the detail contributions resolve
|
|
31
|
+
* wrapper pages (`./pages/*`) that bind the matched `$id` param onto
|
|
32
|
+
* {@link ContractDetailHost}, {@link TemplateDetailHost} and
|
|
33
|
+
* {@link PolicyDetailHost}. Pages stay code-split because every `page` is a
|
|
34
|
+
* dynamic import of the specific host module, never a static reference from
|
|
35
|
+
* this factory.
|
|
36
|
+
*
|
|
37
|
+
* WIDGETS: none today. The legal-owned `BookingContractCard` ships from the
|
|
38
|
+
* package root, but no operator surface currently mounts it through a
|
|
39
|
+
* widget slot — the booking detail page's documents/contract wiring is an
|
|
40
|
+
* operator bookings-domain concern and stays with that host.
|
|
41
|
+
*/
|
|
42
|
+
export function createLegalAdminExtension(options = {}) {
|
|
43
|
+
const { basePath = "/legal", labels = {} } = options;
|
|
44
|
+
const { contracts = "Contracts", contractTemplates = "Contract Templates", policies = "Policies", numberSeries = "Number Series", } = labels;
|
|
45
|
+
return defineAdminExtension({
|
|
46
|
+
id: "legal",
|
|
47
|
+
routes: [
|
|
48
|
+
{
|
|
49
|
+
// Index redirect (formerly the host's `legal/index.tsx` file
|
|
50
|
+
// route): `/legal` lands on the contracts page. This is the route
|
|
51
|
+
// behind the hand-written `legal.home` resolver — it stays
|
|
52
|
+
// unannotated (no `destination:`) until the host's generated
|
|
53
|
+
// destinations module is regenerated to claim it.
|
|
54
|
+
id: "legal-index",
|
|
55
|
+
path: basePath,
|
|
56
|
+
title: contracts,
|
|
57
|
+
redirectTo: `${basePath}/contracts`,
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
id: "legal-contracts-index",
|
|
61
|
+
path: `${basePath}/contracts`,
|
|
62
|
+
title: contracts,
|
|
63
|
+
// Route-backed destination (RFC §4.7 endgame): the key resolves by
|
|
64
|
+
// pure path interpolation of this route, so the host's resolver is
|
|
65
|
+
// generated (`voyant admin generate --destinations`). `legal.home`
|
|
66
|
+
// stays hand-written — it targets the host's index redirect, not a
|
|
67
|
+
// contributed route.
|
|
68
|
+
destination: "contract.list",
|
|
69
|
+
ssr: "data-only",
|
|
70
|
+
page: () => import("./contracts-host.js").then((module) => adminRoutePageModule(module.ContractsHost)),
|
|
71
|
+
// Dynamic import on purpose: the query options pull the legal data
|
|
72
|
+
// layer (client + response schemas), and a static import here would
|
|
73
|
+
// pin it into the workspace-chrome chunk that evaluates this factory.
|
|
74
|
+
loader: async ({ queryClient, runtime }) => {
|
|
75
|
+
const { getLegalContractsQueryOptions } = await import("../query-options.js");
|
|
76
|
+
return queryClient.ensureQueryData(getLegalContractsQueryOptions(toLegalClient(runtime), {
|
|
77
|
+
search: "",
|
|
78
|
+
scope: "all",
|
|
79
|
+
status: "all",
|
|
80
|
+
limit: 25,
|
|
81
|
+
offset: 0,
|
|
82
|
+
}));
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
id: "legal-contracts-detail",
|
|
87
|
+
path: `${basePath}/contracts/$id`,
|
|
88
|
+
title: contracts,
|
|
89
|
+
destination: "contract.detail",
|
|
90
|
+
destinationParams: { id: "contractId" },
|
|
91
|
+
ssr: "data-only",
|
|
92
|
+
page: () => import("./pages/contract-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 contracts index loader above.
|
|
98
|
+
const { getLegalContractAttachmentsQueryOptions, getLegalContractQueryOptions, getLegalContractSignaturesQueryOptions, } = await import("../query-options.js");
|
|
99
|
+
const client = toLegalClient(runtime);
|
|
100
|
+
await queryClient.ensureQueryData(getLegalContractQueryOptions(client, id));
|
|
101
|
+
void queryClient.prefetchQuery(getLegalContractSignaturesQueryOptions(client, { contractId: id }));
|
|
102
|
+
void queryClient.prefetchQuery(getLegalContractAttachmentsQueryOptions(client, { contractId: id }));
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
id: "legal-templates-index",
|
|
107
|
+
path: `${basePath}/templates`,
|
|
108
|
+
title: contractTemplates,
|
|
109
|
+
destination: "contractTemplate.list",
|
|
110
|
+
ssr: "data-only",
|
|
111
|
+
page: () => import("./templates-host.js").then((module) => adminRoutePageModule(module.TemplatesHost)),
|
|
112
|
+
// Dynamic import on purpose — see the contracts index loader above.
|
|
113
|
+
loader: async ({ queryClient, runtime }) => {
|
|
114
|
+
const { getLegalContractTemplatesQueryOptions } = await import("../query-options.js");
|
|
115
|
+
return queryClient.ensureQueryData(getLegalContractTemplatesQueryOptions(toLegalClient(runtime), {
|
|
116
|
+
search: "",
|
|
117
|
+
scope: "all",
|
|
118
|
+
}));
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
id: "legal-templates-detail",
|
|
123
|
+
path: `${basePath}/templates/$id`,
|
|
124
|
+
title: contractTemplates,
|
|
125
|
+
destination: "contractTemplate.detail",
|
|
126
|
+
destinationParams: { id: "templateId" },
|
|
127
|
+
ssr: "data-only",
|
|
128
|
+
page: () => import("./pages/template-detail-page.js"),
|
|
129
|
+
loader: async ({ queryClient, runtime, params }) => {
|
|
130
|
+
const id = params.id;
|
|
131
|
+
if (!id)
|
|
132
|
+
return;
|
|
133
|
+
// Dynamic import on purpose — see the contracts index loader above.
|
|
134
|
+
const { getLegalContractTemplateQueryOptions, getLegalContractTemplateVersionsQueryOptions, } = await import("../query-options.js");
|
|
135
|
+
const client = toLegalClient(runtime);
|
|
136
|
+
await queryClient.ensureQueryData(getLegalContractTemplateQueryOptions(client, id));
|
|
137
|
+
void queryClient.prefetchQuery(getLegalContractTemplateVersionsQueryOptions(client, { templateId: id }));
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
id: "legal-policies-index",
|
|
142
|
+
path: `${basePath}/policies`,
|
|
143
|
+
title: policies,
|
|
144
|
+
destination: "policy.list",
|
|
145
|
+
ssr: "data-only",
|
|
146
|
+
page: () => import("./policies-host.js").then((module) => adminRoutePageModule(module.PoliciesHost)),
|
|
147
|
+
// Dynamic import on purpose — see the contracts index loader above.
|
|
148
|
+
loader: async ({ queryClient, runtime }) => {
|
|
149
|
+
const { getLegalPoliciesQueryOptions } = await import("../query-options.js");
|
|
150
|
+
return queryClient.ensureQueryData(getLegalPoliciesQueryOptions(toLegalClient(runtime), {
|
|
151
|
+
search: "",
|
|
152
|
+
kind: "all",
|
|
153
|
+
limit: 25,
|
|
154
|
+
offset: 0,
|
|
155
|
+
}));
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
id: "legal-policies-detail",
|
|
160
|
+
path: `${basePath}/policies/$id`,
|
|
161
|
+
title: policies,
|
|
162
|
+
destination: "policy.detail",
|
|
163
|
+
destinationParams: { id: "policyId" },
|
|
164
|
+
ssr: "data-only",
|
|
165
|
+
page: () => import("./pages/policy-detail-page.js"),
|
|
166
|
+
loader: async ({ queryClient, runtime, params }) => {
|
|
167
|
+
const id = params.id;
|
|
168
|
+
if (!id)
|
|
169
|
+
return;
|
|
170
|
+
// Dynamic import on purpose — see the contracts index loader above.
|
|
171
|
+
const { getLegalPolicyAcceptancesQueryOptions, getLegalPolicyAssignmentsQueryOptions, getLegalPolicyQueryOptions, getLegalPolicyVersionsQueryOptions, } = await import("../query-options.js");
|
|
172
|
+
const client = toLegalClient(runtime);
|
|
173
|
+
await queryClient.ensureQueryData(getLegalPolicyQueryOptions(client, id));
|
|
174
|
+
void queryClient.prefetchQuery(getLegalPolicyVersionsQueryOptions(client, { policyId: id }));
|
|
175
|
+
void queryClient.prefetchQuery(getLegalPolicyAssignmentsQueryOptions(client, { policyId: id }));
|
|
176
|
+
void queryClient.prefetchQuery(getLegalPolicyAcceptancesQueryOptions(client, { limit: 50, offset: 0 }));
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
id: "legal-number-series",
|
|
181
|
+
path: `${basePath}/number-series`,
|
|
182
|
+
title: numberSeries,
|
|
183
|
+
ssr: "data-only",
|
|
184
|
+
page: () => import("./number-series-host.js").then((module) => adminRoutePageModule(module.NumberSeriesHost)),
|
|
185
|
+
// Dynamic import on purpose — see the contracts index loader above.
|
|
186
|
+
loader: async ({ queryClient, runtime }) => {
|
|
187
|
+
const { getLegalContractNumberSeriesQueryOptions } = await import("../query-options.js");
|
|
188
|
+
return queryClient.ensureQueryData(getLegalContractNumberSeriesQueryOptions(toLegalClient(runtime)));
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
],
|
|
192
|
+
});
|
|
193
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** A searchable-select option: stable id + label, optional secondary line. */
|
|
2
|
+
export interface ComboboxOption {
|
|
3
|
+
value: string;
|
|
4
|
+
label: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Merge option groups by value, later groups winning. Used to splice the
|
|
9
|
+
* currently-selected record (fetched by id) into the searched list page so
|
|
10
|
+
* the selection keeps its label even when it falls outside the page.
|
|
11
|
+
*/
|
|
12
|
+
export declare function mergeUniqueOptions(...groups: Array<ComboboxOption[] | undefined>): ComboboxOption[];
|
|
13
|
+
/**
|
|
14
|
+
* Server-search-backed combobox shared by the legal admin dialogs: the
|
|
15
|
+
* option list comes from a domain list hook (re-queried via
|
|
16
|
+
* `onSearchChange`), the selected record's label from a matching detail
|
|
17
|
+
* hook merged in via {@link mergeUniqueOptions}.
|
|
18
|
+
*/
|
|
19
|
+
export declare function SearchableSelect({ value, onChange, options, placeholder, searchPlaceholder, emptyLabel, loadingLabel, loading, disabled, onSearchChange, }: {
|
|
20
|
+
value: string | null | undefined;
|
|
21
|
+
onChange: (value: string | null) => void;
|
|
22
|
+
options: ComboboxOption[];
|
|
23
|
+
placeholder: string;
|
|
24
|
+
searchPlaceholder?: string;
|
|
25
|
+
emptyLabel: string;
|
|
26
|
+
loadingLabel: string;
|
|
27
|
+
loading?: boolean;
|
|
28
|
+
disabled?: boolean;
|
|
29
|
+
onSearchChange?: (value: string) => void;
|
|
30
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
31
|
+
//# sourceMappingURL=legal-admin-shared.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"legal-admin-shared.d.ts","sourceRoot":"","sources":["../../src/admin/legal-admin-shared.tsx"],"names":[],"mappings":"AAaA,8EAA8E;AAC9E,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,MAAM,EAAE,KAAK,CAAC,cAAc,EAAE,GAAG,SAAS,CAAC,GAC7C,cAAc,EAAE,CAQlB;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,KAAK,EACL,QAAQ,EACR,OAAO,EACP,WAAW,EACX,iBAAiB,EACjB,UAAU,EACV,YAAY,EACZ,OAAO,EACP,QAAQ,EACR,cAAc,GACf,EAAE;IACD,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAA;IAChC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAA;IACxC,OAAO,EAAE,cAAc,EAAE,CAAA;IACzB,WAAW,EAAE,MAAM,CAAA;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CACzC,2CA8DA"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Combobox, ComboboxCollection, ComboboxContent, ComboboxEmpty, ComboboxInput, ComboboxItem, ComboboxList, } from "@voyant-travel/ui/components/combobox";
|
|
4
|
+
import { useEffect, useMemo, useState } from "react";
|
|
5
|
+
/**
|
|
6
|
+
* Merge option groups by value, later groups winning. Used to splice the
|
|
7
|
+
* currently-selected record (fetched by id) into the searched list page so
|
|
8
|
+
* the selection keeps its label even when it falls outside the page.
|
|
9
|
+
*/
|
|
10
|
+
export function mergeUniqueOptions(...groups) {
|
|
11
|
+
const map = new Map();
|
|
12
|
+
for (const group of groups) {
|
|
13
|
+
for (const option of group ?? []) {
|
|
14
|
+
map.set(option.value, option);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return Array.from(map.values());
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Server-search-backed combobox shared by the legal admin dialogs: the
|
|
21
|
+
* option list comes from a domain list hook (re-queried via
|
|
22
|
+
* `onSearchChange`), the selected record's label from a matching detail
|
|
23
|
+
* hook merged in via {@link mergeUniqueOptions}.
|
|
24
|
+
*/
|
|
25
|
+
export function SearchableSelect({ value, onChange, options, placeholder, searchPlaceholder, emptyLabel, loadingLabel, loading, disabled, onSearchChange, }) {
|
|
26
|
+
const optionMap = useMemo(() => new Map(options.map((option) => [option.value, option])), [options]);
|
|
27
|
+
const selected = value ? optionMap.get(value) : undefined;
|
|
28
|
+
const selectedLabel = selected?.label ?? "";
|
|
29
|
+
const [inputValue, setInputValue] = useState(selectedLabel);
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
setInputValue(selectedLabel);
|
|
32
|
+
}, [selectedLabel]);
|
|
33
|
+
return (_jsxs(Combobox, { items: options.map((option) => option.value), value: value ?? null, inputValue: inputValue, autoHighlight: true, disabled: disabled, itemToStringValue: (id) => optionMap.get(id)?.label ?? "", onInputValueChange: (next) => {
|
|
34
|
+
setInputValue(next);
|
|
35
|
+
onSearchChange?.(next);
|
|
36
|
+
if (!next)
|
|
37
|
+
onChange(null);
|
|
38
|
+
}, onValueChange: (next) => {
|
|
39
|
+
const resolved = next ?? null;
|
|
40
|
+
onChange(resolved);
|
|
41
|
+
setInputValue(resolved ? (optionMap.get(resolved)?.label ?? "") : "");
|
|
42
|
+
}, children: [_jsx(ComboboxInput, { placeholder: searchPlaceholder ?? placeholder, showClear: !!value, disabled: disabled }), _jsxs(ComboboxContent, { children: [_jsx(ComboboxEmpty, { children: loading ? loadingLabel : emptyLabel }), _jsx(ComboboxList, { children: _jsx(ComboboxCollection, { children: (id) => {
|
|
43
|
+
const option = optionMap.get(id);
|
|
44
|
+
if (!option)
|
|
45
|
+
return null;
|
|
46
|
+
return (_jsx(ComboboxItem, { value: option.value, children: _jsxs("div", { className: "flex min-w-0 flex-col", children: [_jsx("span", { className: "truncate font-medium", children: option.label }), option.description ? (_jsx("span", { className: "truncate text-xs text-muted-foreground", children: option.description })) : null] }) }, option.value));
|
|
47
|
+
} }) })] })] }));
|
|
48
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type LegalContractNumberSeriesRecord } from "../index.js";
|
|
2
|
+
export type NumberSeriesData = LegalContractNumberSeriesRecord;
|
|
3
|
+
type NumberSeriesDialogProps = {
|
|
4
|
+
open: boolean;
|
|
5
|
+
onOpenChange: (open: boolean) => void;
|
|
6
|
+
series?: NumberSeriesData;
|
|
7
|
+
onSuccess: () => void;
|
|
8
|
+
};
|
|
9
|
+
export declare function NumberSeriesDialog({ open, onOpenChange, series, onSuccess, }: NumberSeriesDialogProps): import("react/jsx-runtime").JSX.Element;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=number-series-dialog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"number-series-dialog.d.ts","sourceRoot":"","sources":["../../src/admin/number-series-dialog.tsx"],"names":[],"mappings":"AAwBA,OAAO,EACL,KAAK,+BAA+B,EAGrC,MAAM,aAAa,CAAA;AAepB,MAAM,MAAM,gBAAgB,GAAG,+BAA+B,CAAA;AAE9D,KAAK,uBAAuB,GAAG;IAC7B,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,MAAM,CAAC,EAAE,gBAAgB,CAAA;IACzB,SAAS,EAAE,MAAM,IAAI,CAAA;CACtB,CAAA;AAQD,wBAAgB,kBAAkB,CAAC,EACjC,IAAI,EACJ,YAAY,EACZ,MAAM,EACN,SAAS,GACV,EAAE,uBAAuB,2CAwOzB"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useOperatorAdminMessages } from "@voyant-travel/admin";
|
|
3
|
+
import { formatMessage } from "@voyant-travel/i18n";
|
|
4
|
+
import { Button, Dialog, DialogBody, DialogContent, DialogFooter, DialogHeader, DialogTitle, Input, Label, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@voyant-travel/ui/components";
|
|
5
|
+
import { Switch } from "@voyant-travel/ui/components/switch";
|
|
6
|
+
import { zodResolver } from "@voyant-travel/ui/lib/zod-resolver";
|
|
7
|
+
import { Loader2 } from "lucide-react";
|
|
8
|
+
import { useEffect, useMemo } from "react";
|
|
9
|
+
import { useForm } from "react-hook-form";
|
|
10
|
+
import { z } from "zod/v4";
|
|
11
|
+
import { useLegalContractNumberSeries, useLegalContractNumberSeriesMutation, } from "../index.js";
|
|
12
|
+
const seriesFormSchema = z.object({
|
|
13
|
+
name: z.string().min(1, "nameRequired").max(255),
|
|
14
|
+
prefix: z.string().min(1, "prefixRequired").max(20),
|
|
15
|
+
separator: z.string().max(5).optional(),
|
|
16
|
+
padLength: z.coerce.number().int().min(0).max(12).optional(),
|
|
17
|
+
resetStrategy: z.enum(["never", "annual", "monthly"]),
|
|
18
|
+
scope: z.enum(["customer", "supplier", "partner", "channel", "other"]),
|
|
19
|
+
active: z.boolean(),
|
|
20
|
+
});
|
|
21
|
+
const RESET_STRATEGY_VALUES = ["never", "annual", "monthly"];
|
|
22
|
+
const SCOPE_VALUES = ["customer", "supplier", "partner", "channel", "other"];
|
|
23
|
+
export function NumberSeriesDialog({ open, onOpenChange, series, onSuccess, }) {
|
|
24
|
+
const isEditing = !!series;
|
|
25
|
+
const t = useOperatorAdminMessages().legal.numberSeriesDialog;
|
|
26
|
+
const { create, update } = useLegalContractNumberSeriesMutation();
|
|
27
|
+
const { data: existingList } = useLegalContractNumberSeries();
|
|
28
|
+
const validationByCode = {
|
|
29
|
+
nameRequired: t.validation.nameRequired,
|
|
30
|
+
prefixRequired: t.validation.prefixRequired,
|
|
31
|
+
};
|
|
32
|
+
const resolveValidation = (code) => (code && validationByCode[code]) || code || "";
|
|
33
|
+
const form = useForm({
|
|
34
|
+
resolver: zodResolver(seriesFormSchema),
|
|
35
|
+
defaultValues: {
|
|
36
|
+
name: "",
|
|
37
|
+
prefix: "CTR",
|
|
38
|
+
separator: "",
|
|
39
|
+
padLength: 4,
|
|
40
|
+
resetStrategy: "never",
|
|
41
|
+
scope: "customer",
|
|
42
|
+
active: true,
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
if (open && series) {
|
|
47
|
+
form.reset({
|
|
48
|
+
name: series.name,
|
|
49
|
+
prefix: series.prefix,
|
|
50
|
+
separator: series.separator,
|
|
51
|
+
padLength: series.padLength,
|
|
52
|
+
resetStrategy: series.resetStrategy,
|
|
53
|
+
scope: series.scope,
|
|
54
|
+
active: series.active,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
else if (open) {
|
|
58
|
+
form.reset();
|
|
59
|
+
}
|
|
60
|
+
}, [open, series, form]);
|
|
61
|
+
const onSubmit = async (values) => {
|
|
62
|
+
const payload = {
|
|
63
|
+
name: values.name,
|
|
64
|
+
prefix: values.prefix,
|
|
65
|
+
separator: values.separator || "",
|
|
66
|
+
padLength: values.padLength ?? 4,
|
|
67
|
+
resetStrategy: values.resetStrategy,
|
|
68
|
+
scope: values.scope,
|
|
69
|
+
active: values.active,
|
|
70
|
+
};
|
|
71
|
+
if (isEditing && series) {
|
|
72
|
+
await update.mutateAsync({ id: series.id, input: payload });
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
await create.mutateAsync(payload);
|
|
76
|
+
}
|
|
77
|
+
onSuccess();
|
|
78
|
+
};
|
|
79
|
+
const prefix = form.watch("prefix") || "";
|
|
80
|
+
const separator = form.watch("separator") || "";
|
|
81
|
+
const watchedScope = form.watch("scope");
|
|
82
|
+
const watchedActive = form.watch("active");
|
|
83
|
+
const padLengthValue = form.watch("padLength");
|
|
84
|
+
// The DB has a partial unique index on (prefix, scope) WHERE active.
|
|
85
|
+
// Surface the collision before submit so the operator gets a friendly
|
|
86
|
+
// hint instead of an opaque server error.
|
|
87
|
+
const conflictingSeries = useMemo(() => {
|
|
88
|
+
if (!watchedActive || !prefix)
|
|
89
|
+
return null;
|
|
90
|
+
const rows = existingList?.data ?? [];
|
|
91
|
+
return (rows.find((row) => row.active &&
|
|
92
|
+
row.prefix === prefix &&
|
|
93
|
+
row.scope === watchedScope &&
|
|
94
|
+
row.id !== series?.id) ?? null);
|
|
95
|
+
}, [existingList, watchedActive, prefix, watchedScope, series?.id]);
|
|
96
|
+
const padLength = typeof padLengthValue === "number" && Number.isFinite(padLengthValue) ? padLengthValue : 4;
|
|
97
|
+
const sampleSequence = series ? (series.currentSequence ?? 0) + 1 : 42;
|
|
98
|
+
const sampleNumber = `${prefix}${prefix && separator ? separator : ""}${String(sampleSequence).padStart(padLength, "0")}`;
|
|
99
|
+
return (_jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: _jsxs(DialogContent, { children: [_jsx(DialogHeader, { children: _jsx(DialogTitle, { children: isEditing ? t.titleEdit : t.titleNew }) }), _jsxs("form", { onSubmit: form.handleSubmit(onSubmit), children: [_jsxs(DialogBody, { className: "grid gap-4", children: [_jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: t.nameLabel }), _jsx(Input, { ...form.register("name"), placeholder: t.namePlaceholder }), form.formState.errors.name && (_jsx("p", { className: "text-xs text-destructive", children: resolveValidation(form.formState.errors.name.message) }))] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: t.prefixLabel }), _jsx(Input, { ...form.register("prefix"), placeholder: t.prefixPlaceholder, maxLength: 20 }), _jsx("p", { className: "text-xs text-muted-foreground", children: t.prefixHelp }), form.formState.errors.prefix && (_jsx("p", { className: "text-xs text-destructive", children: resolveValidation(form.formState.errors.prefix.message) }))] })] }), _jsxs("div", { className: "grid grid-cols-3 gap-4", children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: t.separatorLabel }), _jsx(Input, { ...form.register("separator"), placeholder: t.separatorPlaceholder, maxLength: 5 })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: t.padLengthLabel }), _jsx(Input, { ...form.register("padLength"), type: "number", min: 0, max: 12 })] })] }), _jsxs("div", { className: "rounded-md border bg-muted/30 p-3", children: [_jsx("div", { className: "text-sm font-medium", children: t.previewLabel }), _jsx("div", { className: "mt-1 font-mono text-sm", children: sampleNumber || String(sampleSequence).padStart(padLength, "0") }), _jsx("p", { className: "mt-1 text-xs text-muted-foreground", children: series ? t.previewExisting : t.previewSample })] }), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: t.resetStrategyLabel }), _jsxs(Select, { items: RESET_STRATEGY_VALUES.map((value) => ({
|
|
100
|
+
value,
|
|
101
|
+
label: t.resetStrategyOptions[value],
|
|
102
|
+
})), value: form.watch("resetStrategy"), onValueChange: (v) => form.setValue("resetStrategy", v), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: RESET_STRATEGY_VALUES.map((value) => (_jsx(SelectItem, { value: value, children: t.resetStrategyOptions[value] }, value))) })] })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Label, { children: t.scopeLabel }), _jsxs(Select, { items: SCOPE_VALUES.map((value) => ({
|
|
103
|
+
value,
|
|
104
|
+
label: t.scopeOptions[value],
|
|
105
|
+
})), value: form.watch("scope"), onValueChange: (v) => form.setValue("scope", v), children: [_jsx(SelectTrigger, { className: "w-full", children: _jsx(SelectValue, {}) }), _jsx(SelectContent, { children: SCOPE_VALUES.map((value) => (_jsx(SelectItem, { value: value, children: t.scopeOptions[value] }, value))) })] })] })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Switch, { checked: form.watch("active"), onCheckedChange: (checked) => form.setValue("active", checked) }), _jsx(Label, { children: t.activeLabel })] }), conflictingSeries ? (_jsx("p", { className: "rounded-md border border-destructive/50 bg-destructive/10 p-3 text-xs text-destructive", children: formatMessage(t.conflictMessage, {
|
|
106
|
+
prefix: conflictingSeries.prefix,
|
|
107
|
+
scope: conflictingSeries.scope,
|
|
108
|
+
name: conflictingSeries.name,
|
|
109
|
+
}) })) : null] }), _jsxs(DialogFooter, { children: [_jsx(Button, { type: "button", variant: "ghost", onClick: () => onOpenChange(false), children: t.cancel }), _jsxs(Button, { type: "submit", disabled: form.formState.isSubmitting || conflictingSeries !== null, children: [form.formState.isSubmitting && _jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), isEditing ? t.saveChanges : t.createAction] })] })] })] }) }));
|
|
110
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Packaged admin host for the operator-grade contract number series page
|
|
3
|
+
* (packaged-admin RFC Phase 3). Zero-prop: the page navigates nowhere; the
|
|
4
|
+
* create/edit dialog is the packaged {@link NumberSeriesDialog}.
|
|
5
|
+
*/
|
|
6
|
+
export declare function NumberSeriesHost(): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
//# sourceMappingURL=number-series-host.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"number-series-host.d.ts","sourceRoot":"","sources":["../../src/admin/number-series-host.tsx"],"names":[],"mappings":"AAKA;;;;GAIG;AACH,wBAAgB,gBAAgB,4CAI/B"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { NumberSeriesPage } from "../components/number-series-page.js";
|
|
4
|
+
import { NumberSeriesDialog } from "./number-series-dialog.js";
|
|
5
|
+
/**
|
|
6
|
+
* Packaged admin host for the operator-grade contract number series page
|
|
7
|
+
* (packaged-admin RFC Phase 3). Zero-prop: the page navigates nowhere; the
|
|
8
|
+
* create/edit dialog is the packaged {@link NumberSeriesDialog}.
|
|
9
|
+
*/
|
|
10
|
+
export function NumberSeriesHost() {
|
|
11
|
+
return (_jsx(NumberSeriesPage, { renderNumberSeriesDialog: (props) => _jsx(NumberSeriesDialog, { ...props }) }));
|
|
12
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { AdminRoutePageProps } from "@voyant-travel/admin";
|
|
2
|
+
/**
|
|
3
|
+
* Route page for the `legal-contracts-detail` contribution: binds the
|
|
4
|
+
* matched route's `$id` param onto {@link ContractDetailHost}.
|
|
5
|
+
*/
|
|
6
|
+
export default function ContractDetailPage({ params }: AdminRoutePageProps): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
//# sourceMappingURL=contract-detail-page.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract-detail-page.d.ts","sourceRoot":"","sources":["../../../src/admin/pages/contract-detail-page.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAA;AAI/D;;;GAGG;AACH,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAC,EAAE,MAAM,EAAE,EAAE,mBAAmB,2CAEzE"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { ContractDetailHost } from "../contract-detail-host.js";
|
|
3
|
+
/**
|
|
4
|
+
* Route page for the `legal-contracts-detail` contribution: binds the
|
|
5
|
+
* matched route's `$id` param onto {@link ContractDetailHost}.
|
|
6
|
+
*/
|
|
7
|
+
export default function ContractDetailPage({ params }) {
|
|
8
|
+
return _jsx(ContractDetailHost, { id: params.id ?? "" });
|
|
9
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { AdminRoutePageProps } from "@voyant-travel/admin";
|
|
2
|
+
/**
|
|
3
|
+
* Route page for the `legal-policies-detail` contribution: binds the
|
|
4
|
+
* matched route's `$id` param onto {@link PolicyDetailHost}.
|
|
5
|
+
*/
|
|
6
|
+
export default function PolicyDetailPage({ params }: AdminRoutePageProps): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
//# sourceMappingURL=policy-detail-page.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy-detail-page.d.ts","sourceRoot":"","sources":["../../../src/admin/pages/policy-detail-page.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAA;AAI/D;;;GAGG;AACH,MAAM,CAAC,OAAO,UAAU,gBAAgB,CAAC,EAAE,MAAM,EAAE,EAAE,mBAAmB,2CAEvE"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { PolicyDetailHost } from "../policy-detail-host.js";
|
|
3
|
+
/**
|
|
4
|
+
* Route page for the `legal-policies-detail` contribution: binds the
|
|
5
|
+
* matched route's `$id` param onto {@link PolicyDetailHost}.
|
|
6
|
+
*/
|
|
7
|
+
export default function PolicyDetailPage({ params }) {
|
|
8
|
+
return _jsx(PolicyDetailHost, { id: params.id ?? "" });
|
|
9
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { AdminRoutePageProps } from "@voyant-travel/admin";
|
|
2
|
+
/**
|
|
3
|
+
* Route page for the `legal-templates-detail` contribution: binds the
|
|
4
|
+
* matched route's `$id` param onto {@link TemplateDetailHost}.
|
|
5
|
+
*/
|
|
6
|
+
export default function TemplateDetailPage({ params }: AdminRoutePageProps): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
//# sourceMappingURL=template-detail-page.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template-detail-page.d.ts","sourceRoot":"","sources":["../../../src/admin/pages/template-detail-page.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAA;AAI/D;;;GAGG;AACH,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAC,EAAE,MAAM,EAAE,EAAE,mBAAmB,2CAEzE"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { TemplateDetailHost } from "../template-detail-host.js";
|
|
3
|
+
/**
|
|
4
|
+
* Route page for the `legal-templates-detail` contribution: binds the
|
|
5
|
+
* matched route's `$id` param onto {@link TemplateDetailHost}.
|
|
6
|
+
*/
|
|
7
|
+
export default function TemplateDetailPage({ params }) {
|
|
8
|
+
return _jsx(TemplateDetailHost, { id: params.id ?? "" });
|
|
9
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Packaged admin host for the operator-grade policies list page
|
|
3
|
+
* (packaged-admin RFC Phase 3). Zero-prop: list state stays
|
|
4
|
+
* component-local, opening a row resolves through the `policy.detail`
|
|
5
|
+
* semantic destination, and the create dialog is the packaged
|
|
6
|
+
* {@link PolicyDialog}.
|
|
7
|
+
*/
|
|
8
|
+
export declare function PoliciesHost(): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
//# sourceMappingURL=policies-host.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policies-host.d.ts","sourceRoot":"","sources":["../../src/admin/policies-host.tsx"],"names":[],"mappings":"AAOA;;;;;;GAMG;AACH,wBAAgB,YAAY,4CAS3B"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useAdminNavigate } from "@voyant-travel/admin";
|
|
4
|
+
import { PoliciesPage } from "../components/policies-page.js";
|
|
5
|
+
import { PolicyDialog } from "./policy-dialog.js";
|
|
6
|
+
/**
|
|
7
|
+
* Packaged admin host for the operator-grade policies list page
|
|
8
|
+
* (packaged-admin RFC Phase 3). Zero-prop: list state stays
|
|
9
|
+
* component-local, opening a row resolves through the `policy.detail`
|
|
10
|
+
* semantic destination, and the create dialog is the packaged
|
|
11
|
+
* {@link PolicyDialog}.
|
|
12
|
+
*/
|
|
13
|
+
export function PoliciesHost() {
|
|
14
|
+
const navigateTo = useAdminNavigate();
|
|
15
|
+
return (_jsx(PoliciesPage, { onOpenPolicy: (id) => navigateTo("policy.detail", { policyId: id }), renderPolicyDialog: (props) => _jsx(PolicyDialog, { ...props }) }));
|
|
16
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type LegalPolicyAssignmentRecord } from "../index.js";
|
|
2
|
+
export type AssignmentData = LegalPolicyAssignmentRecord;
|
|
3
|
+
export interface PolicyAssignmentDialogProps {
|
|
4
|
+
open: boolean;
|
|
5
|
+
onOpenChange: (open: boolean) => void;
|
|
6
|
+
policyId: string;
|
|
7
|
+
assignment?: AssignmentData;
|
|
8
|
+
onSuccess: () => void;
|
|
9
|
+
}
|
|
10
|
+
export declare function PolicyAssignmentDialog({ open, onOpenChange, policyId, assignment, onSuccess, }: PolicyAssignmentDialogProps): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
//# sourceMappingURL=policy-assignment-dialog.d.ts.map
|