freemium F2 polish: welcome email + plano gratuito na vitrine
- edge function send-welcome-email: e-mail de boas-vindas ao DONO do tenant recem-provisionado (destinatario do JWT, SMTP global/sistema, defaults Mailpit). Best-effort, disparada fire-and-forget no OnboardingPage so no provisionamento novo. - vitrine: seed plan_public + bullets dos planos free (cartao "Gratis"); Landingpage passa a mostrar "Gratis para sempre" (isFreePlan) em vez de "—". - build OK Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -92,6 +92,11 @@ async function provision(slugOverride = null) {
|
||||
// caminho pago (intent) — best-effort, não bloqueia
|
||||
try { await supabase.rpc('processar_pos_signup'); } catch (e) { console.warn('[onboarding] processar_pos_signup:', e?.message || e); }
|
||||
|
||||
// welcome email — só no provisionamento NOVO, fire-and-forget (não bloqueia)
|
||||
if (data?.status === 'provisioned') {
|
||||
supabase.functions.invoke('send-welcome-email').catch(() => { /* best-effort */ });
|
||||
}
|
||||
|
||||
await finishAndRedirect(data?.kind || 'therapist');
|
||||
} catch (err) {
|
||||
const msg = String(err?.message || '');
|
||||
|
||||
@@ -80,6 +80,14 @@ function priceFor(p) {
|
||||
return cents;
|
||||
}
|
||||
|
||||
// plano gratuito: por chave (_free) ou preço zero/ausente
|
||||
function isFreePlan(p) {
|
||||
const k = String(p?.plan_key || '').toLowerCase();
|
||||
if (k.endsWith('_free') || k === 'free') return true;
|
||||
const cents = priceFor(p);
|
||||
return cents == null || Number(cents) === 0;
|
||||
}
|
||||
|
||||
async function fetchPricing() {
|
||||
loadingPricing.value = true;
|
||||
try {
|
||||
@@ -481,11 +489,16 @@ onMounted(fetchPricing);
|
||||
</div>
|
||||
|
||||
<div class="mt-4 text-3xl font-semibold leading-none">
|
||||
{{ formatBRLFromCents(priceFor(p)) }}
|
||||
<span class="text-sm font-normal text-[var(--text-color-secondary)]"> /{{ billingInterval === 'month' ? 'mês' : 'ano' }} </span>
|
||||
<template v-if="isFreePlan(p)">
|
||||
Grátis<span class="text-sm font-normal text-[var(--text-color-secondary)]"> para sempre </span>
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ formatBRLFromCents(priceFor(p)) }}
|
||||
<span class="text-sm font-normal text-[var(--text-color-secondary)]"> /{{ billingInterval === 'month' ? 'mês' : 'ano' }} </span>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<div v-if="billingInterval === 'year'" class="text-xs text-emerald-500 mt-1 font-medium">Melhor custo-benefício</div>
|
||||
<div v-if="!isFreePlan(p) && billingInterval === 'year'" class="text-xs text-emerald-500 mt-1 font-medium">Melhor custo-benefício</div>
|
||||
|
||||
<div class="mt-2 text-sm text-[var(--text-color-secondary)] min-h-[44px] leading-relaxed">
|
||||
{{ p.public_description || '—' }}
|
||||
|
||||
Reference in New Issue
Block a user