@spaceinvoices/react-ui 0.4.1 → 0.4.3

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 (245) hide show
  1. package/cli/dist/index.js +1 -1
  2. package/package.json +1 -1
  3. package/registry.json +25 -0
  4. package/src/components/advance-invoices/advance-invoices.hooks.ts +32 -2
  5. package/src/components/advance-invoices/create/create-advance-invoice-form.tsx +109 -4
  6. package/src/components/advance-invoices/create/locales/de.ts +2 -0
  7. package/src/components/advance-invoices/create/locales/es.ts +2 -0
  8. package/src/components/advance-invoices/create/locales/fr.ts +2 -0
  9. package/src/components/advance-invoices/create/locales/hr.ts +2 -0
  10. package/src/components/advance-invoices/create/locales/it.ts +2 -0
  11. package/src/components/advance-invoices/create/locales/nl.ts +2 -0
  12. package/src/components/advance-invoices/create/locales/pl.ts +2 -0
  13. package/src/components/advance-invoices/create/locales/pt.ts +2 -0
  14. package/src/components/advance-invoices/create/locales/sl.ts +2 -0
  15. package/src/components/advance-invoices/create/prepare-advance-invoice-submission.ts +17 -0
  16. package/src/components/advance-invoices/list/list-row-actions.tsx +3 -6
  17. package/src/components/advance-invoices/list/list-table.tsx +105 -2
  18. package/src/components/advance-invoices/list/locales/de.ts +4 -0
  19. package/src/components/advance-invoices/list/locales/en.ts +4 -0
  20. package/src/components/advance-invoices/list/locales/es.ts +4 -0
  21. package/src/components/advance-invoices/list/locales/fr.ts +4 -0
  22. package/src/components/advance-invoices/list/locales/hr.ts +4 -0
  23. package/src/components/advance-invoices/list/locales/it.ts +4 -0
  24. package/src/components/advance-invoices/list/locales/nl.ts +4 -0
  25. package/src/components/advance-invoices/list/locales/pl.ts +4 -0
  26. package/src/components/advance-invoices/list/locales/pt.ts +4 -0
  27. package/src/components/advance-invoices/list/locales/sl.ts +4 -0
  28. package/src/components/credit-notes/create/create-credit-note-form.tsx +177 -6
  29. package/src/components/credit-notes/create/locales/de.ts +8 -0
  30. package/src/components/credit-notes/create/locales/es.ts +8 -0
  31. package/src/components/credit-notes/create/locales/fr.ts +7 -0
  32. package/src/components/credit-notes/create/locales/hr.ts +7 -0
  33. package/src/components/credit-notes/create/locales/it.ts +9 -0
  34. package/src/components/credit-notes/create/locales/nl.ts +7 -0
  35. package/src/components/credit-notes/create/locales/pl.ts +7 -0
  36. package/src/components/credit-notes/create/locales/pt.ts +7 -0
  37. package/src/components/credit-notes/create/locales/sl.ts +7 -0
  38. package/src/components/credit-notes/credit-notes.hooks.ts +30 -0
  39. package/src/components/credit-notes/list/list-row-actions.tsx +3 -6
  40. package/src/components/credit-notes/list/list-table.tsx +79 -8
  41. package/src/components/credit-notes/list/locales/de.ts +4 -1
  42. package/src/components/credit-notes/list/locales/en.ts +5 -0
  43. package/src/components/credit-notes/list/locales/es.ts +4 -1
  44. package/src/components/credit-notes/list/locales/fr.ts +4 -1
  45. package/src/components/credit-notes/list/locales/hr.ts +4 -1
  46. package/src/components/credit-notes/list/locales/it.ts +4 -1
  47. package/src/components/credit-notes/list/locales/nl.ts +4 -1
  48. package/src/components/credit-notes/list/locales/pl.ts +4 -1
  49. package/src/components/credit-notes/list/locales/pt.ts +4 -1
  50. package/src/components/credit-notes/list/locales/sl.ts +4 -1
  51. package/src/components/customers/create-customer-form/create-customer-form.tsx +0 -1
  52. package/src/components/dashboard/collection-rate-card/use-collection-rate.ts +2 -2
  53. package/src/components/dashboard/invoice-status-chart/use-invoice-status.ts +3 -3
  54. package/src/components/dashboard/payment-methods-chart/use-payment-methods.ts +1 -1
  55. package/src/components/dashboard/payment-trend-chart/use-payment-trend.ts +1 -1
  56. package/src/components/dashboard/revenue-trend-chart/use-revenue-trend.ts +1 -1
  57. package/src/components/dashboard/shared/use-revenue-data.ts +4 -4
  58. package/src/components/dashboard/shared/use-stats-counts.ts +4 -4
  59. package/src/components/dashboard/shared/use-stats-query.ts +1 -1
  60. package/src/components/dashboard/tax-collected-card/use-tax-collected.ts +2 -2
  61. package/src/components/dashboard/top-customers-chart/use-top-customers.ts +1 -1
  62. package/src/components/delivery-notes/create/create-delivery-note-form.tsx +332 -0
  63. package/src/components/delivery-notes/create/locales/de.ts +50 -0
  64. package/src/components/delivery-notes/create/locales/es.ts +49 -0
  65. package/src/components/delivery-notes/create/locales/fr.ts +50 -0
  66. package/src/components/delivery-notes/create/locales/hr.ts +49 -0
  67. package/src/components/delivery-notes/create/locales/it.ts +49 -0
  68. package/src/components/delivery-notes/create/locales/nl.ts +50 -0
  69. package/src/components/delivery-notes/create/locales/pl.ts +49 -0
  70. package/src/components/delivery-notes/create/locales/pt.ts +50 -0
  71. package/src/components/delivery-notes/create/locales/sl.ts +49 -0
  72. package/src/components/delivery-notes/create/prepare-delivery-note-submission.ts +38 -0
  73. package/src/components/delivery-notes/create/use-delivery-note-customer-form.ts +1 -0
  74. package/src/components/delivery-notes/delivery-notes.hooks.ts +15 -0
  75. package/src/components/delivery-notes/list/index.ts +3 -0
  76. package/src/components/delivery-notes/list/list-row-actions.tsx +103 -0
  77. package/src/components/delivery-notes/list/list-table.tsx +214 -0
  78. package/src/components/delivery-notes/list/locales/de.ts +9 -0
  79. package/src/components/delivery-notes/list/locales/en.ts +11 -0
  80. package/src/components/delivery-notes/list/locales/es.ts +9 -0
  81. package/src/components/delivery-notes/list/locales/fr.ts +9 -0
  82. package/src/components/delivery-notes/list/locales/hr.ts +9 -0
  83. package/src/components/delivery-notes/list/locales/it.ts +9 -0
  84. package/src/components/delivery-notes/list/locales/nl.ts +9 -0
  85. package/src/components/delivery-notes/list/locales/pl.ts +9 -0
  86. package/src/components/delivery-notes/list/locales/pt.ts +9 -0
  87. package/src/components/delivery-notes/list/locales/sl.ts +9 -0
  88. package/src/components/delivery-notes/list/use-delivery-note-download.ts +63 -0
  89. package/src/components/documents/create/document-details-section.tsx +103 -33
  90. package/src/components/documents/create/live-preview.tsx +37 -10
  91. package/src/components/documents/create/mark-as-paid-section.tsx +11 -2
  92. package/src/components/documents/create/prepare-document-submission.ts +1 -1
  93. package/src/components/documents/documents.hooks.ts +2 -1
  94. package/src/components/documents/shared/document-preview-display.tsx +12 -5
  95. package/src/components/documents/types.ts +10 -1
  96. package/src/components/documents/view/document-actions-bar.tsx +30 -0
  97. package/src/components/documents/view/document-details-card.tsx +3 -3
  98. package/src/components/documents/view/document-payments-list.tsx +3 -3
  99. package/src/components/documents/view/document-relations-list.tsx +105 -0
  100. package/src/components/documents/view/locales/de.ts +26 -0
  101. package/src/components/documents/view/locales/es.ts +26 -0
  102. package/src/components/documents/view/locales/fr.ts +26 -0
  103. package/src/components/documents/view/locales/hr.ts +26 -0
  104. package/src/components/documents/view/locales/it.ts +26 -0
  105. package/src/components/documents/view/locales/nl.ts +26 -0
  106. package/src/components/documents/view/locales/pl.ts +26 -0
  107. package/src/components/documents/view/locales/pt.ts +26 -0
  108. package/src/components/documents/view/locales/sl.ts +26 -0
  109. package/src/components/documents/view/use-document-download.ts +5 -3
  110. package/src/components/entities/create-entity-form.tsx +1 -1
  111. package/src/components/entities/entity-settings-form/entity-settings-form.tsx +2 -3
  112. package/src/components/entities/entity-settings-form/locales/es.ts +2 -0
  113. package/src/components/entities/entity-settings-form/locales/fr.ts +2 -0
  114. package/src/components/entities/entity-settings-form/locales/hr.ts +2 -0
  115. package/src/components/entities/entity-settings-form/locales/it.ts +2 -0
  116. package/src/components/entities/entity-settings-form/locales/nl.ts +2 -0
  117. package/src/components/entities/entity-settings-form/locales/pl.ts +2 -0
  118. package/src/components/entities/entity-settings-form/locales/pt.ts +2 -0
  119. package/src/components/entities/fina-settings-form/fina-operator-required-dialog.tsx +109 -0
  120. package/src/components/entities/fina-settings-form/fina-settings-form.tsx +377 -35
  121. package/src/components/entities/fina-settings-form/fina-settings.hooks.ts +106 -20
  122. package/src/components/entities/fina-settings-form/index.ts +1 -0
  123. package/src/components/entities/fina-settings-form/locales/de.ts +54 -34
  124. package/src/components/entities/fina-settings-form/locales/en.ts +51 -34
  125. package/src/components/entities/fina-settings-form/locales/es.ts +50 -34
  126. package/src/components/entities/fina-settings-form/locales/fr.ts +50 -34
  127. package/src/components/entities/fina-settings-form/locales/hr.ts +50 -34
  128. package/src/components/entities/fina-settings-form/locales/it.ts +50 -34
  129. package/src/components/entities/fina-settings-form/locales/nl.ts +50 -34
  130. package/src/components/entities/fina-settings-form/locales/pl.ts +50 -34
  131. package/src/components/entities/fina-settings-form/locales/pt.ts +50 -34
  132. package/src/components/entities/fina-settings-form/locales/sl.ts +50 -34
  133. package/src/components/entities/fina-settings-form/sections/certificate-settings-section.tsx +18 -0
  134. package/src/components/entities/fina-settings-form/sections/premises-management-section.tsx +64 -89
  135. package/src/components/entities/fina-settings-form/sections/register-premise-dialog.tsx +51 -323
  136. package/src/components/entities/furs-settings-form/furs-operator-required-dialog.tsx +106 -0
  137. package/src/components/entities/furs-settings-form/furs-settings-form.tsx +33 -10
  138. package/src/components/entities/furs-settings-form/furs-settings.hooks.ts +12 -11
  139. package/src/components/entities/furs-settings-form/index.ts +1 -0
  140. package/src/components/entities/furs-settings-form/locales/de.ts +27 -3
  141. package/src/components/entities/furs-settings-form/locales/en.ts +17 -3
  142. package/src/components/entities/furs-settings-form/locales/es.ts +26 -3
  143. package/src/components/entities/furs-settings-form/locales/fr.ts +26 -3
  144. package/src/components/entities/furs-settings-form/locales/hr.ts +26 -3
  145. package/src/components/entities/furs-settings-form/locales/it.ts +26 -3
  146. package/src/components/entities/furs-settings-form/locales/nl.ts +26 -3
  147. package/src/components/entities/furs-settings-form/locales/pl.ts +26 -3
  148. package/src/components/entities/furs-settings-form/locales/pt.ts +26 -3
  149. package/src/components/entities/furs-settings-form/locales/sl.ts +16 -3
  150. package/src/components/entities/furs-settings-form/sections/certificate-settings-section.tsx +22 -0
  151. package/src/components/entities/furs-settings-form/sections/general-settings-section.tsx +26 -5
  152. package/src/components/entities/furs-settings-form/sections/register-premise-dialog.tsx +14 -2
  153. package/src/components/entities/settings/tax-rules-settings-form.tsx +4 -4
  154. package/src/components/estimates/list/list-row-actions.tsx +3 -7
  155. package/src/components/estimates/list/list-table.tsx +35 -2
  156. package/src/components/estimates/list/locales/de.ts +3 -0
  157. package/src/components/estimates/list/locales/en.ts +3 -0
  158. package/src/components/estimates/list/locales/es.ts +3 -0
  159. package/src/components/estimates/list/locales/fr.ts +3 -0
  160. package/src/components/estimates/list/locales/hr.ts +3 -0
  161. package/src/components/estimates/list/locales/it.ts +3 -0
  162. package/src/components/estimates/list/locales/nl.ts +3 -0
  163. package/src/components/estimates/list/locales/pl.ts +3 -0
  164. package/src/components/estimates/list/locales/pt.ts +3 -0
  165. package/src/components/estimates/list/locales/sl.ts +3 -0
  166. package/src/components/export/document-export-form.tsx +34 -34
  167. package/src/components/invoices/create/create-invoice-form.tsx +107 -5
  168. package/src/components/invoices/create/prepare-invoice-submission.ts +17 -0
  169. package/src/components/invoices/invoices-furs.hooks.ts +24 -9
  170. package/src/components/invoices/invoices.hooks.ts +32 -2
  171. package/src/components/invoices/list/list-row-actions.tsx +26 -11
  172. package/src/components/invoices/list/list-table.tsx +121 -5
  173. package/src/components/invoices/list/locales/de.ts +5 -0
  174. package/src/components/invoices/list/locales/en.ts +5 -0
  175. package/src/components/invoices/list/locales/es.ts +5 -0
  176. package/src/components/invoices/list/locales/fr.ts +5 -0
  177. package/src/components/invoices/list/locales/hr.ts +5 -0
  178. package/src/components/invoices/list/locales/it.ts +5 -0
  179. package/src/components/invoices/list/locales/nl.ts +5 -0
  180. package/src/components/invoices/list/locales/pl.ts +5 -0
  181. package/src/components/invoices/list/locales/pt.ts +5 -0
  182. package/src/components/invoices/list/locales/sl.ts +5 -0
  183. package/src/components/invoices/view/fiscalization-status-card.tsx +4 -1
  184. package/src/components/items/item-list-table/item-list-row-actions.tsx +5 -8
  185. package/src/components/items/item-list-table/item-list-row.tsx +5 -3
  186. package/src/components/items/item-list-table/item-list-table.tsx +5 -1
  187. package/src/components/recurring-invoices/create-recurring-invoice-form/create-recurring-invoice-form.tsx +418 -0
  188. package/src/components/recurring-invoices/create-recurring-invoice-form/locales/de.ts +45 -0
  189. package/src/components/recurring-invoices/create-recurring-invoice-form/locales/es.ts +44 -0
  190. package/src/components/recurring-invoices/create-recurring-invoice-form/locales/fr.ts +44 -0
  191. package/src/components/recurring-invoices/create-recurring-invoice-form/locales/hr.ts +44 -0
  192. package/src/components/recurring-invoices/create-recurring-invoice-form/locales/it.ts +44 -0
  193. package/src/components/recurring-invoices/create-recurring-invoice-form/locales/nl.ts +44 -0
  194. package/src/components/recurring-invoices/create-recurring-invoice-form/locales/pl.ts +44 -0
  195. package/src/components/recurring-invoices/create-recurring-invoice-form/locales/pt.ts +44 -0
  196. package/src/components/recurring-invoices/create-recurring-invoice-form/locales/sl.ts +44 -0
  197. package/src/components/recurring-invoices/index.ts +3 -0
  198. package/src/components/recurring-invoices/list/index.ts +2 -0
  199. package/src/components/recurring-invoices/list/list-row-actions.tsx +139 -0
  200. package/src/components/recurring-invoices/list/list-table.tsx +179 -0
  201. package/src/components/recurring-invoices/list/locales/de.ts +27 -0
  202. package/src/components/recurring-invoices/list/locales/en.ts +5 -0
  203. package/src/components/recurring-invoices/list/locales/es.ts +27 -0
  204. package/src/components/recurring-invoices/list/locales/fr.ts +27 -0
  205. package/src/components/recurring-invoices/list/locales/hr.ts +27 -0
  206. package/src/components/recurring-invoices/list/locales/it.ts +27 -0
  207. package/src/components/recurring-invoices/list/locales/nl.ts +27 -0
  208. package/src/components/recurring-invoices/list/locales/pl.ts +27 -0
  209. package/src/components/recurring-invoices/list/locales/pt.ts +27 -0
  210. package/src/components/recurring-invoices/list/locales/sl.ts +27 -0
  211. package/src/components/recurring-invoices/recurring-invoices.hooks.ts +28 -0
  212. package/src/components/table/data-table.tsx +122 -5
  213. package/src/components/table/selection-toolbar.tsx +36 -0
  214. package/src/components/tax-reports/kir-export-form.tsx +75 -55
  215. package/src/components/taxes/tax-list-table/tax-list-row-actions.tsx +3 -6
  216. package/src/components/taxes/tax-list-table/tax-list-row.tsx +3 -2
  217. package/src/components/taxes/tax-list-table/tax-list-table.tsx +5 -1
  218. package/src/components/ui/checkbox.tsx +5 -5
  219. package/src/generate-schemas.ts +45 -18
  220. package/src/generated/schemas/authorizeshopify_body.ts +22 -0
  221. package/src/generated/schemas/creditnote.ts +0 -2
  222. package/src/generated/schemas/deliverynote.ts +134 -0
  223. package/src/generated/schemas/entity.ts +5 -1
  224. package/src/generated/schemas/index.ts +42 -28
  225. package/src/generated/schemas/order.ts +129 -0
  226. package/src/generated/schemas/orderintegration.ts +51 -0
  227. package/src/generated/schemas/payment.ts +24 -2
  228. package/src/generated/schemas/recurringinvoice.ts +61 -0
  229. package/src/generated/schemas/renderadvanceinvoicepreview_body.ts +108 -140
  230. package/src/generated/schemas/rendercreditnotepreview_body.ts +109 -141
  231. package/src/generated/schemas/renderdeliverynotepreview_body.ts +185 -0
  232. package/src/generated/schemas/renderestimatepreview_body.ts +79 -82
  233. package/src/generated/schemas/renderinvoicepreview_body.ts +109 -141
  234. package/src/generated/schemas/startpdfexport_body.ts +18 -2
  235. package/src/generated/schemas/userfinasettings.ts +19 -0
  236. package/src/generated/schemas/webhook.ts +54 -0
  237. package/src/hooks/use-duplicate-document.ts +11 -3
  238. package/src/hooks/use-next-document-number.ts +2 -2
  239. package/src/lib/furs-error-utils.ts +36 -0
  240. package/src/lib/schemas/advance-invoice.ts +3 -3
  241. package/src/lib/schemas/credit-note.ts +3 -3
  242. package/src/lib/schemas/estimate.ts +3 -3
  243. package/src/lib/schemas/invoice.ts +3 -3
  244. package/src/providers/sdk-provider.tsx +5 -7
  245. package/src/providers/white-label-provider.tsx +3 -0
@@ -0,0 +1,27 @@
1
+ export default {
2
+ Name: "Nome",
3
+ Frequency: "Frequência",
4
+ Status: "Estado",
5
+ "Next Run": "Próxima execução",
6
+ Generated: "Geradas",
7
+ Created: "Criado",
8
+ Every: "A cada",
9
+ Actions: "Ações",
10
+ "Open menu": "Abrir menu",
11
+ "View source invoice": "Ver fatura de origem",
12
+ Pause: "Pausar",
13
+ Resume: "Retomar",
14
+ "Processing...": "Processando...",
15
+ "Delete schedule": "Eliminar agendamento",
16
+ "Deleting...": "Eliminando...",
17
+ "frequency.daily": "Diário",
18
+ "frequency.weekly": "Semanal",
19
+ "frequency.monthly": "Mensal",
20
+ "frequency.yearly": "Anual",
21
+ "status.active": "Ativo",
22
+ "status.paused": "Pausado",
23
+ "status.completed": "Concluído",
24
+ "Your list is empty": "A sua lista de faturas recorrentes está vazia",
25
+ "Get started by creating your first entry": "Comece criando o seu primeiro agendamento recorrente",
26
+ "No results found": "Nenhuma fatura recorrente encontrada",
27
+ } as const;
@@ -0,0 +1,27 @@
1
+ export default {
2
+ Name: "Ime",
3
+ Frequency: "Pogostost",
4
+ Status: "Status",
5
+ "Next Run": "Naslednje izvajanje",
6
+ Generated: "Ustvarjeno",
7
+ Created: "Ustvarjeno",
8
+ Every: "Vsak",
9
+ Actions: "Akcije",
10
+ "Open menu": "Odpri meni",
11
+ "View source invoice": "Prikaži izvorni račun",
12
+ Pause: "Zaustavi",
13
+ Resume: "Nadaljuj",
14
+ "Processing...": "Obdelujem...",
15
+ "Delete schedule": "Izbriši urnik",
16
+ "Deleting...": "Brišem...",
17
+ "frequency.daily": "Dnevno",
18
+ "frequency.weekly": "Tedensko",
19
+ "frequency.monthly": "Mesečno",
20
+ "frequency.yearly": "Letno",
21
+ "status.active": "Aktiven",
22
+ "status.paused": "Zaustavljen",
23
+ "status.completed": "Zaključen",
24
+ "Your list is empty": "Vaš seznam ponavljajočih računov je prazen",
25
+ "Get started by creating your first entry": "Začnite z ustvarjanjem prvega ponavljajočega urnika",
26
+ "No results found": "Ni najdenih ponavljajočih računov",
27
+ } as const;
@@ -0,0 +1,28 @@
1
+ import type { CreateRecurringInvoiceBody, RecurringInvoice } from "@spaceinvoices/js-sdk";
2
+
3
+ import { createResourceHooks } from "@/ui/hooks/create-resource-hooks";
4
+
5
+ export const RECURRING_INVOICES_CACHE_KEY = "recurring-invoices";
6
+
7
+ const {
8
+ useCreateResource: useCreateRecurringInvoice,
9
+ useUpdateResource: useUpdateRecurringInvoice,
10
+ useDeleteResource: useDeleteRecurringInvoice,
11
+ useRestoreResource: useRestoreRecurringInvoice,
12
+ usePermanentDeleteResource: usePermanentDeleteRecurringInvoice,
13
+ } = createResourceHooks<RecurringInvoice, CreateRecurringInvoiceBody>(
14
+ "recurringInvoices",
15
+ RECURRING_INVOICES_CACHE_KEY,
16
+ {
17
+ restoreMethodName: "restoreRecurringInvoice",
18
+ permanentDeleteMethodName: "permanentDeleteRecurringInvoice",
19
+ },
20
+ );
21
+
22
+ export {
23
+ useCreateRecurringInvoice,
24
+ useUpdateRecurringInvoice,
25
+ useDeleteRecurringInvoice,
26
+ useRestoreRecurringInvoice,
27
+ usePermanentDeleteRecurringInvoice,
28
+ };
@@ -1,6 +1,7 @@
1
1
  import type { JSX, ReactNode } from "react";
2
- import { Fragment, memo, useState } from "react";
2
+ import { Fragment, memo, useCallback, useMemo, useState } from "react";
3
3
 
4
+ import { Checkbox } from "@/ui/components/ui/checkbox";
4
5
  import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/ui/components/ui/table";
5
6
  import { FilterBar } from "./filter-bar";
6
7
  import { useTableQuery } from "./hooks/use-table-query";
@@ -47,6 +48,14 @@ export type DataTableProps<T> = {
47
48
  t?: (key: string) => string;
48
49
  /** Locale for date formatting */
49
50
  locale?: string;
51
+ /** Enable row selection with checkboxes */
52
+ selectable?: boolean;
53
+ /** Currently selected IDs (controlled) */
54
+ selectedIds?: Set<string>;
55
+ /** Callback when selection changes */
56
+ onSelectionChange?: (selectedIds: Set<string>) => void;
57
+ /** Content to render in selection toolbar (shown when items selected) */
58
+ selectionToolbar?: (selectedCount: number) => ReactNode;
50
59
  };
51
60
 
52
61
  /**
@@ -70,6 +79,10 @@ export function DataTable<T extends { id: string }>({
70
79
  filterConfig,
71
80
  t = (key) => key,
72
81
  locale,
82
+ selectable,
83
+ selectedIds,
84
+ onSelectionChange,
85
+ selectionToolbar,
73
86
  }: DataTableProps<T>) {
74
87
  // Filter panel open state - starts open if filters are active in URL
75
88
  const hasInitialFilters = Boolean(
@@ -108,6 +121,43 @@ export function DataTable<T extends { id: string }>({
108
121
  params.filter_http_status,
109
122
  );
110
123
 
124
+ // Selection helpers
125
+ const pageIds = useMemo(() => data.map((item) => item.id), [data]);
126
+ const selectedCount = selectedIds?.size ?? 0;
127
+ const allPageSelected = selectable && pageIds.length > 0 && pageIds.every((id) => selectedIds?.has(id));
128
+ const somePageSelected = selectable && pageIds.some((id) => selectedIds?.has(id));
129
+
130
+ const handleToggleAll = useCallback(() => {
131
+ if (!onSelectionChange || !selectedIds) return;
132
+ const next = new Set(selectedIds);
133
+ if (allPageSelected) {
134
+ // Deselect all on current page
135
+ for (const id of pageIds) {
136
+ next.delete(id);
137
+ }
138
+ } else {
139
+ // Select all on current page
140
+ for (const id of pageIds) {
141
+ next.add(id);
142
+ }
143
+ }
144
+ onSelectionChange(next);
145
+ }, [onSelectionChange, selectedIds, allPageSelected, pageIds]);
146
+
147
+ const handleToggleRow = useCallback(
148
+ (id: string) => {
149
+ if (!onSelectionChange || !selectedIds) return;
150
+ const next = new Set(selectedIds);
151
+ if (next.has(id)) {
152
+ next.delete(id);
153
+ } else {
154
+ next.add(id);
155
+ }
156
+ onSelectionChange(next);
157
+ },
158
+ [onSelectionChange, selectedIds],
159
+ );
160
+
111
161
  // Show skeleton during initial load (with filter bar for consistency)
112
162
  if (isFetching && !queryResult) {
113
163
  return (
@@ -123,7 +173,7 @@ export function DataTable<T extends { id: string }>({
123
173
  isOpen={filterPanelOpen}
124
174
  onToggle={setFilterPanelOpen}
125
175
  />
126
- <TableSkeleton columns={columns.length} rows={10} />
176
+ <TableSkeleton columns={columns.length + (selectable ? 1 : 0)} rows={10} />
127
177
  </div>
128
178
  );
129
179
  }
@@ -155,12 +205,26 @@ export function DataTable<T extends { id: string }>({
155
205
  onToggle={setFilterPanelOpen}
156
206
  />
157
207
 
208
+ {selectable && selectedCount > 0 && selectionToolbar && (
209
+ <div className="flex items-center gap-3 rounded-lg border bg-muted/50 px-4 py-2">
210
+ {selectionToolbar(selectedCount)}
211
+ </div>
212
+ )}
213
+
158
214
  <div className="rounded-lg border">
159
215
  <Table>
160
216
  {renderHeader ? (
161
217
  renderHeader({ orderBy: params.order_by, onSort: handleSort })
162
218
  ) : (
163
- <DefaultTableHeader columns={columns} orderBy={params.order_by} onSort={handleSort} />
219
+ <DefaultTableHeader
220
+ columns={columns}
221
+ orderBy={params.order_by}
222
+ onSort={handleSort}
223
+ selectable={selectable}
224
+ allPageSelected={allPageSelected}
225
+ somePageSelected={somePageSelected}
226
+ onToggleAll={handleToggleAll}
227
+ />
164
228
  )}
165
229
 
166
230
  <TableBody>
@@ -172,7 +236,17 @@ export function DataTable<T extends { id: string }>({
172
236
  }
173
237
 
174
238
  // Default row renderer
175
- return <DefaultTableRow key={item.id} item={item} columns={columns} onRowClick={onRowClick} />;
239
+ return (
240
+ <DefaultTableRow
241
+ key={item.id}
242
+ item={item}
243
+ columns={columns}
244
+ onRowClick={onRowClick}
245
+ selectable={selectable}
246
+ isSelected={selectedIds?.has(item.id)}
247
+ onToggleSelect={handleToggleRow}
248
+ />
249
+ );
176
250
  })
177
251
  ) : (
178
252
  <TableNoResults resource={resourceName} search={handleSearch} t={t} />
@@ -199,14 +273,31 @@ const DefaultTableHeader = memo(function DefaultTableHeader<T>({
199
273
  columns,
200
274
  orderBy,
201
275
  onSort,
276
+ selectable,
277
+ allPageSelected,
278
+ somePageSelected,
279
+ onToggleAll,
202
280
  }: {
203
281
  columns: Column<T>[];
204
282
  orderBy?: string;
205
283
  onSort?: (order: string | null) => void;
284
+ selectable?: boolean;
285
+ allPageSelected?: boolean;
286
+ somePageSelected?: boolean;
287
+ onToggleAll?: () => void;
206
288
  }) {
207
289
  return (
208
290
  <TableHeader>
209
291
  <TableRow>
292
+ {selectable && (
293
+ <TableHead className="w-[40px]">
294
+ <Checkbox
295
+ checked={allPageSelected || false}
296
+ indeterminate={!allPageSelected && somePageSelected}
297
+ onCheckedChange={onToggleAll}
298
+ />
299
+ </TableHead>
300
+ )}
210
301
  {columns.map((column) => (
211
302
  <TableHead key={column.id} className={column.className} style={{ textAlign: column.align }}>
212
303
  {column.sortable ? (
@@ -226,7 +317,15 @@ const DefaultTableHeader = memo(function DefaultTableHeader<T>({
226
317
  </TableRow>
227
318
  </TableHeader>
228
319
  );
229
- }) as <T>(props: { columns: Column<T>[]; orderBy?: string; onSort?: (order: string | null) => void }) => JSX.Element;
320
+ }) as <T>(props: {
321
+ columns: Column<T>[];
322
+ orderBy?: string;
323
+ onSort?: (order: string | null) => void;
324
+ selectable?: boolean;
325
+ allPageSelected?: boolean;
326
+ somePageSelected?: boolean;
327
+ onToggleAll?: () => void;
328
+ }) => JSX.Element;
230
329
 
231
330
  /**
232
331
  * Default row renderer using column definitions
@@ -235,13 +334,28 @@ const DefaultTableRow = memo(function DefaultTableRow<T extends { id: string }>(
235
334
  item,
236
335
  columns,
237
336
  onRowClick,
337
+ selectable,
338
+ isSelected,
339
+ onToggleSelect,
238
340
  }: {
239
341
  item: T;
240
342
  columns: Column<T>[];
241
343
  onRowClick?: (item: T) => void;
344
+ selectable?: boolean;
345
+ isSelected?: boolean;
346
+ onToggleSelect?: (id: string) => void;
242
347
  }) {
243
348
  return (
244
349
  <TableRow className={onRowClick ? "cursor-pointer" : undefined} onClick={() => onRowClick?.(item)}>
350
+ {selectable && (
351
+ <TableCell className="w-[40px]">
352
+ <Checkbox
353
+ checked={isSelected || false}
354
+ onCheckedChange={() => onToggleSelect?.(item.id)}
355
+ onClick={(e) => e.stopPropagation()}
356
+ />
357
+ </TableCell>
358
+ )}
245
359
  {columns.map((column) => (
246
360
  <TableCell key={column.id} className={column.className} style={{ textAlign: column.align }}>
247
361
  {column.cell?.(item)}
@@ -253,4 +367,7 @@ const DefaultTableRow = memo(function DefaultTableRow<T extends { id: string }>(
253
367
  item: T;
254
368
  columns: Column<T>[];
255
369
  onRowClick?: (item: T) => void;
370
+ selectable?: boolean;
371
+ isSelected?: boolean;
372
+ onToggleSelect?: (id: string) => void;
256
373
  }) => JSX.Element;
@@ -0,0 +1,36 @@
1
+ import { FileDown, X } from "lucide-react";
2
+ import { Button } from "@/ui/components/ui/button";
3
+
4
+ type SelectionToolbarProps = {
5
+ selectedCount: number;
6
+ onExportPdfs?: () => void;
7
+ onDeselectAll?: () => void;
8
+ t?: (key: string) => string;
9
+ };
10
+
11
+ export function SelectionToolbar({
12
+ selectedCount,
13
+ onExportPdfs,
14
+ onDeselectAll,
15
+ t = (key) => key,
16
+ }: SelectionToolbarProps) {
17
+ return (
18
+ <>
19
+ <span className="font-medium text-sm">
20
+ {selectedCount} {t("selected")}
21
+ </span>
22
+ {onExportPdfs && (
23
+ <Button variant="outline" size="sm" onClick={onExportPdfs}>
24
+ <FileDown className="mr-1.5 size-4" />
25
+ {t("Export PDFs")}
26
+ </Button>
27
+ )}
28
+ {onDeselectAll && (
29
+ <Button variant="ghost" size="sm" onClick={onDeselectAll}>
30
+ <X className="mr-1.5 size-4" />
31
+ {t("Deselect all")}
32
+ </Button>
33
+ )}
34
+ </>
35
+ );
36
+ }
@@ -84,76 +84,96 @@ export function KirExportForm({ sdk, entityId, t, onSuccess, onError, onLoadingC
84
84
  }
85
85
  };
86
86
 
87
+ const fileName = `KIR_${year}_${periodType === "month" ? `M${month}` : `Q${quarter}`}.zip`;
88
+
87
89
  return (
88
90
  <div className="space-y-4">
89
- {/* Year Selection */}
90
- <div className="space-y-2">
91
- <Label htmlFor="kir-year">{t("kir-export.year")}</Label>
92
- <Select value={year.toString()} onValueChange={(v) => setYear(Number(v))}>
93
- <SelectTrigger id="kir-year">
94
- <SelectValue />
95
- </SelectTrigger>
96
- <SelectContent>
97
- {yearOptions.map((y) => (
98
- <SelectItem key={y} value={y.toString()}>
99
- {y}
100
- </SelectItem>
101
- ))}
102
- </SelectContent>
103
- </Select>
104
- </div>
105
-
106
- {/* Period Type Selection */}
107
- <div className="space-y-2">
108
- <Label htmlFor="kir-period-type">{t("kir-export.period-type")}</Label>
109
- <Select value={periodType} onValueChange={(v) => setPeriodType(v as PeriodType)}>
110
- <SelectTrigger id="kir-period-type">
111
- <SelectValue />
112
- </SelectTrigger>
113
- <SelectContent>
114
- <SelectItem value="month">{t("kir-export.period-types.month")}</SelectItem>
115
- <SelectItem value="quarter">{t("kir-export.period-types.quarter")}</SelectItem>
116
- </SelectContent>
117
- </Select>
118
- </div>
119
-
120
- {/* Month/Quarter Selection */}
121
- {periodType === "month" ? (
91
+ {/* Year + Period Type + Month/Quarter */}
92
+ <div className="grid grid-cols-3 gap-4">
122
93
  <div className="space-y-2">
123
- <Label htmlFor="kir-month">{t("kir-export.month")}</Label>
124
- <Select value={month.toString()} onValueChange={(v) => setMonth(Number(v))}>
125
- <SelectTrigger id="kir-month">
94
+ <Label htmlFor="kir-year">{t("kir-export.year")}</Label>
95
+ <Select value={year.toString()} onValueChange={(v) => setYear(Number(v))}>
96
+ <SelectTrigger id="kir-year">
126
97
  <SelectValue />
127
98
  </SelectTrigger>
128
99
  <SelectContent>
129
- {Array.from({ length: 12 }, (_, i) => i + 1).map((m) => (
130
- <SelectItem key={m} value={m.toString()}>
131
- {t(`kir-export.months.${m}`)}
100
+ {yearOptions.map((y) => (
101
+ <SelectItem key={y} value={y.toString()}>
102
+ {y}
132
103
  </SelectItem>
133
104
  ))}
134
105
  </SelectContent>
135
106
  </Select>
136
107
  </div>
137
- ) : (
108
+
138
109
  <div className="space-y-2">
139
- <Label htmlFor="kir-quarter">{t("kir-export.quarter")}</Label>
140
- <Select value={quarter.toString()} onValueChange={(v) => setQuarter(Number(v))}>
141
- <SelectTrigger id="kir-quarter">
142
- <SelectValue />
143
- </SelectTrigger>
144
- <SelectContent>
145
- {[1, 2, 3, 4].map((q) => (
146
- <SelectItem key={q} value={q.toString()}>
147
- {t(`kir-export.quarters.${q}`)}
148
- </SelectItem>
149
- ))}
150
- </SelectContent>
151
- </Select>
110
+ <Label>{t("kir-export.period-type")}</Label>
111
+ <div className="flex rounded-md border">
112
+ <button
113
+ type="button"
114
+ onClick={() => setPeriodType("month")}
115
+ className={`flex-1 rounded-l-md px-3 py-2 font-medium text-sm transition-colors ${
116
+ periodType === "month" ? "bg-primary text-primary-foreground" : "hover:bg-muted"
117
+ }`}
118
+ >
119
+ {t("kir-export.period-types.month")}
120
+ </button>
121
+ <button
122
+ type="button"
123
+ onClick={() => setPeriodType("quarter")}
124
+ className={`flex-1 rounded-r-md border-l px-3 py-2 font-medium text-sm transition-colors ${
125
+ periodType === "quarter" ? "bg-primary text-primary-foreground" : "hover:bg-muted"
126
+ }`}
127
+ >
128
+ {t("kir-export.period-types.quarter")}
129
+ </button>
130
+ </div>
152
131
  </div>
153
- )}
132
+
133
+ {periodType === "month" ? (
134
+ <div className="space-y-2">
135
+ <Label htmlFor="kir-month">{t("kir-export.month")}</Label>
136
+ <Select value={month.toString()} onValueChange={(v) => setMonth(Number(v))}>
137
+ <SelectTrigger id="kir-month">
138
+ <SelectValue />
139
+ </SelectTrigger>
140
+ <SelectContent>
141
+ {Array.from({ length: 12 }, (_, i) => i + 1).map((m) => (
142
+ <SelectItem key={m} value={m.toString()}>
143
+ {t(`kir-export.months.${m}`)}
144
+ </SelectItem>
145
+ ))}
146
+ </SelectContent>
147
+ </Select>
148
+ </div>
149
+ ) : (
150
+ <div className="space-y-2">
151
+ <Label htmlFor="kir-quarter">{t("kir-export.quarter")}</Label>
152
+ <Select value={quarter.toString()} onValueChange={(v) => setQuarter(Number(v))}>
153
+ <SelectTrigger id="kir-quarter">
154
+ <SelectValue />
155
+ </SelectTrigger>
156
+ <SelectContent>
157
+ {[1, 2, 3, 4].map((q) => (
158
+ <SelectItem key={q} value={q.toString()}>
159
+ {t(`kir-export.quarters.${q}`)}
160
+ </SelectItem>
161
+ ))}
162
+ </SelectContent>
163
+ </Select>
164
+ </div>
165
+ )}
166
+ </div>
167
+
168
+ {/* File Preview */}
169
+ <div className="rounded-md border border-dashed p-3">
170
+ <p className="text-muted-foreground text-sm">
171
+ {t("kir-export.file-preview")}: <span className="font-medium font-mono text-foreground">{fileName}</span>
172
+ </p>
173
+ </div>
154
174
 
155
175
  {/* Export Button */}
156
- <Button onClick={handleExport} disabled={isExporting} className="w-full">
176
+ <Button onClick={handleExport} disabled={isExporting} className="w-full" size="lg">
157
177
  {isExporting ? (
158
178
  <>
159
179
  <Loader2 className="mr-2 h-4 w-4 animate-spin" />
@@ -12,14 +12,11 @@ import {
12
12
 
13
13
  type TaxListRowActionsProps = {
14
14
  tax: Tax;
15
+ onView?: (tax: Tax) => void;
15
16
  t: (key: string) => string;
16
17
  };
17
18
 
18
- export default function TaxListRowActions({ tax, t }: TaxListRowActionsProps) {
19
- const handleViewTax = () => {
20
- window.location.href = `/app/taxes/${tax.id}`;
21
- };
22
-
19
+ export default function TaxListRowActions({ tax, onView, t }: TaxListRowActionsProps) {
23
20
  return (
24
21
  <DropdownMenu>
25
22
  <DropdownMenuTrigger asChild>
@@ -34,7 +31,7 @@ export default function TaxListRowActions({ tax, t }: TaxListRowActionsProps) {
34
31
  {t("Copy tax ID")}
35
32
  </DropdownMenuItem>
36
33
  <DropdownMenuSeparator />
37
- <DropdownMenuItem className="cursor-pointer" onClick={handleViewTax}>
34
+ <DropdownMenuItem className="cursor-pointer" onClick={() => onView?.(tax)}>
38
35
  {t("View tax")}
39
36
  </DropdownMenuItem>
40
37
  </DropdownMenuContent>
@@ -8,10 +8,11 @@ import TaxListRowActions from "./tax-list-row-actions";
8
8
  type TaxListRowProps = {
9
9
  tax: Tax;
10
10
  onRowClick?: (tax: Tax) => void;
11
+ onView?: (tax: Tax) => void;
11
12
  t: (key: string) => string;
12
13
  };
13
14
 
14
- export default function TaxListRow({ tax, onRowClick, t }: TaxListRowProps) {
15
+ export default function TaxListRow({ tax, onRowClick, onView, t }: TaxListRowProps) {
15
16
  const formatTaxRates = (taxRates: Tax["tax_rates"]) => {
16
17
  if (!taxRates || taxRates.length === 0) return "-";
17
18
  return taxRates.map((rate) => `${rate.rate}%`).join(", ");
@@ -39,7 +40,7 @@ export default function TaxListRow({ tax, onRowClick, t }: TaxListRowProps) {
39
40
  <TableCell>{formatTaxRates(tax.tax_rates)}</TableCell>
40
41
  <TableCell>{formatDate(tax.created_at)}</TableCell>
41
42
  <TableCell className="text-right">
42
- <TaxListRowActions tax={tax} t={t} />
43
+ <TaxListRowActions tax={tax} onView={onView} t={t} />
43
44
  </TableCell>
44
45
  </TableRow>
45
46
  );
@@ -34,6 +34,7 @@ const translations = {
34
34
 
35
35
  type TaxListTableProps = {
36
36
  entityId?: string;
37
+ onView?: (tax: Tax) => void;
37
38
  } & ListTableProps<Tax> &
38
39
  ComponentTranslationProps;
39
40
 
@@ -41,6 +42,7 @@ export default function TaxListTable({
41
42
  queryParams,
42
43
  createNewTrigger,
43
44
  onRowClick,
45
+ onView,
44
46
  onChangeParams,
45
47
  entityId,
46
48
  ...i18nProps
@@ -61,7 +63,9 @@ export default function TaxListTable({
61
63
  { id: "created_at", header: t("Created"), sortable: true },
62
64
  { id: "actions", header: "", align: "right" },
63
65
  ]}
64
- renderRow={(tax) => <TaxListRow tax={tax} key={tax.id} onRowClick={(tax) => onRowClick?.(tax)} t={t} />}
66
+ renderRow={(tax) => (
67
+ <TaxListRow tax={tax} key={tax.id} onRowClick={(tax) => onRowClick?.(tax)} onView={onView} t={t} />
68
+ )}
65
69
  renderHeader={(headerProps) => <TaxListHeader orderBy={headerProps.orderBy} onSort={headerProps.onSort} t={t} />}
66
70
  queryParams={queryParams}
67
71
  resourceName="tax"
@@ -1,14 +1,15 @@
1
1
  import { Checkbox as CheckboxPrimitive } from "@base-ui/react/checkbox"
2
2
 
3
3
  import { cn } from "@/ui/lib/utils"
4
- import { CheckIcon } from "lucide-react"
4
+ import { CheckIcon, MinusIcon } from "lucide-react"
5
5
 
6
- function Checkbox({ className, ...props }: CheckboxPrimitive.Root.Props) {
6
+ function Checkbox({ className, indeterminate, ...props }: CheckboxPrimitive.Root.Props & { indeterminate?: boolean }) {
7
7
  return (
8
8
  <CheckboxPrimitive.Root
9
9
  data-slot="checkbox"
10
+ indeterminate={indeterminate}
10
11
  className={cn(
11
- "border-input dark:bg-input/30 data-checked:bg-primary data-checked:text-primary-foreground dark:data-checked:bg-primary data-checked:border-primary aria-invalid:aria-checked:border-primary aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 flex size-4 items-center justify-center rounded-[4px] border shadow-xs transition-shadow group-has-disabled/field:opacity-50 focus-visible:ring-[3px] aria-invalid:ring-[3px] peer relative shrink-0 outline-none after:absolute after:-inset-x-3 after:-inset-y-2 cursor-pointer disabled:cursor-not-allowed disabled:opacity-50",
12
+ "border-input dark:bg-input/30 data-checked:bg-primary data-checked:text-primary-foreground dark:data-checked:bg-primary data-checked:border-primary aria-invalid:aria-checked:border-primary aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 flex size-4 items-center justify-center rounded-[4px] border shadow-xs transition-shadow group-has-disabled/field:opacity-50 focus-visible:ring-[3px] aria-invalid:ring-[3px] peer relative shrink-0 outline-none after:absolute after:-inset-x-3 after:-inset-y-2 cursor-pointer disabled:cursor-not-allowed disabled:opacity-50 data-[indeterminate]:bg-primary data-[indeterminate]:text-primary-foreground data-[indeterminate]:border-primary",
12
13
  className
13
14
  )}
14
15
  {...props}
@@ -17,8 +18,7 @@ function Checkbox({ className, ...props }: CheckboxPrimitive.Root.Props) {
17
18
  data-slot="checkbox-indicator"
18
19
  className="[&>svg]:size-3.5 grid place-content-center text-current transition-none"
19
20
  >
20
- <CheckIcon
21
- />
21
+ {indeterminate ? <MinusIcon /> : <CheckIcon />}
22
22
  </CheckboxPrimitive.Indicator>
23
23
  </CheckboxPrimitive.Root>
24
24
  )