feat: Add dynamic contact info and social media settings
This commit is contained in:
@@ -93,5 +93,14 @@ model Settings {
|
||||
id String @id @default(cuid())
|
||||
showPartnerBadge Boolean @default(false)
|
||||
partnerName String @default("Coca-Cola")
|
||||
// Informações de Contato
|
||||
address String? // Endereço completo
|
||||
phone String? // Telefone
|
||||
email String? // Email
|
||||
// Redes Sociais
|
||||
instagram String? // URL Instagram
|
||||
linkedin String? // URL LinkedIn
|
||||
facebook String? // URL Facebook
|
||||
whatsapp String? // Número WhatsApp
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
@@ -22,6 +22,14 @@ export default function ConfiguracoesPage() {
|
||||
const [customColor, setCustomColor] = useState('#FF6B35');
|
||||
const [showPartnerBadge, setShowPartnerBadge] = useState(false);
|
||||
const [partnerName, setPartnerName] = useState('Coca-Cola');
|
||||
// Campos de contato
|
||||
const [address, setAddress] = useState('');
|
||||
const [phone, setPhone] = useState('');
|
||||
const [email, setEmail] = useState('');
|
||||
const [instagram, setInstagram] = useState('');
|
||||
const [linkedin, setLinkedin] = useState('');
|
||||
const [facebook, setFacebook] = useState('');
|
||||
const [whatsapp, setWhatsapp] = useState('');
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [saving, setSaving] = useState(false);
|
||||
|
||||
@@ -54,6 +62,13 @@ export default function ConfiguracoesPage() {
|
||||
const data = await response.json();
|
||||
setShowPartnerBadge(data.showPartnerBadge || false);
|
||||
setPartnerName(data.partnerName || 'Coca-Cola');
|
||||
setAddress(data.address || '');
|
||||
setPhone(data.phone || '');
|
||||
setEmail(data.email || '');
|
||||
setInstagram(data.instagram || '');
|
||||
setLinkedin(data.linkedin || '');
|
||||
setFacebook(data.facebook || '');
|
||||
setWhatsapp(data.whatsapp || '');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Erro ao carregar settings:', error);
|
||||
@@ -65,16 +80,26 @@ export default function ConfiguracoesPage() {
|
||||
const response = await fetch('/api/settings', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ showPartnerBadge, partnerName })
|
||||
body: JSON.stringify({
|
||||
showPartnerBadge,
|
||||
partnerName,
|
||||
address: address || null,
|
||||
phone: phone || null,
|
||||
email: email || null,
|
||||
instagram: instagram || null,
|
||||
linkedin: linkedin || null,
|
||||
facebook: facebook || null,
|
||||
whatsapp: whatsapp || null
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) throw new Error('Erro ao salvar');
|
||||
|
||||
success('Configurações do badge salvas!');
|
||||
// Dispatch event para atualizar o PartnerBadge em tempo real
|
||||
success('Configurações salvas!');
|
||||
// Dispatch event para atualizar em tempo real
|
||||
window.dispatchEvent(new Event('settings:refresh'));
|
||||
} catch (error) {
|
||||
showError('Erro ao salvar configurações do badge');
|
||||
showError('Erro ao salvar configurações');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -394,6 +419,154 @@ export default function ConfiguracoesPage() {
|
||||
Salvar Configurações do Badge
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Contact Information Settings */}
|
||||
<div className="bg-white dark:bg-secondary p-8 rounded-2xl border border-gray-200 dark:border-white/10 shadow-sm">
|
||||
<div className="flex items-start gap-4 mb-6">
|
||||
<div className="w-12 h-12 bg-linear-to-br from-blue-500 to-blue-600 rounded-xl flex items-center justify-center shadow-lg shadow-blue-500/30">
|
||||
<i className="ri-contacts-book-2-fill text-2xl text-white"></i>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<h2 className="text-xl font-bold text-secondary dark:text-white mb-1">Informações de Contato</h2>
|
||||
<p className="text-gray-500 dark:text-gray-400 text-sm">
|
||||
Configure as informações de contato que aparecem no rodapé do site.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
{/* Address */}
|
||||
<div>
|
||||
<label className="block text-sm font-bold text-gray-700 dark:text-gray-300 mb-2">
|
||||
<i className="ri-map-pin-line mr-2 text-primary"></i>
|
||||
Endereço
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={address}
|
||||
onChange={(e) => setAddress(e.target.value)}
|
||||
placeholder="Ex: Rua das Flores, 123 - Centro, Vitória - ES"
|
||||
className="w-full px-4 py-3 bg-gray-50 dark:bg-white/5 border border-gray-200 dark:border-white/10 rounded-xl text-gray-900 dark:text-white focus:outline-none focus:border-primary focus:ring-1 focus:ring-primary transition-all"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Phone */}
|
||||
<div>
|
||||
<label className="block text-sm font-bold text-gray-700 dark:text-gray-300 mb-2">
|
||||
<i className="ri-phone-line mr-2 text-primary"></i>
|
||||
Telefone
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={phone}
|
||||
onChange={(e) => setPhone(e.target.value)}
|
||||
placeholder="Ex: (27) 99999-9999"
|
||||
className="w-full px-4 py-3 bg-gray-50 dark:bg-white/5 border border-gray-200 dark:border-white/10 rounded-xl text-gray-900 dark:text-white focus:outline-none focus:border-primary focus:ring-1 focus:ring-primary transition-all"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Email */}
|
||||
<div>
|
||||
<label className="block text-sm font-bold text-gray-700 dark:text-gray-300 mb-2">
|
||||
<i className="ri-mail-line mr-2 text-primary"></i>
|
||||
Email
|
||||
</label>
|
||||
<input
|
||||
type="email"
|
||||
value={email}
|
||||
onChange={(e) => setEmail(e.target.value)}
|
||||
placeholder="Ex: contato@empresa.com.br"
|
||||
className="w-full px-4 py-3 bg-gray-50 dark:bg-white/5 border border-gray-200 dark:border-white/10 rounded-xl text-gray-900 dark:text-white focus:outline-none focus:border-primary focus:ring-1 focus:ring-primary transition-all"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Social Media Settings */}
|
||||
<div className="bg-white dark:bg-secondary p-8 rounded-2xl border border-gray-200 dark:border-white/10 shadow-sm">
|
||||
<div className="flex items-start gap-4 mb-6">
|
||||
<div className="w-12 h-12 bg-linear-to-br from-pink-500 to-purple-600 rounded-xl flex items-center justify-center shadow-lg shadow-pink-500/30">
|
||||
<i className="ri-share-circle-fill text-2xl text-white"></i>
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<h2 className="text-xl font-bold text-secondary dark:text-white mb-1">Redes Sociais</h2>
|
||||
<p className="text-gray-500 dark:text-gray-400 text-sm">
|
||||
Configure os links das suas redes sociais. Deixe em branco para ocultar.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
{/* Instagram */}
|
||||
<div>
|
||||
<label className="block text-sm font-bold text-gray-700 dark:text-gray-300 mb-2">
|
||||
<i className="ri-instagram-line mr-2 text-pink-500"></i>
|
||||
Instagram
|
||||
</label>
|
||||
<input
|
||||
type="url"
|
||||
value={instagram}
|
||||
onChange={(e) => setInstagram(e.target.value)}
|
||||
placeholder="https://instagram.com/suaempresa"
|
||||
className="w-full px-4 py-3 bg-gray-50 dark:bg-white/5 border border-gray-200 dark:border-white/10 rounded-xl text-gray-900 dark:text-white focus:outline-none focus:border-primary focus:ring-1 focus:ring-primary transition-all"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* LinkedIn */}
|
||||
<div>
|
||||
<label className="block text-sm font-bold text-gray-700 dark:text-gray-300 mb-2">
|
||||
<i className="ri-linkedin-fill mr-2 text-blue-600"></i>
|
||||
LinkedIn
|
||||
</label>
|
||||
<input
|
||||
type="url"
|
||||
value={linkedin}
|
||||
onChange={(e) => setLinkedin(e.target.value)}
|
||||
placeholder="https://linkedin.com/company/suaempresa"
|
||||
className="w-full px-4 py-3 bg-gray-50 dark:bg-white/5 border border-gray-200 dark:border-white/10 rounded-xl text-gray-900 dark:text-white focus:outline-none focus:border-primary focus:ring-1 focus:ring-primary transition-all"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Facebook */}
|
||||
<div>
|
||||
<label className="block text-sm font-bold text-gray-700 dark:text-gray-300 mb-2">
|
||||
<i className="ri-facebook-fill mr-2 text-blue-500"></i>
|
||||
Facebook
|
||||
</label>
|
||||
<input
|
||||
type="url"
|
||||
value={facebook}
|
||||
onChange={(e) => setFacebook(e.target.value)}
|
||||
placeholder="https://facebook.com/suaempresa"
|
||||
className="w-full px-4 py-3 bg-gray-50 dark:bg-white/5 border border-gray-200 dark:border-white/10 rounded-xl text-gray-900 dark:text-white focus:outline-none focus:border-primary focus:ring-1 focus:ring-primary transition-all"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* WhatsApp */}
|
||||
<div>
|
||||
<label className="block text-sm font-bold text-gray-700 dark:text-gray-300 mb-2">
|
||||
<i className="ri-whatsapp-line mr-2 text-green-500"></i>
|
||||
WhatsApp
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
value={whatsapp}
|
||||
onChange={(e) => setWhatsapp(e.target.value)}
|
||||
placeholder="Ex: (27) 99999-9999"
|
||||
className="w-full px-4 py-3 bg-gray-50 dark:bg-white/5 border border-gray-200 dark:border-white/10 rounded-xl text-gray-900 dark:text-white focus:outline-none focus:border-primary focus:ring-1 focus:ring-primary transition-all"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Save All Settings Button */}
|
||||
<button
|
||||
onClick={handleSaveSettings}
|
||||
className="w-full mt-6 px-6 py-3 bg-primary text-white rounded-xl font-bold hover:opacity-90 transition-colors shadow-lg shadow-primary/20 flex items-center justify-center gap-2"
|
||||
>
|
||||
<i className="ri-save-line"></i>
|
||||
Salvar Informações de Contato
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
@@ -66,7 +66,17 @@ export async function POST(request: NextRequest) {
|
||||
}
|
||||
|
||||
const body = await request.json();
|
||||
const { showPartnerBadge, partnerName } = body;
|
||||
const {
|
||||
showPartnerBadge,
|
||||
partnerName,
|
||||
address,
|
||||
phone,
|
||||
email,
|
||||
instagram,
|
||||
linkedin,
|
||||
facebook,
|
||||
whatsapp
|
||||
} = body;
|
||||
|
||||
let settings = await prisma.settings.findFirst();
|
||||
|
||||
@@ -74,7 +84,14 @@ export async function POST(request: NextRequest) {
|
||||
settings = await prisma.settings.create({
|
||||
data: {
|
||||
showPartnerBadge: showPartnerBadge ?? false,
|
||||
partnerName: partnerName ?? 'Coca-Cola'
|
||||
partnerName: partnerName ?? 'Coca-Cola',
|
||||
address: address ?? null,
|
||||
phone: phone ?? null,
|
||||
email: email ?? null,
|
||||
instagram: instagram ?? null,
|
||||
linkedin: linkedin ?? null,
|
||||
facebook: facebook ?? null,
|
||||
whatsapp: whatsapp ?? null
|
||||
}
|
||||
});
|
||||
} else {
|
||||
@@ -82,7 +99,14 @@ export async function POST(request: NextRequest) {
|
||||
where: { id: settings.id },
|
||||
data: {
|
||||
...(showPartnerBadge !== undefined && { showPartnerBadge }),
|
||||
...(partnerName !== undefined && { partnerName })
|
||||
...(partnerName !== undefined && { partnerName }),
|
||||
...(address !== undefined && { address }),
|
||||
...(phone !== undefined && { phone }),
|
||||
...(email !== undefined && { email }),
|
||||
...(instagram !== undefined && { instagram }),
|
||||
...(linkedin !== undefined && { linkedin }),
|
||||
...(facebook !== undefined && { facebook }),
|
||||
...(whatsapp !== undefined && { whatsapp })
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,15 +1,56 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
import Link from 'next/link';
|
||||
import { useLocale } from '@/contexts/LocaleContext';
|
||||
import { PartnerBadge } from './PartnerBadge';
|
||||
|
||||
type ContactSettings = {
|
||||
address?: string | null;
|
||||
phone?: string | null;
|
||||
email?: string | null;
|
||||
instagram?: string | null;
|
||||
linkedin?: string | null;
|
||||
facebook?: string | null;
|
||||
whatsapp?: string | null;
|
||||
};
|
||||
|
||||
export default function Footer() {
|
||||
const { locale, t } = useLocale();
|
||||
const [contact, setContact] = useState<ContactSettings>({});
|
||||
|
||||
// Prefixo para links
|
||||
const prefix = locale === 'pt' ? '' : `/${locale}`;
|
||||
|
||||
useEffect(() => {
|
||||
const fetchSettings = async () => {
|
||||
try {
|
||||
const response = await fetch('/api/settings');
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
setContact({
|
||||
address: data.address,
|
||||
phone: data.phone,
|
||||
email: data.email,
|
||||
instagram: data.instagram,
|
||||
linkedin: data.linkedin,
|
||||
facebook: data.facebook,
|
||||
whatsapp: data.whatsapp
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Erro ao carregar configurações:', error);
|
||||
}
|
||||
};
|
||||
|
||||
fetchSettings();
|
||||
|
||||
// Atualizar quando settings mudar
|
||||
const handleRefresh = () => fetchSettings();
|
||||
window.addEventListener('settings:refresh', handleRefresh);
|
||||
return () => window.removeEventListener('settings:refresh', handleRefresh);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<footer className="bg-secondary text-white pt-16 pb-8">
|
||||
<div className="container mx-auto px-4">
|
||||
@@ -32,15 +73,26 @@ export default function Footer() {
|
||||
</div>
|
||||
|
||||
<div className="flex gap-4">
|
||||
<a href="#" className="w-10 h-10 rounded-full bg-white/10 flex items-center justify-center hover:bg-primary transition-colors">
|
||||
<i className="ri-instagram-line"></i>
|
||||
</a>
|
||||
<a href="#" className="w-10 h-10 rounded-full bg-white/10 flex items-center justify-center hover:bg-primary transition-colors">
|
||||
<i className="ri-linkedin-fill"></i>
|
||||
</a>
|
||||
<a href="#" className="w-10 h-10 rounded-full bg-white/10 flex items-center justify-center hover:bg-primary transition-colors">
|
||||
<i className="ri-facebook-fill"></i>
|
||||
</a>
|
||||
{contact.instagram && (
|
||||
<a href={contact.instagram} target="_blank" rel="noopener noreferrer" className="w-10 h-10 rounded-full bg-white/10 flex items-center justify-center hover:bg-primary transition-colors">
|
||||
<i className="ri-instagram-line"></i>
|
||||
</a>
|
||||
)}
|
||||
{contact.linkedin && (
|
||||
<a href={contact.linkedin} target="_blank" rel="noopener noreferrer" className="w-10 h-10 rounded-full bg-white/10 flex items-center justify-center hover:bg-primary transition-colors">
|
||||
<i className="ri-linkedin-fill"></i>
|
||||
</a>
|
||||
)}
|
||||
{contact.facebook && (
|
||||
<a href={contact.facebook} target="_blank" rel="noopener noreferrer" className="w-10 h-10 rounded-full bg-white/10 flex items-center justify-center hover:bg-primary transition-colors">
|
||||
<i className="ri-facebook-fill"></i>
|
||||
</a>
|
||||
)}
|
||||
{contact.whatsapp && (
|
||||
<a href={`https://wa.me/${contact.whatsapp.replace(/\D/g, '')}`} target="_blank" rel="noopener noreferrer" className="w-10 h-10 rounded-full bg-white/10 flex items-center justify-center hover:bg-primary transition-colors">
|
||||
<i className="ri-whatsapp-line"></i>
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -71,18 +123,33 @@ export default function Footer() {
|
||||
<div>
|
||||
<h3 className="text-lg font-bold font-headline mb-6">{t('nav.contact')}</h3>
|
||||
<ul className="space-y-4">
|
||||
<li className="flex items-start gap-3 text-gray-400">
|
||||
<i className="ri-map-pin-line mt-1 text-primary"></i>
|
||||
<span>Endereço da Empresa, 123<br />Cidade - ES</span>
|
||||
</li>
|
||||
<li className="flex items-center gap-3 text-gray-400">
|
||||
<i className="ri-phone-line text-primary"></i>
|
||||
<span>(27) 99999-9999</span>
|
||||
</li>
|
||||
<li className="flex items-center gap-3 text-gray-400">
|
||||
<i className="ri-mail-line text-primary"></i>
|
||||
<span>contato@octto.com.br</span>
|
||||
</li>
|
||||
{contact.address && (
|
||||
<li className="flex items-start gap-3 text-gray-400">
|
||||
<i className="ri-map-pin-line mt-1 text-primary"></i>
|
||||
<span>{contact.address}</span>
|
||||
</li>
|
||||
)}
|
||||
{contact.phone && (
|
||||
<li className="flex items-center gap-3 text-gray-400">
|
||||
<i className="ri-phone-line text-primary"></i>
|
||||
<a href={`tel:${contact.phone.replace(/\D/g, '')}`} className="hover:text-primary transition-colors">
|
||||
{contact.phone}
|
||||
</a>
|
||||
</li>
|
||||
)}
|
||||
{contact.email && (
|
||||
<li className="flex items-center gap-3 text-gray-400">
|
||||
<i className="ri-mail-line text-primary"></i>
|
||||
<a href={`mailto:${contact.email}`} className="hover:text-primary transition-colors">
|
||||
{contact.email}
|
||||
</a>
|
||||
</li>
|
||||
)}
|
||||
{!contact.address && !contact.phone && !contact.email && (
|
||||
<li className="text-gray-500 text-sm italic">
|
||||
Informações de contato não configuradas
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user