@rkosafo/cai.components 0.0.78 → 0.0.80
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/README.md +8 -8
- package/dist/baseEditor/index.svelte +32 -32
- package/dist/builders/filters/FilterBuilder.svelte +641 -641
- package/dist/forms/FormCheckbox/FormCheckbox.svelte +53 -53
- package/dist/forms/FormClEditor/ClEdito.svelte +68 -68
- package/dist/forms/FormDatepicker/FormDatepicker.svelte +159 -159
- package/dist/forms/FormFileUpload/FormFileUplad.svelte +134 -134
- package/dist/forms/FormInput/FormInput.svelte +87 -87
- package/dist/forms/FormRadio/FormRadio.svelte +53 -53
- package/dist/forms/FormSelect/FormSelect.svelte +88 -88
- package/dist/forms/FormTextarea/FormTextarea.svelte +78 -78
- package/dist/forms/button-toggle/ButtonToggle.svelte +119 -119
- package/dist/forms/button-toggle/CheckIcon.svelte +28 -28
- package/dist/forms/checkbox/Checkbox.svelte +82 -82
- package/dist/forms/checkbox/CheckboxButton.svelte +92 -92
- package/dist/forms/datepicker/Datepicker.svelte +707 -707
- package/dist/forms/form/Form.svelte +69 -69
- package/dist/forms/input/Input.svelte +363 -363
- package/dist/forms/label/Label.svelte +38 -38
- package/dist/forms/radio/Radio.svelte +48 -48
- package/dist/forms/radio/RadioButton.svelte +22 -22
- package/dist/forms/select/Select.svelte +56 -56
- package/dist/forms/textarea/Textarea.svelte +165 -165
- package/dist/forms/toggle/Toggle.svelte +70 -70
- package/dist/layout/Chat/CategorySelector.svelte +52 -52
- package/dist/layout/Chat/ChatEntry.svelte +246 -246
- package/dist/layout/Chat/ChatEntrySkeleton.svelte +81 -81
- package/dist/layout/Chat/ChatHeader.svelte +172 -172
- package/dist/layout/Chat/ChatInput.svelte +207 -207
- package/dist/layout/Chat/DraggableWindow.svelte +230 -230
- package/dist/layout/Chat/PreviewPage.svelte +182 -182
- package/dist/layout/Chat/RichText.svelte +216 -216
- package/dist/layout/ComponentCanvas/Canvas.svelte +40 -40
- package/dist/layout/ComponentCanvas/ComponentRenderer.svelte +85 -85
- package/dist/layout/TF/Content/Content.svelte +21 -21
- package/dist/layout/TF/Header/Header.svelte +166 -166
- package/dist/layout/TF/Sidebar/Sidebar.svelte +148 -148
- package/dist/layout/TF/Wrapper/Wrapper.svelte +17 -17
- package/dist/layout/mailing/MailPaginator.svelte +36 -36
- package/dist/layout/mailing/MailSidebar.svelte +39 -39
- package/dist/layout/mailing/MailToolBar.svelte +174 -174
- package/dist/layout/mailing/MailingContent.svelte +10 -10
- package/dist/layout/mailing/MailingHeader.svelte +55 -55
- package/dist/layout/mailing/MailingMessageCard.svelte +112 -112
- package/dist/layout/mailing/MailingMessageViewer.svelte +87 -87
- package/dist/layout/mailing/MailingModule.svelte +448 -448
- package/dist/styles/docs.css +615 -615
- package/dist/styles/tf-layout.css +185 -185
- package/dist/themes/ThemeProvider.svelte +20 -20
- package/dist/types/index.d.ts +2 -0
- package/dist/typography/heading/Heading.svelte +35 -35
- package/dist/ui/accordion/Accordion.svelte +49 -49
- package/dist/ui/accordion/AccordionItem.svelte +173 -173
- package/dist/ui/alert/Alert.svelte +83 -83
- package/dist/ui/alertDialog/AlertDialog.svelte +40 -40
- package/dist/ui/avatar/Avatar.svelte +77 -77
- package/dist/ui/box/Box.svelte +28 -28
- package/dist/ui/breadcrumb/Breadcrumb.svelte +39 -39
- package/dist/ui/buttons/ActionButton.svelte +234 -234
- package/dist/ui/buttons/Button.svelte +102 -102
- package/dist/ui/buttons/GradientButton.svelte +59 -59
- package/dist/ui/datatable/Datatable.svelte +525 -525
- package/dist/ui/drawer/Drawer.svelte +300 -300
- package/dist/ui/dropdown/Dropdown.svelte +36 -36
- package/dist/ui/dropdown/DropdownDivider.svelte +11 -11
- package/dist/ui/dropdown/DropdownGroup.svelte +14 -14
- package/dist/ui/dropdown/DropdownHeader.svelte +14 -14
- package/dist/ui/dropdown/DropdownItem.svelte +52 -52
- package/dist/ui/footer/Footer.svelte +15 -15
- package/dist/ui/footer/FooterBrand.svelte +37 -37
- package/dist/ui/footer/FooterCopyright.svelte +45 -45
- package/dist/ui/footer/FooterIcon.svelte +22 -22
- package/dist/ui/footer/FooterLink.svelte +33 -33
- package/dist/ui/footer/FooterLinkGroup.svelte +13 -13
- package/dist/ui/icons/IconifyIcon.svelte +7 -7
- package/dist/ui/indicator/Indicator.svelte +42 -42
- package/dist/ui/modal/Modal.svelte +265 -265
- package/dist/ui/notificationList/NotificationList.svelte +123 -123
- package/dist/ui/pageLoader/PageLoader.svelte +14 -14
- package/dist/ui/pageLoader/PageLoader2.svelte +99 -0
- package/dist/ui/pageLoader/PageLoader2.svelte.d.ts +24 -0
- package/dist/ui/pageLoader/index.d.ts +2 -1
- package/dist/ui/pageLoader/index.js +2 -1
- package/dist/ui/paginate/Paginate.svelte +96 -96
- package/dist/ui/speedDial/SpeedDial.svelte +77 -77
- package/dist/ui/speedDial/SpeedDialButton.svelte +75 -75
- package/dist/ui/speedDial/SpeedDialTrigger.svelte +79 -79
- package/dist/ui/tab/Tab.svelte +93 -67
- package/dist/ui/table/Table.svelte +396 -396
- package/dist/ui/tableLoader/TableLoader.svelte +24 -24
- package/dist/ui/toast/Toast.svelte +337 -337
- package/dist/ui/toast/Toast.svelte.d.ts +10 -10
- package/dist/ui/toolbar/Toolbar.svelte +59 -59
- package/dist/ui/toolbar/ToolbarButton.svelte +56 -56
- package/dist/ui/toolbar/ToolbarGroup.svelte +43 -43
- package/dist/ui/tooltip/Tooltip.svelte +51 -51
- package/dist/utils/Popper.svelte +257 -257
- package/dist/utils/closeButton/CloseButton.svelte +88 -88
- package/dist/utils/index.d.ts +2 -2
- package/dist/utils/index.js +3 -3
- package/dist/utils/singleSelection.svelte.js +48 -48
- package/dist/youtube/index.svelte +12 -12
- package/package.json +1 -1
|
@@ -1,525 +1,525 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { goto } from '$app/navigation';
|
|
3
|
-
import { page } from '$app/state';
|
|
4
|
-
import {
|
|
5
|
-
AlertDialog,
|
|
6
|
-
Button,
|
|
7
|
-
Datepicker,
|
|
8
|
-
Drawer,
|
|
9
|
-
extractQueryParam,
|
|
10
|
-
Input,
|
|
11
|
-
loadFromLocalStorage,
|
|
12
|
-
Paginate,
|
|
13
|
-
saveToLocalStorage,
|
|
14
|
-
Select,
|
|
15
|
-
Table,
|
|
16
|
-
TableLoader,
|
|
17
|
-
toast,
|
|
18
|
-
type DatatableProps,
|
|
19
|
-
type IFormChangeProp,
|
|
20
|
-
type TableFilter
|
|
21
|
-
} from '../../index.js';
|
|
22
|
-
import { PageInfo } from '../../utils/paginate.svelte.js';
|
|
23
|
-
import debounce from 'lodash/debounce';
|
|
24
|
-
import { onMount } from 'svelte';
|
|
25
|
-
import { writable } from 'svelte/store';
|
|
26
|
-
import { slide } from 'svelte/transition';
|
|
27
|
-
|
|
28
|
-
let {
|
|
29
|
-
persitFiltersToUrl = false,
|
|
30
|
-
showTopActionsBackground = true,
|
|
31
|
-
fillSpace = true,
|
|
32
|
-
onAfterAction,
|
|
33
|
-
hideSearchBox = false,
|
|
34
|
-
showAdd = true,
|
|
35
|
-
addButtonLabel = 'Add New',
|
|
36
|
-
searchPlaceholder = 'Search...',
|
|
37
|
-
addNewHeading = 'Add New Record',
|
|
38
|
-
updateHeading = 'Update',
|
|
39
|
-
headerColor = 'blue',
|
|
40
|
-
newRecord = {},
|
|
41
|
-
query = $bindable(''),
|
|
42
|
-
hiddenColumns = [],
|
|
43
|
-
customFilterValues = {},
|
|
44
|
-
onAddNew,
|
|
45
|
-
busy = false,
|
|
46
|
-
showFilterDateRange = false,
|
|
47
|
-
loadingBodySize = 10,
|
|
48
|
-
loadingHeaderSize = 6,
|
|
49
|
-
allowLoadAfterCreate = true,
|
|
50
|
-
allowDispatchAfterAction = false,
|
|
51
|
-
modalSize = 'md',
|
|
52
|
-
take = 15,
|
|
53
|
-
onActionClicked,
|
|
54
|
-
onRowClicked,
|
|
55
|
-
onView,
|
|
56
|
-
onEdit,
|
|
57
|
-
onDelete,
|
|
58
|
-
editor,
|
|
59
|
-
customFilter,
|
|
60
|
-
handleCheckbox,
|
|
61
|
-
read = $bindable((skip?: number, take?: number, filter?: TableFilter<any>) => {
|
|
62
|
-
return null;
|
|
63
|
-
}),
|
|
64
|
-
updateEntry = (x: any) => {
|
|
65
|
-
return null;
|
|
66
|
-
},
|
|
67
|
-
createEntry = async (x: any) => {
|
|
68
|
-
return { success: false, data: null, error: null } as any;
|
|
69
|
-
},
|
|
70
|
-
deleteEntry = async (id: string | number) => {
|
|
71
|
-
return { success: false, data: null, error: null } as any;
|
|
72
|
-
},
|
|
73
|
-
modalFooter,
|
|
74
|
-
showModalButtons = true,
|
|
75
|
-
customAddAction,
|
|
76
|
-
...otherProps
|
|
77
|
-
}: DatatableProps = $props();
|
|
78
|
-
|
|
79
|
-
const PAGE_SIZE_KEY = 'customTablePageSize';
|
|
80
|
-
let editorHeading = $state('');
|
|
81
|
-
let hideForm = $state(true);
|
|
82
|
-
let editing = $state(false);
|
|
83
|
-
let activeEntry = $state<any>({});
|
|
84
|
-
let pageInfo = new PageInfo();
|
|
85
|
-
const rangeDate = $derived(getRange());
|
|
86
|
-
let allColumns = $state(writable<any>([]));
|
|
87
|
-
let pathname = $state('');
|
|
88
|
-
let search = $state('');
|
|
89
|
-
let pageNumber = $state(0);
|
|
90
|
-
let searchParams = $state<any>(null);
|
|
91
|
-
let showAlert = $state(false);
|
|
92
|
-
let tableData = $state<any[]>([]);
|
|
93
|
-
let isLoading = $state(false);
|
|
94
|
-
let deleteLoading = $state(false);
|
|
95
|
-
let isValid = $state(false);
|
|
96
|
-
let viewing = $state(false);
|
|
97
|
-
let dataToSave = $state<any>({});
|
|
98
|
-
|
|
99
|
-
function addNew() {
|
|
100
|
-
if (onAddNew) {
|
|
101
|
-
onAddNew();
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
editorHeading = addNewHeading;
|
|
105
|
-
activeEntry = (newRecord && { ...newRecord }) || null;
|
|
106
|
-
editing = false;
|
|
107
|
-
hideForm = false;
|
|
108
|
-
viewing = false;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
async function fetchData(page: number, params: TableFilter) {
|
|
112
|
-
try {
|
|
113
|
-
let currentPage = 0;
|
|
114
|
-
busy = true;
|
|
115
|
-
if (params.search) {
|
|
116
|
-
pageInfo.setCurrentPage(1);
|
|
117
|
-
currentPage = pageInfo.currentPage;
|
|
118
|
-
} else {
|
|
119
|
-
currentPage = page || pageInfo.currentPage;
|
|
120
|
-
}
|
|
121
|
-
let newParams: any = {
|
|
122
|
-
page: currentPage,
|
|
123
|
-
pageSize: pageInfo.pageSize,
|
|
124
|
-
search: params.search ?? '',
|
|
125
|
-
filter: params.filter ?? {},
|
|
126
|
-
order: params.order ?? []
|
|
127
|
-
};
|
|
128
|
-
const ret = await read(newParams.page, newParams.pageSize, {
|
|
129
|
-
...params,
|
|
130
|
-
filter: { ...customFilterValues },
|
|
131
|
-
search: newParams.search ?? ''
|
|
132
|
-
});
|
|
133
|
-
if (!ret?.success) {
|
|
134
|
-
// showError(ret?.message || 'Failed to load data');
|
|
135
|
-
toast.error(ret?.message || 'Failed to load data');
|
|
136
|
-
return true;
|
|
137
|
-
}
|
|
138
|
-
const xs = ret.data;
|
|
139
|
-
// console.log({xs})
|
|
140
|
-
pageInfo.totalItems = xs.totalCount;
|
|
141
|
-
pageInfo.setHasNextPage(xs.pageInfo.hasNextPage);
|
|
142
|
-
pageInfo.setHasPrevPage(xs.pageInfo.hasPreviousPage);
|
|
143
|
-
tableData = xs.items;
|
|
144
|
-
} catch (e: any) {
|
|
145
|
-
toast.error(e.message || e);
|
|
146
|
-
} finally {
|
|
147
|
-
busy = false;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
const debouncedSearch = debounce(fetchData, 300);
|
|
152
|
-
|
|
153
|
-
function onSearchChange(e: Event) {
|
|
154
|
-
const target = e.target as HTMLInputElement | null;
|
|
155
|
-
const value = target ? target.value : '';
|
|
156
|
-
debouncedSearch(pageNumber, { search: value });
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
function getRange() {
|
|
160
|
-
return { from: undefined, to: undefined };
|
|
161
|
-
}
|
|
162
|
-
function handleDateRangeChange(e) {
|
|
163
|
-
console.log({ e });
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
async function handlePageSize(val: number) {
|
|
167
|
-
pageInfo.setPageSize(val);
|
|
168
|
-
await fetchData(pageInfo.currentPage, { search: query });
|
|
169
|
-
|
|
170
|
-
saveToLocalStorage(PAGE_SIZE_KEY, { pageSize: val });
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
async function getMore() {
|
|
174
|
-
if (pageInfo.gotoNext()) {
|
|
175
|
-
const value = pageInfo.currentPage;
|
|
176
|
-
if (persitFiltersToUrl) {
|
|
177
|
-
const current = new URLSearchParams(Array.from(searchParams.entries()) as any);
|
|
178
|
-
|
|
179
|
-
if (!value) {
|
|
180
|
-
current.delete('page');
|
|
181
|
-
} else {
|
|
182
|
-
current.set('page', String(value));
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
const search = current.toString();
|
|
186
|
-
const page = search ? `?${search}` : '';
|
|
187
|
-
await goto(`${pathname}${page}`);
|
|
188
|
-
}
|
|
189
|
-
await fetchData(value, { search: query });
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
async function getLess() {
|
|
194
|
-
if (pageInfo.gotoPrev()) {
|
|
195
|
-
const value = pageInfo.currentPage;
|
|
196
|
-
if (persitFiltersToUrl) {
|
|
197
|
-
const current = new URLSearchParams(Array.from(searchParams.entries()) as any);
|
|
198
|
-
if (!value) {
|
|
199
|
-
current.delete('page');
|
|
200
|
-
} else {
|
|
201
|
-
current.set('page', String(value));
|
|
202
|
-
}
|
|
203
|
-
const search = current.toString();
|
|
204
|
-
const page = search ? `?${search}` : '';
|
|
205
|
-
await goto(`${pathname}${page}`);
|
|
206
|
-
}
|
|
207
|
-
await fetchData(value, { search: query });
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
function handleExternalFetch(event: CustomEvent) {
|
|
212
|
-
const { page: customPage, params: customParams } = event.detail || {};
|
|
213
|
-
const fetchPage = customPage !== undefined ? customPage : pageNumber;
|
|
214
|
-
const fetchParams = customParams || { search: query };
|
|
215
|
-
|
|
216
|
-
fetchData(fetchPage, fetchParams);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
function handleEdit(val: any) {
|
|
220
|
-
if (onEdit) {
|
|
221
|
-
onEdit(val);
|
|
222
|
-
return;
|
|
223
|
-
}
|
|
224
|
-
activeEntry = val;
|
|
225
|
-
editorHeading = updateHeading;
|
|
226
|
-
editing = true;
|
|
227
|
-
hideForm = false;
|
|
228
|
-
viewing = false;
|
|
229
|
-
}
|
|
230
|
-
function handleView(val: any) {
|
|
231
|
-
if (onView) {
|
|
232
|
-
onView(val);
|
|
233
|
-
return;
|
|
234
|
-
}
|
|
235
|
-
activeEntry = val;
|
|
236
|
-
editorHeading = 'View Record';
|
|
237
|
-
editing = true;
|
|
238
|
-
hideForm = false;
|
|
239
|
-
viewing = true;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
function handleRowClicked(val: any) {
|
|
243
|
-
if (onRowClicked) {
|
|
244
|
-
onRowClicked(val);
|
|
245
|
-
return;
|
|
246
|
-
}
|
|
247
|
-
activeEntry = val;
|
|
248
|
-
editorHeading = addNewHeading;
|
|
249
|
-
editing = true;
|
|
250
|
-
hideForm = false;
|
|
251
|
-
}
|
|
252
|
-
function handleDelete(val: any) {
|
|
253
|
-
if (onDelete) {
|
|
254
|
-
onDelete(val);
|
|
255
|
-
return;
|
|
256
|
-
}
|
|
257
|
-
activeEntry = val;
|
|
258
|
-
showAlert = true;
|
|
259
|
-
// editorHeading = updateHeading;
|
|
260
|
-
// editing = true;
|
|
261
|
-
// hideForm = true;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
function closeSideModal() {
|
|
265
|
-
hideForm = true;
|
|
266
|
-
activeEntry = null;
|
|
267
|
-
viewing = false;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
async function handleAction({ action, data }: { action: string; data: FormData }) {
|
|
271
|
-
// let formData = data;
|
|
272
|
-
let formData = dataToSave;
|
|
273
|
-
|
|
274
|
-
// console.log({ formData });
|
|
275
|
-
try {
|
|
276
|
-
isLoading = true;
|
|
277
|
-
const ret = editing
|
|
278
|
-
? await updateEntry({ ...formData, id: activeEntry.id })
|
|
279
|
-
: await createEntry(formData);
|
|
280
|
-
|
|
281
|
-
if (ret?.success) {
|
|
282
|
-
const successMessage = allowLoadAfterCreate
|
|
283
|
-
? editing
|
|
284
|
-
? 'Successfully updated record'
|
|
285
|
-
: 'Successfully added record'
|
|
286
|
-
: '';
|
|
287
|
-
toast.success(ret.message || successMessage);
|
|
288
|
-
allowLoadAfterCreate && (await fetchData(pageNumber, { search: query }));
|
|
289
|
-
|
|
290
|
-
allowDispatchAfterAction &&
|
|
291
|
-
onAfterAction &&
|
|
292
|
-
onAfterAction({ type: 'create', values: formData, data: ret.data });
|
|
293
|
-
|
|
294
|
-
hideForm = true;
|
|
295
|
-
activeEntry = {};
|
|
296
|
-
dataToSave = {};
|
|
297
|
-
closeSideModal();
|
|
298
|
-
} else {
|
|
299
|
-
toast.error(ret?.message || 'Failed');
|
|
300
|
-
}
|
|
301
|
-
} catch (error: any) {
|
|
302
|
-
toast.error(error?.message || 'failed');
|
|
303
|
-
} finally {
|
|
304
|
-
isLoading = false;
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
function closeAlert() {
|
|
309
|
-
activeEntry = {};
|
|
310
|
-
if (showAlert) showAlert = false;
|
|
311
|
-
if (deleteLoading) deleteLoading = false;
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
async function doDelete(id: string) {
|
|
315
|
-
try {
|
|
316
|
-
deleteLoading = true;
|
|
317
|
-
const ret = await deleteEntry(id);
|
|
318
|
-
if (!ret?.success) {
|
|
319
|
-
toast.error(ret?.message || 'Failed to delete');
|
|
320
|
-
return;
|
|
321
|
-
}
|
|
322
|
-
toast.success(ret.message);
|
|
323
|
-
closeAlert();
|
|
324
|
-
await fetchData(pageNumber, { search: query });
|
|
325
|
-
} catch (error: any) {
|
|
326
|
-
toast.error(error?.message || error);
|
|
327
|
-
} finally {
|
|
328
|
-
deleteLoading = false;
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
function handleFormChange(val: IFormChangeProp<any>) {
|
|
333
|
-
const { values, isValid: validForm } = val;
|
|
334
|
-
isValid = validForm;
|
|
335
|
-
dataToSave = values;
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
$effect(() => {
|
|
339
|
-
searchParams = page.url.searchParams;
|
|
340
|
-
search = page.url.search;
|
|
341
|
-
pathname = page.url.pathname;
|
|
342
|
-
|
|
343
|
-
pageNumber = extractQueryParam(page.url.search, 'page')
|
|
344
|
-
? Number(extractQueryParam(page.url.search, 'page'))
|
|
345
|
-
: pageInfo.currentPage;
|
|
346
|
-
});
|
|
347
|
-
|
|
348
|
-
onMount(() => {
|
|
349
|
-
const res = loadFromLocalStorage<{ pageSize: string }>(PAGE_SIZE_KEY);
|
|
350
|
-
if (res?.pageSize) {
|
|
351
|
-
pageInfo.setPageSize(Number(res?.pageSize));
|
|
352
|
-
} else {
|
|
353
|
-
pageInfo.setPageSize(take);
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
if (pageNumber) {
|
|
357
|
-
pageInfo.setCurrentPage(pageNumber);
|
|
358
|
-
fetchData(pageNumber, { search: query });
|
|
359
|
-
} else {
|
|
360
|
-
fetchData(pageInfo.currentPage, { search: query });
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
// Listen for custom event from parent
|
|
364
|
-
window.addEventListener('reFetchTableData', handleExternalFetch as EventListener);
|
|
365
|
-
|
|
366
|
-
// Cleanup on destroy
|
|
367
|
-
return () => {
|
|
368
|
-
window.removeEventListener('reFetchTableData', handleExternalFetch as EventListener);
|
|
369
|
-
};
|
|
370
|
-
});
|
|
371
|
-
</script>
|
|
372
|
-
|
|
373
|
-
<div class="flex h-full w-full flex-col gap-2">
|
|
374
|
-
<div
|
|
375
|
-
class="flex w-full flex-col gap-2"
|
|
376
|
-
class:custom-container={!fillSpace}
|
|
377
|
-
class:px-4={fillSpace}
|
|
378
|
-
class:table-background={showTopActionsBackground}
|
|
379
|
-
class:py-2={!showTopActionsBackground}
|
|
380
|
-
>
|
|
381
|
-
<div class="flex w-full flex-col gap-2 sm:justify-between lg:flex-row lg:items-center">
|
|
382
|
-
<div class="flex w-full flex-col gap-2 sm:flex-row">
|
|
383
|
-
<div class:hidden={hideSearchBox} class="w-full lg:max-w-lg">
|
|
384
|
-
<Input
|
|
385
|
-
value={query}
|
|
386
|
-
oninput={onSearchChange}
|
|
387
|
-
placeholder={searchPlaceholder}
|
|
388
|
-
class="h-9.5 ps-8"
|
|
389
|
-
>
|
|
390
|
-
{#snippet left()}
|
|
391
|
-
<iconify-icon icon="eva:search-outline" class="text-xl text-gray-500"></iconify-icon>
|
|
392
|
-
{/snippet}
|
|
393
|
-
</Input>
|
|
394
|
-
</div>
|
|
395
|
-
<div class:hidden={!showFilterDateRange} class="w-full sm:max-w-60">
|
|
396
|
-
<Datepicker
|
|
397
|
-
placeholder="Date Range"
|
|
398
|
-
onselect={handleDateRangeChange}
|
|
399
|
-
range
|
|
400
|
-
rangeFrom={rangeDate.from}
|
|
401
|
-
rangeTo={rangeDate.to}
|
|
402
|
-
/>
|
|
403
|
-
</div>
|
|
404
|
-
</div>
|
|
405
|
-
|
|
406
|
-
<div class="flex shrink-0 flex-col gap-4 sm:flex-row sm:items-center">
|
|
407
|
-
<div class="flex items-center gap-2">
|
|
408
|
-
<div class="text-sm">Page Size</div>
|
|
409
|
-
<Select
|
|
410
|
-
value={pageInfo.pageSize}
|
|
411
|
-
clearable={false}
|
|
412
|
-
searchable={false}
|
|
413
|
-
options={[
|
|
414
|
-
{ value: 15, label: '15' },
|
|
415
|
-
{ value: 20, label: '20' },
|
|
416
|
-
{ value: 25, label: '25' },
|
|
417
|
-
{ value: 30, label: '30' },
|
|
418
|
-
{ value: 40, label: '40' },
|
|
419
|
-
{ value: 45, label: '45' },
|
|
420
|
-
{ value: 50, label: '50' },
|
|
421
|
-
{ value: 100, label: '100' }
|
|
422
|
-
]}
|
|
423
|
-
placeholder="15"
|
|
424
|
-
onChange={(e) => {
|
|
425
|
-
const { value } = e;
|
|
426
|
-
handlePageSize(value);
|
|
427
|
-
}}
|
|
428
|
-
/>
|
|
429
|
-
</div>
|
|
430
|
-
<div>
|
|
431
|
-
<Paginate
|
|
432
|
-
onNextPage={getMore}
|
|
433
|
-
onPreviousPage={getLess}
|
|
434
|
-
currentPage={pageInfo.currentPage}
|
|
435
|
-
totalPages={pageInfo.totalPages}
|
|
436
|
-
hasNextPage={pageInfo.hasNextPage}
|
|
437
|
-
hasPreviousPage={pageInfo.hasPrevPage}
|
|
438
|
-
recordCount={pageInfo.totalItems}
|
|
439
|
-
refresh={() => {
|
|
440
|
-
fetchData(pageNumber, { search: query });
|
|
441
|
-
}}
|
|
442
|
-
tableColumns={$allColumns}
|
|
443
|
-
bind:hiddenColumns
|
|
444
|
-
/>
|
|
445
|
-
</div>
|
|
446
|
-
{#if customAddAction}
|
|
447
|
-
{@render customAddAction?.()}
|
|
448
|
-
{:else}
|
|
449
|
-
<div class:hidden={!showAdd} class="shrink-0">
|
|
450
|
-
<Button onclick={addNew}>{addButtonLabel}</Button>
|
|
451
|
-
</div>
|
|
452
|
-
{/if}
|
|
453
|
-
</div>
|
|
454
|
-
</div>
|
|
455
|
-
</div>
|
|
456
|
-
<div class:custom-container={!fillSpace} class="flex h-full w-full flex-col gap-2">
|
|
457
|
-
{@render customFilter?.({
|
|
458
|
-
pageSize: pageInfo.pageSize ?? 0,
|
|
459
|
-
currentPage: pageInfo.currentPage ?? 0,
|
|
460
|
-
search: query ?? ''
|
|
461
|
-
})}
|
|
462
|
-
{#if busy}
|
|
463
|
-
<TableLoader bodySize={loadingBodySize} headerSize={loadingHeaderSize} />
|
|
464
|
-
{:else}
|
|
465
|
-
<div class="h-full w-full flex-grow">
|
|
466
|
-
<Table
|
|
467
|
-
data={tableData}
|
|
468
|
-
{headerColor}
|
|
469
|
-
bind:hiddenColumns
|
|
470
|
-
onEdit={handleEdit}
|
|
471
|
-
onView={handleView}
|
|
472
|
-
onDelete={handleDelete}
|
|
473
|
-
onRowClicked={handleRowClicked}
|
|
474
|
-
{onActionClicked}
|
|
475
|
-
{handleCheckbox}
|
|
476
|
-
{...otherProps}
|
|
477
|
-
/>
|
|
478
|
-
</div>
|
|
479
|
-
{/if}
|
|
480
|
-
</div>
|
|
481
|
-
</div>
|
|
482
|
-
|
|
483
|
-
<Drawer
|
|
484
|
-
bind:hidden={hideForm}
|
|
485
|
-
placement="right"
|
|
486
|
-
activateClickOutside={false}
|
|
487
|
-
title={editorHeading}
|
|
488
|
-
size={modalSize}
|
|
489
|
-
onclose={closeSideModal}
|
|
490
|
-
form
|
|
491
|
-
transitionType={slide}
|
|
492
|
-
transitionParams={{
|
|
493
|
-
duration: 300,
|
|
494
|
-
axis: 'x'
|
|
495
|
-
}}
|
|
496
|
-
onaction={handleAction}
|
|
497
|
-
>
|
|
498
|
-
{@render editor?.({
|
|
499
|
-
recordId: activeEntry.id,
|
|
500
|
-
data: activeEntry,
|
|
501
|
-
onChange: handleFormChange as any,
|
|
502
|
-
readonly: viewing
|
|
503
|
-
})}
|
|
504
|
-
|
|
505
|
-
{#snippet footer()}
|
|
506
|
-
{#if showModalButtons}
|
|
507
|
-
{#if modalFooter}
|
|
508
|
-
{@render modalFooter()}
|
|
509
|
-
{:else if !viewing}
|
|
510
|
-
<Button disabled={!isValid} loading={isLoading} type="submit" class="w-full" value="submit"
|
|
511
|
-
>Submit</Button
|
|
512
|
-
>
|
|
513
|
-
{/if}
|
|
514
|
-
{/if}
|
|
515
|
-
{/snippet}
|
|
516
|
-
</Drawer>
|
|
517
|
-
|
|
518
|
-
<AlertDialog
|
|
519
|
-
bind:open={showAlert}
|
|
520
|
-
message="Are you sure you want to delete this?"
|
|
521
|
-
icon="ion:trash"
|
|
522
|
-
onCancel={closeAlert}
|
|
523
|
-
busy={deleteLoading}
|
|
524
|
-
onYes={() => doDelete(activeEntry?.id)}
|
|
525
|
-
/>
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { goto } from '$app/navigation';
|
|
3
|
+
import { page } from '$app/state';
|
|
4
|
+
import {
|
|
5
|
+
AlertDialog,
|
|
6
|
+
Button,
|
|
7
|
+
Datepicker,
|
|
8
|
+
Drawer,
|
|
9
|
+
extractQueryParam,
|
|
10
|
+
Input,
|
|
11
|
+
loadFromLocalStorage,
|
|
12
|
+
Paginate,
|
|
13
|
+
saveToLocalStorage,
|
|
14
|
+
Select,
|
|
15
|
+
Table,
|
|
16
|
+
TableLoader,
|
|
17
|
+
toast,
|
|
18
|
+
type DatatableProps,
|
|
19
|
+
type IFormChangeProp,
|
|
20
|
+
type TableFilter
|
|
21
|
+
} from '../../index.js';
|
|
22
|
+
import { PageInfo } from '../../utils/paginate.svelte.js';
|
|
23
|
+
import debounce from 'lodash/debounce';
|
|
24
|
+
import { onMount } from 'svelte';
|
|
25
|
+
import { writable } from 'svelte/store';
|
|
26
|
+
import { slide } from 'svelte/transition';
|
|
27
|
+
|
|
28
|
+
let {
|
|
29
|
+
persitFiltersToUrl = false,
|
|
30
|
+
showTopActionsBackground = true,
|
|
31
|
+
fillSpace = true,
|
|
32
|
+
onAfterAction,
|
|
33
|
+
hideSearchBox = false,
|
|
34
|
+
showAdd = true,
|
|
35
|
+
addButtonLabel = 'Add New',
|
|
36
|
+
searchPlaceholder = 'Search...',
|
|
37
|
+
addNewHeading = 'Add New Record',
|
|
38
|
+
updateHeading = 'Update',
|
|
39
|
+
headerColor = 'blue',
|
|
40
|
+
newRecord = {},
|
|
41
|
+
query = $bindable(''),
|
|
42
|
+
hiddenColumns = [],
|
|
43
|
+
customFilterValues = {},
|
|
44
|
+
onAddNew,
|
|
45
|
+
busy = false,
|
|
46
|
+
showFilterDateRange = false,
|
|
47
|
+
loadingBodySize = 10,
|
|
48
|
+
loadingHeaderSize = 6,
|
|
49
|
+
allowLoadAfterCreate = true,
|
|
50
|
+
allowDispatchAfterAction = false,
|
|
51
|
+
modalSize = 'md',
|
|
52
|
+
take = 15,
|
|
53
|
+
onActionClicked,
|
|
54
|
+
onRowClicked,
|
|
55
|
+
onView,
|
|
56
|
+
onEdit,
|
|
57
|
+
onDelete,
|
|
58
|
+
editor,
|
|
59
|
+
customFilter,
|
|
60
|
+
handleCheckbox,
|
|
61
|
+
read = $bindable((skip?: number, take?: number, filter?: TableFilter<any>) => {
|
|
62
|
+
return null;
|
|
63
|
+
}),
|
|
64
|
+
updateEntry = (x: any) => {
|
|
65
|
+
return null;
|
|
66
|
+
},
|
|
67
|
+
createEntry = async (x: any) => {
|
|
68
|
+
return { success: false, data: null, error: null } as any;
|
|
69
|
+
},
|
|
70
|
+
deleteEntry = async (id: string | number) => {
|
|
71
|
+
return { success: false, data: null, error: null } as any;
|
|
72
|
+
},
|
|
73
|
+
modalFooter,
|
|
74
|
+
showModalButtons = true,
|
|
75
|
+
customAddAction,
|
|
76
|
+
...otherProps
|
|
77
|
+
}: DatatableProps = $props();
|
|
78
|
+
|
|
79
|
+
const PAGE_SIZE_KEY = 'customTablePageSize';
|
|
80
|
+
let editorHeading = $state('');
|
|
81
|
+
let hideForm = $state(true);
|
|
82
|
+
let editing = $state(false);
|
|
83
|
+
let activeEntry = $state<any>({});
|
|
84
|
+
let pageInfo = new PageInfo();
|
|
85
|
+
const rangeDate = $derived(getRange());
|
|
86
|
+
let allColumns = $state(writable<any>([]));
|
|
87
|
+
let pathname = $state('');
|
|
88
|
+
let search = $state('');
|
|
89
|
+
let pageNumber = $state(0);
|
|
90
|
+
let searchParams = $state<any>(null);
|
|
91
|
+
let showAlert = $state(false);
|
|
92
|
+
let tableData = $state<any[]>([]);
|
|
93
|
+
let isLoading = $state(false);
|
|
94
|
+
let deleteLoading = $state(false);
|
|
95
|
+
let isValid = $state(false);
|
|
96
|
+
let viewing = $state(false);
|
|
97
|
+
let dataToSave = $state<any>({});
|
|
98
|
+
|
|
99
|
+
function addNew() {
|
|
100
|
+
if (onAddNew) {
|
|
101
|
+
onAddNew();
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
editorHeading = addNewHeading;
|
|
105
|
+
activeEntry = (newRecord && { ...newRecord }) || null;
|
|
106
|
+
editing = false;
|
|
107
|
+
hideForm = false;
|
|
108
|
+
viewing = false;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async function fetchData(page: number, params: TableFilter) {
|
|
112
|
+
try {
|
|
113
|
+
let currentPage = 0;
|
|
114
|
+
busy = true;
|
|
115
|
+
if (params.search) {
|
|
116
|
+
pageInfo.setCurrentPage(1);
|
|
117
|
+
currentPage = pageInfo.currentPage;
|
|
118
|
+
} else {
|
|
119
|
+
currentPage = page || pageInfo.currentPage;
|
|
120
|
+
}
|
|
121
|
+
let newParams: any = {
|
|
122
|
+
page: currentPage,
|
|
123
|
+
pageSize: pageInfo.pageSize,
|
|
124
|
+
search: params.search ?? '',
|
|
125
|
+
filter: params.filter ?? {},
|
|
126
|
+
order: params.order ?? []
|
|
127
|
+
};
|
|
128
|
+
const ret = await read(newParams.page, newParams.pageSize, {
|
|
129
|
+
...params,
|
|
130
|
+
filter: { ...customFilterValues },
|
|
131
|
+
search: newParams.search ?? ''
|
|
132
|
+
});
|
|
133
|
+
if (!ret?.success) {
|
|
134
|
+
// showError(ret?.message || 'Failed to load data');
|
|
135
|
+
toast.error(ret?.message || 'Failed to load data');
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
const xs = ret.data;
|
|
139
|
+
// console.log({xs})
|
|
140
|
+
pageInfo.totalItems = xs.totalCount;
|
|
141
|
+
pageInfo.setHasNextPage(xs.pageInfo.hasNextPage);
|
|
142
|
+
pageInfo.setHasPrevPage(xs.pageInfo.hasPreviousPage);
|
|
143
|
+
tableData = xs.items;
|
|
144
|
+
} catch (e: any) {
|
|
145
|
+
toast.error(e.message || e);
|
|
146
|
+
} finally {
|
|
147
|
+
busy = false;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const debouncedSearch = debounce(fetchData, 300);
|
|
152
|
+
|
|
153
|
+
function onSearchChange(e: Event) {
|
|
154
|
+
const target = e.target as HTMLInputElement | null;
|
|
155
|
+
const value = target ? target.value : '';
|
|
156
|
+
debouncedSearch(pageNumber, { search: value });
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function getRange() {
|
|
160
|
+
return { from: undefined, to: undefined };
|
|
161
|
+
}
|
|
162
|
+
function handleDateRangeChange(e) {
|
|
163
|
+
console.log({ e });
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async function handlePageSize(val: number) {
|
|
167
|
+
pageInfo.setPageSize(val);
|
|
168
|
+
await fetchData(pageInfo.currentPage, { search: query });
|
|
169
|
+
|
|
170
|
+
saveToLocalStorage(PAGE_SIZE_KEY, { pageSize: val });
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
async function getMore() {
|
|
174
|
+
if (pageInfo.gotoNext()) {
|
|
175
|
+
const value = pageInfo.currentPage;
|
|
176
|
+
if (persitFiltersToUrl) {
|
|
177
|
+
const current = new URLSearchParams(Array.from(searchParams.entries()) as any);
|
|
178
|
+
|
|
179
|
+
if (!value) {
|
|
180
|
+
current.delete('page');
|
|
181
|
+
} else {
|
|
182
|
+
current.set('page', String(value));
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const search = current.toString();
|
|
186
|
+
const page = search ? `?${search}` : '';
|
|
187
|
+
await goto(`${pathname}${page}`);
|
|
188
|
+
}
|
|
189
|
+
await fetchData(value, { search: query });
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
async function getLess() {
|
|
194
|
+
if (pageInfo.gotoPrev()) {
|
|
195
|
+
const value = pageInfo.currentPage;
|
|
196
|
+
if (persitFiltersToUrl) {
|
|
197
|
+
const current = new URLSearchParams(Array.from(searchParams.entries()) as any);
|
|
198
|
+
if (!value) {
|
|
199
|
+
current.delete('page');
|
|
200
|
+
} else {
|
|
201
|
+
current.set('page', String(value));
|
|
202
|
+
}
|
|
203
|
+
const search = current.toString();
|
|
204
|
+
const page = search ? `?${search}` : '';
|
|
205
|
+
await goto(`${pathname}${page}`);
|
|
206
|
+
}
|
|
207
|
+
await fetchData(value, { search: query });
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function handleExternalFetch(event: CustomEvent) {
|
|
212
|
+
const { page: customPage, params: customParams } = event.detail || {};
|
|
213
|
+
const fetchPage = customPage !== undefined ? customPage : pageNumber;
|
|
214
|
+
const fetchParams = customParams || { search: query };
|
|
215
|
+
|
|
216
|
+
fetchData(fetchPage, fetchParams);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function handleEdit(val: any) {
|
|
220
|
+
if (onEdit) {
|
|
221
|
+
onEdit(val);
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
activeEntry = val;
|
|
225
|
+
editorHeading = updateHeading;
|
|
226
|
+
editing = true;
|
|
227
|
+
hideForm = false;
|
|
228
|
+
viewing = false;
|
|
229
|
+
}
|
|
230
|
+
function handleView(val: any) {
|
|
231
|
+
if (onView) {
|
|
232
|
+
onView(val);
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
activeEntry = val;
|
|
236
|
+
editorHeading = 'View Record';
|
|
237
|
+
editing = true;
|
|
238
|
+
hideForm = false;
|
|
239
|
+
viewing = true;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function handleRowClicked(val: any) {
|
|
243
|
+
if (onRowClicked) {
|
|
244
|
+
onRowClicked(val);
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
activeEntry = val;
|
|
248
|
+
editorHeading = addNewHeading;
|
|
249
|
+
editing = true;
|
|
250
|
+
hideForm = false;
|
|
251
|
+
}
|
|
252
|
+
function handleDelete(val: any) {
|
|
253
|
+
if (onDelete) {
|
|
254
|
+
onDelete(val);
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
activeEntry = val;
|
|
258
|
+
showAlert = true;
|
|
259
|
+
// editorHeading = updateHeading;
|
|
260
|
+
// editing = true;
|
|
261
|
+
// hideForm = true;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function closeSideModal() {
|
|
265
|
+
hideForm = true;
|
|
266
|
+
activeEntry = null;
|
|
267
|
+
viewing = false;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
async function handleAction({ action, data }: { action: string; data: FormData }) {
|
|
271
|
+
// let formData = data;
|
|
272
|
+
let formData = dataToSave;
|
|
273
|
+
|
|
274
|
+
// console.log({ formData });
|
|
275
|
+
try {
|
|
276
|
+
isLoading = true;
|
|
277
|
+
const ret = editing
|
|
278
|
+
? await updateEntry({ ...formData, id: activeEntry.id })
|
|
279
|
+
: await createEntry(formData);
|
|
280
|
+
|
|
281
|
+
if (ret?.success) {
|
|
282
|
+
const successMessage = allowLoadAfterCreate
|
|
283
|
+
? editing
|
|
284
|
+
? 'Successfully updated record'
|
|
285
|
+
: 'Successfully added record'
|
|
286
|
+
: '';
|
|
287
|
+
toast.success(ret.message || successMessage);
|
|
288
|
+
allowLoadAfterCreate && (await fetchData(pageNumber, { search: query }));
|
|
289
|
+
|
|
290
|
+
allowDispatchAfterAction &&
|
|
291
|
+
onAfterAction &&
|
|
292
|
+
onAfterAction({ type: 'create', values: formData, data: ret.data });
|
|
293
|
+
|
|
294
|
+
hideForm = true;
|
|
295
|
+
activeEntry = {};
|
|
296
|
+
dataToSave = {};
|
|
297
|
+
closeSideModal();
|
|
298
|
+
} else {
|
|
299
|
+
toast.error(ret?.message || 'Failed');
|
|
300
|
+
}
|
|
301
|
+
} catch (error: any) {
|
|
302
|
+
toast.error(error?.message || 'failed');
|
|
303
|
+
} finally {
|
|
304
|
+
isLoading = false;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
function closeAlert() {
|
|
309
|
+
activeEntry = {};
|
|
310
|
+
if (showAlert) showAlert = false;
|
|
311
|
+
if (deleteLoading) deleteLoading = false;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
async function doDelete(id: string) {
|
|
315
|
+
try {
|
|
316
|
+
deleteLoading = true;
|
|
317
|
+
const ret = await deleteEntry(id);
|
|
318
|
+
if (!ret?.success) {
|
|
319
|
+
toast.error(ret?.message || 'Failed to delete');
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
toast.success(ret.message);
|
|
323
|
+
closeAlert();
|
|
324
|
+
await fetchData(pageNumber, { search: query });
|
|
325
|
+
} catch (error: any) {
|
|
326
|
+
toast.error(error?.message || error);
|
|
327
|
+
} finally {
|
|
328
|
+
deleteLoading = false;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function handleFormChange(val: IFormChangeProp<any>) {
|
|
333
|
+
const { values, isValid: validForm } = val;
|
|
334
|
+
isValid = validForm;
|
|
335
|
+
dataToSave = values;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
$effect(() => {
|
|
339
|
+
searchParams = page.url.searchParams;
|
|
340
|
+
search = page.url.search;
|
|
341
|
+
pathname = page.url.pathname;
|
|
342
|
+
|
|
343
|
+
pageNumber = extractQueryParam(page.url.search, 'page')
|
|
344
|
+
? Number(extractQueryParam(page.url.search, 'page'))
|
|
345
|
+
: pageInfo.currentPage;
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
onMount(() => {
|
|
349
|
+
const res = loadFromLocalStorage<{ pageSize: string }>(PAGE_SIZE_KEY);
|
|
350
|
+
if (res?.pageSize) {
|
|
351
|
+
pageInfo.setPageSize(Number(res?.pageSize));
|
|
352
|
+
} else {
|
|
353
|
+
pageInfo.setPageSize(take);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
if (pageNumber) {
|
|
357
|
+
pageInfo.setCurrentPage(pageNumber);
|
|
358
|
+
fetchData(pageNumber, { search: query });
|
|
359
|
+
} else {
|
|
360
|
+
fetchData(pageInfo.currentPage, { search: query });
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// Listen for custom event from parent
|
|
364
|
+
window.addEventListener('reFetchTableData', handleExternalFetch as EventListener);
|
|
365
|
+
|
|
366
|
+
// Cleanup on destroy
|
|
367
|
+
return () => {
|
|
368
|
+
window.removeEventListener('reFetchTableData', handleExternalFetch as EventListener);
|
|
369
|
+
};
|
|
370
|
+
});
|
|
371
|
+
</script>
|
|
372
|
+
|
|
373
|
+
<div class="flex h-full w-full flex-col gap-2">
|
|
374
|
+
<div
|
|
375
|
+
class="flex w-full flex-col gap-2"
|
|
376
|
+
class:custom-container={!fillSpace}
|
|
377
|
+
class:px-4={fillSpace}
|
|
378
|
+
class:table-background={showTopActionsBackground}
|
|
379
|
+
class:py-2={!showTopActionsBackground}
|
|
380
|
+
>
|
|
381
|
+
<div class="flex w-full flex-col gap-2 sm:justify-between lg:flex-row lg:items-center">
|
|
382
|
+
<div class="flex w-full flex-col gap-2 sm:flex-row">
|
|
383
|
+
<div class:hidden={hideSearchBox} class="w-full lg:max-w-lg">
|
|
384
|
+
<Input
|
|
385
|
+
value={query}
|
|
386
|
+
oninput={onSearchChange}
|
|
387
|
+
placeholder={searchPlaceholder}
|
|
388
|
+
class="h-9.5 ps-8"
|
|
389
|
+
>
|
|
390
|
+
{#snippet left()}
|
|
391
|
+
<iconify-icon icon="eva:search-outline" class="text-xl text-gray-500"></iconify-icon>
|
|
392
|
+
{/snippet}
|
|
393
|
+
</Input>
|
|
394
|
+
</div>
|
|
395
|
+
<div class:hidden={!showFilterDateRange} class="w-full sm:max-w-60">
|
|
396
|
+
<Datepicker
|
|
397
|
+
placeholder="Date Range"
|
|
398
|
+
onselect={handleDateRangeChange}
|
|
399
|
+
range
|
|
400
|
+
rangeFrom={rangeDate.from}
|
|
401
|
+
rangeTo={rangeDate.to}
|
|
402
|
+
/>
|
|
403
|
+
</div>
|
|
404
|
+
</div>
|
|
405
|
+
|
|
406
|
+
<div class="flex shrink-0 flex-col gap-4 sm:flex-row sm:items-center">
|
|
407
|
+
<div class="flex items-center gap-2">
|
|
408
|
+
<div class="text-sm">Page Size</div>
|
|
409
|
+
<Select
|
|
410
|
+
value={pageInfo.pageSize}
|
|
411
|
+
clearable={false}
|
|
412
|
+
searchable={false}
|
|
413
|
+
options={[
|
|
414
|
+
{ value: 15, label: '15' },
|
|
415
|
+
{ value: 20, label: '20' },
|
|
416
|
+
{ value: 25, label: '25' },
|
|
417
|
+
{ value: 30, label: '30' },
|
|
418
|
+
{ value: 40, label: '40' },
|
|
419
|
+
{ value: 45, label: '45' },
|
|
420
|
+
{ value: 50, label: '50' },
|
|
421
|
+
{ value: 100, label: '100' }
|
|
422
|
+
]}
|
|
423
|
+
placeholder="15"
|
|
424
|
+
onChange={(e) => {
|
|
425
|
+
const { value } = e;
|
|
426
|
+
handlePageSize(value);
|
|
427
|
+
}}
|
|
428
|
+
/>
|
|
429
|
+
</div>
|
|
430
|
+
<div>
|
|
431
|
+
<Paginate
|
|
432
|
+
onNextPage={getMore}
|
|
433
|
+
onPreviousPage={getLess}
|
|
434
|
+
currentPage={pageInfo.currentPage}
|
|
435
|
+
totalPages={pageInfo.totalPages}
|
|
436
|
+
hasNextPage={pageInfo.hasNextPage}
|
|
437
|
+
hasPreviousPage={pageInfo.hasPrevPage}
|
|
438
|
+
recordCount={pageInfo.totalItems}
|
|
439
|
+
refresh={() => {
|
|
440
|
+
fetchData(pageNumber, { search: query });
|
|
441
|
+
}}
|
|
442
|
+
tableColumns={$allColumns}
|
|
443
|
+
bind:hiddenColumns
|
|
444
|
+
/>
|
|
445
|
+
</div>
|
|
446
|
+
{#if customAddAction}
|
|
447
|
+
{@render customAddAction?.()}
|
|
448
|
+
{:else}
|
|
449
|
+
<div class:hidden={!showAdd} class="shrink-0">
|
|
450
|
+
<Button onclick={addNew}>{addButtonLabel}</Button>
|
|
451
|
+
</div>
|
|
452
|
+
{/if}
|
|
453
|
+
</div>
|
|
454
|
+
</div>
|
|
455
|
+
</div>
|
|
456
|
+
<div class:custom-container={!fillSpace} class="flex h-full w-full flex-col gap-2">
|
|
457
|
+
{@render customFilter?.({
|
|
458
|
+
pageSize: pageInfo.pageSize ?? 0,
|
|
459
|
+
currentPage: pageInfo.currentPage ?? 0,
|
|
460
|
+
search: query ?? ''
|
|
461
|
+
})}
|
|
462
|
+
{#if busy}
|
|
463
|
+
<TableLoader bodySize={loadingBodySize} headerSize={loadingHeaderSize} />
|
|
464
|
+
{:else}
|
|
465
|
+
<div class="h-full w-full flex-grow">
|
|
466
|
+
<Table
|
|
467
|
+
data={tableData}
|
|
468
|
+
{headerColor}
|
|
469
|
+
bind:hiddenColumns
|
|
470
|
+
onEdit={handleEdit}
|
|
471
|
+
onView={handleView}
|
|
472
|
+
onDelete={handleDelete}
|
|
473
|
+
onRowClicked={handleRowClicked}
|
|
474
|
+
{onActionClicked}
|
|
475
|
+
{handleCheckbox}
|
|
476
|
+
{...otherProps}
|
|
477
|
+
/>
|
|
478
|
+
</div>
|
|
479
|
+
{/if}
|
|
480
|
+
</div>
|
|
481
|
+
</div>
|
|
482
|
+
|
|
483
|
+
<Drawer
|
|
484
|
+
bind:hidden={hideForm}
|
|
485
|
+
placement="right"
|
|
486
|
+
activateClickOutside={false}
|
|
487
|
+
title={editorHeading}
|
|
488
|
+
size={modalSize}
|
|
489
|
+
onclose={closeSideModal}
|
|
490
|
+
form
|
|
491
|
+
transitionType={slide}
|
|
492
|
+
transitionParams={{
|
|
493
|
+
duration: 300,
|
|
494
|
+
axis: 'x'
|
|
495
|
+
}}
|
|
496
|
+
onaction={handleAction}
|
|
497
|
+
>
|
|
498
|
+
{@render editor?.({
|
|
499
|
+
recordId: activeEntry.id,
|
|
500
|
+
data: activeEntry,
|
|
501
|
+
onChange: handleFormChange as any,
|
|
502
|
+
readonly: viewing
|
|
503
|
+
})}
|
|
504
|
+
|
|
505
|
+
{#snippet footer()}
|
|
506
|
+
{#if showModalButtons}
|
|
507
|
+
{#if modalFooter}
|
|
508
|
+
{@render modalFooter()}
|
|
509
|
+
{:else if !viewing}
|
|
510
|
+
<Button disabled={!isValid} loading={isLoading} type="submit" class="w-full" value="submit"
|
|
511
|
+
>Submit</Button
|
|
512
|
+
>
|
|
513
|
+
{/if}
|
|
514
|
+
{/if}
|
|
515
|
+
{/snippet}
|
|
516
|
+
</Drawer>
|
|
517
|
+
|
|
518
|
+
<AlertDialog
|
|
519
|
+
bind:open={showAlert}
|
|
520
|
+
message="Are you sure you want to delete this?"
|
|
521
|
+
icon="ion:trash"
|
|
522
|
+
onCancel={closeAlert}
|
|
523
|
+
busy={deleteLoading}
|
|
524
|
+
onYes={() => doDelete(activeEntry?.id)}
|
|
525
|
+
/>
|