import React, { useState, useEffect, useMemo } from 'react'; import { Plus, Search, LayoutDashboard, Shirt, LogOut, Trash2, Heart, Loader2, AlertCircle, UserCircle, Settings, Moon, Sun, ShieldAlert, Edit2, Image as ImageIcon, Check, RotateCcw, Trash, PanelLeftClose, PanelLeftOpen, Sparkles, CloudSun, ArrowRight, Droplets, CheckCircle2, PieChart, History, X } from 'lucide-react'; import { signInWithEmailAndPassword, createUserWithEmailAndPassword, onAuthStateChanged, signOut, signInWithCustomToken } from 'firebase/auth'; import { collection, doc, onSnapshot, addDoc, updateDoc, deleteDoc, writeBatch } from 'firebase/firestore'; import { auth, db, appId } from './lib/firebase'; import { Card } from './components/ui/Card'; import { Badge } from './components/ui/Badge'; import { Input } from './components/ui/Input'; export default function App() { const [view, setView] = useState('auth'); const [user, setUser] = useState(null); const [loading, setLoading] = useState(true); const [clothes, setClothes] = useState([]); const [looks, setLooks] = useState([]); const [editingItem, setEditingItem] = useState(null); const [darkMode, setDarkMode] = useState(false); const [searchTerm, setSearchTerm] = useState(''); const [imageUrlDraft, setImageUrlDraft] = useState(''); const [sidebarOpen, setSidebarOpen] = useState(true); const [authMode, setAuthMode] = useState('login'); const [authError, setAuthError] = useState(''); const [categoryFilter, setCategoryFilter] = useState('Todos'); // Estado para criação de Looks const [selectedForLook, setSelectedForLook] = useState([]); // 1. Inicializar Autenticação useEffect(() => { const initAuth = async () => { const token = import.meta.env.VITE_INITIAL_AUTH_TOKEN; if (token) { try { await signInWithCustomToken(auth, token); } catch (e) { } } }; initAuth(); const unsubscribe = onAuthStateChanged(auth, (currentUser) => { setUser(currentUser); currentUser ? setView('dashboard') : setView('auth'); setLoading(false); }); return () => unsubscribe(); }, []); // 2. Dados em Tempo Real (Roupas e Looks) useEffect(() => { if (!user) return; // Roupas const clothesCol = collection(db, 'artifacts', appId, 'users', user.uid, 'clothes'); const unsubClothes = onSnapshot(clothesCol, (snap) => { setClothes(snap.docs.map(d => ({ id: d.id, ...d.data() }))); }, (err) => console.error(err)); // Looks const looksCol = collection(db, 'artifacts', appId, 'users', user.uid, 'looks'); const unsubLooks = onSnapshot(looksCol, (snap) => { setLooks(snap.docs.map(d => ({ id: d.id, ...d.data() }))); }, (err) => console.error(err)); return () => { unsubClothes(); unsubLooks(); }; }, [user]); // --- Lógicas de Negócio --- const activeClothes = useMemo(() => clothes.filter(c => c.status === 'active'), [clothes]); const laundryClothes = useMemo(() => clothes.filter(c => c.status === 'laundry'), [clothes]); const trashClothes = useMemo(() => clothes.filter(c => c.status === 'trash'), [clothes]); const filteredClothes = useMemo(() => { return activeClothes.filter(c => { const matchesSearch = (c.name || "").toLowerCase().includes(searchTerm.toLowerCase()) || (c.color || "").toLowerCase().includes(searchTerm.toLowerCase()); const matchesCategory = categoryFilter === 'Todos' || c.category === categoryFilter; return matchesSearch && matchesCategory; }); }, [activeClothes, searchTerm, categoryFilter]); // Ações de Itens const handleItemAction = async (action, item) => { if (!user) return; const docRef = doc(db, 'artifacts', appId, 'users', user.uid, 'clothes', item.id || item); switch (action) { case 'favorite': await updateDoc(docRef, { favorite: !item.favorite }); break; case 'trash': await updateDoc(docRef, { status: 'trash', trashedAt: new Date().getTime() }); break; case 'restore': await updateDoc(docRef, { status: 'active', trashedAt: null }); break; case 'laundry': await updateDoc(docRef, { status: 'laundry' }); break; case 'clean': await updateDoc(docRef, { status: 'active' }); break; case 'delete': if (window.confirm("Apagar permanentemente?")) await deleteDoc(docRef); break; } }; const saveItem = async (e) => { e.preventDefault(); if (!user) return; setLoading(true); const formData = new FormData(e.target); const itemData = { name: formData.get('name'), category: formData.get('category'), color: formData.get('color'), imageUrl: formData.get('imageUrl') || 'https://images.unsplash.com/photo-1521572267360-ee0c2909d518?q=80&w=500&auto=format&fit=crop', status: 'active', favorite: editingItem ? (editingItem.favorite || false) : false, updatedAt: new Date().getTime() }; try { if (editingItem) { const docRef = doc(db, 'artifacts', appId, 'users', user.uid, 'clothes', editingItem.id); await updateDoc(docRef, itemData); } else { itemData.createdAt = new Date().getTime(); const clothesCol = collection(db, 'artifacts', appId, 'users', user.uid, 'clothes'); await addDoc(clothesCol, itemData); } setEditingItem(null); setImageUrlDraft(''); setView('closet'); } catch (e) { console.error(e); } finally { setLoading(false); } }; const createLook = async (e) => { e.preventDefault(); if (selectedForLook.length < 2) return; setLoading(true); const fd = new FormData(e.target); try { const looksCol = collection(db, 'artifacts', appId, 'users', user.uid, 'looks'); await addDoc(looksCol, { name: fd.get('lookName'), items: selectedForLook, createdAt: new Date().getTime() }); setSelectedForLook([]); setView('outfits'); } catch (e) { console.error(e); } finally { setLoading(false); } }; const deleteLook = async (id) => { if (!window.confirm("Apagar este Look?")) return; const docRef = doc(db, 'artifacts', appId, 'users', user.uid, 'looks', id); await deleteDoc(docRef); }; const handleAuth = async (e) => { e.preventDefault(); setAuthError(''); setLoading(true); const fd = new FormData(e.target); const email = fd.get('email'); const password = fd.get('password'); try { if (authMode === 'login') await signInWithEmailAndPassword(auth, email, password); else await createUserWithEmailAndPassword(auth, email, password); } catch (err) { console.error(err); if (err.code === 'auth/operation-not-allowed') { setAuthError('O login por e-mail está desativado.'); } else { setAuthError(err.message); } } finally { setLoading(false); } }; const emptyTrashPermanently = async () => { if (!user || !window.confirm("Esvaziar o lixo permanentemente?")) return; setLoading(true); try { const batch = writeBatch(db); trashClothes.forEach(item => { const docRef = doc(db, 'artifacts', appId, 'users', user.uid, 'clothes', item.id); batch.delete(docRef); }); await batch.commit(); } catch (e) { console.error(e); } finally { setLoading(false); } }; const clearAllToTrash = async () => { if (!user || !window.confirm("Mover todas as peças ativas para o lixo?")) return; setLoading(true); try { const batch = writeBatch(db); activeClothes.forEach(item => { const docRef = doc(db, 'artifacts', appId, 'users', user.uid, 'clothes', item.id); batch.update(docRef, { status: 'trash', trashedAt: new Date().getTime() }); }); await batch.commit(); } catch (e) { console.error(e); } finally { setLoading(false); } }; if (loading && !user) return
; if (view === 'auth') { return (

MyCloset

O Futuro do Teu Estilo

{authError &&
{authError}
}
); } return (
{/* Sidebar - Design Futurista */} {/* Área Principal */}
{/* Header Superior */}

{view === 'dashboard' && 'Visão Geral'} {view === 'closet' && 'O Meu Armário'} {view === 'laundry' && 'Lavandaria'} {view === 'outfits' && 'Looks & Estilo'} {view === 'settings' && 'Definições'}

{/* Conteúdo Dinâmico */}
{/* DASHBOARD */} {view === 'dashboard' && (
{[ { label: 'Roupas Prontas', val: activeClothes.length, icon: Shirt, col: 'indigo' }, { label: 'Na Lavandaria', val: laundryClothes.length, icon: Droplets, col: 'blue' }, { label: 'Meus Looks', val: looks.length, icon: Sparkles, col: 'purple' }, { label: 'Favoritos', val: activeClothes.filter(c => c.favorite).length, icon: Heart, col: 'rose' }, ].map((s, i) => (

{s.label}

{s.val}

))}
Hoje em Portugal

22°C - Ensolarado

Está um dia fantástico! Recomendamos as tuas peças leves. Que tal um visual casual com as tuas sapatilhas favoritas?

{activeClothes.filter(c => c.category === 'Tops').slice(0, 2).map(c => (
))}

Top Cores

{['Preto', 'Branco', 'Azul'].map(color => (
{color} {Math.floor(Math.random() * 40 + 20)}%
))}
)} {/* ARMÁRIO */} {view === 'closet' && (
setSearchTerm(e.target.value)} />
{['Todos', 'Tops', 'Bottoms', 'Calçado', 'Casacos', 'Acessórios'].map(cat => ( ))}
{filteredClothes.map(item => (
{item.name}
{item.category}

{item.name}

{item.color}
))}
)} {/* LAVANDARIA */} {view === 'laundry' && (

Cesto da Roupa

Aqui encontras as peças que marcaste como sujas. Lava-as para que voltem ao armário principal.

{laundryClothes.map(item => (

{item.name}

A lavar
))} {laundryClothes.length === 0 && (
Cesto Vazio
)}
)} {/* LOOKS */} {view === 'outfits' && (

Criar Novo Look

Peças Selecionadas ({selectedForLook.length})

{selectedForLook.map(id => { const item = clothes.find(c => c.id === id); return (
); })} {selectedForLook.length === 0 &&

Seleciona peças...

}

Armário

{activeClothes.map(c => ( ))}

Histórico de Looks

{looks.map(look => (

{look.name}

{look.items.length} Peças • {new Date(look.createdAt).toLocaleDateString()}

{look.items.map(itemId => { const item = clothes.find(c => c.id === itemId); return (
); })}
))}
)} {/* ADICIONAR / EDITAR */} {(view === 'add' || view === 'edit') && (

{editingItem ? 'Editar' : 'Novo Item'}

{editingItem?.imageUrl || imageUrlDraft.startsWith('http') ? ( ) : (

Preview

)}
setImageUrlDraft(v)} />
)} {/* DEFINIÇÕES */} {view === 'settings' && (
{user?.email?.[0]?.toUpperCase() || 'U'}

A Tua Conta

{user?.email || 'Modo PAP'}

Reciclagem

{trashClothes.length > 0 && }
{trashClothes.map(item => (

{item.name}

Eliminado

))}

Zona Crítica

Ações de limpeza total do armário.

)}
); }