// Telas: Histórico, Favoritos, Configurações, Paywall, Checkout, Compartilhamento
const { useState: useStateMisc, useEffect: useEffectMisc } = React;
function ListScreen({ t, lang, kind, items, onOpen, emptyText }) {
if (!items.length) {
return (
{kind === 'fav' ? '♡' : '◷'}
{emptyText}
);
}
return (
{items.map((it) => {
const theme = window.THEMES.find(x => x.id === it.theme_id);
const date = new Date(it.created_at || it.viewed_at);
return (
);
})}
);
}
function Settings({ t, lang, setLang, profile, onSignOut, onUpgrade, trialDaysLeft, onEnableNotifications }) {
const [notifStatus, setNotifStatus] = useStateMisc(
'Notification' in window ? Notification.permission : 'unsupported'
);
async function handleEnableNotifications() {
if (notifStatus === 'granted') return;
const result = await Notification.requestPermission();
setNotifStatus(result);
if (result === 'granted' && onEnableNotifications) {
onEnableNotifications();
}
}
const notifLabels = {
granted: { en: '🔔 Notifications enabled', pt: '🔔 Notificações ativadas', es: '🔔 Notificaciones activadas' },
denied: { en: '🔕 Blocked — enable in browser settings', pt: '🔕 Bloqueado — ative nas configurações do navegador', es: '🔕 Bloqueado — activa en configuración del navegador' },
default: { en: '🔔 Enable daily verse notifications', pt: '🔔 Ativar notificações do versículo diário', es: '🔔 Activar notificaciones del versículo diario' },
};
const notifLabel = (notifLabels[notifStatus] || notifLabels.default)[lang] || (notifLabels[notifStatus] || notifLabels.default).en;
return (
{(profile?.name || profile?.email || '?')[0].toUpperCase()}
{profile?.name || profile?.email?.split('@')[0] || '—'}
{profile?.email || ''}
{t.plan}
{profile?.subscription_status === 'active' ? (
<>
{t.sub_active}
{t.sub_until} {profile?.subscription_until ? new Date(profile.subscription_until).toLocaleDateString() : '—'}
>
) : (
<>
{t.trial_active}
{trialDaysLeft} {t.trial_left}
>
)}
{notifStatus !== 'unsupported' && 'Notification' in window && (
)}
);
}
function PlanPicker({ t, plan, onChange }) {
return (
);
}
function Paywall({ t, onSubscribe, onClose, plan, setPlan }) {
return (
✦
{t.paywall_title}
{t.paywall_sub}
{t.paywall_features.map((f, i) => - ✓{f}
)}
);
}
function Checkout({ t, onClose, onConfirm, plan = 'yearly', setPlan }) {
const [card, setCard] = useStateMisc('');
const [exp, setExp] = useStateMisc('');
const [cvc, setCvc] = useStateMisc('');
const [done, setDone] = useStateMisc(false);
const [loading, setLoading] = useStateMisc(false);
const isMonthly = plan === 'monthly';
const planLabel = isMonthly ? t.checkout_plan_monthly : t.checkout_plan_yearly;
const priceLabel = isMonthly ? `${t.plan_monthly_price}${t.plan_per_month}` : `${t.plan_yearly_price}${t.plan_per_year}`;
const totalLabel = isMonthly ? `${t.plan_monthly_price}.00` : `${t.plan_yearly_price}.00`;
function fmt(v) { return v.replace(/\D/g, '').slice(0, 16).replace(/(.{4})/g, '$1 ').trim(); }
function fmtExp(v) { v = v.replace(/\D/g, '').slice(0, 4); return v.length > 2 ? v.slice(0, 2) + '/' + v.slice(2) : v; }
async function submit(e) {
e.preventDefault();
setLoading(true);
await new Promise(r => setTimeout(r, 1100));
setDone(true);
setLoading(false);
if (onConfirm && !done) {
// surface the chosen plan up via onConfirm only on success-cta below
}
}
if (done) {
return (
✦
{t.success_title}
{t.success_sub}
);
}
return (
{t.checkout_title}
{setPlan &&
}
{planLabel}
{t.pricing_trial}
{priceLabel}
);
}
function Share({ t, lang, payload, onClose }) {
const [copied, setCopied] = useStateMisc(false);
if (!payload) return null;
const shareUrl = 'https://mywisdomverse.online';
const callToAction = {
en: '✨ Get your daily Bible verse — free for 7 days',
pt: '✨ Receba seu versículo diário — 7 dias grátis',
es: '✨ Recibe tu versículo diario — 7 días gratis',
}[lang] || '✨ Get your daily Bible verse — free for 7 days';
// Gera o canvas e retorna como Blob
function generateImageBlob() {
return new Promise((resolve) => {
const c = document.createElement('canvas');
c.width = 1080; c.height = 1080;
const ctx = c.getContext('2d');
const g = ctx.createRadialGradient(540, 380, 100, 540, 540, 800);
g.addColorStop(0, '#fbf3df'); g.addColorStop(0.6, '#f1e3c0'); g.addColorStop(1, '#d8bd86');
ctx.fillStyle = g; ctx.fillRect(0, 0, 1080, 1080);
ctx.strokeStyle = 'rgba(122,90,48,0.3)'; ctx.lineWidth = 2;
ctx.strokeRect(60, 60, 960, 960);
ctx.fillStyle = '#7a5a30'; ctx.font = '64px serif'; ctx.textAlign = 'center';
ctx.fillText('✧', 540, 200);
ctx.fillStyle = '#3a2c14';
ctx.font = 'italic 44px "Cormorant Garamond", serif';
const words = payload.text.split(' ');
let line = '', y = 420;
for (const w of words) {
const test = line + w + ' ';
if (ctx.measureText(test).width > 880 && line) {
ctx.fillText(line.trim(), 540, y); y += 60; line = w + ' ';
} else { line = test; }
}
if (line) ctx.fillText(line.trim(), 540, y);
ctx.font = '500 26px "Inter", sans-serif';
ctx.fillStyle = '#7a5a30';
ctx.fillText(payload.ref.toUpperCase(), 540, y + 80);
ctx.strokeStyle = 'rgba(122,90,48,0.35)'; ctx.lineWidth = 1;
ctx.beginPath(); ctx.moveTo(200, y + 120); ctx.lineTo(880, y + 120); ctx.stroke();
ctx.font = '500 20px "Inter", sans-serif';
ctx.fillStyle = 'rgba(122,90,48,0.6)';
ctx.fillText('My Verse', 540, y + 170);
c.toBlob(resolve, 'image/png');
});
}
// Compartilhamento nativo com imagem + link
async function shareNative() {
const isMobile = /Android|iPhone|iPad|iPod/i.test(navigator.userAgent);
if (isMobile && navigator.share) {
// Mobile: tenta share com imagem
try {
const blob = await generateImageBlob();
const file = new File([blob], 'myverse.png', { type: 'image/png' });
const shareData = {
title: 'My Verse',
text: callToAction,
url: shareUrl,
};
if (navigator.canShare && navigator.canShare({ files: [file] })) {
await navigator.share({ ...shareData, files: [file] });
} else {
await navigator.share(shareData);
}
} catch (e) {
if (e.name !== 'AbortError') {
// Fallback: copia texto
navigator.clipboard.writeText(`"${payload.text}" — ${payload.ref}\n\n${callToAction}\n${shareUrl}`).catch(() => {});
setCopied(true);
setTimeout(() => setCopied(false), 1600);
}
}
} else {
// Desktop: copia link para área de transferência
navigator.clipboard.writeText(`"${payload.text}" — ${payload.ref}\n\n${callToAction}\n${shareUrl}`).catch(() => {});
setCopied(true);
setTimeout(() => setCopied(false), 1600);
}
}
// WhatsApp direto (texto + link — sem duplicar)
const whatsappText = `"${payload.text}" — ${payload.ref}\n\n${callToAction}\n${shareUrl}`;
const whatsappUrl = `https://wa.me/?text=${encodeURIComponent(whatsappText)}`;
// Download da imagem
async function downloadImage() {
const blob = await generateImageBlob();
const a = document.createElement('a');
a.download = `versiculo-${payload.ref.replace(/[^a-z0-9]/gi, '_')}.png`;
a.href = URL.createObjectURL(blob); a.click();
URL.revokeObjectURL(a.href);
}
return (
e.stopPropagation()} style={{ width:'100%', maxWidth:320, borderRadius:20, background:'var(--paper)', padding:'24px' }}>
✧
"{payload.text}"
{payload.ref}
{t.share_title}
💬 WhatsApp
);
}
function FavDetail({ lang, item, onClose, onShare }) {
if (!item) return null;
const theme = window.THEMES?.find(x => x.id === item.theme_id);
const themeName = theme?.[lang] || '';
const shareLabel = { en: 'Share', pt: 'Compartilhar', es: 'Compartir' }[lang] || 'Share';
return (
e.stopPropagation()} style={{
background: 'var(--paper)', borderRadius: 20, padding: '28px 24px',
width: '100%', maxWidth: 320, position: 'relative',
boxShadow: '0 8px 40px rgba(30,20,8,0.25)',
}}>
{/* Botão fechar */}
{/* Cartão do versículo */}
{theme &&
{theme.icon}
}
"{item.text}"
{item.verse_ref}
{themeName && (
{themeName}
)}
{/* Divisor */}
{/* Botão compartilhar */}
);
}
Object.assign(window, { ListScreen, Settings, Paywall, Checkout, Share, FavDetail, PlanPicker });