fix and expand paymentBoxes

This commit is contained in:
Arman
2024-02-05 15:35:50 +01:00
parent 8ed33ceeaf
commit 62adbd503a
5 changed files with 74 additions and 129 deletions
+35 -6
View File
@@ -1,12 +1,18 @@
<script lang="ts">
import { FormList, InputText } from '$lib/elements/forms';
import { FormList, InputChoice, InputText } from '$lib/elements/forms';
import { onDestroy, onMount } from 'svelte';
import { CreditCardBrandImage, RadioBoxes } from '..';
import { unmountPaymentElement } from '$lib/stores/stripe';
import { Pill } from '$lib/elements';
export let methods: Record<string, unknown>[];
export let group: string;
export let name: string;
export let defaultMethod: string = null;
export let backupMethod: string = null;
export let disabledCondition: string = null;
export let setAsDefault = false;
export let showSetAsDefault = false;
let element: HTMLDivElement;
let loader: HTMLDivElement;
@@ -42,13 +48,36 @@
}
</script>
<RadioBoxes elements={methods} total={methods?.length} variableName="$id" name="payment" bind:group>
<RadioBoxes
elements={methods}
total={methods?.length}
variableName="$id"
name="payment"
bind:group
{disabledCondition}>
<svelte:fragment slot="element" let:element>
<slot {element}>
<span class="u-flex u-cross-center u-gap-8" style="padding-inline:0.25rem">
<span>
<span class="u-capitalize">{element.brand}</span> ending in {element.last4}</span>
<CreditCardBrandImage brand={element.brand?.toString()} />
<span class="u-flex u-gap-16 u-flex-vertical">
<span class="u-flex u-gap-16">
<span class="u-flex u-cross-center u-gap-8" style="padding-inline:0.25rem">
<span>
<span class="u-capitalize">{element.brand}</span> ending in {element.last4}</span>
<CreditCardBrandImage brand={element.brand?.toString()} />
</span>
{#if element.$id === backupMethod}
<Pill>Backup</Pill>
{:else if element.$id === defaultMethod}
<Pill>Default</Pill>
{/if}
</span>
{#if !!defaultMethod && element.$id !== defaultMethod && group === element.$id && showSetAsDefault}
<ul>
<InputChoice
bind:value={setAsDefault}
id="default"
label="Set as default payment method for this organization" />
</ul>
{/if}
</span>
</slot>
</svelte:fragment>
+4 -4
View File
@@ -13,7 +13,7 @@
{#if total}
{#each elements as element}
{@const value = element[variableName]?.toString()}
<div class="box" data-private>
<ul class="box" data-private>
<InputRadio
id={`${name}-${value}`}
{value}
@@ -22,11 +22,11 @@
disabled={disabledCondition ? value === disabledCondition : false}>
<slot name="element" {element} />
</InputRadio>
</div>
</ul>
{/each}
{/if}
<div class="box">
<ul class="box">
{#if total}
<InputRadio id="payment-method" value={null} {name} bind:group>
<slot name="new">
@@ -37,5 +37,5 @@
{#if group === null}
<slot />
{/if}
</div>
</ul>
</div>
@@ -127,7 +127,7 @@
event="download_invoice">
Download PDF
</DropListLink>
{#if status === 'overdue' || status === 'failed'}
{#if status === 'overdue' || status === 'failed' || true}
<DropListItem
icon="refresh"
on:click={() => {
@@ -1,16 +1,16 @@
<script lang="ts">
import { invalidate } from '$app/navigation';
import { CreditCardBrandImage, FakeModal } from '$lib/components';
import { Button, FormList, InputRadio, InputText } from '$lib/elements/forms';
import { FakeModal } from '$lib/components';
import { Button } from '$lib/elements/forms';
import { sdk } from '$lib/stores/sdk';
import { organization } from '$lib/stores/organization';
import { Dependencies } from '$lib/constants';
import { initializeStripe, isStripeInitialized, submitStripeCard } from '$lib/stores/stripe';
import { onDestroy, onMount } from 'svelte';
import { submitStripeCard } from '$lib/stores/stripe';
import { onMount } from 'svelte';
import type { PaymentList } from '$lib/sdk/billing';
import { addNotification } from '$lib/stores/notifications';
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
import { Pill } from '$lib/elements';
import { PaymentBoxes } from '$lib/components/billing';
export let show = false;
export let isBackup = false;
@@ -18,10 +18,6 @@
let selectedPaymentMethodId: string;
let name: string;
let error: string;
let element: HTMLDivElement;
let loader: HTMLDivElement;
let observer: MutationObserver;
onMount(async () => {
methods = await sdk.forConsole.billing.listPaymentMethods();
@@ -32,27 +28,6 @@
selectedPaymentMethodId = isBackup
? $organization.backupPaymentMethodId
: $organization.paymentMethodId;
observer = new MutationObserver((mutationsList) => {
for (let mutation of mutationsList) {
if (mutation.type === 'childList') {
if (mutation.addedNodes.length > 0) {
for (let node of Array.from(mutation.addedNodes)) {
if (
node instanceof Element &&
node.className.toLowerCase().includes('__privatestripeelement')
) {
loader.style.display = 'none';
}
}
}
}
}
});
});
onDestroy(() => {
observer.disconnect();
});
async function handleSubmit() {
@@ -105,19 +80,8 @@
}
}
$: if (selectedPaymentMethodId === null && !$isStripeInitialized && show) {
initializeStripe();
}
$: filteredMethods = methods?.paymentMethods.filter((method) => !!method?.last4);
$: if (show) {
isStripeInitialized.set(false);
if (element) {
observer.observe(element, { childList: true });
}
}
$: if (!show) {
selectedPaymentMethodId = null;
}
@@ -131,70 +95,16 @@
headerDivider={false}
title="Replace payment method">
<p class="text">Replace the existing payment method for your organization.</p>
<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"
value={null}
name="payment"
bind:group={selectedPaymentMethodId}>
<span style="padding-inline:0.25rem">Add new payment method</span>
</InputRadio>
{/if}
{#if selectedPaymentMethodId === null}
<FormList>
<InputText
id="name"
label="Cardholder name"
placeholder="Cardholder name"
bind:value={name}
required
autofocus={true} />
<div class="aw-stripe-container" data-private>
<div class="loader-container" bind:this={loader}>
<div class="loader"></div>
</div>
<div id="payment-element" bind:this={element}>
<!-- Stripe will create form elements here -->
</div>
</div>
</FormList>
{/if}
</div>
</div>
</FormList>
<PaymentBoxes
methods={filteredMethods}
bind:name
bind:group={selectedPaymentMethodId}
defaultMethod={$organization?.paymentMethodId}
backupMethod={$organization?.backupPaymentMethodId}
disabledCondition={isBackup
? $organization.paymentMethodId
: $organization.backupPaymentMethodId} />
<svelte:fragment slot="footer">
<Button text on:click={() => (show = false)}>Cancel</Button>
<Button
@@ -206,17 +116,3 @@
</Button>
</svelte:fragment>
</FakeModal>
<style lang="scss">
.aw-stripe-container {
min-height: 295px;
position: relative;
.loader-container {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 0;
}
}
</style>
@@ -11,12 +11,22 @@
import { confirmPayment } from '$lib/stores/stripe';
import { organization } from '$lib/stores/organization';
import { toLocaleDate } from '$lib/helpers/date';
import { PaymentBoxes } from '$lib/components/billing';
import { paymentMethods } from '$lib/stores/billing';
import { onMount } from 'svelte';
const endpoint = VARS.APPWRITE_ENDPOINT ?? `${$page.url.origin}/v1`;
export let show = false;
export let invoice: Invoice;
let error: string = null;
let isButtonDisabled = false;
let name: string;
let paymentMethodId: string;
let setAsDefault = false;
onMount(() => {
paymentMethodId = $organization.paymentMethodId;
});
async function handleSubmit() {
isButtonDisabled = true;
@@ -42,6 +52,7 @@
isButtonDisabled = false;
}
}
$: filteredMethods = $paymentMethods?.paymentMethods.filter((method) => !!method?.last4);
$: if (!show) {
invoice = null;
@@ -69,6 +80,15 @@
href={`${endpoint}/organizations/${$page.params.organization}/invoices/${invoice.$id}/view`}>
View invoice
</Button>
<PaymentBoxes
methods={filteredMethods}
defaultMethod={$organization?.paymentMethodId}
backupMethod={$organization?.backupPaymentMethodId}
showSetAsDefault
bind:setAsDefault
bind:name
bind:group={paymentMethodId} />
<svelte:fragment slot="footer">
<Button text on:click={() => (show = false)}>Cancel</Button>
<Button secondary submit disabled={isButtonDisabled}>Retry</Button>