@spaceinvoices/react-ui 0.4.8 → 0.4.10

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 (258) hide show
  1. package/cli/dist/index.js +1 -1
  2. package/package.json +1 -1
  3. package/src/common/autocomplete.tsx +69 -6
  4. package/src/components/advance-invoices/create/create-advance-invoice-form.tsx +124 -285
  5. package/src/components/advance-invoices/list/list-table.tsx +10 -3
  6. package/src/components/advance-invoices/list/locales/de.ts +2 -0
  7. package/src/components/advance-invoices/list/locales/en.ts +1 -0
  8. package/src/components/advance-invoices/list/locales/es.ts +1 -0
  9. package/src/components/advance-invoices/list/locales/fr.ts +1 -0
  10. package/src/components/advance-invoices/list/locales/hr.ts +1 -0
  11. package/src/components/advance-invoices/list/locales/it.ts +1 -0
  12. package/src/components/advance-invoices/list/locales/nl.ts +1 -0
  13. package/src/components/advance-invoices/list/locales/pl.ts +1 -0
  14. package/src/components/advance-invoices/list/locales/pt.ts +1 -0
  15. package/src/components/advance-invoices/list/locales/sl.ts +1 -0
  16. package/src/components/advance-invoices/list/use-advance-invoice-download.ts +1 -12
  17. package/src/components/credit-notes/create/create-credit-note-form.tsx +116 -238
  18. package/src/components/credit-notes/list/list-table.tsx +6 -3
  19. package/src/components/credit-notes/list/use-credit-note-download.ts +1 -12
  20. package/src/components/customers/customer-autocomplete.tsx +64 -11
  21. package/src/components/customers/customer-list-table/customer-list-table.tsx +3 -2
  22. package/src/components/dashboard/collection-rate-card/collection-rate-card.tsx +9 -1
  23. package/src/components/dashboard/collection-rate-card/locales/bg.ts +3 -0
  24. package/src/components/dashboard/collection-rate-card/locales/cs.ts +3 -0
  25. package/src/components/dashboard/collection-rate-card/locales/et.ts +3 -0
  26. package/src/components/dashboard/collection-rate-card/locales/fi.ts +3 -0
  27. package/src/components/dashboard/collection-rate-card/locales/is.ts +3 -0
  28. package/src/components/dashboard/collection-rate-card/locales/nb.ts +3 -0
  29. package/src/components/dashboard/collection-rate-card/locales/sk.ts +3 -0
  30. package/src/components/dashboard/collection-rate-card/locales/sv.ts +3 -0
  31. package/src/components/dashboard/invoice-status-chart/invoice-status-chart.tsx +10 -2
  32. package/src/components/dashboard/invoice-status-chart/locales/bg.ts +10 -0
  33. package/src/components/dashboard/invoice-status-chart/locales/cs.ts +10 -0
  34. package/src/components/dashboard/invoice-status-chart/locales/de.ts +1 -0
  35. package/src/components/dashboard/invoice-status-chart/locales/es.ts +1 -0
  36. package/src/components/dashboard/invoice-status-chart/locales/et.ts +10 -0
  37. package/src/components/dashboard/invoice-status-chart/locales/fi.ts +10 -0
  38. package/src/components/dashboard/invoice-status-chart/locales/fr.ts +1 -0
  39. package/src/components/dashboard/invoice-status-chart/locales/hr.ts +1 -0
  40. package/src/components/dashboard/invoice-status-chart/locales/is.ts +10 -0
  41. package/src/components/dashboard/invoice-status-chart/locales/it.ts +1 -0
  42. package/src/components/dashboard/invoice-status-chart/locales/nb.ts +10 -0
  43. package/src/components/dashboard/invoice-status-chart/locales/nl.ts +1 -0
  44. package/src/components/dashboard/invoice-status-chart/locales/pl.ts +1 -0
  45. package/src/components/dashboard/invoice-status-chart/locales/pt.ts +1 -0
  46. package/src/components/dashboard/invoice-status-chart/locales/sk.ts +10 -0
  47. package/src/components/dashboard/invoice-status-chart/locales/sl.ts +1 -0
  48. package/src/components/dashboard/invoice-status-chart/locales/sv.ts +10 -0
  49. package/src/components/dashboard/payment-methods-chart/locales/bg.ts +12 -0
  50. package/src/components/dashboard/payment-methods-chart/locales/cs.ts +12 -0
  51. package/src/components/dashboard/payment-methods-chart/locales/et.ts +12 -0
  52. package/src/components/dashboard/payment-methods-chart/locales/fi.ts +12 -0
  53. package/src/components/dashboard/payment-methods-chart/locales/is.ts +12 -0
  54. package/src/components/dashboard/payment-methods-chart/locales/nb.ts +12 -0
  55. package/src/components/dashboard/payment-methods-chart/locales/sk.ts +12 -0
  56. package/src/components/dashboard/payment-methods-chart/locales/sv.ts +12 -0
  57. package/src/components/dashboard/payment-methods-chart/payment-methods-chart.tsx +9 -1
  58. package/src/components/dashboard/payment-trend-chart/locales/bg.ts +6 -0
  59. package/src/components/dashboard/payment-trend-chart/locales/cs.ts +6 -0
  60. package/src/components/dashboard/payment-trend-chart/locales/de.ts +1 -0
  61. package/src/components/dashboard/payment-trend-chart/locales/es.ts +1 -0
  62. package/src/components/dashboard/payment-trend-chart/locales/et.ts +6 -0
  63. package/src/components/dashboard/payment-trend-chart/locales/fi.ts +6 -0
  64. package/src/components/dashboard/payment-trend-chart/locales/fr.ts +1 -0
  65. package/src/components/dashboard/payment-trend-chart/locales/hr.ts +1 -0
  66. package/src/components/dashboard/payment-trend-chart/locales/is.ts +6 -0
  67. package/src/components/dashboard/payment-trend-chart/locales/it.ts +1 -0
  68. package/src/components/dashboard/payment-trend-chart/locales/nb.ts +6 -0
  69. package/src/components/dashboard/payment-trend-chart/locales/nl.ts +1 -0
  70. package/src/components/dashboard/payment-trend-chart/locales/pl.ts +1 -0
  71. package/src/components/dashboard/payment-trend-chart/locales/pt.ts +1 -0
  72. package/src/components/dashboard/payment-trend-chart/locales/sk.ts +6 -0
  73. package/src/components/dashboard/payment-trend-chart/locales/sl.ts +1 -0
  74. package/src/components/dashboard/payment-trend-chart/locales/sv.ts +6 -0
  75. package/src/components/dashboard/payment-trend-chart/payment-trend-chart.tsx +15 -8
  76. package/src/components/dashboard/revenue-trend-chart/locales/bg.ts +6 -0
  77. package/src/components/dashboard/revenue-trend-chart/locales/cs.ts +6 -0
  78. package/src/components/dashboard/revenue-trend-chart/locales/de.ts +1 -0
  79. package/src/components/dashboard/revenue-trend-chart/locales/es.ts +1 -0
  80. package/src/components/dashboard/revenue-trend-chart/locales/et.ts +6 -0
  81. package/src/components/dashboard/revenue-trend-chart/locales/fi.ts +6 -0
  82. package/src/components/dashboard/revenue-trend-chart/locales/fr.ts +1 -0
  83. package/src/components/dashboard/revenue-trend-chart/locales/hr.ts +1 -0
  84. package/src/components/dashboard/revenue-trend-chart/locales/is.ts +6 -0
  85. package/src/components/dashboard/revenue-trend-chart/locales/it.ts +1 -0
  86. package/src/components/dashboard/revenue-trend-chart/locales/nb.ts +6 -0
  87. package/src/components/dashboard/revenue-trend-chart/locales/nl.ts +1 -0
  88. package/src/components/dashboard/revenue-trend-chart/locales/pl.ts +1 -0
  89. package/src/components/dashboard/revenue-trend-chart/locales/pt.ts +1 -0
  90. package/src/components/dashboard/revenue-trend-chart/locales/sk.ts +6 -0
  91. package/src/components/dashboard/revenue-trend-chart/locales/sl.ts +1 -0
  92. package/src/components/dashboard/revenue-trend-chart/locales/sv.ts +6 -0
  93. package/src/components/dashboard/revenue-trend-chart/revenue-trend-chart.tsx +15 -8
  94. package/src/components/dashboard/tax-collected-card/locales.ts +110 -0
  95. package/src/components/dashboard/tax-collected-card/tax-collected-card.tsx +8 -2
  96. package/src/components/dashboard/tax-collected-card/use-tax-collected.ts +4 -4
  97. package/src/components/dashboard/top-customers-chart/locales/bg.ts +7 -0
  98. package/src/components/dashboard/top-customers-chart/locales/cs.ts +7 -0
  99. package/src/components/dashboard/top-customers-chart/locales/de.ts +2 -0
  100. package/src/components/dashboard/top-customers-chart/locales/es.ts +2 -0
  101. package/src/components/dashboard/top-customers-chart/locales/et.ts +7 -0
  102. package/src/components/dashboard/top-customers-chart/locales/fi.ts +7 -0
  103. package/src/components/dashboard/top-customers-chart/locales/fr.ts +2 -0
  104. package/src/components/dashboard/top-customers-chart/locales/hr.ts +2 -0
  105. package/src/components/dashboard/top-customers-chart/locales/is.ts +7 -0
  106. package/src/components/dashboard/top-customers-chart/locales/it.ts +2 -0
  107. package/src/components/dashboard/top-customers-chart/locales/nb.ts +7 -0
  108. package/src/components/dashboard/top-customers-chart/locales/nl.ts +2 -0
  109. package/src/components/dashboard/top-customers-chart/locales/pl.ts +2 -0
  110. package/src/components/dashboard/top-customers-chart/locales/pt.ts +2 -0
  111. package/src/components/dashboard/top-customers-chart/locales/sk.ts +7 -0
  112. package/src/components/dashboard/top-customers-chart/locales/sl.ts +2 -0
  113. package/src/components/dashboard/top-customers-chart/locales/sv.ts +7 -0
  114. package/src/components/dashboard/top-customers-chart/top-customers-chart.tsx +23 -12
  115. package/src/components/delivery-notes/create/create-delivery-note-form.tsx +33 -20
  116. package/src/components/delivery-notes/list/list-table.tsx +22 -13
  117. package/src/components/delivery-notes/list/locales/de.ts +2 -0
  118. package/src/components/delivery-notes/list/locales/en.ts +1 -0
  119. package/src/components/delivery-notes/list/locales/es.ts +1 -0
  120. package/src/components/delivery-notes/list/locales/fr.ts +1 -0
  121. package/src/components/delivery-notes/list/locales/hr.ts +1 -0
  122. package/src/components/delivery-notes/list/locales/it.ts +1 -0
  123. package/src/components/delivery-notes/list/locales/nl.ts +1 -0
  124. package/src/components/delivery-notes/list/locales/pl.ts +1 -0
  125. package/src/components/delivery-notes/list/locales/pt.ts +1 -0
  126. package/src/components/delivery-notes/list/locales/sl.ts +1 -0
  127. package/src/components/delivery-notes/list/use-delivery-note-download.ts +1 -12
  128. package/src/components/documents/create/document-add-item-form.tsx +28 -16
  129. package/src/components/documents/create/document-add-item-tax-rate-field.tsx +12 -2
  130. package/src/components/documents/create/document-items-section.tsx +70 -39
  131. package/src/components/documents/create/document-recipient-section.tsx +10 -1
  132. package/src/components/documents/create/live-preview.tsx +113 -15
  133. package/src/components/documents/create/prepare-document-submission.ts +35 -16
  134. package/src/components/documents/create/use-document-customer-form.ts +14 -3
  135. package/src/components/documents/documents.hooks.ts +7 -2
  136. package/src/components/documents/shared/document-preview-display.tsx +136 -67
  137. package/src/components/documents/shared/scaled-document-preview.tsx +45 -5
  138. package/src/components/documents/view/document-actions-bar.tsx +284 -182
  139. package/src/components/documents/view/document-activities-list.tsx +3 -0
  140. package/src/components/documents/view/document-payments-list.tsx +3 -0
  141. package/src/components/documents/view/locales/de.ts +8 -0
  142. package/src/components/documents/view/locales/es.ts +8 -0
  143. package/src/components/documents/view/locales/fr.ts +8 -0
  144. package/src/components/documents/view/locales/hr.ts +8 -0
  145. package/src/components/documents/view/locales/it.ts +8 -0
  146. package/src/components/documents/view/locales/nl.ts +8 -0
  147. package/src/components/documents/view/locales/pl.ts +8 -0
  148. package/src/components/documents/view/locales/pt.ts +8 -0
  149. package/src/components/documents/view/locales/sl.ts +8 -0
  150. package/src/components/documents/view/use-document-download.ts +14 -25
  151. package/src/components/entities/create-entity-form.tsx +101 -16
  152. package/src/components/entities/fina-settings-form/fina-operator-required-dialog.tsx +3 -3
  153. package/src/components/entities/fina-settings-form/fina-settings-form.tsx +78 -124
  154. package/src/components/entities/fina-settings-form/sections/certificate-settings-section.tsx +8 -1
  155. package/src/components/entities/fina-settings-form/sections/premises-management-section.tsx +14 -2
  156. package/src/components/entities/fina-settings-form/sections/register-premise-dialog.tsx +7 -2
  157. package/src/components/entities/furs-settings-form/furs-settings-form.tsx +56 -130
  158. package/src/components/entities/furs-settings-form/sections/certificate-settings-section.tsx +8 -1
  159. package/src/components/entities/furs-settings-form/sections/enable-fiscalization-section.tsx +1 -0
  160. package/src/components/entities/furs-settings-form/sections/general-settings-section.tsx +15 -2
  161. package/src/components/entities/furs-settings-form/sections/premises-management-section.tsx +20 -3
  162. package/src/components/entities/furs-settings-form/sections/register-premise-dialog.tsx +38 -12
  163. package/src/components/entities/settings/eslog-settings-form.tsx +13 -1
  164. package/src/components/entities/settings/pdf-template-selector/demo-invoice-data.ts +3 -22
  165. package/src/components/entities/shared/fiscalization-step-flow.ts +77 -0
  166. package/src/components/entities/shared/fiscalization-step-tabs.tsx +71 -0
  167. package/src/components/estimates/create/create-estimate-form.tsx +34 -21
  168. package/src/components/estimates/list/list-table.tsx +23 -14
  169. package/src/components/estimates/list/locales/de.ts +2 -0
  170. package/src/components/estimates/list/locales/en.ts +1 -0
  171. package/src/components/estimates/list/locales/es.ts +1 -0
  172. package/src/components/estimates/list/locales/fr.ts +1 -0
  173. package/src/components/estimates/list/locales/hr.ts +1 -0
  174. package/src/components/estimates/list/locales/it.ts +1 -0
  175. package/src/components/estimates/list/locales/nl.ts +1 -0
  176. package/src/components/estimates/list/locales/pl.ts +1 -0
  177. package/src/components/estimates/list/locales/pt.ts +1 -0
  178. package/src/components/estimates/list/locales/sl.ts +1 -0
  179. package/src/components/estimates/list/use-estimate-download.ts +1 -12
  180. package/src/components/export/document-export-form.tsx +33 -7
  181. package/src/components/export/sales-per-item-export-form.tsx +23 -7
  182. package/src/components/invoices/create/create-invoice-form.tsx +295 -329
  183. package/src/components/invoices/create/prepare-invoice-submission.ts +0 -8
  184. package/src/components/invoices/list/list-table.tsx +7 -4
  185. package/src/components/invoices/list/use-invoice-download.ts +1 -11
  186. package/src/components/invoices/send-email-dialog/locales/de.ts +2 -0
  187. package/src/components/invoices/send-email-dialog/locales/es.ts +2 -0
  188. package/src/components/invoices/send-email-dialog/locales/fr.ts +2 -0
  189. package/src/components/invoices/send-email-dialog/locales/hr.ts +2 -0
  190. package/src/components/invoices/send-email-dialog/locales/it.ts +2 -0
  191. package/src/components/invoices/send-email-dialog/locales/nl.ts +2 -0
  192. package/src/components/invoices/send-email-dialog/locales/pl.ts +2 -0
  193. package/src/components/invoices/send-email-dialog/locales/pt.ts +2 -0
  194. package/src/components/invoices/send-email-dialog/locales/sl.ts +2 -0
  195. package/src/components/invoices/send-email-dialog/send-email-dialog.tsx +77 -8
  196. package/src/components/invoices/view/eslog-info-display.tsx +17 -1
  197. package/src/components/invoices/view/fiscalization-status-card.tsx +7 -3
  198. package/src/components/items/item-combobox.tsx +26 -6
  199. package/src/components/items/item-list-table/item-list-table.tsx +5 -2
  200. package/src/components/payments/list/list-table.tsx +14 -4
  201. package/src/components/recurring-invoices/list/list-table.tsx +7 -4
  202. package/src/components/request-logs/locales.ts +412 -0
  203. package/src/components/request-logs/request-log-detail.tsx +37 -21
  204. package/src/components/request-logs/request-log-list-table.tsx +57 -11
  205. package/src/components/table/data-table.tsx +5 -2
  206. package/src/components/table/date-cell.tsx +3 -1
  207. package/src/components/table/filter-bar.tsx +14 -2
  208. package/src/components/table/hooks/use-table-query.ts +1 -1
  209. package/src/components/table/locales.ts +1116 -0
  210. package/src/components/table/search-input.tsx +12 -3
  211. package/src/components/table/selection-toolbar.tsx +23 -6
  212. package/src/components/table/table-empty-state.tsx +43 -3
  213. package/src/components/table/table-no-results.tsx +3 -3
  214. package/src/components/table/table-pagination.tsx +4 -3
  215. package/src/components/table/types.ts +1 -0
  216. package/src/components/tax-reports/index.ts +1 -0
  217. package/src/components/tax-reports/kir-export-form.tsx +46 -8
  218. package/src/components/tax-reports/slovenia-tax-profile-step.tsx +191 -0
  219. package/src/components/tax-reports/slovenia-yearly-export-form.tsx +509 -0
  220. package/src/components/tax-reports/slovenia-yearly-review-step.tsx +253 -0
  221. package/src/components/tax-reports/slovenia-yearly-summary.tsx +19 -0
  222. package/src/components/taxes/tax-list-table/tax-list-table.tsx +3 -2
  223. package/src/components/ui/sticky-form-footer.tsx +7 -1
  224. package/src/components/webhook-logs/index.ts +6 -0
  225. package/src/components/webhook-logs/locales.ts +392 -0
  226. package/src/components/webhook-logs/webhook-delivery-detail.tsx +255 -0
  227. package/src/components/webhook-logs/webhook-delivery-list-table.tsx +278 -0
  228. package/src/components/wl-subscription/index.ts +1 -0
  229. package/src/components/wl-subscription/locked-feature.tsx +1 -0
  230. package/src/components/wl-subscription/paywall.tsx +193 -0
  231. package/src/components/wl-subscription/upgrade-modal.tsx +93 -29
  232. package/src/generate-schemas.ts +10 -5
  233. package/src/generated/schemas/customer.ts +2 -0
  234. package/src/generated/schemas/entity.ts +34 -0
  235. package/src/generated/schemas/me.ts +20 -1
  236. package/src/generated/schemas/renderadvanceinvoicepreview_body.ts +40 -34
  237. package/src/generated/schemas/rendercreditnotepreview_body.ts +42 -36
  238. package/src/generated/schemas/renderdeliverynotepreview_body.ts +23 -13
  239. package/src/generated/schemas/renderestimatepreview_body.ts +23 -13
  240. package/src/generated/schemas/renderinvoicepreview_body.ts +40 -34
  241. package/src/generated/schemas/sendemail_body.ts +44 -0
  242. package/src/generated/schemas/startpdfexport_body.ts +91 -1
  243. package/src/generated/schemas/webhook.ts +10 -0
  244. package/src/hooks/use-duplicate-document.ts +51 -13
  245. package/src/hooks/use-eslog-validation.ts +59 -0
  246. package/src/hooks/use-premise-selection.ts +186 -0
  247. package/src/lib/browser-cookies.ts +4 -4
  248. package/src/lib/date-fns-locale.ts +48 -0
  249. package/src/lib/fiscalization-options.ts +81 -0
  250. package/src/lib/locale.ts +38 -0
  251. package/src/lib/template-variables.tsx +1 -1
  252. package/src/lib/translation.ts +14 -3
  253. package/src/providers/entities-context.tsx +1 -0
  254. package/src/providers/entities-provider.tsx +102 -3
  255. package/src/providers/form-footer-context.tsx +37 -4
  256. package/src/providers/sdk-provider.tsx +7 -2
  257. package/src/providers/white-label-provider.tsx +4 -1
  258. package/src/providers/wl-subscription-provider.tsx +90 -3
@@ -0,0 +1,7 @@
1
+ export default {
2
+ "Revenue": "Intäkter",
3
+ "Unknown": "Okänd",
4
+ "Top Customers": "Toppkunder",
5
+ "Top 5 customers by revenue": "Topp 5 kunder efter intäkter",
6
+ "No data available": "Ingen data tillgänglig",
7
+ } as const;
@@ -6,18 +6,26 @@ import { type ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent } f
6
6
  import { createTranslation } from "@/ui/lib/translation";
7
7
  import { ChartEmptyState } from "../chart-empty-state";
8
8
  import { LoadingCard } from "../loading-card";
9
+ import bg from "./locales/bg";
10
+ import cs from "./locales/cs";
9
11
  import de from "./locales/de";
12
+ import et from "./locales/et";
10
13
  import es from "./locales/es";
14
+ import fi from "./locales/fi";
11
15
  import fr from "./locales/fr";
12
16
  import hr from "./locales/hr";
17
+ import is from "./locales/is";
13
18
  import it from "./locales/it";
19
+ import nb from "./locales/nb";
14
20
  import nl from "./locales/nl";
15
21
  import pl from "./locales/pl";
16
22
  import pt from "./locales/pt";
23
+ import sk from "./locales/sk";
17
24
  import sl from "./locales/sl";
25
+ import sv from "./locales/sv";
18
26
  import { useTopCustomersData } from "./use-top-customers";
19
27
 
20
- const translations = { sl, de, it, fr, es, pt, nl, pl, hr } as const;
28
+ const translations = { bg, cs, de, et, es, fi, fr, hr, is, it, nb, nl, pl, pt, sk, sl, sv } as const;
21
29
 
22
30
  export type TopCustomersChartData = { name: string; revenue: number }[];
23
31
 
@@ -41,13 +49,6 @@ type TurnkeyProps = BaseProps & {
41
49
 
42
50
  export type TopCustomersChartProps = DataProps | TurnkeyProps;
43
51
 
44
- const chartConfig = {
45
- revenue: {
46
- label: "Revenue",
47
- color: "var(--chart-1)",
48
- },
49
- } satisfies ChartConfig;
50
-
51
52
  function formatCurrency(value: number, currency: string, locale?: string): string {
52
53
  return new Intl.NumberFormat(locale, {
53
54
  style: "currency",
@@ -74,6 +75,12 @@ export function TopCustomersChart(props: TopCustomersChartProps) {
74
75
  }
75
76
 
76
77
  const hasData = data.length > 0;
78
+ const chartConfig = {
79
+ revenue: {
80
+ label: t("Revenue"),
81
+ color: "var(--chart-1)",
82
+ },
83
+ } satisfies ChartConfig;
77
84
 
78
85
  // Placeholder data for empty state
79
86
  const placeholderData = [
@@ -86,10 +93,14 @@ export function TopCustomersChart(props: TopCustomersChartProps) {
86
93
 
87
94
  // Truncate long names for display
88
95
  const chartData = hasData
89
- ? data.map((d) => ({
90
- ...d,
91
- displayName: d.name.length > 18 ? `${d.name.substring(0, 18)}...` : d.name,
92
- }))
96
+ ? data.map((d) => {
97
+ const localizedName = d.name === "Unknown" ? t("Unknown") : d.name;
98
+ return {
99
+ ...d,
100
+ name: localizedName,
101
+ displayName: localizedName.length > 18 ? `${localizedName.substring(0, 18)}...` : localizedName,
102
+ };
103
+ })
93
104
  : placeholderData;
94
105
 
95
106
  const chartContent = (
@@ -193,6 +193,7 @@ export default function CreateDeliveryNoteForm({
193
193
  const formValues = useWatch({
194
194
  control: form.control,
195
195
  });
196
+ const prevPayloadRef = useRef("");
196
197
 
197
198
  // ============================================================================
198
199
  // VIES Check - determine if reverse charge applies
@@ -301,36 +302,47 @@ export default function CreateDeliveryNoteForm({
301
302
  secondaryAction,
302
303
  });
303
304
 
304
- useEffect(() => {
305
- const callback = onChangeRef.current;
306
- if (!callback) return;
307
-
308
- const currentItems = form.getValues("items") || [];
305
+ const buildPreviewPayload = useCallback((values: CreateDeliveryNoteFormValues): DeliveryNotePreviewPayload => {
306
+ const currentItems = values.items || [];
309
307
 
310
- // Transform items to use gross_price when price mode is gross
311
308
  const transformedItems = currentItems.map((item: any, index: number) => {
312
309
  const { price, ...rest } = item;
313
310
  const isGross = priceModesRef.current[index] ?? false;
314
- if (isGross) {
315
- return { ...rest, gross_price: price };
316
- }
317
- return { ...rest, price };
311
+ return isGross ? { ...rest, gross_price: price } : { ...rest, price };
318
312
  });
319
313
 
320
- const payload: DeliveryNotePreviewPayload = {
321
- number: formValues.number,
322
- date: formValues.date,
323
- customer_id: formValues.customer_id,
324
- customer: formValues.customer,
314
+ return {
315
+ number: values.number,
316
+ date: values.date,
317
+ customer_id: values.customer_id,
318
+ customer: values.customer,
325
319
  items: transformedItems,
326
- currency_code: formValues.currency_code,
327
- reference: formValues.reference,
328
- note: formValues.note,
329
- signature: formValues.signature,
320
+ currency_code: values.currency_code,
321
+ reference: values.reference,
322
+ note: values.note,
323
+ signature: values.signature,
330
324
  hide_prices: hidePrices,
331
325
  };
326
+ }, [hidePrices]);
327
+
328
+ const emitPreviewPayload = useCallback((payload: DeliveryNotePreviewPayload) => {
329
+ const callback = onChangeRef.current;
330
+ if (!callback) return;
331
+
332
+ const payloadStr = JSON.stringify(payload);
333
+ if (payloadStr === prevPayloadRef.current) return;
334
+ prevPayloadRef.current = payloadStr;
335
+
332
336
  callback(payload);
333
- }, [formValues, form, hidePrices]);
337
+ }, []);
338
+
339
+ useEffect(() => {
340
+ emitPreviewPayload(buildPreviewPayload(formValues as CreateDeliveryNoteFormValues));
341
+ }, [buildPreviewPayload, emitPreviewPayload, formValues]);
342
+
343
+ const emitCurrentPreviewPayload = useCallback(() => {
344
+ emitPreviewPayload(buildPreviewPayload(form.getValues()));
345
+ }, [buildPreviewPayload, emitPreviewPayload, form]);
334
346
 
335
347
  const onSubmit = (values: CreateDeliveryNoteFormValues) => {
336
348
  submitDeliveryNote(values, false);
@@ -379,6 +391,7 @@ export default function CreateDeliveryNoteForm({
379
391
  maxTaxesPerItem={activeEntity?.country_rules?.max_taxes_per_item}
380
392
  priceModesRef={priceModesRef}
381
393
  initialPriceModes={initialPriceModes}
394
+ onItemsStateChange={emitCurrentPreviewPayload}
382
395
  taxesDisabled={reverseChargeApplies}
383
396
  taxesDisabledMessage={
384
397
  reverseChargeApplies ? t("Reverse charge - tax exempt EU B2B sale") : viesWarning ? viesWarning : undefined
@@ -3,6 +3,7 @@ import { useCallback, useMemo, useState } from "react";
3
3
  import { DataTable } from "@/ui/components/table/data-table";
4
4
  import { FormattedDate } from "@/ui/components/table/date-cell";
5
5
  import { useTableFetch } from "@/ui/components/table/hooks/use-table-fetch";
6
+ import { withTableTranslations } from "@/ui/components/table/locales";
6
7
  import { SelectionToolbar } from "@/ui/components/table/selection-toolbar";
7
8
  import type {
8
9
  Column,
@@ -28,7 +29,7 @@ import pl from "./locales/pl";
28
29
  import pt from "./locales/pt";
29
30
  import sl from "./locales/sl";
30
31
 
31
- const translations = {
32
+ const translations = withTableTranslations({
32
33
  en,
33
34
  sl,
34
35
  de,
@@ -39,12 +40,13 @@ const translations = {
39
40
  nl,
40
41
  pl,
41
42
  hr,
42
- } as const;
43
+ } as const);
43
44
 
44
45
  type DeliveryNoteListTableProps = {
45
46
  t?: (key: string) => string;
46
47
  namespace?: string;
47
48
  locale?: string;
49
+ translationLocale?: string;
48
50
  entityId?: string;
49
51
  onView?: (deliveryNote: DeliveryNote) => void;
50
52
  onDuplicate?: (deliveryNote: DeliveryNote) => void;
@@ -77,6 +79,7 @@ export default function DeliveryNoteListTable({
77
79
  }: DeliveryNoteListTableProps) {
78
80
  const t = createTranslation({
79
81
  translations,
82
+ locale: i18nProps.translationLocale ?? i18nProps.locale,
80
83
  ...i18nProps,
81
84
  });
82
85
 
@@ -127,16 +130,22 @@ export default function DeliveryNoteListTable({
127
130
  }, []);
128
131
 
129
132
  const selectionToolbar = useCallback(
130
- (count: number) => (
131
- <SelectionToolbar
132
- selectedCount={count}
133
- onExportPdfs={onExportSelected ? handleExportPdfs : undefined}
134
- onCopyToInvoice={onCopyToInvoice ? handleCopyToInvoice : undefined}
135
- onDeselectAll={handleDeselectAll}
136
- t={t}
137
- />
138
- ),
139
- [handleExportPdfs, handleCopyToInvoice, handleDeselectAll, onExportSelected, onCopyToInvoice, t],
133
+ (count: number, data: DeliveryNote[]) => {
134
+ const hasDrafts = data.some((d) => selectedIds.has(d.id) && (d as any).is_draft);
135
+
136
+ return (
137
+ <SelectionToolbar
138
+ selectedCount={count}
139
+ onExportPdfs={onExportSelected ? handleExportPdfs : undefined}
140
+ onCopyToInvoice={onCopyToInvoice ? handleCopyToInvoice : undefined}
141
+ copyToInvoiceDisabled={hasDrafts}
142
+ copyToInvoiceTooltip={hasDrafts ? t("Finalize draft documents before copying to invoice") : undefined}
143
+ onDeselectAll={handleDeselectAll}
144
+ t={t}
145
+ />
146
+ );
147
+ },
148
+ [handleExportPdfs, handleCopyToInvoice, handleDeselectAll, onExportSelected, onCopyToInvoice, selectedIds, t],
140
149
  );
141
150
 
142
151
  const columns: Column<DeliveryNote>[] = useMemo(
@@ -168,7 +177,7 @@ export default function DeliveryNoteListTable({
168
177
  {
169
178
  id: "date",
170
179
  header: t("Date"),
171
- cell: (deliveryNote) => <FormattedDate date={deliveryNote.date} />,
180
+ cell: (deliveryNote) => <FormattedDate date={deliveryNote.date} locale={i18nProps.locale} />,
172
181
  },
173
182
  {
174
183
  id: "total",
@@ -28,6 +28,8 @@ export default {
28
28
  "Export PDFs": "PDFs exportieren",
29
29
  "Deselect all": "Alle abwählen",
30
30
  "Copy to Invoice": "In Rechnung kopieren",
31
+ "Finalize draft documents before copying to invoice":
32
+ "Entwurfsdokumente abschließen, bevor Sie in eine Rechnung kopieren",
31
33
  Void: "Stornieren",
32
34
  Voided: "Storniert",
33
35
  // Row action translations
@@ -28,6 +28,7 @@ export default {
28
28
  "Export PDFs": "Export PDFs",
29
29
  "Deselect all": "Deselect all",
30
30
  "Copy to Invoice": "Copy to Invoice",
31
+ "Finalize draft documents before copying to invoice": "Finalize draft documents before copying to invoice",
31
32
  Void: "Void",
32
33
  Voided: "Voided",
33
34
  // Row action translations
@@ -28,6 +28,7 @@ export default {
28
28
  "Export PDFs": "Exportar PDFs",
29
29
  "Deselect all": "Deseleccionar todo",
30
30
  "Copy to Invoice": "Copiar a factura",
31
+ "Finalize draft documents before copying to invoice": "Finalice los borradores antes de copiar a factura",
31
32
  Void: "Anular",
32
33
  Voided: "Anulado",
33
34
  // Row action translations
@@ -28,6 +28,7 @@ export default {
28
28
  "Export PDFs": "Exporter les PDFs",
29
29
  "Deselect all": "Tout désélectionner",
30
30
  "Copy to Invoice": "Copier vers facture",
31
+ "Finalize draft documents before copying to invoice": "Finalisez les brouillons avant de copier en facture",
31
32
  Void: "Annuler",
32
33
  Voided: "Annulé",
33
34
  // Row action translations
@@ -28,6 +28,7 @@ export default {
28
28
  "Export PDFs": "Izvezi PDF-ove",
29
29
  "Deselect all": "Poništi odabir",
30
30
  "Copy to Invoice": "Kopiraj u račun",
31
+ "Finalize draft documents before copying to invoice": "Dovršite skice dokumenata prije kopiranja u račun",
31
32
  Void: "Storniraj",
32
33
  Voided: "Poništeno",
33
34
  // Row action translations
@@ -28,6 +28,7 @@ export default {
28
28
  "Export PDFs": "Esporta PDF",
29
29
  "Deselect all": "Deseleziona tutto",
30
30
  "Copy to Invoice": "Copia in fattura",
31
+ "Finalize draft documents before copying to invoice": "Finalizzare i documenti bozza prima di copiare in fattura",
31
32
  Void: "Annulla",
32
33
  Voided: "Annullato",
33
34
  // Row action translations
@@ -28,6 +28,7 @@ export default {
28
28
  "Export PDFs": "PDFs exporteren",
29
29
  "Deselect all": "Alles deselecteren",
30
30
  "Copy to Invoice": "Kopieer naar factuur",
31
+ "Finalize draft documents before copying to invoice": "Rond conceptdocumenten af voordat u naar factuur kopieert",
31
32
  Void: "Nietig verklaren",
32
33
  Voided: "Ongeldig verklaard",
33
34
  // Row action translations
@@ -28,6 +28,7 @@ export default {
28
28
  "Export PDFs": "Eksportuj PDF-y",
29
29
  "Deselect all": "Odznacz wszystko",
30
30
  "Copy to Invoice": "Kopiuj do faktury",
31
+ "Finalize draft documents before copying to invoice": "Sfinalizuj wersje robocze przed skopiowaniem do faktury",
31
32
  Void: "Anuluj",
32
33
  Voided: "Anulowana",
33
34
  // Row action translations
@@ -28,6 +28,7 @@ export default {
28
28
  "Export PDFs": "Exportar PDFs",
29
29
  "Deselect all": "Desmarcar tudo",
30
30
  "Copy to Invoice": "Copiar para fatura",
31
+ "Finalize draft documents before copying to invoice": "Finalize os rascunhos antes de copiar para fatura",
31
32
  Void: "Anular",
32
33
  Voided: "Anulado",
33
34
  // Row action translations
@@ -28,6 +28,7 @@ export default {
28
28
  "Export PDFs": "Izvozi PDF-je",
29
29
  "Deselect all": "Počisti izbor",
30
30
  "Copy to Invoice": "Kopiraj v račun",
31
+ "Finalize draft documents before copying to invoice": "Dokončajte osnutke dokumentov pred kopiranjem v račun",
31
32
  Void: "Storniraj",
32
33
  Voided: "Stornirano",
33
34
  // Row action translations
@@ -33,19 +33,8 @@ export function useDeliveryNoteDownload({
33
33
  onDownloadStart?.();
34
34
 
35
35
  try {
36
- // SDK signature: renderPdf(id, params?, SDKMethodOptions?)
37
- // entity_id goes in SDKMethodOptions (last arg), not params
38
- // Note: renderPdf is on invoices module but works with any document ID
39
- const blob = await sdk.invoices.renderPdf(deliveryNote.id, {}, { entity_id: activeEntity.id });
40
- const downloadUrl = window.URL.createObjectURL(blob);
41
- const link = document.createElement("a");
42
- link.href = downloadUrl;
43
36
  const fileName = `${t("Delivery Note")} ${deliveryNote.number}.pdf`;
44
- link.download = fileName;
45
- document.body.appendChild(link);
46
- link.click();
47
- document.body.removeChild(link);
48
- window.URL.revokeObjectURL(downloadUrl);
37
+ await sdk.invoices.downloadPdf(deliveryNote.id, fileName, {}, { entity_id: activeEntity.id });
49
38
 
50
39
  onDownloadSuccess?.(fileName);
51
40
  } catch (error) {
@@ -1,6 +1,6 @@
1
1
  import type { Item } from "@spaceinvoices/js-sdk";
2
2
  import { ChevronDown, ChevronUp, DollarSign, Minus, Percent, Plus, PlusIcon, Trash2 } from "lucide-react";
3
- import { useState } from "react";
3
+ import { useEffect, useState } from "react";
4
4
  import type { Control, UseFormReturn } from "react-hook-form";
5
5
  import { useWatch } from "react-hook-form";
6
6
 
@@ -77,10 +77,13 @@ export default function DocumentAddItemForm({
77
77
  control,
78
78
  name: `items.${index}.taxes`,
79
79
  });
80
-
81
80
  // Component-local state for gross/net price mode (not in form schema)
82
81
  const [isGrossPrice, setIsGrossPrice] = useState(initialIsGrossPrice);
83
82
 
83
+ useEffect(() => {
84
+ setIsGrossPrice(initialIsGrossPrice);
85
+ }, [initialIsGrossPrice]);
86
+
84
87
  const setPriceMode = (mode: string) => {
85
88
  const isGross = mode === "gross";
86
89
  setIsGrossPrice(isGross);
@@ -91,12 +94,16 @@ export default function DocumentAddItemForm({
91
94
  const currentTaxes = taxes || [];
92
95
  if (currentTaxes.length >= maxTaxesPerItem) return;
93
96
 
94
- form.setValue(`items.${index}.taxes`, [
95
- ...currentTaxes,
96
- {
97
- rate: 22,
98
- },
99
- ]);
97
+ form.setValue(
98
+ `items.${index}.taxes`,
99
+ [
100
+ ...currentTaxes,
101
+ {
102
+ rate: 22,
103
+ },
104
+ ],
105
+ { shouldDirty: true, shouldTouch: true },
106
+ );
100
107
  };
101
108
 
102
109
  const removeTax = (taxIndex: number) => {
@@ -104,6 +111,7 @@ export default function DocumentAddItemForm({
104
111
  form.setValue(
105
112
  `items.${index}.taxes`,
106
113
  currentTaxes.filter((_: any, i: number) => i !== taxIndex),
114
+ { shouldDirty: true, shouldTouch: true },
107
115
  );
108
116
  };
109
117
 
@@ -111,23 +119,23 @@ export default function DocumentAddItemForm({
111
119
  const handleItemSelect = (item: Item | null, customName?: string) => {
112
120
  if (item) {
113
121
  // Selected a saved item - set item_id and prefill fields for visual feedback
114
- form.setValue(`items.${index}.item_id`, item.id);
115
- form.setValue(`items.${index}.name`, item.name);
122
+ form.setValue(`items.${index}.item_id`, item.id, { shouldDirty: true, shouldTouch: true });
123
+ form.setValue(`items.${index}.name`, item.name, { shouldDirty: true, shouldTouch: true });
116
124
 
117
125
  // Prefill price (use gross_price if available, otherwise price)
118
126
  if (item.gross_price !== null && item.gross_price !== undefined) {
119
- form.setValue(`items.${index}.price`, item.gross_price);
127
+ form.setValue(`items.${index}.price`, item.gross_price, { shouldDirty: true, shouldTouch: true });
120
128
  setIsGrossPrice(true);
121
129
  onPriceModeChange?.(true);
122
130
  } else if (item.price !== null && item.price !== undefined) {
123
- form.setValue(`items.${index}.price`, item.price);
131
+ form.setValue(`items.${index}.price`, item.price, { shouldDirty: true, shouldTouch: true });
124
132
  setIsGrossPrice(false);
125
133
  onPriceModeChange?.(false);
126
134
  }
127
135
 
128
136
  // Prefill description
129
137
  if (item.description) {
130
- form.setValue(`items.${index}.description`, item.description);
138
+ form.setValue(`items.${index}.description`, item.description, { shouldDirty: true, shouldTouch: true });
131
139
  }
132
140
 
133
141
  // Prefill taxes from item's tax_ids (or clear if item has no taxes)
@@ -135,14 +143,15 @@ export default function DocumentAddItemForm({
135
143
  form.setValue(
136
144
  `items.${index}.taxes`,
137
145
  item.tax_ids.map((tax_id) => ({ tax_id })),
146
+ { shouldDirty: true, shouldTouch: true },
138
147
  );
139
148
  } else {
140
- form.setValue(`items.${index}.taxes`, []);
149
+ form.setValue(`items.${index}.taxes`, [], { shouldDirty: true, shouldTouch: true });
141
150
  }
142
151
  } else if (customName) {
143
152
  // Custom name entered - clear item_id, just use the name
144
- form.setValue(`items.${index}.item_id`, undefined);
145
- form.setValue(`items.${index}.name`, customName);
153
+ form.setValue(`items.${index}.item_id`, undefined, { shouldDirty: true, shouldTouch: true });
154
+ form.setValue(`items.${index}.name`, customName, { shouldDirty: true, shouldTouch: true });
146
155
  }
147
156
  };
148
157
 
@@ -225,7 +234,10 @@ export default function DocumentAddItemForm({
225
234
  entityId={entityId}
226
235
  value={field.value}
227
236
  onSelect={handleItemSelect}
237
+ onCommitInlineName={(nextName) => form.setValue(`items.${index}.name`, nextName)}
238
+ commitOnBlurMode={field.value ? "update-inline" : "create"}
228
239
  placeholder={t("Search or enter item name...")}
240
+ inputTestId={`document-item-input-${index}`}
229
241
  />
230
242
  </FormControl>
231
243
  <FormMessage />
@@ -7,8 +7,16 @@ import { Button } from "@/ui/components/ui/button";
7
7
  import { FormControl, FormField, FormItem, FormLabel, FormMessage } from "@/ui/components/ui/form";
8
8
  import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/ui/components/ui/select";
9
9
  import type { ComponentTranslationProps } from "@/ui/lib/translation";
10
+ import { createTranslation } from "@/ui/lib/translation";
10
11
  import { useListTaxes } from "../../taxes/taxes.hooks";
11
12
 
13
+ const translations = {
14
+ en: {
15
+ Tax: "Tax",
16
+ "Add...": "Add...",
17
+ },
18
+ } as const;
19
+
12
20
  /**
13
21
  * Get the current active rate from a tax (most recent rate by valid_from)
14
22
  */
@@ -43,9 +51,11 @@ export default function DocumentAddItemTaxRateField({
43
51
  onRemove,
44
52
  onAddNewTax,
45
53
  showLabel = true,
46
- t,
54
+ t: translateFn,
55
+ namespace,
56
+ locale,
47
57
  }: DocumentAddItemTaxRateFieldProps) {
48
- const translate = t || ((key: string) => key);
58
+ const translate = createTranslation({ t: translateFn, namespace, locale, translations });
49
59
  const { setValue } = useFormContext();
50
60
 
51
61
  // Fetch available taxes