diff --git a/src/lib/actions/analytics.ts b/src/lib/actions/analytics.ts index 8a15993fcf..2b71457969 100644 --- a/src/lib/actions/analytics.ts +++ b/src/lib/actions/analytics.ts @@ -287,5 +287,8 @@ export enum Submit { SmsResetTemplate = 'submit_sms_reset_template', SmsUpdateInviteTemplate = 'submit_sms_update_invite_template', SmsUpdateLoginTemplate = 'submit_sms_update_login_template', - SmsUpdateVerificationTemplate = 'submit_sms_update_verification_template' + SmsUpdateVerificationTemplate = 'submit_sms_update_verification_template', + MessagingProviderCreate = 'submit_messaging_provider_create', + MessagingProviderDelete = 'submit_messaging_provider_delete', + MessagingProviderUpdate = 'submit_messaging_provider_update' } diff --git a/src/lib/components/drop.svelte b/src/lib/components/drop.svelte index d6c899df21..f61ff6a246 100644 --- a/src/lib/components/drop.svelte +++ b/src/lib/components/drop.svelte @@ -13,6 +13,7 @@ export let noStyle = false; export let fullWidth = false; export let fixed = false; + export let display = 'block'; const dispatch = createEventDispatcher<{ blur: undefined; @@ -100,7 +101,11 @@ -
+
diff --git a/src/lib/components/labelCard.svelte b/src/lib/components/labelCard.svelte index 9d30f9b0c1..461e5a53f7 100644 --- a/src/lib/components/labelCard.svelte +++ b/src/lib/components/labelCard.svelte @@ -1,5 +1,7 @@ + + +
+
+ Providers +
+ +
+
+ + +
+ + + +
+
+
+
+ + +
+
+ + +
+
+
+ {#if data.providers.total} + + + + {:else if data.search && data.search != 'empty'} + +
+ Sorry, we couldn't find '{data.search}' +

There are no providers that match your search.

+
+ +
+ {:else} + + +
+ + Create your first provider to get started. + +

+ Need a hand? Learn more in our documentation. +

+
+
+ + + + +
+
+ {/if} + diff --git a/src/routes/console/project-[project]/messaging/providers/+page.ts b/src/routes/console/project-[project]/messaging/providers/+page.ts new file mode 100644 index 0000000000..45f465b7d3 --- /dev/null +++ b/src/routes/console/project-[project]/messaging/providers/+page.ts @@ -0,0 +1,77 @@ +import { Query } from '@appwrite.io/console'; +import { sdk } from '$lib/stores/sdk'; +import { + View, + getLimit, + getPage, + getQuery, + getSearch, + getView, + pageToOffset +} from '$lib/helpers/load'; +import { Dependencies, PAGE_LIMIT } from '$lib/constants'; +import { providersById, type Provider } from '../store'; +import { queries, queryParamToMap } from '$lib/components/filters/store'; + +const providers = Object.values(providersById); + +let data: { providers: Provider[]; total: number } = { + providers: [...providers], + total: providers.length +}; + +export const load = async ({ depends, url, route }) => { + depends(Dependencies.MESSAGING_PROVIDERS); + + const page = getPage(url); + const search = getSearch(url); + const view = getView(url, route, View.Grid); + const limit = getLimit(url, route, PAGE_LIMIT); + const offset = pageToOffset(page, limit); + const query = getQuery(url); + + const parsedQueries = queryParamToMap(query || '[]'); + queries.set(parsedQueries); + + // TODO: get rid of demo data + let providers: { providers: Provider[]; total: number } = { providers: [], total: 0 }; + if (search == 'demo') { + providers = data; + } else { + const params = { + queries: [ + Query.limit(limit), + Query.offset(offset), + Query.orderDesc(''), + ...parsedQueries.values() + ] + }; + + if (search) { + params['search'] = search; + } + + const response = await sdk.forProject.client.call( + 'GET', + new URL(sdk.forProject.client.config.endpoint + '/messaging/providers'), + { + 'X-Appwrite-Project': sdk.forProject.client.config.project, + 'content-type': 'application/json', + 'X-Appwrite-Mode': 'admin' + }, + params + ); + + providers = response; + } + + return { + offset, + limit, + search, + query, + page, + view, + providers + }; +}; diff --git a/src/routes/console/project-[project]/messaging/providers/create.svelte b/src/routes/console/project-[project]/messaging/providers/create.svelte new file mode 100644 index 0000000000..d828be10c8 --- /dev/null +++ b/src/routes/console/project-[project]/messaging/providers/create.svelte @@ -0,0 +1,274 @@ + + + diff --git a/src/routes/console/project-[project]/messaging/providers/createProviderDropdown.svelte b/src/routes/console/project-[project]/messaging/providers/createProviderDropdown.svelte new file mode 100644 index 0000000000..e829f4927c --- /dev/null +++ b/src/routes/console/project-[project]/messaging/providers/createProviderDropdown.svelte @@ -0,0 +1,49 @@ + + + + + + + + {#each Object.entries(providers) as [type, option]} + { + if ( + type !== ProviderTypes.Email && + type !== ProviderTypes.Sms && + type !== ProviderTypes.Push + ) + return; + $providerType = type; + const p = Object.keys(providers[type].providers).shift(); + if (p && isValueOfStringEnum(Providers, p)) { + $provider = p; + } + showCreateDropdown = false; + wizard.start(Create); + }}> + {option.name} + + {/each} + + diff --git a/src/routes/console/project-[project]/messaging/providers/provider-[provider]/+layout.svelte b/src/routes/console/project-[project]/messaging/providers/provider-[provider]/+layout.svelte new file mode 100644 index 0000000000..944197a93a --- /dev/null +++ b/src/routes/console/project-[project]/messaging/providers/provider-[provider]/+layout.svelte @@ -0,0 +1,5 @@ + + Provider - Appwrite + + + diff --git a/src/routes/console/project-[project]/messaging/providers/provider-[provider]/+layout.ts b/src/routes/console/project-[project]/messaging/providers/provider-[provider]/+layout.ts new file mode 100644 index 0000000000..07531b6b5f --- /dev/null +++ b/src/routes/console/project-[project]/messaging/providers/provider-[provider]/+layout.ts @@ -0,0 +1,31 @@ +import type { LayoutLoad } from './$types'; +import Breadcrumbs from './breadcrumbs.svelte'; +import Header from './header.svelte'; +import { sdk } from '$lib/stores/sdk'; +import { Dependencies } from '$lib/constants'; +import { error } from '@sveltejs/kit'; + +export const load: LayoutLoad = async ({ params, depends }) => { + depends(Dependencies.MESSAGING_PROVIDER); + + const response = await sdk.forProject.client.call( + 'GET', + new URL(sdk.forProject.client.config.endpoint + '/messaging/providers/' + params.provider), + { + 'X-Appwrite-Project': sdk.forProject.client.config.project, + 'content-type': 'application/json', + 'X-Appwrite-Mode': 'admin' + } + ); + + + try { + return { + header: Header, + breadcrumbs: Breadcrumbs, + provider: response + }; + } catch (e) { + throw error(e.code, e.message); + } +}; diff --git a/src/routes/console/project-[project]/messaging/providers/provider-[provider]/+page.svelte b/src/routes/console/project-[project]/messaging/providers/provider-[provider]/+page.svelte new file mode 100644 index 0000000000..2262f62ac1 --- /dev/null +++ b/src/routes/console/project-[project]/messaging/providers/provider-[provider]/+page.svelte @@ -0,0 +1,12 @@ + + + + + + + diff --git a/src/routes/console/project-[project]/messaging/providers/provider-[provider]/breadcrumbs.svelte b/src/routes/console/project-[project]/messaging/providers/provider-[provider]/breadcrumbs.svelte new file mode 100644 index 0000000000..5a3f26f90d --- /dev/null +++ b/src/routes/console/project-[project]/messaging/providers/provider-[provider]/breadcrumbs.svelte @@ -0,0 +1,27 @@ + + + diff --git a/src/routes/console/project-[project]/messaging/providers/provider-[provider]/dangerZone.svelte b/src/routes/console/project-[project]/messaging/providers/provider-[provider]/dangerZone.svelte new file mode 100644 index 0000000000..7befc15c0e --- /dev/null +++ b/src/routes/console/project-[project]/messaging/providers/provider-[provider]/dangerZone.svelte @@ -0,0 +1,45 @@ + + + + + +
+ Delete provider +
+

The provider's instance will be permanently deleted. This action is irreversible.

+ + + +
{$provider.name}
+
+

+ Last updated: {toLocaleDateTime($provider.$updatedAt)} +

+
+
+ + + + +
+ + diff --git a/src/routes/console/project-[project]/messaging/providers/provider-[provider]/deleteProvider.svelte b/src/routes/console/project-[project]/messaging/providers/provider-[provider]/deleteProvider.svelte new file mode 100644 index 0000000000..e32cbf6aae --- /dev/null +++ b/src/routes/console/project-[project]/messaging/providers/provider-[provider]/deleteProvider.svelte @@ -0,0 +1,59 @@ + + + +

+ Are you sure you want to delete {$provider.name} from '{$project.name}'? +

+ + + + +
diff --git a/src/routes/console/project-[project]/messaging/providers/provider-[provider]/header.svelte b/src/routes/console/project-[project]/messaging/providers/provider-[provider]/header.svelte new file mode 100644 index 0000000000..d78a0f0d43 --- /dev/null +++ b/src/routes/console/project-[project]/messaging/providers/provider-[provider]/header.svelte @@ -0,0 +1,17 @@ + + + + + + {$provider?.name ? $provider?.name : '-'} + + {$provider?.$id} + + diff --git a/src/routes/console/project-[project]/messaging/providers/provider-[provider]/store.ts b/src/routes/console/project-[project]/messaging/providers/provider-[provider]/store.ts new file mode 100644 index 0000000000..a69272a70c --- /dev/null +++ b/src/routes/console/project-[project]/messaging/providers/provider-[provider]/store.ts @@ -0,0 +1,9 @@ +import { derived } from 'svelte/store'; +import { page } from '$app/stores'; +import type { Provider } from '../../store'; + +export const provider = derived( + page, + // TODO: Set actual type + ($page) => $page.data.provider as Provider +); diff --git a/src/routes/console/project-[project]/messaging/providers/provider-[provider]/updateName.svelte b/src/routes/console/project-[project]/messaging/providers/provider-[provider]/updateName.svelte new file mode 100644 index 0000000000..f77b626ca1 --- /dev/null +++ b/src/routes/console/project-[project]/messaging/providers/provider-[provider]/updateName.svelte @@ -0,0 +1,51 @@ + + +
+ + Name + + +
    + +
+
+ + + + +
+ diff --git a/src/routes/console/project-[project]/messaging/providers/provider-[provider]/updateStatus.svelte b/src/routes/console/project-[project]/messaging/providers/provider-[provider]/updateStatus.svelte new file mode 100644 index 0000000000..f4fddcc744 --- /dev/null +++ b/src/routes/console/project-[project]/messaging/providers/provider-[provider]/updateStatus.svelte @@ -0,0 +1,367 @@ + + + +
+ + {$provider.name} + +
+ +
+
+
    + +
+

Provider:

+

Channel:

+

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

+
+
+
+ + +
+ + +
+
+
diff --git a/src/routes/console/project-[project]/messaging/providers/store.ts b/src/routes/console/project-[project]/messaging/providers/store.ts new file mode 100644 index 0000000000..714db9d9a7 --- /dev/null +++ b/src/routes/console/project-[project]/messaging/providers/store.ts @@ -0,0 +1,381 @@ +import { writable } from 'svelte/store'; +import type { Column } from '$lib/helpers/types'; +import { Providers } from '../provider.svelte'; +import { ProviderTypes } from '../providerType.svelte'; + +export let showCreate = writable(false); + +export const columns = writable([ + { id: '$id', title: 'Provider ID', type: 'string', show: true }, + { id: 'name', title: 'Name', type: 'string', show: true }, + { id: 'provider', title: 'Provider', type: 'string', show: true }, + { id: 'type', title: 'Type', type: 'string', show: true }, + { id: 'enabled', title: 'Status', type: 'boolean', show: true } +]); + +type ProvidersMap = { + [key in ProviderTypes]: { + name: string; + text: string; + icon: string; + providers: { + [key in Providers]?: { + imageIcon: string; + title: string; + description: string; + configure: { + label: string; + name: string; + type: 'text' | 'phone' | 'email' | 'domain' | 'file' | 'switch'; + placeholder?: string; + description?: string; + popover?: string[]; + allowedFileExtensions?: string[]; + }[]; + }; + }; + }; +}; + +export const providers: ProvidersMap = { + [ProviderTypes.Sms]: { + name: 'SMS', + text: 'SMS', + icon: 'annotation', + providers: { + [Providers.Twilio]: { + imageIcon: 'twilio', + title: 'Twilio', + description: '', + configure: [ + { + label: 'Account SID', + name: 'accountSid', + type: 'text', + placeholder: 'Enter Account SID', + popover: [ + 'How to get the Account SID?', + 'Head to Twilio console -> Account info -> Account SID.' + ] + }, + { + label: 'Auth token', + name: 'authToken', + type: 'text', + placeholder: 'Enter Auth token', + popover: [ + 'How to get the Auth token?', + 'Head to Twilio console -> Account info -> Auth Token.' + ] + }, + { + label: 'Sender number', + name: 'from', + type: 'phone', + placeholder: 'Enter phone', + popover: [ + 'How to get sender number?', + 'Head to Twilio console -> Account info -> My Twilio phone number.', + 'If you have multiple Twilio phone numbers, you can select one as the default number.' + ] + } + ] + }, + [Providers.Msg91]: { + imageIcon: 'msg91', + title: 'MSG91', + description: '', + configure: [ + { + label: 'Auth key', + name: 'authKey', + type: 'text', + placeholder: 'Enter auth key', + popover: [ + 'How to get the Auth key?', + 'Create an account in MSG91.', + 'Click to open the Username dropdown -> Authkey -> Verify your mobile number -> Create Authkey.' + ] + }, + { + label: 'Sender ID', + name: 'senderId', + type: 'text', + placeholder: 'Enter sender ID', + popover: [ + 'How to create a Sender ID?', + 'Head to MSG91 dashboard -> SMS -> Sender ID -> Create sender ID.' + ] + }, + { + label: 'Sender number', + name: 'from', + type: 'phone', + placeholder: 'Enter phone' + } + ] + }, + [Providers.Telesign]: { + imageIcon: 'telesign', + title: 'Telesign', + description: '', + configure: [ + { + label: 'Username', + name: 'username', + type: 'text', + placeholder: 'Enter username' + }, + { + label: 'Password', + name: 'password', + type: 'text', + placeholder: 'Enter password' + }, + { + label: 'Sender number', + name: 'from', + type: 'phone', + placeholder: 'Enter phone' + } + ] + }, + [Providers.Textmagic]: { + imageIcon: 'textmagic', + title: 'Textmagic', + description: '', + configure: [ + { + label: 'API key', + name: 'apiKey', + type: 'text', + placeholder: 'Enter API key', + popover: [ + 'How to get the API key?', + 'Create an account in Textmagic.', + 'Head to TextMagic dashboard -> API Settings -> Add new API key.' + ] + }, + { + label: 'Username', + name: 'username', + type: 'text', + placeholder: 'Enter username' + }, + { + label: 'Sender number', + name: 'from', + type: 'phone', + placeholder: 'Enter phone' + } + ] + }, + [Providers.Vonage]: { + imageIcon: 'vonage', + title: 'Vonage', + description: '', + configure: [ + { + label: 'API key', + name: 'apiKey', + type: 'text', + placeholder: 'Enter API key', + popover: [ + 'How to get the API key?', + 'Create an account in Vonage.', + 'Head to Vonage dashboard and copy the API key.' + ] + }, + { + label: 'API secret', + name: 'apiSecret', + type: 'text', + placeholder: 'Enter API secret', + popover: [ + 'How to get the API secret?', + 'Head to Vonage dashboard and copy the API secret.' + ] + }, + { + label: 'Sender number', + name: 'from', + type: 'phone', + placeholder: 'Enter phone' + } + ] + } + } + }, + [ProviderTypes.Email]: { + name: 'Email', + text: 'emails', + icon: 'mail', + providers: { + [Providers.Mailgun]: { + imageIcon: 'mailgun', + title: 'Mailgun', + description: '', + configure: [ + { + label: 'API key', + name: 'apiKey', + type: 'text', + placeholder: 'Enter API key', + popover: [ + 'How to get the API key?', + 'Create an account in Mailgun.', + 'Head to Profile -> API Security -> Add new key.' + ] + }, + { + label: 'Domain', + name: 'domain', + type: 'domain', + placeholder: 'Enter domain', + popover: [ + 'How to create a domain?', + 'Head to Sending -> Domains -> Add new domain.', + 'Follow Mailgun instructions to verify the domain name.' + ] + }, + { + label: 'EU region', + name: 'isEuRegion', + type: 'switch', + description: + 'Enable the EU region setting if your domain is within the European Union.' + }, + { + label: 'Sender email', + name: 'from', + type: 'email', + placeholder: 'Enter email' + } + ] + }, + [Providers.Sendgrid]: { + imageIcon: 'sendgrid', + title: 'Sendgrid', + description: '', + configure: [ + { + label: 'API key', + name: 'apiKey', + type: 'text', + placeholder: 'Enter API key', + popover: [ + 'How to get the API key?', + 'Create an account in Mailgun.', + 'Head to Profile -> API Security -> Add new key.' + ] + }, + { + label: 'Sender email', + name: 'from', + type: 'email', + placeholder: 'Enter email' + } + ] + } + } + }, + [ProviderTypes.Push]: { + name: 'Push notification', + text: 'notifications', + icon: 'device-mobile', + providers: { + [Providers.FCM]: { + imageIcon: 'firebase', + title: 'FCM', + description: 'Firebase Cloud Messaging', + configure: [ + { + label: 'Server key (.json file)', + name: 'serverKey', + type: 'file', + allowedFileExtensions: ['json'], + placeholder: 'Enter server key', + popover: [ + 'How to get the FCM server key?', + 'Head to Project settings -> Service accounts -> Generate new private key.', + 'Generating the new key will result in the download of a JSON file.' + ] + } + ] + }, + [Providers.APNS]: { + imageIcon: 'apple', + title: 'APNS', + description: 'Apple Push Notification Service', + configure: [ + { + label: 'Team ID', + name: 'teamId', + type: 'text', + placeholder: 'Enter team ID', + popover: [ + 'How to get the team ID?', + 'Head to Apple Developer Member Center -> Membership details -> Team ID.' + ] + }, + { + label: 'Bundle ID', + name: 'bundleId', + type: 'text', + placeholder: 'Enter bundle ID', + popover: [ + 'How to get the bundle ID?', + 'Head to Apple Developer Member Center -> Certificates, Identifiers & Profiles -> Identifiers.', + ` +
+ Screenshot of Bundle ID in Apple +
+
+
+
+
+
` + ] + }, + { + label: 'Authentication key ID', + name: 'authKeyId', + type: 'text', + placeholder: 'Enter key ID', + popover: [ + 'How to get the auth key ID?', + 'Head to Apple Developer Member Center -> Certificates, Identifiers & Profiles -> Keys.', + 'Click on your key to view details.' + ] + }, + { + label: 'Auth key (.p8 file)', + name: 'authKey', + type: 'file', + allowedFileExtensions: ['p8'], + popover: [ + 'How to get the authentication key?', + 'Head to Apple Developer Member Center (under Program resources) -> Certificates, Identifiers & Profiles -> Keys.', + 'Create a key and give it a name. Enable the Apple Push Notifications service (APNS), and register your key.' + ] + } + ] + } + // [Providers.MQTT]: { + // imageIcon: 'mqtt', + // title: 'MQTT', + // description: 'Message Queuing Telemtry Transport' + // } + } + } +}; diff --git a/src/routes/console/project-[project]/messaging/providers/table.svelte b/src/routes/console/project-[project]/messaging/providers/table.svelte new file mode 100644 index 0000000000..2921c40ecf --- /dev/null +++ b/src/routes/console/project-[project]/messaging/providers/table.svelte @@ -0,0 +1,170 @@ + + + + + d.$id)} /> + {#each $columns as column} + {#if column.show} + {column.title} + {/if} + {/each} + + + {#each data.providers.providers as provider (provider.$id)} + + + {#each $columns as column} + {#if column.show} + {#if column.id === '$id'} + {#key $columns} + + {provider.$id} + + {/key} + {:else if column.id === 'provider'} + + + + {:else if column.id === 'type'} + + + + {:else if column.id === 'enabled'} + + + {#if provider.enabled} + + {/if} + + {provider.enabled ? 'enabled' : 'disabled'} + + + + {:else} + + {provider[column.id]} + + {/if} + {/if} + {/each} + + {/each} + + + + 0}> +
+
+ {selectedIds.length} +

+ + {selectedIds.length > 1 ? 'providers' : 'provider'} + + selected +

+
+ +
+ + +
+
+
+ + +

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

+ + + + +
diff --git a/src/routes/console/project-[project]/messaging/providers/update.svelte b/src/routes/console/project-[project]/messaging/providers/update.svelte new file mode 100644 index 0000000000..4f3c14c44f --- /dev/null +++ b/src/routes/console/project-[project]/messaging/providers/update.svelte @@ -0,0 +1,268 @@ + + + diff --git a/src/routes/console/project-[project]/messaging/providers/wizard/configure.svelte b/src/routes/console/project-[project]/messaging/providers/wizard/configure.svelte new file mode 100644 index 0000000000..404b4f69ad --- /dev/null +++ b/src/routes/console/project-[project]/messaging/providers/wizard/configure.svelte @@ -0,0 +1,147 @@ + + + + Configure + + Set up the credentials below to enable {providers[$providerType].providers[$provider].title} + for sending + {providers[$providerType].text}. + + + {#each inputs as input} + {#if input.type === 'text'} + + + {@html input.popover?.join('

')} +
+
+ {:else if input.type === 'email'} + + +

+ {@html input.popover?.join('

')} +

+
+
+ {:else if input.type === 'domain'} + + +

+ {@html input.popover?.join('

')} +

+
+
+ {:else if input.type === 'phone'} + + +

+ {@html input.popover?.join('

')} +

+
+
+ {:else if input.type === 'file'} + + +

+ {@html input.popover?.join('

')} +

+
+
+ {:else if input.type === 'switch'} + + + {input.description} + + + {/if} + {/each} +
+ +

Need a hand?

+ +
+
+
+
+ Read the full guide in the documentation +
+
+ +
+
+
+
+ Invite a team member to complete this step +
+
+
diff --git a/src/routes/console/project-[project]/messaging/providers/wizard/provider.svelte b/src/routes/console/project-[project]/messaging/providers/wizard/provider.svelte new file mode 100644 index 0000000000..1f9e238a1a --- /dev/null +++ b/src/routes/console/project-[project]/messaging/providers/wizard/provider.svelte @@ -0,0 +1,161 @@ + + + + Provider + + + + {#if !showCustomId} +
+ (showCustomId = !showCustomId)} + > +
+ {:else} + + {/if} +

+ Select a provider you would like to enable for sending {providers[$providerType].text}. +

+
+ {#each Object.entries(providers[$providerType].providers) as [value, option]} + + {option.title} + {#if option.description} + {option.description} + {/if} + + {/each} +
+
+
diff --git a/src/routes/console/project-[project]/messaging/providers/wizard/store.ts b/src/routes/console/project-[project]/messaging/providers/wizard/store.ts new file mode 100644 index 0000000000..9f47f8a41a --- /dev/null +++ b/src/routes/console/project-[project]/messaging/providers/wizard/store.ts @@ -0,0 +1,103 @@ +import type { Providers } from '../../provider.svelte'; +import type { ProviderTypes } from '../../providerType.svelte'; +import { writable } from 'svelte/store'; + +type ProviderParams = { + providerId: string; + name: string; + default: boolean; + enabled: boolean; +}; + +/** + * SMS providers + */ + +export type TwilioProviderParams = ProviderParams & { + accountSid: string; + authToken: string; + from: string; +}; + +export type Msg91ProviderParams = ProviderParams & { + from: string; + senderId: string; + authKey: string; +}; + +export type TelesignProviderParams = ProviderParams & { + from: string; + username: string; + password: string; +}; + +export type TextmagicProviderParams = ProviderParams & { + from: string; + username: string; + apiKey: string; +}; + +export type VonageProviderParams = ProviderParams & { + from: string; + apiKey: string; + apiSecret: string; +}; + +/** + * Email providers + */ + +export type MailgunProviderParams = ProviderParams & { + isEuRegion: boolean; + from: string; + apiKey: string; + domain: string; +}; + +export type SendgridProviderParams = ProviderParams & { + from: string; + apiKey: string; +}; + +/** + * Push providers + */ + +export type FCMProviderParams = ProviderParams & { + serverKey: string; +}; + +export type APNSProviderParams = ProviderParams & { + authKey: string; + authKeyId: string; + teamId: string; + bundleId: string; +}; + +export type MQTTProviderParams = ProviderParams & { + serverKey: string; +}; + +export const providerType = writable(null); +export const provider = writable(null); +export const providerParams = writable<{ + twilio: Partial; + msg91: Partial; + telesign: Partial; + textmagic: Partial; + vonage: Partial; + mailgun: Partial; + sendgrid: Partial; + fcm: Partial; + apns: Partial; +}>({ + twilio: null, + msg91: null, + telesign: null, + textmagic: null, + vonage: null, + mailgun: null, + sendgrid: null, + fcm: null, + apns: null +}); diff --git a/src/routes/console/project-[project]/messaging/providers/wizard/store.ts.bak b/src/routes/console/project-[project]/messaging/providers/wizard/store.ts.bak new file mode 100644 index 0000000000..0ee3ba46ca --- /dev/null +++ b/src/routes/console/project-[project]/messaging/providers/wizard/store.ts.bak @@ -0,0 +1,161 @@ +import { writable } from 'svelte/store'; +import type { Column } from '$lib/components/viewSelector.svelte'; + +export let showCreate = writable(false); + +export const columns = writable([ + { id: '$id', title: 'Provider ID', show: true }, + { id: 'name', title: 'Name', show: true }, + { id: 'provider', title: 'Provider', show: true }, + { id: 'channel', title: 'Channel', show: true }, + { id: 'status', title: 'Status', show: true } +]); + +export type Instruction = { + text: string; + input: { + label: string; + name: string; + type: 'text' | 'domain' | 'email'; + placeholder: string; + }; +}; + +export const providers = { + sms: { + name: 'SMS', + text: 'SMS', + icon: 'annotation', + providers: { + twilio: { + imageIcon: 'twilio', + title: 'Twilio', + description: '' + }, + msg91: { + imageIcon: 'msg91', + title: 'MSG91', + description: '' + }, + telesign: { + imageIcon: 'telesign', + title: 'Telesign', + description: '' + }, + textmagic: { + imageIcon: 'textmagic', + title: 'Textmagic', + description: '' + }, + vonage: { + imageIcon: 'vonage', + title: 'Vonage', + description: '' + } + } + }, + email: { + name: 'Email', + text: 'emails', + icon: 'mail', + providers: { + mailgun: { + imageIcon: 'mailgun', + title: 'Mailgun', + description: '', + initialize: [ + { + text: 'Before you can create a Mailgun provider, you need to first create a Mailgun account.' + }, + { + text: 'Head to your Profile > API Security.' + }, + { + text: 'Generate a key and give it a name. Copy and paste it in the field below.', + input: { + label: 'API key', + name: 'apiKey', + type: 'text', + placeholder: 'Enter API key' + } + }, + { + // TODO: Update link to domain verification + text: 'Head to Sending > Domains and click on \'Add New Domain\'. Verify your domain by following the instructions.', + input: { + label: 'Base URL', + name: 'baseUrl', + type: 'text', + placeholder: 'Enter base URL' + } + } + ], + configure: [ + { + text: 'Provide a display name your recipient will see when they receive your emails.', + input: { + label: 'From', + name: 'from', + type: 'text', + placeholder: 'Enter name' + } + }, + { + text: 'Provide an email address that will be visible to the recipient as the senders email address for this message.', + input: { + label: 'From email address', + name: 'email', + type: 'email', + placeholder: 'Enter email' + } + }, + { + text: 'Provide an email address for users to use when replying to your emails.', + input: { + label: 'Reply to', + name: 'replyTo', + type: 'email', + placeholder: 'Enter email' + } + }, + { + text: 'Provide the domain as it is registered on Mailgun.', + input: { + label: 'Domain', + name: 'domain', + type: 'domain', + placeholder: 'Enter domain' + } + } + ] + }, + sendgrid: { + imageIcon: 'sendgrid', + title: 'Sendgrid', + description: '' + } + } + }, + push: { + name: 'Push notification', + text: 'notifications', + icon: 'device-mobile', + providers: { + fcm: { + imageIcon: 'firebase', + title: 'FCM', + description: 'Firebase Cloud Messaging' + }, + apns: { + imageIcon: 'apple', + title: 'APNS', + description: 'Apple Push Notification Service' + }, + mqtt: { + imageIcon: 'mqtt', + title: 'MQTT', + description: 'Message Queuing Telemtry Transport' + } + } + } +}; diff --git a/static/images/apns-bundle-id.png b/static/images/apns-bundle-id.png new file mode 100644 index 0000000000..90fde1eff2 Binary files /dev/null and b/static/images/apns-bundle-id.png differ