update: component to scroll to, better scroll logic.

This commit is contained in:
Darshan
2025-03-18 10:54:01 +05:30
parent 8df183b190
commit 21a4d714a4
4 changed files with 187 additions and 188 deletions
+4 -2
View File
@@ -70,7 +70,8 @@
class={resolvedClasses}
style="pointer-events: {internalDisabled ? 'none' : 'auto'};"
aria-label={ariaLabel}
use:multiAction={actions}>
use:multiAction={actions}
{...$$restProps}>
<slot />
</a>
{:else}
@@ -81,7 +82,8 @@
class={resolvedClasses}
aria-label={ariaLabel}
type={submit ? 'submit' : 'button'}
use:multiAction={actions}>
use:multiAction={actions}
{...$$restProps}>
{#if $isSubmitting && submissionLoader}
<span
class="loader is-small"
@@ -18,9 +18,7 @@
import { addNotification } from '$lib/stores/notifications';
import { currentPlan, organization } from '$lib/stores/organization';
import { sdk } from '$lib/stores/sdk';
import { onMount, tick } from 'svelte';
import { page } from '$app/stores';
import { scrollToUpdateBudget } from '$routes/(console)/organization-[organization]/billing/store';
import { onMount } from 'svelte';
export let alertsEnabled = false;
@@ -80,121 +78,106 @@
$: isButtonDisabled =
symmetricDifference(alerts, $organization.budgetAlerts).length === 0 || !alertsEnabled;
let formHolderElement: HTMLDivElement;
$: if ($scrollToUpdateBudget) {
history.replaceState(null, '', $page.url.pathname);
tick().then(() => {
formHolderElement?.scrollIntoView({
block: 'nearest'
});
});
}
</script>
<div id="update-budget-section" bind:this={formHolderElement} style:padding-block-start="1.5rem">
<Form onSubmit={updateBudget}>
<CardGrid>
<Heading tag="h2" size="6">Billing alerts</Heading>
<Form onSubmit={updateBudget}>
<CardGrid>
<Heading tag="h2" size="6">Billing alerts</Heading>
<p class="text">
{#if !$currentPlan.budgeting}
Get notified by email when your organization meets a percentage of your budget
cap. <b
>{tierToPlan($organization.billingPlan).name} organizations will receive one
notification at 75% resource usage.</b>
{:else}
Get notified by email when your organization meets or exceeds a percentage of
your specified billing alert(s).
{/if}
</p>
<svelte:fragment slot="aside">
{#if !$currentPlan.budgeting}
<p class="text">
{#if !$currentPlan.budgeting}
Get notified by email when your organization meets a percentage of your budget cap. <b
>{tierToPlan($organization.billingPlan).name} organizations will receive one notification
at 75% resource usage.</b>
{:else}
Get notified by email when your organization meets or exceeds a percentage of your
specified billing alert(s).
{/if}
</p>
<svelte:fragment slot="aside">
{#if !$currentPlan.budgeting}
<Alert type="info">
<svelte:fragment slot="title"
>Billing alerts are a Pro plan feature
</svelte:fragment>
Upgrade to a Pro plan to manage when you receive billing alerts for your organization.
</Alert>
{:else}
<FormList>
<Alert type="info">
<svelte:fragment slot="title"
>Billing alerts are a Pro plan feature
</svelte:fragment>
Upgrade to a Pro plan to manage when you receive billing alerts for your organization.
You can set a maximum of 4 billing alerts per organization.
</Alert>
{:else}
<FormList>
<Alert type="info">
You can set a maximum of 4 billing alerts per organization.
</Alert>
<div class="u-flex u-gap-16">
<InputSelectSearch
disabled={!alertsEnabled}
label="Percentage (%) of budget cap"
placeholder="Select a percentage"
id="alerts"
{options}
bind:search
interactiveOutput
bind:value={selectedAlert}
on:select={() => (search = selectedAlert.toString())} />
<div style="align-self: flex-end">
<Button
secondary
disabled={alerts.length > 3 ||
(!search && !selectedAlert) ||
!alertsEnabled}
on:click={addAlert}>
Add alert
</Button>
</div>
<div class="u-flex u-gap-16">
<InputSelectSearch
disabled={!alertsEnabled}
label="Percentage (%) of budget cap"
placeholder="Select a percentage"
id="alerts"
{options}
bind:search
interactiveOutput
bind:value={selectedAlert}
on:select={() => (search = selectedAlert.toString())} />
<div style="align-self: flex-end">
<Button
secondary
disabled={alerts.length > 3 ||
(!search && !selectedAlert) ||
!alertsEnabled}
on:click={addAlert}>
Add alert
</Button>
</div>
</FormList>
</div>
</FormList>
{#if alerts.length}
<Table noMargin noStyles transparent>
<TableHeader>
<TableCellHead>Alert at budget cap %</TableCellHead>
<TableCellHead width={30} />
</TableHeader>
<TableBody>
{#each alerts.sort() as alert}
<TableRow>
<TableCellText title="Percentage">
{alert}%
</TableCellText>
<TableCell>
<Button
text
round
ariaLabel="remove alert"
on:click={() =>
(alerts = alerts.filter((a) => a !== alert))}>
<span class="icon-x" aria-hidden="true" />
</Button>
</TableCell>
</TableRow>
{/each}
</TableBody>
</Table>
{/if}
{#if alerts.length}
<Table noMargin noStyles transparent>
<TableHeader>
<TableCellHead>Alert at budget cap %</TableCellHead>
<TableCellHead width={30} />
</TableHeader>
<TableBody>
{#each alerts.sort() as alert}
<TableRow>
<TableCellText title="Percentage">
{alert}%
</TableCellText>
<TableCell>
<Button
text
round
ariaLabel="remove alert"
on:click={() =>
(alerts = alerts.filter((a) => a !== alert))}>
<span class="icon-x" aria-hidden="true" />
</Button>
</TableCell>
</TableRow>
{/each}
</TableBody>
</Table>
{/if}
</svelte:fragment>
{/if}
</svelte:fragment>
<svelte:fragment slot="actions">
{#if $organization?.billingPlan === BillingPlan.FREE || $organization?.billingPlan === BillingPlan.GITHUB_EDUCATION}
<Button
secondary
href={$upgradeURL}
on:click={() => {
trackEvent('click_organization_upgrade', {
from: 'button',
source: 'billing_alerts_card'
});
}}
>Upgrade to Pro
</Button>
{:else}
<Button disabled={isButtonDisabled} submit>Update</Button>
{/if}
</svelte:fragment>
</CardGrid>
</Form>
</div>
<svelte:fragment slot="actions">
{#if $organization?.billingPlan === BillingPlan.FREE || $organization?.billingPlan === BillingPlan.GITHUB_EDUCATION}
<Button
secondary
href={$upgradeURL}
on:click={() => {
trackEvent('click_organization_upgrade', {
from: 'button',
source: 'billing_alerts_card'
});
}}
>Upgrade to Pro
</Button>
{:else}
<Button disabled={isButtonDisabled} submit>Update</Button>
{/if}
</svelte:fragment>
</CardGrid>
</Form>
@@ -8,8 +8,10 @@
import { addNotification } from '$lib/stores/notifications';
import { organization, currentPlan } from '$lib/stores/organization';
import { sdk } from '$lib/stores/sdk';
import { onMount } from 'svelte';
import { onMount, tick } from 'svelte';
import BudgetAlert from './budgetAlert.svelte';
import { page } from '$app/stores';
import { scrollToUpdateBudget } from './store';
let capActive = false;
let budget: number;
@@ -47,72 +49,91 @@
$: if (!capActive) {
budget = null;
}
let formHolderElement: HTMLDivElement;
$: if ($scrollToUpdateBudget) {
// clean the url in the search bar.
history.replaceState(null, '', $page.url.pathname);
tick().then(() => {
const elementTop = formHolderElement.getBoundingClientRect().top + window.scrollY;
// Offset 60 to prevent misalignment.
window.scrollTo({ top: elementTop - 60 });
});
}
</script>
<Form onSubmit={updateBudget}>
<CardGrid>
<Heading tag="h2" size="6">Budget cap</Heading>
<div id="update-budget-section" bind:this={formHolderElement} style:padding-block-start="1.5rem">
<Form onSubmit={updateBudget}>
<CardGrid>
<Heading tag="h2" size="6">Budget cap</Heading>
<p class="text">
Restrict your resource usage by setting a budget cap. Cap usage is reset at the
beginning of each billing cycle.
</p>
<svelte:fragment slot="aside">
{#if !$currentPlan.budgeting}
<Alert type="info">
<svelte:fragment slot="title">
Budget caps are a Pro plan feature
</svelte:fragment>
Upgrade to a Pro plan to set a budget cap for your organization. For more information
on what you can do with a Pro plan,
<a
class="link"
href="https://appwrite.io/pricing"
target="_blank"
rel="noopener noreferrer">view our pricing guide.</a>
</Alert>
{:else}
<FormList>
<InputSwitch id="cap-active" label="Enable budget cap" bind:value={capActive}>
<svelte:fragment slot="description">
Budget cap limits do not include the base amount of your plan. <button
class="link"
type="button"
on:click={() => ($showUsageRatesModal = true)}
>Learn more about usage rates.
</button>
<p class="text">
Restrict your resource usage by setting a budget cap. Cap usage is reset at the
beginning of each billing cycle.
</p>
<svelte:fragment slot="aside">
{#if !$currentPlan.budgeting}
<Alert type="info">
<svelte:fragment slot="title">
Budget caps are a Pro plan feature
</svelte:fragment>
</InputSwitch>
{#if capActive}
<InputNumber
placeholder="Add budget cap"
id="cap"
autofocus
label="Budget cap (USD)"
bind:value={budget} />
{/if}
</FormList>
{/if}
</svelte:fragment>
Upgrade to a Pro plan to set a budget cap for your organization. For more information
on what you can do with a Pro plan,
<a
class="link"
href="https://appwrite.io/pricing"
target="_blank"
rel="noopener noreferrer">view our pricing guide.</a>
</Alert>
{:else}
<FormList>
<InputSwitch
id="cap-active"
label="Enable budget cap"
bind:value={capActive}>
<svelte:fragment slot="description">
Budget cap limits do not include the base amount of your plan. <button
class="link"
type="button"
on:click={() => ($showUsageRatesModal = true)}
>Learn more about usage rates.
</button>
</svelte:fragment>
</InputSwitch>
{#if capActive}
<InputNumber
placeholder="Add budget cap"
id="cap"
autofocus
label="Budget cap (USD)"
bind:value={budget} />
{/if}
</FormList>
{/if}
</svelte:fragment>
<svelte:fragment slot="actions">
{#if $organization?.billingPlan === BillingPlan.FREE}
<Button
secondary
href={$upgradeURL}
on:click={() => {
trackEvent('click_organization_upgrade', {
from: 'button',
source: 'billing_budget_cap'
});
}}
>Upgrade to Pro
</Button>
{:else}
<Button disabled={$organization?.billingBudget === budget} submit>Update</Button>
{/if}
</svelte:fragment>
</CardGrid>
</Form>
<svelte:fragment slot="actions">
{#if $organization?.billingPlan === BillingPlan.FREE}
<Button
secondary
href={$upgradeURL}
on:click={() => {
trackEvent('click_organization_upgrade', {
from: 'button',
source: 'billing_budget_cap'
});
}}
>Upgrade to Pro
</Button>
{:else}
<Button disabled={$organization?.billingBudget === budget} submit
>Update</Button>
{/if}
</svelte:fragment>
</CardGrid>
</Form>
</div>
<BudgetAlert alertsEnabled={capActive && budget > 0} />
@@ -6,18 +6,9 @@
import { HeaderAlert } from '$lib/layout';
import { hideBillingHeaderRoutes, readOnly, showBudgetAlert } from '$lib/stores/billing';
import { base } from '$app/paths';
import { goto } from '$app/navigation';
$: isSameUrl = $page.url.pathname === redirectUrl;
$: redirectUrl = `${base}/organization-${$organization.$id}/billing`;
function scrollOrNavigate() {
if (isSameUrl) {
document.querySelector('#update-budget-section')?.scrollIntoView({ block: 'nearest' });
} else {
goto(`${redirectUrl}#update-budget`);
}
}
$: redirectUrl = `${base}/organization-${$organization.$id}/billing#update-budget`;
$: isSameUrl = $page.url.pathname === new URL(redirectUrl, window.location.origin).pathname;
</script>
{#if $showBudgetAlert && $organization?.$id && $organization?.billingPlan !== BillingPlan.FREE && $readOnly && !hideBillingHeaderRoutes.includes($page.url.pathname)}
@@ -30,7 +21,9 @@
<Button href={`${base}/organization-${$organization.$id}/usage`} text fullWidthMobile>
<span class="text">View usage</span>
</Button>
<Button secondary fullWidthMobile on:click={scrollOrNavigate}>
<!-- target="_self" for same page navigation -->
<Button secondary fullWidthMobile href={redirectUrl} target={isSameUrl ? '_self' : ''}>
<span class="text">Update limit</span>
</Button>
</svelte:fragment>