foodsnap/src/pages/Dashboard.tsx

236 lines
7.5 KiB
TypeScript
Raw Normal View History

import React, { useState, useEffect } from 'react';
import {
LayoutDashboard, History, CreditCard, Settings, LogOut, Plus, Search, Calendar, ChevronRight, Zap, ExternalLink, MessageCircle, Loader2, Utensils, ShieldAlert, Smartphone, QrCode, CheckCircle2, Dumbbell, Timer, PlayCircle, ScanEye, BrainCircuit, Activity, ScanLine, Sparkles, TrendingUp
} from 'lucide-react';
import CoachWizard from '@/components/coach/CoachWizard';
import { User } from '@/types';
import { supabase } from '@/lib/supabase';
import { useLanguage } from '@/contexts/LanguageContext';
// Custom Hooks
import { useDashboardStats } from '@/hooks/useDashboardStats';
import { useDashboardHistory } from '@/hooks/useDashboardHistory';
import { useCoachPlan } from '@/hooks/useCoachPlan';
// Layout Components
import Sidebar from '@/components/layout/Sidebar';
import MobileNav from '@/components/layout/MobileNav';
// Feature Components
import DashboardOverview from '@/components/dashboard/DashboardOverview';
import DashboardHistory from '@/components/dashboard/DashboardHistory';
import DashboardSubscription from '@/components/dashboard/DashboardSubscription';
import DashboardCoach from '@/components/dashboard/DashboardCoach';
interface DashboardProps {
user: User;
onLogout: () => void;
onOpenAdmin?: () => void; // Optional prop for admin toggle
onOpenPro?: () => void; // Optional prop for professional toggle
initialTab?: 'overview' | 'history' | 'subscription' | 'coach';
}
const Dashboard: React.FC<DashboardProps> = ({ user, onLogout, onOpenAdmin, onOpenPro, initialTab }) => {
const { t, language } = useLanguage();
const [activeTab, setActiveTab] = useState<'overview' | 'history' | 'subscription' | 'coach'>(initialTab || 'overview');
const [isCoachWizardOpen, setIsCoachWizardOpen] = useState(false);
// Custom Hooks
const { stats, loadingStats } = useDashboardStats(user.id);
const { history, loadingHistory } = useDashboardHistory(user.id);
const { coachPlan, setCoachPlan, coachHistory } = useCoachPlan(user.id);
// WhatsApp Config
const [whatsappNumber, setWhatsappNumber] = useState("5541999999999"); // Default fallback
const fetchSystemSettings = async () => {
try {
const { data } = await supabase
.from('app_settings')
.select('value')
.eq('key', 'whatsapp_number')
.maybeSingle();
if (data && data.value) {
setWhatsappNumber(data.value);
}
} catch (err) {
console.error("Failed to fetch settings", err);
}
};
useEffect(() => {
fetchSystemSettings();
// Realtime Subscription: Escuta alterações na tabela app_settings
const settingsChannel = supabase
.channel('public:app_settings')
.on(
'postgres_changes',
{
event: '*', // Escuta INSERT e UPDATE
schema: 'public',
table: 'app_settings',
filter: 'key=eq.whatsapp_number',
},
(payload) => {
if (payload.new && (payload.new as any).value) {
setWhatsappNumber((payload.new as any).value);
}
}
)
.subscribe();
return () => {
supabase.removeChannel(settingsChannel);
};
}, [user.id]);
const whatsappUrl = `https://wa.me/${whatsappNumber}?text=Oi`;
const qrCodeUrl = `https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=${encodeURIComponent(whatsappUrl)}`;
const handleStripePortal = async () => {
try {
const { data: { session } } = await supabase.auth.getSession();
if (!session) {
alert("Sessão expirada. Faça login novamente.");
return;
}
const response = await fetch(`${import.meta.env.VITE_SUPABASE_URL}/functions/v1/stripe-portal`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${session.access_token}`,
},
});
if (!response.ok) throw new Error("Erro ao gerar link do portal");
const { url } = await response.json();
if (url) {
window.location.href = url;
} else {
alert("Erro: URL do portal não retornada.");
}
} catch (error) {
console.error("Erro no portal:", error);
alert("Não foi possível acessar o portal de pagamentos.");
}
};
// Helper para o nome do plano (Correção do bug de nome vazio)
const getPlanLabel = () => {
if (user.plan === 'pro') return 'PRO';
if (user.plan === 'trial') return 'Trial';
// Traduções manuais para o plano gratuito
if (language === 'pt') return 'Gratuito';
if (language === 'es') return 'Gratis';
return 'Free';
};
const planName = getPlanLabel();
const fallbackImage = "https://images.unsplash.com/photo-1546069901-ba9599a7e63c?w=400&q=80";
return (
<div className="min-h-screen bg-gray-50 flex font-sans text-gray-900">
{/* Sidebar Navigation */}
<Sidebar
user={user}
activeTab={activeTab}
setActiveTab={setActiveTab}
onLogout={onLogout}
onOpenAdmin={onOpenAdmin}
onOpenPro={onOpenPro}
t={t}
coachHistory={coachHistory}
onSelectCoachPlan={(plan) => {
setCoachPlan(plan);
setActiveTab('coach');
}}
/>
{/* Mobile Bottom Navigation */}
<MobileNav
activeTab={activeTab}
setActiveTab={setActiveTab}
t={t}
/>
<main className="flex-1 md:ml-64 p-4 md:p-8 pb-24 md:pb-8">
{/* Mobile Header */}
<div className="md:hidden flex justify-between items-center mb-6">
<span className="font-bold text-lg">FoodSnap</span>
<div className="flex gap-2">
{onOpenAdmin && (
<button onClick={onOpenAdmin} className="p-2 text-gray-500 hover:text-red-600">
<ShieldAlert size={20} />
</button>
)}
<button onClick={onLogout}><LogOut size={20} className="text-gray-500" /></button>
</div>
</div >
{/* Content Switcher */}
{activeTab === 'overview' && (
<DashboardOverview
user={user}
stats={stats}
loadingStats={loadingStats}
history={history}
loadingHistory={loadingHistory}
planName={planName}
t={t}
whatsappUrl={whatsappUrl}
qrCodeUrl={qrCodeUrl}
whatsappNumber={whatsappNumber}
setActiveTab={setActiveTab}
fallbackImage={fallbackImage}
/>
)}
{activeTab === 'history' && (
<DashboardHistory
history={history}
loadingHistory={loadingHistory}
t={t}
fallbackImage={fallbackImage}
/>
)}
{activeTab === 'subscription' && (
<DashboardSubscription
user={user}
planName={planName}
t={t}
handleStripePortal={handleStripePortal}
/>
)}
{activeTab === 'coach' && (
<DashboardCoach
coachPlan={coachPlan}
setCoachPlan={setCoachPlan}
coachHistory={coachHistory}
setIsCoachWizardOpen={setIsCoachWizardOpen}
userPlan={user.plan}
/>
)}
</main >
<CoachWizard
isOpen={isCoachWizardOpen}
onClose={() => setIsCoachWizardOpen(false)}
onComplete={(data: any) => {
console.log("Wizard Completed:", data);
setCoachPlan(data);
setIsCoachWizardOpen(false);
}}
/>
</div >
);
};
export default Dashboard;