Add Sites waitlist functionality

- Create waitlist store with join/check functions
- Add waitlist UI with join button and success state
- Conditionally show Sites based on org and live status
- Store waitlist status in user prefs and session storage
This commit is contained in:
Torsten Dittmann
2025-06-03 17:38:24 +02:00
parent 745a5964c4
commit 4ea999871f
4 changed files with 82 additions and 15 deletions
+30
View File
@@ -0,0 +1,30 @@
import { get } from 'svelte/store';
import { user } from '$lib/stores/user';
import { sdk } from '$lib/stores/sdk';
const userPreferences = () => get(user)?.prefs;
export const joinWaitlistSites = () => {
const prefs = userPreferences();
const newPrefs = {
...prefs,
joinWaitlistSites: true
};
sdk.forConsole.account.updatePrefs(newPrefs);
if (sessionStorage) {
sessionStorage.setItem('joinWaitlistSites', 'true');
}
};
export const isOnWaitlistSites = (): boolean => {
const prefs = userPreferences();
const joinedInPrefs = 'joinWaitlistSites' in prefs;
let joinedInSession = false;
if (sessionStorage) {
joinedInSession = sessionStorage.getItem('joinWaitlistSites') === 'true';
}
return joinedInSession || joinedInPrefs;
};
@@ -1,12 +1,16 @@
import Breadcrumbs from './breadcrumbs.svelte';
import Header from './header.svelte';
import { Dependencies } from '$lib/constants';
import { isCloud } from '$lib/system';
export const load = async ({ depends }) => {
export const load = async ({ depends, parent }) => {
const { organization } = await parent();
depends(Dependencies.SITES);
const sitesLive = !isCloud || organization.$id === 'appwriteOfficials';
return {
header: Header,
breadcrumbs: Breadcrumbs
header: sitesLive ? Header : undefined,
breadcrumbs: Breadcrumbs,
sitesLive
};
};
@@ -29,10 +29,13 @@
import { Dependencies } from '$lib/constants';
import { sdk } from '$lib/stores/sdk';
import { isSmallViewport } from '$lib/stores/viewport';
import { isOnWaitlistSites, joinWaitlistSites } from '$lib/stores/waitlist';
import { addNotification } from '$lib/stores/notifications';
export let data;
let show = false;
let isOnWaitlist = isOnWaitlistSites();
$: $registerCommands([
{
@@ -68,6 +71,16 @@
? EmptyLightMobile
: EmptyLight;
$: imgClass = $isSmallViewport ? 'mobile' : 'desktop';
function addToWaitlist() {
joinWaitlistSites();
addNotification({
type: 'success',
title: 'Waitlist joined',
message: "We'll let you know as soon as Appwrite Sites is ready for you."
});
isOnWaitlist = true;
}
</script>
<Container>
@@ -120,18 +133,37 @@
<img src={imgSrc} alt="create" aria-hidden="true" height="242" class={imgClass} />
<Layout.Stack>
<Layout.Stack gap="m" alignItems="center">
{#if isOnWaitlist}
<Typography.Title size="s" align="center" color="--fgcolor-neutral-primary">
Appwrite Sites is in high demand
You've successfully joined the Sites waitlist
</Typography.Title>
<div style:max-width="600px">
<Typography.Text align="center" color="--fgcolor-neutral-secondary">
To ensure a smooth experience for everyone, were rolling out access
gradually.
</Typography.Text>
</div>
</Layout.Stack>
<Typography.Text align="center" color="--fgcolor-neutral-secondary">
We can't wait for you to try out Sites on Cloud. You will get access
soon.
</Typography.Text>
{:else}
<Layout.Stack gap="m" alignItems="center">
<Typography.Title
size="s"
align="center"
color="--fgcolor-neutral-primary">
Appwrite Sites is in high demand
</Typography.Title>
<div style:max-width="600px">
<Typography.Text align="center" color="--fgcolor-neutral-secondary">
To ensure a smooth experience for everyone, were rolling out
access gradually. Join the waitlist and be one of the first to
deploy with Sites.
</Typography.Text>
</div>
<div style:margin-block-start="1rem">
<Button on:click={addToWaitlist}>Join waitlist</Button>
</div>
</Layout.Stack>
{/if}
</Layout.Stack>
</Layout.Stack>
</Card.Base>
@@ -2,8 +2,11 @@ import { Query, type Models } from '@appwrite.io/console';
import { sdk } from '$lib/stores/sdk';
import { getLimit, getPage, getSearch, getView, pageToOffset, View } from '$lib/helpers/load';
import { CARD_LIMIT, Dependencies } from '$lib/constants';
import type { PageLoad } from './$types';
export const load: PageLoad = async ({ url, depends, route, params, parent }) => {
const { sitesLive } = await parent();
export const load = async ({ url, depends, route, params }) => {
depends(Dependencies.SITES);
const page = getPage(url);
const search = getSearch(url);
@@ -11,8 +14,6 @@ export const load = async ({ url, depends, route, params }) => {
const offset = pageToOffset(page, limit);
const view = getView(url, route, View.Grid, View.Grid);
const sitesLive = false;
if (!sitesLive)
return {
sitesLive,