diff --git a/src/app/api/auth/register/route.ts b/src/app/api/auth/register/route.ts new file mode 100644 index 0000000..c004b95 --- /dev/null +++ b/src/app/api/auth/register/route.ts @@ -0,0 +1,88 @@ +import { NextRequest, NextResponse } from 'next/server'; +import crypto from 'crypto'; +import fs from 'fs'; +import path from 'path'; + +const DB_FILE = path.join(process.cwd(), 'data', 'users.json'); + +interface User { + id: string; + name: string; + email: string; + passwordHash: string; + createdAt: string; +} + +function ensureDbDirectory() { + const dir = path.dirname(DB_FILE); + if (!fs.existsSync(dir)) { + fs.mkdirSync(dir, { recursive: true }); + } +} + +function hashPassword(password: string): string { + return crypto.createHash('sha256').update(password).digest('hex'); +} + +function getUsers(): User[] { + try { + if (fs.existsSync(DB_FILE)) { + const data = fs.readFileSync(DB_FILE, 'utf-8'); + return JSON.parse(data); + } + } catch (error) { + console.error('Error reading users file:', error); + } + return []; +} + +function saveUsers(users: User[]) { + ensureDbDirectory(); + fs.writeFileSync(DB_FILE, JSON.stringify(users, null, 2)); +} + +export async function POST(request: NextRequest) { + try { + const body = await request.json(); + const { name, email, password } = body; + + if (!name || !email || !password) { + return NextResponse.json( + { message: 'Missing required fields' }, + { status: 400 } + ); + } + + const users = getUsers(); + const existingUser = users.find(u => u.email === email); + + if (existingUser) { + return NextResponse.json( + { message: 'Email already registered' }, + { status: 409 } + ); + } + + const newUser: User = { + id: crypto.randomUUID(), + name, + email, + passwordHash: hashPassword(password), + createdAt: new Date().toISOString(), + }; + + users.push(newUser); + saveUsers(users); + + return NextResponse.json( + { message: 'User registered successfully', userId: newUser.id }, + { status: 201 } + ); + } catch (error) { + console.error('Registration error:', error); + return NextResponse.json( + { message: 'Internal server error' }, + { status: 500 } + ); + } +} diff --git a/src/app/auth/login/page.tsx b/src/app/auth/login/page.tsx new file mode 100644 index 0000000..c9dc7ed --- /dev/null +++ b/src/app/auth/login/page.tsx @@ -0,0 +1,168 @@ +"use client"; + +import { useState } from "react"; +import { useRouter } from "next/navigation"; +import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider"; +import NavbarStyleCentered from '@/components/navbar/NavbarStyleCentered/NavbarStyleCentered'; +import FooterBase from '@/components/sections/footer/FooterBase'; +import Input from '@/components/form/Input'; +import ButtonDirectionalHover from '@/components/button/ButtonDirectionalHover/ButtonDirectionalHover'; +import { Mail, Lock, LogIn } 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 handleLogin = 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(); + throw new Error(data.message || "Login failed"); + } + + router.push("/dashboard"); + } catch (err: any) { + setError(err.message); + } finally { + setIsLoading(false); + } + }; + + return ( + + + + + + + + + + + + Login + + Acesse sua conta FitFlow Pro + + + + + + Email + + + + + + + + + + Senha + + + + + + + + {error && ( + + {error} + + )} + + + + + + + + + Não tem conta?{" "} + + Registre-se + + + + + + + + + + ); +} diff --git a/src/app/auth/register/page.tsx b/src/app/auth/register/page.tsx new file mode 100644 index 0000000..d23541a --- /dev/null +++ b/src/app/auth/register/page.tsx @@ -0,0 +1,212 @@ +"use client"; + +import { useState } from "react"; +import { useRouter } from "next/navigation"; +import { ThemeProvider } from "@/providers/themeProvider/ThemeProvider"; +import NavbarStyleCentered from '@/components/navbar/NavbarStyleCentered/NavbarStyleCentered'; +import FooterBase from '@/components/sections/footer/FooterBase'; +import Input from '@/components/form/Input'; +import ButtonDirectionalHover from '@/components/button/ButtonDirectionalHover/ButtonDirectionalHover'; +import { Mail, Lock, User, UserPlus } from 'lucide-react'; + +export default function RegisterPage() { + const router = useRouter(); + const [name, setName] = useState(""); + const [email, setEmail] = useState(""); + const [password, setPassword] = useState(""); + const [confirmPassword, setConfirmPassword] = useState(""); + const [error, setError] = useState(""); + const [isLoading, setIsLoading] = useState(false); + + const handleRegister = async (e: React.FormEvent) => { + e.preventDefault(); + setError(""); + + if (password !== confirmPassword) { + setError("Senhas não correspondem"); + return; + } + + setIsLoading(true); + + try { + const response = await fetch("/api/auth/register", { + method: "POST", headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ name, email, password }), + }); + + if (!response.ok) { + const data = await response.json(); + throw new Error(data.message || "Registration failed"); + } + + router.push("/auth/login?registered=true"); + } catch (err: any) { + setError(err.message); + } finally { + setIsLoading(false); + } + }; + + return ( + + + + + + + + + + + + Registrar + + Crie sua conta FitFlow Pro + + + + + + Nome Completo + + + + + + + + + + Email + + + + + + + + + + Senha + + + + + + + + + + Confirmar Senha + + + + + + + + {error && ( + + {error} + + )} + + + + + + + + + Já tem conta?{" "} + + Faça login + + + + + + + + + + ); +} diff --git a/src/app/page.tsx b/src/app/page.tsx index 71a22d0..1f4b5e5 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -34,8 +34,9 @@ export default function LandingPage() { { name: "Dashboard", id: "dashboard" }, { name: "Treino", id: "training" }, { name: "Nutrição", id: "nutrition" }, + { name: "Receitas", id: "/recipes" }, { name: "Comunidade", id: "community" }, - { name: "Perfil", id: "onboarding" } + { name: "Perfil", id: "profile" } ]} button={{ text: "Começar Agora", href: "contact" }} brandName="FitFlow Pro" @@ -212,12 +213,14 @@ export default function LandingPage() { tagIcon={Apple} plans={[ { - id: "deficit", badge: "Perda de Peso", price: "Déficit Calórico", subtitle: "Receitas otimizadas para queima de calorias", features: [ + id: "deficit", badge: "Perda de Peso", badgeIcon: TrendingDown, + price: "Déficit Calórico", subtitle: "Receitas otimizadas para queima de calorias", features: [ "Macros calculados automaticamente", "Prep time entre 15-30 min", "Proteína alta, carboidrato estratégico", "Rastreamento integrado", "Sugestões diárias personalizadas" ] }, { - id: "surplus", badge: "Ganho de Massa", price: "Superávit Estratégico", subtitle: "Nutrição para crescimento muscular", features: [ + id: "surplus", badge: "Ganho de Massa", badgeIcon: TrendingUp, + price: "Superávit Estratégico", subtitle: "Nutrição para crescimento muscular", features: [ "Calorias calculadas para ganho", "Proteína máxima (2g por kg)", "Carbos pré e pós-treino", "Tempo de preparo eficiente", "Sincronizado com treino de força" ] } @@ -260,16 +263,16 @@ export default function LandingPage() { tagIcon={Users} members={[ { - id: "1", name: "Marcus A.", role: "Elite Runner", imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AoRNSPr0mCBj85JKsHl7qxTHsl/professional-athlete-portrait-male-fitne-1773256979726-5009f852.png?_wi=1" + id: "1", name: "Marcus A.", role: "Elite Runner", imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AoRNSPr0mCBj85JKsHl7qxTHsl/professional-athlete-portrait-male-fitne-1773256979726-5009f852.png?_wi=1", imageAlt: "Marcus A." }, { - id: "2", name: "Ana L.", role: "Strength Coach", imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AoRNSPr0mCBj85JKsHl7qxTHsl/fit-female-athlete-portrait-determined-e-1773256980310-c05dce2f.png?_wi=1" + id: "2", name: "Ana L.", role: "Strength Coach", imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AoRNSPr0mCBj85JKsHl7qxTHsl/fit-female-athlete-portrait-determined-e-1773256980310-c05dce2f.png?_wi=1", imageAlt: "Ana L." }, { - id: "3", name: "Rafael S.", role: "Nutrition Expert", imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AoRNSPr0mCBj85JKsHl7qxTHsl/athletic-male-trainer-portrait-confident-1773256979906-c5e05a88.png?_wi=1" + id: "3", name: "Rafael S.", role: "Nutrition Expert", imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AoRNSPr0mCBj85JKsHl7qxTHsl/athletic-male-trainer-portrait-confident-1773256979906-c5e05a88.png?_wi=1", imageAlt: "Rafael S." }, { - id: "4", name: "Sofia M.", role: "Fitness Trainer", imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AoRNSPr0mCBj85JKsHl7qxTHsl/female-fitness-coach-portrait-profession-1773256979710-97e8b5fe.png?_wi=1" + id: "4", name: "Sofia M.", role: "Fitness Trainer", imageSrc: "https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AoRNSPr0mCBj85JKsHl7qxTHsl/female-fitness-coach-portrait-profession-1773256979710-97e8b5fe.png?_wi=1", imageAlt: "Sofia M." } ]} animationType="blur-reveal" @@ -283,22 +286,22 @@ export default function LandingPage() { ('all'); + + const filteredRecipes = activeGoal === 'all' + ? recipes + : recipes.filter(recipe => recipe.goal === activeGoal); + + return ( + + + + + + + + + + + + + Filtrar por Objetivo + + setActiveGoal('all')} + className={`px-6 py-3 rounded-full font-semibold transition-all duration-300 ${ + activeGoal === 'all' + ? 'bg-primary-cta text-white shadow-lg' + : 'bg-secondary-cta bg-opacity-50 hover:bg-opacity-100' + }`} + > + Todas as Receitas + + setActiveGoal('weight-loss')} + className={`px-6 py-3 rounded-full font-semibold transition-all duration-300 flex items-center gap-2 ${ + activeGoal === 'weight-loss' + ? 'bg-primary-cta text-white shadow-lg' + : 'bg-secondary-cta bg-opacity-50 hover:bg-opacity-100' + }`} + > + + Perda de Peso + + setActiveGoal('muscle-gain')} + className={`px-6 py-3 rounded-full font-semibold transition-all duration-300 flex items-center gap-2 ${ + activeGoal === 'muscle-gain' + ? 'bg-primary-cta text-white shadow-lg' + : 'bg-secondary-cta bg-opacity-50 hover:bg-opacity-100' + }`} + > + + Ganho de Massa + + + + + + + + + + + + + + + ); +}
Acesse sua conta FitFlow Pro
{error}
+ Não tem conta?{" "} + + Registre-se + +
Crie sua conta FitFlow Pro
+ Já tem conta?{" "} + + Faça login + +