@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,256 @@
|
|
|
1
|
+
import type { Payment } from "@spaceinvoices/js-sdk";
|
|
2
|
+
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
|
3
|
+
import { MoreHorizontal, Pencil, Plus, Trash2 } from "lucide-react";
|
|
4
|
+
import { useState } from "react";
|
|
5
|
+
import { Button } from "@/ui/components/ui/button";
|
|
6
|
+
import { Card, CardContent, CardHeader, CardTitle } from "@/ui/components/ui/card";
|
|
7
|
+
import {
|
|
8
|
+
Dialog,
|
|
9
|
+
DialogContent,
|
|
10
|
+
DialogDescription,
|
|
11
|
+
DialogFooter,
|
|
12
|
+
DialogHeader,
|
|
13
|
+
DialogTitle,
|
|
14
|
+
} from "@/ui/components/ui/dialog";
|
|
15
|
+
import {
|
|
16
|
+
DropdownMenu,
|
|
17
|
+
DropdownMenuContent,
|
|
18
|
+
DropdownMenuItem,
|
|
19
|
+
DropdownMenuTrigger,
|
|
20
|
+
} from "@/ui/components/ui/dropdown-menu";
|
|
21
|
+
import { Skeleton } from "@/ui/components/ui/skeleton";
|
|
22
|
+
import type { ComponentTranslationProps } from "@/ui/lib/translation";
|
|
23
|
+
import { createTranslation } from "@/ui/lib/translation";
|
|
24
|
+
import { useSDK } from "@/ui/providers/sdk-provider";
|
|
25
|
+
import de from "./locales/de";
|
|
26
|
+
import sl from "./locales/sl";
|
|
27
|
+
|
|
28
|
+
const translations = { de, sl } as const;
|
|
29
|
+
|
|
30
|
+
type DocumentType = "invoice" | "credit_note" | "advance_invoice";
|
|
31
|
+
|
|
32
|
+
interface DocumentPaymentsListProps extends ComponentTranslationProps {
|
|
33
|
+
documentId: string;
|
|
34
|
+
documentType: DocumentType;
|
|
35
|
+
entityId: string;
|
|
36
|
+
currencyCode: string;
|
|
37
|
+
/** Locale for formatting */
|
|
38
|
+
locale?: string;
|
|
39
|
+
/** Callback when Add Payment is clicked */
|
|
40
|
+
onAddPayment?: () => void;
|
|
41
|
+
/** Callback when Edit Payment is clicked */
|
|
42
|
+
onEditPayment?: (payment: Payment) => void;
|
|
43
|
+
/** Callback on successful delete */
|
|
44
|
+
onDeleteSuccess?: () => void;
|
|
45
|
+
/** Callback on delete error */
|
|
46
|
+
onDeleteError?: (error: string) => void;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Format currency value
|
|
51
|
+
*/
|
|
52
|
+
function formatCurrency(amount: number, currencyCode: string, locale: string): string {
|
|
53
|
+
return new Intl.NumberFormat(locale, {
|
|
54
|
+
style: "currency",
|
|
55
|
+
currency: currencyCode,
|
|
56
|
+
}).format(amount);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Format date
|
|
61
|
+
*/
|
|
62
|
+
function formatDate(date: Date | string | null, locale: string): string {
|
|
63
|
+
if (!date) return "-";
|
|
64
|
+
const d = typeof date === "string" ? new Date(date) : date;
|
|
65
|
+
return new Intl.DateTimeFormat(locale, {
|
|
66
|
+
month: "short",
|
|
67
|
+
day: "numeric",
|
|
68
|
+
}).format(d);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Document Payments List Component
|
|
73
|
+
*
|
|
74
|
+
* Displays a list of payments for a document with CRUD actions:
|
|
75
|
+
* - View payments with date, amount, type
|
|
76
|
+
* - Add new payment
|
|
77
|
+
* - Edit existing payment
|
|
78
|
+
* - Delete payment with confirmation
|
|
79
|
+
*/
|
|
80
|
+
export function DocumentPaymentsList({
|
|
81
|
+
documentId,
|
|
82
|
+
documentType,
|
|
83
|
+
entityId,
|
|
84
|
+
currencyCode,
|
|
85
|
+
locale = "en",
|
|
86
|
+
onAddPayment,
|
|
87
|
+
onEditPayment,
|
|
88
|
+
onDeleteSuccess,
|
|
89
|
+
onDeleteError,
|
|
90
|
+
...i18nProps
|
|
91
|
+
}: DocumentPaymentsListProps) {
|
|
92
|
+
const t = createTranslation({ translations, locale, ...i18nProps });
|
|
93
|
+
const { sdk } = useSDK();
|
|
94
|
+
const queryClient = useQueryClient();
|
|
95
|
+
|
|
96
|
+
const [paymentToDelete, setPaymentToDelete] = useState<Payment | null>(null);
|
|
97
|
+
const [isDeleting, setIsDeleting] = useState(false);
|
|
98
|
+
|
|
99
|
+
// Build the filter based on document type
|
|
100
|
+
const getFilter = () => {
|
|
101
|
+
if (documentType === "invoice") {
|
|
102
|
+
return { invoice_id: documentId };
|
|
103
|
+
}
|
|
104
|
+
if (documentType === "advance_invoice") {
|
|
105
|
+
return { advance_invoice_id: documentId };
|
|
106
|
+
}
|
|
107
|
+
if (documentType === "credit_note") {
|
|
108
|
+
return { credit_note_id: documentId };
|
|
109
|
+
}
|
|
110
|
+
return {};
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
// Fetch payments for this document
|
|
114
|
+
// SDK list methods return { data: Payment[], pagination: ... }
|
|
115
|
+
const { data: paymentsData, isLoading } = useQuery({
|
|
116
|
+
queryKey: ["payments", documentType, documentId, entityId],
|
|
117
|
+
queryFn: async () => {
|
|
118
|
+
if (!sdk) throw new Error("SDK not initialized");
|
|
119
|
+
|
|
120
|
+
const response = await sdk.payments.list({
|
|
121
|
+
entity_id: entityId,
|
|
122
|
+
query: JSON.stringify(getFilter()),
|
|
123
|
+
order_by: "-date",
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
return response.data;
|
|
127
|
+
},
|
|
128
|
+
enabled: !!sdk && !!entityId && !!documentId,
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
const payments = paymentsData || [];
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Handle payment deletion
|
|
135
|
+
*/
|
|
136
|
+
const handleDelete = async () => {
|
|
137
|
+
if (!paymentToDelete || !sdk) return;
|
|
138
|
+
|
|
139
|
+
setIsDeleting(true);
|
|
140
|
+
try {
|
|
141
|
+
await sdk.payments.delete(paymentToDelete.id, { entity_id: entityId });
|
|
142
|
+
|
|
143
|
+
// Invalidate queries to refresh data
|
|
144
|
+
queryClient.invalidateQueries({ queryKey: ["payments"] });
|
|
145
|
+
queryClient.invalidateQueries({ queryKey: ["documents"] });
|
|
146
|
+
|
|
147
|
+
onDeleteSuccess?.();
|
|
148
|
+
} catch (error) {
|
|
149
|
+
console.error("Failed to delete payment:", error);
|
|
150
|
+
onDeleteError?.(t("Delete failed"));
|
|
151
|
+
} finally {
|
|
152
|
+
setIsDeleting(false);
|
|
153
|
+
setPaymentToDelete(null);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Get payment type label
|
|
159
|
+
*/
|
|
160
|
+
const getTypeLabel = (type: string): string => {
|
|
161
|
+
const labels: Record<string, string> = {
|
|
162
|
+
cash: t("cash"),
|
|
163
|
+
bank_transfer: t("bank_transfer"),
|
|
164
|
+
card: t("card"),
|
|
165
|
+
check: t("check"),
|
|
166
|
+
credit_note: t("credit_note"),
|
|
167
|
+
other: t("other"),
|
|
168
|
+
advance: t("advance_invoice"),
|
|
169
|
+
};
|
|
170
|
+
return labels[type] || type;
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
const fmt = (amount: number) => formatCurrency(amount, currencyCode, locale);
|
|
174
|
+
const fmtDate = (date: Date | string | null) => formatDate(date, locale);
|
|
175
|
+
|
|
176
|
+
return (
|
|
177
|
+
<>
|
|
178
|
+
<Card>
|
|
179
|
+
<CardHeader className="flex flex-row items-center justify-between pb-3">
|
|
180
|
+
<CardTitle className="text-lg">
|
|
181
|
+
{t("Payments")} {payments.length > 0 && `(${payments.length})`}
|
|
182
|
+
</CardTitle>
|
|
183
|
+
<Button variant="outline" size="sm" onClick={onAddPayment} className="cursor-pointer">
|
|
184
|
+
<Plus className="mr-1 h-4 w-4" />
|
|
185
|
+
{t("Add payment")}
|
|
186
|
+
</Button>
|
|
187
|
+
</CardHeader>
|
|
188
|
+
<CardContent>
|
|
189
|
+
{isLoading ? (
|
|
190
|
+
<div className="space-y-2">
|
|
191
|
+
<Skeleton className="h-10 w-full" />
|
|
192
|
+
<Skeleton className="h-10 w-full" />
|
|
193
|
+
</div>
|
|
194
|
+
) : payments.length === 0 ? (
|
|
195
|
+
<p className="py-4 text-center text-muted-foreground text-sm">{t("No payments")}</p>
|
|
196
|
+
) : (
|
|
197
|
+
<div className="space-y-2">
|
|
198
|
+
{payments.map((payment) => (
|
|
199
|
+
<div key={payment.id} className="flex items-center justify-between rounded-md border p-3">
|
|
200
|
+
<div className="flex items-center gap-4">
|
|
201
|
+
<span className="text-muted-foreground text-sm">{fmtDate(payment.date)}</span>
|
|
202
|
+
<span className="font-medium">{fmt(payment.amount)}</span>
|
|
203
|
+
<span className="text-muted-foreground text-sm">{getTypeLabel(payment.type)}</span>
|
|
204
|
+
</div>
|
|
205
|
+
<DropdownMenu>
|
|
206
|
+
<DropdownMenuTrigger asChild>
|
|
207
|
+
<Button variant="ghost" size="sm" className="h-8 w-8 cursor-pointer p-0">
|
|
208
|
+
<MoreHorizontal className="h-4 w-4" />
|
|
209
|
+
</Button>
|
|
210
|
+
</DropdownMenuTrigger>
|
|
211
|
+
<DropdownMenuContent align="end">
|
|
212
|
+
<DropdownMenuItem onClick={() => onEditPayment?.(payment)} className="cursor-pointer">
|
|
213
|
+
<Pencil className="mr-2 h-4 w-4" />
|
|
214
|
+
{t("Edit")}
|
|
215
|
+
</DropdownMenuItem>
|
|
216
|
+
<DropdownMenuItem
|
|
217
|
+
onClick={() => setPaymentToDelete(payment)}
|
|
218
|
+
className="cursor-pointer text-destructive focus:text-destructive"
|
|
219
|
+
>
|
|
220
|
+
<Trash2 className="mr-2 h-4 w-4" />
|
|
221
|
+
{t("Delete")}
|
|
222
|
+
</DropdownMenuItem>
|
|
223
|
+
</DropdownMenuContent>
|
|
224
|
+
</DropdownMenu>
|
|
225
|
+
</div>
|
|
226
|
+
))}
|
|
227
|
+
</div>
|
|
228
|
+
)}
|
|
229
|
+
</CardContent>
|
|
230
|
+
</Card>
|
|
231
|
+
|
|
232
|
+
{/* Delete Confirmation Dialog */}
|
|
233
|
+
<Dialog open={!!paymentToDelete} onOpenChange={() => setPaymentToDelete(null)}>
|
|
234
|
+
<DialogContent>
|
|
235
|
+
<DialogHeader>
|
|
236
|
+
<DialogTitle>{t("Delete payment")}</DialogTitle>
|
|
237
|
+
<DialogDescription>{t("Delete payment confirmation")}</DialogDescription>
|
|
238
|
+
</DialogHeader>
|
|
239
|
+
<DialogFooter>
|
|
240
|
+
<Button
|
|
241
|
+
variant="outline"
|
|
242
|
+
disabled={isDeleting}
|
|
243
|
+
onClick={() => setPaymentToDelete(null)}
|
|
244
|
+
className="cursor-pointer"
|
|
245
|
+
>
|
|
246
|
+
{t("Cancel")}
|
|
247
|
+
</Button>
|
|
248
|
+
<Button variant="destructive" onClick={handleDelete} disabled={isDeleting} className="cursor-pointer">
|
|
249
|
+
{t("Delete")}
|
|
250
|
+
</Button>
|
|
251
|
+
</DialogFooter>
|
|
252
|
+
</DialogContent>
|
|
253
|
+
</Dialog>
|
|
254
|
+
</>
|
|
255
|
+
);
|
|
256
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
// Actions
|
|
3
|
+
PDF: "PDF",
|
|
4
|
+
Send: "Senden",
|
|
5
|
+
Payment: "Zahlung",
|
|
6
|
+
Share: "Teilen",
|
|
7
|
+
Unshare: "Freigabe aufheben",
|
|
8
|
+
Copied: "Kopiert",
|
|
9
|
+
"Copy shareable link": "Freigabelink kopieren",
|
|
10
|
+
"Unshare document": "Dokumentfreigabe aufheben",
|
|
11
|
+
"Unshare document confirmation":
|
|
12
|
+
"Sind Sie sicher, dass Sie den öffentlichen Zugang zu diesem Dokument entfernen möchten?",
|
|
13
|
+
"Document unshared": "Dokument ist nicht mehr freigegeben",
|
|
14
|
+
"Unshare failed": "Freigabe aufheben fehlgeschlagen",
|
|
15
|
+
"Download failed": "Download fehlgeschlagen",
|
|
16
|
+
"e-SLOG download failed": "e-SLOG Download fehlgeschlagen",
|
|
17
|
+
Duplicate: "Duplizieren",
|
|
18
|
+
"Duplicate invoice": "Rechnung duplizieren",
|
|
19
|
+
"Duplicate estimate": "Angebot duplizieren",
|
|
20
|
+
"Duplicate credit_note": "Gutschrift duplizieren",
|
|
21
|
+
"Duplicate advance_invoice": "Anzahlungsrechnung duplizieren",
|
|
22
|
+
"Create invoice": "Rechnung erstellen",
|
|
23
|
+
"Create estimate": "Angebot erstellen",
|
|
24
|
+
"Create credit_note": "Gutschrift erstellen",
|
|
25
|
+
"Create advance_invoice": "Anzahlungsrechnung erstellen",
|
|
26
|
+
|
|
27
|
+
// Details card
|
|
28
|
+
Details: "Details",
|
|
29
|
+
Number: "Nummer",
|
|
30
|
+
Date: "Datum",
|
|
31
|
+
"Due date": "Fälligkeitsdatum",
|
|
32
|
+
"Service date": "Leistungsdatum",
|
|
33
|
+
"Service period": "Leistungszeitraum",
|
|
34
|
+
"Valid until": "Gültig bis",
|
|
35
|
+
Customer: "Kunde",
|
|
36
|
+
Subtotal: "Zwischensumme",
|
|
37
|
+
Tax: "Steuer",
|
|
38
|
+
Total: "Gesamt",
|
|
39
|
+
Paid: "Bezahlt",
|
|
40
|
+
Due: "Offen",
|
|
41
|
+
Status: "Status",
|
|
42
|
+
|
|
43
|
+
// Payment status
|
|
44
|
+
"Paid in full": "Vollständig bezahlt",
|
|
45
|
+
"Partially paid": "Teilweise bezahlt",
|
|
46
|
+
Unpaid: "Unbezahlt",
|
|
47
|
+
Voided: "Storniert",
|
|
48
|
+
|
|
49
|
+
// Payments list
|
|
50
|
+
Payments: "Zahlungen",
|
|
51
|
+
"No payments": "Keine Zahlungen",
|
|
52
|
+
"Add payment": "Zahlung hinzufügen",
|
|
53
|
+
Edit: "Bearbeiten",
|
|
54
|
+
Delete: "Löschen",
|
|
55
|
+
"Delete payment": "Zahlung löschen",
|
|
56
|
+
"Delete payment confirmation": "Sind Sie sicher, dass Sie diese Zahlung löschen möchten?",
|
|
57
|
+
Cancel: "Abbrechen",
|
|
58
|
+
|
|
59
|
+
// Payment types
|
|
60
|
+
cash: "Bargeld",
|
|
61
|
+
bank_transfer: "Banküberweisung",
|
|
62
|
+
card: "Karte",
|
|
63
|
+
check: "Scheck",
|
|
64
|
+
credit_note: "Gutschrift",
|
|
65
|
+
other: "Andere",
|
|
66
|
+
advance_invoice: "Anzahlungsrechnung",
|
|
67
|
+
|
|
68
|
+
// Errors
|
|
69
|
+
"Delete failed": "Löschen fehlgeschlagen",
|
|
70
|
+
|
|
71
|
+
// Draft actions
|
|
72
|
+
Finalize: "Fertigstellen",
|
|
73
|
+
"Delete Draft": "Entwurf löschen",
|
|
74
|
+
"Finalize document": "Dokument fertigstellen",
|
|
75
|
+
"Finalize document confirmation":
|
|
76
|
+
"Dadurch wird dem Dokument eine endgültige Nummer zugewiesen. Nach der Fertigstellung kann das Dokument nicht mehr gelöscht werden. Möchten Sie fortfahren?",
|
|
77
|
+
"Delete draft document": "Entwurfsdokument löschen",
|
|
78
|
+
"Delete draft confirmation":
|
|
79
|
+
"Sind Sie sicher, dass Sie diesen Entwurf löschen möchten? Diese Aktion kann nicht rückgängig gemacht werden.",
|
|
80
|
+
"Document finalized": "Dokument wurde fertiggestellt",
|
|
81
|
+
"Finalize failed": "Fertigstellung fehlgeschlagen",
|
|
82
|
+
"Draft deleted": "Entwurf wurde gelöscht",
|
|
83
|
+
"Delete draft failed": "Entwurf löschen fehlgeschlagen",
|
|
84
|
+
Draft: "Entwurf",
|
|
85
|
+
} as const;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
// Actions
|
|
3
|
+
PDF: "PDF",
|
|
4
|
+
Send: "Pošlji",
|
|
5
|
+
Payment: "Plačilo",
|
|
6
|
+
Share: "Deli",
|
|
7
|
+
Unshare: "Odstrani deljenje",
|
|
8
|
+
Copied: "Kopirano",
|
|
9
|
+
"Copy shareable link": "Kopiraj povezavo za deljenje",
|
|
10
|
+
"Unshare document": "Odstrani deljenje dokumenta",
|
|
11
|
+
"Unshare document confirmation": "Ali ste prepričani, da želite odstraniti javni dostop do tega dokumenta?",
|
|
12
|
+
"Document unshared": "Dokument ni več deljen",
|
|
13
|
+
"Unshare failed": "Odstranitev deljenja ni uspela",
|
|
14
|
+
"Download failed": "Prenos ni uspel",
|
|
15
|
+
"e-SLOG download failed": "Prenos e-SLOG ni uspel",
|
|
16
|
+
Duplicate: "Podvoji",
|
|
17
|
+
"Duplicate invoice": "Podvoji račun",
|
|
18
|
+
"Duplicate estimate": "Podvoji predračun",
|
|
19
|
+
"Duplicate credit_note": "Podvoji dobropis",
|
|
20
|
+
"Duplicate advance_invoice": "Podvoji avansni račun",
|
|
21
|
+
"Create invoice": "Ustvari račun",
|
|
22
|
+
"Create estimate": "Ustvari predračun",
|
|
23
|
+
"Create credit_note": "Ustvari dobropis",
|
|
24
|
+
"Create advance_invoice": "Ustvari avansni račun",
|
|
25
|
+
|
|
26
|
+
// Details card
|
|
27
|
+
Details: "Podrobnosti",
|
|
28
|
+
Number: "Številka",
|
|
29
|
+
Date: "Datum",
|
|
30
|
+
"Due date": "Datum zapadlosti",
|
|
31
|
+
"Service date": "Datum storitve",
|
|
32
|
+
"Service period": "Obdobje storitve",
|
|
33
|
+
"Valid until": "Veljavno do",
|
|
34
|
+
Customer: "Stranka",
|
|
35
|
+
Subtotal: "Vmesni seštevek",
|
|
36
|
+
Tax: "Davek",
|
|
37
|
+
Total: "Skupaj",
|
|
38
|
+
Paid: "Plačano",
|
|
39
|
+
Due: "Za plačilo",
|
|
40
|
+
Status: "Status",
|
|
41
|
+
|
|
42
|
+
// Payment status
|
|
43
|
+
"Paid in full": "Plačano v celoti",
|
|
44
|
+
"Partially paid": "Delno plačano",
|
|
45
|
+
Unpaid: "Neplačano",
|
|
46
|
+
Voided: "Stornirano",
|
|
47
|
+
|
|
48
|
+
// Payments list
|
|
49
|
+
Payments: "Plačila",
|
|
50
|
+
"No payments": "Ni plačil",
|
|
51
|
+
"Add payment": "Dodaj plačilo",
|
|
52
|
+
Edit: "Uredi",
|
|
53
|
+
Delete: "Izbriši",
|
|
54
|
+
"Delete payment": "Izbriši plačilo",
|
|
55
|
+
"Delete payment confirmation": "Ali ste prepričani, da želite izbrisati to plačilo?",
|
|
56
|
+
Cancel: "Prekliči",
|
|
57
|
+
|
|
58
|
+
// Payment types
|
|
59
|
+
cash: "Gotovina",
|
|
60
|
+
bank_transfer: "Bančno nakazilo",
|
|
61
|
+
card: "Kartica",
|
|
62
|
+
check: "Ček",
|
|
63
|
+
credit_note: "Dobropis",
|
|
64
|
+
other: "Drugo",
|
|
65
|
+
advance_invoice: "Avansni račun",
|
|
66
|
+
|
|
67
|
+
// Errors
|
|
68
|
+
"Delete failed": "Brisanje ni uspelo",
|
|
69
|
+
|
|
70
|
+
// Draft actions
|
|
71
|
+
Finalize: "Potrdi",
|
|
72
|
+
"Delete Draft": "Izbriši osnutek",
|
|
73
|
+
"Finalize document": "Potrdi dokument",
|
|
74
|
+
"Finalize document confirmation":
|
|
75
|
+
"S tem boste dokumentu dodelili končno številko. Po potrditvi dokumenta ni več mogoče izbrisati. Ali želite nadaljevati?",
|
|
76
|
+
"Delete draft document": "Izbriši osnutek dokumenta",
|
|
77
|
+
"Delete draft confirmation":
|
|
78
|
+
"Ali ste prepričani, da želite izbrisati ta osnutek? Tega dejanja ni mogoče razveljaviti.",
|
|
79
|
+
"Document finalized": "Dokument je bil potrjen",
|
|
80
|
+
"Finalize failed": "Potrditev ni uspela",
|
|
81
|
+
"Draft deleted": "Osnutek je bil izbrisan",
|
|
82
|
+
"Delete draft failed": "Brisanje osnutka ni uspelo",
|
|
83
|
+
Draft: "Osnutek",
|
|
84
|
+
} as const;
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import type { AdvanceInvoice, CreditNote, Estimate, Invoice } from "@spaceinvoices/js-sdk";
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import { useEntities } from "@/ui/providers/entities-context";
|
|
4
|
+
import { useSDK } from "@/ui/providers/sdk-provider";
|
|
5
|
+
|
|
6
|
+
type Document = Invoice | Estimate | CreditNote | AdvanceInvoice;
|
|
7
|
+
type DocumentType = "invoice" | "estimate" | "credit_note" | "advance_invoice";
|
|
8
|
+
|
|
9
|
+
// Document type labels for PDF filename
|
|
10
|
+
const TYPE_LABELS: Record<string, string> = {
|
|
11
|
+
invoice: "Invoice",
|
|
12
|
+
estimate: "Estimate",
|
|
13
|
+
credit_note: "Credit Note",
|
|
14
|
+
advance_invoice: "Advance Invoice",
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
interface UseDocumentDownloadOptions {
|
|
18
|
+
onDownloadStart?: () => void;
|
|
19
|
+
onDownloadSuccess?: (fileName: string) => void;
|
|
20
|
+
onDownloadError?: (error: string) => void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Hook for downloading document PDFs and e-SLOG XML
|
|
25
|
+
*/
|
|
26
|
+
export function useDocumentDownload({
|
|
27
|
+
onDownloadStart,
|
|
28
|
+
onDownloadSuccess,
|
|
29
|
+
onDownloadError,
|
|
30
|
+
}: UseDocumentDownloadOptions = {}) {
|
|
31
|
+
const { sdk } = useSDK();
|
|
32
|
+
const { activeEntity } = useEntities();
|
|
33
|
+
|
|
34
|
+
const [isDownloadingPdf, setIsDownloadingPdf] = useState(false);
|
|
35
|
+
const [isDownloadingEslog, setIsDownloadingEslog] = useState(false);
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Download PDF in specified locale
|
|
39
|
+
*/
|
|
40
|
+
const downloadPdf = async (document: Document, documentType: DocumentType, _locale: string) => {
|
|
41
|
+
if (!sdk || !activeEntity?.id) {
|
|
42
|
+
onDownloadError?.("Download failed");
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
setIsDownloadingPdf(true);
|
|
47
|
+
onDownloadStart?.();
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
// SDK signature: renderPdf(id, params?, SDKMethodOptions?)
|
|
51
|
+
// entity_id goes in SDKMethodOptions (last arg), not params
|
|
52
|
+
// Note: renderPdf is on invoices module but works with any document ID via /documents/{id}/pdf
|
|
53
|
+
const blob = await sdk.invoices.renderPdf(document.id, {}, { entity_id: activeEntity.id });
|
|
54
|
+
const downloadUrl = window.URL.createObjectURL(blob);
|
|
55
|
+
const link = window.document.createElement("a");
|
|
56
|
+
link.href = downloadUrl;
|
|
57
|
+
|
|
58
|
+
const typeLabel = TYPE_LABELS[documentType] || "Document";
|
|
59
|
+
const fileName = `${typeLabel} ${document.number}.pdf`;
|
|
60
|
+
link.download = fileName;
|
|
61
|
+
|
|
62
|
+
window.document.body.appendChild(link);
|
|
63
|
+
link.click();
|
|
64
|
+
window.document.body.removeChild(link);
|
|
65
|
+
window.URL.revokeObjectURL(downloadUrl);
|
|
66
|
+
|
|
67
|
+
onDownloadSuccess?.(fileName);
|
|
68
|
+
} catch (error) {
|
|
69
|
+
console.error("Error downloading PDF:", error);
|
|
70
|
+
onDownloadError?.("Download failed");
|
|
71
|
+
} finally {
|
|
72
|
+
setIsDownloadingPdf(false);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Download e-SLOG XML
|
|
78
|
+
*/
|
|
79
|
+
const downloadEslog = async (document: Document, documentType: DocumentType) => {
|
|
80
|
+
if (!sdk || !activeEntity?.id) {
|
|
81
|
+
onDownloadError?.("Download failed");
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
setIsDownloadingEslog(true);
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
const typeMap: Record<DocumentType, string> = {
|
|
89
|
+
invoice: "invoice",
|
|
90
|
+
advance_invoice: "advance_invoice",
|
|
91
|
+
credit_note: "credit_note",
|
|
92
|
+
estimate: "estimate",
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
// e-SLOG download - cast to any since the SDK structure may vary
|
|
96
|
+
const eSlogModule = (sdk as any).eSlog;
|
|
97
|
+
if (!eSlogModule?.download) {
|
|
98
|
+
throw new Error("e-SLOG download not available");
|
|
99
|
+
}
|
|
100
|
+
const xml = await eSlogModule.download(document.id, typeMap[documentType], { entity_id: activeEntity.id });
|
|
101
|
+
|
|
102
|
+
const blob = new Blob([xml], { type: "application/xml" });
|
|
103
|
+
const url = window.URL.createObjectURL(blob);
|
|
104
|
+
const a = window.document.createElement("a");
|
|
105
|
+
a.href = url;
|
|
106
|
+
a.download = `${document.number}.xml`;
|
|
107
|
+
window.document.body.appendChild(a);
|
|
108
|
+
a.click();
|
|
109
|
+
window.URL.revokeObjectURL(url);
|
|
110
|
+
window.document.body.removeChild(a);
|
|
111
|
+
} catch (error) {
|
|
112
|
+
console.error("Error downloading e-SLOG:", error);
|
|
113
|
+
onDownloadError?.("e-SLOG download failed");
|
|
114
|
+
} finally {
|
|
115
|
+
setIsDownloadingEslog(false);
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
isDownloadingPdf,
|
|
121
|
+
isDownloadingEslog,
|
|
122
|
+
downloadPdf,
|
|
123
|
+
downloadEslog,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { zodResolver } from "@hookform/resolvers/zod";
|
|
2
|
+
import type { CreateEntityRequest, Entity } from "@spaceinvoices/js-sdk";
|
|
3
|
+
import type { Resolver } from "react-hook-form";
|
|
4
|
+
import { useForm } from "react-hook-form";
|
|
5
|
+
import { FormInput } from "@/ui/components/form";
|
|
6
|
+
import { Button } from "@/ui/components/ui/button";
|
|
7
|
+
import { Form } from "@/ui/components/ui/form";
|
|
8
|
+
import { type CreateEntitySchema, createEntitySchema } from "@/ui/generated/schemas";
|
|
9
|
+
|
|
10
|
+
import ButtonLoader from "../button-loader";
|
|
11
|
+
import { useCreateEntity } from "./entities.hooks";
|
|
12
|
+
|
|
13
|
+
export type CreateEntityFormProps = {
|
|
14
|
+
t?: (key: string) => string;
|
|
15
|
+
namespace?: string;
|
|
16
|
+
accountId?: string;
|
|
17
|
+
environment?: string;
|
|
18
|
+
onSuccess?: (data: Entity) => void;
|
|
19
|
+
onError?: (error: unknown) => void;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const defaultTranslate = (text: string) => text;
|
|
23
|
+
|
|
24
|
+
export function CreateEntityForm({
|
|
25
|
+
t = defaultTranslate,
|
|
26
|
+
namespace = "",
|
|
27
|
+
accountId,
|
|
28
|
+
environment,
|
|
29
|
+
onSuccess,
|
|
30
|
+
onError,
|
|
31
|
+
}: CreateEntityFormProps) {
|
|
32
|
+
const translate = (key: string) => t(namespace ? `${namespace}.${key}` : key);
|
|
33
|
+
|
|
34
|
+
const form = useForm<CreateEntitySchema>({
|
|
35
|
+
resolver: zodResolver(createEntitySchema) as Resolver<CreateEntitySchema>,
|
|
36
|
+
defaultValues: {
|
|
37
|
+
name: "",
|
|
38
|
+
address: "",
|
|
39
|
+
address_2: "",
|
|
40
|
+
post_code: "",
|
|
41
|
+
city: "",
|
|
42
|
+
state: "",
|
|
43
|
+
country: "",
|
|
44
|
+
tax_number: "",
|
|
45
|
+
environment,
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// Wrap onSuccess to reset form only after successful mutation
|
|
50
|
+
const handleSuccess = (data: Entity) => {
|
|
51
|
+
form.reset();
|
|
52
|
+
onSuccess?.(data);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// Use the createEntity mutation hook
|
|
56
|
+
const { mutate: createEntity, isPending } = useCreateEntity({
|
|
57
|
+
entityId: null,
|
|
58
|
+
accountId,
|
|
59
|
+
onSuccess: handleSuccess,
|
|
60
|
+
onError: (error, _variables, _context) => {
|
|
61
|
+
onError?.(error);
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
const onSubmit = async (values: CreateEntitySchema) => {
|
|
66
|
+
try {
|
|
67
|
+
// Zod validation ensures required fields are present before this is called
|
|
68
|
+
// The type cast is safe because React Hook Form's DeepPartial doesn't reflect runtime validation
|
|
69
|
+
createEntity(values as CreateEntityRequest);
|
|
70
|
+
} catch (e) {
|
|
71
|
+
onError?.(e);
|
|
72
|
+
form.setError("root", {
|
|
73
|
+
type: "submit",
|
|
74
|
+
message: "Failed to create entity",
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
return (
|
|
80
|
+
<Form {...form}>
|
|
81
|
+
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
|
|
82
|
+
<FormInput control={form.control} name="name" label={translate("Name")} placeholder="Name" required />
|
|
83
|
+
|
|
84
|
+
<FormInput control={form.control} name="country" label="Country" placeholder="Country" required />
|
|
85
|
+
|
|
86
|
+
<FormInput control={form.control} name="address" label="Address" placeholder="Address" />
|
|
87
|
+
|
|
88
|
+
<FormInput control={form.control} name="address_2" label="Address 2" placeholder="Address 2" />
|
|
89
|
+
|
|
90
|
+
<div className="grid grid-cols-2 gap-4">
|
|
91
|
+
<FormInput control={form.control} name="post_code" label="Post code" placeholder="Post code" />
|
|
92
|
+
<FormInput control={form.control} name="city" label="City" placeholder="City" />
|
|
93
|
+
</div>
|
|
94
|
+
|
|
95
|
+
<FormInput control={form.control} name="state" label="State" placeholder="State" />
|
|
96
|
+
|
|
97
|
+
<FormInput control={form.control} name="tax_number" label="Tax number" placeholder="Tax number" />
|
|
98
|
+
|
|
99
|
+
<Button type="submit" className="w-full cursor-pointer" disabled={isPending} aria-busy={isPending}>
|
|
100
|
+
{isPending ? <ButtonLoader /> : "Create"}
|
|
101
|
+
</Button>
|
|
102
|
+
</form>
|
|
103
|
+
</Form>
|
|
104
|
+
);
|
|
105
|
+
}
|