@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,597 @@
1
+ /**
2
+ * Shared document details section for invoices and estimates
3
+ * Handles: number, date, and document-type-specific date field (date_due or date_valid_till)
4
+ */
5
+ import type { Entity, Estimate, Invoice } from "@spaceinvoices/js-sdk";
6
+ import { CalendarIcon } from "lucide-react";
7
+ import { useRef, useState } from "react";
8
+ import { Button } from "@/ui/components/ui/button";
9
+ import { Calendar } from "@/ui/components/ui/calendar";
10
+ import { FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/ui/components/ui/form";
11
+ import { Input } from "@/ui/components/ui/input";
12
+ import { Popover, PopoverContent, PopoverTrigger } from "@/ui/components/ui/popover";
13
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/ui/components/ui/select";
14
+ import { Textarea } from "@/ui/components/ui/textarea";
15
+ import { Tooltip, TooltipContent, TooltipTrigger } from "@/ui/components/ui/tooltip";
16
+ import { CURRENCY_CODES } from "@/ui/lib/constants";
17
+ import { cn } from "@/ui/lib/utils";
18
+ import type { DocumentTypes } from "../types";
19
+ import type { AnyControl } from "./form-types";
20
+ import { SmartCodeInsertButton } from "./smart-code-insert-button";
21
+
22
+ type FursPremise = {
23
+ id: string;
24
+ business_premise_name: string;
25
+ };
26
+
27
+ type FursDevice = {
28
+ id: string;
29
+ electronic_device_name: string;
30
+ };
31
+
32
+ type FursInlineProps = {
33
+ premises: FursPremise[];
34
+ devices: FursDevice[];
35
+ selectedPremise?: string;
36
+ selectedDevice?: string;
37
+ onPremiseChange: (value: string | undefined) => void;
38
+ onDeviceChange: (value: string | undefined) => void;
39
+ isSkipped?: boolean;
40
+ };
41
+
42
+ type ServiceDateProps = {
43
+ dateType: "single" | "range";
44
+ onDateTypeChange: (type: "single" | "range") => void;
45
+ };
46
+
47
+ type DocumentDetailsSectionProps = {
48
+ control: AnyControl;
49
+ documentType: DocumentTypes;
50
+ t: (key: string) => string;
51
+ children?: React.ReactNode; // For document-specific additions (e.g., mark as paid for invoices)
52
+ fursInline?: FursInlineProps; // FURS premise/device inline with number
53
+ serviceDate?: ServiceDateProps; // Service date section (invoice only)
54
+ };
55
+
56
+ export function DocumentDetailsSection({
57
+ control,
58
+ documentType,
59
+ t,
60
+ children,
61
+ fursInline,
62
+ serviceDate,
63
+ }: DocumentDetailsSectionProps) {
64
+ // Determine the date field name based on document type
65
+ const dateFieldName =
66
+ documentType === "invoice" || documentType === "advance_invoice" ? "date_due" : "date_valid_till";
67
+ const dateFieldLabel =
68
+ documentType === "invoice" || documentType === "advance_invoice" ? t("Due Date") : t("Valid Until");
69
+
70
+ // Check if FURS inline should show premise/device selects
71
+ const showFursSelects = fursInline && !fursInline.isSkipped;
72
+
73
+ return (
74
+ <div className="flex-1 space-y-4">
75
+ <h2 className="font-bold text-xl">{t("Details")}</h2>
76
+
77
+ {/* Number field - with optional FURS premise/device inline (Premise | Device | Number) */}
78
+ <FormField
79
+ control={control}
80
+ name="number"
81
+ render={({ field }) => (
82
+ <FormItem>
83
+ <FormLabel>{t("Number")} *</FormLabel>
84
+ {showFursSelects ? (
85
+ <div className="flex gap-2">
86
+ <Select
87
+ value={fursInline.selectedPremise || ""}
88
+ onValueChange={(v) => fursInline.onPremiseChange(v ?? undefined)}
89
+ >
90
+ <SelectTrigger className="w-24">
91
+ <SelectValue placeholder={t("Premise")} />
92
+ </SelectTrigger>
93
+ <SelectContent>
94
+ {fursInline.premises.map((premise) => (
95
+ <SelectItem key={premise.id} value={premise.business_premise_name}>
96
+ {premise.business_premise_name}
97
+ </SelectItem>
98
+ ))}
99
+ </SelectContent>
100
+ </Select>
101
+ <Select
102
+ value={fursInline.selectedDevice || ""}
103
+ onValueChange={(v) => fursInline.onDeviceChange(v ?? undefined)}
104
+ disabled={!fursInline.selectedPremise || fursInline.devices.length === 0}
105
+ >
106
+ <SelectTrigger className="w-24">
107
+ <SelectValue placeholder={t("Device")} />
108
+ </SelectTrigger>
109
+ <SelectContent>
110
+ {fursInline.devices.map((device) => (
111
+ <SelectItem key={device.id} value={device.electronic_device_name}>
112
+ {device.electronic_device_name}
113
+ </SelectItem>
114
+ ))}
115
+ </SelectContent>
116
+ </Select>
117
+ <Tooltip>
118
+ <TooltipTrigger asChild>
119
+ <FormControl>
120
+ <Input {...field} disabled className="flex-1" />
121
+ </FormControl>
122
+ </TooltipTrigger>
123
+ <TooltipContent>
124
+ <p>{t("Number format can be changed in settings")}</p>
125
+ </TooltipContent>
126
+ </Tooltip>
127
+ </div>
128
+ ) : (
129
+ <Tooltip>
130
+ <TooltipTrigger asChild>
131
+ <FormControl>
132
+ <Input {...field} disabled />
133
+ </FormControl>
134
+ </TooltipTrigger>
135
+ <TooltipContent>
136
+ <p>{t("Number format can be changed in settings")}</p>
137
+ </TooltipContent>
138
+ </Tooltip>
139
+ )}
140
+ <FormMessage />
141
+ </FormItem>
142
+ )}
143
+ />
144
+
145
+ <FormField
146
+ control={control}
147
+ name="date"
148
+ render={({ field }) => (
149
+ <FormItem>
150
+ <FormLabel className="">{t("Date")} *</FormLabel>
151
+ <Popover>
152
+ <PopoverTrigger asChild>
153
+ <FormControl>
154
+ <Button
155
+ variant="outline"
156
+ className={cn("w-full pl-3 text-left font-normal", !field.value && "text-muted-foreground")}
157
+ >
158
+ {field.value ? new Date(field.value).toLocaleDateString() : <span>{t("Pick a date")}</span>}
159
+ <CalendarIcon className="ml-auto h-4 w-4 opacity-50" />
160
+ </Button>
161
+ </FormControl>
162
+ </PopoverTrigger>
163
+ <PopoverContent className="w-auto p-0" align="start">
164
+ <Calendar
165
+ mode="single"
166
+ selected={field.value ? new Date(field.value) : undefined}
167
+ onSelect={(date) => field.onChange(date?.toISOString())}
168
+ disabled={(date) => date > new Date() || date < new Date("1900-01-01")}
169
+ initialFocus
170
+ />
171
+ </PopoverContent>
172
+ </Popover>
173
+ <FormMessage />
174
+ </FormItem>
175
+ )}
176
+ />
177
+
178
+ {/* Service Date - Invoice only */}
179
+ {serviceDate && (
180
+ <FormField
181
+ control={control}
182
+ name="date_service"
183
+ render={({ field }) => (
184
+ <FormItem>
185
+ <div className="flex items-center justify-between">
186
+ <FormLabel>{t("Service Date")}</FormLabel>
187
+ <Select
188
+ value={serviceDate.dateType}
189
+ onValueChange={(v) => serviceDate.onDateTypeChange(v as "single" | "range")}
190
+ >
191
+ <SelectTrigger className="h-7 w-auto gap-1 border-none px-2 font-normal text-xs shadow-none">
192
+ <SelectValue>{serviceDate.dateType === "single" ? t("Single Date") : t("Date Range")}</SelectValue>
193
+ </SelectTrigger>
194
+ <SelectContent>
195
+ <SelectItem value="single">{t("Single Date")}</SelectItem>
196
+ <SelectItem value="range">{t("Date Range")}</SelectItem>
197
+ </SelectContent>
198
+ </Select>
199
+ </div>
200
+
201
+ {serviceDate.dateType === "single" ? (
202
+ <Popover>
203
+ <PopoverTrigger asChild>
204
+ <FormControl>
205
+ <Button
206
+ variant="outline"
207
+ className={cn("w-full pl-3 text-left font-normal", !field.value && "text-muted-foreground")}
208
+ >
209
+ {field.value ? new Date(field.value).toLocaleDateString() : <span>{t("Pick a date")}</span>}
210
+ <CalendarIcon className="ml-auto h-4 w-4 opacity-50" />
211
+ </Button>
212
+ </FormControl>
213
+ </PopoverTrigger>
214
+ <PopoverContent className="w-auto p-0" align="start">
215
+ <Calendar
216
+ mode="single"
217
+ selected={field.value ? new Date(field.value) : undefined}
218
+ onSelect={(date) => field.onChange(date?.toISOString())}
219
+ initialFocus
220
+ />
221
+ </PopoverContent>
222
+ </Popover>
223
+ ) : (
224
+ <div className="grid grid-cols-2 gap-2">
225
+ <Popover>
226
+ <PopoverTrigger asChild>
227
+ <FormControl>
228
+ <Button
229
+ variant="outline"
230
+ className={cn("w-full pl-3 text-left font-normal", !field.value && "text-muted-foreground")}
231
+ >
232
+ {field.value ? new Date(field.value).toLocaleDateString() : <span>{t("From")}</span>}
233
+ <CalendarIcon className="ml-auto h-4 w-4 opacity-50" />
234
+ </Button>
235
+ </FormControl>
236
+ </PopoverTrigger>
237
+ <PopoverContent className="w-auto p-0" align="start">
238
+ <Calendar
239
+ mode="single"
240
+ selected={field.value ? new Date(field.value) : undefined}
241
+ onSelect={(date) => field.onChange(date?.toISOString())}
242
+ initialFocus
243
+ />
244
+ </PopoverContent>
245
+ </Popover>
246
+
247
+ <FormField
248
+ control={control}
249
+ name="date_service_to"
250
+ render={({ field: toField }) => (
251
+ <Popover>
252
+ <PopoverTrigger asChild>
253
+ <Button
254
+ variant="outline"
255
+ className={cn(
256
+ "w-full pl-3 text-left font-normal",
257
+ !toField.value && "text-muted-foreground",
258
+ )}
259
+ >
260
+ {toField.value ? new Date(toField.value).toLocaleDateString() : <span>{t("To")}</span>}
261
+ <CalendarIcon className="ml-auto h-4 w-4 opacity-50" />
262
+ </Button>
263
+ </PopoverTrigger>
264
+ <PopoverContent className="w-auto p-0" align="start">
265
+ <Calendar
266
+ mode="single"
267
+ selected={toField.value ? new Date(toField.value) : undefined}
268
+ onSelect={(date) => toField.onChange(date?.toISOString())}
269
+ initialFocus
270
+ />
271
+ </PopoverContent>
272
+ </Popover>
273
+ )}
274
+ />
275
+ </div>
276
+ )}
277
+ <FormMessage />
278
+ </FormItem>
279
+ )}
280
+ />
281
+ )}
282
+
283
+ <FormField
284
+ control={control}
285
+ name={dateFieldName}
286
+ render={({ field }) => (
287
+ <FormItem>
288
+ <FormLabel className="">{dateFieldLabel}</FormLabel>
289
+ <Popover>
290
+ <PopoverTrigger asChild>
291
+ <FormControl>
292
+ <Button
293
+ variant="outline"
294
+ className={cn("w-full pl-3 text-left font-normal", !field.value && "text-muted-foreground")}
295
+ >
296
+ {field.value ? new Date(field.value).toLocaleDateString() : <span>{t("Pick a date")}</span>}
297
+ <CalendarIcon className="ml-auto h-4 w-4 opacity-50" />
298
+ </Button>
299
+ </FormControl>
300
+ </PopoverTrigger>
301
+ <PopoverContent className="w-auto p-0" align="start">
302
+ <Calendar
303
+ mode="single"
304
+ selected={field.value ? new Date(field.value) : undefined}
305
+ onSelect={(date) => field.onChange(date?.toISOString())}
306
+ disabled={(date) => date < new Date("1900-01-01")}
307
+ initialFocus
308
+ />
309
+ </PopoverContent>
310
+ </Popover>
311
+ <FormMessage />
312
+ </FormItem>
313
+ )}
314
+ />
315
+
316
+ <FormField
317
+ control={control}
318
+ name="currency_code"
319
+ render={({ field }) => (
320
+ <FormItem>
321
+ <FormLabel>{t("Currency")} *</FormLabel>
322
+ <Select onValueChange={(value) => value && field.onChange(value)} value={field.value || ""}>
323
+ <FormControl>
324
+ <SelectTrigger className="h-10">
325
+ <SelectValue placeholder={t("Select currency")} />
326
+ </SelectTrigger>
327
+ </FormControl>
328
+ <SelectContent>
329
+ {CURRENCY_CODES.map((currency) => (
330
+ <SelectItem key={currency.value} value={currency.value}>
331
+ {currency.label}
332
+ </SelectItem>
333
+ ))}
334
+ </SelectContent>
335
+ </Select>
336
+ <FormMessage />
337
+ </FormItem>
338
+ )}
339
+ />
340
+
341
+ {/* Document-specific additions (e.g., mark as paid for invoices) */}
342
+ {children}
343
+ </div>
344
+ );
345
+ }
346
+
347
+ /**
348
+ * Note field component with smart code insertion button
349
+ * Exported for use in document forms (placed after items section)
350
+ */
351
+ // Helper functions for template variable replacement (shared with InputWithPreview)
352
+ function formatVariableName(varName: string): string {
353
+ return varName
354
+ .split("_")
355
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
356
+ .join(" ");
357
+ }
358
+
359
+ function getVariableValue(
360
+ varName: string,
361
+ entity?: Entity | null,
362
+ document?: Partial<Invoice | Estimate> | null,
363
+ ): string | null {
364
+ if (!entity) return null;
365
+
366
+ // Entity-related variables
367
+ if (varName === "entity_name") return entity.name || null;
368
+ if (varName === "entity_email") return (entity.settings as any)?.email || null;
369
+
370
+ // Date variables
371
+ if (varName === "current_date") {
372
+ return new Date().toLocaleDateString("en-US", { month: "long", day: "numeric", year: "numeric" });
373
+ }
374
+ if (varName === "current_year") return new Date().getFullYear().toString();
375
+
376
+ // Document-specific variables
377
+ if (document) {
378
+ if (varName === "document_number") return (document as any).number || null;
379
+ if (varName === "document_date" && (document as any).date) {
380
+ return new Date((document as any).date).toLocaleDateString("en-US", {
381
+ month: "long",
382
+ day: "numeric",
383
+ year: "numeric",
384
+ });
385
+ }
386
+ if (varName === "document_total" && (document as any).total_with_tax) {
387
+ return new Intl.NumberFormat("en-US", {
388
+ style: "currency",
389
+ currency: (document as any).currency_code || "USD",
390
+ }).format(Number((document as any).total_with_tax));
391
+ }
392
+ if (varName === "document_currency") return (document as any).currency_code || null;
393
+
394
+ // Invoice due date
395
+ if (varName === "document_due_date" && (document as any).date_due) {
396
+ return new Date((document as any).date_due).toLocaleDateString("en-US", {
397
+ month: "long",
398
+ day: "numeric",
399
+ year: "numeric",
400
+ });
401
+ }
402
+
403
+ // Estimate valid until
404
+ if (varName === "document_valid_until" && (document as any).date_valid_till) {
405
+ return new Date((document as any).date_valid_till).toLocaleDateString("en-US", {
406
+ month: "long",
407
+ day: "numeric",
408
+ year: "numeric",
409
+ });
410
+ }
411
+
412
+ // Customer variables
413
+ if ((document as any).customer) {
414
+ if (varName === "customer_name") return (document as any).customer.name || null;
415
+ if (varName === "customer_email") return (document as any).customer.email || null;
416
+ }
417
+ }
418
+
419
+ return null;
420
+ }
421
+
422
+ function replaceTemplateVariablesForPreview(
423
+ template: string,
424
+ entity?: Entity | null,
425
+ document?: Partial<Invoice | Estimate> | null,
426
+ ): React.ReactNode[] {
427
+ if (!template) return [];
428
+
429
+ const parts: React.ReactNode[] = [];
430
+ const regex = /\{([^}]+)\}/g;
431
+ let lastIndex = 0;
432
+ let match: RegExpExecArray | null = null;
433
+
434
+ match = regex.exec(template);
435
+ while (match !== null) {
436
+ if (match.index > lastIndex) {
437
+ parts.push(template.slice(lastIndex, match.index));
438
+ }
439
+
440
+ const varName = match[1];
441
+ const actualValue = getVariableValue(varName, entity, document);
442
+ const displayValue = actualValue || formatVariableName(varName);
443
+
444
+ parts.push(
445
+ <span
446
+ key={match.index}
447
+ className={cn(
448
+ "rounded px-1.5 py-0.5 font-medium text-xs",
449
+ actualValue ? "bg-secondary text-secondary-foreground" : "bg-primary/10 text-primary",
450
+ )}
451
+ >
452
+ {displayValue}
453
+ </span>,
454
+ );
455
+
456
+ lastIndex = regex.lastIndex;
457
+ match = regex.exec(template);
458
+ }
459
+
460
+ if (lastIndex < template.length) {
461
+ parts.push(template.slice(lastIndex));
462
+ }
463
+
464
+ return parts;
465
+ }
466
+
467
+ export function DocumentNoteField({
468
+ control,
469
+ t,
470
+ entity,
471
+ document,
472
+ }: {
473
+ control: AnyControl;
474
+ t: (key: string) => string;
475
+ entity?: Entity | null;
476
+ document?: Partial<Invoice | Estimate> | null;
477
+ }) {
478
+ const textareaRef = useRef<HTMLTextAreaElement>(null);
479
+ const [isFocused, setIsFocused] = useState(false);
480
+
481
+ return (
482
+ <FormField
483
+ control={control}
484
+ name="note"
485
+ render={({ field }) => {
486
+ const hasContent = field.value;
487
+ const showPreview = !isFocused && hasContent && entity;
488
+ const preview = showPreview ? replaceTemplateVariablesForPreview(field.value || "", entity, document) : null;
489
+
490
+ return (
491
+ <FormItem>
492
+ <div className="flex items-center justify-between">
493
+ <FormLabel>{t("Note")}</FormLabel>
494
+ <SmartCodeInsertButton
495
+ textareaRef={textareaRef}
496
+ value={field.value || ""}
497
+ onInsert={(newValue) => field.onChange(newValue)}
498
+ t={t}
499
+ />
500
+ </div>
501
+ <FormControl>
502
+ <div className="relative">
503
+ <Textarea
504
+ {...field}
505
+ ref={(e) => {
506
+ field.ref(e);
507
+ (textareaRef as React.MutableRefObject<HTMLTextAreaElement | null>).current = e;
508
+ }}
509
+ value={field.value || ""}
510
+ placeholder={showPreview ? "" : t("Add payment instructions, terms, or other notes...")}
511
+ rows={5}
512
+ className={cn("resize-y", showPreview && "text-transparent caret-transparent")}
513
+ onFocus={() => setIsFocused(true)}
514
+ onBlur={() => setIsFocused(false)}
515
+ />
516
+ {showPreview && (
517
+ <div className="pointer-events-none absolute inset-0 z-10 flex items-start overflow-hidden rounded-md border border-input bg-background px-3 py-2 shadow-xs">
518
+ <div className="w-full whitespace-pre-wrap text-base md:text-sm">{preview}</div>
519
+ </div>
520
+ )}
521
+ </div>
522
+ </FormControl>
523
+ <FormMessage />
524
+ </FormItem>
525
+ );
526
+ }}
527
+ />
528
+ );
529
+ }
530
+
531
+ /**
532
+ * Payment terms field component with smart code insertion button
533
+ * Similar to DocumentNoteField, exported for use in document forms
534
+ */
535
+ export function DocumentPaymentTermsField({
536
+ control,
537
+ t,
538
+ entity,
539
+ document,
540
+ }: {
541
+ control: AnyControl;
542
+ t: (key: string) => string;
543
+ entity?: Entity | null;
544
+ document?: Partial<Invoice | Estimate> | null;
545
+ }) {
546
+ const textareaRef = useRef<HTMLTextAreaElement>(null);
547
+ const [isFocused, setIsFocused] = useState(false);
548
+
549
+ return (
550
+ <FormField
551
+ control={control}
552
+ name="payment_terms"
553
+ render={({ field }) => {
554
+ const hasContent = field.value;
555
+ const showPreview = !isFocused && hasContent && entity;
556
+ const preview = showPreview ? replaceTemplateVariablesForPreview(field.value || "", entity, document) : null;
557
+
558
+ return (
559
+ <FormItem>
560
+ <div className="flex items-center justify-between">
561
+ <FormLabel>{t("Payment Terms")}</FormLabel>
562
+ <SmartCodeInsertButton
563
+ textareaRef={textareaRef}
564
+ value={field.value || ""}
565
+ onInsert={(newValue) => field.onChange(newValue)}
566
+ t={t}
567
+ />
568
+ </div>
569
+ <FormControl>
570
+ <div className="relative">
571
+ <Textarea
572
+ {...field}
573
+ ref={(e) => {
574
+ field.ref(e);
575
+ (textareaRef as React.MutableRefObject<HTMLTextAreaElement | null>).current = e;
576
+ }}
577
+ value={field.value || ""}
578
+ placeholder={showPreview ? "" : t("Add payment terms...")}
579
+ rows={3}
580
+ className={cn("resize-y", showPreview && "text-transparent caret-transparent")}
581
+ onFocus={() => setIsFocused(true)}
582
+ onBlur={() => setIsFocused(false)}
583
+ />
584
+ {showPreview && (
585
+ <div className="pointer-events-none absolute inset-0 z-10 flex items-start overflow-hidden rounded-md border border-input bg-background px-3 py-2 shadow-xs">
586
+ <div className="w-full whitespace-pre-wrap text-base md:text-sm">{preview}</div>
587
+ </div>
588
+ )}
589
+ </div>
590
+ </FormControl>
591
+ <FormMessage />
592
+ </FormItem>
593
+ );
594
+ }}
595
+ />
596
+ );
597
+ }