feat: new org creation

This commit is contained in:
Arman
2024-04-24 18:05:38 +02:00
parent e1ccdb7352
commit 5a2d85f3f0
11 changed files with 197 additions and 13 deletions
+9 -9
View File
@@ -7,8 +7,8 @@
"name": "@appwrite/console",
"dependencies": {
"@appwrite.io/console": "^0.5.0",
"@appwrite.io/pink": "0.11.0",
"@appwrite.io/pink-icons": "0.11.0",
"@appwrite.io/pink": "0.16.0",
"@appwrite.io/pink-icons": "0.16.0",
"@popperjs/core": "^2.11.8",
"@sentry/svelte": "^7.66.0",
"@sentry/tracing": "^7.66.0",
@@ -167,19 +167,19 @@
}
},
"node_modules/@appwrite.io/pink": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/@appwrite.io/pink/-/pink-0.11.0.tgz",
"integrity": "sha512-0/ztJxeV6Cy1FnXy2ClLELzDnR4eRtGAhQ24napCg0VwOFevSIc0S7jcRrWVyA6WRuwex4eGiEn2JeYMTq70Xg==",
"version": "0.16.0",
"resolved": "https://registry.npmjs.org/@appwrite.io/pink/-/pink-0.16.0.tgz",
"integrity": "sha512-KprOd+36I0w6PC0x6NJclvyJNpCsjAPcrCHL3QixSX0dZ66wqFE6NitF/KiVVCxbuBaNgjrm7oQ0hr7dt1Sm5Q==",
"dependencies": {
"@appwrite.io/pink-icons": "0.11.0",
"@appwrite.io/pink-icons": "0.16.0",
"normalize.css": "^8.0.1",
"the-new-css-reset": "^1.11.2"
}
},
"node_modules/@appwrite.io/pink-icons": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/@appwrite.io/pink-icons/-/pink-icons-0.11.0.tgz",
"integrity": "sha512-FOvP87m4S17QRQPrLzsSlwrbIeJNJi5RliGUQYONIhmI0PiwE4Xm5LXFE+NqFYsR56w2X3jYdJIHdIdZlH3XjA=="
"version": "0.16.0",
"resolved": "https://registry.npmjs.org/@appwrite.io/pink-icons/-/pink-icons-0.16.0.tgz",
"integrity": "sha512-tWaG5lFXnKzbFbGf4SlxoFYj2yH7kQDejFq+UHdfzBrqteSfZpxIxdNmKHIea1ztcmsat4y+R0ZbVX9iOv+oPw=="
},
"node_modules/@babel/code-frame": {
"version": "7.23.5",
+2 -2
View File
@@ -19,8 +19,8 @@
},
"dependencies": {
"@appwrite.io/console": "^0.5.0",
"@appwrite.io/pink": "0.11.0",
"@appwrite.io/pink-icons": "0.11.0",
"@appwrite.io/pink": "0.16.0",
"@appwrite.io/pink-icons": "0.16.0",
"@popperjs/core": "^2.11.8",
"@sentry/svelte": "^7.66.0",
"@sentry/tracing": "^7.66.0",
+4 -1
View File
@@ -6,6 +6,7 @@
hide?: boolean;
tooltip?: string;
for?: string;
class?: string;
}
export let required: $$Props['required'] = false;
@@ -13,12 +14,14 @@
export let optionalText: $$Props['optionalText'] = undefined;
export let hide: $$Props['hide'] = false;
export let tooltip: $$Props['tooltip'] = null;
let classes: string = undefined;
export { classes as class };
</script>
<label
class:is-required={required && !hideRequired}
class:u-hide={hide}
class="label"
class="label {classes}"
{...$$restProps}>
<slot />
</label>
+4
View File
@@ -19,3 +19,7 @@ export { default as GridHeader } from './gridHeader.svelte';
export { default as ContainerHeader } from './containerHeader.svelte';
export { default as HeaderAlert } from './headerAlert.svelte';
export { default as ContainerButton } from './containerButton.svelte';
export { default as WizardSecondaryContainer } from './wizardSecondaryContainer.svelte';
export { default as WizardSecondaryContent } from './wizardSecondaryContent.svelte';
export { default as WizardSecondaryHeader } from './wizardSecondaryHeader.svelte';
export { default as WizardSecondaryFooter } from './wizardSecondaryFooter.svelte';
@@ -0,0 +1,20 @@
<section class="wizard-secondary c-wizard-position">
<div class="wizard-secondary-container">
<slot />
</div>
</section>
<style lang="scss">
.c-wizard-position {
background-color: hsl(var(--p-body-bg-color));
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 30;
width: 100%;
height: 100%;
max-height: 100vh;
}
</style>
@@ -0,0 +1,11 @@
<div class="wizard-secondary-content">
<div class="wizard-secondary-content-1">
<slot />
</div>
<div class="wizard-secondary-content-sep"></div>
<div class="wizard-secondary-content-2">
<div class="wizard-secondary-content-sticky">
<slot name="aside" />
</div>
</div>
</div>
@@ -0,0 +1,8 @@
<div class="wizard-secondary-options">
<div class="wizard-secondary-options-start">
<slot name="start" />
</div>
<div class="wizard-secondary-options-end">
<slot />
</div>
</div>
@@ -0,0 +1,17 @@
<script lang="ts">
import { Heading } from '$lib/components';
import { Button } from '$lib/elements/forms';
export let href: string;
</script>
<header class="wizard-secondary-header">
<div class="u-flex u-main-space-between u-gap-32">
<Heading size={1} tag="h1"><slot /></Heading>
<Button text round class="u-margin-block-start-8" ariaLabel="close modal" {href}>
<span class="icon-x u-font-size-20" aria-hidden="true"></span>
</Button>
</div>
{#if $$slots.description}
<p class="body-text-2"><slot name="description" /></p>
{/if}
</header>
+1 -1
View File
@@ -114,7 +114,7 @@ export type TierData = {
export const tierFree: TierData = {
name: 'Starter',
description: 'For personal, passion projects.'
description: 'For personal hobby projects of small scale and students.'
};
export const tierPro: TierData = {
@@ -0,0 +1,93 @@
<script lang="ts">
import { base } from '$app/paths';
import { LabelCard } from '$lib/components';
import { BillingPlan } from '$lib/constants';
import { Button, Form, FormList, InputText, Label } from '$lib/elements/forms';
import { formatCurrency } from '$lib/helpers/numbers';
import {
WizardSecondaryContainer,
WizardSecondaryContent,
WizardSecondaryFooter,
WizardSecondaryHeader
} from '$lib/layout';
import { plansInfo, tierFree, tierPro } from '$lib/stores/billing';
import { organizationList, type Organization } from '$lib/stores/organization';
import { createOrganization } from './store';
$: anyOrgFree = $organizationList.teams?.find(
(org) => (org as Organization)?.billingPlan === BillingPlan.STARTER
);
$: freePlan = $plansInfo.get(BillingPlan.STARTER);
$: proPlan = $plansInfo.get(BillingPlan.PRO);
</script>
<WizardSecondaryContainer>
<WizardSecondaryHeader href={`${base}/console`}>Create organization</WizardSecondaryHeader>
<WizardSecondaryContent>
<Form onSubmit={() => console.log('test')}>
<FormList>
<InputText label="Name" placeholder="Enter name" id="name" />
</FormList>
<Label class="u-margin-block-start-16">Select plan</Label>
<ul
class="u-flex u-gap-16 u-margin-block-start-8"
style="--p-grid-item-size:16em; --p-grid-item-size-small-screens:16rem; --grid-gap: 1rem;">
<li class="u-flex-basis-50-percent">
<LabelCard
name="plan"
bind:group={$createOrganization.billingPlan}
value="tier-0"
disabled={!!anyOrgFree}
tooltipShow={!!anyOrgFree}
tooltipText="You are limited to 1 Free organization per account.">
<svelte:fragment slot="custom" let:disabled>
<div
class="u-flex u-flex-vertical u-gap-4 u-width-full-line"
class:u-opacity-50={disabled}>
<h4 class="body-text-2 u-bold">
{tierFree.name}
</h4>
<p class="u-color-text-gray u-small">{tierFree.description}</p>
<p>
{formatCurrency(freePlan?.price ?? 0)}
</p>
</div>
</svelte:fragment>
</LabelCard>
</li>
<li class="u-flex-basis-50-percent">
<LabelCard
name="plan"
bind:group={$createOrganization.billingPlan}
value="tier-1">
<svelte:fragment slot="custom">
<div class="u-flex u-flex-vertical u-gap-4 u-width-full-line">
<h4 class="body-text-2 u-bold">
{tierPro.name}
</h4>
<p class="u-color-text-gray u-small">
{tierPro.description}
</p>
<p>
{formatCurrency(proPlan?.price ?? 0)} per member/month + usage
</p>
</div>
</svelte:fragment>
</LabelCard>
</li>
</ul>
</Form>
<svelte:fragment slot="aside">
<div class="card">
Lorem ipsum dolor sit amet consectetur adipisicing elit. Recusandae, incidunt!
</div>
</svelte:fragment>
</WizardSecondaryContent>
<WizardSecondaryFooter>
<Button href={`${base}/console`} secondary>Cancel</Button>
<Button on:click>Create organization</Button>
</WizardSecondaryFooter>
</WizardSecondaryContainer>
@@ -0,0 +1,28 @@
import { BillingPlan } from '$lib/constants';
import type { WizardStepsType } from '$lib/layout/wizard.svelte';
import type { Tier } from '$lib/stores/billing';
import { writable } from 'svelte/store';
export const createOrgSteps = writable<WizardStepsType>(new Map());
export const createOrganizationFinalAction = writable<string>('Start trial');
export const createOrganization = writable<{
id?: string;
name: string;
billingPlan: Tier;
paymentMethodId: string;
billingAddressId: string;
collaborators?: string[];
billingBudget?: number;
taxId?: string;
couponCode?: string;
}>({
id: null,
name: null,
billingPlan: BillingPlan.PRO,
paymentMethodId: null,
collaborators: [],
billingAddressId: null,
taxId: null,
couponCode: null
});