Merge pull request #3 from rede5/dev

Dev
This commit is contained in:
João Vitor 2025-12-04 11:37:46 -03:00 committed by GitHub
commit 449ee3d5bc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 1223 additions and 907 deletions

View file

@ -77,20 +77,22 @@ const AppContent: React.FC = () => {
<main>{renderPage()}</main>
{currentPage === "home" && (
<footer className="bg-gradient-to-br from-brand-purple to-brand-purple/90 text-brand-black py-16 md:py-20">
<div className="w-full max-w-[1600px] mx-auto px-6 sm:px-8 md:px-12 lg:px-16 xl:px-20">
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-8 sm:gap-10 md:gap-12 lg:gap-16 xl:gap-20 mb-12 md:mb-16">
<footer className="bg-gradient-to-br from-brand-purple to-brand-purple/90 text-brand-black py-12 sm:py-16 md:py-20">
<div className="w-full max-w-[1600px] mx-auto px-4 sm:px-6 md:px-8 lg:px-12 xl:px-16">
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6 sm:gap-8 md:gap-10 lg:gap-12 xl:gap-16 mb-8 sm:mb-12 md:mb-16">
{/* Logo e Descrição */}
<div className="lg:col-span-1">
<img
src="/logo.png"
alt="Photum Formaturas"
className="h-40 sm:h-34 md:h-28 lg:h-42 mb-4 md:mb-6"
/>
<p className="text-brand-black/80 text-sm sm:text-base md:text-lg leading-relaxed">
Eternizando momentos únicos com excelência e profissionalismo
desde 2020.
</p>
<div className="lg:col-span-1 text-center sm:text-left">
<div className="flex flex-col items-center sm:items-start">
<img
src="/logo.png"
alt="Photum Formaturas"
className="h-24 sm:h-28 md:h-32 lg:h-36 mb-4 md:mb-6"
/>
<p className="text-brand-black/80 text-xs sm:text-sm md:text-base leading-relaxed">
Eternizando momentos únicos com excelência e profissionalismo
desde 2020.
</p>
</div>
</div>
{/* Serviços */}

View file

@ -17,17 +17,17 @@ export const Button: React.FC<ButtonProps> = ({
const baseStyles = "inline-flex items-center justify-center font-medium transition-all duration-300 focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed";
const variants = {
primary: "bg-brand-black text-white hover:bg-gray-800 focus:ring-brand-black",
primary: "bg-[#492E61] text-white hover:bg-[#3a2450] focus:ring-[#492E61]",
secondary: "bg-[#B9CF32] text-white hover:bg-[#a5bd2e] focus:ring-[#B9CF32]",
outline: "border border-brand-black text-brand-black hover:bg-gray-50 focus:ring-brand-black",
ghost: "text-brand-black hover:bg-gray-100 hover:text-gray-900"
outline: "border border-[#492E61] text-[#492E61] hover:bg-[#492E61]/5 focus:ring-[#492E61]",
ghost: "text-[#492E61] hover:bg-[#492E61]/10 hover:text-[#3a2450]"
};
const sizes = {
sm: "text-xs px-3 py-1.5 rounded-sm",
md: "text-sm px-5 py-2.5 rounded-sm",
lg: "text-base px-8 py-3 rounded-sm",
xl: "text-lg px-10 py-4 rounded-md font-semibold"
sm: "text-xs px-3 py-1.5 rounded-md",
md: "text-sm px-5 py-2.5 rounded-lg",
lg: "text-base px-8 py-3 rounded-lg",
xl: "text-lg px-10 py-4 rounded-xl font-semibold"
};
return (

View file

@ -14,85 +14,85 @@ export const EventCard: React.FC<EventCardProps> = ({ event, onClick }) => {
const fullAddress = `${event.address.street}, ${event.address.number} - ${event.address.city}/${event.address.state}`;
return (
<div
<div
className="group bg-white rounded-lg border border-gray-100 overflow-hidden hover:shadow-xl transition-all duration-300 cursor-pointer flex flex-col h-full"
onClick={onClick}
>
<div className="relative h-48 overflow-hidden bg-gray-100">
<div className="relative h-40 sm:h-44 md:h-48 overflow-hidden bg-gray-100">
{/* Skeleton / Loading State */}
{!imageLoaded && (
<div className="absolute inset-0 bg-gray-200 animate-pulse flex items-center justify-center">
<div className="w-8 h-8 border-2 border-gray-300 border-t-brand-gold rounded-full animate-spin"></div>
<div className="w-6 h-6 sm:w-8 sm:h-8 border-2 border-gray-300 border-t-brand-gold rounded-full animate-spin"></div>
</div>
)}
<img
src={event.coverImage}
alt={event.name}
<img
src={event.coverImage}
alt={event.name}
className={`w-full h-full object-cover transition-all duration-700 group-hover:scale-105 ${imageLoaded ? 'opacity-100' : 'opacity-0'}`}
onLoad={() => setImageLoaded(true)}
/>
<div className="absolute inset-0 bg-gradient-to-t from-black/60 to-transparent opacity-60"></div>
<div className="absolute top-3 right-3">
<span className={`text-xs font-semibold px-2 py-1 rounded-sm uppercase tracking-wide ${STATUS_COLORS[event.status]}`}>
<div className="absolute top-2 sm:top-3 right-2 sm:right-3">
<span className={`text-[10px] sm:text-xs font-semibold px-1.5 sm:px-2 py-0.5 sm:py-1 rounded-sm uppercase tracking-wide ${STATUS_COLORS[event.status]}`}>
{event.status}
</span>
</div>
<div className="absolute bottom-3 left-4 text-white">
<p className="text-xs font-light uppercase tracking-widest opacity-90">{event.type}</p>
<h3 className="text-lg font-serif font-medium drop-shadow-md">{event.name}</h3>
<div className="absolute bottom-2 sm:bottom-3 left-3 sm:left-4 text-white">
<p className="text-[10px] sm:text-xs font-light uppercase tracking-widest opacity-90">{event.type}</p>
<h3 className="text-base sm:text-lg font-serif font-medium drop-shadow-md line-clamp-1">{event.name}</h3>
</div>
</div>
<div className="p-5 flex-1 flex flex-col justify-between">
<div className="space-y-3">
<div className="flex items-center text-gray-500 text-sm">
<Calendar size={16} className="mr-2 text-brand-gold" />
<span>{new Date(event.date).toLocaleDateString()} às {event.time}</span>
<div className="p-3 sm:p-4 md:p-5 flex-1 flex flex-col justify-between">
<div className="space-y-2 sm:space-y-3">
<div className="flex items-center text-gray-500 text-xs sm:text-sm">
<Calendar size={14} className="sm:w-4 sm:h-4 mr-1.5 sm:mr-2 text-brand-gold flex-shrink-0" />
<span className="truncate">{new Date(event.date).toLocaleDateString()} às {event.time}</span>
</div>
{/* Location with Tooltip */}
<div className="relative group/tooltip">
<div
className="flex items-center text-gray-500 text-sm"
<div
className="flex items-center text-gray-500 text-xs sm:text-sm"
title={fullAddress} // Native tooltip fallback
>
<MapPin size={16} className="mr-2 text-brand-gold flex-shrink-0" />
<MapPin size={14} className="sm:w-4 sm:h-4 mr-1.5 sm:mr-2 text-brand-gold flex-shrink-0" />
<span className="truncate">{event.address.city}, {event.address.state}</span>
</div>
{/* Custom Tooltip */}
<div className="absolute bottom-full left-0 mb-2 hidden group-hover/tooltip:block z-20 pointer-events-none">
{/* Custom Tooltip - Hidden on mobile */}
<div className="absolute bottom-full left-0 mb-2 hidden sm:group-hover/tooltip:block z-20 pointer-events-none">
<div className="bg-brand-black text-white text-xs rounded py-1.5 px-3 whitespace-nowrap shadow-xl">
{event.address.street}, {event.address.number}
<br/>
{event.address.city} - {event.address.state}
{/* Arrow */}
<div className="absolute top-full left-3 -mt-1 border-4 border-transparent border-t-brand-black"></div>
{event.address.street}, {event.address.number}
<br />
{event.address.city} - {event.address.state}
{/* Arrow */}
<div className="absolute top-full left-3 -mt-1 border-4 border-transparent border-t-brand-black"></div>
</div>
</div>
</div>
{event.contacts.length > 0 && (
<div className="flex items-center text-gray-500 text-sm">
<UserCheck size={16} className="mr-2 text-brand-gold" />
<span>{event.contacts.length} {event.contacts.length === 1 ? 'Fornecedor/Contato' : 'Fornecedores/Contatos'}</span>
<div className="flex items-center text-gray-500 text-xs sm:text-sm">
<UserCheck size={14} className="sm:w-4 sm:h-4 mr-1.5 sm:mr-2 text-brand-gold flex-shrink-0" />
<span className="truncate">{event.contacts.length} {event.contacts.length === 1 ? 'Contato' : 'Contatos'}</span>
</div>
)}
</div>
<div className="mt-5 pt-4 border-t border-gray-50 flex items-center justify-between">
<div className="flex -space-x-2">
{[1,2,3].map(i => (
<div key={i} className="w-8 h-8 rounded-full border-2 border-white bg-gray-200" style={{backgroundImage: `url(https://i.pravatar.cc/100?img=${i})`, backgroundSize: 'cover'}}></div>
))}
<div className="w-8 h-8 rounded-full border-2 border-white bg-gray-100 flex items-center justify-center text-xs text-gray-500 font-medium">
+4
</div>
</div>
<button className="text-brand-black group-hover:text-brand-gold transition-colors">
<ArrowRight size={20} />
</button>
<div className="mt-3 sm:mt-4 md:mt-5 pt-3 sm:pt-4 border-t border-gray-50 flex items-center justify-between">
<div className="flex -space-x-1.5 sm:-space-x-2">
{[1, 2, 3].map(i => (
<div key={i} className="w-6 h-6 sm:w-7 sm:h-7 md:w-8 md:h-8 rounded-full border-2 border-white bg-gray-200" style={{ backgroundImage: `url(https://i.pravatar.cc/100?img=${i})`, backgroundSize: 'cover' }}></div>
))}
<div className="w-6 h-6 sm:w-7 sm:h-7 md:w-8 md:h-8 rounded-full border-2 border-white bg-gray-100 flex items-center justify-center text-[10px] sm:text-xs text-gray-500 font-medium">
+4
</div>
</div>
<button className="text-brand-black group-hover:text-brand-gold transition-colors">
<ArrowRight size={18} className="sm:w-5 sm:h-5" />
</button>
</div>
</div>
</div>

View file

@ -92,13 +92,13 @@ export const EventForm: React.FC<EventFormProps> = ({
const formTitle = initialData
? "Editar Evento"
: isClientRequest
? "Solicitar Orçamento/Evento"
: "Cadastrar Novo Evento";
? "Solicitar Orçamento/Evento"
: "Cadastrar Novo Evento";
const submitLabel = initialData
? "Salvar Alterações"
: isClientRequest
? "Enviar Solicitação"
: "Criar Evento";
? "Enviar Solicitação"
: "Criar Evento";
// Address Autocomplete Logic using Mapbox
useEffect(() => {
@ -264,11 +264,11 @@ export const EventForm: React.FC<EventFormProps> = ({
<div className="bg-white rounded-lg shadow-xl overflow-hidden max-w-4xl mx-auto border border-gray-100 slide-up relative">
{/* Success Toast */}
{showToast && (
<div className="absolute top-4 right-4 z-50 bg-brand-black text-white px-6 py-4 rounded shadow-2xl flex items-center space-x-3 fade-in">
<CheckCircle className="text-brand-gold h-6 w-6" />
<div className="absolute top-4 right-4 z-50 bg-brand-black text-white px-4 sm:px-6 py-3 sm:py-4 rounded shadow-2xl flex items-center space-x-2 sm:space-x-3 fade-in">
<CheckCircle className="text-brand-gold h-5 w-5 sm:h-6 sm:w-6" />
<div>
<h4 className="font-bold text-sm">Sucesso!</h4>
<p className="text-xs text-gray-300">
<h4 className="font-bold text-xs sm:text-sm">Sucesso!</h4>
<p className="text-[10px] sm:text-xs text-gray-300">
As informações foram salvas.
</p>
</div>
@ -276,40 +276,67 @@ export const EventForm: React.FC<EventFormProps> = ({
)}
{/* Form Header */}
<div className="bg-gray-50 border-b px-8 py-6 flex justify-between items-center">
<div>
<h2 className="text-2xl font-serif text-brand-black">{formTitle}</h2>
<p className="text-sm text-gray-500 mt-1">
{isClientRequest
? "Preencha os detalhes do seu sonho. Nossa equipe analisará em breve."
: "Preencha as informações técnicas do evento."}
</p>
</div>
<div className="flex space-x-2">
{["details", "location", "briefing", "files"].map((tab, idx) => (
<div
key={tab}
className={`flex flex-col items-center ${
activeTab === tab ? "opacity-100" : "opacity-40"
}`}
>
<span
className={`w-8 h-8 rounded-full flex items-center justify-center text-xs font-bold mb-1 ${
activeTab === tab
? "bg-brand-black text-white"
: "bg-gray-200 text-gray-600"
}`}
<div className="bg-gray-50 border-b px-4 sm:px-6 md:px-8 py-4 sm:py-5 md:py-6">
<div className="flex flex-col sm:flex-row sm:justify-between sm:items-center gap-3 sm:gap-0">
<div>
<h2 className="text-xl sm:text-2xl font-serif text-brand-black">{formTitle}</h2>
<p className="text-xs sm:text-sm text-gray-500 mt-1">
{isClientRequest
? "Preencha os detalhes do seu sonho. Nossa equipe analisará em breve."
: "Preencha as informações técnicas do evento."}
</p>
</div>
{/* Step indicators - Hidden on mobile, shown on tablet+ */}
<div className="hidden sm:flex space-x-2">
{["details", "location", "briefing", "files"].map((tab, idx) => (
<div
key={tab}
className={`flex flex-col items-center ${activeTab === tab ? "opacity-100" : "opacity-40"
}`}
>
{idx + 1}
</span>
</div>
<span
className={`w-7 h-7 sm:w-8 sm:h-8 rounded-full flex items-center justify-center text-xs font-bold mb-1 ${activeTab === tab
? "bg-[#492E61] text-white"
: "bg-gray-200 text-gray-600"
}`}
>
{idx + 1}
</span>
</div>
))}
</div>
</div>
</div>
{/* Mobile Tabs - Horizontal */}
<div className="lg:hidden border-b border-gray-200 bg-white overflow-x-auto scrollbar-hide">
<div className="flex min-w-max">
{[
{ id: "details", label: "Detalhes", icon: "1" },
{ id: "location", label: "Localização", icon: "2" },
{ id: "briefing", label: isClientRequest ? "Desejos" : "Briefing", icon: "3" },
{ id: "files", label: "Arquivos", icon: "4" },
].map((item) => (
<button
key={item.id}
onClick={() => setActiveTab(item.id as any)}
className={`flex-1 px-4 py-3 text-xs sm:text-sm font-medium transition-colors border-b-2 whitespace-nowrap ${activeTab === item.id
? "text-brand-gold border-brand-gold bg-brand-gold/5"
: "text-gray-500 border-transparent hover:bg-gray-50"
}`}
>
<span className="inline-block w-5 h-5 rounded-full text-[10px] leading-5 text-center mr-1.5 ${
activeTab === item.id ? 'bg-brand-gold text-white' : 'bg-gray-200 text-gray-600'
}">{item.icon}</span>
{item.label}
</button>
))}
</div>
</div>
<div className="grid grid-cols-4 min-h-[500px]">
{/* Sidebar Navigation for Form */}
<div className="col-span-1 border-r border-gray-100 bg-gray-50/50 p-4 space-y-2">
<div className="lg:grid lg:grid-cols-4 min-h-[500px]">
{/* Desktop Sidebar Navigation */}
<div className="hidden lg:block lg:col-span-1 border-r border-gray-100 bg-gray-50/50 p-4 space-y-2">
{[
{ id: "details", label: "Detalhes & Data" },
{ id: "location", label: "Localização" },
@ -322,11 +349,10 @@ export const EventForm: React.FC<EventFormProps> = ({
<button
key={item.id}
onClick={() => setActiveTab(item.id as any)}
className={`w-full text-left px-4 py-3 rounded-sm text-sm font-medium transition-colors ${
activeTab === item.id
? "bg-white shadow-sm text-brand-gold border-l-4 border-brand-gold"
: "text-gray-500 hover:bg-gray-100"
}`}
className={`w-full text-left px-4 py-3 rounded-sm text-sm font-medium transition-colors ${activeTab === item.id
? "bg-white shadow-sm text-brand-gold border-l-4 border-brand-gold"
: "text-gray-500 hover:bg-gray-100"
}`}
>
{item.label}
</button>
@ -334,7 +360,7 @@ export const EventForm: React.FC<EventFormProps> = ({
</div>
{/* Form Content */}
<div className="col-span-3 p-8">
<div className="lg:col-span-3 p-4 sm:p-6 md:p-8">
{activeTab === "details" && (
<div className="space-y-6 fade-in">
<div className="grid grid-cols-1 gap-6">
@ -355,7 +381,7 @@ export const EventForm: React.FC<EventFormProps> = ({
}
/>
<div className="grid grid-cols-2 gap-4">
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<Input
label="Horário de Início*"
type="time"
@ -509,11 +535,11 @@ export const EventForm: React.FC<EventFormProps> = ({
<div className="flex items-center justify-between w-full px-2">
<span className="text-sm text-gray-500 truncate max-w-[200px]">
{formData.coverImage &&
!formData.coverImage.startsWith("http")
!formData.coverImage.startsWith("http")
? "Imagem selecionada"
: formData.coverImage
? "Imagem atual (URL)"
: "Clique para selecionar..."}
? "Imagem atual (URL)"
: "Clique para selecionar..."}
</span>
<div className="bg-gray-100 p-1.5 rounded hover:bg-gray-200">
<Upload size={16} className="text-gray-600" />
@ -535,8 +561,8 @@ export const EventForm: React.FC<EventFormProps> = ({
</div>
</div>
<div className="flex justify-end mt-8">
<Button onClick={() => setActiveTab("location")}>
<div className="flex flex-col sm:flex-row justify-end gap-3 sm:gap-0 mt-8">
<Button onClick={() => setActiveTab("location")} className="w-full sm:w-auto">
Próximo: Localização
</Button>
</div>
@ -605,8 +631,8 @@ export const EventForm: React.FC<EventFormProps> = ({
)}
</div>
<div className="grid grid-cols-3 gap-4">
<div className="col-span-2">
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4">
<div className="sm:col-span-2">
<Input
label="Rua"
value={formData.address.street}
@ -639,7 +665,7 @@ export const EventForm: React.FC<EventFormProps> = ({
inputMode="numeric"
/>
</div>
<div className="grid grid-cols-2 gap-4">
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<Input
label="Cidade"
value={formData.address.city}
@ -683,7 +709,8 @@ export const EventForm: React.FC<EventFormProps> = ({
initialLat={formData.address.lat || -22.7394}
initialLng={formData.address.lng || -47.3314}
onLocationChange={handleMapLocationChange}
height="450px"
height="300px"
className="sm:h-[400px] md:h-[450px]"
/>
</div>
@ -704,14 +731,15 @@ export const EventForm: React.FC<EventFormProps> = ({
</div>
)}
<div className="flex justify-between mt-8">
<div className="flex flex-col sm:flex-row justify-between gap-3 mt-8">
<Button
variant="outline"
onClick={() => setActiveTab("details")}
className="w-full sm:w-auto"
>
Voltar
</Button>
<Button onClick={() => setActiveTab("briefing")}>
<Button onClick={() => setActiveTab("briefing")} className="w-full sm:w-auto">
Próximo
</Button>
</div>
@ -777,9 +805,8 @@ export const EventForm: React.FC<EventFormProps> = ({
/>
<button
onClick={() => removeContact(idx)}
className={`mt-1 p-2 text-gray-400 hover:text-red-500 ${
idx === 0 ? "mt-7" : ""
}`}
className={`mt-1 p-2 text-gray-400 hover:text-red-500 ${idx === 0 ? "mt-7" : ""
}`}
>
<X size={16} />
</button>
@ -788,14 +815,15 @@ export const EventForm: React.FC<EventFormProps> = ({
</div>
</div>
<div className="flex justify-between mt-8">
<div className="flex flex-col sm:flex-row justify-between gap-3 mt-8">
<Button
variant="outline"
onClick={() => setActiveTab("location")}
className="w-full sm:w-auto"
>
Voltar
</Button>
<Button onClick={() => setActiveTab("files")}>Próximo</Button>
<Button onClick={() => setActiveTab("files")} className="w-full sm:w-auto">Próximo</Button>
</div>
</div>
)}
@ -845,14 +873,15 @@ export const EventForm: React.FC<EventFormProps> = ({
</div>
)}
<div className="flex justify-between mt-8">
<div className="flex flex-col sm:flex-row justify-between gap-3 mt-8">
<Button
variant="outline"
onClick={() => setActiveTab("briefing")}
className="w-full sm:w-auto"
>
Voltar
</Button>
<Button onClick={handleSubmit} variant="secondary">
<Button onClick={handleSubmit} variant="secondary" className="w-full sm:w-auto">
{submitLabel}
</Button>
</div>

View file

@ -1,7 +1,7 @@
import React, { useState, useEffect } from "react";
import { UserRole } from "../types";
import { useAuth } from "../contexts/AuthContext";
import { Menu, X, LogOut, User } from "lucide-react";
import { Menu, X, LogOut, User, Settings, Camera, Mail, Phone } from "lucide-react";
import { Button } from "./Button";
interface NavbarProps {
@ -14,6 +14,13 @@ export const Navbar: React.FC<NavbarProps> = ({ onNavigate, currentPage }) => {
const [isScrolled, setIsScrolled] = useState(false);
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
const [isAccountDropdownOpen, setIsAccountDropdownOpen] = useState(false);
const [isEditProfileModalOpen, setIsEditProfileModalOpen] = useState(false);
const [profileData, setProfileData] = useState({
name: user?.name || "",
email: user?.email || "",
phone: "",
avatar: user?.avatar || "",
});
useEffect(() => {
const handleScroll = () => {
@ -23,6 +30,19 @@ export const Navbar: React.FC<NavbarProps> = ({ onNavigate, currentPage }) => {
return () => window.removeEventListener("scroll", handleScroll);
}, []);
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (isAccountDropdownOpen) {
const target = event.target as HTMLElement;
if (!target.closest('.relative')) {
setIsAccountDropdownOpen(false);
}
}
};
document.addEventListener("mousedown", handleClickOutside);
return () => document.removeEventListener("mousedown", handleClickOutside);
}, [isAccountDropdownOpen]);
const getLinks = () => {
if (!user) return [];
@ -60,196 +80,585 @@ export const Navbar: React.FC<NavbarProps> = ({ onNavigate, currentPage }) => {
};
return (
<nav className="fixed w-full z-50 bg-white shadow-sm py-3">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex justify-between items-center h-16">
{/* Logo */}
<div
className="flex-shrink-0 flex items-center cursor-pointer"
onClick={() => onNavigate("home")}
>
<img
src="/logo.png"
alt="Photum Formaturas"
className="h-30 mb-6 w-auto object-contain"
/>
</div>
<>
<nav className="fixed w-full z-50 bg-white shadow-sm py-3">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div className="flex justify-between items-center h-16">
{/* Logo */}
<div
className="flex-shrink-0 flex items-center cursor-pointer"
onClick={() => onNavigate("home")}
>
<img
src="/logo.png"
alt="Photum Formaturas"
className="h-16 md:h-28 mb-0 md:mb-6 w-auto object-contain"
/>
</div>
{/* Desktop Navigation */}
{user && (
<div className="hidden md:flex items-center space-x-6">
{getLinks().map((link) => (
<button
key={link.path}
onClick={() => onNavigate(link.path)}
className={`text-sm font-medium tracking-wide uppercase hover:text-brand-gold transition-colors pb-1 ${
currentPage === link.path
{/* Desktop Navigation */}
{user && (
<div className="hidden md:flex items-center space-x-6">
{getLinks().map((link) => (
<button
key={link.path}
onClick={() => onNavigate(link.path)}
className={`text-sm font-medium tracking-wide uppercase hover:text-brand-gold transition-colors pb-1 ${currentPage === link.path
? "text-brand-gold border-b-2 border-brand-gold"
: "text-gray-600 border-b-2 border-transparent"
}`}
>
{link.name}
</button>
))}
</div>
)}
{/* Right Side Actions */}
<div className="hidden md:flex items-center space-x-4">
{user ? (
<div className="flex items-center space-x-4 pl-4 border-l border-gray-200">
<div className="flex flex-col items-end mr-2">
<span className="text-sm font-bold text-brand-black leading-tight">
{user.name}
</span>
<span className="text-[10px] uppercase tracking-wider text-brand-gold leading-tight">
{getRoleLabel()}
</span>
</div>
<div className="h-9 w-9 rounded-full bg-gray-100 overflow-hidden border border-gray-200 ring-2 ring-transparent hover:ring-brand-gold transition-all">
<img
src={user.avatar}
alt="Avatar"
className="w-full h-full object-cover"
/>
</div>
<button
onClick={logout}
className="text-gray-400 hover:text-red-500 transition-colors p-1"
title="Sair"
>
<LogOut size={18} />
</button>
</div>
) : (
<div className="relative">
<button
onClick={() =>
setIsAccountDropdownOpen(!isAccountDropdownOpen)
}
className="flex items-center gap-2 p-2 rounded-full hover:bg-gray-100 transition-colors"
>
<div className="w-10 h-10 rounded-full border-2 border-brand-gold flex items-center justify-center text-brand-gold hover:bg-brand-gold hover:text-white transition-colors">
<User size={24} />
</div>
<div className="text-left hidden lg:block">
<p className="text-xs text-gray-500">Olá, bem-vindo(a)</p>
<p className="text-sm font-medium text-brand-black">
Entrar / Cadastrar
</p>
</div>
</button>
{/* Dropdown Popup - Centralizado */}
{isAccountDropdownOpen && (
<div className="absolute left-1/2 -translate-x-1/2 top-full mt-2 w-64 bg-white rounded-xl shadow-xl border border-gray-200 overflow-hidden z-50 fade-in">
<div className="p-4 space-y-3">
<Button
onClick={() => {
onNavigate("login");
setIsAccountDropdownOpen(false);
}}
variant="secondary"
className="w-full rounded-xl"
>
ENTRAR
</Button>
<Button
onClick={() => {
onNavigate("register");
setIsAccountDropdownOpen(false);
}}
className="w-full bg-purple-600 text-white hover:bg-purple-700 focus:ring-purple-500 rounded-xl"
>
Cadastre-se agora
</Button>
</div>
</div>
)}
}`}
>
{link.name}
</button>
))}
</div>
)}
</div>
{/* Mobile Button */}
<div className="md:hidden flex items-center">
<button
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
className="text-brand-black hover:text-brand-gold p-2"
>
{isMobileMenuOpen ? <X size={24} /> : <Menu size={24} />}
</button>
</div>
</div>
</div>
{/* Mobile Menu */}
{isMobileMenuOpen && (
<div className="md:hidden absolute top-full left-0 w-full bg-white border-b border-gray-100 shadow-lg fade-in">
<div className="px-4 py-4 space-y-3">
{user &&
getLinks().map((link) => (
<button
key={link.path}
onClick={() => {
onNavigate(link.path);
setIsMobileMenuOpen(false);
}}
className="block w-full text-left text-base font-medium text-gray-700 hover:text-brand-gold py-2 border-b border-gray-50"
>
{link.name}
</button>
))}
<div className="pt-4">
{/* Right Side Actions */}
<div className="hidden md:flex items-center space-x-4">
{user ? (
<div className="flex items-center justify-between">
<div className="flex items-center">
<img
src={user.avatar}
className="w-8 h-8 rounded-full mr-2"
/>
<div>
<span className="font-bold text-sm block">
{user.name}
</span>
<span className="text-xs text-brand-gold">
{getRoleLabel()}
</span>
</div>
<div className="flex items-center gap-3">
<div className="flex flex-col items-end mr-2">
<span className="text-sm font-bold text-brand-black leading-tight">
{user.name}
</span>
<span className="text-[10px] uppercase tracking-wider text-brand-gold leading-tight">
{getRoleLabel()}
</span>
</div>
{/* Avatar com dropdown */}
<div className="relative">
<button
onClick={() => setIsAccountDropdownOpen(!isAccountDropdownOpen)}
className="h-9 w-9 rounded-full bg-gray-100 overflow-hidden border border-gray-200 ring-2 ring-transparent hover:ring-brand-gold transition-all cursor-pointer"
>
<img
src={user.avatar}
alt="Avatar"
className="w-full h-full object-cover"
/>
</button>
{/* Profile Preview Dropdown */}
{isAccountDropdownOpen && (
<div className="absolute right-0 top-full mt-3 w-80 bg-white rounded-2xl shadow-2xl border border-gray-100 overflow-hidden z-50 fade-in">
{/* Header com foto e info */}
<div className="bg-gradient-to-r from-[#492E61] to-[#5a3a7a] p-6 text-center relative">
<div className="w-20 h-20 mx-auto mb-3 rounded-full bg-white/20 backdrop-blur-sm flex items-center justify-center border-4 border-white/30 overflow-hidden">
<img
src={user.avatar}
alt={user.name}
className="w-full h-full object-cover"
/>
</div>
<h3 className="text-white font-bold text-lg mb-1">{user.name}</h3>
<p className="text-white/90 text-sm mb-1">{user.email}</p>
<span className="inline-block px-3 py-1 bg-white/20 backdrop-blur-sm rounded-full text-xs font-medium text-white border border-white/30">
{getRoleLabel()}
</span>
</div>
{/* Menu Items */}
<div className="p-4 space-y-2 bg-gray-50">
{/* Editar Perfil - Apenas para Fotógrafos e Clientes */}
{(user.role === UserRole.PHOTOGRAPHER || user.role === UserRole.EVENT_OWNER) && (
<button
onClick={() => {
setIsEditProfileModalOpen(true);
setIsAccountDropdownOpen(false);
}}
className="w-full flex items-center gap-3 px-4 py-3 rounded-xl hover:bg-white transition-colors text-left group"
>
<div className="w-10 h-10 rounded-lg bg-[#492E61]/10 flex items-center justify-center group-hover:bg-[#492E61]/20 transition-colors">
<User size={20} className="text-[#492E61]" />
</div>
<div className="flex-1">
<p className="text-sm font-semibold text-gray-900">Editar Perfil</p>
<p className="text-xs text-gray-500">Atualize suas informações</p>
</div>
</button>
)}
{/* Configurações - Apenas para CEO e Business Owner */}
{(user.role === UserRole.BUSINESS_OWNER || user.role === UserRole.SUPERADMIN) && (
<button
onClick={() => {
onNavigate("settings");
setIsAccountDropdownOpen(false);
}}
className="w-full flex items-center gap-3 px-4 py-3 rounded-xl hover:bg-white transition-colors text-left group"
>
<div className="w-10 h-10 rounded-lg bg-gray-200 flex items-center justify-center group-hover:bg-gray-300 transition-colors">
<Settings size={20} className="text-gray-600" />
</div>
<div className="flex-1">
<p className="text-sm font-semibold text-gray-900">Configurações</p>
<p className="text-xs text-gray-500">Preferências da conta</p>
</div>
</button>
)}
{/* Sair */}
<button
onClick={() => {
logout();
setIsAccountDropdownOpen(false);
}}
className="w-full flex items-center gap-3 px-4 py-3 rounded-xl hover:bg-red-50 transition-colors text-left group border-t border-gray-200 mt-2 pt-4"
>
<div className="w-10 h-10 rounded-lg bg-red-100 flex items-center justify-center group-hover:bg-red-200 transition-colors">
<LogOut size={20} className="text-red-600" />
</div>
<div className="flex-1">
<p className="text-sm font-semibold text-red-600">Sair da Conta</p>
<p className="text-xs text-red-400">Desconectar do sistema</p>
</div>
</button>
</div>
</div>
)}
</div>
<Button variant="ghost" size="sm" onClick={logout}>
Sair
</Button>
</div>
) : (
<div className="flex flex-col gap-2">
<Button
className="w-full rounded-lg"
size="lg"
variant="secondary"
onClick={() => {
onNavigate("login");
setIsMobileMenuOpen(false);
}}
<div className="relative">
<button
onClick={() =>
setIsAccountDropdownOpen(!isAccountDropdownOpen)
}
className="flex items-center gap-2 px-4 py-2 rounded-full hover:bg-gray-100 transition-colors shadow-md"
>
ENTRAR
</Button>
<Button
className="w-full bg-purple-600 text-white hover:bg-purple-700 focus:ring-purple-500 rounded-lg"
size="lg"
onClick={() => {
onNavigate("register");
setIsMobileMenuOpen(false);
}}
<div className="w-10 h-10 rounded-full border-2 border-brand-gold flex items-center justify-center text-brand-gold hover:bg-brand-gold hover:text-white transition-colors">
<User size={24} />
</div>
<div className="text-left hidden lg:block">
<p className="text-xs text-gray-500">Olá, bem-vindo(a)</p>
<p className="text-xs font-semibold text-gray-700">Entrar/Cadastrar</p>
</div>
</button>
{/* Dropdown Popup - Responsivo */}
{isAccountDropdownOpen && (
<div className="absolute right-0 lg:left-1/2 lg:-translate-x-1/2 top-full mt-3 w-72 bg-white rounded-2xl shadow-2xl border border-gray-100 overflow-hidden z-50 fade-in">
{/* Header com ícone */}
<div className="bg-gradient-to-r from-[#492E61] to-[#5a3a7a] p-6 text-center">
<div className="w-16 h-16 mx-auto mb-3 rounded-full bg-white/20 backdrop-blur-sm flex items-center justify-center border-2 border-white/30">
<User size={32} className="text-white" />
</div>
<p className="text-white/70 text-xs mb-1">Olá, bem-vindo(a)</p>
<p className="text-white font-semibold text-base">Entrar/Cadastrar</p>
</div>
{/* Botões */}
<div className="p-5 space-y-3 bg-gray-50">
<Button
onClick={() => {
onNavigate("login");
setIsAccountDropdownOpen(false);
}}
variant="secondary"
className="w-full rounded-xl shadow-sm hover:shadow-md transition-shadow"
>
ENTRAR
</Button>
<Button
onClick={() => {
onNavigate("register");
setIsAccountDropdownOpen(false);
}}
variant="primary"
className="w-full rounded-xl shadow-sm hover:shadow-md transition-shadow"
>
Cadastre-se agora
</Button>
</div>
</div>
)}
</div>
)}
</div>
{/* Mobile Buttons */}
<div className="md:hidden flex items-center gap-2">
{user ? (
<>
<div className="relative">
<button
onClick={() => setIsAccountDropdownOpen(!isAccountDropdownOpen)}
className="h-10 w-10 rounded-full bg-gray-100 overflow-hidden border border-gray-200 ring-2 ring-transparent active:ring-brand-gold transition-all shadow-md"
>
<img
src={user.avatar}
alt="Avatar"
className="w-full h-full object-cover"
/>
</button>
{/* Profile Preview Dropdown Mobile */}
{isAccountDropdownOpen && (
<div className="absolute right-0 top-full mt-3 w-80 bg-white rounded-2xl shadow-2xl border border-gray-100 overflow-hidden z-50 fade-in">
{/* Header com foto e info */}
<div className="bg-gradient-to-r from-[#492E61] to-[#5a3a7a] p-6 text-center relative">
<div className="w-20 h-20 mx-auto mb-3 rounded-full bg-white/20 backdrop-blur-sm flex items-center justify-center border-4 border-white/30 overflow-hidden">
<img
src={user.avatar}
alt={user.name}
className="w-full h-full object-cover"
/>
</div>
<h3 className="text-white font-bold text-lg mb-1">{user.name}</h3>
<p className="text-white/90 text-sm mb-1">{user.email}</p>
<span className="inline-block px-3 py-1 bg-white/20 backdrop-blur-sm rounded-full text-xs font-medium text-white border border-white/30">
{getRoleLabel()}
</span>
</div>
{/* Menu Items */}
<div className="p-4 space-y-2 bg-gray-50">
{/* Editar Perfil - Apenas para Fotógrafos e Clientes */}
{(user.role === UserRole.PHOTOGRAPHER || user.role === UserRole.EVENT_OWNER) && (
<button
onClick={() => {
setIsEditProfileModalOpen(true);
setIsAccountDropdownOpen(false);
}}
className="w-full flex items-center gap-3 px-4 py-3 rounded-xl hover:bg-white transition-colors text-left group"
>
<div className="w-10 h-10 rounded-lg bg-[#492E61]/10 flex items-center justify-center group-hover:bg-[#492E61]/20 transition-colors">
<User size={20} className="text-[#492E61]" />
</div>
<div className="flex-1">
<p className="text-sm font-semibold text-gray-900">Editar Perfil</p>
<p className="text-xs text-gray-500">Atualize suas informações</p>
</div>
</button>
)}
{/* Configurações - Apenas para CEO e Business Owner */}
{(user.role === UserRole.BUSINESS_OWNER || user.role === UserRole.SUPERADMIN) && (
<button
onClick={() => {
onNavigate("settings");
setIsAccountDropdownOpen(false);
}}
className="w-full flex items-center gap-3 px-4 py-3 rounded-xl hover:bg-white transition-colors text-left group"
>
<div className="w-10 h-10 rounded-lg bg-gray-200 flex items-center justify-center group-hover:bg-gray-300 transition-colors">
<Settings size={20} className="text-gray-600" />
</div>
<div className="flex-1">
<p className="text-sm font-semibold text-gray-900">Configurações</p>
<p className="text-xs text-gray-500">Preferências da conta</p>
</div>
</button>
)}
{/* Sair */}
<button
onClick={() => {
logout();
setIsAccountDropdownOpen(false);
}}
className="w-full flex items-center gap-3 px-4 py-3 rounded-xl hover:bg-red-50 transition-colors text-left group border-t border-gray-200 mt-2 pt-4"
>
<div className="w-10 h-10 rounded-lg bg-red-100 flex items-center justify-center group-hover:bg-red-200 transition-colors">
<LogOut size={20} className="text-red-600" />
</div>
<div className="flex-1">
<p className="text-sm font-semibold text-red-600">Sair da Conta</p>
<p className="text-xs text-red-400">Desconectar do sistema</p>
</div>
</button>
</div>
</div>
)}
</div>
{/* Menu Hamburguer - Apenas para usuários logados */}
<button
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
className="text-brand-black hover:text-brand-gold p-2"
>
Cadastre-se agora
</Button>
{isMobileMenuOpen ? <X size={24} /> : <Menu size={24} />}
</button>
</>
) : (
<div className="relative">
<button
onClick={() => setIsAccountDropdownOpen(!isAccountDropdownOpen)}
className="w-10 h-10 rounded-full border-2 border-brand-gold flex items-center justify-center text-brand-gold shadow-md"
>
<User size={20} />
</button>
{/* Dropdown Popup Mobile */}
{isAccountDropdownOpen && (
<div className="absolute right-0 top-full mt-3 w-72 bg-white rounded-2xl shadow-2xl border border-gray-100 overflow-hidden z-50 fade-in">
{/* Header com ícone */}
<div className="bg-gradient-to-r from-[#492E61] to-[#5a3a7a] p-6 text-center">
<div className="w-16 h-16 mx-auto mb-3 rounded-full bg-white/20 backdrop-blur-sm flex items-center justify-center border-2 border-white/30">
<User size={32} className="text-white" />
</div>
<p className="text-white/70 text-xs mb-1">Olá, bem-vindo(a)</p>
<p className="text-white font-semibold text-base">Entrar/Cadastrar</p>
</div>
{/* Botões */}
<div className="p-5 space-y-3 bg-gray-50">
<Button
onClick={() => {
onNavigate("login");
setIsAccountDropdownOpen(false);
}}
variant="secondary"
className="w-full rounded-xl shadow-sm hover:shadow-md transition-shadow"
>
ENTRAR
</Button>
<Button
onClick={() => {
onNavigate("register");
setIsAccountDropdownOpen(false);
}}
variant="primary"
className="w-full rounded-xl shadow-sm hover:shadow-md transition-shadow"
>
Cadastre-se agora
</Button>
</div>
</div>
)}
</div>
)}
</div>
</div>
</div>
)}
</nav>
{/* Mobile Menu */}
{isMobileMenuOpen && (
<div className="md:hidden absolute top-full left-0 w-full bg-white border-b border-gray-100 shadow-lg fade-in">
<div className="px-4 py-4 space-y-3">
{user &&
getLinks().map((link) => (
<button
key={link.path}
onClick={() => {
onNavigate(link.path);
setIsMobileMenuOpen(false);
}}
className="block w-full text-left text-base font-medium text-gray-700 hover:text-brand-gold py-2 border-b border-gray-50"
>
{link.name}
</button>
))}
<div className="pt-4">
{user ? (
<div className="space-y-3">
{/* Info do usuário */}
<div className="flex items-center justify-between pb-3 border-b border-gray-100">
<div className="flex items-center">
<img
src={user.avatar}
className="w-10 h-10 rounded-full mr-3 border-2 border-gray-200"
alt={user.name}
/>
<div>
<span className="font-bold text-sm block text-gray-900">
{user.name}
</span>
<span className="text-xs text-brand-gold font-medium">
{getRoleLabel()}
</span>
</div>
</div>
</div>
{/* Botão Editar Perfil - Apenas para Fotógrafos e Clientes */}
{(user.role === UserRole.PHOTOGRAPHER || user.role === UserRole.EVENT_OWNER) && (
<button
onClick={() => {
setIsEditProfileModalOpen(true);
setIsMobileMenuOpen(false);
}}
className="w-full flex items-center gap-3 px-4 py-3 bg-[#492E61]/5 hover:bg-[#492E61]/10 rounded-xl transition-colors"
>
<div className="w-10 h-10 rounded-lg bg-[#492E61]/10 flex items-center justify-center">
<User size={20} className="text-[#492E61]" />
</div>
<div className="flex-1 text-left">
<p className="text-sm font-semibold text-gray-900">Editar Perfil</p>
<p className="text-xs text-gray-500">Atualize suas informações</p>
</div>
</button>
)}
{/* Botão Sair */}
<button
onClick={() => {
logout();
setIsMobileMenuOpen(false);
}}
className="w-full flex items-center gap-3 px-4 py-3 bg-red-50 hover:bg-red-100 rounded-xl transition-colors"
>
<div className="w-10 h-10 rounded-lg bg-red-100 flex items-center justify-center">
<LogOut size={20} className="text-red-600" />
</div>
<div className="flex-1 text-left">
<p className="text-sm font-semibold text-red-600">Sair da Conta</p>
<p className="text-xs text-red-400">Desconectar do sistema</p>
</div>
</button>
</div>
) : (
<div className="flex flex-col gap-2">
<Button
className="w-full rounded-lg"
size="lg"
variant="secondary"
onClick={() => {
onNavigate("login");
setIsMobileMenuOpen(false);
}}
>
ENTRAR
</Button>
<Button
className="w-full bg-purple-600 text-white hover:bg-purple-700 focus:ring-purple-500 rounded-lg"
size="lg"
onClick={() => {
onNavigate("register");
setIsMobileMenuOpen(false);
}}
>
Cadastre-se agora
</Button>
</div>
)}
</div>
</div>
</div>
)}
</nav>
{/* Modal de Edição de Perfil - Apenas para Fotógrafos e Clientes */}
{
isEditProfileModalOpen && (user?.role === UserRole.PHOTOGRAPHER || user?.role === UserRole.EVENT_OWNER) && (
<div
className="fixed inset-0 bg-black/50 backdrop-blur-sm flex items-center justify-center z-[100] p-4 fade-in"
onClick={() => setIsEditProfileModalOpen(false)}
>
<div
className="bg-white rounded-2xl shadow-2xl max-w-2xl w-full max-h-[90vh] overflow-y-auto"
onClick={(e) => e.stopPropagation()}
>
{/* Header */}
<div className="bg-gradient-to-r from-[#492E61] to-[#5a3a7a] p-6 sm:p-8 text-center relative">
<button
onClick={() => setIsEditProfileModalOpen(false)}
className="absolute top-4 right-4 text-white/80 hover:text-white transition-colors"
>
<X size={24} />
</button>
<div className="w-24 h-24 mx-auto mb-4 rounded-full bg-white/20 backdrop-blur-sm flex items-center justify-center border-4 border-white/30 overflow-hidden relative group">
<img
src={profileData.avatar}
alt="Avatar"
className="w-full h-full object-cover"
/>
<div className="absolute inset-0 bg-black/40 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center cursor-pointer">
<Camera size={28} className="text-white" />
</div>
</div>
<h2 className="text-2xl font-bold text-white mb-1">Editar Perfil</h2>
<p className="text-white/80 text-sm">Atualize suas informações pessoais</p>
</div>
{/* Form */}
<form
className="p-6 sm:p-8 space-y-6"
onSubmit={(e) => {
e.preventDefault();
// Aqui você pode adicionar a lógica para salvar os dados
alert("Perfil atualizado com sucesso!");
setIsEditProfileModalOpen(false);
}}
>
{/* Nome Completo */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Nome Completo
</label>
<div className="relative">
<User size={20} className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400" />
<input
type="text"
value={profileData.name}
onChange={(e) => setProfileData({ ...profileData, name: e.target.value })}
className="w-full pl-11 pr-4 py-3 border border-gray-300 rounded-xl focus:outline-none focus:ring-2 focus:ring-[#492E61] focus:border-transparent transition-all"
placeholder="Seu nome completo"
required
/>
</div>
</div>
{/* Email */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Email
</label>
<div className="relative">
<Mail size={20} className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400" />
<input
type="email"
value={profileData.email}
onChange={(e) => setProfileData({ ...profileData, email: e.target.value })}
className="w-full pl-11 pr-4 py-3 border border-gray-300 rounded-xl focus:outline-none focus:ring-2 focus:ring-[#492E61] focus:border-transparent transition-all"
placeholder="seu@email.com"
required
/>
</div>
</div>
{/* Telefone */}
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Telefone
</label>
<div className="relative">
<Phone size={20} className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400" />
<input
type="tel"
value={profileData.phone}
onChange={(e) => setProfileData({ ...profileData, phone: e.target.value })}
className="w-full pl-11 pr-4 py-3 border border-gray-300 rounded-xl focus:outline-none focus:ring-2 focus:ring-[#492E61] focus:border-transparent transition-all"
placeholder="(00) 00000-0000"
/>
</div>
</div>
{/* Botões */}
<div className="flex flex-col sm:flex-row gap-3 pt-4 border-t border-gray-200">
<button
type="button"
onClick={() => setIsEditProfileModalOpen(false)}
className="flex-1 px-6 py-3 border border-gray-300 text-gray-700 rounded-xl hover:bg-gray-50 transition-colors font-medium"
>
Cancelar
</button>
<button
type="submit"
className="flex-1 px-6 py-3 bg-[#492E61] text-white rounded-xl hover:bg-[#3a2450] transition-colors font-medium shadow-lg hover:shadow-xl"
>
Salvar Alterações
</button>
</div>
</form>
</div>
</div>
)
}
</>
);
};

View file

@ -229,6 +229,16 @@
padding: 15px !important;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15) !important;
}
/* Hide scrollbar for mobile tabs */
.scrollbar-hide {
-ms-overflow-style: none;
scrollbar-width: none;
}
.scrollbar-hide::-webkit-scrollbar {
display: none;
}
</style>
</head>

View file

@ -1,5 +1,5 @@
import React, { useState } from 'react';
import { Calendar, Clock, MapPin, User, ChevronLeft, ChevronRight } from 'lucide-react';
import { Calendar as CalendarIcon, Clock, MapPin, User, ChevronLeft, ChevronRight, Plus, Filter, Search } from 'lucide-react';
interface Event {
id: string;
@ -78,61 +78,32 @@ const MOCK_EVENTS: Event[] = [
export const CalendarPage: React.FC = () => {
const [selectedMonth, setSelectedMonth] = useState(new Date());
const [selectedEvent, setSelectedEvent] = useState<Event | null>(null);
const [selectedDate, setSelectedDate] = useState<Date | null>(null);
const [viewMode, setViewMode] = useState<'month' | 'week'>('month');
const getStatusColor = (status: Event['status']) => {
switch (status) {
case 'confirmed':
return 'bg-green-100 text-green-800';
case 'pending':
return 'bg-yellow-100 text-yellow-800';
case 'completed':
return 'bg-gray-100 text-gray-800';
case 'confirmed': return 'bg-green-100 text-green-700 border-green-200';
case 'pending': return 'bg-yellow-100 text-yellow-700 border-yellow-200';
case 'completed': return 'bg-gray-100 text-gray-700 border-gray-200';
}
};
const getStatusLabel = (status: Event['status']) => {
switch (status) {
case 'confirmed':
return 'Confirmado';
case 'pending':
return 'Pendente';
case 'completed':
return 'Concluído';
case 'confirmed': return 'Confirmado';
case 'pending': return 'Pendente';
case 'completed': return 'Concluído';
}
};
const getTypeColor = (type: Event['type']) => {
switch (type) {
case 'formatura':
return 'bg-blue-100 text-blue-800';
case 'casamento':
return 'bg-pink-100 text-pink-800';
case 'evento':
return 'bg-purple-100 text-purple-800';
case 'formatura': return 'bg-[#492E61] text-white';
case 'casamento': return 'bg-pink-500 text-white';
case 'evento': return 'bg-blue-500 text-white';
}
};
const getTypeLabel = (type: Event['type']) => {
switch (type) {
case 'formatura':
return 'Formatura';
case 'casamento':
return 'Casamento';
case 'evento':
return 'Evento';
}
};
const formatDate = (dateString: string) => {
const date = new Date(dateString + 'T00:00:00');
return date.toLocaleDateString('pt-BR', {
day: '2-digit',
month: 'long',
year: 'numeric'
});
};
const nextMonth = () => {
setSelectedMonth(new Date(selectedMonth.getFullYear(), selectedMonth.getMonth() + 1));
};
@ -141,110 +112,121 @@ export const CalendarPage: React.FC = () => {
setSelectedMonth(new Date(selectedMonth.getFullYear(), selectedMonth.getMonth() - 1));
};
const currentMonthName = selectedMonth.toLocaleDateString('pt-BR', {
month: 'long',
year: 'numeric'
});
// Generate calendar days
const generateCalendarDays = () => {
const year = selectedMonth.getFullYear();
const month = selectedMonth.getMonth();
const firstDay = new Date(year, month, 1);
const lastDay = new Date(year, month + 1, 0);
const firstDayOfWeek = firstDay.getDay();
const daysInMonth = lastDay.getDate();
const startingDayOfWeek = firstDay.getDay();
const days: (Date | null)[] = [];
// Add empty cells for days before month starts
for (let i = 0; i < firstDayOfWeek; i++) {
// Add empty cells for days before the first day of the month
for (let i = 0; i < startingDayOfWeek; i++) {
days.push(null);
}
// Add all days of the month
for (let day = 1; day <= daysInMonth; day++) {
days.push(new Date(year, month, day));
}
return days;
};
const getEventsForDate = (date: Date) => {
return MOCK_EVENTS.filter(event => {
const eventDate = new Date(event.date + 'T00:00:00');
return eventDate.getDate() === date.getDate() &&
eventDate.getMonth() === date.getMonth() &&
eventDate.getFullYear() === date.getFullYear();
return eventDate.toDateString() === date.toDateString();
});
};
const isToday = (date: Date) => {
const today = new Date();
return date.getDate() === today.getDate() &&
date.getMonth() === today.getMonth() &&
date.getFullYear() === today.getFullYear();
return date.toDateString() === today.toDateString();
};
const currentMonthName = selectedMonth.toLocaleDateString('pt-BR', { month: 'long', year: 'numeric' });
const calendarDays = generateCalendarDays();
// Filter events for selected month
const monthEvents = MOCK_EVENTS.filter(event => {
const eventDate = new Date(event.date + 'T00:00:00');
return eventDate.getMonth() === selectedMonth.getMonth() &&
eventDate.getFullYear() === selectedMonth.getFullYear();
});
// Sort events by date
const sortedEvents = [...MOCK_EVENTS].sort((a, b) =>
new Date(a.date).getTime() - new Date(b.date).getTime()
);
return (
<div className="min-h-screen bg-gray-50 pt-20 sm:pt-24 md:pt-32 pb-8 sm:pb-12">
<div className="min-h-screen bg-gradient-to-br from-gray-50 to-gray-100 pt-20 sm:pt-24 md:pt-32 pb-8 sm:pb-12">
<div className="max-w-7xl mx-auto px-3 sm:px-4 md:px-6 lg:px-8">
{/* Header */}
<div className="mb-6 sm:mb-8">
<h1 className="text-2xl sm:text-3xl font-serif font-bold text-brand-black mb-1 sm:mb-2">
Minha Agenda
</h1>
<p className="text-sm sm:text-base text-gray-600">
Gerencie seus eventos e compromissos fotográficos
</p>
<div className="mb-4 sm:mb-6 md:mb-8 flex flex-col gap-3 sm:gap-4">
<div>
<h1 className="text-2xl sm:text-3xl md:text-4xl font-bold text-[#B8D033] mb-1 sm:mb-2">
Minha Agenda
</h1>
<p className="text-xs sm:text-sm md:text-base text-gray-600">
Gerencie seus eventos e compromissos fotográficos
</p>
</div>
<div className="flex gap-2">
</div>
</div>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-4 sm:gap-6">
{/* Full Calendar Grid */}
<div className="lg:col-span-2">
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-3 sm:p-4">
<div className="flex items-center justify-between mb-3 sm:mb-4">
<button
onClick={prevMonth}
className="p-1 sm:p-1.5 hover:bg-gray-100 rounded-full transition-colors"
>
<ChevronLeft className="w-4 h-4 sm:w-5 sm:h-5" />
</button>
<h2 className="text-base sm:text-lg font-bold capitalize" style={{ color: '#B9CF33' }}>
{currentMonthName}
</h2>
<button
onClick={nextMonth}
className="p-1 sm:p-1.5 hover:bg-gray-100 rounded-full transition-colors"
>
<ChevronRight className="w-4 h-4 sm:w-5 sm:h-5" />
</button>
{/* Calendar Section */}
<div className="lg:col-span-2 space-y-4 sm:space-y-6">
{/* Calendar Card */}
<div className="bg-white rounded-2xl shadow-xl border border-gray-200 overflow-hidden">
{/* Calendar Header */}
<div className="bg-gradient-to-r from-[#492E61] to-[#5a3a7a] p-4 sm:p-6">
<div className="flex items-center justify-between mb-3 sm:mb-4">
<button
onClick={prevMonth}
className="p-1.5 sm:p-2 hover:bg-white/20 rounded-lg transition-colors"
>
<ChevronLeft className="w-5 h-5 sm:w-6 sm:h-6 text-white" />
</button>
<h2 className="text-lg sm:text-xl md:text-2xl font-bold text-white capitalize">
{currentMonthName}
</h2>
<button
onClick={nextMonth}
className="p-1.5 sm:p-2 hover:bg-white/20 rounded-lg transition-colors"
>
<ChevronRight className="w-5 h-5 sm:w-6 sm:h-6 text-white" />
</button>
</div>
{/* Stats */}
<div className="grid grid-cols-3 gap-2 sm:gap-4">
<div className="bg-white/10 backdrop-blur-sm rounded-lg p-2 sm:p-3 text-center">
<p className="text-white/80 text-[10px] sm:text-xs mb-0.5 sm:mb-1">Total</p>
<p className="text-xl sm:text-2xl font-bold text-white">{monthEvents.length}</p>
</div>
<div className="bg-white/10 backdrop-blur-sm rounded-lg p-2 sm:p-3 text-center">
<p className="text-white/80 text-[10px] sm:text-xs mb-0.5 sm:mb-1">Confirmados</p>
<p className="text-xl sm:text-2xl font-bold text-green-300">
{monthEvents.filter(e => e.status === 'confirmed').length}
</p>
</div>
<div className="bg-white/10 backdrop-blur-sm rounded-lg p-2 sm:p-3 text-center">
<p className="text-white/80 text-[10px] sm:text-xs mb-0.5 sm:mb-1">Pendentes</p>
<p className="text-xl sm:text-2xl font-bold text-yellow-300">
{monthEvents.filter(e => e.status === 'pending').length}
</p>
</div>
</div>
</div>
{/* Calendar Grid */}
<div className="mb-3 sm:mb-4">
<div className="p-3 sm:p-4 md:p-6">
{/* Week Days Header */}
<div className="grid grid-cols-7 gap-0.5 sm:gap-1 mb-1">
<div className="grid grid-cols-7 gap-1 sm:gap-2 mb-1 sm:mb-2">
{['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sáb'].map((day) => (
<div
key={day}
className="text-center text-[10px] sm:text-xs font-semibold text-gray-600 py-1"
className="text-center text-[10px] sm:text-xs md:text-sm font-bold text-gray-600 py-1 sm:py-2"
>
{day}
</div>
@ -252,332 +234,147 @@ export const CalendarPage: React.FC = () => {
</div>
{/* Calendar Days */}
<div className="grid grid-cols-7 gap-0.5 sm:gap-1">
{calendarDays.map((date, index) => {
if (!date) {
return (
<div
key={`empty-${index}`}
className="h-10 sm:h-12 bg-gray-50 rounded"
/>
);
<div className="grid grid-cols-7 gap-1 sm:gap-2">
{calendarDays.map((day, index) => {
if (!day) {
return <div key={`empty-${index}`} className="aspect-square" />;
}
const dayEvents = getEventsForDate(date);
const hasEvents = dayEvents.length > 0;
const today = isToday(date);
const dayEvents = getEventsForDate(day);
const today = isToday(day);
return (
<button
<div
key={index}
onClick={() => setSelectedDate(date)}
className={`
h-10 sm:h-12 rounded p-0.5 sm:p-1 transition-all duration-200
${today ? 'bg-[#B9CF33] text-white font-bold' : 'hover:bg-gray-100 active:bg-gray-200'}
${hasEvents && !today ? 'bg-blue-50 border border-[#B9CF33] sm:border-2' : 'bg-white border border-gray-200'}
relative group
`}
className={`aspect-square rounded-lg sm:rounded-xl border-2 p-1 sm:p-2 transition-all cursor-pointer hover:shadow-lg ${today
? 'border-[#492E61] bg-[#492E61]/5'
: dayEvents.length > 0
? 'border-[#B9CF32] bg-[#B9CF32]/5 hover:bg-[#B9CF32]/10'
: 'border-gray-200 hover:border-gray-300 hover:bg-gray-50'
}`}
>
<div className="flex flex-col items-center justify-center h-full">
<span className={`text-[10px] sm:text-xs ${today ? 'text-white' : 'text-gray-700'}`}>
{date.getDate()}
<div className="h-full flex flex-col">
<span
className={`text-xs sm:text-sm font-semibold mb-0.5 sm:mb-1 ${today
? 'text-[#492E61]'
: dayEvents.length > 0
? 'text-gray-900'
: 'text-gray-600'
}`}
>
{day.getDate()}
</span>
{hasEvents && (
<div className="flex gap-0.5 mt-0.5">
{dayEvents.slice(0, 3).map((event, i) => (
{dayEvents.length > 0 && (
<div className="flex-1 flex flex-col gap-0.5 sm:gap-1">
{dayEvents.slice(0, 1).map((event) => (
<div
key={i}
className={`w-0.5 h-0.5 sm:w-1 sm:h-1 rounded-full ${
event.status === 'confirmed' ? 'bg-green-500' :
event.status === 'pending' ? 'bg-yellow-500' :
'bg-gray-400'
}`}
/>
key={event.id}
className={`text-[6px] sm:text-[8px] px-0.5 sm:px-1 py-0.5 rounded ${getTypeColor(event.type)} truncate leading-tight`}
>
{event.title}
</div>
))}
{dayEvents.length > 1 && (
<span className="text-[6px] sm:text-[8px] text-gray-500 font-medium">
+{dayEvents.length - 1}
</span>
)}
</div>
)}
</div>
{/* Tooltip on hover - hide on mobile */}
{hasEvents && (
<div className="absolute bottom-full left-1/2 transform -translate-x-1/2 mb-2 hidden sm:group-hover:block z-10">
<div className="bg-gray-900 text-white text-xs rounded py-1 px-2 whitespace-nowrap">
{dayEvents.length} evento{dayEvents.length > 1 ? 's' : ''}
</div>
</div>
)}
</button>
</div>
);
})}
</div>
</div>
</div>
<div className="mt-3 sm:mt-4 pt-3 sm:pt-4 border-t border-gray-200">
<div className="grid grid-cols-2 gap-2 text-xs">
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between">
<span className="text-gray-600 text-[10px] sm:text-xs">Eventos este mês:</span>
<span className="font-bold text-sm sm:text-base" style={{ color: '#B9CF33' }}>{monthEvents.length}</span>
</div>
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between">
<span className="text-gray-600 text-[10px] sm:text-xs">Total:</span>
<span className="font-semibold text-sm sm:text-base">{MOCK_EVENTS.length}</span>
</div>
{/* Legend */}
<div className="bg-white rounded-2xl shadow-lg border border-gray-200 p-4 sm:p-6">
<h3 className="text-base sm:text-lg font-bold text-gray-900 mb-3 sm:mb-4">Legenda</h3>
<div className="grid grid-cols-2 sm:grid-cols-3 gap-3 sm:gap-4">
<div className="flex items-center gap-2">
<div className="w-3 h-3 sm:w-4 sm:h-4 rounded bg-green-500"></div>
<span className="text-xs sm:text-sm text-gray-700">Confirmado</span>
</div>
<div className="flex items-center gap-2">
<div className="w-3 h-3 sm:w-4 sm:h-4 rounded bg-yellow-500"></div>
<span className="text-xs sm:text-sm text-gray-700">Pendente</span>
</div>
<div className="flex items-center gap-2">
<div className="w-3 h-3 sm:w-4 sm:h-4 rounded bg-gray-400"></div>
<span className="text-xs sm:text-sm text-gray-700">Concluído</span>
</div>
<div className="flex items-center gap-2">
<div className="w-3 h-3 sm:w-4 sm:h-4 rounded bg-[#492E61]"></div>
<span className="text-xs sm:text-sm text-gray-700">Formatura</span>
</div>
<div className="flex items-center gap-2">
<div className="w-3 h-3 sm:w-4 sm:h-4 rounded bg-pink-500"></div>
<span className="text-xs sm:text-sm text-gray-700">Casamento</span>
</div>
<div className="flex items-center gap-2">
<div className="w-3 h-3 sm:w-4 sm:h-4 rounded bg-blue-500"></div>
<span className="text-xs sm:text-sm text-gray-700">Evento</span>
</div>
</div>
</div>
</div>
{/* Legend and Info Sidebar */}
<div className="lg:col-span-1">
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-3 sm:p-4 lg:sticky lg:top-24">
<h3 className="text-sm font-bold mb-2 sm:mb-3" style={{ color: '#492E61' }}>Legenda</h3>
<div className="grid grid-cols-2 sm:grid-cols-1 gap-2 mb-3 sm:mb-4">
<div className="flex items-center gap-2 text-xs">
<div className="w-3 h-3 rounded-full bg-green-500 flex-shrink-0"></div>
<span>Confirmado</span>
</div>
<div className="flex items-center gap-2 text-xs">
<div className="w-3 h-3 rounded-full bg-yellow-500 flex-shrink-0"></div>
<span>Pendente</span>
</div>
<div className="flex items-center gap-2 text-xs">
<div className="w-3 h-3 rounded-full bg-gray-500 flex-shrink-0"></div>
<span>Concluído</span>
</div>
<div className="flex items-center gap-2 text-xs">
<div className="w-3 h-3 rounded flex-shrink-0" style={{ backgroundColor: '#B9CF33' }}></div>
<span>Hoje</span>
</div>
<div className="flex items-center gap-2 text-xs col-span-2 sm:col-span-1">
<div className="w-3 h-3 rounded bg-blue-50 border-2 flex-shrink-0" style={{ borderColor: '#B9CF33' }}></div>
<span>Com eventos</span>
</div>
{/* Events List Sidebar */}
<div className="space-y-4 sm:space-y-6">
{/* Search */}
<div className="bg-white rounded-2xl shadow-lg border border-gray-200 p-3 sm:p-4">
<div className="relative">
<Search className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400" size={18} />
<input
type="text"
placeholder="Buscar eventos..."
className="w-full pl-9 sm:pl-10 pr-3 sm:pr-4 py-2 sm:py-3 border border-gray-300 rounded-xl focus:outline-none focus:ring-2 focus:ring-[#492E61] focus:border-transparent text-sm"
/>
</div>
</div>
{selectedDate && (
<div className="pt-3 sm:pt-4 border-t border-gray-200">
<h3 className="text-xs font-bold mb-2" style={{ color: '#492E61' }}>
{selectedDate.toLocaleDateString('pt-BR', {
day: '2-digit',
month: 'long',
year: 'numeric'
})}
</h3>
{getEventsForDate(selectedDate).length > 0 ? (
<div className="space-y-2">
{getEventsForDate(selectedDate).map(event => (
<div
key={event.id}
className="p-2 bg-gray-50 rounded cursor-pointer hover:bg-gray-100 active:bg-gray-200 transition-colors"
onClick={() => setSelectedEvent(event)}
>
<div className="font-medium text-xs text-gray-900 mb-1 line-clamp-1">
{event.title}
</div>
<div className="text-xs text-gray-600 flex items-center">
<Clock size={10} className="inline mr-1 flex-shrink-0" />
{event.time}
</div>
</div>
))}
{/* Upcoming Events */}
<div className="bg-white rounded-2xl shadow-lg border border-gray-200 p-4 sm:p-6">
<h3 className="text-base sm:text-lg font-bold text-gray-900 mb-3 sm:mb-4 flex items-center gap-2">
<CalendarIcon size={18} className="sm:w-5 sm:h-5 text-[#492E61]" />
Próximos Eventos
</h3>
<div className="space-y-2 sm:space-y-3 max-h-[400px] sm:max-h-[600px] overflow-y-auto">
{MOCK_EVENTS.slice(0, 5).map((event) => (
<div
key={event.id}
className="p-3 sm:p-4 border-l-4 rounded-lg bg-gray-50 hover:bg-gray-100 transition-colors cursor-pointer"
style={{ borderLeftColor: event.type === 'formatura' ? '#492E61' : event.type === 'casamento' ? '#ec4899' : '#3b82f6' }}
>
<div className="flex items-start justify-between mb-2 gap-2">
<h4 className="font-semibold text-gray-900 text-xs sm:text-sm flex-1">{event.title}</h4>
<span className={`text-[10px] sm:text-xs px-1.5 sm:px-2 py-0.5 sm:py-1 rounded-full border whitespace-nowrap ${getStatusColor(event.status)}`}>
{getStatusLabel(event.status)}
</span>
</div>
) : (
<p className="text-xs text-gray-500">Nenhum evento neste dia</p>
)}
</div>
)}
</div>
</div>
{/* Events List */}
<div className="lg:col-span-3 mt-4 sm:mt-6">
<div className="bg-white rounded-lg shadow-sm border border-gray-200">
<div className="p-4 sm:p-6 border-b border-gray-200">
<h2 className="text-lg sm:text-xl font-bold" style={{ color: '#492E61' }}>Próximos Eventos</h2>
</div>
<div className="divide-y divide-gray-200">
{sortedEvents.length === 0 ? (
<div className="p-8 sm:p-12 text-center text-gray-500">
<Calendar className="w-10 h-10 sm:w-12 sm:h-12 mx-auto mb-3 sm:mb-4 text-gray-300" />
<p className="text-sm sm:text-base">Nenhum evento agendado</p>
</div>
) : (
sortedEvents.map((event) => (
<div
key={event.id}
className="p-4 sm:p-6 hover:bg-gray-50 active:bg-gray-100 transition-colors cursor-pointer"
onClick={() => setSelectedEvent(event)}
>
<div className="flex items-start justify-between mb-2 sm:mb-3 gap-3 sm:gap-4">
<div className="flex-1 min-w-0">
<div className="flex items-start sm:items-center gap-2 mb-2 flex-col sm:flex-row">
<h3 className="text-base sm:text-lg font-semibold text-brand-black line-clamp-2">
{event.title}
</h3>
<span className={`px-2 py-1 rounded-full text-xs font-medium ${getTypeColor(event.type)} whitespace-nowrap`}>
{getTypeLabel(event.type)}
</span>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-1.5 sm:gap-2">
<div className="flex items-center text-xs sm:text-sm text-gray-600">
<Calendar className="w-3 h-3 sm:w-4 sm:h-4 mr-1.5 sm:mr-2 flex-shrink-0" style={{ color: '#B9CF33' }} />
<span className="truncate">{formatDate(event.date)}</span>
</div>
<div className="flex items-center text-xs sm:text-sm text-gray-600">
<Clock className="w-3 h-3 sm:w-4 sm:h-4 mr-1.5 sm:mr-2 flex-shrink-0" style={{ color: '#B9CF33' }} />
<span>{event.time}</span>
</div>
<div className="flex items-center text-xs sm:text-sm text-gray-600">
<MapPin className="w-3 h-3 sm:w-4 sm:h-4 mr-1.5 sm:mr-2 flex-shrink-0" style={{ color: '#B9CF33' }} />
<span className="truncate">{event.location}</span>
</div>
<div className="flex items-center text-xs sm:text-sm text-gray-600">
<User className="w-3 h-3 sm:w-4 sm:h-4 mr-1.5 sm:mr-2 flex-shrink-0" style={{ color: '#B9CF33' }} />
<span className="truncate">{event.client}</span>
</div>
</div>
</div>
<span className={`px-2 sm:px-3 py-1 rounded-full text-[10px] sm:text-xs font-medium whitespace-nowrap ${getStatusColor(event.status)} flex-shrink-0`}>
{getStatusLabel(event.status)}
</span>
<div className="space-y-1">
<div className="flex items-center gap-1.5 sm:gap-2 text-[10px] sm:text-xs text-gray-600">
<Clock size={12} className="sm:w-3.5 sm:h-3.5 flex-shrink-0" />
<span>{new Date(event.date).toLocaleDateString('pt-BR')} às {event.time}</span>
</div>
<div className="flex items-center gap-1.5 sm:gap-2 text-[10px] sm:text-xs text-gray-600">
<MapPin size={12} className="sm:w-3.5 sm:h-3.5 flex-shrink-0" />
<span className="truncate">{event.location}</span>
</div>
<div className="flex items-center gap-1.5 sm:gap-2 text-[10px] sm:text-xs text-gray-600">
<User size={12} className="sm:w-3.5 sm:h-3.5 flex-shrink-0" />
<span>{event.client}</span>
</div>
</div>
))
)}
</div>
))}
</div>
</div>
</div>
</div>
</div>
{/* Event Detail Modal - Improved & Centered */}
{selectedEvent && (
<div
className="fixed inset-0 bg-black/60 backdrop-blur-sm flex items-center justify-center z-50 p-4 animate-fadeIn"
onClick={() => setSelectedEvent(null)}
>
<div
className="bg-white rounded-2xl max-w-lg w-full shadow-2xl transform transition-all duration-300 animate-slideUp overflow-hidden"
onClick={(e) => e.stopPropagation()}
>
{/* Header with gradient */}
<div className="relative p-6 pb-8 bg-gradient-to-br from-[#B9CF33] to-[#a5bd2e]">
<button
onClick={() => setSelectedEvent(null)}
className="absolute top-4 right-4 w-8 h-8 flex items-center justify-center rounded-full bg-white/20 hover:bg-white/30 text-white transition-colors"
>
</button>
<div className="text-white">
<h2 className="text-xl sm:text-2xl font-bold mb-3 pr-8">
{selectedEvent.title}
</h2>
<div className="flex flex-wrap gap-2">
<span className="px-3 py-1 rounded-full text-xs font-medium bg-white/90 text-gray-800">
{getTypeLabel(selectedEvent.type)}
</span>
<span className={`px-3 py-1 rounded-full text-xs font-medium ${getStatusColor(selectedEvent.status)}`}>
{getStatusLabel(selectedEvent.status)}
</span>
</div>
</div>
</div>
{/* Content */}
<div className="p-6 space-y-4">
{/* Date */}
<div className="flex items-center gap-4 p-4 bg-gray-50 rounded-xl hover:bg-gray-100 transition-colors group">
<div className="w-12 h-12 rounded-xl bg-[#B9CF33]/10 flex items-center justify-center group-hover:scale-110 transition-transform">
<Calendar className="w-6 h-6" style={{ color: '#B9CF33' }} />
</div>
<div className="flex-1">
<p className="text-xs text-gray-500 mb-0.5">Data</p>
<p className="font-semibold text-gray-900">{formatDate(selectedEvent.date)}</p>
</div>
</div>
{/* Time */}
<div className="flex items-center gap-4 p-4 bg-gray-50 rounded-xl hover:bg-gray-100 transition-colors group">
<div className="w-12 h-12 rounded-xl bg-[#B9CF33]/10 flex items-center justify-center group-hover:scale-110 transition-transform">
<Clock className="w-6 h-6" style={{ color: '#B9CF33' }} />
</div>
<div className="flex-1">
<p className="text-xs text-gray-500 mb-0.5">Horário</p>
<p className="font-semibold text-gray-900">{selectedEvent.time}</p>
</div>
</div>
{/* Location */}
<div className="flex items-center gap-4 p-4 bg-gray-50 rounded-xl hover:bg-gray-100 transition-colors group">
<div className="w-12 h-12 rounded-xl bg-[#B9CF33]/10 flex items-center justify-center group-hover:scale-110 transition-transform">
<MapPin className="w-6 h-6" style={{ color: '#B9CF33' }} />
</div>
<div className="flex-1">
<p className="text-xs text-gray-500 mb-0.5">Local</p>
<p className="font-semibold text-gray-900">{selectedEvent.location}</p>
</div>
</div>
{/* Client */}
<div className="flex items-center gap-4 p-4 bg-gray-50 rounded-xl hover:bg-gray-100 transition-colors group">
<div className="w-12 h-12 rounded-xl bg-[#B9CF33]/10 flex items-center justify-center group-hover:scale-110 transition-transform">
<User className="w-6 h-6" style={{ color: '#B9CF33' }} />
</div>
<div className="flex-1">
<p className="text-xs text-gray-500 mb-0.5">Cliente</p>
<p className="font-semibold text-gray-900">{selectedEvent.client}</p>
</div>
</div>
</div>
{/* Actions */}
<div className="p-6 pt-4 bg-gray-50 flex flex-col sm:flex-row gap-3">
<button
onClick={() => setSelectedEvent(null)}
className="flex-1 px-6 py-3 bg-white border-2 border-gray-200 text-gray-700 rounded-xl hover:bg-gray-50 hover:border-gray-300 active:scale-95 transition-all font-medium"
>
Fechar
</button>
<button
className="flex-1 px-6 py-3 text-white rounded-xl transition-all font-medium shadow-lg hover:shadow-xl active:scale-95"
style={{ backgroundColor: '#B9CF33' }}
onMouseEnter={(e) => e.currentTarget.style.backgroundColor = '#a5bd2e'}
onMouseLeave={(e) => e.currentTarget.style.backgroundColor = '#B9CF33'}
>
Ver Detalhes
</button>
</div>
</div>
</div>
)}
<style>{`
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(20px) scale(0.95);
}
to {
opacity: 1;
transform: translateY(0) scale(1);
}
}
.animate-fadeIn {
animation: fadeIn 0.2s ease-out;
}
.animate-slideUp {
animation: slideUp 0.3s ease-out;
}
`}</style>
</div>
);
};

View file

@ -236,33 +236,31 @@ export const Dashboard: React.FC<DashboardProps> = ({
{(user.role === UserRole.BUSINESS_OWNER ||
user.role === UserRole.SUPERADMIN) && (
<div className="flex space-x-2 bg-white p-1 rounded border border-gray-200">
<button
onClick={() => setActiveFilter("all")}
className={`px-3 py-1 text-xs font-medium rounded-sm ${
activeFilter === "all"
<div className="flex space-x-2 bg-white p-1 rounded border border-gray-200">
<button
onClick={() => setActiveFilter("all")}
className={`px-3 py-1 text-xs font-medium rounded-sm ${activeFilter === "all"
? "bg-brand-black text-white"
: "text-gray-600 hover:bg-gray-100"
}`}
>
Todos
</button>
<button
onClick={() => setActiveFilter("pending")}
className={`px-3 py-1 text-xs font-medium rounded-sm flex items-center ${
activeFilter === "pending"
}`}
>
Todos
</button>
<button
onClick={() => setActiveFilter("pending")}
className={`px-3 py-1 text-xs font-medium rounded-sm flex items-center ${activeFilter === "pending"
? "bg-brand-gold text-white"
: "text-gray-600 hover:bg-gray-100"
}`}
>
<Clock size={12} className="mr-1" /> Pendentes
</button>
</div>
)}
}`}
>
<Clock size={12} className="mr-1" /> Pendentes
</button>
</div>
)}
</div>
{/* Grid */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-2 xl:grid-cols-3 gap-4 sm:gap-6 md:gap-8">
{filteredEvents.map((event) => (
<div key={event.id} className="relative group">
{renderAdminActions(event)}
@ -334,31 +332,33 @@ export const Dashboard: React.FC<DashboardProps> = ({
</div>
</div>
<div className="p-8">
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
<div className="col-span-2 space-y-8">
<div className="p-4 sm:p-6 md:p-8">
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6 md:gap-8">
<div className="lg:col-span-2 space-y-6 md:space-y-8">
{/* Actions Toolbar */}
<div className="flex flex-wrap gap-3 border-b pb-4">
<div className="flex flex-wrap gap-2 sm:gap-3 border-b pb-4">
{(user.role === UserRole.BUSINESS_OWNER ||
user.role === UserRole.SUPERADMIN) && (
<>
<Button
variant="outline"
onClick={() => setView("edit")}
>
<Edit size={16} className="mr-2" /> Editar Detalhes
</Button>
<Button variant="outline" onClick={handleManageTeam}>
<Users size={16} className="mr-2" /> Gerenciar
Equipe
</Button>
</>
)}
<>
<Button
variant="outline"
onClick={() => setView("edit")}
className="text-sm"
>
<Edit size={16} className="mr-2" /> Editar Detalhes
</Button>
<Button variant="outline" onClick={handleManageTeam} className="text-sm">
<Users size={16} className="mr-2" /> Gerenciar
Equipe
</Button>
</>
)}
{user.role === UserRole.EVENT_OWNER &&
selectedEvent.status !== EventStatus.ARCHIVED && (
<Button
variant="outline"
onClick={() => setView("edit")}
className="text-sm"
>
<Edit size={16} className="mr-2" /> Editar
Informações
@ -467,11 +467,10 @@ export const Dashboard: React.FC<DashboardProps> = ({
)}
</div>
<div className="col-span-1 space-y-6">
<div className="lg:col-span-1 space-y-4 sm:space-y-6">
<div
className={`p-6 rounded-sm border ${
STATUS_COLORS[selectedEvent.status]
} bg-opacity-10`}
className={`p-6 rounded-sm border ${STATUS_COLORS[selectedEvent.status]
} bg-opacity-10`}
>
<h4 className="font-bold uppercase tracking-widest text-xs mb-2 opacity-70">
Status Atual
@ -518,43 +517,43 @@ export const Dashboard: React.FC<DashboardProps> = ({
{(selectedEvent.photographerIds.length > 0 ||
user.role === UserRole.BUSINESS_OWNER) && (
<div className="border p-6 rounded-sm">
<div className="flex justify-between items-center mb-4">
<h4 className="font-bold uppercase tracking-widest text-xs text-gray-400">
Equipe Designada
</h4>
{(user.role === UserRole.BUSINESS_OWNER ||
user.role === UserRole.SUPERADMIN) && (
<button
onClick={handleManageTeam}
className="text-brand-gold hover:text-brand-black"
>
<PlusCircle size={16} />
</button>
<div className="border p-6 rounded-sm">
<div className="flex justify-between items-center mb-4">
<h4 className="font-bold uppercase tracking-widest text-xs text-gray-400">
Equipe Designada
</h4>
{(user.role === UserRole.BUSINESS_OWNER ||
user.role === UserRole.SUPERADMIN) && (
<button
onClick={handleManageTeam}
className="text-brand-gold hover:text-brand-black"
>
<PlusCircle size={16} />
</button>
)}
</div>
{selectedEvent.photographerIds.length > 0 ? (
<div className="flex -space-x-2">
{selectedEvent.photographerIds.map((id, idx) => (
<div
key={id}
className="w-10 h-10 rounded-full border-2 border-white bg-gray-300"
style={{
backgroundImage: `url(https://i.pravatar.cc/100?u=${id})`,
backgroundSize: "cover",
}}
title={id}
></div>
))}
</div>
) : (
<p className="text-sm text-gray-400 italic">
Nenhum profissional atribuído.
</p>
)}
</div>
{selectedEvent.photographerIds.length > 0 ? (
<div className="flex -space-x-2">
{selectedEvent.photographerIds.map((id, idx) => (
<div
key={id}
className="w-10 h-10 rounded-full border-2 border-white bg-gray-300"
style={{
backgroundImage: `url(https://i.pravatar.cc/100?u=${id})`,
backgroundSize: "cover",
}}
title={id}
></div>
))}
</div>
) : (
<p className="text-sm text-gray-400 italic">
Nenhum profissional atribuído.
</p>
)}
</div>
)}
)}
</div>
</div>
</div>

View file

@ -172,26 +172,26 @@ export const FinancePage: React.FC = () => {
};
return (
<div className="min-h-screen bg-gray-50 pt-32 pb-12">
<div className="min-h-screen bg-gray-50 pt-20 sm:pt-24 md:pt-28 lg:pt-32 pb-8 sm:pb-12">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
{/* Header */}
<div className="mb-8 flex items-center justify-between">
<div className="mb-6 sm:mb-8 flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
<div>
<h1 className="text-3xl font-serif font-bold text-brand-black mb-2">
<h1 className="text-2xl sm:text-3xl font-serif font-bold text-brand-black mb-2">
Financeiro
</h1>
<p className="text-gray-600">
<p className="text-sm sm:text-base text-gray-600">
Acompanhe receitas, despesas e fluxo de caixa
</p>
</div>
<button className="flex items-center gap-2 px-4 py-2 bg-brand-gold text-white rounded-md hover:bg-[#a5bd2e] transition-colors font-medium">
<Download size={20} />
Exportar Relatório
<button className="flex items-center justify-center gap-2 px-4 py-2 bg-brand-gold text-white rounded-md hover:bg-[#a5bd2e] transition-colors font-medium text-sm sm:text-base whitespace-nowrap">
<Download size={18} className="sm:w-5 sm:h-5" />
Exportar
</button>
</div>
{/* Stats Cards */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-3 sm:gap-4 md:gap-6 mb-6 sm:mb-8">
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
<div className="flex items-center justify-between mb-2">
<p className="text-sm text-gray-600">Receitas</p>
@ -232,14 +232,14 @@ export const FinancePage: React.FC = () => {
</div>
{/* Filters */}
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6 mb-6">
<div className="flex flex-col md:flex-row gap-4">
<div className="flex gap-2">
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-3 sm:p-4 md:p-6 mb-4 sm:mb-6">
<div className="flex flex-col gap-3 sm:gap-4">
<div className="flex flex-wrap gap-2">
<button
onClick={() => setFilterType('all')}
className={`px-4 py-2 rounded-md font-medium transition-colors ${filterType === 'all'
? 'bg-brand-gold text-white'
: 'bg-gray-100 text-gray-700 hover:bg-gray-200'
? 'bg-brand-gold text-white'
: 'bg-gray-100 text-gray-700 hover:bg-gray-200'
}`}
>
Todas
@ -247,8 +247,8 @@ export const FinancePage: React.FC = () => {
<button
onClick={() => setFilterType('income')}
className={`px-4 py-2 rounded-md font-medium transition-colors ${filterType === 'income'
? 'bg-green-600 text-white'
: 'bg-gray-100 text-gray-700 hover:bg-gray-200'
? 'bg-green-600 text-white'
: 'bg-gray-100 text-gray-700 hover:bg-gray-200'
}`}
>
Receitas
@ -256,19 +256,19 @@ export const FinancePage: React.FC = () => {
<button
onClick={() => setFilterType('expense')}
className={`px-4 py-2 rounded-md font-medium transition-colors ${filterType === 'expense'
? 'bg-red-600 text-white'
: 'bg-gray-100 text-gray-700 hover:bg-gray-200'
? 'bg-red-600 text-white'
: 'bg-gray-100 text-gray-700 hover:bg-gray-200'
}`}
>
Despesas
</button>
</div>
<div className="flex gap-2">
<div className="flex flex-wrap gap-2">
<button
onClick={() => setFilterStatus('all')}
className={`px-4 py-2 rounded-md font-medium transition-colors ${filterStatus === 'all'
? 'bg-brand-black text-white'
: 'bg-gray-100 text-gray-700 hover:bg-gray-200'
? 'bg-brand-black text-white'
: 'bg-gray-100 text-gray-700 hover:bg-gray-200'
}`}
>
Todos Status
@ -276,8 +276,8 @@ export const FinancePage: React.FC = () => {
<button
onClick={() => setFilterStatus('paid')}
className={`px-4 py-2 rounded-md font-medium transition-colors ${filterStatus === 'paid'
? 'bg-green-600 text-white'
: 'bg-gray-100 text-gray-700 hover:bg-gray-200'
? 'bg-green-600 text-white'
: 'bg-gray-100 text-gray-700 hover:bg-gray-200'
}`}
>
Pagos
@ -285,8 +285,8 @@ export const FinancePage: React.FC = () => {
<button
onClick={() => setFilterStatus('pending')}
className={`px-4 py-2 rounded-md font-medium transition-colors ${filterStatus === 'pending'
? 'bg-yellow-600 text-white'
: 'bg-gray-100 text-gray-700 hover:bg-gray-200'
? 'bg-yellow-600 text-white'
: 'bg-gray-100 text-gray-700 hover:bg-gray-200'
}`}
>
Pendentes

View file

@ -98,11 +98,11 @@ export const Home: React.FC<HomeProps> = ({ onEnter }) => {
<div className={`inline-flex items-center justify-center w-24 h-24 sm:w-32 sm:h-32 md:w-36 md:h-36 mb-6 sm:mb-8 transform transition-all duration-700 ease-out ${albumsVisible ? 'opacity-100 scale-100 rotate-0' : 'opacity-0 scale-75 -rotate-12'} hover:scale-110 hover:rotate-3`}>
<img src="/HOME_17.png" alt="Álbuns" className="w-full h-full object-contain drop-shadow-2xl" />
</div>
<h2 className={`text-3xl sm:text-4xl md:text-5xl lg:text-6xl font-bold mb-4 sm:mb-6 md:mb-8 leading-tight transition-all duration-700 ease-out delay-100 ${albumsVisible ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-10'}`} style={{color: '#B9CF33'}}>
ÁLBUNS<br/>PERSONALIZADOS
<h2 className={`text-3xl sm:text-4xl md:text-5xl lg:text-6xl font-bold mb-4 sm:mb-6 md:mb-8 leading-tight transition-all duration-700 ease-out delay-100 ${albumsVisible ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-10'}`} style={{ color: '#B9CF33' }}>
ÁLBUNS<br />PERSONALIZADOS
</h2>
<div className={`space-y-2 sm:space-y-3 text-gray-700 transition-all duration-700 ease-out delay-200 ${albumsVisible ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-10'}`}>
<p className="text-sm sm:text-base md:text-lg leading-relaxed">
Escolha a cor, tamanho, tecido, acabamento, modelo,
@ -117,7 +117,7 @@ export const Home: React.FC<HomeProps> = ({ onEnter }) => {
</div>
{/* Right side - CTA */}
<div ref={ctaRef} className={`w-full lg:w-2/8 flex flex-col items-center lg:items-start justify-center lg:ml-40 mt-8 lg:mt-0 transition-all duration-700 ease-out delay-300 ${ctaVisible ? 'opacity-100 translate-x-0 scale-100' : 'opacity-0 translate-x-20 scale-90'}`}>
<div ref={ctaRef} className={`w-full lg:w-1/2 flex flex-col items-center justify-center mt-8 lg:mt-0 transition-all duration-700 ease-out delay-300 ${ctaVisible ? 'opacity-100 translate-x-0 scale-100' : 'opacity-0 translate-x-20 scale-90'}`}>
<div className="bg-white rounded-lg shadow-2xl p-6 sm:p-8 md:p-10 border-t-4 transform transition-all duration-300 hover:shadow-xl hover:-translate-y-2 w-full max-w-sm" style={{ borderColor: '#B9CF33' }}>
<div className={`flex justify-center mb-4 sm:mb-6 transition-all duration-700 ease-out delay-400 ${ctaVisible ? 'opacity-100 scale-100' : 'opacity-0 scale-80'}`}>
<div className="w-38 h-38 sm:w-38 sm:h-38 md:w-50 md:h-50 transform transition-transform duration-300 hover:scale-110">
@ -138,7 +138,7 @@ export const Home: React.FC<HomeProps> = ({ onEnter }) => {
</div>
</div>
</div>
{/* Decorative elements */}
<div className="hidden sm:block absolute top-10 right-10 w-32 h-32 rounded-full opacity-10" style={{ backgroundColor: '#B9CF33' }}></div>
<div className="hidden sm:block absolute bottom-10 left-10 w-24 h-24 rounded-full opacity-10" style={{ backgroundColor: '#C2388B' }}></div>
@ -149,30 +149,30 @@ export const Home: React.FC<HomeProps> = ({ onEnter }) => {
{/* Decorative gradient circles */}
<div className="hidden md:block absolute -top-24 -right-24 w-96 h-96 rounded-full opacity-10 blur-3xl" style={{ backgroundColor: '#B9CF33' }}></div>
<div className="hidden md:block absolute -bottom-24 -left-24 w-96 h-96 rounded-full opacity-10 blur-3xl" style={{ backgroundColor: '#C2388B' }}></div>
<div className="max-w-7xl mx-auto px-4 sm:px-6 md:px-8 lg:px-12 xl:px-20 relative z-10">
<div className={`text-center mb-8 sm:mb-10 md:mb-12 transition-all duration-700 ${contactVisible ? 'opacity-100 translate-y-0' : 'opacity-0 -translate-y-10'}`}>
<h2 className="text-2xl sm:text-3xl md:text-4xl font-bold text-[#B9CF32] mb-2 sm:mb-3 tracking-wide">ENTRE EM CONTATO</h2>
<p className="text-sm sm:text-base text-white/90">Envie sua mensagem, ligue ou faça uma visita em nossa empresa!</p>
</div>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-4 sm:gap-6 items-start max-w-7xl mx-auto">
<div className="grid grid-cols-1 lg:grid-cols-3 gap-4 sm:gap-6 items-end max-w-7xl mx-auto">
{/* Left side - Location Info */}
<div className={`space-y-2.5 sm:space-y-3 text-white transition-all duration-700 delay-200 ${contactVisible ? 'opacity-100 translate-x-0' : 'opacity-0 -translate-x-20'}`}>
<div className="group">
<div className="flex items-start gap-2 p-2 sm:p-2.5 rounded-lg transition-all duration-300 hover:bg-white/10 hover:shadow-lg cursor-pointer border border-white/5 hover:border-white/20">
<div className="flex-shrink-0 w-8 h-8 rounded-full bg-white/20 flex items-center justify-center transition-transform duration-300 group-hover:scale-110">
<svg className="w-5 h-5 text-white" fill="currentColor" viewBox="0 0 24 24">
<path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"/>
<path d="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z" />
</svg>
</div>
<div className="flex-1 min-w-0">
<p className="font-bold mb-0.5 text-sm">Rua Bom Recreio, 305</p>
<p className="text-white/80 text-xs">Jd. Boer II Americana SP</p>
<p className="text-white/80 text-xs mb-1">CEP 13477-720</p>
<a
href="https://www.google.com/maps/place/Photum+Formaturas/@-22.7442887,-47.290221,21z/data=!4m12!1m5!3m4!2zMjLCsDQ0JzM5LjMiUyA0N8KwMTcnMjQuOCJX!8m2!3d-22.744247!4d-47.290221!3m5!1s0x94c89755cd9e70a9:0x15496eb4ec405483!8m2!3d-22.7442757!4d-47.2902662!16s%2Fg%2F11g6my_mm1?hl=pt&entry=ttu&g_ep=EgoyMDI1MTEyMy4xIKXMDSoASAFQAw%3D%3D"
target="_blank"
<a
href="https://www.google.com/maps/place/Photum+Formaturas/@-22.7442887,-47.290221,21z/data=!4m12!1m5!3m4!2zMjLCsDQ0JzM5LjMiUyA0N8KwMTcnMjQuOCJX!8m2!3d-22.744247!4d-47.290221!3m5!1s0x94c89755cd9e70a9:0x15496eb4ec405483!8m2!3d-22.7442757!4d-47.2902662!16s%2Fg%2F11g6my_mm1?hl=pt&entry=ttu&g_ep=EgoyMDI1MTEyMy4xIKXMDSoASAFQAw%3D%3D"
target="_blank"
rel="noopener noreferrer"
className="text-xs underline hover:text-white transition-colors inline-flex items-center gap-1 font-medium"
>
@ -184,7 +184,7 @@ export const Home: React.FC<HomeProps> = ({ onEnter }) => {
{/* Mini Map */}
<div className="rounded-lg overflow-hidden shadow-lg border border-white/10 h-32 sm:h-36">
<iframe
<iframe
src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d235.28736842715582!2d-47.29022099999999!3d-22.7442887!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x94c89755cd9e70a9%3A0x15496eb4ec405483!2sPhotum%20Formaturas!5e0!3m2!1spt-BR!2sbr!4v1701234567890!5m2!1spt-BR!2sbr"
width="100%"
height="100%"
@ -199,7 +199,7 @@ export const Home: React.FC<HomeProps> = ({ onEnter }) => {
<div className="flex items-center gap-2 p-2 sm:p-2.5 rounded-lg transition-all duration-300 hover:bg-white/10 hover:shadow-lg cursor-pointer border border-white/5 hover:border-white/20">
<div className="flex-shrink-0 w-8 h-8 rounded-full bg-white/20 flex items-center justify-center transition-transform duration-300 group-hover:scale-110">
<svg className="w-5 h-5 text-white" fill="currentColor" viewBox="0 0 24 24">
<path d="M20 15.5c-1.25 0-2.45-.2-3.57-.57-.35-.11-.74-.03-1.02.24l-2.2 2.2c-2.83-1.44-5.15-3.75-6.59-6.59l2.2-2.21c.28-.26.36-.65.25-1C8.7 6.45 8.5 5.25 8.5 4c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1 0 9.39 7.61 17 17 17 .55 0 1-.45 1-1v-3.5c0-.55-.45-1-1-1zM19 12h2c0-4.97-4.03-9-9-9v2c3.87 0 7 3.13 7 7zm-4 0h2c0-2.76-2.24-5-5-5v2c1.66 0 3 1.34 3 3z"/>
<path d="M20 15.5c-1.25 0-2.45-.2-3.57-.57-.35-.11-.74-.03-1.02.24l-2.2 2.2c-2.83-1.44-5.15-3.75-6.59-6.59l2.2-2.21c.28-.26.36-.65.25-1C8.7 6.45 8.5 5.25 8.5 4c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1 0 9.39 7.61 17 17 17 .55 0 1-.45 1-1v-3.5c0-.55-.45-1-1-1zM19 12h2c0-4.97-4.03-9-9-9v2c3.87 0 7 3.13 7 7zm-4 0h2c0-2.76-2.24-5-5-5v2c1.66 0 3 1.34 3 3z" />
</svg>
</div>
<div className="flex-1">
@ -213,7 +213,7 @@ export const Home: React.FC<HomeProps> = ({ onEnter }) => {
<div className="flex items-center gap-2 p-2 sm:p-2.5 rounded-lg transition-all duration-300 hover:bg-white/10 hover:shadow-lg cursor-pointer border border-white/5 hover:border-white/20">
<div className="flex-shrink-0 w-8 h-8 rounded-full bg-white/20 flex items-center justify-center transition-transform duration-300 group-hover:scale-110">
<svg className="w-5 h-5 text-white" fill="currentColor" viewBox="0 0 24 24">
<path d="M20 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z"/>
<path d="M20 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 4l-8 5-8-5V6l8 5 8-5v2z" />
</svg>
</div>
<div className="flex-1 min-w-0">
@ -226,26 +226,26 @@ export const Home: React.FC<HomeProps> = ({ onEnter }) => {
</div>
{/* Center - Contact Form */}
<div className={`space-y-2.5 bg-gradient-to-br from-white/10 to-white/5 p-4 sm:p-5 rounded-xl backdrop-blur-md border border-white/10 shadow-2xl transition-all duration-700 delay-250 ${contactVisible ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-10'}`}>
<div className={`space-y-2.5 bg-gradient-to-br from-white/10 to-white/5 p-6 sm:p-8 rounded-2xl backdrop-blur-md border border-white/10 shadow-2xl transition-all duration-700 delay-250 ${contactVisible ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-10'}`}>
<input
type="text"
placeholder="Nome"
className="w-full px-3 py-2 text-sm bg-white/5 border-b-2 border-white/20 text-white placeholder-white/50 focus:border-white focus:bg-white/10 focus:outline-none transition-all duration-300 rounded-t-lg"
className="w-full px-5 py-2 text-sm bg-white/5 border-b-2 border-white/20 text-white placeholder-white/50 focus:border-white focus:bg-white/10 focus:outline-none transition-all duration-300 rounded-t-lg"
/>
<input
type="email"
placeholder="E-mail"
className="w-full px-3 py-2 text-sm bg-white/5 border-b-2 border-white/20 text-white placeholder-white/50 focus:border-white focus:bg-white/10 focus:outline-none transition-all duration-300 rounded-t-lg"
className="w-full px-5 py-2 text-sm bg-white/5 border-b-2 border-white/20 text-white placeholder-white/50 focus:border-white focus:bg-white/10 focus:outline-none transition-all duration-300 rounded-t-lg"
/>
<input
type="tel"
placeholder="Telefone"
className="w-full px-3 py-2 text-sm bg-white/5 border-b-2 border-white/20 text-white placeholder-white/50 focus:border-white focus:bg-white/10 focus:outline-none transition-all duration-300 rounded-t-lg"
className="w-full px-5 py-2 text-sm bg-white/5 border-b-2 border-white/20 text-white placeholder-white/50 focus:border-white focus:bg-white/10 focus:outline-none transition-all duration-300 rounded-t-lg"
/>
<textarea
placeholder="Mensagem"
rows={3}
className="w-full px-3 py-2 text-sm bg-white/5 border-b-2 border-white/20 text-white placeholder-white/50 focus:border-white focus:bg-white/10 focus:outline-none transition-all duration-300 resize-none rounded-t-lg"
className="w-full px-5 py-2 text-sm bg-white/5 border-b-2 border-white/20 text-white placeholder-white/50 focus:border-white focus:bg-white/10 focus:outline-none transition-all duration-300 resize-none rounded-t-lg"
></textarea>
<button
className="w-full px-6 py-2.5 text-sm text-white font-bold rounded-lg hover:opacity-90 transition-all duration-300 transform hover:scale-105 hover:shadow-xl active:scale-95 relative overflow-hidden group flex items-center justify-center gap-2"
@ -261,19 +261,19 @@ export const Home: React.FC<HomeProps> = ({ onEnter }) => {
{/* Right side - WhatsApp Card */}
<div className={`transition-all duration-700 delay-300 ${contactVisible ? 'opacity-100 translate-x-0' : 'opacity-0 translate-x-20'}`}>
<div className="bg-gradient-to-br from-[#25D366]/20 to-[#128C7E]/20 p-5 sm:p-6 rounded-xl backdrop-blur-md border border-[#25D366]/30 shadow-2xl hover:shadow-[#25D366]/20 hover:-translate-y-1 transition-all duration-300">
<div className="flex flex-col items-center text-center space-y-3">
<div className="bg-gradient-to-br from-white/10 to-white/5 p-6 sm:p-8 rounded-2xl backdrop-blur-md border border-white/10 shadow-2xl hover:shadow-[#25D366]/20 hover:-translate-y-1 transition-all duration-300">
<div className="flex flex-col items-center text-center space-y-4">
{/* WhatsApp Icon */}
<div className="w-16 h-16 sm:w-20 sm:h-20 rounded-full bg-[#25D366] flex items-center justify-center shadow-lg transform hover:scale-110 transition-transform duration-300">
<svg className="w-10 h-10 sm:w-12 sm:h-12 text-white" fill="currentColor" viewBox="0 0 24 24">
<path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z"/>
<div className="w-20 h-20 sm:w-24 sm:h-24 rounded-full bg-[#25D366] flex items-center justify-center shadow-lg transform hover:scale-110 transition-transform duration-300">
<svg className="w-12 h-12 sm:w-14 sm:h-14 text-white" fill="currentColor" viewBox="0 0 24 24">
<path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z" />
</svg>
</div>
{/* Text */}
<div className="space-y-1">
<h3 className="text-lg sm:text-xl font-bold text-white">Tire suas dúvidas</h3>
<p className="text-xs sm:text-sm text-white/90 leading-snug">
<div className="space-y-2">
<h3 className="text-xl sm:text-2xl font-bold text-white">Tire suas dúvidas</h3>
<p className="text-sm sm:text-base text-white/80 leading-relaxed">
Faça orçamento direto no nosso WhatsApp
</p>
</div>
@ -283,18 +283,18 @@ export const Home: React.FC<HomeProps> = ({ onEnter }) => {
href="https://wa.me/5519999999999"
target="_blank"
rel="noopener noreferrer"
className="w-full bg-[#25D366] hover:bg-[#128C7E] text-white font-bold py-2.5 px-4 rounded-lg transition-all duration-300 transform hover:scale-105 hover:shadow-xl active:scale-95 flex items-center justify-center gap-2 group text-sm"
className="w-full bg-[#25D366] hover:bg-[#128C7E] text-white font-bold py-3.5 px-6 rounded-xl transition-all duration-300 transform hover:scale-105 hover:shadow-xl active:scale-95 flex items-center justify-center gap-2 group text-base shadow-lg"
>
<svg className="w-5 h-5 transform group-hover:rotate-12 transition-transform duration-300" fill="currentColor" viewBox="0 0 24 24">
<path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z"/>
<svg className="w-6 h-6 transform group-hover:rotate-12 transition-transform duration-300" fill="currentColor" viewBox="0 0 24 24">
<path d="M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z" />
</svg>
<span>Falar no WhatsApp</span>
</a>
{/* Additional Info */}
<div className="flex items-center gap-1.5 text-xs text-white/80">
<div className="flex items-center gap-2 text-sm text-white/70 bg-white/5 px-4 py-2 rounded-full">
<div className="w-2 h-2 bg-[#25D366] rounded-full animate-pulse"></div>
<span>Resposta rápida garantida</span>
<span className="font-medium">Resposta rápida garantida</span>
</div>
</div>
</div>

View file

@ -19,7 +19,7 @@ export const Login: React.FC<LoginProps> = ({ onNavigate }) => {
e.preventDefault();
setIsLoading(true);
setError('');
const success = await login(email);
if (!success) {
setError('Usuário não encontrado. Tente um dos e-mails de demonstração.');
@ -32,37 +32,46 @@ export const Login: React.FC<LoginProps> = ({ onNavigate }) => {
};
const getRoleLabel = (role: UserRole) => {
switch(role) {
case UserRole.SUPERADMIN: return "Superadmin";
case UserRole.BUSINESS_OWNER: return "Empresa";
case UserRole.PHOTOGRAPHER: return "Fotógrafo";
case UserRole.EVENT_OWNER: return "Cliente";
default: return role;
}
switch (role) {
case UserRole.SUPERADMIN: return "Superadmin";
case UserRole.BUSINESS_OWNER: return "Empresa";
case UserRole.PHOTOGRAPHER: return "Fotógrafo";
case UserRole.EVENT_OWNER: return "Cliente";
default: return role;
}
}
return (
<div className="min-h-screen flex flex-col lg:flex-row bg-white">
{/* Left Side - Image */}
<div className="hidden lg:flex lg:w-1/2 relative overflow-hidden">
<img
src="https://plus.unsplash.com/premium_photo-1713296255442-e9338f42aad8?q=80&w=722&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="Photum Login"
<img
src="https://plus.unsplash.com/premium_photo-1713296255442-e9338f42aad8?q=80&w=722&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D"
alt="Photum Login"
className="absolute inset-0 w-full h-full object-cover"
/>
<div className="absolute inset-0 bg-gradient-to-br from-[#492E61]/90 to-[#492E61]/70 flex items-center justify-center">
<div className="text-center text-white p-12">
<h1 className="text-5xl font-serif font-bold mb-4">Photum Formaturas</h1>
<p className="text-xl font-light tracking-wide max-w-md mx-auto">Gestão de eventos premium para quem não abre mão da excelência.</p>
</div>
<div className="text-center text-white p-12">
<h1 className="text-5xl font-serif font-bold mb-4">Photum Formaturas</h1>
<p className="text-xl font-light tracking-wide max-w-md mx-auto">Gestão de eventos premium para quem não abre mão da excelência.</p>
</div>
</div>
</div>
{/* Right Side - Form */}
<div className="w-full lg:w-1/2 flex items-center justify-center p-4 sm:p-6 md:p-8 lg:p-16">
<div className="max-w-md w-full space-y-6 sm:space-y-8 fade-in">
{/* Logo Mobile */}
<div className="lg:hidden flex justify-center mb-6">
<img
src="/logo.png"
alt="Photum Formaturas"
className="h-16 w-auto object-contain"
/>
</div>
<div className="text-center lg:text-left">
<span className="font-bold tracking-widest uppercase text-xs sm:text-sm" style={{color: '#B9CF33'}}>Bem-vindo de volta</span>
<span className="font-bold tracking-widest uppercase text-xs sm:text-sm" style={{ color: '#B9CF33' }}>Bem-vindo de volta</span>
<h2 className="mt-2 text-2xl sm:text-3xl font-serif font-bold text-gray-900">Acesse sua conta</h2>
<p className="mt-2 text-xs sm:text-sm text-gray-600">
Não tem uma conta?{' '}
@ -70,7 +79,7 @@ export const Login: React.FC<LoginProps> = ({ onNavigate }) => {
type="button"
onClick={() => onNavigate?.('register')}
className="font-medium hover:opacity-80 transition-opacity"
style={{color: '#B9CF33'}}
style={{ color: '#B9CF33' }}
>
Cadastre-se
</button>
@ -90,7 +99,7 @@ export const Login: React.FC<LoginProps> = ({ onNavigate }) => {
value={email}
onChange={(e) => setEmail(e.target.value)}
className="w-full px-3 sm:px-4 py-2.5 sm:py-3 text-sm sm:text-base border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:border-transparent transition-all"
style={{focusRing: '2px solid #B9CF33'}}
style={{ focusRing: '2px solid #B9CF33' }}
onFocus={(e) => e.target.style.borderColor = '#B9CF33'}
onBlur={(e) => e.target.style.borderColor = '#d1d5db'}
/>
@ -121,22 +130,22 @@ export const Login: React.FC<LoginProps> = ({ onNavigate }) => {
type="submit"
disabled={isLoading}
className="w-full px-6 sm:px-10 py-3 sm:py-4 text-white font-bold text-base sm:text-lg rounded-lg transition-all duration-300 transform hover:scale-[1.02] hover:shadow-xl active:scale-95 disabled:opacity-50 disabled:cursor-not-allowed"
style={{backgroundColor: '#4E345F'}}
style={{ backgroundColor: '#4E345F' }}
>
{isLoading ? 'Entrando...' : 'Entrar no Sistema'}
</button>
</form>
{/* Demo Users Quick Select */}
{/* Demo Users Quick Select - Melhorado para Mobile */}
<div className="mt-6 sm:mt-10 pt-6 sm:pt-10 border-t border-gray-200">
<p className="text-[10px] sm:text-xs uppercase tracking-widest mb-3 sm:mb-4 text-center text-gray-400">Usuários de Demonstração (Clique para preencher)</p>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-2 sm:gap-3">
<div className="space-y-2">
{availableUsers.map(user => (
<button
key={user.id}
onClick={() => fillCredentials(user.email)}
className="flex flex-col items-start p-3 sm:p-4 border-2 rounded-lg hover:bg-gray-50 transition-all duration-300 text-left group transform hover:scale-[1.02]"
style={{borderColor: '#e5e7eb'}}
className="w-full flex items-center justify-between p-3 sm:p-4 border-2 rounded-xl hover:bg-gray-50 transition-all duration-300 text-left group transform hover:scale-[1.01] active:scale-[0.99]"
style={{ borderColor: '#e5e7eb' }}
onMouseEnter={(e) => {
e.currentTarget.style.borderColor = '#B9CF33';
e.currentTarget.style.boxShadow = '0 4px 12px rgba(185, 207, 51, 0.15)';
@ -146,9 +155,16 @@ export const Login: React.FC<LoginProps> = ({ onNavigate }) => {
e.currentTarget.style.boxShadow = 'none';
}}
>
<span className="text-xs sm:text-sm font-bold text-gray-900">{user.name}</span>
<span className="text-[10px] sm:text-xs uppercase tracking-wide mt-0.5 sm:mt-1 font-semibold" style={{color: '#B9CF33'}}>{getRoleLabel(user.role)}</span>
<span className="text-[10px] sm:text-xs text-gray-500 mt-0.5 sm:mt-1 truncate w-full">{user.email}</span>
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2 mb-1">
<span className="text-sm sm:text-base font-bold text-gray-900 truncate">{user.name}</span>
<span className="text-[10px] sm:text-xs uppercase tracking-wide font-semibold px-2 py-0.5 rounded-full whitespace-nowrap" style={{ backgroundColor: '#B9CF33', color: '#fff' }}>{getRoleLabel(user.role)}</span>
</div>
<span className="text-xs sm:text-sm text-gray-500 truncate block">{user.email}</span>
</div>
<svg className="w-5 h-5 text-gray-400 group-hover:text-[#B9CF33] transition-colors flex-shrink-0 ml-2" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
</svg>
</button>
))}
</div>

View file

@ -81,7 +81,7 @@ export const Register: React.FC<RegisterProps> = ({ onNavigate }) => {
};
addInstitution(newInstitution);
setShowInstitutionForm(false);
// Complete registration
setIsLoading(true);
setTimeout(() => {
@ -149,15 +149,24 @@ export const Register: React.FC<RegisterProps> = ({ onNavigate }) => {
{/* Right Side - Form */}
<div className="w-full lg:w-1/2 flex items-center justify-center p-4 sm:p-6 md:p-8 lg:p-16">
<div className="max-w-md w-full space-y-6 sm:space-y-8 fade-in">
{/* Logo Mobile */}
<div className="lg:hidden flex justify-center mb-6">
<img
src="/logo.png"
alt="Photum Formaturas"
className="h-16 w-auto object-contain"
/>
</div>
<div className="text-center lg:text-left">
<span className="font-bold tracking-widest uppercase text-xs sm:text-sm" style={{color: '#B9CF33'}}>Comece agora</span>
<span className="font-bold tracking-widest uppercase text-xs sm:text-sm" style={{ color: '#B9CF33' }}>Comece agora</span>
<h2 className="mt-2 text-2xl sm:text-3xl font-serif font-bold text-gray-900">Crie sua conta</h2>
<p className="mt-2 text-xs sm:text-sm text-gray-600">
tem uma conta?{' '}
<button
onClick={() => onNavigate('login')}
className="font-medium hover:opacity-80 transition-opacity"
style={{color: '#B9CF33'}}
style={{ color: '#B9CF33' }}
>
Faça login
</button>
@ -221,7 +230,7 @@ export const Register: React.FC<RegisterProps> = ({ onNavigate }) => {
checked={agreedToTerms}
onChange={(e) => setAgreedToTerms(e.target.checked)}
className="mt-0.5 sm:mt-1 h-4 w-4 flex-shrink-0 border-gray-300 rounded focus:ring-2"
style={{accentColor: '#B9CF33'}}
style={{ accentColor: '#B9CF33' }}
/>
<label className="ml-2 text-xs sm:text-sm text-gray-600">
Concordo com os{' '}
@ -229,7 +238,7 @@ export const Register: React.FC<RegisterProps> = ({ onNavigate }) => {
type="button"
onClick={() => onNavigate('terms')}
className="hover:opacity-80 transition-opacity underline"
style={{color: '#B9CF33'}}
style={{ color: '#B9CF33' }}
>
termos de uso
</button>{' '}
@ -238,7 +247,7 @@ export const Register: React.FC<RegisterProps> = ({ onNavigate }) => {
type="button"
onClick={() => onNavigate('privacy')}
className="hover:opacity-80 transition-opacity underline"
style={{color: '#B9CF33'}}
style={{ color: '#B9CF33' }}
>
política de privacidade
</button>
@ -255,7 +264,7 @@ export const Register: React.FC<RegisterProps> = ({ onNavigate }) => {
checked={formData.wantsToAddInstitution}
onChange={(e) => setFormData(prev => ({ ...prev, wantsToAddInstitution: e.target.checked }))}
className="mt-0.5 sm:mt-1 h-4 w-4 flex-shrink-0 border-gray-300 rounded focus:ring-2"
style={{accentColor: '#B9CF33'}}
style={{ accentColor: '#B9CF33' }}
/>
<label className="ml-2 text-xs sm:text-sm text-gray-700">
<span className="font-medium text-xs sm:text-sm">Cadastrar universidade agora (Opcional)</span>

View file

@ -42,28 +42,76 @@ export const SettingsPage: React.FC = () => {
};
return (
<div className="min-h-screen bg-gray-50 pt-32 pb-12">
<div className="min-h-screen bg-gray-50 pt-20 sm:pt-24 md:pt-28 lg:pt-32 pb-8 sm:pb-12">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
{/* Header */}
<div className="mb-8">
<h1 className="text-3xl font-serif font-bold text-brand-black mb-2">
<div className="mb-6 sm:mb-8">
<h1 className="text-2xl sm:text-3xl font-serif font-bold text-brand-black mb-2">
Configurações
</h1>
<p className="text-gray-600">
<p className="text-sm sm:text-base text-gray-600">
Gerencie suas preferências e informações da conta
</p>
</div>
<div className="grid grid-cols-1 lg:grid-cols-4 gap-6">
{/* Sidebar */}
<div className="lg:col-span-1">
<div className="grid grid-cols-1 lg:grid-cols-4 gap-4 sm:gap-6">
{/* Mobile Tabs - Horizontal */}
<div className="lg:hidden">
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-2">
<nav className="flex overflow-x-auto gap-1 scrollbar-hide">
<button
onClick={() => setActiveTab('profile')}
className={`flex items-center gap-2 px-3 py-2 rounded-md transition-colors whitespace-nowrap text-sm ${activeTab === 'profile'
? 'bg-brand-gold text-white'
: 'text-gray-700 hover:bg-gray-100'
}`}
>
<User size={18} />
<span className="font-medium">Perfil</span>
</button>
<button
onClick={() => setActiveTab('account')}
className={`flex items-center gap-2 px-3 py-2 rounded-md transition-colors whitespace-nowrap text-sm ${activeTab === 'account'
? 'bg-brand-gold text-white'
: 'text-gray-700 hover:bg-gray-100'
}`}
>
<Lock size={18} />
<span className="font-medium">Conta</span>
</button>
<button
onClick={() => setActiveTab('notifications')}
className={`flex items-center gap-2 px-3 py-2 rounded-md transition-colors whitespace-nowrap text-sm ${activeTab === 'notifications'
? 'bg-brand-gold text-white'
: 'text-gray-700 hover:bg-gray-100'
}`}
>
<Bell size={18} />
<span className="font-medium">Notificações</span>
</button>
<button
onClick={() => setActiveTab('appearance')}
className={`flex items-center gap-2 px-3 py-2 rounded-md transition-colors whitespace-nowrap text-sm ${activeTab === 'appearance'
? 'bg-brand-gold text-white'
: 'text-gray-700 hover:bg-gray-100'
}`}
>
<Palette size={18} />
<span className="font-medium">Aparência</span>
</button>
</nav>
</div>
</div>
{/* Desktop Sidebar - Vertical */}
<div className="hidden lg:block lg:col-span-1">
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-4">
<nav className="space-y-1">
<button
onClick={() => setActiveTab('profile')}
className={`w-full flex items-center gap-3 px-4 py-3 rounded-md transition-colors ${activeTab === 'profile'
? 'bg-brand-gold text-white'
: 'text-gray-700 hover:bg-gray-100'
? 'bg-brand-gold text-white'
: 'text-gray-700 hover:bg-gray-100'
}`}
>
<User size={20} />
@ -72,8 +120,8 @@ export const SettingsPage: React.FC = () => {
<button
onClick={() => setActiveTab('account')}
className={`w-full flex items-center gap-3 px-4 py-3 rounded-md transition-colors ${activeTab === 'account'
? 'bg-brand-gold text-white'
: 'text-gray-700 hover:bg-gray-100'
? 'bg-brand-gold text-white'
: 'text-gray-700 hover:bg-gray-100'
}`}
>
<Lock size={20} />
@ -82,8 +130,8 @@ export const SettingsPage: React.FC = () => {
<button
onClick={() => setActiveTab('notifications')}
className={`w-full flex items-center gap-3 px-4 py-3 rounded-md transition-colors ${activeTab === 'notifications'
? 'bg-brand-gold text-white'
: 'text-gray-700 hover:bg-gray-100'
? 'bg-brand-gold text-white'
: 'text-gray-700 hover:bg-gray-100'
}`}
>
<Bell size={20} />
@ -92,8 +140,8 @@ export const SettingsPage: React.FC = () => {
<button
onClick={() => setActiveTab('appearance')}
className={`w-full flex items-center gap-3 px-4 py-3 rounded-md transition-colors ${activeTab === 'appearance'
? 'bg-brand-gold text-white'
: 'text-gray-700 hover:bg-gray-100'
? 'bg-brand-gold text-white'
: 'text-gray-700 hover:bg-gray-100'
}`}
>
<Palette size={20} />
@ -105,28 +153,28 @@ export const SettingsPage: React.FC = () => {
{/* Content */}
<div className="lg:col-span-3">
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-8">
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-4 sm:p-6 md:p-8">
{/* Profile Tab */}
{activeTab === 'profile' && (
<div>
<h2 className="text-2xl font-semibold mb-6">Informações do Perfil</h2>
<h2 className="text-xl sm:text-2xl font-semibold mb-4 sm:mb-6">Informações do Perfil</h2>
<div className="mb-8">
<div className="flex items-center gap-6">
<div className="mb-6 sm:mb-8">
<div className="flex flex-col sm:flex-row items-center sm:items-start gap-4 sm:gap-6">
<div className="relative">
<img
src={profileData.avatar}
alt="Avatar"
className="w-24 h-24 rounded-full object-cover"
className="w-20 h-20 sm:w-24 sm:h-24 rounded-full object-cover"
/>
<button className="absolute bottom-0 right-0 w-8 h-8 bg-brand-gold text-white rounded-full flex items-center justify-center hover:bg-[#a5bd2e] transition-colors">
<Camera size={16} />
<button className="absolute bottom-0 right-0 w-7 h-7 sm:w-8 sm:h-8 bg-brand-gold text-white rounded-full flex items-center justify-center hover:bg-[#a5bd2e] transition-colors">
<Camera size={14} className="sm:w-4 sm:h-4" />
</button>
</div>
<div>
<h3 className="font-semibold text-lg">{profileData.name}</h3>
<p className="text-sm text-gray-600">{profileData.email}</p>
<button className="text-sm text-brand-gold hover:underline mt-1">
<div className="text-center sm:text-left">
<h3 className="font-semibold text-base sm:text-lg">{profileData.name}</h3>
<p className="text-xs sm:text-sm text-gray-600">{profileData.email}</p>
<button className="text-xs sm:text-sm text-brand-gold hover:underline mt-1">
Alterar foto
</button>
</div>

View file

@ -188,20 +188,20 @@ export const TeamPage: React.FC = () => {
};
return (
<div className="min-h-screen bg-gray-50 pt-32 pb-12">
<div className="min-h-screen bg-gray-50 pt-20 sm:pt-24 md:pt-28 lg:pt-32 pb-8 sm:pb-12">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
{/* Header */}
<div className="mb-8">
<h1 className="text-3xl font-serif font-bold text-brand-black mb-2">
<div className="mb-6 sm:mb-8">
<h1 className="text-2xl sm:text-3xl font-serif font-bold text-brand-black mb-2">
Equipe & Fotógrafos
</h1>
<p className="text-gray-600">
<p className="text-sm sm:text-base text-gray-600">
Gerencie sua equipe de fotógrafos profissionais
</p>
</div>
{/* Stats */}
<div className="grid grid-cols-1 md:grid-cols-4 gap-6 mb-8">
<div className="grid grid-cols-2 lg:grid-cols-4 gap-3 sm:gap-4 md:gap-6 mb-6 sm:mb-8">
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
<div className="flex items-center justify-between">
<div>
@ -251,8 +251,8 @@ export const TeamPage: React.FC = () => {
</div>
{/* Filters and Search */}
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6 mb-6">
<div className="flex flex-col md:flex-row gap-4">
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-3 sm:p-4 md:p-6 mb-4 sm:mb-6">
<div className="flex flex-col gap-3 sm:gap-4">
<div className="flex-1 relative">
<Search
className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400"
@ -266,34 +266,31 @@ export const TeamPage: React.FC = () => {
className="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-brand-gold"
/>
</div>
<div className="flex gap-2">
<div className="flex flex-wrap gap-2">
<button
onClick={() => setStatusFilter("all")}
className={`px-4 py-2 rounded-md font-medium transition-colors ${
statusFilter === "all"
className={`px-4 py-2 rounded-md font-medium transition-colors ${statusFilter === "all"
? "bg-brand-gold text-white"
: "bg-gray-100 text-gray-700 hover:bg-gray-200"
}`}
}`}
>
Todos
</button>
<button
onClick={() => setStatusFilter("active")}
className={`px-4 py-2 rounded-md font-medium transition-colors ${
statusFilter === "active"
className={`px-4 py-2 rounded-md font-medium transition-colors ${statusFilter === "active"
? "bg-green-600 text-white"
: "bg-gray-100 text-gray-700 hover:bg-gray-200"
}`}
}`}
>
Disponíveis
</button>
<button
onClick={() => setStatusFilter("busy")}
className={`px-4 py-2 rounded-md font-medium transition-colors ${
statusFilter === "busy"
className={`px-4 py-2 rounded-md font-medium transition-colors ${statusFilter === "busy"
? "bg-yellow-600 text-white"
: "bg-gray-100 text-gray-700 hover:bg-gray-200"
}`}
}`}
>
Em Evento
</button>
@ -310,7 +307,7 @@ export const TeamPage: React.FC = () => {
</div>
{/* Photographers Grid */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 sm:gap-6">
{filteredPhotographers.map((photographer) => (
<div
key={photographer.id}
@ -419,11 +416,11 @@ export const TeamPage: React.FC = () => {
e.preventDefault();
alert(
"Fotógrafo adicionado com sucesso!\n\n" +
JSON.stringify(
{ ...newPhotographer, avatarFile: avatarFile?.name },
null,
2
)
JSON.stringify(
{ ...newPhotographer, avatarFile: avatarFile?.name },
null,
2
)
);
setShowAddModal(false);
setNewPhotographer({