Homepage: restored original v0 design, replaced lorem ipsum with real service descriptions, added BusinessHours (Opening Hours) section, alternating bg-gray-50 section backgrounds. Layout: added global sticky footer (hidden on /admin/schedule, /account, and ?format=pdf pages), wrapped content in min-h-screen flex layout. PortfolioCarousel: set heading to Playfair Display.
110 lines
3.3 KiB
Svelte
110 lines
3.3 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';
|
|
import { page } from '$app/stores';
|
|
|
|
const { children } = $props();
|
|
|
|
let hideFooter = $derived(
|
|
$page.url.pathname === '/admin/schedule' ||
|
|
$page.url.pathname === '/account' ||
|
|
$page.url.searchParams.get('format') === 'pdf'
|
|
);
|
|
|
|
// 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
|
|
// TODO: `/api/verify-email` doesn't exist in the backend. The correct endpoints are
|
|
// `POST /api/verify/generate` (send verification code) and `POST /api/verify/check` (verify code).
|
|
// This call silently 404s. Fix required — either add the missing backend route or refactor
|
|
// to use `/api/verify/generate` + `/api/verify/check`.
|
|
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} />
|
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="anonymous" />
|
|
<link
|
|
href="https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400..900;1,400..900&display=swap"
|
|
rel="stylesheet"
|
|
/>
|
|
</svelte:head>
|
|
|
|
<div class="flex min-h-screen flex-col">
|
|
<NavBar />
|
|
<Toaster position={toasterPosition} />
|
|
|
|
<main class="flex-1 pt-16">
|
|
{#if authStore.currentUser?.role === 'unverified_email'}
|
|
<div class="w-full bg-red-600 py-2 pr-8 pl-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>
|
|
|
|
{#if !hideFooter}
|
|
<footer class="border-t py-3 text-center text-xs text-gray-500 md:py-4 md:text-sm">
|
|
© {new Date().getFullYear()} Crussell Nails. All rights reserved.
|
|
</footer>
|
|
{/if}
|
|
</div>
|
|
|
|
<style>
|
|
@media print {
|
|
:global(nav) {
|
|
display: none !important;
|
|
}
|
|
:global(main > div.bg-red-600) {
|
|
display: none !important;
|
|
}
|
|
:global(main) {
|
|
padding-top: 0 !important;
|
|
}
|
|
}
|
|
</style>
|