Spaces:
Sleeping
Sleeping
| @page "/" | |
| @using LibraryManagement.Shared.Models | |
| @using BlazorWebAssembly.Services | |
| @using Microsoft.AspNetCore.Components.Authorization | |
| @inject LibraryApiClient ApiClient | |
| @inject NavigationManager Navigation | |
| @inject AuthenticationStateProvider AuthStateProvider | |
| <AuthorizeView> | |
| <Authorized> | |
| <!-- Authenticated Dashboard View --> | |
| <div class="space-y-12 animate-fade"> | |
| <section> | |
| <h1 class="text-4xl font-black tracking-tight mb-2 text-main"> | |
| Welcome back, <span class="text-primary">@context.User.Identity?.Name</span> | |
| </h1> | |
| <p class="text-lg text-muted">Here is what's happening with your library account today.</p> | |
| </section> | |
| <AuthorizeView Roles="Librarian" Context="LibrarianContext"> | |
| <Authorized> | |
| <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-12"> | |
| <div class="bg-card p-6 flex flex-col gap-3 group border border-border rounded-3xl transition-all shadow-sm"> | |
| <div class="flex items-center justify-between"> | |
| <span class="text-[10px] font-black text-muted uppercase tracking-widest">Total Books</span> | |
| </div> | |
| <div class="text-3xl font-black text-main">@_totalBooks</div> | |
| </div> | |
| <div class="bg-card p-6 flex flex-col gap-3 group border border-border rounded-3xl transition-all shadow-sm"> | |
| <div class="flex items-center justify-between"> | |
| <span class="text-[10px] font-black text-muted uppercase tracking-widest">Active Loans</span> | |
| </div> | |
| <div class="text-3xl font-black text-main">@_activeLoans</div> | |
| </div> | |
| <div class="bg-card p-6 flex flex-col gap-3 group border border-border rounded-3xl transition-all shadow-sm border-l-4 border-l-red-500"> | |
| <div class="flex items-center justify-between"> | |
| <span class="text-[10px] font-black text-red-500 uppercase tracking-widest">Overdue</span> | |
| </div> | |
| <div class="text-3xl font-black text-red-600">@_overdueLoans</div> | |
| </div> | |
| <div class="bg-card p-6 flex flex-col gap-3 group border border-border rounded-3xl transition-all shadow-sm"> | |
| <div class="flex items-center justify-between"> | |
| <span class="text-[10px] font-black text-muted uppercase tracking-widest">Active Members</span> | |
| </div> | |
| <div class="text-3xl font-black text-main">@_totalMembers</div> | |
| </div> | |
| </div> | |
| </Authorized> | |
| </AuthorizeView> | |
| <AuthorizeView Roles="Member" Context="MemberContext"> | |
| <Authorized> | |
| <div class="grid grid-cols-1 md:grid-cols-3 gap-8"> | |
| <!-- Loyalty Points --> | |
| <div class="bg-card p-8 rounded-3xl border border-border shadow-sm hover:shadow-md transition-all"> | |
| <p class="text-[10px] font-black text-muted uppercase tracking-widest mb-4">Loyalty Balance</p> | |
| <div class="flex items-baseline gap-2 mb-4"> | |
| <h3 class="text-5xl font-black text-main">@(_loyaltyAccount?.CurrentBalance.ToString("N0") ?? "0")</h3> | |
| <span class="text-xs font-bold text-primary">POINTS</span> | |
| </div> | |
| <div class="flex items-center justify-between"> | |
| <span class="text-xs font-bold text-muted uppercase">Tier: @(_loyaltyAccount?.Tier ?? "Member")</span> | |
| </div> | |
| </div> | |
| <!-- Active Loans --> | |
| <div class="bg-card p-8 rounded-3xl border border-border shadow-sm hover:shadow-md transition-all"> | |
| <p class="text-[10px] font-black text-muted uppercase tracking-widest mb-4">Current Loans</p> | |
| <h3 class="text-5xl font-black text-main mb-4">@_activeLoans</h3> | |
| <div class="flex gap-2"> | |
| @if (_overdueLoans > 0) | |
| { | |
| <span class="px-3 py-1 bg-red-500/10 text-red-600 text-[10px] font-black uppercase rounded-lg">@_overdueLoans Overdue</span> | |
| } | |
| else | |
| { | |
| <span class="px-3 py-1 bg-green-500/10 text-green-600 text-[10px] font-black uppercase rounded-lg">Healthy</span> | |
| } | |
| </div> | |
| </div> | |
| <!-- Subscription --> | |
| <div class="bg-card p-8 rounded-3xl border border-border shadow-sm hover:shadow-md transition-all"> | |
| <p class="text-[10px] font-black text-muted uppercase tracking-widest mb-4">Membership</p> | |
| <h3 class="text-2xl font-black text-main mb-1 uppercase">@(_currentSub?.MembershipType ?? "Free")</h3> | |
| <p class="text-xs text-muted mb-6">@( _currentSub != null ? "Active Status" : "No Active Plan" )</p> | |
| <a href="/membership" class="text-xs font-black text-primary uppercase tracking-widest hover:underline">Manage Plan</a> | |
| </div> | |
| </div> | |
| </Authorized> | |
| </AuthorizeView> | |
| <section> | |
| <h2 class="text-xl font-bold mb-6 text-main">Recent Arrivals</h2> | |
| @if (_recentBooks.Any()) | |
| { | |
| <div class="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-6 gap-6"> | |
| @foreach (var book in _recentBooks) | |
| { | |
| <a href="/books" class="group cursor-pointer"> | |
| <div class="bg-card aspect-[2/3] rounded-2xl border border-border overflow-hidden relative mb-2 group-hover:border-primary/50 transition-colors"> | |
| @if (!string.IsNullOrEmpty(book.CoverUrl)) | |
| { | |
| <img src="@book.CoverUrl" alt="@book.Title" class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-500" /> | |
| } | |
| else | |
| { | |
| <div class="absolute inset-0 flex items-center justify-center text-primary/20 group-hover:text-primary/40 transition-colors"> | |
| <svg class="w-12 h-12" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18 18.246 18.477 16.5 18c-1.746 0-3.332.477-4.5 1.253"></path></svg> | |
| </div> | |
| } | |
| </div> | |
| <h3 class="text-xs font-bold text-main truncate">@book.Title</h3> | |
| <p class="text-[10px] text-muted truncate">@book.Author</p> | |
| </a> | |
| } | |
| </div> | |
| } | |
| else | |
| { | |
| <div class="text-muted text-sm italic">Loading recent arrivals...</div> | |
| } | |
| </section> | |
| </div> | |
| </Authorized> | |
| <NotAuthorized> | |
| <!-- Guest Landing Page --> | |
| <div class="space-y-32 animate-fade pb-24"> | |
| <!-- Hero Section --> | |
| <section class="relative pt-20 overflow-hidden"> | |
| <div class="max-w-7xl mx-auto px-8 relative z-10"> | |
| <div class="text-center"> | |
| <div class="inline-flex items-center gap-2 px-4 py-2 rounded-full bg-primary/10 text-primary text-[10px] font-black uppercase tracking-widest mb-8 animate-bounce"> | |
| <span class="relative flex h-2 w-2"> | |
| <span class="animate-ping absolute inline-flex h-full w-full rounded-full bg-primary opacity-75"></span> | |
| <span class="relative inline-flex rounded-full h-2 w-2 bg-primary"></span> | |
| </span> | |
| New: Audiobooks Collection Now Live | |
| </div> | |
| <h1 class="text-8xl font-black tracking-tighter text-main mb-8 leading-[0.9]"> | |
| Where Every Page <br /> | |
| <span class="text-transparent bg-clip-text bg-gradient-to-r from-primary to-emerald-500 italic">Finds a Purpose.</span> | |
| </h1> | |
| <p class="text-xl text-muted max-w-2xl mx-auto leading-relaxed mb-12"> | |
| Join the next generation of readers in a digital-first library experience. Access thousands of titles, earn loyalty rewards, and track your progress seamlessly. | |
| </p> | |
| <div class="flex flex-col sm:flex-row items-center justify-center gap-6"> | |
| <a href="/register" class="w-full sm:w-auto bg-primary text-white px-10 py-5 rounded-2xl font-black text-lg hover:bg-primary-hover shadow-2xl shadow-primary/30 transition-all transform hover:scale-105 active:scale-95 inline-block text-center"> | |
| Start Reading Now | |
| </a> | |
| <a href="/membership" class="w-full sm:w-auto bg-card border border-border text-main px-10 py-5 rounded-2xl font-black text-lg hover:bg-body transition-all inline-block text-center"> | |
| View Memberships | |
| </a> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Background Decorative Elements --> | |
| <div class="absolute top-0 left-1/2 -translate-x-1/2 w-full h-full -z-10 pointer-events-none opacity-20"> | |
| <div class="absolute top-20 left-1/4 w-96 h-96 bg-primary/30 rounded-full blur-[120px]"></div> | |
| <div class="absolute bottom-0 right-1/4 w-96 h-96 bg-emerald-500/20 rounded-full blur-[120px]"></div> | |
| </div> | |
| </section> | |
| <!-- Stats Grid --> | |
| <div class="max-w-7xl mx-auto px-8"> | |
| <div class="grid grid-cols-2 md:grid-cols-4 gap-8 bg-card border border-border p-12 rounded-[3rem] shadow-xl"> | |
| <div class="text-center"> | |
| <h3 class="text-5xl font-black text-main mb-2 tracking-tighter">12k+</h3> | |
| <p class="text-muted font-bold uppercase tracking-widest text-[10px]">Verified Books</p> | |
| </div> | |
| <div class="text-center border-l border-border"> | |
| <h3 class="text-5xl font-black text-main mb-2 tracking-tighter">5.2k</h3> | |
| <p class="text-muted font-bold uppercase tracking-widest text-[10px]">Active Readers</p> | |
| </div> | |
| <div class="text-center border-l border-border"> | |
| <h3 class="text-5xl font-black text-main mb-2 tracking-tighter">98%</h3> | |
| <p class="text-muted font-bold uppercase tracking-widest text-[10px]">Satisfaction</p> | |
| </div> | |
| <div class="text-center border-l border-border"> | |
| <h3 class="text-5xl font-black text-main mb-2 tracking-tighter">24/7</h3> | |
| <p class="text-muted font-bold uppercase tracking-widest text-[10px]">Digital Access</p> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Features Section --> | |
| <section class="max-w-7xl mx-auto px-8"> | |
| <div class="text-center mb-20"> | |
| <h2 class="text-xs font-black text-primary uppercase tracking-[0.3em] mb-4">Core Ecosystem</h2> | |
| <h3 class="text-5xl font-black text-main tracking-tight">Everything you need to <br/> master your reading journey.</h3> | |
| </div> | |
| <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8"> | |
| <!-- Feature 1 --> | |
| <div class="group bg-card p-10 rounded-[2.5rem] border border-border hover:border-primary/50 transition-all hover:shadow-2xl hover:shadow-primary/5"> | |
| <div class="w-14 h-14 bg-primary/10 rounded-2xl flex items-center justify-center text-primary mb-8 group-hover:scale-110 transition-transform"> | |
| <svg class="w-7 h-7" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18 18.246 18.477 16.5 18c-1.746 0-3.332.477-4.5 1.253"></path></svg> | |
| </div> | |
| <h4 class="text-xl font-bold text-main mb-4 uppercase tracking-tight">Borrow Thousands</h4> | |
| <p class="text-muted text-sm leading-relaxed">Access our vast physical and digital catalog with a single click. No more waiting in lines.</p> | |
| </div> | |
| <!-- Feature 2 --> | |
| <div class="group bg-card p-10 rounded-[2.5rem] border border-border hover:border-primary/50 transition-all hover:shadow-2xl hover:shadow-primary/5"> | |
| <div class="w-14 h-14 bg-primary/10 rounded-2xl flex items-center justify-center text-primary mb-8 group-hover:scale-110 transition-transform"> | |
| <svg class="w-7 h-7" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"></path></svg> | |
| </div> | |
| <h4 class="text-xl font-bold text-main mb-4 uppercase tracking-tight">Track Reading</h4> | |
| <p class="text-muted text-sm leading-relaxed">Visualize your reading habits with detailed analytics and personal dashboards.</p> | |
| </div> | |
| <!-- Feature 3 --> | |
| <div class="group bg-card p-10 rounded-[2.5rem] border border-border hover:border-primary/50 transition-all hover:shadow-2xl hover:shadow-primary/5"> | |
| <div class="w-14 h-14 bg-primary/10 rounded-2xl flex items-center justify-center text-primary mb-8 group-hover:scale-110 transition-transform"> | |
| <svg class="w-7 h-7" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9"></path></svg> | |
| </div> | |
| <h4 class="text-xl font-bold text-main mb-4 uppercase tracking-tight">Stay Notified</h4> | |
| <p class="text-muted text-sm leading-relaxed">Never miss a due date with Firebase-powered instant renewal notifications.</p> | |
| </div> | |
| <!-- Feature 4 --> | |
| <div class="group bg-card p-10 rounded-[2.5rem] border border-border hover:border-primary/50 transition-all hover:shadow-2xl hover:shadow-primary/5"> | |
| <div class="w-14 h-14 bg-primary/10 rounded-2xl flex items-center justify-center text-primary mb-8 group-hover:scale-110 transition-transform"> | |
| <svg class="w-7 h-7" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M12 8v13m0-13V6a2 2 0 112 2h-2zm0 0V5.5A2.5 2.5 0 109.5 8H12zm-7 4h14M5 12a2 2 0 110-4h14a2 2 0 110 4M5 12v7a2 2 0 002 2h10a2 2 0 002-2v-7"></path></svg> | |
| </div> | |
| <h4 class="text-xl font-bold text-main mb-4 uppercase tracking-tight">Earn Loyalty</h4> | |
| <p class="text-muted text-sm leading-relaxed">Collect points for every interaction and redeem them for premium membership tiers.</p> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- Testimonials --> | |
| <section class="bg-body border-y border-border py-32 relative overflow-hidden"> | |
| <div class="max-w-7xl mx-auto px-8 relative z-10"> | |
| <div class="grid grid-cols-1 lg:grid-cols-2 gap-24 items-center"> | |
| <div> | |
| <h2 class="text-xs font-black text-primary uppercase tracking-[0.3em] mb-4">Wall of Praise</h2> | |
| <h3 class="text-6xl font-black text-main tracking-tighter mb-8 leading-tight">Loved by <br/> modern readers.</h3> | |
| <p class="text-lg text-muted leading-relaxed mb-12"> | |
| Don't just take our word for it. Join thousands of satisfied members who have transformed their reading habits. | |
| </p> | |
| <div class="flex gap-4"> | |
| <div class="flex -space-x-4"> | |
| @for(int i=1; i<=4; i++) { | |
| <div class="w-12 h-12 rounded-full border-4 border-card bg-primary/20 flex items-center justify-center text-xs font-bold">U@i</div> | |
| } | |
| </div> | |
| <div class="flex flex-col justify-center"> | |
| <span class="text-sm font-black text-main uppercase">5,000+ Active Members</span> | |
| <span class="text-[10px] text-muted font-bold uppercase tracking-widest">Global Community</span> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="space-y-6"> | |
| <div class="bg-card p-10 rounded-[2.5rem] border border-border shadow-xl transform hover:-rotate-1 transition-transform"> | |
| <div class="flex gap-1 text-primary mb-6"> | |
| @for(int i=0; i<5; i++) { <svg class="w-4 h-4 fill-current" viewBox="0 0 20 20"><path d="M9.049 2.927c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.371 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.54 1.118l-2.8-2.034a1 1 0 00-1.175 0l-2.8 2.034c-.784.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.364-1.118L2.98 8.72c-.783-.57-.38-1.81.588-1.81h3.461a1 1 0 00.951-.69l1.07-3.292z"/></svg> } | |
| </div> | |
| <p class="text-main font-medium italic mb-6 leading-relaxed">"The loyalty system is a game changer. I've earned three months of free premium just by returning my books on time!"</p> | |
| <div class="flex items-center gap-4"> | |
| <div class="w-10 h-10 rounded-full bg-primary/10 flex items-center justify-center font-black text-xs text-primary">SC</div> | |
| <div> | |
| <h5 class="text-sm font-bold text-main">Sarah Chen</h5> | |
| <p class="text-[10px] text-muted font-bold uppercase">Gold Member</p> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="bg-card p-10 rounded-[2.5rem] border border-border shadow-xl transform translate-x-8 hover:rotate-1 transition-transform"> | |
| <p class="text-main font-medium italic mb-6 leading-relaxed">"Finally a library system that feels like it belongs in 2026. The interface is stunning and the notifications are so helpful."</p> | |
| <div class="flex items-center gap-4"> | |
| <div class="w-10 h-10 rounded-full bg-primary/10 flex items-center justify-center font-black text-xs text-primary">JM</div> | |
| <div> | |
| <h5 class="text-sm font-bold text-main">James Miller</h5> | |
| <p class="text-[10px] text-muted font-bold uppercase">Active Reader</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- Final CTA --> | |
| <section class="max-w-7xl mx-auto px-8"> | |
| <div class="bg-primary p-16 md:p-24 rounded-[4rem] text-center text-white relative overflow-hidden shadow-2xl shadow-primary/40"> | |
| <div class="relative z-10"> | |
| <h2 class="text-5xl md:text-7xl font-black tracking-tighter mb-8 leading-tight">Ready to start your <br/> next chapter?</h2> | |
| <p class="text-xl text-white/80 max-w-2xl mx-auto mb-12 font-medium">Join thousands of readers today and get your first month of Premium for free.</p> | |
| <div class="flex flex-col sm:flex-row items-center justify-center gap-6"> | |
| <a href="/register" class="w-full sm:w-auto bg-white text-primary px-12 py-6 rounded-2xl font-black text-xl hover:bg-white/90 transition-all transform hover:scale-105 shadow-xl">Create Free Account</a> | |
| <a href="/contact" class="w-full sm:w-auto border-2 border-white/30 text-white px-12 py-6 rounded-2xl font-black text-xl hover:bg-white/10 transition-all">Talk to Librarian</a> | |
| </div> | |
| </div> | |
| <!-- CTA Decoration --> | |
| <div class="absolute top-0 right-0 -translate-y-1/2 translate-x-1/2 w-[600px] h-[600px] bg-white/10 rounded-full blur-[100px]"></div> | |
| </div> | |
| </section> | |
| </div> | |
| </NotAuthorized> | |
| </AuthorizeView> | |
| @code { | |
| private int _totalBooks = 0; | |
| private int _activeLoans = 0; | |
| private int _overdueLoans = 0; | |
| private int _totalMembers = 0; | |
| private IEnumerable<BookDto> _recentBooks = Enumerable.Empty<BookDto>(); | |
| private LoyaltyAccountDto? _loyaltyAccount; | |
| private SubscriptionDto? _currentSub; | |
| private bool _isLoading = true; | |
| protected override async Task OnInitializedAsync() | |
| { | |
| try | |
| { | |
| var authState = await AuthStateProvider.GetAuthenticationStateAsync(); | |
| var user = authState.User; | |
| if (user.Identity?.IsAuthenticated == true) | |
| { | |
| var books = await ApiClient.GetBooksAsync(); | |
| _totalBooks = books.Count(); | |
| _recentBooks = books.Take(6); | |
| if (user.IsInRole("Member")) | |
| { | |
| try { | |
| var borrowings = await ApiClient.GetMyBorrowingsAsync(); | |
| _activeLoans = borrowings.Count(b => b.Status == "Borrowed"); | |
| _overdueLoans = borrowings.Count(b => b.Status == "Overdue" || (b.Status == "Borrowed" && b.DueDate < DateTime.UtcNow)); | |
| _loyaltyAccount = await ApiClient.GetMyLoyaltyAccountAsync(); | |
| _currentSub = await ApiClient.GetMySubscriptionAsync(); | |
| } catch {} | |
| } | |
| if (user.IsInRole("Librarian")) | |
| { | |
| try { | |
| var allBorrowings = await ApiClient.GetAllBorrowingsAsync(); | |
| _activeLoans = allBorrowings.Count(b => b.Status == "Borrowed"); | |
| _overdueLoans = allBorrowings.Count(b => b.Status == "Overdue" || (b.Status == "Borrowed" && b.DueDate < DateTime.UtcNow)); | |
| var members = await ApiClient.GetUsersAsync(); | |
| _totalMembers = members.Count(); | |
| } catch {} | |
| } | |
| } | |
| } | |
| catch { } | |
| finally | |
| { | |
| _isLoading = false; | |
| } | |
| } | |
| } | |