@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,18 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
"Send Invoice by Email": "Rechnung per E-Mail senden",
|
|
3
|
+
"Send invoice by email description":
|
|
4
|
+
"Senden Sie Rechnung #{number} per E-Mail an einen Kunden. Markdown-Formatierung wird im Text unterstützt.",
|
|
5
|
+
"Recipient Email": "Empfänger E-Mail",
|
|
6
|
+
"Subject (Optional)": "Betreff (Optional)",
|
|
7
|
+
"Invoice Subject": "Rechnungsbetreff",
|
|
8
|
+
"Leave empty to use default": "Leer lassen für Standardwert",
|
|
9
|
+
"Message (Optional)": "Nachricht (Optional)",
|
|
10
|
+
"Email message placeholder": "E-Mail-Nachricht... Unterstützt **fett**, *kursiv*, [Links](url) und Listen",
|
|
11
|
+
Cancel: "Abbrechen",
|
|
12
|
+
"Send Email": "E-Mail senden",
|
|
13
|
+
"Email sent": "E-Mail gesendet",
|
|
14
|
+
"Invoice sent to": "Rechnung gesendet an",
|
|
15
|
+
"Failed to send email": "E-Mail konnte nicht gesendet werden",
|
|
16
|
+
"Sandbox email warning":
|
|
17
|
+
"Im Sandbox-Modus können E-Mails nur an verifizierte Teammitglieder dieses Kontos gesendet werden.",
|
|
18
|
+
} as const;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
"Send Invoice by Email": "Pošlji račun po e-pošti",
|
|
3
|
+
"Send invoice by email description":
|
|
4
|
+
"Pošljite račun #{number} stranki po e-pošti. V besedilu je podprto oblikovanje Markdown.",
|
|
5
|
+
"Recipient Email": "E-pošta prejemnika",
|
|
6
|
+
"Subject (Optional)": "Zadeva (neobvezno)",
|
|
7
|
+
"Invoice Subject": "Zadeva računa",
|
|
8
|
+
"Leave empty to use default": "Pustite prazno za privzeto vrednost",
|
|
9
|
+
"Message (Optional)": "Sporočilo (neobvezno)",
|
|
10
|
+
"Email message placeholder": "E-poštno sporočilo... Podpira **krepko**, *ležeče*, [povezave](url) in sezname",
|
|
11
|
+
Cancel: "Prekliči",
|
|
12
|
+
"Send Email": "Pošlji e-pošto",
|
|
13
|
+
"Email sent": "E-pošta poslana",
|
|
14
|
+
"Invoice sent to": "Račun poslan na",
|
|
15
|
+
"Failed to send email": "Pošiljanje e-pošte ni uspelo",
|
|
16
|
+
"Sandbox email warning": "V testnem načinu lahko pošiljate e-pošto samo verificiranim članom ekipe tega računa.",
|
|
17
|
+
} as const;
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import { zodResolver } from "@hookform/resolvers/zod";
|
|
2
|
+
import type { Invoice } from "@spaceinvoices/js-sdk";
|
|
3
|
+
import { AlertCircle, Mail } from "lucide-react";
|
|
4
|
+
import { useEffect, useState } from "react";
|
|
5
|
+
import type { Resolver } from "react-hook-form";
|
|
6
|
+
import { useForm } from "react-hook-form";
|
|
7
|
+
import { toast } from "sonner";
|
|
8
|
+
import { InputWithPreview } from "@/ui/components/entities/entity-settings-form/input-with-preview";
|
|
9
|
+
import { Alert, AlertDescription } from "@/ui/components/ui/alert";
|
|
10
|
+
import { Button } from "@/ui/components/ui/button";
|
|
11
|
+
import {
|
|
12
|
+
Dialog,
|
|
13
|
+
DialogContent,
|
|
14
|
+
DialogDescription,
|
|
15
|
+
DialogHeader,
|
|
16
|
+
DialogTitle,
|
|
17
|
+
DialogTrigger,
|
|
18
|
+
} from "@/ui/components/ui/dialog";
|
|
19
|
+
import {
|
|
20
|
+
Form,
|
|
21
|
+
FormControl,
|
|
22
|
+
FormDescription,
|
|
23
|
+
FormField,
|
|
24
|
+
FormItem,
|
|
25
|
+
FormLabel,
|
|
26
|
+
FormMessage,
|
|
27
|
+
} from "@/ui/components/ui/form";
|
|
28
|
+
import { Input } from "@/ui/components/ui/input";
|
|
29
|
+
import { Spinner } from "@/ui/components/ui/spinner";
|
|
30
|
+
import { type SendEmailSchema, sendEmailSchema } from "@/ui/generated/schemas";
|
|
31
|
+
import type { ComponentTranslationProps } from "@/ui/lib/translation";
|
|
32
|
+
import { createTranslation } from "@/ui/lib/translation";
|
|
33
|
+
import { useEntities } from "@/ui/providers/entities-context";
|
|
34
|
+
import { useSDK } from "@/ui/providers/sdk-provider";
|
|
35
|
+
import de from "./locales/de";
|
|
36
|
+
import sl from "./locales/sl";
|
|
37
|
+
|
|
38
|
+
const translations = { de, sl } as const;
|
|
39
|
+
|
|
40
|
+
type SendEmailDialogProps = {
|
|
41
|
+
invoice: Invoice;
|
|
42
|
+
defaultEmail?: string;
|
|
43
|
+
defaultSubject?: string;
|
|
44
|
+
defaultBody?: string;
|
|
45
|
+
onSuccess?: () => void;
|
|
46
|
+
onError?: (error: string) => void;
|
|
47
|
+
ButtonLoader?: React.ComponentType;
|
|
48
|
+
/** When true, only renders a DropdownMenuItem trigger (deprecated - use controlled mode instead) */
|
|
49
|
+
renderAsDropdownItem?: boolean;
|
|
50
|
+
/** @deprecated Use locale prop instead */
|
|
51
|
+
translationFn?: (key: string) => string;
|
|
52
|
+
/** Controlled mode: externally control dialog open state */
|
|
53
|
+
open?: boolean;
|
|
54
|
+
/** Controlled mode: callback when open state changes */
|
|
55
|
+
onOpenChange?: (open: boolean) => void;
|
|
56
|
+
} & ComponentTranslationProps;
|
|
57
|
+
|
|
58
|
+
export function SendEmailDialog({
|
|
59
|
+
invoice,
|
|
60
|
+
defaultEmail = "",
|
|
61
|
+
defaultSubject = "",
|
|
62
|
+
defaultBody = "",
|
|
63
|
+
onSuccess,
|
|
64
|
+
onError,
|
|
65
|
+
ButtonLoader,
|
|
66
|
+
renderAsDropdownItem = false,
|
|
67
|
+
translationFn,
|
|
68
|
+
open: controlledOpen,
|
|
69
|
+
onOpenChange,
|
|
70
|
+
locale = "en",
|
|
71
|
+
...i18nProps
|
|
72
|
+
}: SendEmailDialogProps) {
|
|
73
|
+
const t = translationFn || createTranslation({ translations, locale, ...i18nProps });
|
|
74
|
+
|
|
75
|
+
const [internalOpen, setInternalOpen] = useState(false);
|
|
76
|
+
|
|
77
|
+
// Support both controlled and uncontrolled modes
|
|
78
|
+
const isControlled = controlledOpen !== undefined;
|
|
79
|
+
const open = isControlled ? controlledOpen : internalOpen;
|
|
80
|
+
// biome-ignore lint/suspicious/noEmptyBlockStatements: noop fallback for controlled mode
|
|
81
|
+
const setOpen = isControlled ? onOpenChange || (() => {}) : setInternalOpen;
|
|
82
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
83
|
+
const { sdk } = useSDK();
|
|
84
|
+
const { activeEntity } = useEntities();
|
|
85
|
+
|
|
86
|
+
// Get entity email defaults if not provided
|
|
87
|
+
const entitySettings = (activeEntity?.settings as Record<string, any>) || {};
|
|
88
|
+
const emailDefaults = entitySettings.email_defaults || {};
|
|
89
|
+
|
|
90
|
+
const finalSubject = defaultSubject || emailDefaults.invoice_subject || `Invoice #${invoice.number}`;
|
|
91
|
+
const finalBody =
|
|
92
|
+
defaultBody || emailDefaults.invoice_body || `Please find your invoice #${invoice.number} attached.`;
|
|
93
|
+
|
|
94
|
+
const form = useForm<SendEmailSchema>({
|
|
95
|
+
resolver: zodResolver(sendEmailSchema) as Resolver<SendEmailSchema>,
|
|
96
|
+
defaultValues: {
|
|
97
|
+
to: defaultEmail,
|
|
98
|
+
subject: finalSubject,
|
|
99
|
+
bodyText: finalBody,
|
|
100
|
+
attachPdf: false,
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// Reset form and fetch customer email when dialog opens
|
|
105
|
+
useEffect(() => {
|
|
106
|
+
if (!open) return;
|
|
107
|
+
|
|
108
|
+
// Reset form to defaults when dialog opens
|
|
109
|
+
form.reset({
|
|
110
|
+
to: defaultEmail,
|
|
111
|
+
subject: finalSubject,
|
|
112
|
+
bodyText: finalBody,
|
|
113
|
+
attachPdf: false,
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// Fetch customer email from linked customer if not in invoice snapshot
|
|
117
|
+
const fetchCustomerEmail = async () => {
|
|
118
|
+
if (defaultEmail || !invoice.customer_id || !sdk || !activeEntity?.id) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
try {
|
|
123
|
+
const response = await sdk.customers.list(
|
|
124
|
+
{ query: JSON.stringify({ id: invoice.customer_id }), limit: 1 },
|
|
125
|
+
{ entity_id: activeEntity.id },
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
const customer = response.data[0];
|
|
129
|
+
if (customer?.email) {
|
|
130
|
+
form.setValue("to", customer.email);
|
|
131
|
+
}
|
|
132
|
+
} catch {
|
|
133
|
+
// Silently fail - customer might not exist or not have email
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
fetchCustomerEmail();
|
|
138
|
+
}, [open, defaultEmail, invoice.customer_id, sdk, activeEntity?.id, form, finalSubject, finalBody]);
|
|
139
|
+
|
|
140
|
+
const onSubmit = async (values: SendEmailSchema) => {
|
|
141
|
+
setIsLoading(true);
|
|
142
|
+
try {
|
|
143
|
+
if (!sdk) throw new Error("SDK not initialized");
|
|
144
|
+
|
|
145
|
+
// Ensure we have an active entity
|
|
146
|
+
if (!activeEntity?.id) throw new Error("Entity context required");
|
|
147
|
+
|
|
148
|
+
// Call the email API endpoint using SDK
|
|
149
|
+
await (sdk.email as any).send(
|
|
150
|
+
{
|
|
151
|
+
to: values.to,
|
|
152
|
+
subject: values.subject,
|
|
153
|
+
bodyText: values.bodyText,
|
|
154
|
+
documentId: invoice.id,
|
|
155
|
+
},
|
|
156
|
+
{ entity_id: activeEntity.id },
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
toast.success(t("Email sent"), {
|
|
160
|
+
description: `${t("Invoice sent to")} ${values.to}`,
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
setOpen(false);
|
|
164
|
+
form.reset();
|
|
165
|
+
onSuccess?.();
|
|
166
|
+
} catch (error) {
|
|
167
|
+
const errorMessage = error instanceof Error ? error.message : t("Failed to send email");
|
|
168
|
+
toast.error(t("Failed to send email"), {
|
|
169
|
+
description: errorMessage,
|
|
170
|
+
});
|
|
171
|
+
onError?.(errorMessage);
|
|
172
|
+
} finally {
|
|
173
|
+
setIsLoading(false);
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
// In controlled mode, no trigger is rendered - parent controls the dialog
|
|
178
|
+
const showTrigger = !isControlled && !renderAsDropdownItem;
|
|
179
|
+
|
|
180
|
+
return (
|
|
181
|
+
<Dialog open={open} onOpenChange={setOpen}>
|
|
182
|
+
{showTrigger && (
|
|
183
|
+
<DialogTrigger asChild>
|
|
184
|
+
<Button variant="ghost" size="sm" className="h-8 w-8 cursor-pointer p-0">
|
|
185
|
+
<Mail className="h-4 w-4" />
|
|
186
|
+
<span className="sr-only">{t("Send Email")}</span>
|
|
187
|
+
</Button>
|
|
188
|
+
</DialogTrigger>
|
|
189
|
+
)}
|
|
190
|
+
<DialogContent className="sm:max-w-md">
|
|
191
|
+
<DialogHeader>
|
|
192
|
+
<DialogTitle>{t("Send Invoice by Email")}</DialogTitle>
|
|
193
|
+
<DialogDescription>
|
|
194
|
+
{t("Send invoice by email description").replace("{number}", invoice.number)}
|
|
195
|
+
</DialogDescription>
|
|
196
|
+
</DialogHeader>
|
|
197
|
+
|
|
198
|
+
{activeEntity?.environment === "sandbox" && (
|
|
199
|
+
<Alert className="border-amber-200 bg-amber-50 dark:border-amber-900 dark:bg-amber-950">
|
|
200
|
+
<AlertCircle className="h-4 w-4 text-amber-600" />
|
|
201
|
+
<AlertDescription className="text-amber-800 dark:text-amber-200">
|
|
202
|
+
{t("Sandbox email warning")}
|
|
203
|
+
</AlertDescription>
|
|
204
|
+
</Alert>
|
|
205
|
+
)}
|
|
206
|
+
|
|
207
|
+
<Form {...form}>
|
|
208
|
+
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
|
|
209
|
+
<FormField
|
|
210
|
+
control={form.control}
|
|
211
|
+
name="to"
|
|
212
|
+
render={({ field }) => (
|
|
213
|
+
<FormItem>
|
|
214
|
+
<FormLabel>{t("Recipient Email")}</FormLabel>
|
|
215
|
+
<FormControl>
|
|
216
|
+
<Input type="email" placeholder="customer@example.com" {...field} disabled={isLoading} />
|
|
217
|
+
</FormControl>
|
|
218
|
+
<FormMessage />
|
|
219
|
+
</FormItem>
|
|
220
|
+
)}
|
|
221
|
+
/>
|
|
222
|
+
|
|
223
|
+
<FormField
|
|
224
|
+
control={form.control}
|
|
225
|
+
name="subject"
|
|
226
|
+
render={({ field }) => (
|
|
227
|
+
<FormItem>
|
|
228
|
+
<FormLabel>{t("Subject (Optional)")}</FormLabel>
|
|
229
|
+
<FormControl>
|
|
230
|
+
<InputWithPreview
|
|
231
|
+
value={field.value || ""}
|
|
232
|
+
onChange={field.onChange}
|
|
233
|
+
placeholder={t("Invoice Subject")}
|
|
234
|
+
entity={activeEntity!}
|
|
235
|
+
document={invoice}
|
|
236
|
+
disabled={isLoading}
|
|
237
|
+
className="h-10"
|
|
238
|
+
/>
|
|
239
|
+
</FormControl>
|
|
240
|
+
<FormDescription>{t("Leave empty to use default")}</FormDescription>
|
|
241
|
+
<FormMessage />
|
|
242
|
+
</FormItem>
|
|
243
|
+
)}
|
|
244
|
+
/>
|
|
245
|
+
|
|
246
|
+
<FormField
|
|
247
|
+
control={form.control}
|
|
248
|
+
name="bodyText"
|
|
249
|
+
render={({ field }) => (
|
|
250
|
+
<FormItem>
|
|
251
|
+
<FormLabel>{t("Message (Optional)")}</FormLabel>
|
|
252
|
+
<FormControl>
|
|
253
|
+
<InputWithPreview
|
|
254
|
+
value={field.value || ""}
|
|
255
|
+
onChange={field.onChange}
|
|
256
|
+
placeholder={t("Email message placeholder")}
|
|
257
|
+
entity={activeEntity!}
|
|
258
|
+
document={invoice}
|
|
259
|
+
disabled={isLoading}
|
|
260
|
+
multiline
|
|
261
|
+
rows={4}
|
|
262
|
+
/>
|
|
263
|
+
</FormControl>
|
|
264
|
+
<FormDescription>{t("Leave empty to use default")}</FormDescription>
|
|
265
|
+
<FormMessage />
|
|
266
|
+
</FormItem>
|
|
267
|
+
)}
|
|
268
|
+
/>
|
|
269
|
+
|
|
270
|
+
<div className="flex justify-end gap-2">
|
|
271
|
+
<Button
|
|
272
|
+
type="button"
|
|
273
|
+
variant="outline"
|
|
274
|
+
className="cursor-pointer"
|
|
275
|
+
onClick={() => setOpen(false)}
|
|
276
|
+
disabled={isLoading}
|
|
277
|
+
>
|
|
278
|
+
{t("Cancel")}
|
|
279
|
+
</Button>
|
|
280
|
+
<Button type="submit" className="min-w-[100px] cursor-pointer" disabled={isLoading}>
|
|
281
|
+
{isLoading ? ButtonLoader ? <ButtonLoader /> : <Spinner /> : t("Send Email")}
|
|
282
|
+
</Button>
|
|
283
|
+
</div>
|
|
284
|
+
</form>
|
|
285
|
+
</Form>
|
|
286
|
+
</DialogContent>
|
|
287
|
+
</Dialog>
|
|
288
|
+
);
|
|
289
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// Stub file - TODO: implement properly
|
|
2
|
+
import type { RefObject } from "react";
|
|
3
|
+
|
|
4
|
+
type ScaledDocumentPreviewProps = {
|
|
5
|
+
htmlContent: string;
|
|
6
|
+
scale: number;
|
|
7
|
+
contentHeight: number;
|
|
8
|
+
A4_WIDTH_PX: number;
|
|
9
|
+
contentRef: RefObject<HTMLDivElement>;
|
|
10
|
+
entityUpdatedAt?: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export function ScaledDocumentPreview({
|
|
14
|
+
htmlContent,
|
|
15
|
+
scale,
|
|
16
|
+
contentHeight,
|
|
17
|
+
A4_WIDTH_PX,
|
|
18
|
+
contentRef,
|
|
19
|
+
}: ScaledDocumentPreviewProps) {
|
|
20
|
+
return (
|
|
21
|
+
<div
|
|
22
|
+
ref={contentRef}
|
|
23
|
+
style={{
|
|
24
|
+
width: A4_WIDTH_PX,
|
|
25
|
+
transform: `scale(${scale})`,
|
|
26
|
+
transformOrigin: "top left",
|
|
27
|
+
height: contentHeight,
|
|
28
|
+
}}
|
|
29
|
+
dangerouslySetInnerHTML={{ __html: htmlContent }}
|
|
30
|
+
/>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// Stub file - TODO: implement properly
|
|
2
|
+
import { useEffect, useRef, useState } from "react";
|
|
3
|
+
|
|
4
|
+
const A4_WIDTH_PX = 794; // A4 width at 96 DPI
|
|
5
|
+
|
|
6
|
+
export function useA4Scaling(content: string) {
|
|
7
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
|
8
|
+
const contentRef = useRef<HTMLDivElement>(null);
|
|
9
|
+
const [scale, setScale] = useState(1);
|
|
10
|
+
const [contentHeight, setContentHeight] = useState(0);
|
|
11
|
+
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
if (!containerRef.current || !content) return;
|
|
14
|
+
|
|
15
|
+
const updateScale = () => {
|
|
16
|
+
const containerWidth = containerRef.current?.clientWidth || A4_WIDTH_PX;
|
|
17
|
+
const newScale = Math.min(1, containerWidth / A4_WIDTH_PX);
|
|
18
|
+
setScale(newScale);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
updateScale();
|
|
22
|
+
window.addEventListener("resize", updateScale);
|
|
23
|
+
return () => window.removeEventListener("resize", updateScale);
|
|
24
|
+
}, [content]);
|
|
25
|
+
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
if (contentRef.current) {
|
|
28
|
+
setContentHeight(contentRef.current.scrollHeight * scale);
|
|
29
|
+
}
|
|
30
|
+
}, [scale]);
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
containerRef,
|
|
34
|
+
contentRef,
|
|
35
|
+
scale,
|
|
36
|
+
contentHeight,
|
|
37
|
+
A4_WIDTH_PX,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import type { Entity, Invoice } from "@spaceinvoices/js-sdk";
|
|
2
|
+
import { AlertCircle, CheckCircle2, Download, FileCode2, XCircle } from "lucide-react";
|
|
3
|
+
import { Alert, AlertDescription, AlertTitle } from "@/ui/components/ui/alert";
|
|
4
|
+
import { Badge } from "@/ui/components/ui/badge";
|
|
5
|
+
import { Button } from "@/ui/components/ui/button";
|
|
6
|
+
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/ui/components/ui/card";
|
|
7
|
+
import type { ComponentTranslationProps } from "@/ui/lib/translation";
|
|
8
|
+
import { createTranslation } from "@/ui/lib/translation";
|
|
9
|
+
|
|
10
|
+
// Type for eslog data
|
|
11
|
+
interface EslogData {
|
|
12
|
+
validation_enabled?: boolean | null;
|
|
13
|
+
validation_status?: "valid" | "invalid" | "not_validated" | null;
|
|
14
|
+
validation_errors?: string[] | null;
|
|
15
|
+
validated_at?: string | null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface EslogInfoDisplayProps extends ComponentTranslationProps {
|
|
19
|
+
invoice: Invoice;
|
|
20
|
+
/** Entity is used to determine if e-SLOG should be shown (for SI entities) */
|
|
21
|
+
entity?: Entity | null;
|
|
22
|
+
onDownload?: () => void;
|
|
23
|
+
isDownloading?: boolean;
|
|
24
|
+
showDownloadButton?: boolean;
|
|
25
|
+
/** When true, force show the component even if no eslog data exists (for SI entities with validation enabled) */
|
|
26
|
+
forceShow?: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* e-SLOG Info Display Component
|
|
31
|
+
*
|
|
32
|
+
* Shows e-SLOG validation status, errors, and download button for valid documents
|
|
33
|
+
*/
|
|
34
|
+
export function EslogInfoDisplay({
|
|
35
|
+
invoice,
|
|
36
|
+
entity,
|
|
37
|
+
onDownload,
|
|
38
|
+
isDownloading,
|
|
39
|
+
showDownloadButton = true,
|
|
40
|
+
forceShow = false,
|
|
41
|
+
t: translateFn,
|
|
42
|
+
namespace,
|
|
43
|
+
locale,
|
|
44
|
+
}: EslogInfoDisplayProps) {
|
|
45
|
+
const t = createTranslation({
|
|
46
|
+
t: translateFn,
|
|
47
|
+
namespace,
|
|
48
|
+
locale,
|
|
49
|
+
translations: {},
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// Cast eslog to the proper type
|
|
53
|
+
const eslog = invoice.eslog as EslogData | undefined | null;
|
|
54
|
+
|
|
55
|
+
// Check if entity is Slovenian and has e-SLOG validation enabled in settings
|
|
56
|
+
const isSlovenianEntity = entity?.country_code === "SI";
|
|
57
|
+
const entityEslogEnabled = !!(entity?.settings as any)?.eslog_validation_enabled;
|
|
58
|
+
|
|
59
|
+
// Show component if:
|
|
60
|
+
// 1. Document has eslog data, OR
|
|
61
|
+
// 2. Entity is Slovenian with eslog enabled (forceShow), OR
|
|
62
|
+
// 3. forceShow is explicitly true
|
|
63
|
+
const shouldShow = eslog || (forceShow && isSlovenianEntity && entityEslogEnabled);
|
|
64
|
+
|
|
65
|
+
if (!shouldShow) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// If no eslog data but we should show (SI entity with setting enabled), treat as not_validated
|
|
70
|
+
const effectiveEslog: EslogData = eslog || {
|
|
71
|
+
validation_status: "not_validated",
|
|
72
|
+
validation_enabled: null,
|
|
73
|
+
validation_errors: null,
|
|
74
|
+
validated_at: null,
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const getStatusBadge = () => {
|
|
78
|
+
switch (effectiveEslog.validation_status) {
|
|
79
|
+
case "valid":
|
|
80
|
+
return (
|
|
81
|
+
<Badge className="bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-100">
|
|
82
|
+
<CheckCircle2 className="mr-1 h-3 w-3" />
|
|
83
|
+
{t("Valid")}
|
|
84
|
+
</Badge>
|
|
85
|
+
);
|
|
86
|
+
case "invalid":
|
|
87
|
+
return (
|
|
88
|
+
<Badge className="bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-100">
|
|
89
|
+
<XCircle className="mr-1 h-3 w-3" />
|
|
90
|
+
{t("Invalid")}
|
|
91
|
+
</Badge>
|
|
92
|
+
);
|
|
93
|
+
case "not_validated":
|
|
94
|
+
return (
|
|
95
|
+
<Badge className="bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-100">{t("Not validated")}</Badge>
|
|
96
|
+
);
|
|
97
|
+
default:
|
|
98
|
+
return (
|
|
99
|
+
<Badge className="bg-gray-100 text-gray-800 dark:bg-gray-800 dark:text-gray-100">{t("Not validated")}</Badge>
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
return (
|
|
105
|
+
<Card>
|
|
106
|
+
<CardHeader>
|
|
107
|
+
<CardTitle className="flex items-center gap-2">
|
|
108
|
+
<FileCode2 className="h-5 w-5" />
|
|
109
|
+
{t("e-SLOG 2.0")}
|
|
110
|
+
{getStatusBadge()}
|
|
111
|
+
</CardTitle>
|
|
112
|
+
<CardDescription>{t("Slovenian electronic invoice format (EN 16931)")}</CardDescription>
|
|
113
|
+
</CardHeader>
|
|
114
|
+
<CardContent className="space-y-4">
|
|
115
|
+
{/* Validation Errors */}
|
|
116
|
+
{effectiveEslog.validation_status === "invalid" &&
|
|
117
|
+
effectiveEslog.validation_errors &&
|
|
118
|
+
effectiveEslog.validation_errors.length > 0 && (
|
|
119
|
+
<Alert variant="destructive">
|
|
120
|
+
<AlertCircle className="h-4 w-4" />
|
|
121
|
+
<AlertTitle>{t("Validation Errors")}</AlertTitle>
|
|
122
|
+
<AlertDescription>
|
|
123
|
+
<ul className="mt-2 list-disc space-y-1 pl-4">
|
|
124
|
+
{effectiveEslog.validation_errors.map((error, index) => (
|
|
125
|
+
<li key={index} className="text-sm">
|
|
126
|
+
{error}
|
|
127
|
+
</li>
|
|
128
|
+
))}
|
|
129
|
+
</ul>
|
|
130
|
+
</AlertDescription>
|
|
131
|
+
</Alert>
|
|
132
|
+
)}
|
|
133
|
+
|
|
134
|
+
{/* Download Button for valid documents */}
|
|
135
|
+
{showDownloadButton && effectiveEslog.validation_status === "valid" && onDownload && (
|
|
136
|
+
<Button onClick={onDownload} disabled={isDownloading} className="w-full" variant="outline">
|
|
137
|
+
<Download className="mr-2 h-4 w-4" />
|
|
138
|
+
{isDownloading ? t("Downloading...") : t("Download e-SLOG XML")}
|
|
139
|
+
</Button>
|
|
140
|
+
)}
|
|
141
|
+
|
|
142
|
+
{/* Not validated info */}
|
|
143
|
+
{(effectiveEslog.validation_status === "not_validated" || !effectiveEslog.validation_status) && (
|
|
144
|
+
<div className="rounded-lg border border-gray-200 bg-gray-50 p-3 text-gray-600 text-sm dark:border-gray-700 dark:bg-gray-800 dark:text-gray-300">
|
|
145
|
+
{t(
|
|
146
|
+
"This document has not been validated for e-SLOG. Enable validation in entity settings or on the document to validate.",
|
|
147
|
+
)}
|
|
148
|
+
</div>
|
|
149
|
+
)}
|
|
150
|
+
|
|
151
|
+
{/* Validation timestamp */}
|
|
152
|
+
{effectiveEslog.validated_at && (
|
|
153
|
+
<div className="pt-2 text-muted-foreground text-sm">
|
|
154
|
+
{t("Validated at")}: {new Date(effectiveEslog.validated_at).toLocaleString()}
|
|
155
|
+
</div>
|
|
156
|
+
)}
|
|
157
|
+
</CardContent>
|
|
158
|
+
</Card>
|
|
159
|
+
);
|
|
160
|
+
}
|