@spaceinvoices/react-ui 0.4.2 → 0.4.4
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.
- package/cli/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/common/autocomplete.tsx +18 -2
- package/src/components/advance-invoices/create/create-advance-invoice-form.tsx +0 -1
- package/src/components/advance-invoices/create/locales/de.ts +2 -0
- package/src/components/advance-invoices/create/locales/es.ts +2 -0
- package/src/components/advance-invoices/create/locales/fr.ts +2 -0
- package/src/components/advance-invoices/create/locales/hr.ts +1 -0
- package/src/components/advance-invoices/create/locales/it.ts +2 -0
- package/src/components/advance-invoices/create/locales/nl.ts +2 -0
- package/src/components/advance-invoices/create/locales/pl.ts +1 -0
- package/src/components/advance-invoices/create/locales/pt.ts +1 -0
- package/src/components/advance-invoices/create/locales/sl.ts +1 -0
- package/src/components/advance-invoices/create/prepare-advance-invoice-submission.ts +0 -1
- package/src/components/advance-invoices/list/list-table.tsx +130 -40
- package/src/components/advance-invoices/list/locales/de.ts +6 -0
- package/src/components/advance-invoices/list/locales/en.ts +5 -0
- package/src/components/advance-invoices/list/locales/es.ts +6 -0
- package/src/components/advance-invoices/list/locales/fr.ts +6 -0
- package/src/components/advance-invoices/list/locales/hr.ts +6 -0
- package/src/components/advance-invoices/list/locales/it.ts +6 -0
- package/src/components/advance-invoices/list/locales/nl.ts +6 -0
- package/src/components/advance-invoices/list/locales/pl.ts +6 -0
- package/src/components/advance-invoices/list/locales/pt.ts +6 -0
- package/src/components/advance-invoices/list/locales/sl.ts +6 -0
- package/src/components/credit-notes/create/create-credit-note-form.tsx +114 -3
- package/src/components/credit-notes/create/locales/de.ts +2 -0
- package/src/components/credit-notes/create/locales/es.ts +2 -0
- package/src/components/credit-notes/create/locales/fr.ts +2 -0
- package/src/components/credit-notes/create/locales/hr.ts +1 -0
- package/src/components/credit-notes/create/locales/it.ts +2 -0
- package/src/components/credit-notes/create/locales/nl.ts +2 -0
- package/src/components/credit-notes/create/locales/pl.ts +1 -0
- package/src/components/credit-notes/create/locales/pt.ts +1 -0
- package/src/components/credit-notes/create/locales/sl.ts +1 -0
- package/src/components/credit-notes/credit-notes.hooks.ts +30 -0
- package/src/components/credit-notes/list/list-table.tsx +111 -36
- package/src/components/credit-notes/list/locales/de.ts +6 -1
- package/src/components/credit-notes/list/locales/en.ts +6 -0
- package/src/components/credit-notes/list/locales/es.ts +6 -1
- package/src/components/credit-notes/list/locales/fr.ts +6 -1
- package/src/components/credit-notes/list/locales/hr.ts +6 -1
- package/src/components/credit-notes/list/locales/it.ts +6 -1
- package/src/components/credit-notes/list/locales/nl.ts +6 -1
- package/src/components/credit-notes/list/locales/pl.ts +6 -1
- package/src/components/credit-notes/list/locales/pt.ts +6 -1
- package/src/components/credit-notes/list/locales/sl.ts +6 -1
- package/src/components/customers/customer-list-table/customer-list-table.tsx +0 -3
- package/src/components/customers/customer-list-table/locales/de.ts +1 -0
- package/src/components/customers/customer-list-table/locales/es.ts +1 -0
- package/src/components/customers/customer-list-table/locales/fr.ts +1 -0
- package/src/components/customers/customer-list-table/locales/hr.ts +1 -0
- package/src/components/customers/customer-list-table/locales/it.ts +1 -0
- package/src/components/customers/customer-list-table/locales/nl.ts +1 -0
- package/src/components/customers/customer-list-table/locales/pl.ts +1 -0
- package/src/components/customers/customer-list-table/locales/pt.ts +1 -0
- package/src/components/customers/customer-list-table/locales/sl.ts +1 -0
- package/src/components/dashboard/collection-rate-card/use-collection-rate.ts +2 -2
- package/src/components/dashboard/invoice-status-chart/use-invoice-status.ts +3 -3
- package/src/components/dashboard/payment-methods-chart/use-payment-methods.ts +1 -1
- package/src/components/dashboard/payment-trend-chart/use-payment-trend.ts +1 -1
- package/src/components/dashboard/revenue-trend-chart/use-revenue-trend.ts +1 -1
- package/src/components/dashboard/shared/use-revenue-data.ts +4 -4
- package/src/components/dashboard/shared/use-stats-counts.ts +4 -4
- package/src/components/dashboard/shared/use-stats-query.ts +1 -1
- package/src/components/dashboard/tax-collected-card/use-tax-collected.ts +2 -2
- package/src/components/dashboard/top-customers-chart/use-top-customers.ts +1 -1
- package/src/components/delivery-notes/create/create-delivery-note-form.tsx +332 -0
- package/src/components/delivery-notes/create/locales/de.ts +50 -0
- package/src/components/delivery-notes/create/locales/es.ts +49 -0
- package/src/components/delivery-notes/create/locales/fr.ts +50 -0
- package/src/components/delivery-notes/create/locales/hr.ts +49 -0
- package/src/components/delivery-notes/create/locales/it.ts +49 -0
- package/src/components/delivery-notes/create/locales/nl.ts +50 -0
- package/src/components/delivery-notes/create/locales/pl.ts +49 -0
- package/src/components/delivery-notes/create/locales/pt.ts +50 -0
- package/src/components/delivery-notes/create/locales/sl.ts +49 -0
- package/src/components/delivery-notes/create/prepare-delivery-note-submission.ts +38 -0
- package/src/components/delivery-notes/create/use-delivery-note-customer-form.ts +1 -0
- package/src/components/delivery-notes/delivery-notes.hooks.ts +15 -0
- package/src/components/delivery-notes/list/index.ts +3 -0
- package/src/components/delivery-notes/list/list-row-actions.tsx +122 -0
- package/src/components/delivery-notes/list/list-table.tsx +247 -0
- package/src/components/delivery-notes/list/locales/de.ts +13 -0
- package/src/components/delivery-notes/list/locales/en.ts +13 -0
- package/src/components/delivery-notes/list/locales/es.ts +13 -0
- package/src/components/delivery-notes/list/locales/fr.ts +13 -0
- package/src/components/delivery-notes/list/locales/hr.ts +13 -0
- package/src/components/delivery-notes/list/locales/it.ts +13 -0
- package/src/components/delivery-notes/list/locales/nl.ts +13 -0
- package/src/components/delivery-notes/list/locales/pl.ts +13 -0
- package/src/components/delivery-notes/list/locales/pt.ts +13 -0
- package/src/components/delivery-notes/list/locales/sl.ts +13 -0
- package/src/components/delivery-notes/list/use-delivery-note-download.ts +63 -0
- package/src/components/documents/create/document-details-section.tsx +76 -58
- package/src/components/documents/create/linked-documents-info.tsx +82 -0
- package/src/components/documents/create/live-preview.tsx +38 -11
- package/src/components/documents/create/prepare-document-submission.ts +1 -1
- package/src/components/documents/documents.hooks.ts +2 -1
- package/src/components/documents/shared/document-preview-display.tsx +12 -5
- package/src/components/documents/types.ts +12 -3
- package/src/components/documents/view/document-activities-list.tsx +65 -47
- package/src/components/documents/view/document-details-card.tsx +102 -77
- package/src/components/documents/view/document-payments-list.tsx +102 -68
- package/src/components/documents/view/document-relations-list.tsx +120 -0
- package/src/components/documents/view/document-sidebar.tsx +151 -0
- package/src/components/documents/view/index.ts +2 -0
- package/src/components/documents/view/locales/de.ts +23 -0
- package/src/components/documents/view/locales/es.ts +23 -0
- package/src/components/documents/view/locales/fr.ts +23 -0
- package/src/components/documents/view/locales/hr.ts +23 -0
- package/src/components/documents/view/locales/it.ts +23 -0
- package/src/components/documents/view/locales/nl.ts +23 -0
- package/src/components/documents/view/locales/pl.ts +23 -0
- package/src/components/documents/view/locales/pt.ts +23 -0
- package/src/components/documents/view/locales/sl.ts +23 -0
- package/src/components/documents/view/use-document-download.ts +8 -5
- package/src/components/entities/create-entity-form.tsx +165 -13
- package/src/components/entities/entity-settings-form/entity-settings-form.tsx +101 -1
- package/src/components/entities/entity-settings-form/locales/de.ts +9 -0
- package/src/components/entities/entity-settings-form/locales/es.ts +9 -0
- package/src/components/entities/entity-settings-form/locales/fr.ts +9 -0
- package/src/components/entities/entity-settings-form/locales/hr.ts +9 -0
- package/src/components/entities/entity-settings-form/locales/it.ts +9 -0
- package/src/components/entities/entity-settings-form/locales/nl.ts +9 -0
- package/src/components/entities/entity-settings-form/locales/pl.ts +9 -0
- package/src/components/entities/entity-settings-form/locales/pt.ts +9 -0
- package/src/components/entities/entity-settings-form/locales/sl.ts +9 -0
- package/src/components/entities/fina-settings-form/fina-settings-form.tsx +83 -71
- package/src/components/entities/fina-settings-form/fina-settings.hooks.ts +7 -2
- package/src/components/entities/fina-settings-form/locales/de.ts +2 -2
- package/src/components/entities/fina-settings-form/locales/en.ts +2 -2
- package/src/components/entities/fina-settings-form/locales/es.ts +2 -2
- package/src/components/entities/fina-settings-form/locales/fr.ts +2 -2
- package/src/components/entities/fina-settings-form/locales/hr.ts +2 -2
- package/src/components/entities/fina-settings-form/locales/it.ts +2 -2
- package/src/components/entities/fina-settings-form/locales/nl.ts +2 -2
- package/src/components/entities/fina-settings-form/locales/pl.ts +2 -2
- package/src/components/entities/fina-settings-form/locales/pt.ts +2 -2
- package/src/components/entities/fina-settings-form/locales/sl.ts +2 -2
- package/src/components/entities/furs-settings-form/furs-settings-form.tsx +10 -1
- package/src/components/entities/furs-settings-form/furs-settings.hooks.ts +7 -2
- package/src/components/entities/furs-settings-form/locales/en.ts +0 -1
- package/src/components/entities/furs-settings-form/sections/general-settings-section.tsx +12 -4
- package/src/components/entities/settings/pdf-template-selector/locales/de.ts +3 -1
- package/src/components/entities/settings/pdf-template-selector/locales/es.ts +3 -1
- package/src/components/entities/settings/pdf-template-selector/locales/fr.ts +4 -1
- package/src/components/entities/settings/pdf-template-selector/locales/hr.ts +4 -1
- package/src/components/entities/settings/pdf-template-selector/locales/it.ts +3 -1
- package/src/components/entities/settings/pdf-template-selector/locales/nl.ts +3 -1
- package/src/components/entities/settings/pdf-template-selector/locales/pl.ts +3 -1
- package/src/components/entities/settings/pdf-template-selector/locales/pt.ts +3 -1
- package/src/components/entities/settings/pdf-template-selector/locales/sl.ts +3 -1
- package/src/components/entities/settings/pdf-template-selector/pdf-template-cards.tsx +1 -0
- package/src/components/estimates/create/create-estimate-form.tsx +29 -2
- package/src/components/estimates/list/list-table.tsx +3 -6
- package/src/components/estimates/list/locales/de.ts +1 -0
- package/src/components/estimates/list/locales/es.ts +1 -0
- package/src/components/estimates/list/locales/fr.ts +1 -0
- package/src/components/estimates/list/locales/hr.ts +1 -0
- package/src/components/estimates/list/locales/it.ts +1 -0
- package/src/components/estimates/list/locales/nl.ts +1 -0
- package/src/components/estimates/list/locales/pl.ts +1 -0
- package/src/components/estimates/list/locales/pt.ts +1 -0
- package/src/components/estimates/list/locales/sl.ts +1 -0
- package/src/components/export/document-export-form.tsx +9 -2
- package/src/components/export/index.ts +2 -0
- package/src/components/export/sales-per-item-export-form.tsx +223 -0
- package/src/components/invoices/create/create-invoice-form.tsx +48 -1
- package/src/components/invoices/create/locales/de.ts +11 -0
- package/src/components/invoices/create/locales/es.ts +11 -0
- package/src/components/invoices/create/locales/fr.ts +11 -0
- package/src/components/invoices/create/locales/hr.ts +10 -0
- package/src/components/invoices/create/locales/it.ts +11 -0
- package/src/components/invoices/create/locales/nl.ts +11 -0
- package/src/components/invoices/create/locales/pl.ts +10 -0
- package/src/components/invoices/create/locales/pt.ts +10 -0
- package/src/components/invoices/create/locales/sl.ts +10 -0
- package/src/components/invoices/invoices-furs.hooks.ts +27 -9
- package/src/components/invoices/list/list-row-actions.tsx +3 -3
- package/src/components/invoices/list/list-table.tsx +132 -21
- package/src/components/invoices/list/locales/de.ts +6 -0
- package/src/components/invoices/list/locales/en.ts +5 -0
- package/src/components/invoices/list/locales/es.ts +6 -0
- package/src/components/invoices/list/locales/fr.ts +6 -0
- package/src/components/invoices/list/locales/hr.ts +6 -0
- package/src/components/invoices/list/locales/it.ts +6 -0
- package/src/components/invoices/list/locales/nl.ts +6 -0
- package/src/components/invoices/list/locales/pl.ts +6 -0
- package/src/components/invoices/list/locales/pt.ts +6 -0
- package/src/components/invoices/list/locales/sl.ts +6 -0
- package/src/components/invoices/view/fiscalization-status-card.tsx +42 -24
- package/src/components/items/item-combobox.tsx +5 -3
- package/src/components/items/item-list-table/item-list-header.tsx +4 -17
- package/src/components/items/item-list-table/item-list-row-actions.tsx +3 -2
- package/src/components/items/item-list-table/item-list-row.tsx +3 -2
- package/src/components/items/item-list-table/item-list-table.tsx +3 -3
- package/src/components/items/item-list-table/locales/de.ts +1 -0
- package/src/components/items/item-list-table/locales/es.ts +1 -0
- package/src/components/items/item-list-table/locales/fr.ts +1 -0
- package/src/components/items/item-list-table/locales/hr.ts +1 -0
- package/src/components/items/item-list-table/locales/it.ts +1 -0
- package/src/components/items/item-list-table/locales/nl.ts +1 -0
- package/src/components/items/item-list-table/locales/pl.ts +1 -0
- package/src/components/items/item-list-table/locales/pt.ts +1 -0
- package/src/components/items/item-list-table/locales/sl.ts +1 -0
- package/src/components/payments/list/list-table.tsx +0 -4
- package/src/components/payments/list/locales/de.ts +1 -0
- package/src/components/payments/list/locales/es.ts +1 -0
- package/src/components/payments/list/locales/fr.ts +1 -0
- package/src/components/payments/list/locales/hr.ts +1 -0
- package/src/components/payments/list/locales/it.ts +1 -0
- package/src/components/payments/list/locales/nl.ts +1 -0
- package/src/components/payments/list/locales/pl.ts +1 -0
- package/src/components/payments/list/locales/pt.ts +1 -0
- package/src/components/payments/list/locales/sl.ts +1 -0
- package/src/components/recurring-invoices/list/list-table.tsx +0 -7
- package/src/components/recurring-invoices/list/locales/de.ts +1 -0
- package/src/components/recurring-invoices/list/locales/es.ts +1 -0
- package/src/components/recurring-invoices/list/locales/fr.ts +1 -0
- package/src/components/recurring-invoices/list/locales/hr.ts +1 -0
- package/src/components/recurring-invoices/list/locales/it.ts +1 -0
- package/src/components/recurring-invoices/list/locales/nl.ts +1 -0
- package/src/components/recurring-invoices/list/locales/pl.ts +1 -0
- package/src/components/recurring-invoices/list/locales/pt.ts +1 -0
- package/src/components/recurring-invoices/list/locales/sl.ts +1 -0
- package/src/components/request-logs/request-log-list-table.tsx +0 -3
- package/src/components/table/README.md +14 -121
- package/src/components/table/data-table.tsx +22 -37
- package/src/components/table/hooks/use-table-state.ts +3 -27
- package/src/components/table/index.ts +0 -2
- package/src/components/table/selection-toolbar.tsx +35 -1
- package/src/components/table/table-empty-state.tsx +6 -3
- package/src/components/table/table-no-results.tsx +10 -5
- package/src/components/table/types.ts +0 -5
- package/src/components/taxes/tax-list-table/locales/de.ts +1 -0
- package/src/components/taxes/tax-list-table/locales/es.ts +1 -0
- package/src/components/taxes/tax-list-table/locales/fr.ts +1 -0
- package/src/components/taxes/tax-list-table/locales/hr.ts +1 -0
- package/src/components/taxes/tax-list-table/locales/it.ts +1 -0
- package/src/components/taxes/tax-list-table/locales/nl.ts +1 -0
- package/src/components/taxes/tax-list-table/locales/pl.ts +1 -0
- package/src/components/taxes/tax-list-table/locales/pt.ts +1 -0
- package/src/components/taxes/tax-list-table/locales/sl.ts +1 -0
- package/src/components/taxes/tax-list-table/tax-list-header.tsx +3 -14
- package/src/components/taxes/tax-list-table/tax-list-table.tsx +3 -3
- package/src/components/ui/popover.tsx +3 -1
- package/src/components/ui/tooltip.tsx +3 -1
- package/src/generated/schemas/deliverynote.ts +134 -0
- package/src/generated/schemas/entity.ts +4 -0
- package/src/generated/schemas/index.ts +3 -0
- package/src/generated/schemas/order.ts +5 -3
- package/src/generated/schemas/payment.ts +22 -2
- package/src/generated/schemas/renderadvanceinvoicepreview_body.ts +1 -0
- package/src/generated/schemas/rendercreditnotepreview_body.ts +1 -0
- package/src/generated/schemas/renderdeliverynotepreview_body.ts +185 -0
- package/src/generated/schemas/renderestimatepreview_body.ts +1 -0
- package/src/generated/schemas/renderinvoicepreview_body.ts +1 -0
- package/src/generated/schemas/startpdfexport_body.ts +18 -2
- package/src/generated/schemas/userfinasettings.ts +19 -0
- package/src/generated/schemas/webhook.ts +12 -0
- package/src/hooks/use-duplicate-document.ts +49 -6
- package/src/hooks/use-next-document-number.ts +2 -2
- package/src/lib/fiscalization.ts +12 -0
- package/src/lib/schemas/advance-invoice.ts +0 -1
- package/src/providers/sdk-provider.tsx +5 -7
- package/src/components/table/sortable-header.tsx +0 -56
|
@@ -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
|
-
{
|
|
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
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AdvanceInvoice, CreditNote, Estimate, Invoice } from "@spaceinvoices/js-sdk";
|
|
1
|
+
import type { AdvanceInvoice, CreditNote, DeliveryNote, Estimate, Invoice } from "@spaceinvoices/js-sdk";
|
|
2
2
|
import { Badge } from "@/ui/components/ui/badge";
|
|
3
3
|
import { Card, CardContent, CardHeader, CardTitle } from "@/ui/components/ui/card";
|
|
4
4
|
import { Separator } from "@/ui/components/ui/separator";
|
|
@@ -17,14 +17,15 @@ import sl from "./locales/sl";
|
|
|
17
17
|
const translations = { sl, de, it, fr, es, pt, nl, pl, hr } as const;
|
|
18
18
|
|
|
19
19
|
// Document type union
|
|
20
|
-
type Document = Invoice | Estimate | CreditNote | AdvanceInvoice;
|
|
21
|
-
type DocumentType = "invoice" | "estimate" | "credit_note" | "advance_invoice";
|
|
20
|
+
type Document = Invoice | Estimate | CreditNote | AdvanceInvoice | DeliveryNote;
|
|
21
|
+
type DocumentType = "invoice" | "estimate" | "credit_note" | "advance_invoice" | "delivery_note";
|
|
22
22
|
|
|
23
23
|
interface DocumentDetailsCardProps extends ComponentTranslationProps {
|
|
24
24
|
document: Document;
|
|
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,7 +80,13 @@ function getPaymentStatus(
|
|
|
79
80
|
* - Totals breakdown
|
|
80
81
|
* - Payment status (for invoices/advance invoices)
|
|
81
82
|
*/
|
|
82
|
-
export function DocumentDetailsCard({
|
|
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;
|
|
@@ -98,6 +105,96 @@ export function DocumentDetailsCard({ document, documentType, locale = "en", ...
|
|
|
98
105
|
// Calculate tax total
|
|
99
106
|
const taxTotal = document.total_with_tax - document.total;
|
|
100
107
|
|
|
108
|
+
const bodyContent = (
|
|
109
|
+
<>
|
|
110
|
+
{/* Document info */}
|
|
111
|
+
<div className="grid grid-cols-2 gap-x-4 gap-y-2 text-sm">
|
|
112
|
+
<div className="text-muted-foreground">{t("Number")}</div>
|
|
113
|
+
<div className="text-right font-medium">{document.number}</div>
|
|
114
|
+
|
|
115
|
+
<div className="text-muted-foreground">{t("Date")}</div>
|
|
116
|
+
<div className="text-right">{fmtDate(document.date)}</div>
|
|
117
|
+
|
|
118
|
+
{isInvoiceOrAdvance && invoiceDoc.date_due && (
|
|
119
|
+
<>
|
|
120
|
+
<div className="text-muted-foreground">{t("Due date")}</div>
|
|
121
|
+
<div className="text-right">{fmtDate(invoiceDoc.date_due)}</div>
|
|
122
|
+
</>
|
|
123
|
+
)}
|
|
124
|
+
|
|
125
|
+
{isInvoiceOrAdvance && (invoiceDoc as any).date_service && (
|
|
126
|
+
<>
|
|
127
|
+
<div className="text-muted-foreground">
|
|
128
|
+
{(invoiceDoc as any).date_service_to ? t("Service period") : t("Service date")}
|
|
129
|
+
</div>
|
|
130
|
+
<div className="text-right">
|
|
131
|
+
{(invoiceDoc as any).date_service_to
|
|
132
|
+
? `${fmtDate((invoiceDoc as any).date_service)} - ${fmtDate((invoiceDoc as any).date_service_to)}`
|
|
133
|
+
: fmtDate((invoiceDoc as any).date_service)}
|
|
134
|
+
</div>
|
|
135
|
+
</>
|
|
136
|
+
)}
|
|
137
|
+
|
|
138
|
+
{isEstimate && estimateDoc.date_valid_till && (
|
|
139
|
+
<>
|
|
140
|
+
<div className="text-muted-foreground">{t("Valid until")}</div>
|
|
141
|
+
<div className="text-right">{fmtDate(estimateDoc.date_valid_till)}</div>
|
|
142
|
+
</>
|
|
143
|
+
)}
|
|
144
|
+
|
|
145
|
+
<div className="text-muted-foreground">{t("Customer")}</div>
|
|
146
|
+
<div className="text-right">{customerName}</div>
|
|
147
|
+
</div>
|
|
148
|
+
|
|
149
|
+
<Separator />
|
|
150
|
+
|
|
151
|
+
{/* Totals */}
|
|
152
|
+
<div className="space-y-2 text-sm">
|
|
153
|
+
<div className="flex justify-between">
|
|
154
|
+
<span className="text-muted-foreground">{t("Subtotal")}</span>
|
|
155
|
+
<span>{fmt(document.total)}</span>
|
|
156
|
+
</div>
|
|
157
|
+
<div className="flex justify-between">
|
|
158
|
+
<span className="text-muted-foreground">{t("Tax")}</span>
|
|
159
|
+
<span>{fmt(taxTotal)}</span>
|
|
160
|
+
</div>
|
|
161
|
+
<div className="flex justify-between font-semibold">
|
|
162
|
+
<span>{t("Total")}</span>
|
|
163
|
+
<span>{fmt(document.total_with_tax)}</span>
|
|
164
|
+
</div>
|
|
165
|
+
|
|
166
|
+
{/* Payment info for invoices/advance invoices */}
|
|
167
|
+
{isInvoiceOrAdvance && invoiceDoc.total_paid > 0 && (
|
|
168
|
+
<>
|
|
169
|
+
<Separator />
|
|
170
|
+
<div className="flex justify-between text-green-600">
|
|
171
|
+
<span>{t("Paid")}</span>
|
|
172
|
+
<span>-{fmt(invoiceDoc.total_paid)}</span>
|
|
173
|
+
</div>
|
|
174
|
+
<div className="flex justify-between font-semibold">
|
|
175
|
+
<span>{t("Due")}</span>
|
|
176
|
+
<span>{fmt(invoiceDoc.total_due)}</span>
|
|
177
|
+
</div>
|
|
178
|
+
</>
|
|
179
|
+
)}
|
|
180
|
+
</div>
|
|
181
|
+
</>
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
if (variant === "inline") {
|
|
185
|
+
return (
|
|
186
|
+
<div className="space-y-3">
|
|
187
|
+
<div className="flex items-center justify-between font-medium text-sm">
|
|
188
|
+
{t("Details")}
|
|
189
|
+
{isInvoiceOrAdvance && (
|
|
190
|
+
<Badge variant={getPaymentStatus(invoiceDoc, t).variant}>{getPaymentStatus(invoiceDoc, t).label}</Badge>
|
|
191
|
+
)}
|
|
192
|
+
</div>
|
|
193
|
+
<div className="space-y-4">{bodyContent}</div>
|
|
194
|
+
</div>
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
|
|
101
198
|
return (
|
|
102
199
|
<Card>
|
|
103
200
|
<CardHeader className="pb-3">
|
|
@@ -108,79 +205,7 @@ export function DocumentDetailsCard({ document, documentType, locale = "en", ...
|
|
|
108
205
|
)}
|
|
109
206
|
</CardTitle>
|
|
110
207
|
</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>
|
|
208
|
+
<CardContent className="space-y-4">{bodyContent}</CardContent>
|
|
184
209
|
</Card>
|
|
185
210
|
);
|
|
186
211
|
}
|
|
@@ -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 });
|
|
@@ -147,9 +149,9 @@ export function DocumentPaymentsList({
|
|
|
147
149
|
try {
|
|
148
150
|
await sdk.payments.delete(paymentToDelete.id, { entity_id: entityId });
|
|
149
151
|
|
|
150
|
-
// Invalidate
|
|
151
|
-
queryClient.invalidateQueries({ queryKey: ["payments"] });
|
|
152
|
-
queryClient.invalidateQueries({ queryKey: ["documents"] });
|
|
152
|
+
// Invalidate this document's payments and document view
|
|
153
|
+
queryClient.invalidateQueries({ queryKey: ["payments", documentType, documentId] });
|
|
154
|
+
queryClient.invalidateQueries({ queryKey: ["documents", documentType, documentId] });
|
|
153
155
|
|
|
154
156
|
onDeleteSuccess?.();
|
|
155
157
|
} catch (error) {
|
|
@@ -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
|
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import type { DocumentRelation } from "@spaceinvoices/js-sdk";
|
|
2
|
+
import { Link2 } from "lucide-react";
|
|
3
|
+
import { Card, CardContent, CardHeader, CardTitle } from "@/ui/components/ui/card";
|
|
4
|
+
import type { ComponentTranslationProps } from "@/ui/lib/translation";
|
|
5
|
+
import { createTranslation } from "@/ui/lib/translation";
|
|
6
|
+
import de from "./locales/de";
|
|
7
|
+
import es from "./locales/es";
|
|
8
|
+
import fr from "./locales/fr";
|
|
9
|
+
import hr from "./locales/hr";
|
|
10
|
+
import it from "./locales/it";
|
|
11
|
+
import nl from "./locales/nl";
|
|
12
|
+
import pl from "./locales/pl";
|
|
13
|
+
import pt from "./locales/pt";
|
|
14
|
+
import sl from "./locales/sl";
|
|
15
|
+
|
|
16
|
+
const translations = { sl, de, it, fr, es, pt, nl, pl, hr } as const;
|
|
17
|
+
|
|
18
|
+
interface DocumentRelationsListProps extends ComponentTranslationProps {
|
|
19
|
+
documentId: string;
|
|
20
|
+
documentRelations?: DocumentRelation[];
|
|
21
|
+
locale?: string;
|
|
22
|
+
onNavigate?: (documentId: string) => void;
|
|
23
|
+
variant?: "card" | "inline";
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function getDocumentTypeLabel(type: string, t: (key: string) => string): string {
|
|
27
|
+
const labels: Record<string, string> = {
|
|
28
|
+
invoice: t("Invoice"),
|
|
29
|
+
estimate: t("Estimate"),
|
|
30
|
+
credit_note: t("Credit note"),
|
|
31
|
+
advance_invoice: t("Advance invoice"),
|
|
32
|
+
delivery_note: t("Delivery note"),
|
|
33
|
+
};
|
|
34
|
+
return labels[type] || type;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function getRelationLabel(relationType: string, t: (key: string) => string): string {
|
|
38
|
+
const labels: Record<string, string> = {
|
|
39
|
+
credit_for: t("Credit for"),
|
|
40
|
+
converted_from: t("Converted from"),
|
|
41
|
+
converted_to: t("Converted to"),
|
|
42
|
+
has_credit: t("Has credit"),
|
|
43
|
+
advance_applied: t("Advance applied"),
|
|
44
|
+
applied_to: t("Applied to"),
|
|
45
|
+
delivered_for: t("Delivered for"),
|
|
46
|
+
has_delivery: t("Has delivery"),
|
|
47
|
+
fulfills: t("Fulfills"),
|
|
48
|
+
fulfilled_by: t("Fulfilled by"),
|
|
49
|
+
references: t("References"),
|
|
50
|
+
};
|
|
51
|
+
return labels[relationType] || relationType;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function DocumentRelationsList({
|
|
55
|
+
documentId,
|
|
56
|
+
documentRelations,
|
|
57
|
+
locale = "en",
|
|
58
|
+
onNavigate,
|
|
59
|
+
variant = "card",
|
|
60
|
+
...i18nProps
|
|
61
|
+
}: DocumentRelationsListProps) {
|
|
62
|
+
const t = createTranslation({ translations, locale, ...i18nProps });
|
|
63
|
+
|
|
64
|
+
const relations = documentRelations || [];
|
|
65
|
+
|
|
66
|
+
if (relations.length === 0) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const bodyContent = (
|
|
71
|
+
<div className="space-y-2">
|
|
72
|
+
{relations.map((relation) => {
|
|
73
|
+
const isSource = relation.source_id === documentId;
|
|
74
|
+
const otherType = isSource ? relation.target_type : relation.source_type;
|
|
75
|
+
const otherId = isSource ? relation.target_id : relation.source_id;
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<div key={relation.id} className="flex items-center justify-between rounded-md border p-3">
|
|
79
|
+
<div className="flex flex-col gap-0.5">
|
|
80
|
+
<span className="font-medium text-sm">{getDocumentTypeLabel(otherType, t)}</span>
|
|
81
|
+
<span className="text-muted-foreground text-xs">{getRelationLabel(relation.relation_type, t)}</span>
|
|
82
|
+
</div>
|
|
83
|
+
{onNavigate ? (
|
|
84
|
+
<button
|
|
85
|
+
type="button"
|
|
86
|
+
onClick={() => onNavigate(otherId)}
|
|
87
|
+
className="flex items-center gap-1 text-primary text-sm hover:underline"
|
|
88
|
+
>
|
|
89
|
+
<Link2 className="h-3.5 w-3.5" />
|
|
90
|
+
{t("View")}
|
|
91
|
+
</button>
|
|
92
|
+
) : null}
|
|
93
|
+
</div>
|
|
94
|
+
);
|
|
95
|
+
})}
|
|
96
|
+
</div>
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
if (variant === "inline") {
|
|
100
|
+
return (
|
|
101
|
+
<div>
|
|
102
|
+
<h3 className="mb-3 font-medium text-sm">
|
|
103
|
+
{t("Linked documents")} ({relations.length})
|
|
104
|
+
</h3>
|
|
105
|
+
{bodyContent}
|
|
106
|
+
</div>
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return (
|
|
111
|
+
<Card>
|
|
112
|
+
<CardHeader className="pb-3">
|
|
113
|
+
<CardTitle className="text-lg">
|
|
114
|
+
{t("Linked documents")} ({relations.length})
|
|
115
|
+
</CardTitle>
|
|
116
|
+
</CardHeader>
|
|
117
|
+
<CardContent>{bodyContent}</CardContent>
|
|
118
|
+
</Card>
|
|
119
|
+
);
|
|
120
|
+
}
|