@spaceinvoices/react-ui 0.4.8 → 0.4.10

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 (258) hide show
  1. package/cli/dist/index.js +1 -1
  2. package/package.json +1 -1
  3. package/src/common/autocomplete.tsx +69 -6
  4. package/src/components/advance-invoices/create/create-advance-invoice-form.tsx +124 -285
  5. package/src/components/advance-invoices/list/list-table.tsx +10 -3
  6. package/src/components/advance-invoices/list/locales/de.ts +2 -0
  7. package/src/components/advance-invoices/list/locales/en.ts +1 -0
  8. package/src/components/advance-invoices/list/locales/es.ts +1 -0
  9. package/src/components/advance-invoices/list/locales/fr.ts +1 -0
  10. package/src/components/advance-invoices/list/locales/hr.ts +1 -0
  11. package/src/components/advance-invoices/list/locales/it.ts +1 -0
  12. package/src/components/advance-invoices/list/locales/nl.ts +1 -0
  13. package/src/components/advance-invoices/list/locales/pl.ts +1 -0
  14. package/src/components/advance-invoices/list/locales/pt.ts +1 -0
  15. package/src/components/advance-invoices/list/locales/sl.ts +1 -0
  16. package/src/components/advance-invoices/list/use-advance-invoice-download.ts +1 -12
  17. package/src/components/credit-notes/create/create-credit-note-form.tsx +116 -238
  18. package/src/components/credit-notes/list/list-table.tsx +6 -3
  19. package/src/components/credit-notes/list/use-credit-note-download.ts +1 -12
  20. package/src/components/customers/customer-autocomplete.tsx +64 -11
  21. package/src/components/customers/customer-list-table/customer-list-table.tsx +3 -2
  22. package/src/components/dashboard/collection-rate-card/collection-rate-card.tsx +9 -1
  23. package/src/components/dashboard/collection-rate-card/locales/bg.ts +3 -0
  24. package/src/components/dashboard/collection-rate-card/locales/cs.ts +3 -0
  25. package/src/components/dashboard/collection-rate-card/locales/et.ts +3 -0
  26. package/src/components/dashboard/collection-rate-card/locales/fi.ts +3 -0
  27. package/src/components/dashboard/collection-rate-card/locales/is.ts +3 -0
  28. package/src/components/dashboard/collection-rate-card/locales/nb.ts +3 -0
  29. package/src/components/dashboard/collection-rate-card/locales/sk.ts +3 -0
  30. package/src/components/dashboard/collection-rate-card/locales/sv.ts +3 -0
  31. package/src/components/dashboard/invoice-status-chart/invoice-status-chart.tsx +10 -2
  32. package/src/components/dashboard/invoice-status-chart/locales/bg.ts +10 -0
  33. package/src/components/dashboard/invoice-status-chart/locales/cs.ts +10 -0
  34. package/src/components/dashboard/invoice-status-chart/locales/de.ts +1 -0
  35. package/src/components/dashboard/invoice-status-chart/locales/es.ts +1 -0
  36. package/src/components/dashboard/invoice-status-chart/locales/et.ts +10 -0
  37. package/src/components/dashboard/invoice-status-chart/locales/fi.ts +10 -0
  38. package/src/components/dashboard/invoice-status-chart/locales/fr.ts +1 -0
  39. package/src/components/dashboard/invoice-status-chart/locales/hr.ts +1 -0
  40. package/src/components/dashboard/invoice-status-chart/locales/is.ts +10 -0
  41. package/src/components/dashboard/invoice-status-chart/locales/it.ts +1 -0
  42. package/src/components/dashboard/invoice-status-chart/locales/nb.ts +10 -0
  43. package/src/components/dashboard/invoice-status-chart/locales/nl.ts +1 -0
  44. package/src/components/dashboard/invoice-status-chart/locales/pl.ts +1 -0
  45. package/src/components/dashboard/invoice-status-chart/locales/pt.ts +1 -0
  46. package/src/components/dashboard/invoice-status-chart/locales/sk.ts +10 -0
  47. package/src/components/dashboard/invoice-status-chart/locales/sl.ts +1 -0
  48. package/src/components/dashboard/invoice-status-chart/locales/sv.ts +10 -0
  49. package/src/components/dashboard/payment-methods-chart/locales/bg.ts +12 -0
  50. package/src/components/dashboard/payment-methods-chart/locales/cs.ts +12 -0
  51. package/src/components/dashboard/payment-methods-chart/locales/et.ts +12 -0
  52. package/src/components/dashboard/payment-methods-chart/locales/fi.ts +12 -0
  53. package/src/components/dashboard/payment-methods-chart/locales/is.ts +12 -0
  54. package/src/components/dashboard/payment-methods-chart/locales/nb.ts +12 -0
  55. package/src/components/dashboard/payment-methods-chart/locales/sk.ts +12 -0
  56. package/src/components/dashboard/payment-methods-chart/locales/sv.ts +12 -0
  57. package/src/components/dashboard/payment-methods-chart/payment-methods-chart.tsx +9 -1
  58. package/src/components/dashboard/payment-trend-chart/locales/bg.ts +6 -0
  59. package/src/components/dashboard/payment-trend-chart/locales/cs.ts +6 -0
  60. package/src/components/dashboard/payment-trend-chart/locales/de.ts +1 -0
  61. package/src/components/dashboard/payment-trend-chart/locales/es.ts +1 -0
  62. package/src/components/dashboard/payment-trend-chart/locales/et.ts +6 -0
  63. package/src/components/dashboard/payment-trend-chart/locales/fi.ts +6 -0
  64. package/src/components/dashboard/payment-trend-chart/locales/fr.ts +1 -0
  65. package/src/components/dashboard/payment-trend-chart/locales/hr.ts +1 -0
  66. package/src/components/dashboard/payment-trend-chart/locales/is.ts +6 -0
  67. package/src/components/dashboard/payment-trend-chart/locales/it.ts +1 -0
  68. package/src/components/dashboard/payment-trend-chart/locales/nb.ts +6 -0
  69. package/src/components/dashboard/payment-trend-chart/locales/nl.ts +1 -0
  70. package/src/components/dashboard/payment-trend-chart/locales/pl.ts +1 -0
  71. package/src/components/dashboard/payment-trend-chart/locales/pt.ts +1 -0
  72. package/src/components/dashboard/payment-trend-chart/locales/sk.ts +6 -0
  73. package/src/components/dashboard/payment-trend-chart/locales/sl.ts +1 -0
  74. package/src/components/dashboard/payment-trend-chart/locales/sv.ts +6 -0
  75. package/src/components/dashboard/payment-trend-chart/payment-trend-chart.tsx +15 -8
  76. package/src/components/dashboard/revenue-trend-chart/locales/bg.ts +6 -0
  77. package/src/components/dashboard/revenue-trend-chart/locales/cs.ts +6 -0
  78. package/src/components/dashboard/revenue-trend-chart/locales/de.ts +1 -0
  79. package/src/components/dashboard/revenue-trend-chart/locales/es.ts +1 -0
  80. package/src/components/dashboard/revenue-trend-chart/locales/et.ts +6 -0
  81. package/src/components/dashboard/revenue-trend-chart/locales/fi.ts +6 -0
  82. package/src/components/dashboard/revenue-trend-chart/locales/fr.ts +1 -0
  83. package/src/components/dashboard/revenue-trend-chart/locales/hr.ts +1 -0
  84. package/src/components/dashboard/revenue-trend-chart/locales/is.ts +6 -0
  85. package/src/components/dashboard/revenue-trend-chart/locales/it.ts +1 -0
  86. package/src/components/dashboard/revenue-trend-chart/locales/nb.ts +6 -0
  87. package/src/components/dashboard/revenue-trend-chart/locales/nl.ts +1 -0
  88. package/src/components/dashboard/revenue-trend-chart/locales/pl.ts +1 -0
  89. package/src/components/dashboard/revenue-trend-chart/locales/pt.ts +1 -0
  90. package/src/components/dashboard/revenue-trend-chart/locales/sk.ts +6 -0
  91. package/src/components/dashboard/revenue-trend-chart/locales/sl.ts +1 -0
  92. package/src/components/dashboard/revenue-trend-chart/locales/sv.ts +6 -0
  93. package/src/components/dashboard/revenue-trend-chart/revenue-trend-chart.tsx +15 -8
  94. package/src/components/dashboard/tax-collected-card/locales.ts +110 -0
  95. package/src/components/dashboard/tax-collected-card/tax-collected-card.tsx +8 -2
  96. package/src/components/dashboard/tax-collected-card/use-tax-collected.ts +4 -4
  97. package/src/components/dashboard/top-customers-chart/locales/bg.ts +7 -0
  98. package/src/components/dashboard/top-customers-chart/locales/cs.ts +7 -0
  99. package/src/components/dashboard/top-customers-chart/locales/de.ts +2 -0
  100. package/src/components/dashboard/top-customers-chart/locales/es.ts +2 -0
  101. package/src/components/dashboard/top-customers-chart/locales/et.ts +7 -0
  102. package/src/components/dashboard/top-customers-chart/locales/fi.ts +7 -0
  103. package/src/components/dashboard/top-customers-chart/locales/fr.ts +2 -0
  104. package/src/components/dashboard/top-customers-chart/locales/hr.ts +2 -0
  105. package/src/components/dashboard/top-customers-chart/locales/is.ts +7 -0
  106. package/src/components/dashboard/top-customers-chart/locales/it.ts +2 -0
  107. package/src/components/dashboard/top-customers-chart/locales/nb.ts +7 -0
  108. package/src/components/dashboard/top-customers-chart/locales/nl.ts +2 -0
  109. package/src/components/dashboard/top-customers-chart/locales/pl.ts +2 -0
  110. package/src/components/dashboard/top-customers-chart/locales/pt.ts +2 -0
  111. package/src/components/dashboard/top-customers-chart/locales/sk.ts +7 -0
  112. package/src/components/dashboard/top-customers-chart/locales/sl.ts +2 -0
  113. package/src/components/dashboard/top-customers-chart/locales/sv.ts +7 -0
  114. package/src/components/dashboard/top-customers-chart/top-customers-chart.tsx +23 -12
  115. package/src/components/delivery-notes/create/create-delivery-note-form.tsx +33 -20
  116. package/src/components/delivery-notes/list/list-table.tsx +22 -13
  117. package/src/components/delivery-notes/list/locales/de.ts +2 -0
  118. package/src/components/delivery-notes/list/locales/en.ts +1 -0
  119. package/src/components/delivery-notes/list/locales/es.ts +1 -0
  120. package/src/components/delivery-notes/list/locales/fr.ts +1 -0
  121. package/src/components/delivery-notes/list/locales/hr.ts +1 -0
  122. package/src/components/delivery-notes/list/locales/it.ts +1 -0
  123. package/src/components/delivery-notes/list/locales/nl.ts +1 -0
  124. package/src/components/delivery-notes/list/locales/pl.ts +1 -0
  125. package/src/components/delivery-notes/list/locales/pt.ts +1 -0
  126. package/src/components/delivery-notes/list/locales/sl.ts +1 -0
  127. package/src/components/delivery-notes/list/use-delivery-note-download.ts +1 -12
  128. package/src/components/documents/create/document-add-item-form.tsx +28 -16
  129. package/src/components/documents/create/document-add-item-tax-rate-field.tsx +12 -2
  130. package/src/components/documents/create/document-items-section.tsx +70 -39
  131. package/src/components/documents/create/document-recipient-section.tsx +10 -1
  132. package/src/components/documents/create/live-preview.tsx +113 -15
  133. package/src/components/documents/create/prepare-document-submission.ts +35 -16
  134. package/src/components/documents/create/use-document-customer-form.ts +14 -3
  135. package/src/components/documents/documents.hooks.ts +7 -2
  136. package/src/components/documents/shared/document-preview-display.tsx +136 -67
  137. package/src/components/documents/shared/scaled-document-preview.tsx +45 -5
  138. package/src/components/documents/view/document-actions-bar.tsx +284 -182
  139. package/src/components/documents/view/document-activities-list.tsx +3 -0
  140. package/src/components/documents/view/document-payments-list.tsx +3 -0
  141. package/src/components/documents/view/locales/de.ts +8 -0
  142. package/src/components/documents/view/locales/es.ts +8 -0
  143. package/src/components/documents/view/locales/fr.ts +8 -0
  144. package/src/components/documents/view/locales/hr.ts +8 -0
  145. package/src/components/documents/view/locales/it.ts +8 -0
  146. package/src/components/documents/view/locales/nl.ts +8 -0
  147. package/src/components/documents/view/locales/pl.ts +8 -0
  148. package/src/components/documents/view/locales/pt.ts +8 -0
  149. package/src/components/documents/view/locales/sl.ts +8 -0
  150. package/src/components/documents/view/use-document-download.ts +14 -25
  151. package/src/components/entities/create-entity-form.tsx +101 -16
  152. package/src/components/entities/fina-settings-form/fina-operator-required-dialog.tsx +3 -3
  153. package/src/components/entities/fina-settings-form/fina-settings-form.tsx +78 -124
  154. package/src/components/entities/fina-settings-form/sections/certificate-settings-section.tsx +8 -1
  155. package/src/components/entities/fina-settings-form/sections/premises-management-section.tsx +14 -2
  156. package/src/components/entities/fina-settings-form/sections/register-premise-dialog.tsx +7 -2
  157. package/src/components/entities/furs-settings-form/furs-settings-form.tsx +56 -130
  158. package/src/components/entities/furs-settings-form/sections/certificate-settings-section.tsx +8 -1
  159. package/src/components/entities/furs-settings-form/sections/enable-fiscalization-section.tsx +1 -0
  160. package/src/components/entities/furs-settings-form/sections/general-settings-section.tsx +15 -2
  161. package/src/components/entities/furs-settings-form/sections/premises-management-section.tsx +20 -3
  162. package/src/components/entities/furs-settings-form/sections/register-premise-dialog.tsx +38 -12
  163. package/src/components/entities/settings/eslog-settings-form.tsx +13 -1
  164. package/src/components/entities/settings/pdf-template-selector/demo-invoice-data.ts +3 -22
  165. package/src/components/entities/shared/fiscalization-step-flow.ts +77 -0
  166. package/src/components/entities/shared/fiscalization-step-tabs.tsx +71 -0
  167. package/src/components/estimates/create/create-estimate-form.tsx +34 -21
  168. package/src/components/estimates/list/list-table.tsx +23 -14
  169. package/src/components/estimates/list/locales/de.ts +2 -0
  170. package/src/components/estimates/list/locales/en.ts +1 -0
  171. package/src/components/estimates/list/locales/es.ts +1 -0
  172. package/src/components/estimates/list/locales/fr.ts +1 -0
  173. package/src/components/estimates/list/locales/hr.ts +1 -0
  174. package/src/components/estimates/list/locales/it.ts +1 -0
  175. package/src/components/estimates/list/locales/nl.ts +1 -0
  176. package/src/components/estimates/list/locales/pl.ts +1 -0
  177. package/src/components/estimates/list/locales/pt.ts +1 -0
  178. package/src/components/estimates/list/locales/sl.ts +1 -0
  179. package/src/components/estimates/list/use-estimate-download.ts +1 -12
  180. package/src/components/export/document-export-form.tsx +33 -7
  181. package/src/components/export/sales-per-item-export-form.tsx +23 -7
  182. package/src/components/invoices/create/create-invoice-form.tsx +295 -329
  183. package/src/components/invoices/create/prepare-invoice-submission.ts +0 -8
  184. package/src/components/invoices/list/list-table.tsx +7 -4
  185. package/src/components/invoices/list/use-invoice-download.ts +1 -11
  186. package/src/components/invoices/send-email-dialog/locales/de.ts +2 -0
  187. package/src/components/invoices/send-email-dialog/locales/es.ts +2 -0
  188. package/src/components/invoices/send-email-dialog/locales/fr.ts +2 -0
  189. package/src/components/invoices/send-email-dialog/locales/hr.ts +2 -0
  190. package/src/components/invoices/send-email-dialog/locales/it.ts +2 -0
  191. package/src/components/invoices/send-email-dialog/locales/nl.ts +2 -0
  192. package/src/components/invoices/send-email-dialog/locales/pl.ts +2 -0
  193. package/src/components/invoices/send-email-dialog/locales/pt.ts +2 -0
  194. package/src/components/invoices/send-email-dialog/locales/sl.ts +2 -0
  195. package/src/components/invoices/send-email-dialog/send-email-dialog.tsx +77 -8
  196. package/src/components/invoices/view/eslog-info-display.tsx +17 -1
  197. package/src/components/invoices/view/fiscalization-status-card.tsx +7 -3
  198. package/src/components/items/item-combobox.tsx +26 -6
  199. package/src/components/items/item-list-table/item-list-table.tsx +5 -2
  200. package/src/components/payments/list/list-table.tsx +14 -4
  201. package/src/components/recurring-invoices/list/list-table.tsx +7 -4
  202. package/src/components/request-logs/locales.ts +412 -0
  203. package/src/components/request-logs/request-log-detail.tsx +37 -21
  204. package/src/components/request-logs/request-log-list-table.tsx +57 -11
  205. package/src/components/table/data-table.tsx +5 -2
  206. package/src/components/table/date-cell.tsx +3 -1
  207. package/src/components/table/filter-bar.tsx +14 -2
  208. package/src/components/table/hooks/use-table-query.ts +1 -1
  209. package/src/components/table/locales.ts +1116 -0
  210. package/src/components/table/search-input.tsx +12 -3
  211. package/src/components/table/selection-toolbar.tsx +23 -6
  212. package/src/components/table/table-empty-state.tsx +43 -3
  213. package/src/components/table/table-no-results.tsx +3 -3
  214. package/src/components/table/table-pagination.tsx +4 -3
  215. package/src/components/table/types.ts +1 -0
  216. package/src/components/tax-reports/index.ts +1 -0
  217. package/src/components/tax-reports/kir-export-form.tsx +46 -8
  218. package/src/components/tax-reports/slovenia-tax-profile-step.tsx +191 -0
  219. package/src/components/tax-reports/slovenia-yearly-export-form.tsx +509 -0
  220. package/src/components/tax-reports/slovenia-yearly-review-step.tsx +253 -0
  221. package/src/components/tax-reports/slovenia-yearly-summary.tsx +19 -0
  222. package/src/components/taxes/tax-list-table/tax-list-table.tsx +3 -2
  223. package/src/components/ui/sticky-form-footer.tsx +7 -1
  224. package/src/components/webhook-logs/index.ts +6 -0
  225. package/src/components/webhook-logs/locales.ts +392 -0
  226. package/src/components/webhook-logs/webhook-delivery-detail.tsx +255 -0
  227. package/src/components/webhook-logs/webhook-delivery-list-table.tsx +278 -0
  228. package/src/components/wl-subscription/index.ts +1 -0
  229. package/src/components/wl-subscription/locked-feature.tsx +1 -0
  230. package/src/components/wl-subscription/paywall.tsx +193 -0
  231. package/src/components/wl-subscription/upgrade-modal.tsx +93 -29
  232. package/src/generate-schemas.ts +10 -5
  233. package/src/generated/schemas/customer.ts +2 -0
  234. package/src/generated/schemas/entity.ts +34 -0
  235. package/src/generated/schemas/me.ts +20 -1
  236. package/src/generated/schemas/renderadvanceinvoicepreview_body.ts +40 -34
  237. package/src/generated/schemas/rendercreditnotepreview_body.ts +42 -36
  238. package/src/generated/schemas/renderdeliverynotepreview_body.ts +23 -13
  239. package/src/generated/schemas/renderestimatepreview_body.ts +23 -13
  240. package/src/generated/schemas/renderinvoicepreview_body.ts +40 -34
  241. package/src/generated/schemas/sendemail_body.ts +44 -0
  242. package/src/generated/schemas/startpdfexport_body.ts +91 -1
  243. package/src/generated/schemas/webhook.ts +10 -0
  244. package/src/hooks/use-duplicate-document.ts +51 -13
  245. package/src/hooks/use-eslog-validation.ts +59 -0
  246. package/src/hooks/use-premise-selection.ts +186 -0
  247. package/src/lib/browser-cookies.ts +4 -4
  248. package/src/lib/date-fns-locale.ts +48 -0
  249. package/src/lib/fiscalization-options.ts +81 -0
  250. package/src/lib/locale.ts +38 -0
  251. package/src/lib/template-variables.tsx +1 -1
  252. package/src/lib/translation.ts +14 -3
  253. package/src/providers/entities-context.tsx +1 -0
  254. package/src/providers/entities-provider.tsx +102 -3
  255. package/src/providers/form-footer-context.tsx +37 -4
  256. package/src/providers/sdk-provider.tsx +7 -2
  257. package/src/providers/white-label-provider.tsx +4 -1
  258. package/src/providers/wl-subscription-provider.tsx +90 -3
@@ -188,7 +188,14 @@ export const RegisterPremiseDialog: FC<RegisterPremiseDialogProps> = ({
188
188
  <FormItem>
189
189
  <FormLabel>{t("Cadastral Number")} *</FormLabel>
190
190
  <FormControl>
191
- <Input type="text" inputMode="numeric" pattern="[0-9]*" placeholder="123" {...field} />
191
+ <Input
192
+ type="text"
193
+ inputMode="numeric"
194
+ pattern="[0-9]*"
195
+ placeholder="123"
196
+ {...field}
197
+ data-testid="furs-real-estate-cadastral-number"
198
+ />
192
199
  </FormControl>
193
200
  <FormDescription>{t("Required by FURS (must be numeric)")}</FormDescription>
194
201
  <FormMessage />
@@ -205,7 +212,14 @@ export const RegisterPremiseDialog: FC<RegisterPremiseDialogProps> = ({
205
212
  <FormItem>
206
213
  <FormLabel>{t("Building Number")} *</FormLabel>
207
214
  <FormControl>
208
- <Input type="text" inputMode="numeric" pattern="[0-9]*" placeholder="456" {...field} />
215
+ <Input
216
+ type="text"
217
+ inputMode="numeric"
218
+ pattern="[0-9]*"
219
+ placeholder="456"
220
+ {...field}
221
+ data-testid="furs-real-estate-building-number"
222
+ />
209
223
  </FormControl>
210
224
  <FormDescription className="text-xs">{t("Numeric, use 0 if not applicable")}</FormDescription>
211
225
  <FormMessage />
@@ -219,7 +233,14 @@ export const RegisterPremiseDialog: FC<RegisterPremiseDialogProps> = ({
219
233
  <FormItem>
220
234
  <FormLabel>{t("Building Section")} *</FormLabel>
221
235
  <FormControl>
222
- <Input type="text" inputMode="numeric" pattern="[0-9]*" placeholder="1" {...field} />
236
+ <Input
237
+ type="text"
238
+ inputMode="numeric"
239
+ pattern="[0-9]*"
240
+ placeholder="1"
241
+ {...field}
242
+ data-testid="furs-real-estate-building-section"
243
+ />
223
244
  </FormControl>
224
245
  <FormDescription className="text-xs">{t("Numeric, use 0 if not applicable")}</FormDescription>
225
246
  <FormMessage />
@@ -236,7 +257,7 @@ export const RegisterPremiseDialog: FC<RegisterPremiseDialogProps> = ({
236
257
  <FormItem>
237
258
  <FormLabel>{t("Community")} *</FormLabel>
238
259
  <FormControl>
239
- <Input placeholder="Ljubljana" {...field} />
260
+ <Input placeholder="Ljubljana" {...field} data-testid="furs-real-estate-community" />
240
261
  </FormControl>
241
262
  <FormDescription>{t("Slovenian administrative community (občina) name")}</FormDescription>
242
263
  <FormMessage />
@@ -252,7 +273,7 @@ export const RegisterPremiseDialog: FC<RegisterPremiseDialogProps> = ({
252
273
  <FormItem>
253
274
  <FormLabel>{t("Street")} *</FormLabel>
254
275
  <FormControl>
255
- <Input placeholder="Dunajska cesta" {...field} />
276
+ <Input placeholder="Dunajska cesta" {...field} data-testid="furs-real-estate-street" />
256
277
  </FormControl>
257
278
  <FormMessage />
258
279
  </FormItem>
@@ -267,7 +288,7 @@ export const RegisterPremiseDialog: FC<RegisterPremiseDialogProps> = ({
267
288
  <FormItem>
268
289
  <FormLabel>{t("House Number")} *</FormLabel>
269
290
  <FormControl>
270
- <Input placeholder="22" {...field} />
291
+ <Input placeholder="22" {...field} data-testid="furs-real-estate-house-number" />
271
292
  </FormControl>
272
293
  <FormMessage />
273
294
  </FormItem>
@@ -280,7 +301,12 @@ export const RegisterPremiseDialog: FC<RegisterPremiseDialogProps> = ({
280
301
  <FormItem>
281
302
  <FormLabel>{t("Additional")}</FormLabel>
282
303
  <FormControl>
283
- <Input placeholder="A" {...field} value={field.value || ""} />
304
+ <Input
305
+ placeholder="A"
306
+ {...field}
307
+ value={field.value || ""}
308
+ data-testid="furs-real-estate-house-number-additional"
309
+ />
284
310
  </FormControl>
285
311
  <FormMessage />
286
312
  </FormItem>
@@ -296,7 +322,7 @@ export const RegisterPremiseDialog: FC<RegisterPremiseDialogProps> = ({
296
322
  <FormItem>
297
323
  <FormLabel>{t("City")} *</FormLabel>
298
324
  <FormControl>
299
- <Input placeholder="Ljubljana" {...field} />
325
+ <Input placeholder="Ljubljana" {...field} data-testid="furs-real-estate-city" />
300
326
  </FormControl>
301
327
  <FormMessage />
302
328
  </FormItem>
@@ -309,7 +335,7 @@ export const RegisterPremiseDialog: FC<RegisterPremiseDialogProps> = ({
309
335
  <FormItem>
310
336
  <FormLabel>{t("Postal Code")} *</FormLabel>
311
337
  <FormControl>
312
- <Input placeholder="1000" {...field} />
338
+ <Input placeholder="1000" {...field} data-testid="furs-real-estate-postal-code" />
313
339
  </FormControl>
314
340
  <FormDescription className="text-xs">{t("Exactly 4 digits")}</FormDescription>
315
341
  <FormMessage />
@@ -322,7 +348,7 @@ export const RegisterPremiseDialog: FC<RegisterPremiseDialogProps> = ({
322
348
  <Button type="button" variant="outline" onClick={() => onOpenChange(false)} disabled={isPending}>
323
349
  {t("Cancel")}
324
350
  </Button>
325
- <Button type="submit" disabled={isPending}>
351
+ <Button type="submit" disabled={isPending} data-testid="furs-register-premise-submit">
326
352
  {isPending ? t("Registering...") : t("Register Premise")}
327
353
  </Button>
328
354
  </DialogFooter>
@@ -345,7 +371,7 @@ export const RegisterPremiseDialog: FC<RegisterPremiseDialogProps> = ({
345
371
  <FormItem>
346
372
  <FormLabel>{t("Premise Name")}</FormLabel>
347
373
  <FormControl>
348
- <Input placeholder="P1" {...field} />
374
+ <Input placeholder="P1" {...field} data-testid="furs-movable-premise-name" />
349
375
  </FormControl>
350
376
  <FormDescription>{t("Unique identifier for this premise (e.g., P1, P2)")}</FormDescription>
351
377
  <FormMessage />
@@ -382,7 +408,7 @@ export const RegisterPremiseDialog: FC<RegisterPremiseDialogProps> = ({
382
408
  <Button type="button" variant="outline" onClick={() => onOpenChange(false)} disabled={isPending}>
383
409
  {t("Cancel")}
384
410
  </Button>
385
- <Button type="submit" disabled={isPending}>
411
+ <Button type="submit" disabled={isPending} data-testid="furs-register-premise-submit">
386
412
  {isPending ? t("Registering...") : t("Register Premise")}
387
413
  </Button>
388
414
  </DialogFooter>
@@ -16,6 +16,18 @@ const eslogSettingsSchema = z.object({
16
16
 
17
17
  type EslogSettingsSchema = z.infer<typeof eslogSettingsSchema>;
18
18
 
19
+ const translations = {
20
+ en: {
21
+ "Save Settings": "Save Settings",
22
+ "Enable e-SLOG validation": "Enable e-SLOG validation",
23
+ "When enabled, documents will be automatically validated against e-SLOG 2.0 requirements when created.":
24
+ "When enabled, documents will be automatically validated against e-SLOG 2.0 requirements when created.",
25
+ "About e-SLOG 2.0": "About e-SLOG 2.0",
26
+ "e-SLOG 2.0 is the Slovenian electronic invoice standard based on the European EN 16931 specification. Valid documents can be downloaded in XML format and attached to emails.":
27
+ "e-SLOG 2.0 is the Slovenian electronic invoice standard based on the European EN 16931 specification. Valid documents can be downloaded in XML format and attached to emails.",
28
+ },
29
+ } as const;
30
+
19
31
  export type EslogSettingsFormProps = {
20
32
  entity: Entity;
21
33
  onSuccess?: (data: Entity) => void;
@@ -30,7 +42,7 @@ export function EslogSettingsForm({
30
42
  onSuccess,
31
43
  onError,
32
44
  }: EslogSettingsFormProps) {
33
- const t = createTranslation({ t: translateProp, namespace, locale, translations: {} });
45
+ const t = createTranslation({ t: translateProp, namespace, locale, translations });
34
46
 
35
47
  const currentSettings = (entity.settings as Record<string, unknown>) || {};
36
48
 
@@ -116,12 +116,13 @@ const demoDataByLocale: Record<string, LocaleDemoData> = {
116
116
  },
117
117
  };
118
118
 
119
+ import { getFullLocale } from "@/ui/lib/locale";
120
+
119
121
  /**
120
122
  * Get demo invoice data for template preview based on locale
121
123
  */
122
124
  export function getDemoInvoiceData(locale: string): DemoInvoiceData {
123
- // Normalize locale (e.g., "en" -> "en-US", "sl" -> "sl-SI")
124
- const normalizedLocale = normalizeLocale(locale);
125
+ const normalizedLocale = getFullLocale(locale);
125
126
  const data = demoDataByLocale[normalizedLocale] || demoDataByLocale["en-US"];
126
127
 
127
128
  const today = new Date();
@@ -142,23 +143,3 @@ export function getDemoInvoiceData(locale: string): DemoInvoiceData {
142
143
  note: data.note,
143
144
  };
144
145
  }
145
-
146
- function normalizeLocale(locale: string): string {
147
- const mapping: Record<string, string> = {
148
- en: "en-US",
149
- sl: "sl-SI",
150
- de: "de-DE",
151
- fr: "fr-FR",
152
- es: "es-ES",
153
- it: "it-IT",
154
- };
155
-
156
- // If already full locale, return as-is if supported
157
- if (demoDataByLocale[locale]) {
158
- return locale;
159
- }
160
-
161
- // Try to match short code
162
- const shortCode = locale.split("-")[0].toLowerCase();
163
- return mapping[shortCode] || "en-US";
164
- }
@@ -0,0 +1,77 @@
1
+ import { useCallback, useEffect, useRef, useState } from "react";
2
+
3
+ export interface FiscalizationStepConfig<T extends string> {
4
+ id: T;
5
+ title: string;
6
+ complete: boolean;
7
+ unlocked: boolean;
8
+ }
9
+
10
+ interface UseFiscalizationStepFlowOptions<T extends string> {
11
+ initialStep: T;
12
+ isReady: boolean;
13
+ steps: FiscalizationStepConfig<T>[];
14
+ getDefaultStep: () => T;
15
+ onStepChange?: (step: T) => void;
16
+ }
17
+
18
+ export function useFiscalizationStepFlow<T extends string>({
19
+ initialStep,
20
+ isReady,
21
+ steps,
22
+ getDefaultStep,
23
+ onStepChange,
24
+ }: UseFiscalizationStepFlowOptions<T>) {
25
+ const [activeStep, setActiveStep] = useState<T>(initialStep);
26
+ const [hasInitializedStep, setHasInitializedStep] = useState(false);
27
+ const previousInitialStep = useRef(initialStep);
28
+
29
+ const handleStepChange = useCallback(
30
+ (newStep: T) => {
31
+ setActiveStep(newStep);
32
+ onStepChange?.(newStep);
33
+ },
34
+ [onStepChange],
35
+ );
36
+
37
+ // biome-ignore lint/correctness/useExhaustiveDependencies: caller controls step definitions and default-step logic
38
+ useEffect(() => {
39
+ if (!hasInitializedStep && isReady) {
40
+ const smartStep = getDefaultStep();
41
+ if (smartStep !== activeStep) {
42
+ handleStepChange(smartStep);
43
+ }
44
+ setHasInitializedStep(true);
45
+ }
46
+ }, [isReady, hasInitializedStep]);
47
+
48
+ useEffect(() => {
49
+ const currentStepInfo = steps.find((step) => step.id === activeStep);
50
+ if (currentStepInfo && !currentStepInfo.unlocked) {
51
+ const firstUnlockedStep = steps.find((step) => step.unlocked);
52
+ if (firstUnlockedStep) {
53
+ handleStepChange(firstUnlockedStep.id);
54
+ }
55
+ }
56
+ }, [activeStep, steps, handleStepChange]);
57
+
58
+ useEffect(() => {
59
+ if (!hasInitializedStep) return;
60
+
61
+ if (previousInitialStep.current === initialStep) {
62
+ return;
63
+ }
64
+
65
+ previousInitialStep.current = initialStep;
66
+
67
+ const nextStepInfo = steps.find((step) => step.id === initialStep);
68
+ if (nextStepInfo?.unlocked && initialStep !== activeStep) {
69
+ setActiveStep(initialStep);
70
+ }
71
+ }, [activeStep, hasInitializedStep, initialStep, steps]);
72
+
73
+ return {
74
+ activeStep,
75
+ handleStepChange,
76
+ };
77
+ }
@@ -0,0 +1,71 @@
1
+ import { CheckCircle2 } from "lucide-react";
2
+ import { Tabs, TabsList, TabsTrigger } from "@/ui/components/ui/tabs";
3
+ import { Tooltip, TooltipContent, TooltipTrigger } from "@/ui/components/ui/tooltip";
4
+ import { cn } from "@/ui/lib/utils";
5
+ import type { FiscalizationStepConfig } from "./fiscalization-step-flow";
6
+
7
+ interface FiscalizationStepTabsProps<T extends string> {
8
+ activeStep: T;
9
+ steps: FiscalizationStepConfig<T>[];
10
+ testIdPrefix: string;
11
+ onStepChange: (step: T) => void;
12
+ getTooltipText: (step: FiscalizationStepConfig<T>) => string;
13
+ }
14
+
15
+ export function FiscalizationStepTabs<T extends string>({
16
+ activeStep,
17
+ steps,
18
+ testIdPrefix,
19
+ onStepChange,
20
+ getTooltipText,
21
+ }: FiscalizationStepTabsProps<T>) {
22
+ return (
23
+ <div className="grid items-start gap-6 lg:grid-cols-[1fr_280px]">
24
+ <Tabs value={activeStep} onValueChange={(value) => onStepChange(value as T)} className="w-full">
25
+ <TabsList className="grid w-full grid-cols-4 rounded-none p-0">
26
+ {steps.map((step, index) => {
27
+ const isLocked = !step.unlocked;
28
+
29
+ const trigger = (
30
+ <TabsTrigger
31
+ value={step.id}
32
+ disabled={isLocked}
33
+ data-testid={`${testIdPrefix}-${step.id}`}
34
+ className={cn("cursor-pointer justify-center", !step.unlocked && "opacity-50")}
35
+ >
36
+ <span className="flex items-center gap-2">
37
+ {step.complete ? (
38
+ <CheckCircle2 className="h-4 w-4 text-green-500" />
39
+ ) : (
40
+ <span className="text-xs">{index + 1}</span>
41
+ )}
42
+ {step.title}
43
+ </span>
44
+ </TabsTrigger>
45
+ );
46
+
47
+ if (isLocked) {
48
+ return (
49
+ <Tooltip key={step.id} delayDuration={0}>
50
+ <TooltipTrigger asChild>
51
+ <span className="flex cursor-not-allowed justify-center">{trigger}</span>
52
+ </TooltipTrigger>
53
+ <TooltipContent>
54
+ <p>{getTooltipText(step)}</p>
55
+ </TooltipContent>
56
+ </Tooltip>
57
+ );
58
+ }
59
+
60
+ return (
61
+ <span key={step.id} className="flex justify-center">
62
+ {trigger}
63
+ </span>
64
+ );
65
+ })}
66
+ </TabsList>
67
+ </Tabs>
68
+ <div className="hidden lg:block" />
69
+ </div>
70
+ );
71
+ }
@@ -250,6 +250,7 @@ export default function CreateEstimateForm({
250
250
  const formValues = useWatch({
251
251
  control: form.control,
252
252
  });
253
+ const prevPayloadRef = useRef("");
253
254
 
254
255
  // ============================================================================
255
256
  // VIES Check - determine if reverse charge applies
@@ -380,37 +381,48 @@ export default function CreateEstimateForm({
380
381
  form.setValue("date_valid_till", calculateDueDate(currentDate, validDays));
381
382
  }, [formValues.date, activeEntity, form]);
382
383
 
383
- useEffect(() => {
384
- const callback = onChangeRef.current;
385
- if (!callback) return;
386
-
387
- const currentItems = form.getValues("items") || [];
384
+ const buildPreviewPayload = useCallback((values: CreateEstimateFormValues): EstimatePreviewPayload => {
385
+ const currentItems = values.items || [];
388
386
 
389
- // Transform items to use gross_price when price mode is gross
390
387
  const transformedItems = currentItems.map((item: any, index: number) => {
391
388
  const { price, ...rest } = item;
392
389
  const isGross = priceModesRef.current[index] ?? false;
393
- if (isGross) {
394
- return { ...rest, gross_price: price };
395
- }
396
- return { ...rest, price };
390
+ return isGross ? { ...rest, gross_price: price } : { ...rest, price };
397
391
  });
398
392
 
399
- const payload: EstimatePreviewPayload = {
400
- number: formValues.number,
401
- date: formValues.date,
402
- customer_id: formValues.customer_id,
403
- customer: formValues.customer,
393
+ return {
394
+ number: values.number,
395
+ date: values.date,
396
+ customer_id: values.customer_id,
397
+ customer: values.customer,
404
398
  items: transformedItems,
405
- currency_code: formValues.currency_code,
406
- reference: formValues.reference,
407
- note: formValues.note,
408
- payment_terms: formValues.payment_terms,
409
- signature: formValues.signature,
399
+ currency_code: values.currency_code,
400
+ reference: values.reference,
401
+ note: values.note,
402
+ payment_terms: values.payment_terms,
403
+ signature: values.signature,
410
404
  title_type: titleType,
411
405
  };
406
+ }, [titleType]);
407
+
408
+ const emitPreviewPayload = useCallback((payload: EstimatePreviewPayload) => {
409
+ const callback = onChangeRef.current;
410
+ if (!callback) return;
411
+
412
+ const payloadStr = JSON.stringify(payload);
413
+ if (payloadStr === prevPayloadRef.current) return;
414
+ prevPayloadRef.current = payloadStr;
415
+
412
416
  callback(payload);
413
- }, [formValues, form, titleType]);
417
+ }, []);
418
+
419
+ useEffect(() => {
420
+ emitPreviewPayload(buildPreviewPayload(formValues as CreateEstimateFormValues));
421
+ }, [buildPreviewPayload, emitPreviewPayload, formValues]);
422
+
423
+ const emitCurrentPreviewPayload = useCallback(() => {
424
+ emitPreviewPayload(buildPreviewPayload(form.getValues()));
425
+ }, [buildPreviewPayload, emitPreviewPayload, form]);
414
426
 
415
427
  const onSubmit = (values: CreateEstimateFormValues) => {
416
428
  submitEstimate(values, false);
@@ -447,6 +459,7 @@ export default function CreateEstimateForm({
447
459
  maxTaxesPerItem={activeEntity?.country_rules?.max_taxes_per_item}
448
460
  priceModesRef={priceModesRef}
449
461
  initialPriceModes={initialPriceModes}
462
+ onItemsStateChange={emitCurrentPreviewPayload}
450
463
  taxesDisabled={reverseChargeApplies}
451
464
  taxesDisabledMessage={
452
465
  reverseChargeApplies ? t("Reverse charge - tax exempt EU B2B sale") : viesWarning ? viesWarning : undefined
@@ -3,6 +3,7 @@ import { useCallback, useMemo, useState } from "react";
3
3
  import { DataTable } from "@/ui/components/table/data-table";
4
4
  import { FormattedDate } from "@/ui/components/table/date-cell";
5
5
  import { useTableFetch } from "@/ui/components/table/hooks/use-table-fetch";
6
+ import { withTableTranslations } from "@/ui/components/table/locales";
6
7
  import { SelectionToolbar } from "@/ui/components/table/selection-toolbar";
7
8
  import type {
8
9
  Column,
@@ -28,7 +29,7 @@ import pl from "./locales/pl";
28
29
  import pt from "./locales/pt";
29
30
  import sl from "./locales/sl";
30
31
 
31
- const translations = {
32
+ const translations = withTableTranslations({
32
33
  en,
33
34
  sl,
34
35
  de,
@@ -39,12 +40,13 @@ const translations = {
39
40
  nl,
40
41
  pl,
41
42
  hr,
42
- } as const;
43
+ } as const);
43
44
 
44
45
  type EstimateListTableProps = {
45
46
  t?: (key: string) => string;
46
47
  namespace?: string;
47
48
  locale?: string;
49
+ translationLocale?: string;
48
50
  entityId?: string;
49
51
  onView?: (estimate: Estimate) => void;
50
52
  onDuplicate?: (estimate: Estimate) => void;
@@ -73,6 +75,7 @@ export default function EstimateListTable({
73
75
  }: EstimateListTableProps) {
74
76
  const t = createTranslation({
75
77
  translations,
78
+ locale: i18nProps.translationLocale ?? i18nProps.locale,
76
79
  ...i18nProps,
77
80
  });
78
81
 
@@ -123,16 +126,22 @@ export default function EstimateListTable({
123
126
  }, []);
124
127
 
125
128
  const selectionToolbar = useCallback(
126
- (count: number) => (
127
- <SelectionToolbar
128
- selectedCount={count}
129
- onExportPdfs={onExportSelected ? handleExportPdfs : undefined}
130
- onCopyToInvoice={onCopyToInvoice ? handleCopyToInvoice : undefined}
131
- onDeselectAll={handleDeselectAll}
132
- t={t}
133
- />
134
- ),
135
- [handleExportPdfs, handleCopyToInvoice, handleDeselectAll, onExportSelected, onCopyToInvoice, t],
129
+ (count: number, data: Estimate[]) => {
130
+ const hasDrafts = data.some((d) => selectedIds.has(d.id) && (d as any).is_draft);
131
+
132
+ return (
133
+ <SelectionToolbar
134
+ selectedCount={count}
135
+ onExportPdfs={onExportSelected ? handleExportPdfs : undefined}
136
+ onCopyToInvoice={onCopyToInvoice ? handleCopyToInvoice : undefined}
137
+ copyToInvoiceDisabled={hasDrafts}
138
+ copyToInvoiceTooltip={hasDrafts ? t("Finalize draft documents before copying to invoice") : undefined}
139
+ onDeselectAll={handleDeselectAll}
140
+ t={t}
141
+ />
142
+ );
143
+ },
144
+ [handleExportPdfs, handleCopyToInvoice, handleDeselectAll, onExportSelected, onCopyToInvoice, selectedIds, t],
136
145
  );
137
146
 
138
147
  const columns: Column<Estimate>[] = useMemo(
@@ -164,12 +173,12 @@ export default function EstimateListTable({
164
173
  {
165
174
  id: "date",
166
175
  header: t("Date"),
167
- cell: (estimate) => <FormattedDate date={estimate.date} />,
176
+ cell: (estimate) => <FormattedDate date={estimate.date} locale={i18nProps.locale} />,
168
177
  },
169
178
  {
170
179
  id: "date_valid_till",
171
180
  header: t("Valid Until"),
172
- cell: (estimate) => <FormattedDate date={estimate.date_valid_till} />,
181
+ cell: (estimate) => <FormattedDate date={estimate.date_valid_till} locale={i18nProps.locale} />,
173
182
  },
174
183
  {
175
184
  id: "total",
@@ -37,4 +37,6 @@ export default {
37
37
  "Export PDFs": "PDFs exportieren",
38
38
  "Deselect all": "Auswahl aufheben",
39
39
  "Copy to Invoice": "In Rechnung kopieren",
40
+ "Finalize draft documents before copying to invoice":
41
+ "Entwurfsdokumente abschließen, bevor Sie in eine Rechnung kopieren",
40
42
  } as const;
@@ -9,4 +9,5 @@ export default {
9
9
  "Export PDFs": "Export PDFs",
10
10
  "Deselect all": "Deselect all",
11
11
  "Copy to Invoice": "Copy to Invoice",
12
+ "Finalize draft documents before copying to invoice": "Finalize draft documents before copying to invoice",
12
13
  } as const;
@@ -34,4 +34,5 @@ export default {
34
34
  "Export PDFs": "Exportar PDFs",
35
35
  "Deselect all": "Deseleccionar todo",
36
36
  "Copy to Invoice": "Copiar a factura",
37
+ "Finalize draft documents before copying to invoice": "Finalice los borradores antes de copiar a factura",
37
38
  } as const;
@@ -34,4 +34,5 @@ export default {
34
34
  "Export PDFs": "Exporter les PDF",
35
35
  "Deselect all": "Tout désélectionner",
36
36
  "Copy to Invoice": "Copier vers facture",
37
+ "Finalize draft documents before copying to invoice": "Finalisez les brouillons avant de copier en facture",
37
38
  } as const;
@@ -34,4 +34,5 @@ export default {
34
34
  "Export PDFs": "Izvezi PDF-ove",
35
35
  "Deselect all": "Poništi odabir",
36
36
  "Copy to Invoice": "Kopiraj u račun",
37
+ "Finalize draft documents before copying to invoice": "Dovršite skice dokumenata prije kopiranja u račun",
37
38
  } as const;
@@ -34,4 +34,5 @@ export default {
34
34
  "Export PDFs": "Esporta PDF",
35
35
  "Deselect all": "Deseleziona tutto",
36
36
  "Copy to Invoice": "Copia in fattura",
37
+ "Finalize draft documents before copying to invoice": "Finalizzare i documenti bozza prima di copiare in fattura",
37
38
  } as const;
@@ -34,4 +34,5 @@ export default {
34
34
  "Export PDFs": "PDFs exporteren",
35
35
  "Deselect all": "Alles deselecteren",
36
36
  "Copy to Invoice": "Kopieer naar factuur",
37
+ "Finalize draft documents before copying to invoice": "Rond conceptdocumenten af voordat u naar factuur kopieert",
37
38
  } as const;
@@ -34,4 +34,5 @@ export default {
34
34
  "Export PDFs": "Eksportuj PDF-y",
35
35
  "Deselect all": "Odznacz wszystko",
36
36
  "Copy to Invoice": "Kopiuj do faktury",
37
+ "Finalize draft documents before copying to invoice": "Sfinalizuj wersje robocze przed skopiowaniem do faktury",
37
38
  } as const;
@@ -34,4 +34,5 @@ export default {
34
34
  "Export PDFs": "Exportar PDFs",
35
35
  "Deselect all": "Desselecionar tudo",
36
36
  "Copy to Invoice": "Copiar para fatura",
37
+ "Finalize draft documents before copying to invoice": "Finalize os rascunhos antes de copiar para fatura",
37
38
  } as const;
@@ -37,4 +37,5 @@ export default {
37
37
  "Export PDFs": "Izvozi PDF-je",
38
38
  "Deselect all": "Počisti izbiro",
39
39
  "Copy to Invoice": "Kopiraj v račun",
40
+ "Finalize draft documents before copying to invoice": "Dokončajte osnutke dokumentov pred kopiranjem v račun",
40
41
  } as const;
@@ -33,19 +33,8 @@ export function useEstimateDownload({
33
33
  onDownloadStart?.();
34
34
 
35
35
  try {
36
- // SDK signature: renderPdf(id, params?, SDKMethodOptions?)
37
- // entity_id goes in SDKMethodOptions (last arg), not params
38
- // Note: renderPdf is on invoices module but works with any document ID
39
- const blob = await sdk.invoices.renderPdf(estimate.id, {}, { entity_id: activeEntity.id });
40
- const downloadUrl = window.URL.createObjectURL(blob);
41
- const link = document.createElement("a");
42
- link.href = downloadUrl;
43
36
  const fileName = `${t("Estimate")} ${estimate.number}.pdf`;
44
- link.download = fileName;
45
- document.body.appendChild(link);
46
- link.click();
47
- document.body.removeChild(link);
48
- window.URL.revokeObjectURL(downloadUrl);
37
+ await sdk.invoices.downloadPdf(estimate.id, fileName, {}, { entity_id: activeEntity.id });
49
38
 
50
39
  onDownloadSuccess?.(fileName);
51
40
  } catch (error) {