Add permanent access feature
- Added a boolean field `liberado_permanente` to the `usuarios` table. - Updated the RLS policy to allow inserts if `liberado_permanente` is true. - Updated the frontend to show a custom message if the insert is blocked.
This commit is contained in:
parent
f16b060416
commit
b0bbce2637
@ -8,6 +8,7 @@ interface AccessControlResult {
|
||||
motivo: string | null; // mensagem para exibir ao usuário se bloqueado
|
||||
diasRestantesTrial: number;
|
||||
trialExpiraEm: Date | null;
|
||||
adminLiberou: boolean;
|
||||
}
|
||||
|
||||
export function useAccessControl(): AccessControlResult {
|
||||
@ -17,6 +18,7 @@ export function useAccessControl(): AccessControlResult {
|
||||
motivo: null,
|
||||
diasRestantesTrial: 0,
|
||||
trialExpiraEm: null,
|
||||
adminLiberou: false,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
@ -29,14 +31,15 @@ export function useAccessControl(): AccessControlResult {
|
||||
motivo: "Erro ao identificar usuário. Faça login novamente.",
|
||||
diasRestantesTrial: 0,
|
||||
trialExpiraEm: null,
|
||||
adminLiberou: false,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Buscar data de cadastro do usuário
|
||||
// Buscar data de cadastro e liberado_permanente do usuário
|
||||
const { data: usuarios, error: userError } = await supabase
|
||||
.from("usuarios")
|
||||
.select("created_at")
|
||||
.select("created_at, liberado_permanente")
|
||||
.eq("email", userEmail.trim().toLowerCase());
|
||||
|
||||
if (userError || !usuarios || usuarios.length === 0) {
|
||||
@ -46,6 +49,7 @@ export function useAccessControl(): AccessControlResult {
|
||||
motivo: "Erro ao buscar dados do usuário. Tente novamente mais tarde.",
|
||||
diasRestantesTrial: 0,
|
||||
trialExpiraEm: null,
|
||||
adminLiberou: false,
|
||||
});
|
||||
return;
|
||||
}
|
||||
@ -56,6 +60,19 @@ export function useAccessControl(): AccessControlResult {
|
||||
trialExpiraEm.setDate(trialExpiraEm.getDate() + 30);
|
||||
const dentroTrial = agora < trialExpiraEm;
|
||||
const diasRestantes = Math.ceil((trialExpiraEm.getTime() - agora.getTime()) / (1000 * 60 * 60 * 24));
|
||||
const liberadoPermanente = usuarios[0].liberado_permanente === true;
|
||||
|
||||
if (liberadoPermanente) {
|
||||
setResult({
|
||||
loading: false,
|
||||
podeAdicionarTransacao: true,
|
||||
motivo: "Seu acesso foi liberado permanentemente pelo administrador.",
|
||||
diasRestantesTrial: 0,
|
||||
trialExpiraEm,
|
||||
adminLiberou: true,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (dentroTrial) {
|
||||
setResult({
|
||||
@ -64,6 +81,7 @@ export function useAccessControl(): AccessControlResult {
|
||||
motivo: null,
|
||||
diasRestantesTrial: diasRestantes,
|
||||
trialExpiraEm,
|
||||
adminLiberou: false,
|
||||
});
|
||||
return;
|
||||
}
|
||||
@ -82,17 +100,24 @@ export function useAccessControl(): AccessControlResult {
|
||||
motivo: "Erro ao verificar status de pagamento.",
|
||||
diasRestantesTrial: 0,
|
||||
trialExpiraEm,
|
||||
adminLiberou: false,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (pagamentos && pagamentos.length > 0) {
|
||||
const pagamentoMesVigente = pagamentos && pagamentos.some((p: any) => {
|
||||
const pgDate = new Date(p.created_at);
|
||||
return pgDate.getFullYear() === agora.getFullYear() && pgDate.getMonth() === agora.getMonth();
|
||||
});
|
||||
|
||||
if (pagamentoMesVigente) {
|
||||
setResult({
|
||||
loading: false,
|
||||
podeAdicionarTransacao: true,
|
||||
motivo: null,
|
||||
diasRestantesTrial: 0,
|
||||
trialExpiraEm,
|
||||
adminLiberou: false,
|
||||
});
|
||||
return;
|
||||
}
|
||||
@ -101,9 +126,10 @@ export function useAccessControl(): AccessControlResult {
|
||||
loading: false,
|
||||
podeAdicionarTransacao: false,
|
||||
motivo:
|
||||
"Seu período de teste acabou. Para continuar adicionando transações realize o pagamento da assinatura.",
|
||||
"Seu período de teste acabou. Para continuar adicionando transações, realize o pagamento da assinatura.",
|
||||
diasRestantesTrial: 0,
|
||||
trialExpiraEm,
|
||||
adminLiberou: false,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@ -506,6 +506,7 @@ export type Database = {
|
||||
empresa: string | null
|
||||
id: string
|
||||
instancia_zap: string | null
|
||||
liberado_permanente: boolean | null
|
||||
nome: string | null
|
||||
remote_jid: string | null
|
||||
status_instancia: string | null
|
||||
@ -518,6 +519,7 @@ export type Database = {
|
||||
empresa?: string | null
|
||||
id?: string
|
||||
instancia_zap?: string | null
|
||||
liberado_permanente?: boolean | null
|
||||
nome?: string | null
|
||||
remote_jid?: string | null
|
||||
status_instancia?: string | null
|
||||
@ -530,6 +532,7 @@ export type Database = {
|
||||
empresa?: string | null
|
||||
id?: string
|
||||
instancia_zap?: string | null
|
||||
liberado_permanente?: boolean | null
|
||||
nome?: string | null
|
||||
remote_jid?: string | null
|
||||
status_instancia?: string | null
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import Layout from '@/components/layout/Layout';
|
||||
import TransactionsTable from '@/components/dashboard/TransactionsTable';
|
||||
@ -61,10 +62,17 @@ const TransacoesPage = () => {
|
||||
<p className="text-sm text-muted-foreground">
|
||||
Dados de: {formatMonthDisplay(selectedMonth)}
|
||||
</p>
|
||||
{!access.loading && access.podeAdicionarTransacao && access.diasRestantesTrial > 0 && (
|
||||
<div className="mt-1 text-xs text-blue-600 font-medium">
|
||||
{`Você está em período gratuito. ${access.diasRestantesTrial} dia(s) restante(s) de teste.`}
|
||||
</div>
|
||||
{/* Exibe mensagem para trial OU para admin-liberou */}
|
||||
{!access.loading && access.podeAdicionarTransacao && (
|
||||
access.adminLiberou ? (
|
||||
<div className="mt-1 text-xs text-green-600 font-bold">
|
||||
{access.motivo}
|
||||
</div>
|
||||
) : (access.diasRestantesTrial > 0 && (
|
||||
<div className="mt-1 text-xs text-blue-600 font-medium">
|
||||
{`Você está em período gratuito. ${access.diasRestantesTrial} dia(s) restante(s) de teste.`}
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
<MonthFilter
|
||||
@ -73,6 +81,7 @@ const TransacoesPage = () => {
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Mensagem de bloqueio */}
|
||||
{!access.loading && !access.podeAdicionarTransacao && (
|
||||
<div className="bg-yellow-100 border border-yellow-300 text-yellow-800 px-4 py-3 rounded relative mb-4">
|
||||
<span className="font-medium">Atenção:</span> {access.motivo}
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
|
||||
-- Adiciona campo para liberar acesso vitalício/manual pelo admin
|
||||
ALTER TABLE public.usuarios ADD COLUMN IF NOT EXISTS liberado_permanente boolean DEFAULT false;
|
||||
|
||||
-- Atualiza a policy de insert em transacoes para aceitar "liberado_permanente"
|
||||
DROP POLICY IF EXISTS "Permitir inserts apenas com trial ativo ou pagamento aprovado do mês" ON public.transacoes;
|
||||
|
||||
CREATE POLICY "Permitir inserts apenas com trial/pagamento ou liberar permanente"
|
||||
ON public.transacoes
|
||||
FOR INSERT
|
||||
WITH CHECK (
|
||||
EXISTS (SELECT 1 FROM public.usuarios u WHERE u.email = login)
|
||||
AND (
|
||||
-- Caso o admin tenha liberado o usuário permanentemente
|
||||
(SELECT u.liberado_permanente FROM public.usuarios u WHERE u.email = login) = true
|
||||
-- Ou está dentro do período trial (primeiros 30 dias)
|
||||
OR (SELECT NOW() < u.created_at + INTERVAL '30 days' FROM public.usuarios u WHERE u.email = login)
|
||||
-- Ou possui pagamento aprovado para o mês vigente
|
||||
OR EXISTS (
|
||||
SELECT 1 FROM public.pagamentos_mercadopago p
|
||||
WHERE p.payer_email = login
|
||||
AND p.status = 'approved'
|
||||
AND date_trunc('month', p.created_at) = date_trunc('month', NOW())
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
-- Mantém permissões normais nas outras operações
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE ON public.transacoes TO authenticated;
|
||||
Loading…
Reference in New Issue
Block a user