Initial commit: CMS completo com gerenciamento de leads e personalização de tema
This commit is contained in:
110
frontend/src/app/admin/paginas/page.tsx
Normal file
110
frontend/src/app/admin/paginas/page.tsx
Normal file
@@ -0,0 +1,110 @@
|
||||
"use client";
|
||||
|
||||
import Link from 'next/link';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useToast } from '@/contexts/ToastContext';
|
||||
|
||||
interface PageContent {
|
||||
id: string;
|
||||
slug: string;
|
||||
content: any;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
export default function PagesList() {
|
||||
const [pages, setPages] = useState<PageContent[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const { error: showError } = useToast();
|
||||
|
||||
const pageDefinitions = [
|
||||
{
|
||||
title: 'Página Inicial',
|
||||
slug: 'home',
|
||||
desc: 'Banner principal, textos de destaque e chamadas.',
|
||||
icon: 'ri-home-4-line'
|
||||
},
|
||||
{
|
||||
title: 'Sobre Nós',
|
||||
slug: 'sobre',
|
||||
desc: 'História da empresa, missão, visão e valores.',
|
||||
icon: 'ri-team-line'
|
||||
},
|
||||
{
|
||||
title: 'Contato',
|
||||
slug: 'contato',
|
||||
desc: 'Endereço, telefones, emails e horário de funcionamento.',
|
||||
icon: 'ri-contacts-book-line'
|
||||
},
|
||||
];
|
||||
|
||||
useEffect(() => {
|
||||
fetchPages();
|
||||
}, []);
|
||||
|
||||
const fetchPages = async () => {
|
||||
try {
|
||||
const response = await fetch('/api/pages');
|
||||
if (!response.ok) throw new Error('Erro ao carregar páginas');
|
||||
|
||||
const data = await response.json();
|
||||
setPages(data);
|
||||
} catch (err) {
|
||||
showError('Erro ao carregar páginas');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className="flex items-center justify-center h-64">
|
||||
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-primary"></div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="mb-8">
|
||||
<h1 className="text-3xl font-bold font-headline text-secondary dark:text-white mb-2">Gerenciar Páginas</h1>
|
||||
<p className="text-gray-500 dark:text-gray-400">Edite o conteúdo estático das páginas do site.</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
{pageDefinitions.map((pageDef) => {
|
||||
const pageData = pages.find(p => p.slug === pageDef.slug);
|
||||
const lastUpdate = pageData
|
||||
? new Date(pageData.updatedAt).toLocaleDateString('pt-BR')
|
||||
: 'Não configurado';
|
||||
|
||||
return (
|
||||
<div key={pageDef.slug} className="bg-white dark:bg-secondary rounded-2xl border border-gray-200 dark:border-white/10 p-6 shadow-sm hover:shadow-md transition-all group">
|
||||
<div className="flex items-start justify-between mb-4">
|
||||
<div className="w-12 h-12 rounded-xl bg-primary/10 text-primary flex items-center justify-center text-2xl group-hover:scale-110 transition-transform">
|
||||
<i className={pageDef.icon}></i>
|
||||
</div>
|
||||
<span className={`text-xs font-medium px-2 py-1 rounded-lg ${
|
||||
pageData
|
||||
? 'text-green-600 bg-green-100 dark:bg-green-900/30'
|
||||
: 'text-orange-600 bg-orange-100 dark:bg-orange-900/30'
|
||||
}`}>
|
||||
{pageData ? `Atualizado ${lastUpdate}` : 'Não configurado'}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<h3 className="text-xl font-bold text-secondary dark:text-white mb-2">{pageDef.title}</h3>
|
||||
<p className="text-gray-500 dark:text-gray-400 text-sm mb-6 h-10">{pageDef.desc}</p>
|
||||
|
||||
<Link
|
||||
href={`/admin/paginas/${pageDef.slug}`}
|
||||
className="block w-full py-3 text-center rounded-xl border border-gray-200 dark:border-white/10 font-bold text-gray-600 dark:text-gray-300 hover:bg-primary hover:text-white hover:border-primary transition-all"
|
||||
>
|
||||
Editar Conteúdo
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user