- backend/handlers/user/account.go: Wire DELETE /api/user/account to call anonymize_user() for registered users and delete_guest_user() for guests, with CardDAV contact cleanup - backend/handlers/user/profile_test.go: Add TestAccount_DeleteGuest and enhance TestAccount_Delete to verify anonymization results - backend/main.go: Add GET /api/health endpoint with DB ping and S3 status check; add HSTS and Referrer-Policy security headers; replace http.ListenAndServe with http.Server + graceful SIGTERM/SIGINT shutdown - frontend/routes/+layout.svelte: Replace alert() with toast notifications for email verification flow - frontend/routes/login/+page.svelte: Replace alert() with toast.info for social login prototype buttons - frontend/booking/BookingFlow.svelte: Remove 2 console.log debug calls; add cancellation policy note in Step 3; add timezone policy comment - frontend/ImageUpload.svelte: Comment out debug console.log - init-scripts/init-script.sql: Add delete_guest_user() SQL function - docs: Update README.md and Obsidian notes to reflect completed items
71 lines
2.0 KiB
Svelte
71 lines
2.0 KiB
Svelte
<script lang="ts">
|
|
import '../app.css';
|
|
import favicon from '$lib/assets/favicon.svg';
|
|
import NavBar from '$lib/components/layout/NavBar.svelte';
|
|
import { Toaster } from '$lib/components/ui/sonner/index.js';
|
|
import { toast } from 'svelte-sonner';
|
|
import { authStore } from '$lib/stores/auth.svelte';
|
|
import { onMount } from 'svelte';
|
|
|
|
let { children } = $props();
|
|
|
|
// Default to 'top-center' (mobile-first approach)
|
|
let toasterPosition = $state<'top-center' | 'bottom-center'>('top-center');
|
|
|
|
function updateToasterPosition() {
|
|
// Use 640px (Tailwind's 'sm' breakpoint) to differentiate desktop and mobile
|
|
if (typeof window !== 'undefined' && window.innerWidth >= 768) {
|
|
toasterPosition = 'bottom-center';
|
|
} else {
|
|
toasterPosition = 'top-center';
|
|
}
|
|
}
|
|
|
|
onMount(() => {
|
|
updateToasterPosition();
|
|
window.addEventListener('resize', updateToasterPosition);
|
|
return () => {
|
|
window.removeEventListener('resize', updateToasterPosition);
|
|
};
|
|
});
|
|
|
|
// Verify email address
|
|
async function verify_email() {
|
|
const loadingToast = toast.loading('Verifying email address...');
|
|
const response = await fetch('/api/verify-email', {
|
|
method: 'POST'
|
|
});
|
|
|
|
if (response.ok) {
|
|
toast.success('Email verified successfully!', { id: loadingToast });
|
|
window.location.reload();
|
|
} else {
|
|
toast.error('Failed to verify email address', { id: loadingToast });
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<svelte:head>
|
|
<link rel="icon" href={favicon} />
|
|
</svelte:head>
|
|
|
|
<NavBar />
|
|
<Toaster position={toasterPosition} />
|
|
|
|
<main class="pt-16">
|
|
{#if authStore.currentUser?.role === 'unverified_email'}
|
|
<div class="w-full bg-red-600 py-2 pl-8 pr-8 text-center text-sm font-medium text-white">
|
|
Please verify your email address to continue. Didn't recieve the email? Check your spam
|
|
folder, or <button
|
|
type="button"
|
|
onclick={verify_email}
|
|
class="cursor-pointer border-0 bg-transparent p-0 text-white underline"
|
|
>
|
|
click here
|
|
</button>
|
|
to resend it.
|
|
</div>
|
|
{/if}
|
|
{@render children?.()}
|
|
</main>
|