Run SQL to create tables and policies
This commit executes the provided SQL script to create the necessary tables (`faqs`, `faq_feedback`, `contatos`) and associated policies for the help system, as reviewed by the user. It also creates a storage bucket for contact form attachments.
This commit is contained in:
parent
1d22b504a0
commit
c323023e28
@ -75,7 +75,7 @@ const ContactForm = ({ onBack }: ContactFormProps) => {
|
|||||||
|
|
||||||
// Salvar contato no banco
|
// Salvar contato no banco
|
||||||
const { error } = await supabase
|
const { error } = await supabase
|
||||||
.from('contatos')
|
.from('contatos' as any)
|
||||||
.insert({
|
.insert({
|
||||||
assunto: formData.assunto,
|
assunto: formData.assunto,
|
||||||
motivo: formData.motivo,
|
motivo: formData.motivo,
|
||||||
|
|||||||
@ -29,13 +29,13 @@ const FAQList = () => {
|
|||||||
const loadFAQs = async () => {
|
const loadFAQs = async () => {
|
||||||
try {
|
try {
|
||||||
const { data, error } = await supabase
|
const { data, error } = await supabase
|
||||||
.from('faqs')
|
.from('faqs' as any)
|
||||||
.select('*')
|
.select('*')
|
||||||
.eq('ativo', true)
|
.eq('ativo', true)
|
||||||
.order('created_at', { ascending: false });
|
.order('created_at', { ascending: false });
|
||||||
|
|
||||||
if (error) throw error;
|
if (error) throw error;
|
||||||
setFaqs(data || []);
|
setFaqs((data as FAQ[]) || []);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Erro ao carregar FAQs:', error);
|
console.error('Erro ao carregar FAQs:', error);
|
||||||
toast({
|
toast({
|
||||||
@ -61,7 +61,7 @@ const FAQList = () => {
|
|||||||
const handleFeedback = async (faqId: string, helpful: boolean) => {
|
const handleFeedback = async (faqId: string, helpful: boolean) => {
|
||||||
try {
|
try {
|
||||||
const { error } = await supabase
|
const { error } = await supabase
|
||||||
.from('faq_feedback')
|
.from('faq_feedback' as any)
|
||||||
.insert({
|
.insert({
|
||||||
faq_id: faqId,
|
faq_id: faqId,
|
||||||
helpful: helpful,
|
helpful: helpful,
|
||||||
|
|||||||
@ -20,10 +20,11 @@ const HelpIcon = () => {
|
|||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="icon"
|
size="icon"
|
||||||
className="fixed bottom-6 right-6 h-14 w-14 rounded-full shadow-lg hover:shadow-xl transition-all z-50 bg-blue-600 text-white hover:bg-blue-700 border-0"
|
className="fixed bottom-6 right-6 h-16 w-16 rounded-full shadow-lg hover:shadow-xl transition-all z-50 bg-blue-600 text-white hover:bg-blue-700 border-0 flex flex-col items-center justify-center p-2"
|
||||||
onClick={() => setIsOpen(true)}
|
onClick={() => setIsOpen(true)}
|
||||||
>
|
>
|
||||||
<HelpCircle className="h-6 w-6" />
|
<HelpCircle className="h-6 w-6 mb-1" />
|
||||||
|
<span className="text-xs font-medium">Ajuda</span>
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
<Dialog open={isOpen} onOpenChange={setIsOpen}>
|
||||||
|
|||||||
@ -159,6 +159,39 @@ export type Database = {
|
|||||||
}
|
}
|
||||||
Relationships: []
|
Relationships: []
|
||||||
}
|
}
|
||||||
|
contatos: {
|
||||||
|
Row: {
|
||||||
|
anexo_url: string | null
|
||||||
|
assunto: string
|
||||||
|
created_at: string
|
||||||
|
id: string
|
||||||
|
mensagem: string
|
||||||
|
motivo: string
|
||||||
|
status: string
|
||||||
|
user_id: string | null
|
||||||
|
}
|
||||||
|
Insert: {
|
||||||
|
anexo_url?: string | null
|
||||||
|
assunto: string
|
||||||
|
created_at?: string
|
||||||
|
id?: string
|
||||||
|
mensagem: string
|
||||||
|
motivo: string
|
||||||
|
status?: string
|
||||||
|
user_id?: string | null
|
||||||
|
}
|
||||||
|
Update: {
|
||||||
|
anexo_url?: string | null
|
||||||
|
assunto?: string
|
||||||
|
created_at?: string
|
||||||
|
id?: string
|
||||||
|
mensagem?: string
|
||||||
|
motivo?: string
|
||||||
|
status?: string
|
||||||
|
user_id?: string | null
|
||||||
|
}
|
||||||
|
Relationships: []
|
||||||
|
}
|
||||||
conversas_zap: {
|
conversas_zap: {
|
||||||
Row: {
|
Row: {
|
||||||
created_at: string
|
created_at: string
|
||||||
@ -264,6 +297,65 @@ export type Database = {
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
faq_feedback: {
|
||||||
|
Row: {
|
||||||
|
created_at: string
|
||||||
|
faq_id: string
|
||||||
|
helpful: boolean
|
||||||
|
id: string
|
||||||
|
user_id: string | null
|
||||||
|
}
|
||||||
|
Insert: {
|
||||||
|
created_at?: string
|
||||||
|
faq_id: string
|
||||||
|
helpful: boolean
|
||||||
|
id?: string
|
||||||
|
user_id?: string | null
|
||||||
|
}
|
||||||
|
Update: {
|
||||||
|
created_at?: string
|
||||||
|
faq_id?: string
|
||||||
|
helpful?: boolean
|
||||||
|
id?: string
|
||||||
|
user_id?: string | null
|
||||||
|
}
|
||||||
|
Relationships: [
|
||||||
|
{
|
||||||
|
foreignKeyName: "faq_feedback_faq_id_fkey"
|
||||||
|
columns: ["faq_id"]
|
||||||
|
isOneToOne: false
|
||||||
|
referencedRelation: "faqs"
|
||||||
|
referencedColumns: ["id"]
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
faqs: {
|
||||||
|
Row: {
|
||||||
|
ativo: boolean
|
||||||
|
created_at: string
|
||||||
|
id: string
|
||||||
|
imagem_url: string | null
|
||||||
|
pergunta: string
|
||||||
|
resposta: string
|
||||||
|
}
|
||||||
|
Insert: {
|
||||||
|
ativo?: boolean
|
||||||
|
created_at?: string
|
||||||
|
id?: string
|
||||||
|
imagem_url?: string | null
|
||||||
|
pergunta: string
|
||||||
|
resposta: string
|
||||||
|
}
|
||||||
|
Update: {
|
||||||
|
ativo?: boolean
|
||||||
|
created_at?: string
|
||||||
|
id?: string
|
||||||
|
imagem_url?: string | null
|
||||||
|
pergunta?: string
|
||||||
|
resposta?: string
|
||||||
|
}
|
||||||
|
Relationships: []
|
||||||
|
}
|
||||||
faturas_cartao: {
|
faturas_cartao: {
|
||||||
Row: {
|
Row: {
|
||||||
ano: number
|
ano: number
|
||||||
|
|||||||
@ -57,12 +57,12 @@ const AdminFAQ = () => {
|
|||||||
const loadFAQs = async () => {
|
const loadFAQs = async () => {
|
||||||
try {
|
try {
|
||||||
const { data, error } = await supabase
|
const { data, error } = await supabase
|
||||||
.from('faqs')
|
.from('faqs' as any)
|
||||||
.select('*')
|
.select('*')
|
||||||
.order('created_at', { ascending: false });
|
.order('created_at', { ascending: false });
|
||||||
|
|
||||||
if (error) throw error;
|
if (error) throw error;
|
||||||
setFaqs(data || []);
|
setFaqs((data as FAQ[]) || []);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Erro ao carregar FAQs:', error);
|
console.error('Erro ao carregar FAQs:', error);
|
||||||
toast({
|
toast({
|
||||||
@ -78,7 +78,7 @@ const AdminFAQ = () => {
|
|||||||
const loadStats = async () => {
|
const loadStats = async () => {
|
||||||
try {
|
try {
|
||||||
const { data, error } = await supabase
|
const { data, error } = await supabase
|
||||||
.from('faq_feedback')
|
.from('faq_feedback' as any)
|
||||||
.select(`
|
.select(`
|
||||||
faq_id,
|
faq_id,
|
||||||
helpful,
|
helpful,
|
||||||
@ -128,7 +128,7 @@ const AdminFAQ = () => {
|
|||||||
try {
|
try {
|
||||||
if (editingFaq) {
|
if (editingFaq) {
|
||||||
const { error } = await supabase
|
const { error } = await supabase
|
||||||
.from('faqs')
|
.from('faqs' as any)
|
||||||
.update(formData)
|
.update(formData)
|
||||||
.eq('id', editingFaq.id);
|
.eq('id', editingFaq.id);
|
||||||
|
|
||||||
@ -136,7 +136,7 @@ const AdminFAQ = () => {
|
|||||||
toast({ title: "FAQ atualizado com sucesso!" });
|
toast({ title: "FAQ atualizado com sucesso!" });
|
||||||
} else {
|
} else {
|
||||||
const { error } = await supabase
|
const { error } = await supabase
|
||||||
.from('faqs')
|
.from('faqs' as any)
|
||||||
.insert(formData);
|
.insert(formData);
|
||||||
|
|
||||||
if (error) throw error;
|
if (error) throw error;
|
||||||
@ -171,7 +171,7 @@ const AdminFAQ = () => {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const { error } = await supabase
|
const { error } = await supabase
|
||||||
.from('faqs')
|
.from('faqs' as any)
|
||||||
.delete()
|
.delete()
|
||||||
.eq('id', id);
|
.eq('id', id);
|
||||||
|
|
||||||
@ -191,7 +191,7 @@ const AdminFAQ = () => {
|
|||||||
const handleToggleActive = async (id: string, ativo: boolean) => {
|
const handleToggleActive = async (id: string, ativo: boolean) => {
|
||||||
try {
|
try {
|
||||||
const { error } = await supabase
|
const { error } = await supabase
|
||||||
.from('faqs')
|
.from('faqs' as any)
|
||||||
.update({ ativo: !ativo })
|
.update({ ativo: !ativo })
|
||||||
.eq('id', id);
|
.eq('id', id);
|
||||||
|
|
||||||
@ -251,7 +251,7 @@ const AdminFAQ = () => {
|
|||||||
<div className="truncate">{faq.pergunta}</div>
|
<div className="truncate">{faq.pergunta}</div>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<Badge variant={faq.ativo ? "success" : "secondary"}>
|
<Badge variant={faq.ativo ? "default" : "secondary"}>
|
||||||
{faq.ativo ? 'Ativo' : 'Inativo'}
|
{faq.ativo ? 'Ativo' : 'Inativo'}
|
||||||
</Badge>
|
</Badge>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
|||||||
@ -0,0 +1,73 @@
|
|||||||
|
|
||||||
|
-- Criar tabela para FAQs (Perguntas Frequentes)
|
||||||
|
CREATE TABLE public.faqs (
|
||||||
|
id UUID NOT NULL DEFAULT gen_random_uuid() PRIMARY KEY,
|
||||||
|
pergunta TEXT NOT NULL,
|
||||||
|
resposta TEXT NOT NULL,
|
||||||
|
imagem_url TEXT,
|
||||||
|
ativo BOOLEAN NOT NULL DEFAULT true,
|
||||||
|
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now()
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Criar tabela para feedback dos FAQs
|
||||||
|
CREATE TABLE public.faq_feedback (
|
||||||
|
id UUID NOT NULL DEFAULT gen_random_uuid() PRIMARY KEY,
|
||||||
|
faq_id UUID NOT NULL REFERENCES public.faqs(id) ON DELETE CASCADE,
|
||||||
|
helpful BOOLEAN NOT NULL,
|
||||||
|
user_id UUID REFERENCES auth.users(id),
|
||||||
|
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now()
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Criar tabela para contatos/mensagens de suporte
|
||||||
|
CREATE TABLE public.contatos (
|
||||||
|
id UUID NOT NULL DEFAULT gen_random_uuid() PRIMARY KEY,
|
||||||
|
user_id UUID REFERENCES auth.users(id),
|
||||||
|
assunto TEXT NOT NULL,
|
||||||
|
motivo TEXT NOT NULL,
|
||||||
|
mensagem TEXT NOT NULL,
|
||||||
|
anexo_url TEXT,
|
||||||
|
status TEXT NOT NULL DEFAULT 'pendente',
|
||||||
|
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now()
|
||||||
|
);
|
||||||
|
|
||||||
|
-- Criar bucket para anexos de contato
|
||||||
|
INSERT INTO storage.buckets (id, name, public)
|
||||||
|
VALUES ('anexos-contato', 'anexos-contato', true);
|
||||||
|
|
||||||
|
-- Política para permitir upload de anexos pelos usuários autenticados
|
||||||
|
CREATE POLICY "Usuarios podem fazer upload de anexos"
|
||||||
|
ON storage.objects FOR INSERT
|
||||||
|
WITH CHECK (bucket_id = 'anexos-contato' AND auth.role() = 'authenticated');
|
||||||
|
|
||||||
|
-- Política para permitir visualização pública dos anexos
|
||||||
|
CREATE POLICY "Anexos são públicos para visualização"
|
||||||
|
ON storage.objects FOR SELECT
|
||||||
|
USING (bucket_id = 'anexos-contato');
|
||||||
|
|
||||||
|
-- Habilitar RLS nas tabelas
|
||||||
|
ALTER TABLE public.faqs ENABLE ROW LEVEL SECURITY;
|
||||||
|
ALTER TABLE public.faq_feedback ENABLE ROW LEVEL SECURITY;
|
||||||
|
ALTER TABLE public.contatos ENABLE ROW LEVEL SECURITY;
|
||||||
|
|
||||||
|
-- Políticas para FAQs (todos podem ver FAQs ativos)
|
||||||
|
CREATE POLICY "Qualquer um pode ver FAQs ativos"
|
||||||
|
ON public.faqs FOR SELECT
|
||||||
|
USING (ativo = true);
|
||||||
|
|
||||||
|
-- Políticas para feedback (usuários autenticados podem dar feedback)
|
||||||
|
CREATE POLICY "Usuarios autenticados podem dar feedback"
|
||||||
|
ON public.faq_feedback FOR INSERT
|
||||||
|
WITH CHECK (auth.role() = 'authenticated');
|
||||||
|
|
||||||
|
CREATE POLICY "Usuarios podem ver feedbacks"
|
||||||
|
ON public.faq_feedback FOR SELECT
|
||||||
|
USING (true);
|
||||||
|
|
||||||
|
-- Políticas para contatos (usuários podem criar e ver seus próprios contatos)
|
||||||
|
CREATE POLICY "Usuarios podem criar contatos"
|
||||||
|
ON public.contatos FOR INSERT
|
||||||
|
WITH CHECK (auth.role() = 'authenticated');
|
||||||
|
|
||||||
|
CREATE POLICY "Usuarios podem ver seus contatos"
|
||||||
|
ON public.contatos FOR SELECT
|
||||||
|
USING (user_id = auth.uid());
|
||||||
Loading…
Reference in New Issue
Block a user