@spaceinvoices/react-ui 0.4.1 → 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.
Files changed (245) hide show
  1. package/cli/dist/index.js +1 -1
  2. package/package.json +1 -1
  3. package/registry.json +25 -0
  4. package/src/components/advance-invoices/advance-invoices.hooks.ts +32 -2
  5. package/src/components/advance-invoices/create/create-advance-invoice-form.tsx +109 -4
  6. package/src/components/advance-invoices/create/locales/de.ts +2 -0
  7. package/src/components/advance-invoices/create/locales/es.ts +2 -0
  8. package/src/components/advance-invoices/create/locales/fr.ts +2 -0
  9. package/src/components/advance-invoices/create/locales/hr.ts +2 -0
  10. package/src/components/advance-invoices/create/locales/it.ts +2 -0
  11. package/src/components/advance-invoices/create/locales/nl.ts +2 -0
  12. package/src/components/advance-invoices/create/locales/pl.ts +2 -0
  13. package/src/components/advance-invoices/create/locales/pt.ts +2 -0
  14. package/src/components/advance-invoices/create/locales/sl.ts +2 -0
  15. package/src/components/advance-invoices/create/prepare-advance-invoice-submission.ts +17 -0
  16. package/src/components/advance-invoices/list/list-row-actions.tsx +3 -6
  17. package/src/components/advance-invoices/list/list-table.tsx +105 -2
  18. package/src/components/advance-invoices/list/locales/de.ts +4 -0
  19. package/src/components/advance-invoices/list/locales/en.ts +4 -0
  20. package/src/components/advance-invoices/list/locales/es.ts +4 -0
  21. package/src/components/advance-invoices/list/locales/fr.ts +4 -0
  22. package/src/components/advance-invoices/list/locales/hr.ts +4 -0
  23. package/src/components/advance-invoices/list/locales/it.ts +4 -0
  24. package/src/components/advance-invoices/list/locales/nl.ts +4 -0
  25. package/src/components/advance-invoices/list/locales/pl.ts +4 -0
  26. package/src/components/advance-invoices/list/locales/pt.ts +4 -0
  27. package/src/components/advance-invoices/list/locales/sl.ts +4 -0
  28. package/src/components/credit-notes/create/create-credit-note-form.tsx +177 -6
  29. package/src/components/credit-notes/create/locales/de.ts +8 -0
  30. package/src/components/credit-notes/create/locales/es.ts +8 -0
  31. package/src/components/credit-notes/create/locales/fr.ts +7 -0
  32. package/src/components/credit-notes/create/locales/hr.ts +7 -0
  33. package/src/components/credit-notes/create/locales/it.ts +9 -0
  34. package/src/components/credit-notes/create/locales/nl.ts +7 -0
  35. package/src/components/credit-notes/create/locales/pl.ts +7 -0
  36. package/src/components/credit-notes/create/locales/pt.ts +7 -0
  37. package/src/components/credit-notes/create/locales/sl.ts +7 -0
  38. package/src/components/credit-notes/credit-notes.hooks.ts +30 -0
  39. package/src/components/credit-notes/list/list-row-actions.tsx +3 -6
  40. package/src/components/credit-notes/list/list-table.tsx +79 -8
  41. package/src/components/credit-notes/list/locales/de.ts +4 -1
  42. package/src/components/credit-notes/list/locales/en.ts +5 -0
  43. package/src/components/credit-notes/list/locales/es.ts +4 -1
  44. package/src/components/credit-notes/list/locales/fr.ts +4 -1
  45. package/src/components/credit-notes/list/locales/hr.ts +4 -1
  46. package/src/components/credit-notes/list/locales/it.ts +4 -1
  47. package/src/components/credit-notes/list/locales/nl.ts +4 -1
  48. package/src/components/credit-notes/list/locales/pl.ts +4 -1
  49. package/src/components/credit-notes/list/locales/pt.ts +4 -1
  50. package/src/components/credit-notes/list/locales/sl.ts +4 -1
  51. package/src/components/customers/create-customer-form/create-customer-form.tsx +0 -1
  52. package/src/components/dashboard/collection-rate-card/use-collection-rate.ts +2 -2
  53. package/src/components/dashboard/invoice-status-chart/use-invoice-status.ts +3 -3
  54. package/src/components/dashboard/payment-methods-chart/use-payment-methods.ts +1 -1
  55. package/src/components/dashboard/payment-trend-chart/use-payment-trend.ts +1 -1
  56. package/src/components/dashboard/revenue-trend-chart/use-revenue-trend.ts +1 -1
  57. package/src/components/dashboard/shared/use-revenue-data.ts +4 -4
  58. package/src/components/dashboard/shared/use-stats-counts.ts +4 -4
  59. package/src/components/dashboard/shared/use-stats-query.ts +1 -1
  60. package/src/components/dashboard/tax-collected-card/use-tax-collected.ts +2 -2
  61. package/src/components/dashboard/top-customers-chart/use-top-customers.ts +1 -1
  62. package/src/components/delivery-notes/create/create-delivery-note-form.tsx +332 -0
  63. package/src/components/delivery-notes/create/locales/de.ts +50 -0
  64. package/src/components/delivery-notes/create/locales/es.ts +49 -0
  65. package/src/components/delivery-notes/create/locales/fr.ts +50 -0
  66. package/src/components/delivery-notes/create/locales/hr.ts +49 -0
  67. package/src/components/delivery-notes/create/locales/it.ts +49 -0
  68. package/src/components/delivery-notes/create/locales/nl.ts +50 -0
  69. package/src/components/delivery-notes/create/locales/pl.ts +49 -0
  70. package/src/components/delivery-notes/create/locales/pt.ts +50 -0
  71. package/src/components/delivery-notes/create/locales/sl.ts +49 -0
  72. package/src/components/delivery-notes/create/prepare-delivery-note-submission.ts +38 -0
  73. package/src/components/delivery-notes/create/use-delivery-note-customer-form.ts +1 -0
  74. package/src/components/delivery-notes/delivery-notes.hooks.ts +15 -0
  75. package/src/components/delivery-notes/list/index.ts +3 -0
  76. package/src/components/delivery-notes/list/list-row-actions.tsx +103 -0
  77. package/src/components/delivery-notes/list/list-table.tsx +214 -0
  78. package/src/components/delivery-notes/list/locales/de.ts +9 -0
  79. package/src/components/delivery-notes/list/locales/en.ts +11 -0
  80. package/src/components/delivery-notes/list/locales/es.ts +9 -0
  81. package/src/components/delivery-notes/list/locales/fr.ts +9 -0
  82. package/src/components/delivery-notes/list/locales/hr.ts +9 -0
  83. package/src/components/delivery-notes/list/locales/it.ts +9 -0
  84. package/src/components/delivery-notes/list/locales/nl.ts +9 -0
  85. package/src/components/delivery-notes/list/locales/pl.ts +9 -0
  86. package/src/components/delivery-notes/list/locales/pt.ts +9 -0
  87. package/src/components/delivery-notes/list/locales/sl.ts +9 -0
  88. package/src/components/delivery-notes/list/use-delivery-note-download.ts +63 -0
  89. package/src/components/documents/create/document-details-section.tsx +103 -33
  90. package/src/components/documents/create/live-preview.tsx +37 -10
  91. package/src/components/documents/create/mark-as-paid-section.tsx +11 -2
  92. package/src/components/documents/create/prepare-document-submission.ts +1 -1
  93. package/src/components/documents/documents.hooks.ts +2 -1
  94. package/src/components/documents/shared/document-preview-display.tsx +12 -5
  95. package/src/components/documents/types.ts +10 -1
  96. package/src/components/documents/view/document-actions-bar.tsx +30 -0
  97. package/src/components/documents/view/document-details-card.tsx +3 -3
  98. package/src/components/documents/view/document-payments-list.tsx +3 -3
  99. package/src/components/documents/view/document-relations-list.tsx +105 -0
  100. package/src/components/documents/view/locales/de.ts +26 -0
  101. package/src/components/documents/view/locales/es.ts +26 -0
  102. package/src/components/documents/view/locales/fr.ts +26 -0
  103. package/src/components/documents/view/locales/hr.ts +26 -0
  104. package/src/components/documents/view/locales/it.ts +26 -0
  105. package/src/components/documents/view/locales/nl.ts +26 -0
  106. package/src/components/documents/view/locales/pl.ts +26 -0
  107. package/src/components/documents/view/locales/pt.ts +26 -0
  108. package/src/components/documents/view/locales/sl.ts +26 -0
  109. package/src/components/documents/view/use-document-download.ts +5 -3
  110. package/src/components/entities/create-entity-form.tsx +1 -1
  111. package/src/components/entities/entity-settings-form/entity-settings-form.tsx +2 -3
  112. package/src/components/entities/entity-settings-form/locales/es.ts +2 -0
  113. package/src/components/entities/entity-settings-form/locales/fr.ts +2 -0
  114. package/src/components/entities/entity-settings-form/locales/hr.ts +2 -0
  115. package/src/components/entities/entity-settings-form/locales/it.ts +2 -0
  116. package/src/components/entities/entity-settings-form/locales/nl.ts +2 -0
  117. package/src/components/entities/entity-settings-form/locales/pl.ts +2 -0
  118. package/src/components/entities/entity-settings-form/locales/pt.ts +2 -0
  119. package/src/components/entities/fina-settings-form/fina-operator-required-dialog.tsx +109 -0
  120. package/src/components/entities/fina-settings-form/fina-settings-form.tsx +377 -35
  121. package/src/components/entities/fina-settings-form/fina-settings.hooks.ts +106 -20
  122. package/src/components/entities/fina-settings-form/index.ts +1 -0
  123. package/src/components/entities/fina-settings-form/locales/de.ts +54 -34
  124. package/src/components/entities/fina-settings-form/locales/en.ts +51 -34
  125. package/src/components/entities/fina-settings-form/locales/es.ts +50 -34
  126. package/src/components/entities/fina-settings-form/locales/fr.ts +50 -34
  127. package/src/components/entities/fina-settings-form/locales/hr.ts +50 -34
  128. package/src/components/entities/fina-settings-form/locales/it.ts +50 -34
  129. package/src/components/entities/fina-settings-form/locales/nl.ts +50 -34
  130. package/src/components/entities/fina-settings-form/locales/pl.ts +50 -34
  131. package/src/components/entities/fina-settings-form/locales/pt.ts +50 -34
  132. package/src/components/entities/fina-settings-form/locales/sl.ts +50 -34
  133. package/src/components/entities/fina-settings-form/sections/certificate-settings-section.tsx +18 -0
  134. package/src/components/entities/fina-settings-form/sections/premises-management-section.tsx +64 -89
  135. package/src/components/entities/fina-settings-form/sections/register-premise-dialog.tsx +51 -323
  136. package/src/components/entities/furs-settings-form/furs-operator-required-dialog.tsx +106 -0
  137. package/src/components/entities/furs-settings-form/furs-settings-form.tsx +33 -10
  138. package/src/components/entities/furs-settings-form/furs-settings.hooks.ts +12 -11
  139. package/src/components/entities/furs-settings-form/index.ts +1 -0
  140. package/src/components/entities/furs-settings-form/locales/de.ts +27 -3
  141. package/src/components/entities/furs-settings-form/locales/en.ts +17 -3
  142. package/src/components/entities/furs-settings-form/locales/es.ts +26 -3
  143. package/src/components/entities/furs-settings-form/locales/fr.ts +26 -3
  144. package/src/components/entities/furs-settings-form/locales/hr.ts +26 -3
  145. package/src/components/entities/furs-settings-form/locales/it.ts +26 -3
  146. package/src/components/entities/furs-settings-form/locales/nl.ts +26 -3
  147. package/src/components/entities/furs-settings-form/locales/pl.ts +26 -3
  148. package/src/components/entities/furs-settings-form/locales/pt.ts +26 -3
  149. package/src/components/entities/furs-settings-form/locales/sl.ts +16 -3
  150. package/src/components/entities/furs-settings-form/sections/certificate-settings-section.tsx +22 -0
  151. package/src/components/entities/furs-settings-form/sections/general-settings-section.tsx +26 -5
  152. package/src/components/entities/furs-settings-form/sections/register-premise-dialog.tsx +14 -2
  153. package/src/components/entities/settings/tax-rules-settings-form.tsx +4 -4
  154. package/src/components/estimates/list/list-row-actions.tsx +3 -7
  155. package/src/components/estimates/list/list-table.tsx +35 -2
  156. package/src/components/estimates/list/locales/de.ts +3 -0
  157. package/src/components/estimates/list/locales/en.ts +3 -0
  158. package/src/components/estimates/list/locales/es.ts +3 -0
  159. package/src/components/estimates/list/locales/fr.ts +3 -0
  160. package/src/components/estimates/list/locales/hr.ts +3 -0
  161. package/src/components/estimates/list/locales/it.ts +3 -0
  162. package/src/components/estimates/list/locales/nl.ts +3 -0
  163. package/src/components/estimates/list/locales/pl.ts +3 -0
  164. package/src/components/estimates/list/locales/pt.ts +3 -0
  165. package/src/components/estimates/list/locales/sl.ts +3 -0
  166. package/src/components/export/document-export-form.tsx +34 -34
  167. package/src/components/invoices/create/create-invoice-form.tsx +107 -5
  168. package/src/components/invoices/create/prepare-invoice-submission.ts +17 -0
  169. package/src/components/invoices/invoices-furs.hooks.ts +24 -9
  170. package/src/components/invoices/invoices.hooks.ts +32 -2
  171. package/src/components/invoices/list/list-row-actions.tsx +26 -11
  172. package/src/components/invoices/list/list-table.tsx +121 -5
  173. package/src/components/invoices/list/locales/de.ts +5 -0
  174. package/src/components/invoices/list/locales/en.ts +5 -0
  175. package/src/components/invoices/list/locales/es.ts +5 -0
  176. package/src/components/invoices/list/locales/fr.ts +5 -0
  177. package/src/components/invoices/list/locales/hr.ts +5 -0
  178. package/src/components/invoices/list/locales/it.ts +5 -0
  179. package/src/components/invoices/list/locales/nl.ts +5 -0
  180. package/src/components/invoices/list/locales/pl.ts +5 -0
  181. package/src/components/invoices/list/locales/pt.ts +5 -0
  182. package/src/components/invoices/list/locales/sl.ts +5 -0
  183. package/src/components/invoices/view/fiscalization-status-card.tsx +4 -1
  184. package/src/components/items/item-list-table/item-list-row-actions.tsx +5 -8
  185. package/src/components/items/item-list-table/item-list-row.tsx +5 -3
  186. package/src/components/items/item-list-table/item-list-table.tsx +5 -1
  187. package/src/components/recurring-invoices/create-recurring-invoice-form/create-recurring-invoice-form.tsx +418 -0
  188. package/src/components/recurring-invoices/create-recurring-invoice-form/locales/de.ts +45 -0
  189. package/src/components/recurring-invoices/create-recurring-invoice-form/locales/es.ts +44 -0
  190. package/src/components/recurring-invoices/create-recurring-invoice-form/locales/fr.ts +44 -0
  191. package/src/components/recurring-invoices/create-recurring-invoice-form/locales/hr.ts +44 -0
  192. package/src/components/recurring-invoices/create-recurring-invoice-form/locales/it.ts +44 -0
  193. package/src/components/recurring-invoices/create-recurring-invoice-form/locales/nl.ts +44 -0
  194. package/src/components/recurring-invoices/create-recurring-invoice-form/locales/pl.ts +44 -0
  195. package/src/components/recurring-invoices/create-recurring-invoice-form/locales/pt.ts +44 -0
  196. package/src/components/recurring-invoices/create-recurring-invoice-form/locales/sl.ts +44 -0
  197. package/src/components/recurring-invoices/index.ts +3 -0
  198. package/src/components/recurring-invoices/list/index.ts +2 -0
  199. package/src/components/recurring-invoices/list/list-row-actions.tsx +139 -0
  200. package/src/components/recurring-invoices/list/list-table.tsx +179 -0
  201. package/src/components/recurring-invoices/list/locales/de.ts +27 -0
  202. package/src/components/recurring-invoices/list/locales/en.ts +5 -0
  203. package/src/components/recurring-invoices/list/locales/es.ts +27 -0
  204. package/src/components/recurring-invoices/list/locales/fr.ts +27 -0
  205. package/src/components/recurring-invoices/list/locales/hr.ts +27 -0
  206. package/src/components/recurring-invoices/list/locales/it.ts +27 -0
  207. package/src/components/recurring-invoices/list/locales/nl.ts +27 -0
  208. package/src/components/recurring-invoices/list/locales/pl.ts +27 -0
  209. package/src/components/recurring-invoices/list/locales/pt.ts +27 -0
  210. package/src/components/recurring-invoices/list/locales/sl.ts +27 -0
  211. package/src/components/recurring-invoices/recurring-invoices.hooks.ts +28 -0
  212. package/src/components/table/data-table.tsx +122 -5
  213. package/src/components/table/selection-toolbar.tsx +36 -0
  214. package/src/components/tax-reports/kir-export-form.tsx +75 -55
  215. package/src/components/taxes/tax-list-table/tax-list-row-actions.tsx +3 -6
  216. package/src/components/taxes/tax-list-table/tax-list-row.tsx +3 -2
  217. package/src/components/taxes/tax-list-table/tax-list-table.tsx +5 -1
  218. package/src/components/ui/checkbox.tsx +5 -5
  219. package/src/generate-schemas.ts +45 -18
  220. package/src/generated/schemas/authorizeshopify_body.ts +22 -0
  221. package/src/generated/schemas/creditnote.ts +0 -2
  222. package/src/generated/schemas/deliverynote.ts +134 -0
  223. package/src/generated/schemas/entity.ts +5 -1
  224. package/src/generated/schemas/index.ts +42 -28
  225. package/src/generated/schemas/order.ts +129 -0
  226. package/src/generated/schemas/orderintegration.ts +51 -0
  227. package/src/generated/schemas/payment.ts +24 -2
  228. package/src/generated/schemas/recurringinvoice.ts +61 -0
  229. package/src/generated/schemas/renderadvanceinvoicepreview_body.ts +108 -140
  230. package/src/generated/schemas/rendercreditnotepreview_body.ts +109 -141
  231. package/src/generated/schemas/renderdeliverynotepreview_body.ts +185 -0
  232. package/src/generated/schemas/renderestimatepreview_body.ts +79 -82
  233. package/src/generated/schemas/renderinvoicepreview_body.ts +109 -141
  234. package/src/generated/schemas/startpdfexport_body.ts +18 -2
  235. package/src/generated/schemas/userfinasettings.ts +19 -0
  236. package/src/generated/schemas/webhook.ts +54 -0
  237. package/src/hooks/use-duplicate-document.ts +11 -3
  238. package/src/hooks/use-next-document-number.ts +2 -2
  239. package/src/lib/furs-error-utils.ts +36 -0
  240. package/src/lib/schemas/advance-invoice.ts +3 -3
  241. package/src/lib/schemas/credit-note.ts +3 -3
  242. package/src/lib/schemas/estimate.ts +3 -3
  243. package/src/lib/schemas/invoice.ts +3 -3
  244. package/src/providers/sdk-provider.tsx +5 -7
  245. package/src/providers/white-label-provider.tsx +3 -0
@@ -39,6 +39,25 @@ type FursInlineProps = {
39
39
  isSkipped?: boolean;
40
40
  };
41
41
 
42
+ type FinaPremise = {
43
+ id: string;
44
+ premise_id: string;
45
+ };
46
+
47
+ type FinaDevice = {
48
+ id: string;
49
+ device_id: string;
50
+ };
51
+
52
+ type FinaInlineProps = {
53
+ premises: FinaPremise[];
54
+ devices: FinaDevice[];
55
+ selectedPremise?: string;
56
+ selectedDevice?: string;
57
+ onPremiseChange: (value: string | undefined) => void;
58
+ onDeviceChange: (value: string | undefined) => void;
59
+ };
60
+
42
61
  type ServiceDateProps = {
43
62
  dateType: "single" | "range";
44
63
  onDateTypeChange: (type: "single" | "range") => void;
@@ -50,6 +69,7 @@ type DocumentDetailsSectionProps = {
50
69
  t: (key: string) => string;
51
70
  children?: React.ReactNode; // For document-specific additions (e.g., mark as paid for invoices)
52
71
  fursInline?: FursInlineProps; // FURS premise/device inline with number
72
+ finaInline?: FinaInlineProps; // FINA premise/device inline with number
53
73
  serviceDate?: ServiceDateProps; // Service date section (invoice only)
54
74
  };
55
75
 
@@ -59,16 +79,20 @@ export function DocumentDetailsSection({
59
79
  t,
60
80
  children,
61
81
  fursInline,
82
+ finaInline,
62
83
  serviceDate,
63
84
  }: DocumentDetailsSectionProps) {
64
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";
65
88
  const dateFieldName =
66
89
  documentType === "invoice" || documentType === "advance_invoice" ? "date_due" : "date_valid_till";
67
90
  const dateFieldLabel =
68
91
  documentType === "invoice" || documentType === "advance_invoice" ? t("Due Date") : t("Valid Until");
69
92
 
70
- // Check if FURS inline should show premise/device selects
93
+ // Check if FURS/FINA inline should show premise/device selects
71
94
  const showFursSelects = fursInline && !fursInline.isSkipped;
95
+ const showFinaSelects = !!finaInline;
72
96
 
73
97
  return (
74
98
  <div className="flex-1 space-y-4">
@@ -125,6 +149,50 @@ export function DocumentDetailsSection({
125
149
  </TooltipContent>
126
150
  </Tooltip>
127
151
  </div>
152
+ ) : showFinaSelects ? (
153
+ <div className="flex gap-2">
154
+ <Select
155
+ value={finaInline.selectedPremise || ""}
156
+ onValueChange={(v) => finaInline.onPremiseChange(v ?? undefined)}
157
+ >
158
+ <SelectTrigger className="w-24">
159
+ <SelectValue placeholder={t("Premise")} />
160
+ </SelectTrigger>
161
+ <SelectContent>
162
+ {finaInline.premises.map((premise) => (
163
+ <SelectItem key={premise.id} value={premise.premise_id}>
164
+ {premise.premise_id}
165
+ </SelectItem>
166
+ ))}
167
+ </SelectContent>
168
+ </Select>
169
+ <Select
170
+ value={finaInline.selectedDevice || ""}
171
+ onValueChange={(v) => finaInline.onDeviceChange(v ?? undefined)}
172
+ disabled={!finaInline.selectedPremise || finaInline.devices.length === 0}
173
+ >
174
+ <SelectTrigger className="w-24">
175
+ <SelectValue placeholder={t("Device")} />
176
+ </SelectTrigger>
177
+ <SelectContent>
178
+ {finaInline.devices.map((device) => (
179
+ <SelectItem key={device.id} value={device.device_id}>
180
+ {device.device_id}
181
+ </SelectItem>
182
+ ))}
183
+ </SelectContent>
184
+ </Select>
185
+ <Tooltip>
186
+ <TooltipTrigger asChild>
187
+ <FormControl>
188
+ <Input {...field} disabled className="flex-1" />
189
+ </FormControl>
190
+ </TooltipTrigger>
191
+ <TooltipContent>
192
+ <p>{t("Number format can be changed in settings")}</p>
193
+ </TooltipContent>
194
+ </Tooltip>
195
+ </div>
128
196
  ) : (
129
197
  <Tooltip>
130
198
  <TooltipTrigger asChild>
@@ -280,38 +348,40 @@ export function DocumentDetailsSection({
280
348
  />
281
349
  )}
282
350
 
283
- <FormField
284
- control={control}
285
- name={dateFieldName}
286
- render={({ field }) => (
287
- <FormItem>
288
- <FormLabel className="">{dateFieldLabel}</FormLabel>
289
- <Popover>
290
- <PopoverTrigger asChild>
291
- <FormControl>
292
- <Button
293
- variant="outline"
294
- className={cn("w-full pl-3 text-left font-normal", !field.value && "text-muted-foreground")}
295
- >
296
- {field.value ? new Date(field.value).toLocaleDateString() : <span>{t("Pick a date")}</span>}
297
- <CalendarIcon className="ml-auto h-4 w-4 opacity-50" />
298
- </Button>
299
- </FormControl>
300
- </PopoverTrigger>
301
- <PopoverContent className="w-auto p-0" align="start">
302
- <Calendar
303
- mode="single"
304
- selected={field.value ? new Date(field.value) : undefined}
305
- onSelect={(date) => field.onChange(date?.toISOString())}
306
- disabled={(date) => date < new Date("1900-01-01")}
307
- initialFocus
308
- />
309
- </PopoverContent>
310
- </Popover>
311
- <FormMessage />
312
- </FormItem>
313
- )}
314
- />
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
+ )}
315
385
 
316
386
  <FormField
317
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 wrapper
108
- const html = await sdk.invoices.renderInvoicePreview(
109
- previewData as any,
110
- { partial: "true", template, locale },
111
- { entity_id: activeEntity.id },
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...</p>
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">Invoice Preview</p>
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
  )}
@@ -29,6 +29,8 @@ type MarkAsPaidSectionProps = {
29
29
  onPaymentTypesChange: (values: string[]) => void;
30
30
  /** Translation function */
31
31
  t: (key: string) => string;
32
+ /** Always show payment type selector (e.g. for FINA fiscalization) */
33
+ alwaysShowPaymentType?: boolean;
32
34
  };
33
35
 
34
36
  export function MarkAsPaidSection({
@@ -37,9 +39,12 @@ export function MarkAsPaidSection({
37
39
  paymentTypes,
38
40
  onPaymentTypesChange,
39
41
  t,
42
+ alwaysShowPaymentType,
40
43
  }: MarkAsPaidSectionProps) {
44
+ const showPaymentTypes = checked || alwaysShowPaymentType;
45
+
41
46
  return (
42
- <div className={cn("flex flex-col gap-4 rounded-md border p-4", checked && "gap-3")}>
47
+ <div className={cn("flex flex-col gap-4 rounded-md border p-4", showPaymentTypes && "gap-3")}>
43
48
  <div className="flex flex-row items-center space-x-3 space-y-0">
44
49
  <Checkbox checked={checked} onCheckedChange={(v) => onCheckedChange(v === true)} />
45
50
  <div className="flex items-center gap-1 leading-none">
@@ -61,9 +66,13 @@ export function MarkAsPaidSection({
61
66
  </div>
62
67
  </div>
63
68
 
64
- {checked && (
69
+ {showPaymentTypes && (
65
70
  <div className="flex flex-col gap-2">
71
+ {alwaysShowPaymentType && !checked && (
72
+ <Label className="text-muted-foreground text-xs">{t("Payment Type")}</Label>
73
+ )}
66
74
  {paymentTypes.map((type, index) => (
75
+ // biome-ignore lint/suspicious/noArrayIndexKey: payment types list uses index key
67
76
  <div key={index} className="flex items-center gap-2">
68
77
  <Select
69
78
  value={type}
@@ -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...</p>
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,5 +1,6 @@
1
1
  import type { AdvanceInvoice, CreditNote, Estimate, Invoice } from "@spaceinvoices/js-sdk";
2
2
  import {
3
+ Ban,
3
4
  Check,
4
5
  CheckCircle,
5
6
  ChevronDown,
@@ -11,6 +12,7 @@ import {
11
12
  Mail,
12
13
  Pencil,
13
14
  Plus,
15
+ RefreshCw,
14
16
  Share2,
15
17
  Trash2,
16
18
  } from "lucide-react";
@@ -88,6 +90,14 @@ interface DocumentActionsBarProps extends ComponentTranslationProps {
88
90
  onDeleteDraft?: () => void;
89
91
  /** Whether draft deletion is in progress */
90
92
  isDeletingDraft?: boolean;
93
+ /** Called when user wants to create a recurring schedule from this document */
94
+ onCreateRecurring?: () => void;
95
+ /** Custom label for recurring button (e.g. "Edit Recurring" when one already exists) */
96
+ recurringLabel?: string;
97
+ /** Called when user wants to void the document */
98
+ onVoid?: () => void;
99
+ /** Whether voiding is in progress */
100
+ isVoiding?: boolean;
91
101
  }
92
102
 
93
103
  function getApiLocale(uiLanguage: string): string {
@@ -128,6 +138,10 @@ export function DocumentActionsBar({
128
138
  isFinalizing,
129
139
  onDeleteDraft,
130
140
  isDeletingDraft,
141
+ onCreateRecurring,
142
+ recurringLabel,
143
+ onVoid,
144
+ isVoiding,
131
145
  ...i18nProps
132
146
  }: DocumentActionsBarProps) {
133
147
  const t = createTranslation({ translations, locale: currentLocale, ...i18nProps });
@@ -298,6 +312,14 @@ export function DocumentActionsBar({
298
312
  </Button>
299
313
  ) : null}
300
314
 
315
+ {/* Recurring */}
316
+ {onCreateRecurring && (
317
+ <Button variant="outline" size="sm" onClick={onCreateRecurring} className="cursor-pointer">
318
+ <RefreshCw className="mr-2 h-4 w-4" />
319
+ {recurringLabel || t("Recurring")}
320
+ </Button>
321
+ )}
322
+
301
323
  {/* Duplicate/Convert */}
302
324
  {onDuplicate && (
303
325
  <DropdownMenu>
@@ -318,6 +340,14 @@ export function DocumentActionsBar({
318
340
  </DropdownMenu>
319
341
  )}
320
342
 
343
+ {/* Void */}
344
+ {!isDraft && onVoid && (
345
+ <Button variant="destructive" size="sm" onClick={onVoid} disabled={isVoiding} className="cursor-pointer">
346
+ {isVoiding ? <Loader2 className="mr-2 h-4 w-4 animate-spin" /> : <Ban className="mr-2 h-4 w-4" />}
347
+ {isVoiding ? t("Voiding...") : t("Void")}
348
+ </Button>
349
+ )}
350
+
321
351
  {/* Draft Actions */}
322
352
  {isDraft && onFinalize && (
323
353
  <Button variant="default" size="sm" onClick={onFinalize} disabled={isFinalizing} className="cursor-pointer">
@@ -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 queries to refresh data
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
+ }