From 232deea662eaa1580501311e7d90bbfcb1e153ae Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Sun, 25 Feb 2024 16:57:20 -0800 Subject: [PATCH 01/21] feat(messaging) update the message topics card to allow updating --- .../messaging/message-[message]/+page.svelte | 14 +- .../messaging/message-[message]/topics.svelte | 59 ------- .../message-[message]/updateTopics.svelte | 161 ++++++++++++++++++ 3 files changed, 173 insertions(+), 61 deletions(-) delete mode 100644 src/routes/console/project-[project]/messaging/message-[message]/topics.svelte create mode 100644 src/routes/console/project-[project]/messaging/message-[message]/updateTopics.svelte diff --git a/src/routes/console/project-[project]/messaging/message-[message]/+page.svelte b/src/routes/console/project-[project]/messaging/message-[message]/+page.svelte index 8bcefdc55..c10d41aac 100644 --- a/src/routes/console/project-[project]/messaging/message-[message]/+page.svelte +++ b/src/routes/console/project-[project]/messaging/message-[message]/+page.svelte @@ -13,11 +13,18 @@ import type { PageData } from './$types'; import { isValueOfStringEnum } from '$lib/helpers/types'; import { MessageStatus, MessagingProviderType } from '@appwrite.io/console'; - import Topics from './topics.svelte'; + import UpdateTopics from './updateTopics.svelte'; import Targets from './targets.svelte'; + import { onMount } from 'svelte'; export let data: PageData; + onMount(() => { + if (isValueOfStringEnum(MessagingProviderType, $message.providerType)) { + $providerType = $message.providerType; + } + }); + async function onEdit() { if (!isValueOfStringEnum(MessagingProviderType, $message.providerType)) { throw new Error(`Invalid provider type: ${$message.providerType}`); @@ -110,7 +117,10 @@ message={$message} onEdit={$message.status === MessageStatus.Draft ? onEdit : null} /> {/if} - + {#if $message.status !== MessageStatus.Processing} diff --git a/src/routes/console/project-[project]/messaging/message-[message]/topics.svelte b/src/routes/console/project-[project]/messaging/message-[message]/topics.svelte deleted file mode 100644 index 1df5200aa..000000000 --- a/src/routes/console/project-[project]/messaging/message-[message]/topics.svelte +++ /dev/null @@ -1,59 +0,0 @@ - - - - Topics - - {@const sum = topics.length} - {#if sum} -
- - - ID - Name - Subscribers - - - {#each topics.slice(offset, offset + limit) as topic (topic.$id)} - - - {topic.$id} - - - - {topic.name} - - - - {topic.smsTotal + topic.emailTotal + topic.pushTotal} - - - {/each} - -
-
-

Total topics: {sum}

- -
-
- {:else} - Edit the message to add a Topic - {/if} -
-
diff --git a/src/routes/console/project-[project]/messaging/message-[message]/updateTopics.svelte b/src/routes/console/project-[project]/messaging/message-[message]/updateTopics.svelte new file mode 100644 index 000000000..283f03064 --- /dev/null +++ b/src/routes/console/project-[project]/messaging/message-[message]/updateTopics.svelte @@ -0,0 +1,161 @@ + + +
+ + Topics + +
+
+ Topic +
+ +
+ {@const sum = topicIds.length} + {#if sum} +
+ + + + + + + {#each topics.slice(offset, offset + limit) as topic (topic.$id)} + + +
+ + + + {topic.name} + + + ({getTotal(topic)} targets) + + +
+
+ +
+ +
+
+
+ {/each} +
+
+
+

Total topics: {sum}

+ +
+
+ {:else} + (showTopics = true)}>Add a Topic + {/if} +
+ + + +
+
+ + { + showTopics = false; + topicsById = e.detail; + }} /> From 3d364d193810b01b547aa29e37232ade3c362e00 Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Sun, 25 Feb 2024 17:50:01 -0800 Subject: [PATCH 02/21] feat(messaging): update the message targets card to allow updating --- .../messaging/message-[message]/+page.svelte | 7 +- .../message-[message]/targets.svelte | 62 ------ .../message-[message]/updateTargets.svelte | 182 ++++++++++++++++++ 3 files changed, 187 insertions(+), 64 deletions(-) delete mode 100644 src/routes/console/project-[project]/messaging/message-[message]/targets.svelte create mode 100644 src/routes/console/project-[project]/messaging/message-[message]/updateTargets.svelte diff --git a/src/routes/console/project-[project]/messaging/message-[message]/+page.svelte b/src/routes/console/project-[project]/messaging/message-[message]/+page.svelte index c10d41aac..daacb54fc 100644 --- a/src/routes/console/project-[project]/messaging/message-[message]/+page.svelte +++ b/src/routes/console/project-[project]/messaging/message-[message]/+page.svelte @@ -14,7 +14,7 @@ import { isValueOfStringEnum } from '$lib/helpers/types'; import { MessageStatus, MessagingProviderType } from '@appwrite.io/console'; import UpdateTopics from './updateTopics.svelte'; - import Targets from './targets.svelte'; + import UpdateTargets from './updateTargets.svelte'; import { onMount } from 'svelte'; export let data: PageData; @@ -121,7 +121,10 @@ messageId={$message.$id} messageType={$providerType} selectedTopicsById={data.topicsById} /> - + {#if $message.status !== MessageStatus.Processing} {/if} diff --git a/src/routes/console/project-[project]/messaging/message-[message]/targets.svelte b/src/routes/console/project-[project]/messaging/message-[message]/targets.svelte deleted file mode 100644 index ca3e6ae03..000000000 --- a/src/routes/console/project-[project]/messaging/message-[message]/targets.svelte +++ /dev/null @@ -1,62 +0,0 @@ - - - - Targets - - {@const sum = targets.length} - {#if sum} -
- - - ID - Name - Identifier - - - {#each targets.slice(offset, offset + limit) as target (target.$id)} - - - {target.$id} - - - - {usersById[target.userId]?.name || 'Unknown'} - - - - {target.providerType === MessagingProviderType.Push - ? target.name - : target.identifier} - - - {/each} - -
-
-

Total targets: {sum}

- -
-
- {:else} - Edit the message to add a Target - {/if} -
-
diff --git a/src/routes/console/project-[project]/messaging/message-[message]/updateTargets.svelte b/src/routes/console/project-[project]/messaging/message-[message]/updateTargets.svelte new file mode 100644 index 000000000..bf7d3ddf4 --- /dev/null +++ b/src/routes/console/project-[project]/messaging/message-[message]/updateTargets.svelte @@ -0,0 +1,182 @@ + + +
+ + Targets + +
+
+ Target +
+ +
+ {@const sum = targetIds.length} + {#if sum} +
+ + + + + + + + {#each targets.slice(offset, offset + limit) as target (target.$id)} + + +
+ + + + {#if target.providerType === MessagingProviderType.Push} + {target.name} + {:else} + {target.identifier} + {/if} + + +
+
+ +
+ +
+
+
+ {/each} +
+
+
+

Total targets: {sum}

+ +
+
+ {:else} + (showTargets = true)}>Add a Target + {/if} +
+ + + +
+
+ + { + showTargets = false; + targetsById = e.detail; + }}> + Select existing targets to which you want to send this message. + From 87845fd7dd6fdbd988b0f5e053ccbe8ce512553a Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Sun, 25 Feb 2024 18:18:50 -0800 Subject: [PATCH 03/21] feat(messaging): rename the message preview cards and enable updating --- .../messaging/message-[message]/+page.svelte | 99 ++----------------- .../message-[message]/emailMessage.svelte | 66 +++++++++++++ .../message-[message]/emailPreview.svelte | 33 ------- .../message-[message]/pushMessage.svelte | 71 +++++++++++++ .../message-[message]/pushPreview.svelte | 33 ------- .../message-[message]/smsMessage.svelte | 64 ++++++++++++ .../message-[message]/smsPreview.svelte | 29 ------ 7 files changed, 208 insertions(+), 187 deletions(-) create mode 100644 src/routes/console/project-[project]/messaging/message-[message]/emailMessage.svelte delete mode 100644 src/routes/console/project-[project]/messaging/message-[message]/emailPreview.svelte create mode 100644 src/routes/console/project-[project]/messaging/message-[message]/pushMessage.svelte delete mode 100644 src/routes/console/project-[project]/messaging/message-[message]/pushPreview.svelte create mode 100644 src/routes/console/project-[project]/messaging/message-[message]/smsMessage.svelte delete mode 100644 src/routes/console/project-[project]/messaging/message-[message]/smsPreview.svelte diff --git a/src/routes/console/project-[project]/messaging/message-[message]/+page.svelte b/src/routes/console/project-[project]/messaging/message-[message]/+page.svelte index daacb54fc..b8ebca83b 100644 --- a/src/routes/console/project-[project]/messaging/message-[message]/+page.svelte +++ b/src/routes/console/project-[project]/messaging/message-[message]/+page.svelte @@ -1,15 +1,12 @@ {#if $message.providerType === MessagingProviderType.Email} - + {:else if $message.providerType === MessagingProviderType.Sms} - + {:else if $message.providerType === MessagingProviderType.Push} - + {/if} + import { invalidate } from '$app/navigation'; + import { trackEvent, Submit, trackError } from '$lib/actions/analytics'; + import { CardGrid, Heading } from '$lib/components'; + import { Dependencies } from '$lib/constants'; + import { Button, Form, FormList, InputText, InputTextarea } from '$lib/elements/forms'; + import { addNotification } from '$lib/stores/notifications'; + import { sdk } from '$lib/stores/sdk'; + import type { Models } from '@appwrite.io/console'; + import { onMount } from 'svelte'; + + export let message: Models.Message & { data: Record }; + + let subject = ''; + let content = ''; + let disabled = true; + + onMount(() => { + subject = message.data.subject; + content = message.data.content; + }); + + async function update() { + try { + await sdk.forProject.messaging.updateEmail( + message.$id, + undefined, + undefined, + undefined, + subject, + content + ); + await invalidate(Dependencies.MESSAGING_MESSAGE); + addNotification({ + message: 'Message has been updated', + type: 'success' + }); + trackEvent(Submit.MessagingMessageUpdate); + } catch (error) { + addNotification({ + message: error.message, + type: 'error' + }); + trackError(error, Submit.MessagingMessageUpdate); + } + } + + $: disabled = subject === message.data.subject && content === message.data.content; + + +
+ +
+ Message +
+ + + + + + + + + +
+
diff --git a/src/routes/console/project-[project]/messaging/message-[message]/emailPreview.svelte b/src/routes/console/project-[project]/messaging/message-[message]/emailPreview.svelte deleted file mode 100644 index c6d5e051d..000000000 --- a/src/routes/console/project-[project]/messaging/message-[message]/emailPreview.svelte +++ /dev/null @@ -1,33 +0,0 @@ - - - -
- Preview -
- - - - - - -
- -
-
-
-
diff --git a/src/routes/console/project-[project]/messaging/message-[message]/pushMessage.svelte b/src/routes/console/project-[project]/messaging/message-[message]/pushMessage.svelte new file mode 100644 index 000000000..fcc7a1802 --- /dev/null +++ b/src/routes/console/project-[project]/messaging/message-[message]/pushMessage.svelte @@ -0,0 +1,71 @@ + + +
+ +
+ Message +
+ +
+
+ + + + +
+
+
+ + + +
+
diff --git a/src/routes/console/project-[project]/messaging/message-[message]/pushPreview.svelte b/src/routes/console/project-[project]/messaging/message-[message]/pushPreview.svelte deleted file mode 100644 index eefb59c0a..000000000 --- a/src/routes/console/project-[project]/messaging/message-[message]/pushPreview.svelte +++ /dev/null @@ -1,33 +0,0 @@ - - - -
- Preview -
- -
-
- - - - - - -
- -
-
-
-
diff --git a/src/routes/console/project-[project]/messaging/message-[message]/smsMessage.svelte b/src/routes/console/project-[project]/messaging/message-[message]/smsMessage.svelte new file mode 100644 index 000000000..8d0e63f15 --- /dev/null +++ b/src/routes/console/project-[project]/messaging/message-[message]/smsMessage.svelte @@ -0,0 +1,64 @@ + + +
+ +
+ Message + +
+ + + + + + + + +
+
diff --git a/src/routes/console/project-[project]/messaging/message-[message]/smsPreview.svelte b/src/routes/console/project-[project]/messaging/message-[message]/smsPreview.svelte deleted file mode 100644 index 8e6e772bb..000000000 --- a/src/routes/console/project-[project]/messaging/message-[message]/smsPreview.svelte +++ /dev/null @@ -1,29 +0,0 @@ - - - -
- Preview - -
- - - - -
- -
-
-
-
From cb4a69adb627ccd82adf95ba88f143a32a971335 Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Sun, 25 Feb 2024 21:54:14 -0800 Subject: [PATCH 04/21] fix(messaging): ensure scheduledAt is saved in draft messages --- .../console/project-[project]/messaging/wizard/step3.svelte | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/routes/console/project-[project]/messaging/wizard/step3.svelte b/src/routes/console/project-[project]/messaging/wizard/step3.svelte index ba2e7be3b..c7ee27769 100644 --- a/src/routes/console/project-[project]/messaging/wizard/step3.svelte +++ b/src/routes/console/project-[project]/messaging/wizard/step3.svelte @@ -44,7 +44,6 @@ $messageParams[$providerType].status = MessageStatus.Processing; if (when === 'later') { $messageParams[$providerType].status = 'scheduled' as MessageStatus; - $messageParams[$providerType].scheduledAt = dateTime.toISOString(); } } @@ -61,6 +60,9 @@ ? new Date(now.getTime() - timeZoneOffset).toISOString().split('T')[1].substring(0, 5) : '00:00'; $: dateTime = new Date(`${date}T${time}`); + $: if (!isNaN(dateTime.getTime())) { + $messageParams[$providerType].scheduledAt = dateTime.toISOString(); + } From 2c9788bad802367bba524942b3e6966839cf2278 Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Sun, 25 Feb 2024 22:29:00 -0800 Subject: [PATCH 05/21] fix(messaging): update message details to show scheduled/delivered at Only show when available. Othersise, hide the entire line. --- .../messaging/message-[message]/overview.svelte | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/routes/console/project-[project]/messaging/message-[message]/overview.svelte b/src/routes/console/project-[project]/messaging/message-[message]/overview.svelte index b9c95e2d8..7e0116886 100644 --- a/src/routes/console/project-[project]/messaging/message-[message]/overview.svelte +++ b/src/routes/console/project-[project]/messaging/message-[message]/overview.svelte @@ -42,7 +42,12 @@

Created: {toLocaleDateTime($message.$createdAt)}

-

Scheduled at: {toLocaleDateTime(scheduledAt)}

+ {#if $message.scheduledAt} +

Scheduled at: {toLocaleDateTime($message.scheduledAt)}

+ {/if} + {#if $message.deliveredAt} +

Sent at: {toLocaleDateTime($message.deliveredAt)}

+ {/if}
From 1d6a8017e1c9f4ffe981e08762674e30ec802937 Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Sun, 25 Feb 2024 22:34:41 -0800 Subject: [PATCH 06/21] feat(messaging): update overview card to support scheduling and sending --- .../messaging/message-[message]/+page.svelte | 2 +- .../message-[message]/overview.svelte | 60 ++++---- .../message-[message]/scheduleModal.svelte | 144 ++++++++++++++++++ .../message-[message]/sendModal.svelte | 102 +++++++++++++ 4 files changed, 277 insertions(+), 31 deletions(-) create mode 100644 src/routes/console/project-[project]/messaging/message-[message]/scheduleModal.svelte create mode 100644 src/routes/console/project-[project]/messaging/message-[message]/sendModal.svelte diff --git a/src/routes/console/project-[project]/messaging/message-[message]/+page.svelte b/src/routes/console/project-[project]/messaging/message-[message]/+page.svelte index b8ebca83b..d542f2ed7 100644 --- a/src/routes/console/project-[project]/messaging/message-[message]/+page.svelte +++ b/src/routes/console/project-[project]/messaging/message-[message]/+page.svelte @@ -24,7 +24,7 @@ - + {#if $message.providerType === MessagingProviderType.Email} {:else if $message.providerType === MessagingProviderType.Sms} diff --git a/src/routes/console/project-[project]/messaging/message-[message]/overview.svelte b/src/routes/console/project-[project]/messaging/message-[message]/overview.svelte index 7e0116886..ce12622c6 100644 --- a/src/routes/console/project-[project]/messaging/message-[message]/overview.svelte +++ b/src/routes/console/project-[project]/messaging/message-[message]/overview.svelte @@ -4,38 +4,27 @@ import { message } from './store'; import ProviderType from '../providerType.svelte'; import MessageStatusPill from '../messageStatusPill.svelte'; - import { MessagingProviderType } from '@appwrite.io/console'; + import { MessagingProviderType, type Models } from '@appwrite.io/console'; import { Button } from '$lib/elements/forms'; import FailedModal from '../failedModal.svelte'; + import SendModal from './sendModal.svelte'; + import ScheduleModal from './scheduleModal.svelte'; - let scheduledAt: string = ''; + export let messageType: MessagingProviderType; + export let topics: Models.Topic[]; + + let showSend = false; + let showSchedule = false; let showFailed = false; let errors: string[] = []; - - if ($message.status === 'sent') { - scheduledAt = $message.deliveredAt; - } else if ($message.status === 'scheduled') { - scheduledAt = $message.scheduledAt; - } - - let providerType = 'Invalid provider type'; - switch ($message.providerType) { - case MessagingProviderType.Email: - providerType = 'Email'; - break; - case MessagingProviderType.Sms: - providerType = 'SMS'; - break; - case MessagingProviderType.Push: - providerType = 'Push'; - break; - } - +
- {providerType} + + +
@@ -56,14 +45,25 @@ - + {#if $message.status === 'draft' || $message.status === 'scheduled'} +
+ + +
+ {:else if $message.status === 'failed'} + + {/if}
+ + + + diff --git a/src/routes/console/project-[project]/messaging/message-[message]/scheduleModal.svelte b/src/routes/console/project-[project]/messaging/message-[message]/scheduleModal.svelte new file mode 100644 index 000000000..2dc24a7fd --- /dev/null +++ b/src/routes/console/project-[project]/messaging/message-[message]/scheduleModal.svelte @@ -0,0 +1,144 @@ + + + +
+ +
+ + +
+
+ + {#if !dateTime || isNaN(dateTime.getTime())} + The message will be sent later + {:else} + The message will be sent at {dateTime.toLocaleString('en', formatOptions)} + {/if} + +
+ + + + +
diff --git a/src/routes/console/project-[project]/messaging/message-[message]/sendModal.svelte b/src/routes/console/project-[project]/messaging/message-[message]/sendModal.svelte new file mode 100644 index 000000000..ba06222b1 --- /dev/null +++ b/src/routes/console/project-[project]/messaging/message-[message]/sendModal.svelte @@ -0,0 +1,102 @@ + + + +
+

+ You are about to send a message to an estimated {totalTargets} targets. Would you like to proceed? +

+ +

This action is irreversible.

+
+ + + + +
From 41a7caa6b5a33abf73e64c295376a72ac222a4f5 Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Sun, 25 Feb 2024 22:47:03 -0800 Subject: [PATCH 07/21] refactor(messaging): remove unused update message wizard code --- .../{wizard.svelte => create.svelte} | 119 +----------------- .../messaging/createMessageDropdown.svelte | 7 +- .../messaging/wizard/emailFormList.svelte | 26 ++-- .../messaging/wizard/pushFormList.svelte | 26 ++-- .../messaging/wizard/smsFormList.svelte | 26 ++-- .../messaging/wizard/store.ts | 1 - 6 files changed, 34 insertions(+), 171 deletions(-) rename src/routes/console/project-[project]/messaging/{wizard.svelte => create.svelte} (54%) diff --git a/src/routes/console/project-[project]/messaging/wizard.svelte b/src/routes/console/project-[project]/messaging/create.svelte similarity index 54% rename from src/routes/console/project-[project]/messaging/wizard.svelte rename to src/routes/console/project-[project]/messaging/create.svelte index 4fbc93c55..1392df1ec 100644 --- a/src/routes/console/project-[project]/messaging/wizard.svelte +++ b/src/routes/console/project-[project]/messaging/create.svelte @@ -7,13 +7,12 @@ import { sdk } from '$lib/stores/sdk'; import { Submit, trackError, trackEvent } from '$lib/actions/analytics'; import { addNotification } from '$lib/stores/notifications'; - import { goto, invalidate } from '$app/navigation'; + import { goto } from '$app/navigation'; import { base } from '$app/paths'; import { project } from '../store'; import { wizard } from '$lib/stores/wizard'; - import { providerType, messageParams, operation } from './wizard/store'; + import { providerType, messageParams } from './wizard/store'; import { ID, MessageStatus, MessagingProviderType, type Models } from '@appwrite.io/console'; - import { Dependencies } from '$lib/constants'; async function create() { try { @@ -112,115 +111,9 @@ } } - async function update() { - try { - let response: Models.Message; - - const messageId = $messageParams[$providerType].messageId; - - const params = $messageParams[$providerType]; - - console.log(params); - - switch ($providerType) { - case MessagingProviderType.Email: - response = await sdk.forProject.messaging.updateEmail( - messageId, - $messageParams[$providerType].topics, - $messageParams[$providerType].users, - $messageParams[$providerType].targets, - $messageParams[$providerType].subject, - $messageParams[$providerType].content, - $messageParams[$providerType].status, - $messageParams[$providerType].html, - undefined, - undefined, - $messageParams[$providerType].scheduledAt - ); - break; - case MessagingProviderType.Sms: - response = await sdk.forProject.messaging.updateSms( - messageId, - $messageParams[$providerType].topics, - $messageParams[$providerType].users, - $messageParams[$providerType].targets, - $messageParams[$providerType].content, - $messageParams[$providerType].status, - $messageParams[$providerType].scheduledAt - ); - break; - case MessagingProviderType.Push: - { - const customData: Record = {}; - const { data } = $messageParams[MessagingProviderType.Push]; - if (data && data.length > 0) { - data.forEach((item) => { - if (item[0] === '') return; - customData[item[0]] = item[1]; - }); - } - - response = await sdk.forProject.messaging.updatePush( - messageId, - $messageParams[$providerType].topics, - $messageParams[$providerType].users, - $messageParams[$providerType].targets, - $messageParams[$providerType].title, - $messageParams[$providerType].body, - customData, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - undefined, - $messageParams[$providerType].status, - $messageParams[$providerType].scheduledAt - ); - } - break; - } - wizard.hide(); - let message = ''; - switch (response.status) { - case MessageStatus.Draft: - message = 'The message has been saved as draft.'; - break; - case MessageStatus.Processing: - message = 'The message is queued for processing.'; - break; - case 'scheduled': - // TODO: fix message status - message = 'The message has been scheduled.'; - break; - } - addNotification({ - type: 'success', - message - }); - await invalidate(Dependencies.MESSAGING_MESSAGE); - trackEvent(Submit.MessagingMessageUpdate, { - providerType: $providerType, - status: params.status - }); - await goto(`${base}/console/project-${$project.$id}/messaging/message-${response.$id}`); - } catch (error) { - addNotification({ - type: 'error', - message: error.message - }); - trackError(error, Submit.MessagingMessageUpdate); - } - } - async function saveDraft() { $messageParams[$providerType].status = MessageStatus.Draft; - if ($operation === 'create') { - create(); - } else { - update(); - } + create(); } const stepsComponents: WizardStepsType = new Map(); @@ -256,8 +149,4 @@ }); - + diff --git a/src/routes/console/project-[project]/messaging/createMessageDropdown.svelte b/src/routes/console/project-[project]/messaging/createMessageDropdown.svelte index f35e08683..4e23952a0 100644 --- a/src/routes/console/project-[project]/messaging/createMessageDropdown.svelte +++ b/src/routes/console/project-[project]/messaging/createMessageDropdown.svelte @@ -3,8 +3,8 @@ import { Button } from '$lib/elements/forms'; import { wizard } from '$lib/stores/wizard'; import { providers } from './providers/store'; - import Wizard from './wizard.svelte'; - import { messageParams, operation, providerType, targetsById } from './wizard/store'; + import Create from './create.svelte'; + import { messageParams, providerType, targetsById } from './wizard/store'; import { topicsById } from './store'; import { MessagingProviderType } from '@appwrite.io/console'; @@ -30,7 +30,6 @@ ) return; $providerType = type; - $operation = 'create'; $topicsById = {}; $targetsById = {}; const common = { @@ -62,7 +61,7 @@ break; } showCreateDropdown = false; - wizard.start(Wizard); + wizard.start(Create); }}> {option.name} diff --git a/src/routes/console/project-[project]/messaging/wizard/emailFormList.svelte b/src/routes/console/project-[project]/messaging/wizard/emailFormList.svelte index bcc6be1d6..60992f0dd 100644 --- a/src/routes/console/project-[project]/messaging/wizard/emailFormList.svelte +++ b/src/routes/console/project-[project]/messaging/wizard/emailFormList.svelte @@ -1,5 +1,5 @@ - +

You are about to send a message to an estimated Date: Mon, 26 Feb 2024 08:21:35 -0800 Subject: [PATCH 11/21] fix(messaging): make schedule message modal bigger Give the inputs a bit more room. --- .../messaging/message-[message]/scheduleModal.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/console/project-[project]/messaging/message-[message]/scheduleModal.svelte b/src/routes/console/project-[project]/messaging/message-[message]/scheduleModal.svelte index 2dc24a7fd..76bbef6ca 100644 --- a/src/routes/console/project-[project]/messaging/message-[message]/scheduleModal.svelte +++ b/src/routes/console/project-[project]/messaging/message-[message]/scheduleModal.svelte @@ -119,7 +119,7 @@ $: dateTime = new Date(`${date}T${time}`); - +

Date: Mon, 26 Feb 2024 08:31:33 -0800 Subject: [PATCH 12/21] fix(messaging): fix topics & targets empty state for non-draft Show empty search and link to docs since they shouldn't edit it. --- .../messaging/message-[message]/+page.svelte | 2 ++ .../message-[message]/updateTargets.svelte | 22 ++++++++++++++++--- .../message-[message]/updateTopics.svelte | 22 ++++++++++++++++--- 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/src/routes/console/project-[project]/messaging/message-[message]/+page.svelte b/src/routes/console/project-[project]/messaging/message-[message]/+page.svelte index d542f2ed7..3c0647e5c 100644 --- a/src/routes/console/project-[project]/messaging/message-[message]/+page.svelte +++ b/src/routes/console/project-[project]/messaging/message-[message]/+page.svelte @@ -35,10 +35,12 @@ {#if $message.status !== MessageStatus.Processing} diff --git a/src/routes/console/project-[project]/messaging/message-[message]/updateTargets.svelte b/src/routes/console/project-[project]/messaging/message-[message]/updateTargets.svelte index bfa045ca6..13abd4a0d 100644 --- a/src/routes/console/project-[project]/messaging/message-[message]/updateTargets.svelte +++ b/src/routes/console/project-[project]/messaging/message-[message]/updateTargets.svelte @@ -1,5 +1,5 @@ - + {#if $message.providerType === MessagingProviderType.Email} {:else if $message.providerType === MessagingProviderType.Sms} @@ -32,16 +32,8 @@ {:else if $message.providerType === MessagingProviderType.Push} {/if} - - + + {#if $message.status !== MessageStatus.Processing} {/if} diff --git a/src/routes/console/project-[project]/messaging/message-[message]/overview.svelte b/src/routes/console/project-[project]/messaging/message-[message]/overview.svelte index ce12622c6..2b08d0000 100644 --- a/src/routes/console/project-[project]/messaging/message-[message]/overview.svelte +++ b/src/routes/console/project-[project]/messaging/message-[message]/overview.svelte @@ -1,16 +1,15 @@ - +
- + - +
-

Created: {toLocaleDateTime($message.$createdAt)}

- {#if $message.scheduledAt} -

Scheduled at: {toLocaleDateTime($message.scheduledAt)}

+

Created: {toLocaleDateTime(message.$createdAt)}

+ {#if message.scheduledAt} +

Scheduled at: {toLocaleDateTime(message.scheduledAt)}

{/if} - {#if $message.deliveredAt} -

Sent at: {toLocaleDateTime($message.deliveredAt)}

+ {#if message.deliveredAt} +

Sent at: {toLocaleDateTime(message.deliveredAt)}

{/if}
- +
- {#if $message.status === 'draft' || $message.status === 'scheduled'} + {#if message.status === 'draft' || message.status === 'scheduled'}
- {:else if $message.status === 'failed'} + {:else if message.status === 'failed'} {/if}
- + - + diff --git a/src/routes/console/project-[project]/messaging/message-[message]/scheduleModal.svelte b/src/routes/console/project-[project]/messaging/message-[message]/scheduleModal.svelte index 76bbef6ca..1b81dbd4c 100644 --- a/src/routes/console/project-[project]/messaging/message-[message]/scheduleModal.svelte +++ b/src/routes/console/project-[project]/messaging/message-[message]/scheduleModal.svelte @@ -9,7 +9,6 @@ import { Dependencies } from '$lib/constants'; export let show = false; - export let messageType: MessagingProviderType; export let message: Models.Message & { data: Record }; export let topics: Models.Topic[]; @@ -35,11 +34,11 @@ }; for (const topic of topics) { - if (messageType == MessagingProviderType.Push) { + if (message.providerType == MessagingProviderType.Push) { totalTargets = totalTargets + topic.pushTotal; - } else if (messageType == MessagingProviderType.Email) { + } else if (message.providerType == MessagingProviderType.Email) { totalTargets = totalTargets + topic.emailTotal; - } else if (messageType == MessagingProviderType.Sms) { + } else if (message.providerType == MessagingProviderType.Sms) { totalTargets = totalTargets + topic.smsTotal; } } @@ -47,7 +46,7 @@ const update = async () => { const status = MessageStatus.Scheduled; try { - if (messageType == MessagingProviderType.Email) { + if (message.providerType == MessagingProviderType.Email) { await sdk.forProject.messaging.updateEmail( message.$id, undefined, @@ -61,7 +60,7 @@ undefined, dateTime.toISOString() ); - } else if (messageType == MessagingProviderType.Sms) { + } else if (message.providerType == MessagingProviderType.Sms) { await sdk.forProject.messaging.updateSms( message.$id, undefined, @@ -71,7 +70,7 @@ status, dateTime.toISOString() ); - } else if (messageType == MessagingProviderType.Push) { + } else if (message.providerType == MessagingProviderType.Push) { await sdk.forProject.messaging.updatePush( message.$id, undefined, @@ -97,7 +96,7 @@ type: 'success' }); trackEvent(Submit.MessagingMessageUpdate, { - providerType: messageType, + providerType: message.providerType, status }); show = false; diff --git a/src/routes/console/project-[project]/messaging/message-[message]/sendModal.svelte b/src/routes/console/project-[project]/messaging/message-[message]/sendModal.svelte index 1bc47006f..2bf51ef7f 100644 --- a/src/routes/console/project-[project]/messaging/message-[message]/sendModal.svelte +++ b/src/routes/console/project-[project]/messaging/message-[message]/sendModal.svelte @@ -9,18 +9,17 @@ import { Dependencies } from '$lib/constants'; export let show = false; - export let messageType: MessagingProviderType; export let message: Models.Message & { data: Record }; export let topics: Models.Topic[]; let totalTargets = message.targets?.length ?? 0; for (const topic of topics) { - if (messageType == MessagingProviderType.Push) { + if (message.providerType == MessagingProviderType.Push) { totalTargets = totalTargets + topic.pushTotal; - } else if (messageType == MessagingProviderType.Email) { + } else if (message.providerType == MessagingProviderType.Email) { totalTargets = totalTargets + topic.emailTotal; - } else if (messageType == MessagingProviderType.Sms) { + } else if (message.providerType == MessagingProviderType.Sms) { totalTargets = totalTargets + topic.smsTotal; } } @@ -28,7 +27,7 @@ const update = async () => { const status = MessageStatus.Processing; try { - if (messageType == MessagingProviderType.Email) { + if (message.providerType == MessagingProviderType.Email) { await sdk.forProject.messaging.updateEmail( message.$id, undefined, @@ -38,7 +37,7 @@ undefined, status ); - } else if (messageType == MessagingProviderType.Sms) { + } else if (message.providerType == MessagingProviderType.Sms) { await sdk.forProject.messaging.updateSms( message.$id, undefined, @@ -47,7 +46,7 @@ undefined, status ); - } else if (messageType == MessagingProviderType.Push) { + } else if (message.providerType == MessagingProviderType.Push) { await sdk.forProject.messaging.updatePush( message.$id, undefined, @@ -72,7 +71,7 @@ type: 'success' }); trackEvent(Submit.MessagingMessageUpdate, { - providerType: messageType, + providerType: message.providerType, status }); show = false; diff --git a/src/routes/console/project-[project]/messaging/message-[message]/updateTargets.svelte b/src/routes/console/project-[project]/messaging/message-[message]/updateTargets.svelte index 13abd4a0d..ba729f0d0 100644 --- a/src/routes/console/project-[project]/messaging/message-[message]/updateTargets.svelte +++ b/src/routes/console/project-[project]/messaging/message-[message]/updateTargets.svelte @@ -18,12 +18,12 @@ import { addNotification } from '$lib/stores/notifications'; import { Button, Form } from '$lib/elements/forms'; import UserTargetsModal from '../userTargetsModal.svelte'; + import { isValueOfStringEnum } from '$lib/helpers/types'; - export let messageId: string; - export let messageType: MessagingProviderType; - export let messageStatus: string; + export let message: Models.Message & { data: Record }; export let selectedTargetsById: Record; + let providerType: MessagingProviderType; let offset = 0; const limit = 10; let showTargets = false; @@ -32,6 +32,10 @@ let targets: Models.Target[] = []; let disabled = true; + if (isValueOfStringEnum(MessagingProviderType, message.providerType)) { + providerType = message.providerType; + } + onMount(() => { targetsById = { ...selectedTargetsById }; }); @@ -43,23 +47,23 @@ async function update() { try { - if (messageType == MessagingProviderType.Email) { + if (message.providerType == MessagingProviderType.Email) { await sdk.forProject.messaging.updateEmail( - messageId, + message.$id, undefined, undefined, targetIds ); - } else if (messageType == MessagingProviderType.Sms) { + } else if (message.providerType == MessagingProviderType.Sms) { await sdk.forProject.messaging.updateSms( - messageId, + message.$id, undefined, undefined, targetIds ); - } else if (messageType == MessagingProviderType.Push) { + } else if (message.providerType == MessagingProviderType.Push) { await sdk.forProject.messaging.updatePush( - messageId, + message.$id, undefined, undefined, targetIds @@ -159,7 +163,7 @@
- {:else if messageStatus == MessageStatus.Draft} + {:else if message.status == MessageStatus.Draft} (showTargets = true)}>Add a target {:else} @@ -186,7 +190,7 @@ { diff --git a/src/routes/console/project-[project]/messaging/message-[message]/updateTopics.svelte b/src/routes/console/project-[project]/messaging/message-[message]/updateTopics.svelte index ba41efaf4..d0f1da8b6 100644 --- a/src/routes/console/project-[project]/messaging/message-[message]/updateTopics.svelte +++ b/src/routes/console/project-[project]/messaging/message-[message]/updateTopics.svelte @@ -19,12 +19,12 @@ import { Form, Button } from '$lib/elements/forms'; import { onMount } from 'svelte'; import { getTotal } from '../wizard/store'; + import { isValueOfStringEnum } from '$lib/helpers/types'; - export let messageId: string; - export let messageType: MessagingProviderType; - export let messageStatus: string; + export let message: Models.Message; export let selectedTopicsById: Record; + let providerType: MessagingProviderType; let offset = 0; const limit = 10; let showTopics = false; @@ -33,6 +33,10 @@ let topics: Models.Topic[] = []; let disabled = true; + if (isValueOfStringEnum(MessagingProviderType, message.providerType)) { + providerType = message.providerType; + } + onMount(() => { topicsById = { ...selectedTopicsById }; }); @@ -44,12 +48,12 @@ async function update() { try { - if (messageType == MessagingProviderType.Email) { - await sdk.forProject.messaging.updateEmail(messageId, topicIds); - } else if (messageType == MessagingProviderType.Sms) { - await sdk.forProject.messaging.updateSms(messageId, topicIds); - } else if (messageType == MessagingProviderType.Push) { - await sdk.forProject.messaging.updatePush(messageId, topicIds); + if (message.providerType == MessagingProviderType.Email) { + await sdk.forProject.messaging.updateEmail(message.$id, topicIds); + } else if (message.providerType == MessagingProviderType.Sms) { + await sdk.forProject.messaging.updateSms(message.$id, topicIds); + } else if (message.providerType == MessagingProviderType.Push) { + await sdk.forProject.messaging.updatePush(message.$id, topicIds); } await invalidate(Dependencies.MESSAGING_MESSAGE); addNotification({ @@ -142,7 +146,7 @@
- {:else if messageStatus == MessageStatus.Draft} + {:else if message.status == MessageStatus.Draft} (showTopics = true)}>Add a topic {:else} @@ -168,7 +172,7 @@ { From 88f661149bcaba9368a997aa0df697e661b65baa Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Mon, 26 Feb 2024 11:41:07 -0800 Subject: [PATCH 14/21] fix(messaging): show cancel and reschedule for scheduled messages --- .../messaging/message-[message]/overview.svelte | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/routes/console/project-[project]/messaging/message-[message]/overview.svelte b/src/routes/console/project-[project]/messaging/message-[message]/overview.svelte index 2b08d0000..3373321cc 100644 --- a/src/routes/console/project-[project]/messaging/message-[message]/overview.svelte +++ b/src/routes/console/project-[project]/messaging/message-[message]/overview.svelte @@ -3,7 +3,7 @@ import { toLocaleDateTime } from '$lib/helpers/date'; import ProviderType from '../providerType.svelte'; import MessageStatusPill from '../messageStatusPill.svelte'; - import { type Models } from '@appwrite.io/console'; + import { MessageStatus, type Models } from '@appwrite.io/console'; import { Button } from '$lib/elements/forms'; import FailedModal from '../failedModal.svelte'; import SendModal from './sendModal.svelte'; @@ -44,11 +44,16 @@ - {#if message.status === 'draft' || message.status === 'scheduled'} + {#if message.status === MessageStatus.Draft}
+ {:else if message.status === MessageStatus.Scheduled} +
+ + +
{:else if message.status === 'failed'} + {#if message.status == MessageStatus.Draft} + + {/if}
@@ -141,17 +143,19 @@ -
- +
diff --git a/src/routes/console/project-[project]/messaging/message-[message]/updateTopics.svelte b/src/routes/console/project-[project]/messaging/message-[message]/updateTopics.svelte index d0f1da8b6..f2ef9f55c 100644 --- a/src/routes/console/project-[project]/messaging/message-[message]/updateTopics.svelte +++ b/src/routes/console/project-[project]/messaging/message-[message]/updateTopics.svelte @@ -83,7 +83,7 @@ - + Topics {@const sum = topicIds.length} @@ -92,15 +92,17 @@
Topic
- + {#if message.status == MessageStatus.Draft} + + {/if}
@@ -125,16 +127,19 @@ -
- +
From bd9bf4cb699037c6a1dcd7953c0c024f8eac5c6c Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Mon, 26 Feb 2024 13:02:55 -0800 Subject: [PATCH 16/21] feat(messaging): add custom data to message details --- .../message-[message]/pushMessage.svelte | 109 +++++++++++++++++- 1 file changed, 105 insertions(+), 4 deletions(-) diff --git a/src/routes/console/project-[project]/messaging/message-[message]/pushMessage.svelte b/src/routes/console/project-[project]/messaging/message-[message]/pushMessage.svelte index c882c88fb..f9bd9398d 100644 --- a/src/routes/console/project-[project]/messaging/message-[message]/pushMessage.svelte +++ b/src/routes/console/project-[project]/messaging/message-[message]/pushMessage.svelte @@ -1,6 +1,16 @@ @@ -69,7 +106,71 @@ label="Message" disabled={message.status != MessageStatus.Draft} bind:value={body}> -
+ + + + +
+
    + {#each customData || [] as _, rowIndex} + + + + + + + + + {/each} +
+ {#if dataError} + {dataError} + {/if} + +
+ From 3c1219dc234aff0f78e5b500781fec5f457d010d Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Mon, 26 Feb 2024 14:52:53 -0800 Subject: [PATCH 17/21] fix(messaging): add html mode switch to email message --- .../message-[message]/emailMessage.svelte | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/routes/console/project-[project]/messaging/message-[message]/emailMessage.svelte b/src/routes/console/project-[project]/messaging/message-[message]/emailMessage.svelte index fa4e9154f..d3b046d8c 100644 --- a/src/routes/console/project-[project]/messaging/message-[message]/emailMessage.svelte +++ b/src/routes/console/project-[project]/messaging/message-[message]/emailMessage.svelte @@ -3,7 +3,7 @@ import { trackEvent, Submit, trackError } from '$lib/actions/analytics'; import { CardGrid, Heading } from '$lib/components'; import { Dependencies } from '$lib/constants'; - import { Button, Form, FormList, InputText, InputTextarea } from '$lib/elements/forms'; + import { Button, Form, FormList, InputSwitch, InputText, InputTextarea } from '$lib/elements/forms'; import { addNotification } from '$lib/stores/notifications'; import { sdk } from '$lib/stores/sdk'; import { MessageStatus, type Models } from '@appwrite.io/console'; @@ -13,11 +13,13 @@ let subject = ''; let content = ''; + let html = false; let disabled = true; onMount(() => { subject = message.data.subject; content = message.data.content; + html = (message.data['html'] ?? false) as boolean; }); async function update() { @@ -28,7 +30,9 @@ undefined, undefined, subject, - content + content, + undefined, + html ); await invalidate(Dependencies.MESSAGING_MESSAGE); addNotification({ @@ -45,7 +49,7 @@ } } - $: disabled = subject === message.data.subject && content === message.data.content; + $: disabled = subject === message.data.subject && content === message.data.content && html === (message.data['html'] ?? false) as boolean;
@@ -65,6 +69,11 @@ label="Message" disabled={message.status != MessageStatus.Draft} bind:value={content}> + + + Enable the HTML mode if your message contains HTML tags. + +
From 8d1934f303d10204a5ccf76032bb8ff29dec3b51 Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Mon, 26 Feb 2024 14:54:30 -0800 Subject: [PATCH 18/21] fix(messaging): update topics/targets confirmation message --- .../messaging/message-[message]/updateTargets.svelte | 2 +- .../messaging/message-[message]/updateTopics.svelte | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/console/project-[project]/messaging/message-[message]/updateTargets.svelte b/src/routes/console/project-[project]/messaging/message-[message]/updateTargets.svelte index 159c2299a..c4a1ca0db 100644 --- a/src/routes/console/project-[project]/messaging/message-[message]/updateTargets.svelte +++ b/src/routes/console/project-[project]/messaging/message-[message]/updateTargets.svelte @@ -71,7 +71,7 @@ } await invalidate(Dependencies.MESSAGING_MESSAGE); addNotification({ - message: 'Message has been updated', + message: 'Targets have been updated', type: 'success' }); trackEvent(Submit.MessagingMessageUpdate); diff --git a/src/routes/console/project-[project]/messaging/message-[message]/updateTopics.svelte b/src/routes/console/project-[project]/messaging/message-[message]/updateTopics.svelte index f2ef9f55c..96dd7ab4c 100644 --- a/src/routes/console/project-[project]/messaging/message-[message]/updateTopics.svelte +++ b/src/routes/console/project-[project]/messaging/message-[message]/updateTopics.svelte @@ -57,7 +57,7 @@ } await invalidate(Dependencies.MESSAGING_MESSAGE); addNotification({ - message: 'Message has been updated', + message: 'Topics have been updated', type: 'success' }); trackEvent(Submit.MessagingMessageUpdate); From 2d3c7ef5201bcfc244b56d36e2313a49af7fcf6c Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Mon, 26 Feb 2024 15:05:26 -0800 Subject: [PATCH 19/21] feat(messaging): support cancelling a scheduled message Update status to draft. --- .../message-[message]/cancelModal.svelte | 92 +++++++++++++++++++ .../message-[message]/overview.svelte | 8 +- 2 files changed, 98 insertions(+), 2 deletions(-) create mode 100644 src/routes/console/project-[project]/messaging/message-[message]/cancelModal.svelte diff --git a/src/routes/console/project-[project]/messaging/message-[message]/cancelModal.svelte b/src/routes/console/project-[project]/messaging/message-[message]/cancelModal.svelte new file mode 100644 index 000000000..504b67a54 --- /dev/null +++ b/src/routes/console/project-[project]/messaging/message-[message]/cancelModal.svelte @@ -0,0 +1,92 @@ + + + +
+

+ Are you sure you want to cancel the scheduling of {message.data.title ?? message.data.subject ?? message.data.content ?? 'Message'}? +

+
+ + + +
diff --git a/src/routes/console/project-[project]/messaging/message-[message]/overview.svelte b/src/routes/console/project-[project]/messaging/message-[message]/overview.svelte index 3373321cc..d020e9b99 100644 --- a/src/routes/console/project-[project]/messaging/message-[message]/overview.svelte +++ b/src/routes/console/project-[project]/messaging/message-[message]/overview.svelte @@ -8,12 +8,14 @@ import FailedModal from '../failedModal.svelte'; import SendModal from './sendModal.svelte'; import ScheduleModal from './scheduleModal.svelte'; - + import CancelModal from './cancelModal.svelte'; + export let message: Models.Message & { data: Record }; export let topics: Models.Topic[]; let showSend = false; let showSchedule = false; + let showCancel = false; let showFailed = false; let errors: string[] = []; @@ -51,7 +53,7 @@ {:else if message.status === MessageStatus.Scheduled}
- +
{:else if message.status === 'failed'} @@ -70,4 +72,6 @@ + + From 16d24f93c2d77d6996f4fab4d74b90dbaf45173c Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Tue, 27 Feb 2024 10:21:46 -0800 Subject: [PATCH 20/21] feat(messaging): hide remove topic/target button for non-draft messages --- .../message-[message]/cancelModal.svelte | 6 +++- .../message-[message]/emailMessage.svelte | 14 ++++++-- .../message-[message]/overview.svelte | 2 +- .../message-[message]/updateTargets.svelte | 30 +++++++++-------- .../message-[message]/updateTopics.svelte | 33 ++++++++++--------- 5 files changed, 52 insertions(+), 33 deletions(-) diff --git a/src/routes/console/project-[project]/messaging/message-[message]/cancelModal.svelte b/src/routes/console/project-[project]/messaging/message-[message]/cancelModal.svelte index 504b67a54..17ab1bf15 100644 --- a/src/routes/console/project-[project]/messaging/message-[message]/cancelModal.svelte +++ b/src/routes/console/project-[project]/messaging/message-[message]/cancelModal.svelte @@ -83,7 +83,11 @@

Are you sure you want to cancel the scheduling of {message.data.title ?? message.data.subject ?? message.data.content ?? 'Message'}? + >{message.data.title ?? + message.data.subject ?? + message.data.content ?? + 'Message'}?

diff --git a/src/routes/console/project-[project]/messaging/message-[message]/emailMessage.svelte b/src/routes/console/project-[project]/messaging/message-[message]/emailMessage.svelte index d3b046d8c..7b4dc8338 100644 --- a/src/routes/console/project-[project]/messaging/message-[message]/emailMessage.svelte +++ b/src/routes/console/project-[project]/messaging/message-[message]/emailMessage.svelte @@ -3,7 +3,14 @@ import { trackEvent, Submit, trackError } from '$lib/actions/analytics'; import { CardGrid, Heading } from '$lib/components'; import { Dependencies } from '$lib/constants'; - import { Button, Form, FormList, InputSwitch, InputText, InputTextarea } from '$lib/elements/forms'; + import { + Button, + Form, + FormList, + InputSwitch, + InputText, + InputTextarea + } from '$lib/elements/forms'; import { addNotification } from '$lib/stores/notifications'; import { sdk } from '$lib/stores/sdk'; import { MessageStatus, type Models } from '@appwrite.io/console'; @@ -49,7 +56,10 @@ } } - $: disabled = subject === message.data.subject && content === message.data.content && html === (message.data['html'] ?? false) as boolean; + $: disabled = + subject === message.data.subject && + content === message.data.content && + html === ((message.data['html'] ?? false) as boolean); diff --git a/src/routes/console/project-[project]/messaging/message-[message]/overview.svelte b/src/routes/console/project-[project]/messaging/message-[message]/overview.svelte index d020e9b99..9c307ca1c 100644 --- a/src/routes/console/project-[project]/messaging/message-[message]/overview.svelte +++ b/src/routes/console/project-[project]/messaging/message-[message]/overview.svelte @@ -9,7 +9,7 @@ import SendModal from './sendModal.svelte'; import ScheduleModal from './scheduleModal.svelte'; import CancelModal from './cancelModal.svelte'; - + export let message: Models.Message & { data: Record }; export let topics: Models.Topic[]; diff --git a/src/routes/console/project-[project]/messaging/message-[message]/updateTargets.svelte b/src/routes/console/project-[project]/messaging/message-[message]/updateTargets.svelte index c4a1ca0db..4252511c5 100644 --- a/src/routes/console/project-[project]/messaging/message-[message]/updateTargets.svelte +++ b/src/routes/console/project-[project]/messaging/message-[message]/updateTargets.svelte @@ -143,20 +143,22 @@ -
- -
+ {#if message.status === MessageStatus.Draft} +
+ +
+ {/if}
{/each} diff --git a/src/routes/console/project-[project]/messaging/message-[message]/updateTopics.svelte b/src/routes/console/project-[project]/messaging/message-[message]/updateTopics.svelte index 96dd7ab4c..26d18021d 100644 --- a/src/routes/console/project-[project]/messaging/message-[message]/updateTopics.svelte +++ b/src/routes/console/project-[project]/messaging/message-[message]/updateTopics.svelte @@ -123,24 +123,27 @@ ({getTotal(topic)} targets) - + + -
- -
+ {#if message.status === MessageStatus.Draft} +
+ +
+ {/if}
{/each} From 6d0177322e26b7ad4b1afcd44f966f0e03d7e656 Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Tue, 27 Feb 2024 14:46:23 -0800 Subject: [PATCH 21/21] refactor(messaging): refactor date handling into reusable date functions --- package.json | 6 +-- src/lib/helpers/date.ts | 32 ++++++++++++++ .../message-[message]/scheduleModal.svelte | 18 ++++---- .../messaging/wizard/step3.svelte | 12 +++--- tests/unit/helpers/date.test.ts | 42 +++++++++++++++++-- 5 files changed, 86 insertions(+), 24 deletions(-) diff --git a/package.json b/package.json index 07f589ab2..4b34c64da 100644 --- a/package.json +++ b/package.json @@ -12,9 +12,9 @@ "check:watch": "svelte-check --tsconfig ./tsconfig.json --watch", "lint": "prettier --check . && eslint .", "format": "prettier --write .", - "test": "vitest run", - "test:ui": "vitest --ui", - "test:watch": "vitest watch", + "test": "TZ=EST vitest run", + "test:ui": "TZ=EST vitest --ui", + "test:watch": "TZ=EST vitest watch", "e2e": "playwright test tests/e2e" }, "dependencies": { diff --git a/src/lib/helpers/date.ts b/src/lib/helpers/date.ts index c8aaf0fc8..d0802c9cc 100644 --- a/src/lib/helpers/date.ts +++ b/src/lib/helpers/date.ts @@ -41,6 +41,38 @@ export const toLocaleDateTime = (datetime: string | number) => { return date.toLocaleDateString('en', options); }; +/** + * Returns a date string usig the local timezone in ISO format (yyyy-mm-dd) + * + * @param datetime date string or milliseconds since the epoch + */ +export const toLocaleDateISO = (datetime: string | number) => { + const date = new Date(datetime); + + if (isNaN(date.getTime())) { + return 'n/a'; + } + + // Use Sweden's locale (sv) since it matches ISO format + return date.toLocaleDateString('sv'); +}; + +/** + * Returns a time string usig the local timezone in ISO format (hh:mm:ss) + * + * @param datetime date string or milliseconds since the epoch + */ +export const toLocaleTimeISO = (datetime: string | number) => { + const date = new Date(datetime); + + if (isNaN(date.getTime())) { + return 'n/a'; + } + + // Use Sweden's locale (sv) since it matches ISO format + return date.toLocaleTimeString('sv'); +}; + export const isSameDay = (date1: Date, date2: Date) => { return ( date1.getFullYear() === date2.getFullYear() && diff --git a/src/routes/console/project-[project]/messaging/message-[message]/scheduleModal.svelte b/src/routes/console/project-[project]/messaging/message-[message]/scheduleModal.svelte index 1b81dbd4c..f3fd47088 100644 --- a/src/routes/console/project-[project]/messaging/message-[message]/scheduleModal.svelte +++ b/src/routes/console/project-[project]/messaging/message-[message]/scheduleModal.svelte @@ -7,19 +7,17 @@ import { Submit, trackEvent, trackError } from '$lib/actions/analytics'; import { MessageStatus, MessagingProviderType, type Models } from '@appwrite.io/console'; import { Dependencies } from '$lib/constants'; + import { isSameDay, toLocaleDateISO, toLocaleTimeISO } from '$lib/helpers/date'; export let show = false; export let message: Models.Message & { data: Record }; export let topics: Models.Topic[]; let now = new Date(); - let timeZoneOffset: number; let minDate: string; // Use Sweden's locale (sv) since it matches ISO format - let date = - message.scheduledAt == null ? null : new Date(message.scheduledAt).toLocaleDateString('sv'); - let time = - message.scheduledAt == null ? null : new Date(message.scheduledAt).toLocaleTimeString('sv'); + let date = message.scheduledAt == null ? null : toLocaleDateISO(message.scheduledAt); + let time = message.scheduledAt == null ? null : toLocaleTimeISO(message.scheduledAt); let dateTime: Date; let totalTargets = message.targets?.length ?? 0; @@ -109,12 +107,10 @@ } }; - $: timeZoneOffset = now ? now.getTimezoneOffset() * 60 * 1000 : 0; - $: minDate = new Date(now.getTime() - timeZoneOffset).toISOString().split('T')[0]; - $: minTime = - date === minDate - ? new Date(now.getTime() - timeZoneOffset).toISOString().split('T')[1].substring(0, 5) - : '00:00'; + $: minDate = toLocaleDateISO(now.getTime()); + $: minTime = isSameDay(new Date(date), new Date(minDate)) + ? toLocaleTimeISO(now.getTime()) + : '00:00'; $: dateTime = new Date(`${date}T${time}`); diff --git a/src/routes/console/project-[project]/messaging/wizard/step3.svelte b/src/routes/console/project-[project]/messaging/wizard/step3.svelte index c7ee27769..078943bbf 100644 --- a/src/routes/console/project-[project]/messaging/wizard/step3.svelte +++ b/src/routes/console/project-[project]/messaging/wizard/step3.svelte @@ -4,10 +4,10 @@ import { WizardStep } from '$lib/layout'; import { MessageStatus, MessagingProviderType } from '@appwrite.io/console'; import { messageParams, providerType } from './store'; + import { isSameDay, toLocaleDateISO, toLocaleTimeISO } from '$lib/helpers/date'; let when: 'now' | 'later' = 'now'; let now = new Date(); - let timeZoneOffset: number; let minDate: string; let date: string; let time: string; @@ -53,12 +53,10 @@ $: if (when === 'later') { now = new Date(); } - $: timeZoneOffset = now ? now.getTimezoneOffset() * 60 * 1000 : 0; - $: minDate = new Date(now.getTime() - timeZoneOffset).toISOString().split('T')[0]; - $: minTime = - date === minDate - ? new Date(now.getTime() - timeZoneOffset).toISOString().split('T')[1].substring(0, 5) - : '00:00'; + $: minDate = toLocaleDateISO(now.getTime()); + $: minTime = isSameDay(new Date(date), new Date(minDate)) + ? toLocaleTimeISO(now.getTime()) + : '00:00'; $: dateTime = new Date(`${date}T${time}`); $: if (!isNaN(dateTime.getTime())) { $messageParams[$providerType].scheduledAt = dateTime.toISOString(); diff --git a/tests/unit/helpers/date.test.ts b/tests/unit/helpers/date.test.ts index fab13619a..d28106973 100644 --- a/tests/unit/helpers/date.test.ts +++ b/tests/unit/helpers/date.test.ts @@ -4,13 +4,16 @@ import { toLocaleDateTime, isSameDay, isValidDate, - diffDays + diffDays, + toLocaleDateISO, + toLocaleTimeISO } from '$lib/helpers/date'; describe('local date', () => { [ ['2022-11-15 08:26:28', 'Nov 15, 2022'], - ['2022-11-15 00:26:28', 'Nov 15, 2022'] + ['2022-11-15 00:26:28', 'Nov 15, 2022'], + ['2022-11-15 00:26:28Z', 'Nov 14, 2022'] ].forEach(([value, expected]) => { it(value, () => { expect(toLocaleDate(value)).toBe(expected); @@ -25,7 +28,8 @@ describe('local date', () => { describe('local date time', () => { [ ['2022-11-15 08:26:28', 'Nov 15, 2022, 08:26'], - ['2022-11-15 00:26:28', 'Nov 15, 2022, 00:26'] + ['2022-11-15 00:26:28', 'Nov 15, 2022, 00:26'], + ['2022-11-15 00:26:28Z', 'Nov 14, 2022, 19:26'] ].forEach(([value, expected]) => { it(value, () => { expect(toLocaleDateTime(value)).toBe(expected); @@ -37,6 +41,38 @@ describe('local date time', () => { }); }); +describe('local date ISO', () => { + [ + ['2022-11-15 20:26:28Z', '2022-11-15'], + ['2022-11-15 08:26:28Z', '2022-11-15'], + ['2022-11-16 00:26:28Z', '2022-11-15'] + ].forEach(([value, expected]) => { + it(value, () => { + expect(toLocaleDateISO(value)).toBe(expected); + }); + }); + + it('invalid date', () => { + expect(toLocaleDateISO('')).toBe('n/a'); + }); +}); + +describe('local time ISO', () => { + [ + ['2022-11-15 20:26:28Z', '15:26:28'], + ['2022-11-15 08:26:28Z', '03:26:28'], + ['2022-11-16 00:26:28Z', '19:26:28'] + ].forEach(([value, expected]) => { + it(value, () => { + expect(toLocaleTimeISO(value)).toBe(expected); + }); + }); + + it('invalid date', () => { + expect(toLocaleTimeISO('')).toBe('n/a'); + }); +}); + describe('is same day', () => { const entries: Array<[string, string, boolean]> = [ ['2022-11-15 08:26:28', '2022-11-15 08:26:28', true],