mirror of
https://github.com/appwrite/console.git
synced 2026-06-06 19:27:48 +00:00
feat: add dedicated 402 budget limit error page
Replace generic error display for 402 responses with a dedicated budget limit error page. Includes a 'Go to billing' CTA when an organization is in context, and a 'Change organization' secondary action on both console-level and project-level error pages.
This commit is contained in:
@@ -5,7 +5,12 @@
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import { isVerifyEmailRedirectError } from '$lib/helpers/emailVerification';
|
||||
import { Container } from '$lib/layout';
|
||||
import { Typography } from '@appwrite.io/pink-svelte';
|
||||
import { Badge, Layout, Typography } from '@appwrite.io/pink-svelte';
|
||||
|
||||
const isPaymentError = $derived(page.status === 402);
|
||||
const billingUrl = $derived(
|
||||
page.params.organization ? `${base}/organization-${page.params.organization}/billing` : null
|
||||
);
|
||||
|
||||
$effect(() => {
|
||||
const verifyEmailPath = resolve('/verify-email');
|
||||
@@ -15,15 +20,59 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
<Container>
|
||||
<div>
|
||||
<Typography.Title size="xl"
|
||||
>{'status' in page.error
|
||||
? page.error.status || 'Invalid Argument'
|
||||
: 'Invalid Argument'}</Typography.Title>
|
||||
<Typography.Title>{page.error.message}</Typography.Title>
|
||||
</div>
|
||||
<div>
|
||||
<Button href={base}>Back to the console</Button>
|
||||
</div>
|
||||
</Container>
|
||||
{#if isPaymentError}
|
||||
<section class="budget-error">
|
||||
<div class="budget-error__content">
|
||||
<Layout.Stack gap="s" alignItems="center">
|
||||
<Badge type="error" variant="secondary" content="Budget limit reached" />
|
||||
<Layout.Stack gap="xs" alignItems="center">
|
||||
<Typography.Title size="l" align="center">
|
||||
Your organization has reached its budget limit
|
||||
</Typography.Title>
|
||||
<Typography.Text align="center">
|
||||
Access to resources has been blocked. Update your billing settings to
|
||||
restore access.
|
||||
</Typography.Text>
|
||||
</Layout.Stack>
|
||||
<div class="u-margin-block-start-16">
|
||||
<Layout.Stack direction="row" gap="s" justifyContent="center">
|
||||
{#if billingUrl}
|
||||
<Button href={billingUrl}>Go to billing</Button>
|
||||
{/if}
|
||||
<Button secondary href="{base}/account/organizations"
|
||||
>Change organization</Button>
|
||||
</Layout.Stack>
|
||||
</div>
|
||||
</Layout.Stack>
|
||||
</div>
|
||||
</section>
|
||||
{:else}
|
||||
<Container>
|
||||
<div>
|
||||
<Typography.Title size="xl"
|
||||
>{'status' in page.error
|
||||
? page.error.status || 'Invalid Argument'
|
||||
: 'Invalid Argument'}</Typography.Title>
|
||||
<Typography.Title>{page.error.message}</Typography.Title>
|
||||
</div>
|
||||
<div>
|
||||
<Button href={base}>Back to the console</Button>
|
||||
</div>
|
||||
</Container>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.budget-error {
|
||||
min-height: calc(100vh - 48px - 2rem);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 4rem 1.5rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.budget-error__content {
|
||||
width: min(100%, 33rem);
|
||||
max-width: 33rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<script lang="ts">
|
||||
import { base } from '$app/paths';
|
||||
import { page } from '$app/state';
|
||||
import { Button } from '$lib/elements/forms';
|
||||
import { currentPlan, organizationList } from '$lib/stores/organization';
|
||||
import { currentPlan, organization, organizationList } from '$lib/stores/organization';
|
||||
import SupportWizard from '$routes/(console)/supportWizard.svelte';
|
||||
import { wizard } from '$lib/stores/wizard';
|
||||
import { Badge, Layout, Typography } from '@appwrite.io/pink-svelte';
|
||||
import type { Models } from '@appwrite.io/console';
|
||||
|
||||
function contactSupport() {
|
||||
wizard.start(SupportWizard);
|
||||
}
|
||||
@@ -16,9 +16,39 @@
|
||||
);
|
||||
|
||||
$: hasPremiumSupport = $currentPlan?.premiumSupport ?? allOrgsHavePremiumSupport ?? false;
|
||||
|
||||
$: orgId = $organization?.$id;
|
||||
$: billingUrl = orgId ? `${base}/organization-${orgId}/billing` : null;
|
||||
$: isPaymentError = page.status === 402;
|
||||
</script>
|
||||
|
||||
{#if page.error.type === 'general_resource_blocked'}
|
||||
{#if isPaymentError}
|
||||
<section class="resource-blocked">
|
||||
<div class="resource-blocked__content">
|
||||
<Layout.Stack gap="s" alignItems="center">
|
||||
<Badge type="error" variant="secondary" content="Budget limit reached" />
|
||||
<Layout.Stack gap="xs" alignItems="center">
|
||||
<Typography.Title size="l" align="center">
|
||||
Your organization has reached its budget limit
|
||||
</Typography.Title>
|
||||
<Typography.Text align="center">
|
||||
Access to this resource has been blocked. Update your billing settings to
|
||||
restore access.
|
||||
</Typography.Text>
|
||||
</Layout.Stack>
|
||||
<div class="u-margin-block-start-16">
|
||||
<Layout.Stack direction="row" gap="s" justifyContent="center">
|
||||
{#if billingUrl}
|
||||
<Button href={billingUrl}>Go to billing</Button>
|
||||
{/if}
|
||||
<Button secondary href="{base}/account/organizations"
|
||||
>Change organization</Button>
|
||||
</Layout.Stack>
|
||||
</div>
|
||||
</Layout.Stack>
|
||||
</div>
|
||||
</section>
|
||||
{:else if page.error.type === 'general_resource_blocked'}
|
||||
<section class="resource-blocked">
|
||||
<div class="resource-blocked__content">
|
||||
<Layout.Stack gap="s" alignItems="center">
|
||||
|
||||
Reference in New Issue
Block a user