@spaceinvoices/react-ui 0.4.2 → 0.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/common/autocomplete.tsx +18 -2
- package/src/components/advance-invoices/create/create-advance-invoice-form.tsx +0 -1
- package/src/components/advance-invoices/create/locales/de.ts +2 -0
- package/src/components/advance-invoices/create/locales/es.ts +2 -0
- package/src/components/advance-invoices/create/locales/fr.ts +2 -0
- package/src/components/advance-invoices/create/locales/hr.ts +1 -0
- package/src/components/advance-invoices/create/locales/it.ts +2 -0
- package/src/components/advance-invoices/create/locales/nl.ts +2 -0
- package/src/components/advance-invoices/create/locales/pl.ts +1 -0
- package/src/components/advance-invoices/create/locales/pt.ts +1 -0
- package/src/components/advance-invoices/create/locales/sl.ts +1 -0
- package/src/components/advance-invoices/create/prepare-advance-invoice-submission.ts +0 -1
- package/src/components/advance-invoices/list/list-table.tsx +130 -40
- package/src/components/advance-invoices/list/locales/de.ts +6 -0
- package/src/components/advance-invoices/list/locales/en.ts +5 -0
- package/src/components/advance-invoices/list/locales/es.ts +6 -0
- package/src/components/advance-invoices/list/locales/fr.ts +6 -0
- package/src/components/advance-invoices/list/locales/hr.ts +6 -0
- package/src/components/advance-invoices/list/locales/it.ts +6 -0
- package/src/components/advance-invoices/list/locales/nl.ts +6 -0
- package/src/components/advance-invoices/list/locales/pl.ts +6 -0
- package/src/components/advance-invoices/list/locales/pt.ts +6 -0
- package/src/components/advance-invoices/list/locales/sl.ts +6 -0
- package/src/components/credit-notes/create/create-credit-note-form.tsx +114 -3
- package/src/components/credit-notes/create/locales/de.ts +2 -0
- package/src/components/credit-notes/create/locales/es.ts +2 -0
- package/src/components/credit-notes/create/locales/fr.ts +2 -0
- package/src/components/credit-notes/create/locales/hr.ts +1 -0
- package/src/components/credit-notes/create/locales/it.ts +2 -0
- package/src/components/credit-notes/create/locales/nl.ts +2 -0
- package/src/components/credit-notes/create/locales/pl.ts +1 -0
- package/src/components/credit-notes/create/locales/pt.ts +1 -0
- package/src/components/credit-notes/create/locales/sl.ts +1 -0
- package/src/components/credit-notes/credit-notes.hooks.ts +30 -0
- package/src/components/credit-notes/list/list-table.tsx +111 -36
- package/src/components/credit-notes/list/locales/de.ts +6 -1
- package/src/components/credit-notes/list/locales/en.ts +6 -0
- package/src/components/credit-notes/list/locales/es.ts +6 -1
- package/src/components/credit-notes/list/locales/fr.ts +6 -1
- package/src/components/credit-notes/list/locales/hr.ts +6 -1
- package/src/components/credit-notes/list/locales/it.ts +6 -1
- package/src/components/credit-notes/list/locales/nl.ts +6 -1
- package/src/components/credit-notes/list/locales/pl.ts +6 -1
- package/src/components/credit-notes/list/locales/pt.ts +6 -1
- package/src/components/credit-notes/list/locales/sl.ts +6 -1
- package/src/components/customers/customer-list-table/customer-list-table.tsx +0 -3
- package/src/components/customers/customer-list-table/locales/de.ts +1 -0
- package/src/components/customers/customer-list-table/locales/es.ts +1 -0
- package/src/components/customers/customer-list-table/locales/fr.ts +1 -0
- package/src/components/customers/customer-list-table/locales/hr.ts +1 -0
- package/src/components/customers/customer-list-table/locales/it.ts +1 -0
- package/src/components/customers/customer-list-table/locales/nl.ts +1 -0
- package/src/components/customers/customer-list-table/locales/pl.ts +1 -0
- package/src/components/customers/customer-list-table/locales/pt.ts +1 -0
- package/src/components/customers/customer-list-table/locales/sl.ts +1 -0
- package/src/components/dashboard/collection-rate-card/use-collection-rate.ts +2 -2
- package/src/components/dashboard/invoice-status-chart/use-invoice-status.ts +3 -3
- package/src/components/dashboard/payment-methods-chart/use-payment-methods.ts +1 -1
- package/src/components/dashboard/payment-trend-chart/use-payment-trend.ts +1 -1
- package/src/components/dashboard/revenue-trend-chart/use-revenue-trend.ts +1 -1
- package/src/components/dashboard/shared/use-revenue-data.ts +4 -4
- package/src/components/dashboard/shared/use-stats-counts.ts +4 -4
- package/src/components/dashboard/shared/use-stats-query.ts +1 -1
- package/src/components/dashboard/tax-collected-card/use-tax-collected.ts +2 -2
- package/src/components/dashboard/top-customers-chart/use-top-customers.ts +1 -1
- package/src/components/delivery-notes/create/create-delivery-note-form.tsx +332 -0
- package/src/components/delivery-notes/create/locales/de.ts +50 -0
- package/src/components/delivery-notes/create/locales/es.ts +49 -0
- package/src/components/delivery-notes/create/locales/fr.ts +50 -0
- package/src/components/delivery-notes/create/locales/hr.ts +49 -0
- package/src/components/delivery-notes/create/locales/it.ts +49 -0
- package/src/components/delivery-notes/create/locales/nl.ts +50 -0
- package/src/components/delivery-notes/create/locales/pl.ts +49 -0
- package/src/components/delivery-notes/create/locales/pt.ts +50 -0
- package/src/components/delivery-notes/create/locales/sl.ts +49 -0
- package/src/components/delivery-notes/create/prepare-delivery-note-submission.ts +38 -0
- package/src/components/delivery-notes/create/use-delivery-note-customer-form.ts +1 -0
- package/src/components/delivery-notes/delivery-notes.hooks.ts +15 -0
- package/src/components/delivery-notes/list/index.ts +3 -0
- package/src/components/delivery-notes/list/list-row-actions.tsx +122 -0
- package/src/components/delivery-notes/list/list-table.tsx +247 -0
- package/src/components/delivery-notes/list/locales/de.ts +13 -0
- package/src/components/delivery-notes/list/locales/en.ts +13 -0
- package/src/components/delivery-notes/list/locales/es.ts +13 -0
- package/src/components/delivery-notes/list/locales/fr.ts +13 -0
- package/src/components/delivery-notes/list/locales/hr.ts +13 -0
- package/src/components/delivery-notes/list/locales/it.ts +13 -0
- package/src/components/delivery-notes/list/locales/nl.ts +13 -0
- package/src/components/delivery-notes/list/locales/pl.ts +13 -0
- package/src/components/delivery-notes/list/locales/pt.ts +13 -0
- package/src/components/delivery-notes/list/locales/sl.ts +13 -0
- package/src/components/delivery-notes/list/use-delivery-note-download.ts +63 -0
- package/src/components/documents/create/document-details-section.tsx +76 -58
- package/src/components/documents/create/linked-documents-info.tsx +82 -0
- package/src/components/documents/create/live-preview.tsx +38 -11
- package/src/components/documents/create/prepare-document-submission.ts +1 -1
- package/src/components/documents/documents.hooks.ts +2 -1
- package/src/components/documents/shared/document-preview-display.tsx +12 -5
- package/src/components/documents/types.ts +12 -3
- package/src/components/documents/view/document-activities-list.tsx +65 -47
- package/src/components/documents/view/document-details-card.tsx +102 -77
- package/src/components/documents/view/document-payments-list.tsx +102 -68
- package/src/components/documents/view/document-relations-list.tsx +120 -0
- package/src/components/documents/view/document-sidebar.tsx +151 -0
- package/src/components/documents/view/index.ts +2 -0
- package/src/components/documents/view/locales/de.ts +23 -0
- package/src/components/documents/view/locales/es.ts +23 -0
- package/src/components/documents/view/locales/fr.ts +23 -0
- package/src/components/documents/view/locales/hr.ts +23 -0
- package/src/components/documents/view/locales/it.ts +23 -0
- package/src/components/documents/view/locales/nl.ts +23 -0
- package/src/components/documents/view/locales/pl.ts +23 -0
- package/src/components/documents/view/locales/pt.ts +23 -0
- package/src/components/documents/view/locales/sl.ts +23 -0
- package/src/components/documents/view/use-document-download.ts +8 -5
- package/src/components/entities/create-entity-form.tsx +165 -13
- package/src/components/entities/entity-settings-form/entity-settings-form.tsx +101 -1
- package/src/components/entities/entity-settings-form/locales/de.ts +9 -0
- package/src/components/entities/entity-settings-form/locales/es.ts +9 -0
- package/src/components/entities/entity-settings-form/locales/fr.ts +9 -0
- package/src/components/entities/entity-settings-form/locales/hr.ts +9 -0
- package/src/components/entities/entity-settings-form/locales/it.ts +9 -0
- package/src/components/entities/entity-settings-form/locales/nl.ts +9 -0
- package/src/components/entities/entity-settings-form/locales/pl.ts +9 -0
- package/src/components/entities/entity-settings-form/locales/pt.ts +9 -0
- package/src/components/entities/entity-settings-form/locales/sl.ts +9 -0
- package/src/components/entities/fina-settings-form/fina-settings-form.tsx +83 -71
- package/src/components/entities/fina-settings-form/fina-settings.hooks.ts +7 -2
- package/src/components/entities/fina-settings-form/locales/de.ts +2 -2
- package/src/components/entities/fina-settings-form/locales/en.ts +2 -2
- package/src/components/entities/fina-settings-form/locales/es.ts +2 -2
- package/src/components/entities/fina-settings-form/locales/fr.ts +2 -2
- package/src/components/entities/fina-settings-form/locales/hr.ts +2 -2
- package/src/components/entities/fina-settings-form/locales/it.ts +2 -2
- package/src/components/entities/fina-settings-form/locales/nl.ts +2 -2
- package/src/components/entities/fina-settings-form/locales/pl.ts +2 -2
- package/src/components/entities/fina-settings-form/locales/pt.ts +2 -2
- package/src/components/entities/fina-settings-form/locales/sl.ts +2 -2
- package/src/components/entities/furs-settings-form/furs-settings-form.tsx +10 -1
- package/src/components/entities/furs-settings-form/furs-settings.hooks.ts +7 -2
- package/src/components/entities/furs-settings-form/locales/en.ts +0 -1
- package/src/components/entities/furs-settings-form/sections/general-settings-section.tsx +12 -4
- package/src/components/entities/settings/pdf-template-selector/locales/de.ts +3 -1
- package/src/components/entities/settings/pdf-template-selector/locales/es.ts +3 -1
- package/src/components/entities/settings/pdf-template-selector/locales/fr.ts +4 -1
- package/src/components/entities/settings/pdf-template-selector/locales/hr.ts +4 -1
- package/src/components/entities/settings/pdf-template-selector/locales/it.ts +3 -1
- package/src/components/entities/settings/pdf-template-selector/locales/nl.ts +3 -1
- package/src/components/entities/settings/pdf-template-selector/locales/pl.ts +3 -1
- package/src/components/entities/settings/pdf-template-selector/locales/pt.ts +3 -1
- package/src/components/entities/settings/pdf-template-selector/locales/sl.ts +3 -1
- package/src/components/entities/settings/pdf-template-selector/pdf-template-cards.tsx +1 -0
- package/src/components/estimates/create/create-estimate-form.tsx +29 -2
- package/src/components/estimates/list/list-table.tsx +3 -6
- package/src/components/estimates/list/locales/de.ts +1 -0
- package/src/components/estimates/list/locales/es.ts +1 -0
- package/src/components/estimates/list/locales/fr.ts +1 -0
- package/src/components/estimates/list/locales/hr.ts +1 -0
- package/src/components/estimates/list/locales/it.ts +1 -0
- package/src/components/estimates/list/locales/nl.ts +1 -0
- package/src/components/estimates/list/locales/pl.ts +1 -0
- package/src/components/estimates/list/locales/pt.ts +1 -0
- package/src/components/estimates/list/locales/sl.ts +1 -0
- package/src/components/export/document-export-form.tsx +9 -2
- package/src/components/export/index.ts +2 -0
- package/src/components/export/sales-per-item-export-form.tsx +223 -0
- package/src/components/invoices/create/create-invoice-form.tsx +48 -1
- package/src/components/invoices/create/locales/de.ts +11 -0
- package/src/components/invoices/create/locales/es.ts +11 -0
- package/src/components/invoices/create/locales/fr.ts +11 -0
- package/src/components/invoices/create/locales/hr.ts +10 -0
- package/src/components/invoices/create/locales/it.ts +11 -0
- package/src/components/invoices/create/locales/nl.ts +11 -0
- package/src/components/invoices/create/locales/pl.ts +10 -0
- package/src/components/invoices/create/locales/pt.ts +10 -0
- package/src/components/invoices/create/locales/sl.ts +10 -0
- package/src/components/invoices/invoices-furs.hooks.ts +27 -9
- package/src/components/invoices/list/list-row-actions.tsx +3 -3
- package/src/components/invoices/list/list-table.tsx +132 -21
- package/src/components/invoices/list/locales/de.ts +6 -0
- package/src/components/invoices/list/locales/en.ts +5 -0
- package/src/components/invoices/list/locales/es.ts +6 -0
- package/src/components/invoices/list/locales/fr.ts +6 -0
- package/src/components/invoices/list/locales/hr.ts +6 -0
- package/src/components/invoices/list/locales/it.ts +6 -0
- package/src/components/invoices/list/locales/nl.ts +6 -0
- package/src/components/invoices/list/locales/pl.ts +6 -0
- package/src/components/invoices/list/locales/pt.ts +6 -0
- package/src/components/invoices/list/locales/sl.ts +6 -0
- package/src/components/invoices/view/fiscalization-status-card.tsx +42 -24
- package/src/components/items/item-combobox.tsx +5 -3
- package/src/components/items/item-list-table/item-list-header.tsx +4 -17
- package/src/components/items/item-list-table/item-list-row-actions.tsx +3 -2
- package/src/components/items/item-list-table/item-list-row.tsx +3 -2
- package/src/components/items/item-list-table/item-list-table.tsx +3 -3
- package/src/components/items/item-list-table/locales/de.ts +1 -0
- package/src/components/items/item-list-table/locales/es.ts +1 -0
- package/src/components/items/item-list-table/locales/fr.ts +1 -0
- package/src/components/items/item-list-table/locales/hr.ts +1 -0
- package/src/components/items/item-list-table/locales/it.ts +1 -0
- package/src/components/items/item-list-table/locales/nl.ts +1 -0
- package/src/components/items/item-list-table/locales/pl.ts +1 -0
- package/src/components/items/item-list-table/locales/pt.ts +1 -0
- package/src/components/items/item-list-table/locales/sl.ts +1 -0
- package/src/components/payments/list/list-table.tsx +0 -4
- package/src/components/payments/list/locales/de.ts +1 -0
- package/src/components/payments/list/locales/es.ts +1 -0
- package/src/components/payments/list/locales/fr.ts +1 -0
- package/src/components/payments/list/locales/hr.ts +1 -0
- package/src/components/payments/list/locales/it.ts +1 -0
- package/src/components/payments/list/locales/nl.ts +1 -0
- package/src/components/payments/list/locales/pl.ts +1 -0
- package/src/components/payments/list/locales/pt.ts +1 -0
- package/src/components/payments/list/locales/sl.ts +1 -0
- package/src/components/recurring-invoices/list/list-table.tsx +0 -7
- package/src/components/recurring-invoices/list/locales/de.ts +1 -0
- package/src/components/recurring-invoices/list/locales/es.ts +1 -0
- package/src/components/recurring-invoices/list/locales/fr.ts +1 -0
- package/src/components/recurring-invoices/list/locales/hr.ts +1 -0
- package/src/components/recurring-invoices/list/locales/it.ts +1 -0
- package/src/components/recurring-invoices/list/locales/nl.ts +1 -0
- package/src/components/recurring-invoices/list/locales/pl.ts +1 -0
- package/src/components/recurring-invoices/list/locales/pt.ts +1 -0
- package/src/components/recurring-invoices/list/locales/sl.ts +1 -0
- package/src/components/request-logs/request-log-list-table.tsx +0 -3
- package/src/components/table/README.md +14 -121
- package/src/components/table/data-table.tsx +22 -37
- package/src/components/table/hooks/use-table-state.ts +3 -27
- package/src/components/table/index.ts +0 -2
- package/src/components/table/selection-toolbar.tsx +35 -1
- package/src/components/table/table-empty-state.tsx +6 -3
- package/src/components/table/table-no-results.tsx +10 -5
- package/src/components/table/types.ts +0 -5
- package/src/components/taxes/tax-list-table/locales/de.ts +1 -0
- package/src/components/taxes/tax-list-table/locales/es.ts +1 -0
- package/src/components/taxes/tax-list-table/locales/fr.ts +1 -0
- package/src/components/taxes/tax-list-table/locales/hr.ts +1 -0
- package/src/components/taxes/tax-list-table/locales/it.ts +1 -0
- package/src/components/taxes/tax-list-table/locales/nl.ts +1 -0
- package/src/components/taxes/tax-list-table/locales/pl.ts +1 -0
- package/src/components/taxes/tax-list-table/locales/pt.ts +1 -0
- package/src/components/taxes/tax-list-table/locales/sl.ts +1 -0
- package/src/components/taxes/tax-list-table/tax-list-header.tsx +3 -14
- package/src/components/taxes/tax-list-table/tax-list-table.tsx +3 -3
- package/src/components/ui/popover.tsx +3 -1
- package/src/components/ui/tooltip.tsx +3 -1
- package/src/generated/schemas/deliverynote.ts +134 -0
- package/src/generated/schemas/entity.ts +4 -0
- package/src/generated/schemas/index.ts +3 -0
- package/src/generated/schemas/order.ts +5 -3
- package/src/generated/schemas/payment.ts +22 -2
- package/src/generated/schemas/renderadvanceinvoicepreview_body.ts +1 -0
- package/src/generated/schemas/rendercreditnotepreview_body.ts +1 -0
- package/src/generated/schemas/renderdeliverynotepreview_body.ts +185 -0
- package/src/generated/schemas/renderestimatepreview_body.ts +1 -0
- package/src/generated/schemas/renderinvoicepreview_body.ts +1 -0
- package/src/generated/schemas/startpdfexport_body.ts +18 -2
- package/src/generated/schemas/userfinasettings.ts +19 -0
- package/src/generated/schemas/webhook.ts +12 -0
- package/src/hooks/use-duplicate-document.ts +49 -6
- package/src/hooks/use-next-document-number.ts +2 -2
- package/src/lib/fiscalization.ts +12 -0
- package/src/lib/schemas/advance-invoice.ts +0 -1
- package/src/providers/sdk-provider.tsx +5 -7
- package/src/components/table/sortable-header.tsx +0 -56
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Table Component Library
|
|
2
2
|
|
|
3
|
-
A comprehensive, type-safe table system with built-in
|
|
3
|
+
A comprehensive, type-safe table system with built-in search, pagination, and loading states.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
@@ -32,7 +32,6 @@ function InvoiceTable() {
|
|
|
32
32
|
{
|
|
33
33
|
id: "number",
|
|
34
34
|
header: "Invoice #",
|
|
35
|
-
sortable: true,
|
|
36
35
|
cell: (invoice) => (
|
|
37
36
|
<a href={`/invoices/${invoice.id}`} className="underline">
|
|
38
37
|
{invoice.number}
|
|
@@ -47,14 +46,12 @@ function InvoiceTable() {
|
|
|
47
46
|
{
|
|
48
47
|
id: "date",
|
|
49
48
|
header: "Date",
|
|
50
|
-
sortable: true,
|
|
51
49
|
cell: (invoice) => <FormattedDate date={invoice.date} />,
|
|
52
50
|
},
|
|
53
51
|
{
|
|
54
52
|
id: "total",
|
|
55
53
|
header: "Total",
|
|
56
54
|
align: "right",
|
|
57
|
-
sortable: true,
|
|
58
55
|
cell: (invoice) => `$${invoice.total}`,
|
|
59
56
|
},
|
|
60
57
|
]}
|
|
@@ -81,17 +78,12 @@ function InvoiceTable() {
|
|
|
81
78
|
return (
|
|
82
79
|
<DataTable<Invoice>
|
|
83
80
|
columns={[
|
|
84
|
-
{
|
|
85
|
-
{
|
|
86
|
-
{
|
|
87
|
-
{
|
|
81
|
+
{ id: "number", header: "Number" },
|
|
82
|
+
{ id: "customer", header: "Customer" },
|
|
83
|
+
{ id: "date", header: "Date" },
|
|
84
|
+
{ id: "total", header: "Total", align: "right" },
|
|
88
85
|
]}
|
|
89
|
-
renderHeader={(
|
|
90
|
-
<InvoiceListHeader
|
|
91
|
-
orderBy={props.orderBy}
|
|
92
|
-
onSort={props.onSort}
|
|
93
|
-
/>
|
|
94
|
-
)}
|
|
86
|
+
renderHeader={() => <InvoiceListHeader />}
|
|
95
87
|
renderRow={(invoice) => (
|
|
96
88
|
<InvoiceListRow
|
|
97
89
|
key={invoice.id}
|
|
@@ -117,7 +109,6 @@ function InvoiceTable() {
|
|
|
117
109
|
| `cacheKey` | `string` | Yes | Unique key for react-query cache |
|
|
118
110
|
| `onFetch` | `(params) => Promise<Response>` | Yes | Data fetch function |
|
|
119
111
|
| `resourceName` | `string` | Yes | Resource name for empty states |
|
|
120
|
-
| `defaultOrderBy` | `string` | No | Default sort order (e.g., "-id") |
|
|
121
112
|
| `queryParams` | `TableQueryParams` | No | External query parameters |
|
|
122
113
|
| `onChangeParams` | `(params) => void` | No | Callback for param changes |
|
|
123
114
|
| `entityId` | `string` | No | Entity ID for multi-tenant filtering |
|
|
@@ -125,7 +116,7 @@ function InvoiceTable() {
|
|
|
125
116
|
| `createNewTrigger` | `ReactNode` | No | Custom create action |
|
|
126
117
|
| `onRowClick` | `(item: T) => void` | No | Row click handler |
|
|
127
118
|
| `renderRow` | `(item: T) => ReactNode` | No | Custom row renderer |
|
|
128
|
-
| `renderHeader` | `(
|
|
119
|
+
| `renderHeader` | `() => ReactNode` | No | Custom header renderer |
|
|
129
120
|
|
|
130
121
|
### Column Definition
|
|
131
122
|
|
|
@@ -133,8 +124,6 @@ function InvoiceTable() {
|
|
|
133
124
|
type Column<T> = {
|
|
134
125
|
id: string; // Unique column identifier
|
|
135
126
|
header: ReactNode; // Header label or component
|
|
136
|
-
sortField?: string; // Field name for sorting (if different from id)
|
|
137
|
-
sortable?: boolean; // Enable sorting
|
|
138
127
|
align?: "left" | "center" | "right"; // Text alignment
|
|
139
128
|
cell?: (item: T) => ReactNode; // Cell renderer function
|
|
140
129
|
className?: string; // Optional CSS classes
|
|
@@ -150,9 +139,8 @@ Manages table state internally with optional URL sync:
|
|
|
150
139
|
```tsx
|
|
151
140
|
import { useTableState } from "@space-invoices/ui";
|
|
152
141
|
|
|
153
|
-
const { params,
|
|
154
|
-
initialParams: {
|
|
155
|
-
defaultOrderBy: "-id",
|
|
142
|
+
const { params, handleSearch, handlePageChange } = useTableState({
|
|
143
|
+
initialParams: {},
|
|
156
144
|
onChangeParams: (params) => {
|
|
157
145
|
// Optional: sync with router or external state
|
|
158
146
|
navigate({ search: params });
|
|
@@ -170,7 +158,7 @@ import { useTableQuery } from "@space-invoices/ui";
|
|
|
170
158
|
const { data, isFetching } = useTableQuery({
|
|
171
159
|
cacheKey: "customers",
|
|
172
160
|
fetchFn: (params) => sdk.customers.getCustomers(params),
|
|
173
|
-
params: {
|
|
161
|
+
params: { search: "acme" },
|
|
174
162
|
entityId: "entity-123",
|
|
175
163
|
});
|
|
176
164
|
```
|
|
@@ -203,21 +191,6 @@ Search input with optional debouncing:
|
|
|
203
191
|
/>
|
|
204
192
|
```
|
|
205
193
|
|
|
206
|
-
### SortableHeader
|
|
207
|
-
|
|
208
|
-
Sortable column header with visual indicators:
|
|
209
|
-
|
|
210
|
-
```tsx
|
|
211
|
-
<SortableHeader
|
|
212
|
-
field="name"
|
|
213
|
-
currentOrder="-name"
|
|
214
|
-
onSort={(order) => console.log(order)}
|
|
215
|
-
align="left"
|
|
216
|
-
>
|
|
217
|
-
Customer Name
|
|
218
|
-
</SortableHeader>
|
|
219
|
-
```
|
|
220
|
-
|
|
221
194
|
### Pagination
|
|
222
195
|
|
|
223
196
|
Cursor-based pagination controls:
|
|
@@ -259,7 +232,6 @@ For straightforward tables, define columns with cell renderers:
|
|
|
259
232
|
{
|
|
260
233
|
id: "name",
|
|
261
234
|
header: "Name",
|
|
262
|
-
sortable: true,
|
|
263
235
|
cell: (item) => item.name,
|
|
264
236
|
},
|
|
265
237
|
{
|
|
@@ -281,14 +253,14 @@ For advanced tables with complex row/header components:
|
|
|
281
253
|
```tsx
|
|
282
254
|
<DataTable
|
|
283
255
|
columns={[
|
|
284
|
-
{ id: "name", header: "Name"
|
|
256
|
+
{ id: "name", header: "Name" },
|
|
285
257
|
{ id: "email", header: "Email" },
|
|
286
258
|
]}
|
|
287
259
|
renderRow={(item) => (
|
|
288
260
|
<CustomRow key={item.id} item={item} />
|
|
289
261
|
)}
|
|
290
|
-
renderHeader={(
|
|
291
|
-
<CustomHeader
|
|
262
|
+
renderHeader={() => (
|
|
263
|
+
<CustomHeader />
|
|
292
264
|
)}
|
|
293
265
|
cacheKey="users"
|
|
294
266
|
resourceName="user"
|
|
@@ -296,84 +268,6 @@ For advanced tables with complex row/header components:
|
|
|
296
268
|
/>
|
|
297
269
|
```
|
|
298
270
|
|
|
299
|
-
## Key Improvements
|
|
300
|
-
|
|
301
|
-
### 1. Simplified State Management
|
|
302
|
-
|
|
303
|
-
**Before:**
|
|
304
|
-
- Manual `useState` for params
|
|
305
|
-
- Manual URL sync with `updateQueryParams`
|
|
306
|
-
- Complex callback chains
|
|
307
|
-
|
|
308
|
-
**After:**
|
|
309
|
-
- `useTableState` hook handles everything
|
|
310
|
-
- Automatic URL sync
|
|
311
|
-
- Single source of truth
|
|
312
|
-
|
|
313
|
-
### 2. Cleaner Hooks
|
|
314
|
-
|
|
315
|
-
**Before:**
|
|
316
|
-
```tsx
|
|
317
|
-
const { data, isFetching } = useTableQuery({
|
|
318
|
-
cacheKey,
|
|
319
|
-
fetchFn,
|
|
320
|
-
params,
|
|
321
|
-
entityId,
|
|
322
|
-
});
|
|
323
|
-
|
|
324
|
-
// Unnecessary isMounted ref logic
|
|
325
|
-
const isMounted = useRef(true);
|
|
326
|
-
```
|
|
327
|
-
|
|
328
|
-
**After:**
|
|
329
|
-
```tsx
|
|
330
|
-
// Simplified, no ref needed
|
|
331
|
-
const { data, isFetching } = useTableQuery({
|
|
332
|
-
cacheKey,
|
|
333
|
-
fetchFn,
|
|
334
|
-
params,
|
|
335
|
-
entityId,
|
|
336
|
-
});
|
|
337
|
-
```
|
|
338
|
-
|
|
339
|
-
### 3. Better Column API
|
|
340
|
-
|
|
341
|
-
**Before:**
|
|
342
|
-
- Column definitions not used for rendering
|
|
343
|
-
- Must implement custom row/header components
|
|
344
|
-
|
|
345
|
-
**After:**
|
|
346
|
-
- Column definitions drive rendering
|
|
347
|
-
- Optional custom renderers for flexibility
|
|
348
|
-
- Built-in cell renderers via `cell` prop
|
|
349
|
-
|
|
350
|
-
### 4. Improved Type Safety
|
|
351
|
-
|
|
352
|
-
**Before:**
|
|
353
|
-
```typescript
|
|
354
|
-
// Loose typing on columns
|
|
355
|
-
columns: { field: string; header: React.ReactNode }[]
|
|
356
|
-
```
|
|
357
|
-
|
|
358
|
-
**After:**
|
|
359
|
-
```typescript
|
|
360
|
-
// Strongly typed with generics
|
|
361
|
-
columns: Column<T>[]
|
|
362
|
-
// T is your data type (e.g., Invoice, Customer)
|
|
363
|
-
```
|
|
364
|
-
|
|
365
|
-
### 5. Better UX
|
|
366
|
-
|
|
367
|
-
**Before:**
|
|
368
|
-
- Basic search input
|
|
369
|
-
- Minimal empty states
|
|
370
|
-
|
|
371
|
-
**After:**
|
|
372
|
-
- Search with clear button
|
|
373
|
-
- Rich empty states with icons
|
|
374
|
-
- Better error handling in date formatter
|
|
375
|
-
- Improved accessibility
|
|
376
|
-
|
|
377
271
|
## Best Practices
|
|
378
272
|
|
|
379
273
|
1. **Use column definitions for simple tables**: Less code, easier to maintain
|
|
@@ -382,8 +276,7 @@ columns: Column<T>[]
|
|
|
382
276
|
4. **Handle loading states**: The component handles this automatically
|
|
383
277
|
5. **Provide meaningful resource names**: Used in empty states
|
|
384
278
|
6. **Use FormattedDate**: Consistent date formatting with error handling
|
|
385
|
-
7. **
|
|
386
|
-
8. **Use proper TypeScript types**: Import from `@spaceinvoices/js-sdk`
|
|
279
|
+
7. **Use proper TypeScript types**: Import from `@spaceinvoices/js-sdk`
|
|
387
280
|
|
|
388
281
|
## Testing
|
|
389
282
|
|
|
@@ -6,7 +6,6 @@ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@
|
|
|
6
6
|
import { FilterBar } from "./filter-bar";
|
|
7
7
|
import { useTableQuery } from "./hooks/use-table-query";
|
|
8
8
|
import { useTableState } from "./hooks/use-table-state";
|
|
9
|
-
import { SortableHeader } from "./sortable-header";
|
|
10
9
|
import { TableEmptyState } from "./table-empty-state";
|
|
11
10
|
import { TableNoResults } from "./table-no-results";
|
|
12
11
|
import { Pagination } from "./table-pagination";
|
|
@@ -22,8 +21,6 @@ export type DataTableProps<T> = {
|
|
|
22
21
|
onFetch: (params: TableQueryParams) => Promise<TableQueryResponse<T>>;
|
|
23
22
|
/** Resource name for empty states (e.g., "customer", "invoice") */
|
|
24
23
|
resourceName: string;
|
|
25
|
-
/** Default sort order (e.g., "-id", "name") */
|
|
26
|
-
defaultOrderBy?: string;
|
|
27
24
|
/** Initial/external query parameters */
|
|
28
25
|
queryParams?: TableQueryParams;
|
|
29
26
|
/** Callback when params change (for external state management) */
|
|
@@ -36,12 +33,14 @@ export type DataTableProps<T> = {
|
|
|
36
33
|
createNewLink?: string;
|
|
37
34
|
/** Custom trigger for create action */
|
|
38
35
|
createNewTrigger?: ReactNode;
|
|
36
|
+
/** Callback for "Create new" click — enables client-side navigation instead of full page reload */
|
|
37
|
+
onCreateNew?: () => void;
|
|
39
38
|
/** Optional row click handler */
|
|
40
39
|
onRowClick?: (item: T) => void;
|
|
41
40
|
/** Custom row renderer (overrides default cell rendering) */
|
|
42
41
|
renderRow?: (item: T) => ReactNode;
|
|
43
42
|
/** Custom header renderer (overrides default header) */
|
|
44
|
-
renderHeader?: (
|
|
43
|
+
renderHeader?: () => ReactNode;
|
|
45
44
|
/** Filter configuration (date fields, status filter) */
|
|
46
45
|
filterConfig?: FilterConfig;
|
|
47
46
|
/** Translation function */
|
|
@@ -55,7 +54,7 @@ export type DataTableProps<T> = {
|
|
|
55
54
|
/** Callback when selection changes */
|
|
56
55
|
onSelectionChange?: (selectedIds: Set<string>) => void;
|
|
57
56
|
/** Content to render in selection toolbar (shown when items selected) */
|
|
58
|
-
selectionToolbar?: (selectedCount: number) => ReactNode;
|
|
57
|
+
selectionToolbar?: (selectedCount: number, data: T[]) => ReactNode;
|
|
59
58
|
};
|
|
60
59
|
|
|
61
60
|
/**
|
|
@@ -66,13 +65,13 @@ export function DataTable<T extends { id: string }>({
|
|
|
66
65
|
cacheKey,
|
|
67
66
|
onFetch,
|
|
68
67
|
resourceName,
|
|
69
|
-
defaultOrderBy = "-id",
|
|
70
68
|
queryParams,
|
|
71
69
|
onChangeParams,
|
|
72
70
|
disableUrlSync,
|
|
73
71
|
entityId,
|
|
74
72
|
createNewLink,
|
|
75
73
|
createNewTrigger,
|
|
74
|
+
onCreateNew,
|
|
76
75
|
onRowClick,
|
|
77
76
|
renderRow,
|
|
78
77
|
renderHeader,
|
|
@@ -94,14 +93,12 @@ export function DataTable<T extends { id: string }>({
|
|
|
94
93
|
);
|
|
95
94
|
const [filterPanelOpen, setFilterPanelOpen] = useState(hasInitialFilters);
|
|
96
95
|
|
|
97
|
-
// Manage table state (
|
|
98
|
-
const { params, apiParams, filterState,
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
disableUrlSync,
|
|
104
|
-
});
|
|
96
|
+
// Manage table state (search, pagination, filters)
|
|
97
|
+
const { params, apiParams, filterState, handleSearch, handlePageChange, handleFilterChange } = useTableState({
|
|
98
|
+
initialParams: queryParams,
|
|
99
|
+
onChangeParams,
|
|
100
|
+
disableUrlSync,
|
|
101
|
+
});
|
|
105
102
|
|
|
106
103
|
// Fetch table data (use apiParams which has the query JSON for API)
|
|
107
104
|
const { data: queryResult, isFetching } = useTableQuery<T>({
|
|
@@ -121,6 +118,12 @@ export function DataTable<T extends { id: string }>({
|
|
|
121
118
|
params.filter_http_status,
|
|
122
119
|
);
|
|
123
120
|
|
|
121
|
+
// Combined clear handler for both search and filters
|
|
122
|
+
const handleClearAll = useCallback(() => {
|
|
123
|
+
handleSearch(null);
|
|
124
|
+
handleFilterChange(null);
|
|
125
|
+
}, [handleSearch, handleFilterChange]);
|
|
126
|
+
|
|
124
127
|
// Selection helpers
|
|
125
128
|
const pageIds = useMemo(() => data.map((item) => item.id), [data]);
|
|
126
129
|
const selectedCount = selectedIds?.size ?? 0;
|
|
@@ -186,6 +189,7 @@ export function DataTable<T extends { id: string }>({
|
|
|
186
189
|
resource={resourceName}
|
|
187
190
|
createNewLink={createNewLink}
|
|
188
191
|
createNewTrigger={createNewTrigger}
|
|
192
|
+
onCreateNew={onCreateNew}
|
|
189
193
|
t={t}
|
|
190
194
|
/>
|
|
191
195
|
);
|
|
@@ -207,19 +211,17 @@ export function DataTable<T extends { id: string }>({
|
|
|
207
211
|
|
|
208
212
|
{selectable && selectedCount > 0 && selectionToolbar && (
|
|
209
213
|
<div className="flex items-center gap-3 rounded-lg border bg-muted/50 px-4 py-2">
|
|
210
|
-
{selectionToolbar(selectedCount)}
|
|
214
|
+
{selectionToolbar(selectedCount, data)}
|
|
211
215
|
</div>
|
|
212
216
|
)}
|
|
213
217
|
|
|
214
218
|
<div className="rounded-lg border">
|
|
215
219
|
<Table>
|
|
216
220
|
{renderHeader ? (
|
|
217
|
-
renderHeader(
|
|
221
|
+
renderHeader()
|
|
218
222
|
) : (
|
|
219
223
|
<DefaultTableHeader
|
|
220
224
|
columns={columns}
|
|
221
|
-
orderBy={params.order_by}
|
|
222
|
-
onSort={handleSort}
|
|
223
225
|
selectable={selectable}
|
|
224
226
|
allPageSelected={allPageSelected}
|
|
225
227
|
somePageSelected={somePageSelected}
|
|
@@ -249,7 +251,7 @@ export function DataTable<T extends { id: string }>({
|
|
|
249
251
|
);
|
|
250
252
|
})
|
|
251
253
|
) : (
|
|
252
|
-
<TableNoResults resource={resourceName} search={handleSearch} t={t} />
|
|
254
|
+
<TableNoResults resource={resourceName} search={handleSearch} onClear={handleClearAll} t={t} />
|
|
253
255
|
)}
|
|
254
256
|
</TableBody>
|
|
255
257
|
</Table>
|
|
@@ -271,16 +273,12 @@ export function DataTable<T extends { id: string }>({
|
|
|
271
273
|
*/
|
|
272
274
|
const DefaultTableHeader = memo(function DefaultTableHeader<T>({
|
|
273
275
|
columns,
|
|
274
|
-
orderBy,
|
|
275
|
-
onSort,
|
|
276
276
|
selectable,
|
|
277
277
|
allPageSelected,
|
|
278
278
|
somePageSelected,
|
|
279
279
|
onToggleAll,
|
|
280
280
|
}: {
|
|
281
281
|
columns: Column<T>[];
|
|
282
|
-
orderBy?: string;
|
|
283
|
-
onSort?: (order: string | null) => void;
|
|
284
282
|
selectable?: boolean;
|
|
285
283
|
allPageSelected?: boolean;
|
|
286
284
|
somePageSelected?: boolean;
|
|
@@ -300,18 +298,7 @@ const DefaultTableHeader = memo(function DefaultTableHeader<T>({
|
|
|
300
298
|
)}
|
|
301
299
|
{columns.map((column) => (
|
|
302
300
|
<TableHead key={column.id} className={column.className} style={{ textAlign: column.align }}>
|
|
303
|
-
{column.
|
|
304
|
-
<SortableHeader
|
|
305
|
-
field={column.sortField ?? column.id}
|
|
306
|
-
currentOrder={orderBy}
|
|
307
|
-
onSort={onSort}
|
|
308
|
-
align={column.align}
|
|
309
|
-
>
|
|
310
|
-
{column.header}
|
|
311
|
-
</SortableHeader>
|
|
312
|
-
) : (
|
|
313
|
-
column.header
|
|
314
|
-
)}
|
|
301
|
+
{column.header}
|
|
315
302
|
</TableHead>
|
|
316
303
|
))}
|
|
317
304
|
</TableRow>
|
|
@@ -319,8 +306,6 @@ const DefaultTableHeader = memo(function DefaultTableHeader<T>({
|
|
|
319
306
|
);
|
|
320
307
|
}) as <T>(props: {
|
|
321
308
|
columns: Column<T>[];
|
|
322
|
-
orderBy?: string;
|
|
323
|
-
onSort?: (order: string | null) => void;
|
|
324
309
|
selectable?: boolean;
|
|
325
310
|
allPageSelected?: boolean;
|
|
326
311
|
somePageSelected?: boolean;
|
|
@@ -3,7 +3,6 @@ import type { FilterState, HttpMethodFilter, HttpStatusCodeFilter, StatusFilter,
|
|
|
3
3
|
|
|
4
4
|
type UseTableStateProps = {
|
|
5
5
|
initialParams?: TableQueryParams;
|
|
6
|
-
defaultOrderBy?: string;
|
|
7
6
|
onChangeParams?: (params: TableQueryParams) => void;
|
|
8
7
|
/** When true, disables URL sync entirely (for embedded tables like dashboard) */
|
|
9
8
|
disableUrlSync?: boolean;
|
|
@@ -115,17 +114,11 @@ export function buildQueryFromFilterState(state: FilterState | null): string | u
|
|
|
115
114
|
}
|
|
116
115
|
|
|
117
116
|
/**
|
|
118
|
-
* Manages table state (
|
|
117
|
+
* Manages table state (search, pagination, filters) with optional URL sync
|
|
119
118
|
*/
|
|
120
|
-
export function useTableState({
|
|
121
|
-
initialParams = {},
|
|
122
|
-
defaultOrderBy = "-id",
|
|
123
|
-
onChangeParams,
|
|
124
|
-
disableUrlSync = false,
|
|
125
|
-
}: UseTableStateProps) {
|
|
119
|
+
export function useTableState({ initialParams = {}, onChangeParams, disableUrlSync = false }: UseTableStateProps) {
|
|
126
120
|
const [params, setParams] = useState<TableQueryParams>({
|
|
127
121
|
...initialParams,
|
|
128
|
-
order_by: initialParams.order_by ?? defaultOrderBy,
|
|
129
122
|
});
|
|
130
123
|
|
|
131
124
|
// Use ref for onChangeParams to keep it stable
|
|
@@ -147,10 +140,9 @@ export function useTableState({
|
|
|
147
140
|
isUpdatingFromInitialRef.current = true;
|
|
148
141
|
setParams({
|
|
149
142
|
...initialParams,
|
|
150
|
-
order_by: initialParams.order_by ?? defaultOrderBy,
|
|
151
143
|
});
|
|
152
144
|
}
|
|
153
|
-
}, [initialParams
|
|
145
|
+
}, [initialParams]);
|
|
154
146
|
|
|
155
147
|
// Sync params to parent or URL when they change
|
|
156
148
|
useEffect(() => {
|
|
@@ -185,21 +177,6 @@ export function useTableState({
|
|
|
185
177
|
}
|
|
186
178
|
}, [params, disableUrlSync]);
|
|
187
179
|
|
|
188
|
-
/**
|
|
189
|
-
* Handle sort change
|
|
190
|
-
*/
|
|
191
|
-
const handleSort = useCallback(
|
|
192
|
-
(order: string | null) => {
|
|
193
|
-
setParams((prevParams) => ({
|
|
194
|
-
...prevParams,
|
|
195
|
-
order_by: order ?? defaultOrderBy,
|
|
196
|
-
prev_cursor: undefined,
|
|
197
|
-
next_cursor: undefined,
|
|
198
|
-
}));
|
|
199
|
-
},
|
|
200
|
-
[defaultOrderBy],
|
|
201
|
-
);
|
|
202
|
-
|
|
203
180
|
/**
|
|
204
181
|
* Handle search change
|
|
205
182
|
*/
|
|
@@ -285,7 +262,6 @@ export function useTableState({
|
|
|
285
262
|
params,
|
|
286
263
|
apiParams,
|
|
287
264
|
filterState,
|
|
288
|
-
handleSort,
|
|
289
265
|
handleSearch,
|
|
290
266
|
handlePageChange,
|
|
291
267
|
handleFilterChange,
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
* Table Component Library
|
|
3
3
|
*
|
|
4
4
|
* A comprehensive, type-safe table system with built-in:
|
|
5
|
-
* - Sorting (client and server-side)
|
|
6
5
|
* - Search/filtering
|
|
7
6
|
* - Cursor-based pagination
|
|
8
7
|
* - Loading states
|
|
@@ -20,7 +19,6 @@ export { useTableQuery } from "./hooks/use-table-query";
|
|
|
20
19
|
export { useTableState } from "./hooks/use-table-state";
|
|
21
20
|
// Supporting components
|
|
22
21
|
export { SearchInput } from "./search-input";
|
|
23
|
-
export { SortableHeader } from "./sortable-header";
|
|
24
22
|
export { TableEmptyState } from "./table-empty-state";
|
|
25
23
|
export { TableNoResults } from "./table-no-results";
|
|
26
24
|
export { Pagination } from "./table-pagination";
|
|
@@ -1,9 +1,14 @@
|
|
|
1
|
-
import { FileDown, X } from "lucide-react";
|
|
1
|
+
import { FileDown, FileText, RefreshCw, X } from "lucide-react";
|
|
2
2
|
import { Button } from "@/ui/components/ui/button";
|
|
3
|
+
import { Tooltip, TooltipContent, TooltipTrigger } from "@/ui/components/ui/tooltip";
|
|
3
4
|
|
|
4
5
|
type SelectionToolbarProps = {
|
|
5
6
|
selectedCount: number;
|
|
6
7
|
onExportPdfs?: () => void;
|
|
8
|
+
onCopyToInvoice?: () => void;
|
|
9
|
+
onRetryFiscalization?: () => void;
|
|
10
|
+
retryFiscalizationDisabled?: boolean;
|
|
11
|
+
retryFiscalizationTooltip?: string;
|
|
7
12
|
onDeselectAll?: () => void;
|
|
8
13
|
t?: (key: string) => string;
|
|
9
14
|
};
|
|
@@ -11,6 +16,10 @@ type SelectionToolbarProps = {
|
|
|
11
16
|
export function SelectionToolbar({
|
|
12
17
|
selectedCount,
|
|
13
18
|
onExportPdfs,
|
|
19
|
+
onCopyToInvoice,
|
|
20
|
+
onRetryFiscalization,
|
|
21
|
+
retryFiscalizationDisabled,
|
|
22
|
+
retryFiscalizationTooltip,
|
|
14
23
|
onDeselectAll,
|
|
15
24
|
t = (key) => key,
|
|
16
25
|
}: SelectionToolbarProps) {
|
|
@@ -25,6 +34,31 @@ export function SelectionToolbar({
|
|
|
25
34
|
{t("Export PDFs")}
|
|
26
35
|
</Button>
|
|
27
36
|
)}
|
|
37
|
+
{onCopyToInvoice && (
|
|
38
|
+
<Button variant="outline" size="sm" onClick={onCopyToInvoice}>
|
|
39
|
+
<FileText className="mr-1.5 size-4" />
|
|
40
|
+
{t("Copy to Invoice")}
|
|
41
|
+
</Button>
|
|
42
|
+
)}
|
|
43
|
+
{onRetryFiscalization &&
|
|
44
|
+
(retryFiscalizationDisabled && retryFiscalizationTooltip ? (
|
|
45
|
+
<Tooltip>
|
|
46
|
+
<TooltipTrigger>
|
|
47
|
+
<span>
|
|
48
|
+
<Button variant="outline" size="sm" disabled>
|
|
49
|
+
<RefreshCw className="mr-1.5 size-4" />
|
|
50
|
+
{t("Retry Fiscalization")}
|
|
51
|
+
</Button>
|
|
52
|
+
</span>
|
|
53
|
+
</TooltipTrigger>
|
|
54
|
+
<TooltipContent>{retryFiscalizationTooltip}</TooltipContent>
|
|
55
|
+
</Tooltip>
|
|
56
|
+
) : (
|
|
57
|
+
<Button variant="outline" size="sm" onClick={onRetryFiscalization}>
|
|
58
|
+
<RefreshCw className="mr-1.5 size-4" />
|
|
59
|
+
{t("Retry Fiscalization")}
|
|
60
|
+
</Button>
|
|
61
|
+
))}
|
|
28
62
|
{onDeselectAll && (
|
|
29
63
|
<Button variant="ghost" size="sm" onClick={onDeselectAll}>
|
|
30
64
|
<X className="mr-1.5 size-4" />
|
|
@@ -6,6 +6,8 @@ type TableEmptyStateProps = {
|
|
|
6
6
|
resource: string;
|
|
7
7
|
createNewLink?: string;
|
|
8
8
|
createNewTrigger?: React.ReactNode;
|
|
9
|
+
/** Callback for "Create new" click — enables client-side navigation instead of full page reload */
|
|
10
|
+
onCreateNew?: () => void;
|
|
9
11
|
/** Number of rows to calculate height (default: 10) */
|
|
10
12
|
rows?: number;
|
|
11
13
|
/** Translation function */
|
|
@@ -21,6 +23,7 @@ const ROW_HEIGHT = 53;
|
|
|
21
23
|
export function TableEmptyState({
|
|
22
24
|
createNewLink,
|
|
23
25
|
createNewTrigger,
|
|
26
|
+
onCreateNew,
|
|
24
27
|
rows = 10,
|
|
25
28
|
t = (key) => key,
|
|
26
29
|
}: TableEmptyStateProps) {
|
|
@@ -32,13 +35,13 @@ export function TableEmptyState({
|
|
|
32
35
|
<Sprout size={70} strokeWidth={0.35} className="text-muted-foreground" />
|
|
33
36
|
<div className="space-y-1 text-center">
|
|
34
37
|
<p className="font-light text-lg text-muted-foreground">{t("Your list is empty")}</p>
|
|
35
|
-
{(createNewLink || createNewTrigger) && (
|
|
38
|
+
{(createNewLink || createNewTrigger || onCreateNew) && (
|
|
36
39
|
<p className="text-muted-foreground text-sm">{t("Get started by creating your first entry")}</p>
|
|
37
40
|
)}
|
|
38
41
|
</div>
|
|
39
42
|
{createNewLink && (
|
|
40
|
-
<Button variant="default" size="sm" asChild>
|
|
41
|
-
<a href={createNewLink}>{t("Create new")}</a>
|
|
43
|
+
<Button variant="default" size="sm" {...(onCreateNew ? { onClick: onCreateNew } : { asChild: true })}>
|
|
44
|
+
{onCreateNew ? t("Create new") : <a href={createNewLink}>{t("Create new")}</a>}
|
|
42
45
|
</Button>
|
|
43
46
|
)}
|
|
44
47
|
{createNewTrigger && !createNewLink && <div>{createNewTrigger}</div>}
|
|
@@ -6,6 +6,8 @@ import { TableCell, TableRow } from "@/ui/components/ui/table";
|
|
|
6
6
|
type TableNoResultsProps = {
|
|
7
7
|
resource: string;
|
|
8
8
|
search?: (value: null) => void;
|
|
9
|
+
/** Combined clear handler for both search and filters */
|
|
10
|
+
onClear?: () => void;
|
|
9
11
|
/** Number of rows to calculate height (default: 10) */
|
|
10
12
|
rows?: number;
|
|
11
13
|
/** Translation function */
|
|
@@ -18,10 +20,13 @@ const ROW_HEIGHT = 53;
|
|
|
18
20
|
/**
|
|
19
21
|
* No results message shown when search returns empty
|
|
20
22
|
*/
|
|
21
|
-
export function TableNoResults({ search, rows = 10, t = (key) => key }: TableNoResultsProps) {
|
|
23
|
+
export function TableNoResults({ search, onClear, rows = 10, t = (key) => key }: TableNoResultsProps) {
|
|
22
24
|
// Calculate height based on row count (min 150px)
|
|
23
25
|
const height = Math.max(rows * ROW_HEIGHT, 150);
|
|
24
26
|
|
|
27
|
+
const handleClear = onClear ?? (search ? () => search(null) : undefined);
|
|
28
|
+
const clearLabel = onClear ? t("Clear all") : t("Clear search");
|
|
29
|
+
|
|
25
30
|
return (
|
|
26
31
|
<TableRow className="hover:bg-transparent">
|
|
27
32
|
<TableCell colSpan={100} className="text-center align-middle" style={{ height }}>
|
|
@@ -29,11 +34,11 @@ export function TableNoResults({ search, rows = 10, t = (key) => key }: TableNoR
|
|
|
29
34
|
<FileX size={32} strokeWidth={1.5} className="text-muted-foreground" />
|
|
30
35
|
<div className="space-y-1">
|
|
31
36
|
<p className="font-medium text-muted-foreground">{t("No results found")}</p>
|
|
32
|
-
{
|
|
37
|
+
{handleClear && <p className="text-muted-foreground text-sm">{t("Try adjusting your search criteria")}</p>}
|
|
33
38
|
</div>
|
|
34
|
-
{
|
|
35
|
-
<Button variant="link" size="sm" onClick={
|
|
36
|
-
{
|
|
39
|
+
{handleClear && (
|
|
40
|
+
<Button variant="link" size="sm" onClick={handleClear} className="underline">
|
|
41
|
+
{clearLabel}
|
|
37
42
|
</Button>
|
|
38
43
|
)}
|
|
39
44
|
</div>
|
|
@@ -10,10 +10,6 @@ export type Column<T> = {
|
|
|
10
10
|
header: ReactNode;
|
|
11
11
|
/** Cell renderer function - returns content for each row. Optional when using renderRow. */
|
|
12
12
|
cell?: (item: T) => ReactNode;
|
|
13
|
-
/** Field name for sorting (if different from id) */
|
|
14
|
-
sortField?: string;
|
|
15
|
-
/** Whether this column is sortable */
|
|
16
|
-
sortable?: boolean;
|
|
17
13
|
/** Text alignment */
|
|
18
14
|
align?: "left" | "center" | "right";
|
|
19
15
|
/** Optional CSS class for the column */
|
|
@@ -24,7 +20,6 @@ export type Column<T> = {
|
|
|
24
20
|
* Query parameters for table data fetching
|
|
25
21
|
*/
|
|
26
22
|
export type TableQueryParams = {
|
|
27
|
-
order_by?: string;
|
|
28
23
|
search?: string;
|
|
29
24
|
prev_cursor?: string;
|
|
30
25
|
next_cursor?: string;
|