mirror of
https://github.com/jcreek/SvelteKitSaasBoilerplate.git
synced 2026-07-12 18:43:50 +00:00
254 lines
7.2 KiB
Svelte
254 lines
7.2 KiB
Svelte
<script lang="ts">
|
|
import { enhance } from '$app/forms';
|
|
import type { SubmitFunction } from '@sveltejs/kit';
|
|
|
|
export let data;
|
|
export let form;
|
|
|
|
let { session, user, subscriptions, transactions, pageSize } = data;
|
|
$: ({ session, supabase, user, transactions } = data);
|
|
|
|
let profileForm: HTMLFormElement;
|
|
let loading = false;
|
|
let name: string = user?.name ?? '';
|
|
|
|
const handleSubmit: SubmitFunction = () => {
|
|
loading = true;
|
|
return async () => {
|
|
loading = false;
|
|
};
|
|
};
|
|
|
|
const handleSignOut: SubmitFunction = () => {
|
|
loading = true;
|
|
return async ({ update }) => {
|
|
loading = false;
|
|
update();
|
|
};
|
|
};
|
|
|
|
const handleAccountDeletion: SubmitFunction = () => {
|
|
loading = true;
|
|
if (session.user && session.user.email) {
|
|
alert('Check your email to confirm account deletion.');
|
|
} else {
|
|
alert('Please sign in to delete your account.');
|
|
}
|
|
|
|
return async () => {
|
|
loading = false;
|
|
};
|
|
};
|
|
|
|
let startingAfter: string | undefined = undefined;
|
|
let endingBefore: string | undefined = undefined;
|
|
let hasNextPage = true;
|
|
let hasPreviousPage = false;
|
|
|
|
const handlePaginationSubmit: SubmitFunction = () => {
|
|
loading = true;
|
|
|
|
return async ({ result }) => {
|
|
transactions = JSON.parse(result.data.transactions);
|
|
hasNextPage = result.data.hasNextPage;
|
|
hasPreviousPage = !result.data.isFirstPage;
|
|
loading = false;
|
|
};
|
|
};
|
|
</script>
|
|
|
|
<div
|
|
class="account-page max-w-4xl mx-auto p-6 bg-base-100 rounded-lg shadow-md space-y-6 overflow-y-auto"
|
|
>
|
|
<!-- Flex container for two columns -->
|
|
<div class="flex flex-col lg:flex-row gap-6">
|
|
<!-- Left Column: Account Overview, Subscriptions, and Billing History -->
|
|
<div class="flex-1 space-y-6">
|
|
<!-- Account Overview -->
|
|
<section class="space-y-4">
|
|
<h2 class="text-xl font-semibold">Account Overview</h2>
|
|
<div class="form-control">
|
|
<label for="email" class="label font-medium">Email</label>
|
|
<input
|
|
id="email"
|
|
type="email"
|
|
class="input input-bordered"
|
|
value={session.user.email}
|
|
disabled
|
|
/>
|
|
</div>
|
|
<div class="text-sm text-gray-500">Signed in with magic link.</div>
|
|
<form
|
|
class="form-widget space-y-4"
|
|
method="post"
|
|
action="?/update"
|
|
use:enhance={handleSubmit}
|
|
bind:this={profileForm}
|
|
>
|
|
<div class="form-control">
|
|
<label for="name" class="label font-medium">Name</label>
|
|
<input
|
|
id="name"
|
|
name="name"
|
|
type="text"
|
|
value={form?.name ?? name}
|
|
class="input input-bordered w-full"
|
|
placeholder="Enter your name"
|
|
/>
|
|
</div>
|
|
|
|
<div>
|
|
<input
|
|
type="submit"
|
|
class="btn btn-primary w-full"
|
|
value={loading ? 'Loading...' : 'Update Name'}
|
|
disabled={loading}
|
|
/>
|
|
</div>
|
|
</form>
|
|
</section>
|
|
|
|
<!-- Active Subscriptions -->
|
|
<section class="space-y-4">
|
|
<h2 class="text-xl font-semibold">Subscriptions</h2>
|
|
{#if subscriptions.length === 0}
|
|
<p class="text-gray-600">You do not have any subscriptions.</p>
|
|
{:else}
|
|
<ul class="space-y-3">
|
|
{#each subscriptions as subscription}
|
|
<li class="p-4 border border-gray-200 rounded-md">
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<p class="font-semibold">{subscription.productName}</p>
|
|
<p class="text-sm text-gray-500">
|
|
Price: {subscription.amount}
|
|
{subscription.currency} / {subscription.interval}
|
|
</p>
|
|
<p class="text-sm text-gray-500">
|
|
Expiry Date: {subscription.expiryDate}
|
|
</p>
|
|
<p class="text-sm text-gray-500">
|
|
Status: {subscription.status}
|
|
</p>
|
|
</div>
|
|
<!-- <button class="btn btn-secondary btn-sm">Manage</button> -->
|
|
</div>
|
|
</li>
|
|
{/each}
|
|
</ul>
|
|
{/if}
|
|
</section>
|
|
|
|
<!-- Billing History -->
|
|
<section class="space-y-4">
|
|
<h2 class="text-xl font-semibold">Billing History</h2>
|
|
|
|
{#if transactions && transactions.length > 0}
|
|
<ul class="space-y-3">
|
|
{#each transactions as transaction}
|
|
<li class="flex justify-between p-4 border border-gray-200 rounded-md">
|
|
<div>
|
|
<p class="text-sm text-gray-500">Date: {transaction.created}</p>
|
|
<p class="text-sm text-gray-500">
|
|
Amount: {transaction.amount}
|
|
{transaction.currency}
|
|
</p>
|
|
</div>
|
|
{#if transaction.receipt_url}
|
|
<a href={transaction.receipt_url} class="btn btn-outline btn-sm" target="_blank">
|
|
Download Receipt
|
|
</a>
|
|
{:else}
|
|
<span class="text-gray-500">Receipt unavailable</span>
|
|
{/if}
|
|
</li>
|
|
{/each}
|
|
</ul>
|
|
{:else}
|
|
<p class="text-gray-600">No transactions found.</p>
|
|
{/if}
|
|
|
|
<!-- Pagination Form -->
|
|
<form method="post" action="?/paginate" use:enhance={handlePaginationSubmit}>
|
|
<div class="flex justify-center items-center space-x-2 mt-4">
|
|
<input type="hidden" name="startingAfter" value={startingAfter} />
|
|
<input type="hidden" name="endingBefore" value={endingBefore} />
|
|
|
|
<button
|
|
type="submit"
|
|
name="direction"
|
|
value="previous"
|
|
class="btn btn-outline"
|
|
disabled={!hasPreviousPage || loading}
|
|
on:click={() => {
|
|
if (transactions.length) {
|
|
endingBefore = transactions[0].id;
|
|
startingAfter = undefined;
|
|
}
|
|
}}
|
|
>
|
|
Previous
|
|
</button>
|
|
|
|
<button
|
|
type="submit"
|
|
name="direction"
|
|
value="next"
|
|
class="btn btn-outline"
|
|
disabled={!hasNextPage || loading}
|
|
on:click={() => {
|
|
if (transactions.length) {
|
|
startingAfter = transactions[transactions.length - 1].id;
|
|
endingBefore = undefined;
|
|
}
|
|
}}
|
|
>
|
|
Next
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</section>
|
|
</div>
|
|
|
|
<!-- Right Column: Notification Preferences and Feedback -->
|
|
<div class="flex-none w-full lg:w-64 space-y-6">
|
|
<!-- Notification Preferences -->
|
|
<section class="space-y-4">
|
|
<h2 class="text-xl font-semibold">Notification Preferences</h2>
|
|
<form method="post" action="?/update_notifications" class="space-y-2">
|
|
<label class="flex items-center space-x-3">
|
|
<input type="checkbox" class="checkbox checkbox-primary" />
|
|
<!-- checked={user.notifications.productUpdates} -->
|
|
<span>Product Updates</span>
|
|
</label>
|
|
<label class="flex items-center space-x-3">
|
|
<input type="checkbox" class="checkbox checkbox-primary" />
|
|
<!-- checked={user.notifications.billingReminders} -->
|
|
<span>Billing Reminders</span>
|
|
</label>
|
|
<label class="flex items-center space-x-3">
|
|
<input type="checkbox" class="checkbox checkbox-primary" />
|
|
<!-- checked={user.notifications.promotions} -->
|
|
<span>Promotional Emails</span>
|
|
</label>
|
|
</form>
|
|
</section>
|
|
|
|
<!-- Feedback Section -->
|
|
<section class="space-y-4">
|
|
<h2 class="text-xl font-semibold">Feedback</h2>
|
|
<p class="text-gray-600">
|
|
We'd love to hear your thoughts! Please feel free to provide any feedback.
|
|
</p>
|
|
<a href="/contact" class="btn btn-outline w-full">Provide Feedback</a>
|
|
</section>
|
|
</div>
|
|
|
|
<form method="post" action="?/delete" use:enhance={handleAccountDeletion}>
|
|
<div>
|
|
<button class="button block" disabled={loading}>Delete My Account</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|