mirror of
https://github.com/appwrite/console.git
synced 2026-06-06 19:27:48 +00:00
fix: replace card and small refactor
This commit is contained in:
@@ -0,0 +1,152 @@
|
||||
<script lang="ts">
|
||||
import { Alert } from '$lib/components';
|
||||
import { onMount } from 'svelte';
|
||||
import Form from '$lib/elements/forms/form.svelte';
|
||||
import { trackEvent } from '$lib/actions/analytics';
|
||||
import { clickOnEnter } from '$lib/helpers/a11y';
|
||||
|
||||
export let show = false;
|
||||
export let size: 'small' | 'big' = 'big';
|
||||
export let icon: string = null;
|
||||
export let state: 'success' | 'warning' | 'error' | 'info' = null;
|
||||
export let error: string = null;
|
||||
export let closable = true;
|
||||
export let headerDivider = true;
|
||||
export let onSubmit: (e: SubmitEvent) => Promise<void> | void = function () {
|
||||
return;
|
||||
};
|
||||
export let title = '';
|
||||
export let description = '';
|
||||
|
||||
let backdrop: HTMLDivElement;
|
||||
|
||||
onMount(async () => {
|
||||
document.body.appendChild(backdrop);
|
||||
});
|
||||
|
||||
function handleBLur(event: MouseEvent) {
|
||||
if (event.target === backdrop) {
|
||||
trackEvent('click_close_modal', {
|
||||
from: 'backdrop'
|
||||
});
|
||||
closeModal();
|
||||
}
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
if (show) {
|
||||
show = false;
|
||||
document.documentElement.classList.remove('u-overflow-hidden');
|
||||
}
|
||||
}
|
||||
|
||||
function handleKeydown(event: KeyboardEvent) {
|
||||
if (event.key === 'Escape') {
|
||||
event.preventDefault();
|
||||
trackEvent('click_close_modal', {
|
||||
from: 'escape'
|
||||
});
|
||||
closeModal();
|
||||
}
|
||||
}
|
||||
|
||||
$: if (show) {
|
||||
document.documentElement.classList.add('u-overflow-hidden');
|
||||
} else {
|
||||
closeModal();
|
||||
error = null;
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window on:keydown={handleKeydown} />
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div
|
||||
class="payment-modal-backdrop"
|
||||
on:keyup={clickOnEnter}
|
||||
on:click={handleBLur}
|
||||
bind:this={backdrop}>
|
||||
<div
|
||||
class="modal payment-modal"
|
||||
class:is-small={size === 'small'}
|
||||
class:is-big={size === 'big'}
|
||||
class:is-separate-header={headerDivider}>
|
||||
<Form isModal {onSubmit}>
|
||||
<header class="modal-header">
|
||||
<div class="u-flex u-main-space-between u-cross-center u-gap-16">
|
||||
<div class="u-flex u-cross-center u-gap-16">
|
||||
{#if icon}
|
||||
<div
|
||||
class="avatar is-medium"
|
||||
class:is-success={state === 'success'}
|
||||
class:is-warning={state === 'warning'}
|
||||
class:is-danger={state === 'error'}
|
||||
class:is-info={state === 'info'}>
|
||||
<span class={`icon-${icon}`} aria-hidden="true" />
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<h4 class="modal-title heading-level-5">
|
||||
<slot name="title">
|
||||
{title}
|
||||
</slot>
|
||||
</h4>
|
||||
</div>
|
||||
{#if closable}
|
||||
<button
|
||||
type="button"
|
||||
class="button is-text is-only-icon"
|
||||
style="--button-size:1.5rem;"
|
||||
aria-label="Close Modal"
|
||||
title="Close Modal"
|
||||
on:click={() =>
|
||||
trackEvent('click_close_modal', {
|
||||
from: 'button'
|
||||
})}
|
||||
on:click={closeModal}>
|
||||
<span class="icon-x" aria-hidden="true" />
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
</header>
|
||||
<div class="modal-content">
|
||||
{#if error}
|
||||
<Alert
|
||||
dismissible
|
||||
type="warning"
|
||||
on:dismiss={() => {
|
||||
error = null;
|
||||
}}>
|
||||
{error}
|
||||
</Alert>
|
||||
{/if}
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
{#if $$slots.footer}
|
||||
<div class="modal-footer">
|
||||
<div class="u-flex u-main-end u-gap-16">
|
||||
<slot name="footer" />
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</Form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.payment-modal-backdrop {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 100000;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: hsl(240 22% 10% / 0.3);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
:global() {
|
||||
background-color: hsl(240 5% 8% / 0.6);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -67,3 +67,4 @@ export { default as SvgIcon } from './svgIcon.svelte';
|
||||
export { default as MigrationBox } from './migrationBox.svelte';
|
||||
export { default as FloatingActionBar } from './floatingActionBar.svelte';
|
||||
export { default as LoadingDots } from './loadingDots.svelte';
|
||||
export { default as FakeModal } from './fakeModal.svelte';
|
||||
|
||||
@@ -1,23 +1,18 @@
|
||||
<script lang="ts">
|
||||
import { Alert } from '$lib/components';
|
||||
import { FakeModal } from '$lib/components';
|
||||
import { InputText, Button, FormList } from '$lib/elements/forms';
|
||||
import { onMount } from 'svelte';
|
||||
import { initializeStripe, submitStripeCard } from '$lib/stores/stripe';
|
||||
import { invalidate } from '$app/navigation';
|
||||
import { Dependencies } from '$lib/constants';
|
||||
import { addNotification } from '$lib/stores/notifications';
|
||||
import Form from '$lib/elements/forms/form.svelte';
|
||||
import { trackEvent } from '$lib/actions/analytics';
|
||||
import { clickOnEnter } from '$lib/helpers/a11y';
|
||||
|
||||
export let show = false;
|
||||
|
||||
let name: string;
|
||||
let error: string;
|
||||
let backdrop: HTMLDivElement;
|
||||
|
||||
onMount(async () => {
|
||||
document.body.appendChild(backdrop);
|
||||
await initializeStripe();
|
||||
});
|
||||
|
||||
@@ -25,7 +20,7 @@
|
||||
try {
|
||||
await submitStripeCard(name);
|
||||
invalidate(Dependencies.PAYMENT_METHODS);
|
||||
closeModal();
|
||||
show = false;
|
||||
addNotification({
|
||||
type: 'success',
|
||||
message: 'A new payment method has been added to your account'
|
||||
@@ -35,121 +30,25 @@
|
||||
console.log(e.message);
|
||||
}
|
||||
}
|
||||
|
||||
function handleBLur(event: MouseEvent) {
|
||||
if (event.target === backdrop) {
|
||||
trackEvent('click_close_modal', {
|
||||
from: 'backdrop'
|
||||
});
|
||||
closeModal();
|
||||
}
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
if (show) {
|
||||
show = false;
|
||||
document.documentElement.classList.remove('u-overflow-hidden');
|
||||
}
|
||||
}
|
||||
|
||||
function handleKeydown(event: KeyboardEvent) {
|
||||
if (event.key === 'Escape') {
|
||||
event.preventDefault();
|
||||
trackEvent('click_close_modal', {
|
||||
from: 'escape'
|
||||
});
|
||||
closeModal();
|
||||
}
|
||||
}
|
||||
|
||||
$: if (show) {
|
||||
document.documentElement.classList.add('u-overflow-hidden');
|
||||
} else {
|
||||
closeModal();
|
||||
error = null;
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window on:keydown={handleKeydown} />
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div
|
||||
class="payment-modal-backdrop"
|
||||
on:keyup={clickOnEnter}
|
||||
on:click={handleBLur}
|
||||
bind:this={backdrop}>
|
||||
<div class="modal is-big payment-modal">
|
||||
<Form isModal onSubmit={handleSubmit}>
|
||||
<header class="modal-header">
|
||||
<div class="u-flex u-main-space-between u-cross-center u-gap-16">
|
||||
<div class="u-flex u-cross-center u-gap-16">
|
||||
<h4 class="modal-title heading-level-5">Add payment method</h4>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
class="button is-text is-only-icon"
|
||||
style="--button-size:1.5rem;"
|
||||
aria-label="Close Modal"
|
||||
title="Close Modal"
|
||||
on:click={() =>
|
||||
trackEvent('click_close_modal', {
|
||||
from: 'button'
|
||||
})}
|
||||
on:click={closeModal}>
|
||||
<span class="icon-x" aria-hidden="true" />
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
<div class="modal-content">
|
||||
{#if error}
|
||||
<Alert
|
||||
dismissible
|
||||
type="warning"
|
||||
on:dismiss={() => {
|
||||
error = null;
|
||||
}}>
|
||||
{error}
|
||||
</Alert>
|
||||
{/if}
|
||||
<FormList gap={16}>
|
||||
<InputText
|
||||
id="name"
|
||||
label="Cardholder name"
|
||||
placeholder="Cardholder name"
|
||||
bind:value={name}
|
||||
required
|
||||
autofocus={true}
|
||||
hideRequired />
|
||||
<FakeModal bind:show title="Add payment method" bind:error onSubmit={handleSubmit}>
|
||||
<FormList gap={16}>
|
||||
<InputText
|
||||
id="name"
|
||||
label="Cardholder name"
|
||||
placeholder="Cardholder name"
|
||||
bind:value={name}
|
||||
required
|
||||
autofocus={true}
|
||||
hideRequired />
|
||||
|
||||
<div id="payment-element">
|
||||
<!-- Elements will create form elements here -->
|
||||
</div>
|
||||
</FormList>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<div class="u-flex u-main-end u-gap-16">
|
||||
<Button secondary on:click={() => (show = false)}>Cancel</Button>
|
||||
<Button submit disabled={!name}>Save</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
.payment-modal-backdrop {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 100000;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: hsl(240 22% 10% / 0.3);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
:global() {
|
||||
background-color: hsl(240 5% 8% / 0.6);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<div id="payment-element">
|
||||
<!-- Elements will create form elements here -->
|
||||
</div>
|
||||
</FormList>
|
||||
<svelte:fragment slot="footer">
|
||||
<Button secondary on:click={() => (show = false)}>Cancel</Button>
|
||||
<Button submit disabled={!name}>Save</Button>
|
||||
</svelte:fragment>
|
||||
</FakeModal>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { invalidate } from '$app/navigation';
|
||||
import { CreditCardBrandImage, Modal } from '$lib/components';
|
||||
import { CreditCardBrandImage, FakeModal } from '$lib/components';
|
||||
import { Button, FormList, InputRadio, InputText } from '$lib/elements/forms';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import { organization } from '$lib/stores/organization';
|
||||
@@ -30,12 +30,10 @@
|
||||
// TODO: fix new payment method replacement
|
||||
async function handleSubmit() {
|
||||
try {
|
||||
console.log(selectedPaymentMethodId);
|
||||
if (!selectedPaymentMethodId) {
|
||||
const method = await submitStripeCard(name);
|
||||
selectedPaymentMethodId = method.$id;
|
||||
}
|
||||
console.log(selectedPaymentMethodId);
|
||||
isBackup
|
||||
? await addBackupPaymentMethod(selectedPaymentMethodId)
|
||||
: await addPaymentMethod(selectedPaymentMethodId);
|
||||
@@ -95,7 +93,7 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<Modal
|
||||
<FakeModal
|
||||
bind:show
|
||||
bind:error
|
||||
onSubmit={handleSubmit}
|
||||
@@ -103,61 +101,66 @@
|
||||
headerDivider={false}
|
||||
title="Replace payment method">
|
||||
<p class="text">Replace the existing payment method for your organization.</p>
|
||||
<div class:boxes-wrapper={methods?.total}>
|
||||
{#if methods?.total}
|
||||
{#each filteredMethods as method}
|
||||
<div class="box">
|
||||
<FormList>
|
||||
<div class:boxes-wrapper={methods?.total}>
|
||||
{#if methods?.total}
|
||||
{#each filteredMethods as method}
|
||||
<div class="box">
|
||||
<InputRadio
|
||||
id={`payment-method-${method.$id}`}
|
||||
disabled={isBackup
|
||||
? method.$id === $organization.paymentMethodId
|
||||
: method.$id === $organization.backupPaymentMethodId}
|
||||
value={method.$id}
|
||||
name="payment"
|
||||
bind:group={selectedPaymentMethodId}>
|
||||
<span class="u-flex u-gap-16 u-main-space-between">
|
||||
<span
|
||||
class="u-flex u-cross-center u-gap-8"
|
||||
style="padding-inline:0.25rem">
|
||||
<span>
|
||||
<span class="u-capitalize">{method.brand}</span> ending in {method.last4}</span>
|
||||
<CreditCardBrandImage brand={method.brand} />
|
||||
</span>
|
||||
{#if method.$id === $organization.backupPaymentMethodId}
|
||||
<Pill>Backup</Pill>
|
||||
{:else if method.$id === $organization.paymentMethodId}
|
||||
<Pill>Default</Pill>
|
||||
{/if}
|
||||
</span>
|
||||
</InputRadio>
|
||||
</div>
|
||||
{/each}
|
||||
{/if}
|
||||
|
||||
<div class="box">
|
||||
{#if methods?.total}
|
||||
<InputRadio
|
||||
id={`payment-method-${method.$id}`}
|
||||
disabled={isBackup
|
||||
? method.$id === $organization.paymentMethodId
|
||||
: method.$id === $organization.backupPaymentMethodId}
|
||||
value={method.$id}
|
||||
id="payment-method"
|
||||
value={null}
|
||||
name="payment"
|
||||
bind:group={selectedPaymentMethodId}>
|
||||
<span class="u-flex u-gap-16 u-main-space-between">
|
||||
<span class="u-flex u-cross-center u-gap-8">
|
||||
<span>
|
||||
<span class="u-capitalize">{method.brand}</span> ending in {method.last4}</span>
|
||||
<CreditCardBrandImage brand={method.brand} />
|
||||
</span>
|
||||
{#if method.$id === $organization.backupPaymentMethodId}
|
||||
<Pill>Backup</Pill>
|
||||
{:else if method.$id === $organization.paymentMethodId}
|
||||
<Pill>Default</Pill>
|
||||
{/if}
|
||||
</span>
|
||||
<span style="padding-inline:0.25rem">Add new payment method</span>
|
||||
</InputRadio>
|
||||
</div>
|
||||
{/each}
|
||||
{/if}
|
||||
{/if}
|
||||
{#if selectedPaymentMethodId === null}
|
||||
<FormList>
|
||||
<InputText
|
||||
id="name"
|
||||
label="Cardholder name"
|
||||
placeholder="Cardholder name"
|
||||
bind:value={name}
|
||||
required
|
||||
autofocus={true} />
|
||||
|
||||
<div class="box">
|
||||
{#if methods?.total}
|
||||
<InputRadio
|
||||
id="payment-method"
|
||||
label="Add new payment method"
|
||||
value={null}
|
||||
name="payment"
|
||||
bind:group={selectedPaymentMethodId} />
|
||||
{/if}
|
||||
{#if selectedPaymentMethodId === null}
|
||||
<FormList>
|
||||
<InputText
|
||||
id="name"
|
||||
label="Cardholder name"
|
||||
placeholder="Cardholder name"
|
||||
bind:value={name}
|
||||
required
|
||||
autofocus={true} />
|
||||
|
||||
<div id="payment-element">
|
||||
<!-- Elements will create form elements here -->
|
||||
</div>
|
||||
</FormList>
|
||||
{/if}
|
||||
<div id="payment-element">
|
||||
<!-- Elements will create form elements here -->
|
||||
</div>
|
||||
</FormList>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</FormList>
|
||||
<svelte:fragment slot="footer">
|
||||
<Button text on:click={() => (show = false)}>Cancel</Button>
|
||||
<Button
|
||||
@@ -167,4 +170,4 @@
|
||||
(isBackup ? $organization.backupPaymentMethodId : $organization.paymentMethodId)}
|
||||
>Save</Button>
|
||||
</svelte:fragment>
|
||||
</Modal>
|
||||
</FakeModal>
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
$: if ($changeOrganizationTier.billingPlan === 'tier-0' && $changeTierSteps) {
|
||||
$changeTierSteps = updateStepStatus($changeTierSteps, 2, true);
|
||||
$changeTierSteps = updateStepStatus($changeTierSteps, 3, true);
|
||||
$changeTierSteps = updateStepStatus($changeTierSteps, 4, true);
|
||||
}
|
||||
|
||||
$: if (
|
||||
@@ -26,6 +27,7 @@
|
||||
) {
|
||||
$changeTierSteps = updateStepStatus($changeTierSteps, 2, false);
|
||||
$changeTierSteps = updateStepStatus($changeTierSteps, 3, false);
|
||||
$changeTierSteps = updateStepStatus($changeTierSteps, 4, false);
|
||||
}
|
||||
|
||||
$: if ($changeOrganizationTier.billingPlan) {
|
||||
@@ -73,10 +75,12 @@
|
||||
members = await sdk.forConsole.teams.listMemberships($organization.$id);
|
||||
|
||||
//Select closest tier from starting one
|
||||
if ($organization.billingPlan === 'tier-2') {
|
||||
$changeOrganizationTier.billingPlan = 'tier-1';
|
||||
} else if ($organization.billingPlan === 'tier-1') {
|
||||
$changeOrganizationTier.billingPlan = 'tier-2';
|
||||
// if ($organization.billingPlan === 'tier-2') {
|
||||
// $changeOrganizationTier.billingPlan = 'tier-1';
|
||||
// }
|
||||
// else
|
||||
if ($organization.billingPlan === 'tier-1') {
|
||||
$changeOrganizationTier.billingPlan = 'tier-0';
|
||||
} else if ($organization.billingPlan === 'tier-0') {
|
||||
$changeOrganizationTier.billingPlan = 'tier-1';
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { Box, CreditCardBrandImage } from '$lib/components';
|
||||
import { Pill } from '$lib/elements';
|
||||
import { InputTextarea } from '$lib/elements/forms';
|
||||
import { FormList, InputTextarea } from '$lib/elements/forms';
|
||||
import { toLocaleDate } from '$lib/helpers/date';
|
||||
import { WizardStep } from '$lib/layout';
|
||||
import { plansInfo } from '$lib/stores/billing';
|
||||
@@ -56,11 +56,13 @@
|
||||
know.
|
||||
</svelte:fragment>
|
||||
<!-- TODO: submit feedback -->
|
||||
<InputTextarea
|
||||
id="comment"
|
||||
label="Your feedback here"
|
||||
placeholder="This is my reason for downgrading..."
|
||||
bind:value={comment} />
|
||||
<FormList>
|
||||
<InputTextarea
|
||||
id="comment"
|
||||
label="Your feedback here"
|
||||
placeholder="This is my reason for downgrading..."
|
||||
bind:value={comment} />
|
||||
</FormList>
|
||||
</WizardStep>
|
||||
{:else}
|
||||
<WizardStep>
|
||||
|
||||
Reference in New Issue
Block a user