@voyantjs/legal-ui 0.74.2 → 0.75.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/dist/components/booking-contract-card.d.ts +3 -4
- package/dist/components/booking-contract-card.d.ts.map +1 -1
- package/dist/components/booking-contract-card.js +11 -5
- package/dist/components/contract-detail-page.d.ts.map +1 -1
- package/dist/components/contract-detail-page.js +12 -2
- package/package.json +9 -9
|
@@ -12,10 +12,9 @@ export interface BookingContractCardProps {
|
|
|
12
12
|
/** Optional language fallbacks for default-template resolution. */
|
|
13
13
|
fallbackLanguages?: string[];
|
|
14
14
|
/**
|
|
15
|
-
* API base for attachment download redirects
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* tab correctly.
|
|
15
|
+
* API base for attachment download redirects. Defaults to the active
|
|
16
|
+
* `VoyantLegalProvider` base URL; override when a host needs a different
|
|
17
|
+
* download origin than its data hooks use.
|
|
19
18
|
*/
|
|
20
19
|
apiBaseUrl?: string;
|
|
21
20
|
labels?: BookingContractCardLabels;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"booking-contract-card.d.ts","sourceRoot":"","sources":["../../src/components/booking-contract-card.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"booking-contract-card.d.ts","sourceRoot":"","sources":["../../src/components/booking-contract-card.tsx"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAgB1D,MAAM,MAAM,yBAAyB,GAAG,OAAO,CAC7C,IAAI,CAAC,eAAe,CAAC,qBAAqB,CAAC,EAAE,sBAAsB,CAAC,CACrE,CAAA;AAED,MAAM,WAAW,wBAAwB;IACvC,gFAAgF;IAChF,SAAS,EAAE,MAAM,CAAA;IACjB,kFAAkF;IAClF,aAAa,CAAC,EAAE,UAAU,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAA;IACzE,oEAAoE;IACpE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,mEAAmE;IACnE,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC5B;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,MAAM,CAAC,EAAE,yBAAyB,CAAA;CACnC;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,SAAS,EACT,aAA0B,EAC1B,QAAQ,EACR,SAAS,EACT,iBAAiB,EACjB,UAAU,EACV,MAAM,GACP,EAAE,wBAAwB,2CA2F1B"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useDefaultLegalContractTemplate, useLegalContractAttachments, useLegalContractMutation, useLegalContractNumberSeries, useLegalContracts, } from "@voyantjs/legal-react";
|
|
3
|
+
import { useDefaultLegalContractTemplate, useLegalContractAttachments, useLegalContractMutation, useLegalContractNumberSeries, useLegalContracts, useVoyantLegalContext, } from "@voyantjs/legal-react";
|
|
4
4
|
import { Badge, Button, Card, CardContent, CardHeader, CardTitle } from "@voyantjs/ui/components";
|
|
5
5
|
import { Download, FilePlus2, FileText, Loader2, RotateCw } from "lucide-react";
|
|
6
6
|
import { useLegalUiI18nOrDefault } from "../i18n/index.js";
|
|
@@ -33,6 +33,8 @@ const STATUS_VARIANT = {
|
|
|
33
33
|
*/
|
|
34
34
|
export function BookingContractCard({ bookingId, contractScope = "customer", language, channelId, fallbackLanguages, apiBaseUrl, labels, }) {
|
|
35
35
|
const i18n = useLegalUiI18nOrDefault();
|
|
36
|
+
const { baseUrl } = useVoyantLegalContext();
|
|
37
|
+
const resolvedApiBaseUrl = apiBaseUrl ?? baseUrl;
|
|
36
38
|
const merged = { ...i18n.messages.bookingContractCard, ...labels };
|
|
37
39
|
const contractsQuery = useLegalContracts({ bookingId, limit: 25 });
|
|
38
40
|
const contracts = contractsQuery.data?.data ?? [];
|
|
@@ -65,7 +67,7 @@ export function BookingContractCard({ bookingId, contractScope = "customer", lan
|
|
|
65
67
|
},
|
|
66
68
|
});
|
|
67
69
|
};
|
|
68
|
-
return (_jsxs(Card, { children: [_jsx(CardHeader, { children: _jsxs(CardTitle, { className: "flex items-center gap-2 text-base", children: [_jsx(FileText, { className: "h-4 w-4" }), merged.heading] }) }), _jsx(CardContent, { className: "flex flex-col gap-3", children: contractsQuery.isLoading ? (_jsxs("div", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [_jsx(Loader2, { className: "h-3.5 w-3.5 animate-spin" }), i18n.messages.common.loading] })) : contracts.length === 0 ? (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx("p", { className: "text-xs text-muted-foreground", children: merged.empty }), generationPrerequisitesLoaded && canGenerate ? (_jsxs(Button, { type: "button", size: "sm", onClick: handleGenerateForBooking, disabled: generateForBooking.isPending, className: "w-fit", children: [generateForBooking.isPending ? (_jsx(Loader2, { className: "h-3.5 w-3.5 animate-spin" })) : (_jsx(FilePlus2, { className: "h-3.5 w-3.5" })), _jsx("span", { className: "ml-1 text-xs", children: generateForBooking.isPending ? merged.generating : merged.generateContract })] })) : generationPrerequisitesLoaded ? (_jsx("p", { className: "text-[11px] text-muted-foreground", children: merged.generateUnavailable })) : null] })) : (contracts.map((contract) => (_jsx(BookingContractRow, { contract: contract, apiBaseUrl:
|
|
70
|
+
return (_jsxs(Card, { children: [_jsx(CardHeader, { children: _jsxs(CardTitle, { className: "flex items-center gap-2 text-base", children: [_jsx(FileText, { className: "h-4 w-4" }), merged.heading] }) }), _jsx(CardContent, { className: "flex flex-col gap-3", children: contractsQuery.isLoading ? (_jsxs("div", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [_jsx(Loader2, { className: "h-3.5 w-3.5 animate-spin" }), i18n.messages.common.loading] })) : contracts.length === 0 ? (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx("p", { className: "text-xs text-muted-foreground", children: merged.empty }), generationPrerequisitesLoaded && canGenerate ? (_jsxs(Button, { type: "button", size: "sm", onClick: handleGenerateForBooking, disabled: generateForBooking.isPending, className: "w-fit", children: [generateForBooking.isPending ? (_jsx(Loader2, { className: "h-3.5 w-3.5 animate-spin" })) : (_jsx(FilePlus2, { className: "h-3.5 w-3.5" })), _jsx("span", { className: "ml-1 text-xs", children: generateForBooking.isPending ? merged.generating : merged.generateContract })] })) : generationPrerequisitesLoaded ? (_jsx("p", { className: "text-[11px] text-muted-foreground", children: merged.generateUnavailable })) : null] })) : (contracts.map((contract) => (_jsx(BookingContractRow, { contract: contract, apiBaseUrl: resolvedApiBaseUrl, labels: merged }, contract.id)))) })] }));
|
|
69
71
|
}
|
|
70
72
|
function BookingContractRow({ contract, apiBaseUrl, labels, }) {
|
|
71
73
|
const i18n = useLegalUiI18nOrDefault();
|
|
@@ -81,13 +83,17 @@ function BookingContractRow({ contract, apiBaseUrl, labels, }) {
|
|
|
81
83
|
};
|
|
82
84
|
return (_jsxs("div", { className: "flex flex-col gap-2 rounded-md border p-3", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsxs("div", { className: "flex items-center gap-2 text-sm", children: [_jsxs("span", { className: "font-medium", children: [labels.contractNumber, contract.contractNumber ?? labels.unsaved] }), _jsx(Badge, { variant: STATUS_VARIANT[contract.status] ?? "outline", className: "text-[10px]", children: i18n.messages.bookingContractCard.contractStatusLabels[contract.status] })] }), _jsxs(Button, { type: "button", variant: "ghost", size: "sm", onClick: handleGenerate, disabled: isPending, children: [isPending ? (_jsx(Loader2, { className: "h-3.5 w-3.5 animate-spin" })) : (_jsx(RotateCw, { className: "h-3.5 w-3.5" })), _jsx("span", { className: "ml-1 text-xs", children: hasDocument ? labels.regenerate : labels.generate })] })] }), contract.issuedAt ? (_jsxs("p", { className: "text-[11px] text-muted-foreground", children: [labels.issuedAt, ": ", i18n.formatDate(contract.issuedAt)] })) : null, documentAttachments.length > 0 ? (_jsx("div", { className: "flex flex-col gap-1", children: documentAttachments.map((attachment) => (_jsx(AttachmentDownloadRow, { attachment: attachment, apiBaseUrl: apiBaseUrl, downloadLabel: labels.download }, attachment.id))) })) : (_jsx("p", { className: "text-[11px] text-muted-foreground", children: labels.noAttachments }))] }));
|
|
83
85
|
}
|
|
86
|
+
function withApiBaseUrl(baseUrl, path) {
|
|
87
|
+
const trimmedBase = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
|
|
88
|
+
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
89
|
+
return `${trimmedBase}${normalizedPath}`;
|
|
90
|
+
}
|
|
84
91
|
function AttachmentDownloadRow({ attachment, apiBaseUrl, downloadLabel, }) {
|
|
85
92
|
const i18n = useLegalUiI18nOrDefault();
|
|
86
93
|
// The download endpoint returns a 302 to the signed URL. A plain <a> link
|
|
87
94
|
// with target="_blank" lets the browser follow it and open the file in a
|
|
88
|
-
// new tab.
|
|
89
|
-
|
|
90
|
-
const href = `${apiBaseUrl ?? ""}/v1/admin/legal/contracts/attachments/${attachment.id}/download`;
|
|
95
|
+
// new tab. The href uses the same API base as the data hooks by default.
|
|
96
|
+
const href = withApiBaseUrl(apiBaseUrl ?? "", `/v1/admin/legal/contracts/attachments/${attachment.id}/download`);
|
|
91
97
|
const sizeKb = typeof attachment.fileSize === "number"
|
|
92
98
|
? `${i18n.formatNumber(Math.round(attachment.fileSize / 1024))} ${i18n.messages.common.kilobytes}`
|
|
93
99
|
: null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract-detail-page.d.ts","sourceRoot":"","sources":["../../src/components/contract-detail-page.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,6BAA6B,EAClC,KAAK,mBAAmB,
|
|
1
|
+
{"version":3,"file":"contract-detail-page.d.ts","sourceRoot":"","sources":["../../src/components/contract-detail-page.tsx"],"names":[],"mappings":"AAEA,OAAO,EACL,KAAK,6BAA6B,EAClC,KAAK,mBAAmB,EAOzB,MAAM,uBAAuB,CAAA;AAoB9B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAmCtC,MAAM,WAAW,uBAAuB;IACtC,EAAE,EAAE,MAAM,CAAA;IACV,iBAAiB,CAAC,EAAE,MAAM,IAAI,CAAA;IAC9B,oBAAoB,CAAC,EAAE,CAAC,KAAK,EAAE,+BAA+B,KAAK,SAAS,CAAA;IAC5E,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,4BAA4B,KAAK,SAAS,CAAA;IACpE,yBAAyB,CAAC,EAAE,CAAC,UAAU,EAAE,6BAA6B,KAAK,MAAM,CAAA;IACjF,KAAK,CAAC,EAAE,uBAAuB,CAAA;IAC/B;;;;OAIG;IACH,yBAAyB,CAAC,EAAE,CAAC,QAAQ,EAAE,mBAAmB,KAAK,MAAM,GAAG,IAAI,GAAG,SAAS,CAAA;CACzF;AAED,MAAM,WAAW,uBAAuB;IACtC,cAAc,CAAC,EAAE,SAAS,CAAA;IAC1B,cAAc,CAAC,EAAE,SAAS,CAAA;IAC1B,iBAAiB,CAAC,EAAE,SAAS,CAAA;IAC7B,gBAAgB,CAAC,EAAE,SAAS,CAAA;CAC7B;AAED,MAAM,MAAM,qBAAqB,GAC7B,QAAQ,GACR,cAAc,GACd,UAAU,GACV,SAAS,GACT,SAAS,GACT,OAAO,GACP,iBAAiB,GACjB,QAAQ,CAAA;AAEZ,MAAM,WAAW,4BAA4B;IAC3C,IAAI,EAAE,qBAAqB,CAAA;IAC3B,EAAE,EAAE,MAAM,CAAA;IACV,QAAQ,EAAE,mBAAmB,CAAA;CAC9B;AAED,MAAM,WAAW,+BAA+B;IAC9C,IAAI,EAAE,OAAO,CAAA;IACb,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACrC,QAAQ,EAAE,mBAAmB,CAAA;IAC7B,SAAS,EAAE,MAAM,IAAI,CAAA;CACtB;AAED,wBAAgB,kBAAkB,CAAC,EACjC,EAAE,EACF,iBAAiB,EACjB,oBAAoB,EACpB,eAAe,EACf,yBAAyB,EACzB,KAAK,EACL,yBAAyB,GAC1B,EAAE,uBAAuB,2CA6XzB"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useQueryClient } from "@tanstack/react-query";
|
|
3
3
|
import { formatMessage } from "@voyantjs/i18n";
|
|
4
|
-
import { useLegalContract, useLegalContractAttachmentMutation, useLegalContractAttachments, useLegalContractMutation, useLegalContractSignatures, } from "@voyantjs/legal-react";
|
|
4
|
+
import { useLegalContract, useLegalContractAttachmentMutation, useLegalContractAttachments, useLegalContractMutation, useLegalContractSignatures, useVoyantLegalContext, } from "@voyantjs/legal-react";
|
|
5
5
|
import { Badge, Button } from "@voyantjs/ui/components";
|
|
6
6
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from "@voyantjs/ui/components/table";
|
|
7
7
|
import { ArrowLeft, CheckCircle2, ExternalLink, FileText, Pencil, Plus, Send, Trash2, } from "lucide-react";
|
|
@@ -19,8 +19,17 @@ const statusVariant = {
|
|
|
19
19
|
expired: "destructive",
|
|
20
20
|
void: "destructive",
|
|
21
21
|
};
|
|
22
|
+
function withApiBaseUrl(baseUrl, path) {
|
|
23
|
+
const trimmedBase = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
|
|
24
|
+
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
25
|
+
return `${trimmedBase}${normalizedPath}`;
|
|
26
|
+
}
|
|
27
|
+
function getDefaultLegalContractAttachmentDownloadHref(baseUrl, attachment) {
|
|
28
|
+
return withApiBaseUrl(baseUrl, `/v1/admin/legal/contracts/attachments/${attachment.id}/download`);
|
|
29
|
+
}
|
|
22
30
|
export function ContractDetailPage({ id, onBackToContracts, renderContractDialog, renderReference, getAttachmentDownloadHref, slots, resolveSendRecipientEmail, }) {
|
|
23
31
|
const queryClient = useQueryClient();
|
|
32
|
+
const { baseUrl } = useVoyantLegalContext();
|
|
24
33
|
const i18n = useLegalUiI18nOrDefault();
|
|
25
34
|
const messages = useLegalUiMessagesOrDefault();
|
|
26
35
|
const f = messages.contractDetailPage;
|
|
@@ -63,7 +72,8 @@ export function ContractDetailPage({ id, onBackToContracts, renderContractDialog
|
|
|
63
72
|
!contract.orderId ? (_jsx("p", { className: "text-muted-foreground", children: f.empty.noParties })) : null] }) })), slots?.signaturesContent !== undefined ? (slots.signaturesContent) : (_jsx(ContractSection, { title: f.sections.signatures, action: canAddSignature ? (_jsxs(Button, { size: "sm", onClick: () => setSignOpen(true), children: [_jsx(Plus, { className: "mr-2 size-4", "aria-hidden": "true" }), f.actions.addSignature] })) : null, children: !signatures || signatures.length === 0 ? (_jsx("p", { className: "py-4 text-center text-sm text-muted-foreground", children: f.empty.noSignatures })) : (_jsx("div", { className: "rounded border bg-background", children: _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: f.fields.name }), _jsx(TableHead, { children: f.fields.email }), _jsx(TableHead, { children: f.fields.role }), _jsx(TableHead, { children: f.fields.method }), _jsx(TableHead, { children: f.fields.signedAt })] }) }), _jsx(TableBody, { children: signatures.map((signature) => (_jsxs(TableRow, { children: [_jsx(TableCell, { children: signature.signerName }), _jsx(TableCell, { children: signature.signerEmail ?? messages.common.noResultsDash }), _jsx(TableCell, { children: signature.signerRole ?? messages.common.noResultsDash }), _jsx(TableCell, { children: signature.method }), _jsx(TableCell, { children: i18n.formatDateTime(signature.signedAt) })] }, signature.id))) })] }) })) })), slots?.documentsContent !== undefined ? (slots.documentsContent) : (_jsx(ContractSection, { title: f.sections.documents, action: _jsxs(Button, { size: "sm", onClick: () => {
|
|
64
73
|
setEditingAttachment(undefined);
|
|
65
74
|
setAttachOpen(true);
|
|
66
|
-
}, children: [_jsx(Plus, { className: "mr-2 size-4", "aria-hidden": "true" }), f.actions.addDocument] }), children: !attachments || attachments.length === 0 ? (_jsx("p", { className: "py-4 text-center text-sm text-muted-foreground", children: f.empty.noAttachments })) : (_jsx("div", { className: "rounded border bg-background", children: _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: f.fields.name }), _jsx(TableHead, { children: f.fields.kind }), _jsx(TableHead, { className: "w-16" })] }) }), _jsx(TableBody, { children: attachments.map((attachment) => (_jsx(AttachmentRow, { attachment: attachment, downloadHref: getAttachmentDownloadHref?.(attachment)
|
|
75
|
+
}, children: [_jsx(Plus, { className: "mr-2 size-4", "aria-hidden": "true" }), f.actions.addDocument] }), children: !attachments || attachments.length === 0 ? (_jsx("p", { className: "py-4 text-center text-sm text-muted-foreground", children: f.empty.noAttachments })) : (_jsx("div", { className: "rounded border bg-background", children: _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { children: [_jsx(TableHead, { children: f.fields.name }), _jsx(TableHead, { children: f.fields.kind }), _jsx(TableHead, { className: "w-16" })] }) }), _jsx(TableBody, { children: attachments.map((attachment) => (_jsx(AttachmentRow, { attachment: attachment, downloadHref: getAttachmentDownloadHref?.(attachment) ??
|
|
76
|
+
getDefaultLegalContractAttachmentDownloadHref(baseUrl, attachment), onEdit: () => {
|
|
67
77
|
setEditingAttachment(attachment);
|
|
68
78
|
setAttachOpen(true);
|
|
69
79
|
}, onDelete: () => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voyantjs/legal-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.75.2",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -45,12 +45,12 @@
|
|
|
45
45
|
"react-dom": "^19.0.0",
|
|
46
46
|
"react-hook-form": "^7.60.0",
|
|
47
47
|
"zod": "^4.3.6",
|
|
48
|
-
"@voyantjs/crm-react": "0.
|
|
49
|
-
"@voyantjs/legal-react": "0.
|
|
50
|
-
"@voyantjs/ui": "0.
|
|
48
|
+
"@voyantjs/crm-react": "0.75.2",
|
|
49
|
+
"@voyantjs/legal-react": "0.75.2",
|
|
50
|
+
"@voyantjs/ui": "0.75.2"
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
|
-
"@voyantjs/i18n": "0.
|
|
53
|
+
"@voyantjs/i18n": "0.75.2"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
56
|
"@tanstack/react-query": "^5.100.11",
|
|
@@ -63,10 +63,10 @@
|
|
|
63
63
|
"typescript": "^6.0.2",
|
|
64
64
|
"vitest": "^4.1.2",
|
|
65
65
|
"zod": "^4.3.6",
|
|
66
|
-
"@voyantjs/crm-react": "0.
|
|
67
|
-
"@voyantjs/i18n": "0.
|
|
68
|
-
"@voyantjs/legal-react": "0.
|
|
69
|
-
"@voyantjs/ui": "0.
|
|
66
|
+
"@voyantjs/crm-react": "0.75.2",
|
|
67
|
+
"@voyantjs/i18n": "0.75.2",
|
|
68
|
+
"@voyantjs/legal-react": "0.75.2",
|
|
69
|
+
"@voyantjs/ui": "0.75.2",
|
|
70
70
|
"@voyantjs/voyant-typescript-config": "0.1.0"
|
|
71
71
|
},
|
|
72
72
|
"files": [
|