diff --git a/src/components/dashboard/DashboardCoach.tsx b/src/components/dashboard/DashboardCoach.tsx index d29e3d1..a26ca2c 100644 --- a/src/components/dashboard/DashboardCoach.tsx +++ b/src/components/dashboard/DashboardCoach.tsx @@ -7,9 +7,12 @@ interface DashboardCoachProps { setCoachPlan: (plan: any) => void; coachHistory?: any[]; // Array of coach_analyses records setIsCoachWizardOpen: (open: boolean) => void; + userPlan: 'free' | 'pro' | 'trial'; } -const DashboardCoach: React.FC = ({ coachPlan, setCoachPlan, coachHistory = [], setIsCoachWizardOpen }) => { +const DashboardCoach: React.FC = ({ coachPlan, setCoachPlan, coachHistory = [], setIsCoachWizardOpen, userPlan }) => { + + const isPaid = userPlan === 'pro' || userPlan === 'trial'; // ───────────────────────────────────────────────────────────────────────────── // STATE 1: NO HISTORY (HERO / ONBOARDING) @@ -43,13 +46,23 @@ const DashboardCoach: React.FC = ({ coachPlan, setCoachPlan

- + {isPaid ? ( + + ) : ( + + )}
@@ -108,7 +121,7 @@ const DashboardCoach: React.FC = ({ coachPlan, setCoachPlan ].map((stat, i) => (

{stat.value}

-

{stat.label}

+

- {coachPlan ? ( - setCoachPlan(null)} /> - ) : ( -

-
- + + // 🔒 FREE PLAN LOCK + if (!isPaid) { + return ( +
+
+
+
+ +
+
+ +
+

Funcionalidade PRO

+

+ O Personal IA está disponível apenas para membros PRO. Desbloqueie todo o potencial do seu corpo agora. +

+ + +
+
+
+ ); + } + + + return ( +
+ {coachPlan ? ( + setCoachPlan(null)} /> + ) : ( +
+ +
+ +
+

Selecione uma análise

+

+ Escolha um protocolo no menu lateral ("Coach AI → Histórico") ou gere um novo para transformar seus resultados. +

+ + +
+ )}
-

Selecione uma análise

-

- Escolha um protocolo no menu lateral ("Coach AI → Histórico") ou gere um novo. -

- -
- )} -
- ); + ); }; -export default DashboardCoach; + export default DashboardCoach; diff --git a/src/components/dashboard/DashboardSubscription.tsx b/src/components/dashboard/DashboardSubscription.tsx index 1c8e584..020d9af 100644 --- a/src/components/dashboard/DashboardSubscription.tsx +++ b/src/components/dashboard/DashboardSubscription.tsx @@ -60,17 +60,20 @@ const DashboardSubscription: React.FC = ({ user, pla
-
- {t.dashboard.currentPlan} - {(user.plan === 'pro' || user.plan === 'trial') && ( - - Ativo +
+

{t.dashboard.currentPlan}

+
+ + {planName === 'PRO' ? 'Professional' : planName} +
+ {/* Check if user has a valid date and is NOT on free plan (unless free plan has an expiry which is rare but possible for trials) */} + {user.plan !== 'free' && user.plan_valid_until && ( +

+ Válido até {new Date(user.plan_valid_until).toLocaleDateString('pt-BR')} +

)}
-

- {planName} -

diff --git a/src/pages/Dashboard.tsx b/src/pages/Dashboard.tsx index bb5f6c1..6ce17ce 100644 --- a/src/pages/Dashboard.tsx +++ b/src/pages/Dashboard.tsx @@ -213,6 +213,7 @@ const Dashboard: React.FC = ({ user, onLogout, onOpenAdmin, onOp setCoachPlan={setCoachPlan} coachHistory={coachHistory} setIsCoachWizardOpen={setIsCoachWizardOpen} + userPlan={user.plan} /> )} diff --git a/supabase/functions/whatsapp-webhook/index.ts b/supabase/functions/whatsapp-webhook/index.ts index 599cc7e..883b6ce 100644 --- a/supabase/functions/whatsapp-webhook/index.ts +++ b/supabase/functions/whatsapp-webhook/index.ts @@ -545,6 +545,27 @@ serve(async (req) => { textMessage && /coach|treino|avalia[çc][aã]o/i.test(textMessage) ) { + // [STRICT VALIDATION] Check for active PAID plan + const { data: entitlement } = await supabase + .from("user_entitlements") + .select("is_active, valid_until, entitlement_code") + .eq("user_id", userId) + .match({ is_active: true }) // Ensure active + .maybeSingle(); + + const isPaid = entitlement && + ['pro', 'mensal', 'trimestral', 'anual', 'trial', 'paid'].includes(entitlement.entitlement_code) && + (!entitlement.valid_until || new Date(entitlement.valid_until) > new Date()); + + if (!isPaid) { + await sendWhatsAppMessage( + remoteJid, + "🔒 *Funcionalidade Exclusiva PRO*\n\nO *Personal Coach IA* está disponível apenas para assinantes PRO.\n\nCom o plano PRO você tem:\n✅ Treinos personalizados\n✅ Dieta sob medida\n✅ Ajustes mensais\n\nFaça o upgrade agora em: https://foodsnap.com.br" + ); + return new Response("Coach Blocked (Free)", { status: 200 }); + } + + // [LOGIC START] Verificar última avaliação (Limite de 7 dias) // [LOGIC START] Verificar última avaliação (Limite de 7 dias) const { data: lastAnalysis } = await supabase .from("coach_analyses") @@ -807,16 +828,16 @@ serve(async (req) => { if (state === "IDLE") { console.log(`[WH] Entering Food Scan flow. isImage=${isImage}`); // 6a. Verificar plano e quota + // 6a. Verificar plano e quota const { data: entitlement } = await supabase .from("user_entitlements") .select("is_active, valid_until, entitlement_code") .eq("user_id", userId) - .eq("is_active", true) - .order("valid_until", { ascending: false, nullsFirst: false }) + .match({ is_active: true }) .maybeSingle(); - const isPaid = - entitlement?.is_active && + const isPaid = entitlement && + ['pro', 'mensal', 'trimestral', 'anual', 'trial', 'paid'].includes(entitlement.entitlement_code) && (!entitlement.valid_until || new Date(entitlement.valid_until) > new Date()); if (!isPaid) {