@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,213 @@
1
+ import type { FursFiscalizationResponse, Invoice } from "@spaceinvoices/js-sdk";
2
+ import { AlertCircle, Check, CheckCircle2, Clock, Copy, XCircle } from "lucide-react";
3
+ import { useState } from "react";
4
+ import { Alert, AlertDescription, AlertTitle } from "@/ui/components/ui/alert";
5
+ import { Badge } from "@/ui/components/ui/badge";
6
+ import { Button } from "@/ui/components/ui/button";
7
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/ui/components/ui/card";
8
+ import type { ComponentTranslationProps } from "@/ui/lib/translation";
9
+ import { createTranslation } from "@/ui/lib/translation";
10
+ import de from "../../entities/furs-settings-form/locales/de";
11
+ import en from "../../entities/furs-settings-form/locales/en";
12
+ import sl from "../../entities/furs-settings-form/locales/sl";
13
+
14
+ const translations = { de, sl, en } as const;
15
+
16
+ // Type alias for easier use
17
+ type FursData = FursFiscalizationResponse;
18
+
19
+ interface FursInfoDisplayProps extends ComponentTranslationProps {
20
+ invoice: Invoice;
21
+ }
22
+
23
+ /**
24
+ * FURS Fiscalization Info Display Component
25
+ *
26
+ * Shows FURS fiscalization status, ZOI, EOR, QR code, and other related data
27
+ */
28
+ export function FursInfoDisplay({ invoice, t: translateFn, namespace, locale }: FursInfoDisplayProps) {
29
+ const [copiedField, setCopiedField] = useState<string | null>(null);
30
+
31
+ const t = createTranslation({
32
+ t: translateFn,
33
+ namespace,
34
+ locale,
35
+ translations,
36
+ });
37
+
38
+ // Cast furs to the proper type (SDK has it as object, but it's actually FursData)
39
+ const furs = invoice.furs as FursData | undefined;
40
+
41
+ // If no FURS data, don't render anything
42
+ if (!furs) {
43
+ return null;
44
+ }
45
+
46
+ const copyToClipboard = async (text: string, fieldName: string) => {
47
+ try {
48
+ await navigator.clipboard.writeText(text);
49
+ setCopiedField(fieldName);
50
+ setTimeout(() => setCopiedField(null), 2000);
51
+ } catch (err) {
52
+ console.error("Failed to copy:", err);
53
+ }
54
+ };
55
+
56
+ const getStatusBadge = () => {
57
+ switch (furs.status) {
58
+ case "success":
59
+ return (
60
+ <Badge className="bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-100">
61
+ <CheckCircle2 className="mr-1 h-3 w-3" />
62
+ {t("Fiscalized")}
63
+ </Badge>
64
+ );
65
+ case "pending":
66
+ return (
67
+ <Badge className="bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-100">
68
+ <Clock className="mr-1 h-3 w-3" />
69
+ {t("Pending")}
70
+ </Badge>
71
+ );
72
+ case "failed":
73
+ return (
74
+ <Badge className="bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-100">
75
+ <XCircle className="mr-1 h-3 w-3" />
76
+ {t("Failed")}
77
+ </Badge>
78
+ );
79
+ default:
80
+ return null;
81
+ }
82
+ };
83
+
84
+ return (
85
+ <Card>
86
+ <CardHeader>
87
+ <CardTitle className="flex items-center gap-2">
88
+ {t("FURS Fiscalization")}
89
+ {getStatusBadge()}
90
+ </CardTitle>
91
+ <CardDescription>{t("Slovenian tax authority fiscalization details")}</CardDescription>
92
+ </CardHeader>
93
+ <CardContent className="space-y-4">
94
+ {/* Error Message */}
95
+ {furs.status === "failed" && furs.error && (
96
+ <Alert variant="destructive">
97
+ <AlertCircle className="h-4 w-4" />
98
+ <AlertTitle>{t("Fiscalization Error")}</AlertTitle>
99
+ <AlertDescription>{furs.error}</AlertDescription>
100
+ </Alert>
101
+ )}
102
+
103
+ {/* Cancellation Info */}
104
+ {furs.cancellation_reason && (
105
+ <Alert>
106
+ <AlertCircle className="h-4 w-4" />
107
+ <AlertTitle>{t("Cancelled")}</AlertTitle>
108
+ <AlertDescription>{furs.cancellation_reason}</AlertDescription>
109
+ </Alert>
110
+ )}
111
+
112
+ {/* FURS Data */}
113
+ {furs.data && (
114
+ <div className="space-y-3">
115
+ {/* ZOI Code */}
116
+ {furs.data.zoi && (
117
+ <div className="flex items-center justify-between rounded-lg border p-3">
118
+ <div className="space-y-1">
119
+ <p className="font-medium text-sm">{t("ZOI")}</p>
120
+ <p className="font-mono text-muted-foreground text-xs">{furs.data.zoi}</p>
121
+ </div>
122
+ <Button variant="ghost" size="sm" onClick={() => copyToClipboard(furs.data!.zoi!, "zoi")}>
123
+ {copiedField === "zoi" ? <Check className="h-4 w-4 text-green-600" /> : <Copy className="h-4 w-4" />}
124
+ </Button>
125
+ </div>
126
+ )}
127
+
128
+ {/* EOR Code */}
129
+ {furs.data.eor && (
130
+ <div className="flex items-center justify-between rounded-lg border p-3">
131
+ <div className="space-y-1">
132
+ <p className="font-medium text-sm">{t("EOR")}</p>
133
+ <p className="font-mono text-muted-foreground text-xs">{furs.data.eor}</p>
134
+ </div>
135
+ <Button variant="ghost" size="sm" onClick={() => copyToClipboard(furs.data!.eor!, "eor")}>
136
+ {copiedField === "eor" ? <Check className="h-4 w-4 text-green-600" /> : <Copy className="h-4 w-4" />}
137
+ </Button>
138
+ </div>
139
+ )}
140
+
141
+ {/* Cancelled EOR */}
142
+ {furs.data.cancelled && furs.data.cancelled_eor && (
143
+ <div className="flex items-center justify-between rounded-lg border border-red-200 bg-red-50 p-3 dark:border-red-800 dark:bg-red-950">
144
+ <div className="space-y-1">
145
+ <p className="font-medium text-red-900 text-sm dark:text-red-100">{t("Cancellation EOR")}</p>
146
+ <p className="font-mono text-red-700 text-xs dark:text-red-300">{furs.data.cancelled_eor}</p>
147
+ </div>
148
+ <Button
149
+ variant="ghost"
150
+ size="sm"
151
+ onClick={() => copyToClipboard(furs.data!.cancelled_eor!, "cancelled_eor")}
152
+ >
153
+ {copiedField === "cancelled_eor" ? (
154
+ <Check className="h-4 w-4 text-green-600" />
155
+ ) : (
156
+ <Copy className="h-4 w-4" />
157
+ )}
158
+ </Button>
159
+ </div>
160
+ )}
161
+
162
+ {/* Business Premise & Device */}
163
+ <div className="grid grid-cols-2 gap-3">
164
+ {furs.data.business_premise_name && (
165
+ <div className="space-y-1">
166
+ <p className="font-medium text-sm">{t("Business Premise")}</p>
167
+ <p className="text-muted-foreground text-sm">{furs.data.business_premise_name}</p>
168
+ </div>
169
+ )}
170
+ {furs.data.electronic_device_name && (
171
+ <div className="space-y-1">
172
+ <p className="font-medium text-sm">{t("Electronic Device")}</p>
173
+ <p className="text-muted-foreground text-sm">{furs.data.electronic_device_name}</p>
174
+ </div>
175
+ )}
176
+ </div>
177
+
178
+ {/* Invoice Number & Iteration */}
179
+ {furs.data.invoice_number && (
180
+ <div className="grid grid-cols-2 gap-3">
181
+ <div className="space-y-1">
182
+ <p className="font-medium text-sm">{t("Invoice Number")}</p>
183
+ <p className="text-muted-foreground text-sm">{furs.data.invoice_number}</p>
184
+ </div>
185
+ {furs.data.iteration !== undefined && (
186
+ <div className="space-y-1">
187
+ <p className="font-medium text-sm">{t("Iteration")}</p>
188
+ <p className="text-muted-foreground text-sm">{furs.data.iteration}</p>
189
+ </div>
190
+ )}
191
+ </div>
192
+ )}
193
+
194
+ {/* QR Code */}
195
+ {furs.data.qr_code && (
196
+ <div className="flex flex-col items-center gap-2 rounded-lg border p-4">
197
+ <p className="font-medium text-sm">{t("QR Code")}</p>
198
+ <img src={`data:image/png;base64,${furs.data.qr_code}`} alt="FURS QR Code" className="h-48 w-48" />
199
+ </div>
200
+ )}
201
+ </div>
202
+ )}
203
+
204
+ {/* Fiscalized Timestamp */}
205
+ {furs.fiscalized_at && (
206
+ <div className="pt-2 text-muted-foreground text-sm">
207
+ {t("Fiscalized at")}: {new Date(furs.fiscalized_at).toLocaleString()}
208
+ </div>
209
+ )}
210
+ </CardContent>
211
+ </Card>
212
+ );
213
+ }
@@ -0,0 +1,155 @@
1
+ import { zodResolver } from "@hookform/resolvers/zod";
2
+ import type { CreateItemRequest, Item } from "@spaceinvoices/js-sdk";
3
+ import { Minus, Plus } from "lucide-react";
4
+ import { useState } from "react";
5
+ import { useForm } from "react-hook-form";
6
+ import { FormInput } from "@/ui/components/form";
7
+ import { Button } from "@/ui/components/ui/button";
8
+ import {
9
+ DropdownMenu,
10
+ DropdownMenuContent,
11
+ DropdownMenuRadioGroup,
12
+ DropdownMenuRadioItem,
13
+ DropdownMenuTrigger,
14
+ } from "@/ui/components/ui/dropdown-menu";
15
+ import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/ui/components/ui/form";
16
+ import { Input } from "@/ui/components/ui/input";
17
+ import { Tooltip, TooltipContent, TooltipTrigger } from "@/ui/components/ui/tooltip";
18
+ import type { CreateItemSchema } from "@/ui/generated/schemas";
19
+ import { createItemSchema } from "@/ui/generated/schemas";
20
+ import type { ComponentTranslationProps } from "@/ui/lib/translation";
21
+ import { createTranslation } from "@/ui/lib/translation";
22
+
23
+ import { useCreateItem } from "../items.hooks";
24
+ import de from "./locales/de";
25
+ import sl from "./locales/sl";
26
+
27
+ const translations = {
28
+ sl,
29
+ de,
30
+ } as const;
31
+
32
+ type CreateItemFormProps = {
33
+ entityId: string;
34
+ onSuccess?: (item: Item) => void;
35
+ onError?: (error: Error) => void;
36
+ renderSubmitButton?: (props: { isSubmitting: boolean; submit: () => void }) => React.ReactNode;
37
+ } & ComponentTranslationProps;
38
+
39
+ export default function CreateItemForm({
40
+ entityId,
41
+ onSuccess,
42
+ onError,
43
+ renderSubmitButton,
44
+ ...i18nProps
45
+ }: CreateItemFormProps) {
46
+ const t = createTranslation({
47
+ ...i18nProps,
48
+ translations,
49
+ });
50
+
51
+ const [isGrossPrice, setIsGrossPrice] = useState(false);
52
+
53
+ const form = useForm<CreateItemSchema>({
54
+ resolver: zodResolver(createItemSchema),
55
+ defaultValues: {
56
+ name: "",
57
+ description: "",
58
+ price: 0,
59
+ },
60
+ });
61
+
62
+ const setPriceMode = (mode: string) => {
63
+ setIsGrossPrice(mode === "gross");
64
+ };
65
+
66
+ const { mutate: createItem, isPending } = useCreateItem({
67
+ entityId,
68
+ onSuccess: (item, _variables, _context) => {
69
+ onSuccess?.(item);
70
+ form.reset(); // Reset form after successful submission
71
+ },
72
+ onError: (error, _variables, _context) => {
73
+ form.setError("root", {
74
+ type: "submit",
75
+ message: t("There was an error creating the item"),
76
+ });
77
+ onError?.(error);
78
+ },
79
+ });
80
+
81
+ const onSubmit = async (values: CreateItemSchema) => {
82
+ // Zod validation ensures required fields (name, price) are present before this is called
83
+ // The type cast is safe because React Hook Form's DeepPartial doesn't reflect runtime validation
84
+ const { price, ...rest } = values;
85
+
86
+ // Transform price based on is_gross_price flag
87
+ const payload = isGrossPrice ? { ...rest, gross_price: price } : { ...rest, price };
88
+
89
+ createItem(payload as CreateItemRequest);
90
+ };
91
+
92
+ const handleSubmitClick = () => {
93
+ form.handleSubmit(onSubmit)();
94
+ };
95
+
96
+ return (
97
+ <Form {...form}>
98
+ <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
99
+ <FormInput control={form.control} name="name" label={t("Name")} placeholder={t("Enter name")} />
100
+
101
+ <FormInput
102
+ control={form.control}
103
+ name="description"
104
+ label={t("Description")}
105
+ placeholder={t("Enter description")}
106
+ />
107
+
108
+ <FormField
109
+ control={form.control}
110
+ name="price"
111
+ render={({ field }) => (
112
+ <FormItem>
113
+ <FormLabel>
114
+ {isGrossPrice ? t("Gross price") : t("Price")} <span className="text-red-500">*</span>
115
+ </FormLabel>
116
+ <div className="flex items-center gap-1">
117
+ <FormControl className="min-w-0 flex-1">
118
+ <Input type="number" {...field} onChange={(e) => field.onChange(Number(e.target.value))} />
119
+ </FormControl>
120
+ <Tooltip>
121
+ <TooltipTrigger asChild>
122
+ <div>
123
+ <DropdownMenu>
124
+ <DropdownMenuTrigger asChild>
125
+ <Button type="button" variant="ghost" size="icon" className="h-9 w-9 shrink-0">
126
+ {isGrossPrice ? <Minus className="h-4 w-4" /> : <Plus className="h-4 w-4" />}
127
+ </Button>
128
+ </DropdownMenuTrigger>
129
+ <DropdownMenuContent align="end">
130
+ <DropdownMenuRadioGroup value={isGrossPrice ? "gross" : "net"} onValueChange={setPriceMode}>
131
+ <DropdownMenuRadioItem value="net">{t("Net price")}</DropdownMenuRadioItem>
132
+ <DropdownMenuRadioItem value="gross">{t("Gross price")}</DropdownMenuRadioItem>
133
+ </DropdownMenuRadioGroup>
134
+ </DropdownMenuContent>
135
+ </DropdownMenu>
136
+ </div>
137
+ </TooltipTrigger>
138
+ <TooltipContent>
139
+ {isGrossPrice ? t("Gross price (tax included)") : t("Net price (before tax)")}
140
+ </TooltipContent>
141
+ </Tooltip>
142
+ </div>
143
+ <FormMessage />
144
+ </FormItem>
145
+ )}
146
+ />
147
+
148
+ {renderSubmitButton?.({
149
+ isSubmitting: isPending || form.formState.isSubmitting,
150
+ submit: handleSubmitClick,
151
+ })}
152
+ </form>
153
+ </Form>
154
+ );
155
+ }
@@ -0,0 +1,14 @@
1
+ export default {
2
+ Name: "Name",
3
+ "Enter name": "Namen eingeben",
4
+ Description: "Beschreibung",
5
+ "Enter description": "Beschreibung eingeben",
6
+ Unit: "Einheit",
7
+ Price: "Preis",
8
+ "There was an error creating the item": "Beim Erstellen des Artikels ist ein Fehler aufgetreten",
9
+ // Gross price support
10
+ "Gross price": "Bruttopreis",
11
+ "Net price": "Nettopreis",
12
+ "Gross price (tax included)": "Bruttopreis (inkl. MwSt.)",
13
+ "Net price (before tax)": "Nettopreis (exkl. MwSt.)",
14
+ };
@@ -0,0 +1,9 @@
1
+ export default {
2
+ Name: "Name",
3
+ "Enter name": "Enter name",
4
+ Description: "Description",
5
+ "Enter description": "Enter description",
6
+ Unit: "Unit",
7
+ Price: "Price",
8
+ "There was an error creating the item": "There was an error creating the item",
9
+ };
@@ -0,0 +1,14 @@
1
+ export default {
2
+ Name: "Naziv",
3
+ "Enter name": "Vnesite naziv",
4
+ Description: "Opis",
5
+ "Enter description": "Vnesite opis",
6
+ Unit: "Enota",
7
+ Price: "Cena",
8
+ "There was an error creating the item": "Prišlo je do napake pri ustvarjanju izdelka",
9
+ // Gross price support
10
+ "Gross price": "Bruto cena",
11
+ "Net price": "Neto cena",
12
+ "Gross price (tax included)": "Bruto cena (z davkom)",
13
+ "Net price (before tax)": "Neto cena (brez davka)",
14
+ };
@@ -0,0 +1,147 @@
1
+ import type { Item } from "@spaceinvoices/js-sdk";
2
+
3
+ import { Plus } from "lucide-react";
4
+ import { useEffect, useMemo, useState } from "react";
5
+
6
+ import { Autocomplete } from "@/ui/common/autocomplete";
7
+ import { useDebounce } from "@/ui/hooks/use-debounce";
8
+
9
+ import { useItemSearch, useRecentItems } from "./items.hooks";
10
+
11
+ type ItemComboboxProps = {
12
+ entityId: string;
13
+ value?: string;
14
+ onSelect?: (item: Item | null, customName?: string) => void;
15
+ placeholder?: string;
16
+ className?: string;
17
+ disabled?: boolean;
18
+ };
19
+
20
+ /**
21
+ * Autocomplete for selecting saved catalog items
22
+ * Shows recent items, allows search, and supports custom names
23
+ */
24
+ export function ItemCombobox({
25
+ entityId,
26
+ value,
27
+ onSelect,
28
+ placeholder = "Search or enter item name...",
29
+ className,
30
+ disabled,
31
+ }: ItemComboboxProps) {
32
+ const [search, setSearch] = useState("");
33
+ const [displayValue, setDisplayValue] = useState("");
34
+ const debouncedSearch = useDebounce(search, 300);
35
+
36
+ // Fetch recent items (non-blocking, cached)
37
+ const { data: recentData } = useRecentItems(entityId);
38
+ const recentItems = recentData?.data || [];
39
+
40
+ // Fetch search results
41
+ const { data: searchData, isLoading } = useItemSearch(entityId, debouncedSearch);
42
+ const searchResults = searchData?.data || [];
43
+
44
+ // Use search results if searching, otherwise show recent items
45
+ const items = useMemo(() => {
46
+ if (debouncedSearch) {
47
+ return searchResults;
48
+ }
49
+ return recentItems;
50
+ }, [debouncedSearch, searchResults, recentItems]);
51
+
52
+ // Format price for display
53
+ const formatPrice = (item: Item) => {
54
+ const price = item.gross_price ?? item.price;
55
+ if (price === null || price === undefined) return "";
56
+ return ` - ${price.toFixed(2)}`;
57
+ };
58
+
59
+ const options = items.map((item) => ({
60
+ value: item.id,
61
+ label: (
62
+ <div className="flex flex-col overflow-hidden">
63
+ <span className="truncate">{item.name}</span>
64
+ <span className="truncate text-muted-foreground text-xs">
65
+ {formatPrice(item)}
66
+ {item.description && ` · ${item.description}`}
67
+ </span>
68
+ </div>
69
+ ),
70
+ }));
71
+
72
+ // Add "Use custom name" option when there's search text
73
+ if (debouncedSearch?.trim()) {
74
+ options.unshift({
75
+ value: `__custom__:${debouncedSearch}`,
76
+ label: (
77
+ <span className="flex items-center gap-2">
78
+ <Plus className="size-4" />
79
+ Use "{debouncedSearch}"
80
+ </span>
81
+ ),
82
+ });
83
+ }
84
+
85
+ const handleSearch = (value: string) => {
86
+ setSearch(value);
87
+ // Clear displayValue when user starts typing
88
+ if (displayValue && value !== displayValue) {
89
+ setDisplayValue("");
90
+ }
91
+ };
92
+
93
+ const handleValueChange = (selectedValue: string) => {
94
+ // Handle custom name selection
95
+ if (selectedValue.startsWith("__custom__:")) {
96
+ const customName = selectedValue.replace("__custom__:", "");
97
+ onSelect?.(null, customName);
98
+ setSearch(customName);
99
+ setDisplayValue(customName);
100
+ return;
101
+ }
102
+
103
+ // Find selected item
104
+ const selectedItem =
105
+ items.find((i) => i.id === selectedValue) ||
106
+ recentItems.find((i) => i.id === selectedValue) ||
107
+ searchResults.find((i) => i.id === selectedValue);
108
+
109
+ if (selectedItem) {
110
+ onSelect?.(selectedItem);
111
+ setSearch(selectedItem.name);
112
+ setDisplayValue(selectedItem.name);
113
+ }
114
+ };
115
+
116
+ const handleBlur = () => {
117
+ // If nothing was selected but there's text, treat as custom name
118
+ if (!displayValue && search) {
119
+ handleValueChange(`__custom__:${search}`);
120
+ }
121
+ };
122
+
123
+ // Reset when value changes externally
124
+ useEffect(() => {
125
+ if (!value) {
126
+ setSearch("");
127
+ setDisplayValue("");
128
+ }
129
+ }, [value]);
130
+
131
+ return (
132
+ <Autocomplete
133
+ searchValue={search}
134
+ onSearch={handleSearch}
135
+ value={value}
136
+ onValueChange={handleValueChange}
137
+ onBlur={handleBlur}
138
+ options={options}
139
+ placeholder={placeholder}
140
+ className={className}
141
+ disabled={disabled}
142
+ loading={isLoading}
143
+ emptyText={debouncedSearch ? "No items found" : "Recent items"}
144
+ displayValue={displayValue}
145
+ />
146
+ );
147
+ }
@@ -0,0 +1,33 @@
1
+ import { TableHead, TableHeader, TableRow } from "@/ui/components/ui/table";
2
+ import type { ComponentTranslationProps } from "@/ui/lib/translation";
3
+ import { createTranslation } from "@/ui/lib/translation";
4
+
5
+ import { SortableHeader } from "../../table/sortable-header";
6
+
7
+ type ItemListHeaderProps = {
8
+ orderBy?: string;
9
+ onSort?: (order: string | null) => void;
10
+ } & ComponentTranslationProps;
11
+
12
+ export default function ItemListHeader({ orderBy, onSort, ...i18nProps }: ItemListHeaderProps) {
13
+ const t = createTranslation(i18nProps);
14
+
15
+ return (
16
+ <TableHeader>
17
+ <TableRow>
18
+ <TableHead>
19
+ <SortableHeader field="name" currentOrder={orderBy} onSort={onSort}>
20
+ {t("Name")}
21
+ </SortableHeader>
22
+ </TableHead>
23
+ <TableHead>
24
+ <SortableHeader field="description" currentOrder={orderBy} onSort={onSort}>
25
+ {t("Description")}
26
+ </SortableHeader>
27
+ </TableHead>
28
+ <TableHead className="text-right">{t("Price")}</TableHead>
29
+ <TableHead className="w-[42px] text-right" />
30
+ </TableRow>
31
+ </TableHeader>
32
+ );
33
+ }
@@ -0,0 +1,48 @@
1
+ import type { Item } from "@spaceinvoices/js-sdk";
2
+
3
+ import { MoreHorizontal } from "lucide-react";
4
+ import { Button } from "@/ui/components/ui/button";
5
+ import {
6
+ DropdownMenu,
7
+ DropdownMenuContent,
8
+ DropdownMenuItem,
9
+ DropdownMenuLabel,
10
+ DropdownMenuSeparator,
11
+ DropdownMenuTrigger,
12
+ } from "@/ui/components/ui/dropdown-menu";
13
+ import type { ComponentTranslationProps } from "@/ui/lib/translation";
14
+ import { createTranslation } from "@/ui/lib/translation";
15
+
16
+ type ItemListRowActionsProps = {
17
+ item: Item;
18
+ } & ComponentTranslationProps;
19
+
20
+ export default function ItemListRowActions({ item, ...i18nProps }: ItemListRowActionsProps) {
21
+ const t = createTranslation(i18nProps);
22
+
23
+ return (
24
+ <DropdownMenu>
25
+ <DropdownMenuTrigger asChild>
26
+ <Button variant="ghost" className="h-8 w-8 p-0" id="action-menu-trigger">
27
+ <span className="sr-only">{t("Open menu")}</span>
28
+ <MoreHorizontal className="h-4 w-4" />
29
+ </Button>
30
+ </DropdownMenuTrigger>
31
+ <DropdownMenuContent align="end">
32
+ <DropdownMenuLabel>{t("Actions")}</DropdownMenuLabel>
33
+ <DropdownMenuItem className="cursor-pointer" onClick={() => navigator.clipboard.writeText(item.id)}>
34
+ {t("Copy item ID")}
35
+ </DropdownMenuItem>
36
+ <DropdownMenuSeparator />
37
+ <DropdownMenuItem
38
+ className="cursor-pointer"
39
+ onClick={() => {
40
+ window.location.href = `/app/items/${item.id}`;
41
+ }}
42
+ >
43
+ {t("View item")}
44
+ </DropdownMenuItem>
45
+ </DropdownMenuContent>
46
+ </DropdownMenu>
47
+ );
48
+ }
@@ -0,0 +1,32 @@
1
+ import type { Item } from "@spaceinvoices/js-sdk";
2
+ import { Package } from "lucide-react";
3
+ import { TableCell, TableRow } from "@/ui/components/ui/table";
4
+ import type { ComponentTranslationProps } from "@/ui/lib/translation";
5
+ import { createTranslation } from "@/ui/lib/translation";
6
+ import { Button } from "../../ui/button";
7
+ import ItemListRowActions from "./item-list-row-actions";
8
+
9
+ type ItemListRowProps = {
10
+ item: Item;
11
+ onRowClick?: (item: Item) => void;
12
+ } & ComponentTranslationProps;
13
+
14
+ export default function ItemListRow({ item, onRowClick, ...i18nProps }: ItemListRowProps) {
15
+ const t = createTranslation(i18nProps);
16
+
17
+ return (
18
+ <TableRow>
19
+ <TableCell className="font-medium">
20
+ <Button variant="link" className="py-0 underline" onClick={() => onRowClick?.(item)}>
21
+ <Package className="h-4 w-4 flex-shrink-0" />
22
+ {item.name}
23
+ </Button>
24
+ </TableCell>
25
+ <TableCell>{item.description}</TableCell>
26
+ <TableCell className="text-right">{item.price}</TableCell>
27
+ <TableCell className="text-right">
28
+ <ItemListRowActions item={item} t={t} />
29
+ </TableCell>
30
+ </TableRow>
31
+ );
32
+ }