Better skeleton use, live services in booking
This commit is contained in:
@@ -1,11 +1,21 @@
|
||||
<script lang="ts">
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import { Skeleton } from '$lib/components/ui/skeleton';
|
||||
import { navigating, page } from '$app/stores';
|
||||
import { authStore } from '$lib/stores/auth.svelte';
|
||||
|
||||
// Mobile menu state
|
||||
let mobileMenuOpen: boolean = false;
|
||||
// Centralized link definition
|
||||
const links = [
|
||||
{ href: '/', label: 'Home', showWhen: 'always', width: 'w-12' },
|
||||
{ href: '/prices', label: 'Price List', showWhen: 'guest', width: 'w-20' },
|
||||
{ href: '/book', label: 'Book your appointment', showWhen: 'auth', width: 'w-36' },
|
||||
{ href: '/portfolio', label: 'Portfolio', showWhen: 'always', width: 'w-20' },
|
||||
{ href: '/contact', label: 'Contact', showWhen: 'always', width: 'w-16' },
|
||||
{ href: '/account', label: 'My Account', showWhen: 'auth', width: 'w-24' },
|
||||
{ href: '/admin', label: 'Admin Dashboard', showWhen: 'admin', width: 'w-28' }
|
||||
];
|
||||
|
||||
let mobileMenuOpen: boolean = false;
|
||||
function toggleMenu() {
|
||||
mobileMenuOpen = !mobileMenuOpen;
|
||||
}
|
||||
@@ -14,6 +24,21 @@
|
||||
$: if ($navigating) {
|
||||
mobileMenuOpen = false;
|
||||
}
|
||||
|
||||
// Helper to decide visibility
|
||||
const canShow = (link: { href: string; label: string; showWhen: string; width: string }) => {
|
||||
if (authStore.isLoading) return true; // keep skeleton placeholders
|
||||
|
||||
// hide booking link for admins
|
||||
if (link.href === '/book' && authStore.currentUser?.role === 'admin') return false;
|
||||
if (link.href === '/contact' && authStore.currentUser?.role === 'admin') return false;
|
||||
|
||||
if (link.showWhen === 'always') return true;
|
||||
if (link.showWhen === 'guest' && !authStore.isAuthenticated) return true;
|
||||
if (link.showWhen === 'auth' && authStore.isAuthenticated) return true;
|
||||
if (link.showWhen === 'admin' && authStore.currentUser?.role === 'admin') return true;
|
||||
return false;
|
||||
};
|
||||
</script>
|
||||
|
||||
<nav
|
||||
@@ -42,36 +67,37 @@
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="feather feather-instagram"
|
||||
><rect x="2" y="2" width="20" height="20" rx="5" ry="5"></rect><path
|
||||
d="M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z"
|
||||
></path><line x1="17.5" y1="6.5" x2="17.51" y2="6.5"></line></svg
|
||||
>
|
||||
<rect x="2" y="2" width="20" height="20" rx="5" ry="5"></rect>
|
||||
<path d="M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z"></path>
|
||||
<line x1="17.5" y1="6.5" x2="17.51" y2="6.5"></line>
|
||||
</svg>
|
||||
</a>
|
||||
<!-- Add more social icons here -->
|
||||
</div>
|
||||
|
||||
<!-- Center: Links -->
|
||||
<!-- Center: Desktop Links -->
|
||||
<div class="hidden space-x-8 md:flex">
|
||||
<a href="/" class="hover:text-primary font-medium text-gray-800">Home</a>
|
||||
{#if !authStore?.isAuthenticated}
|
||||
<a href="/prices" class="hover:text-primary font-medium text-gray-800">Price List</a>
|
||||
{:else}
|
||||
<a href="/book" class="hover:text-primary font-medium text-gray-800"
|
||||
>Book your appointment</a
|
||||
>
|
||||
{/if}
|
||||
<a href="/portfolio" class="hover:text-primary font-medium text-gray-800">Portfolio</a>
|
||||
<a href="/contact" class="hover:text-primary font-medium text-gray-800">Contact</a>
|
||||
{#if authStore?.isAuthenticated}
|
||||
<a href="/account" class="hover:text-primary font-medium text-gray-800">My Account</a>
|
||||
{/if}
|
||||
{#each links as link}
|
||||
{#if canShow(link)}
|
||||
{#if authStore.isLoading}
|
||||
<Skeleton class={`h-4 ${link.width} rounded`} />
|
||||
{:else}
|
||||
<a href={link.href} class="hover:text-primary font-medium text-gray-800"
|
||||
>{link.label}</a
|
||||
>
|
||||
{/if}
|
||||
{/if}
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<!-- Desktop Login Button -->
|
||||
<div class="hidden items-center md:flex">
|
||||
<!-- if not logged in and not on login page -->
|
||||
{#if !authStore?.isAuthenticated && $page.url.pathname !== '/login'}
|
||||
{#if !authStore.isLoading && !authStore.isAuthenticated && $page.url.pathname !== '/login'}
|
||||
<Button href="/login">Login</Button>
|
||||
{/if}
|
||||
{#if authStore.isLoading}
|
||||
<Skeleton class="h-8 w-16 rounded" />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- Mobile: Burger -->
|
||||
@@ -94,41 +120,25 @@
|
||||
{#if mobileMenuOpen}
|
||||
<div class="bg-background border-b border-gray-200 md:hidden">
|
||||
<div class="space-y-1 px-2 pb-3 pt-2">
|
||||
<a href="/" class="text-primary block rounded px-3 py-2 text-center hover:text-gray-800"
|
||||
>Home</a
|
||||
>
|
||||
{#each links as link}
|
||||
{#if canShow(link)}
|
||||
{#if authStore.isLoading}
|
||||
<Skeleton class="h-4 w-full rounded" />
|
||||
{:else}
|
||||
<a
|
||||
href={link.href}
|
||||
class="text-primary block rounded px-3 py-2 text-center hover:text-gray-800"
|
||||
>
|
||||
{link.label}
|
||||
</a>
|
||||
{/if}
|
||||
{/if}
|
||||
{/each}
|
||||
|
||||
{#if !authStore?.isAuthenticated}
|
||||
<a
|
||||
href="/prices"
|
||||
class="text-primary block rounded px-3 py-2 text-center hover:text-gray-800"
|
||||
>Price list</a
|
||||
>
|
||||
{:else}
|
||||
<a
|
||||
href="/book"
|
||||
class="text-primary block rounded px-3 py-2 text-center hover:text-gray-800"
|
||||
>Book your appointment</a
|
||||
>
|
||||
{/if}
|
||||
|
||||
<a
|
||||
href="/portfolio"
|
||||
class="text-primary block rounded px-3 py-2 text-center hover:text-gray-800">Portfolio</a
|
||||
>
|
||||
<a
|
||||
href="/contact"
|
||||
class="text-primary block rounded px-3 py-2 text-center hover:text-gray-800">Contact</a
|
||||
>
|
||||
|
||||
{#if !authStore?.isAuthenticated}
|
||||
{#if authStore.isLoading}
|
||||
<Skeleton class="mt-2 h-8 w-full rounded" />
|
||||
{:else if !authStore.isAuthenticated}
|
||||
<Button href="/login" class="mt-2 w-full text-center">Login</Button>
|
||||
{:else}
|
||||
<a
|
||||
href="/Account"
|
||||
class="text-primary block rounded px-3 py-2 text-center hover:text-gray-800"
|
||||
>My Account</a
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -50,6 +50,11 @@ class AuthStore {
|
||||
return this.loading;
|
||||
}
|
||||
|
||||
get hasLoaded() {
|
||||
return !this.loading;
|
||||
}
|
||||
|
||||
|
||||
private initializeAuth() {
|
||||
const storedToken = localStorage.getItem('authToken');
|
||||
if (storedToken) {
|
||||
|
||||
Reference in New Issue
Block a user