@spaceinvoices/react-ui 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +340 -0
- package/cli/dist/index.js +922 -0
- package/package.json +87 -0
- package/registry.json +600 -0
- package/spaceinvoices.schema.json +47 -0
- package/src/app.tsx +25 -0
- package/src/common/autocomplete.tsx +135 -0
- package/src/components/activities/activity-timeline.tsx +160 -0
- package/src/components/activities/index.ts +1 -0
- package/src/components/activities/locales/de.ts +30 -0
- package/src/components/activities/locales/sl.ts +30 -0
- package/src/components/advance-invoices/advance-invoices.hooks.ts +75 -0
- package/src/components/advance-invoices/create/create-advance-invoice-form.tsx +702 -0
- package/src/components/advance-invoices/create/locales/de.ts +29 -0
- package/src/components/advance-invoices/create/locales/sl.ts +25 -0
- package/src/components/advance-invoices/create/prepare-advance-invoice-submission.ts +74 -0
- package/src/components/advance-invoices/index.ts +5 -0
- package/src/components/advance-invoices/list/index.ts +3 -0
- package/src/components/advance-invoices/list/list-row-actions.tsx +119 -0
- package/src/components/advance-invoices/list/list-table.tsx +178 -0
- package/src/components/advance-invoices/list/locales/de.ts +32 -0
- package/src/components/advance-invoices/list/locales/sl.ts +32 -0
- package/src/components/advance-invoices/list/use-advance-invoice-download.ts +63 -0
- package/src/components/button-loader.tsx +11 -0
- package/src/components/combobox.tsx +96 -0
- package/src/components/company-registry/company-registry-autocomplete.tsx +151 -0
- package/src/components/company-registry/company-registry.hooks.ts +67 -0
- package/src/components/company-registry/index.ts +7 -0
- package/src/components/credit-notes/create/create-credit-note-form.tsx +332 -0
- package/src/components/credit-notes/create/index.ts +1 -0
- package/src/components/credit-notes/create/locales/de.ts +69 -0
- package/src/components/credit-notes/create/locales/sl.ts +67 -0
- package/src/components/credit-notes/credit-notes.hooks.ts +22 -0
- package/src/components/credit-notes/index.ts +10 -0
- package/src/components/credit-notes/list/index.ts +3 -0
- package/src/components/credit-notes/list/list-row-actions.tsx +116 -0
- package/src/components/credit-notes/list/list-table.tsx +183 -0
- package/src/components/credit-notes/list/locales/de.ts +33 -0
- package/src/components/credit-notes/list/locales/sl.ts +33 -0
- package/src/components/credit-notes/list/use-credit-note-download.ts +65 -0
- package/src/components/customers/create-customer-form/create-customer-form.tsx +134 -0
- package/src/components/customers/create-customer-form/locales/de.ts +20 -0
- package/src/components/customers/create-customer-form/locales/sl.ts +20 -0
- package/src/components/customers/customer-autocomplete.tsx +173 -0
- package/src/components/customers/customer-combobox.tsx +130 -0
- package/src/components/customers/customer-list-table/customer-list-row-actions.tsx +48 -0
- package/src/components/customers/customer-list-table/customer-list-table.tsx +124 -0
- package/src/components/customers/customer-list-table/index.ts +2 -0
- package/src/components/customers/customer-list-table/locales/de.ts +16 -0
- package/src/components/customers/customer-list-table/locales/sl.ts +16 -0
- package/src/components/customers/customers.hooks.test.ts +348 -0
- package/src/components/customers/customers.hooks.ts +57 -0
- package/src/components/customers/index.ts +5 -0
- package/src/components/dashboard/chart-empty-state.tsx +29 -0
- package/src/components/dashboard/collection-rate-card/collection-rate-card.tsx +80 -0
- package/src/components/dashboard/collection-rate-card/index.ts +4 -0
- package/src/components/dashboard/collection-rate-card/locales/sl.ts +3 -0
- package/src/components/dashboard/collection-rate-card/use-collection-rate.ts +74 -0
- package/src/components/dashboard/index.ts +54 -0
- package/src/components/dashboard/invoice-status-chart/index.ts +4 -0
- package/src/components/dashboard/invoice-status-chart/invoice-status-chart.tsx +130 -0
- package/src/components/dashboard/invoice-status-chart/locales/sl.ts +9 -0
- package/src/components/dashboard/invoice-status-chart/use-invoice-status.ts +105 -0
- package/src/components/dashboard/loading-card.tsx +19 -0
- package/src/components/dashboard/payment-methods-chart/index.ts +4 -0
- package/src/components/dashboard/payment-methods-chart/locales/sl.ts +12 -0
- package/src/components/dashboard/payment-methods-chart/payment-methods-chart.tsx +152 -0
- package/src/components/dashboard/payment-methods-chart/use-payment-methods.ts +50 -0
- package/src/components/dashboard/payment-trend-chart/index.ts +4 -0
- package/src/components/dashboard/payment-trend-chart/locales/sl.ts +5 -0
- package/src/components/dashboard/payment-trend-chart/payment-trend-chart.tsx +137 -0
- package/src/components/dashboard/payment-trend-chart/use-payment-trend.ts +92 -0
- package/src/components/dashboard/revenue-card.tsx +49 -0
- package/src/components/dashboard/revenue-trend-chart/index.ts +4 -0
- package/src/components/dashboard/revenue-trend-chart/locales/sl.ts +5 -0
- package/src/components/dashboard/revenue-trend-chart/revenue-trend-chart.tsx +137 -0
- package/src/components/dashboard/revenue-trend-chart/use-revenue-trend.ts +93 -0
- package/src/components/dashboard/shared/index.ts +5 -0
- package/src/components/dashboard/shared/use-revenue-data.ts +160 -0
- package/src/components/dashboard/shared/use-stats-counts.ts +89 -0
- package/src/components/dashboard/shared/use-stats-query.ts +38 -0
- package/src/components/dashboard/stat-card.tsx +41 -0
- package/src/components/dashboard/tax-collected-card/index.ts +2 -0
- package/src/components/dashboard/tax-collected-card/tax-collected-card.tsx +77 -0
- package/src/components/dashboard/tax-collected-card/use-tax-collected.ts +145 -0
- package/src/components/dashboard/top-customers-chart/index.ts +4 -0
- package/src/components/dashboard/top-customers-chart/locales/sl.ts +5 -0
- package/src/components/dashboard/top-customers-chart/top-customers-chart.tsx +130 -0
- package/src/components/dashboard/top-customers-chart/use-top-customers.ts +72 -0
- package/src/components/documents/create/document-add-item-form.tsx +379 -0
- package/src/components/documents/create/document-add-item-tax-rate-field.tsx +120 -0
- package/src/components/documents/create/document-details-section.tsx +597 -0
- package/src/components/documents/create/document-items-section.tsx +133 -0
- package/src/components/documents/create/document-recipient-section.tsx +101 -0
- package/src/components/documents/create/form-types.ts +36 -0
- package/src/components/documents/create/index.ts +9 -0
- package/src/components/documents/create/live-preview.tsx +235 -0
- package/src/components/documents/create/mark-as-paid-section.tsx +82 -0
- package/src/components/documents/create/prepare-document-submission.test.ts +132 -0
- package/src/components/documents/create/prepare-document-submission.ts +187 -0
- package/src/components/documents/create/prepare-preview-data.test.ts +155 -0
- package/src/components/documents/create/prepare-preview-data.ts +16 -0
- package/src/components/documents/create/smart-code-insert-button.tsx +139 -0
- package/src/components/documents/create/use-document-customer-form.ts +161 -0
- package/src/components/documents/document-preview.tsx +13 -0
- package/src/components/documents/documents.hooks.ts +146 -0
- package/src/components/documents/index.ts +23 -0
- package/src/components/documents/shared/document-preview-display.tsx +172 -0
- package/src/components/documents/shared/index.ts +3 -0
- package/src/components/documents/shared/scaled-document-preview.tsx +70 -0
- package/src/components/documents/shared/use-a4-scaling.ts +62 -0
- package/src/components/documents/types.ts +61 -0
- package/src/components/documents/view/document-actions-bar.tsx +328 -0
- package/src/components/documents/view/document-details-card.tsx +179 -0
- package/src/components/documents/view/document-payments-list.tsx +256 -0
- package/src/components/documents/view/index.ts +4 -0
- package/src/components/documents/view/locales/de.ts +85 -0
- package/src/components/documents/view/locales/sl.ts +84 -0
- package/src/components/documents/view/use-document-download.ts +125 -0
- package/src/components/entities/create-entity-form.tsx +105 -0
- package/src/components/entities/entities.hooks.ts +50 -0
- package/src/components/entities/entity-settings-form/email-template-variables-info.tsx +103 -0
- package/src/components/entities/entity-settings-form/entity-settings-form.tsx +1326 -0
- package/src/components/entities/entity-settings-form/image-upload-with-crop.tsx +222 -0
- package/src/components/entities/entity-settings-form/index.ts +2 -0
- package/src/components/entities/entity-settings-form/input-with-preview.tsx +190 -0
- package/src/components/entities/entity-settings-form/locales/de.ts +192 -0
- package/src/components/entities/entity-settings-form/locales/sl.ts +188 -0
- package/src/components/entities/furs-settings-form/furs-settings-form.tsx +410 -0
- package/src/components/entities/furs-settings-form/furs-settings.hooks.ts +320 -0
- package/src/components/entities/furs-settings-form/index.ts +3 -0
- package/src/components/entities/furs-settings-form/locales/de.ts +233 -0
- package/src/components/entities/furs-settings-form/locales/en.ts +194 -0
- package/src/components/entities/furs-settings-form/locales/sl.ts +196 -0
- package/src/components/entities/furs-settings-form/sections/certificate-settings-section.tsx +242 -0
- package/src/components/entities/furs-settings-form/sections/enable-fiscalization-section.tsx +139 -0
- package/src/components/entities/furs-settings-form/sections/general-settings-section.tsx +252 -0
- package/src/components/entities/furs-settings-form/sections/premises-management-section.tsx +370 -0
- package/src/components/entities/furs-settings-form/sections/register-premise-dialog.tsx +420 -0
- package/src/components/entities/keys.ts +2 -0
- package/src/components/entities/settings/branding-settings-form.tsx +274 -0
- package/src/components/entities/settings/company-settings-form.tsx +256 -0
- package/src/components/entities/settings/defaults-settings-form.tsx +501 -0
- package/src/components/entities/settings/email-settings-form.tsx +288 -0
- package/src/components/entities/settings/eslog-settings-form.tsx +113 -0
- package/src/components/entities/settings/index.ts +8 -0
- package/src/components/entities/settings/number-format-settings-form.tsx +244 -0
- package/src/components/entities/settings/pdf-template-selector/demo-invoice-data.ts +164 -0
- package/src/components/entities/settings/pdf-template-selector/index.ts +2 -0
- package/src/components/entities/settings/pdf-template-selector/locales/de.ts +18 -0
- package/src/components/entities/settings/pdf-template-selector/locales/sl.ts +18 -0
- package/src/components/entities/settings/pdf-template-selector/pdf-template-cards.tsx +49 -0
- package/src/components/entities/settings/settings-footer.tsx +16 -0
- package/src/components/entities/settings/tax-rules-settings-form.tsx +346 -0
- package/src/components/estimates/create/create-estimate-form.tsx +384 -0
- package/src/components/estimates/create/locales/de.ts +64 -0
- package/src/components/estimates/create/locales/sl.ts +63 -0
- package/src/components/estimates/create/prepare-estimate-submission.ts +39 -0
- package/src/components/estimates/create/use-estimate-customer-form.ts +5 -0
- package/src/components/estimates/estimates.hooks.ts +15 -0
- package/src/components/estimates/index.ts +6 -0
- package/src/components/estimates/list/index.ts +3 -0
- package/src/components/estimates/list/list-row-actions.tsx +103 -0
- package/src/components/estimates/list/list-table.tsx +171 -0
- package/src/components/estimates/list/locales/de.ts +26 -0
- package/src/components/estimates/list/locales/sl.ts +26 -0
- package/src/components/estimates/list/use-estimate-download.ts +63 -0
- package/src/components/export/document-export-form.tsx +288 -0
- package/src/components/export/index.ts +2 -0
- package/src/components/form/form-input.tsx +89 -0
- package/src/components/form/index.ts +1 -0
- package/src/components/invoices/create/create-invoice-form.tsx +852 -0
- package/src/components/invoices/create/eslog-validation.test.ts +242 -0
- package/src/components/invoices/create/eslog-validation.ts +208 -0
- package/src/components/invoices/create/locales/de.ts +118 -0
- package/src/components/invoices/create/locales/sl.ts +114 -0
- package/src/components/invoices/create/prepare-invoice-submission.test.ts +777 -0
- package/src/components/invoices/create/prepare-invoice-submission.ts +79 -0
- package/src/components/invoices/create/use-invoice-customer-form.ts +5 -0
- package/src/components/invoices/index.ts +9 -0
- package/src/components/invoices/invoices-furs.hooks.ts +28 -0
- package/src/components/invoices/invoices.hooks.ts +110 -0
- package/src/components/invoices/list/index.ts +3 -0
- package/src/components/invoices/list/list-row-actions.tsx +132 -0
- package/src/components/invoices/list/list-table.tsx +165 -0
- package/src/components/invoices/list/locales/de.ts +33 -0
- package/src/components/invoices/list/locales/sl.ts +33 -0
- package/src/components/invoices/list/use-invoice-download.ts +62 -0
- package/src/components/invoices/send-email-dialog/index.ts +1 -0
- package/src/components/invoices/send-email-dialog/locales/de.ts +18 -0
- package/src/components/invoices/send-email-dialog/locales/sl.ts +17 -0
- package/src/components/invoices/send-email-dialog/send-email-dialog.tsx +289 -0
- package/src/components/invoices/send-email-dialog.tsx +2 -0
- package/src/components/invoices/shared/index.ts +2 -0
- package/src/components/invoices/shared/scaled-document-preview.tsx +32 -0
- package/src/components/invoices/shared/use-a4-scaling.tsx +39 -0
- package/src/components/invoices/view/eslog-info-display.tsx +160 -0
- package/src/components/invoices/view/furs-info-display.tsx +213 -0
- package/src/components/items/create-item-form/create-item-form.tsx +155 -0
- package/src/components/items/create-item-form/locales/de.ts +14 -0
- package/src/components/items/create-item-form/locales/en.ts +9 -0
- package/src/components/items/create-item-form/locales/sl.ts +14 -0
- package/src/components/items/item-combobox.tsx +147 -0
- package/src/components/items/item-list-table/item-list-header.tsx +33 -0
- package/src/components/items/item-list-table/item-list-row-actions.tsx +48 -0
- package/src/components/items/item-list-table/item-list-row.tsx +32 -0
- package/src/components/items/item-list-table/item-list-table.tsx +76 -0
- package/src/components/items/item-list-table/locales/de.ts +10 -0
- package/src/components/items/item-list-table/locales/en.ts +10 -0
- package/src/components/items/item-list-table/locales/sl.ts +10 -0
- package/src/components/items/items.hooks.ts +63 -0
- package/src/components/loading-spinner.tsx +24 -0
- package/src/components/payments/create-payment-form/create-payment-form.tsx +222 -0
- package/src/components/payments/create-payment-form/locales/de.ts +20 -0
- package/src/components/payments/create-payment-form/locales/sl.ts +20 -0
- package/src/components/payments/edit-payment-form/edit-payment-form.tsx +230 -0
- package/src/components/payments/edit-payment-form/index.ts +1 -0
- package/src/components/payments/edit-payment-form/locales/de.ts +20 -0
- package/src/components/payments/edit-payment-form/locales/sl.ts +20 -0
- package/src/components/payments/index.ts +4 -0
- package/src/components/payments/list/index.ts +2 -0
- package/src/components/payments/list/list-row-actions.tsx +98 -0
- package/src/components/payments/list/list-table.tsx +186 -0
- package/src/components/payments/list/locales/de.ts +19 -0
- package/src/components/payments/list/locales/sl.ts +19 -0
- package/src/components/payments/payments.hooks.ts +15 -0
- package/src/components/request-logs/index.ts +3 -0
- package/src/components/request-logs/request-log-detail.tsx +242 -0
- package/src/components/request-logs/request-log-list-table.tsx +266 -0
- package/src/components/request-logs/request-logs-page.tsx +10 -0
- package/src/components/table/README.md +410 -0
- package/src/components/table/data-table.tsx +251 -0
- package/src/components/table/date-cell.tsx +35 -0
- package/src/components/table/filter-bar.tsx +114 -0
- package/src/components/table/filter-panel.tsx +407 -0
- package/src/components/table/hooks/use-table-fetch.ts +17 -0
- package/src/components/table/hooks/use-table-query.ts +36 -0
- package/src/components/table/hooks/use-table-state.ts +293 -0
- package/src/components/table/index.ts +35 -0
- package/src/components/table/search-input.tsx +85 -0
- package/src/components/table/sortable-header.tsx +56 -0
- package/src/components/table/table-empty-state.tsx +40 -0
- package/src/components/table/table-no-results.tsx +41 -0
- package/src/components/table/table-pagination.tsx +42 -0
- package/src/components/table/table-skeleton.tsx +54 -0
- package/src/components/table/types.ts +136 -0
- package/src/components/tax-reports/index.ts +1 -0
- package/src/components/tax-reports/kir-export-form.tsx +172 -0
- package/src/components/taxes/create-tax-form/create-tax-form.tsx +112 -0
- package/src/components/taxes/create-tax-form/locales/de.ts +8 -0
- package/src/components/taxes/create-tax-form/locales/en.ts +7 -0
- package/src/components/taxes/create-tax-form/locales/sl.ts +8 -0
- package/src/components/taxes/tax-list-table/locales/de.ts +11 -0
- package/src/components/taxes/tax-list-table/locales/en.ts +10 -0
- package/src/components/taxes/tax-list-table/locales/sl.ts +11 -0
- package/src/components/taxes/tax-list-table/tax-list-header.tsx +29 -0
- package/src/components/taxes/tax-list-table/tax-list-row-actions.tsx +43 -0
- package/src/components/taxes/tax-list-table/tax-list-row.tsx +46 -0
- package/src/components/taxes/tax-list-table/tax-list-table.tsx +59 -0
- package/src/components/taxes/taxes.hooks.ts +35 -0
- package/src/components/ui/alert-dialog.tsx +61 -0
- package/src/components/ui/alert.tsx +72 -0
- package/src/components/ui/badge.tsx +48 -0
- package/src/components/ui/breadcrumb.tsx +132 -0
- package/src/components/ui/button.tsx +61 -0
- package/src/components/ui/calendar.tsx +213 -0
- package/src/components/ui/card.tsx +94 -0
- package/src/components/ui/chart.tsx +380 -0
- package/src/components/ui/checkbox.tsx +27 -0
- package/src/components/ui/collapsible.tsx +56 -0
- package/src/components/ui/command.tsx +187 -0
- package/src/components/ui/dialog.tsx +187 -0
- package/src/components/ui/drawer.tsx +123 -0
- package/src/components/ui/dropdown-menu.tsx +291 -0
- package/src/components/ui/form.tsx +166 -0
- package/src/components/ui/input-group.tsx +149 -0
- package/src/components/ui/input.tsx +20 -0
- package/src/components/ui/label.tsx +18 -0
- package/src/components/ui/loading-spinner.tsx +16 -0
- package/src/components/ui/popover.tsx +108 -0
- package/src/components/ui/radio-group.tsx +37 -0
- package/src/components/ui/select.tsx +200 -0
- package/src/components/ui/separator.tsx +23 -0
- package/src/components/ui/sheet.tsx +145 -0
- package/src/components/ui/sidebar.tsx +771 -0
- package/src/components/ui/skeleton.tsx +13 -0
- package/src/components/ui/sonner.tsx +60 -0
- package/src/components/ui/spinner.tsx +10 -0
- package/src/components/ui/sticky-form-footer.tsx +55 -0
- package/src/components/ui/switch.tsx +30 -0
- package/src/components/ui/table.tsx +101 -0
- package/src/components/ui/tabs.tsx +80 -0
- package/src/components/ui/textarea.tsx +18 -0
- package/src/components/ui/tooltip.tsx +89 -0
- package/src/components/wl-subscription/index.ts +2 -0
- package/src/components/wl-subscription/locked-feature.tsx +173 -0
- package/src/components/wl-subscription/upgrade-modal.tsx +209 -0
- package/src/frontend.tsx +28 -0
- package/src/generate-schemas.ts +265 -0
- package/src/generated/schemas/advanceinvoice.ts +177 -0
- package/src/generated/schemas/creditnote.ts +187 -0
- package/src/generated/schemas/customer.ts +29 -0
- package/src/generated/schemas/entity.ts +252 -0
- package/src/generated/schemas/estimate.ts +159 -0
- package/src/generated/schemas/furssettings.ts +25 -0
- package/src/generated/schemas/index.ts +24 -0
- package/src/generated/schemas/invoice.ts +167 -0
- package/src/generated/schemas/item.ts +38 -0
- package/src/generated/schemas/payment.ts +44 -0
- package/src/generated/schemas/previewadvanceinvoice_body.ts +354 -0
- package/src/generated/schemas/previewestimate_body.ts +309 -0
- package/src/generated/schemas/registerfursmovablepremise_body.ts +22 -0
- package/src/generated/schemas/registerfursrealestatepremise_body.ts +32 -0
- package/src/generated/schemas/renderdocument_body.ts +594 -0
- package/src/generated/schemas/sendemail_body.ts +26 -0
- package/src/generated/schemas/startpdfexport_body.ts +20 -0
- package/src/generated/schemas/tax.ts +48 -0
- package/src/generated/schemas/uploadfile_body.ts +23 -0
- package/src/generated/schemas/uploadfurscertificate_body.ts +20 -0
- package/src/generated/schemas/userfurssettings.ts +19 -0
- package/src/hooks/create-resource-hooks.test.ts +483 -0
- package/src/hooks/create-resource-hooks.ts +300 -0
- package/src/hooks/use-debounce.ts +12 -0
- package/src/hooks/use-duplicate-document.ts +185 -0
- package/src/hooks/use-media-query.tsx +19 -0
- package/src/hooks/use-mobile.ts +39 -0
- package/src/hooks/use-next-document-number.ts +57 -0
- package/src/hooks/use-resource-mutation.ts +118 -0
- package/src/hooks/use-vies-check.ts +130 -0
- package/src/index.css +11 -0
- package/src/index.html +13 -0
- package/src/index.tsx +12 -0
- package/src/lib/auth.ts +4 -0
- package/src/lib/browser-cookies.ts +70 -0
- package/src/lib/constants.ts +287 -0
- package/src/lib/cookies.ts +36 -0
- package/src/lib/schemas/advance-invoice.ts +43 -0
- package/src/lib/schemas/credit-note.ts +32 -0
- package/src/lib/schemas/estimate.ts +31 -0
- package/src/lib/schemas/index.ts +18 -0
- package/src/lib/schemas/invoice.ts +43 -0
- package/src/lib/schemas/shared.ts +79 -0
- package/src/lib/translation.ts +38 -0
- package/src/lib/utils.ts +6 -0
- package/src/providers/entities-context.tsx +41 -0
- package/src/providers/entities-provider.tsx +201 -0
- package/src/providers/form-footer-context.tsx +72 -0
- package/src/providers/sdk-provider.tsx +164 -0
- package/src/providers/white-label-provider.tsx +91 -0
- package/src/providers/wl-subscription-provider.tsx +277 -0
- package/src/utils/string-helpers.ts +111 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared document types for invoices, estimates, credit notes, and advance invoices
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export type DocumentTypes = "invoice" | "estimate" | "credit_note" | "advance_invoice";
|
|
6
|
+
|
|
7
|
+
export interface DocumentConfig {
|
|
8
|
+
type: DocumentTypes;
|
|
9
|
+
apiEndpoint: string;
|
|
10
|
+
cacheKey: string;
|
|
11
|
+
dateFieldName: "date_due" | "date_valid_till" | null;
|
|
12
|
+
dateFieldLabel: string | null;
|
|
13
|
+
singularName: string;
|
|
14
|
+
pluralName: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const DOCUMENT_CONFIGS: Record<DocumentTypes, DocumentConfig> = {
|
|
18
|
+
invoice: {
|
|
19
|
+
type: "invoice",
|
|
20
|
+
apiEndpoint: "invoices",
|
|
21
|
+
cacheKey: "invoices",
|
|
22
|
+
dateFieldName: "date_due",
|
|
23
|
+
dateFieldLabel: "Due Date",
|
|
24
|
+
singularName: "Invoice",
|
|
25
|
+
pluralName: "Invoices",
|
|
26
|
+
},
|
|
27
|
+
estimate: {
|
|
28
|
+
type: "estimate",
|
|
29
|
+
apiEndpoint: "estimates",
|
|
30
|
+
cacheKey: "estimates",
|
|
31
|
+
dateFieldName: "date_valid_till",
|
|
32
|
+
dateFieldLabel: "Valid Until",
|
|
33
|
+
singularName: "Estimate",
|
|
34
|
+
pluralName: "Estimates",
|
|
35
|
+
},
|
|
36
|
+
credit_note: {
|
|
37
|
+
type: "credit_note",
|
|
38
|
+
apiEndpoint: "credit-notes",
|
|
39
|
+
cacheKey: "credit-notes",
|
|
40
|
+
dateFieldName: null, // Credit notes don't have a due date
|
|
41
|
+
dateFieldLabel: null,
|
|
42
|
+
singularName: "Credit Note",
|
|
43
|
+
pluralName: "Credit Notes",
|
|
44
|
+
},
|
|
45
|
+
advance_invoice: {
|
|
46
|
+
type: "advance_invoice",
|
|
47
|
+
apiEndpoint: "advance-invoices",
|
|
48
|
+
cacheKey: "advance-invoices",
|
|
49
|
+
dateFieldName: "date_due",
|
|
50
|
+
dateFieldLabel: "Due Date",
|
|
51
|
+
singularName: "Advance Invoice",
|
|
52
|
+
pluralName: "Advance Invoices",
|
|
53
|
+
},
|
|
54
|
+
} as const;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Get document configuration by type
|
|
58
|
+
*/
|
|
59
|
+
export function getDocumentConfig(type: DocumentTypes): DocumentConfig {
|
|
60
|
+
return DOCUMENT_CONFIGS[type];
|
|
61
|
+
}
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
import type { AdvanceInvoice, CreditNote, Estimate, Invoice } from "@spaceinvoices/js-sdk";
|
|
2
|
+
import {
|
|
3
|
+
Check,
|
|
4
|
+
CheckCircle,
|
|
5
|
+
ChevronDown,
|
|
6
|
+
Copy,
|
|
7
|
+
Download,
|
|
8
|
+
FileCode2,
|
|
9
|
+
Link2Off,
|
|
10
|
+
Loader2,
|
|
11
|
+
Mail,
|
|
12
|
+
Pencil,
|
|
13
|
+
Plus,
|
|
14
|
+
Share2,
|
|
15
|
+
Trash2,
|
|
16
|
+
} from "lucide-react";
|
|
17
|
+
import { useState } from "react";
|
|
18
|
+
import { Button } from "@/ui/components/ui/button";
|
|
19
|
+
import {
|
|
20
|
+
DropdownMenu,
|
|
21
|
+
DropdownMenuContent,
|
|
22
|
+
DropdownMenuItem,
|
|
23
|
+
DropdownMenuTrigger,
|
|
24
|
+
} from "@/ui/components/ui/dropdown-menu";
|
|
25
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from "@/ui/components/ui/tooltip";
|
|
26
|
+
import { type DocumentType, getAllowedDuplicateTargets } from "@/ui/hooks/use-duplicate-document";
|
|
27
|
+
import type { ComponentTranslationProps } from "@/ui/lib/translation";
|
|
28
|
+
import { createTranslation } from "@/ui/lib/translation";
|
|
29
|
+
import type { Entity } from "@/ui/providers/entities-context";
|
|
30
|
+
import de from "./locales/de";
|
|
31
|
+
import sl from "./locales/sl";
|
|
32
|
+
import { useDocumentDownload } from "./use-document-download";
|
|
33
|
+
|
|
34
|
+
const translations = { de, sl } as const;
|
|
35
|
+
|
|
36
|
+
type Document = Invoice | Estimate | CreditNote | AdvanceInvoice;
|
|
37
|
+
|
|
38
|
+
const PDF_LOCALES = [
|
|
39
|
+
{ code: "en-US", label: "English" },
|
|
40
|
+
{ code: "de-DE", label: "Deutsch" },
|
|
41
|
+
{ code: "es-ES", label: "Español" },
|
|
42
|
+
{ code: "fr-FR", label: "Français" },
|
|
43
|
+
{ code: "it-IT", label: "Italiano" },
|
|
44
|
+
{ code: "sl-SI", label: "Slovenščina" },
|
|
45
|
+
] as const;
|
|
46
|
+
|
|
47
|
+
interface DocumentActionsBarProps extends ComponentTranslationProps {
|
|
48
|
+
document: Document;
|
|
49
|
+
documentType: DocumentType;
|
|
50
|
+
entity: Entity;
|
|
51
|
+
currentLocale: string;
|
|
52
|
+
onAddPayment?: () => void;
|
|
53
|
+
onSendEmail?: () => void;
|
|
54
|
+
onDownloadStart?: () => void;
|
|
55
|
+
onDownloadSuccess?: (fileName: string) => void;
|
|
56
|
+
onDownloadError?: (error: string) => void;
|
|
57
|
+
onShareLinkCopied?: () => void;
|
|
58
|
+
/** Called when user wants to share the document (generate shareable link) */
|
|
59
|
+
onShare?: () => Promise<void>;
|
|
60
|
+
/** Called when user wants to unshare the document (remove shareable link) */
|
|
61
|
+
onUnshare?: () => Promise<void>;
|
|
62
|
+
/** Whether sharing is in progress */
|
|
63
|
+
isSharing?: boolean;
|
|
64
|
+
/** Whether unsharing is in progress */
|
|
65
|
+
isUnsharing?: boolean;
|
|
66
|
+
/** Called when user wants to duplicate/convert document */
|
|
67
|
+
onDuplicate?: (targetType: DocumentType) => void;
|
|
68
|
+
/** Called when user wants to edit the document */
|
|
69
|
+
onEdit?: () => void;
|
|
70
|
+
/** Whether the document is editable (not voided, not FURS fiscalized) */
|
|
71
|
+
isEditable?: boolean;
|
|
72
|
+
/** Called when user wants to finalize a draft document */
|
|
73
|
+
onFinalize?: () => void;
|
|
74
|
+
/** Whether finalization is in progress */
|
|
75
|
+
isFinalizing?: boolean;
|
|
76
|
+
/** Called when user wants to delete a draft document */
|
|
77
|
+
onDeleteDraft?: () => void;
|
|
78
|
+
/** Whether draft deletion is in progress */
|
|
79
|
+
isDeletingDraft?: boolean;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function getApiLocale(uiLanguage: string): string {
|
|
83
|
+
const localeMap: Record<string, string> = {
|
|
84
|
+
en: "en-US",
|
|
85
|
+
sl: "sl-SI",
|
|
86
|
+
de: "de-DE",
|
|
87
|
+
es: "es-ES",
|
|
88
|
+
fr: "fr-FR",
|
|
89
|
+
it: "it-IT",
|
|
90
|
+
};
|
|
91
|
+
return localeMap[uiLanguage] || "en-US";
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function DocumentActionsBar({
|
|
95
|
+
document,
|
|
96
|
+
documentType,
|
|
97
|
+
entity,
|
|
98
|
+
currentLocale,
|
|
99
|
+
onAddPayment,
|
|
100
|
+
onSendEmail,
|
|
101
|
+
onDownloadStart,
|
|
102
|
+
onDownloadSuccess,
|
|
103
|
+
onDownloadError,
|
|
104
|
+
onShareLinkCopied,
|
|
105
|
+
onShare,
|
|
106
|
+
onUnshare,
|
|
107
|
+
isSharing,
|
|
108
|
+
isUnsharing,
|
|
109
|
+
onDuplicate,
|
|
110
|
+
onEdit,
|
|
111
|
+
isEditable,
|
|
112
|
+
onFinalize,
|
|
113
|
+
isFinalizing,
|
|
114
|
+
onDeleteDraft,
|
|
115
|
+
isDeletingDraft,
|
|
116
|
+
...i18nProps
|
|
117
|
+
}: DocumentActionsBarProps) {
|
|
118
|
+
const t = createTranslation({ translations, locale: currentLocale, ...i18nProps });
|
|
119
|
+
const [linkCopied, setLinkCopied] = useState(false);
|
|
120
|
+
|
|
121
|
+
const { isDownloadingPdf, isDownloadingEslog, downloadPdf, downloadEslog } = useDocumentDownload({
|
|
122
|
+
onDownloadStart,
|
|
123
|
+
onDownloadSuccess,
|
|
124
|
+
onDownloadError,
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
const supportsPayments =
|
|
128
|
+
documentType === "invoice" || documentType === "advance_invoice" || documentType === "credit_note";
|
|
129
|
+
|
|
130
|
+
const eslogFeatureAvailable = entity.country_rules?.features?.includes("eslog") ?? false;
|
|
131
|
+
const eslogValid = (document as Invoice).eslog?.validation_status === "valid";
|
|
132
|
+
const showEslogDownload = eslogFeatureAvailable && eslogValid;
|
|
133
|
+
|
|
134
|
+
const shareableId = (document as Invoice).shareable_id;
|
|
135
|
+
const shareUrl = shareableId ? `${window.location.origin}/public/invoices/${shareableId}` : null;
|
|
136
|
+
|
|
137
|
+
const handleDownloadPdf = (locale: string) => downloadPdf(document, documentType, locale);
|
|
138
|
+
const handleDownloadEslog = () => downloadEslog(document, documentType);
|
|
139
|
+
|
|
140
|
+
const handleCopyShareLink = async () => {
|
|
141
|
+
if (!shareUrl) return;
|
|
142
|
+
try {
|
|
143
|
+
await navigator.clipboard.writeText(shareUrl);
|
|
144
|
+
setLinkCopied(true);
|
|
145
|
+
onShareLinkCopied?.();
|
|
146
|
+
setTimeout(() => setLinkCopied(false), 2000);
|
|
147
|
+
} catch (error) {
|
|
148
|
+
console.error("Failed to copy link:", error);
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
const apiLocale = getApiLocale(currentLocale);
|
|
153
|
+
const isDraft = (document as any).is_draft === true;
|
|
154
|
+
|
|
155
|
+
return (
|
|
156
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
157
|
+
{/* PDF Download */}
|
|
158
|
+
<div className="flex">
|
|
159
|
+
<Button
|
|
160
|
+
variant="outline"
|
|
161
|
+
size="sm"
|
|
162
|
+
disabled={isDownloadingPdf}
|
|
163
|
+
onClick={() => handleDownloadPdf(apiLocale)}
|
|
164
|
+
className="cursor-pointer rounded-r-none"
|
|
165
|
+
>
|
|
166
|
+
{isDownloadingPdf ? <Loader2 className="mr-2 h-4 w-4 animate-spin" /> : <Download className="mr-2 h-4 w-4" />}
|
|
167
|
+
{t("PDF")}
|
|
168
|
+
</Button>
|
|
169
|
+
<DropdownMenu>
|
|
170
|
+
<DropdownMenuTrigger asChild>
|
|
171
|
+
<Button
|
|
172
|
+
variant="outline"
|
|
173
|
+
size="sm"
|
|
174
|
+
disabled={isDownloadingPdf}
|
|
175
|
+
className="cursor-pointer rounded-l-none border-l-0 px-2"
|
|
176
|
+
>
|
|
177
|
+
<ChevronDown className="h-4 w-4" />
|
|
178
|
+
</Button>
|
|
179
|
+
</DropdownMenuTrigger>
|
|
180
|
+
<DropdownMenuContent align="end">
|
|
181
|
+
{PDF_LOCALES.map((locale) => (
|
|
182
|
+
<DropdownMenuItem
|
|
183
|
+
key={locale.code}
|
|
184
|
+
onClick={() => handleDownloadPdf(locale.code)}
|
|
185
|
+
className="cursor-pointer"
|
|
186
|
+
>
|
|
187
|
+
{locale.label}
|
|
188
|
+
</DropdownMenuItem>
|
|
189
|
+
))}
|
|
190
|
+
</DropdownMenuContent>
|
|
191
|
+
</DropdownMenu>
|
|
192
|
+
</div>
|
|
193
|
+
|
|
194
|
+
{/* e-SLOG Download */}
|
|
195
|
+
{showEslogDownload && (
|
|
196
|
+
<Button
|
|
197
|
+
variant="outline"
|
|
198
|
+
size="sm"
|
|
199
|
+
disabled={isDownloadingEslog}
|
|
200
|
+
onClick={handleDownloadEslog}
|
|
201
|
+
className="cursor-pointer"
|
|
202
|
+
>
|
|
203
|
+
{isDownloadingEslog ? (
|
|
204
|
+
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
|
205
|
+
) : (
|
|
206
|
+
<FileCode2 className="mr-2 h-4 w-4" />
|
|
207
|
+
)}
|
|
208
|
+
e-SLOG
|
|
209
|
+
</Button>
|
|
210
|
+
)}
|
|
211
|
+
|
|
212
|
+
{/* Send Email */}
|
|
213
|
+
<Button variant="outline" size="sm" onClick={onSendEmail} className="cursor-pointer">
|
|
214
|
+
<Mail className="mr-2 h-4 w-4" />
|
|
215
|
+
{t("Send")}
|
|
216
|
+
</Button>
|
|
217
|
+
|
|
218
|
+
{/* Add Payment */}
|
|
219
|
+
{supportsPayments && (
|
|
220
|
+
<Button variant="outline" size="sm" onClick={onAddPayment} className="cursor-pointer">
|
|
221
|
+
<Plus className="mr-2 h-4 w-4" />
|
|
222
|
+
{t("Payment")}
|
|
223
|
+
</Button>
|
|
224
|
+
)}
|
|
225
|
+
|
|
226
|
+
{/* Edit */}
|
|
227
|
+
{onEdit && isEditable && (
|
|
228
|
+
<Button variant="outline" size="sm" onClick={onEdit} className="cursor-pointer">
|
|
229
|
+
<Pencil className="mr-2 h-4 w-4" />
|
|
230
|
+
{t("Edit")}
|
|
231
|
+
</Button>
|
|
232
|
+
)}
|
|
233
|
+
|
|
234
|
+
{/* Share Link */}
|
|
235
|
+
{shareUrl ? (
|
|
236
|
+
<div className="flex">
|
|
237
|
+
<Tooltip>
|
|
238
|
+
<TooltipTrigger asChild>
|
|
239
|
+
<Button
|
|
240
|
+
variant="outline"
|
|
241
|
+
size="sm"
|
|
242
|
+
onClick={handleCopyShareLink}
|
|
243
|
+
className="cursor-pointer rounded-r-none"
|
|
244
|
+
>
|
|
245
|
+
{linkCopied ? <Check className="mr-2 h-4 w-4 text-green-600" /> : <Share2 className="mr-2 h-4 w-4" />}
|
|
246
|
+
{linkCopied ? t("Copied") : t("Share")}
|
|
247
|
+
</Button>
|
|
248
|
+
</TooltipTrigger>
|
|
249
|
+
<TooltipContent>
|
|
250
|
+
<p>{t("Copy shareable link")}</p>
|
|
251
|
+
</TooltipContent>
|
|
252
|
+
</Tooltip>
|
|
253
|
+
<DropdownMenu>
|
|
254
|
+
<DropdownMenuTrigger asChild>
|
|
255
|
+
<Button variant="outline" size="sm" className="cursor-pointer rounded-l-none border-l-0 px-2">
|
|
256
|
+
<ChevronDown className="h-4 w-4" />
|
|
257
|
+
</Button>
|
|
258
|
+
</DropdownMenuTrigger>
|
|
259
|
+
<DropdownMenuContent align="end">
|
|
260
|
+
<DropdownMenuItem onClick={handleCopyShareLink} className="cursor-pointer">
|
|
261
|
+
<Share2 className="mr-2 h-4 w-4" />
|
|
262
|
+
{t("Copy shareable link")}
|
|
263
|
+
</DropdownMenuItem>
|
|
264
|
+
<DropdownMenuItem
|
|
265
|
+
onClick={onUnshare}
|
|
266
|
+
disabled={isUnsharing}
|
|
267
|
+
className="hover:!bg-destructive hover:!text-destructive-foreground focus:!bg-destructive focus:!text-destructive-foreground cursor-pointer text-destructive"
|
|
268
|
+
>
|
|
269
|
+
{isUnsharing ? (
|
|
270
|
+
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
|
271
|
+
) : (
|
|
272
|
+
<Link2Off className="mr-2 h-4 w-4" />
|
|
273
|
+
)}
|
|
274
|
+
{t("Unshare")}
|
|
275
|
+
</DropdownMenuItem>
|
|
276
|
+
</DropdownMenuContent>
|
|
277
|
+
</DropdownMenu>
|
|
278
|
+
</div>
|
|
279
|
+
) : onShare ? (
|
|
280
|
+
<Button variant="outline" size="sm" onClick={onShare} disabled={isSharing} className="cursor-pointer">
|
|
281
|
+
{isSharing ? <Loader2 className="mr-2 h-4 w-4 animate-spin" /> : <Share2 className="mr-2 h-4 w-4" />}
|
|
282
|
+
{t("Share")}
|
|
283
|
+
</Button>
|
|
284
|
+
) : null}
|
|
285
|
+
|
|
286
|
+
{/* Duplicate/Convert */}
|
|
287
|
+
{onDuplicate && (
|
|
288
|
+
<DropdownMenu>
|
|
289
|
+
<DropdownMenuTrigger asChild>
|
|
290
|
+
<Button variant="outline" size="sm" className="cursor-pointer">
|
|
291
|
+
<Copy className="mr-2 h-4 w-4" />
|
|
292
|
+
{t("Duplicate")}
|
|
293
|
+
<ChevronDown className="ml-1 h-4 w-4" />
|
|
294
|
+
</Button>
|
|
295
|
+
</DropdownMenuTrigger>
|
|
296
|
+
<DropdownMenuContent align="end">
|
|
297
|
+
{getAllowedDuplicateTargets(documentType).map((targetType) => (
|
|
298
|
+
<DropdownMenuItem key={targetType} onClick={() => onDuplicate(targetType)} className="cursor-pointer">
|
|
299
|
+
{targetType === documentType ? t(`Duplicate ${documentType}`) : t(`Create ${targetType}`)}
|
|
300
|
+
</DropdownMenuItem>
|
|
301
|
+
))}
|
|
302
|
+
</DropdownMenuContent>
|
|
303
|
+
</DropdownMenu>
|
|
304
|
+
)}
|
|
305
|
+
|
|
306
|
+
{/* Draft Actions */}
|
|
307
|
+
{isDraft && onFinalize && (
|
|
308
|
+
<Button variant="default" size="sm" onClick={onFinalize} disabled={isFinalizing} className="cursor-pointer">
|
|
309
|
+
{isFinalizing ? <Loader2 className="mr-2 h-4 w-4 animate-spin" /> : <CheckCircle className="mr-2 h-4 w-4" />}
|
|
310
|
+
{t("Finalize")}
|
|
311
|
+
</Button>
|
|
312
|
+
)}
|
|
313
|
+
|
|
314
|
+
{isDraft && onDeleteDraft && (
|
|
315
|
+
<Button
|
|
316
|
+
variant="destructive"
|
|
317
|
+
size="sm"
|
|
318
|
+
onClick={onDeleteDraft}
|
|
319
|
+
disabled={isDeletingDraft}
|
|
320
|
+
className="cursor-pointer"
|
|
321
|
+
>
|
|
322
|
+
{isDeletingDraft ? <Loader2 className="mr-2 h-4 w-4 animate-spin" /> : <Trash2 className="mr-2 h-4 w-4" />}
|
|
323
|
+
{t("Delete Draft")}
|
|
324
|
+
</Button>
|
|
325
|
+
)}
|
|
326
|
+
</div>
|
|
327
|
+
);
|
|
328
|
+
}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import type { AdvanceInvoice, CreditNote, Estimate, Invoice } from "@spaceinvoices/js-sdk";
|
|
2
|
+
import { Badge } from "@/ui/components/ui/badge";
|
|
3
|
+
import { Card, CardContent, CardHeader, CardTitle } from "@/ui/components/ui/card";
|
|
4
|
+
import { Separator } from "@/ui/components/ui/separator";
|
|
5
|
+
import type { ComponentTranslationProps } from "@/ui/lib/translation";
|
|
6
|
+
import { createTranslation } from "@/ui/lib/translation";
|
|
7
|
+
import de from "./locales/de";
|
|
8
|
+
import sl from "./locales/sl";
|
|
9
|
+
|
|
10
|
+
const translations = { de, sl } as const;
|
|
11
|
+
|
|
12
|
+
// Document type union
|
|
13
|
+
type Document = Invoice | Estimate | CreditNote | AdvanceInvoice;
|
|
14
|
+
type DocumentType = "invoice" | "estimate" | "credit_note" | "advance_invoice";
|
|
15
|
+
|
|
16
|
+
interface DocumentDetailsCardProps extends ComponentTranslationProps {
|
|
17
|
+
document: Document;
|
|
18
|
+
documentType: DocumentType;
|
|
19
|
+
/** Locale for date formatting */
|
|
20
|
+
locale?: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Format currency value
|
|
25
|
+
*/
|
|
26
|
+
function formatCurrency(amount: number, currencyCode: string, locale: string): string {
|
|
27
|
+
return new Intl.NumberFormat(locale, {
|
|
28
|
+
style: "currency",
|
|
29
|
+
currency: currencyCode,
|
|
30
|
+
}).format(amount);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Format date
|
|
35
|
+
*/
|
|
36
|
+
function formatDate(date: Date | string | null | undefined, locale: string): string {
|
|
37
|
+
if (!date) return "-";
|
|
38
|
+
const d = typeof date === "string" ? new Date(date) : date;
|
|
39
|
+
return new Intl.DateTimeFormat(locale, {
|
|
40
|
+
year: "numeric",
|
|
41
|
+
month: "short",
|
|
42
|
+
day: "numeric",
|
|
43
|
+
}).format(d);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Get payment status for invoice/advance invoice
|
|
48
|
+
*/
|
|
49
|
+
function getPaymentStatus(
|
|
50
|
+
document: Invoice | AdvanceInvoice,
|
|
51
|
+
t: (key: string) => string,
|
|
52
|
+
): { label: string; variant: "default" | "secondary" | "destructive" | "outline" } {
|
|
53
|
+
// Check voided_at - ensure it's a valid date, not just truthy
|
|
54
|
+
if (document.voided_at && new Date(document.voided_at).getTime() > 0) {
|
|
55
|
+
return { label: t("Voided"), variant: "secondary" };
|
|
56
|
+
}
|
|
57
|
+
if (document.paid_in_full) {
|
|
58
|
+
return { label: t("Paid in full"), variant: "default" };
|
|
59
|
+
}
|
|
60
|
+
if (document.total_paid > 0) {
|
|
61
|
+
return { label: t("Partially paid"), variant: "outline" };
|
|
62
|
+
}
|
|
63
|
+
return { label: t("Unpaid"), variant: "destructive" };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Document Details Card Component
|
|
68
|
+
*
|
|
69
|
+
* Displays document metadata including:
|
|
70
|
+
* - Document number and dates
|
|
71
|
+
* - Customer information
|
|
72
|
+
* - Totals breakdown
|
|
73
|
+
* - Payment status (for invoices/advance invoices)
|
|
74
|
+
*/
|
|
75
|
+
export function DocumentDetailsCard({ document, documentType, locale = "en", ...i18nProps }: DocumentDetailsCardProps) {
|
|
76
|
+
const t = createTranslation({ translations, locale, ...i18nProps });
|
|
77
|
+
|
|
78
|
+
const currencyCode = document.currency_code;
|
|
79
|
+
const fmt = (amount: number) => formatCurrency(amount, currencyCode, locale);
|
|
80
|
+
const fmtDate = (date: Date | string | null | undefined) => formatDate(date, locale);
|
|
81
|
+
|
|
82
|
+
// Type guards for document-specific fields
|
|
83
|
+
const isInvoiceOrAdvance = documentType === "invoice" || documentType === "advance_invoice";
|
|
84
|
+
const isEstimate = documentType === "estimate";
|
|
85
|
+
const invoiceDoc = document as Invoice | AdvanceInvoice;
|
|
86
|
+
const estimateDoc = document as Estimate;
|
|
87
|
+
|
|
88
|
+
// Get customer name
|
|
89
|
+
const customerName = document.customer?.name || "-";
|
|
90
|
+
|
|
91
|
+
// Calculate tax total
|
|
92
|
+
const taxTotal = document.total_with_tax - document.total;
|
|
93
|
+
|
|
94
|
+
return (
|
|
95
|
+
<Card>
|
|
96
|
+
<CardHeader className="pb-3">
|
|
97
|
+
<CardTitle className="flex items-center justify-between text-lg">
|
|
98
|
+
{t("Details")}
|
|
99
|
+
{isInvoiceOrAdvance && (
|
|
100
|
+
<Badge variant={getPaymentStatus(invoiceDoc, t).variant}>{getPaymentStatus(invoiceDoc, t).label}</Badge>
|
|
101
|
+
)}
|
|
102
|
+
</CardTitle>
|
|
103
|
+
</CardHeader>
|
|
104
|
+
<CardContent className="space-y-4">
|
|
105
|
+
{/* Document info */}
|
|
106
|
+
<div className="grid grid-cols-2 gap-x-4 gap-y-2 text-sm">
|
|
107
|
+
<div className="text-muted-foreground">{t("Number")}</div>
|
|
108
|
+
<div className="font-medium">{document.number}</div>
|
|
109
|
+
|
|
110
|
+
<div className="text-muted-foreground">{t("Date")}</div>
|
|
111
|
+
<div>{fmtDate(document.date)}</div>
|
|
112
|
+
|
|
113
|
+
{isInvoiceOrAdvance && (
|
|
114
|
+
<>
|
|
115
|
+
<div className="text-muted-foreground">{t("Due date")}</div>
|
|
116
|
+
<div>{fmtDate(invoiceDoc.date_due)}</div>
|
|
117
|
+
</>
|
|
118
|
+
)}
|
|
119
|
+
|
|
120
|
+
{isInvoiceOrAdvance && (invoiceDoc as any).date_service && (
|
|
121
|
+
<>
|
|
122
|
+
<div className="text-muted-foreground">
|
|
123
|
+
{(invoiceDoc as any).date_service_to ? t("Service period") : t("Service date")}
|
|
124
|
+
</div>
|
|
125
|
+
<div>
|
|
126
|
+
{(invoiceDoc as any).date_service_to
|
|
127
|
+
? `${fmtDate((invoiceDoc as any).date_service)} - ${fmtDate((invoiceDoc as any).date_service_to)}`
|
|
128
|
+
: fmtDate((invoiceDoc as any).date_service)}
|
|
129
|
+
</div>
|
|
130
|
+
</>
|
|
131
|
+
)}
|
|
132
|
+
|
|
133
|
+
{isEstimate && estimateDoc.date_valid_till && (
|
|
134
|
+
<>
|
|
135
|
+
<div className="text-muted-foreground">{t("Valid until")}</div>
|
|
136
|
+
<div>{fmtDate(estimateDoc.date_valid_till)}</div>
|
|
137
|
+
</>
|
|
138
|
+
)}
|
|
139
|
+
|
|
140
|
+
<div className="text-muted-foreground">{t("Customer")}</div>
|
|
141
|
+
<div>{customerName}</div>
|
|
142
|
+
</div>
|
|
143
|
+
|
|
144
|
+
<Separator />
|
|
145
|
+
|
|
146
|
+
{/* Totals */}
|
|
147
|
+
<div className="space-y-2 text-sm">
|
|
148
|
+
<div className="flex justify-between">
|
|
149
|
+
<span className="text-muted-foreground">{t("Subtotal")}</span>
|
|
150
|
+
<span>{fmt(document.total)}</span>
|
|
151
|
+
</div>
|
|
152
|
+
<div className="flex justify-between">
|
|
153
|
+
<span className="text-muted-foreground">{t("Tax")}</span>
|
|
154
|
+
<span>{fmt(taxTotal)}</span>
|
|
155
|
+
</div>
|
|
156
|
+
<div className="flex justify-between font-semibold">
|
|
157
|
+
<span>{t("Total")}</span>
|
|
158
|
+
<span>{fmt(document.total_with_tax)}</span>
|
|
159
|
+
</div>
|
|
160
|
+
|
|
161
|
+
{/* Payment info for invoices/advance invoices */}
|
|
162
|
+
{isInvoiceOrAdvance && invoiceDoc.total_paid > 0 && (
|
|
163
|
+
<>
|
|
164
|
+
<Separator />
|
|
165
|
+
<div className="flex justify-between text-green-600">
|
|
166
|
+
<span>{t("Paid")}</span>
|
|
167
|
+
<span>-{fmt(invoiceDoc.total_paid)}</span>
|
|
168
|
+
</div>
|
|
169
|
+
<div className="flex justify-between font-semibold">
|
|
170
|
+
<span>{t("Due")}</span>
|
|
171
|
+
<span>{fmt(invoiceDoc.total_due)}</span>
|
|
172
|
+
</div>
|
|
173
|
+
</>
|
|
174
|
+
)}
|
|
175
|
+
</div>
|
|
176
|
+
</CardContent>
|
|
177
|
+
</Card>
|
|
178
|
+
);
|
|
179
|
+
}
|