@spaceinvoices/react-ui 0.4.2 → 0.4.3
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/cli/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/components/advance-invoices/list/list-table.tsx +60 -0
- package/src/components/advance-invoices/list/locales/de.ts +1 -0
- package/src/components/advance-invoices/list/locales/en.ts +1 -0
- package/src/components/advance-invoices/list/locales/es.ts +1 -0
- package/src/components/advance-invoices/list/locales/fr.ts +1 -0
- package/src/components/advance-invoices/list/locales/hr.ts +1 -0
- package/src/components/advance-invoices/list/locales/it.ts +1 -0
- package/src/components/advance-invoices/list/locales/nl.ts +1 -0
- package/src/components/advance-invoices/list/locales/pl.ts +1 -0
- package/src/components/advance-invoices/list/locales/pt.ts +1 -0
- package/src/components/advance-invoices/list/locales/sl.ts +1 -0
- package/src/components/credit-notes/list/list-table.tsx +34 -6
- package/src/components/credit-notes/list/locales/de.ts +1 -1
- package/src/components/credit-notes/list/locales/en.ts +2 -0
- package/src/components/credit-notes/list/locales/es.ts +1 -1
- package/src/components/credit-notes/list/locales/fr.ts +1 -1
- package/src/components/credit-notes/list/locales/hr.ts +1 -1
- package/src/components/credit-notes/list/locales/it.ts +1 -1
- package/src/components/credit-notes/list/locales/nl.ts +1 -1
- package/src/components/credit-notes/list/locales/pl.ts +1 -1
- package/src/components/credit-notes/list/locales/pt.ts +1 -1
- package/src/components/credit-notes/list/locales/sl.ts +1 -1
- package/src/components/dashboard/collection-rate-card/use-collection-rate.ts +2 -2
- package/src/components/dashboard/invoice-status-chart/use-invoice-status.ts +3 -3
- package/src/components/dashboard/payment-methods-chart/use-payment-methods.ts +1 -1
- package/src/components/dashboard/payment-trend-chart/use-payment-trend.ts +1 -1
- package/src/components/dashboard/revenue-trend-chart/use-revenue-trend.ts +1 -1
- package/src/components/dashboard/shared/use-revenue-data.ts +4 -4
- package/src/components/dashboard/shared/use-stats-counts.ts +4 -4
- package/src/components/dashboard/shared/use-stats-query.ts +1 -1
- package/src/components/dashboard/tax-collected-card/use-tax-collected.ts +2 -2
- package/src/components/dashboard/top-customers-chart/use-top-customers.ts +1 -1
- package/src/components/delivery-notes/create/create-delivery-note-form.tsx +332 -0
- package/src/components/delivery-notes/create/locales/de.ts +50 -0
- package/src/components/delivery-notes/create/locales/es.ts +49 -0
- package/src/components/delivery-notes/create/locales/fr.ts +50 -0
- package/src/components/delivery-notes/create/locales/hr.ts +49 -0
- package/src/components/delivery-notes/create/locales/it.ts +49 -0
- package/src/components/delivery-notes/create/locales/nl.ts +50 -0
- package/src/components/delivery-notes/create/locales/pl.ts +49 -0
- package/src/components/delivery-notes/create/locales/pt.ts +50 -0
- package/src/components/delivery-notes/create/locales/sl.ts +49 -0
- package/src/components/delivery-notes/create/prepare-delivery-note-submission.ts +38 -0
- package/src/components/delivery-notes/create/use-delivery-note-customer-form.ts +1 -0
- package/src/components/delivery-notes/delivery-notes.hooks.ts +15 -0
- package/src/components/delivery-notes/list/index.ts +3 -0
- package/src/components/delivery-notes/list/list-row-actions.tsx +103 -0
- package/src/components/delivery-notes/list/list-table.tsx +214 -0
- package/src/components/delivery-notes/list/locales/de.ts +9 -0
- package/src/components/delivery-notes/list/locales/en.ts +11 -0
- package/src/components/delivery-notes/list/locales/es.ts +9 -0
- package/src/components/delivery-notes/list/locales/fr.ts +9 -0
- package/src/components/delivery-notes/list/locales/hr.ts +9 -0
- package/src/components/delivery-notes/list/locales/it.ts +9 -0
- package/src/components/delivery-notes/list/locales/nl.ts +9 -0
- package/src/components/delivery-notes/list/locales/pl.ts +9 -0
- package/src/components/delivery-notes/list/locales/pt.ts +9 -0
- package/src/components/delivery-notes/list/locales/sl.ts +9 -0
- package/src/components/delivery-notes/list/use-delivery-note-download.ts +63 -0
- package/src/components/documents/create/document-details-section.tsx +36 -32
- package/src/components/documents/create/live-preview.tsx +37 -10
- package/src/components/documents/create/prepare-document-submission.ts +1 -1
- package/src/components/documents/documents.hooks.ts +2 -1
- package/src/components/documents/shared/document-preview-display.tsx +12 -5
- package/src/components/documents/types.ts +10 -1
- package/src/components/documents/view/document-details-card.tsx +3 -3
- package/src/components/documents/view/document-payments-list.tsx +3 -3
- package/src/components/documents/view/document-relations-list.tsx +105 -0
- package/src/components/documents/view/locales/de.ts +21 -0
- package/src/components/documents/view/locales/es.ts +21 -0
- package/src/components/documents/view/locales/fr.ts +21 -0
- package/src/components/documents/view/locales/hr.ts +21 -0
- package/src/components/documents/view/locales/it.ts +21 -0
- package/src/components/documents/view/locales/nl.ts +21 -0
- package/src/components/documents/view/locales/pl.ts +21 -0
- package/src/components/documents/view/locales/pt.ts +21 -0
- package/src/components/documents/view/locales/sl.ts +21 -0
- package/src/components/documents/view/use-document-download.ts +5 -3
- package/src/components/entities/fina-settings-form/fina-settings-form.tsx +77 -65
- package/src/components/entities/fina-settings-form/fina-settings.hooks.ts +7 -2
- package/src/components/entities/furs-settings-form/furs-settings-form.tsx +10 -1
- package/src/components/entities/furs-settings-form/furs-settings.hooks.ts +7 -2
- package/src/components/entities/furs-settings-form/sections/general-settings-section.tsx +12 -4
- package/src/components/invoices/invoices-furs.hooks.ts +24 -9
- package/src/components/invoices/list/list-row-actions.tsx +3 -3
- package/src/components/invoices/list/list-table.tsx +68 -3
- package/src/components/invoices/list/locales/de.ts +1 -0
- package/src/components/invoices/list/locales/en.ts +1 -0
- package/src/components/invoices/list/locales/es.ts +1 -0
- package/src/components/invoices/list/locales/fr.ts +1 -0
- package/src/components/invoices/list/locales/hr.ts +1 -0
- package/src/components/invoices/list/locales/it.ts +1 -0
- package/src/components/invoices/list/locales/nl.ts +1 -0
- package/src/components/invoices/list/locales/pl.ts +1 -0
- package/src/components/invoices/list/locales/pt.ts +1 -0
- package/src/components/invoices/list/locales/sl.ts +1 -0
- package/src/components/items/item-list-table/item-list-row-actions.tsx +3 -2
- package/src/components/items/item-list-table/item-list-row.tsx +3 -2
- package/src/generated/schemas/deliverynote.ts +134 -0
- package/src/generated/schemas/entity.ts +4 -0
- package/src/generated/schemas/index.ts +3 -0
- package/src/generated/schemas/order.ts +5 -3
- package/src/generated/schemas/payment.ts +22 -2
- package/src/generated/schemas/renderadvanceinvoicepreview_body.ts +1 -0
- package/src/generated/schemas/rendercreditnotepreview_body.ts +1 -0
- package/src/generated/schemas/renderdeliverynotepreview_body.ts +185 -0
- package/src/generated/schemas/renderestimatepreview_body.ts +1 -0
- package/src/generated/schemas/renderinvoicepreview_body.ts +1 -0
- package/src/generated/schemas/startpdfexport_body.ts +18 -2
- package/src/generated/schemas/userfinasettings.ts +19 -0
- package/src/generated/schemas/webhook.ts +12 -0
- package/src/hooks/use-duplicate-document.ts +11 -3
- package/src/hooks/use-next-document-number.ts +2 -2
- package/src/providers/sdk-provider.tsx +5 -7
|
@@ -83,6 +83,8 @@ export function DocumentDetailsSection({
|
|
|
83
83
|
serviceDate,
|
|
84
84
|
}: DocumentDetailsSectionProps) {
|
|
85
85
|
// Determine the date field name based on document type
|
|
86
|
+
// Delivery notes don't have a secondary date field
|
|
87
|
+
const hasSecondaryDate = documentType !== "delivery_note";
|
|
86
88
|
const dateFieldName =
|
|
87
89
|
documentType === "invoice" || documentType === "advance_invoice" ? "date_due" : "date_valid_till";
|
|
88
90
|
const dateFieldLabel =
|
|
@@ -346,38 +348,40 @@ export function DocumentDetailsSection({
|
|
|
346
348
|
/>
|
|
347
349
|
)}
|
|
348
350
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
<
|
|
355
|
-
|
|
356
|
-
<
|
|
357
|
-
<
|
|
358
|
-
<
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
<
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
351
|
+
{hasSecondaryDate && (
|
|
352
|
+
<FormField
|
|
353
|
+
control={control}
|
|
354
|
+
name={dateFieldName}
|
|
355
|
+
render={({ field }) => (
|
|
356
|
+
<FormItem>
|
|
357
|
+
<FormLabel className="">{dateFieldLabel}</FormLabel>
|
|
358
|
+
<Popover>
|
|
359
|
+
<PopoverTrigger asChild>
|
|
360
|
+
<FormControl>
|
|
361
|
+
<Button
|
|
362
|
+
variant="outline"
|
|
363
|
+
className={cn("w-full pl-3 text-left font-normal", !field.value && "text-muted-foreground")}
|
|
364
|
+
>
|
|
365
|
+
{field.value ? new Date(field.value).toLocaleDateString() : <span>{t("Pick a date")}</span>}
|
|
366
|
+
<CalendarIcon className="ml-auto h-4 w-4 opacity-50" />
|
|
367
|
+
</Button>
|
|
368
|
+
</FormControl>
|
|
369
|
+
</PopoverTrigger>
|
|
370
|
+
<PopoverContent className="w-auto p-0" align="start">
|
|
371
|
+
<Calendar
|
|
372
|
+
mode="single"
|
|
373
|
+
selected={field.value ? new Date(field.value) : undefined}
|
|
374
|
+
onSelect={(date) => field.onChange(date?.toISOString())}
|
|
375
|
+
disabled={(date) => date < new Date("1900-01-01")}
|
|
376
|
+
initialFocus
|
|
377
|
+
/>
|
|
378
|
+
</PopoverContent>
|
|
379
|
+
</Popover>
|
|
380
|
+
<FormMessage />
|
|
381
|
+
</FormItem>
|
|
382
|
+
)}
|
|
383
|
+
/>
|
|
384
|
+
)}
|
|
381
385
|
|
|
382
386
|
<FormField
|
|
383
387
|
control={control}
|
|
@@ -8,6 +8,7 @@ import { useEntities } from "@/ui/providers/entities-context";
|
|
|
8
8
|
import { useSDK } from "@/ui/providers/sdk-provider";
|
|
9
9
|
import { ScaledDocumentPreview } from "../shared/scaled-document-preview";
|
|
10
10
|
import { useA4Scaling } from "../shared/use-a4-scaling";
|
|
11
|
+
import type { DocumentTypes } from "../types";
|
|
11
12
|
import { filterUnresolvedTaxes } from "./prepare-preview-data";
|
|
12
13
|
|
|
13
14
|
export type PdfTemplateId = "modern" | "classic" | "minimal" | "fashion";
|
|
@@ -23,6 +24,12 @@ type LiveInvoicePreviewProps = {
|
|
|
23
24
|
locale?: string;
|
|
24
25
|
/** Fixed scale to use instead of dynamic scaling. Useful to prevent layout shifts. */
|
|
25
26
|
fixedScale?: number;
|
|
27
|
+
/** Translation function for UI strings */
|
|
28
|
+
t?: (key: string) => string;
|
|
29
|
+
/** Document type label for display (e.g., "Invoice", "Estimate") */
|
|
30
|
+
documentTypeLabel?: string;
|
|
31
|
+
/** Document type to determine which render endpoint to use */
|
|
32
|
+
documentType?: DocumentTypes;
|
|
26
33
|
};
|
|
27
34
|
|
|
28
35
|
/**
|
|
@@ -44,7 +51,11 @@ export function LiveInvoicePreview({
|
|
|
44
51
|
className,
|
|
45
52
|
locale,
|
|
46
53
|
fixedScale,
|
|
54
|
+
t: tProp,
|
|
55
|
+
documentTypeLabel,
|
|
56
|
+
documentType = "invoice",
|
|
47
57
|
}: LiveInvoicePreviewProps) {
|
|
58
|
+
const t = tProp ?? ((key: string) => key);
|
|
48
59
|
const [previewHtml, setPreviewHtml] = useState<string>("");
|
|
49
60
|
const [isLoading, setIsLoading] = useState(false);
|
|
50
61
|
const [error, setError] = useState<string | null>(null);
|
|
@@ -104,12 +115,27 @@ export function LiveInvoicePreview({
|
|
|
104
115
|
},
|
|
105
116
|
};
|
|
106
117
|
|
|
107
|
-
// Call the render API using the SDK
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
118
|
+
// Call the render API using the appropriate SDK method for the document type
|
|
119
|
+
const renderParams = { partial: "true" as const, template, locale };
|
|
120
|
+
const requestOpts = { entity_id: activeEntity.id };
|
|
121
|
+
let html: string;
|
|
122
|
+
switch (documentType) {
|
|
123
|
+
case "estimate":
|
|
124
|
+
html = await sdk.estimates.renderEstimatePreview(previewData as any, renderParams, requestOpts);
|
|
125
|
+
break;
|
|
126
|
+
case "credit_note":
|
|
127
|
+
html = await sdk.creditNotes.renderCreditNotePreview(previewData as any, renderParams, requestOpts);
|
|
128
|
+
break;
|
|
129
|
+
case "advance_invoice":
|
|
130
|
+
html = await sdk.advanceInvoices.renderAdvanceInvoicePreview(previewData as any, renderParams, requestOpts);
|
|
131
|
+
break;
|
|
132
|
+
case "delivery_note":
|
|
133
|
+
html = await sdk.deliveryNotes.renderDeliveryNotePreview(previewData as any, renderParams, requestOpts);
|
|
134
|
+
break;
|
|
135
|
+
default:
|
|
136
|
+
html = await sdk.invoices.renderInvoicePreview(previewData as any, renderParams, requestOpts);
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
113
139
|
|
|
114
140
|
setPreviewHtml(html);
|
|
115
141
|
setError(null);
|
|
@@ -146,6 +172,7 @@ export function LiveInvoicePreview({
|
|
|
146
172
|
template,
|
|
147
173
|
locale,
|
|
148
174
|
sdk,
|
|
175
|
+
documentType,
|
|
149
176
|
],
|
|
150
177
|
);
|
|
151
178
|
|
|
@@ -195,7 +222,7 @@ export function LiveInvoicePreview({
|
|
|
195
222
|
<div className="absolute inset-0 z-10 flex items-center justify-center bg-background/80 backdrop-blur-sm">
|
|
196
223
|
<div className="flex flex-col items-center gap-2">
|
|
197
224
|
<Loader2 className="h-8 w-8 animate-spin text-primary" />
|
|
198
|
-
<p className="text-muted-foreground text-sm">Generating preview
|
|
225
|
+
<p className="text-muted-foreground text-sm">{t("Generating preview...")}</p>
|
|
199
226
|
</div>
|
|
200
227
|
</div>
|
|
201
228
|
)}
|
|
@@ -204,7 +231,7 @@ export function LiveInvoicePreview({
|
|
|
204
231
|
{error && !isLoading && (
|
|
205
232
|
<div className="flex min-h-[200px] items-center justify-center rounded-lg border border-destructive/50 bg-destructive/10 p-8">
|
|
206
233
|
<div className="text-center">
|
|
207
|
-
<p className="font-semibold text-destructive">Preview Error</p>
|
|
234
|
+
<p className="font-semibold text-destructive">{t("Preview Error")}</p>
|
|
208
235
|
<p className="text-muted-foreground text-sm">{error}</p>
|
|
209
236
|
</div>
|
|
210
237
|
</div>
|
|
@@ -214,8 +241,8 @@ export function LiveInvoicePreview({
|
|
|
214
241
|
{!previewHtml && !isLoading && !error && (
|
|
215
242
|
<div className="flex min-h-[200px] items-center justify-center rounded-lg border border-dashed p-8">
|
|
216
243
|
<div className="text-center">
|
|
217
|
-
<p className="font-semibold text-muted-foreground">
|
|
218
|
-
<p className="text-muted-foreground text-sm">Start filling the form to see a live preview</p>
|
|
244
|
+
<p className="font-semibold text-muted-foreground">{documentTypeLabel || t("Document Preview")}</p>
|
|
245
|
+
<p className="text-muted-foreground text-sm">{t("Start filling the form to see a live preview")}</p>
|
|
219
246
|
</div>
|
|
220
247
|
</div>
|
|
221
248
|
)}
|
|
@@ -33,7 +33,7 @@ type PrepareDocumentOptions = {
|
|
|
33
33
|
/** For invoices/credit notes: payment types when markAsPaid is true */
|
|
34
34
|
paymentTypes?: string[];
|
|
35
35
|
/** Document type for specific date handling */
|
|
36
|
-
documentType: "invoice" | "estimate" | "credit_note" | "advance_invoice";
|
|
36
|
+
documentType: "invoice" | "estimate" | "credit_note" | "advance_invoice" | "delivery_note";
|
|
37
37
|
/** Secondary date field value (date_due for invoices, date_valid_till for estimates) */
|
|
38
38
|
secondaryDate?: string;
|
|
39
39
|
/** Map of item index to gross price mode (collected from component state) */
|
|
@@ -2,7 +2,7 @@ import { useMutation, useQueryClient } from "@tanstack/react-query";
|
|
|
2
2
|
import { useSDK } from "@/ui/providers/sdk-provider";
|
|
3
3
|
|
|
4
4
|
// Document type union for API calls
|
|
5
|
-
export type DocumentType = "invoice" | "estimate" | "credit_note" | "advance_invoice";
|
|
5
|
+
export type DocumentType = "invoice" | "estimate" | "credit_note" | "advance_invoice" | "delivery_note";
|
|
6
6
|
|
|
7
7
|
// Cache key map for invalidation
|
|
8
8
|
const CACHE_KEYS: Record<DocumentType, string> = {
|
|
@@ -10,6 +10,7 @@ const CACHE_KEYS: Record<DocumentType, string> = {
|
|
|
10
10
|
estimate: "estimates",
|
|
11
11
|
credit_note: "credit-notes",
|
|
12
12
|
advance_invoice: "advance-invoices",
|
|
13
|
+
delivery_note: "delivery-notes",
|
|
13
14
|
};
|
|
14
15
|
|
|
15
16
|
// ============================================================================
|
|
@@ -27,7 +27,7 @@ function getDocTypePathFromShareableId(shareableId: string): string {
|
|
|
27
27
|
type DocumentPreviewDisplayProps = {
|
|
28
28
|
/** The document to display (invoice, estimate, credit note, or advance invoice) */
|
|
29
29
|
document: Document;
|
|
30
|
-
template?: "modern";
|
|
30
|
+
template?: "modern" | "classic" | "minimal" | "fashion";
|
|
31
31
|
className?: string;
|
|
32
32
|
apiBaseUrl?: string;
|
|
33
33
|
/** Locale for document rendering (e.g., "en-US", "sl-SI"). Uses user's UI language. */
|
|
@@ -36,6 +36,10 @@ type DocumentPreviewDisplayProps = {
|
|
|
36
36
|
isPublicView?: boolean;
|
|
37
37
|
/** Shareable ID for public view (required when isPublicView is true) */
|
|
38
38
|
shareableId?: string;
|
|
39
|
+
/** Translation function for UI strings */
|
|
40
|
+
t?: (key: string) => string;
|
|
41
|
+
/** Document type label for display (e.g., "Invoice", "Estimate") */
|
|
42
|
+
documentTypeLabel?: string;
|
|
39
43
|
};
|
|
40
44
|
|
|
41
45
|
/**
|
|
@@ -53,7 +57,10 @@ export function DocumentPreviewDisplay({
|
|
|
53
57
|
locale,
|
|
54
58
|
isPublicView = false,
|
|
55
59
|
shareableId,
|
|
60
|
+
t: tProp,
|
|
61
|
+
documentTypeLabel,
|
|
56
62
|
}: DocumentPreviewDisplayProps) {
|
|
63
|
+
const t = tProp ?? ((key: string) => key);
|
|
57
64
|
const [previewHtml, setPreviewHtml] = useState<string>("");
|
|
58
65
|
const [isLoading, setIsLoading] = useState(true);
|
|
59
66
|
const [error, setError] = useState<string | null>(null);
|
|
@@ -133,7 +140,7 @@ export function DocumentPreviewDisplay({
|
|
|
133
140
|
<div className="flex h-full items-center justify-center rounded-lg border bg-muted/50">
|
|
134
141
|
<div className="flex flex-col items-center gap-2">
|
|
135
142
|
<Loader2 className="h-8 w-8 animate-spin text-primary" />
|
|
136
|
-
<p className="text-muted-foreground text-sm">Loading preview
|
|
143
|
+
<p className="text-muted-foreground text-sm">{t("Loading preview...")}</p>
|
|
137
144
|
</div>
|
|
138
145
|
</div>
|
|
139
146
|
)}
|
|
@@ -143,7 +150,7 @@ export function DocumentPreviewDisplay({
|
|
|
143
150
|
<div className="flex h-full items-center justify-center rounded-lg border border-destructive/50 bg-destructive/10 p-8">
|
|
144
151
|
<div className="flex flex-col items-center gap-2 text-center">
|
|
145
152
|
<AlertCircle className="h-8 w-8 text-destructive" />
|
|
146
|
-
<p className="font-semibold text-destructive">Preview Error</p>
|
|
153
|
+
<p className="font-semibold text-destructive">{t("Preview Error")}</p>
|
|
147
154
|
<p className="text-muted-foreground text-sm">{error}</p>
|
|
148
155
|
</div>
|
|
149
156
|
</div>
|
|
@@ -157,8 +164,8 @@ export function DocumentPreviewDisplay({
|
|
|
157
164
|
<FileText className="h-8 w-8 text-muted-foreground" />
|
|
158
165
|
</div>
|
|
159
166
|
<div>
|
|
160
|
-
<p className="font-medium text-muted-foreground">Document Preview</p>
|
|
161
|
-
<p className="text-muted-foreground/70 text-sm">Preview will appear here</p>
|
|
167
|
+
<p className="font-medium text-muted-foreground">{documentTypeLabel || t("Document Preview")}</p>
|
|
168
|
+
<p className="text-muted-foreground/70 text-sm">{t("Preview will appear here")}</p>
|
|
162
169
|
</div>
|
|
163
170
|
</div>
|
|
164
171
|
</div>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Shared document types for invoices, estimates, credit notes, and advance invoices
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
export type DocumentTypes = "invoice" | "estimate" | "credit_note" | "advance_invoice";
|
|
5
|
+
export type DocumentTypes = "invoice" | "estimate" | "credit_note" | "advance_invoice" | "delivery_note";
|
|
6
6
|
|
|
7
7
|
export interface DocumentConfig {
|
|
8
8
|
type: DocumentTypes;
|
|
@@ -51,6 +51,15 @@ export const DOCUMENT_CONFIGS: Record<DocumentTypes, DocumentConfig> = {
|
|
|
51
51
|
singularName: "Advance Invoice",
|
|
52
52
|
pluralName: "Advance Invoices",
|
|
53
53
|
},
|
|
54
|
+
delivery_note: {
|
|
55
|
+
type: "delivery_note",
|
|
56
|
+
apiEndpoint: "delivery-notes",
|
|
57
|
+
cacheKey: "delivery-notes",
|
|
58
|
+
dateFieldName: null,
|
|
59
|
+
dateFieldLabel: null,
|
|
60
|
+
singularName: "Delivery Note",
|
|
61
|
+
pluralName: "Delivery Notes",
|
|
62
|
+
},
|
|
54
63
|
} as const;
|
|
55
64
|
|
|
56
65
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AdvanceInvoice, CreditNote, Estimate, Invoice } from "@spaceinvoices/js-sdk";
|
|
1
|
+
import type { AdvanceInvoice, CreditNote, DeliveryNote, Estimate, Invoice } from "@spaceinvoices/js-sdk";
|
|
2
2
|
import { Badge } from "@/ui/components/ui/badge";
|
|
3
3
|
import { Card, CardContent, CardHeader, CardTitle } from "@/ui/components/ui/card";
|
|
4
4
|
import { Separator } from "@/ui/components/ui/separator";
|
|
@@ -17,8 +17,8 @@ import sl from "./locales/sl";
|
|
|
17
17
|
const translations = { sl, de, it, fr, es, pt, nl, pl, hr } as const;
|
|
18
18
|
|
|
19
19
|
// Document type union
|
|
20
|
-
type Document = Invoice | Estimate | CreditNote | AdvanceInvoice;
|
|
21
|
-
type DocumentType = "invoice" | "estimate" | "credit_note" | "advance_invoice";
|
|
20
|
+
type Document = Invoice | Estimate | CreditNote | AdvanceInvoice | DeliveryNote;
|
|
21
|
+
type DocumentType = "invoice" | "estimate" | "credit_note" | "advance_invoice" | "delivery_note";
|
|
22
22
|
|
|
23
23
|
interface DocumentDetailsCardProps extends ComponentTranslationProps {
|
|
24
24
|
document: Document;
|
|
@@ -147,9 +147,9 @@ export function DocumentPaymentsList({
|
|
|
147
147
|
try {
|
|
148
148
|
await sdk.payments.delete(paymentToDelete.id, { entity_id: entityId });
|
|
149
149
|
|
|
150
|
-
// Invalidate
|
|
151
|
-
queryClient.invalidateQueries({ queryKey: ["payments"] });
|
|
152
|
-
queryClient.invalidateQueries({ queryKey: ["documents"] });
|
|
150
|
+
// Invalidate this document's payments and document view
|
|
151
|
+
queryClient.invalidateQueries({ queryKey: ["payments", documentType, documentId] });
|
|
152
|
+
queryClient.invalidateQueries({ queryKey: ["documents", documentType, documentId] });
|
|
153
153
|
|
|
154
154
|
onDeleteSuccess?.();
|
|
155
155
|
} catch (error) {
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import type { DocumentRelation } from "@spaceinvoices/js-sdk";
|
|
2
|
+
import { Link2 } from "lucide-react";
|
|
3
|
+
import { Card, CardContent, CardHeader, CardTitle } from "@/ui/components/ui/card";
|
|
4
|
+
import type { ComponentTranslationProps } from "@/ui/lib/translation";
|
|
5
|
+
import { createTranslation } from "@/ui/lib/translation";
|
|
6
|
+
import de from "./locales/de";
|
|
7
|
+
import es from "./locales/es";
|
|
8
|
+
import fr from "./locales/fr";
|
|
9
|
+
import hr from "./locales/hr";
|
|
10
|
+
import it from "./locales/it";
|
|
11
|
+
import nl from "./locales/nl";
|
|
12
|
+
import pl from "./locales/pl";
|
|
13
|
+
import pt from "./locales/pt";
|
|
14
|
+
import sl from "./locales/sl";
|
|
15
|
+
|
|
16
|
+
const translations = { sl, de, it, fr, es, pt, nl, pl, hr } as const;
|
|
17
|
+
|
|
18
|
+
interface DocumentRelationsListProps extends ComponentTranslationProps {
|
|
19
|
+
documentId: string;
|
|
20
|
+
documentRelations?: DocumentRelation[];
|
|
21
|
+
locale?: string;
|
|
22
|
+
onNavigate?: (documentId: string) => void;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function getDocumentTypeLabel(type: string, t: (key: string) => string): string {
|
|
26
|
+
const labels: Record<string, string> = {
|
|
27
|
+
invoice: t("Invoice"),
|
|
28
|
+
estimate: t("Estimate"),
|
|
29
|
+
credit_note: t("Credit note"),
|
|
30
|
+
advance_invoice: t("Advance invoice"),
|
|
31
|
+
delivery_note: t("Delivery note"),
|
|
32
|
+
};
|
|
33
|
+
return labels[type] || type;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function getRelationLabel(relationType: string, t: (key: string) => string): string {
|
|
37
|
+
const labels: Record<string, string> = {
|
|
38
|
+
credit_for: t("Credit for"),
|
|
39
|
+
converted_from: t("Converted from"),
|
|
40
|
+
converted_to: t("Converted to"),
|
|
41
|
+
has_credit: t("Has credit"),
|
|
42
|
+
advance_applied: t("Advance applied"),
|
|
43
|
+
applied_to: t("Applied to"),
|
|
44
|
+
delivered_for: t("Delivered for"),
|
|
45
|
+
has_delivery: t("Has delivery"),
|
|
46
|
+
fulfills: t("Fulfills"),
|
|
47
|
+
fulfilled_by: t("Fulfilled by"),
|
|
48
|
+
references: t("References"),
|
|
49
|
+
};
|
|
50
|
+
return labels[relationType] || relationType;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export function DocumentRelationsList({
|
|
54
|
+
documentId,
|
|
55
|
+
documentRelations,
|
|
56
|
+
locale = "en",
|
|
57
|
+
onNavigate,
|
|
58
|
+
...i18nProps
|
|
59
|
+
}: DocumentRelationsListProps) {
|
|
60
|
+
const t = createTranslation({ translations, locale, ...i18nProps });
|
|
61
|
+
|
|
62
|
+
const relations = documentRelations || [];
|
|
63
|
+
|
|
64
|
+
if (relations.length === 0) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<Card>
|
|
70
|
+
<CardHeader className="pb-3">
|
|
71
|
+
<CardTitle className="text-lg">
|
|
72
|
+
{t("Linked documents")} ({relations.length})
|
|
73
|
+
</CardTitle>
|
|
74
|
+
</CardHeader>
|
|
75
|
+
<CardContent>
|
|
76
|
+
<div className="space-y-2">
|
|
77
|
+
{relations.map((relation) => {
|
|
78
|
+
const isSource = relation.source_id === documentId;
|
|
79
|
+
const otherType = isSource ? relation.target_type : relation.source_type;
|
|
80
|
+
const otherId = isSource ? relation.target_id : relation.source_id;
|
|
81
|
+
|
|
82
|
+
return (
|
|
83
|
+
<div key={relation.id} className="flex items-center justify-between rounded-md border p-3">
|
|
84
|
+
<div className="flex flex-col gap-0.5">
|
|
85
|
+
<span className="font-medium text-sm">{getDocumentTypeLabel(otherType, t)}</span>
|
|
86
|
+
<span className="text-muted-foreground text-xs">{getRelationLabel(relation.relation_type, t)}</span>
|
|
87
|
+
</div>
|
|
88
|
+
{onNavigate ? (
|
|
89
|
+
<button
|
|
90
|
+
type="button"
|
|
91
|
+
onClick={() => onNavigate(otherId)}
|
|
92
|
+
className="flex items-center gap-1 text-primary text-sm hover:underline"
|
|
93
|
+
>
|
|
94
|
+
<Link2 className="h-3.5 w-3.5" />
|
|
95
|
+
{t("View")}
|
|
96
|
+
</button>
|
|
97
|
+
) : null}
|
|
98
|
+
</div>
|
|
99
|
+
);
|
|
100
|
+
})}
|
|
101
|
+
</div>
|
|
102
|
+
</CardContent>
|
|
103
|
+
</Card>
|
|
104
|
+
);
|
|
105
|
+
}
|
|
@@ -119,4 +119,25 @@ export default {
|
|
|
119
119
|
Dutch: "Niederländisch",
|
|
120
120
|
Polish: "Polnisch",
|
|
121
121
|
Croatian: "Kroatisch",
|
|
122
|
+
|
|
123
|
+
// Linked documents
|
|
124
|
+
"Linked documents": "Verknüpfte Dokumente",
|
|
125
|
+
"No linked documents": "Keine verknüpften Dokumente",
|
|
126
|
+
Invoice: "Rechnung",
|
|
127
|
+
Estimate: "Angebot",
|
|
128
|
+
"Credit note": "Gutschrift",
|
|
129
|
+
"Advance invoice": "Anzahlungsrechnung",
|
|
130
|
+
"Delivery note": "Lieferschein",
|
|
131
|
+
"Credit for": "Gutschrift für",
|
|
132
|
+
"Converted from": "Konvertiert von",
|
|
133
|
+
"Converted to": "Konvertiert zu",
|
|
134
|
+
"Has credit": "Hat Gutschrift",
|
|
135
|
+
"Advance applied": "Anzahlung angewendet",
|
|
136
|
+
"Applied to": "Angewendet auf",
|
|
137
|
+
"Delivered for": "Geliefert für",
|
|
138
|
+
"Has delivery": "Hat Lieferschein",
|
|
139
|
+
Fulfills: "Erfüllt",
|
|
140
|
+
"Fulfilled by": "Erfüllt durch",
|
|
141
|
+
References: "Verweist auf",
|
|
142
|
+
View: "Ansehen",
|
|
122
143
|
} as const;
|
|
@@ -117,4 +117,25 @@ export default {
|
|
|
117
117
|
Dutch: "Neerlandés",
|
|
118
118
|
Polish: "Polaco",
|
|
119
119
|
Croatian: "Croata",
|
|
120
|
+
|
|
121
|
+
// Linked documents
|
|
122
|
+
"Linked documents": "Documentos vinculados",
|
|
123
|
+
"No linked documents": "Sin documentos vinculados",
|
|
124
|
+
Invoice: "Factura",
|
|
125
|
+
Estimate: "Presupuesto",
|
|
126
|
+
"Credit note": "Nota de crédito",
|
|
127
|
+
"Advance invoice": "Factura anticipada",
|
|
128
|
+
"Delivery note": "Albarán",
|
|
129
|
+
"Credit for": "Crédito para",
|
|
130
|
+
"Converted from": "Convertido desde",
|
|
131
|
+
"Converted to": "Convertido a",
|
|
132
|
+
"Has credit": "Tiene crédito",
|
|
133
|
+
"Advance applied": "Anticipo aplicado",
|
|
134
|
+
"Applied to": "Aplicado a",
|
|
135
|
+
"Delivered for": "Entregado para",
|
|
136
|
+
"Has delivery": "Tiene albarán",
|
|
137
|
+
Fulfills: "Cumple",
|
|
138
|
+
"Fulfilled by": "Cumplido por",
|
|
139
|
+
References: "Referencia",
|
|
140
|
+
View: "Ver",
|
|
120
141
|
} as const;
|
|
@@ -117,4 +117,25 @@ export default {
|
|
|
117
117
|
Dutch: "Néerlandais",
|
|
118
118
|
Polish: "Polonais",
|
|
119
119
|
Croatian: "Croate",
|
|
120
|
+
|
|
121
|
+
// Linked documents
|
|
122
|
+
"Linked documents": "Documents liés",
|
|
123
|
+
"No linked documents": "Aucun document lié",
|
|
124
|
+
Invoice: "Facture",
|
|
125
|
+
Estimate: "Devis",
|
|
126
|
+
"Credit note": "Avoir",
|
|
127
|
+
"Advance invoice": "Facture d'acompte",
|
|
128
|
+
"Delivery note": "Bon de livraison",
|
|
129
|
+
"Credit for": "Avoir pour",
|
|
130
|
+
"Converted from": "Converti depuis",
|
|
131
|
+
"Converted to": "Converti en",
|
|
132
|
+
"Has credit": "A un avoir",
|
|
133
|
+
"Advance applied": "Acompte appliqué",
|
|
134
|
+
"Applied to": "Appliqué à",
|
|
135
|
+
"Delivered for": "Livré pour",
|
|
136
|
+
"Has delivery": "A un bon de livraison",
|
|
137
|
+
Fulfills: "Remplit",
|
|
138
|
+
"Fulfilled by": "Rempli par",
|
|
139
|
+
References: "Référence",
|
|
140
|
+
View: "Voir",
|
|
120
141
|
} as const;
|
|
@@ -117,4 +117,25 @@ export default {
|
|
|
117
117
|
Dutch: "Nizozemski",
|
|
118
118
|
Polish: "Poljski",
|
|
119
119
|
Croatian: "Hrvatski",
|
|
120
|
+
|
|
121
|
+
// Linked documents
|
|
122
|
+
"Linked documents": "Povezani dokumenti",
|
|
123
|
+
"No linked documents": "Nema povezanih dokumenata",
|
|
124
|
+
Invoice: "Račun",
|
|
125
|
+
Estimate: "Ponuda",
|
|
126
|
+
"Credit note": "Knjižno odobrenje",
|
|
127
|
+
"Advance invoice": "Avansni račun",
|
|
128
|
+
"Delivery note": "Otpremnica",
|
|
129
|
+
"Credit for": "Odobrenje za",
|
|
130
|
+
"Converted from": "Pretvoreno iz",
|
|
131
|
+
"Converted to": "Pretvoreno u",
|
|
132
|
+
"Has credit": "Ima odobrenje",
|
|
133
|
+
"Advance applied": "Avans primijenjen",
|
|
134
|
+
"Applied to": "Primijenjeno na",
|
|
135
|
+
"Delivered for": "Dostavljeno za",
|
|
136
|
+
"Has delivery": "Ima otpremnicu",
|
|
137
|
+
Fulfills: "Ispunjava",
|
|
138
|
+
"Fulfilled by": "Ispunjeno od",
|
|
139
|
+
References: "Upućuje na",
|
|
140
|
+
View: "Pogledaj",
|
|
120
141
|
} as const;
|
|
@@ -117,4 +117,25 @@ export default {
|
|
|
117
117
|
Dutch: "Olandese",
|
|
118
118
|
Polish: "Polacco",
|
|
119
119
|
Croatian: "Croato",
|
|
120
|
+
|
|
121
|
+
// Linked documents
|
|
122
|
+
"Linked documents": "Documenti collegati",
|
|
123
|
+
"No linked documents": "Nessun documento collegato",
|
|
124
|
+
Invoice: "Fattura",
|
|
125
|
+
Estimate: "Preventivo",
|
|
126
|
+
"Credit note": "Nota di credito",
|
|
127
|
+
"Advance invoice": "Fattura di acconto",
|
|
128
|
+
"Delivery note": "Bolla di consegna",
|
|
129
|
+
"Credit for": "Credito per",
|
|
130
|
+
"Converted from": "Convertito da",
|
|
131
|
+
"Converted to": "Convertito in",
|
|
132
|
+
"Has credit": "Ha credito",
|
|
133
|
+
"Advance applied": "Acconto applicato",
|
|
134
|
+
"Applied to": "Applicato a",
|
|
135
|
+
"Delivered for": "Consegnato per",
|
|
136
|
+
"Has delivery": "Ha bolla di consegna",
|
|
137
|
+
Fulfills: "Adempie",
|
|
138
|
+
"Fulfilled by": "Adempiuto da",
|
|
139
|
+
References: "Riferisce a",
|
|
140
|
+
View: "Visualizza",
|
|
120
141
|
} as const;
|
|
@@ -118,4 +118,25 @@ export default {
|
|
|
118
118
|
Dutch: "Nederlands",
|
|
119
119
|
Polish: "Pools",
|
|
120
120
|
Croatian: "Kroatisch",
|
|
121
|
+
|
|
122
|
+
// Linked documents
|
|
123
|
+
"Linked documents": "Gekoppelde documenten",
|
|
124
|
+
"No linked documents": "Geen gekoppelde documenten",
|
|
125
|
+
Invoice: "Factuur",
|
|
126
|
+
Estimate: "Offerte",
|
|
127
|
+
"Credit note": "Creditnota",
|
|
128
|
+
"Advance invoice": "Voorschotfactuur",
|
|
129
|
+
"Delivery note": "Afleverbon",
|
|
130
|
+
"Credit for": "Creditering voor",
|
|
131
|
+
"Converted from": "Geconverteerd van",
|
|
132
|
+
"Converted to": "Geconverteerd naar",
|
|
133
|
+
"Has credit": "Heeft creditering",
|
|
134
|
+
"Advance applied": "Voorschot toegepast",
|
|
135
|
+
"Applied to": "Toegepast op",
|
|
136
|
+
"Delivered for": "Geleverd voor",
|
|
137
|
+
"Has delivery": "Heeft afleverbon",
|
|
138
|
+
Fulfills: "Vervult",
|
|
139
|
+
"Fulfilled by": "Vervuld door",
|
|
140
|
+
References: "Verwijst naar",
|
|
141
|
+
View: "Bekijken",
|
|
121
142
|
} as const;
|
|
@@ -117,4 +117,25 @@ export default {
|
|
|
117
117
|
Dutch: "Niderlandzki",
|
|
118
118
|
Polish: "Polski",
|
|
119
119
|
Croatian: "Chorwacki",
|
|
120
|
+
|
|
121
|
+
// Linked documents
|
|
122
|
+
"Linked documents": "Powiązane dokumenty",
|
|
123
|
+
"No linked documents": "Brak powiązanych dokumentów",
|
|
124
|
+
Invoice: "Faktura",
|
|
125
|
+
Estimate: "Kosztorys",
|
|
126
|
+
"Credit note": "Nota kredytowa",
|
|
127
|
+
"Advance invoice": "Faktura zaliczkowa",
|
|
128
|
+
"Delivery note": "Dowód dostawy",
|
|
129
|
+
"Credit for": "Kredyt dla",
|
|
130
|
+
"Converted from": "Przekonwertowano z",
|
|
131
|
+
"Converted to": "Przekonwertowano na",
|
|
132
|
+
"Has credit": "Ma kredyt",
|
|
133
|
+
"Advance applied": "Zaliczka zastosowana",
|
|
134
|
+
"Applied to": "Zastosowano do",
|
|
135
|
+
"Delivered for": "Dostarczone dla",
|
|
136
|
+
"Has delivery": "Ma dowód dostawy",
|
|
137
|
+
Fulfills: "Realizuje",
|
|
138
|
+
"Fulfilled by": "Zrealizowano przez",
|
|
139
|
+
References: "Odnosi się do",
|
|
140
|
+
View: "Zobacz",
|
|
120
141
|
} as const;
|
|
@@ -117,4 +117,25 @@ export default {
|
|
|
117
117
|
Dutch: "Neerlandês",
|
|
118
118
|
Polish: "Polaco",
|
|
119
119
|
Croatian: "Croata",
|
|
120
|
+
|
|
121
|
+
// Linked documents
|
|
122
|
+
"Linked documents": "Documentos vinculados",
|
|
123
|
+
"No linked documents": "Sem documentos vinculados",
|
|
124
|
+
Invoice: "Fatura",
|
|
125
|
+
Estimate: "Orçamento",
|
|
126
|
+
"Credit note": "Nota de crédito",
|
|
127
|
+
"Advance invoice": "Fatura antecipada",
|
|
128
|
+
"Delivery note": "Guia de remessa",
|
|
129
|
+
"Credit for": "Crédito para",
|
|
130
|
+
"Converted from": "Convertido de",
|
|
131
|
+
"Converted to": "Convertido para",
|
|
132
|
+
"Has credit": "Tem crédito",
|
|
133
|
+
"Advance applied": "Adiantamento aplicado",
|
|
134
|
+
"Applied to": "Aplicado a",
|
|
135
|
+
"Delivered for": "Entregue para",
|
|
136
|
+
"Has delivery": "Tem guia de remessa",
|
|
137
|
+
Fulfills: "Cumpre",
|
|
138
|
+
"Fulfilled by": "Cumprido por",
|
|
139
|
+
References: "Referência",
|
|
140
|
+
View: "Ver",
|
|
120
141
|
} as const;
|