From 5019d4c2f898ff3efca6c1c346513eb7d6c9c132 Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Mon, 8 Jan 2024 16:46:31 -0800 Subject: [PATCH 01/12] Add a route to show user targets There's some code for creating a target, but it must go through design first. --- src/lib/actions/analytics.ts | 2 + src/lib/constants.ts | 1 + .../auth/user-[user]/header.svelte | 5 + .../auth/user-[user]/targets/+page.svelte | 118 ++++++++++++ .../auth/user-[user]/targets/+page.ts | 83 ++++++++ .../auth/user-[user]/targets/create.svelte | 146 +++++++++++++++ .../auth/user-[user]/targets/store.ts | 10 + .../auth/user-[user]/targets/table.svelte | 177 ++++++++++++++++++ 8 files changed, 542 insertions(+) create mode 100644 src/routes/console/project-[project]/auth/user-[user]/targets/+page.svelte create mode 100644 src/routes/console/project-[project]/auth/user-[user]/targets/+page.ts create mode 100644 src/routes/console/project-[project]/auth/user-[user]/targets/create.svelte create mode 100644 src/routes/console/project-[project]/auth/user-[user]/targets/store.ts create mode 100644 src/routes/console/project-[project]/auth/user-[user]/targets/table.svelte diff --git a/src/lib/actions/analytics.ts b/src/lib/actions/analytics.ts index 39551514b2..44ad9b0da0 100644 --- a/src/lib/actions/analytics.ts +++ b/src/lib/actions/analytics.ts @@ -161,6 +161,8 @@ export enum Submit { UserUpdateStatus = 'submit_user_update_status', UserUpdateVerificationEmail = 'submit_user_update_verification_email', UserUpdateVerificationPhone = 'submit_user_update_verification_phone', + UserTargetCreate = 'submit_user_target_create', + UserTargetDelete = 'submit_user_target_delete', OrganizationCreate = 'submit_organization_create', OrganizationDelete = 'submit_organization_delete', OrganizationUpdateName = 'submit_organization_update_name', diff --git a/src/lib/constants.ts b/src/lib/constants.ts index da342ce92c..260bae7f1c 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -16,6 +16,7 @@ export enum Dependencies { ACCOUNT_SESSIONS = 'dependency:account_sessions', USER = 'dependency:user', USERS = 'dependency:users', + USER_TARGETS = 'dependency:user_targets', SESSIONS = 'dependency:sessions', TEAM = 'dependency:team', TEAMS = 'dependency:teams', diff --git a/src/routes/console/project-[project]/auth/user-[user]/header.svelte b/src/routes/console/project-[project]/auth/user-[user]/header.svelte index 06f7d48f2e..e3e0641fc9 100644 --- a/src/routes/console/project-[project]/auth/user-[user]/header.svelte +++ b/src/routes/console/project-[project]/auth/user-[user]/header.svelte @@ -19,6 +19,11 @@ title: 'Memberships', event: 'memberships' }, + { + href: `${path}/targets`, + title: 'Targets', + event: 'targets' + }, { href: `${path}/sessions`, title: 'Sessions', diff --git a/src/routes/console/project-[project]/auth/user-[user]/targets/+page.svelte b/src/routes/console/project-[project]/auth/user-[user]/targets/+page.svelte new file mode 100644 index 0000000000..e47d65f9d1 --- /dev/null +++ b/src/routes/console/project-[project]/auth/user-[user]/targets/+page.svelte @@ -0,0 +1,118 @@ + + + +
+
+ Targets +
+ +
+
+ + + +
+ +
+ +
+ +
+
+
+
+
+ + +
+
+ + +
+
+
+ {#if data.targets.total} + + + + {:else if $hasPageQueries} + + {:else if data.search} + +
+ Sorry, we couldn't find '{data.search}' +

There are no targets that match your search.

+
+ +
+ {:else} + + (showAdd = true)} + href="https://appwrite.io/docs/references/cloud/client-web/teams" + target="subscriber" /> + {/if} + + + (showAdd = false)} /> + diff --git a/src/routes/console/project-[project]/auth/user-[user]/targets/+page.ts b/src/routes/console/project-[project]/auth/user-[user]/targets/+page.ts new file mode 100644 index 0000000000..55a04e0f56 --- /dev/null +++ b/src/routes/console/project-[project]/auth/user-[user]/targets/+page.ts @@ -0,0 +1,83 @@ +import { Query } from '@appwrite.io/console'; +import { sdk } from '$lib/stores/sdk'; +import { getLimit, getPage, getQuery, getSearch, pageToOffset } from '$lib/helpers/load'; +import { Dependencies, PAGE_LIMIT } from '$lib/constants'; +import type { PageLoad } from './$types'; +import { queryParamToMap, queries } from '$lib/components/filters'; +import type { Provider, Target } from '$routes/console/project-[project]/messaging/store'; + +export const load: PageLoad = async ({ params, url, route, depends }) => { + depends(Dependencies.USER_TARGETS); + const page = getPage(url); + const limit = getLimit(url, route, PAGE_LIMIT); + const offset = pageToOffset(page, limit); + const search = getSearch(url); + const query = getQuery(url); + + const parsedQueries = queryParamToMap(query || '[]'); + queries.set(parsedQueries); + + const payload = { + queries: [ + Query.limit(limit), + Query.offset(offset), + Query.orderDesc(''), + ...parsedQueries.values() + ] + }; + + if (search) { + payload['search'] = search; + } + + // TODO: remove when the API is ready with data + // This allows us to mock w/ data and when search returns 0 results + const targets: { targets: Target[]; total: number } = + await sdk.forProject.client.call( + 'GET', + new URL( + `${sdk.forProject.client.config.endpoint}/users/${params.user}/targets` + ), + { + 'X-Appwrite-Project': sdk.forProject.client.config.project, + 'content-type': 'application/json', + 'X-Appwrite-Mode': 'admin' + }, + payload + ); + + const promisesById: Record> = {}; + targets.targets.forEach((target) => { + if (target.providerId && !promisesById[target.providerId]) { + promisesById[target.providerId] = sdk.forProject.client.call( + 'GET', + new URL( + `${sdk.forProject.client.config.endpoint}/messaging/providers/${target.providerId}` + ), + { + 'X-Appwrite-Project': sdk.forProject.client.config.project, + 'content-type': 'application/json', + 'X-Appwrite-Mode': 'admin' + } + ); + } + }); + + const providersById: Record = {}; + const resolved = await Promise.allSettled(Object.values(promisesById)); + resolved.forEach((result) => { + if (result.status === 'fulfilled') { + const provider = result.value; + providersById[provider.$id] = provider; + } + }); + + return { + offset, + limit, + search, + query, + targets, + providersById, + }; +}; diff --git a/src/routes/console/project-[project]/auth/user-[user]/targets/create.svelte b/src/routes/console/project-[project]/auth/user-[user]/targets/create.svelte new file mode 100644 index 0000000000..d8973633cf --- /dev/null +++ b/src/routes/console/project-[project]/auth/user-[user]/targets/create.svelte @@ -0,0 +1,146 @@ + + + + + + {#if providerType === ProviderTypes.Push} + + + + {:else if providerType === ProviderTypes.Email} + + {:else if providerType === ProviderTypes.Sms} + + {/if} + + {#if !showCustomId} +
+ (showCustomId = !showCustomId)} + > +
+ {:else} + + {/if} +
+ + + + +
diff --git a/src/routes/console/project-[project]/auth/user-[user]/targets/store.ts b/src/routes/console/project-[project]/auth/user-[user]/targets/store.ts new file mode 100644 index 0000000000..425b4ccbd4 --- /dev/null +++ b/src/routes/console/project-[project]/auth/user-[user]/targets/store.ts @@ -0,0 +1,10 @@ +import type { Column } from '$lib/helpers/types'; +import { writable } from 'svelte/store'; + +export const columns = writable([ + { id: '$id', title: 'Target ID', type: 'string', show: true, width: 140 }, + { id: 'target', title: 'Target', type: 'string', show: true, filter: false, width: 140 }, + { id: 'providerType', title: 'Type', type: 'string', show: true, filter: true, width: 80 }, + { id: 'provider', title: 'Provider', type: 'string', show: true, filter: false, width: 80 }, + { id: '$createdAt', title: 'Created', type: 'string', show: true, width: 100 } +]); diff --git a/src/routes/console/project-[project]/auth/user-[user]/targets/table.svelte b/src/routes/console/project-[project]/auth/user-[user]/targets/table.svelte new file mode 100644 index 0000000000..7382c498b9 --- /dev/null +++ b/src/routes/console/project-[project]/auth/user-[user]/targets/table.svelte @@ -0,0 +1,177 @@ + + + + + d.$id)} /> + {#each $columns as column} + {#if column.show} + {column.title} + {/if} + {/each} + + + {#each data.targets.targets as target (target.$id)} + {@const provider = data.providersById[target.providerId]} + + + + {#each $columns as column} + {#if column.show} + {#if column.id === '$id'} + {#key $columns} + + + {target[column.id]} + + + {/key} + {:else if column.id === 'target'} + + {#if target.providerType === ProviderTypes.Push} + {target.name} + {:else} + {target.identifier} + {/if} + + {:else if column.id === 'providerType'} + + + + {:else if column.id === 'provider'} + + {#if provider} + + {/if} + + {:else if column.id === '$createdAt'} + + {toLocaleDateTime(target[column.id])} + + {:else} + + {target[column.id]} + + {/if} + {/if} + {/each} + + {/each} + + + + 0}> +
+
+ {selectedIds.length} +

+ + {selectedIds.length > 1 ? 'subscribers' : 'subscriber'} + + selected +

+
+ +
+ + +
+
+
+ + +

+ Are you sure you want to delete {selectedIds.length} + {selectedIds.length > 1 ? 'targets' : 'target'}? +

+ + + + +
From 0cb05f1180fb27c2cff112aa7a3063707c3a9140 Mon Sep 17 00:00:00 2001 From: Steven Nguyen Date: Thu, 11 Jan 2024 01:57:30 +0000 Subject: [PATCH 02/12] Allow topics with empty string We must pass undefined because the server won't accept an empty string. Undefined will make the server use the default value, which is an empty string. --- .../project-[project]/messaging/topics/create.svelte | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/routes/console/project-[project]/messaging/topics/create.svelte b/src/routes/console/project-[project]/messaging/topics/create.svelte index 2bb52245e2..3d9dd416e3 100644 --- a/src/routes/console/project-[project]/messaging/topics/create.svelte +++ b/src/routes/console/project-[project]/messaging/topics/create.svelte @@ -1,8 +1,8 @@ -

Grant access to any authenticated or anonymous user.

+

Select recipients for this message from your users.

Date: Thu, 18 Jan 2024 00:07:53 +0000 Subject: [PATCH 09/12] Remove bullet points from the topics modal --- .../messaging/topicsModal.svelte | 42 ++++++++++--------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/src/routes/console/project-[project]/messaging/topicsModal.svelte b/src/routes/console/project-[project]/messaging/topicsModal.svelte index f1141b26e0..7285cb44d0 100644 --- a/src/routes/console/project-[project]/messaging/topicsModal.svelte +++ b/src/routes/console/project-[project]/messaging/topicsModal.svelte @@ -1,9 +1,9 @@ @@ -127,6 +131,7 @@ $: sortedSteps = [...steps].sort(([a], [b]) => (a > b ? 1 : -1)); $: isLastStep = $wizard.step === steps.size; + $: currentStep = steps.get($wizard.step); @@ -175,7 +180,7 @@ {/each}