@spaceinvoices/react-ui 0.1.1

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 (352) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +340 -0
  3. package/cli/dist/index.js +922 -0
  4. package/package.json +87 -0
  5. package/registry.json +600 -0
  6. package/spaceinvoices.schema.json +47 -0
  7. package/src/app.tsx +25 -0
  8. package/src/common/autocomplete.tsx +135 -0
  9. package/src/components/activities/activity-timeline.tsx +160 -0
  10. package/src/components/activities/index.ts +1 -0
  11. package/src/components/activities/locales/de.ts +30 -0
  12. package/src/components/activities/locales/sl.ts +30 -0
  13. package/src/components/advance-invoices/advance-invoices.hooks.ts +75 -0
  14. package/src/components/advance-invoices/create/create-advance-invoice-form.tsx +702 -0
  15. package/src/components/advance-invoices/create/locales/de.ts +29 -0
  16. package/src/components/advance-invoices/create/locales/sl.ts +25 -0
  17. package/src/components/advance-invoices/create/prepare-advance-invoice-submission.ts +74 -0
  18. package/src/components/advance-invoices/index.ts +5 -0
  19. package/src/components/advance-invoices/list/index.ts +3 -0
  20. package/src/components/advance-invoices/list/list-row-actions.tsx +119 -0
  21. package/src/components/advance-invoices/list/list-table.tsx +178 -0
  22. package/src/components/advance-invoices/list/locales/de.ts +32 -0
  23. package/src/components/advance-invoices/list/locales/sl.ts +32 -0
  24. package/src/components/advance-invoices/list/use-advance-invoice-download.ts +63 -0
  25. package/src/components/button-loader.tsx +11 -0
  26. package/src/components/combobox.tsx +96 -0
  27. package/src/components/company-registry/company-registry-autocomplete.tsx +151 -0
  28. package/src/components/company-registry/company-registry.hooks.ts +67 -0
  29. package/src/components/company-registry/index.ts +7 -0
  30. package/src/components/credit-notes/create/create-credit-note-form.tsx +332 -0
  31. package/src/components/credit-notes/create/index.ts +1 -0
  32. package/src/components/credit-notes/create/locales/de.ts +69 -0
  33. package/src/components/credit-notes/create/locales/sl.ts +67 -0
  34. package/src/components/credit-notes/credit-notes.hooks.ts +22 -0
  35. package/src/components/credit-notes/index.ts +10 -0
  36. package/src/components/credit-notes/list/index.ts +3 -0
  37. package/src/components/credit-notes/list/list-row-actions.tsx +116 -0
  38. package/src/components/credit-notes/list/list-table.tsx +183 -0
  39. package/src/components/credit-notes/list/locales/de.ts +33 -0
  40. package/src/components/credit-notes/list/locales/sl.ts +33 -0
  41. package/src/components/credit-notes/list/use-credit-note-download.ts +65 -0
  42. package/src/components/customers/create-customer-form/create-customer-form.tsx +134 -0
  43. package/src/components/customers/create-customer-form/locales/de.ts +20 -0
  44. package/src/components/customers/create-customer-form/locales/sl.ts +20 -0
  45. package/src/components/customers/customer-autocomplete.tsx +173 -0
  46. package/src/components/customers/customer-combobox.tsx +130 -0
  47. package/src/components/customers/customer-list-table/customer-list-row-actions.tsx +48 -0
  48. package/src/components/customers/customer-list-table/customer-list-table.tsx +124 -0
  49. package/src/components/customers/customer-list-table/index.ts +2 -0
  50. package/src/components/customers/customer-list-table/locales/de.ts +16 -0
  51. package/src/components/customers/customer-list-table/locales/sl.ts +16 -0
  52. package/src/components/customers/customers.hooks.test.ts +348 -0
  53. package/src/components/customers/customers.hooks.ts +57 -0
  54. package/src/components/customers/index.ts +5 -0
  55. package/src/components/dashboard/chart-empty-state.tsx +29 -0
  56. package/src/components/dashboard/collection-rate-card/collection-rate-card.tsx +80 -0
  57. package/src/components/dashboard/collection-rate-card/index.ts +4 -0
  58. package/src/components/dashboard/collection-rate-card/locales/sl.ts +3 -0
  59. package/src/components/dashboard/collection-rate-card/use-collection-rate.ts +74 -0
  60. package/src/components/dashboard/index.ts +54 -0
  61. package/src/components/dashboard/invoice-status-chart/index.ts +4 -0
  62. package/src/components/dashboard/invoice-status-chart/invoice-status-chart.tsx +130 -0
  63. package/src/components/dashboard/invoice-status-chart/locales/sl.ts +9 -0
  64. package/src/components/dashboard/invoice-status-chart/use-invoice-status.ts +105 -0
  65. package/src/components/dashboard/loading-card.tsx +19 -0
  66. package/src/components/dashboard/payment-methods-chart/index.ts +4 -0
  67. package/src/components/dashboard/payment-methods-chart/locales/sl.ts +12 -0
  68. package/src/components/dashboard/payment-methods-chart/payment-methods-chart.tsx +152 -0
  69. package/src/components/dashboard/payment-methods-chart/use-payment-methods.ts +50 -0
  70. package/src/components/dashboard/payment-trend-chart/index.ts +4 -0
  71. package/src/components/dashboard/payment-trend-chart/locales/sl.ts +5 -0
  72. package/src/components/dashboard/payment-trend-chart/payment-trend-chart.tsx +137 -0
  73. package/src/components/dashboard/payment-trend-chart/use-payment-trend.ts +92 -0
  74. package/src/components/dashboard/revenue-card.tsx +49 -0
  75. package/src/components/dashboard/revenue-trend-chart/index.ts +4 -0
  76. package/src/components/dashboard/revenue-trend-chart/locales/sl.ts +5 -0
  77. package/src/components/dashboard/revenue-trend-chart/revenue-trend-chart.tsx +137 -0
  78. package/src/components/dashboard/revenue-trend-chart/use-revenue-trend.ts +93 -0
  79. package/src/components/dashboard/shared/index.ts +5 -0
  80. package/src/components/dashboard/shared/use-revenue-data.ts +160 -0
  81. package/src/components/dashboard/shared/use-stats-counts.ts +89 -0
  82. package/src/components/dashboard/shared/use-stats-query.ts +38 -0
  83. package/src/components/dashboard/stat-card.tsx +41 -0
  84. package/src/components/dashboard/tax-collected-card/index.ts +2 -0
  85. package/src/components/dashboard/tax-collected-card/tax-collected-card.tsx +77 -0
  86. package/src/components/dashboard/tax-collected-card/use-tax-collected.ts +145 -0
  87. package/src/components/dashboard/top-customers-chart/index.ts +4 -0
  88. package/src/components/dashboard/top-customers-chart/locales/sl.ts +5 -0
  89. package/src/components/dashboard/top-customers-chart/top-customers-chart.tsx +130 -0
  90. package/src/components/dashboard/top-customers-chart/use-top-customers.ts +72 -0
  91. package/src/components/documents/create/document-add-item-form.tsx +379 -0
  92. package/src/components/documents/create/document-add-item-tax-rate-field.tsx +120 -0
  93. package/src/components/documents/create/document-details-section.tsx +597 -0
  94. package/src/components/documents/create/document-items-section.tsx +133 -0
  95. package/src/components/documents/create/document-recipient-section.tsx +101 -0
  96. package/src/components/documents/create/form-types.ts +36 -0
  97. package/src/components/documents/create/index.ts +9 -0
  98. package/src/components/documents/create/live-preview.tsx +235 -0
  99. package/src/components/documents/create/mark-as-paid-section.tsx +82 -0
  100. package/src/components/documents/create/prepare-document-submission.test.ts +132 -0
  101. package/src/components/documents/create/prepare-document-submission.ts +187 -0
  102. package/src/components/documents/create/prepare-preview-data.test.ts +155 -0
  103. package/src/components/documents/create/prepare-preview-data.ts +16 -0
  104. package/src/components/documents/create/smart-code-insert-button.tsx +139 -0
  105. package/src/components/documents/create/use-document-customer-form.ts +161 -0
  106. package/src/components/documents/document-preview.tsx +13 -0
  107. package/src/components/documents/documents.hooks.ts +146 -0
  108. package/src/components/documents/index.ts +23 -0
  109. package/src/components/documents/shared/document-preview-display.tsx +172 -0
  110. package/src/components/documents/shared/index.ts +3 -0
  111. package/src/components/documents/shared/scaled-document-preview.tsx +70 -0
  112. package/src/components/documents/shared/use-a4-scaling.ts +62 -0
  113. package/src/components/documents/types.ts +61 -0
  114. package/src/components/documents/view/document-actions-bar.tsx +328 -0
  115. package/src/components/documents/view/document-details-card.tsx +179 -0
  116. package/src/components/documents/view/document-payments-list.tsx +256 -0
  117. package/src/components/documents/view/index.ts +4 -0
  118. package/src/components/documents/view/locales/de.ts +85 -0
  119. package/src/components/documents/view/locales/sl.ts +84 -0
  120. package/src/components/documents/view/use-document-download.ts +125 -0
  121. package/src/components/entities/create-entity-form.tsx +105 -0
  122. package/src/components/entities/entities.hooks.ts +50 -0
  123. package/src/components/entities/entity-settings-form/email-template-variables-info.tsx +103 -0
  124. package/src/components/entities/entity-settings-form/entity-settings-form.tsx +1326 -0
  125. package/src/components/entities/entity-settings-form/image-upload-with-crop.tsx +222 -0
  126. package/src/components/entities/entity-settings-form/index.ts +2 -0
  127. package/src/components/entities/entity-settings-form/input-with-preview.tsx +190 -0
  128. package/src/components/entities/entity-settings-form/locales/de.ts +192 -0
  129. package/src/components/entities/entity-settings-form/locales/sl.ts +188 -0
  130. package/src/components/entities/furs-settings-form/furs-settings-form.tsx +410 -0
  131. package/src/components/entities/furs-settings-form/furs-settings.hooks.ts +320 -0
  132. package/src/components/entities/furs-settings-form/index.ts +3 -0
  133. package/src/components/entities/furs-settings-form/locales/de.ts +233 -0
  134. package/src/components/entities/furs-settings-form/locales/en.ts +194 -0
  135. package/src/components/entities/furs-settings-form/locales/sl.ts +196 -0
  136. package/src/components/entities/furs-settings-form/sections/certificate-settings-section.tsx +242 -0
  137. package/src/components/entities/furs-settings-form/sections/enable-fiscalization-section.tsx +139 -0
  138. package/src/components/entities/furs-settings-form/sections/general-settings-section.tsx +252 -0
  139. package/src/components/entities/furs-settings-form/sections/premises-management-section.tsx +370 -0
  140. package/src/components/entities/furs-settings-form/sections/register-premise-dialog.tsx +420 -0
  141. package/src/components/entities/keys.ts +2 -0
  142. package/src/components/entities/settings/branding-settings-form.tsx +274 -0
  143. package/src/components/entities/settings/company-settings-form.tsx +256 -0
  144. package/src/components/entities/settings/defaults-settings-form.tsx +501 -0
  145. package/src/components/entities/settings/email-settings-form.tsx +288 -0
  146. package/src/components/entities/settings/eslog-settings-form.tsx +113 -0
  147. package/src/components/entities/settings/index.ts +8 -0
  148. package/src/components/entities/settings/number-format-settings-form.tsx +244 -0
  149. package/src/components/entities/settings/pdf-template-selector/demo-invoice-data.ts +164 -0
  150. package/src/components/entities/settings/pdf-template-selector/index.ts +2 -0
  151. package/src/components/entities/settings/pdf-template-selector/locales/de.ts +18 -0
  152. package/src/components/entities/settings/pdf-template-selector/locales/sl.ts +18 -0
  153. package/src/components/entities/settings/pdf-template-selector/pdf-template-cards.tsx +49 -0
  154. package/src/components/entities/settings/settings-footer.tsx +16 -0
  155. package/src/components/entities/settings/tax-rules-settings-form.tsx +346 -0
  156. package/src/components/estimates/create/create-estimate-form.tsx +384 -0
  157. package/src/components/estimates/create/locales/de.ts +64 -0
  158. package/src/components/estimates/create/locales/sl.ts +63 -0
  159. package/src/components/estimates/create/prepare-estimate-submission.ts +39 -0
  160. package/src/components/estimates/create/use-estimate-customer-form.ts +5 -0
  161. package/src/components/estimates/estimates.hooks.ts +15 -0
  162. package/src/components/estimates/index.ts +6 -0
  163. package/src/components/estimates/list/index.ts +3 -0
  164. package/src/components/estimates/list/list-row-actions.tsx +103 -0
  165. package/src/components/estimates/list/list-table.tsx +171 -0
  166. package/src/components/estimates/list/locales/de.ts +26 -0
  167. package/src/components/estimates/list/locales/sl.ts +26 -0
  168. package/src/components/estimates/list/use-estimate-download.ts +63 -0
  169. package/src/components/export/document-export-form.tsx +288 -0
  170. package/src/components/export/index.ts +2 -0
  171. package/src/components/form/form-input.tsx +89 -0
  172. package/src/components/form/index.ts +1 -0
  173. package/src/components/invoices/create/create-invoice-form.tsx +852 -0
  174. package/src/components/invoices/create/eslog-validation.test.ts +242 -0
  175. package/src/components/invoices/create/eslog-validation.ts +208 -0
  176. package/src/components/invoices/create/locales/de.ts +118 -0
  177. package/src/components/invoices/create/locales/sl.ts +114 -0
  178. package/src/components/invoices/create/prepare-invoice-submission.test.ts +777 -0
  179. package/src/components/invoices/create/prepare-invoice-submission.ts +79 -0
  180. package/src/components/invoices/create/use-invoice-customer-form.ts +5 -0
  181. package/src/components/invoices/index.ts +9 -0
  182. package/src/components/invoices/invoices-furs.hooks.ts +28 -0
  183. package/src/components/invoices/invoices.hooks.ts +110 -0
  184. package/src/components/invoices/list/index.ts +3 -0
  185. package/src/components/invoices/list/list-row-actions.tsx +132 -0
  186. package/src/components/invoices/list/list-table.tsx +165 -0
  187. package/src/components/invoices/list/locales/de.ts +33 -0
  188. package/src/components/invoices/list/locales/sl.ts +33 -0
  189. package/src/components/invoices/list/use-invoice-download.ts +62 -0
  190. package/src/components/invoices/send-email-dialog/index.ts +1 -0
  191. package/src/components/invoices/send-email-dialog/locales/de.ts +18 -0
  192. package/src/components/invoices/send-email-dialog/locales/sl.ts +17 -0
  193. package/src/components/invoices/send-email-dialog/send-email-dialog.tsx +289 -0
  194. package/src/components/invoices/send-email-dialog.tsx +2 -0
  195. package/src/components/invoices/shared/index.ts +2 -0
  196. package/src/components/invoices/shared/scaled-document-preview.tsx +32 -0
  197. package/src/components/invoices/shared/use-a4-scaling.tsx +39 -0
  198. package/src/components/invoices/view/eslog-info-display.tsx +160 -0
  199. package/src/components/invoices/view/furs-info-display.tsx +213 -0
  200. package/src/components/items/create-item-form/create-item-form.tsx +155 -0
  201. package/src/components/items/create-item-form/locales/de.ts +14 -0
  202. package/src/components/items/create-item-form/locales/en.ts +9 -0
  203. package/src/components/items/create-item-form/locales/sl.ts +14 -0
  204. package/src/components/items/item-combobox.tsx +147 -0
  205. package/src/components/items/item-list-table/item-list-header.tsx +33 -0
  206. package/src/components/items/item-list-table/item-list-row-actions.tsx +48 -0
  207. package/src/components/items/item-list-table/item-list-row.tsx +32 -0
  208. package/src/components/items/item-list-table/item-list-table.tsx +76 -0
  209. package/src/components/items/item-list-table/locales/de.ts +10 -0
  210. package/src/components/items/item-list-table/locales/en.ts +10 -0
  211. package/src/components/items/item-list-table/locales/sl.ts +10 -0
  212. package/src/components/items/items.hooks.ts +63 -0
  213. package/src/components/loading-spinner.tsx +24 -0
  214. package/src/components/payments/create-payment-form/create-payment-form.tsx +222 -0
  215. package/src/components/payments/create-payment-form/locales/de.ts +20 -0
  216. package/src/components/payments/create-payment-form/locales/sl.ts +20 -0
  217. package/src/components/payments/edit-payment-form/edit-payment-form.tsx +230 -0
  218. package/src/components/payments/edit-payment-form/index.ts +1 -0
  219. package/src/components/payments/edit-payment-form/locales/de.ts +20 -0
  220. package/src/components/payments/edit-payment-form/locales/sl.ts +20 -0
  221. package/src/components/payments/index.ts +4 -0
  222. package/src/components/payments/list/index.ts +2 -0
  223. package/src/components/payments/list/list-row-actions.tsx +98 -0
  224. package/src/components/payments/list/list-table.tsx +186 -0
  225. package/src/components/payments/list/locales/de.ts +19 -0
  226. package/src/components/payments/list/locales/sl.ts +19 -0
  227. package/src/components/payments/payments.hooks.ts +15 -0
  228. package/src/components/request-logs/index.ts +3 -0
  229. package/src/components/request-logs/request-log-detail.tsx +242 -0
  230. package/src/components/request-logs/request-log-list-table.tsx +266 -0
  231. package/src/components/request-logs/request-logs-page.tsx +10 -0
  232. package/src/components/table/README.md +410 -0
  233. package/src/components/table/data-table.tsx +251 -0
  234. package/src/components/table/date-cell.tsx +35 -0
  235. package/src/components/table/filter-bar.tsx +114 -0
  236. package/src/components/table/filter-panel.tsx +407 -0
  237. package/src/components/table/hooks/use-table-fetch.ts +17 -0
  238. package/src/components/table/hooks/use-table-query.ts +36 -0
  239. package/src/components/table/hooks/use-table-state.ts +293 -0
  240. package/src/components/table/index.ts +35 -0
  241. package/src/components/table/search-input.tsx +85 -0
  242. package/src/components/table/sortable-header.tsx +56 -0
  243. package/src/components/table/table-empty-state.tsx +40 -0
  244. package/src/components/table/table-no-results.tsx +41 -0
  245. package/src/components/table/table-pagination.tsx +42 -0
  246. package/src/components/table/table-skeleton.tsx +54 -0
  247. package/src/components/table/types.ts +136 -0
  248. package/src/components/tax-reports/index.ts +1 -0
  249. package/src/components/tax-reports/kir-export-form.tsx +172 -0
  250. package/src/components/taxes/create-tax-form/create-tax-form.tsx +112 -0
  251. package/src/components/taxes/create-tax-form/locales/de.ts +8 -0
  252. package/src/components/taxes/create-tax-form/locales/en.ts +7 -0
  253. package/src/components/taxes/create-tax-form/locales/sl.ts +8 -0
  254. package/src/components/taxes/tax-list-table/locales/de.ts +11 -0
  255. package/src/components/taxes/tax-list-table/locales/en.ts +10 -0
  256. package/src/components/taxes/tax-list-table/locales/sl.ts +11 -0
  257. package/src/components/taxes/tax-list-table/tax-list-header.tsx +29 -0
  258. package/src/components/taxes/tax-list-table/tax-list-row-actions.tsx +43 -0
  259. package/src/components/taxes/tax-list-table/tax-list-row.tsx +46 -0
  260. package/src/components/taxes/tax-list-table/tax-list-table.tsx +59 -0
  261. package/src/components/taxes/taxes.hooks.ts +35 -0
  262. package/src/components/ui/alert-dialog.tsx +61 -0
  263. package/src/components/ui/alert.tsx +72 -0
  264. package/src/components/ui/badge.tsx +48 -0
  265. package/src/components/ui/breadcrumb.tsx +132 -0
  266. package/src/components/ui/button.tsx +61 -0
  267. package/src/components/ui/calendar.tsx +213 -0
  268. package/src/components/ui/card.tsx +94 -0
  269. package/src/components/ui/chart.tsx +380 -0
  270. package/src/components/ui/checkbox.tsx +27 -0
  271. package/src/components/ui/collapsible.tsx +56 -0
  272. package/src/components/ui/command.tsx +187 -0
  273. package/src/components/ui/dialog.tsx +187 -0
  274. package/src/components/ui/drawer.tsx +123 -0
  275. package/src/components/ui/dropdown-menu.tsx +291 -0
  276. package/src/components/ui/form.tsx +166 -0
  277. package/src/components/ui/input-group.tsx +149 -0
  278. package/src/components/ui/input.tsx +20 -0
  279. package/src/components/ui/label.tsx +18 -0
  280. package/src/components/ui/loading-spinner.tsx +16 -0
  281. package/src/components/ui/popover.tsx +108 -0
  282. package/src/components/ui/radio-group.tsx +37 -0
  283. package/src/components/ui/select.tsx +200 -0
  284. package/src/components/ui/separator.tsx +23 -0
  285. package/src/components/ui/sheet.tsx +145 -0
  286. package/src/components/ui/sidebar.tsx +771 -0
  287. package/src/components/ui/skeleton.tsx +13 -0
  288. package/src/components/ui/sonner.tsx +60 -0
  289. package/src/components/ui/spinner.tsx +10 -0
  290. package/src/components/ui/sticky-form-footer.tsx +55 -0
  291. package/src/components/ui/switch.tsx +30 -0
  292. package/src/components/ui/table.tsx +101 -0
  293. package/src/components/ui/tabs.tsx +80 -0
  294. package/src/components/ui/textarea.tsx +18 -0
  295. package/src/components/ui/tooltip.tsx +89 -0
  296. package/src/components/wl-subscription/index.ts +2 -0
  297. package/src/components/wl-subscription/locked-feature.tsx +173 -0
  298. package/src/components/wl-subscription/upgrade-modal.tsx +209 -0
  299. package/src/frontend.tsx +28 -0
  300. package/src/generate-schemas.ts +265 -0
  301. package/src/generated/schemas/advanceinvoice.ts +177 -0
  302. package/src/generated/schemas/creditnote.ts +187 -0
  303. package/src/generated/schemas/customer.ts +29 -0
  304. package/src/generated/schemas/entity.ts +252 -0
  305. package/src/generated/schemas/estimate.ts +159 -0
  306. package/src/generated/schemas/furssettings.ts +25 -0
  307. package/src/generated/schemas/index.ts +24 -0
  308. package/src/generated/schemas/invoice.ts +167 -0
  309. package/src/generated/schemas/item.ts +38 -0
  310. package/src/generated/schemas/payment.ts +44 -0
  311. package/src/generated/schemas/previewadvanceinvoice_body.ts +354 -0
  312. package/src/generated/schemas/previewestimate_body.ts +309 -0
  313. package/src/generated/schemas/registerfursmovablepremise_body.ts +22 -0
  314. package/src/generated/schemas/registerfursrealestatepremise_body.ts +32 -0
  315. package/src/generated/schemas/renderdocument_body.ts +594 -0
  316. package/src/generated/schemas/sendemail_body.ts +26 -0
  317. package/src/generated/schemas/startpdfexport_body.ts +20 -0
  318. package/src/generated/schemas/tax.ts +48 -0
  319. package/src/generated/schemas/uploadfile_body.ts +23 -0
  320. package/src/generated/schemas/uploadfurscertificate_body.ts +20 -0
  321. package/src/generated/schemas/userfurssettings.ts +19 -0
  322. package/src/hooks/create-resource-hooks.test.ts +483 -0
  323. package/src/hooks/create-resource-hooks.ts +300 -0
  324. package/src/hooks/use-debounce.ts +12 -0
  325. package/src/hooks/use-duplicate-document.ts +185 -0
  326. package/src/hooks/use-media-query.tsx +19 -0
  327. package/src/hooks/use-mobile.ts +39 -0
  328. package/src/hooks/use-next-document-number.ts +57 -0
  329. package/src/hooks/use-resource-mutation.ts +118 -0
  330. package/src/hooks/use-vies-check.ts +130 -0
  331. package/src/index.css +11 -0
  332. package/src/index.html +13 -0
  333. package/src/index.tsx +12 -0
  334. package/src/lib/auth.ts +4 -0
  335. package/src/lib/browser-cookies.ts +70 -0
  336. package/src/lib/constants.ts +287 -0
  337. package/src/lib/cookies.ts +36 -0
  338. package/src/lib/schemas/advance-invoice.ts +43 -0
  339. package/src/lib/schemas/credit-note.ts +32 -0
  340. package/src/lib/schemas/estimate.ts +31 -0
  341. package/src/lib/schemas/index.ts +18 -0
  342. package/src/lib/schemas/invoice.ts +43 -0
  343. package/src/lib/schemas/shared.ts +79 -0
  344. package/src/lib/translation.ts +38 -0
  345. package/src/lib/utils.ts +6 -0
  346. package/src/providers/entities-context.tsx +41 -0
  347. package/src/providers/entities-provider.tsx +201 -0
  348. package/src/providers/form-footer-context.tsx +72 -0
  349. package/src/providers/sdk-provider.tsx +164 -0
  350. package/src/providers/white-label-provider.tsx +91 -0
  351. package/src/providers/wl-subscription-provider.tsx +277 -0
  352. package/src/utils/string-helpers.ts +111 -0
@@ -0,0 +1,702 @@
1
+ import { zodResolver } from "@hookform/resolvers/zod";
2
+ import type { AdvanceInvoice, CreateAdvanceInvoiceRequest } from "@spaceinvoices/js-sdk";
3
+ import { AlertCircle, Check, FileCode2, X } from "lucide-react";
4
+ import type { ReactNode } from "react";
5
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
6
+ import type { Resolver } from "react-hook-form";
7
+ import { useForm, useWatch } from "react-hook-form";
8
+ import { Alert, AlertDescription, AlertTitle } from "@/ui/components/ui/alert";
9
+ import { Button } from "@/ui/components/ui/button";
10
+ import { Form } from "@/ui/components/ui/form";
11
+ import { Skeleton } from "@/ui/components/ui/skeleton";
12
+ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/ui/components/ui/tooltip";
13
+ import type { CreateAdvanceInvoiceSchema } from "@/ui/generated/schemas";
14
+ import { createAdvanceInvoiceSchema } from "@/ui/generated/schemas";
15
+ import { useNextDocumentNumber } from "@/ui/hooks/use-next-document-number";
16
+ import { useViesCheck } from "@/ui/hooks/use-vies-check";
17
+ import type { ComponentTranslationProps } from "@/ui/lib/translation";
18
+ import { createTranslation } from "@/ui/lib/translation";
19
+ import { cn } from "@/ui/lib/utils";
20
+ import { useEntities } from "@/ui/providers/entities-context";
21
+ import { useFormFooterRegistration } from "@/ui/providers/form-footer-context";
22
+ import { DocumentDetailsSection, DocumentNoteField } from "../../documents/create/document-details-section";
23
+ import { DocumentItemsSection, type PriceModesMap } from "../../documents/create/document-items-section";
24
+ import { DocumentRecipientSection } from "../../documents/create/document-recipient-section";
25
+ import { MarkAsPaidSection } from "../../documents/create/mark-as-paid-section";
26
+ import { useDocumentCustomerForm } from "../../documents/create/use-document-customer-form";
27
+ import type { DocumentTypes } from "../../documents/types";
28
+ import { useFursPremises, useFursSettings } from "../../entities/furs-settings-form/furs-settings.hooks";
29
+ import { getEntityErrors, getFormFieldErrors, validateEslogForm } from "../../invoices/create/eslog-validation";
30
+ import { getLastUsedFursCombo, setLastUsedFursCombo, useCreateAdvanceInvoice } from "../advance-invoices.hooks";
31
+ import de from "./locales/de";
32
+ import sl from "./locales/sl";
33
+ import { prepareAdvanceInvoiceSubmission } from "./prepare-advance-invoice-submission";
34
+
35
+ const translations = {
36
+ sl,
37
+ de,
38
+ } as const;
39
+
40
+ // Form values: extend schema with local-only fields (number is for display, not sent to API)
41
+ type CreateAdvanceInvoiceFormValues = CreateAdvanceInvoiceSchema & {
42
+ number?: string;
43
+ };
44
+
45
+ /** Preview payload extends request with display-only fields */
46
+ type AdvanceInvoicePreviewPayload = Partial<CreateAdvanceInvoiceRequest> & { number?: string };
47
+
48
+ type CreateAdvanceInvoiceFormProps = {
49
+ type: DocumentTypes;
50
+ entityId: string;
51
+ onSuccess?: (data: AdvanceInvoice) => void;
52
+ onError?: (error: unknown) => void;
53
+ onChange?: (data: AdvanceInvoicePreviewPayload) => void;
54
+ onAddNewTax?: () => void;
55
+ onHeaderActionChange?: (action: ReactNode) => void;
56
+ /** Initial values for form fields (used for document duplication) */
57
+ initialValues?: Partial<CreateAdvanceInvoiceRequest>;
58
+ } & ComponentTranslationProps;
59
+
60
+ export default function CreateAdvanceInvoiceForm({
61
+ type: _type,
62
+ entityId,
63
+ onSuccess,
64
+ onError,
65
+ onChange,
66
+ onAddNewTax,
67
+ onHeaderActionChange,
68
+ initialValues,
69
+ t: translateProp,
70
+ namespace,
71
+ locale,
72
+ }: CreateAdvanceInvoiceFormProps) {
73
+ const t = createTranslation({
74
+ t: translateProp,
75
+ namespace,
76
+ locale,
77
+ translations,
78
+ });
79
+
80
+ const { activeEntity } = useEntities();
81
+
82
+ // Get default note from entity settings (use invoice defaults)
83
+ // Note: Advance invoices don't have payment terms - they are documents requesting payment
84
+ const defaultNote = (activeEntity?.settings as any)?.default_invoice_note || "";
85
+
86
+ // ============================================================================
87
+ // FURS Settings & Premises
88
+ // ============================================================================
89
+ const { data: fursSettings, isLoading: isFursSettingsLoading } = useFursSettings(entityId);
90
+ const { data: fursPremises, isLoading: isFursPremisesLoading } = useFursPremises(entityId, {
91
+ enabled: fursSettings?.enabled === true,
92
+ });
93
+
94
+ // Loading state for FURS - don't render form until we know if FURS is active
95
+ const isFursLoading = isFursSettingsLoading || (fursSettings?.enabled && isFursPremisesLoading);
96
+
97
+ // Check if FURS is enabled and has active premises
98
+ const isFursEnabled = fursSettings?.enabled === true;
99
+ const activePremises = useMemo(() => fursPremises?.filter((p) => p.is_active) || [], [fursPremises]);
100
+ const hasFursPremises = activePremises.length > 0;
101
+
102
+ // FURS premise/device selection state
103
+ const [selectedPremiseName, setSelectedPremiseName] = useState<string | undefined>();
104
+ const [selectedDeviceName, setSelectedDeviceName] = useState<string | undefined>();
105
+ const [skipFiscalization, setSkipFiscalization] = useState(false);
106
+
107
+ // UI-only state (not part of API schema)
108
+ const [markAsPaid, setMarkAsPaid] = useState(false);
109
+ const [paymentType, setPaymentType] = useState("bank_transfer");
110
+ const [isDraftPending, setIsDraftPending] = useState(false);
111
+
112
+ // Price modes per item (gross vs net) - collected from component state at submit
113
+ const initialPriceModes = useMemo(() => {
114
+ if (!initialValues?.items) return {};
115
+ return initialValues.items.reduce((acc, item, index) => {
116
+ acc[index] = item.gross_price != null;
117
+ return acc;
118
+ }, {} as PriceModesMap);
119
+ }, [initialValues?.items]);
120
+ const priceModesRef = useRef<PriceModesMap>(initialPriceModes);
121
+
122
+ // ============================================================================
123
+ // e-SLOG Settings (Slovenian e-Invoice)
124
+ // ============================================================================
125
+ const isSlovenianEntity = activeEntity?.country_code === "SI";
126
+ const entityEslogEnabled = !!(activeEntity?.settings as any)?.eslog_validation_enabled;
127
+ const isEslogAvailable = isSlovenianEntity && entityEslogEnabled;
128
+
129
+ // e-SLOG validation state - defaults to entity setting
130
+ const [eslogValidationEnabled, setEslogValidationEnabled] = useState<boolean | undefined>(undefined);
131
+ // e-SLOG entity-level errors (require settings update, can't be fixed in form)
132
+ const [eslogEntityErrors, setEslogEntityErrors] = useState<Array<{ field: string; message: string }>>([]);
133
+
134
+ // Initialize e-SLOG state from entity settings
135
+ useEffect(() => {
136
+ if (isEslogAvailable && eslogValidationEnabled === undefined) {
137
+ setEslogValidationEnabled(true);
138
+ }
139
+ }, [isEslogAvailable, eslogValidationEnabled]);
140
+
141
+ // Clear entity errors when eslog validation is disabled
142
+ useEffect(() => {
143
+ if (!eslogValidationEnabled) {
144
+ setEslogEntityErrors([]);
145
+ }
146
+ }, [eslogValidationEnabled]);
147
+
148
+ // Get active devices for selected premise
149
+ const activeDevices = useMemo(() => {
150
+ if (!selectedPremiseName) return [];
151
+ const premise = activePremises.find((p) => p.business_premise_name === selectedPremiseName);
152
+ return premise?.Devices?.filter((d) => d.is_active) || [];
153
+ }, [activePremises, selectedPremiseName]);
154
+
155
+ // Initialize FURS selection from localStorage or first active combo
156
+ useEffect(() => {
157
+ if (!isFursEnabled || !hasFursPremises || selectedPremiseName) return;
158
+
159
+ const lastUsed = getLastUsedFursCombo(entityId);
160
+ if (lastUsed) {
161
+ // Verify the last-used combo is still valid (premise/device still exist and active)
162
+ const premise = activePremises.find((p) => p.business_premise_name === lastUsed.business_premise_name);
163
+ const device = premise?.Devices?.find(
164
+ (d) => d.electronic_device_name === lastUsed.electronic_device_name && d.is_active,
165
+ );
166
+ if (premise && device) {
167
+ setSelectedPremiseName(lastUsed.business_premise_name);
168
+ setSelectedDeviceName(lastUsed.electronic_device_name);
169
+ return;
170
+ }
171
+ }
172
+
173
+ // Fall back to first active premise/device
174
+ const firstPremise = activePremises[0];
175
+ const firstDevice = firstPremise?.Devices?.find((d) => d.is_active);
176
+ if (firstPremise && firstDevice) {
177
+ setSelectedPremiseName(firstPremise.business_premise_name);
178
+ setSelectedDeviceName(firstDevice.electronic_device_name);
179
+ }
180
+ }, [isFursEnabled, hasFursPremises, activePremises, entityId, selectedPremiseName]);
181
+
182
+ // When premise changes, select first active device
183
+ useEffect(() => {
184
+ if (!selectedPremiseName) return;
185
+ const premise = activePremises.find((p) => p.business_premise_name === selectedPremiseName);
186
+ const firstDevice = premise?.Devices?.find((d) => d.is_active);
187
+ if (firstDevice && selectedDeviceName !== firstDevice.electronic_device_name) {
188
+ // Only update if the current device is not in this premise
189
+ const currentDeviceInPremise = premise?.Devices?.find(
190
+ (d) => d.electronic_device_name === selectedDeviceName && d.is_active,
191
+ );
192
+ if (!currentDeviceInPremise) {
193
+ setSelectedDeviceName(firstDevice.electronic_device_name);
194
+ }
195
+ }
196
+ }, [selectedPremiseName, activePremises, selectedDeviceName]);
197
+
198
+ const form = useForm<CreateAdvanceInvoiceFormValues>({
199
+ // Cast resolver to accept extended form type (includes UI-only fields)
200
+ resolver: zodResolver(createAdvanceInvoiceSchema) as Resolver<CreateAdvanceInvoiceFormValues>,
201
+ defaultValues: {
202
+ number: "", // Will be set by useNextAdvanceInvoiceNumber
203
+ date: initialValues?.date || new Date().toISOString(),
204
+ customer_id: initialValues?.customer_id ?? undefined,
205
+ // Cast customer to form schema type (API type may have additional fields)
206
+ customer: (initialValues?.customer as CreateAdvanceInvoiceFormValues["customer"]) ?? undefined,
207
+ items: initialValues?.items?.length
208
+ ? initialValues.items.map((item) => ({
209
+ name: item.name || "",
210
+ description: item.description || "",
211
+ quantity: item.quantity ?? 1,
212
+ // Use gross_price if set, otherwise use price
213
+ price: item.gross_price ?? item.price,
214
+ taxes: item.taxes || [],
215
+ }))
216
+ : [
217
+ {
218
+ name: "",
219
+ description: "",
220
+ quantity: 1,
221
+ price: undefined,
222
+ taxes: [],
223
+ },
224
+ ],
225
+ currency_code: initialValues?.currency_code || activeEntity?.currency_code || "EUR",
226
+ note: initialValues?.note ?? defaultNote,
227
+ },
228
+ });
229
+
230
+ // Skip fiscalization is only allowed for bank transfers or unpaid invoices
231
+ const canSkipFiscalization = !markAsPaid || paymentType === "bank_transfer";
232
+
233
+ // Auto-disable skip when it becomes invalid (e.g., user changes payment type to cash)
234
+ useEffect(() => {
235
+ if (!canSkipFiscalization && skipFiscalization) {
236
+ setSkipFiscalization(false);
237
+ }
238
+ }, [canSkipFiscalization, skipFiscalization]);
239
+
240
+ // Check if FURS selection is ready (needed to prevent number flashing)
241
+ const isFursSelectionReady = !isFursEnabled || !hasFursPremises || (!!selectedPremiseName && !!selectedDeviceName);
242
+
243
+ // FURS is "active" for this advance invoice if enabled and we have a valid selection (and not skipped)
244
+ const isFursActive =
245
+ isFursEnabled && hasFursPremises && selectedPremiseName && selectedDeviceName && !skipFiscalization;
246
+
247
+ // ============================================================================
248
+ // Next Advance Invoice Number Preview
249
+ // ============================================================================
250
+ const { data: nextNumberData, isLoading: isNextNumberLoading } = useNextDocumentNumber(entityId, "advance_invoice", {
251
+ businessPremiseName: isFursActive ? selectedPremiseName : undefined,
252
+ electronicDeviceName: isFursActive ? selectedDeviceName : undefined,
253
+ enabled: !!entityId && !isFursLoading && isFursSelectionReady,
254
+ });
255
+
256
+ // Overall loading state
257
+ const isFormDataLoading = isFursLoading || !isFursSelectionReady || isNextNumberLoading;
258
+
259
+ // Update header action with FURS and e-SLOG toggle buttons
260
+ useEffect(() => {
261
+ if (!onHeaderActionChange) return;
262
+
263
+ if (isFursLoading) {
264
+ onHeaderActionChange(null);
265
+ return;
266
+ }
267
+
268
+ const showFursToggle = isFursEnabled && hasFursPremises;
269
+ const showEslogToggle = isEslogAvailable;
270
+
271
+ if (showFursToggle || showEslogToggle) {
272
+ const isFursChecked = !skipFiscalization;
273
+ const isEslogChecked = eslogValidationEnabled === true;
274
+
275
+ onHeaderActionChange(
276
+ <div className="flex items-center gap-2">
277
+ {/* e-SLOG toggle */}
278
+ {showEslogToggle && (
279
+ <TooltipProvider>
280
+ <Tooltip>
281
+ <TooltipTrigger asChild>
282
+ <Button
283
+ type="button"
284
+ variant={isEslogChecked ? "outline" : "ghost"}
285
+ size="sm"
286
+ className={cn("h-8 cursor-pointer gap-2", !isEslogChecked && "text-muted-foreground")}
287
+ onClick={() => setEslogValidationEnabled(!eslogValidationEnabled)}
288
+ >
289
+ <div
290
+ className={cn(
291
+ "flex size-4 items-center justify-center rounded border",
292
+ isEslogChecked
293
+ ? "border-primary bg-primary text-primary-foreground"
294
+ : "border-muted-foreground bg-background text-muted-foreground",
295
+ )}
296
+ >
297
+ {isEslogChecked ? <Check className="size-3" /> : <FileCode2 className="size-3" />}
298
+ </div>
299
+ <span>{t("e-SLOG")}</span>
300
+ </Button>
301
+ </TooltipTrigger>
302
+ <TooltipContent side="bottom" className="max-w-xs">
303
+ {isEslogChecked
304
+ ? t("Click to skip e-SLOG validation for this advance invoice")
305
+ : t("Click to enable e-SLOG validation")}
306
+ </TooltipContent>
307
+ </Tooltip>
308
+ </TooltipProvider>
309
+ )}
310
+
311
+ {/* FURS toggle */}
312
+ {showFursToggle && (
313
+ <TooltipProvider>
314
+ <Tooltip>
315
+ <TooltipTrigger asChild>
316
+ <Button
317
+ type="button"
318
+ variant={isFursChecked ? "outline" : "ghost"}
319
+ size="sm"
320
+ className={cn(
321
+ "h-8 cursor-pointer gap-2",
322
+ !canSkipFiscalization && "cursor-not-allowed opacity-50",
323
+ !isFursChecked && "text-destructive hover:text-destructive",
324
+ )}
325
+ onClick={() => canSkipFiscalization && setSkipFiscalization(!skipFiscalization)}
326
+ >
327
+ <div
328
+ className={cn(
329
+ "flex size-4 items-center justify-center rounded border",
330
+ isFursChecked
331
+ ? "border-primary bg-primary text-primary-foreground"
332
+ : "border-destructive bg-destructive text-destructive-foreground",
333
+ )}
334
+ >
335
+ {isFursChecked ? <Check className="size-3" /> : <X className="size-3" />}
336
+ </div>
337
+ <span>{t("Fiscally verify")}</span>
338
+ </Button>
339
+ </TooltipTrigger>
340
+ <TooltipContent side="bottom" className="max-w-xs">
341
+ {canSkipFiscalization
342
+ ? isFursChecked
343
+ ? t("Click to skip fiscalization for this advance invoice")
344
+ : t("Click to enable fiscalization")
345
+ : t("Cannot skip fiscalization for cash payments")}
346
+ </TooltipContent>
347
+ </Tooltip>
348
+ </TooltipProvider>
349
+ )}
350
+ </div>,
351
+ );
352
+ } else {
353
+ onHeaderActionChange(null);
354
+ }
355
+ }, [
356
+ isFursLoading,
357
+ isFursEnabled,
358
+ hasFursPremises,
359
+ skipFiscalization,
360
+ canSkipFiscalization,
361
+ isEslogAvailable,
362
+ eslogValidationEnabled,
363
+ onHeaderActionChange,
364
+ t,
365
+ ]);
366
+
367
+ // Pre-fill advance invoice number from preview
368
+ useEffect(() => {
369
+ if (nextNumberData?.number) {
370
+ form.setValue("number", nextNumberData.number);
371
+ }
372
+ }, [nextNumberData?.number, form]);
373
+
374
+ const formValues = useWatch({
375
+ control: form.control,
376
+ });
377
+
378
+ // ============================================================================
379
+ // VIES Check - determine if reverse charge applies
380
+ // ============================================================================
381
+ const { reverseChargeApplies, warning: viesWarning } = useViesCheck({
382
+ issuerCountryCode: activeEntity?.country_code,
383
+ isTaxSubject: activeEntity?.is_tax_subject ?? true,
384
+ customerCountry: formValues.customer?.country,
385
+ customerCountryCode: formValues.customer?.country_code,
386
+ customerTaxNumber: formValues.customer?.tax_number,
387
+ enabled: !!activeEntity,
388
+ });
389
+
390
+ // Customer form management
391
+ const {
392
+ originalCustomer,
393
+ showCustomerForm,
394
+ shouldFocusName,
395
+ selectedCustomerId,
396
+ initialCustomerName,
397
+ handleCustomerSelect,
398
+ handleCustomerClear,
399
+ } = useDocumentCustomerForm(form as any);
400
+
401
+ const { mutate: createAdvanceInvoice, isPending } = useCreateAdvanceInvoice({
402
+ entityId,
403
+ onSuccess: (data) => {
404
+ // Save FURS combo to localStorage on successful creation
405
+ if (isFursActive && selectedPremiseName && selectedDeviceName) {
406
+ setLastUsedFursCombo(entityId, {
407
+ business_premise_name: selectedPremiseName,
408
+ electronic_device_name: selectedDeviceName,
409
+ });
410
+ }
411
+ onSuccess?.(data);
412
+ },
413
+ onError,
414
+ });
415
+
416
+ // Shared submit logic for both regular save and save as draft
417
+ const submitAdvanceInvoice = useCallback(
418
+ (values: CreateAdvanceInvoiceFormValues, isDraft: boolean) => {
419
+ // Skip e-SLOG and FURS validation for drafts
420
+ if (!isDraft && eslogValidationEnabled) {
421
+ const validationErrors = validateEslogForm(values, activeEntity);
422
+
423
+ if (validationErrors.length > 0) {
424
+ const entityErrors = getEntityErrors(validationErrors);
425
+ const formErrors = getFormFieldErrors(validationErrors);
426
+ setEslogEntityErrors(entityErrors);
427
+ for (const error of formErrors) {
428
+ form.setError(error.field as any, {
429
+ type: "eslog",
430
+ message: error.message,
431
+ });
432
+ }
433
+ return;
434
+ }
435
+ setEslogEntityErrors([]);
436
+ }
437
+
438
+ // Build FURS options (skip for drafts)
439
+ const fursOptions =
440
+ !isDraft && isFursEnabled
441
+ ? skipFiscalization
442
+ ? { skip: true }
443
+ : selectedPremiseName && selectedDeviceName
444
+ ? { business_premise_name: selectedPremiseName, electronic_device_name: selectedDeviceName }
445
+ : undefined
446
+ : undefined;
447
+
448
+ // Build e-SLOG options (skip for drafts)
449
+ const eslogOptions =
450
+ !isDraft && isEslogAvailable ? { validation_enabled: eslogValidationEnabled === true } : undefined;
451
+
452
+ const payload = prepareAdvanceInvoiceSubmission(values, {
453
+ originalCustomer,
454
+ wasCustomerFormShown: showCustomerForm,
455
+ markAsPaid: isDraft ? false : markAsPaid,
456
+ paymentType,
457
+ furs: fursOptions,
458
+ eslog: eslogOptions,
459
+ priceModes: priceModesRef.current,
460
+ isDraft,
461
+ });
462
+
463
+ createAdvanceInvoice(payload);
464
+ },
465
+ [
466
+ activeEntity,
467
+ createAdvanceInvoice,
468
+ eslogValidationEnabled,
469
+ form,
470
+ isEslogAvailable,
471
+ isFursEnabled,
472
+ markAsPaid,
473
+ originalCustomer,
474
+ paymentType,
475
+ selectedDeviceName,
476
+ selectedPremiseName,
477
+ showCustomerForm,
478
+ skipFiscalization,
479
+ ],
480
+ );
481
+
482
+ // Handle save as draft
483
+ const handleSaveAsDraft = useCallback(async () => {
484
+ setIsDraftPending(true);
485
+ try {
486
+ const isValid = await form.trigger();
487
+ if (isValid) {
488
+ const values = form.getValues();
489
+ submitAdvanceInvoice(values, true);
490
+ }
491
+ } finally {
492
+ setIsDraftPending(false);
493
+ }
494
+ }, [form, submitAdvanceInvoice]);
495
+
496
+ useFormFooterRegistration({
497
+ formId: "create-advance-invoice-form",
498
+ isPending,
499
+ isDirty: form.formState.isDirty,
500
+ label: t("Save"),
501
+ secondaryAction: {
502
+ label: t("Save as Draft"),
503
+ onClick: handleSaveAsDraft,
504
+ isPending: isDraftPending,
505
+ },
506
+ });
507
+
508
+ // Set default note from entity settings (advance invoices don't have payment terms)
509
+ useEffect(() => {
510
+ const entityDefaultNote = (activeEntity?.settings as any)?.default_invoice_note;
511
+ if (entityDefaultNote && !form.getValues("note")) {
512
+ form.setValue("note", entityDefaultNote);
513
+ }
514
+ }, [activeEntity, form]);
515
+
516
+ // Auto-add tax field for tax subject entities
517
+ useEffect(() => {
518
+ if (activeEntity?.is_tax_subject) {
519
+ const items = form.getValues("items") || [];
520
+ if (items.length > 0 && (!items[0].taxes || items[0].taxes.length === 0)) {
521
+ form.setValue("items.0.taxes", [{ tax_id: undefined }]);
522
+ }
523
+ }
524
+ }, [activeEntity?.is_tax_subject, form]);
525
+
526
+ useEffect(() => {
527
+ if (onChange) {
528
+ const currentItems = form.getValues("items") || [];
529
+
530
+ // Transform items to use gross_price when price mode is gross
531
+ const transformedItems = currentItems.map((item: any, index: number) => {
532
+ const { price, ...rest } = item;
533
+ const isGross = priceModesRef.current[index] ?? false;
534
+ if (isGross) {
535
+ return { ...rest, gross_price: price };
536
+ }
537
+ return { ...rest, price };
538
+ });
539
+
540
+ const payload: AdvanceInvoicePreviewPayload = {
541
+ number: formValues.number,
542
+ date: formValues.date,
543
+ customer_id: formValues.customer_id,
544
+ customer: formValues.customer,
545
+ items: transformedItems,
546
+ currency_code: formValues.currency_code,
547
+ note: formValues.note,
548
+ };
549
+ onChange(payload);
550
+ }
551
+ }, [formValues, onChange, form]);
552
+
553
+ const onSubmit = (values: CreateAdvanceInvoiceFormValues) => {
554
+ submitAdvanceInvoice(values, false);
555
+ };
556
+
557
+ // Show skeleton while loading
558
+ if (isFormDataLoading) {
559
+ return (
560
+ <div className="space-y-8">
561
+ <div className="flex w-full flex-col md:flex-row md:gap-6">
562
+ <div className="flex-1 space-y-4">
563
+ <Skeleton className="h-7 w-24" />
564
+ <Skeleton className="h-10 w-full" />
565
+ </div>
566
+ <div className="flex-1 space-y-4">
567
+ <Skeleton className="h-7 w-20" />
568
+ <Skeleton className="h-5 w-16" />
569
+ <Skeleton className="h-10 w-full" />
570
+ <Skeleton className="h-5 w-12" />
571
+ <Skeleton className="h-10 w-full" />
572
+ <Skeleton className="h-5 w-16" />
573
+ <Skeleton className="h-10 w-full" />
574
+ <Skeleton className="h-5 w-20" />
575
+ <Skeleton className="h-10 w-full" />
576
+ <div className="space-y-3 rounded-md border p-4">
577
+ <div className="flex items-center gap-3">
578
+ <Skeleton className="h-4 w-4 rounded" />
579
+ <Skeleton className="h-5 w-28" />
580
+ </div>
581
+ </div>
582
+ </div>
583
+ </div>
584
+
585
+ <div className="space-y-4">
586
+ <Skeleton className="h-7 w-16" />
587
+ <div className="space-y-4 rounded-lg border p-4">
588
+ <Skeleton className="h-10 w-full" />
589
+ <div className="flex gap-4">
590
+ <Skeleton className="h-10 w-24" />
591
+ <Skeleton className="h-10 flex-1" />
592
+ </div>
593
+ </div>
594
+ <Skeleton className="h-9 w-24" />
595
+ </div>
596
+
597
+ <div className="space-y-2">
598
+ <Skeleton className="h-5 w-12" />
599
+ <Skeleton className="h-24 w-full" />
600
+ </div>
601
+
602
+ <Skeleton className="h-10 w-24" />
603
+ </div>
604
+ );
605
+ }
606
+
607
+ return (
608
+ <Form {...form}>
609
+ <form id="create-advance-invoice-form" onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
610
+ {/* e-SLOG entity-level validation errors */}
611
+ {eslogEntityErrors.length > 0 && (
612
+ <Alert variant="destructive">
613
+ <AlertCircle className="h-4 w-4" />
614
+ <AlertTitle>{t("e-SLOG Validation Failed")}</AlertTitle>
615
+ <AlertDescription>
616
+ <p className="mb-2">{t("The following entity settings need to be updated:")}</p>
617
+ <ul className="list-disc space-y-1 pl-4">
618
+ {eslogEntityErrors.map((error) => (
619
+ <li key={error.field} className="text-sm">
620
+ {error.message}
621
+ </li>
622
+ ))}
623
+ </ul>
624
+ </AlertDescription>
625
+ </Alert>
626
+ )}
627
+
628
+ <div className="flex w-full flex-col md:flex-row md:gap-6">
629
+ <DocumentRecipientSection
630
+ control={form.control}
631
+ entityId={entityId}
632
+ onCustomerSelect={handleCustomerSelect}
633
+ onCustomerClear={handleCustomerClear}
634
+ showCustomerForm={showCustomerForm}
635
+ shouldFocusName={shouldFocusName}
636
+ selectedCustomerId={selectedCustomerId}
637
+ initialCustomerName={initialCustomerName}
638
+ t={t}
639
+ />
640
+ <DocumentDetailsSection
641
+ control={form.control}
642
+ documentType={_type}
643
+ t={t}
644
+ fursInline={
645
+ isFursEnabled && hasFursPremises
646
+ ? {
647
+ premises: activePremises.map((p) => ({ id: p.id, business_premise_name: p.business_premise_name })),
648
+ devices: activeDevices.map((d) => ({ id: d.id, electronic_device_name: d.electronic_device_name })),
649
+ selectedPremise: selectedPremiseName,
650
+ selectedDevice: selectedDeviceName,
651
+ onPremiseChange: setSelectedPremiseName,
652
+ onDeviceChange: setSelectedDeviceName,
653
+ isSkipped: skipFiscalization,
654
+ }
655
+ : undefined
656
+ }
657
+ >
658
+ {/* Mark as paid section (UI-only state, not in form schema) */}
659
+ <MarkAsPaidSection
660
+ checked={markAsPaid}
661
+ onCheckedChange={setMarkAsPaid}
662
+ paymentType={paymentType}
663
+ onPaymentTypeChange={setPaymentType}
664
+ t={t}
665
+ />
666
+ </DocumentDetailsSection>
667
+ </div>
668
+
669
+ <DocumentItemsSection
670
+ control={form.control}
671
+ watch={form.watch}
672
+ setValue={form.setValue}
673
+ getValues={form.getValues}
674
+ entityId={entityId}
675
+ currencyCode={activeEntity?.currency_code ?? undefined}
676
+ onAddNewTax={onAddNewTax}
677
+ t={t}
678
+ taxesDisabled={reverseChargeApplies}
679
+ taxesDisabledMessage={
680
+ reverseChargeApplies ? t("Reverse charge - tax exempt EU B2B sale") : viesWarning ? viesWarning : undefined
681
+ }
682
+ maxTaxesPerItem={activeEntity?.country_rules?.max_taxes_per_item}
683
+ priceModesRef={priceModesRef}
684
+ initialPriceModes={initialPriceModes}
685
+ />
686
+
687
+ <DocumentNoteField
688
+ control={form.control}
689
+ t={t}
690
+ entity={activeEntity}
691
+ document={{
692
+ number: formValues.number,
693
+ date: formValues.date,
694
+ date_due: formValues.date_due,
695
+ currency_code: formValues.currency_code,
696
+ customer: formValues.customer as any,
697
+ }}
698
+ />
699
+ </form>
700
+ </Form>
701
+ );
702
+ }