@spaceinvoices/react-ui 0.4.3 → 0.4.5

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 (263) hide show
  1. package/cli/dist/index.js +1 -1
  2. package/package.json +1 -1
  3. package/src/common/autocomplete.tsx +18 -2
  4. package/src/components/advance-invoices/create/create-advance-invoice-form.tsx +61 -12
  5. package/src/components/advance-invoices/create/locales/de.ts +17 -0
  6. package/src/components/advance-invoices/create/locales/es.ts +17 -0
  7. package/src/components/advance-invoices/create/locales/fr.ts +17 -0
  8. package/src/components/advance-invoices/create/locales/hr.ts +16 -0
  9. package/src/components/advance-invoices/create/locales/it.ts +17 -0
  10. package/src/components/advance-invoices/create/locales/nl.ts +17 -0
  11. package/src/components/advance-invoices/create/locales/pl.ts +16 -0
  12. package/src/components/advance-invoices/create/locales/pt.ts +16 -0
  13. package/src/components/advance-invoices/create/locales/sl.ts +16 -0
  14. package/src/components/advance-invoices/create/prepare-advance-invoice-submission.ts +0 -1
  15. package/src/components/advance-invoices/list/list-row-actions.tsx +48 -1
  16. package/src/components/advance-invoices/list/list-table.tsx +100 -50
  17. package/src/components/advance-invoices/list/locales/de.ts +9 -0
  18. package/src/components/advance-invoices/list/locales/en.ts +7 -0
  19. package/src/components/advance-invoices/list/locales/es.ts +9 -0
  20. package/src/components/advance-invoices/list/locales/fr.ts +9 -0
  21. package/src/components/advance-invoices/list/locales/hr.ts +8 -0
  22. package/src/components/advance-invoices/list/locales/it.ts +9 -0
  23. package/src/components/advance-invoices/list/locales/nl.ts +9 -0
  24. package/src/components/advance-invoices/list/locales/pl.ts +8 -0
  25. package/src/components/advance-invoices/list/locales/pt.ts +9 -0
  26. package/src/components/advance-invoices/list/locales/sl.ts +8 -0
  27. package/src/components/credit-notes/create/create-credit-note-form.tsx +185 -11
  28. package/src/components/credit-notes/create/locales/de.ts +18 -0
  29. package/src/components/credit-notes/create/locales/es.ts +18 -0
  30. package/src/components/credit-notes/create/locales/fr.ts +18 -0
  31. package/src/components/credit-notes/create/locales/hr.ts +17 -0
  32. package/src/components/credit-notes/create/locales/it.ts +18 -0
  33. package/src/components/credit-notes/create/locales/nl.ts +18 -0
  34. package/src/components/credit-notes/create/locales/pl.ts +17 -0
  35. package/src/components/credit-notes/create/locales/pt.ts +17 -0
  36. package/src/components/credit-notes/create/locales/sl.ts +18 -1
  37. package/src/components/credit-notes/credit-notes.hooks.ts +30 -0
  38. package/src/components/credit-notes/list/list-row-actions.tsx +44 -1
  39. package/src/components/credit-notes/list/list-table.tsx +93 -32
  40. package/src/components/credit-notes/list/locales/de.ts +7 -0
  41. package/src/components/credit-notes/list/locales/en.ts +6 -0
  42. package/src/components/credit-notes/list/locales/es.ts +7 -0
  43. package/src/components/credit-notes/list/locales/fr.ts +7 -0
  44. package/src/components/credit-notes/list/locales/hr.ts +7 -0
  45. package/src/components/credit-notes/list/locales/it.ts +7 -0
  46. package/src/components/credit-notes/list/locales/nl.ts +7 -0
  47. package/src/components/credit-notes/list/locales/pl.ts +7 -0
  48. package/src/components/credit-notes/list/locales/pt.ts +7 -0
  49. package/src/components/credit-notes/list/locales/sl.ts +7 -0
  50. package/src/components/customers/customer-list-table/customer-list-table.tsx +0 -3
  51. package/src/components/customers/customer-list-table/locales/de.ts +1 -0
  52. package/src/components/customers/customer-list-table/locales/es.ts +1 -0
  53. package/src/components/customers/customer-list-table/locales/fr.ts +1 -0
  54. package/src/components/customers/customer-list-table/locales/hr.ts +1 -0
  55. package/src/components/customers/customer-list-table/locales/it.ts +1 -0
  56. package/src/components/customers/customer-list-table/locales/nl.ts +1 -0
  57. package/src/components/customers/customer-list-table/locales/pl.ts +1 -0
  58. package/src/components/customers/customer-list-table/locales/pt.ts +1 -0
  59. package/src/components/customers/customer-list-table/locales/sl.ts +1 -0
  60. package/src/components/dashboard/collection-rate-card/use-collection-rate.ts +48 -9
  61. package/src/components/dashboard/revenue-trend-chart/use-revenue-trend.ts +77 -48
  62. package/src/components/dashboard/shared/use-revenue-data.ts +77 -9
  63. package/src/components/delivery-notes/create/create-delivery-note-form.tsx +67 -7
  64. package/src/components/delivery-notes/create/locales/de.ts +16 -0
  65. package/src/components/delivery-notes/create/locales/es.ts +16 -0
  66. package/src/components/delivery-notes/create/locales/fr.ts +16 -0
  67. package/src/components/delivery-notes/create/locales/hr.ts +16 -0
  68. package/src/components/delivery-notes/create/locales/it.ts +16 -0
  69. package/src/components/delivery-notes/create/locales/nl.ts +16 -0
  70. package/src/components/delivery-notes/create/locales/pl.ts +16 -0
  71. package/src/components/delivery-notes/create/locales/pt.ts +16 -0
  72. package/src/components/delivery-notes/create/locales/sl.ts +17 -1
  73. package/src/components/delivery-notes/list/list-row-actions.tsx +20 -1
  74. package/src/components/delivery-notes/list/list-table.tsx +50 -8
  75. package/src/components/delivery-notes/list/locales/de.ts +35 -0
  76. package/src/components/delivery-notes/list/locales/en.ts +33 -0
  77. package/src/components/delivery-notes/list/locales/es.ts +35 -0
  78. package/src/components/delivery-notes/list/locales/fr.ts +35 -0
  79. package/src/components/delivery-notes/list/locales/hr.ts +35 -0
  80. package/src/components/delivery-notes/list/locales/it.ts +35 -0
  81. package/src/components/delivery-notes/list/locales/nl.ts +35 -0
  82. package/src/components/delivery-notes/list/locales/pl.ts +35 -0
  83. package/src/components/delivery-notes/list/locales/pt.ts +35 -0
  84. package/src/components/delivery-notes/list/locales/sl.ts +35 -0
  85. package/src/components/documents/create/document-add-item-form.tsx +70 -0
  86. package/src/components/documents/create/document-details-section.tsx +163 -29
  87. package/src/components/documents/create/document-items-section.tsx +21 -4
  88. package/src/components/documents/create/linked-documents-info.tsx +82 -0
  89. package/src/components/documents/create/live-preview.tsx +25 -5
  90. package/src/components/documents/create/mark-as-paid-section.tsx +29 -20
  91. package/src/components/documents/create/prepare-document-submission.ts +19 -7
  92. package/src/components/documents/shared/document-preview-display.tsx +3 -4
  93. package/src/components/documents/types.ts +2 -2
  94. package/src/components/documents/view/document-actions-bar.tsx +7 -27
  95. package/src/components/documents/view/document-activities-list.tsx +65 -47
  96. package/src/components/documents/view/document-details-card.tsx +118 -76
  97. package/src/components/documents/view/document-payments-list.tsx +99 -65
  98. package/src/components/documents/view/document-relations-list.tsx +43 -28
  99. package/src/components/documents/view/document-sidebar.tsx +151 -0
  100. package/src/components/documents/view/index.ts +2 -0
  101. package/src/components/documents/view/locales/de.ts +4 -0
  102. package/src/components/documents/view/locales/es.ts +4 -0
  103. package/src/components/documents/view/locales/fr.ts +4 -0
  104. package/src/components/documents/view/locales/hr.ts +4 -0
  105. package/src/components/documents/view/locales/it.ts +4 -0
  106. package/src/components/documents/view/locales/nl.ts +4 -0
  107. package/src/components/documents/view/locales/pl.ts +4 -0
  108. package/src/components/documents/view/locales/pt.ts +4 -0
  109. package/src/components/documents/view/locales/sl.ts +5 -1
  110. package/src/components/documents/view/use-document-download.ts +7 -3
  111. package/src/components/entities/create-entity-form.tsx +166 -13
  112. package/src/components/entities/entity-settings-form/entity-settings-form.tsx +101 -1
  113. package/src/components/entities/entity-settings-form/input-with-preview.tsx +30 -2
  114. package/src/components/entities/entity-settings-form/locales/de.ts +10 -0
  115. package/src/components/entities/entity-settings-form/locales/es.ts +10 -0
  116. package/src/components/entities/entity-settings-form/locales/fr.ts +10 -0
  117. package/src/components/entities/entity-settings-form/locales/hr.ts +10 -0
  118. package/src/components/entities/entity-settings-form/locales/it.ts +10 -0
  119. package/src/components/entities/entity-settings-form/locales/nl.ts +10 -0
  120. package/src/components/entities/entity-settings-form/locales/pl.ts +10 -0
  121. package/src/components/entities/entity-settings-form/locales/pt.ts +10 -0
  122. package/src/components/entities/entity-settings-form/locales/sl.ts +10 -0
  123. package/src/components/entities/fina-settings-form/fina-settings-form.tsx +6 -6
  124. package/src/components/entities/fina-settings-form/locales/de.ts +2 -2
  125. package/src/components/entities/fina-settings-form/locales/en.ts +2 -2
  126. package/src/components/entities/fina-settings-form/locales/es.ts +2 -2
  127. package/src/components/entities/fina-settings-form/locales/fr.ts +2 -2
  128. package/src/components/entities/fina-settings-form/locales/hr.ts +2 -2
  129. package/src/components/entities/fina-settings-form/locales/it.ts +2 -2
  130. package/src/components/entities/fina-settings-form/locales/nl.ts +2 -2
  131. package/src/components/entities/fina-settings-form/locales/pl.ts +2 -2
  132. package/src/components/entities/fina-settings-form/locales/pt.ts +2 -2
  133. package/src/components/entities/fina-settings-form/locales/sl.ts +2 -2
  134. package/src/components/entities/furs-settings-form/locales/en.ts +0 -1
  135. package/src/components/entities/settings/company-settings-form.tsx +173 -20
  136. package/src/components/entities/settings/pdf-template-selector/locales/de.ts +3 -1
  137. package/src/components/entities/settings/pdf-template-selector/locales/es.ts +3 -1
  138. package/src/components/entities/settings/pdf-template-selector/locales/fr.ts +4 -1
  139. package/src/components/entities/settings/pdf-template-selector/locales/hr.ts +4 -1
  140. package/src/components/entities/settings/pdf-template-selector/locales/it.ts +3 -1
  141. package/src/components/entities/settings/pdf-template-selector/locales/nl.ts +3 -1
  142. package/src/components/entities/settings/pdf-template-selector/locales/pl.ts +3 -1
  143. package/src/components/entities/settings/pdf-template-selector/locales/pt.ts +3 -1
  144. package/src/components/entities/settings/pdf-template-selector/locales/sl.ts +3 -1
  145. package/src/components/entities/settings/pdf-template-selector/pdf-template-cards.tsx +1 -0
  146. package/src/components/estimates/create/create-estimate-form.tsx +93 -8
  147. package/src/components/estimates/create/locales/de.ts +16 -0
  148. package/src/components/estimates/create/locales/es.ts +16 -0
  149. package/src/components/estimates/create/locales/fr.ts +16 -0
  150. package/src/components/estimates/create/locales/hr.ts +16 -0
  151. package/src/components/estimates/create/locales/it.ts +16 -0
  152. package/src/components/estimates/create/locales/nl.ts +16 -0
  153. package/src/components/estimates/create/locales/pl.ts +16 -0
  154. package/src/components/estimates/create/locales/pt.ts +16 -0
  155. package/src/components/estimates/create/locales/sl.ts +17 -1
  156. package/src/components/estimates/list/list-table.tsx +14 -8
  157. package/src/components/estimates/list/locales/de.ts +2 -0
  158. package/src/components/estimates/list/locales/en.ts +1 -0
  159. package/src/components/estimates/list/locales/es.ts +2 -0
  160. package/src/components/estimates/list/locales/fr.ts +2 -0
  161. package/src/components/estimates/list/locales/hr.ts +2 -0
  162. package/src/components/estimates/list/locales/it.ts +2 -0
  163. package/src/components/estimates/list/locales/nl.ts +2 -0
  164. package/src/components/estimates/list/locales/pl.ts +2 -0
  165. package/src/components/estimates/list/locales/pt.ts +2 -0
  166. package/src/components/estimates/list/locales/sl.ts +2 -0
  167. package/src/components/export/document-export-form.tsx +55 -14
  168. package/src/components/export/index.ts +2 -0
  169. package/src/components/export/sales-per-item-export-form.tsx +223 -0
  170. package/src/components/invoices/create/create-invoice-form.tsx +106 -11
  171. package/src/components/invoices/create/locales/de.ts +26 -0
  172. package/src/components/invoices/create/locales/es.ts +26 -0
  173. package/src/components/invoices/create/locales/fr.ts +26 -0
  174. package/src/components/invoices/create/locales/hr.ts +25 -0
  175. package/src/components/invoices/create/locales/it.ts +26 -0
  176. package/src/components/invoices/create/locales/nl.ts +26 -0
  177. package/src/components/invoices/create/locales/pl.ts +25 -0
  178. package/src/components/invoices/create/locales/pt.ts +25 -0
  179. package/src/components/invoices/create/locales/sl.ts +26 -1
  180. package/src/components/invoices/invoices-furs.hooks.ts +4 -1
  181. package/src/components/invoices/list/list-table.tsx +77 -31
  182. package/src/components/invoices/list/locales/de.ts +5 -0
  183. package/src/components/invoices/list/locales/en.ts +4 -0
  184. package/src/components/invoices/list/locales/es.ts +5 -0
  185. package/src/components/invoices/list/locales/fr.ts +5 -0
  186. package/src/components/invoices/list/locales/hr.ts +5 -0
  187. package/src/components/invoices/list/locales/it.ts +5 -0
  188. package/src/components/invoices/list/locales/nl.ts +5 -0
  189. package/src/components/invoices/list/locales/pl.ts +5 -0
  190. package/src/components/invoices/list/locales/pt.ts +5 -0
  191. package/src/components/invoices/list/locales/sl.ts +5 -0
  192. package/src/components/invoices/view/fiscalization-status-card.tsx +44 -24
  193. package/src/components/items/item-combobox.tsx +5 -3
  194. package/src/components/items/item-list-table/item-list-header.tsx +4 -17
  195. package/src/components/items/item-list-table/item-list-table.tsx +3 -3
  196. package/src/components/items/item-list-table/locales/de.ts +1 -0
  197. package/src/components/items/item-list-table/locales/es.ts +1 -0
  198. package/src/components/items/item-list-table/locales/fr.ts +1 -0
  199. package/src/components/items/item-list-table/locales/hr.ts +1 -0
  200. package/src/components/items/item-list-table/locales/it.ts +1 -0
  201. package/src/components/items/item-list-table/locales/nl.ts +1 -0
  202. package/src/components/items/item-list-table/locales/pl.ts +1 -0
  203. package/src/components/items/item-list-table/locales/pt.ts +1 -0
  204. package/src/components/items/item-list-table/locales/sl.ts +1 -0
  205. package/src/components/payments/list/list-table.tsx +0 -4
  206. package/src/components/payments/list/locales/de.ts +1 -0
  207. package/src/components/payments/list/locales/es.ts +1 -0
  208. package/src/components/payments/list/locales/fr.ts +1 -0
  209. package/src/components/payments/list/locales/hr.ts +1 -0
  210. package/src/components/payments/list/locales/it.ts +1 -0
  211. package/src/components/payments/list/locales/nl.ts +1 -0
  212. package/src/components/payments/list/locales/pl.ts +1 -0
  213. package/src/components/payments/list/locales/pt.ts +1 -0
  214. package/src/components/payments/list/locales/sl.ts +1 -0
  215. package/src/components/recurring-invoices/list/list-table.tsx +0 -7
  216. package/src/components/recurring-invoices/list/locales/de.ts +1 -0
  217. package/src/components/recurring-invoices/list/locales/es.ts +1 -0
  218. package/src/components/recurring-invoices/list/locales/fr.ts +1 -0
  219. package/src/components/recurring-invoices/list/locales/hr.ts +1 -0
  220. package/src/components/recurring-invoices/list/locales/it.ts +1 -0
  221. package/src/components/recurring-invoices/list/locales/nl.ts +1 -0
  222. package/src/components/recurring-invoices/list/locales/pl.ts +1 -0
  223. package/src/components/recurring-invoices/list/locales/pt.ts +1 -0
  224. package/src/components/recurring-invoices/list/locales/sl.ts +1 -0
  225. package/src/components/request-logs/request-log-list-table.tsx +0 -3
  226. package/src/components/table/README.md +14 -121
  227. package/src/components/table/data-table.tsx +22 -37
  228. package/src/components/table/hooks/use-table-state.ts +3 -27
  229. package/src/components/table/index.ts +0 -2
  230. package/src/components/table/search-input.tsx +17 -0
  231. package/src/components/table/selection-toolbar.tsx +35 -1
  232. package/src/components/table/table-empty-state.tsx +6 -3
  233. package/src/components/table/table-no-results.tsx +10 -5
  234. package/src/components/table/types.ts +0 -5
  235. package/src/components/taxes/tax-list-table/locales/de.ts +1 -0
  236. package/src/components/taxes/tax-list-table/locales/es.ts +1 -0
  237. package/src/components/taxes/tax-list-table/locales/fr.ts +1 -0
  238. package/src/components/taxes/tax-list-table/locales/hr.ts +1 -0
  239. package/src/components/taxes/tax-list-table/locales/it.ts +1 -0
  240. package/src/components/taxes/tax-list-table/locales/nl.ts +1 -0
  241. package/src/components/taxes/tax-list-table/locales/pl.ts +1 -0
  242. package/src/components/taxes/tax-list-table/locales/pt.ts +1 -0
  243. package/src/components/taxes/tax-list-table/locales/sl.ts +1 -0
  244. package/src/components/taxes/tax-list-table/tax-list-header.tsx +3 -14
  245. package/src/components/taxes/tax-list-table/tax-list-table.tsx +3 -3
  246. package/src/components/ui/popover.tsx +3 -1
  247. package/src/components/ui/tooltip.tsx +3 -1
  248. package/src/generated/schemas/advanceinvoice.ts +4 -2
  249. package/src/generated/schemas/creditnote.ts +2 -1
  250. package/src/generated/schemas/deliverynote.ts +2 -1
  251. package/src/generated/schemas/estimate.ts +4 -2
  252. package/src/generated/schemas/index.ts +1 -1
  253. package/src/generated/schemas/invoice.ts +2 -1
  254. package/src/generated/schemas/renderadvanceinvoicepreview_body.ts +17 -23
  255. package/src/generated/schemas/rendercreditnotepreview_body.ts +17 -23
  256. package/src/generated/schemas/renderdeliverynotepreview_body.ts +17 -23
  257. package/src/generated/schemas/renderestimatepreview_body.ts +17 -23
  258. package/src/generated/schemas/renderinvoicepreview_body.ts +19 -23
  259. package/src/hooks/use-duplicate-document.ts +56 -14
  260. package/src/hooks/use-vies-check.ts +3 -0
  261. package/src/lib/fiscalization.ts +12 -0
  262. package/src/lib/schemas/advance-invoice.ts +0 -1
  263. package/src/components/table/sortable-header.tsx +0 -56
@@ -44,7 +44,8 @@ const translations = { sl, de, it, fr, es, pt, nl, pl, hr } as const;
44
44
 
45
45
  type Document = Invoice | Estimate | CreditNote | AdvanceInvoice;
46
46
 
47
- const PDF_LOCALE_CODES = [
47
+ /** Language options for PDF label translations (formatting always uses entity locale) */
48
+ const PDF_LANGUAGE_CODES = [
48
49
  { label: "English", code: "en-US" },
49
50
  { label: "German", code: "de-DE" },
50
51
  { label: "Slovenian", code: "sl-SI" },
@@ -100,22 +101,6 @@ interface DocumentActionsBarProps extends ComponentTranslationProps {
100
101
  isVoiding?: boolean;
101
102
  }
102
103
 
103
- function getApiLocale(uiLanguage: string): string {
104
- const localeMap: Record<string, string> = {
105
- en: "en-US",
106
- de: "de-DE",
107
- sl: "sl-SI",
108
- it: "it-IT",
109
- fr: "fr-FR",
110
- es: "es-ES",
111
- pt: "pt-PT",
112
- nl: "nl-NL",
113
- pl: "pl-PL",
114
- hr: "hr-HR",
115
- };
116
- return localeMap[uiLanguage] || "en-US";
117
- }
118
-
119
104
  export function DocumentActionsBar({
120
105
  document,
121
106
  documentType,
@@ -163,7 +148,7 @@ export function DocumentActionsBar({
163
148
  const shareableId = (document as Invoice).shareable_id;
164
149
  const shareUrl = shareableId ? `${window.location.origin}/public/invoices/${shareableId}` : null;
165
150
 
166
- const handleDownloadPdf = (locale: string) => downloadPdf(document, documentType, locale);
151
+ const handleDownloadPdf = (language?: string) => downloadPdf(document, documentType, language);
167
152
  const handleDownloadEslog = () => downloadEslog(document, documentType);
168
153
 
169
154
  const handleCopyShareLink = async () => {
@@ -178,7 +163,6 @@ export function DocumentActionsBar({
178
163
  }
179
164
  };
180
165
 
181
- const apiLocale = getApiLocale(currentLocale);
182
166
  const isDraft = (document as any).is_draft === true;
183
167
 
184
168
  return (
@@ -189,7 +173,7 @@ export function DocumentActionsBar({
189
173
  variant="outline"
190
174
  size="sm"
191
175
  disabled={isDownloadingPdf}
192
- onClick={() => handleDownloadPdf(apiLocale)}
176
+ onClick={() => handleDownloadPdf()}
193
177
  className="cursor-pointer rounded-r-none"
194
178
  >
195
179
  {isDownloadingPdf ? <Loader2 className="mr-2 h-4 w-4 animate-spin" /> : <Download className="mr-2 h-4 w-4" />}
@@ -207,13 +191,9 @@ export function DocumentActionsBar({
207
191
  </Button>
208
192
  </DropdownMenuTrigger>
209
193
  <DropdownMenuContent align="end">
210
- {PDF_LOCALE_CODES.map((locale) => (
211
- <DropdownMenuItem
212
- key={locale.code}
213
- onClick={() => handleDownloadPdf(locale.code)}
214
- className="cursor-pointer"
215
- >
216
- {t(locale.label)}
194
+ {PDF_LANGUAGE_CODES.map((lang) => (
195
+ <DropdownMenuItem key={lang.code} onClick={() => handleDownloadPdf(lang.code)} className="cursor-pointer">
196
+ {t(lang.label)}
217
197
  </DropdownMenuItem>
218
198
  ))}
219
199
  </DropdownMenuContent>
@@ -27,6 +27,7 @@ interface DocumentActivitiesListProps extends ComponentTranslationProps {
27
27
  entityId: string;
28
28
  currentUserId?: string;
29
29
  locale?: string;
30
+ variant?: "card" | "inline";
30
31
  }
31
32
 
32
33
  function formatActivityDate(date: string, locale: string): string {
@@ -67,6 +68,7 @@ export function DocumentActivitiesList({
67
68
  entityId,
68
69
  currentUserId,
69
70
  locale = "en",
71
+ variant = "card",
70
72
  ...i18nProps
71
73
  }: DocumentActivitiesListProps) {
72
74
  const t = createTranslation({ translations, locale, ...i18nProps });
@@ -107,60 +109,76 @@ export function DocumentActivitiesList({
107
109
  const hasPrev = cursors.length > 0;
108
110
  const hasNext = !!pagination?.has_more;
109
111
 
112
+ const paginationButtons = (hasPrev || hasNext) && (
113
+ <div className="flex items-center gap-1">
114
+ <Button
115
+ variant="ghost"
116
+ size="sm"
117
+ onClick={handlePrevPage}
118
+ disabled={!hasPrev}
119
+ className="h-8 w-8 cursor-pointer p-0"
120
+ >
121
+ <ChevronLeft className="h-4 w-4" />
122
+ </Button>
123
+ <Button
124
+ variant="ghost"
125
+ size="sm"
126
+ onClick={handleNextPage}
127
+ disabled={!hasNext}
128
+ className="h-8 w-8 cursor-pointer p-0"
129
+ >
130
+ <ChevronRight className="h-4 w-4" />
131
+ </Button>
132
+ </div>
133
+ );
134
+
135
+ const bodyContent = isLoading ? (
136
+ <div className="space-y-2">
137
+ <Skeleton className="h-10 w-full" />
138
+ <Skeleton className="h-10 w-full" />
139
+ <Skeleton className="h-10 w-full" />
140
+ </div>
141
+ ) : activities.length === 0 ? (
142
+ <p className="py-4 text-center text-muted-foreground text-sm">{t("No activity")}</p>
143
+ ) : (
144
+ <div className="space-y-2">
145
+ {activities.map((activity) => (
146
+ <div key={activity.id} className="flex items-start justify-between rounded-md border p-3">
147
+ <div className="flex flex-col gap-0.5">
148
+ <span className="font-medium text-sm">{getActionLabel(activity.action, t)}</span>
149
+ <span className="text-muted-foreground text-xs">
150
+ {t("by")} {getActorLabel(activity, t, currentUserId)}
151
+ </span>
152
+ </div>
153
+ <span className="text-muted-foreground text-xs">{formatActivityDate(activity.created_at, locale)}</span>
154
+ </div>
155
+ ))}
156
+ </div>
157
+ );
158
+
159
+ if (variant === "inline") {
160
+ return (
161
+ <div>
162
+ <div className="mb-3 flex items-center justify-between">
163
+ <h3 className="font-medium text-sm">
164
+ {t("Activity")} {pagination && pagination.total > 0 && `(${pagination.total})`}
165
+ </h3>
166
+ {paginationButtons}
167
+ </div>
168
+ {bodyContent}
169
+ </div>
170
+ );
171
+ }
172
+
110
173
  return (
111
174
  <Card>
112
175
  <CardHeader className="flex flex-row items-center justify-between pb-3">
113
176
  <CardTitle className="text-lg">
114
177
  {t("Activity")} {pagination && pagination.total > 0 && `(${pagination.total})`}
115
178
  </CardTitle>
116
- {(hasPrev || hasNext) && (
117
- <div className="flex items-center gap-1">
118
- <Button
119
- variant="ghost"
120
- size="sm"
121
- onClick={handlePrevPage}
122
- disabled={!hasPrev}
123
- className="h-8 w-8 cursor-pointer p-0"
124
- >
125
- <ChevronLeft className="h-4 w-4" />
126
- </Button>
127
- <Button
128
- variant="ghost"
129
- size="sm"
130
- onClick={handleNextPage}
131
- disabled={!hasNext}
132
- className="h-8 w-8 cursor-pointer p-0"
133
- >
134
- <ChevronRight className="h-4 w-4" />
135
- </Button>
136
- </div>
137
- )}
179
+ {paginationButtons}
138
180
  </CardHeader>
139
- <CardContent>
140
- {isLoading ? (
141
- <div className="space-y-2">
142
- <Skeleton className="h-10 w-full" />
143
- <Skeleton className="h-10 w-full" />
144
- <Skeleton className="h-10 w-full" />
145
- </div>
146
- ) : activities.length === 0 ? (
147
- <p className="py-4 text-center text-muted-foreground text-sm">{t("No activity")}</p>
148
- ) : (
149
- <div className="space-y-2">
150
- {activities.map((activity) => (
151
- <div key={activity.id} className="flex items-start justify-between rounded-md border p-3">
152
- <div className="flex flex-col gap-0.5">
153
- <span className="font-medium text-sm">{getActionLabel(activity.action, t)}</span>
154
- <span className="text-muted-foreground text-xs">
155
- {t("by")} {getActorLabel(activity, t, currentUserId)}
156
- </span>
157
- </div>
158
- <span className="text-muted-foreground text-xs">{formatActivityDate(activity.created_at, locale)}</span>
159
- </div>
160
- ))}
161
- </div>
162
- )}
163
- </CardContent>
181
+ <CardContent>{bodyContent}</CardContent>
164
182
  </Card>
165
183
  );
166
184
  }
@@ -25,6 +25,7 @@ interface DocumentDetailsCardProps extends ComponentTranslationProps {
25
25
  documentType: DocumentType;
26
26
  /** Locale for date formatting */
27
27
  locale?: string;
28
+ variant?: "card" | "inline";
28
29
  }
29
30
 
30
31
  /**
@@ -79,10 +80,17 @@ function getPaymentStatus(
79
80
  * - Totals breakdown
80
81
  * - Payment status (for invoices/advance invoices)
81
82
  */
82
- export function DocumentDetailsCard({ document, documentType, locale = "en", ...i18nProps }: DocumentDetailsCardProps) {
83
+ export function DocumentDetailsCard({
84
+ document,
85
+ documentType,
86
+ locale = "en",
87
+ variant = "card",
88
+ ...i18nProps
89
+ }: DocumentDetailsCardProps) {
83
90
  const t = createTranslation({ translations, locale, ...i18nProps });
84
91
 
85
92
  const currencyCode = document.currency_code;
93
+ const sign = documentType === "credit_note" ? -1 : 1;
86
94
  const fmt = (amount: number) => formatCurrency(amount, currencyCode, locale);
87
95
  const fmtDate = (date: Date | string | null | undefined) => formatDate(date, locale);
88
96
 
@@ -95,8 +103,114 @@ export function DocumentDetailsCard({ document, documentType, locale = "en", ...
95
103
  // Get customer name
96
104
  const customerName = document.customer?.name || "-";
97
105
 
98
- // Calculate tax total
99
- const taxTotal = document.total_with_tax - document.total;
106
+ const bodyContent = (
107
+ <>
108
+ {/* Document info */}
109
+ <div className="grid grid-cols-2 gap-x-4 gap-y-2 text-sm">
110
+ <div className="text-muted-foreground">{t("Number")}</div>
111
+ <div className="text-right font-medium">{document.number}</div>
112
+
113
+ <div className="text-muted-foreground">{t("Date")}</div>
114
+ <div className="text-right">{fmtDate(document.date)}</div>
115
+
116
+ {isInvoiceOrAdvance && invoiceDoc.date_due && (
117
+ <>
118
+ <div className="text-muted-foreground">{t("Due date")}</div>
119
+ <div className="text-right">{fmtDate(invoiceDoc.date_due)}</div>
120
+ </>
121
+ )}
122
+
123
+ {isInvoiceOrAdvance && (invoiceDoc as any).date_service && (
124
+ <>
125
+ <div className="text-muted-foreground">
126
+ {(invoiceDoc as any).date_service_to ? t("Service period") : t("Service date")}
127
+ </div>
128
+ <div className="text-right">
129
+ {(invoiceDoc as any).date_service_to
130
+ ? `${fmtDate((invoiceDoc as any).date_service)} - ${fmtDate((invoiceDoc as any).date_service_to)}`
131
+ : fmtDate((invoiceDoc as any).date_service)}
132
+ </div>
133
+ </>
134
+ )}
135
+
136
+ {isEstimate && estimateDoc.date_valid_till && (
137
+ <>
138
+ <div className="text-muted-foreground">{t("Valid until")}</div>
139
+ <div className="text-right">{fmtDate(estimateDoc.date_valid_till)}</div>
140
+ </>
141
+ )}
142
+
143
+ <div className="text-muted-foreground">{t("Customer")}</div>
144
+ <div className="text-right">{customerName}</div>
145
+ </div>
146
+
147
+ <Separator />
148
+
149
+ {/* Totals */}
150
+ <div className="space-y-2 text-sm">
151
+ <div className="flex justify-between">
152
+ <span className="text-muted-foreground">{t("Subtotal")}</span>
153
+ <span>{fmt(document.total * sign)}</span>
154
+ </div>
155
+ {document.taxes && document.taxes.length > 0 ? (
156
+ document.taxes.map((tax: Document["taxes"][number]) => {
157
+ const taxAmount = tax.amount ?? 0;
158
+ return (
159
+ <div key={String(tax.rate)} className="flex justify-between">
160
+ <span className="text-muted-foreground">
161
+ {t("Tax")} {tax.rate ?? 0}%{" "}
162
+ {tax.base != null && (
163
+ <span className="text-xs">
164
+ {t("of")} {fmt(tax.base * sign)}
165
+ </span>
166
+ )}
167
+ </span>
168
+ <span>{fmt(taxAmount * sign)}</span>
169
+ </div>
170
+ );
171
+ })
172
+ ) : (
173
+ <div className="flex justify-between">
174
+ <span className="text-muted-foreground">{t("Tax")}</span>
175
+ <span>{fmt(0)}</span>
176
+ </div>
177
+ )}
178
+ <div className="flex justify-between font-semibold">
179
+ <span>{t("Total")}</span>
180
+ <span>{fmt(document.total_with_tax * sign)}</span>
181
+ </div>
182
+
183
+ {/* Payment info for invoices/advance invoices */}
184
+ {isInvoiceOrAdvance && invoiceDoc.total_paid > 0 && (
185
+ <>
186
+ <Separator />
187
+ <div className="flex justify-between text-green-600">
188
+ <span>{t("Paid")}</span>
189
+ <span>-{fmt(invoiceDoc.total_paid)}</span>
190
+ </div>
191
+ <div className="flex justify-between font-semibold">
192
+ <span>{t("Due")}</span>
193
+ <span>{fmt(invoiceDoc.total_due)}</span>
194
+ </div>
195
+ </>
196
+ )}
197
+ </div>
198
+ </>
199
+ );
200
+
201
+ if (variant === "inline") {
202
+ return (
203
+ <div className="space-y-3">
204
+ <div className="flex items-center justify-between font-medium text-sm">
205
+ {t("Details")}
206
+ {isInvoiceOrAdvance && (
207
+ <Badge variant={getPaymentStatus(invoiceDoc, t).variant}>{getPaymentStatus(invoiceDoc, t).label}</Badge>
208
+ )}
209
+ </div>
210
+ <div className="space-y-4">{bodyContent}</div>
211
+ </div>
212
+ );
213
+ }
100
214
 
101
215
  return (
102
216
  <Card>
@@ -108,79 +222,7 @@ export function DocumentDetailsCard({ document, documentType, locale = "en", ...
108
222
  )}
109
223
  </CardTitle>
110
224
  </CardHeader>
111
- <CardContent className="space-y-4">
112
- {/* Document info */}
113
- <div className="grid grid-cols-2 gap-x-4 gap-y-2 text-sm">
114
- <div className="text-muted-foreground">{t("Number")}</div>
115
- <div className="text-right font-medium">{document.number}</div>
116
-
117
- <div className="text-muted-foreground">{t("Date")}</div>
118
- <div className="text-right">{fmtDate(document.date)}</div>
119
-
120
- {isInvoiceOrAdvance && (
121
- <>
122
- <div className="text-muted-foreground">{t("Due date")}</div>
123
- <div className="text-right">{fmtDate(invoiceDoc.date_due)}</div>
124
- </>
125
- )}
126
-
127
- {isInvoiceOrAdvance && (invoiceDoc as any).date_service && (
128
- <>
129
- <div className="text-muted-foreground">
130
- {(invoiceDoc as any).date_service_to ? t("Service period") : t("Service date")}
131
- </div>
132
- <div className="text-right">
133
- {(invoiceDoc as any).date_service_to
134
- ? `${fmtDate((invoiceDoc as any).date_service)} - ${fmtDate((invoiceDoc as any).date_service_to)}`
135
- : fmtDate((invoiceDoc as any).date_service)}
136
- </div>
137
- </>
138
- )}
139
-
140
- {isEstimate && estimateDoc.date_valid_till && (
141
- <>
142
- <div className="text-muted-foreground">{t("Valid until")}</div>
143
- <div className="text-right">{fmtDate(estimateDoc.date_valid_till)}</div>
144
- </>
145
- )}
146
-
147
- <div className="text-muted-foreground">{t("Customer")}</div>
148
- <div className="text-right">{customerName}</div>
149
- </div>
150
-
151
- <Separator />
152
-
153
- {/* Totals */}
154
- <div className="space-y-2 text-sm">
155
- <div className="flex justify-between">
156
- <span className="text-muted-foreground">{t("Subtotal")}</span>
157
- <span>{fmt(document.total)}</span>
158
- </div>
159
- <div className="flex justify-between">
160
- <span className="text-muted-foreground">{t("Tax")}</span>
161
- <span>{fmt(taxTotal)}</span>
162
- </div>
163
- <div className="flex justify-between font-semibold">
164
- <span>{t("Total")}</span>
165
- <span>{fmt(document.total_with_tax)}</span>
166
- </div>
167
-
168
- {/* Payment info for invoices/advance invoices */}
169
- {isInvoiceOrAdvance && invoiceDoc.total_paid > 0 && (
170
- <>
171
- <Separator />
172
- <div className="flex justify-between text-green-600">
173
- <span>{t("Paid")}</span>
174
- <span>-{fmt(invoiceDoc.total_paid)}</span>
175
- </div>
176
- <div className="flex justify-between font-semibold">
177
- <span>{t("Due")}</span>
178
- <span>{fmt(invoiceDoc.total_due)}</span>
179
- </div>
180
- </>
181
- )}
182
- </div>
183
- </CardContent>
225
+ <CardContent className="space-y-4">{bodyContent}</CardContent>
184
226
  </Card>
185
227
  );
186
228
  }
@@ -51,6 +51,7 @@ interface DocumentPaymentsListProps extends ComponentTranslationProps {
51
51
  onDeleteSuccess?: () => void;
52
52
  /** Callback on delete error */
53
53
  onDeleteError?: (error: string) => void;
54
+ variant?: "card" | "inline";
54
55
  }
55
56
 
56
57
  /**
@@ -94,6 +95,7 @@ export function DocumentPaymentsList({
94
95
  onEditPayment,
95
96
  onDeleteSuccess,
96
97
  onDeleteError,
98
+ variant = "card",
97
99
  ...i18nProps
98
100
  }: DocumentPaymentsListProps) {
99
101
  const t = createTranslation({ translations, locale, ...i18nProps });
@@ -180,6 +182,101 @@ export function DocumentPaymentsList({
180
182
  const fmt = (amount: number) => formatCurrency(amount, currencyCode, locale);
181
183
  const fmtDate = (date: Date | string | null) => formatDate(date, locale);
182
184
 
185
+ const headerContent = (
186
+ <div
187
+ className={
188
+ variant === "inline" ? "flex items-center justify-between" : "flex flex-row items-center justify-between"
189
+ }
190
+ >
191
+ <h3
192
+ className={variant === "inline" ? "font-medium text-sm" : "font-semibold text-lg leading-none tracking-tight"}
193
+ >
194
+ {t("Payments")} {payments.length > 0 && `(${payments.length})`}
195
+ </h3>
196
+ <Button variant="outline" size="sm" onClick={onAddPayment} className="cursor-pointer">
197
+ <Plus className="mr-1 h-4 w-4" />
198
+ {t("Add payment")}
199
+ </Button>
200
+ </div>
201
+ );
202
+
203
+ const bodyContent = isLoading ? (
204
+ <div className="space-y-2">
205
+ <Skeleton className="h-10 w-full" />
206
+ <Skeleton className="h-10 w-full" />
207
+ </div>
208
+ ) : payments.length === 0 ? (
209
+ <p className="py-4 text-center text-muted-foreground text-sm">{t("No payments")}</p>
210
+ ) : (
211
+ <div className="space-y-2">
212
+ {payments.map((payment) => (
213
+ <div key={payment.id} className="flex items-center justify-between rounded-md border p-3">
214
+ <div className="flex items-center gap-4">
215
+ <span className="text-muted-foreground text-sm">{fmtDate(payment.date)}</span>
216
+ <span className="font-medium">{fmt(payment.amount)}</span>
217
+ <span className="text-muted-foreground text-sm">{getTypeLabel(payment.type)}</span>
218
+ </div>
219
+ <DropdownMenu>
220
+ <DropdownMenuTrigger asChild>
221
+ <Button variant="ghost" size="sm" className="h-8 w-8 cursor-pointer p-0">
222
+ <MoreHorizontal className="h-4 w-4" />
223
+ </Button>
224
+ </DropdownMenuTrigger>
225
+ <DropdownMenuContent align="end">
226
+ <DropdownMenuItem onClick={() => onEditPayment?.(payment)} className="cursor-pointer">
227
+ <Pencil className="mr-2 h-4 w-4" />
228
+ {t("Edit")}
229
+ </DropdownMenuItem>
230
+ <DropdownMenuItem
231
+ onClick={() => setPaymentToDelete(payment)}
232
+ className="cursor-pointer text-destructive focus:text-destructive"
233
+ >
234
+ <Trash2 className="mr-2 h-4 w-4" />
235
+ {t("Delete")}
236
+ </DropdownMenuItem>
237
+ </DropdownMenuContent>
238
+ </DropdownMenu>
239
+ </div>
240
+ ))}
241
+ </div>
242
+ );
243
+
244
+ const deleteDialog = (
245
+ <Dialog open={!!paymentToDelete} onOpenChange={() => setPaymentToDelete(null)}>
246
+ <DialogContent>
247
+ <DialogHeader>
248
+ <DialogTitle>{t("Delete payment")}</DialogTitle>
249
+ <DialogDescription>{t("Delete payment confirmation")}</DialogDescription>
250
+ </DialogHeader>
251
+ <DialogFooter>
252
+ <Button
253
+ variant="outline"
254
+ disabled={isDeleting}
255
+ onClick={() => setPaymentToDelete(null)}
256
+ className="cursor-pointer"
257
+ >
258
+ {t("Cancel")}
259
+ </Button>
260
+ <Button variant="destructive" onClick={handleDelete} disabled={isDeleting} className="cursor-pointer">
261
+ {t("Delete")}
262
+ </Button>
263
+ </DialogFooter>
264
+ </DialogContent>
265
+ </Dialog>
266
+ );
267
+
268
+ if (variant === "inline") {
269
+ return (
270
+ <>
271
+ <div>
272
+ {headerContent}
273
+ <div className="mt-3">{bodyContent}</div>
274
+ </div>
275
+ {deleteDialog}
276
+ </>
277
+ );
278
+ }
279
+
183
280
  return (
184
281
  <>
185
282
  <Card>
@@ -192,72 +289,9 @@ export function DocumentPaymentsList({
192
289
  {t("Add payment")}
193
290
  </Button>
194
291
  </CardHeader>
195
- <CardContent>
196
- {isLoading ? (
197
- <div className="space-y-2">
198
- <Skeleton className="h-10 w-full" />
199
- <Skeleton className="h-10 w-full" />
200
- </div>
201
- ) : payments.length === 0 ? (
202
- <p className="py-4 text-center text-muted-foreground text-sm">{t("No payments")}</p>
203
- ) : (
204
- <div className="space-y-2">
205
- {payments.map((payment) => (
206
- <div key={payment.id} className="flex items-center justify-between rounded-md border p-3">
207
- <div className="flex items-center gap-4">
208
- <span className="text-muted-foreground text-sm">{fmtDate(payment.date)}</span>
209
- <span className="font-medium">{fmt(payment.amount)}</span>
210
- <span className="text-muted-foreground text-sm">{getTypeLabel(payment.type)}</span>
211
- </div>
212
- <DropdownMenu>
213
- <DropdownMenuTrigger asChild>
214
- <Button variant="ghost" size="sm" className="h-8 w-8 cursor-pointer p-0">
215
- <MoreHorizontal className="h-4 w-4" />
216
- </Button>
217
- </DropdownMenuTrigger>
218
- <DropdownMenuContent align="end">
219
- <DropdownMenuItem onClick={() => onEditPayment?.(payment)} className="cursor-pointer">
220
- <Pencil className="mr-2 h-4 w-4" />
221
- {t("Edit")}
222
- </DropdownMenuItem>
223
- <DropdownMenuItem
224
- onClick={() => setPaymentToDelete(payment)}
225
- className="cursor-pointer text-destructive focus:text-destructive"
226
- >
227
- <Trash2 className="mr-2 h-4 w-4" />
228
- {t("Delete")}
229
- </DropdownMenuItem>
230
- </DropdownMenuContent>
231
- </DropdownMenu>
232
- </div>
233
- ))}
234
- </div>
235
- )}
236
- </CardContent>
292
+ <CardContent>{bodyContent}</CardContent>
237
293
  </Card>
238
-
239
- {/* Delete Confirmation Dialog */}
240
- <Dialog open={!!paymentToDelete} onOpenChange={() => setPaymentToDelete(null)}>
241
- <DialogContent>
242
- <DialogHeader>
243
- <DialogTitle>{t("Delete payment")}</DialogTitle>
244
- <DialogDescription>{t("Delete payment confirmation")}</DialogDescription>
245
- </DialogHeader>
246
- <DialogFooter>
247
- <Button
248
- variant="outline"
249
- disabled={isDeleting}
250
- onClick={() => setPaymentToDelete(null)}
251
- className="cursor-pointer"
252
- >
253
- {t("Cancel")}
254
- </Button>
255
- <Button variant="destructive" onClick={handleDelete} disabled={isDeleting} className="cursor-pointer">
256
- {t("Delete")}
257
- </Button>
258
- </DialogFooter>
259
- </DialogContent>
260
- </Dialog>
294
+ {deleteDialog}
261
295
  </>
262
296
  );
263
297
  }