import React, { useState, useEffect, useRef, useMemo } from 'react'; import { Home, Target, BookOpen, User, PlusCircle, CheckCircle2, Circle, Flame, Award, Settings, Brain, Heart, Moon, Sun, Droplets, Dumbbell, Book, Cross, ChevronRight, Activity, Smile, Frown, MessageSquare, Zap, BarChart3, ShieldCheck, Users, Trophy, Flag, LogOut, Mail, Lock, AlertCircle, Loader2 } from 'lucide-react'; import { AreaChart, Area, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from 'recharts'; import { initializeApp } from 'firebase/app'; import { getAuth, signInAnonymously, signInWithCustomToken, onAuthStateChanged, createUserWithEmailAndPassword, signInWithEmailAndPassword, signOut, updateProfile } from 'firebase/auth'; import { getFirestore, doc, getDoc, setDoc, updateDoc, onSnapshot, collection, query, addDoc, getDocs, deleteDoc, serverTimestamp, arrayUnion } from 'firebase/firestore'; // --- CONFIGURAÇÃO FIREBASE --- const firebaseConfig = typeof __firebase_config !== 'undefined' ? JSON.parse(__firebase_config) : {}; const app = initializeApp(firebaseConfig); const auth = getAuth(app); const db = getFirestore(app); const appId = typeof __app_id !== 'undefined' ? __app_id : 'transforma-app-v1'; const LEVELS = [ { name: 'Bronze', minXp: 0, color: 'text-orange-400', border: 'border-orange-400/50', bg: 'bg-orange-500/10' }, { name: 'Prata', minXp: 1000, color: 'text-slate-300', border: 'border-slate-300/50', bg: 'bg-slate-400/10' }, { name: 'Ouro', minXp: 2500, color: 'text-yellow-400', border: 'border-yellow-400/50', bg: 'bg-yellow-400/10' }, { name: 'Platina', minXp: 5000, color: 'text-cyan-400', border: 'border-cyan-400/50', bg: 'bg-cyan-400/10' }, { name: 'Diamante', minXp: 10000, color: 'text-purple-400', border: 'border-purple-400/50', bg: 'bg-purple-400/10' }, { name: 'Mestre', minXp: 20000, color: 'text-rose-500', border: 'border-rose-500/50', bg: 'bg-rose-500/10' }, { name: 'Lenda', minXp: 50000, color: 'text-amber-500', border: 'border-amber-500/50', bg: 'bg-amber-500/10' }, ]; const ICONS_MAP = { Sun, Cross, BookOpen, Droplets, Dumbbell, Book, ShieldCheck, Moon, Heart, Flame }; const INITIAL_HABITS = [ { id: 'h1', title: 'Check-in Matinal', xp: 20, iconName: 'Sun', category: 'mental', done: false }, { id: 'h2', title: 'Orar (10 min)', xp: 50, iconName: 'Cross', category: 'spiritual', done: false }, { id: 'h3', title: 'Ler Versículo do Dia', xp: 30, iconName: 'BookOpen', category: 'spiritual', done: false }, { id: 'h4', title: 'Beber 2L de Água', xp: 40, iconName: 'Droplets', category: 'physical', done: false }, { id: 'h5', title: 'Treino Fisico', xp: 100, iconName: 'Dumbbell', category: 'physical', done: false }, { id: 'h6', title: 'Leitura (20 pág)', xp: 30, iconName: 'Book', category: 'mental', done: false }, { id: 'h7', title: 'Zero Pornografia/Álcool', xp: 100, iconName: 'ShieldCheck', category: 'discipline', done: false }, { id: 'h8', title: 'Dormir antes das 23h', xp: 50, iconName: 'Moon', category: 'physical', done: false }, ]; const WEEKLY_CHART_DATA = [ { name: 'Seg', score: 65 }, { name: 'Ter', score: 72 }, { name: 'Qua', score: 68 }, { name: 'Qui', score: 85 }, { name: 'Sex', score: 90 }, { name: 'Sáb', score: 88 }, { name: 'Dom', score: 95 }, ]; export default function App() { // Navigation & UI State const [activeTab, setActiveTab] = useState('home'); const [showCheckIn, setShowCheckIn] = useState(false); const [showLevelUp, setShowLevelUp] = useState(false); const [loading, setLoading] = useState(true); const [authError, setAuthError] = useState(''); // Auth State const [user, setUser] = useState(null); const [isAuthScreen, setIsAuthScreen] = useState(false); const [authMode, setAuthMode] = useState('login'); // 'login' | 'register' // App Data State const [userData, setUserData] = useState(null); const [habits, setHabits] = useState([]); const [journalEntries, setJournalEntries] = useState([]); // Community State const [leaderboard, setLeaderboard] = useState([]); const [challenges, setChallenges] = useState([]); // Temp State const [journalText, setJournalText] = useState(''); const [aiFeedback, setAiFeedback] = useState(null); const [isAnalyzing, setIsAnalyzing] = useState(false); // Forms const emailRef = useRef(null); const passRef = useRef(null); const nameRef = useRef(null); const challengeTitleRef = useRef(null); const challengeRewardRef = useRef(null); useEffect(() => { // 1. Mandatory Auth Initialization const initAuth = async () => { try { if (typeof __initial_auth_token !== 'undefined' && __initial_auth_token) { await signInWithCustomToken(auth, __initial_auth_token); } else { // Fallback to anonymous so we satisfy rules, but we'll show login UI if anonymous await signInAnonymously(auth); } } catch (err) { console.error("Auth Init Error", err); } }; initAuth(); // 2. Auth State Listener const unsubscribe = onAuthStateChanged(auth, (currentUser) => { setUser(currentUser); if (currentUser) { // If user is anonymous, we force them to the Auth screen for a premium experience if (currentUser.isAnonymous) { setIsAuthScreen(true); setLoading(false); } else { setIsAuthScreen(false); // Initial check-in logic const lastCheckIn = localStorage.getItem(`checkin_${currentUser.uid}`); const today = new Date().toDateString(); if (lastCheckIn !== today) setShowCheckIn(true); } } else { setIsAuthScreen(true); setLoading(false); } }); return () => unsubscribe(); }, []); useEffect(() => { if (!user || user.isAnonymous) return; setLoading(true); // 1. Listen to Private User Profile const profileRef = doc(db, 'artifacts', appId, 'users', user.uid, 'profile'); const unsubProfile = onSnapshot(profileRef, (docSnap) => { if (docSnap.exists()) { const data = docSnap.data(); // Handle Level Up Notification if (userData && data.levelIndex > userData.levelIndex) { setShowLevelUp(true); setTimeout(() => setShowLevelUp(false), 4000); } setUserData(data); } else { // Create initial profile const newProfile = { uid: user.uid, name: user.displayName || 'Guerreiro(a)', xp: 0, streak: 1, levelIndex: 0, lifeScore: 50, createdAt: serverTimestamp() }; setDoc(profileRef, newProfile); // Also add user to Public Leaderboard const publicUserRef = doc(db, 'artifacts', appId, 'public', 'data', 'users', user.uid); setDoc(publicUserRef, { uid: user.uid, name: newProfile.name, xp: newProfile.xp, levelIndex: newProfile.levelIndex, streak: newProfile.streak }); } setLoading(false); }, (err) => console.error(err)); // 2. Listen to Private Habits const habitsRef = collection(db, 'artifacts', appId, 'users', user.uid, 'habits'); const unsubHabits = onSnapshot(habitsRef, (snapshot) => { if (snapshot.empty && habits.length === 0) { // Initialize habits INITIAL_HABITS.forEach(h => { setDoc(doc(habitsRef, h.id), h); }); } else { const loadedHabits = []; snapshot.forEach(d => loadedHabits.push({ id: d.id, ...d.data() })); // Reset habits daily (simple client-side check for demo) const today = new Date().toDateString(); const storedDate = localStorage.getItem(`habits_date_${user.uid}`); if (storedDate !== today) { loadedHabits.forEach(h => { if (h.done) { updateDoc(doc(habitsRef, h.id), { done: false }); h.done = false; } }); localStorage.setItem(`habits_date_${user.uid}`, today); } setHabits(loadedHabits.sort((a,b) => a.id.localeCompare(b.id))); } }, (err) => console.error(err)); // 3. Listen to Public Community (Users & Challenges) const publicUsersRef = collection(db, 'artifacts', appId, 'public', 'data', 'users'); const unsubUsers = onSnapshot(publicUsersRef, (snapshot) => { const usersList = []; snapshot.forEach(d => usersList.push(d.data())); // Sort in memory (Rule 2) setLeaderboard(usersList.sort((a, b) => b.xp - a.xp)); }); const publicChallengesRef = collection(db, 'artifacts', appId, 'public', 'data', 'challenges'); const unsubChallenges = onSnapshot(publicChallengesRef, (snapshot) => { const chalList = []; snapshot.forEach(d => chalList.push({ id: d.id, ...d.data() })); setChallenges(chalList); }); return () => { unsubProfile(); unsubHabits(); unsubUsers(); unsubChallenges(); }; }, [user]); const updateXP = async (amount) => { if (!user || !userData) return; let newXp = userData.xp + amount; let newLifeScore = userData.lifeScore; // Simplistic Life Score math if (amount > 0) newLifeScore = Math.min(100, newLifeScore + 1); if (amount < 0) newLifeScore = Math.max(0, newLifeScore - 1); // Calculate level let newLevelIndex = userData.levelIndex; while (LEVELS[newLevelIndex + 1] && newXp >= LEVELS[newLevelIndex + 1].minXp) { newLevelIndex++; } const updates = { xp: newXp, levelIndex: newLevelIndex, lifeScore: newLifeScore }; // Update Private Profile await updateDoc(doc(db, 'artifacts', appId, 'users', user.uid, 'profile'), updates); // Update Public Leaderboard Profile await updateDoc(doc(db, 'artifacts', appId, 'public', 'data', 'users', user.uid), { xp: newXp, levelIndex: newLevelIndex }); }; const handleAuth = async (e) => { e.preventDefault(); setAuthError(''); setLoading(true); const email = emailRef.current?.value; const pass = passRef.current?.value; const name = nameRef.current?.value; try { if (authMode === 'register') { const cred = await createUserWithEmailAndPassword(auth, email, pass); await updateProfile(cred.user, { displayName: name }); } else { await signInWithEmailAndPassword(auth, email, pass); } } catch (err) { setAuthError(err.message); setLoading(false); } }; const handleLogout = async () => { await signOut(auth); // When signed out, the mandatory listener will sign them back in anonymously // but our UI catches isAnonymous and shows the auth screen. }; const toggleHabit = async (habit) => { if (!user) return; const isNowDone = !habit.done; // Optimistic UI Update setHabits(prev => prev.map(h => h.id === habit.id ? { ...h, done: isNowDone } : h)); // Backend Update await updateDoc(doc(db, 'artifacts', appId, 'users', user.uid, 'habits', habit.id), { done: isNowDone }); // Update XP await updateXP(isNowDone ? habit.xp : -habit.xp); }; const completeCheckIn = async () => { setShowCheckIn(false); localStorage.setItem(`checkin_${user.uid}`, new Date().toDateString()); await updateXP(50); // Find check-in habit and mark done const checkinHabit = habits.find(h => h.title.includes('Check-in')); if (checkinHabit && !checkinHabit.done) { await toggleHabit(checkinHabit); } }; const analyzeJournal = async () => { if (journalText.trim().length < 10 || !user) return; setIsAnalyzing(true); // Simulate AI delay setTimeout(async () => { const text = journalText.toLowerCase(); let feedback = { sentiment: 'Neutro', message: 'Continue firme no seu propósito. Deus está no controle e cada dia é uma página em branco.', verse: '"Tudo posso naquele que me fortalece." - Filipenses 4:13' }; if (text.includes('triste') || text.includes('ansioso') || text.includes('medo') || text.includes('difícil')) { feedback = { sentiment: 'Acolhimento', message: 'Percebo que hoje foi desafiador. Não se cobre tanto. A dor faz parte da jornada de restauração. Respire fundo, entregue essa ansiedade a Deus. Você não está sozinho.', verse: '"Lançando sobre ele toda a vossa ansiedade, porque ele tem cuidado de vós." - 1 Pedro 5:7' }; } else if (text.includes('grato') || text.includes('feliz') || text.includes('consegui') || text.includes('venci')) { feedback = { sentiment: 'Motivacional', message: 'Que alegria ler isso! Você está construindo uma mentalidade de vencedor. Cada pequena vitória gera dopamina e reforça seu novo eu.', verse: '"Este é o dia que o Senhor fez; regozijemo-nos e alegremo-nos nele." - Salmos 118:24' }; } setAiFeedback(feedback); setIsAnalyzing(false); await updateXP(50); // Save entry await addDoc(collection(db, 'artifacts', appId, 'users', user.uid, 'journal'), { text: journalText, feedback: feedback, createdAt: serverTimestamp() }); setJournalText(''); }, 1500); }; const handleCreateChallenge = async (e) => { e.preventDefault(); if (!user || !userData) return; const title = challengeTitleRef.current.value; const reward = parseInt(challengeRewardRef.current.value); if (!title || !reward) return; await addDoc(collection(db, 'artifacts', appId, 'public', 'data', 'challenges'), { title, reward, creatorId: user.uid, creatorName: userData.name, participants: [user.uid], createdAt: serverTimestamp() }); challengeTitleRef.current.value = ''; challengeRewardRef.current.value = ''; }; const joinChallenge = async (challengeId, currentParticipants) => { if (!user) return; if (currentParticipants.includes(user.uid)) return; // Already joined await updateDoc(doc(db, 'artifacts', appId, 'public', 'data', 'challenges', challengeId), { participants: [...currentParticipants, user.uid] }); // Give immediate tiny reward for joining await updateXP(10); }; if (loading && !isAuthScreen) { return (
Seu mentor, psicólogo e treinador em um só lugar.
Hoje Deus lhe deu mais uma oportunidade. Como você está começando o dia?
Pronto para evoluir hoje?
Baseado nos seus hábitos e saúde emocional.
"Pois Deus não nos deu um espírito de covardia, mas de poder, de amor e de equilíbrio."
2 Timóteo 1:7
{habit.title}
+{habit.xp} XPTodas missões concluídas hoje!
Construa disciplina, ganhe recompensas.
{habit.title}
{habit.done ? 'Concluído' : `+${habit.xp} XP`}Cresça em comunidade, participe de desafios.
{u.name} {isMe && '(Você)'}
{lvl.name}Criado por {chal.creatorName}
Nenhum desafio ativo. Crie o primeiro!
}Mentoria guiada por IA. Desabafe e evolua.
{aiFeedback.message}
{aiFeedback.verse}
{userData.streak}
Dias Focados
{Math.floor(userData.xp / 1000)}
Conquistas
Evolução Concluída
Nível {currentLevelInfo.name} Alcançado!