mirror of
https://github.com/appwrite/console.git
synced 2026-06-06 19:27:48 +00:00
feat: new billing address flow during creation and upgrade
This commit is contained in:
@@ -14,7 +14,6 @@
|
||||
changeOrganizationFinalAction,
|
||||
changeOrganizationTier,
|
||||
changeTierSteps,
|
||||
currentBillingAddress,
|
||||
isUpgrade
|
||||
} from './wizard/cloudOrganizationChangeTier/store';
|
||||
import { goto, invalidate } from '$app/navigation';
|
||||
@@ -24,7 +23,6 @@
|
||||
import { organization } from '$lib/stores/organization';
|
||||
import { wizard } from '$lib/stores/wizard';
|
||||
import { tierToPlan } from '$lib/stores/billing';
|
||||
import deepEqual from 'deep-equal';
|
||||
import { user } from '$lib/stores/user';
|
||||
import { feedback } from '$lib/stores/feedback';
|
||||
|
||||
@@ -82,10 +80,14 @@
|
||||
);
|
||||
|
||||
//Add billing address
|
||||
if (
|
||||
if ($changeOrganizationTier.billingAddressId) {
|
||||
await sdk.forConsole.billing.setBillingAddress(
|
||||
org.$id,
|
||||
$changeOrganizationTier.billingAddressId
|
||||
);
|
||||
} else if (
|
||||
$changeOrganizationTier.billingAddress &&
|
||||
$changeOrganizationTier.billingAddress.streetAddress &&
|
||||
!deepEqual($changeOrganizationTier.billingAddress, $currentBillingAddress)
|
||||
$changeOrganizationTier.billingAddress.streetAddress
|
||||
) {
|
||||
const response = await sdk.forConsole.billing.createAddress(
|
||||
$changeOrganizationTier.billingAddress.country,
|
||||
@@ -180,6 +182,7 @@
|
||||
billingPlan: 'tier-1',
|
||||
paymentMethodId: null,
|
||||
collaborators: [],
|
||||
billingAddressId: null,
|
||||
billingAddress: {
|
||||
$id: null,
|
||||
streetAddress: null,
|
||||
|
||||
@@ -33,7 +33,12 @@
|
||||
$createOrganization.paymentMethodId
|
||||
);
|
||||
//Add billing address
|
||||
if (
|
||||
if ($createOrganization.billingAddressId) {
|
||||
await sdk.forConsole.billing.setBillingAddress(
|
||||
org.$id,
|
||||
$createOrganization.billingAddressId
|
||||
);
|
||||
} else if (
|
||||
$createOrganization.billingAddress &&
|
||||
$createOrganization.billingAddress.streetAddress
|
||||
) {
|
||||
@@ -106,6 +111,7 @@
|
||||
billingPlan: 'tier-1',
|
||||
paymentMethodId: null,
|
||||
collaborators: [],
|
||||
billingAddressId: null,
|
||||
billingAddress: {
|
||||
$id: null,
|
||||
streetAddress: null,
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
<script lang="ts">
|
||||
import { FormItem, FormList, InputSelect, InputText } from '$lib/elements/forms';
|
||||
import { FormItem, FormList, InputRadio, InputSelect, InputText } from '$lib/elements/forms';
|
||||
import { WizardStep } from '$lib/layout';
|
||||
import { onMount } from 'svelte';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import { Alert } from '$lib/components';
|
||||
import { createOrganization } from './store';
|
||||
import type { AddressesList } from '$lib/sdk/billing';
|
||||
|
||||
let options = [
|
||||
{
|
||||
@@ -12,8 +13,11 @@
|
||||
label: 'United States'
|
||||
}
|
||||
];
|
||||
let addressList: AddressesList;
|
||||
|
||||
onMount(async () => {
|
||||
addressList = await sdk.forConsole.billing.listAddresses();
|
||||
$createOrganization.billingAddressId = addressList.billingAddresses?.[0]?.$id ?? null;
|
||||
const countryList = await sdk.forProject.locale.listCountries();
|
||||
options = countryList.countries.map((country) => {
|
||||
return {
|
||||
@@ -32,54 +36,98 @@
|
||||
Depending on your location, your billing address might need to be in the same country
|
||||
associated with the payment method for your organization.
|
||||
</Alert>
|
||||
<FormList gap={16} class="u-margin-block-start-24">
|
||||
<InputText
|
||||
bind:value={$createOrganization.taxId}
|
||||
id="text"
|
||||
label="Tax ID"
|
||||
placeholder="Enter tax ID"
|
||||
optionalText="(optional)" />
|
||||
<InputSelect
|
||||
bind:value={$createOrganization.billingAddress.country}
|
||||
{options}
|
||||
label="Country or region"
|
||||
placeholder="Select country or region"
|
||||
id="country"
|
||||
required />
|
||||
<InputText
|
||||
bind:value={$createOrganization.billingAddress.streetAddress}
|
||||
id="address"
|
||||
label="Street address"
|
||||
placeholder="Enter street address"
|
||||
required />
|
||||
<InputText
|
||||
bind:value={$createOrganization.billingAddress.addressLine2}
|
||||
id="address2"
|
||||
label="Address line 2"
|
||||
placeholder="Unit number, floor, etc." />
|
||||
<InputText
|
||||
bind:value={$createOrganization.billingAddress.city}
|
||||
id="city"
|
||||
label="City or suburb"
|
||||
placeholder="Enter your city"
|
||||
required />
|
||||
<FormItem isMultiple>
|
||||
<InputText
|
||||
isMultiple
|
||||
fullWidth
|
||||
bind:value={$createOrganization.billingAddress.state}
|
||||
id="state"
|
||||
label="State"
|
||||
placeholder="Enter your state"
|
||||
required />
|
||||
<InputText
|
||||
isMultiple
|
||||
fullWidth
|
||||
bind:value={$createOrganization.billingAddress.postalCode}
|
||||
id="zip"
|
||||
label="Postal code"
|
||||
placeholder="Enter postal code"
|
||||
required />
|
||||
</FormItem>
|
||||
|
||||
<p class="text u-margin-block-start-24"><b>Billing address</b></p>
|
||||
<FormList class="u-margin-block-start-8">
|
||||
<div class:boxes-wrapper={addressList?.total}>
|
||||
{#if addressList?.total}
|
||||
{#each addressList.billingAddresses as address}
|
||||
<div class="box">
|
||||
<InputRadio
|
||||
id={`address-${address.$id}`}
|
||||
value={address.$id}
|
||||
name="address"
|
||||
bind:group={$createOrganization.billingAddressId}>
|
||||
<div
|
||||
class="u-line-height-1-5 u-flex u-flex-vertical u-gap-2"
|
||||
style="padding-inline:0.25rem">
|
||||
<p class="text">{address.streetAddress}</p>
|
||||
{#if address?.addressLine2}
|
||||
<p class="text">{address.addressLine2}</p>
|
||||
{/if}
|
||||
<p class="text">{address.city}</p>
|
||||
<p class="text">{address.state}</p>
|
||||
<p class="text">{address.postalCode}</p>
|
||||
<p class="text">{address.country}</p>
|
||||
</div>
|
||||
</InputRadio>
|
||||
</div>
|
||||
{/each}
|
||||
{/if}
|
||||
|
||||
<div class="box">
|
||||
{#if addressList?.total}
|
||||
<InputRadio
|
||||
id="address"
|
||||
value={null}
|
||||
name="address"
|
||||
bind:group={$createOrganization.billingAddressId}>
|
||||
<span style="padding-inline:0.25rem">Add new billing address</span>
|
||||
</InputRadio>
|
||||
{/if}
|
||||
{#if $createOrganization.billingAddressId === null}
|
||||
<FormList gap={16} class="u-margin-block-start-24">
|
||||
<InputText
|
||||
bind:value={$createOrganization.taxId}
|
||||
id="text"
|
||||
label="Tax ID"
|
||||
placeholder="Enter tax ID"
|
||||
optionalText="(optional)" />
|
||||
<InputSelect
|
||||
bind:value={$createOrganization.billingAddress.country}
|
||||
{options}
|
||||
label="Country or region"
|
||||
placeholder="Select country or region"
|
||||
id="country"
|
||||
required />
|
||||
<InputText
|
||||
bind:value={$createOrganization.billingAddress.streetAddress}
|
||||
id="address"
|
||||
label="Street address"
|
||||
placeholder="Enter street address"
|
||||
required />
|
||||
<InputText
|
||||
bind:value={$createOrganization.billingAddress.addressLine2}
|
||||
id="address2"
|
||||
label="Address line 2"
|
||||
placeholder="Unit number, floor, etc." />
|
||||
<InputText
|
||||
bind:value={$createOrganization.billingAddress.city}
|
||||
id="city"
|
||||
label="City or suburb"
|
||||
placeholder="Enter your city"
|
||||
required />
|
||||
<FormItem isMultiple>
|
||||
<InputText
|
||||
isMultiple
|
||||
fullWidth
|
||||
bind:value={$createOrganization.billingAddress.state}
|
||||
id="state"
|
||||
label="State"
|
||||
placeholder="Enter your state"
|
||||
required />
|
||||
<InputText
|
||||
isMultiple
|
||||
fullWidth
|
||||
bind:value={$createOrganization.billingAddress.postalCode}
|
||||
id="zip"
|
||||
label="Postal code"
|
||||
placeholder="Enter postal code"
|
||||
required />
|
||||
</FormItem>
|
||||
</FormList>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</FormList>
|
||||
</WizardStep>
|
||||
|
||||
@@ -11,7 +11,8 @@ export const createOrganization = writable<{
|
||||
name: string;
|
||||
billingPlan: Tier;
|
||||
paymentMethodId: string;
|
||||
billingAddress: Address;
|
||||
billingAddressId: string;
|
||||
billingAddress?: Address;
|
||||
collaborators?: string[];
|
||||
billingBudget?: number;
|
||||
taxId?: string;
|
||||
@@ -21,6 +22,7 @@ export const createOrganization = writable<{
|
||||
billingPlan: 'tier-1',
|
||||
paymentMethodId: null,
|
||||
collaborators: [],
|
||||
billingAddressId: null,
|
||||
billingAddress: {
|
||||
$id: null,
|
||||
streetAddress: null,
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<script lang="ts">
|
||||
import { FormItem, FormList, InputSelect, InputText } from '$lib/elements/forms';
|
||||
import { FormItem, FormList, InputRadio, InputSelect, InputText } from '$lib/elements/forms';
|
||||
import { WizardStep } from '$lib/layout';
|
||||
import { onMount } from 'svelte';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import { Alert } from '$lib/components';
|
||||
import { changeOrganizationTier, currentBillingAddress } from './store';
|
||||
import { changeOrganizationTier } from './store';
|
||||
import { organization } from '$lib/stores/organization';
|
||||
import { deepClone } from '$lib/helpers/object';
|
||||
import type { AddressesList } from '$lib/sdk/billing';
|
||||
|
||||
let options = [
|
||||
{
|
||||
@@ -14,8 +14,13 @@
|
||||
label: 'United States'
|
||||
}
|
||||
];
|
||||
let addressList: AddressesList;
|
||||
|
||||
onMount(async () => {
|
||||
addressList = await sdk.forConsole.billing.listAddresses();
|
||||
$changeOrganizationTier.billingAddressId = $organization.billingAddressId
|
||||
? $organization.billingAddressId
|
||||
: addressList.billingAddresses?.[0]?.$id ?? null;
|
||||
const countryList = await sdk.forProject.locale.listCountries();
|
||||
options = countryList.countries.map((country) => {
|
||||
return {
|
||||
@@ -23,13 +28,6 @@
|
||||
label: country.name
|
||||
};
|
||||
});
|
||||
|
||||
if ($organization.billingAddressId) {
|
||||
$currentBillingAddress = await sdk.forConsole.billing.getAddress(
|
||||
$organization.billingAddressId
|
||||
);
|
||||
$changeOrganizationTier.billingAddress = deepClone($currentBillingAddress);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -41,54 +39,98 @@
|
||||
Depending on your location, your billing address might need to be in the same country
|
||||
associated with the payment method for your organization.
|
||||
</Alert>
|
||||
<FormList gap={16} class="u-margin-block-start-24">
|
||||
<InputText
|
||||
bind:value={$changeOrganizationTier.taxId}
|
||||
id="text"
|
||||
label="Tax ID"
|
||||
placeholder="Enter tax ID"
|
||||
optionalText="(optional)" />
|
||||
<InputSelect
|
||||
bind:value={$changeOrganizationTier.billingAddress.country}
|
||||
{options}
|
||||
label="Country or region"
|
||||
placeholder="Select country or region"
|
||||
id="country"
|
||||
required />
|
||||
<InputText
|
||||
bind:value={$changeOrganizationTier.billingAddress.streetAddress}
|
||||
id="address"
|
||||
label="Street address"
|
||||
placeholder="Enter street address"
|
||||
required />
|
||||
<InputText
|
||||
bind:value={$changeOrganizationTier.billingAddress.addressLine2}
|
||||
id="address2"
|
||||
label="Address line 2"
|
||||
placeholder="Unit number, floor, etc." />
|
||||
<InputText
|
||||
bind:value={$changeOrganizationTier.billingAddress.city}
|
||||
id="city"
|
||||
label="City or suburb"
|
||||
placeholder="Enter your city"
|
||||
required />
|
||||
<FormItem isMultiple>
|
||||
<InputText
|
||||
isMultiple
|
||||
fullWidth
|
||||
bind:value={$changeOrganizationTier.billingAddress.state}
|
||||
id="state"
|
||||
label="State"
|
||||
placeholder="Enter your state"
|
||||
required />
|
||||
<InputText
|
||||
isMultiple
|
||||
fullWidth
|
||||
bind:value={$changeOrganizationTier.billingAddress.postalCode}
|
||||
id="zip"
|
||||
label="Postal code"
|
||||
placeholder="Enter postal code"
|
||||
required />
|
||||
</FormItem>
|
||||
|
||||
<p class="text u-margin-block-start-24"><b>Billing address</b></p>
|
||||
<FormList class="u-margin-block-start-8">
|
||||
<div class:boxes-wrapper={addressList?.total}>
|
||||
{#if addressList?.total}
|
||||
{#each addressList.billingAddresses as address}
|
||||
<div class="box">
|
||||
<InputRadio
|
||||
id={`address-${address.$id}`}
|
||||
value={address.$id}
|
||||
name="address"
|
||||
bind:group={$changeOrganizationTier.billingAddressId}>
|
||||
<div
|
||||
class="u-line-height-1-5 u-flex u-flex-vertical u-gap-2"
|
||||
style="padding-inline:0.25rem">
|
||||
<p class="text">{address.streetAddress}</p>
|
||||
{#if address?.addressLine2}
|
||||
<p class="text">{address.addressLine2}</p>
|
||||
{/if}
|
||||
<p class="text">{address.city}</p>
|
||||
<p class="text">{address.state}</p>
|
||||
<p class="text">{address.postalCode}</p>
|
||||
<p class="text">{address.country}</p>
|
||||
</div>
|
||||
</InputRadio>
|
||||
</div>
|
||||
{/each}
|
||||
{/if}
|
||||
|
||||
<div class="box">
|
||||
{#if addressList?.total}
|
||||
<InputRadio
|
||||
id="address"
|
||||
value={null}
|
||||
name="address"
|
||||
bind:group={$changeOrganizationTier.billingAddressId}>
|
||||
<span style="padding-inline:0.25rem">Add new billing address</span>
|
||||
</InputRadio>
|
||||
{/if}
|
||||
{#if $changeOrganizationTier.billingAddressId === null}
|
||||
<FormList gap={16} class="u-margin-block-start-24">
|
||||
<InputText
|
||||
bind:value={$changeOrganizationTier.taxId}
|
||||
id="text"
|
||||
label="Tax ID"
|
||||
placeholder="Enter tax ID"
|
||||
optionalText="(optional)" />
|
||||
<InputSelect
|
||||
bind:value={$changeOrganizationTier.billingAddress.country}
|
||||
{options}
|
||||
label="Country or region"
|
||||
placeholder="Select country or region"
|
||||
id="country"
|
||||
required />
|
||||
<InputText
|
||||
bind:value={$changeOrganizationTier.billingAddress.streetAddress}
|
||||
id="address"
|
||||
label="Street address"
|
||||
placeholder="Enter street address"
|
||||
required />
|
||||
<InputText
|
||||
bind:value={$changeOrganizationTier.billingAddress.addressLine2}
|
||||
id="address2"
|
||||
label="Address line 2"
|
||||
placeholder="Unit number, floor, etc." />
|
||||
<InputText
|
||||
bind:value={$changeOrganizationTier.billingAddress.city}
|
||||
id="city"
|
||||
label="City or suburb"
|
||||
placeholder="Enter your city"
|
||||
required />
|
||||
<FormItem isMultiple>
|
||||
<InputText
|
||||
isMultiple
|
||||
fullWidth
|
||||
bind:value={$changeOrganizationTier.billingAddress.state}
|
||||
id="state"
|
||||
label="State"
|
||||
placeholder="Enter your state"
|
||||
required />
|
||||
<InputText
|
||||
isMultiple
|
||||
fullWidth
|
||||
bind:value={$changeOrganizationTier.billingAddress.postalCode}
|
||||
id="zip"
|
||||
label="Postal code"
|
||||
placeholder="Enter postal code"
|
||||
required />
|
||||
</FormItem>
|
||||
</FormList>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</FormList>
|
||||
</WizardStep>
|
||||
|
||||
@@ -11,7 +11,8 @@ export const changeOrganizationTier = writable<{
|
||||
id?: string;
|
||||
billingPlan: Tier;
|
||||
paymentMethodId: string;
|
||||
billingAddress: Address;
|
||||
billingAddressId: string;
|
||||
billingAddress?: Address;
|
||||
billingBudget?: number;
|
||||
collaborators?: string[];
|
||||
isOverLimit?: boolean;
|
||||
@@ -31,6 +32,7 @@ export const changeOrganizationTier = writable<{
|
||||
paymentMethodId: null,
|
||||
collaborators: [],
|
||||
isOverLimit: false,
|
||||
billingAddressId: null,
|
||||
billingAddress: {
|
||||
$id: null,
|
||||
streetAddress: null,
|
||||
@@ -42,13 +44,3 @@ export const changeOrganizationTier = writable<{
|
||||
},
|
||||
taxId: null
|
||||
});
|
||||
|
||||
export const currentBillingAddress = writable<Address>({
|
||||
$id: null,
|
||||
streetAddress: null,
|
||||
addressLine2: null,
|
||||
city: null,
|
||||
state: null,
|
||||
postalCode: null,
|
||||
country: null
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user