@spaceinvoices/react-ui 0.4.5 → 0.4.6
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/advance-invoices.hooks.ts +2 -2
- package/src/components/advance-invoices/create/create-advance-invoice-form.tsx +91 -35
- package/src/components/advance-invoices/create/locales/de.ts +5 -0
- package/src/components/advance-invoices/create/locales/es.ts +5 -0
- package/src/components/advance-invoices/create/locales/fr.ts +5 -0
- package/src/components/advance-invoices/create/locales/hr.ts +5 -0
- package/src/components/advance-invoices/create/locales/it.ts +5 -0
- package/src/components/advance-invoices/create/locales/nl.ts +5 -0
- package/src/components/advance-invoices/create/locales/pl.ts +5 -0
- package/src/components/advance-invoices/create/locales/pt.ts +5 -0
- package/src/components/advance-invoices/create/locales/sl.ts +5 -0
- package/src/components/advance-invoices/create/prepare-advance-invoice-submission.ts +5 -5
- package/src/components/credit-notes/create/create-credit-note-form.tsx +91 -35
- package/src/components/credit-notes/create/locales/de.ts +5 -0
- package/src/components/credit-notes/create/locales/es.ts +5 -0
- package/src/components/credit-notes/create/locales/fr.ts +5 -0
- package/src/components/credit-notes/create/locales/hr.ts +5 -0
- package/src/components/credit-notes/create/locales/it.ts +5 -0
- package/src/components/credit-notes/create/locales/nl.ts +5 -0
- package/src/components/credit-notes/create/locales/pl.ts +5 -0
- package/src/components/credit-notes/create/locales/pt.ts +5 -0
- package/src/components/credit-notes/create/locales/sl.ts +5 -0
- package/src/components/credit-notes/credit-notes.hooks.ts +2 -2
- package/src/components/delivery-notes/create/create-delivery-note-form.tsx +47 -0
- package/src/components/delivery-notes/create/locales/de.ts +5 -0
- package/src/components/delivery-notes/create/locales/es.ts +5 -0
- package/src/components/delivery-notes/create/locales/fr.ts +5 -0
- package/src/components/delivery-notes/create/locales/hr.ts +5 -0
- package/src/components/delivery-notes/create/locales/it.ts +5 -0
- package/src/components/delivery-notes/create/locales/nl.ts +5 -0
- package/src/components/delivery-notes/create/locales/pl.ts +5 -0
- package/src/components/delivery-notes/create/locales/pt.ts +5 -0
- package/src/components/delivery-notes/create/locales/sl.ts +5 -0
- package/src/components/documents/create/document-details-section.tsx +472 -346
- package/src/components/documents/create/prepare-document-submission.ts +3 -1
- package/src/components/documents/create/smart-code-insert-button.tsx +6 -0
- package/src/components/documents/view/document-details-card.tsx +6 -0
- package/src/components/documents/view/locales/de.ts +1 -0
- package/src/components/documents/view/locales/es.ts +1 -0
- package/src/components/documents/view/locales/fr.ts +1 -0
- package/src/components/documents/view/locales/hr.ts +1 -0
- package/src/components/documents/view/locales/it.ts +1 -0
- package/src/components/documents/view/locales/nl.ts +1 -0
- package/src/components/documents/view/locales/pl.ts +1 -0
- package/src/components/documents/view/locales/pt.ts +1 -0
- package/src/components/documents/view/locales/sl.ts +1 -0
- package/src/components/entities/entity-settings-form/email-template-variables-info.tsx +6 -0
- package/src/components/entities/entity-settings-form/input-with-preview.tsx +2 -145
- package/src/components/entities/entity-settings-form/locales/de.ts +4 -0
- package/src/components/entities/entity-settings-form/locales/es.ts +4 -0
- package/src/components/entities/entity-settings-form/locales/fr.ts +4 -0
- package/src/components/entities/entity-settings-form/locales/hr.ts +4 -0
- package/src/components/entities/entity-settings-form/locales/it.ts +4 -0
- package/src/components/entities/entity-settings-form/locales/nl.ts +4 -0
- package/src/components/entities/entity-settings-form/locales/pl.ts +4 -0
- package/src/components/entities/entity-settings-form/locales/pt.ts +4 -0
- package/src/components/entities/entity-settings-form/locales/sl.ts +4 -0
- package/src/components/entities/fina-settings-form/fina-settings-form.tsx +15 -0
- package/src/components/entities/fina-settings-form/fina-settings.hooks.ts +5 -1
- package/src/components/entities/fina-settings-form/locales/de.ts +3 -0
- package/src/components/entities/fina-settings-form/locales/en.ts +3 -0
- package/src/components/entities/fina-settings-form/locales/es.ts +3 -0
- package/src/components/entities/fina-settings-form/locales/fr.ts +3 -0
- package/src/components/entities/fina-settings-form/locales/hr.ts +3 -0
- package/src/components/entities/fina-settings-form/locales/it.ts +3 -0
- package/src/components/entities/fina-settings-form/locales/nl.ts +3 -0
- package/src/components/entities/fina-settings-form/locales/pl.ts +3 -0
- package/src/components/entities/fina-settings-form/locales/pt.ts +3 -0
- package/src/components/entities/fina-settings-form/locales/sl.ts +3 -0
- package/src/components/entities/fina-settings-form/sections/premises-management-section.tsx +4 -4
- package/src/components/entities/fina-settings-form/sections/register-premise-dialog.tsx +3 -3
- package/src/components/entities/settings/defaults-settings-form.tsx +38 -1
- package/src/components/entities/settings/tax-rules-settings-form.tsx +1 -2
- package/src/components/estimates/create/create-estimate-form.tsx +43 -2
- package/src/components/estimates/create/locales/de.ts +5 -0
- package/src/components/estimates/create/locales/es.ts +5 -0
- package/src/components/estimates/create/locales/fr.ts +5 -0
- package/src/components/estimates/create/locales/hr.ts +5 -0
- package/src/components/estimates/create/locales/it.ts +5 -0
- package/src/components/estimates/create/locales/nl.ts +5 -0
- package/src/components/estimates/create/locales/pl.ts +5 -0
- package/src/components/estimates/create/locales/pt.ts +5 -0
- package/src/components/estimates/create/locales/sl.ts +5 -0
- package/src/components/invoices/create/create-invoice-form.tsx +130 -40
- package/src/components/invoices/create/locales/de.ts +13 -0
- package/src/components/invoices/create/locales/es.ts +13 -0
- package/src/components/invoices/create/locales/fr.ts +13 -0
- package/src/components/invoices/create/locales/hr.ts +13 -0
- package/src/components/invoices/create/locales/it.ts +13 -0
- package/src/components/invoices/create/locales/nl.ts +13 -0
- package/src/components/invoices/create/locales/pl.ts +13 -0
- package/src/components/invoices/create/locales/pt.ts +13 -0
- package/src/components/invoices/create/locales/sl.ts +13 -0
- package/src/components/invoices/create/prepare-invoice-submission.ts +5 -5
- package/src/components/invoices/invoices.hooks.ts +2 -2
- package/src/components/table/table-pagination.tsx +1 -1
- package/src/generated/schemas/advanceinvoice.ts +2 -0
- package/src/generated/schemas/creditnote.ts +1 -0
- package/src/generated/schemas/deliverynote.ts +1 -0
- package/src/generated/schemas/entity.ts +4 -4
- package/src/generated/schemas/entityapikey.ts +19 -0
- package/src/generated/schemas/estimate.ts +2 -0
- package/src/generated/schemas/index.ts +1 -0
- package/src/generated/schemas/invoice.ts +2 -0
- package/src/generated/schemas/renderadvanceinvoicepreview_body.ts +1 -1
- package/src/generated/schemas/rendercreditnotepreview_body.ts +1 -1
- package/src/generated/schemas/renderdeliverynotepreview_body.ts +1 -1
- package/src/generated/schemas/renderestimatepreview_body.ts +1 -1
- package/src/generated/schemas/renderinvoicepreview_body.ts +1 -1
- package/src/generated/schemas/startpdfexport_body.ts +14 -2
- package/src/generated/schemas/webhook.ts +4 -0
- package/src/lib/template-variables.tsx +167 -0
- package/src/providers/entities-context.tsx +2 -2
|
@@ -116,8 +116,8 @@ export function setLastUsedFursCombo(entityId: string, combo: FursCombo): void {
|
|
|
116
116
|
const FINA_LAST_USED_KEY = "hr:fina:last-used";
|
|
117
117
|
|
|
118
118
|
export type FinaCombo = {
|
|
119
|
-
|
|
120
|
-
|
|
119
|
+
business_premise_name: string;
|
|
120
|
+
electronic_device_name: string;
|
|
121
121
|
};
|
|
122
122
|
|
|
123
123
|
export function getLastUsedFinaCombo(entityId: string): FinaCombo | null {
|
|
@@ -16,7 +16,7 @@ export function Pagination({ prevCursor, nextCursor, onPageChange }: PaginationP
|
|
|
16
16
|
const hasNext = Boolean(nextCursor);
|
|
17
17
|
|
|
18
18
|
return (
|
|
19
|
-
<div className="flex items-center justify-
|
|
19
|
+
<div className="flex items-center justify-start space-x-2">
|
|
20
20
|
<Button
|
|
21
21
|
variant="outline"
|
|
22
22
|
size="sm"
|
|
@@ -96,6 +96,7 @@ const createAdvanceInvoiceSchemaDefinition = z.object({
|
|
|
96
96
|
).optional(),
|
|
97
97
|
note: z.union([z.string(), z.null()]).optional(),
|
|
98
98
|
tax_clause: z.union([z.string(), z.null()]).optional(),
|
|
99
|
+
footer: z.union([z.string(), z.null()]).optional(),
|
|
99
100
|
currency_code: z.string().max(3).optional(),
|
|
100
101
|
metadata: z.union([z.record(z.string(), z.any()), z.null()]).optional(),
|
|
101
102
|
date_due: z.union([z.string(), z.null()]).optional(),
|
|
@@ -228,6 +229,7 @@ const updateAdvanceInvoiceSchemaDefinition = z
|
|
|
228
229
|
)
|
|
229
230
|
.min(1),
|
|
230
231
|
note: z.union([z.string(), z.null()]),
|
|
232
|
+
footer: z.union([z.string(), z.null()]),
|
|
231
233
|
currency_code: z.string(),
|
|
232
234
|
metadata: z.union([z.object({}).partial().passthrough(), z.null()]),
|
|
233
235
|
change_reason: z.string().max(500),
|
|
@@ -110,6 +110,7 @@ const updateCreditNoteSchemaDefinition = z
|
|
|
110
110
|
)
|
|
111
111
|
.min(1),
|
|
112
112
|
note: z.union([z.string(), z.null()]),
|
|
113
|
+
footer: z.union([z.string(), z.null()]),
|
|
113
114
|
payment_terms: z.union([z.string(), z.null()]),
|
|
114
115
|
currency_code: z.string(),
|
|
115
116
|
metadata: z.union([z.object({}).partial().passthrough(), z.null()]),
|
|
@@ -84,6 +84,7 @@ const createDeliveryNoteSchemaDefinition = z.object({
|
|
|
84
84
|
note: z.union([z.string(), z.null()]).optional(),
|
|
85
85
|
payment_terms: z.union([z.string(), z.null()]).optional(),
|
|
86
86
|
tax_clause: z.union([z.string(), z.null()]).optional(),
|
|
87
|
+
footer: z.union([z.string(), z.null()]).optional(),
|
|
87
88
|
currency_code: z.string().max(3).optional(),
|
|
88
89
|
metadata: z.union([z.record(z.string(), z.any()), z.null()]).optional(),
|
|
89
90
|
hide_prices: z.boolean().optional(),
|
|
@@ -30,7 +30,7 @@ const createEntitySchemaDefinition = z.object({
|
|
|
30
30
|
settings: z
|
|
31
31
|
.object({
|
|
32
32
|
pdf_template: z.union([
|
|
33
|
-
z.enum(["modern", "classic", "minimal", "fashion"]),
|
|
33
|
+
z.enum(["modern", "classic", "condensed", "minimal", "fashion"]),
|
|
34
34
|
z.null(),
|
|
35
35
|
]),
|
|
36
36
|
number_formats: z.union([
|
|
@@ -90,7 +90,7 @@ const createEntitySchemaDefinition = z.object({
|
|
|
90
90
|
operator_oib: z.string().min(11).max(11),
|
|
91
91
|
operator_label: z.string(),
|
|
92
92
|
u_sust_pdv: z.boolean().default(true),
|
|
93
|
-
numbering_sequence: z.enum(["N", "P"]).default("
|
|
93
|
+
numbering_sequence: z.enum(["N", "P"]).default("P"),
|
|
94
94
|
certificate_expiry: z.string(),
|
|
95
95
|
})
|
|
96
96
|
.partial()
|
|
@@ -181,7 +181,7 @@ const patchEntitySchemaDefinition = z
|
|
|
181
181
|
settings: z
|
|
182
182
|
.object({
|
|
183
183
|
pdf_template: z.union([
|
|
184
|
-
z.enum(["modern", "classic", "minimal", "fashion"]),
|
|
184
|
+
z.enum(["modern", "classic", "condensed", "minimal", "fashion"]),
|
|
185
185
|
z.null(),
|
|
186
186
|
]),
|
|
187
187
|
number_formats: z.union([
|
|
@@ -241,7 +241,7 @@ const patchEntitySchemaDefinition = z
|
|
|
241
241
|
operator_oib: z.string().min(11).max(11),
|
|
242
242
|
operator_label: z.string(),
|
|
243
243
|
u_sust_pdv: z.boolean().default(true),
|
|
244
|
-
numbering_sequence: z.enum(["N", "P"]).default("
|
|
244
|
+
numbering_sequence: z.enum(["N", "P"]).default("P"),
|
|
245
245
|
certificate_expiry: z.string(),
|
|
246
246
|
})
|
|
247
247
|
.partial()
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file was automatically generated using 'bun generate-schemas'.
|
|
3
|
+
* Do not edit this file manually. To update, run the generator again.
|
|
4
|
+
* @generated
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
|
|
9
|
+
// Schemas for entityapikey endpoints
|
|
10
|
+
|
|
11
|
+
// Schema for create entityapikey operation
|
|
12
|
+
const createEntityApiKeySchemaDefinition = z
|
|
13
|
+
.object({ name: z.string().max(255), ttl: z.number().int().gte(60) })
|
|
14
|
+
.partial();
|
|
15
|
+
|
|
16
|
+
// Type for create entityapikey operation
|
|
17
|
+
export type CreateEntityApiKeySchema = z.infer<typeof createEntityApiKeySchemaDefinition>;
|
|
18
|
+
|
|
19
|
+
export const createEntityApiKeySchema = createEntityApiKeySchemaDefinition;
|
|
@@ -86,6 +86,7 @@ const createEstimateSchemaDefinition = z.object({
|
|
|
86
86
|
note: z.union([z.string(), z.null()]).optional(),
|
|
87
87
|
payment_terms: z.union([z.string(), z.null()]).optional(),
|
|
88
88
|
tax_clause: z.union([z.string(), z.null()]).optional(),
|
|
89
|
+
footer: z.union([z.string(), z.null()]).optional(),
|
|
89
90
|
currency_code: z.string().max(3).optional(),
|
|
90
91
|
metadata: z.union([z.record(z.string(), z.any()), z.null()]).optional(),
|
|
91
92
|
date_valid_till: z.union([z.string(), z.null()]).optional(),
|
|
@@ -181,6 +182,7 @@ const updateEstimateSchemaDefinition = z
|
|
|
181
182
|
)
|
|
182
183
|
.min(1),
|
|
183
184
|
note: z.union([z.string(), z.null()]),
|
|
185
|
+
footer: z.union([z.string(), z.null()]),
|
|
184
186
|
payment_terms: z.union([z.string(), z.null()]),
|
|
185
187
|
currency_code: z.string(),
|
|
186
188
|
metadata: z.union([z.object({}).partial().passthrough(), z.null()]),
|
|
@@ -16,6 +16,7 @@ export * from './customestimate';
|
|
|
16
16
|
export * from './custominvoice';
|
|
17
17
|
export * from './deliverynote';
|
|
18
18
|
export * from './entity';
|
|
19
|
+
export * from './entityapikey';
|
|
19
20
|
export * from './entityuserrole';
|
|
20
21
|
export * from './estimate';
|
|
21
22
|
export * from './finasettings';
|
|
@@ -97,6 +97,7 @@ const createInvoiceSchemaDefinition = z.object({
|
|
|
97
97
|
note: z.union([z.string(), z.null()]).optional(),
|
|
98
98
|
payment_terms: z.union([z.string(), z.null()]).optional(),
|
|
99
99
|
tax_clause: z.union([z.string(), z.null()]).optional(),
|
|
100
|
+
footer: z.union([z.string(), z.null()]).optional(),
|
|
100
101
|
currency_code: z.string().max(3).optional(),
|
|
101
102
|
metadata: z.union([z.record(z.string(), z.any()), z.null()]).optional(),
|
|
102
103
|
date_due: z.union([z.string(), z.null()]).optional(),
|
|
@@ -237,6 +238,7 @@ const updateInvoiceSchemaDefinition = z
|
|
|
237
238
|
)
|
|
238
239
|
.min(1),
|
|
239
240
|
note: z.union([z.string(), z.null()]),
|
|
241
|
+
footer: z.union([z.string(), z.null()]),
|
|
240
242
|
payment_terms: z.union([z.string(), z.null()]),
|
|
241
243
|
currency_code: z.string(),
|
|
242
244
|
metadata: z.union([z.object({}).partial().passthrough(), z.null()]),
|
|
@@ -162,7 +162,7 @@ const CreateDocumentItem = z
|
|
|
162
162
|
description: z.union([z.string(), z.null()]),
|
|
163
163
|
price: z.number(),
|
|
164
164
|
gross_price: z.number(),
|
|
165
|
-
quantity: z.
|
|
165
|
+
quantity: z.number().gte(-140737488355328).lte(140737488355327),
|
|
166
166
|
unit: z.union([z.string(), z.null()]),
|
|
167
167
|
taxes: z.array(DocumentItemTax),
|
|
168
168
|
discounts: z.array(LineDiscount).max(5),
|
|
@@ -163,7 +163,7 @@ const CreateDocumentItem = z
|
|
|
163
163
|
description: z.union([z.string(), z.null()]),
|
|
164
164
|
price: z.number(),
|
|
165
165
|
gross_price: z.number(),
|
|
166
|
-
quantity: z.
|
|
166
|
+
quantity: z.number().gte(-140737488355328).lte(140737488355327),
|
|
167
167
|
unit: z.union([z.string(), z.null()]),
|
|
168
168
|
taxes: z.array(DocumentItemTax),
|
|
169
169
|
discounts: z.array(LineDiscount).max(5),
|
|
@@ -131,7 +131,7 @@ const CreateDocumentItem = z
|
|
|
131
131
|
description: z.union([z.string(), z.null()]),
|
|
132
132
|
price: z.number(),
|
|
133
133
|
gross_price: z.number(),
|
|
134
|
-
quantity: z.
|
|
134
|
+
quantity: z.number().gte(-140737488355328).lte(140737488355327),
|
|
135
135
|
unit: z.union([z.string(), z.null()]),
|
|
136
136
|
taxes: z.array(DocumentItemTax),
|
|
137
137
|
discounts: z.array(LineDiscount).max(5),
|
|
@@ -131,7 +131,7 @@ const CreateDocumentItem = z
|
|
|
131
131
|
description: z.union([z.string(), z.null()]),
|
|
132
132
|
price: z.number(),
|
|
133
133
|
gross_price: z.number(),
|
|
134
|
-
quantity: z.
|
|
134
|
+
quantity: z.number().gte(-140737488355328).lte(140737488355327),
|
|
135
135
|
unit: z.union([z.string(), z.null()]),
|
|
136
136
|
taxes: z.array(DocumentItemTax),
|
|
137
137
|
discounts: z.array(LineDiscount).max(5),
|
|
@@ -164,7 +164,7 @@ const CreateDocumentItem = z
|
|
|
164
164
|
description: z.union([z.string(), z.null()]),
|
|
165
165
|
price: z.number(),
|
|
166
166
|
gross_price: z.number(),
|
|
167
|
-
quantity: z.
|
|
167
|
+
quantity: z.number().gte(-140737488355328).lte(140737488355327),
|
|
168
168
|
unit: z.union([z.string(), z.null()]),
|
|
169
169
|
taxes: z.array(DocumentItemTax),
|
|
170
170
|
discounts: z.array(LineDiscount).max(5),
|
|
@@ -11,7 +11,13 @@ import { z } from 'zod';
|
|
|
11
11
|
// Dependency schema for startpdfexport_body
|
|
12
12
|
const PdfExportByDocumentIds = z
|
|
13
13
|
.object({
|
|
14
|
-
type: z.enum([
|
|
14
|
+
type: z.enum([
|
|
15
|
+
"invoice",
|
|
16
|
+
"estimate",
|
|
17
|
+
"credit_note",
|
|
18
|
+
"advance_invoice",
|
|
19
|
+
"delivery_note",
|
|
20
|
+
]),
|
|
15
21
|
document_ids: z.array(z.string()).min(1),
|
|
16
22
|
})
|
|
17
23
|
.passthrough();
|
|
@@ -20,7 +26,13 @@ const PdfExportByDocumentIds = z
|
|
|
20
26
|
// Dependency schema for startpdfexport_body
|
|
21
27
|
const PdfExportByDateRange = z
|
|
22
28
|
.object({
|
|
23
|
-
type: z.enum([
|
|
29
|
+
type: z.enum([
|
|
30
|
+
"invoice",
|
|
31
|
+
"estimate",
|
|
32
|
+
"credit_note",
|
|
33
|
+
"advance_invoice",
|
|
34
|
+
"delivery_note",
|
|
35
|
+
]),
|
|
24
36
|
date_from: z.string().optional(),
|
|
25
37
|
date_to: z.string().optional(),
|
|
26
38
|
})
|
|
@@ -49,6 +49,7 @@ const createWebhookSchemaDefinition = z.object({
|
|
|
49
49
|
"advance_invoice.created",
|
|
50
50
|
"advance_invoice.paid",
|
|
51
51
|
"advance_invoice.applied",
|
|
52
|
+
"advance_invoice.voided",
|
|
52
53
|
"advance_invoice.deleted",
|
|
53
54
|
"advance_invoice.restored",
|
|
54
55
|
"item.created",
|
|
@@ -87,6 +88,7 @@ const createWebhookSchemaDefinition = z.object({
|
|
|
87
88
|
"delivery_note.created",
|
|
88
89
|
"delivery_note.sent",
|
|
89
90
|
"delivery_note.cancelled",
|
|
91
|
+
"delivery_note.voided",
|
|
90
92
|
"delivery_note.deleted",
|
|
91
93
|
"delivery_note.restored",
|
|
92
94
|
])
|
|
@@ -142,6 +144,7 @@ const updateWebhookSchemaDefinition = z
|
|
|
142
144
|
"advance_invoice.created",
|
|
143
145
|
"advance_invoice.paid",
|
|
144
146
|
"advance_invoice.applied",
|
|
147
|
+
"advance_invoice.voided",
|
|
145
148
|
"advance_invoice.deleted",
|
|
146
149
|
"advance_invoice.restored",
|
|
147
150
|
"item.created",
|
|
@@ -180,6 +183,7 @@ const updateWebhookSchemaDefinition = z
|
|
|
180
183
|
"delivery_note.created",
|
|
181
184
|
"delivery_note.sent",
|
|
182
185
|
"delivery_note.cancelled",
|
|
186
|
+
"delivery_note.voided",
|
|
183
187
|
"delivery_note.deleted",
|
|
184
188
|
"delivery_note.restored",
|
|
185
189
|
])
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import type { Entity, Estimate, Invoice } from "@spaceinvoices/js-sdk";
|
|
2
|
+
import { cn } from "@/ui/lib/utils";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Convert snake_case variable name to Title Case for display
|
|
6
|
+
* e.g., "document_number" -> "Document Number", "bank_account.iban" -> "Bank Account Iban"
|
|
7
|
+
*/
|
|
8
|
+
export function formatVariableName(varName: string): string {
|
|
9
|
+
return varName
|
|
10
|
+
.replace(/\./g, "_")
|
|
11
|
+
.split("_")
|
|
12
|
+
.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
|
13
|
+
.join(" ");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Resolve a template variable to its actual value from entity/document data.
|
|
18
|
+
* Returns null if the variable can't be resolved (shown as a placeholder in preview).
|
|
19
|
+
*/
|
|
20
|
+
export function getVariableValue(
|
|
21
|
+
varName: string,
|
|
22
|
+
entity?: Entity | null,
|
|
23
|
+
document?: Partial<Invoice | Estimate> | null,
|
|
24
|
+
): string | null {
|
|
25
|
+
if (!entity) return null;
|
|
26
|
+
|
|
27
|
+
// Entity-related variables
|
|
28
|
+
if (varName === "entity_name") return entity.name || null;
|
|
29
|
+
if (varName === "entity_email") return (entity.settings as any)?.email || null;
|
|
30
|
+
if (varName === "entity_address") return entity.address || null;
|
|
31
|
+
if (varName === "entity_post_code") return entity.post_code || null;
|
|
32
|
+
if (varName === "entity_city") return entity.city || null;
|
|
33
|
+
if (varName === "entity_country") return entity.country || null;
|
|
34
|
+
if (varName === "entity_tax_number") return entity.tax_number || null;
|
|
35
|
+
if (varName === "entity_company_number") return entity.company_number || null;
|
|
36
|
+
|
|
37
|
+
// Date variables
|
|
38
|
+
if (varName === "current_date") {
|
|
39
|
+
return new Date().toLocaleDateString("en-US", { month: "long", day: "numeric", year: "numeric" });
|
|
40
|
+
}
|
|
41
|
+
if (varName === "current_year") return new Date().getFullYear().toString();
|
|
42
|
+
|
|
43
|
+
// Document-specific variables
|
|
44
|
+
if (document) {
|
|
45
|
+
if (varName === "document_number") return (document as any).number || null;
|
|
46
|
+
if (varName === "document_date" && (document as any).date) {
|
|
47
|
+
return new Date((document as any).date).toLocaleDateString("en-US", {
|
|
48
|
+
month: "long",
|
|
49
|
+
day: "numeric",
|
|
50
|
+
year: "numeric",
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
if (varName === "document_total" && (document as any).total_with_tax) {
|
|
54
|
+
return new Intl.NumberFormat("en-US", {
|
|
55
|
+
style: "currency",
|
|
56
|
+
currency: (document as any).currency_code || "USD",
|
|
57
|
+
}).format(Number((document as any).total_with_tax));
|
|
58
|
+
}
|
|
59
|
+
if (varName === "document_currency") return (document as any).currency_code || null;
|
|
60
|
+
|
|
61
|
+
// Invoice due date
|
|
62
|
+
if ("date_due" in document && varName === "document_due_date") {
|
|
63
|
+
return document.date_due
|
|
64
|
+
? new Date(document.date_due).toLocaleDateString("en-US", {
|
|
65
|
+
month: "long",
|
|
66
|
+
day: "numeric",
|
|
67
|
+
year: "numeric",
|
|
68
|
+
})
|
|
69
|
+
: null;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Estimate valid until
|
|
73
|
+
if ("date_valid_till" in document && varName === "document_valid_until") {
|
|
74
|
+
return document.date_valid_till
|
|
75
|
+
? new Date(document.date_valid_till).toLocaleDateString("en-US", {
|
|
76
|
+
month: "long",
|
|
77
|
+
day: "numeric",
|
|
78
|
+
year: "numeric",
|
|
79
|
+
})
|
|
80
|
+
: null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Customer variables
|
|
84
|
+
if ((document as any).customer) {
|
|
85
|
+
if (varName === "customer_name") return (document as any).customer.name || null;
|
|
86
|
+
if (varName === "customer_email") return (document as any).customer.email || null;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Bank account variables (from entity settings)
|
|
91
|
+
const bankAccounts = (entity.settings as any)?.bank_accounts as
|
|
92
|
+
| Array<{
|
|
93
|
+
iban?: string;
|
|
94
|
+
bank_name?: string;
|
|
95
|
+
bic?: string;
|
|
96
|
+
account_number?: string;
|
|
97
|
+
routing_number?: string;
|
|
98
|
+
sort_code?: string;
|
|
99
|
+
is_default?: boolean;
|
|
100
|
+
}>
|
|
101
|
+
| undefined;
|
|
102
|
+
const bankAccount = bankAccounts?.find((acc) => acc.is_default) ?? bankAccounts?.[0];
|
|
103
|
+
|
|
104
|
+
if (varName === "bank_account" && bankAccount) {
|
|
105
|
+
const lines: string[] = [];
|
|
106
|
+
if (bankAccount.bank_name) lines.push(bankAccount.bank_name);
|
|
107
|
+
if (bankAccount.iban) lines.push(`IBAN: ${bankAccount.iban}`);
|
|
108
|
+
else if (bankAccount.account_number) lines.push(`Account: ${bankAccount.account_number}`);
|
|
109
|
+
if (bankAccount.bic) lines.push(`BIC: ${bankAccount.bic}`);
|
|
110
|
+
return lines.join(", ") || null;
|
|
111
|
+
}
|
|
112
|
+
if (varName === "bank_account.iban") return bankAccount?.iban || null;
|
|
113
|
+
if (varName === "bank_account.bank_name") return bankAccount?.bank_name || null;
|
|
114
|
+
if (varName === "bank_account.bic") return bankAccount?.bic || null;
|
|
115
|
+
if (varName === "bank_account.account_number") return bankAccount?.account_number || null;
|
|
116
|
+
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Replace template variables in a string with styled React nodes for preview.
|
|
122
|
+
* Resolved values get a secondary bg, unresolved show as primary-colored placeholders.
|
|
123
|
+
*/
|
|
124
|
+
export function replaceTemplateVariablesForPreview(
|
|
125
|
+
template: string,
|
|
126
|
+
entity?: Entity | null,
|
|
127
|
+
document?: Partial<Invoice | Estimate> | null,
|
|
128
|
+
): React.ReactNode[] {
|
|
129
|
+
if (!template) return [];
|
|
130
|
+
|
|
131
|
+
const parts: React.ReactNode[] = [];
|
|
132
|
+
const regex = /\{([^}]+)\}/g;
|
|
133
|
+
let lastIndex = 0;
|
|
134
|
+
let match: RegExpExecArray | null = null;
|
|
135
|
+
|
|
136
|
+
match = regex.exec(template);
|
|
137
|
+
while (match !== null) {
|
|
138
|
+
if (match.index > lastIndex) {
|
|
139
|
+
parts.push(template.slice(lastIndex, match.index));
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const varName = match[1];
|
|
143
|
+
const actualValue = getVariableValue(varName, entity, document);
|
|
144
|
+
const displayValue = actualValue || formatVariableName(varName);
|
|
145
|
+
|
|
146
|
+
parts.push(
|
|
147
|
+
<span
|
|
148
|
+
key={match.index}
|
|
149
|
+
className={cn(
|
|
150
|
+
"rounded px-1.5 py-0.5 font-medium text-xs",
|
|
151
|
+
actualValue ? "bg-secondary text-secondary-foreground" : "bg-primary/10 text-primary",
|
|
152
|
+
)}
|
|
153
|
+
>
|
|
154
|
+
{displayValue}
|
|
155
|
+
</span>,
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
lastIndex = regex.lastIndex;
|
|
159
|
+
match = regex.exec(template);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (lastIndex < template.length) {
|
|
163
|
+
parts.push(template.slice(lastIndex));
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return parts;
|
|
167
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Entity as SDKEntity } from "@spaceinvoices/js-sdk";
|
|
2
2
|
|
|
3
3
|
import { createContext, useContext } from "react";
|
|
4
4
|
|
|
5
5
|
/** Entity type with country_rules included (from getEntities response) */
|
|
6
|
-
export type Entity =
|
|
6
|
+
export type Entity = SDKEntity;
|
|
7
7
|
|
|
8
8
|
export type EntityEnvironment = "live" | "sandbox";
|
|
9
9
|
|