@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
@@ -0,0 +1,186 @@
1
+ /**
2
+ * Shared hook for FURS/FINA premise and device selection.
3
+ *
4
+ * Encapsulates the premise/device loading, localStorage persistence,
5
+ * auto-selection, and readiness logic duplicated across invoice,
6
+ * credit note, and advance invoice create forms.
7
+ */
8
+
9
+ import { useEffect, useMemo, useState } from "react";
10
+
11
+ import { useFinaPremises, useFinaSettings } from "../components/entities/fina-settings-form/fina-settings.hooks";
12
+ import { useFursPremises, useFursSettings } from "../components/entities/furs-settings-form/furs-settings.hooks";
13
+ import {
14
+ type FinaCombo,
15
+ type FursCombo,
16
+ getLastUsedFinaCombo,
17
+ getLastUsedFursCombo,
18
+ setLastUsedFinaCombo,
19
+ setLastUsedFursCombo,
20
+ } from "../components/invoices/invoices.hooks";
21
+
22
+ /** Minimal premise shape needed by the hook */
23
+ type Premise = {
24
+ id: string;
25
+ business_premise_name: string;
26
+ is_active?: boolean;
27
+ Devices?: Array<{
28
+ electronic_device_name: string;
29
+ is_active?: boolean;
30
+ }>;
31
+ };
32
+
33
+ export type PremiseSelectionResult = {
34
+ /** Whether the fiscalization system is enabled in settings */
35
+ isEnabled: boolean;
36
+ /** Raw settings object (for form-specific logic like unified_numbering) */
37
+ settings: any;
38
+ /** Whether settings/premises are still loading */
39
+ isLoading: boolean;
40
+ /** Active (non-archived) premises */
41
+ activePremises: Premise[];
42
+ /** Whether there are any active premises */
43
+ hasPremises: boolean;
44
+ /** Active devices for the currently selected premise */
45
+ activeDevices: Array<{ electronic_device_name: string; is_active?: boolean }>;
46
+ /** Currently selected premise name */
47
+ selectedPremiseName: string | undefined;
48
+ /** Currently selected device name */
49
+ selectedDeviceName: string | undefined;
50
+ /** Update selected premise */
51
+ setSelectedPremiseName: (name: string | undefined) => void;
52
+ /** Update selected device */
53
+ setSelectedDeviceName: (name: string | undefined) => void;
54
+ /** True when disabled OR both premise+device are selected */
55
+ isSelectionReady: boolean;
56
+ /** True when enabled, has premises, and both are selected */
57
+ isActive: boolean;
58
+ /** Save current combo to localStorage (call on successful submission) */
59
+ saveCombo: () => void;
60
+ };
61
+
62
+ export function usePremiseSelection(opts: {
63
+ entityId: string;
64
+ type: "furs" | "fina";
65
+ enabled?: boolean;
66
+ }): PremiseSelectionResult {
67
+ const { entityId, type } = opts;
68
+ const externalEnabled = opts.enabled !== false;
69
+
70
+ // --- FURS hooks (only called when type is furs) ---
71
+ const { data: fursSettings, isLoading: isFursSettingsLoading } = useFursSettings(entityId, {
72
+ enabled: type === "furs" && externalEnabled,
73
+ });
74
+ const { data: fursPremises, isLoading: isFursPremisesLoading } = useFursPremises(entityId, {
75
+ enabled: type === "furs" && externalEnabled && fursSettings?.enabled === true,
76
+ });
77
+
78
+ // --- FINA hooks (only called when type is fina) ---
79
+ const { data: finaSettings, isLoading: isFinaSettingsLoading } = useFinaSettings(entityId, {
80
+ enabled: type === "fina" && externalEnabled,
81
+ });
82
+ const { data: finaPremises, isLoading: isFinaPremisesLoading } = useFinaPremises(entityId, {
83
+ enabled: type === "fina" && externalEnabled && finaSettings?.enabled === true,
84
+ });
85
+
86
+ // Unified values
87
+ const settings = type === "furs" ? fursSettings : finaSettings;
88
+ const premises = type === "furs" ? fursPremises : finaPremises;
89
+ const isSettingsLoading = type === "furs" ? isFursSettingsLoading : isFinaSettingsLoading;
90
+ const isPremisesLoading = type === "furs" ? isFursPremisesLoading : isFinaPremisesLoading;
91
+
92
+ const isEnabled = settings?.enabled === true;
93
+ const isLoading = isSettingsLoading || (isEnabled && isPremisesLoading);
94
+
95
+ const activePremises = useMemo(() => (premises?.filter((p: any) => p.is_active) as Premise[]) || [], [premises]);
96
+ const hasPremises = activePremises.length > 0;
97
+
98
+ // Selection state
99
+ const [selectedPremiseName, setSelectedPremiseName] = useState<string | undefined>();
100
+ const [selectedDeviceName, setSelectedDeviceName] = useState<string | undefined>();
101
+
102
+ // Active devices for selected premise
103
+ const activeDevices = useMemo(() => {
104
+ if (!selectedPremiseName) return [];
105
+ const premise = activePremises.find((p) => p.business_premise_name === selectedPremiseName);
106
+ const devices = premise?.Devices?.filter((d) => d.is_active) || [];
107
+ // For FURS, exclude the legacy "OLD" device
108
+ return type === "furs" ? devices.filter((d) => d.electronic_device_name !== "OLD") : devices;
109
+ }, [activePremises, selectedPremiseName, type]);
110
+
111
+ // Initialize selection from localStorage or first active combo
112
+ useEffect(() => {
113
+ if (!isEnabled || !hasPremises || selectedPremiseName) return;
114
+
115
+ const lastUsed = type === "furs" ? getLastUsedFursCombo(entityId) : getLastUsedFinaCombo(entityId);
116
+
117
+ if (lastUsed) {
118
+ const premise = activePremises.find((p) => p.business_premise_name === lastUsed.business_premise_name);
119
+ const device = premise?.Devices?.find(
120
+ (d) => d.electronic_device_name === lastUsed.electronic_device_name && d.is_active,
121
+ );
122
+ if (premise && device) {
123
+ setSelectedPremiseName(lastUsed.business_premise_name);
124
+ setSelectedDeviceName(lastUsed.electronic_device_name);
125
+ return;
126
+ }
127
+ }
128
+
129
+ // Fall back to first active premise/device
130
+ const firstPremise = activePremises[0];
131
+ const firstDevice = firstPremise?.Devices?.find((d) => d.is_active);
132
+ if (firstPremise && firstDevice) {
133
+ setSelectedPremiseName(firstPremise.business_premise_name);
134
+ setSelectedDeviceName(firstDevice.electronic_device_name);
135
+ }
136
+ }, [isEnabled, hasPremises, activePremises, entityId, selectedPremiseName, type]);
137
+
138
+ // When premise changes, auto-select first active device if current is invalid
139
+ useEffect(() => {
140
+ if (!selectedPremiseName) return;
141
+ const premise = activePremises.find((p) => p.business_premise_name === selectedPremiseName);
142
+ const devicesForPremise =
143
+ type === "furs"
144
+ ? premise?.Devices?.filter((d) => d.is_active && d.electronic_device_name !== "OLD")
145
+ : premise?.Devices?.filter((d) => d.is_active);
146
+ const firstDevice = devicesForPremise?.[0];
147
+ if (firstDevice && selectedDeviceName !== firstDevice.electronic_device_name) {
148
+ const currentDeviceInPremise = devicesForPremise?.find((d) => d.electronic_device_name === selectedDeviceName);
149
+ if (!currentDeviceInPremise) {
150
+ setSelectedDeviceName(firstDevice.electronic_device_name);
151
+ }
152
+ }
153
+ }, [selectedPremiseName, activePremises, selectedDeviceName, type]);
154
+
155
+ const isSelectionReady = !isEnabled || !hasPremises || (!!selectedPremiseName && !!selectedDeviceName);
156
+ const isActive = !!(isEnabled && hasPremises && selectedPremiseName && selectedDeviceName);
157
+
158
+ const saveCombo = () => {
159
+ if (!isActive || !selectedPremiseName || !selectedDeviceName) return;
160
+ const combo: FursCombo | FinaCombo = {
161
+ business_premise_name: selectedPremiseName,
162
+ electronic_device_name: selectedDeviceName,
163
+ };
164
+ if (type === "furs") {
165
+ setLastUsedFursCombo(entityId, combo);
166
+ } else {
167
+ setLastUsedFinaCombo(entityId, combo);
168
+ }
169
+ };
170
+
171
+ return {
172
+ isEnabled,
173
+ settings,
174
+ isLoading: !!isLoading,
175
+ activePremises,
176
+ hasPremises,
177
+ activeDevices,
178
+ selectedPremiseName,
179
+ selectedDeviceName,
180
+ setSelectedPremiseName,
181
+ setSelectedDeviceName,
182
+ isSelectionReady,
183
+ isActive,
184
+ saveCombo,
185
+ };
186
+ }
@@ -16,7 +16,7 @@ type CookieOptions = {
16
16
  * Sets a cookie with the given name, value, and options
17
17
  */
18
18
  export function setCookie(name: string, value: string, options: CookieOptions = {}) {
19
- if (typeof window === "undefined") {
19
+ if (typeof document === "undefined") {
20
20
  console.warn("setCookie called on server");
21
21
  return;
22
22
  }
@@ -41,7 +41,7 @@ export function setCookie(name: string, value: string, options: CookieOptions =
41
41
  * Gets a cookie value by name
42
42
  */
43
43
  export function getCookie(name: string): string | undefined {
44
- if (typeof window === "undefined") {
44
+ if (typeof document === "undefined") {
45
45
  return undefined;
46
46
  }
47
47
 
@@ -52,7 +52,7 @@ export function getCookie(name: string): string | undefined {
52
52
  * Removes a cookie by name, clearing both host-only and domain-scoped versions
53
53
  */
54
54
  export function deleteCookie(name: string, path = "/") {
55
- if (typeof window === "undefined") {
55
+ if (typeof document === "undefined") {
56
56
  console.warn("deleteCookie called on server");
57
57
  return;
58
58
  }
@@ -64,7 +64,7 @@ export function deleteCookie(name: string, path = "/") {
64
64
  });
65
65
 
66
66
  // Also delete domain cookie (e.g. .spaceinvoices.com) if on spaceinvoices.com
67
- const hostname = window.location.hostname;
67
+ const hostname = typeof window !== "undefined" ? window.location.hostname : globalThis.location?.hostname ?? "";
68
68
  if (hostname === "spaceinvoices.com" || hostname.endsWith(".spaceinvoices.com")) {
69
69
  setCookie(name, "", {
70
70
  path,
@@ -0,0 +1,48 @@
1
+ import type { Locale } from "date-fns";
2
+ import {
3
+ bg,
4
+ cs,
5
+ de,
6
+ enUS,
7
+ es,
8
+ et,
9
+ fi,
10
+ fr,
11
+ hr,
12
+ is,
13
+ it,
14
+ nb,
15
+ nl,
16
+ pl,
17
+ pt,
18
+ sk,
19
+ sl,
20
+ sv,
21
+ } from "date-fns/locale";
22
+ import { getLocaleLanguage } from "./locale";
23
+
24
+ const DATE_FNS_LOCALES: Record<string, Locale> = {
25
+ bg,
26
+ cs,
27
+ de,
28
+ en: enUS,
29
+ es,
30
+ et,
31
+ fi,
32
+ fr,
33
+ hr,
34
+ is,
35
+ it,
36
+ nb,
37
+ nl,
38
+ pl,
39
+ pt,
40
+ sk,
41
+ sl,
42
+ sv,
43
+ };
44
+
45
+ export function getDateFnsLocale(locale?: string): Locale {
46
+ const language = getLocaleLanguage(locale);
47
+ return DATE_FNS_LOCALES[language ?? ""] ?? enUS;
48
+ }
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Pure functions for building FURS/FINA/eSLOG submission options.
3
+ *
4
+ * Extracted from the submit callbacks of invoice, credit note,
5
+ * and advance invoice forms where this logic was duplicated.
6
+ */
7
+
8
+ export type FursSubmitOptions = { skip: true } | { business_premise_name: string; electronic_device_name: string };
9
+
10
+ export type FinaSubmitOptions = {
11
+ business_premise_name: string;
12
+ electronic_device_name: string;
13
+ payment_type: string;
14
+ };
15
+
16
+ export type EslogSubmitOptions = {
17
+ validation_enabled: boolean;
18
+ };
19
+
20
+ /**
21
+ * Build FURS fiscalization options for document submission.
22
+ *
23
+ * Returns undefined when FURS should not be included (drafts, disabled, edit mode).
24
+ */
25
+ export function buildFursOptions(opts: {
26
+ isDraft: boolean;
27
+ isEnabled: boolean;
28
+ isEditMode?: boolean;
29
+ skipFiscalization?: boolean;
30
+ premiseName?: string;
31
+ deviceName?: string;
32
+ }): FursSubmitOptions | undefined {
33
+ if (opts.isDraft || opts.isEditMode || !opts.isEnabled) return undefined;
34
+ if (opts.skipFiscalization) return { skip: true };
35
+ if (opts.premiseName && opts.deviceName) {
36
+ return {
37
+ business_premise_name: opts.premiseName,
38
+ electronic_device_name: opts.deviceName,
39
+ };
40
+ }
41
+ return undefined;
42
+ }
43
+
44
+ /**
45
+ * Build FINA fiscalization options for document submission.
46
+ *
47
+ * Returns undefined when FINA should not be included (drafts, numbering disabled).
48
+ */
49
+ export function buildFinaOptions(opts: {
50
+ isDraft: boolean;
51
+ useFinaNumbering: boolean;
52
+ isEditMode?: boolean;
53
+ premiseName?: string;
54
+ deviceName?: string;
55
+ paymentType?: string;
56
+ }): FinaSubmitOptions | undefined {
57
+ if (opts.isDraft || opts.isEditMode || !opts.useFinaNumbering) return undefined;
58
+ if (opts.premiseName && opts.deviceName) {
59
+ return {
60
+ business_premise_name: opts.premiseName,
61
+ electronic_device_name: opts.deviceName,
62
+ payment_type: opts.paymentType || "bank_transfer",
63
+ };
64
+ }
65
+ return undefined;
66
+ }
67
+
68
+ /**
69
+ * Build eSLOG validation options for document submission.
70
+ *
71
+ * Returns undefined when eSLOG should not be included (drafts, edit mode, unavailable).
72
+ */
73
+ export function buildEslogOptions(opts: {
74
+ isDraft: boolean;
75
+ isEditMode?: boolean;
76
+ isAvailable: boolean;
77
+ isEnabled: boolean | undefined;
78
+ }): EslogSubmitOptions | undefined {
79
+ if (opts.isDraft || opts.isEditMode || !opts.isAvailable) return undefined;
80
+ return { validation_enabled: opts.isEnabled === true };
81
+ }
@@ -0,0 +1,38 @@
1
+ export function normalizeLocale(locale?: string, fallback = "en"): string {
2
+ return locale?.trim().toLowerCase().replace(/_/g, "-") || fallback;
3
+ }
4
+
5
+ export function getLocaleLanguage(locale?: string, fallback = "en"): string {
6
+ return normalizeLocale(locale, fallback).split("-")[0] || fallback;
7
+ }
8
+
9
+ const LANGUAGE_TO_LOCALE: Record<string, string> = {
10
+ en: "en-US",
11
+ de: "de-DE",
12
+ sl: "sl-SI",
13
+ it: "it-IT",
14
+ fr: "fr-FR",
15
+ es: "es-ES",
16
+ pt: "pt-PT",
17
+ nl: "nl-NL",
18
+ pl: "pl-PL",
19
+ hr: "hr-HR",
20
+ sv: "sv-SE",
21
+ fi: "fi-FI",
22
+ et: "et-EE",
23
+ bg: "bg-BG",
24
+ cs: "cs-CZ",
25
+ sk: "sk-SK",
26
+ nb: "nb-NO",
27
+ is: "is-IS",
28
+ };
29
+
30
+ export function getFullLocale(locale?: string, fallback = "en-US"): string {
31
+ const normalized = normalizeLocale(locale, fallback);
32
+ if (Object.values(LANGUAGE_TO_LOCALE).includes(normalized)) {
33
+ return normalized;
34
+ }
35
+
36
+ const language = getLocaleLanguage(normalized, fallback.split("-")[0]);
37
+ return LANGUAGE_TO_LOCALE[language] || fallback;
38
+ }
@@ -26,7 +26,7 @@ export function getVariableValue(
26
26
 
27
27
  // Entity-related variables
28
28
  if (varName === "entity_name") return entity.name || null;
29
- if (varName === "entity_email") return (entity.settings as any)?.email || null;
29
+ if (varName === "entity_email") return entity.email || null;
30
30
  if (varName === "entity_address") return entity.address || null;
31
31
  if (varName === "entity_post_code") return entity.post_code || null;
32
32
  if (varName === "entity_city") return entity.city || null;
@@ -1,4 +1,5 @@
1
1
  import { useCallback } from "react";
2
+ import { getLocaleLanguage, normalizeLocale } from "./locale";
2
3
 
3
4
  type TranslationFunction = (key: string) => string;
4
5
 
@@ -24,9 +25,19 @@ export function createTranslation({ t, namespace, locale = "en", translations =
24
25
  }
25
26
  }
26
27
 
27
- // 2. Look up in local translations for current locale
28
- if (translations[locale]) {
29
- const translation = translations[locale][key];
28
+ const normalizedLocale = normalizeLocale(locale);
29
+ const baseLocale = getLocaleLanguage(normalizedLocale);
30
+
31
+ // 2. Look up in local translations for current locale, then base language
32
+ const localeTranslations = translations[normalizedLocale] ?? translations[baseLocale];
33
+ if (localeTranslations) {
34
+ const translation = localeTranslations[key];
35
+ if (translation) return translation;
36
+ }
37
+
38
+ const englishTranslations = translations.en;
39
+ if (englishTranslations) {
40
+ const translation = englishTranslations[key];
30
41
  if (translation) return translation;
31
42
  }
32
43
 
@@ -12,6 +12,7 @@ export type EntitiesContextType = {
12
12
  activeEntity: Entity | null;
13
13
  setActiveEntity: (entity: Entity | null) => void;
14
14
  environment: EntityEnvironment;
15
+ /** @deprecated Use URL-based sandbox routing instead of calling setEnvironment directly */
15
16
  setEnvironment: (environment: EntityEnvironment) => void;
16
17
  isLoading: boolean;
17
18
  refetchEntities: () => Promise<void>;
@@ -26,6 +26,10 @@ type EntitiesProviderProps = {
26
26
  cookieDomain?: string;
27
27
  /** When provided (from URL param), this entity ID is used as the source of truth instead of the cookie */
28
28
  urlEntityId?: string;
29
+ /** When provided, determines environment from URL instead of cookie. true = sandbox, false = live. */
30
+ isSandbox?: boolean;
31
+ /** Called when urlEntityId is not found in any environment, allowing parent to try other accounts */
32
+ onEntityNotFound?: (entityId: string) => boolean | void | Promise<boolean | void>;
29
33
  };
30
34
 
31
35
  export function EntitiesProvider({
@@ -34,6 +38,8 @@ export function EntitiesProvider({
34
38
  onNoEntities,
35
39
  cookieDomain,
36
40
  urlEntityId,
41
+ isSandbox,
42
+ onEntityNotFound,
37
43
  }: EntitiesProviderProps) {
38
44
  const { sdk, isInitialized } = useSDK();
39
45
  const [cookies, setCookie, removeCookie] = useCookies([ACTIVE_ENTITY_COOKIE, ACTIVE_ENVIRONMENT_COOKIE]);
@@ -44,12 +50,24 @@ export function EntitiesProvider({
44
50
  // URL entity ID takes precedence over cookie
45
51
  const resolvedEntityId = urlEntityId ?? initialEntityIdFromCookie;
46
52
 
53
+ // When isSandbox is provided (URL-driven), use it as source of truth; otherwise fall back to cookie
47
54
  const resolvedInitialEnvironment: EntityEnvironment =
48
- initialEnvironmentFromCookie ?? (initialActiveEntity?.environment as EntityEnvironment | undefined) ?? "live";
55
+ isSandbox !== undefined
56
+ ? isSandbox
57
+ ? "sandbox"
58
+ : "live"
59
+ : (initialEnvironmentFromCookie ?? (initialActiveEntity?.environment as EntityEnvironment | undefined) ?? "live");
49
60
 
50
61
  const [environment, setEnvironmentState] = useState<EntityEnvironment>(resolvedInitialEnvironment);
51
62
  const previousEnvironment = useRef(environment);
52
63
 
64
+ // Sync environment with isSandbox prop when it changes (URL-driven navigation)
65
+ useEffect(() => {
66
+ if (isSandbox === undefined) return;
67
+ const target: EntityEnvironment = isSandbox ? "sandbox" : "live";
68
+ setEnvironmentState((current) => (current === target ? current : target));
69
+ }, [isSandbox]);
70
+
53
71
  // Store the initial entity ID (from URL or cookie) so we can match it when entities load
54
72
  const initialEntityIdRef = useRef(resolvedEntityId);
55
73
 
@@ -65,6 +83,7 @@ export function EntitiesProvider({
65
83
  const {
66
84
  data: entities = [],
67
85
  isLoading,
86
+ isFetching,
68
87
  refetch,
69
88
  isError,
70
89
  error,
@@ -88,10 +107,50 @@ export function EntitiesProvider({
88
107
  });
89
108
 
90
109
  // When no entities in current environment, check the other before giving up
110
+ // Skip auto-switch when isSandbox is explicitly set (URL-driven) — respect the user's intent
91
111
  const hasCalledNoEntities = useRef(false);
92
112
  const hasTriedFallback = useRef(false);
113
+ const resolvingUrlEntityRef = useRef<string | null>(null);
114
+ const emptyUrlEntityRefetchKeyRef = useRef<string | null>(null);
93
115
  useEffect(() => {
94
- if (isLoading || entities.length > 0 || hasCalledNoEntities.current) return;
116
+ if (isLoading || isFetching || entities.length > 0 || hasCalledNoEntities.current) return;
117
+
118
+ if (urlEntityId) {
119
+ const refetchKey = `${urlEntityId}:${environment}`;
120
+ if (emptyUrlEntityRefetchKeyRef.current !== refetchKey) {
121
+ emptyUrlEntityRefetchKeyRef.current = refetchKey;
122
+ void refetch();
123
+ return;
124
+ }
125
+
126
+ if (resolvingUrlEntityRef.current === urlEntityId) return;
127
+ resolvingUrlEntityRef.current = urlEntityId;
128
+
129
+ if (!onEntityNotFound) {
130
+ hasCalledNoEntities.current = true;
131
+ onNoEntities?.();
132
+ return;
133
+ }
134
+
135
+ void Promise.resolve(onEntityNotFound(urlEntityId))
136
+ .then((resolved) => {
137
+ if (resolved) return;
138
+ hasCalledNoEntities.current = true;
139
+ onNoEntities?.();
140
+ })
141
+ .catch(() => {
142
+ hasCalledNoEntities.current = true;
143
+ onNoEntities?.();
144
+ });
145
+ return;
146
+ }
147
+
148
+ // When environment is explicitly set via URL, don't auto-switch to the other environment
149
+ if (isSandbox !== undefined) {
150
+ hasCalledNoEntities.current = true;
151
+ onNoEntities?.();
152
+ return;
153
+ }
95
154
 
96
155
  // Try the other environment before calling onNoEntities
97
156
  if (!hasTriedFallback.current && sdk) {
@@ -118,7 +177,18 @@ export function EntitiesProvider({
118
177
  if (!hasTriedFallback.current) return;
119
178
  hasCalledNoEntities.current = true;
120
179
  onNoEntities?.();
121
- }, [isLoading, entities.length, onNoEntities, sdk, environment]);
180
+ }, [
181
+ isLoading,
182
+ isFetching,
183
+ entities.length,
184
+ onEntityNotFound,
185
+ onNoEntities,
186
+ refetch,
187
+ sdk,
188
+ environment,
189
+ isSandbox,
190
+ urlEntityId,
191
+ ]);
122
192
 
123
193
  // Memoize entities to prevent unnecessary re-renders
124
194
  const memoizedEntities = useMemo(() => entities, [entities]);
@@ -130,6 +200,13 @@ export function EntitiesProvider({
130
200
  }
131
201
  }, [environment]);
132
202
 
203
+ useEffect(() => {
204
+ if (entities.length > 0) {
205
+ emptyUrlEntityRefetchKeyRef.current = null;
206
+ resolvingUrlEntityRef.current = null;
207
+ }
208
+ }, [entities.length]);
209
+
133
210
  // Sync active entity when entities list changes
134
211
  // Use ref to read current activeEntityState without causing re-runs
135
212
  const activeEntityRef = useRef(activeEntityState);
@@ -139,6 +216,8 @@ export function EntitiesProvider({
139
216
  useEffect(() => {
140
217
  if (urlEntityId) {
141
218
  initialEntityIdRef.current = urlEntityId;
219
+ resolvingUrlEntityRef.current = null;
220
+ emptyUrlEntityRefetchKeyRef.current = null;
142
221
  }
143
222
  }, [urlEntityId]);
144
223
 
@@ -201,6 +280,26 @@ export function EntitiesProvider({
201
280
  setEnvironmentState(altEnv);
202
281
  }, [urlEntityId, memoizedEntities, isLoading, environment]);
203
282
 
283
+ // After environment fallback has been attempted and entity is still not found, notify parent
284
+ const entityNotFoundCallbackFired = useRef<string | null>(null);
285
+ useEffect(() => {
286
+ if (!urlEntityId || !onEntityNotFound || isLoading) return;
287
+ if (memoizedEntities.length === 0) return;
288
+
289
+ const found = memoizedEntities.some((e) => e.id === urlEntityId);
290
+ if (found) {
291
+ entityNotFoundCallbackFired.current = null;
292
+ return;
293
+ }
294
+
295
+ // Only fire after the environment fallback has already been attempted for this entity
296
+ if (urlEntityFallbackAttempted.current !== urlEntityId) return;
297
+ if (entityNotFoundCallbackFired.current === urlEntityId) return;
298
+
299
+ entityNotFoundCallbackFired.current = urlEntityId;
300
+ onEntityNotFound(urlEntityId);
301
+ }, [urlEntityId, memoizedEntities, isLoading, onEntityNotFound]);
302
+
204
303
  const cookieOpts = useMemo(
205
304
  () => ({
206
305
  path: "/",
@@ -1,4 +1,4 @@
1
- import { createContext, type ReactNode, useContext, useEffect, useState } from "react";
1
+ import { createContext, type ReactNode, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
2
2
 
3
3
  type SecondaryAction = {
4
4
  label: string;
@@ -54,6 +54,37 @@ export function useFormFooterRegistration({
54
54
  secondaryAction,
55
55
  }: UseFormFooterRegistrationProps) {
56
56
  const { setFormFooter } = useFormFooterContext();
57
+ const onSubmitRef = useRef(onSubmit);
58
+ const secondaryActionRef = useRef(secondaryAction);
59
+
60
+ useEffect(() => {
61
+ onSubmitRef.current = onSubmit;
62
+ }, [onSubmit]);
63
+
64
+ useEffect(() => {
65
+ secondaryActionRef.current = secondaryAction;
66
+ }, [secondaryAction]);
67
+
68
+ const stableOnSubmit = useCallback(() => {
69
+ onSubmitRef.current?.();
70
+ }, []);
71
+
72
+ const hasSecondaryAction = !!secondaryAction;
73
+ const secondaryActionLabel = secondaryAction?.label;
74
+ const secondaryActionPending = secondaryAction?.isPending;
75
+ const stableSecondaryActionOnClick = useCallback(() => {
76
+ secondaryActionRef.current?.onClick();
77
+ }, []);
78
+
79
+ const stableSecondaryAction = useMemo(() => {
80
+ if (!hasSecondaryAction || !secondaryActionLabel) return undefined;
81
+
82
+ return {
83
+ label: secondaryActionLabel,
84
+ isPending: secondaryActionPending,
85
+ onClick: stableSecondaryActionOnClick,
86
+ };
87
+ }, [hasSecondaryAction, secondaryActionLabel, secondaryActionPending, stableSecondaryActionOnClick]);
57
88
 
58
89
  useEffect(() => {
59
90
  setFormFooter({
@@ -61,12 +92,14 @@ export function useFormFooterRegistration({
61
92
  isPending,
62
93
  isDirty,
63
94
  label,
64
- onSubmit,
65
- secondaryAction,
95
+ onSubmit: onSubmit ? stableOnSubmit : undefined,
96
+ secondaryAction: stableSecondaryAction,
66
97
  });
98
+ }, [formId, isPending, isDirty, label, onSubmit, setFormFooter, stableOnSubmit, stableSecondaryAction]);
67
99
 
100
+ useEffect(() => {
68
101
  return () => {
69
102
  setFormFooter(null);
70
103
  };
71
- }, [formId, isPending, isDirty, label, onSubmit, secondaryAction, setFormFooter]);
104
+ }, [setFormFooter]);
72
105
  }