@vendure/dashboard 3.3.6-master-202507090236 → 3.3.6-master-202507110238
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/dist/plugin/tests/barrel-exports.spec.js +1 -1
- package/package.json +4 -4
- package/src/app/routes/_authenticated/_orders/components/edit-order-table.tsx +30 -37
- package/src/app/routes/_authenticated/_orders/components/fulfillment-details.tsx +33 -53
- package/src/app/routes/_authenticated/_orders/components/order-address.tsx +14 -7
- package/src/app/routes/_authenticated/_orders/components/order-line-custom-fields-form.tsx +23 -12
- package/src/app/routes/_authenticated/_orders/components/order-modification-preview-dialog.tsx +364 -0
- package/src/app/routes/_authenticated/_orders/components/order-modification-summary.tsx +222 -0
- package/src/app/routes/_authenticated/_orders/components/order-table.tsx +146 -85
- package/src/app/routes/_authenticated/_orders/components/payment-details.tsx +268 -31
- package/src/app/routes/_authenticated/_orders/components/settle-refund-dialog.tsx +80 -0
- package/src/app/routes/_authenticated/_orders/components/state-transition-control.tsx +102 -0
- package/src/app/routes/_authenticated/_orders/components/use-transition-order-to-state.tsx +144 -0
- package/src/app/routes/_authenticated/_orders/orders.graphql.ts +118 -2
- package/src/app/routes/_authenticated/_orders/orders_.$id.tsx +144 -52
- package/src/app/routes/_authenticated/_orders/orders_.$id_.modify.tsx +550 -0
- package/src/app/routes/_authenticated/_orders/orders_.draft.$id.tsx +0 -17
- package/src/app/routes/_authenticated/_orders/utils/order-types.ts +5 -2
- package/src/app/routes/_authenticated/_orders/utils/order-utils.ts +4 -3
- package/src/app/routes/_authenticated/_products/products_.$id.tsx +0 -1
- package/src/lib/components/data-display/date-time.tsx +7 -1
- package/src/lib/components/data-input/relation-input.tsx +11 -0
- package/src/lib/components/data-input/relation-selector.tsx +9 -2
- package/src/lib/components/data-table/data-table-utils.ts +34 -0
- package/src/lib/components/data-table/data-table-view-options.tsx +2 -2
- package/src/lib/components/data-table/data-table.tsx +5 -2
- package/src/lib/components/data-table/use-generated-columns.tsx +307 -0
- package/src/lib/components/shared/paginated-list-data-table.tsx +15 -286
- package/src/lib/components/shared/product-variant-selector.tsx +28 -4
- package/src/lib/framework/component-registry/dynamic-component.tsx +3 -3
- package/src/lib/framework/document-introspection/get-document-structure.spec.ts +321 -2
- package/src/lib/framework/document-introspection/get-document-structure.ts +149 -31
- package/src/lib/framework/extension-api/types/layout.ts +21 -6
- package/src/lib/framework/layout-engine/layout-extensions.ts +1 -4
- package/src/lib/framework/layout-engine/page-layout.tsx +61 -10
- package/src/lib/framework/page/use-detail-page.ts +10 -7
- package/vite/tests/barrel-exports.spec.ts +1 -1
|
@@ -40,6 +40,12 @@ export interface RelationSelectorConfig<T = any> {
|
|
|
40
40
|
|
|
41
41
|
export interface RelationSelectorProps<T = any> {
|
|
42
42
|
config: RelationSelectorConfig<T>;
|
|
43
|
+
/**
|
|
44
|
+
* @description
|
|
45
|
+
* The label for the selector trigger. Default is
|
|
46
|
+
* "Select item" for single select and "Select items" for multi select.
|
|
47
|
+
*/
|
|
48
|
+
selectorLabel?: React.ReactNode;
|
|
43
49
|
value?: string | string[];
|
|
44
50
|
onChange: (value: string | string[]) => void;
|
|
45
51
|
disabled?: boolean;
|
|
@@ -186,6 +192,7 @@ export function RelationSelector<T>({
|
|
|
186
192
|
onChange,
|
|
187
193
|
disabled,
|
|
188
194
|
className,
|
|
195
|
+
selectorLabel,
|
|
189
196
|
}: Readonly<RelationSelectorProps<T>>) {
|
|
190
197
|
const [open, setOpen] = useState(false);
|
|
191
198
|
const [selectedItemsCache, setSelectedItemsCache] = useState<T[]>([]);
|
|
@@ -396,10 +403,10 @@ export function RelationSelector<T>({
|
|
|
396
403
|
{isMultiple
|
|
397
404
|
? selectedItems.length > 0
|
|
398
405
|
? `Add more (${selectedItems.length} selected)`
|
|
399
|
-
:
|
|
406
|
+
: selectorLabel ?? <Trans>Select items</Trans>
|
|
400
407
|
: selectedItems.length > 0
|
|
401
408
|
? 'Change selection'
|
|
402
|
-
:
|
|
409
|
+
: selectorLabel ?? <Trans>Select item</Trans>}
|
|
403
410
|
</Trans>
|
|
404
411
|
</Button>
|
|
405
412
|
</PopoverTrigger>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { FieldInfo } from '@/vdb/framework/document-introspection/get-document-structure.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Returns the default column visibility configuration.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```ts
|
|
8
|
+
* const columnVisibility = getColumnVisibility(fields, {
|
|
9
|
+
* id: false,
|
|
10
|
+
* createdAt: false,
|
|
11
|
+
* updatedAt: false,
|
|
12
|
+
* });
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export function getColumnVisibility(
|
|
16
|
+
fields: FieldInfo[],
|
|
17
|
+
defaultVisibility?: Record<string, boolean | undefined>,
|
|
18
|
+
customFieldColumnNames?: string[],
|
|
19
|
+
): Record<string, boolean> {
|
|
20
|
+
const allDefaultsTrue = defaultVisibility && Object.values(defaultVisibility).every(v => v === true);
|
|
21
|
+
const allDefaultsFalse = defaultVisibility && Object.values(defaultVisibility).every(v => v === false);
|
|
22
|
+
return {
|
|
23
|
+
id: false,
|
|
24
|
+
createdAt: false,
|
|
25
|
+
updatedAt: false,
|
|
26
|
+
...(allDefaultsTrue ? { ...Object.fromEntries(fields.map(f => [f.name, false])) } : {}),
|
|
27
|
+
...(allDefaultsFalse ? { ...Object.fromEntries(fields.map(f => [f.name, true])) } : {}),
|
|
28
|
+
// Make custom fields hidden by default unless overridden
|
|
29
|
+
...(customFieldColumnNames
|
|
30
|
+
? { ...Object.fromEntries(customFieldColumnNames.map(f => [f, false])) }
|
|
31
|
+
: {}),
|
|
32
|
+
...defaultVisibility,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { closestCenter, DndContext } from '@dnd-kit/core';
|
|
4
4
|
import { restrictToVerticalAxis } from '@dnd-kit/modifiers';
|
|
5
5
|
import { SortableContext, useSortable, verticalListSortingStrategy } from '@dnd-kit/sortable';
|
|
6
6
|
import { CSS } from '@dnd-kit/utilities';
|
|
@@ -83,7 +83,7 @@ export function DataTableViewOptions<TData>({ table }: DataTableViewOptionsProps
|
|
|
83
83
|
<Trans>Columns</Trans>
|
|
84
84
|
</Button>
|
|
85
85
|
</DropdownMenuTrigger>
|
|
86
|
-
<DropdownMenuContent align="end"
|
|
86
|
+
<DropdownMenuContent align="end">
|
|
87
87
|
<DndContext
|
|
88
88
|
collisionDetection={closestCenter}
|
|
89
89
|
onDragEnd={handleDragEnd}
|
|
@@ -36,6 +36,7 @@ export interface FacetedFilter {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
interface DataTableProps<TData> {
|
|
39
|
+
children?: React.ReactNode;
|
|
39
40
|
columns: ColumnDef<TData, any>[];
|
|
40
41
|
data: TData[];
|
|
41
42
|
totalItems: number;
|
|
@@ -62,6 +63,7 @@ interface DataTableProps<TData> {
|
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
export function DataTable<TData>({
|
|
66
|
+
children,
|
|
65
67
|
columns,
|
|
66
68
|
data,
|
|
67
69
|
totalItems,
|
|
@@ -178,7 +180,7 @@ export function DataTable<TData>({
|
|
|
178
180
|
/>
|
|
179
181
|
))}
|
|
180
182
|
</Suspense>
|
|
181
|
-
<AddFilterMenu columns={table.getAllColumns()} />
|
|
183
|
+
{onFilterChange && <AddFilterMenu columns={table.getAllColumns()} />}
|
|
182
184
|
</div>
|
|
183
185
|
<div className="flex gap-1">
|
|
184
186
|
{columnFilters
|
|
@@ -266,11 +268,12 @@ export function DataTable<TData>({
|
|
|
266
268
|
</TableCell>
|
|
267
269
|
</TableRow>
|
|
268
270
|
)}
|
|
271
|
+
{children}
|
|
269
272
|
</TableBody>
|
|
270
273
|
</Table>
|
|
271
274
|
<DataTableBulkActions bulkActions={bulkActions ?? []} table={table} />
|
|
272
275
|
</div>
|
|
273
|
-
<DataTablePagination table={table} />
|
|
276
|
+
{onPageChange && totalItems != null && <DataTablePagination table={table} />}
|
|
274
277
|
</>
|
|
275
278
|
);
|
|
276
279
|
}
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import { DisplayComponent } from '@/vdb/framework/component-registry/dynamic-component.js';
|
|
2
|
+
import { FieldInfo, getTypeFieldInfo } from '@/vdb/framework/document-introspection/get-document-structure.js';
|
|
3
|
+
import { api } from '@/vdb/graphql/api.js';
|
|
4
|
+
import { Trans, useLingui } from '@/vdb/lib/trans.js';
|
|
5
|
+
import { TypedDocumentNode } from '@graphql-typed-document-node/core';
|
|
6
|
+
import { useMutation } from '@tanstack/react-query';
|
|
7
|
+
import { AccessorKeyColumnDef, createColumnHelper, Row } from '@tanstack/react-table';
|
|
8
|
+
import { EllipsisIcon, TrashIcon } from 'lucide-react';
|
|
9
|
+
import { useMemo } from 'react';
|
|
10
|
+
import { toast } from 'sonner';
|
|
11
|
+
import {
|
|
12
|
+
AdditionalColumns,
|
|
13
|
+
AllItemFieldKeys,
|
|
14
|
+
CustomizeColumnConfig,
|
|
15
|
+
FacetedFilterConfig,
|
|
16
|
+
PaginatedListItemFields,
|
|
17
|
+
RowAction,
|
|
18
|
+
usePaginatedList,
|
|
19
|
+
} from '../shared/paginated-list-data-table.js';
|
|
20
|
+
import {
|
|
21
|
+
AlertDialog,
|
|
22
|
+
AlertDialogAction,
|
|
23
|
+
AlertDialogCancel,
|
|
24
|
+
AlertDialogContent,
|
|
25
|
+
AlertDialogDescription,
|
|
26
|
+
AlertDialogFooter,
|
|
27
|
+
AlertDialogHeader,
|
|
28
|
+
AlertDialogTitle,
|
|
29
|
+
AlertDialogTrigger,
|
|
30
|
+
} from '../ui/alert-dialog.js';
|
|
31
|
+
import { Button } from '../ui/button.js';
|
|
32
|
+
import { Checkbox } from '../ui/checkbox.js';
|
|
33
|
+
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '../ui/dropdown-menu.js';
|
|
34
|
+
import { DataTableColumnHeader } from './data-table-column-header.js';
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @description
|
|
38
|
+
* This hook is used to generate the columns for a data table, combining the fields
|
|
39
|
+
* from the query with the additional columns and the custom fields.
|
|
40
|
+
*
|
|
41
|
+
* It also
|
|
42
|
+
* - adds the row actions and the delete mutation.
|
|
43
|
+
* - adds the row selection column.
|
|
44
|
+
* - adds the custom field columns.
|
|
45
|
+
*/
|
|
46
|
+
export function useGeneratedColumns<T extends TypedDocumentNode<any, any>>({
|
|
47
|
+
fields,
|
|
48
|
+
customizeColumns,
|
|
49
|
+
rowActions,
|
|
50
|
+
deleteMutation,
|
|
51
|
+
additionalColumns,
|
|
52
|
+
defaultColumnOrder,
|
|
53
|
+
facetedFilters,
|
|
54
|
+
includeSelectionColumn = true,
|
|
55
|
+
includeActionsColumn = true,
|
|
56
|
+
enableSorting = true,
|
|
57
|
+
}: Readonly<{
|
|
58
|
+
fields: FieldInfo[];
|
|
59
|
+
customizeColumns?: CustomizeColumnConfig<T>;
|
|
60
|
+
rowActions?: RowAction<PaginatedListItemFields<T>>[];
|
|
61
|
+
deleteMutation?: TypedDocumentNode<any, any>;
|
|
62
|
+
additionalColumns?: AdditionalColumns<T>;
|
|
63
|
+
defaultColumnOrder?: Array<string | number | symbol>;
|
|
64
|
+
facetedFilters?: FacetedFilterConfig<T>;
|
|
65
|
+
includeSelectionColumn?: boolean;
|
|
66
|
+
includeActionsColumn?: boolean;
|
|
67
|
+
enableSorting?: boolean;
|
|
68
|
+
}>) {
|
|
69
|
+
const columnHelper = createColumnHelper<PaginatedListItemFields<T>>();
|
|
70
|
+
|
|
71
|
+
const { columns, customFieldColumnNames } = useMemo(() => {
|
|
72
|
+
const columnConfigs: Array<{ fieldInfo: FieldInfo; isCustomField: boolean }> = [];
|
|
73
|
+
const customFieldColumnNames: string[] = [];
|
|
74
|
+
|
|
75
|
+
columnConfigs.push(
|
|
76
|
+
...fields // Filter out custom fields
|
|
77
|
+
.filter(field => field.name !== 'customFields' && !field.type.endsWith('CustomFields'))
|
|
78
|
+
.map(field => ({ fieldInfo: field, isCustomField: false })),
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
const customFieldColumn = fields.find(field => field.name === 'customFields');
|
|
82
|
+
if (customFieldColumn && customFieldColumn.type !== 'JSON') {
|
|
83
|
+
const customFieldFields = getTypeFieldInfo(customFieldColumn.type);
|
|
84
|
+
columnConfigs.push(
|
|
85
|
+
...customFieldFields.map(field => ({ fieldInfo: field, isCustomField: true })),
|
|
86
|
+
);
|
|
87
|
+
customFieldColumnNames.push(...customFieldFields.map(field => field.name));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const queryBasedColumns = columnConfigs.map(({ fieldInfo, isCustomField }) => {
|
|
91
|
+
const customConfig = customizeColumns?.[fieldInfo.name as unknown as AllItemFieldKeys<T>] ?? {};
|
|
92
|
+
const { header, ...customConfigRest } = customConfig;
|
|
93
|
+
const enableColumnFilter = fieldInfo.isScalar && !facetedFilters?.[fieldInfo.name];
|
|
94
|
+
|
|
95
|
+
return columnHelper.accessor(fieldInfo.name as any, {
|
|
96
|
+
id: fieldInfo.name,
|
|
97
|
+
meta: { fieldInfo, isCustomField },
|
|
98
|
+
enableColumnFilter,
|
|
99
|
+
enableSorting: fieldInfo.isScalar && enableSorting,
|
|
100
|
+
// Filtering is done on the server side, but we set this to 'equalsString' because
|
|
101
|
+
// otherwise the TanStack Table with apply an "auto" function which somehow
|
|
102
|
+
// prevents certain filters from working.
|
|
103
|
+
filterFn: 'equalsString',
|
|
104
|
+
cell: ({ cell, row }) => {
|
|
105
|
+
const cellValue = cell.getValue();
|
|
106
|
+
const value =
|
|
107
|
+
cellValue ??
|
|
108
|
+
(isCustomField ? row.original?.customFields?.[fieldInfo.name] : undefined);
|
|
109
|
+
|
|
110
|
+
if (fieldInfo.list && Array.isArray(value)) {
|
|
111
|
+
return value.join(', ');
|
|
112
|
+
}
|
|
113
|
+
if (
|
|
114
|
+
(fieldInfo.type === 'DateTime' && typeof value === 'string') ||
|
|
115
|
+
value instanceof Date
|
|
116
|
+
) {
|
|
117
|
+
return <DisplayComponent id="vendure:dateTime" value={value} />;
|
|
118
|
+
}
|
|
119
|
+
if (fieldInfo.type === 'Boolean') {
|
|
120
|
+
if (cell.column.id === 'enabled') {
|
|
121
|
+
return <DisplayComponent id="vendure:booleanBadge" value={value} />;
|
|
122
|
+
} else {
|
|
123
|
+
return <DisplayComponent id="vendure:booleanCheckbox" value={value} />;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (fieldInfo.type === 'Asset') {
|
|
127
|
+
return <DisplayComponent id="vendure:asset" value={value} />;
|
|
128
|
+
}
|
|
129
|
+
if (value !== null && typeof value === 'object') {
|
|
130
|
+
return JSON.stringify(value);
|
|
131
|
+
}
|
|
132
|
+
return value;
|
|
133
|
+
},
|
|
134
|
+
header: headerContext => {
|
|
135
|
+
return (
|
|
136
|
+
<DataTableColumnHeader headerContext={headerContext} customConfig={customConfig} />
|
|
137
|
+
);
|
|
138
|
+
},
|
|
139
|
+
...customConfigRest,
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
let finalColumns = [...queryBasedColumns];
|
|
144
|
+
|
|
145
|
+
for (const [id, column] of Object.entries(additionalColumns ?? {})) {
|
|
146
|
+
if (!id) {
|
|
147
|
+
throw new Error('Column id is required');
|
|
148
|
+
}
|
|
149
|
+
finalColumns.push(columnHelper.accessor(id as any, { ...column, id }));
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (defaultColumnOrder) {
|
|
153
|
+
// ensure the columns with ids matching the items in defaultColumnOrder
|
|
154
|
+
// appear as the first columns in sequence, and leave the remainder in the
|
|
155
|
+
// existing order
|
|
156
|
+
const orderedColumns = finalColumns
|
|
157
|
+
.filter(column => column.id && defaultColumnOrder.includes(column.id as any))
|
|
158
|
+
.sort(
|
|
159
|
+
(a, b) =>
|
|
160
|
+
defaultColumnOrder.indexOf(a.id as any) - defaultColumnOrder.indexOf(b.id as any),
|
|
161
|
+
);
|
|
162
|
+
const remainingColumns = finalColumns.filter(
|
|
163
|
+
column => !column.id || !defaultColumnOrder.includes(column.id as any),
|
|
164
|
+
);
|
|
165
|
+
finalColumns = [...orderedColumns, ...remainingColumns];
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (includeActionsColumn && (rowActions || deleteMutation)) {
|
|
169
|
+
const rowActionColumn = getRowActions(rowActions, deleteMutation);
|
|
170
|
+
if (rowActionColumn) {
|
|
171
|
+
finalColumns.push(rowActionColumn);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (includeSelectionColumn) {
|
|
176
|
+
// Add the row selection column
|
|
177
|
+
finalColumns.unshift({
|
|
178
|
+
id: 'selection',
|
|
179
|
+
accessorKey: 'selection',
|
|
180
|
+
header: ({ table }) => (
|
|
181
|
+
<Checkbox
|
|
182
|
+
className="mx-1"
|
|
183
|
+
checked={table.getIsAllRowsSelected()}
|
|
184
|
+
onCheckedChange={checked =>
|
|
185
|
+
table.toggleAllRowsSelected(checked === 'indeterminate' ? undefined : checked)
|
|
186
|
+
}
|
|
187
|
+
/>
|
|
188
|
+
),
|
|
189
|
+
enableColumnFilter: false,
|
|
190
|
+
cell: ({ row }) => {
|
|
191
|
+
return (
|
|
192
|
+
<Checkbox
|
|
193
|
+
className="mx-1"
|
|
194
|
+
checked={row.getIsSelected()}
|
|
195
|
+
onCheckedChange={row.getToggleSelectedHandler()}
|
|
196
|
+
/>
|
|
197
|
+
);
|
|
198
|
+
},
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return { columns: finalColumns, customFieldColumnNames };
|
|
203
|
+
}, [fields, customizeColumns, rowActions, deleteMutation, additionalColumns, defaultColumnOrder]);
|
|
204
|
+
|
|
205
|
+
return { columns, customFieldColumnNames };
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function getRowActions(
|
|
209
|
+
rowActions?: RowAction<any>[],
|
|
210
|
+
deleteMutation?: TypedDocumentNode<any, any>,
|
|
211
|
+
): AccessorKeyColumnDef<any> | undefined {
|
|
212
|
+
return {
|
|
213
|
+
id: 'actions',
|
|
214
|
+
accessorKey: 'actions',
|
|
215
|
+
header: () => <Trans>Actions</Trans>,
|
|
216
|
+
enableColumnFilter: false,
|
|
217
|
+
cell: ({ row }) => {
|
|
218
|
+
return (
|
|
219
|
+
<DropdownMenu>
|
|
220
|
+
<DropdownMenuTrigger asChild>
|
|
221
|
+
<Button variant="ghost" size="icon">
|
|
222
|
+
<EllipsisIcon />
|
|
223
|
+
</Button>
|
|
224
|
+
</DropdownMenuTrigger>
|
|
225
|
+
<DropdownMenuContent>
|
|
226
|
+
{rowActions?.map((action, index) => (
|
|
227
|
+
<DropdownMenuItem
|
|
228
|
+
onClick={() => action.onClick?.(row)}
|
|
229
|
+
key={`${action.label}-${index}`}
|
|
230
|
+
>
|
|
231
|
+
{action.label}
|
|
232
|
+
</DropdownMenuItem>
|
|
233
|
+
))}
|
|
234
|
+
{deleteMutation && (
|
|
235
|
+
<DeleteMutationRowAction deleteMutation={deleteMutation} row={row} />
|
|
236
|
+
)}
|
|
237
|
+
</DropdownMenuContent>
|
|
238
|
+
</DropdownMenu>
|
|
239
|
+
);
|
|
240
|
+
},
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function DeleteMutationRowAction({
|
|
245
|
+
deleteMutation,
|
|
246
|
+
row,
|
|
247
|
+
}: Readonly<{
|
|
248
|
+
deleteMutation: TypedDocumentNode<any, any>;
|
|
249
|
+
row: Row<{ id: string }>;
|
|
250
|
+
}>) {
|
|
251
|
+
const { refetchPaginatedList } = usePaginatedList();
|
|
252
|
+
const { i18n } = useLingui();
|
|
253
|
+
const { mutate: deleteMutationFn } = useMutation({
|
|
254
|
+
mutationFn: api.mutate(deleteMutation),
|
|
255
|
+
onSuccess: (result: { [key: string]: { result: 'DELETED' | 'NOT_DELETED'; message: string } }) => {
|
|
256
|
+
const unwrappedResult = Object.values(result)[0];
|
|
257
|
+
if (unwrappedResult.result === 'DELETED') {
|
|
258
|
+
refetchPaginatedList();
|
|
259
|
+
toast.success(i18n.t('Deleted successfully'));
|
|
260
|
+
} else {
|
|
261
|
+
toast.error(i18n.t('Failed to delete'), {
|
|
262
|
+
description: unwrappedResult.message,
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
},
|
|
266
|
+
onError: (err: Error) => {
|
|
267
|
+
toast.error(i18n.t('Failed to delete'), {
|
|
268
|
+
description: err.message,
|
|
269
|
+
});
|
|
270
|
+
},
|
|
271
|
+
});
|
|
272
|
+
return (
|
|
273
|
+
<AlertDialog>
|
|
274
|
+
<AlertDialogTrigger asChild>
|
|
275
|
+
<DropdownMenuItem onSelect={e => e.preventDefault()}>
|
|
276
|
+
<div className="flex items-center gap-2 text-destructive">
|
|
277
|
+
<TrashIcon className="w-4 h-4 text-destructive" />
|
|
278
|
+
<Trans>Delete</Trans>
|
|
279
|
+
</div>
|
|
280
|
+
</DropdownMenuItem>
|
|
281
|
+
</AlertDialogTrigger>
|
|
282
|
+
<AlertDialogContent>
|
|
283
|
+
<AlertDialogHeader>
|
|
284
|
+
<AlertDialogTitle>
|
|
285
|
+
<Trans>Confirm deletion</Trans>
|
|
286
|
+
</AlertDialogTitle>
|
|
287
|
+
<AlertDialogDescription>
|
|
288
|
+
<Trans>
|
|
289
|
+
Are you sure you want to delete this item? This action cannot be undone.
|
|
290
|
+
</Trans>
|
|
291
|
+
</AlertDialogDescription>
|
|
292
|
+
</AlertDialogHeader>
|
|
293
|
+
<AlertDialogFooter>
|
|
294
|
+
<AlertDialogCancel>
|
|
295
|
+
<Trans>Cancel</Trans>
|
|
296
|
+
</AlertDialogCancel>
|
|
297
|
+
<AlertDialogAction
|
|
298
|
+
onClick={() => deleteMutationFn({ id: row.original.id })}
|
|
299
|
+
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
|
300
|
+
>
|
|
301
|
+
<Trans>Delete</Trans>
|
|
302
|
+
</AlertDialogAction>
|
|
303
|
+
</AlertDialogFooter>
|
|
304
|
+
</AlertDialogContent>
|
|
305
|
+
</AlertDialog>
|
|
306
|
+
);
|
|
307
|
+
}
|