@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,18 @@
1
+ export default {
2
+ "Send Invoice by Email": "Rechnung per E-Mail senden",
3
+ "Send invoice by email description":
4
+ "Senden Sie Rechnung #{number} per E-Mail an einen Kunden. Markdown-Formatierung wird im Text unterstützt.",
5
+ "Recipient Email": "Empfänger E-Mail",
6
+ "Subject (Optional)": "Betreff (Optional)",
7
+ "Invoice Subject": "Rechnungsbetreff",
8
+ "Leave empty to use default": "Leer lassen für Standardwert",
9
+ "Message (Optional)": "Nachricht (Optional)",
10
+ "Email message placeholder": "E-Mail-Nachricht... Unterstützt **fett**, *kursiv*, [Links](url) und Listen",
11
+ Cancel: "Abbrechen",
12
+ "Send Email": "E-Mail senden",
13
+ "Email sent": "E-Mail gesendet",
14
+ "Invoice sent to": "Rechnung gesendet an",
15
+ "Failed to send email": "E-Mail konnte nicht gesendet werden",
16
+ "Sandbox email warning":
17
+ "Im Sandbox-Modus können E-Mails nur an verifizierte Teammitglieder dieses Kontos gesendet werden.",
18
+ } as const;
@@ -0,0 +1,17 @@
1
+ export default {
2
+ "Send Invoice by Email": "Pošlji račun po e-pošti",
3
+ "Send invoice by email description":
4
+ "Pošljite račun #{number} stranki po e-pošti. V besedilu je podprto oblikovanje Markdown.",
5
+ "Recipient Email": "E-pošta prejemnika",
6
+ "Subject (Optional)": "Zadeva (neobvezno)",
7
+ "Invoice Subject": "Zadeva računa",
8
+ "Leave empty to use default": "Pustite prazno za privzeto vrednost",
9
+ "Message (Optional)": "Sporočilo (neobvezno)",
10
+ "Email message placeholder": "E-poštno sporočilo... Podpira **krepko**, *ležeče*, [povezave](url) in sezname",
11
+ Cancel: "Prekliči",
12
+ "Send Email": "Pošlji e-pošto",
13
+ "Email sent": "E-pošta poslana",
14
+ "Invoice sent to": "Račun poslan na",
15
+ "Failed to send email": "Pošiljanje e-pošte ni uspelo",
16
+ "Sandbox email warning": "V testnem načinu lahko pošiljate e-pošto samo verificiranim članom ekipe tega računa.",
17
+ } as const;
@@ -0,0 +1,289 @@
1
+ import { zodResolver } from "@hookform/resolvers/zod";
2
+ import type { Invoice } from "@spaceinvoices/js-sdk";
3
+ import { AlertCircle, Mail } from "lucide-react";
4
+ import { useEffect, useState } from "react";
5
+ import type { Resolver } from "react-hook-form";
6
+ import { useForm } from "react-hook-form";
7
+ import { toast } from "sonner";
8
+ import { InputWithPreview } from "@/ui/components/entities/entity-settings-form/input-with-preview";
9
+ import { Alert, AlertDescription } from "@/ui/components/ui/alert";
10
+ import { Button } from "@/ui/components/ui/button";
11
+ import {
12
+ Dialog,
13
+ DialogContent,
14
+ DialogDescription,
15
+ DialogHeader,
16
+ DialogTitle,
17
+ DialogTrigger,
18
+ } from "@/ui/components/ui/dialog";
19
+ import {
20
+ Form,
21
+ FormControl,
22
+ FormDescription,
23
+ FormField,
24
+ FormItem,
25
+ FormLabel,
26
+ FormMessage,
27
+ } from "@/ui/components/ui/form";
28
+ import { Input } from "@/ui/components/ui/input";
29
+ import { Spinner } from "@/ui/components/ui/spinner";
30
+ import { type SendEmailSchema, sendEmailSchema } from "@/ui/generated/schemas";
31
+ import type { ComponentTranslationProps } from "@/ui/lib/translation";
32
+ import { createTranslation } from "@/ui/lib/translation";
33
+ import { useEntities } from "@/ui/providers/entities-context";
34
+ import { useSDK } from "@/ui/providers/sdk-provider";
35
+ import de from "./locales/de";
36
+ import sl from "./locales/sl";
37
+
38
+ const translations = { de, sl } as const;
39
+
40
+ type SendEmailDialogProps = {
41
+ invoice: Invoice;
42
+ defaultEmail?: string;
43
+ defaultSubject?: string;
44
+ defaultBody?: string;
45
+ onSuccess?: () => void;
46
+ onError?: (error: string) => void;
47
+ ButtonLoader?: React.ComponentType;
48
+ /** When true, only renders a DropdownMenuItem trigger (deprecated - use controlled mode instead) */
49
+ renderAsDropdownItem?: boolean;
50
+ /** @deprecated Use locale prop instead */
51
+ translationFn?: (key: string) => string;
52
+ /** Controlled mode: externally control dialog open state */
53
+ open?: boolean;
54
+ /** Controlled mode: callback when open state changes */
55
+ onOpenChange?: (open: boolean) => void;
56
+ } & ComponentTranslationProps;
57
+
58
+ export function SendEmailDialog({
59
+ invoice,
60
+ defaultEmail = "",
61
+ defaultSubject = "",
62
+ defaultBody = "",
63
+ onSuccess,
64
+ onError,
65
+ ButtonLoader,
66
+ renderAsDropdownItem = false,
67
+ translationFn,
68
+ open: controlledOpen,
69
+ onOpenChange,
70
+ locale = "en",
71
+ ...i18nProps
72
+ }: SendEmailDialogProps) {
73
+ const t = translationFn || createTranslation({ translations, locale, ...i18nProps });
74
+
75
+ const [internalOpen, setInternalOpen] = useState(false);
76
+
77
+ // Support both controlled and uncontrolled modes
78
+ const isControlled = controlledOpen !== undefined;
79
+ const open = isControlled ? controlledOpen : internalOpen;
80
+ // biome-ignore lint/suspicious/noEmptyBlockStatements: noop fallback for controlled mode
81
+ const setOpen = isControlled ? onOpenChange || (() => {}) : setInternalOpen;
82
+ const [isLoading, setIsLoading] = useState(false);
83
+ const { sdk } = useSDK();
84
+ const { activeEntity } = useEntities();
85
+
86
+ // Get entity email defaults if not provided
87
+ const entitySettings = (activeEntity?.settings as Record<string, any>) || {};
88
+ const emailDefaults = entitySettings.email_defaults || {};
89
+
90
+ const finalSubject = defaultSubject || emailDefaults.invoice_subject || `Invoice #${invoice.number}`;
91
+ const finalBody =
92
+ defaultBody || emailDefaults.invoice_body || `Please find your invoice #${invoice.number} attached.`;
93
+
94
+ const form = useForm<SendEmailSchema>({
95
+ resolver: zodResolver(sendEmailSchema) as Resolver<SendEmailSchema>,
96
+ defaultValues: {
97
+ to: defaultEmail,
98
+ subject: finalSubject,
99
+ bodyText: finalBody,
100
+ attachPdf: false,
101
+ },
102
+ });
103
+
104
+ // Reset form and fetch customer email when dialog opens
105
+ useEffect(() => {
106
+ if (!open) return;
107
+
108
+ // Reset form to defaults when dialog opens
109
+ form.reset({
110
+ to: defaultEmail,
111
+ subject: finalSubject,
112
+ bodyText: finalBody,
113
+ attachPdf: false,
114
+ });
115
+
116
+ // Fetch customer email from linked customer if not in invoice snapshot
117
+ const fetchCustomerEmail = async () => {
118
+ if (defaultEmail || !invoice.customer_id || !sdk || !activeEntity?.id) {
119
+ return;
120
+ }
121
+
122
+ try {
123
+ const response = await sdk.customers.list(
124
+ { query: JSON.stringify({ id: invoice.customer_id }), limit: 1 },
125
+ { entity_id: activeEntity.id },
126
+ );
127
+
128
+ const customer = response.data[0];
129
+ if (customer?.email) {
130
+ form.setValue("to", customer.email);
131
+ }
132
+ } catch {
133
+ // Silently fail - customer might not exist or not have email
134
+ }
135
+ };
136
+
137
+ fetchCustomerEmail();
138
+ }, [open, defaultEmail, invoice.customer_id, sdk, activeEntity?.id, form, finalSubject, finalBody]);
139
+
140
+ const onSubmit = async (values: SendEmailSchema) => {
141
+ setIsLoading(true);
142
+ try {
143
+ if (!sdk) throw new Error("SDK not initialized");
144
+
145
+ // Ensure we have an active entity
146
+ if (!activeEntity?.id) throw new Error("Entity context required");
147
+
148
+ // Call the email API endpoint using SDK
149
+ await (sdk.email as any).send(
150
+ {
151
+ to: values.to,
152
+ subject: values.subject,
153
+ bodyText: values.bodyText,
154
+ documentId: invoice.id,
155
+ },
156
+ { entity_id: activeEntity.id },
157
+ );
158
+
159
+ toast.success(t("Email sent"), {
160
+ description: `${t("Invoice sent to")} ${values.to}`,
161
+ });
162
+
163
+ setOpen(false);
164
+ form.reset();
165
+ onSuccess?.();
166
+ } catch (error) {
167
+ const errorMessage = error instanceof Error ? error.message : t("Failed to send email");
168
+ toast.error(t("Failed to send email"), {
169
+ description: errorMessage,
170
+ });
171
+ onError?.(errorMessage);
172
+ } finally {
173
+ setIsLoading(false);
174
+ }
175
+ };
176
+
177
+ // In controlled mode, no trigger is rendered - parent controls the dialog
178
+ const showTrigger = !isControlled && !renderAsDropdownItem;
179
+
180
+ return (
181
+ <Dialog open={open} onOpenChange={setOpen}>
182
+ {showTrigger && (
183
+ <DialogTrigger asChild>
184
+ <Button variant="ghost" size="sm" className="h-8 w-8 cursor-pointer p-0">
185
+ <Mail className="h-4 w-4" />
186
+ <span className="sr-only">{t("Send Email")}</span>
187
+ </Button>
188
+ </DialogTrigger>
189
+ )}
190
+ <DialogContent className="sm:max-w-md">
191
+ <DialogHeader>
192
+ <DialogTitle>{t("Send Invoice by Email")}</DialogTitle>
193
+ <DialogDescription>
194
+ {t("Send invoice by email description").replace("{number}", invoice.number)}
195
+ </DialogDescription>
196
+ </DialogHeader>
197
+
198
+ {activeEntity?.environment === "sandbox" && (
199
+ <Alert className="border-amber-200 bg-amber-50 dark:border-amber-900 dark:bg-amber-950">
200
+ <AlertCircle className="h-4 w-4 text-amber-600" />
201
+ <AlertDescription className="text-amber-800 dark:text-amber-200">
202
+ {t("Sandbox email warning")}
203
+ </AlertDescription>
204
+ </Alert>
205
+ )}
206
+
207
+ <Form {...form}>
208
+ <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
209
+ <FormField
210
+ control={form.control}
211
+ name="to"
212
+ render={({ field }) => (
213
+ <FormItem>
214
+ <FormLabel>{t("Recipient Email")}</FormLabel>
215
+ <FormControl>
216
+ <Input type="email" placeholder="customer@example.com" {...field} disabled={isLoading} />
217
+ </FormControl>
218
+ <FormMessage />
219
+ </FormItem>
220
+ )}
221
+ />
222
+
223
+ <FormField
224
+ control={form.control}
225
+ name="subject"
226
+ render={({ field }) => (
227
+ <FormItem>
228
+ <FormLabel>{t("Subject (Optional)")}</FormLabel>
229
+ <FormControl>
230
+ <InputWithPreview
231
+ value={field.value || ""}
232
+ onChange={field.onChange}
233
+ placeholder={t("Invoice Subject")}
234
+ entity={activeEntity!}
235
+ document={invoice}
236
+ disabled={isLoading}
237
+ className="h-10"
238
+ />
239
+ </FormControl>
240
+ <FormDescription>{t("Leave empty to use default")}</FormDescription>
241
+ <FormMessage />
242
+ </FormItem>
243
+ )}
244
+ />
245
+
246
+ <FormField
247
+ control={form.control}
248
+ name="bodyText"
249
+ render={({ field }) => (
250
+ <FormItem>
251
+ <FormLabel>{t("Message (Optional)")}</FormLabel>
252
+ <FormControl>
253
+ <InputWithPreview
254
+ value={field.value || ""}
255
+ onChange={field.onChange}
256
+ placeholder={t("Email message placeholder")}
257
+ entity={activeEntity!}
258
+ document={invoice}
259
+ disabled={isLoading}
260
+ multiline
261
+ rows={4}
262
+ />
263
+ </FormControl>
264
+ <FormDescription>{t("Leave empty to use default")}</FormDescription>
265
+ <FormMessage />
266
+ </FormItem>
267
+ )}
268
+ />
269
+
270
+ <div className="flex justify-end gap-2">
271
+ <Button
272
+ type="button"
273
+ variant="outline"
274
+ className="cursor-pointer"
275
+ onClick={() => setOpen(false)}
276
+ disabled={isLoading}
277
+ >
278
+ {t("Cancel")}
279
+ </Button>
280
+ <Button type="submit" className="min-w-[100px] cursor-pointer" disabled={isLoading}>
281
+ {isLoading ? ButtonLoader ? <ButtonLoader /> : <Spinner /> : t("Send Email")}
282
+ </Button>
283
+ </div>
284
+ </form>
285
+ </Form>
286
+ </DialogContent>
287
+ </Dialog>
288
+ );
289
+ }
@@ -0,0 +1,2 @@
1
+ // Re-export from new location for backwards compatibility
2
+ export { SendEmailDialog } from "./send-email-dialog/send-email-dialog";
@@ -0,0 +1,2 @@
1
+ export { ScaledDocumentPreview } from "./scaled-document-preview";
2
+ export { useA4Scaling } from "./use-a4-scaling";
@@ -0,0 +1,32 @@
1
+ // Stub file - TODO: implement properly
2
+ import type { RefObject } from "react";
3
+
4
+ type ScaledDocumentPreviewProps = {
5
+ htmlContent: string;
6
+ scale: number;
7
+ contentHeight: number;
8
+ A4_WIDTH_PX: number;
9
+ contentRef: RefObject<HTMLDivElement>;
10
+ entityUpdatedAt?: string;
11
+ };
12
+
13
+ export function ScaledDocumentPreview({
14
+ htmlContent,
15
+ scale,
16
+ contentHeight,
17
+ A4_WIDTH_PX,
18
+ contentRef,
19
+ }: ScaledDocumentPreviewProps) {
20
+ return (
21
+ <div
22
+ ref={contentRef}
23
+ style={{
24
+ width: A4_WIDTH_PX,
25
+ transform: `scale(${scale})`,
26
+ transformOrigin: "top left",
27
+ height: contentHeight,
28
+ }}
29
+ dangerouslySetInnerHTML={{ __html: htmlContent }}
30
+ />
31
+ );
32
+ }
@@ -0,0 +1,39 @@
1
+ // Stub file - TODO: implement properly
2
+ import { useEffect, useRef, useState } from "react";
3
+
4
+ const A4_WIDTH_PX = 794; // A4 width at 96 DPI
5
+
6
+ export function useA4Scaling(content: string) {
7
+ const containerRef = useRef<HTMLDivElement>(null);
8
+ const contentRef = useRef<HTMLDivElement>(null);
9
+ const [scale, setScale] = useState(1);
10
+ const [contentHeight, setContentHeight] = useState(0);
11
+
12
+ useEffect(() => {
13
+ if (!containerRef.current || !content) return;
14
+
15
+ const updateScale = () => {
16
+ const containerWidth = containerRef.current?.clientWidth || A4_WIDTH_PX;
17
+ const newScale = Math.min(1, containerWidth / A4_WIDTH_PX);
18
+ setScale(newScale);
19
+ };
20
+
21
+ updateScale();
22
+ window.addEventListener("resize", updateScale);
23
+ return () => window.removeEventListener("resize", updateScale);
24
+ }, [content]);
25
+
26
+ useEffect(() => {
27
+ if (contentRef.current) {
28
+ setContentHeight(contentRef.current.scrollHeight * scale);
29
+ }
30
+ }, [scale]);
31
+
32
+ return {
33
+ containerRef,
34
+ contentRef,
35
+ scale,
36
+ contentHeight,
37
+ A4_WIDTH_PX,
38
+ };
39
+ }
@@ -0,0 +1,160 @@
1
+ import type { Entity, Invoice } from "@spaceinvoices/js-sdk";
2
+ import { AlertCircle, CheckCircle2, Download, FileCode2, XCircle } from "lucide-react";
3
+ import { Alert, AlertDescription, AlertTitle } from "@/ui/components/ui/alert";
4
+ import { Badge } from "@/ui/components/ui/badge";
5
+ import { Button } from "@/ui/components/ui/button";
6
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/ui/components/ui/card";
7
+ import type { ComponentTranslationProps } from "@/ui/lib/translation";
8
+ import { createTranslation } from "@/ui/lib/translation";
9
+
10
+ // Type for eslog data
11
+ interface EslogData {
12
+ validation_enabled?: boolean | null;
13
+ validation_status?: "valid" | "invalid" | "not_validated" | null;
14
+ validation_errors?: string[] | null;
15
+ validated_at?: string | null;
16
+ }
17
+
18
+ interface EslogInfoDisplayProps extends ComponentTranslationProps {
19
+ invoice: Invoice;
20
+ /** Entity is used to determine if e-SLOG should be shown (for SI entities) */
21
+ entity?: Entity | null;
22
+ onDownload?: () => void;
23
+ isDownloading?: boolean;
24
+ showDownloadButton?: boolean;
25
+ /** When true, force show the component even if no eslog data exists (for SI entities with validation enabled) */
26
+ forceShow?: boolean;
27
+ }
28
+
29
+ /**
30
+ * e-SLOG Info Display Component
31
+ *
32
+ * Shows e-SLOG validation status, errors, and download button for valid documents
33
+ */
34
+ export function EslogInfoDisplay({
35
+ invoice,
36
+ entity,
37
+ onDownload,
38
+ isDownloading,
39
+ showDownloadButton = true,
40
+ forceShow = false,
41
+ t: translateFn,
42
+ namespace,
43
+ locale,
44
+ }: EslogInfoDisplayProps) {
45
+ const t = createTranslation({
46
+ t: translateFn,
47
+ namespace,
48
+ locale,
49
+ translations: {},
50
+ });
51
+
52
+ // Cast eslog to the proper type
53
+ const eslog = invoice.eslog as EslogData | undefined | null;
54
+
55
+ // Check if entity is Slovenian and has e-SLOG validation enabled in settings
56
+ const isSlovenianEntity = entity?.country_code === "SI";
57
+ const entityEslogEnabled = !!(entity?.settings as any)?.eslog_validation_enabled;
58
+
59
+ // Show component if:
60
+ // 1. Document has eslog data, OR
61
+ // 2. Entity is Slovenian with eslog enabled (forceShow), OR
62
+ // 3. forceShow is explicitly true
63
+ const shouldShow = eslog || (forceShow && isSlovenianEntity && entityEslogEnabled);
64
+
65
+ if (!shouldShow) {
66
+ return null;
67
+ }
68
+
69
+ // If no eslog data but we should show (SI entity with setting enabled), treat as not_validated
70
+ const effectiveEslog: EslogData = eslog || {
71
+ validation_status: "not_validated",
72
+ validation_enabled: null,
73
+ validation_errors: null,
74
+ validated_at: null,
75
+ };
76
+
77
+ const getStatusBadge = () => {
78
+ switch (effectiveEslog.validation_status) {
79
+ case "valid":
80
+ return (
81
+ <Badge className="bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-100">
82
+ <CheckCircle2 className="mr-1 h-3 w-3" />
83
+ {t("Valid")}
84
+ </Badge>
85
+ );
86
+ case "invalid":
87
+ return (
88
+ <Badge className="bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-100">
89
+ <XCircle className="mr-1 h-3 w-3" />
90
+ {t("Invalid")}
91
+ </Badge>
92
+ );
93
+ case "not_validated":
94
+ return (
95
+ <Badge className="bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-100">{t("Not validated")}</Badge>
96
+ );
97
+ default:
98
+ return (
99
+ <Badge className="bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-100">{t("Not validated")}</Badge>
100
+ );
101
+ }
102
+ };
103
+
104
+ return (
105
+ <Card>
106
+ <CardHeader>
107
+ <CardTitle className="flex items-center gap-2">
108
+ <FileCode2 className="h-5 w-5" />
109
+ {t("e-SLOG 2.0")}
110
+ {getStatusBadge()}
111
+ </CardTitle>
112
+ <CardDescription>{t("Slovenian electronic invoice format (EN 16931)")}</CardDescription>
113
+ </CardHeader>
114
+ <CardContent className="space-y-4">
115
+ {/* Validation Errors */}
116
+ {effectiveEslog.validation_status === "invalid" &&
117
+ effectiveEslog.validation_errors &&
118
+ effectiveEslog.validation_errors.length > 0 && (
119
+ <Alert variant="destructive">
120
+ <AlertCircle className="h-4 w-4" />
121
+ <AlertTitle>{t("Validation Errors")}</AlertTitle>
122
+ <AlertDescription>
123
+ <ul className="mt-2 list-disc space-y-1 pl-4">
124
+ {effectiveEslog.validation_errors.map((error, index) => (
125
+ <li key={index} className="text-sm">
126
+ {error}
127
+ </li>
128
+ ))}
129
+ </ul>
130
+ </AlertDescription>
131
+ </Alert>
132
+ )}
133
+
134
+ {/* Download Button for valid documents */}
135
+ {showDownloadButton && effectiveEslog.validation_status === "valid" && onDownload && (
136
+ <Button onClick={onDownload} disabled={isDownloading} className="w-full" variant="outline">
137
+ <Download className="mr-2 h-4 w-4" />
138
+ {isDownloading ? t("Downloading...") : t("Download e-SLOG XML")}
139
+ </Button>
140
+ )}
141
+
142
+ {/* Not validated info */}
143
+ {(effectiveEslog.validation_status === "not_validated" || !effectiveEslog.validation_status) && (
144
+ <div className="rounded-lg border border-gray-200 bg-gray-50 p-3 text-gray-600 text-sm dark:border-gray-700 dark:bg-gray-800 dark:text-gray-300">
145
+ {t(
146
+ "This document has not been validated for e-SLOG. Enable validation in entity settings or on the document to validate.",
147
+ )}
148
+ </div>
149
+ )}
150
+
151
+ {/* Validation timestamp */}
152
+ {effectiveEslog.validated_at && (
153
+ <div className="pt-2 text-muted-foreground text-sm">
154
+ {t("Validated at")}: {new Date(effectiveEslog.validated_at).toLocaleString()}
155
+ </div>
156
+ )}
157
+ </CardContent>
158
+ </Card>
159
+ );
160
+ }