mirror of
https://github.com/appwrite/console.git
synced 2026-06-06 19:27:48 +00:00
feat: retry failed payments
This commit is contained in:
1 parent
58bd9fc8b4
commit
431c5c2cf3
4 files changed
+110
-3
No files matched your search
@@ -263,6 +263,7 @@ export enum Submit {
|
||||
PaymentMethodCreate = 'submit_payment_method_create',
|
||||
PaymentMethodUpdate = 'submit_payment_method_update',
|
||||
PaymentMethodDelete = 'submit_payment_method_delete',
|
||||
RetryPayment = 'submit_retry_payment',
|
||||
BillingAddressCreate = 'submit_billing_address_create',
|
||||
BillingAddressUpdate = 'submit_billing_address_update',
|
||||
BillingAddressDelete = 'submit_billing_address_delete',
|
||||
|
||||
@@ -101,9 +101,15 @@ export async function submitStripeCard(name: string, urlRoute?: string) {
|
||||
}
|
||||
}
|
||||
|
||||
export async function confirmPayment(orgId: string, clientSecret: string, paymentMethodId: string) {
|
||||
export async function confirmPayment(
|
||||
orgId: string,
|
||||
clientSecret: string,
|
||||
paymentMethodId: string,
|
||||
route?: string
|
||||
) {
|
||||
try {
|
||||
const url = `${window.location.origin}/console/organization-${orgId}/billing`;
|
||||
const url =
|
||||
window.location.origin + route ? route : `/console/organization-${orgId}/billing`;
|
||||
|
||||
const paymentMethod = await sdk.forConsole.billing.getPaymentMethod(paymentMethodId);
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import {
|
||||
CardGrid,
|
||||
DropList,
|
||||
DropListItem,
|
||||
DropListLink,
|
||||
EmptySearch,
|
||||
Heading,
|
||||
@@ -20,13 +21,17 @@
|
||||
TableScroll
|
||||
} from '$lib/elements/table';
|
||||
import { toLocaleDate } from '$lib/helpers/date';
|
||||
import type { InvoiceList } from '$lib/sdk/billing';
|
||||
import type { Invoice, InvoiceList } from '$lib/sdk/billing';
|
||||
import { sdk } from '$lib/stores/sdk';
|
||||
import { VARS } from '$lib/system';
|
||||
import { Query } from '@appwrite.io/console';
|
||||
import { onMount } from 'svelte';
|
||||
import RetryPaymentModal from './retryPaymentModal.svelte';
|
||||
import { trackEvent } from '$lib/actions/analytics';
|
||||
|
||||
let showDropdown = [];
|
||||
let showRetryModal = false;
|
||||
let selectedInvoice: Invoice | null = null;
|
||||
|
||||
let offset = 0;
|
||||
let invoiceList: InvoiceList = {
|
||||
@@ -122,6 +127,21 @@
|
||||
event="download_invoice">
|
||||
Download PDF
|
||||
</DropListLink>
|
||||
{#if status === 'overdue' || status === 'failed'}
|
||||
<DropListItem
|
||||
icon="refresh"
|
||||
on:click={() => {
|
||||
selectedInvoice = invoice;
|
||||
showRetryModal = true;
|
||||
showDropdown[i] = !showDropdown[i];
|
||||
trackEvent(`click_retry_payment`, {
|
||||
from: 'button',
|
||||
source: 'billing_invoice_menu'
|
||||
});
|
||||
}}>
|
||||
Retry payment
|
||||
</DropListItem>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</DropList>
|
||||
</TableCell>
|
||||
@@ -144,3 +164,7 @@
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
</CardGrid>
|
||||
|
||||
{#if selectedInvoice}
|
||||
<RetryPaymentModal bind:show={showRetryModal} bind:invoice={selectedInvoice} />
|
||||
{/if}
|
||||
@@ -0,0 +1,76 @@
|
||||
<script lang="ts">
|
||||
import { invalidate } from '$app/navigation';
|
||||
import { FakeModal } from '$lib/components';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import { Dependencies } from '$lib/constants';
|
||||
import type { Invoice } from '$lib/sdk/billing';
|
||||
import { addNotification } from '$lib/stores/notifications';
|
||||
import { Submit, trackError, trackEvent } from '$lib/actions/analytics';
|
||||
import { page } from '$app/stores';
|
||||
import { VARS } from '$lib/system';
|
||||
import { confirmPayment } from '$lib/stores/stripe';
|
||||
import { organization } from '$lib/stores/organization';
|
||||
import { toLocaleDate } from '$lib/helpers/date';
|
||||
|
||||
const endpoint = VARS.APPWRITE_ENDPOINT ?? `${$page.url.origin}/v1`;
|
||||
export let show = false;
|
||||
export let invoice: Invoice;
|
||||
let error: string = null;
|
||||
let isButtonDisabled = false;
|
||||
|
||||
async function handleSubmit() {
|
||||
isButtonDisabled = true;
|
||||
try {
|
||||
await confirmPayment(
|
||||
$organization.$id,
|
||||
invoice.clientSecret,
|
||||
$organization.paymentMethodId
|
||||
);
|
||||
invalidate(Dependencies.ORGANIZATION);
|
||||
invalidate(Dependencies.INVOICES);
|
||||
|
||||
trackEvent(Submit.RetryPayment);
|
||||
addNotification({
|
||||
type: 'success',
|
||||
message: `Payment has been successfully processed`
|
||||
});
|
||||
show = false;
|
||||
} catch (e) {
|
||||
error = e.message;
|
||||
trackError(e, Submit.RetryPayment);
|
||||
} finally {
|
||||
isButtonDisabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
$: if (!show) {
|
||||
invoice = null;
|
||||
}
|
||||
</script>
|
||||
|
||||
<FakeModal
|
||||
bind:show
|
||||
bind:error
|
||||
state="warning"
|
||||
onSubmit={handleSubmit}
|
||||
size="big"
|
||||
headerDivider={false}
|
||||
title="Retry payment">
|
||||
<!-- TODO: format currency -->
|
||||
<p class="text">
|
||||
Your payment of <span class="inline-tag">${invoice.amount}</span> due on {toLocaleDate(
|
||||
invoice.dueAt
|
||||
)} has failed. Retry your payment to avoid service interruptions with your projects.
|
||||
</p>
|
||||
|
||||
<Button
|
||||
external
|
||||
link
|
||||
href={`${endpoint}/organizations/${$page.params.organization}/invoices/${invoice.$id}/view`}>
|
||||
View invoice
|
||||
</Button>
|
||||
<svelte:fragment slot="footer">
|
||||
<Button text on:click={() => (show = false)}>Cancel</Button>
|
||||
<Button secondary submit disabled={isButtonDisabled}>Retry</Button>
|
||||
</svelte:fragment>
|
||||
</FakeModal>
|
||||
Reference in new issue
Block a user