Skip to content

Commit 77d5482

Browse files
stnguyen90TorstenDittmann
authored andcommitted
Add support for saving messages as draft
1 parent b1cd950 commit 77d5482

File tree

16 files changed

+566
-204
lines changed

16 files changed

+566
-204
lines changed

src/lib/actions/analytics.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,7 @@ export enum Submit {
294294
MessagingProviderDelete = 'submit_messaging_provider_delete',
295295
MessagingProviderUpdate = 'submit_messaging_provider_update',
296296
MessagingMessageCreate = 'submit_messaging_message_create',
297+
MessagingMessageUpdate = 'submit_messaging_message_update',
297298
MessagingMessageDelete = 'submit_messaging_message_delete',
298299
MessagingTopicCreate = 'submit_messaging_topic_create',
299300
MessagingTopicDelete = 'submit_messaging_topic_delete',

src/routes/console/project-[project]/messaging/create.svelte

Lines changed: 0 additions & 114 deletions
This file was deleted.

src/routes/console/project-[project]/messaging/createMessageDropdown.svelte

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
import { Button } from '$lib/elements/forms';
44
import { wizard } from '$lib/stores/wizard';
55
import { providers } from './providers/store';
6-
import Create from './create.svelte';
7-
import { messageParams, providerType, targetsById } from './wizard/store';
6+
import Wizard from './wizard.svelte';
7+
import { messageParams, operation, providerType, targetsById } from './wizard/store';
88
import { ProviderTypes } from './providerType.svelte';
99
import { topicsById } from './store';
1010
@@ -30,6 +30,7 @@
3030
)
3131
return;
3232
$providerType = type;
33+
$operation = 'create';
3334
$topicsById = {};
3435
$targetsById = {};
3536
const common = {
@@ -60,7 +61,7 @@
6061
break;
6162
}
6263
showCreateDropdown = false;
63-
wizard.start(Create);
64+
wizard.start(Wizard);
6465
}}>
6566
{option.name}
6667
</DropListItem>

src/routes/console/project-[project]/messaging/message-[message]/+layout.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,51 @@ export const load: LayoutLoad = async ({ params, depends }) => {
2222
}
2323
);
2424

25+
const topicsById = {};
26+
const topicsPromise = Promise.allSettled(
27+
response.topics.map((topicId) => {
28+
return sdk.forProject.client.call(
29+
'GET',
30+
new URL(`${sdk.forProject.client.config.endpoint}/messaging/topics/${topicId}`),
31+
{
32+
'X-Appwrite-Project': sdk.forProject.client.config.project,
33+
'content-type': 'application/json',
34+
'X-Appwrite-Mode': 'admin'
35+
}
36+
);
37+
})
38+
).then((results) => {
39+
results.forEach((result) => {
40+
if (result.status === 'fulfilled') {
41+
topicsById[result.value.$id] = result.value;
42+
}
43+
});
44+
});
45+
46+
const targetsById = {};
47+
const targetsPromise = sdk.forProject.client
48+
.call(
49+
'GET',
50+
new URL(
51+
`${sdk.forProject.client.config.endpoint}/messaging/messages/${params.message}/targets`
52+
),
53+
{
54+
'X-Appwrite-Project': sdk.forProject.client.config.project,
55+
'content-type': 'application/json',
56+
'X-Appwrite-Mode': 'admin'
57+
}
58+
)
59+
.then((response) => {
60+
response.targets.forEach((target) => {
61+
targetsById[target.$id] = target;
62+
});
63+
});
64+
65+
await Promise.allSettled([topicsPromise, targetsPromise]);
66+
2567
return {
68+
topicsById,
69+
targetsById,
2670
header: Header,
2771
breadcrumbs: Breadcrumbs,
2872
message: response

src/routes/console/project-[project]/messaging/message-[message]/+page.svelte

Lines changed: 94 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,107 @@
77
import { ProviderTypes } from '../providerType.svelte';
88
import SMSPreview from './smsPreview.svelte';
99
import PushPreview from './pushPreview.svelte';
10+
import {
11+
MessageStatuses,
12+
messageParams,
13+
operation,
14+
providerType,
15+
targetsById
16+
} from '../wizard/store';
17+
import { topicsById } from '../store';
18+
import { wizard } from '$lib/stores/wizard';
19+
import Wizard from '../wizard.svelte';
20+
import type { PageData } from './$types';
21+
22+
export let data: PageData;
23+
24+
async function onEdit() {
25+
$operation = 'update';
26+
$providerType = $message.providerType;
27+
$topicsById = {};
28+
$targetsById = {};
29+
30+
$topicsById = data.topicsById;
31+
$targetsById = data.targetsById;
32+
33+
$messageParams[$providerType] = {
34+
messageId: $message.$id,
35+
topics: $message.topics,
36+
users: $message.users,
37+
targets: $message.targets,
38+
description: $message.description,
39+
status: MessageStatuses.DRAFT,
40+
scheduledAt: $message.scheduledAt
41+
};
42+
43+
switch ($providerType) {
44+
case ProviderTypes.Email:
45+
{
46+
const { data } = $message;
47+
const params = ['subject', 'content', 'html'];
48+
params.forEach((key) => {
49+
if (typeof data[key] !== 'undefined') {
50+
$messageParams[$providerType][key] = data[key];
51+
}
52+
});
53+
}
54+
break;
55+
case ProviderTypes.Sms:
56+
{
57+
const { data } = $message;
58+
const params = ['content'];
59+
params.forEach((key) => {
60+
if (typeof data[key] !== 'undefined') {
61+
$messageParams[$providerType][key] = data[key];
62+
}
63+
});
64+
}
65+
break;
66+
case ProviderTypes.Push:
67+
{
68+
const { data } = $message;
69+
const params = [
70+
'title',
71+
'body',
72+
'action',
73+
'icon',
74+
'sound',
75+
'color',
76+
'tag',
77+
'badge'
78+
];
79+
params.forEach((key) => {
80+
if (typeof data[key] !== 'undefined') {
81+
$messageParams[$providerType][key] = data[key];
82+
}
83+
});
84+
const dataEntries: [string, string][] = [];
85+
Object.entries(data['data'] ?? {}).forEach(([key, value]) => {
86+
dataEntries.push([key, value.toString()]);
87+
});
88+
$messageParams[$providerType]['data'] = dataEntries || [['', '']];
89+
}
90+
break;
91+
}
92+
93+
wizard.start(Wizard);
94+
}
1095
</script>
1196

1297
<Container>
1398
<Overview />
1499
{#if $message.providerType === ProviderTypes.Email}
15-
<EmailPreview />
100+
<EmailPreview
101+
message={$message}
102+
onEdit={$message.status === MessageStatuses.DRAFT ? onEdit : null} />
16103
{:else if $message.providerType === ProviderTypes.Sms}
17-
<SMSPreview />
104+
<SMSPreview
105+
message={$message}
106+
onEdit={$message.status === MessageStatuses.DRAFT ? onEdit : null} />
18107
{:else if $message.providerType === ProviderTypes.Push}
19-
<PushPreview />
108+
<PushPreview
109+
message={$message}
110+
onEdit={$message.status === MessageStatuses.DRAFT ? onEdit : null} />
20111
{/if}
21112
<Delete />
22113
</Container>
Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
<script lang="ts">
22
import { CardGrid, Heading } from '$lib/components';
3-
import { FormList, InputText, InputTextarea } from '$lib/elements/forms';
4-
import { message } from './store';
3+
import { Button, FormList, InputText, InputTextarea } from '$lib/elements/forms';
4+
import type { Message } from '../store';
5+
6+
export let message: Message;
7+
export let onEdit: () => void = null;
58
</script>
69

710
<CardGrid>
@@ -14,20 +17,17 @@
1417
id="subject"
1518
label="Subject"
1619
disabled={true}
17-
bind:value={$message.data.subject}>
20+
bind:value={message.data.subject}>
1821
</InputText>
1922
<InputTextarea
2023
id="message"
2124
label="Message"
2225
disabled={true}
23-
bind:value={$message.data.content}>
26+
bind:value={message.data.content}>
2427
</InputTextarea>
28+
<div class="u-flex u-main-end">
29+
<Button secondary disabled={onEdit == null} on:click={onEdit}>Edit message</Button>
30+
</div>
2531
</FormList>
2632
</svelte:fragment>
27-
28-
<svelte:fragment slot="actions">
29-
<!-- TODO: Add support for editing draft messages -->
30-
<!-- <Button disabled={$message.status !== 'draft'} on:click={() => console.log('click')}
31-
>Edit message</Button> -->
32-
</svelte:fragment>
3333
</CardGrid>
Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,33 @@
11
<script lang="ts">
22
import { CardGrid, Heading } from '$lib/components';
3-
import { FormList, InputText, InputTextarea } from '$lib/elements/forms';
4-
import { message } from './store';
3+
import { Button, FormList, InputText, InputTextarea } from '$lib/elements/forms';
54
import PushPhone from '../pushPhone.svelte';
5+
import type { Message } from '../store';
6+
7+
export let message: Message;
8+
export let onEdit: () => void = null;
69
</script>
710

811
<CardGrid>
912
<div class="grid-1-2-col-1 u-flex-vertical u-cross-start u-gap-16">
1013
<Heading tag="h6" size="7">Preview</Heading>
1114
<div class="u-flex u-main-center u-margin-block-start-24 u-width-full-line">
12-
<PushPhone title={$message.data.title} body={$message.data.body} />
15+
<PushPhone title={message.data.title} body={message.data.body} />
1316
</div>
1417
</div>
1518
<svelte:fragment slot="aside">
1619
<FormList>
17-
<InputText id="title" label="Title" disabled={true} bind:value={$message.data.title}>
20+
<InputText id="title" label="Title" disabled={true} bind:value={message.data.title}>
1821
</InputText>
1922
<InputTextarea
2023
id="message"
2124
label="Message"
2225
disabled={true}
23-
bind:value={$message.data.body}>
26+
bind:value={message.data.body}>
2427
</InputTextarea>
28+
<div class="u-flex u-main-end">
29+
<Button secondary disabled={onEdit == null} on:click={onEdit}>Edit message</Button>
30+
</div>
2531
</FormList>
2632
</svelte:fragment>
27-
28-
<svelte:fragment slot="actions">
29-
<!-- TODO: Add support for editing draft messages -->
30-
<!-- <Button disabled={$message.status !== 'draft'} on:click={() => console.log('click')}
31-
>Edit message</Button> -->
32-
</svelte:fragment>
3333
</CardGrid>

0 commit comments

Comments
 (0)