@@ -54,6 +54,8 @@ import {
5454 EllipsisVertical ,
5555 Lightbulb ,
5656 CircleCheck ,
57+ Bell ,
58+ BellOff ,
5759} from "lucide-react" ;
5860import {
5961 ResponsiveContainer ,
@@ -87,6 +89,7 @@ import {
8789} from "./cloudAuth" ;
8890import { carregarTudo , sincronizar , migrarLocalParaNuvem } from "./cloudData" ;
8991import { gerarCodigoTelegram , statusTelegram , desconectarTelegram , BOT_URL , BOT_USERNAME } from "./telegramLink" ;
92+ import { suportePush , assinaturaAtual , ativarPush , desativarPush } from "./push" ;
9093import {
9194 temAutenticadorPlataforma ,
9295 registrarBiometria ,
@@ -3086,6 +3089,90 @@ const NAV_EMPRESA = [
30863089// Aba "Minha Conta": mostra quem está logado, ONDE os dados ficam (nuvem x
30873090// aparelho) e o status do Telegram. Ajuda a entender por que o saldo pode
30883091// parecer diferente entre o computador e o celular.
3092+ // Cartão de notificações push da aba Conta: liga/desliga neste aparelho.
3093+ function CartaoNotificacoes ( { userId, showToast } ) {
3094+ const suporte = suportePush ( ) ;
3095+ const [ ativa , setAtiva ] = useState ( undefined ) ; // undefined=carregando
3096+ const [ ocupado , setOcupado ] = useState ( false ) ;
3097+
3098+ useEffect ( ( ) => {
3099+ let vivo = true ;
3100+ assinaturaAtual ( )
3101+ . then ( ( s ) => vivo && setAtiva ( ! ! s ) )
3102+ . catch ( ( ) => vivo && setAtiva ( false ) ) ;
3103+ return ( ) => {
3104+ vivo = false ;
3105+ } ;
3106+ } , [ ] ) ;
3107+
3108+ async function alternar ( ) {
3109+ if ( ocupado ) return ;
3110+ setOcupado ( true ) ;
3111+ try {
3112+ if ( ativa ) {
3113+ await desativarPush ( ) ;
3114+ setAtiva ( false ) ;
3115+ showToast ?. ( "Notificações desligadas neste aparelho." ) ;
3116+ } else {
3117+ await ativarPush ( userId ) ;
3118+ setAtiva ( true ) ;
3119+ showToast ?. ( "Notificações ativadas! 🔔" ) ;
3120+ }
3121+ } catch ( e ) {
3122+ showToast ?. ( e . message || "Não deu certo. Tente de novo." , true , 6000 ) ;
3123+ } finally {
3124+ setOcupado ( false ) ;
3125+ }
3126+ }
3127+
3128+ const descricao =
3129+ suporte === "ios-precisa-instalar"
3130+ ? "No iPhone, primeiro instale o app na tela de início (veja em Dicas do app)."
3131+ : suporte === "bloqueado"
3132+ ? "As notificações estão bloqueadas nas configurações do navegador."
3133+ : suporte === "sem-suporte"
3134+ ? "Este navegador não aceita notificações."
3135+ : ativa === undefined
3136+ ? "Verificando..."
3137+ : ativa
3138+ ? "Ativas neste aparelho ✅ — contas a vencer e lembrete de anotar os gastos."
3139+ : "Avisa das contas a vencer e, de tempos em tempos, lembra de anotar os gastos." ;
3140+
3141+ return (
3142+ < div className = "rounded-2xl border border-slate-200 bg-white p-5 dark:border-slate-800 dark:bg-slate-900" >
3143+ < div className = "flex items-center justify-between gap-3" >
3144+ < div >
3145+ < h3 className = "text-sm font-bold text-slate-700 dark:text-slate-200" >
3146+ Notificações no celular
3147+ </ h3 >
3148+ < p className = "mt-0.5 text-sm text-slate-400" > { descricao } </ p >
3149+ </ div >
3150+ { suporte === "ok" && ativa !== undefined && (
3151+ < button
3152+ onClick = { alternar }
3153+ disabled = { ocupado }
3154+ className = {
3155+ "flex shrink-0 items-center gap-2 rounded-xl px-3 py-2 text-sm font-medium transition disabled:opacity-50 " +
3156+ ( ativa
3157+ ? "bg-slate-100 text-slate-600 hover:bg-slate-200 dark:bg-slate-800 dark:text-slate-300 dark:hover:bg-slate-700"
3158+ : "bg-emerald-50 text-emerald-700 hover:bg-emerald-100 dark:bg-emerald-950/50 dark:text-emerald-300 dark:hover:bg-emerald-950" )
3159+ }
3160+ >
3161+ { ocupado ? (
3162+ < Loader2 size = { 15 } className = "animate-spin" />
3163+ ) : ativa ? (
3164+ < BellOff size = { 15 } />
3165+ ) : (
3166+ < Bell size = { 15 } />
3167+ ) }
3168+ { ativa ? "Desativar" : "Ativar" }
3169+ </ button >
3170+ ) }
3171+ </ div >
3172+ </ div >
3173+ ) ;
3174+ }
3175+
30893176function PaginaConta ( { login, sessao, userId, onConectarTelegram, onLimparDados, onSair, showToast, onVerTour } ) {
30903177 const email = sessao ?. user ?. email || null ;
30913178 const naNuvem = ! ! sessao ;
@@ -3193,6 +3280,9 @@ function PaginaConta({ login, sessao, userId, onConectarTelegram, onLimparDados,
31933280 </ div >
31943281 </ div >
31953282
3283+ { /* Notificações push — só faz sentido logado na nuvem */ }
3284+ { userId && < CartaoNotificacoes userId = { userId } showToast = { showToast } /> }
3285+
31963286 { /* Explicação do saldo diferente entre aparelhos */ }
31973287 < div className = "flex items-start gap-3 rounded-2xl border border-amber-200 bg-amber-50 p-4 text-sm text-amber-800 dark:border-amber-900/60 dark:bg-amber-950/40 dark:text-amber-200" >
31983288 < AlertTriangle size = { 18 } className = "mt-0.5 shrink-0" />
0 commit comments