@spaceinvoices/react-ui 0.4.3 → 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 +80 -50
- package/src/components/advance-invoices/list/locales/de.ts +5 -0
- package/src/components/advance-invoices/list/locales/en.ts +4 -0
- package/src/components/advance-invoices/list/locales/es.ts +5 -0
- package/src/components/advance-invoices/list/locales/fr.ts +5 -0
- package/src/components/advance-invoices/list/locales/hr.ts +5 -0
- package/src/components/advance-invoices/list/locales/it.ts +5 -0
- package/src/components/advance-invoices/list/locales/nl.ts +5 -0
- package/src/components/advance-invoices/list/locales/pl.ts +5 -0
- package/src/components/advance-invoices/list/locales/pt.ts +5 -0
- package/src/components/advance-invoices/list/locales/sl.ts +5 -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 +77 -30
- package/src/components/credit-notes/list/locales/de.ts +5 -0
- package/src/components/credit-notes/list/locales/en.ts +4 -0
- package/src/components/credit-notes/list/locales/es.ts +5 -0
- package/src/components/credit-notes/list/locales/fr.ts +5 -0
- package/src/components/credit-notes/list/locales/hr.ts +5 -0
- package/src/components/credit-notes/list/locales/it.ts +5 -0
- package/src/components/credit-notes/list/locales/nl.ts +5 -0
- package/src/components/credit-notes/list/locales/pl.ts +5 -0
- package/src/components/credit-notes/list/locales/pt.ts +5 -0
- package/src/components/credit-notes/list/locales/sl.ts +5 -0
- 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/delivery-notes/list/list-row-actions.tsx +20 -1
- package/src/components/delivery-notes/list/list-table.tsx +41 -8
- package/src/components/delivery-notes/list/locales/de.ts +4 -0
- package/src/components/delivery-notes/list/locales/en.ts +2 -0
- package/src/components/delivery-notes/list/locales/es.ts +4 -0
- package/src/components/delivery-notes/list/locales/fr.ts +4 -0
- package/src/components/delivery-notes/list/locales/hr.ts +4 -0
- package/src/components/delivery-notes/list/locales/it.ts +4 -0
- package/src/components/delivery-notes/list/locales/nl.ts +4 -0
- package/src/components/delivery-notes/list/locales/pl.ts +4 -0
- package/src/components/delivery-notes/list/locales/pt.ts +4 -0
- package/src/components/delivery-notes/list/locales/sl.ts +4 -0
- package/src/components/documents/create/document-details-section.tsx +41 -27
- package/src/components/documents/create/linked-documents-info.tsx +82 -0
- package/src/components/documents/create/live-preview.tsx +1 -1
- package/src/components/documents/types.ts +2 -2
- package/src/components/documents/view/document-activities-list.tsx +65 -47
- package/src/components/documents/view/document-details-card.tsx +99 -74
- package/src/components/documents/view/document-payments-list.tsx +99 -65
- package/src/components/documents/view/document-relations-list.tsx +43 -28
- 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 +2 -0
- package/src/components/documents/view/locales/es.ts +2 -0
- package/src/components/documents/view/locales/fr.ts +2 -0
- package/src/components/documents/view/locales/hr.ts +2 -0
- package/src/components/documents/view/locales/it.ts +2 -0
- package/src/components/documents/view/locales/nl.ts +2 -0
- package/src/components/documents/view/locales/pl.ts +2 -0
- package/src/components/documents/view/locales/pt.ts +2 -0
- package/src/components/documents/view/locales/sl.ts +2 -0
- package/src/components/documents/view/use-document-download.ts +3 -2
- 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 +6 -6
- 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/locales/en.ts +0 -1
- 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 +4 -1
- package/src/components/invoices/list/list-table.tsx +77 -31
- package/src/components/invoices/list/locales/de.ts +5 -0
- package/src/components/invoices/list/locales/en.ts +4 -0
- package/src/components/invoices/list/locales/es.ts +5 -0
- package/src/components/invoices/list/locales/fr.ts +5 -0
- package/src/components/invoices/list/locales/hr.ts +5 -0
- package/src/components/invoices/list/locales/it.ts +5 -0
- package/src/components/invoices/list/locales/nl.ts +5 -0
- package/src/components/invoices/list/locales/pl.ts +5 -0
- package/src/components/invoices/list/locales/pt.ts +5 -0
- package/src/components/invoices/list/locales/sl.ts +5 -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-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/index.ts +1 -1
- package/src/hooks/use-duplicate-document.ts +40 -5
- package/src/lib/fiscalization.ts +12 -0
- package/src/lib/schemas/advance-invoice.ts +0 -1
- package/src/components/table/sortable-header.tsx +0 -56
|
@@ -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;
|
|
@@ -1,27 +1,16 @@
|
|
|
1
1
|
import { TableHead, TableHeader, TableRow } from "@/ui/components/ui/table";
|
|
2
|
-
import { SortableHeader } from "../../table/sortable-header";
|
|
3
2
|
|
|
4
3
|
type TaxListHeaderProps = {
|
|
5
|
-
orderBy?: string;
|
|
6
|
-
onSort?: (order: string | null) => void;
|
|
7
4
|
t: (key: string) => string;
|
|
8
5
|
};
|
|
9
6
|
|
|
10
|
-
export default function TaxListHeader({
|
|
7
|
+
export default function TaxListHeader({ t }: TaxListHeaderProps) {
|
|
11
8
|
return (
|
|
12
9
|
<TableHeader>
|
|
13
10
|
<TableRow>
|
|
14
|
-
<TableHead>
|
|
15
|
-
<SortableHeader field="name" currentOrder={orderBy} onSort={onSort}>
|
|
16
|
-
{t("Name")}
|
|
17
|
-
</SortableHeader>
|
|
18
|
-
</TableHead>
|
|
11
|
+
<TableHead>{t("Name")}</TableHead>
|
|
19
12
|
<TableHead>{t("Tax Rates")}</TableHead>
|
|
20
|
-
<TableHead>
|
|
21
|
-
<SortableHeader field="created_at" currentOrder={orderBy} onSort={onSort}>
|
|
22
|
-
{t("Created")}
|
|
23
|
-
</SortableHeader>
|
|
24
|
-
</TableHead>
|
|
13
|
+
<TableHead>{t("Created")}</TableHead>
|
|
25
14
|
<TableHead className="text-right" />
|
|
26
15
|
</TableRow>
|
|
27
16
|
</TableHeader>
|
|
@@ -58,15 +58,15 @@ export default function TaxListTable({
|
|
|
58
58
|
return (
|
|
59
59
|
<DataTable
|
|
60
60
|
columns={[
|
|
61
|
-
{ id: "name", header: t("Name")
|
|
61
|
+
{ id: "name", header: t("Name") },
|
|
62
62
|
{ id: "tax_rates", header: t("Tax Rates") },
|
|
63
|
-
{ id: "created_at", header: t("Created")
|
|
63
|
+
{ id: "created_at", header: t("Created") },
|
|
64
64
|
{ id: "actions", header: "", align: "right" },
|
|
65
65
|
]}
|
|
66
66
|
renderRow={(tax) => (
|
|
67
67
|
<TaxListRow tax={tax} key={tax.id} onRowClick={(tax) => onRowClick?.(tax)} onView={onView} t={t} />
|
|
68
68
|
)}
|
|
69
|
-
renderHeader={(
|
|
69
|
+
renderHeader={() => <TaxListHeader t={t} />}
|
|
70
70
|
queryParams={queryParams}
|
|
71
71
|
resourceName="tax"
|
|
72
72
|
cacheKey={TAXES_CACHE_KEY}
|
|
@@ -37,11 +37,12 @@ function PopoverContent({
|
|
|
37
37
|
alignOffset = 0,
|
|
38
38
|
side = "bottom",
|
|
39
39
|
sideOffset = 4,
|
|
40
|
+
positionMethod = "fixed",
|
|
40
41
|
...props
|
|
41
42
|
}: PopoverPrimitive.Popup.Props &
|
|
42
43
|
Pick<
|
|
43
44
|
PopoverPrimitive.Positioner.Props,
|
|
44
|
-
"align" | "alignOffset" | "side" | "sideOffset"
|
|
45
|
+
"align" | "alignOffset" | "side" | "sideOffset" | "positionMethod"
|
|
45
46
|
>) {
|
|
46
47
|
return (
|
|
47
48
|
<PopoverPrimitive.Portal>
|
|
@@ -50,6 +51,7 @@ function PopoverContent({
|
|
|
50
51
|
alignOffset={alignOffset}
|
|
51
52
|
side={side}
|
|
52
53
|
sideOffset={sideOffset}
|
|
54
|
+
positionMethod={positionMethod}
|
|
53
55
|
className="isolate z-50"
|
|
54
56
|
>
|
|
55
57
|
<PopoverPrimitive.Popup
|
|
@@ -54,12 +54,13 @@ function TooltipContent({
|
|
|
54
54
|
sideOffset = 4,
|
|
55
55
|
align = "center",
|
|
56
56
|
alignOffset = 0,
|
|
57
|
+
positionMethod = "fixed",
|
|
57
58
|
children,
|
|
58
59
|
...props
|
|
59
60
|
}: TooltipPrimitive.Popup.Props &
|
|
60
61
|
Pick<
|
|
61
62
|
TooltipPrimitive.Positioner.Props,
|
|
62
|
-
"align" | "alignOffset" | "side" | "sideOffset"
|
|
63
|
+
"align" | "alignOffset" | "side" | "sideOffset" | "positionMethod"
|
|
63
64
|
>) {
|
|
64
65
|
return (
|
|
65
66
|
<TooltipPrimitive.Portal>
|
|
@@ -68,6 +69,7 @@ function TooltipContent({
|
|
|
68
69
|
alignOffset={alignOffset}
|
|
69
70
|
side={side}
|
|
70
71
|
sideOffset={sideOffset}
|
|
72
|
+
positionMethod={positionMethod}
|
|
71
73
|
className="isolate z-50"
|
|
72
74
|
>
|
|
73
75
|
<TooltipPrimitive.Popup
|
|
@@ -13,8 +13,8 @@ export * from './customadvanceinvoice';
|
|
|
13
13
|
export * from './customcreditnote';
|
|
14
14
|
export * from './customer';
|
|
15
15
|
export * from './customestimate';
|
|
16
|
-
export * from './deliverynote';
|
|
17
16
|
export * from './custominvoice';
|
|
17
|
+
export * from './deliverynote';
|
|
18
18
|
export * from './entity';
|
|
19
19
|
export * from './entityuserrole';
|
|
20
20
|
export * from './estimate';
|