From bab0941aa2b34460f2c9bec3447a0da9a70f3da7 Mon Sep 17 00:00:00 2001 From: Arman Date: Thu, 16 May 2024 17:43:12 +0200 Subject: [PATCH 01/43] feat: credit flow --- src/lib/layout/unauthenticated.svelte | 97 ++++++++++++++++-- .../change-plan/+page.svelte | 3 + src/routes/login/+page.ts | 14 +++ static/images/3D-card-illust-dark.png | Bin 0 -> 139459 bytes static/images/3D-card-illust-light.png | Bin 0 -> 129690 bytes 5 files changed, 108 insertions(+), 6 deletions(-) create mode 100644 src/routes/login/+page.ts create mode 100644 static/images/3D-card-illust-dark.png create mode 100644 static/images/3D-card-illust-light.png diff --git a/src/lib/layout/unauthenticated.svelte b/src/lib/layout/unauthenticated.svelte index 1ceb0057c..106a9aef1 100644 --- a/src/lib/layout/unauthenticated.svelte +++ b/src/lib/layout/unauthenticated.svelte @@ -1,4 +1,5 @@
-
@@ -82,6 +120,53 @@ diff --git a/src/routes/console/apply-credit/+page.ts b/src/routes/console/apply-credit/+page.ts index d29101ba0..0c0762b5e 100644 --- a/src/routes/console/apply-credit/+page.ts +++ b/src/routes/console/apply-credit/+page.ts @@ -14,7 +14,7 @@ export const load = async ({ url }) => { } } if (!couponData?.campaign) { - // redirect(303, `${base}/console`); + redirect(303, `${base}/console`); } return { From 4a4f2fe83aa85848ee8f6d06932d88af011a649b Mon Sep 17 00:00:00 2001 From: Arman Date: Mon, 27 May 2024 16:47:47 +0200 Subject: [PATCH 08/43] feat: register page logic --- src/routes/register/+page.svelte | 4 +++- src/routes/register/+page.ts | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 src/routes/register/+page.ts diff --git a/src/routes/register/+page.svelte b/src/routes/register/+page.svelte index ccc179174..c98baae28 100644 --- a/src/routes/register/+page.svelte +++ b/src/routes/register/+page.svelte @@ -21,6 +21,8 @@ import { page } from '$app/stores'; import { redirectTo } from '$routes/store'; + export let data; + let name: string, mail: string, pass: string, disabled: boolean; let terms = false; @@ -73,7 +75,7 @@ Sign up - Appwrite - + Sign up
diff --git a/src/routes/register/+page.ts b/src/routes/register/+page.ts new file mode 100644 index 000000000..ac36b230e --- /dev/null +++ b/src/routes/register/+page.ts @@ -0,0 +1,18 @@ +import { base } from '$app/paths'; +import { sdk } from '$lib/stores/sdk'; +import { redirect } from '@sveltejs/kit'; + +export const load = async ({ url }) => { + if (url.searchParams.has('code')) { + const code = url.searchParams.get('code'); + try { + const couponData = await sdk.forConsole.billing.getCoupon(code); + return { + couponData + }; + } catch (e) { + redirect(303, `${base}/register`); + } + } + return; +}; From 4866eca1d1aed1b08f47571ffc3fe779c15b04a6 Mon Sep 17 00:00:00 2001 From: Arman Date: Mon, 27 May 2024 16:48:49 +0200 Subject: [PATCH 09/43] feat: register redirection logic --- src/routes/register/+page.svelte | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/routes/register/+page.svelte b/src/routes/register/+page.svelte index c98baae28..34862750a 100644 --- a/src/routes/register/+page.svelte +++ b/src/routes/register/+page.svelte @@ -38,7 +38,11 @@ } await invalidate(Dependencies.ACCOUNT); - + trackEvent(Submit.AccountCreate, { campaign_name: data?.couponData?.code }); + if (data?.couponData?.code) { + await goto(`${base}/console/apply-credit?code=${data?.couponData?.code}`); + return; + } if ($page.url.searchParams) { const redirect = $page.url.searchParams.get('redirect'); $page.url.searchParams.delete('redirect'); From e3a84126678a30a2ae2c659ed26d07358415e959 Mon Sep 17 00:00:00 2001 From: Arman Date: Mon, 27 May 2024 16:53:16 +0200 Subject: [PATCH 10/43] fix: linter --- src/routes/console/apply-credit/+page.svelte | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/routes/console/apply-credit/+page.svelte b/src/routes/console/apply-credit/+page.svelte index 2ccf299a6..3c1927d93 100644 --- a/src/routes/console/apply-credit/+page.svelte +++ b/src/routes/console/apply-credit/+page.svelte @@ -40,10 +40,10 @@ let taxId: string; let billingBudget: number; let options = [ - ...$organizationList?.teams?.map((team) => ({ + ...($organizationList?.teams?.map((team) => ({ value: team.$id, label: team.name - })), + })) ?? []), { value: null, label: 'Create new organization' From 0a6cad8a914df049f7525096d2e012c872c53297 Mon Sep 17 00:00:00 2001 From: Arman Date: Tue, 28 May 2024 15:11:55 +0200 Subject: [PATCH 11/43] fix: gradients --- src/lib/layout/unauthenticated.svelte | 47 +++++++++++++-------------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/src/lib/layout/unauthenticated.svelte b/src/lib/layout/unauthenticated.svelte index bf59fba09..24d3aef15 100644 --- a/src/lib/layout/unauthenticated.svelte +++ b/src/lib/layout/unauthenticated.svelte @@ -23,6 +23,7 @@ style:--url={variation === 'card' ? '' : `url(${$app.themeInUse === 'dark' ? imgDark : imgLight})`}> +
{:else if variation === 'card'} -
+
promo
@@ -119,49 +118,47 @@ .side-bg { position: relative; - background-color: #ededf0; overflow: hidden; + z-index: 1; + height: 100%; + width: 100%; } - .side-bg::before { + .side-bg-container { position: absolute; - // inset-block-start: -950px; - inset-block-start: -1450px; - inset-inline-end: -650px; + inset: 0; + block-size: 100%; + inline-size: 100%; + z-index: -1; + } + .side-bg-container::before { + position: absolute; + inset-block-start: -10px; + inset-inline-end: -10px; content: ''; display: block; - inline-size: 100%; - block-size: 100%; + inline-size: 30%; + block-size: 30%; background: radial-gradient(49.55% 43.54% at 47% 50.69%, #e7f8f7 0%, #85dbd8 100%); filter: blur(250px); @media #{$break1} { - // inset-block-start: -200px; - inset-block-start: -500px; - inset-inline-end: -400px; filter: blur(100px); } } - .side-bg::after { + .side-bg-container::after { position: absolute; - // inset-block-end: -850px; - inset-block-end: -1250px; - inset-inline-start: -600px; + inset-block-end: -10px; + inset-inline-start: -10px; content: ''; display: block; - inline-size: 100%; - block-size: 100%; + inline-size: 30%; + block-size: 30%; background: radial-gradient(50% 46.73% at 50% 53.27%, #fe9567 28.17%, #fd366e 59.38%); filter: blur(250px); @media #{$break1} { - // inset-block-end: -200px; - inset-block-end: -400px; - inset-inline-start: -400px; filter: blur(100px); } } - :global(.theme-dark) .side-bg { - background-color: #19191d; - } /* Default (including mobile) */ #main section:first-child { From 5902d29f7260693e4d0e2344918c8d40589b8532 Mon Sep 17 00:00:00 2001 From: Arman Date: Tue, 28 May 2024 15:15:54 +0200 Subject: [PATCH 12/43] fix: spacing and font issues --- src/lib/layout/unauthenticated.svelte | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/lib/layout/unauthenticated.svelte b/src/lib/layout/unauthenticated.svelte index 24d3aef15..b06d957d5 100644 --- a/src/lib/layout/unauthenticated.svelte +++ b/src/lib/layout/unauthenticated.svelte @@ -59,7 +59,7 @@ alt="promo" />
- + You've received ${coupon.credits} in credits

@@ -77,7 +77,9 @@

-

+

From af5d97aaba14a3fe52246f88f1896c5f9f2d9f65 Mon Sep 17 00:00:00 2001 From: Arman Date: Tue, 28 May 2024 15:51:28 +0200 Subject: [PATCH 13/43] feat: add campaign constant, fix edge cases --- src/lib/layout/unauthenticated.svelte | 7 +-- src/lib/stores/campaigns.ts | 15 ++++++ src/routes/console/apply-credit/+page.svelte | 51 ++++++++++++-------- src/routes/console/apply-credit/+page.ts | 6 ++- src/routes/login/+page.svelte | 2 +- src/routes/login/+page.ts | 9 ++-- src/routes/register/+page.ts | 9 ++-- 7 files changed, 66 insertions(+), 33 deletions(-) create mode 100644 src/lib/stores/campaigns.ts diff --git a/src/lib/layout/unauthenticated.svelte b/src/lib/layout/unauthenticated.svelte index b06d957d5..ae6d44edb 100644 --- a/src/lib/layout/unauthenticated.svelte +++ b/src/lib/layout/unauthenticated.svelte @@ -6,6 +6,7 @@ import LoginLight from '$lib/images/login/login-light-mode.png'; import type { Coupon } from '$lib/sdk/billing'; import { app } from '$lib/stores/app'; + import { campaigns } from '$lib/stores/campaigns'; import { user } from '$lib/stores/user'; export const imgLight = LoginLight; @@ -14,6 +15,7 @@ export let coupon: Coupon = null; $: variation = coupon?.code ? 'card' : 'default'; + $: campaign = campaigns.get(coupon.campaign);
@@ -60,11 +62,10 @@
- You've received ${coupon.credits} in credits + {campaign.title.replace('VALUE', coupon.credits)}

- Get ${coupon.credits} in credits when you upgrade or create an organization with - a Pro plan. + {campaign.description.replace('VALUE', coupon.credits)}

diff --git a/src/lib/stores/campaigns.ts b/src/lib/stores/campaigns.ts new file mode 100644 index 000000000..019a0441e --- /dev/null +++ b/src/lib/stores/campaigns.ts @@ -0,0 +1,15 @@ +//campaign welcome and startup + +export const campaigns = new Map(); + +campaigns + .set('welcome', { + title: "You've received $VALUE in credits", + description: + 'Get $VALUE in credits when you upgrade or create an organization with a Pro plan.' + }) + .set('startup', { + title: "You've received $VALUE in credits", + description: + 'Get $VALUE in credits when you upgrade or create an organization with a Pro plan.' + }); diff --git a/src/routes/console/apply-credit/+page.svelte b/src/routes/console/apply-credit/+page.svelte index 3c1927d93..e065e4d09 100644 --- a/src/routes/console/apply-credit/+page.svelte +++ b/src/routes/console/apply-credit/+page.svelte @@ -39,13 +39,14 @@ let collaborators: string[]; let taxId: string; let billingBudget: number; + let newOrgId = ID.unique(); let options = [ ...($organizationList?.teams?.map((team) => ({ value: team.$id, label: team.name })) ?? []), { - value: null, + value: newOrgId, label: 'Create new organization' } ]; @@ -54,9 +55,7 @@ onMount(async () => { await loadPaymentMethods(); if (!$organizationList?.total) { - selectedOrgId = null; - } else { - selectedOrgId = $organizationList?.teams[0]?.$id; + selectedOrgId = newOrgId; } }); @@ -75,7 +74,7 @@ // Create new org if (!selectedOrgId) { org = await sdk.forConsole.billing.createOrganization( - ID.unique(), + newOrgId, name, BillingPlan.PRO, paymentMethodId @@ -166,14 +165,14 @@ label="Select organization" {options} required - placeholder="Create new organization" + placeholder="Select organization" id="organization" /> {/if} - {#if selectedOrg?.billingPlan !== BillingPlan.PRO || !selectedOrg?.paymentMethodId} + {#if selectedOrgId && (selectedOrg?.billingPlan !== BillingPlan.PRO || !selectedOrg?.paymentMethodId)} - {#if !selectedOrgId} + {#if selectedOrgId === newOrgId} {/if} -
- promo +
+
+
+ promo +

+ {data.campaign.title.replace('VALUE', data.couponData.credits)} +

+
{#if selectedOrg?.billingPlan === BillingPlan.PRO}
@@ -207,7 +214,7 @@ >{toLocaleDate(selectedOrg.billingNextInvoiceDate)}.

- {:else if selectedOrg?.$id} + {:else if selectedOrgId} diff --git a/src/routes/console/apply-credit/+page.ts b/src/routes/console/apply-credit/+page.ts index 0c0762b5e..a5e9c5792 100644 --- a/src/routes/console/apply-credit/+page.ts +++ b/src/routes/console/apply-credit/+page.ts @@ -1,5 +1,6 @@ import { base } from '$app/paths'; import type { Coupon } from '$lib/sdk/billing.js'; +import { campaigns } from '$lib/stores/campaigns.js'; import { sdk } from '$lib/stores/sdk.js'; import { redirect } from '@sveltejs/kit'; @@ -13,11 +14,12 @@ export const load = async ({ url }) => { redirect(303, `${base}/console`); } } - if (!couponData?.campaign) { + if (!couponData?.campaign || !campaigns.has(couponData.campaign)) { redirect(303, `${base}/console`); } return { - couponData + couponData, + campaign: campaigns.get(couponData.campaign) }; }; diff --git a/src/routes/login/+page.svelte b/src/routes/login/+page.svelte index 77b60f325..85d4bc2e0 100644 --- a/src/routes/login/+page.svelte +++ b/src/routes/login/+page.svelte @@ -42,8 +42,8 @@ } await invalidate(Dependencies.ACCOUNT); - trackEvent(Submit.AccountCreate, { campaign_name: data?.couponData?.code }); if (data?.couponData?.code) { + trackEvent(Submit.AccountCreate, { campaign_name: data?.couponData?.code }); await goto(`${base}/console/apply-credit?code=${data?.couponData?.code}`); return; } diff --git a/src/routes/login/+page.ts b/src/routes/login/+page.ts index ddf8ff52e..c91140d32 100644 --- a/src/routes/login/+page.ts +++ b/src/routes/login/+page.ts @@ -1,4 +1,5 @@ import { base } from '$app/paths'; +import { campaigns } from '$lib/stores/campaigns'; import { sdk } from '$lib/stores/sdk'; import { redirect } from '@sveltejs/kit'; @@ -7,9 +8,11 @@ export const load = async ({ url }) => { const code = url.searchParams.get('code'); try { const couponData = await sdk.forConsole.billing.getCoupon(code); - return { - couponData - }; + if (couponData?.campaign && campaigns.has(couponData.campaign)) { + return { + couponData + }; + } else redirect(303, `${base}/login`); } catch (e) { redirect(303, `${base}/login`); } diff --git a/src/routes/register/+page.ts b/src/routes/register/+page.ts index ac36b230e..eb4f4ae52 100644 --- a/src/routes/register/+page.ts +++ b/src/routes/register/+page.ts @@ -1,4 +1,5 @@ import { base } from '$app/paths'; +import { campaigns } from '$lib/stores/campaigns.js'; import { sdk } from '$lib/stores/sdk'; import { redirect } from '@sveltejs/kit'; @@ -7,9 +8,11 @@ export const load = async ({ url }) => { const code = url.searchParams.get('code'); try { const couponData = await sdk.forConsole.billing.getCoupon(code); - return { - couponData - }; + if (couponData?.campaign && campaigns.has(couponData.campaign)) { + return { + couponData + }; + } else redirect(303, `${base}/register`); } catch (e) { redirect(303, `${base}/register`); } From 849ac64062fdc622ea7af5d7e7a5e4e2a5bd90e3 Mon Sep 17 00:00:00 2001 From: Arman Date: Tue, 28 May 2024 15:59:48 +0200 Subject: [PATCH 14/43] fix: estimate box and exit modal --- .../billing/estimatedTotalBox.svelte | 35 +++++++++++-------- src/lib/layout/wizardExitModal.svelte | 5 ++- src/lib/layout/wizardSecondaryHeader.svelte | 5 ++- src/routes/console/apply-credit/+page.svelte | 11 ++++-- 4 files changed, 35 insertions(+), 21 deletions(-) diff --git a/src/lib/components/billing/estimatedTotalBox.svelte b/src/lib/components/billing/estimatedTotalBox.svelte index 932700919..88be7db6a 100644 --- a/src/lib/components/billing/estimatedTotalBox.svelte +++ b/src/lib/components/billing/estimatedTotalBox.svelte @@ -10,6 +10,7 @@ export let collaborators: string[]; export let couponData: Partial; export let billingBudget: number; + export let fixedCoupon = false; // If true, the coupon cannot be removed const today = new Date(); const billingPayDate = new Date(today.getTime() + 30 * 24 * 60 * 60 * 1000); @@ -30,7 +31,9 @@ ); -
+

{currentPlan.name} plan

{formatCurrency(currentPlan.price)}

@@ -53,20 +56,22 @@ >Credits applied
{/if}

- + {#if !fixedCoupon} + + {/if}
{#if couponData.credits > 100}

diff --git a/src/lib/layout/wizardExitModal.svelte b/src/lib/layout/wizardExitModal.svelte index b9fd150a2..3d7c2d852 100644 --- a/src/lib/layout/wizardExitModal.svelte +++ b/src/lib/layout/wizardExitModal.svelte @@ -20,9 +20,8 @@ icon="exclamation" state="warning" headerDivider={false}> -

- Are you sure you want to exit from ? All data will be deleted. This action is - irreversible. +

+

diff --git a/src/lib/layout/wizardSecondaryHeader.svelte b/src/lib/layout/wizardSecondaryHeader.svelte index 00ee7cb3b..79b94a815 100644 --- a/src/lib/layout/wizardSecondaryHeader.svelte +++ b/src/lib/layout/wizardSecondaryHeader.svelte @@ -44,6 +44,9 @@ from: 'prompt' }); }}> - this process + + Are you sure you want to exit from this process? All data will be deleted. This action + is irreversible. + {/if} diff --git a/src/routes/console/apply-credit/+page.svelte b/src/routes/console/apply-credit/+page.svelte index e065e4d09..420fd20a3 100644 --- a/src/routes/console/apply-credit/+page.svelte +++ b/src/routes/console/apply-credit/+page.svelte @@ -156,7 +156,13 @@ - Apply credits + Apply credits + + You can apply your credits to an organization at a later date. All other data entered + will be lost. Credits expire {toLocaleDate(data.couponData.expiration)}. + + {#if $organizationList?.total} @@ -208,7 +214,7 @@
{#if selectedOrg?.billingPlan === BillingPlan.PRO} -
+

Credits will automatically be applied to your next invoice on {toLocaleDate(selectedOrg.billingNextInvoiceDate)}. @@ -216,6 +222,7 @@

{:else if selectedOrgId} Date: Wed, 29 May 2024 18:13:55 +0200 Subject: [PATCH 15/43] feat: design fixes --- .../billing/selectPaymentMethod.svelte | 1 + src/lib/components/heading.svelte | 2 + src/lib/layout/unauthenticated.svelte | 139 +++++++++++------- src/lib/layout/wizardSecondaryHeader.svelte | 12 +- src/routes/console/apply-credit/+page.svelte | 17 ++- .../console/create-organization/+page.svelte | 2 +- .../change-plan/+page.svelte | 2 +- 7 files changed, 108 insertions(+), 67 deletions(-) diff --git a/src/lib/components/billing/selectPaymentMethod.svelte b/src/lib/components/billing/selectPaymentMethod.svelte index 0412870a6..0bed8d7e4 100644 --- a/src/lib/components/billing/selectPaymentMethod.svelte +++ b/src/lib/components/billing/selectPaymentMethod.svelte @@ -43,6 +43,7 @@ {/if} diff --git a/src/lib/layout/unauthenticated.svelte b/src/lib/layout/unauthenticated.svelte index ae6d44edb..1ec41c275 100644 --- a/src/lib/layout/unauthenticated.svelte +++ b/src/lib/layout/unauthenticated.svelte @@ -15,21 +15,19 @@ export let coupon: Coupon = null; $: variation = coupon?.code ? 'card' : 'default'; - $: campaign = campaigns.get(coupon.campaign); + $: campaign = campaigns.get(coupon?.campaign);
-
-