@rkosafo/cai.components 0.0.69 → 0.0.71
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/layout/mailing/MailingContent.svelte +10 -0
- package/dist/layout/mailing/MailingContent.svelte.d.ts +6 -0
- package/dist/layout/mailing/MailingHeader.svelte +51 -1
- package/dist/layout/mailing/MailingMessageCard.svelte +38 -35
- package/dist/layout/mailing/MailingMessageViewer.svelte +37 -13
- package/dist/layout/mailing/MailingMessageViewer.svelte.d.ts +1 -1
- package/dist/layout/mailing/MailingModule.svelte +18 -10
- package/dist/layout/mailing/index.d.ts +1 -0
- package/dist/layout/mailing/index.js +1 -0
- package/dist/layout/mailing/types.d.ts +6 -1
- package/package.json +1 -1
|
@@ -1,5 +1,55 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import { Avatar } from '../../ui/avatar/index.js';
|
|
3
|
+
import DropdownDivider from '../../ui/dropdown/DropdownDivider.svelte';
|
|
4
|
+
import { IconifyIcon } from '../../ui/icons/index.js';
|
|
2
5
|
import type { MailingHeaderProps } from './types.js';
|
|
3
6
|
|
|
4
|
-
let { data, replyType = $bindable(undefined) }: MailingHeaderProps = $props();
|
|
7
|
+
let { data, replyType = $bindable(undefined), showReplies }: MailingHeaderProps = $props();
|
|
5
8
|
</script>
|
|
9
|
+
|
|
10
|
+
<div class=" w-full bg-white p-4">
|
|
11
|
+
<div class="flex h-full w-full flex-col">
|
|
12
|
+
<p class="text-xl font-light">{data?.subject}</p>
|
|
13
|
+
<DropdownDivider />
|
|
14
|
+
<div class="flex justify-between pt-3">
|
|
15
|
+
<div class="flex items-center gap-2">
|
|
16
|
+
<Avatar class="h-10 w-10 bg-blue-600 text-white">{data?.user?.initials}</Avatar>
|
|
17
|
+
<div>
|
|
18
|
+
<p class="text-sm">
|
|
19
|
+
{`${data?.user?.firstName} ${data?.user?.surname} - ${data?.user?.staffNumber}`}
|
|
20
|
+
</p>
|
|
21
|
+
<div class="flex items-center gap-1">
|
|
22
|
+
<p class="text-xs text-gray-500 antialiased">to {data?.to}</p>
|
|
23
|
+
<button class="grid place-content-center rounded-full p-1.5 hover:bg-gray-200">
|
|
24
|
+
<IconifyIcon icon="solar:alt-arrow-down-bold" style="font-size: 14px;" />
|
|
25
|
+
</button>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
<div class="flex items-center gap-3" class:hidden={!showReplies}>
|
|
30
|
+
<button
|
|
31
|
+
class="flex items-center gap-1 rounded-lg border border-gray-300 px-2 py-1 text-sm text-gray-700 shadow transition duration-100 hover:bg-gray-200"
|
|
32
|
+
onclick={() => (replyType = 'reply')}
|
|
33
|
+
>
|
|
34
|
+
<IconifyIcon icon="bi:reply" style="font-size: 17px;" />
|
|
35
|
+
Reply
|
|
36
|
+
</button>
|
|
37
|
+
<button
|
|
38
|
+
class="flex items-center gap-1 rounded-lg border border-gray-300 px-2 py-1 text-sm text-gray-700 shadow transition duration-100 hover:bg-gray-200"
|
|
39
|
+
onclick={() => (replyType = 'reply-all')}
|
|
40
|
+
>
|
|
41
|
+
<IconifyIcon icon="ri:reply-all-line" style="font-size: 17px;" />
|
|
42
|
+
Reply all
|
|
43
|
+
</button>
|
|
44
|
+
<button
|
|
45
|
+
class="flex items-center gap-1 rounded-lg border border-gray-300 px-2 py-1 text-sm text-gray-700 shadow transition duration-100 hover:bg-gray-200"
|
|
46
|
+
onclick={() => (replyType = 'forward')}
|
|
47
|
+
>
|
|
48
|
+
<IconifyIcon icon="mdi:forward-outline" style="font-size: 17px;" />
|
|
49
|
+
Forward
|
|
50
|
+
</button>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
<!-- <Divider morePadding={false} /> -->
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
@@ -61,43 +61,46 @@
|
|
|
61
61
|
}}
|
|
62
62
|
/>
|
|
63
63
|
<div class="my-1 flex w-full cursor-pointer items-center justify-between p-1">
|
|
64
|
-
<div class="flex items-center">
|
|
65
|
-
<div class="
|
|
66
|
-
<
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
64
|
+
<div class="flex w-full items-center">
|
|
65
|
+
<div class="flex">
|
|
66
|
+
<div class="mr-4 flex items-center gap-1 space-x-1">
|
|
67
|
+
<button
|
|
68
|
+
onclick={(e) => {
|
|
69
|
+
toggleFavorited?.(id);
|
|
70
|
+
}}
|
|
71
|
+
aria-label="Not starred"
|
|
72
|
+
>
|
|
73
|
+
<IconifyIcon
|
|
74
|
+
style="font-size: 24px"
|
|
75
|
+
icon={isStared ? 'mdi:star' : 'mdi:star-outline'}
|
|
76
|
+
class="flex justify-center transition-colors {isStared
|
|
77
|
+
? 'text-yellow-500 hover:text-yellow-600'
|
|
78
|
+
: 'text-gray-500 hover:text-gray-900'}"
|
|
79
|
+
/>
|
|
80
|
+
</button>
|
|
81
|
+
<button
|
|
82
|
+
onclick={(e) => {
|
|
83
|
+
toggelImportant?.(id);
|
|
84
|
+
}}
|
|
85
|
+
aria-label="Click to mark this email as important"
|
|
86
|
+
>
|
|
87
|
+
<IconifyIcon
|
|
88
|
+
style="font-size: 18px"
|
|
89
|
+
icon={isImportant ? 'ic:outline-bookmark' : 'solar:bookmark-broken'}
|
|
90
|
+
class="flex justify-center transition-colors {isImportant
|
|
91
|
+
? 'text-yellow-500 hover:text-yellow-600'
|
|
92
|
+
: 'text-gray-500 hover:text-gray-900'}"
|
|
93
|
+
/>
|
|
94
|
+
</button>
|
|
95
|
+
</div>
|
|
96
|
+
<span class="w-56 truncate pr-2" class:font-bold={!isRead}>{sender}</span>
|
|
97
|
+
<span class="w-64 truncate" class:font-bold={!isRead}>{subject}</span>
|
|
98
|
+
<span class="mx-1">-</span>
|
|
94
99
|
</div>
|
|
95
|
-
|
|
96
|
-
<
|
|
97
|
-
<span class="mx-1">-</span>
|
|
98
|
-
<span class="w-96 truncate text-sm text-gray-600">{message}</span>
|
|
100
|
+
|
|
101
|
+
<p class=" truncate max-l xl:max-w-2xl 2xl:max-w-5xl text-sm text-gray-600">{message}</p>
|
|
99
102
|
</div>
|
|
100
|
-
<div class="flex w-32 items-center justify-end">
|
|
103
|
+
<div class="flex w-32 shrink-0 items-center justify-end">
|
|
101
104
|
<span class="text-sm" class:font-bold={!isRead} class:text-gray-500={isRead}>
|
|
102
105
|
{formatDate(date)}
|
|
103
106
|
</span>
|
|
@@ -5,18 +5,28 @@
|
|
|
5
5
|
import MailingHeader from './MailingHeader.svelte';
|
|
6
6
|
import { onMount } from 'svelte';
|
|
7
7
|
import toast from 'svelte-french-toast';
|
|
8
|
+
import { getInitials } from '../../index.js';
|
|
9
|
+
import MailingContent from './MailingContent.svelte';
|
|
8
10
|
|
|
9
|
-
let {
|
|
11
|
+
let {
|
|
12
|
+
readMessage,
|
|
13
|
+
recordId = $bindable(0),
|
|
14
|
+
updatePageInfo,
|
|
15
|
+
showReplies = true,
|
|
16
|
+
showHeader = true
|
|
17
|
+
}: MailingMessageViewerProps = $props();
|
|
10
18
|
|
|
11
19
|
let busy = $state(true);
|
|
12
20
|
let header = $state<MailingHeaderData>({} as MailingHeaderData);
|
|
13
21
|
let inputType = $state<MailingReplyType | undefined>(undefined);
|
|
22
|
+
let content = $state('');
|
|
14
23
|
|
|
15
24
|
onMount(async () => {
|
|
16
25
|
try {
|
|
17
26
|
const ret = await readMessage(recordId);
|
|
18
27
|
if (!ret?.success) {
|
|
19
28
|
toast.error(ret?.message);
|
|
29
|
+
recordId = 0;
|
|
20
30
|
return;
|
|
21
31
|
}
|
|
22
32
|
updatePageInfo?.({
|
|
@@ -27,7 +37,18 @@
|
|
|
27
37
|
hasPreviousPage: false
|
|
28
38
|
});
|
|
29
39
|
|
|
30
|
-
|
|
40
|
+
const { data } = ret;
|
|
41
|
+
header = {
|
|
42
|
+
subject: data?.subject ?? '',
|
|
43
|
+
user: {
|
|
44
|
+
firstName: data?.user.firstName ?? '',
|
|
45
|
+
surname: data?.user.surname ?? '',
|
|
46
|
+
staffNumber: data?.user.staffNumber ?? '',
|
|
47
|
+
initials: `${getInitials(data?.user.firstName)}${getInitials(data?.user.surname)}`
|
|
48
|
+
},
|
|
49
|
+
to: data?.to ?? ''
|
|
50
|
+
};
|
|
51
|
+
content = data.message ?? '';
|
|
31
52
|
} catch (error: any) {
|
|
32
53
|
toast.error(error?.message || error);
|
|
33
54
|
} finally {
|
|
@@ -41,23 +62,26 @@
|
|
|
41
62
|
<PageLoader size={50} />
|
|
42
63
|
{:else}
|
|
43
64
|
<div class="flex h-full w-full flex-col gap-2" in:slide>
|
|
44
|
-
<div class=
|
|
45
|
-
<MailingHeader bind:replyType={inputType} data={header} />
|
|
65
|
+
<div class:hidden={!showHeader}>
|
|
66
|
+
<MailingHeader bind:replyType={inputType} data={header} {showReplies} />
|
|
46
67
|
</div>
|
|
47
|
-
|
|
48
|
-
<div
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
68
|
+
<div class="fex-grow h-full w-full">
|
|
69
|
+
<div
|
|
70
|
+
class:h-[71vh]={inputType}
|
|
71
|
+
class:h-full={!inputType}
|
|
72
|
+
class="flex w-full flex-col gap-4"
|
|
73
|
+
>
|
|
74
|
+
<div class="custom-scrollbar h-full flex-grow overflow-y-auto bg-white p-4">
|
|
75
|
+
<MailingContent {content} />
|
|
53
76
|
</div>
|
|
54
|
-
<div class="h-modal p-4 pt-2" class:hidden={!Boolean(inputType)}>
|
|
77
|
+
<div class="h-modal p-4 pt-2" class:hidden={!Boolean(inputType) || !showReplies}>
|
|
55
78
|
<div class=" rounded-md bg-white p-4">
|
|
56
|
-
|
|
79
|
+
Reply
|
|
80
|
+
<!-- <Reply {inputType} /> -->
|
|
57
81
|
</div>
|
|
58
82
|
</div>
|
|
59
83
|
</div>
|
|
60
|
-
</div>
|
|
84
|
+
</div>
|
|
61
85
|
</div>
|
|
62
86
|
{/if}
|
|
63
87
|
</div>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { MailingMessageViewerProps } from './index.js';
|
|
2
|
-
declare const MailingMessageViewer: import("svelte").Component<MailingMessageViewerProps, {}, "">;
|
|
2
|
+
declare const MailingMessageViewer: import("svelte").Component<MailingMessageViewerProps, {}, "recordId">;
|
|
3
3
|
type MailingMessageViewer = ReturnType<typeof MailingMessageViewer>;
|
|
4
4
|
export default MailingMessageViewer;
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
type MailingMessage,
|
|
10
10
|
type MailMarkReadToggleType,
|
|
11
11
|
type MailFavariteToggleType,
|
|
12
|
-
type MailPageInfo
|
|
12
|
+
type MailPageInfo,
|
|
13
|
+
type MailingActiveBox
|
|
13
14
|
} from './index.js';
|
|
14
15
|
import MailingMessageCard from './MailingMessageCard.svelte';
|
|
15
16
|
import { toast, type CrudResult, type TableFilter } from '../../index.js';
|
|
@@ -28,6 +29,7 @@
|
|
|
28
29
|
showMarkReadButton = true,
|
|
29
30
|
showFavoriteButton = true,
|
|
30
31
|
showMarkAsSpamButton = true,
|
|
32
|
+
showReplies = true,
|
|
31
33
|
readInbox = $bindable((skip?: number, take?: number, filter?: TableFilter<any>) => {
|
|
32
34
|
return null;
|
|
33
35
|
}),
|
|
@@ -57,12 +59,10 @@
|
|
|
57
59
|
}
|
|
58
60
|
}: MailingModuleProps = $props();
|
|
59
61
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
let activeBox = $state<ActiveBox>('inbox');
|
|
62
|
+
let activeBox = $state<MailingActiveBox>('inbox');
|
|
63
63
|
let pageInfo = new PageInfo();
|
|
64
64
|
let menutItems = $state([
|
|
65
|
-
{ icon: 'bx:bxs-inbox', title: 'Inbox', count:
|
|
65
|
+
{ icon: 'bx:bxs-inbox', title: 'Inbox', count: 0, path: '' },
|
|
66
66
|
{ icon: 'bx:bxs-send', title: 'Sent', count: 0, path: '' }
|
|
67
67
|
]);
|
|
68
68
|
let openDeleteAlert = $state(false);
|
|
@@ -85,7 +85,11 @@
|
|
|
85
85
|
else return false;
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
async function fetchData(
|
|
88
|
+
async function fetchData(
|
|
89
|
+
page: number,
|
|
90
|
+
params: TableFilter,
|
|
91
|
+
activeBox: MailingActiveBox = 'inbox'
|
|
92
|
+
) {
|
|
89
93
|
try {
|
|
90
94
|
let currentPage = 0;
|
|
91
95
|
if (params.search) {
|
|
@@ -313,7 +317,7 @@
|
|
|
313
317
|
}
|
|
314
318
|
|
|
315
319
|
function updatePageInfo(val: MailPageInfo) {
|
|
316
|
-
console.log({ val });
|
|
320
|
+
// console.log({ val });
|
|
317
321
|
pageInfo.totalItems = 1;
|
|
318
322
|
pageInfo.setHasNextPage(val.hasNextPage);
|
|
319
323
|
pageInfo.setHasPrevPage(val.hasPreviousPage);
|
|
@@ -329,7 +333,9 @@
|
|
|
329
333
|
<div class="h-full w-full">
|
|
330
334
|
<div class="flex h-full w-full gap-2">
|
|
331
335
|
<div class:hidden={!showSidePanel} class="loginbox h-full w-20 rounded-md bg-white">
|
|
332
|
-
<MailSidebar onClick={toggleSideBar} menus={menutItems} {setActiveMenu}
|
|
336
|
+
<MailSidebar onClick={toggleSideBar} menus={menutItems} {setActiveMenu}
|
|
337
|
+
|
|
338
|
+
/>
|
|
333
339
|
</div>
|
|
334
340
|
<div class="flex w-full flex-grow flex-col gap-1">
|
|
335
341
|
<div class="loginbox h-14 rounded bg-white px-4">
|
|
@@ -351,7 +357,7 @@
|
|
|
351
357
|
onMarkAsSpamClick={handleMarkAsSpam}
|
|
352
358
|
onToggleMarkReadClick={handleMarkAsRead}
|
|
353
359
|
onToggleFavoriteClick={handleMarkAsFavorite}
|
|
354
|
-
onBackClick={() => {
|
|
360
|
+
onBackClick={async () => {
|
|
355
361
|
messageSelected = 0;
|
|
356
362
|
selectedMessages = [];
|
|
357
363
|
}}
|
|
@@ -375,9 +381,11 @@
|
|
|
375
381
|
<PageLoader size={50} />
|
|
376
382
|
{:else if messageSelected}
|
|
377
383
|
<MailingMessageViewer
|
|
378
|
-
recordId={messageSelected}
|
|
384
|
+
bind:recordId={messageSelected}
|
|
379
385
|
readMessage={readAMessage}
|
|
380
386
|
{updatePageInfo}
|
|
387
|
+
{showReplies}
|
|
388
|
+
showHeader={activeBox === 'inbox'}
|
|
381
389
|
/>
|
|
382
390
|
{:else if messages.length}
|
|
383
391
|
<div class="custom-scrollbar h-full w-full overflow-auto" in:slide>
|
|
@@ -5,3 +5,4 @@ export { default as MailToolBar } from './MailToolBar.svelte';
|
|
|
5
5
|
export { default as MailingModule } from './MailingModule.svelte';
|
|
6
6
|
export { default as MailingHeader } from './MailingHeader.svelte';
|
|
7
7
|
export { default as MailingMessageViewer } from './MailingMessageViewer.svelte';
|
|
8
|
+
export { default as MailingContent } from './MailingContent.svelte';
|
|
@@ -5,3 +5,4 @@ export { default as MailToolBar } from './MailToolBar.svelte';
|
|
|
5
5
|
export { default as MailingModule } from './MailingModule.svelte';
|
|
6
6
|
export { default as MailingHeader } from './MailingHeader.svelte';
|
|
7
7
|
export { default as MailingMessageViewer } from './MailingMessageViewer.svelte';
|
|
8
|
+
export { default as MailingContent } from './MailingContent.svelte';
|
|
@@ -71,6 +71,7 @@ export interface MailingModuleProps {
|
|
|
71
71
|
toggleFavourite?: (id: string | number) => Promise<CrudResult<any>> | CrudResult<any> | null;
|
|
72
72
|
toggelImportant?: (id: string | number) => Promise<CrudResult<any>> | CrudResult<any> | null;
|
|
73
73
|
readAMessage: (id: string | number) => Promise<CrudResult<any>> | CrudResult<any> | null;
|
|
74
|
+
showReplies?: boolean;
|
|
74
75
|
}
|
|
75
76
|
export interface MailingMessageCardChecked {
|
|
76
77
|
id: number;
|
|
@@ -104,10 +105,13 @@ export interface MailingMessageCardProps extends MailingMessage {
|
|
|
104
105
|
toggelImportant?: (id: number) => void;
|
|
105
106
|
toggleFavorited?: (id: number) => void;
|
|
106
107
|
}
|
|
108
|
+
export type MailingActiveBox = 'inbox' | 'outbox';
|
|
107
109
|
export interface MailingMessageViewerProps {
|
|
108
|
-
readMessage: (id: number) => Promise<CrudResult<MailingMessage>> | CrudResult<MailingMessage> | null;
|
|
110
|
+
readMessage: (id: number, type?: MailingActiveBox) => Promise<CrudResult<MailingMessage>> | CrudResult<MailingMessage> | null;
|
|
109
111
|
recordId: number;
|
|
110
112
|
updatePageInfo?: (val: MailPageInfo) => void;
|
|
113
|
+
showReplies?: boolean;
|
|
114
|
+
showHeader?: boolean;
|
|
111
115
|
}
|
|
112
116
|
export interface MailingHeaderData {
|
|
113
117
|
subject: string;
|
|
@@ -123,4 +127,5 @@ export type MailingReplyType = 'reply' | 'reply-all' | 'forward';
|
|
|
123
127
|
export interface MailingHeaderProps {
|
|
124
128
|
data: MailingHeaderData;
|
|
125
129
|
replyType: MailingReplyType | undefined;
|
|
130
|
+
showReplies?: boolean;
|
|
126
131
|
}
|