@spaceinvoices/react-ui 0.4.8 → 0.4.11

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 (276) hide show
  1. package/README.md +24 -8
  2. package/cli/dist/index.js +89 -26
  3. package/package.json +4 -1
  4. package/spaceinvoices.schema.json +6 -1
  5. package/src/common/autocomplete.tsx +69 -6
  6. package/src/components/advance-invoices/create/create-advance-invoice-form.tsx +124 -285
  7. package/src/components/advance-invoices/list/list-table.tsx +10 -3
  8. package/src/components/advance-invoices/list/locales/de.ts +2 -0
  9. package/src/components/advance-invoices/list/locales/en.ts +1 -0
  10. package/src/components/advance-invoices/list/locales/es.ts +1 -0
  11. package/src/components/advance-invoices/list/locales/fr.ts +1 -0
  12. package/src/components/advance-invoices/list/locales/hr.ts +1 -0
  13. package/src/components/advance-invoices/list/locales/it.ts +1 -0
  14. package/src/components/advance-invoices/list/locales/nl.ts +1 -0
  15. package/src/components/advance-invoices/list/locales/pl.ts +1 -0
  16. package/src/components/advance-invoices/list/locales/pt.ts +1 -0
  17. package/src/components/advance-invoices/list/locales/sl.ts +1 -0
  18. package/src/components/advance-invoices/list/use-advance-invoice-download.ts +1 -12
  19. package/src/components/credit-notes/create/create-credit-note-form.tsx +116 -238
  20. package/src/components/credit-notes/list/list-table.tsx +6 -3
  21. package/src/components/credit-notes/list/use-credit-note-download.ts +1 -12
  22. package/src/components/customers/customer-autocomplete.tsx +64 -11
  23. package/src/components/customers/customer-list-table/customer-list-table.tsx +3 -2
  24. package/src/components/dashboard/collection-rate-card/collection-rate-card.tsx +9 -1
  25. package/src/components/dashboard/collection-rate-card/locales/bg.ts +3 -0
  26. package/src/components/dashboard/collection-rate-card/locales/cs.ts +3 -0
  27. package/src/components/dashboard/collection-rate-card/locales/et.ts +3 -0
  28. package/src/components/dashboard/collection-rate-card/locales/fi.ts +3 -0
  29. package/src/components/dashboard/collection-rate-card/locales/is.ts +3 -0
  30. package/src/components/dashboard/collection-rate-card/locales/nb.ts +3 -0
  31. package/src/components/dashboard/collection-rate-card/locales/sk.ts +3 -0
  32. package/src/components/dashboard/collection-rate-card/locales/sv.ts +3 -0
  33. package/src/components/dashboard/invoice-status-chart/invoice-status-chart.tsx +10 -2
  34. package/src/components/dashboard/invoice-status-chart/locales/bg.ts +10 -0
  35. package/src/components/dashboard/invoice-status-chart/locales/cs.ts +10 -0
  36. package/src/components/dashboard/invoice-status-chart/locales/de.ts +1 -0
  37. package/src/components/dashboard/invoice-status-chart/locales/es.ts +1 -0
  38. package/src/components/dashboard/invoice-status-chart/locales/et.ts +10 -0
  39. package/src/components/dashboard/invoice-status-chart/locales/fi.ts +10 -0
  40. package/src/components/dashboard/invoice-status-chart/locales/fr.ts +1 -0
  41. package/src/components/dashboard/invoice-status-chart/locales/hr.ts +1 -0
  42. package/src/components/dashboard/invoice-status-chart/locales/is.ts +10 -0
  43. package/src/components/dashboard/invoice-status-chart/locales/it.ts +1 -0
  44. package/src/components/dashboard/invoice-status-chart/locales/nb.ts +10 -0
  45. package/src/components/dashboard/invoice-status-chart/locales/nl.ts +1 -0
  46. package/src/components/dashboard/invoice-status-chart/locales/pl.ts +1 -0
  47. package/src/components/dashboard/invoice-status-chart/locales/pt.ts +1 -0
  48. package/src/components/dashboard/invoice-status-chart/locales/sk.ts +10 -0
  49. package/src/components/dashboard/invoice-status-chart/locales/sl.ts +1 -0
  50. package/src/components/dashboard/invoice-status-chart/locales/sv.ts +10 -0
  51. package/src/components/dashboard/payment-methods-chart/locales/bg.ts +12 -0
  52. package/src/components/dashboard/payment-methods-chart/locales/cs.ts +12 -0
  53. package/src/components/dashboard/payment-methods-chart/locales/et.ts +12 -0
  54. package/src/components/dashboard/payment-methods-chart/locales/fi.ts +12 -0
  55. package/src/components/dashboard/payment-methods-chart/locales/is.ts +12 -0
  56. package/src/components/dashboard/payment-methods-chart/locales/nb.ts +12 -0
  57. package/src/components/dashboard/payment-methods-chart/locales/sk.ts +12 -0
  58. package/src/components/dashboard/payment-methods-chart/locales/sv.ts +12 -0
  59. package/src/components/dashboard/payment-methods-chart/payment-methods-chart.tsx +9 -1
  60. package/src/components/dashboard/payment-trend-chart/locales/bg.ts +6 -0
  61. package/src/components/dashboard/payment-trend-chart/locales/cs.ts +6 -0
  62. package/src/components/dashboard/payment-trend-chart/locales/de.ts +1 -0
  63. package/src/components/dashboard/payment-trend-chart/locales/es.ts +1 -0
  64. package/src/components/dashboard/payment-trend-chart/locales/et.ts +6 -0
  65. package/src/components/dashboard/payment-trend-chart/locales/fi.ts +6 -0
  66. package/src/components/dashboard/payment-trend-chart/locales/fr.ts +1 -0
  67. package/src/components/dashboard/payment-trend-chart/locales/hr.ts +1 -0
  68. package/src/components/dashboard/payment-trend-chart/locales/is.ts +6 -0
  69. package/src/components/dashboard/payment-trend-chart/locales/it.ts +1 -0
  70. package/src/components/dashboard/payment-trend-chart/locales/nb.ts +6 -0
  71. package/src/components/dashboard/payment-trend-chart/locales/nl.ts +1 -0
  72. package/src/components/dashboard/payment-trend-chart/locales/pl.ts +1 -0
  73. package/src/components/dashboard/payment-trend-chart/locales/pt.ts +1 -0
  74. package/src/components/dashboard/payment-trend-chart/locales/sk.ts +6 -0
  75. package/src/components/dashboard/payment-trend-chart/locales/sl.ts +1 -0
  76. package/src/components/dashboard/payment-trend-chart/locales/sv.ts +6 -0
  77. package/src/components/dashboard/payment-trend-chart/payment-trend-chart.tsx +15 -8
  78. package/src/components/dashboard/revenue-trend-chart/locales/bg.ts +6 -0
  79. package/src/components/dashboard/revenue-trend-chart/locales/cs.ts +6 -0
  80. package/src/components/dashboard/revenue-trend-chart/locales/de.ts +1 -0
  81. package/src/components/dashboard/revenue-trend-chart/locales/es.ts +1 -0
  82. package/src/components/dashboard/revenue-trend-chart/locales/et.ts +6 -0
  83. package/src/components/dashboard/revenue-trend-chart/locales/fi.ts +6 -0
  84. package/src/components/dashboard/revenue-trend-chart/locales/fr.ts +1 -0
  85. package/src/components/dashboard/revenue-trend-chart/locales/hr.ts +1 -0
  86. package/src/components/dashboard/revenue-trend-chart/locales/is.ts +6 -0
  87. package/src/components/dashboard/revenue-trend-chart/locales/it.ts +1 -0
  88. package/src/components/dashboard/revenue-trend-chart/locales/nb.ts +6 -0
  89. package/src/components/dashboard/revenue-trend-chart/locales/nl.ts +1 -0
  90. package/src/components/dashboard/revenue-trend-chart/locales/pl.ts +1 -0
  91. package/src/components/dashboard/revenue-trend-chart/locales/pt.ts +1 -0
  92. package/src/components/dashboard/revenue-trend-chart/locales/sk.ts +6 -0
  93. package/src/components/dashboard/revenue-trend-chart/locales/sl.ts +1 -0
  94. package/src/components/dashboard/revenue-trend-chart/locales/sv.ts +6 -0
  95. package/src/components/dashboard/revenue-trend-chart/revenue-trend-chart.tsx +15 -8
  96. package/src/components/dashboard/tax-collected-card/locales.ts +110 -0
  97. package/src/components/dashboard/tax-collected-card/tax-collected-card.tsx +8 -2
  98. package/src/components/dashboard/tax-collected-card/use-tax-collected.ts +4 -4
  99. package/src/components/dashboard/top-customers-chart/locales/bg.ts +7 -0
  100. package/src/components/dashboard/top-customers-chart/locales/cs.ts +7 -0
  101. package/src/components/dashboard/top-customers-chart/locales/de.ts +2 -0
  102. package/src/components/dashboard/top-customers-chart/locales/es.ts +2 -0
  103. package/src/components/dashboard/top-customers-chart/locales/et.ts +7 -0
  104. package/src/components/dashboard/top-customers-chart/locales/fi.ts +7 -0
  105. package/src/components/dashboard/top-customers-chart/locales/fr.ts +2 -0
  106. package/src/components/dashboard/top-customers-chart/locales/hr.ts +2 -0
  107. package/src/components/dashboard/top-customers-chart/locales/is.ts +7 -0
  108. package/src/components/dashboard/top-customers-chart/locales/it.ts +2 -0
  109. package/src/components/dashboard/top-customers-chart/locales/nb.ts +7 -0
  110. package/src/components/dashboard/top-customers-chart/locales/nl.ts +2 -0
  111. package/src/components/dashboard/top-customers-chart/locales/pl.ts +2 -0
  112. package/src/components/dashboard/top-customers-chart/locales/pt.ts +2 -0
  113. package/src/components/dashboard/top-customers-chart/locales/sk.ts +7 -0
  114. package/src/components/dashboard/top-customers-chart/locales/sl.ts +2 -0
  115. package/src/components/dashboard/top-customers-chart/locales/sv.ts +7 -0
  116. package/src/components/dashboard/top-customers-chart/top-customers-chart.tsx +23 -12
  117. package/src/components/delivery-notes/create/create-delivery-note-form.tsx +33 -20
  118. package/src/components/delivery-notes/list/list-table.tsx +22 -13
  119. package/src/components/delivery-notes/list/locales/de.ts +2 -0
  120. package/src/components/delivery-notes/list/locales/en.ts +1 -0
  121. package/src/components/delivery-notes/list/locales/es.ts +1 -0
  122. package/src/components/delivery-notes/list/locales/fr.ts +1 -0
  123. package/src/components/delivery-notes/list/locales/hr.ts +1 -0
  124. package/src/components/delivery-notes/list/locales/it.ts +1 -0
  125. package/src/components/delivery-notes/list/locales/nl.ts +1 -0
  126. package/src/components/delivery-notes/list/locales/pl.ts +1 -0
  127. package/src/components/delivery-notes/list/locales/pt.ts +1 -0
  128. package/src/components/delivery-notes/list/locales/sl.ts +1 -0
  129. package/src/components/delivery-notes/list/use-delivery-note-download.ts +1 -12
  130. package/src/components/documents/create/document-add-item-form.tsx +28 -16
  131. package/src/components/documents/create/document-add-item-tax-rate-field.tsx +12 -2
  132. package/src/components/documents/create/document-items-section.tsx +70 -39
  133. package/src/components/documents/create/document-recipient-section.tsx +10 -1
  134. package/src/components/documents/create/live-preview.tsx +113 -15
  135. package/src/components/documents/create/prepare-document-submission.ts +35 -16
  136. package/src/components/documents/create/use-document-customer-form.ts +14 -3
  137. package/src/components/documents/documents.hooks.ts +7 -2
  138. package/src/components/documents/shared/document-preview-display.tsx +136 -67
  139. package/src/components/documents/shared/scaled-document-preview.tsx +45 -5
  140. package/src/components/documents/view/document-actions-bar.tsx +284 -182
  141. package/src/components/documents/view/document-activities-list.tsx +3 -0
  142. package/src/components/documents/view/document-payments-list.tsx +3 -0
  143. package/src/components/documents/view/locales/de.ts +8 -0
  144. package/src/components/documents/view/locales/es.ts +8 -0
  145. package/src/components/documents/view/locales/fr.ts +8 -0
  146. package/src/components/documents/view/locales/hr.ts +8 -0
  147. package/src/components/documents/view/locales/it.ts +8 -0
  148. package/src/components/documents/view/locales/nl.ts +8 -0
  149. package/src/components/documents/view/locales/pl.ts +8 -0
  150. package/src/components/documents/view/locales/pt.ts +8 -0
  151. package/src/components/documents/view/locales/sl.ts +8 -0
  152. package/src/components/documents/view/use-document-download.ts +14 -25
  153. package/src/components/entities/create-entity-form.tsx +101 -16
  154. package/src/components/entities/entity-settings-form/entity-settings-form.tsx +10 -10
  155. package/src/components/entities/entity-settings-form/locales/de.ts +10 -0
  156. package/src/components/entities/entity-settings-form/locales/es.ts +10 -0
  157. package/src/components/entities/entity-settings-form/locales/fr.ts +10 -0
  158. package/src/components/entities/entity-settings-form/locales/hr.ts +10 -0
  159. package/src/components/entities/entity-settings-form/locales/it.ts +10 -0
  160. package/src/components/entities/entity-settings-form/locales/nl.ts +10 -0
  161. package/src/components/entities/entity-settings-form/locales/pl.ts +10 -0
  162. package/src/components/entities/entity-settings-form/locales/pt.ts +10 -0
  163. package/src/components/entities/entity-settings-form/locales/sl.ts +10 -0
  164. package/src/components/entities/fina-settings-form/fina-operator-required-dialog.tsx +3 -3
  165. package/src/components/entities/fina-settings-form/fina-settings-form.tsx +78 -124
  166. package/src/components/entities/fina-settings-form/sections/certificate-settings-section.tsx +8 -1
  167. package/src/components/entities/fina-settings-form/sections/premises-management-section.tsx +14 -2
  168. package/src/components/entities/fina-settings-form/sections/register-premise-dialog.tsx +7 -2
  169. package/src/components/entities/furs-settings-form/furs-settings-form.tsx +56 -130
  170. package/src/components/entities/furs-settings-form/sections/certificate-settings-section.tsx +8 -1
  171. package/src/components/entities/furs-settings-form/sections/enable-fiscalization-section.tsx +1 -0
  172. package/src/components/entities/furs-settings-form/sections/general-settings-section.tsx +15 -2
  173. package/src/components/entities/furs-settings-form/sections/premises-management-section.tsx +20 -3
  174. package/src/components/entities/furs-settings-form/sections/register-premise-dialog.tsx +38 -12
  175. package/src/components/entities/settings/defaults-settings-form.tsx +6 -6
  176. package/src/components/entities/settings/eslog-settings-form.tsx +13 -1
  177. package/src/components/entities/settings/pdf-template-selector/demo-invoice-data.ts +3 -22
  178. package/src/components/entities/shared/fiscalization-step-flow.ts +77 -0
  179. package/src/components/entities/shared/fiscalization-step-tabs.tsx +71 -0
  180. package/src/components/estimates/create/create-estimate-form.tsx +34 -21
  181. package/src/components/estimates/list/list-table.tsx +23 -14
  182. package/src/components/estimates/list/locales/de.ts +2 -0
  183. package/src/components/estimates/list/locales/en.ts +1 -0
  184. package/src/components/estimates/list/locales/es.ts +1 -0
  185. package/src/components/estimates/list/locales/fr.ts +1 -0
  186. package/src/components/estimates/list/locales/hr.ts +1 -0
  187. package/src/components/estimates/list/locales/it.ts +1 -0
  188. package/src/components/estimates/list/locales/nl.ts +1 -0
  189. package/src/components/estimates/list/locales/pl.ts +1 -0
  190. package/src/components/estimates/list/locales/pt.ts +1 -0
  191. package/src/components/estimates/list/locales/sl.ts +1 -0
  192. package/src/components/estimates/list/use-estimate-download.ts +1 -12
  193. package/src/components/export/document-export-form.tsx +33 -7
  194. package/src/components/export/sales-per-item-export-form.tsx +23 -7
  195. package/src/components/invoices/create/create-invoice-form.tsx +295 -329
  196. package/src/components/invoices/create/prepare-invoice-submission.ts +0 -8
  197. package/src/components/invoices/list/list-table.tsx +7 -4
  198. package/src/components/invoices/list/use-invoice-download.ts +1 -11
  199. package/src/components/invoices/send-email-dialog/locales/de.ts +20 -0
  200. package/src/components/invoices/send-email-dialog/locales/es.ts +20 -0
  201. package/src/components/invoices/send-email-dialog/locales/fr.ts +20 -0
  202. package/src/components/invoices/send-email-dialog/locales/hr.ts +20 -0
  203. package/src/components/invoices/send-email-dialog/locales/it.ts +20 -0
  204. package/src/components/invoices/send-email-dialog/locales/nl.ts +20 -0
  205. package/src/components/invoices/send-email-dialog/locales/pl.ts +20 -0
  206. package/src/components/invoices/send-email-dialog/locales/pt.ts +20 -0
  207. package/src/components/invoices/send-email-dialog/locales/sl.ts +20 -0
  208. package/src/components/invoices/send-email-dialog/send-email-dialog.tsx +77 -8
  209. package/src/components/invoices/view/eslog-info-display.tsx +17 -1
  210. package/src/components/invoices/view/fiscalization-status-card.tsx +7 -3
  211. package/src/components/items/item-combobox.tsx +26 -6
  212. package/src/components/items/item-list-table/item-list-table.tsx +5 -2
  213. package/src/components/payments/create-payment-form/index.ts +1 -0
  214. package/src/components/payments/list/list-table.tsx +14 -4
  215. package/src/components/recurring-invoices/list/list-table.tsx +7 -4
  216. package/src/components/request-logs/locales.ts +412 -0
  217. package/src/components/request-logs/request-log-detail.tsx +37 -21
  218. package/src/components/request-logs/request-log-list-table.tsx +57 -11
  219. package/src/components/table/data-table.tsx +5 -2
  220. package/src/components/table/date-cell.tsx +3 -1
  221. package/src/components/table/filter-bar.tsx +14 -2
  222. package/src/components/table/hooks/use-table-query.ts +1 -1
  223. package/src/components/table/locales.ts +1116 -0
  224. package/src/components/table/search-input.tsx +12 -3
  225. package/src/components/table/selection-toolbar.tsx +23 -6
  226. package/src/components/table/table-empty-state.tsx +43 -3
  227. package/src/components/table/table-no-results.tsx +3 -3
  228. package/src/components/table/table-pagination.tsx +4 -3
  229. package/src/components/table/types.ts +1 -0
  230. package/src/components/tax-reports/index.ts +1 -0
  231. package/src/components/tax-reports/kir-export-form.tsx +46 -8
  232. package/src/components/tax-reports/slovenia-tax-profile-step.tsx +191 -0
  233. package/src/components/tax-reports/slovenia-yearly-export-form.tsx +509 -0
  234. package/src/components/tax-reports/slovenia-yearly-review-step.tsx +253 -0
  235. package/src/components/tax-reports/slovenia-yearly-summary.tsx +19 -0
  236. package/src/components/taxes/tax-list-table/tax-list-table.tsx +3 -2
  237. package/src/components/ui/sidebar.tsx +3 -2
  238. package/src/components/ui/sticky-form-footer.tsx +7 -1
  239. package/src/components/webhook-logs/index.ts +6 -0
  240. package/src/components/webhook-logs/locales.ts +392 -0
  241. package/src/components/webhook-logs/webhook-delivery-detail.tsx +255 -0
  242. package/src/components/webhook-logs/webhook-delivery-list-table.tsx +278 -0
  243. package/src/components/wl-subscription/index.ts +1 -0
  244. package/src/components/wl-subscription/locked-feature.tsx +1 -0
  245. package/src/components/wl-subscription/paywall.tsx +193 -0
  246. package/src/components/wl-subscription/upgrade-modal.tsx +93 -29
  247. package/src/generate-schemas.ts +12 -7
  248. package/src/generated/schemas/customer.ts +2 -0
  249. package/src/generated/schemas/entity.ts +134 -0
  250. package/src/generated/schemas/exportsloveniayearlynormiranireport_body.ts +27 -0
  251. package/src/generated/schemas/index.ts +2 -0
  252. package/src/generated/schemas/me.ts +20 -1
  253. package/src/generated/schemas/renderadvanceinvoicepreview_body.ts +40 -34
  254. package/src/generated/schemas/rendercreditnotepreview_body.ts +42 -36
  255. package/src/generated/schemas/renderdeliverynotepreview_body.ts +23 -13
  256. package/src/generated/schemas/renderestimatepreview_body.ts +23 -13
  257. package/src/generated/schemas/renderinvoicepreview_body.ts +40 -34
  258. package/src/generated/schemas/sendemail_body.ts +44 -0
  259. package/src/generated/schemas/sloveniataxprofile.ts +42 -0
  260. package/src/generated/schemas/startpdfexport_body.ts +91 -1
  261. package/src/generated/schemas/webhook.ts +10 -0
  262. package/src/hooks/use-duplicate-document.ts +51 -13
  263. package/src/hooks/use-eslog-validation.ts +59 -0
  264. package/src/hooks/use-premise-selection.ts +186 -0
  265. package/src/lib/browser-cookies.ts +4 -4
  266. package/src/lib/date-fns-locale.ts +48 -0
  267. package/src/lib/fiscalization-options.ts +81 -0
  268. package/src/lib/locale.ts +38 -0
  269. package/src/lib/template-variables.tsx +1 -1
  270. package/src/lib/translation.ts +14 -3
  271. package/src/providers/entities-context.tsx +1 -0
  272. package/src/providers/entities-provider.tsx +102 -3
  273. package/src/providers/form-footer-context.tsx +37 -4
  274. package/src/providers/sdk-provider.tsx +7 -2
  275. package/src/providers/white-label-provider.tsx +4 -1
  276. package/src/providers/wl-subscription-provider.tsx +90 -3
@@ -1,5 +1,5 @@
1
1
  import { AlertCircle, AlertTriangle, Building2, CheckCircle2, ChevronRight, Info, User } from "lucide-react";
2
- import { type FC, type ReactNode, useCallback, useEffect, useState } from "react";
2
+ import { type FC, type ReactNode, useEffect, useState } from "react";
3
3
  import { useUpdateEntity } from "@/ui/components/entities/entities.hooks";
4
4
  import { Alert, AlertDescription, AlertTitle } from "@/ui/components/ui/alert";
5
5
  import { Button } from "@/ui/components/ui/button";
@@ -9,11 +9,11 @@ import { PageLoadingSpinner } from "@/ui/components/ui/loading-spinner";
9
9
  import { RadioGroup, RadioGroupItem } from "@/ui/components/ui/radio-group";
10
10
  import { Separator } from "@/ui/components/ui/separator";
11
11
  import { Switch } from "@/ui/components/ui/switch";
12
- import { Tabs, TabsList, TabsTrigger } from "@/ui/components/ui/tabs";
13
- import { Tooltip, TooltipContent, TooltipTrigger } from "@/ui/components/ui/tooltip";
14
12
  import type { ComponentTranslationProps } from "@/ui/lib/translation";
15
13
  import { createTranslation } from "@/ui/lib/translation";
16
14
  import { cn } from "@/ui/lib/utils";
15
+ import { type FiscalizationStepConfig, useFiscalizationStepFlow } from "../shared/fiscalization-step-flow";
16
+ import { FiscalizationStepTabs } from "../shared/fiscalization-step-tabs";
17
17
  import {
18
18
  useFinaPremises,
19
19
  useFinaSettings,
@@ -82,9 +82,6 @@ export const FinaSettingsForm: FC<FinaSettingsFormProps> = ({
82
82
  renderSection,
83
83
  hideUserOperatorSection,
84
84
  }) => {
85
- const [activeStep, setActiveStep] = useState<FinaStepType>(initialStep);
86
- const [hasInitializedStep, setHasInitializedStep] = useState(false);
87
-
88
85
  const translate = createTranslation({
89
86
  t: translateFn,
90
87
  namespace,
@@ -92,14 +89,6 @@ export const FinaSettingsForm: FC<FinaSettingsFormProps> = ({
92
89
  translations,
93
90
  });
94
91
 
95
- const handleStepChange = useCallback(
96
- (newStep: FinaStepType) => {
97
- setActiveStep(newStep);
98
- onStepChange?.(newStep);
99
- },
100
- [onStepChange],
101
- );
102
-
103
92
  // Entity info state
104
93
  const [entityTaxNumber, setEntityTaxNumber] = useState("");
105
94
  const [entityAddress, setEntityAddress] = useState("");
@@ -201,10 +190,9 @@ export const FinaSettingsForm: FC<FinaSettingsFormProps> = ({
201
190
  // Determine completion status
202
191
  const hasEntityTaxNumber = !!entity.tax_number;
203
192
  // Operator OIB is required by CIS protocol (minOccurs="1" in FiskalizacijaSchema.xsd)
204
- // Can come from user settings or entity-level FINA settings
205
- const hasOperatorSettings =
206
- (!!userFinaSettings?.operator_oib && !!userFinaSettings?.operator_label) ||
207
- (!!finaSettings?.operator_oib && !!finaSettings?.operator_label);
193
+ // Can come from user settings or entity-level FINA settings.
194
+ // operator_label is optional metadata and must not block setup.
195
+ const hasOperatorSettings = !!userFinaSettings?.operator_oib || !!finaSettings?.operator_oib;
208
196
  const hasCertificate = finaSettings?.has_certificate || false;
209
197
  const certificateValid = finaSettings?.certificate_status === "valid";
210
198
  const hasPremises = (premises?.length || 0) > 0;
@@ -217,7 +205,7 @@ export const FinaSettingsForm: FC<FinaSettingsFormProps> = ({
217
205
  const canAccessEnable =
218
206
  hasEntityTaxNumber && hasOperatorSettings && certificateValid && hasPremises && hasPremiseWithDevice;
219
207
 
220
- const steps = [
208
+ const steps: FiscalizationStepConfig<FinaStepType>[] = [
221
209
  {
222
210
  id: "settings" as const,
223
211
  title: translate("General Settings"),
@@ -233,14 +221,14 @@ export const FinaSettingsForm: FC<FinaSettingsFormProps> = ({
233
221
  {
234
222
  id: "premises" as const,
235
223
  title: translate("Business Premises"),
236
- complete: !!hasPremiseWithDevice,
237
- unlocked: canAccessPremises,
224
+ complete: Boolean(hasPremiseWithDevice),
225
+ unlocked: Boolean(canAccessPremises),
238
226
  },
239
227
  {
240
228
  id: "enable" as const,
241
229
  title: translate("Enable Fiscalization"),
242
- complete: finaEnabled,
243
- unlocked: canAccessEnable,
230
+ complete: Boolean(finaEnabled),
231
+ unlocked: Boolean(canAccessEnable),
244
232
  },
245
233
  ];
246
234
 
@@ -255,27 +243,13 @@ export const FinaSettingsForm: FC<FinaSettingsFormProps> = ({
255
243
  return "settings";
256
244
  };
257
245
 
258
- // biome-ignore lint/correctness/useExhaustiveDependencies: Intentionally run only when data loads
259
- useEffect(() => {
260
- if (!hasInitializedStep && !settingsLoading && !premisesLoading) {
261
- const smartStep = getDefaultStep();
262
- if (smartStep !== activeStep) {
263
- handleStepChange(smartStep);
264
- }
265
- setHasInitializedStep(true);
266
- }
267
- }, [settingsLoading, premisesLoading, hasInitializedStep]);
268
-
269
- // biome-ignore lint/correctness/useExhaustiveDependencies: steps is recreated on each render but values are stable
270
- useEffect(() => {
271
- const currentStepInfo = steps.find((s) => s.id === activeStep);
272
- if (currentStepInfo && !currentStepInfo.unlocked) {
273
- const firstUnlockedStep = steps.find((s) => s.unlocked);
274
- if (firstUnlockedStep) {
275
- handleStepChange(firstUnlockedStep.id);
276
- }
277
- }
278
- }, [activeStep, handleStepChange]);
246
+ const { activeStep, handleStepChange } = useFiscalizationStepFlow({
247
+ initialStep,
248
+ isReady: !settingsLoading && !premisesLoading,
249
+ steps,
250
+ getDefaultStep,
251
+ onStepChange,
252
+ });
279
253
 
280
254
  if (entity.country_code !== "HR") {
281
255
  return (
@@ -322,82 +296,39 @@ export const FinaSettingsForm: FC<FinaSettingsFormProps> = ({
322
296
  return content;
323
297
  };
324
298
 
325
- const tabsNavigation = (
326
- <div className="grid items-start gap-6 lg:grid-cols-[1fr_280px]">
327
- <Tabs value={activeStep} onValueChange={(value) => handleStepChange(value as FinaStepType)} className="w-full">
328
- <TabsList className="grid w-full grid-cols-4 rounded-none p-0">
329
- {steps.map((step, index) => {
330
- const isLocked = !step.unlocked;
331
- let tooltipText = "";
332
- if (isLocked) {
333
- if (step.id === "certificate") {
334
- if (!hasEntityTaxNumber) {
335
- tooltipText = translate("Set entity OIB in General Settings first");
336
- } else {
337
- tooltipText = translate("Set operator OIB and label in General Settings first");
338
- }
339
- } else if (step.id === "premises") {
340
- if (!hasEntityTaxNumber) {
341
- tooltipText = translate("Set entity OIB in General Settings first");
342
- } else if (!hasOperatorSettings) {
343
- tooltipText = translate("Set operator OIB and label in General Settings first");
344
- } else {
345
- tooltipText = translate("Upload and validate digital certificate first");
346
- }
347
- } else if (step.id === "enable") {
348
- if (!hasEntityTaxNumber || !hasOperatorSettings) {
349
- tooltipText = translate("Complete General Settings first");
350
- } else if (!certificateValid) {
351
- tooltipText = translate("Upload and validate digital certificate first");
352
- } else if (!hasPremises) {
353
- tooltipText = translate("Register at least one business premise first");
354
- } else {
355
- tooltipText = translate("Register at least one electronic device first");
356
- }
357
- }
358
- }
359
-
360
- const trigger = (
361
- <TabsTrigger
362
- value={step.id}
363
- disabled={isLocked}
364
- className={cn("cursor-pointer justify-center", !step.unlocked && "opacity-50")}
365
- >
366
- <span className="flex items-center gap-2">
367
- {step.complete ? (
368
- <CheckCircle2 className="h-4 w-4 text-green-500" />
369
- ) : (
370
- <span className="text-xs">{index + 1}</span>
371
- )}
372
- {step.title}
373
- </span>
374
- </TabsTrigger>
375
- );
376
-
377
- if (isLocked) {
378
- return (
379
- <Tooltip key={step.id} delayDuration={0}>
380
- <TooltipTrigger asChild>
381
- <span className="flex cursor-not-allowed justify-center">{trigger}</span>
382
- </TooltipTrigger>
383
- <TooltipContent>
384
- <p>{tooltipText}</p>
385
- </TooltipContent>
386
- </Tooltip>
387
- );
388
- }
389
-
390
- return (
391
- <span key={step.id} className="flex justify-center">
392
- {trigger}
393
- </span>
394
- );
395
- })}
396
- </TabsList>
397
- </Tabs>
398
- <div className="hidden lg:block" />
399
- </div>
400
- );
299
+ const getStepTooltipText = (step: (typeof steps)[number]) => {
300
+ if (step.id === "certificate") {
301
+ if (!hasEntityTaxNumber) {
302
+ return translate("Set entity OIB in General Settings first");
303
+ }
304
+ return translate("Set operator OIB in General Settings first");
305
+ }
306
+
307
+ if (step.id === "premises") {
308
+ if (!hasEntityTaxNumber) {
309
+ return translate("Set entity OIB in General Settings first");
310
+ }
311
+ if (!hasOperatorSettings) {
312
+ return translate("Set operator OIB in General Settings first");
313
+ }
314
+ return translate("Upload and validate digital certificate first");
315
+ }
316
+
317
+ if (step.id === "enable") {
318
+ if (!hasEntityTaxNumber || !hasOperatorSettings) {
319
+ return translate("Complete General Settings first");
320
+ }
321
+ if (!certificateValid) {
322
+ return translate("Upload and validate digital certificate first");
323
+ }
324
+ if (!hasPremises) {
325
+ return translate("Register at least one business premise first");
326
+ }
327
+ return translate("Register at least one electronic device first");
328
+ }
329
+
330
+ return "";
331
+ };
401
332
 
402
333
  return (
403
334
  <div className="space-y-6">
@@ -416,7 +347,13 @@ export const FinaSettingsForm: FC<FinaSettingsFormProps> = ({
416
347
  </div>
417
348
  )}
418
349
 
419
- {tabsNavigation}
350
+ <FiscalizationStepTabs
351
+ activeStep={activeStep}
352
+ steps={steps}
353
+ onStepChange={handleStepChange}
354
+ getTooltipText={getStepTooltipText}
355
+ testIdPrefix="fina-tab"
356
+ />
420
357
 
421
358
  {/* Settings step */}
422
359
  {activeStep === "settings" && (
@@ -503,6 +440,7 @@ export const FinaSettingsForm: FC<FinaSettingsFormProps> = ({
503
440
  onClick={handleSaveEntityInfo}
504
441
  disabled={isEntityUpdatePending}
505
442
  className="cursor-pointer"
443
+ data-testid="fina-entity-info-save"
506
444
  >
507
445
  {isEntityUpdatePending ? translate("Saving...") : translate("Save Entity Info")}
508
446
  </Button>
@@ -568,7 +506,11 @@ export const FinaSettingsForm: FC<FinaSettingsFormProps> = ({
568
506
  )}
569
507
 
570
508
  <div className="grid items-start gap-6 lg:grid-cols-[1fr_280px]">
571
- <Button onClick={handleSaveSettings} disabled={isPending || !!operatorOibError}>
509
+ <Button
510
+ onClick={handleSaveSettings}
511
+ disabled={isPending || !!operatorOibError}
512
+ data-testid="fina-settings-save"
513
+ >
572
514
  {isPending ? translate("Saving...") : translate("Save Settings")}
573
515
  </Button>
574
516
  <div className="hidden lg:block" />
@@ -594,7 +536,7 @@ export const FinaSettingsForm: FC<FinaSettingsFormProps> = ({
594
536
  </div>
595
537
  </div>
596
538
 
597
- {(!userFinaSettings?.operator_oib || !userFinaSettings?.operator_label) && (
539
+ {!userFinaSettings?.operator_oib && (
598
540
  <Alert variant="destructive">
599
541
  <AlertTriangle className="h-4 w-4" />
600
542
  <AlertDescription>
@@ -617,6 +559,7 @@ export const FinaSettingsForm: FC<FinaSettingsFormProps> = ({
617
559
  className={cn("mt-1", userOperatorOibError && "border-destructive")}
618
560
  maxLength={11}
619
561
  disabled={userSettingsLoading}
562
+ data-testid="fina-user-operator-oib-input"
620
563
  />
621
564
  {userOperatorOibError && <p className="mt-1 text-destructive text-xs">{userOperatorOibError}</p>}
622
565
  </div>
@@ -629,6 +572,7 @@ export const FinaSettingsForm: FC<FinaSettingsFormProps> = ({
629
572
  placeholder={translate("e.g. Cashier 1")}
630
573
  className="mt-1"
631
574
  disabled={userSettingsLoading}
575
+ data-testid="fina-user-operator-label-input"
632
576
  />
633
577
  </div>
634
578
 
@@ -637,6 +581,7 @@ export const FinaSettingsForm: FC<FinaSettingsFormProps> = ({
637
581
  onClick={handleSaveUserSettings}
638
582
  disabled={isUserSettingsPending || userSettingsLoading || !!userOperatorOibError}
639
583
  className="cursor-pointer"
584
+ data-testid="fina-operator-settings-save"
640
585
  >
641
586
  {isUserSettingsPending ? translate("Saving...") : translate("Save Operator Settings")}
642
587
  </Button>
@@ -656,6 +601,7 @@ export const FinaSettingsForm: FC<FinaSettingsFormProps> = ({
656
601
  type="button"
657
602
  onClick={() => setIsAdvancedOpen(!isAdvancedOpen)}
658
603
  className="flex w-full items-center gap-2 py-2 text-muted-foreground hover:text-foreground"
604
+ data-testid="fina-advanced-toggle"
659
605
  >
660
606
  <ChevronRight className={cn("h-4 w-4 transition-transform", isAdvancedOpen && "rotate-90")} />
661
607
  <span className="font-medium text-sm">{translate("Advanced Settings")}</span>
@@ -683,6 +629,7 @@ export const FinaSettingsForm: FC<FinaSettingsFormProps> = ({
683
629
  placeholder={translate("OIB of the operator (11 digits)")}
684
630
  className={cn("mt-1", operatorOibError && "border-destructive")}
685
631
  maxLength={11}
632
+ data-testid="fina-api-operator-oib-input"
686
633
  />
687
634
  {operatorOibError && <p className="mt-1 text-destructive text-xs">{operatorOibError}</p>}
688
635
  <p className="mt-1 text-muted-foreground text-xs">
@@ -697,6 +644,7 @@ export const FinaSettingsForm: FC<FinaSettingsFormProps> = ({
697
644
  onChange={(e) => setFormData((prev) => ({ ...prev, operator_label: e.target.value }))}
698
645
  placeholder="API Default"
699
646
  className="mt-1"
647
+ data-testid="fina-api-operator-label-input"
700
648
  />
701
649
  <p className="mt-1 text-muted-foreground text-xs">
702
650
  {translate("Operator label for API key usage (optional)")}
@@ -704,7 +652,12 @@ export const FinaSettingsForm: FC<FinaSettingsFormProps> = ({
704
652
  </div>
705
653
  </div>
706
654
 
707
- <Button onClick={handleSaveSettings} disabled={isPending || !!operatorOibError} size="sm">
655
+ <Button
656
+ onClick={handleSaveSettings}
657
+ disabled={isPending || !!operatorOibError}
658
+ size="sm"
659
+ data-testid="fina-advanced-settings-save"
660
+ >
708
661
  {isPending ? translate("Saving...") : translate("Save Settings")}
709
662
  </Button>
710
663
  </div>
@@ -791,6 +744,7 @@ export const FinaSettingsForm: FC<FinaSettingsFormProps> = ({
791
744
  : { enabled: false },
792
745
  });
793
746
  }}
747
+ data-testid="fina-enable-switch"
794
748
  />
795
749
  <Label>{translate("Enable FINA Fiscalization")}</Label>
796
750
  </div>
@@ -145,7 +145,11 @@ export const CertificateSettingsSection: FC<CertificateSettingsSectionProps> = (
145
145
  <div className="space-y-6">
146
146
  {hasCertificate && (
147
147
  <div className="space-y-4">
148
- <Alert variant={currentStatus.variant}>
148
+ <Alert
149
+ variant={currentStatus.variant}
150
+ data-testid="fina-certificate-status"
151
+ data-status={finaSettings?.certificate_status || "unknown"}
152
+ >
149
153
  <StatusIcon className={cn("h-4 w-4", currentStatus.iconColor)} />
150
154
  <AlertTitle>Certificate Status: {currentStatus.label}</AlertTitle>
151
155
  <AlertDescription className="space-y-2">
@@ -193,6 +197,7 @@ export const CertificateSettingsSection: FC<CertificateSettingsSectionProps> = (
193
197
  onChange={handleFileChange}
194
198
  disabled={isPending}
195
199
  className="flex-1"
200
+ data-testid="fina-certificate-file-input"
196
201
  />
197
202
  {certificateFile && <CheckCircle2 className="h-5 w-5 text-green-500" />}
198
203
  </div>
@@ -212,6 +217,7 @@ export const CertificateSettingsSection: FC<CertificateSettingsSectionProps> = (
212
217
  onChange={(e) => setPassphrase(e.target.value)}
213
218
  disabled={isPending}
214
219
  placeholder={t("Enter certificate passphrase")}
220
+ data-testid="fina-certificate-passphrase-input"
215
221
  />
216
222
  </div>
217
223
 
@@ -236,6 +242,7 @@ export const CertificateSettingsSection: FC<CertificateSettingsSectionProps> = (
236
242
  onClick={handleUpload}
237
243
  disabled={!certificateFile || !passphrase || isPending}
238
244
  className={cn(hasCertificate && showUploadForm ? "flex-1" : "w-full", "cursor-pointer")}
245
+ data-testid="fina-certificate-upload-submit"
239
246
  >
240
247
  <Upload className="mr-2 h-4 w-4" />
241
248
  {isPending ? t("Loading...") : hasCertificate ? t("Upload New Certificate") : t("Upload Certificate")}
@@ -151,7 +151,12 @@ export const PremisesManagementSection: FC<PremisesManagementSectionProps> = ({
151
151
  </Alert>
152
152
 
153
153
  {/* Add Premise Button */}
154
- <Button onClick={() => setRegisterDialogOpen(true)} variant="default" className="cursor-pointer">
154
+ <Button
155
+ onClick={() => setRegisterDialogOpen(true)}
156
+ variant="default"
157
+ className="cursor-pointer"
158
+ data-testid="fina-add-premise"
159
+ >
155
160
  <Building2 className="mr-2 h-4 w-4" />
156
161
  {t("Add Premise")}
157
162
  </Button>
@@ -189,7 +194,11 @@ export const PremisesManagementSection: FC<PremisesManagementSectionProps> = ({
189
194
  </Button>
190
195
  </DropdownMenuTrigger>
191
196
  <DropdownMenuContent align="end">
192
- <DropdownMenuItem onClick={() => handleAddDevice(premise.id)} className="cursor-pointer">
197
+ <DropdownMenuItem
198
+ onClick={() => handleAddDevice(premise.id)}
199
+ className="cursor-pointer"
200
+ data-testid={`fina-add-device-${premise.business_premise_name}`}
201
+ >
193
202
  <Cpu className="mr-2 h-4 w-4" />
194
203
  {t("Add Electronic Device")}
195
204
  </DropdownMenuItem>
@@ -245,6 +254,7 @@ export const PremisesManagementSection: FC<PremisesManagementSectionProps> = ({
245
254
  variant="outline"
246
255
  onClick={() => handleAddDevice(premise.id)}
247
256
  className="cursor-pointer"
257
+ data-testid={`fina-add-device-${premise.business_premise_name}`}
248
258
  >
249
259
  <Cpu className="mr-2 h-4 w-4" />
250
260
  {t("Add Electronic Device")}
@@ -307,6 +317,7 @@ export const PremisesManagementSection: FC<PremisesManagementSectionProps> = ({
307
317
  handleRegisterDevice();
308
318
  }
309
319
  }}
320
+ data-testid="fina-device-id-input"
310
321
  />
311
322
  </div>
312
323
  </div>
@@ -324,6 +335,7 @@ export const PremisesManagementSection: FC<PremisesManagementSectionProps> = ({
324
335
  onClick={handleRegisterDevice}
325
336
  disabled={!deviceId.trim() || isRegisteringDevice}
326
337
  className="cursor-pointer"
338
+ data-testid="fina-register-device-submit"
327
339
  >
328
340
  {isRegisteringDevice ? t("Registering...") : t("Register Device")}
329
341
  </Button>
@@ -93,7 +93,7 @@ export const RegisterFinaPremiseDialog: FC<RegisterFinaPremiseDialogProps> = ({
93
93
  <FormItem>
94
94
  <FormLabel>{t("Premise ID")}</FormLabel>
95
95
  <FormControl>
96
- <Input placeholder="PP1" {...field} />
96
+ <Input placeholder="PP1" {...field} data-testid="fina-premise-name-input" />
97
97
  </FormControl>
98
98
  <FormDescription>{t("Unique identifier for this premise (e.g., PP1, OFFICE1)")}</FormDescription>
99
99
  <FormMessage />
@@ -111,7 +111,12 @@ export const RegisterFinaPremiseDialog: FC<RegisterFinaPremiseDialogProps> = ({
111
111
  >
112
112
  {t("Cancel")}
113
113
  </Button>
114
- <Button type="submit" disabled={isPending} className="cursor-pointer">
114
+ <Button
115
+ type="submit"
116
+ disabled={isPending}
117
+ className="cursor-pointer"
118
+ data-testid="fina-register-premise-submit"
119
+ >
115
120
  {isPending ? t("Adding...") : t("Add Premise")}
116
121
  </Button>
117
122
  </DialogFooter>