Merge version_2 into main #3

Merged
bender merged 10 commits from version_2 into main 2026-03-09 19:52:09 +00:00
10 changed files with 1214 additions and 1691 deletions

View File

@@ -3,24 +3,21 @@
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
import NavbarLayoutFloatingInline from "@/components/navbar/NavbarLayoutFloatingInline";
import TextAbout from "@/components/sections/about/TextAbout";
import TeamCardTwo from "@/components/sections/team/TeamCardTwo";
import MetricCardSeven from "@/components/sections/metrics/MetricCardSeven";
import ContactCTA from "@/components/sections/contact/ContactCTA";
import FooterBaseCard from "@/components/sections/footer/FooterBaseCard";
import Link from "next/link";
import { Linkedin, Twitter, Heart, Globe, Mail } from "lucide-react";
import { Heart, Shield, Users, Award } from "lucide-react";
const AboutPage = () => {
export default function AboutPage() {
const navItems = [
{ name: "Home", id: "/" },
{ name: "Browse Animals", id: "/animals" },
{ name: "About", id: "about" },
{ name: "About", id: "/about" },
{ name: "Contact", id: "contact" },
];
const footerColumns = [
{
title: "Adoption",
items: [
title: "Adoption", items: [
{ label: "Browse Pets", href: "/animals" },
{ label: "How to Adopt", href: "#how-it-works" },
{ label: "Adoption Stories", href: "#adoption-stories" },
@@ -28,8 +25,7 @@ const AboutPage = () => {
],
},
{
title: "Company",
items: [
title: "Company", items: [
{ label: "About Us", href: "/about" },
{ label: "Our Team", href: "#team" },
{ label: "Partner with Us", href: "/partner" },
@@ -37,8 +33,7 @@ const AboutPage = () => {
],
},
{
title: "Support",
items: [
title: "Support", items: [
{ label: "Contact Us", href: "/contact" },
{ label: "Donate", href: "/donate" },
{ label: "Volunteer", href: "/volunteer" },
@@ -46,8 +41,7 @@ const AboutPage = () => {
],
},
{
title: "Legal",
items: [
title: "Legal", items: [
{ label: "Privacy Policy", href: "#" },
{ label: "Terms of Service", href: "#" },
{ label: "Cookie Policy", href: "#" },
@@ -73,169 +67,70 @@ const AboutPage = () => {
<NavbarLayoutFloatingInline
navItems={navItems}
brandName="PawsHome"
button={{
text: "Start Adoption",
href: "/animals",
}}
button={{ text: "Start Adoption", href: "/animals" }}
animateOnLoad={true}
/>
</div>
<div id="about" data-section="about">
<div id="mission" data-section="mission">
<TextAbout
tag="Our Mission"
tagIcon={Heart}
tagAnimation="slide-up"
title="We believe every animal deserves a loving home and every family deserves the joy of pet companionship"
useInvertedBackground={true}
title="Transforming Lives Through Pet Adoption: Our Mission to Connect Loving Families with Deserving Animals"
useInvertedBackground={false}
buttons={[
{
text: "Our Story",
href: "/about",
},
{
text: "How We Help",
href: "#how-it-works",
},
{ text: "Get Involved", href: "/contact" },
{ text: "Become a Partner", href: "/partner" },
]}
buttonAnimation="slide-up"
/>
</div>
<div id="team" data-section="team">
<TeamCardTwo
title="Meet Our Dedicated Team"
description="Passionate animal lovers and adoption specialists committed to finding perfect homes for every pet in our care."
tag="Our Team"
tagIcon={Heart}
<div id="shelter-info" data-section="shelter-info">
<TextAbout
tag="About Our Shelter"
tagIcon={Users}
tagAnimation="slide-up"
textboxLayout="default"
animationType="slide-up"
title="PawsHome is a comprehensive animal welfare organization dedicated to rescuing, rehabilitating, and rehoming animals in need. Our state-of-the-art facility provides medical care, behavioral support, and individual attention to every animal in our care, ensuring they are healthy, happy, and ready for their forever homes."
useInvertedBackground={true}
gridVariant="three-columns-all-equal-width"
members={[
{
id: "1",
name: "Emma Thompson",
role: "Founder & Director",
description:
"Veterinarian with 15 years of experience in animal welfare and sanctuary management. Passionate about creating systemic change in pet adoption.",
imageSrc: "http://img.b2bpic.net/free-photo/doctor-carrying-little-gray-puppy_329181-10394.jpg",
imageAlt: "Emma Thompson, Founder & Director",
socialLinks: [
{
icon: Linkedin,
url: "https://linkedin.com",
},
{
icon: Twitter,
url: "https://twitter.com",
},
],
},
{
id: "2",
name: "Marcus Rodriguez",
role: "Adoption Counselor",
description:
"Former shelter manager with deep expertise in matching families with the right pets. Has facilitated over 800 successful adoptions.",
imageSrc: "http://img.b2bpic.net/free-photo/pet-owner-pouring-water-his-friend-bowl_259150-57216.jpg",
imageAlt: "Marcus Rodriguez, Adoption Counselor",
socialLinks: [
{
icon: Linkedin,
url: "https://linkedin.com",
},
{
icon: Heart,
url: "https://example.com",
},
],
},
{
id: "3",
name: "Aisha Patel",
role: "Animal Care Manager",
description:
"Certified animal behaviorist dedicated to ensuring every pet receives individualized care and attention while waiting for their new families.",
imageSrc: "http://img.b2bpic.net/free-photo/x-ray-image-puppy-s-body_329181-14495.jpg",
imageAlt: "Aisha Patel, Animal Care Manager",
socialLinks: [
{
icon: Linkedin,
url: "https://linkedin.com",
},
{
icon: Globe,
url: "https://example.com",
},
],
},
{
id: "4",
name: "James Chen",
role: "Volunteer Coordinator",
description:
"Organizes and manages 50+ active volunteers. Passionate about community engagement and building a support network around animal adoption.",
imageSrc: "http://img.b2bpic.net/free-photo/happy-man-looking-camera-while-holding-cellphone-near-red-wall_23-2148193969.jpg",
imageAlt: "James Chen, Volunteer Coordinator",
socialLinks: [
{
icon: Linkedin,
url: "https://linkedin.com",
},
{
icon: Mail,
url: "mailto:james@pawshome.com",
},
],
},
buttons={[
{ text: "Visit Our Facility", href: "/contact" },
{ text: "Volunteer With Us", href: "/volunteer" },
]}
buttonAnimation="slide-up"
/>
</div>
<div id="metrics" data-section="metrics">
<MetricCardSeven
title="Our Impact By The Numbers"
description="Real statistics showing the difference we're making in animal welfare and pet adoption across our network."
tag="Success Metrics"
tagIcon={Heart}
<div id="values" data-section="values">
<TextAbout
tag="Our Core Values"
tagIcon={Award}
tagAnimation="slide-up"
textboxLayout="default"
animationType="slide-up"
title="Compassion, Transparency, Excellence. We believe in treating every animal with dignity and respect, operating with complete transparency in all our processes, and maintaining the highest standards of animal care and adoption practices."
useInvertedBackground={false}
metrics={[
{
id: "1",
value: "2,500+",
title: "Animals Successfully Adopted",
items: [
"All thoroughly vetted and health-checked",
"Average adoption timeline: 2-3 weeks",
"95% success rate on first-attempt matches",
],
},
{
id: "2",
value: "150+",
title: "Partner Shelters & Rescues",
items: [
"Network across 25 states",
"Supporting small and large operations",
"Unified adoption platform access",
],
},
{
id: "3",
value: "15K+",
title: "Active Community Members",
items: [
"Engaged adopters and supporters",
"50+ trained volunteer advocates",
"Growing monthly membership",
],
},
buttons={[
{ text: "Learn Our Standards", href: "#" },
{ text: "Read Our Impact Report", href: "#" },
]}
buttonAnimation="slide-up"
/>
</div>
<div id="contact-cta" data-section="contact-cta">
<ContactCTA
tag="Questions About Our Shelter"
tagIcon={Shield}
tagAnimation="slide-up"
title="We'd Love to Hear from You"
description="Whether you have questions about our services, want to schedule a facility tour, or are interested in partnership opportunities, our team is here to help."
background={{ variant: "radial-gradient" }}
buttons={[
{ text: "Contact Us", href: "/contact" },
{ text: "Schedule a Tour", href: "/contact" },
]}
buttonAnimation="slide-up"
useInvertedBackground={true}
/>
</div>
@@ -248,6 +143,4 @@ const AboutPage = () => {
</div>
</ThemeProvider>
);
};
export default AboutPage;
}

342
src/app/admin/page.tsx Normal file
View File

@@ -0,0 +1,342 @@
"use client";
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
import NavbarLayoutFloatingInline from "@/components/navbar/NavbarLayoutFloatingInline";
import FooterBaseCard from "@/components/sections/footer/FooterBaseCard";
import { useState } from "react";
import { Plus, Edit2, Trash2, Search, Settings, Users, BarChart3, Heart } from "lucide-react";
export default function AdminPage() {
const [activeTab, setActiveTab] = useState<"animals" | "adoptions" | "users" | "settings">("animals");
const [searchTerm, setSearchTerm] = useState("");
const navItems = [
{ name: "Home", id: "/" },
{ name: "Browse Animals", id: "/animals" },
{ name: "Admin", id: "/admin" },
{ name: "About", id: "about" },
{ name: "Contact", id: "contact" },
];
const footerColumns = [
{
title: "Adoption", items: [
{ label: "Browse Pets", href: "/animals" },
{ label: "How to Adopt", href: "#how-it-works" },
],
},
{
title: "Company", items: [
{ label: "About Us", href: "/about" },
{ label: "Our Team", href: "#team" },
],
},
];
const sampleAnimals = [
{ id: 1, name: "Luna", species: "Dog", breed: "Golden Retriever", status: "Available", adoptionFee: "$150" },
{ id: 2, name: "Max", species: "Cat", breed: "Tabby", status: "Pending", adoptionFee: "$75" },
{ id: 3, name: "Bella", species: "Dog", breed: "Border Collie", status: "Available", adoptionFee: "$120" },
];
const sampleAdoptions = [
{ id: 1, animalName: "Buddy", familyName: "Johnson", status: "Completed", date: "2025-01-10" },
{ id: 2, animalName: "Whiskers", familyName: "Smith", status: "In Progress", date: "2025-01-15" },
{ id: 3, animalName: "Charlie", familyName: "Williams", status: "Pending Review", date: "2025-01-20" },
];
const sampleUsers = [
{ id: 1, name: "John Doe", email: "john@example.com", role: "Admin", status: "Active" },
{ id: 2, name: "Jane Smith", email: "jane@example.com", role: "Staff", status: "Active" },
{ id: 3, name: "Bob Wilson", email: "bob@example.com", role: "Volunteer", status: "Inactive" },
];
return (
<ThemeProvider
defaultButtonVariant="bounce-effect"
defaultTextAnimation="reveal-blur"
borderRadius="pill"
contentWidth="compact"
sizing="largeSmallSizeMediumTitles"
background="noise"
cardStyle="soft-shadow"
primaryButtonStyle="radial-glow"
secondaryButtonStyle="solid"
headingFontWeight="normal"
>
<div id="nav" data-section="nav">
<NavbarLayoutFloatingInline
navItems={navItems}
brandName="PawsHome Admin"
button={{ text: "Dashboard", href: "/admin" }}
/>
</div>
<div className="min-h-screen bg-gradient-to-br from-slate-50 to-slate-100 dark:from-slate-950 dark:to-slate-900 pt-32 pb-20">
<div className="mx-auto max-w-6xl px-4 sm:px-6 lg:px-8">
{/* Header */}
<div className="mb-12">
<h1 className="text-4xl font-bold text-slate-900 dark:text-white mb-2">Admin Dashboard</h1>
<p className="text-lg text-slate-600 dark:text-slate-400">Manage animals, adoptions, users, and platform settings</p>
</div>
{/* Tab Navigation */}
<div className="flex flex-wrap gap-2 mb-8 bg-white dark:bg-slate-800 p-2 rounded-lg shadow-sm">
<button
onClick={() => setActiveTab("animals")}
className={`flex items-center gap-2 px-4 py-2 rounded-lg font-medium transition ${
activeTab === "animals"
? "bg-blue-500 text-white"
: "text-slate-700 dark:text-slate-300 hover:bg-slate-100 dark:hover:bg-slate-700"
}`}
>
<Heart size={20} />
Animals
</button>
<button
onClick={() => setActiveTab("adoptions")}
className={`flex items-center gap-2 px-4 py-2 rounded-lg font-medium transition ${
activeTab === "adoptions"
? "bg-blue-500 text-white"
: "text-slate-700 dark:text-slate-300 hover:bg-slate-100 dark:hover:bg-slate-700"
}`}
>
<BarChart3 size={20} />
Adoptions
</button>
<button
onClick={() => setActiveTab("users")}
className={`flex items-center gap-2 px-4 py-2 rounded-lg font-medium transition ${
activeTab === "users"
? "bg-blue-500 text-white"
: "text-slate-700 dark:text-slate-300 hover:bg-slate-100 dark:hover:bg-slate-700"
}`}
>
<Users size={20} />
Users
</button>
<button
onClick={() => setActiveTab("settings")}
className={`flex items-center gap-2 px-4 py-2 rounded-lg font-medium transition ${
activeTab === "settings"
? "bg-blue-500 text-white"
: "text-slate-700 dark:text-slate-300 hover:bg-slate-100 dark:hover:bg-slate-700"
}`}
>
<Settings size={20} />
Settings
</button>
</div>
{/* Search & Controls */}
{activeTab !== "settings" && (
<div className="flex gap-4 mb-8">
<div className="flex-1 relative">
<Search className="absolute left-3 top-3 text-slate-400" size={20} />
<input
type="text"
placeholder="Search..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="w-full pl-10 pr-4 py-2 border border-slate-300 dark:border-slate-600 rounded-lg bg-white dark:bg-slate-800 text-slate-900 dark:text-white placeholder-slate-500"
/>
</div>
<button className="flex items-center gap-2 px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition font-medium">
<Plus size={20} />
Add New
</button>
</div>
)}
{/* Content Sections */}
{activeTab === "animals" && (
<div className="bg-white dark:bg-slate-800 rounded-lg shadow-md overflow-hidden">
<div className="overflow-x-auto">
<table className="w-full">
<thead className="bg-slate-100 dark:bg-slate-700 border-b border-slate-200 dark:border-slate-600">
<tr>
<th className="px-6 py-3 text-left text-sm font-semibold text-slate-900 dark:text-white">Name</th>
<th className="px-6 py-3 text-left text-sm font-semibold text-slate-900 dark:text-white">Species</th>
<th className="px-6 py-3 text-left text-sm font-semibold text-slate-900 dark:text-white">Breed</th>
<th className="px-6 py-3 text-left text-sm font-semibold text-slate-900 dark:text-white">Status</th>
<th className="px-6 py-3 text-left text-sm font-semibold text-slate-900 dark:text-white">Fee</th>
<th className="px-6 py-3 text-center text-sm font-semibold text-slate-900 dark:text-white">Actions</th>
</tr>
</thead>
<tbody className="divide-y divide-slate-200 dark:divide-slate-700">
{sampleAnimals.map((animal) => (
<tr key={animal.id} className="hover:bg-slate-50 dark:hover:bg-slate-700 transition">
<td className="px-6 py-4 text-sm font-medium text-slate-900 dark:text-white">{animal.name}</td>
<td className="px-6 py-4 text-sm text-slate-600 dark:text-slate-300">{animal.species}</td>
<td className="px-6 py-4 text-sm text-slate-600 dark:text-slate-300">{animal.breed}</td>
<td className="px-6 py-4 text-sm">
<span className={`px-3 py-1 rounded-full text-xs font-semibold ${
animal.status === "Available"
? "bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200"
: "bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200"
}`}>
{animal.status}
</span>
</td>
<td className="px-6 py-4 text-sm text-slate-900 dark:text-white font-medium">{animal.adoptionFee}</td>
<td className="px-6 py-4 text-center">
<div className="flex justify-center gap-2">
<button className="p-2 text-blue-500 hover:bg-blue-50 dark:hover:bg-slate-700 rounded transition" title="Edit">
<Edit2 size={18} />
</button>
<button className="p-2 text-red-500 hover:bg-red-50 dark:hover:bg-slate-700 rounded transition" title="Delete">
<Trash2 size={18} />
</button>
</div>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
)}
{activeTab === "adoptions" && (
<div className="bg-white dark:bg-slate-800 rounded-lg shadow-md overflow-hidden">
<div className="overflow-x-auto">
<table className="w-full">
<thead className="bg-slate-100 dark:bg-slate-700 border-b border-slate-200 dark:border-slate-600">
<tr>
<th className="px-6 py-3 text-left text-sm font-semibold text-slate-900 dark:text-white">Animal</th>
<th className="px-6 py-3 text-left text-sm font-semibold text-slate-900 dark:text-white">Family</th>
<th className="px-6 py-3 text-left text-sm font-semibold text-slate-900 dark:text-white">Status</th>
<th className="px-6 py-3 text-left text-sm font-semibold text-slate-900 dark:text-white">Date</th>
<th className="px-6 py-3 text-center text-sm font-semibold text-slate-900 dark:text-white">Actions</th>
</tr>
</thead>
<tbody className="divide-y divide-slate-200 dark:divide-slate-700">
{sampleAdoptions.map((adoption) => (
<tr key={adoption.id} className="hover:bg-slate-50 dark:hover:bg-slate-700 transition">
<td className="px-6 py-4 text-sm font-medium text-slate-900 dark:text-white">{adoption.animalName}</td>
<td className="px-6 py-4 text-sm text-slate-600 dark:text-slate-300">{adoption.familyName}</td>
<td className="px-6 py-4 text-sm">
<span className={`px-3 py-1 rounded-full text-xs font-semibold ${
adoption.status === "Completed"
? "bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200"
: adoption.status === "In Progress"
? "bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200"
: "bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200"
}`}>
{adoption.status}
</span>
</td>
<td className="px-6 py-4 text-sm text-slate-600 dark:text-slate-300">{adoption.date}</td>
<td className="px-6 py-4 text-center">
<div className="flex justify-center gap-2">
<button className="p-2 text-blue-500 hover:bg-blue-50 dark:hover:bg-slate-700 rounded transition" title="Edit">
<Edit2 size={18} />
</button>
</div>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
)}
{activeTab === "users" && (
<div className="bg-white dark:bg-slate-800 rounded-lg shadow-md overflow-hidden">
<div className="overflow-x-auto">
<table className="w-full">
<thead className="bg-slate-100 dark:bg-slate-700 border-b border-slate-200 dark:border-slate-600">
<tr>
<th className="px-6 py-3 text-left text-sm font-semibold text-slate-900 dark:text-white">Name</th>
<th className="px-6 py-3 text-left text-sm font-semibold text-slate-900 dark:text-white">Email</th>
<th className="px-6 py-3 text-left text-sm font-semibold text-slate-900 dark:text-white">Role</th>
<th className="px-6 py-3 text-left text-sm font-semibold text-slate-900 dark:text-white">Status</th>
<th className="px-6 py-3 text-center text-sm font-semibold text-slate-900 dark:text-white">Actions</th>
</tr>
</thead>
<tbody className="divide-y divide-slate-200 dark:divide-slate-700">
{sampleUsers.map((user) => (
<tr key={user.id} className="hover:bg-slate-50 dark:hover:bg-slate-700 transition">
<td className="px-6 py-4 text-sm font-medium text-slate-900 dark:text-white">{user.name}</td>
<td className="px-6 py-4 text-sm text-slate-600 dark:text-slate-300">{user.email}</td>
<td className="px-6 py-4 text-sm text-slate-600 dark:text-slate-300">{user.role}</td>
<td className="px-6 py-4 text-sm">
<span className={`px-3 py-1 rounded-full text-xs font-semibold ${
user.status === "Active"
? "bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200"
: "bg-slate-100 text-slate-800 dark:bg-slate-700 dark:text-slate-300"
}`}>
{user.status}
</span>
</td>
<td className="px-6 py-4 text-center">
<div className="flex justify-center gap-2">
<button className="p-2 text-blue-500 hover:bg-blue-50 dark:hover:bg-slate-700 rounded transition" title="Edit">
<Edit2 size={18} />
</button>
<button className="p-2 text-red-500 hover:bg-red-50 dark:hover:bg-slate-700 rounded transition" title="Delete">
<Trash2 size={18} />
</button>
</div>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
)}
{activeTab === "settings" && (
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="bg-white dark:bg-slate-800 rounded-lg shadow-md p-6">
<h3 className="text-lg font-semibold text-slate-900 dark:text-white mb-4">Platform Settings</h3>
<div className="space-y-4">
<div>
<label className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">Platform Name</label>
<input type="text" defaultValue="PawsHome" className="w-full px-4 py-2 border border-slate-300 dark:border-slate-600 rounded-lg bg-white dark:bg-slate-700 text-slate-900 dark:text-white" />
</div>
<div>
<label className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">Contact Email</label>
<input type="email" defaultValue="support@pawshome.com" className="w-full px-4 py-2 border border-slate-300 dark:border-slate-600 rounded-lg bg-white dark:bg-slate-700 text-slate-900 dark:text-white" />
</div>
<div>
<label className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">Maximum Adoption Fee</label>
<input type="text" defaultValue="$500" className="w-full px-4 py-2 border border-slate-300 dark:border-slate-600 rounded-lg bg-white dark:bg-slate-700 text-slate-900 dark:text-white" />
</div>
<button className="w-full px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition font-medium">Save Settings</button>
</div>
</div>
<div className="bg-white dark:bg-slate-800 rounded-lg shadow-md p-6">
<h3 className="text-lg font-semibold text-slate-900 dark:text-white mb-4">System Status</h3>
<div className="space-y-3">
<div className="flex justify-between items-center">
<span className="text-slate-600 dark:text-slate-400">Database</span>
<span className="px-3 py-1 bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200 text-xs font-semibold rounded-full">Operational</span>
</div>
<div className="flex justify-between items-center">
<span className="text-slate-600 dark:text-slate-400">API Server</span>
<span className="px-3 py-1 bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200 text-xs font-semibold rounded-full">Operational</span>
</div>
<div className="flex justify-between items-center">
<span className="text-slate-600 dark:text-slate-400">Email Service</span>
<span className="px-3 py-1 bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200 text-xs font-semibold rounded-full">Operational</span>
</div>
</div>
</div>
</div>
)}
</div>
</div>
<div id="footer" data-section="footer">
<FooterBaseCard
logoText="PawsHome"
columns={footerColumns}
copyrightText="© 2025 PawsHome Admin. All rights reserved."
/>
</div>
</ThemeProvider>
);
}

View File

@@ -2,13 +2,77 @@
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
import NavbarLayoutFloatingInline from "@/components/navbar/NavbarLayoutFloatingInline";
import ProductCardOne from "@/components/sections/product/ProductCardOne";
import MetricCardSeven from "@/components/sections/metrics/MetricCardSeven";
import ContactCTA from "@/components/sections/contact/ContactCTA";
import HeroSplitKpi from "@/components/sections/hero/HeroSplitKpi";
import FooterBaseCard from "@/components/sections/footer/FooterBaseCard";
import { Heart, TrendingUp } from "lucide-react";
import { Heart, Filter, Search } from "lucide-react";
import { useState, useMemo } from "react";
interface Animal {
id: string;
name: string;
species: string;
breed: string;
age: string;
gender: string;
size: string;
adoptionFee: string;
imageSrc: string;
imageAlt: string;
description: string;
temperament: string[];
healthStatus: string;
available: boolean;
}
const animalsDatabase: Animal[] = [
{
id: "1", name: "Luna", species: "Dog", breed: "Golden Retriever", age: "3 years", gender: "Female", size: "Large", adoptionFee: "$150", imageSrc: "http://img.b2bpic.net/free-photo/close-up-dog_482257-11548.jpg", imageAlt: "Luna, a beautiful golden retriever", description: "Sweet and gentle Luna loves playing fetch and making new friends. Perfect for active families!", temperament: ["Friendly", "Playful", "Gentle", "Intelligent"],
healthStatus: "Fully vaccinated, microchipped", available: true,
},
{
id: "2", name: "Max", species: "Cat", breed: "Tabby", age: "2 years", gender: "Male", size: "Small", adoptionFee: "$75", imageSrc: "http://img.b2bpic.net/free-photo/focus-eyes-tabby-blue-cement-floor_1150-19546.jpg", imageAlt: "Max, an adorable tabby cat", description: "Energetic Max is always ready for playtime and cuddles. Great for families with older kids.", temperament: ["Energetic", "Affectionate", "Social", "Curious"],
healthStatus: "Fully vaccinated, neutered", available: true,
},
{
id: "3", name: "Bella", species: "Dog", breed: "Border Collie", age: "4 years", gender: "Female", size: "Medium", adoptionFee: "$120", imageSrc: "http://img.b2bpic.net/free-photo/studio-shot-cute-border-collie-dog_23-2148097506.jpg", imageAlt: "Bella, an intelligent border collie", description: "Highly intelligent Bella thrives with mental stimulation and exercise. Perfect for active owners.", temperament: ["Intelligent", "Energetic", "Loyal", "Obedient"],
healthStatus: "Fully vaccinated, microchipped", available: true,
},
{
id: "4", name: "Charlie", species: "Rabbit", breed: "Holland Lop", age: "1 year", gender: "Male", size: "Small", adoptionFee: "$50", imageSrc: "http://img.b2bpic.net/free-photo/cute-rabbit-eating-grass-garden_181624-40766.jpg", imageAlt: "Charlie, an adorable rabbit", description: "Cute Charlie loves fresh vegetables and quiet environments. Great first pet for kids!", temperament: ["Calm", "Social", "Gentle", "Curious"],
healthStatus: "Healthy, neutered", available: true,
},
{
id: "5", name: "Buddy", species: "Dog", breed: "Labrador", age: "5 years", gender: "Male", size: "Large", adoptionFee: "$140", imageSrc: "http://img.b2bpic.net/free-photo/close-up-dog_482257-11548.jpg", imageAlt: "Buddy, a friendly labrador", description: "Loyal Buddy is a senior dog looking for a calm home. Perfect for experienced dog owners.", temperament: ["Loyal", "Calm", "Affectionate", "Well-trained"],
healthStatus: "Fully vaccinated, senior health check", available: true,
},
{
id: "6", name: "Whiskers", species: "Cat", breed: "Siamese", age: "1 year", gender: "Female", size: "Small", adoptionFee: "$85", imageSrc: "http://img.b2bpic.net/free-photo/focus-eyes-tabby-blue-cement-floor_1150-19546.jpg", imageAlt: "Whiskers, a beautiful siamese cat", description: "Vocal and affectionate Whiskers loves human attention and warm laps.", temperament: ["Vocal", "Affectionate", "Playful", "Social"],
healthStatus: "Fully vaccinated, spayed", available: true,
},
];
export default function AnimalsPage() {
const [searchQuery, setSearchQuery] = useState("");
const [speciesFilter, setSpeciesFilter] = useState("All");
const [sizeFilter, setSizeFilter] = useState("All");
const [showFilters, setShowFilters] = useState(false);
const filteredAnimals = useMemo(() => {
return animalsDatabase.filter((animal) => {
const matchesSearch =
animal.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
animal.breed.toLowerCase().includes(searchQuery.toLowerCase()) ||
animal.species.toLowerCase().includes(searchQuery.toLowerCase());
const matchesSpecies =
speciesFilter === "All" || animal.species === speciesFilter;
const matchesSize = sizeFilter === "All" || animal.size === sizeFilter;
return matchesSearch && matchesSpecies && matchesSize;
});
}, [searchQuery, speciesFilter, sizeFilter]);
const navItems = [
{ name: "Home", id: "/" },
{ name: "Browse Animals", id: "/animals" },
@@ -18,26 +82,23 @@ export default function AnimalsPage() {
const footerColumns = [
{
title: "Adoption",
items: [
title: "Adoption", items: [
{ label: "Browse Pets", href: "/animals" },
{ label: "How to Adopt", href: "#how-it-works" },
{ label: "Adoption Stories", href: "#adoption-stories" },
{ label: "How to Adopt", href: "/#how-it-works" },
{ label: "Adoption Stories", href: "/#adoption-stories" },
{ label: "FAQ", href: "/faq" },
],
},
{
title: "Company",
items: [
title: "Company", items: [
{ label: "About Us", href: "/about" },
{ label: "Our Team", href: "#team" },
{ label: "Our Team", href: "/#team" },
{ label: "Partner with Us", href: "/partner" },
{ label: "Blog", href: "/blog" },
],
},
{
title: "Support",
items: [
title: "Support", items: [
{ label: "Contact Us", href: "/contact" },
{ label: "Donate", href: "/donate" },
{ label: "Volunteer", href: "/volunteer" },
@@ -45,8 +106,7 @@ export default function AnimalsPage() {
],
},
{
title: "Legal",
items: [
title: "Legal", items: [
{ label: "Privacy Policy", href: "#" },
{ label: "Terms of Service", href: "#" },
{ label: "Cookie Policy", href: "#" },
@@ -77,126 +137,189 @@ export default function AnimalsPage() {
/>
</div>
<div id="all-available-animals" data-section="all-available-animals">
<ProductCardOne
title="All Available Animals"
description="Browse our complete catalog of adoptable pets. Each animal has been carefully evaluated and is ready to find their forever home. Filter by type, age, or special needs to find your perfect match."
tag="Complete Listings"
<div id="hero" data-section="hero">
<HeroSplitKpi
title="Find Your Perfect Companion"
description="Browse our complete database of available animals. Use filters and search to find the pet that matches your lifestyle and family."
background={{ variant: "glowing-orb" }}
kpis={[
{ value: filteredAnimals.length.toString(), label: "Animals Available" },
{ value: animalsDatabase.length.toString(), label: "Total in Database" },
{ value: "100%", label: "Health Checked" },
]}
enableKpiAnimation={true}
tag="Browse Our Adoptable Pets"
tagIcon={Heart}
tagAnimation="slide-up"
textboxLayout="default"
animationType="slide-up"
useInvertedBackground={false}
gridVariant="three-columns-all-equal-width"
products={[
{
id: "1",
name: "Luna - Golden Retriever",
price: "Adoption Fee: $150",
imageSrc: "http://img.b2bpic.net/free-photo/close-up-dog_482257-11548.jpg?_wi=2",
imageAlt: "Luna, a golden retriever waiting for adoption",
},
{
id: "2",
name: "Max - Tabby Cat",
price: "Adoption Fee: $75",
imageSrc: "http://img.b2bpic.net/free-photo/focus-eyes-tabby-blue-cement-floor_1150-19546.jpg?_wi=2",
imageAlt: "Max, an orange tabby cat",
},
{
id: "3",
name: "Bella - Border Collie",
price: "Adoption Fee: $120",
imageSrc: "http://img.b2bpic.net/free-photo/studio-shot-cute-border-collie-dog_23-2148097506.jpg?_wi=2",
imageAlt: "Bella, a border collie with striking eyes",
},
{
id: "4",
name: "Charlie - Rabbit",
price: "Adoption Fee: $50",
imageSrc: "http://img.b2bpic.net/free-photo/cute-rabbit-eating-grass-garden_181624-40766.jpg?_wi=2",
imageAlt: "Charlie, an adorable Holland lop rabbit",
},
{
id: "5",
name: "Daisy - Pomeranian",
price: "Adoption Fee: $100",
imageSrc: "http://img.b2bpic.net/free-photo/cute-rabbit-eating-grass-garden_181624-40766.jpg?_wi=3",
imageAlt: "Daisy, a fluffy pomeranian puppy",
},
{
id: "6",
name: "Simba - Siamese Cat",
price: "Adoption Fee: $80",
imageSrc: "http://img.b2bpic.net/free-photo/focus-eyes-tabby-blue-cement-floor_1150-19546.jpg?_wi=3",
imageAlt: "Simba, a beautiful siamese cat",
},
]}
buttons={[{ text: "Back to Home", href: "/" }]}
buttons={[{ text: "Back Home", href: "/" }]}
buttonAnimation="slide-up"
imageSrc="http://img.b2bpic.net/free-photo/back-school-nature_169016-2034.jpg"
imageAlt="Happy animals waiting for adoption"
mediaAnimation="slide-up"
imagePosition="right"
/>
</div>
<div id="adoption-stats" data-section="adoption-stats">
<MetricCardSeven
title="Adoption Success Stories"
description="These metrics represent the real impact of our community's commitment to animal welfare and finding forever homes."
tag="By the Numbers"
tagIcon={TrendingUp}
tagAnimation="slide-up"
textboxLayout="default"
animationType="slide-up"
useInvertedBackground={true}
metrics={[
{
id: "1",
value: "2,500+",
title: "Successful Adoptions",
items: [
"Happy homes found",
"Lives transformed",
"Families completed",
],
},
{
id: "2",
value: "98%",
title: "Match Success Rate",
items: [
"Pet and family compatibility",
"Long-term satisfaction",
"Lasting relationships",
],
},
{
id: "3",
value: "7 Days",
title: "Average Adoption Time",
items: [
"Quick approval process",
"Minimal wait period",
"Faster to your home",
],
},
]}
/>
</div>
<div className="py-20">
<div className="w-full max-w-7xl mx-auto px-4 md:px-8">
{/* Search and Filter Bar */}
<div className="mb-8 space-y-4">
{/* Search Input */}
<div className="relative">
<Search className="absolute left-3 top-3 text-foreground/50 w-5 h-5" />
<input
type="text"
placeholder="Search by name, breed, or species..."
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
className="w-full pl-10 pr-4 py-2 bg-card border border-accent/20 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-cta"
/>
</div>
<div id="adoption-cta" data-section="adoption-cta">
<ContactCTA
tag="Ready to Adopt"
tagIcon={Heart}
tagAnimation="slide-up"
title="Find Your Perfect Companion Today"
description="Take the first step towards bringing a loving animal into your family. Our team is here to guide you through the entire adoption process and answer any questions you may have."
background={{ variant: "plain" }}
buttons={[
{ text: "Apply to Adopt", href: "#" },
{ text: "Learn About Requirements", href: "#" },
]}
buttonAnimation="slide-up"
useInvertedBackground={false}
/>
{/* Filter Toggle */}
<button
onClick={() => setShowFilters(!showFilters)}
className="flex items-center gap-2 px-4 py-2 bg-secondary-cta text-foreground rounded-lg hover:bg-primary-cta transition-colors"
>
<Filter className="w-4 h-4" />
{showFilters ? "Hide Filters" : "Show Filters"}
</button>
{/* Filter Options */}
{showFilters && (
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 p-4 bg-card border border-accent/20 rounded-lg">
{/* Species Filter */}
<div>
<label className="block text-sm font-medium mb-2">Species</label>
<select
value={speciesFilter}
onChange={(e) => setSpeciesFilter(e.target.value)}
className="w-full px-3 py-2 bg-background border border-accent/20 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-cta"
>
<option>All</option>
<option>Dog</option>
<option>Cat</option>
<option>Rabbit</option>
</select>
</div>
{/* Size Filter */}
<div>
<label className="block text-sm font-medium mb-2">Size</label>
<select
value={sizeFilter}
onChange={(e) => setSizeFilter(e.target.value)}
className="w-full px-3 py-2 bg-background border border-accent/20 rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-cta"
>
<option>All</option>
<option>Small</option>
<option>Medium</option>
<option>Large</option>
</select>
</div>
</div>
)}
</div>
{/* Results Count */}
<div className="mb-6">
<p className="text-foreground/80">
Showing {filteredAnimals.length} of {animalsDatabase.length} animals
</p>
</div>
{/* Animals Grid */}
{filteredAnimals.length > 0 ? (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{filteredAnimals.map((animal) => (
<div
key={animal.id}
className="bg-card border border-accent/20 rounded-lg overflow-hidden hover:shadow-lg transition-shadow"
>
{/* Image */}
<div className="relative h-48 overflow-hidden bg-background">
<img
src={animal.imageSrc}
alt={animal.imageAlt}
className="w-full h-full object-cover hover:scale-105 transition-transform"
/>
<div className="absolute top-3 right-3 bg-primary-cta text-white px-3 py-1 rounded-full text-sm font-medium">
{animal.adoptionFee}
</div>
</div>
{/* Content */}
<div className="p-4">
<h3 className="text-xl font-semibold text-foreground mb-1">
{animal.name}
</h3>
<p className="text-foreground/70 text-sm mb-3">
{animal.breed} {animal.age}
</p>
{/* Info Grid */}
<div className="grid grid-cols-2 gap-2 mb-4 text-sm">
<div>
<span className="text-foreground/60">Gender:</span>
<p className="text-foreground font-medium">{animal.gender}</p>
</div>
<div>
<span className="text-foreground/60">Size:</span>
<p className="text-foreground font-medium">{animal.size}</p>
</div>
</div>
{/* Description */}
<p className="text-foreground/70 text-sm mb-3">
{animal.description}
</p>
{/* Temperament */}
<div className="mb-4">
<p className="text-foreground/60 text-xs font-medium mb-2">
TEMPERAMENT
</p>
<div className="flex flex-wrap gap-2">
{animal.temperament.map((trait) => (
<span
key={trait}
className="px-2 py-1 bg-background text-foreground text-xs rounded-full border border-accent/20"
>
{trait}
</span>
))}
</div>
</div>
{/* Health Status */}
<p className="text-foreground/70 text-xs mb-4 pb-4 border-b border-accent/20">
{animal.healthStatus}
</p>
{/* CTA */}
<button className="w-full px-4 py-2 bg-primary-cta text-white rounded-lg font-medium hover:opacity-90 transition-opacity">
Learn More & Adopt
</button>
</div>
</div>
))}
</div>
) : (
<div className="text-center py-12">
<p className="text-foreground/70 text-lg">No animals found matching your criteria.</p>
<button
onClick={() => {
setSearchQuery("");
setSpeciesFilter("All");
setSizeFilter("All");
}}
className="mt-4 px-4 py-2 bg-primary-cta text-white rounded-lg font-medium hover:opacity-90 transition-opacity"
>
Reset Filters
</button>
</div>
)}
</div>
</div>
<div id="footer" data-section="footer">
@@ -208,4 +331,4 @@ export default function AnimalsPage() {
</div>
</ThemeProvider>
);
}
}

View File

@@ -0,0 +1,74 @@
import { NextRequest, NextResponse } from "next/server";
import crypto from "crypto";
// Mock user database - in production, use a real database
const mockUsers = [
{
id: "1", email: "demo@pawshome.com", passwordHash: hashPassword("password123"),
name: "Demo User"},
];
function hashPassword(password: string): string {
return crypto.createHash("sha256").update(password).digest("hex");
}
function verifyPassword(password: string, hash: string): boolean {
return hashPassword(password) === hash;
}
function generateToken(): string {
return crypto.randomBytes(32).toString("hex");
}
export async function POST(request: NextRequest) {
try {
const body = await request.json();
const { email, password } = body;
if (!email || !password) {
return NextResponse.json(
{ message: "Email and password are required" },
{ status: 400 }
);
}
// Find user
const user = mockUsers.find((u) => u.email === email);
if (!user) {
return NextResponse.json(
{ message: "Invalid email or password" },
{ status: 401 }
);
}
// Verify password
if (!verifyPassword(password, user.passwordHash)) {
return NextResponse.json(
{ message: "Invalid email or password" },
{ status: 401 }
);
}
// Generate token
const token = generateToken();
// Return success response
return NextResponse.json(
{
token,
user: {
id: user.id,
email: user.email,
name: user.name,
},
},
{ status: 200 }
);
} catch (error) {
console.error("Login error:", error);
return NextResponse.json(
{ message: "Internal server error" },
{ status: 500 }
);
}
}

View File

@@ -0,0 +1,24 @@
import { NextRequest, NextResponse } from "next/server";
export async function POST(request: NextRequest) {
try {
// Clear authentication token on client side via response
const response = NextResponse.json(
{ message: "Logged out successfully" },
{ status: 200 }
);
// Set cookie to expire if using cookies for auth
response.cookies.set({
name: "authToken", value: "", maxAge: 0,
path: "/"});
return response;
} catch (error) {
console.error("Logout error:", error);
return NextResponse.json(
{ message: "Internal server error" },
{ status: 500 }
);
}
}

View File

@@ -0,0 +1,39 @@
import { NextRequest, NextResponse } from "next/server";
export async function GET(request: NextRequest) {
try {
const token = request.headers.get("Authorization")?.replace("Bearer ", "");
if (!token) {
return NextResponse.json(
{ message: "No token provided" },
{ status: 401 }
);
}
// In production, verify token against database/cache
// For this mock, we'll validate basic structure
if (token.length !== 64) {
return NextResponse.json(
{ message: "Invalid token" },
{ status: 401 }
);
}
// Return mock session data
return NextResponse.json(
{
user: {
id: "1", email: "demo@pawshome.com", name: "Demo User"},
isAuthenticated: true,
},
{ status: 200 }
);
} catch (error) {
console.error("Session error:", error);
return NextResponse.json(
{ message: "Internal server error" },
{ status: 500 }
);
}
}

257
src/app/dashboard/page.tsx Normal file
View File

@@ -0,0 +1,257 @@
"use client";
import { useEffect, useState } from "react";
import { useRouter } from "next/navigation";
import Link from "next/link";
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
import NavbarLayoutFloatingInline from "@/components/navbar/NavbarLayoutFloatingInline";
import { LogOut, Heart, Settings } from "lucide-react";
interface User {
id: string;
email: string;
name: string;
}
export default function DashboardPage() {
const router = useRouter();
const [user, setUser] = useState<User | null>(null);
const [isLoading, setIsLoading] = useState(true);
const navItems = [
{ name: "Home", id: "/" },
{ name: "Browse Animals", id: "/animals" },
{ name: "About", id: "/about" },
{ name: "Login", id: "/login" },
];
useEffect(() => {
const checkAuth = async () => {
try {
const token = localStorage.getItem("authToken");
const userStr = localStorage.getItem("user");
if (!token) {
router.push("/login");
return;
}
// Verify session with backend
const response = await fetch("/api/auth/session", {
headers: { Authorization: `Bearer ${token}` },
});
if (!response.ok) {
localStorage.removeItem("authToken");
localStorage.removeItem("user");
router.push("/login");
return;
}
if (userStr) {
setUser(JSON.parse(userStr));
}
} catch (error) {
console.error("Auth check failed:", error);
router.push("/login");
} finally {
setIsLoading(false);
}
};
checkAuth();
}, [router]);
const handleLogout = async () => {
try {
const token = localStorage.getItem("authToken");
if (token) {
await fetch("/api/auth/logout", {
method: "POST", headers: { Authorization: `Bearer ${token}` },
});
}
} catch (error) {
console.error("Logout error:", error);
} finally {
localStorage.removeItem("authToken");
localStorage.removeItem("user");
router.push("/");
}
};
if (isLoading) {
return (
<ThemeProvider
defaultButtonVariant="bounce-effect"
defaultTextAnimation="reveal-blur"
borderRadius="pill"
contentWidth="compact"
sizing="largeSmallSizeMediumTitles"
background="noise"
cardStyle="soft-shadow"
primaryButtonStyle="radial-glow"
secondaryButtonStyle="solid"
headingFontWeight="normal"
>
<div className="flex items-center justify-center min-h-screen">
<div className="text-center">
<div className="inline-block animate-spin rounded-full h-12 w-12 border-b-2 border-primary-cta"></div>
<p className="mt-4 text-foreground/70">Loading...</p>
</div>
</div>
</ThemeProvider>
);
}
if (!user) {
return (
<ThemeProvider
defaultButtonVariant="bounce-effect"
defaultTextAnimation="reveal-blur"
borderRadius="pill"
contentWidth="compact"
sizing="largeSmallSizeMediumTitles"
background="noise"
cardStyle="soft-shadow"
primaryButtonStyle="radial-glow"
secondaryButtonStyle="solid"
headingFontWeight="normal"
>
<div className="flex items-center justify-center min-h-screen">
<p className="text-foreground/70">Redirecting...</p>
</div>
</ThemeProvider>
);
}
return (
<ThemeProvider
defaultButtonVariant="bounce-effect"
defaultTextAnimation="reveal-blur"
borderRadius="pill"
contentWidth="compact"
sizing="largeSmallSizeMediumTitles"
background="noise"
cardStyle="soft-shadow"
primaryButtonStyle="radial-glow"
secondaryButtonStyle="solid"
headingFontWeight="normal"
>
<div id="nav" data-section="nav">
<NavbarLayoutFloatingInline
navItems={navItems}
brandName="PawsHome"
button={{ text: "Start Adoption", href: "/animals" }}
animateOnLoad={true}
/>
</div>
<div className="min-h-screen px-4 py-20">
<div className="max-w-4xl mx-auto">
{/* Header */}
<div className="flex justify-between items-center mb-12">
<div>
<h1 className="text-4xl font-bold text-foreground mb-2">
Welcome, {user.name}!
</h1>
<p className="text-foreground/70">Manage your PawsHome account</p>
</div>
<button
onClick={handleLogout}
className="flex items-center gap-2 bg-red-500 hover:bg-red-600 text-white font-semibold px-4 py-2 rounded-lg transition-colors"
>
<LogOut className="w-4 h-4" />
Log Out
</button>
</div>
{/* Dashboard Grid */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{/* Profile Card */}
<div className="bg-card rounded-lg shadow-lg p-6 border border-accent">
<div className="flex items-center gap-3 mb-4">
<div className="w-12 h-12 rounded-full bg-primary-cta/20 flex items-center justify-center">
<Heart className="w-6 h-6 text-primary-cta" />
</div>
<h2 className="text-xl font-semibold text-foreground">Profile</h2>
</div>
<div className="space-y-4">
<div>
<label className="text-sm text-foreground/70">Name</label>
<p className="text-foreground font-medium">{user.name}</p>
</div>
<div>
<label className="text-sm text-foreground/70">Email</label>
<p className="text-foreground font-medium">{user.email}</p>
</div>
<Link
href="/account/edit"
className="inline-block mt-4 bg-primary-cta hover:bg-primary-cta/90 text-white font-semibold px-4 py-2 rounded-lg transition-colors"
>
Edit Profile
</Link>
</div>
</div>
{/* Favorites Card */}
<div className="bg-card rounded-lg shadow-lg p-6 border border-accent">
<div className="flex items-center gap-3 mb-4">
<div className="w-12 h-12 rounded-full bg-accent/20 flex items-center justify-center">
<Heart className="w-6 h-6 text-accent" />
</div>
<h2 className="text-xl font-semibold text-foreground">Favorites</h2>
</div>
<p className="text-foreground/70 mb-4">
View and manage your favorite animals
</p>
<Link
href="/favorites"
className="inline-block bg-secondary-cta hover:bg-secondary-cta/90 text-foreground font-semibold px-4 py-2 rounded-lg transition-colors"
>
View Favorites
</Link>
</div>
{/* Adoptions Card */}
<div className="bg-card rounded-lg shadow-lg p-6 border border-accent">
<div className="flex items-center gap-3 mb-4">
<div className="w-12 h-12 rounded-full bg-primary-cta/20 flex items-center justify-center">
<Heart className="w-6 h-6 text-primary-cta" />
</div>
<h2 className="text-xl font-semibold text-foreground">My Adoptions</h2>
</div>
<p className="text-foreground/70 mb-4">
Track your adoption applications and status
</p>
<Link
href="/my-adoptions"
className="inline-block bg-primary-cta hover:bg-primary-cta/90 text-white font-semibold px-4 py-2 rounded-lg transition-colors"
>
View Adoptions
</Link>
</div>
{/* Settings Card */}
<div className="bg-card rounded-lg shadow-lg p-6 border border-accent">
<div className="flex items-center gap-3 mb-4">
<div className="w-12 h-12 rounded-full bg-accent/20 flex items-center justify-center">
<Settings className="w-6 h-6 text-accent" />
</div>
<h2 className="text-xl font-semibold text-foreground">Settings</h2>
</div>
<p className="text-foreground/70 mb-4">
Manage your account preferences and notifications
</p>
<Link
href="/account/settings"
className="inline-block bg-secondary-cta hover:bg-secondary-cta/90 text-foreground font-semibold px-4 py-2 rounded-lg transition-colors"
>
Go to Settings
</Link>
</div>
</div>
</div>
</div>
</ThemeProvider>
);
}

File diff suppressed because it is too large Load Diff

158
src/app/login/page.tsx Normal file
View File

@@ -0,0 +1,158 @@
"use client";
import { useState } from "react";
import { useRouter } from "next/navigation";
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
import NavbarLayoutFloatingInline from "@/components/navbar/NavbarLayoutFloatingInline";
import Link from "next/link";
import { Heart } from "lucide-react";
export default function LoginPage() {
const router = useRouter();
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");
const [isLoading, setIsLoading] = useState(false);
const navItems = [
{ name: "Home", id: "/" },
{ name: "Browse Animals", id: "/animals" },
{ name: "About", id: "/about" },
{ name: "Login", id: "/login" },
];
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setError("");
setIsLoading(true);
try {
const response = await fetch("/api/auth/login", {
method: "POST", headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email, password }),
});
if (!response.ok) {
const data = await response.json();
setError(data.message || "Login failed. Please try again.");
setIsLoading(false);
return;
}
const data = await response.json();
localStorage.setItem("authToken", data.token);
localStorage.setItem("user", JSON.stringify(data.user));
router.push("/dashboard");
} catch (err) {
setError("An error occurred. Please try again.");
setIsLoading(false);
}
};
return (
<ThemeProvider
defaultButtonVariant="bounce-effect"
defaultTextAnimation="reveal-blur"
borderRadius="pill"
contentWidth="compact"
sizing="largeSmallSizeMediumTitles"
background="noise"
cardStyle="soft-shadow"
primaryButtonStyle="radial-glow"
secondaryButtonStyle="solid"
headingFontWeight="normal"
>
<div id="nav" data-section="nav">
<NavbarLayoutFloatingInline
navItems={navItems}
brandName="PawsHome"
button={{ text: "Start Adoption", href: "/animals" }}
animateOnLoad={true}
/>
</div>
<div className="min-h-screen flex items-center justify-center px-4 py-20">
<div className="w-full max-w-md">
<div className="bg-card rounded-lg shadow-lg p-8">
<div className="flex justify-center mb-6">
<Heart className="w-8 h-8 text-primary-cta" />
</div>
<h1 className="text-3xl font-bold text-center text-foreground mb-2">
Welcome Back
</h1>
<p className="text-center text-foreground/70 mb-8">
Log in to your PawsHome account
</p>
{error && (
<div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-6">
{error}
</div>
)}
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<label
htmlFor="email"
className="block text-sm font-medium text-foreground mb-2"
>
Email Address
</label>
<input
id="email"
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="you@example.com"
required
className="w-full px-4 py-2 border border-accent rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-cta bg-background text-foreground placeholder-foreground/50"
/>
</div>
<div>
<label
htmlFor="password"
className="block text-sm font-medium text-foreground mb-2"
>
Password
</label>
<input
id="password"
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="••••••••"
required
className="w-full px-4 py-2 border border-accent rounded-lg focus:outline-none focus:ring-2 focus:ring-primary-cta bg-background text-foreground placeholder-foreground/50"
/>
</div>
<button
type="submit"
disabled={isLoading}
className="w-full bg-primary-cta hover:bg-primary-cta/90 text-white font-semibold py-2 rounded-lg transition-colors disabled:opacity-50"
>
{isLoading ? "Logging in..." : "Log In"}
</button>
</form>
<div className="mt-6 text-center">
<p className="text-foreground/70">
Don't have an account?{" "}
<Link href="/signup" className="text-primary-cta hover:underline">
Sign up
</Link>
</p>
</div>
<div className="mt-4 text-center">
<Link href="/forgot-password" className="text-sm text-primary-cta hover:underline">
Forgot your password?
</Link>
</div>
</div>
</div>
</div>
</ThemeProvider>
);
}

View File

@@ -18,7 +18,7 @@ export default function HomePage() {
const navItems = [
{ name: "Home", id: "/" },
{ name: "Browse Animals", id: "/animals" },
{ name: "About", id: "about" },
{ name: "About", id: "/about" },
{ name: "Contact", id: "contact" },
];
@@ -283,4 +283,4 @@ export default function HomePage() {
</div>
</ThemeProvider>
);
}
}