Skip to content

Commit

Permalink
Merge pull request #1108 from appwrite/feat-credit-flow
Browse files Browse the repository at this point in the history
feat: external credit flow
  • Loading branch information
TorstenDittmann committed Jun 5, 2024
2 parents 2870044 + 00cd336 commit 9466280
Show file tree
Hide file tree
Showing 27 changed files with 676 additions and 83 deletions.
45 changes: 26 additions & 19 deletions src/lib/components/billing/estimatedTotalBox.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
export let collaborators: string[];
export let couponData: Partial<Coupon>;
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);
Expand All @@ -30,7 +31,10 @@
);
</script>

<section class="card u-margin-block-start-32 u-flex u-flex-vertical u-gap-8">
<section
class="card u-margin-block-start-32 u-flex u-flex-vertical u-gap-8"
style:--p-card-padding="1.5rem"
style:--p-card-border-radius="var(--border-radius-small)">
<span class="u-flex u-main-space-between">
<p class="text">{currentPlan.name} plan</p>
<p class="text">{formatCurrency(currentPlan.price)}</p>
Expand All @@ -46,29 +50,32 @@
<div class="u-flex u-cross-center u-gap-4">
<p class="text">
<span class="icon-tag u-color-text-success" aria-hidden="true" />
{#if couponData.credits > 100}
{#if couponData.credits >= 100}
{couponData.code.toUpperCase()}
{:else}
<span use:tooltip={{ content: couponData.code.toUpperCase() }}
>Credits applied</span>
<span use:tooltip={{ content: couponData.code.toUpperCase() }}>
Credits applied
</span>
{/if}
</p>
<button
type="button"
class="button is-text is-only-icon"
style="--button-size:1.5rem;"
aria-label="Close"
title="Close"
on:click={() =>
(couponData = {
code: null,
status: null,
credits: null
})}>
<span class="icon-x" aria-hidden="true" />
</button>
{#if !fixedCoupon}
<button
type="button"
class="button is-text is-only-icon"
style="--button-size:1.5rem;"
aria-label="Close"
title="Close"
on:click={() =>
(couponData = {
code: null,
status: null,
credits: null
})}>
<span class="icon-x" aria-hidden="true" />
</button>
{/if}
</div>
{#if couponData.credits > 100}
{#if couponData.credits >= 100}
<p class="inline-tag" use:tooltip={{ content: formatCurrency(couponData.credits) }}>
Credits applied
</p>
Expand Down
11 changes: 7 additions & 4 deletions src/lib/components/billing/selectPaymentMethod.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
{/if}
<InputSelectSearch
id="method"
required
label="Payment method"
placeholder="Select payment method"
bind:value
Expand Down Expand Up @@ -86,12 +87,14 @@
{:else}
<Card
isDashed
style="--p-card-padding:1rem; --p-card-bg-color: transparent; --p-card-border-radius: 0.5rem"
style="--p-card-padding:0.75rem; --p-card-bg-color: transparent; --p-card-border-radius: 0.5rem"
isTile>
<div class="u-flex u-main-space-between u-cross-center">
<p>
<span class="icon-exclamation-circle"></span>
<span class="text">No saved payment methods</span>
<p class="u-flex u-gap-8 u-cross-center">
<span
class="icon-exclamation u-color-text-warning"
style:font-size="var(--icon-size-medium)"></span>
<span class="text">A payment method is required</span>
</p>
<Button secondary on:click={() => (showPaymentModal = true)}>
<span class="icon-plus"></span> <span class="text">Add</span>
Expand Down
2 changes: 2 additions & 0 deletions src/lib/components/heading.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@
export let id: string = null;
let classes = '';
export { classes as class };
export let style = '';
</script>

<svelte:element
this={tag}
class={`heading-level-${size} u-min-width-0 ${classes}`}
class:u-trim-1={trimmed}
{style}
{id}>
<slot />
</svelte:element>
4 changes: 2 additions & 2 deletions src/lib/elements/forms/inputSelect.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@
export let label: string | undefined = undefined;
export let optionalText: string | undefined = undefined;
export let showLabel = true;
export let value: string | number | boolean;
export let value: string | number | boolean | null;
export let placeholder = '';
export let required = false;
export let hideRequired = false;
export let disabled = false;
export let wrapperTag: FormItemTag = 'li';
export let options: {
value: string | boolean | number;
value: string | boolean | number | null;
label: string;
}[];
export let isMultiple = false;
Expand Down
8 changes: 6 additions & 2 deletions src/lib/elements/forms/inputTags.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@
/**
* Allow form submit and tab input switch
*/
if (value === '' && ['Enter', 'Tab'].includes(e.key)) {
if (value === '' && ['Enter', 'Tab', ','].includes(e.key)) {
return;
}
if (['Enter', 'Tab', ' '].includes(e.key)) {
if (['Enter', 'Tab', ' ', ','].includes(e.key)) {
e.preventDefault();
if (validityRegex && !validityRegex.test(value)) {
error = validityMessage ? validityMessage : 'Invalid value';
Expand All @@ -51,6 +51,10 @@
};
const addValue = () => {
if (validityRegex && !validityRegex.test(value) && !!value) {
error = validityMessage ? validityMessage : 'Invalid value';
return;
}
let tag = value.trim();
if (tag.length === 0 || tags.includes(tag)) return;
Expand Down
167 changes: 154 additions & 13 deletions src/lib/layout/unauthenticated.svelte
Original file line number Diff line number Diff line change
@@ -1,20 +1,36 @@
<script lang="ts">
import { Heading } from '$lib/components';
import AppwriteLogoDark from '$lib/images/appwrite-logo-dark.svg';
import AppwriteLogoLight from '$lib/images/appwrite-logo-light.svg';
import LoginDark from '$lib/images/login/login-dark-mode.png';
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;
export const imgDark = LoginDark;
export let coupon: Coupon = null;
$: variation = coupon?.code ? 'card' : 'default';
$: campaign = campaigns.get(coupon?.campaign);
</script>

<main class="grid-1-1 is-full-page" id="main">
<section
class="u-flex u-flex-vertical"
style:--url={`url(${$app.themeInUse === 'dark' ? imgDark : imgLight})`}>
<div class="logo u-flex u-gap-16 is-not-mobile">
class={`u-flex u-flex-vertical ${variation === 'card' ? 'u-cross-center u-main-center u-height-100-percent u-width-full-line side-bg' : 'side-default'}`}
style:--url={variation === 'card'
? ''
: `url(${$app.themeInUse === 'dark' ? imgDark : imgLight})`}>
{#if variation === 'card'}
<div class="side-bg-container" />
{/if}
<div
class="logo u-flex u-gap-16"
class:is-not-mobile={variation === 'default'}
class:logo-variation={variation === 'card'}>
<a href={user ? '/console' : '/'}>
{#if $app.themeInUse === 'dark'}
<img
Expand All @@ -32,20 +48,58 @@
</a>
</div>

<div class="u-flex u-stretch" />
{#if variation === 'default'}
<div class="u-flex u-stretch" />

<div class="tag-line is-not-mobile">
<p>Build like a team of hundreds<span class="underscore">_</span></p>
</div>
<div class="tag-line is-not-mobile">
<p>Build like a team of hundreds<span class="underscore">_</span></p>
</div>
{:else if variation === 'card'}
<div
class="u-flex u-flex-vertical u-main-center u-cross-center u-height-100-percent u-width-full-line">
<img
src={`/images/campaigns/${coupon.campaign}/${$app.themeInUse}.png`}
class="u-block u-image-object-fit-cover side-bg-img"
alt="promo" />

<div class="u-text-center">
<div class="is-only-mobile u-width-full-line">
<Heading
size="5"
tag="h3"
class="u-margin-block-start-16"
trimmed={false}
style="font-weight:normal">
{campaign.title.replace('VALUE', coupon.credits)}
</Heading>
</div>
<div class="is-not-mobile u-width-full-line">
<Heading
size="4"
tag="h3"
class="u-margin-block-start-32"
trimmed={false}
style="font-weight:normal">
{campaign.title.replace('VALUE', coupon.credits)}
</Heading>
</div>
<p class="u-margin-block-start-16 auth-container">
{campaign.description.replace('VALUE', coupon.credits)}
</p>
</div>
</div>
{/if}
</section>
<section class="grid-1-1-col-2 u-flex u-flex-vertical u-cross-center u-main-center">
<slot name="top" />
<div class="container u-flex u-flex-vertical u-cross-center u-main-center">
<div class="form-container u-width-full-line">
<div class="auth-container u-width-full-line">
<h1 class="heading-level-4 u-margin-block-start-auto is-not-mobile">
<slot name="title" />
</h1>
<h1 class="heading-level-5 u-margin-block-start-auto is-only-mobile">
<h1
class="heading-level-5 u-margin-block-start-auto is-only-mobile"
class:u-padding-block-start-24={variation === 'card'}>
<slot name="title" />
</h1>
<div class="u-margin-block-start-24">
Expand Down Expand Up @@ -82,9 +136,86 @@

<style lang="scss">
@import '@appwrite.io/pink/src/abstract/variables/_devices.scss';
@import '@appwrite.io/pink/src/abstract/variables/_common.scss';
.side-bg {
position: relative;
overflow: hidden;
z-index: 1;
height: 100%;
width: 100%;
padding-block: 2rem;
padding-inline: 1rem;
background-color: #ededf0 !important;
&-container {
position: absolute;
inset: 0;
block-size: 100%;
inline-size: 100%;
z-index: -1;
&::before {
position: absolute;
inset-block-start: -200px;
inset-inline-end: -50px;
content: '';
display: block;
inline-size: 32%;
block-size: 32%;
background: radial-gradient(49.55% 43.54% at 47% 50.69%, #e7f8f7 0%, #85dbd8 100%);
filter: blur(150px);
@media #{$break1} {
filter: blur(100px);
}
}
&::after {
position: absolute;
inset-block-end: -50px;
inset-inline-start: -50px;
content: '';
display: block;
inline-size: 30%;
block-size: 30%;
background: radial-gradient(
50% 46.73% at 50% 53.27%,
#fe9567 28.17%,
#fd366e 59.38%
);
filter: blur(200px);
@media #{$break1} {
filter: blur(100px);
}
}
}
&-img {
padding-inline: 6.25rem;
max-width: 40rem;
@media #{$break2} {
max-width: 28rem;
}
@media #{$break1} {
margin-block-start: 3rem;
max-inline-size: 23rem;
padding-inline: 4rem;
}
}
}
:global(.theme-dark) .side-bg {
background-color: #131315 !important;
}
:global(.theme-dark) .side-bg-container::before {
inline-size: 20%;
block-size: 20%;
filter: blur(180px);
}
:global(.theme-dark) .side-bg-container::after {
filter: blur(250px);
}
/* Default (including mobile) */
#main section:first-child {
.side-default {
padding-block-start: 2.25rem;
padding-block-end: 2rem;
Expand All @@ -109,7 +240,7 @@
/* for smaller screens */
@media #{$break2open} {
#main section:first-child {
.side-default {
background: var(--url);
background-repeat: no-repeat;
background-position: top;
Expand All @@ -127,7 +258,7 @@
/* for larger screens */
@media #{$break3open} {
#main section:first-child {
.side-default {
div {
padding-inline-start: 5.625rem;
padding-inline-end: 5rem;
Expand All @@ -152,7 +283,17 @@
-webkit-text-fill-color: transparent;
}
.form-container {
.auth-container {
max-inline-size: 27.5rem;
}
.logo-variation {
padding-block-start: 2rem;
@media #{$break1} {
padding-block-start: 0rem;
& img {
scale: 0.7;
}
}
}
</style>
6 changes: 3 additions & 3 deletions src/lib/layout/wizardExitModal.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@
onSubmit={handleSubmit}
icon="exclamation"
state="warning"
size="small"
headerDivider={false}>
<p>
Are you sure you want to exit from <slot />? All data will be deleted. This action is
irreversible.
<p class="text">
<slot />
</p>
<svelte:fragment slot="footer">
<Button text on:click={() => (show = false)}>Cancel</Button>
Expand Down
Loading

0 comments on commit 9466280

Please sign in to comment.