@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.
Files changed (103) hide show
  1. package/README.md +8 -8
  2. package/dist/baseEditor/index.svelte +32 -32
  3. package/dist/builders/filters/FilterBuilder.svelte +641 -641
  4. package/dist/forms/FormCheckbox/FormCheckbox.svelte +53 -53
  5. package/dist/forms/FormClEditor/ClEdito.svelte +68 -68
  6. package/dist/forms/FormDatepicker/FormDatepicker.svelte +159 -159
  7. package/dist/forms/FormFileUpload/FormFileUplad.svelte +134 -134
  8. package/dist/forms/FormInput/FormInput.svelte +87 -87
  9. package/dist/forms/FormRadio/FormRadio.svelte +53 -53
  10. package/dist/forms/FormSelect/FormSelect.svelte +88 -88
  11. package/dist/forms/FormTextarea/FormTextarea.svelte +78 -78
  12. package/dist/forms/button-toggle/ButtonToggle.svelte +119 -119
  13. package/dist/forms/button-toggle/CheckIcon.svelte +28 -28
  14. package/dist/forms/checkbox/Checkbox.svelte +82 -82
  15. package/dist/forms/checkbox/CheckboxButton.svelte +92 -92
  16. package/dist/forms/datepicker/Datepicker.svelte +707 -707
  17. package/dist/forms/form/Form.svelte +69 -69
  18. package/dist/forms/input/Input.svelte +363 -363
  19. package/dist/forms/label/Label.svelte +38 -38
  20. package/dist/forms/radio/Radio.svelte +48 -48
  21. package/dist/forms/radio/RadioButton.svelte +22 -22
  22. package/dist/forms/select/Select.svelte +56 -56
  23. package/dist/forms/textarea/Textarea.svelte +165 -165
  24. package/dist/forms/toggle/Toggle.svelte +70 -70
  25. package/dist/layout/Chat/CategorySelector.svelte +52 -52
  26. package/dist/layout/Chat/ChatEntry.svelte +246 -246
  27. package/dist/layout/Chat/ChatEntrySkeleton.svelte +81 -81
  28. package/dist/layout/Chat/ChatHeader.svelte +172 -172
  29. package/dist/layout/Chat/ChatInput.svelte +207 -207
  30. package/dist/layout/Chat/DraggableWindow.svelte +230 -230
  31. package/dist/layout/Chat/PreviewPage.svelte +182 -182
  32. package/dist/layout/Chat/RichText.svelte +216 -216
  33. package/dist/layout/ComponentCanvas/Canvas.svelte +40 -40
  34. package/dist/layout/ComponentCanvas/ComponentRenderer.svelte +85 -85
  35. package/dist/layout/TF/Content/Content.svelte +21 -21
  36. package/dist/layout/TF/Header/Header.svelte +166 -166
  37. package/dist/layout/TF/Sidebar/Sidebar.svelte +148 -148
  38. package/dist/layout/TF/Wrapper/Wrapper.svelte +17 -17
  39. package/dist/layout/mailing/MailPaginator.svelte +36 -36
  40. package/dist/layout/mailing/MailSidebar.svelte +39 -39
  41. package/dist/layout/mailing/MailToolBar.svelte +174 -174
  42. package/dist/layout/mailing/MailingContent.svelte +10 -10
  43. package/dist/layout/mailing/MailingHeader.svelte +55 -55
  44. package/dist/layout/mailing/MailingMessageCard.svelte +112 -112
  45. package/dist/layout/mailing/MailingMessageViewer.svelte +87 -87
  46. package/dist/layout/mailing/MailingModule.svelte +448 -448
  47. package/dist/styles/docs.css +615 -615
  48. package/dist/styles/tf-layout.css +185 -185
  49. package/dist/themes/ThemeProvider.svelte +20 -20
  50. package/dist/types/index.d.ts +2 -0
  51. package/dist/typography/heading/Heading.svelte +35 -35
  52. package/dist/ui/accordion/Accordion.svelte +49 -49
  53. package/dist/ui/accordion/AccordionItem.svelte +173 -173
  54. package/dist/ui/alert/Alert.svelte +83 -83
  55. package/dist/ui/alertDialog/AlertDialog.svelte +40 -40
  56. package/dist/ui/avatar/Avatar.svelte +77 -77
  57. package/dist/ui/box/Box.svelte +28 -28
  58. package/dist/ui/breadcrumb/Breadcrumb.svelte +39 -39
  59. package/dist/ui/buttons/ActionButton.svelte +234 -234
  60. package/dist/ui/buttons/Button.svelte +102 -102
  61. package/dist/ui/buttons/GradientButton.svelte +59 -59
  62. package/dist/ui/datatable/Datatable.svelte +525 -525
  63. package/dist/ui/drawer/Drawer.svelte +300 -300
  64. package/dist/ui/dropdown/Dropdown.svelte +36 -36
  65. package/dist/ui/dropdown/DropdownDivider.svelte +11 -11
  66. package/dist/ui/dropdown/DropdownGroup.svelte +14 -14
  67. package/dist/ui/dropdown/DropdownHeader.svelte +14 -14
  68. package/dist/ui/dropdown/DropdownItem.svelte +52 -52
  69. package/dist/ui/footer/Footer.svelte +15 -15
  70. package/dist/ui/footer/FooterBrand.svelte +37 -37
  71. package/dist/ui/footer/FooterCopyright.svelte +45 -45
  72. package/dist/ui/footer/FooterIcon.svelte +22 -22
  73. package/dist/ui/footer/FooterLink.svelte +33 -33
  74. package/dist/ui/footer/FooterLinkGroup.svelte +13 -13
  75. package/dist/ui/icons/IconifyIcon.svelte +7 -7
  76. package/dist/ui/indicator/Indicator.svelte +42 -42
  77. package/dist/ui/modal/Modal.svelte +265 -265
  78. package/dist/ui/notificationList/NotificationList.svelte +123 -123
  79. package/dist/ui/pageLoader/PageLoader.svelte +14 -14
  80. package/dist/ui/pageLoader/PageLoader2.svelte +99 -0
  81. package/dist/ui/pageLoader/PageLoader2.svelte.d.ts +24 -0
  82. package/dist/ui/pageLoader/index.d.ts +2 -1
  83. package/dist/ui/pageLoader/index.js +2 -1
  84. package/dist/ui/paginate/Paginate.svelte +96 -96
  85. package/dist/ui/speedDial/SpeedDial.svelte +77 -77
  86. package/dist/ui/speedDial/SpeedDialButton.svelte +75 -75
  87. package/dist/ui/speedDial/SpeedDialTrigger.svelte +79 -79
  88. package/dist/ui/tab/Tab.svelte +93 -67
  89. package/dist/ui/table/Table.svelte +396 -396
  90. package/dist/ui/tableLoader/TableLoader.svelte +24 -24
  91. package/dist/ui/toast/Toast.svelte +337 -337
  92. package/dist/ui/toast/Toast.svelte.d.ts +10 -10
  93. package/dist/ui/toolbar/Toolbar.svelte +59 -59
  94. package/dist/ui/toolbar/ToolbarButton.svelte +56 -56
  95. package/dist/ui/toolbar/ToolbarGroup.svelte +43 -43
  96. package/dist/ui/tooltip/Tooltip.svelte +51 -51
  97. package/dist/utils/Popper.svelte +257 -257
  98. package/dist/utils/closeButton/CloseButton.svelte +88 -88
  99. package/dist/utils/index.d.ts +2 -2
  100. package/dist/utils/index.js +3 -3
  101. package/dist/utils/singleSelection.svelte.js +48 -48
  102. package/dist/youtube/index.svelte +12 -12
  103. package/package.json +1 -1
@@ -1,448 +1,448 @@
1
- <script lang="ts">
2
- import { PageLoader } from '../../ui/pageLoader/index.js';
3
- import { scale, slide } from 'svelte/transition';
4
- import {
5
- MailSidebar,
6
- MailToolBar,
7
- type MailingModuleProps,
8
- type MailMenu,
9
- type MailingMessage,
10
- type MailMarkReadToggleType,
11
- type MailFavariteToggleType,
12
- type MailPageInfo,
13
- type MailingActiveBox
14
- } from './index.js';
15
- import MailingMessageCard from './MailingMessageCard.svelte';
16
- import { toast, type CrudResult, type TableFilter } from '../../index.js';
17
- import { PageInfo } from '../../utils/paginate.svelte.js';
18
- import AlertDialog from '../../ui/alertDialog/AlertDialog.svelte';
19
- import MailingMessageViewer from './MailingMessageViewer.svelte';
20
- import debounce from 'lodash/debounce';
21
-
22
- let {
23
- showSidePanel = true,
24
- showPagination = true,
25
- showComposeButton = true,
26
- showSearch = true,
27
- customFilterComponent,
28
- showArchiveButton = true,
29
- showDeleteButton = true,
30
- showMarkReadButton = true,
31
- showFavoriteButton = true,
32
- showMarkAsSpamButton = true,
33
- showReplies = true,
34
- showMarkAsImportantButton = true,
35
- readInbox = $bindable((skip?: number, take?: number, filter?: TableFilter<any>) => {
36
- return null;
37
- }),
38
- readOutbox = $bindable((skip?: number, take?: number, filter?: TableFilter<any>) => {
39
- return null;
40
- }),
41
- deleteEntry = async (id: string | number) => {
42
- return { success: false, data: null, error: null } as any;
43
- },
44
- toggleArchieve = async (id: string | number) => {
45
- return { success: false, data: null, error: null } as any;
46
- },
47
- toggleAsRead = async (id: string | number, type?: MailMarkReadToggleType) => {
48
- return { success: false, data: null, error: null } as any;
49
- },
50
- toggleFavourite = async (id: string | number) => {
51
- return { success: false, data: null, error: null } as any;
52
- },
53
- toggleSpam = async (id: string | number) => {
54
- return { success: false, data: null, error: null } as any;
55
- },
56
- toggelImportant = async (id: string | number) => {
57
- return { success: false, data: null, error: null } as any;
58
- },
59
- readAMessage = async (id: string | number) => {
60
- return { success: false, data: null, error: null } as any;
61
- }
62
- }: MailingModuleProps = $props();
63
-
64
- let activeBox = $state<MailingActiveBox>('inbox');
65
- let pageInfo = new PageInfo();
66
- let menutItems = $state([
67
- { icon: 'bx:bxs-inbox', title: 'Inbox', count: 0, path: '' },
68
- { icon: 'bx:bxs-send', title: 'Sent', count: 0, path: '' }
69
- ]);
70
- let openDeleteAlert = $state(false);
71
- let busy = $state(true);
72
- let messages = $state<MailingMessage[]>([]);
73
- let pageNumber = $derived(pageInfo.currentPage);
74
- let query = $state('');
75
- let selectedMessages = $state<number[]>([]);
76
- let messageSelected = $state<number>(0);
77
-
78
- let paginationInfo = new PageInfo();
79
-
80
- function toggleSideBar(val: MailMenu) {
81
- const { title } = val;
82
- if (title === 'Inbox') activeBox = 'inbox';
83
- else activeBox = 'outbox';
84
- }
85
-
86
- function setActiveMenu(val: MailMenu): boolean {
87
- if (activeBox === 'inbox' && val.title === 'Inbox') return true;
88
- else if (activeBox === 'outbox' && val.title === 'Sent') return true;
89
- else return false;
90
- }
91
-
92
- async function fetchData(
93
- page: number,
94
- params: TableFilter,
95
- activeBox: MailingActiveBox = 'inbox'
96
- ) {
97
- try {
98
- let currentPage = 0;
99
- if (params.search) {
100
- pageInfo.setCurrentPage(1);
101
- currentPage = pageInfo.currentPage;
102
- } else {
103
- currentPage = page || pageInfo.currentPage;
104
- }
105
- let newParams: any = {
106
- page: currentPage,
107
- pageSize: pageInfo.pageSize,
108
- search: params.search ?? '',
109
- filter: params.filter ?? {},
110
- order: params.order ?? []
111
- };
112
- let read = activeBox === activeBox ? readInbox : readOutbox;
113
- const ret = await read(newParams.page, newParams.pageSize, {
114
- ...params,
115
- filter: {},
116
- search: newParams.search ?? ''
117
- });
118
- if (!ret?.success) {
119
- // showError(ret?.message || 'Failed to load data');
120
- toast.error(ret?.message || 'Failed to load data');
121
- return true;
122
- }
123
- const xs = ret.data;
124
- // console.log({ xs });
125
- pageInfo.totalItems = xs.totalCount;
126
- pageInfo.setHasNextPage(xs.pageInfo.hasNextPage);
127
- pageInfo.setHasPrevPage(xs.pageInfo.hasPreviousPage);
128
- // tableData = xs.items;
129
- messages = xs.items.map((a) => ({ ...a, isChecked: false }));
130
- } catch (e: any) {
131
- toast.error(e.message || e);
132
- } finally {
133
- busy = false;
134
- }
135
- }
136
-
137
- function handleRefreshClick() {
138
- busy = true;
139
- fetchData(pageNumber, { search: query }, activeBox);
140
- }
141
-
142
- async function handleArchiveClick() {
143
- if (selectedMessages.length === 0) return;
144
-
145
- toast.promise(
146
- (async () => {
147
- const results = [];
148
-
149
- for (const msg of selectedMessages) {
150
- const res = await toggleArchieve(msg);
151
- results.push(res);
152
- }
153
- selectedMessages = [];
154
- fetchData(pageNumber, { search: query }, activeBox);
155
-
156
- return {
157
- message: `${results.length} message(s) archived successfully`,
158
- results
159
- };
160
- })(),
161
- {
162
- loading: `Archiving message(s)...`,
163
- success: (data: any) => data?.message,
164
- error: (err: any) => err?.message || 'Failed to archive messages'
165
- }
166
- );
167
- }
168
-
169
- async function handleMarkAsSpam() {
170
- if (selectedMessages.length === 0) return;
171
-
172
- toast.promise(
173
- (async () => {
174
- const results = [];
175
-
176
- for (const msg of selectedMessages) {
177
- const res = await toggleSpam(msg);
178
- results.push(res);
179
- }
180
- selectedMessages = [];
181
- fetchData(pageNumber, { search: query }, activeBox);
182
-
183
- return {
184
- message: `${results.length} message(s) marked as spam successfully`,
185
- results
186
- };
187
- })(),
188
- {
189
- loading: `Marking message(s) as spam...`,
190
- success: (data: any) => data?.message,
191
- error: (err: any) => err?.message || 'Failed to archive messages'
192
- }
193
- );
194
- }
195
-
196
- async function handleMarkAsRead(val: MailMarkReadToggleType) {
197
- if (selectedMessages.length === 0) return;
198
-
199
- toast.promise(
200
- (async () => {
201
- const results = [];
202
-
203
- for (const msg of selectedMessages) {
204
- const res = await toggleAsRead(msg, val);
205
- results.push(res);
206
- }
207
- selectedMessages = [];
208
- fetchData(pageNumber, { search: query }, activeBox);
209
-
210
- return {
211
- message: `${results.length} message(s) marked as ${val === 'read' ? 'read' : 'unread'} successfully`,
212
- results
213
- };
214
- })(),
215
- {
216
- loading: `Marking message(s) as ${val === 'read' ? 'read' : 'unread'}...`,
217
- success: (data: any) => data?.message,
218
- error: (err: any) =>
219
- err?.message || `Failed to ${val === 'read' ? 'read' : 'unread'} messages`
220
- }
221
- );
222
- }
223
-
224
- async function handleMarkAsFavorite(val: MailFavariteToggleType) {
225
- if (selectedMessages.length === 0) return;
226
-
227
- toast.promise(
228
- (async () => {
229
- const results = [];
230
-
231
- for (const msg of selectedMessages) {
232
- const res = await toggleFavourite(msg);
233
- results.push(res);
234
- }
235
- selectedMessages = [];
236
- fetchData(pageNumber, { search: query }, activeBox);
237
-
238
- return {
239
- message: `${results.length} message(s) marked as ${val === 'favorite' ? 'favorite' : 'unfavorite'} successfully`,
240
- results
241
- };
242
- })(),
243
- {
244
- loading: `Marking message(s) as ${val === 'favorite' ? 'favorite' : 'unfavorite'}...`,
245
- success: (data: any) => data?.message,
246
- error: (err: any) =>
247
- err?.message || `Failed to ${val === 'favorite' ? 'favorite' : 'unfavorite'} messages`
248
- }
249
- );
250
- }
251
-
252
- async function handleMarkAsImportant(val: 'isImportant' | 'notImportant') {
253
- if (selectedMessages.length === 0) return;
254
-
255
- toast.promise(
256
- (async () => {
257
- const results = [];
258
-
259
- for (const msg of selectedMessages) {
260
- const res = await toggelImportant(msg);
261
- results.push(res);
262
- }
263
- selectedMessages = [];
264
- fetchData(pageNumber, { search: query }, activeBox);
265
-
266
- return {
267
- message: `${results.length} message(s) marked as ${val === 'isImportant' ? 'important' : 'not important'} successfully`,
268
- results
269
- };
270
- })(),
271
- {
272
- loading: `Marking message(s) as ${val === 'isImportant' ? 'important' : 'not important'}...`,
273
- success: (data: any) => data?.message,
274
- error: (err: any) =>
275
- err?.message ||
276
- `Failed to ${val === 'isImportant' ? 'important' : 'not important'} messages`
277
- }
278
- );
279
- }
280
-
281
- async function handleDeleteMessages() {
282
- if (selectedMessages.length === 0) return;
283
-
284
- toast.promise(
285
- (async () => {
286
- const results = [];
287
-
288
- for (const msg of selectedMessages) {
289
- const res = await deleteEntry(msg);
290
- results.push(res);
291
- }
292
-
293
- openDeleteAlert = false;
294
- selectedMessages = [];
295
- fetchData(pageNumber, { search: query }, activeBox);
296
-
297
- return {
298
- message: `${results.length} message(s) deleted successfully`,
299
- results
300
- };
301
- })(),
302
- {
303
- loading: `Deleting message(s)...`,
304
- success: (data: any) => data?.message,
305
- error: (err: any) => err?.message || 'Failed to delete messages'
306
- }
307
- );
308
- }
309
-
310
- function handleItemChecked({ checked, id }: any) {
311
- if (checked) {
312
- selectedMessages = [...selectedMessages, id];
313
- } else {
314
- selectedMessages = selectedMessages.filter((a) => a !== id);
315
- }
316
- }
317
-
318
- function handleMessageSelected(id: number) {
319
- messageSelected = id;
320
- selectedMessages = [id];
321
- }
322
-
323
- function updatePageInfo(val: MailPageInfo) {
324
- // console.log({ val });
325
- paginationInfo.totalItems = 1;
326
- paginationInfo.setHasNextPage(val.hasNextPage);
327
- paginationInfo.setHasPrevPage(val.hasPreviousPage);
328
- paginationInfo.setTotalPages(1);
329
- paginationInfo.setPageSize(1);
330
- }
331
-
332
- const debouncedSearch = debounce(fetchData, 300);
333
-
334
- function handleSearch(val: string) {
335
- // query = val;
336
- debouncedSearch(pageNumber, { search: val }, activeBox);
337
- }
338
-
339
- async function getIsRead(id: number): Promise<boolean> {
340
- let status = false;
341
- try {
342
- const ret = await readAMessage(id);
343
- if (!ret?.success) {
344
- return false;
345
- }
346
- status = ret.data?.isRead || false;
347
- return status;
348
- } catch (error) {}
349
- return status;
350
- }
351
-
352
- $effect(() => {
353
- fetchData(pageNumber, { search: query }, activeBox);
354
- });
355
- </script>
356
-
357
- <div class="h-full w-full">
358
- <div class="flex h-full w-full gap-2">
359
- <div class:hidden={!showSidePanel} class="loginbox h-full w-20 rounded-md bg-white">
360
- <MailSidebar onClick={toggleSideBar} menus={menutItems} {setActiveMenu} />
361
- </div>
362
- <div class="flex w-full flex-grow flex-col gap-1">
363
- <div class="loginbox h-14 rounded bg-white px-4">
364
- <MailToolBar
365
- isFavoriteActive={false}
366
- isReadActive={async () => await getIsRead(messageSelected)}
367
- showBackButton={Boolean(messageSelected)}
368
- {showPagination}
369
- {showComposeButton}
370
- {showSearch}
371
- {showArchiveButton}
372
- {showDeleteButton}
373
- {showMarkReadButton}
374
- {showFavoriteButton}
375
- {showMarkAsSpamButton}
376
- {customFilterComponent}
377
- onRefreshClick={handleRefreshClick}
378
- onArchiveClick={handleArchiveClick}
379
- onMarkAsSpamClick={handleMarkAsSpam}
380
- onToggleMarkReadClick={handleMarkAsRead}
381
- onToggleFavoriteClick={handleMarkAsFavorite}
382
- onsearchChange={handleSearch}
383
- onBackClick={() => {
384
- messageSelected = 0;
385
- selectedMessages = [];
386
- }}
387
- onDeleteClick={() => {
388
- if (selectedMessages.length === 0) return;
389
- openDeleteAlert = true;
390
- }}
391
- selectedMails={selectedMessages}
392
- pageInfo={{
393
- currentPage: !messageSelected ? pageInfo.currentPage : paginationInfo.currentPage,
394
- pageSize: !messageSelected ? pageInfo.pageSize : paginationInfo.pageSize,
395
- totalCount: !messageSelected ? pageInfo.totalItems : paginationInfo.totalItems,
396
- hasNextPage: !messageSelected ? pageInfo.hasNextPage : paginationInfo.hasNextPage,
397
- hasPreviousPage: !messageSelected ? pageInfo.hasPrevPage : paginationInfo.hasPrevPage
398
- }}
399
- />
400
- </div>
401
-
402
- <div class="loginbox h-full w-full flex-grow rounded bg-gray-100 p-2">
403
- {#if busy}
404
- <PageLoader size={50} />
405
- {:else if messageSelected}
406
- <MailingMessageViewer
407
- bind:recordId={messageSelected}
408
- readMessage={readAMessage}
409
- {updatePageInfo}
410
- {showReplies}
411
- showHeader={activeBox === 'inbox'}
412
- />
413
- {:else if messages.length}
414
- <div class="custom-scrollbar h-full w-full overflow-auto" in:slide>
415
- {#each messages as message}
416
- <MailingMessageCard
417
- {...message}
418
- onItemChecked={handleItemChecked}
419
- showMarkAsFavorite={showFavoriteButton}
420
- showMarkAsImportant={showMarkAsImportantButton}
421
- toggleFavorited={() => {
422
- selectedMessages = [message.id];
423
- handleMarkAsFavorite(message.isStared ? 'unfavorite' : 'favorite');
424
- }}
425
- toggelImportant={() => {
426
- selectedMessages = [message.id];
427
- handleMarkAsImportant(message.isImportant ? 'notImportant' : 'isImportant');
428
- }}
429
- onItemSelected={handleMessageSelected}
430
- />
431
- {/each}
432
- </div>
433
- {:else}
434
- <div class="grid h-full w-full items-center justify-center p-20" in:scale>
435
- <div class="rounded-[5px] bg-yellow-300 px-10 py-5 text-center">No Records Found</div>
436
- </div>
437
- {/if}
438
- </div>
439
- </div>
440
- </div>
441
- </div>
442
-
443
- <AlertDialog
444
- open={openDeleteAlert}
445
- message={`Are you sure you want to delete ${selectedMessages?.length > 1 ? 'these messages' : 'this message'}`}
446
- onCancel={() => (openDeleteAlert = false)}
447
- onYes={handleDeleteMessages}
448
- />
1
+ <script lang="ts">
2
+ import { PageLoader } from '../../ui/pageLoader/index.js';
3
+ import { scale, slide } from 'svelte/transition';
4
+ import {
5
+ MailSidebar,
6
+ MailToolBar,
7
+ type MailingModuleProps,
8
+ type MailMenu,
9
+ type MailingMessage,
10
+ type MailMarkReadToggleType,
11
+ type MailFavariteToggleType,
12
+ type MailPageInfo,
13
+ type MailingActiveBox
14
+ } from './index.js';
15
+ import MailingMessageCard from './MailingMessageCard.svelte';
16
+ import { toast, type CrudResult, type TableFilter } from '../../index.js';
17
+ import { PageInfo } from '../../utils/paginate.svelte.js';
18
+ import AlertDialog from '../../ui/alertDialog/AlertDialog.svelte';
19
+ import MailingMessageViewer from './MailingMessageViewer.svelte';
20
+ import debounce from 'lodash/debounce';
21
+
22
+ let {
23
+ showSidePanel = true,
24
+ showPagination = true,
25
+ showComposeButton = true,
26
+ showSearch = true,
27
+ customFilterComponent,
28
+ showArchiveButton = true,
29
+ showDeleteButton = true,
30
+ showMarkReadButton = true,
31
+ showFavoriteButton = true,
32
+ showMarkAsSpamButton = true,
33
+ showReplies = true,
34
+ showMarkAsImportantButton = true,
35
+ readInbox = $bindable((skip?: number, take?: number, filter?: TableFilter<any>) => {
36
+ return null;
37
+ }),
38
+ readOutbox = $bindable((skip?: number, take?: number, filter?: TableFilter<any>) => {
39
+ return null;
40
+ }),
41
+ deleteEntry = async (id: string | number) => {
42
+ return { success: false, data: null, error: null } as any;
43
+ },
44
+ toggleArchieve = async (id: string | number) => {
45
+ return { success: false, data: null, error: null } as any;
46
+ },
47
+ toggleAsRead = async (id: string | number, type?: MailMarkReadToggleType) => {
48
+ return { success: false, data: null, error: null } as any;
49
+ },
50
+ toggleFavourite = async (id: string | number) => {
51
+ return { success: false, data: null, error: null } as any;
52
+ },
53
+ toggleSpam = async (id: string | number) => {
54
+ return { success: false, data: null, error: null } as any;
55
+ },
56
+ toggelImportant = async (id: string | number) => {
57
+ return { success: false, data: null, error: null } as any;
58
+ },
59
+ readAMessage = async (id: string | number) => {
60
+ return { success: false, data: null, error: null } as any;
61
+ }
62
+ }: MailingModuleProps = $props();
63
+
64
+ let activeBox = $state<MailingActiveBox>('inbox');
65
+ let pageInfo = new PageInfo();
66
+ let menutItems = $state([
67
+ { icon: 'bx:bxs-inbox', title: 'Inbox', count: 0, path: '' },
68
+ { icon: 'bx:bxs-send', title: 'Sent', count: 0, path: '' }
69
+ ]);
70
+ let openDeleteAlert = $state(false);
71
+ let busy = $state(true);
72
+ let messages = $state<MailingMessage[]>([]);
73
+ let pageNumber = $derived(pageInfo.currentPage);
74
+ let query = $state('');
75
+ let selectedMessages = $state<number[]>([]);
76
+ let messageSelected = $state<number>(0);
77
+
78
+ let paginationInfo = new PageInfo();
79
+
80
+ function toggleSideBar(val: MailMenu) {
81
+ const { title } = val;
82
+ if (title === 'Inbox') activeBox = 'inbox';
83
+ else activeBox = 'outbox';
84
+ }
85
+
86
+ function setActiveMenu(val: MailMenu): boolean {
87
+ if (activeBox === 'inbox' && val.title === 'Inbox') return true;
88
+ else if (activeBox === 'outbox' && val.title === 'Sent') return true;
89
+ else return false;
90
+ }
91
+
92
+ async function fetchData(
93
+ page: number,
94
+ params: TableFilter,
95
+ activeBox: MailingActiveBox = 'inbox'
96
+ ) {
97
+ try {
98
+ let currentPage = 0;
99
+ if (params.search) {
100
+ pageInfo.setCurrentPage(1);
101
+ currentPage = pageInfo.currentPage;
102
+ } else {
103
+ currentPage = page || pageInfo.currentPage;
104
+ }
105
+ let newParams: any = {
106
+ page: currentPage,
107
+ pageSize: pageInfo.pageSize,
108
+ search: params.search ?? '',
109
+ filter: params.filter ?? {},
110
+ order: params.order ?? []
111
+ };
112
+ let read = activeBox === activeBox ? readInbox : readOutbox;
113
+ const ret = await read(newParams.page, newParams.pageSize, {
114
+ ...params,
115
+ filter: {},
116
+ search: newParams.search ?? ''
117
+ });
118
+ if (!ret?.success) {
119
+ // showError(ret?.message || 'Failed to load data');
120
+ toast.error(ret?.message || 'Failed to load data');
121
+ return true;
122
+ }
123
+ const xs = ret.data;
124
+ // console.log({ xs });
125
+ pageInfo.totalItems = xs.totalCount;
126
+ pageInfo.setHasNextPage(xs.pageInfo.hasNextPage);
127
+ pageInfo.setHasPrevPage(xs.pageInfo.hasPreviousPage);
128
+ // tableData = xs.items;
129
+ messages = xs.items.map((a) => ({ ...a, isChecked: false }));
130
+ } catch (e: any) {
131
+ toast.error(e.message || e);
132
+ } finally {
133
+ busy = false;
134
+ }
135
+ }
136
+
137
+ function handleRefreshClick() {
138
+ busy = true;
139
+ fetchData(pageNumber, { search: query }, activeBox);
140
+ }
141
+
142
+ async function handleArchiveClick() {
143
+ if (selectedMessages.length === 0) return;
144
+
145
+ toast.promise(
146
+ (async () => {
147
+ const results = [];
148
+
149
+ for (const msg of selectedMessages) {
150
+ const res = await toggleArchieve(msg);
151
+ results.push(res);
152
+ }
153
+ selectedMessages = [];
154
+ fetchData(pageNumber, { search: query }, activeBox);
155
+
156
+ return {
157
+ message: `${results.length} message(s) archived successfully`,
158
+ results
159
+ };
160
+ })(),
161
+ {
162
+ loading: `Archiving message(s)...`,
163
+ success: (data: any) => data?.message,
164
+ error: (err: any) => err?.message || 'Failed to archive messages'
165
+ }
166
+ );
167
+ }
168
+
169
+ async function handleMarkAsSpam() {
170
+ if (selectedMessages.length === 0) return;
171
+
172
+ toast.promise(
173
+ (async () => {
174
+ const results = [];
175
+
176
+ for (const msg of selectedMessages) {
177
+ const res = await toggleSpam(msg);
178
+ results.push(res);
179
+ }
180
+ selectedMessages = [];
181
+ fetchData(pageNumber, { search: query }, activeBox);
182
+
183
+ return {
184
+ message: `${results.length} message(s) marked as spam successfully`,
185
+ results
186
+ };
187
+ })(),
188
+ {
189
+ loading: `Marking message(s) as spam...`,
190
+ success: (data: any) => data?.message,
191
+ error: (err: any) => err?.message || 'Failed to archive messages'
192
+ }
193
+ );
194
+ }
195
+
196
+ async function handleMarkAsRead(val: MailMarkReadToggleType) {
197
+ if (selectedMessages.length === 0) return;
198
+
199
+ toast.promise(
200
+ (async () => {
201
+ const results = [];
202
+
203
+ for (const msg of selectedMessages) {
204
+ const res = await toggleAsRead(msg, val);
205
+ results.push(res);
206
+ }
207
+ selectedMessages = [];
208
+ fetchData(pageNumber, { search: query }, activeBox);
209
+
210
+ return {
211
+ message: `${results.length} message(s) marked as ${val === 'read' ? 'read' : 'unread'} successfully`,
212
+ results
213
+ };
214
+ })(),
215
+ {
216
+ loading: `Marking message(s) as ${val === 'read' ? 'read' : 'unread'}...`,
217
+ success: (data: any) => data?.message,
218
+ error: (err: any) =>
219
+ err?.message || `Failed to ${val === 'read' ? 'read' : 'unread'} messages`
220
+ }
221
+ );
222
+ }
223
+
224
+ async function handleMarkAsFavorite(val: MailFavariteToggleType) {
225
+ if (selectedMessages.length === 0) return;
226
+
227
+ toast.promise(
228
+ (async () => {
229
+ const results = [];
230
+
231
+ for (const msg of selectedMessages) {
232
+ const res = await toggleFavourite(msg);
233
+ results.push(res);
234
+ }
235
+ selectedMessages = [];
236
+ fetchData(pageNumber, { search: query }, activeBox);
237
+
238
+ return {
239
+ message: `${results.length} message(s) marked as ${val === 'favorite' ? 'favorite' : 'unfavorite'} successfully`,
240
+ results
241
+ };
242
+ })(),
243
+ {
244
+ loading: `Marking message(s) as ${val === 'favorite' ? 'favorite' : 'unfavorite'}...`,
245
+ success: (data: any) => data?.message,
246
+ error: (err: any) =>
247
+ err?.message || `Failed to ${val === 'favorite' ? 'favorite' : 'unfavorite'} messages`
248
+ }
249
+ );
250
+ }
251
+
252
+ async function handleMarkAsImportant(val: 'isImportant' | 'notImportant') {
253
+ if (selectedMessages.length === 0) return;
254
+
255
+ toast.promise(
256
+ (async () => {
257
+ const results = [];
258
+
259
+ for (const msg of selectedMessages) {
260
+ const res = await toggelImportant(msg);
261
+ results.push(res);
262
+ }
263
+ selectedMessages = [];
264
+ fetchData(pageNumber, { search: query }, activeBox);
265
+
266
+ return {
267
+ message: `${results.length} message(s) marked as ${val === 'isImportant' ? 'important' : 'not important'} successfully`,
268
+ results
269
+ };
270
+ })(),
271
+ {
272
+ loading: `Marking message(s) as ${val === 'isImportant' ? 'important' : 'not important'}...`,
273
+ success: (data: any) => data?.message,
274
+ error: (err: any) =>
275
+ err?.message ||
276
+ `Failed to ${val === 'isImportant' ? 'important' : 'not important'} messages`
277
+ }
278
+ );
279
+ }
280
+
281
+ async function handleDeleteMessages() {
282
+ if (selectedMessages.length === 0) return;
283
+
284
+ toast.promise(
285
+ (async () => {
286
+ const results = [];
287
+
288
+ for (const msg of selectedMessages) {
289
+ const res = await deleteEntry(msg);
290
+ results.push(res);
291
+ }
292
+
293
+ openDeleteAlert = false;
294
+ selectedMessages = [];
295
+ fetchData(pageNumber, { search: query }, activeBox);
296
+
297
+ return {
298
+ message: `${results.length} message(s) deleted successfully`,
299
+ results
300
+ };
301
+ })(),
302
+ {
303
+ loading: `Deleting message(s)...`,
304
+ success: (data: any) => data?.message,
305
+ error: (err: any) => err?.message || 'Failed to delete messages'
306
+ }
307
+ );
308
+ }
309
+
310
+ function handleItemChecked({ checked, id }: any) {
311
+ if (checked) {
312
+ selectedMessages = [...selectedMessages, id];
313
+ } else {
314
+ selectedMessages = selectedMessages.filter((a) => a !== id);
315
+ }
316
+ }
317
+
318
+ function handleMessageSelected(id: number) {
319
+ messageSelected = id;
320
+ selectedMessages = [id];
321
+ }
322
+
323
+ function updatePageInfo(val: MailPageInfo) {
324
+ // console.log({ val });
325
+ paginationInfo.totalItems = 1;
326
+ paginationInfo.setHasNextPage(val.hasNextPage);
327
+ paginationInfo.setHasPrevPage(val.hasPreviousPage);
328
+ paginationInfo.setTotalPages(1);
329
+ paginationInfo.setPageSize(1);
330
+ }
331
+
332
+ const debouncedSearch = debounce(fetchData, 300);
333
+
334
+ function handleSearch(val: string) {
335
+ // query = val;
336
+ debouncedSearch(pageNumber, { search: val }, activeBox);
337
+ }
338
+
339
+ async function getIsRead(id: number): Promise<boolean> {
340
+ let status = false;
341
+ try {
342
+ const ret = await readAMessage(id);
343
+ if (!ret?.success) {
344
+ return false;
345
+ }
346
+ status = ret.data?.isRead || false;
347
+ return status;
348
+ } catch (error) {}
349
+ return status;
350
+ }
351
+
352
+ $effect(() => {
353
+ fetchData(pageNumber, { search: query }, activeBox);
354
+ });
355
+ </script>
356
+
357
+ <div class="h-full w-full">
358
+ <div class="flex h-full w-full gap-2">
359
+ <div class:hidden={!showSidePanel} class="loginbox h-full w-20 rounded-md bg-white">
360
+ <MailSidebar onClick={toggleSideBar} menus={menutItems} {setActiveMenu} />
361
+ </div>
362
+ <div class="flex w-full flex-grow flex-col gap-1">
363
+ <div class="loginbox h-14 rounded bg-white px-4">
364
+ <MailToolBar
365
+ isFavoriteActive={false}
366
+ isReadActive={async () => await getIsRead(messageSelected)}
367
+ showBackButton={Boolean(messageSelected)}
368
+ {showPagination}
369
+ {showComposeButton}
370
+ {showSearch}
371
+ {showArchiveButton}
372
+ {showDeleteButton}
373
+ {showMarkReadButton}
374
+ {showFavoriteButton}
375
+ {showMarkAsSpamButton}
376
+ {customFilterComponent}
377
+ onRefreshClick={handleRefreshClick}
378
+ onArchiveClick={handleArchiveClick}
379
+ onMarkAsSpamClick={handleMarkAsSpam}
380
+ onToggleMarkReadClick={handleMarkAsRead}
381
+ onToggleFavoriteClick={handleMarkAsFavorite}
382
+ onsearchChange={handleSearch}
383
+ onBackClick={() => {
384
+ messageSelected = 0;
385
+ selectedMessages = [];
386
+ }}
387
+ onDeleteClick={() => {
388
+ if (selectedMessages.length === 0) return;
389
+ openDeleteAlert = true;
390
+ }}
391
+ selectedMails={selectedMessages}
392
+ pageInfo={{
393
+ currentPage: !messageSelected ? pageInfo.currentPage : paginationInfo.currentPage,
394
+ pageSize: !messageSelected ? pageInfo.pageSize : paginationInfo.pageSize,
395
+ totalCount: !messageSelected ? pageInfo.totalItems : paginationInfo.totalItems,
396
+ hasNextPage: !messageSelected ? pageInfo.hasNextPage : paginationInfo.hasNextPage,
397
+ hasPreviousPage: !messageSelected ? pageInfo.hasPrevPage : paginationInfo.hasPrevPage
398
+ }}
399
+ />
400
+ </div>
401
+
402
+ <div class="loginbox h-full w-full flex-grow rounded bg-gray-100 p-2">
403
+ {#if busy}
404
+ <PageLoader size={50} />
405
+ {:else if messageSelected}
406
+ <MailingMessageViewer
407
+ bind:recordId={messageSelected}
408
+ readMessage={readAMessage}
409
+ {updatePageInfo}
410
+ {showReplies}
411
+ showHeader={activeBox === 'inbox'}
412
+ />
413
+ {:else if messages.length}
414
+ <div class="custom-scrollbar h-full w-full overflow-auto" in:slide>
415
+ {#each messages as message}
416
+ <MailingMessageCard
417
+ {...message}
418
+ onItemChecked={handleItemChecked}
419
+ showMarkAsFavorite={showFavoriteButton}
420
+ showMarkAsImportant={showMarkAsImportantButton}
421
+ toggleFavorited={() => {
422
+ selectedMessages = [message.id];
423
+ handleMarkAsFavorite(message.isStared ? 'unfavorite' : 'favorite');
424
+ }}
425
+ toggelImportant={() => {
426
+ selectedMessages = [message.id];
427
+ handleMarkAsImportant(message.isImportant ? 'notImportant' : 'isImportant');
428
+ }}
429
+ onItemSelected={handleMessageSelected}
430
+ />
431
+ {/each}
432
+ </div>
433
+ {:else}
434
+ <div class="grid h-full w-full items-center justify-center p-20" in:scale>
435
+ <div class="rounded-[5px] bg-yellow-300 px-10 py-5 text-center">No Records Found</div>
436
+ </div>
437
+ {/if}
438
+ </div>
439
+ </div>
440
+ </div>
441
+ </div>
442
+
443
+ <AlertDialog
444
+ open={openDeleteAlert}
445
+ message={`Are you sure you want to delete ${selectedMessages?.length > 1 ? 'these messages' : 'this message'}`}
446
+ onCancel={() => (openDeleteAlert = false)}
447
+ onYes={handleDeleteMessages}
448
+ />