Merge version_3 into main #3

Merged
bender merged 7 commits from version_3 into main 2026-03-07 00:41:27 +00:00
7 changed files with 656 additions and 387 deletions

136
src/app/contact/page.tsx Normal file
View File

@@ -0,0 +1,136 @@
"use client";
import { MessageCircle } from "lucide-react";
import Input from "@/components/form/Input";
import { useState } from "react";
import { Loader } from "lucide-react";
export default function ContactPage() {
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [message, setMessage] = useState("");
const [loading, setLoading] = useState(false);
const [submitted, setSubmitted] = useState(false);
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
setLoading(true);
try {
// Simulate API call
await new Promise((resolve) => setTimeout(resolve, 1000));
setSubmitted(true);
setName("");
setEmail("");
setMessage("");
} finally {
setLoading(false);
}
};
return (
<div className="min-h-screen bg-background">
<div className="max-w-2xl mx-auto px-4 py-12">
<div className="text-center mb-12">
<MessageCircle className="w-12 h-12 text-primary-cta mx-auto mb-4" />
<h1 className="text-4xl font-bold text-foreground mb-2">Get in Touch</h1>
<p className="text-foreground/75">Have a question? We'd love to hear from you.</p>
</div>
<div className="bg-card rounded-lg p-8">
{submitted ? (
<div className="text-center py-8">
<div className="mb-4 text-green-500">
<MessageCircle className="w-12 h-12 mx-auto" />
</div>
<h2 className="text-xl font-bold text-foreground mb-2">Thank you!</h2>
<p className="text-foreground/75 mb-6">We've received your message and will get back to you soon.</p>
<button
onClick={() => setSubmitted(false)}
className="text-primary-cta hover:underline font-medium"
>
Send another message
</button>
</div>
) : (
<form onSubmit={handleSubmit} className="space-y-6">
<div>
<label className="block text-sm font-medium text-foreground mb-2">
Name
</label>
<Input
type="text"
placeholder="Your name"
value={name}
onChange={setName}
required
/>
</div>
<div>
<label className="block text-sm font-medium text-foreground mb-2">
Email
</label>
<Input
type="email"
placeholder="Your email"
value={email}
onChange={setEmail}
required
/>
</div>
<div>
<label className="block text-sm font-medium text-foreground mb-2">
Message
</label>
<textarea
placeholder="Your message"
value={message}
onChange={(e) => setMessage(e.target.value)}
required
rows={6}
className="w-full px-4 py-2 bg-secondary-cta text-foreground placeholder-foreground/50 rounded-lg border border-foreground/10 focus:outline-none focus:border-primary-cta transition-colors resize-none"
/>
</div>
<button
type="submit"
disabled={loading}
className="w-full bg-primary-cta text-white py-3 px-4 rounded-lg font-medium hover:opacity-90 transition-opacity disabled:opacity-50 flex items-center justify-center gap-2"
>
{loading ? (
<>
<Loader className="w-4 h-4 animate-spin" />
Sending...
</>
) : (
"Send Message"
)}
</button>
</form>
)}
</div>
{/* FAQ section */}
<div className="mt-12">
<h2 className="text-2xl font-bold text-foreground mb-6">Frequently Asked Questions</h2>
<div className="space-y-4">
<div className="bg-card rounded-lg p-6">
<h3 className="font-semibold text-foreground mb-2">What is your response time?</h3>
<p className="text-foreground/75">We aim to respond to all inquiries within 24 hours during business days.</p>
</div>
<div className="bg-card rounded-lg p-6">
<h3 className="font-semibold text-foreground mb-2">How can I report content?</h3>
<p className="text-foreground/75">Click the report button on any content and let us know the issue. Our team reviews all reports promptly.</p>
</div>
<div className="bg-card rounded-lg p-6">
<h3 className="font-semibold text-foreground mb-2">Do you have technical support?</h3>
<p className="text-foreground/75">Yes! Email support@mediahub.com for technical issues and we'll help you out.</p>
</div>
</div>
</div>
</div>
</div>
);
}

View File

@@ -1,213 +1,34 @@
"use client";
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
import NavbarStyleFullscreen from "@/components/navbar/NavbarStyleFullscreen/NavbarStyleFullscreen";
import ProductCardTwo from "@/components/sections/product/ProductCardTwo";
import SocialProofOne from "@/components/sections/socialProof/SocialProofOne";
import FooterSimple from "@/components/sections/footer/FooterSimple";
import Link from "next/link";
import { ImageIcon } from "lucide-react";
export default function GalleryPage() {
return (
<ThemeProvider
defaultButtonVariant="hover-magnetic"
defaultTextAnimation="reveal-blur"
borderRadius="rounded"
contentWidth="compact"
sizing="medium"
background="aurora"
cardStyle="gradient-mesh"
primaryButtonStyle="flat"
secondaryButtonStyle="solid"
headingFontWeight="light"
>
<div id="nav" data-section="nav">
<NavbarStyleFullscreen
navItems={[
{ name: "Home", id: "/" },
{ name: "Explore", id: "/gallery" },
{ name: "Upload", id: "upload" },
{ name: "Support", id: "contact" },
{ name: "Join Now", id: "#" },
]}
brandName="MediaHub"
bottomLeftText="Creative Community"
bottomRightText="support@mediahub.com"
/>
</div>
<div className="min-h-screen bg-background">
<div className="max-w-6xl mx-auto px-4 py-12">
<div className="mb-8">
<h1 className="text-4xl font-bold text-foreground mb-2">Creative Gallery</h1>
<p className="text-foreground/75">Discover amazing photos and videos from our creative community</p>
</div>
<div id="gallery" data-section="gallery">
<ProductCardTwo
title="Featured Content Gallery"
description="Discover amazing photos and videos from our creative community"
tag="Gallery"
tagIcon={ImageIcon}
products={[
{
id: "1",
brand: "Sarah Chen",
name: "Sunset Mountain Photography",
price: "4.9★",
rating: 5,
reviewCount: "2.3k",
imageSrc: "http://img.b2bpic.net/free-photo/beautiful-setting-sun-forest-mountain-landscape_181624-23715.jpg?_wi=2",
imageAlt: "sunset mountain landscape photography",
},
{
id: "2",
brand: "Alex Rodriguez",
name: "Urban Street Art",
price: "4.8★",
rating: 5,
reviewCount: "1.9k",
imageSrc: "http://img.b2bpic.net/free-photo/woman-blue-coat-street_158595-2575.jpg?_wi=2",
imageAlt: "urban street art photography city",
},
{
id: "3",
brand: "Maya Patel",
name: "Nature's Beautiful Details",
price: "4.9★",
rating: 5,
reviewCount: "3.1k",
imageSrc: "http://img.b2bpic.net/free-photo/macro-shot-anthurium-flower_23-2147836286.jpg?_wi=2",
imageAlt: "macro photography nature details close-up",
},
{
id: "4",
brand: "James Wilson",
name: "Travel Vlog Collection",
price: "4.7★",
rating: 5,
reviewCount: "2.7k",
imageSrc: "http://img.b2bpic.net/free-photo/camera-man-filming-couple-inside-transparent-bubble-tent-glamping-professional-camera_1268-24534.jpg?_wi=2",
imageAlt: "travel vlog video production cinematography",
},
{
id: "5",
brand: "Emma Thompson",
name: "Creative Animations",
price: "4.8★",
rating: 5,
reviewCount: "1.5k",
imageSrc: "http://img.b2bpic.net/free-photo/video-creator-woman-editing-music-video-dual-monitors-agency-studio_482257-119068.jpg?_wi=2",
imageAlt: "animation creative video motion graphics",
},
{
id: "6",
brand: "Lucas Kim",
name: "Design & Art Showcase",
price: "4.9★",
rating: 5,
reviewCount: "2.2k",
imageSrc: "http://img.b2bpic.net/free-vector/design-process-landing-page-concept_52683-25329.jpg?_wi=2",
imageAlt: "graphic design art illustration showcase",
},
{
id: "7",
brand: "Sophie Turner",
name: "Fashion & Lifestyle",
price: "4.8★",
rating: 5,
reviewCount: "1.8k",
imageSrc: "http://img.b2bpic.net/free-psd/fashion-magazine-template-design_23-2150583108.jpg?_wi=2",
imageAlt: "fashion magazine template design",
},
{
id: "8",
brand: "David Chen",
name: "Architecture & Design",
price: "4.9★",
rating: 5,
reviewCount: "2.4k",
imageSrc: "http://img.b2bpic.net/free-photo/three-frames-shelf_23-2147755106.jpg?_wi=2",
imageAlt: "architecture and design showcase",
},
{
id: "9",
brand: "Jessica Park",
name: "Food & Culinary",
price: "4.7★",
rating: 5,
reviewCount: "1.6k",
imageSrc: "http://img.b2bpic.net/free-photo/professional-camera-recording-cooking-show-content-with-chefs-restaurant-kitchen-filming-people-making-food-recipe-dish-with-fresh-ingredients-gastronomy-cuisine-online-class_482257-46088.jpg?_wi=2",
imageAlt: "professional camera recording cooking show",
},
]}
gridVariant="bento-grid-inverted"
animationType="slide-up"
textboxLayout="default"
useInvertedBackground={false}
/>
{/* Gallery Grid */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{[1, 2, 3, 4, 5, 6].map((item) => (
<div
key={item}
className="bg-card rounded-lg overflow-hidden hover:shadow-lg transition-shadow cursor-pointer group"
>
<div className="aspect-video bg-background/50 flex items-center justify-center group-hover:bg-background transition-colors">
<ImageIcon className="w-12 h-12 text-foreground/30" />
</div>
<div className="p-4">
<h3 className="font-semibold text-foreground mb-1">Featured Content</h3>
<p className="text-sm text-foreground/75">By Creative Community</p>
</div>
</div>
))}
</div>
</div>
<div id="social-proof" data-section="social-proof">
<SocialProofOne
title="Trusted by Creative Communities"
description="Join creators from around the world who share their work on MediaHub"
tag="Social Proof"
textboxLayout="default"
useInvertedBackground={false}
names={[
"Photography Studios",
"Video Production Houses",
"Design Agencies",
"Artists Collective",
"Content Creators",
"Freelance Portfolio",
"Creative Networks",
"Digital Artists",
]}
speed={40}
showCard={true}
/>
</div>
<div id="footer" data-section="footer">
<FooterSimple
columns={[
{
title: "Platform",
items: [
{ label: "Upload", href: "/upload" },
{ label: "Explore", href: "/gallery" },
{ label: "Collections", href: "#collections" },
{ label: "Trending", href: "#trending" },
],
},
{
title: "Community",
items: [
{ label: "Creators", href: "#creators" },
{ label: "Challenges", href: "#challenges" },
{ label: "Support", href: "/support" },
{ label: "Blog", href: "#blog" },
],
},
{
title: "Resources",
items: [
{ label: "Help Center", href: "#help" },
{ label: "API Docs", href: "#docs" },
{ label: "Contact", href: "mailto:support@mediahub.com" },
{ label: "Status", href: "#status" },
],
},
{
title: "Legal",
items: [
{ label: "Privacy Policy", href: "#privacy" },
{ label: "Terms of Service", href: "#terms" },
{ label: "Cookie Policy", href: "#cookies" },
{ label: "Guidelines", href: "#guidelines" },
],
},
]}
bottomLeftText="© 2025 MediaHub. All rights reserved."
bottomRightText="Made with creativity and passion"
/>
</div>
</ThemeProvider>
</div>
);
}
}

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

@@ -0,0 +1,99 @@
"use client";
import { useState } from "react";
import { useAuth } from "@/hooks/useAuth";
import { useRouter } from "next/navigation";
import Input from "@/components/form/Input";
import Link from "next/link";
import { Mail, Lock, Loader } from "lucide-react";
export default function LoginPage() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");
const [loading, setLoading] = useState(false);
const { login } = useAuth();
const router = useRouter();
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
setError("");
setLoading(true);
try {
await login(email, password);
router.push("/");
} catch (err: any) {
setError(err.message || "Login failed. Please try again.");
} finally {
setLoading(false);
}
};
return (
<div className="min-h-screen flex items-center justify-center bg-background px-4">
<div className="w-full max-w-md bg-card rounded-lg p-8 shadow-lg">
<h1 className="text-3xl font-bold text-foreground mb-2">Welcome Back</h1>
<p className="text-foreground/75 mb-6">Sign in to your MediaHub account</p>
{error && (
<div className="mb-4 p-3 bg-red-500/10 border border-red-500 rounded-lg text-red-500 text-sm">
{error}
</div>
)}
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<label className="block text-sm font-medium text-foreground mb-2">
Email Address
</label>
<Input
type="email"
placeholder="Enter your email"
value={email}
onChange={setEmail}
required
/>
</div>
<div>
<label className="block text-sm font-medium text-foreground mb-2">
Password
</label>
<Input
type="password"
placeholder="Enter your password"
value={password}
onChange={setPassword}
required
/>
</div>
<button
type="submit"
disabled={loading}
className="w-full bg-primary-cta text-white py-2 px-4 rounded-lg font-medium hover:opacity-90 transition-opacity disabled:opacity-50 flex items-center justify-center gap-2"
>
{loading ? (
<>
<Loader className="w-4 h-4 animate-spin" />
Signing in...
</>
) : (
"Sign In"
)}
</button>
</form>
<div className="mt-6 text-center">
<p className="text-foreground/75 text-sm">
Don't have an account?{" "}
<Link href="/signup" className="text-primary-cta hover:underline font-medium">
Create one
</Link>
</p>
</div>
</div>
</div>
);
}

View File

@@ -13,8 +13,36 @@ import ContactFaq from "@/components/sections/contact/ContactFaq";
import FooterSimple from "@/components/sections/footer/FooterSimple";
import Link from "next/link";
import { Sparkles, Zap, Upload, Images, FileCheck, Grid, Smartphone, Eye, Users, MessageCircle, Heart, ImageIcon, Check, Phone } from "lucide-react";
import { useAuth } from "@/hooks/useAuth";
import { useRouter } from "next/navigation";
import { useState } from "react";
export default function HomePage() {
const { user, logout } = useAuth();
const router = useRouter();
const [showLogoutMenu, setShowLogoutMenu] = useState(false);
const handleLogout = async () => {
await logout();
setShowLogoutMenu(false);
router.push("/");
};
const navItems = user
? [
{ name: "Home", id: "/" },
{ name: "Explore", id: "/gallery" },
{ name: "Upload", id: "/upload" },
{ name: "Support", id: "/contact" },
]
: [
{ name: "Home", id: "/" },
{ name: "Explore", id: "/gallery" },
{ name: "Upload", id: "/upload" },
{ name: "Support", id: "/contact" },
{ name: "Join Now", id: "/login" },
];
return (
<ThemeProvider
defaultButtonVariant="hover-magnetic"
@@ -30,17 +58,31 @@ export default function HomePage() {
>
<div id="nav" data-section="nav">
<NavbarStyleFullscreen
navItems={[
{ name: "Home", id: "/" },
{ name: "Explore", id: "/gallery" },
{ name: "Upload", id: "upload" },
{ name: "Support", id: "contact" },
{ name: "Join Now", id: "#" },
]}
navItems={navItems}
brandName="MediaHub"
bottomLeftText="Creative Community"
bottomRightText="support@mediahub.com"
bottomRightText={user ? `${user.email}` : "support@mediahub.com"}
/>
{user && (
<div className="fixed top-4 right-4 z-50">
<button
onClick={() => setShowLogoutMenu(!showLogoutMenu)}
className="px-4 py-2 rounded-lg bg-primary-cta text-white text-sm font-medium hover:opacity-90 transition-opacity"
>
{user.email}
</button>
{showLogoutMenu && (
<div className="absolute top-12 right-0 bg-card rounded-lg shadow-lg p-2 w-32">
<button
onClick={handleLogout}
className="w-full text-left px-4 py-2 text-sm hover:bg-background rounded transition-colors"
>
Logout
</button>
</div>
)}
</div>
)}
</div>
<div id="hero" data-section="hero">
@@ -268,7 +310,7 @@ export default function HomePage() {
title: "Community", items: [
{ label: "Creators", href: "#creators" },
{ label: "Challenges", href: "#challenges" },
{ label: "Support", href: "/support" },
{ label: "Support", href: "/contact" },
{ label: "Blog", href: "#blog" },
],
},

124
src/app/signup/page.tsx Normal file
View File

@@ -0,0 +1,124 @@
"use client";
import { useState } from "react";
import { useAuth } from "@/hooks/useAuth";
import { useRouter } from "next/navigation";
import Input from "@/components/form/Input";
import Link from "next/link";
import { Loader } from "lucide-react";
export default function SignupPage() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
const [error, setError] = useState("");
const [loading, setLoading] = useState(false);
const { signup } = useAuth();
const router = useRouter();
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
setError("");
if (password !== confirmPassword) {
setError("Passwords do not match");
return;
}
if (password.length < 6) {
setError("Password must be at least 6 characters");
return;
}
setLoading(true);
try {
await signup(email, password);
router.push("/");
} catch (err: any) {
setError(err.message || "Signup failed. Please try again.");
} finally {
setLoading(false);
}
};
return (
<div className="min-h-screen flex items-center justify-center bg-background px-4">
<div className="w-full max-w-md bg-card rounded-lg p-8 shadow-lg">
<h1 className="text-3xl font-bold text-foreground mb-2">Join MediaHub</h1>
<p className="text-foreground/75 mb-6">Create your account and start sharing</p>
{error && (
<div className="mb-4 p-3 bg-red-500/10 border border-red-500 rounded-lg text-red-500 text-sm">
{error}
</div>
)}
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<label className="block text-sm font-medium text-foreground mb-2">
Email Address
</label>
<Input
type="email"
placeholder="Enter your email"
value={email}
onChange={setEmail}
required
/>
</div>
<div>
<label className="block text-sm font-medium text-foreground mb-2">
Password
</label>
<Input
type="password"
placeholder="Create a password"
value={password}
onChange={setPassword}
required
/>
</div>
<div>
<label className="block text-sm font-medium text-foreground mb-2">
Confirm Password
</label>
<Input
type="password"
placeholder="Confirm your password"
value={confirmPassword}
onChange={setConfirmPassword}
required
/>
</div>
<button
type="submit"
disabled={loading}
className="w-full bg-primary-cta text-white py-2 px-4 rounded-lg font-medium hover:opacity-90 transition-opacity disabled:opacity-50 flex items-center justify-center gap-2"
>
{loading ? (
<>
<Loader className="w-4 h-4 animate-spin" />
Creating account...
</>
) : (
"Create Account"
)}
</button>
</form>
<div className="mt-6 text-center">
<p className="text-foreground/75 text-sm">
Already have an account?{" "}
<Link href="/login" className="text-primary-cta hover:underline font-medium">
Sign in
</Link>
</p>
</div>
</div>
</div>
);
}

View File

@@ -1,183 +1,75 @@
"use client";
import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider";
import NavbarStyleFullscreen from "@/components/navbar/NavbarStyleFullscreen/NavbarStyleFullscreen";
import HeroBillboard from "@/components/sections/hero/HeroBillboard";
import FeatureCardTen from "@/components/sections/feature/FeatureCardTen";
import InlineImageSplitTextAbout from "@/components/sections/about/InlineImageSplitTextAbout";
import FooterSimple from "@/components/sections/footer/FooterSimple";
import { Upload, Images, FileCheck, Zap } from "lucide-react";
import Link from "next/link";
import { useAuth } from "@/hooks/useAuth";
import { useRouter } from "next/navigation";
import { useEffect } from "react";
import { Upload, AlertCircle } from "lucide-react";
export default function UploadPage() {
const { user, loading } = useAuth();
const router = useRouter();
useEffect(() => {
if (!loading && !user) {
router.push("/login?redirect=/upload");
}
}, [user, loading, router]);
if (loading) {
return (
<div className="min-h-screen flex items-center justify-center bg-background">
<div className="text-center">
<div className="animate-spin mb-4">
<Upload className="w-8 h-8 text-primary-cta" />
</div>
<p className="text-foreground">Loading...</p>
</div>
</div>
);
}
if (!user) {
return (
<div className="min-h-screen flex items-center justify-center bg-background">
<div className="max-w-md bg-card rounded-lg p-8 text-center">
<AlertCircle className="w-12 h-12 text-red-500 mx-auto mb-4" />
<h2 className="text-xl font-bold text-foreground mb-2">Sign in required</h2>
<p className="text-foreground/75">You must be logged in to upload content.</p>
</div>
</div>
);
}
return (
<ThemeProvider
defaultButtonVariant="hover-magnetic"
defaultTextAnimation="reveal-blur"
borderRadius="rounded"
contentWidth="compact"
sizing="medium"
background="aurora"
cardStyle="gradient-mesh"
primaryButtonStyle="flat"
secondaryButtonStyle="solid"
headingFontWeight="light"
>
{/* Navbar */}
<div id="nav" data-section="nav">
<NavbarStyleFullscreen
brandName="MediaHub"
navItems={[
{ name: "Home", id: "/" },
{ name: "Explore", id: "/gallery" },
{ name: "Upload", id: "/upload" },
{ name: "Support", id: "/support" },
{ name: "Join Now", id: "#" },
]}
bottomLeftText="Creative Community"
bottomRightText="support@mediahub.com"
/>
</div>
<div className="min-h-screen bg-background">
<div className="max-w-4xl mx-auto px-4 py-12">
<div className="bg-card rounded-lg p-8">
<h1 className="text-3xl font-bold text-foreground mb-2">Upload Content</h1>
<p className="text-foreground/75 mb-8">
Welcome, {user.email}! Share your creative work with the community.
</p>
{/* Hero Section */}
<div id="hero" data-section="hero">
<HeroBillboard
title="Upload Your Creative Vision with the World"
description="Share your stunning photos and videos instantly. Our intuitive upload system makes it effortless to share, organize, and showcase your best work to a thriving global community."
background={{ variant: "sparkles-gradient" }}
tag="Upload Made Easy"
tagIcon={Zap}
buttons={[
{ text: "Start Uploading Now", href: "/upload" },
{ text: "Learn More", href: "/gallery" },
]}
imageSrc="http://img.b2bpic.net/free-vector/template-dashboard-user-panel_23-2148371519.jpg?_wi=2"
imageAlt="Upload interface dashboard"
/>
</div>
{/* Drag and drop area */}
<div className="border-2 border-dashed border-foreground/20 rounded-lg p-12 text-center mb-8 hover:border-foreground/40 transition-colors cursor-pointer">
<Upload className="w-12 h-12 text-foreground/50 mx-auto mb-4" />
<h3 className="text-lg font-semibold text-foreground mb-2">Drag and drop your files</h3>
<p className="text-foreground/75 mb-4">or click to browse from your computer</p>
<p className="text-sm text-foreground/50">Supported formats: JPG, PNG, MP4, MOV, WebM</p>
</div>
{/* Features Section */}
<div id="features" data-section="features">
<FeatureCardTen
title="Seamless Upload & Organization"
description="Everything you need to upload, organize, and manage your creative content with ease"
tag="Upload Features"
tagIcon={Zap}
features={[
{
id: "1",
title: "Drag & Drop Upload System",
description: "Upload multiple photos and videos at once with our intuitive drag-and-drop interface. Batch processing saves time and keeps your workflow smooth.",
media: {
imageSrc: "http://img.b2bpic.net/free-photo/elegant-uber-driver-giving-taxi-ride_23-2149241774.jpg?_wi=2",
},
items: [
{ icon: Upload, text: "Drag & drop upload" },
{ icon: Images, text: "Batch processing" },
{ icon: FileCheck, text: "Auto-organization" },
],
reverse: false,
},
{
id: "2",
title: "Smart File Management",
description: "Automatically organize your uploads into collections. Tag, categorize, and manage your entire portfolio from one powerful dashboard.",
media: {
imageSrc: "http://img.b2bpic.net/free-photo/three-frames-shelf_23-2147755106.jpg?_wi=3",
},
items: [
{ icon: Images, text: "Auto-categorization" },
{ icon: FileCheck, text: "Smart tagging" },
{ icon: Upload, text: "Bulk operations" },
],
reverse: true,
},
{
id: "3",
title: "Quality & Format Support",
description: "Support for all major formats - JPG, PNG, MP4, MOV, WebM and more. Automatic optimization ensures your content looks perfect everywhere.",
media: {
imageSrc: "http://img.b2bpic.net/free-photo/company-partners-working-office_23-2148352762.jpg?_wi=2",
},
items: [
{ icon: FileCheck, text: "Format support" },
{ icon: Images, text: "Auto-optimization" },
{ icon: Upload, text: "Quality preservation" },
],
reverse: false,
},
]}
textboxLayout="default"
animationType="slide-up"
useInvertedBackground={false}
/>
{/* Upload info */}
<div className="bg-background rounded-lg p-6">
<h3 className="font-semibold text-foreground mb-4">Upload Tips:</h3>
<ul className="space-y-2 text-foreground/75 text-sm">
<li> Photos up to 50MB each</li>
<li> Videos up to 500MB each</li>
<li> Organize into collections for easy management</li>
<li> Set privacy controls for each upload</li>
<li> Add tags and descriptions for better discovery</li>
</ul>
</div>
</div>
</div>
{/* CTA Section */}
<div id="process" data-section="process">
<InlineImageSplitTextAbout
heading={[
{ type: "text", content: "Ready to" },
{
type: "image",
src: "http://img.b2bpic.net/free-vector/cute-influencer-talent-agency-logo-template_742173-17610.jpg",
alt: "MediaHub logo",
},
{ type: "text", content: "Share Your Work?" },
]}
buttons={[
{ text: "Begin Uploading", href: "/upload" },
{ text: "Explore Gallery", href: "/gallery" },
]}
useInvertedBackground={false}
/>
</div>
{/* Footer */}
<div id="footer" data-section="footer">
<FooterSimple
columns={[
{
title: "Platform",
items: [
{ label: "Upload", href: "/upload" },
{ label: "Explore", href: "/gallery" },
{ label: "Collections", href: "#collections" },
{ label: "Trending", href: "#trending" },
],
},
{
title: "Community",
items: [
{ label: "Creators", href: "#creators" },
{ label: "Challenges", href: "#challenges" },
{ label: "Support", href: "/support" },
{ label: "Blog", href: "#blog" },
],
},
{
title: "Resources",
items: [
{ label: "Help Center", href: "#help" },
{ label: "API Docs", href: "#docs" },
{ label: "Contact", href: "mailto:support@mediahub.com" },
{ label: "Status", href: "#status" },
],
},
{
title: "Legal",
items: [
{ label: "Privacy Policy", href: "#privacy" },
{ label: "Terms of Service", href: "#terms" },
{ label: "Cookie Policy", href: "#cookies" },
{ label: "Guidelines", href: "#guidelines" },
],
},
]}
bottomLeftText="© 2025 MediaHub. All rights reserved."
bottomRightText="Made with creativity and passion"
/>
</div>
</ThemeProvider>
</div>
);
}
}

155
src/hooks/useAuth.ts Normal file
View File

@@ -0,0 +1,155 @@
"use client";
import { useState, useEffect, useCallback } from "react";
import { useRouter } from "next/navigation";
interface User {
id: string;
email: string;
createdAt: string;
}
interface AuthState {
user: User | null;
loading: boolean;
error: string | null;
}
const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || "http://localhost:3001";
export function useAuth() {
const [state, setState] = useState<AuthState>({
user: null,
loading: true,
error: null,
});
const router = useRouter();
// Check session on mount
useEffect(() => {
checkSession();
}, []);
const checkSession = useCallback(async () => {
try {
const response = await fetch(`${API_BASE_URL}/api/auth/session`, {
credentials: "include"});
if (response.ok) {
const data = await response.json();
setState({
user: data.user,
loading: false,
error: null,
});
} else {
setState({
user: null,
loading: false,
error: null,
});
}
} catch (error) {
setState({
user: null,
loading: false,
error: "Failed to check session"});
}
}, []);
const login = useCallback(
async (email: string, password: string) => {
setState((prev) => ({ ...prev, loading: true, error: null }));
try {
const response = await fetch(`${API_BASE_URL}/api/auth/login`, {
method: "POST", headers: {
"Content-Type": "application/json"},
credentials: "include", body: JSON.stringify({ email, password }),
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.message || "Login failed");
}
const data = await response.json();
setState({
user: data.user,
loading: false,
error: null,
});
} catch (error: any) {
setState({
user: null,
loading: false,
error: error.message || "Login failed"});
throw error;
}
},
[]
);
const signup = useCallback(
async (email: string, password: string) => {
setState((prev) => ({ ...prev, loading: true, error: null }));
try {
const response = await fetch(`${API_BASE_URL}/api/auth/signup`, {
method: "POST", headers: {
"Content-Type": "application/json"},
credentials: "include", body: JSON.stringify({ email, password }),
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.message || "Signup failed");
}
const data = await response.json();
setState({
user: data.user,
loading: false,
error: null,
});
} catch (error: any) {
setState({
user: null,
loading: false,
error: error.message || "Signup failed"});
throw error;
}
},
[]
);
const logout = useCallback(async () => {
setState((prev) => ({ ...prev, loading: true }));
try {
await fetch(`${API_BASE_URL}/api/auth/logout`, {
method: "POST", credentials: "include"});
setState({
user: null,
loading: false,
error: null,
});
} catch (error: any) {
setState({
user: null,
loading: false,
error: error.message || "Logout failed"});
}
}, []);
return {
user: state.user,
loading: state.loading,
error: state.error,
login,
signup,
logout,
checkSession,
};
}