import React, { useState } from 'react';
import {
LayoutDashboard,
Settings,
LogOut,
Save,
Monitor,
Box,
Users,
MessageSquare,
Wrench,
Tags,
FileText,
Check,
Eye,
Trash2,
PlusCircle,
Palette,
Briefcase,
Image,
Upload,
Menu as MenuIcon,
Columns,
X,
ArrowLeftRight
} from 'lucide-react';
import { useNavigate } from 'react-router-dom';
import { useData } from '../../contexts/DataContext';
import { Hero } from '../Hero';
import { Header } from '../Header';
import {
ServicesSection,
PackagesSection,
AboutSection,
TeamSection,
TestimonialsSection,
FaqSection,
BlogSection,
SpecialOffersSection,
ClientsSection,
WhyChooseSection,
GallerySection,
StatsSection,
Footer,
BeforeAfterSection
} from '../AppContent';
import { FooterColumn, FooterLink } from '../../types';
const SidebarItem = ({ icon: Icon, label, active, onClick }: any) => (
{label}
);
const InputGroup = ({ label, value, onChange, type = "text", textarea = false, hint }: any) => (
{label}
{hint && {hint} }
{textarea ? (
);
const SectionTextEditor = ({ sectionKey, title = "Textos da Seção" }: { sectionKey: string, title?: string }) => {
const { data, updateData } = useData();
// @ts-ignore
const texts = data.texts[sectionKey];
if (!texts) return null;
const updateText = (field: string, value: string) => {
// @ts-ignore
updateData('texts', {
...data.texts,
[sectionKey]: {
// @ts-ignore
...data.texts[sectionKey],
[field]: value
}
});
};
return (
{title}
{Object.keys(texts).map((key) => (
updateText(key, v)}
textarea={key === 'description' || key === 'subtitle'}
/>
))}
);
}
const Toggle = ({ label, checked, onChange }: any) => (
{label}
onChange(!checked)}
className={`w-12 h-6 rounded-full p-1 transition-colors ${checked ? 'bg-green-500' : 'bg-zinc-700'}`}
>
);
// Mapa de tradução para as chaves de visibilidade
const sectionLabels: Record = {
hero: 'Topo / Início (Hero)',
specialOffers: 'Ofertas Especiais',
about: 'Sobre Nós',
services: 'Serviços',
bigCta: 'Chamada para Ação (Grande)',
packages: 'Pacotes de Serviços',
gallery: 'Galeria de Fotos',
beforeAfter: 'Comparativo Antes/Depois',
stats: 'Estatísticas',
whyChoose: 'Por que Escolher',
testimonials: 'Depoimentos',
team: 'Equipe',
faq: 'Perguntas Frequentes (FAQ)',
blog: 'Blog / Notícias',
contact: 'Formulário de Contato',
clients: 'Logos de Clientes'
};
export const Dashboard: React.FC = () => {
const navigate = useNavigate();
const { data, updateData } = useData();
const [activeSection, setActiveSection] = useState('config'); // 'config' | 'visibility' | 'content-hero' etc.
const [isPreviewOpen, setIsPreviewOpen] = useState(true);
const [isSaved, setIsSaved] = useState(false);
const [newImageUrl, setNewImageUrl] = useState('');
const handleLogout = () => {
localStorage.removeItem('admin_auth');
navigate('/admin');
};
const handleSave = () => {
setIsSaved(true);
setTimeout(() => setIsSaved(false), 2000);
};
const updateSettings = (field: string, value: any) => {
updateData('settings', { ...data.settings, [field]: value });
};
const updateSocial = (field: string, value: string) => {
updateData('settings', { ...data.settings, social: { ...data.settings.social, [field]: value } });
};
const updateVisibility = (section: string, value: boolean) => {
updateData('visibility', { ...data.visibility, [section]: value });
};
const updateArrayItem = (section: string, index: number, field: string, value: any) => {
// @ts-ignore
const newArray = [...data[section]];
newArray[index] = { ...newArray[index], [field]: value };
// @ts-ignore
updateData(section, newArray);
};
const addItem = (section: string, emptyItem: any) => {
// @ts-ignore
const newArray = [...data[section], emptyItem];
// @ts-ignore
updateData(section, newArray);
};
const removeItem = (section: string, index: number) => {
// @ts-ignore
const newArray = data[section].filter((_, i) => i !== index);
// @ts-ignore
updateData(section, newArray);
};
// --- Header Helpers ---
const updateHeaderItem = (index: number, field: string, value: any) => {
const newItems = [...data.header.items];
// @ts-ignore
newItems[index] = { ...newItems[index], [field]: value };
updateData('header', { ...data.header, items: newItems });
};
const addHeaderItem = () => {
const newItems = [...data.header.items, { label: 'Novo Link', href: '#' }];
updateData('header', { ...data.header, items: newItems });
};
const removeHeaderItem = (index: number) => {
const newItems = data.header.items.filter((_, i) => i !== index);
updateData('header', { ...data.header, items: newItems });
};
const updateCtaButton = (field: string, value: any) => {
updateData('header', { ...data.header, ctaButton: { ...data.header.ctaButton, [field]: value }});
}
// --- Footer Helpers ---
const updateFooterColumn = (index: number, field: string, value: any) => {
const newColumns = [...data.footer.columns];
// @ts-ignore
newColumns[index] = { ...newColumns[index], [field]: value };
updateData('footer', { ...data.footer, columns: newColumns });
};
const removeFooterColumn = (index: number) => {
const newColumns = data.footer.columns.filter((_, i) => i !== index);
updateData('footer', { ...data.footer, columns: newColumns });
};
const addFooterColumn = () => {
const newCol: FooterColumn = { id: `col_${Date.now()}`, title: 'Nova Coluna', type: 'custom', links: [] };
const newColumns = [...data.footer.columns, newCol];
updateData('footer', { ...data.footer, columns: newColumns });
};
const updateFooterLink = (colIndex: number, linkIndex: number, field: string, value: string) => {
const newColumns = [...data.footer.columns];
const col = newColumns[colIndex];
if (col.links) {
const newLinks = [...col.links];
// @ts-ignore
newLinks[linkIndex] = { ...newLinks[linkIndex], [field]: value };
col.links = newLinks;
updateData('footer', { ...data.footer, columns: newColumns });
}
};
const addFooterLink = (colIndex: number) => {
const newColumns = [...data.footer.columns];
const col = newColumns[colIndex];
if (!col.links) col.links = [];
col.links.push({ label: 'Novo Link', href: '#' });
updateData('footer', { ...data.footer, columns: newColumns });
};
const removeFooterLink = (colIndex: number, linkIndex: number) => {
const newColumns = [...data.footer.columns];
const col = newColumns[colIndex];
if (col.links) {
col.links = col.links.filter((_, i) => i !== linkIndex);
updateData('footer', { ...data.footer, columns: newColumns });
}
}
// Função específica para Upload de Imagens na Galeria
const handleImageUpload = (e: React.ChangeEvent) => {
const files = e.target.files;
if (files && files.length > 0) {
const promises: Promise[] = [];
Array.from(files).forEach(file => {
const reader = new FileReader();
const promise = new Promise((resolve) => {
reader.onload = (e) => {
if (e.target?.result) resolve(e.target.result as string);
};
});
reader.readAsDataURL(file as Blob);
promises.push(promise);
});
Promise.all(promises).then(base64Images => {
// @ts-ignore
const updatedGallery = [...data.gallery, ...base64Images];
updateData('gallery', updatedGallery);
});
}
};
const handleAddUrlToGallery = () => {
if (newImageUrl) {
// @ts-ignore
const updatedGallery = [...data.gallery, newImageUrl];
updateData('gallery', updatedGallery);
setNewImageUrl('');
}
};
const renderEditor = () => {
switch(activeSection) {
case 'config':
return (
Configurações Gerais
Identidade Visual
updateSettings('siteName', v)} />
updateSettings('primaryColor', v)} type="color" />
updateSettings('primaryColor', v)} />
updateSettings('logoUrl', v)} hint="Deixe vazio para usar texto" />
updateSettings('faviconUrl', v)} />
Contato & Social
updateSettings('whatsappNumber', v)} hint="Ex: 5511999999999" />
updateSettings('contactPhoneDisplay', v)} />
updateSettings('contactEmail', v)} />
updateSettings('address', v)} />
Redes Sociais (Deixe vazio para ocultar)
updateSocial('instagram', v)} />
updateSocial('facebook', v)} />
updateSocial('twitter', v)} />
updateSocial('youtube', v)} />
updateSocial('linkedin', v)} />
);
case 'visibility':
return (
Controle de Seções (Ativar/Desativar)
{Object.keys(data.visibility).map((key) => (
updateVisibility(key, v)}
/>
))}
);
case 'header':
return (
Menu & Cabeçalho
Botão de Destaque (CTA)
updateCtaButton('show', v)} />
{data.header.ctaButton.show && (
updateCtaButton('text', v)} />
updateCtaButton('url', v)} hint="Deixe vazio para abrir o WhatsApp" />
)}
{data.header.items.map((item, idx) => (
))}
);
case 'footer':
return (
Configuração do Rodapé
updateData('footer', { ...data.footer, description: v })} textarea />
Estrutura de Colunas
Adicionar Coluna
{data.footer.columns.map((col, idx) => (
removeFooterColumn(idx)} className="absolute top-4 right-4 text-red-500 hover:text-red-400">
updateFooterColumn(idx, 'title', v)} />
Tipo de Conteúdo
updateFooterColumn(idx, 'type', e.target.value)}
>
Links Personalizados
Lista de Serviços (Automático)
Horário de Atendimento
{col.type === 'custom' && (
Links da Coluna
addFooterLink(idx)} className="text-xs text-primary hover:text-white">+ Adicionar Link
)}
))}
);
case 'hero':
return (
Editar Início (Hero)
updateData('hero', {...data.hero, title: v})} />
updateData('hero', {...data.hero, subtitle: v})} textarea />
updateData('hero', {...data.hero, buttonText: v})} />
updateData('hero', {...data.hero, bgImage: v})} />
);
case 'services':
return (
Lista de Serviços
addItem('services', { id: Date.now(), title: 'Novo Serviço', description: 'Descrição', image: '' })} className="flex items-center gap-2 text-primary hover:text-white transition-colors text-sm">
Adicionar Serviço
{data.services.map((service, idx) => (
removeItem('services', idx)} className="absolute top-4 right-4 text-red-500 opacity-0 group-hover:opacity-100 transition-opacity">
updateArrayItem('services', idx, 'title', v)} />
updateArrayItem('services', idx, 'description', v)} textarea />
updateArrayItem('services', idx, 'image', v)} />
))}
);
case 'offers':
return (
Lista de Ofertas (Pneus)
addItem('specialOffers', { id: Date.now(), title: 'Novo Pneu', image: '', price: 'R$ 0,00', installment: '', rating: 5, reviews: 0, specs: { fuel: 'C', grip: 'C', noise: '70dB' } })} className="flex items-center gap-2 text-primary hover:text-white transition-colors text-sm">
Adicionar Pneu
{data.specialOffers.map((offer, idx) => (
removeItem('specialOffers', idx)} className="absolute top-4 right-4 text-red-500 opacity-0 group-hover:opacity-100 transition-opacity">
updateArrayItem('specialOffers', idx, 'title', v)} />
updateArrayItem('specialOffers', idx, 'price', v)} />
updateArrayItem('specialOffers', idx, 'installment', v)} />
updateArrayItem('specialOffers', idx, 'image', v)} />
{
const newSpecs = { ...offer.specs, fuel: v };
updateArrayItem('specialOffers', idx, 'specs', newSpecs);
}} />
{
const newSpecs = { ...offer.specs, grip: v };
updateArrayItem('specialOffers', idx, 'specs', newSpecs);
}} />
{
const newSpecs = { ...offer.specs, noise: v };
updateArrayItem('specialOffers', idx, 'specs', newSpecs);
}} />
))}
);
case 'packages':
return (
Lista de Pacotes
addItem('packages', { name: 'Novo Pacote', price: 0, features: [], recommended: false })} className="flex items-center gap-2 text-primary hover:text-white transition-colors text-sm">
Adicionar Pacote
{data.packages.map((pkg, idx) => (
removeItem('packages', idx)} className="absolute top-4 right-4 text-red-500 opacity-0 group-hover:opacity-100 transition-opacity">
updateArrayItem('packages', idx, 'name', v)} />
updateArrayItem('packages', idx, 'price', v)} />
Itens (Separar por vírgula)
updateArrayItem('packages', idx, 'recommended', v)} />
))}
);
case 'gallery':
return (
Galeria de Fotos
{data.gallery.map((img, idx) => (
removeItem('gallery', idx)}
className="bg-red-500 hover:bg-red-600 text-white p-2 rounded-full transform hover:scale-110 transition-all"
>
))}
);
// NOVA SEÇÃO NO EDITOR
case 'beforeAfter':
return (
Comparativo Antes e Depois
Itens do Comparativo
addItem('beforeAfter', { id: Date.now(), title: "Novo Item", imageBefore: "", imageAfter: "" })} className="text-sm text-green-500 hover:text-green-400 flex items-center gap-1"> Adicionar
{data.beforeAfter.map((item, idx) => (
removeItem('beforeAfter', idx)} className="absolute top-4 right-4 text-red-500 hover:text-red-400">
updateArrayItem('beforeAfter', idx, 'title', v)} />
updateArrayItem('beforeAfter', idx, 'imageBefore', v)} />
updateArrayItem('beforeAfter', idx, 'imageAfter', v)} />
))}
);
case 'team':
return (
Lista da Equipe
addItem('team', { name: 'Nome', role: 'Cargo', image: '' })} className="flex items-center gap-2 text-primary hover:text-white transition-colors text-sm">
Adicionar Membro
{data.team.map((member, idx) => (
removeItem('team', idx)} className="absolute top-4 right-4 text-red-500 opacity-0 group-hover:opacity-100 transition-opacity">
updateArrayItem('team', idx, 'name', v)} />
updateArrayItem('team', idx, 'role', v)} />
updateArrayItem('team', idx, 'image', v)} />
))}
);
case 'faq':
return (
Lista de Perguntas
addItem('faqs', { question: 'Pergunta', answer: 'Resposta' })} className="flex items-center gap-2 text-primary hover:text-white transition-colors text-sm">
Adicionar FAQ
{data.faqs.map((faq, idx) => (
removeItem('faqs', idx)} className="absolute top-4 right-4 text-red-500 opacity-0 group-hover:opacity-100 transition-opacity">
updateArrayItem('faqs', idx, 'question', v)} />
updateArrayItem('faqs', idx, 'answer', v)} textarea />
))}
);
case 'clients':
return (
Logos de Clientes
{data.clients.map((client, idx) => (
updateArrayItem('clients', idx, 'name', v)} />
updateArrayItem('clients', idx, 'url', v)} hint="Use PNG transparente" />
))}
);
case 'testimonials':
return (
Lista de Depoimentos
{/* Nota: em uma implementação completa, adicionar botão para novo depoimento */}
{data.testimonials.map((t, idx) => (
updateArrayItem('testimonials', idx, 'name', v)} />
updateArrayItem('testimonials', idx, 'text', v)} textarea />
updateArrayItem('testimonials', idx, 'image', v)} />
))}
);
case 'about':
return (
Itens "O Que Prometemos"
{data.promises.map((item, idx) => (
updateArrayItem('promises', idx, 'title', v)} />
updateArrayItem('promises', idx, 'description', v)} textarea />
))}
);
case 'blog':
return (
{/* Lista de posts não editável aqui para simplificar, foca nos títulos */}
);
default:
return Selecione uma opção no menu lateral.
;
}
};
const renderPreview = () => {
switch(activeSection) {
case 'hero': return ;
case 'header': return (
<>
{/* Spacer for fixed header */}
Conteúdo do Site...
>
);
case 'footer': return ;
case 'services': return ;
case 'offers': return ;
case 'packages': return ;
case 'about': return ;
case 'beforeAfter': return ; // Novo Preview
case 'team': return ;
case 'testimonials': return ;
case 'faq': return ;
case 'blog': return ;
case 'clients': return ;
case 'gallery': return ;
default: return Preview Geral
;
}
}
return (
{/* Sidebar */}
setActiveSection('config')} />
setActiveSection('header')} />
setActiveSection('footer')} />
setActiveSection('visibility')} />
Conteúdo do Site
setActiveSection('hero')} />
setActiveSection('beforeAfter')} />
setActiveSection('offers')} />
setActiveSection('services')} />
setActiveSection('about')} />
setActiveSection('packages')} />
setActiveSection('gallery')} />
setActiveSection('team')} />
setActiveSection('testimonials')} />
setActiveSection('faq')} />
setActiveSection('blog')} />
setActiveSection('clients')} />
Sair
{/* Main Content */}
{/* Topbar */}
Editando: {activeSection === 'hero' ? 'Início' : activeSection === 'offers' ? 'Ofertas' : activeSection === 'about' ? 'Sobre' : activeSection === 'header' ? 'Menu' : activeSection === 'footer' ? 'Rodapé' : sectionLabels[activeSection] || activeSection}
setIsPreviewOpen(!isPreviewOpen)}
className={`flex items-center gap-2 px-3 py-1.5 rounded text-sm font-medium border ${isPreviewOpen ? 'bg-primary/10 border-primary text-primary' : 'border-zinc-700 text-gray-400'}`}
>
{isPreviewOpen ? 'Ocultar Preview' : 'Ver Preview'}
{isSaved ? : }
{isSaved ? 'Salvo!' : 'Publicar Alterações'}
{/* Editor Area */}
{/* Form Side */}
{renderEditor()}
{/* Preview Side */}
{isPreviewOpen && (
Preview em Tempo Real
{/* Scale hack to make desktop preview fit better */}
{renderPreview()}
)}
);
};