feat: implement authentication system with email verification, user management dashboard, and administrative business controls
Some checks failed
Build and Push App / build (push) Failing after 1m9s
Some checks failed
Build and Push App / build (push) Failing after 1m9s
This commit is contained in:
@@ -5,6 +5,7 @@ import { Save, Globe, Mail, Phone, MapPin, Share2, Link as LinkIcon, Loader2, Ne
|
||||
import { getSiteSettings, updateSiteSettings } from '@/app/actions/settings';
|
||||
import { toast } from 'react-hot-toast';
|
||||
import { getBlogPosts } from '@/app/actions/blog';
|
||||
import RichTextEditor from '@/components/RichTextEditor';
|
||||
|
||||
const BUSINESS_CATEGORIES = [
|
||||
"Technologie & IT",
|
||||
@@ -33,7 +34,11 @@ const BLOG_CATEGORIES = [
|
||||
"Formation"
|
||||
];
|
||||
|
||||
export default function SettingsPage() {
|
||||
export default function SettingsPage({
|
||||
searchParams
|
||||
}: {
|
||||
searchParams: Promise<{ tab?: string }>
|
||||
}) {
|
||||
const [isPending, startTransition] = useTransition();
|
||||
const [settings, setSettings] = useState<any>(null);
|
||||
const [allPosts, setAllPosts] = useState<any[]>([]);
|
||||
@@ -41,6 +46,12 @@ export default function SettingsPage() {
|
||||
const [selectedPostIds, setSelectedPostIds] = useState<string[]>([]);
|
||||
const [selectedHomeCategories, setSelectedHomeCategories] = useState<string[]>([]);
|
||||
const [selectedBlogCategories, setSelectedBlogCategories] = useState<string[]>([]);
|
||||
const [resetPasswordTemplate, setResetPasswordTemplate] = useState('');
|
||||
const [verifyEmailTemplate, setVerifyEmailTemplate] = useState('');
|
||||
|
||||
// Use a state for the tab if we want it to be fully client-side reactive without full reload
|
||||
// But since the user wants it "like moderation center", I'll use URL search params
|
||||
const [currentTab, setCurrentTab] = useState('general');
|
||||
|
||||
useEffect(() => {
|
||||
async function loadData() {
|
||||
@@ -53,6 +64,8 @@ export default function SettingsPage() {
|
||||
setSelectedPostIds(settingsData?.homeBlogIds || []);
|
||||
setSelectedHomeCategories(settingsData?.homeCategories || []);
|
||||
setSelectedBlogCategories(settingsData?.homeBlogCategories || []);
|
||||
setResetPasswordTemplate(settingsData?.resetPasswordTemplate || '');
|
||||
setVerifyEmailTemplate(settingsData?.verifyEmailTemplate || '');
|
||||
setLoading(false);
|
||||
}
|
||||
loadData();
|
||||
@@ -80,6 +93,10 @@ export default function SettingsPage() {
|
||||
homeBlogIds: selectedPostIds,
|
||||
homeBlogCategories: selectedBlogCategories,
|
||||
homeCategories: selectedHomeCategories,
|
||||
resetPasswordSubject: formData.get('resetPasswordSubject'),
|
||||
resetPasswordTemplate: resetPasswordTemplate,
|
||||
verifyEmailSubject: formData.get('verifyEmailSubject'),
|
||||
verifyEmailTemplate: verifyEmailTemplate,
|
||||
};
|
||||
|
||||
startTransition(async () => {
|
||||
@@ -123,176 +140,82 @@ export default function SettingsPage() {
|
||||
<div className="flex items-center justify-between mb-8">
|
||||
<div>
|
||||
<h1 className="text-2xl font-bold text-white">Configuration du Site</h1>
|
||||
<p className="text-slate-400">Gérez les informations globales et les coordonnées de contact du site principal.</p>
|
||||
<p className="text-slate-400">Gérez les informations globales, les sections de l'accueil et les modèles d'emails.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Tabs Switcher */}
|
||||
<div className="flex gap-2 mb-8 bg-slate-900/50 p-1 rounded-xl border border-slate-800 w-fit">
|
||||
<button
|
||||
onClick={() => setCurrentTab('general')}
|
||||
className={`px-6 py-2 rounded-lg text-sm font-bold transition-all flex items-center gap-2 ${currentTab === 'general' ? 'bg-indigo-600 text-white shadow-lg' : 'text-slate-400 hover:text-white hover:bg-slate-800'}`}
|
||||
>
|
||||
<Globe className="w-4 h-4" />
|
||||
Général
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setCurrentTab('emails')}
|
||||
className={`px-6 py-2 rounded-lg text-sm font-bold transition-all flex items-center gap-2 ${currentTab === 'emails' ? 'bg-indigo-600 text-white shadow-lg' : 'text-slate-400 hover:text-white hover:bg-slate-800'}`}
|
||||
>
|
||||
<Mail className="w-4 h-4" />
|
||||
Configuration Mail
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<form onSubmit={handleSubmit} className="space-y-6">
|
||||
{/* Section Générale */}
|
||||
<div className="bg-slate-900/50 border border-slate-700 rounded-2xl overflow-hidden">
|
||||
<div className="p-4 bg-slate-800/50 border-b border-slate-700 flex items-center gap-2">
|
||||
<Globe className="w-5 h-5 text-indigo-400" />
|
||||
<h2 className="font-semibold text-white">Informations Générales</h2>
|
||||
</div>
|
||||
<div className="p-6 grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium text-slate-400">Nom du site</label>
|
||||
<input
|
||||
name="siteName"
|
||||
defaultValue={settings?.siteName}
|
||||
className="w-full bg-slate-950 border border-slate-700 rounded-xl p-3 text-white focus:outline-none focus:border-indigo-500"
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium text-slate-400">Slogan du site</label>
|
||||
<input
|
||||
name="siteSlogan"
|
||||
defaultValue={settings?.siteSlogan}
|
||||
className="w-full bg-slate-950 border border-slate-700 rounded-xl p-3 text-white focus:outline-none focus:border-indigo-500"
|
||||
/>
|
||||
</div>
|
||||
<div className="md:col-span-2 space-y-2">
|
||||
<label className="text-sm font-medium text-slate-400">Texte du pied de page (Footer)</label>
|
||||
<input
|
||||
name="footerText"
|
||||
defaultValue={settings?.footerText}
|
||||
className="w-full bg-slate-950 border border-slate-700 rounded-xl p-3 text-white focus:outline-none focus:border-indigo-500"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Section Page d'Accueil - Secteurs */}
|
||||
<div className="bg-slate-900/50 border border-slate-700 rounded-2xl overflow-hidden">
|
||||
<div className="p-4 bg-slate-800/50 border-b border-slate-700 flex items-center gap-2">
|
||||
<Briefcase className="w-5 h-5 text-yellow-400" />
|
||||
<h2 className="font-semibold text-white">Secteurs en Vedette (Home)</h2>
|
||||
</div>
|
||||
<div className="p-6">
|
||||
<p className="text-sm text-slate-400 mb-4">Sélectionnez les secteurs d'activité à afficher sur la page d'accueil.</p>
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-2">
|
||||
{BUSINESS_CATEGORIES.map(cat => (
|
||||
<button
|
||||
key={cat}
|
||||
type="button"
|
||||
onClick={() => toggleHomeCategory(cat)}
|
||||
className={`text-left p-2 rounded-lg border text-xs transition-all ${
|
||||
selectedHomeCategories.includes(cat)
|
||||
? 'bg-indigo-600/20 border-indigo-500 text-indigo-300'
|
||||
: 'bg-slate-950 border-slate-700 text-slate-400 hover:border-slate-500'
|
||||
}`}
|
||||
>
|
||||
{cat}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Section Page d'Accueil - Blog */}
|
||||
<div className="bg-slate-900/50 border border-slate-700 rounded-2xl overflow-hidden">
|
||||
<div className="p-4 bg-slate-800/50 border-b border-slate-700 flex items-center gap-2">
|
||||
<Newspaper className="w-5 h-5 text-purple-400" />
|
||||
<h2 className="font-semibold text-white">Section Blog sur l'Accueil</h2>
|
||||
</div>
|
||||
<div className="p-6 space-y-6">
|
||||
<div className="flex items-center gap-3 p-3 bg-indigo-600/10 border border-indigo-500/20 rounded-xl">
|
||||
<input
|
||||
type="checkbox"
|
||||
name="homeBlogShow"
|
||||
id="homeBlogShow"
|
||||
defaultChecked={settings?.homeBlogShow}
|
||||
className="w-5 h-5 rounded border-slate-700 bg-slate-950 text-indigo-600 focus:ring-indigo-500"
|
||||
/>
|
||||
<label htmlFor="homeBlogShow" className="text-sm font-medium text-slate-300 font-bold uppercase tracking-wider">Activer cette section</label>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium text-slate-400">Titre de la section</label>
|
||||
<input
|
||||
name="homeBlogTitle"
|
||||
defaultValue={settings?.homeBlogTitle}
|
||||
className="w-full bg-slate-950 border border-slate-700 rounded-xl p-3 text-white focus:outline-none focus:border-indigo-500"
|
||||
/>
|
||||
{currentTab === 'general' && (
|
||||
<div className="space-y-6 animate-in fade-in slide-in-from-bottom-2 duration-300">
|
||||
{/* Section Générale */}
|
||||
<div className="bg-slate-900/50 border border-slate-700 rounded-2xl overflow-hidden">
|
||||
<div className="p-4 bg-slate-800/50 border-b border-slate-700 flex items-center gap-2">
|
||||
<Globe className="w-5 h-5 text-indigo-400" />
|
||||
<h2 className="font-semibold text-white">Informations Générales</h2>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium text-slate-400">Sous-titre</label>
|
||||
<input
|
||||
name="homeBlogSubtitle"
|
||||
defaultValue={settings?.homeBlogSubtitle}
|
||||
className="w-full bg-slate-950 border border-slate-700 rounded-xl p-3 text-white focus:outline-none focus:border-indigo-500"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="border-t border-slate-700 pt-6">
|
||||
<label className="text-sm font-medium text-slate-400 block mb-3">Mode de sélection des articles</label>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<label className={`flex flex-col p-4 rounded-xl border cursor-pointer transition-all ${settings?.homeBlogSelection === 'latest' ? 'bg-indigo-600/10 border-indigo-500' : 'bg-slate-950 border-slate-700 hover:border-slate-500'}`}>
|
||||
<input type="radio" name="homeBlogSelection" value="latest" defaultChecked={settings?.homeBlogSelection === 'latest'} className="sr-only" />
|
||||
<span className="text-white font-bold text-sm">Les plus récents</span>
|
||||
<span className="text-xs text-slate-500 mt-1">Affiche automatiquement les X derniers articles.</span>
|
||||
</label>
|
||||
<label className={`flex flex-col p-4 rounded-xl border cursor-pointer transition-all ${settings?.homeBlogSelection === 'manual' ? 'bg-indigo-600/10 border-indigo-500' : 'bg-slate-950 border-slate-700 hover:border-slate-500'}`}>
|
||||
<input type="radio" name="homeBlogSelection" value="manual" defaultChecked={settings?.homeBlogSelection === 'manual'} className="sr-only" />
|
||||
<span className="text-white font-bold text-sm">Sélection manuelle</span>
|
||||
<span className="text-xs text-slate-500 mt-1">Choisissez précisément les articles à mettre en avant.</span>
|
||||
</label>
|
||||
<label className={`flex flex-col p-4 rounded-xl border cursor-pointer transition-all ${settings?.homeBlogSelection === 'category' ? 'bg-indigo-600/10 border-indigo-500' : 'bg-slate-950 border-slate-700 hover:border-slate-500'}`}>
|
||||
<input type="radio" name="homeBlogSelection" value="category" defaultChecked={settings?.homeBlogSelection === 'category'} className="sr-only" />
|
||||
<span className="text-white font-bold text-sm">Par catégorie</span>
|
||||
<span className="text-xs text-slate-500 mt-1">Affiche les articles appartenant à certaines catégories.</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 gap-6">
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium text-slate-400">Nombre maximum d'articles</label>
|
||||
<input
|
||||
type="number"
|
||||
name="homeBlogCount"
|
||||
defaultValue={settings?.homeBlogCount}
|
||||
min="1" max="12"
|
||||
className="w-full bg-slate-950 border border-slate-700 rounded-xl p-3 text-white focus:outline-none focus:border-indigo-500"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Manual Selection UI */}
|
||||
<div className="space-y-3">
|
||||
<label className="text-sm font-medium text-slate-400">Articles sélectionnés (si mode manuel)</label>
|
||||
<div className="grid grid-cols-1 gap-2 max-h-60 overflow-y-auto p-2 bg-slate-950 rounded-xl border border-slate-700">
|
||||
{allPosts.map(post => (
|
||||
<button
|
||||
key={post.id}
|
||||
type="button"
|
||||
onClick={() => togglePostId(post.id)}
|
||||
className={`flex items-center justify-between p-3 rounded-lg text-sm transition-all ${
|
||||
selectedPostIds.includes(post.id)
|
||||
? 'bg-indigo-600/20 border-indigo-500/50 text-white'
|
||||
: 'text-slate-400 hover:bg-slate-900'
|
||||
}`}
|
||||
>
|
||||
<span>{post.title}</span>
|
||||
{selectedPostIds.includes(post.id) && <span className="text-indigo-400 font-bold text-xs">SÉLECTIONNÉ</span>}
|
||||
</button>
|
||||
))}
|
||||
<div className="p-6 grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium text-slate-400">Nom du site</label>
|
||||
<input
|
||||
name="siteName"
|
||||
defaultValue={settings?.siteName}
|
||||
className="w-full bg-slate-950 border border-slate-700 rounded-xl p-3 text-white focus:outline-none focus:border-indigo-500"
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium text-slate-400">Slogan du site</label>
|
||||
<input
|
||||
name="siteSlogan"
|
||||
defaultValue={settings?.siteSlogan}
|
||||
className="w-full bg-slate-950 border border-slate-700 rounded-xl p-3 text-white focus:outline-none focus:border-indigo-500"
|
||||
/>
|
||||
</div>
|
||||
<div className="md:col-span-2 space-y-2">
|
||||
<label className="text-sm font-medium text-slate-400">Texte du pied de page (Footer)</label>
|
||||
<input
|
||||
name="footerText"
|
||||
defaultValue={settings?.footerText}
|
||||
className="w-full bg-slate-950 border border-slate-700 rounded-xl p-3 text-white focus:outline-none focus:border-indigo-500"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Category Selection UI */}
|
||||
<div className="space-y-3">
|
||||
<label className="text-sm font-medium text-slate-400">Catégories d'articles (si mode catégorie)</label>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{BLOG_CATEGORIES.map(cat => (
|
||||
{/* Section Page d'Accueil - Secteurs */}
|
||||
<div className="bg-slate-900/50 border border-slate-700 rounded-2xl overflow-hidden">
|
||||
<div className="p-4 bg-slate-800/50 border-b border-slate-700 flex items-center gap-2">
|
||||
<Briefcase className="w-5 h-5 text-yellow-400" />
|
||||
<h2 className="font-semibold text-white">Secteurs en Vedette (Home)</h2>
|
||||
</div>
|
||||
<div className="p-6">
|
||||
<p className="text-sm text-slate-400 mb-4">Sélectionnez les secteurs d'activité à afficher sur la page d'accueil.</p>
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-2">
|
||||
{BUSINESS_CATEGORIES.map(cat => (
|
||||
<button
|
||||
key={cat}
|
||||
type="button"
|
||||
onClick={() => toggleBlogCategory(cat)}
|
||||
className={`px-4 py-2 rounded-full border text-xs transition-all ${
|
||||
selectedBlogCategories.includes(cat)
|
||||
? 'bg-purple-600 border-purple-500 text-white'
|
||||
onClick={() => toggleHomeCategory(cat)}
|
||||
className={`text-left p-2 rounded-lg border text-xs transition-all ${
|
||||
selectedHomeCategories.includes(cat)
|
||||
? 'bg-indigo-600/20 border-indigo-500 text-indigo-300'
|
||||
: 'bg-slate-950 border-slate-700 text-slate-400 hover:border-slate-500'
|
||||
}`}
|
||||
>
|
||||
@@ -302,109 +225,288 @@ export default function SettingsPage() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Section Contact */}
|
||||
<div className="bg-slate-900/50 border border-slate-700 rounded-2xl overflow-hidden">
|
||||
<div className="p-4 bg-slate-800/50 border-b border-slate-700 flex items-center gap-2">
|
||||
<Mail className="w-5 h-5 text-emerald-400" />
|
||||
<h2 className="font-semibold text-white">Coordonnées de Contact</h2>
|
||||
</div>
|
||||
<div className="p-6 grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium text-slate-400">Email de support</label>
|
||||
<div className="relative">
|
||||
<Mail className="absolute left-3 top-3.5 w-4 h-4 text-slate-500" />
|
||||
<input
|
||||
name="contactEmail"
|
||||
defaultValue={settings?.contactEmail}
|
||||
className="w-full bg-slate-950 border border-slate-700 rounded-xl p-3 pl-10 text-white focus:outline-none focus:border-indigo-500"
|
||||
/>
|
||||
{/* Section Page d'Accueil - Blog */}
|
||||
<div className="bg-slate-900/50 border border-slate-700 rounded-2xl overflow-hidden">
|
||||
<div className="p-4 bg-slate-800/50 border-b border-slate-700 flex items-center gap-2">
|
||||
<Newspaper className="w-5 h-5 text-purple-400" />
|
||||
<h2 className="font-semibold text-white">Section Blog sur l'Accueil</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium text-slate-400">Téléphone de contact</label>
|
||||
<div className="relative">
|
||||
<Phone className="absolute left-3 top-3.5 w-4 h-4 text-slate-500" />
|
||||
<input
|
||||
name="contactPhone"
|
||||
defaultValue={settings?.contactPhone}
|
||||
className="w-full bg-slate-950 border border-slate-700 rounded-xl p-3 pl-10 text-white focus:outline-none focus:border-indigo-500"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="md:col-span-2 space-y-2">
|
||||
<label className="text-sm font-medium text-slate-400">Adresse physique</label>
|
||||
<div className="relative">
|
||||
<MapPin className="absolute left-3 top-3.5 w-4 h-4 text-slate-500" />
|
||||
<input
|
||||
name="address"
|
||||
defaultValue={settings?.address}
|
||||
className="w-full bg-slate-950 border border-slate-700 rounded-xl p-3 pl-10 text-white focus:outline-none focus:border-indigo-500"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="p-6 space-y-6">
|
||||
<div className="flex items-center gap-3 p-3 bg-indigo-600/10 border border-indigo-500/20 rounded-xl">
|
||||
<input
|
||||
type="checkbox"
|
||||
name="homeBlogShow"
|
||||
id="homeBlogShow"
|
||||
defaultChecked={settings?.homeBlogShow}
|
||||
className="w-5 h-5 rounded border-slate-700 bg-slate-950 text-indigo-600 focus:ring-indigo-500"
|
||||
/>
|
||||
<label htmlFor="homeBlogShow" className="text-sm font-medium text-slate-300 font-bold uppercase tracking-wider">Activer cette section</label>
|
||||
</div>
|
||||
|
||||
{/* Section Réseaux Sociaux */}
|
||||
<div className="bg-slate-900/50 border border-slate-700 rounded-2xl overflow-hidden">
|
||||
<div className="p-4 bg-slate-800/50 border-b border-slate-700 flex items-center gap-2">
|
||||
<Share2 className="w-5 h-5 text-blue-400" />
|
||||
<h2 className="font-semibold text-white">Réseaux Sociaux</h2>
|
||||
</div>
|
||||
<div className="p-6 grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium text-slate-400">Facebook URL</label>
|
||||
<div className="relative">
|
||||
<LinkIcon className="absolute left-3 top-3.5 w-4 h-4 text-slate-500" />
|
||||
<input
|
||||
name="facebookUrl"
|
||||
defaultValue={settings?.facebookUrl}
|
||||
placeholder="https://facebook.com/..."
|
||||
className="w-full bg-slate-950 border border-slate-700 rounded-xl p-3 pl-10 text-white focus:outline-none focus:border-indigo-500"
|
||||
/>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium text-slate-400">Titre de la section</label>
|
||||
<input
|
||||
name="homeBlogTitle"
|
||||
defaultValue={settings?.homeBlogTitle}
|
||||
className="w-full bg-slate-950 border border-slate-700 rounded-xl p-3 text-white focus:outline-none focus:border-indigo-500"
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium text-slate-400">Sous-titre</label>
|
||||
<input
|
||||
name="homeBlogSubtitle"
|
||||
defaultValue={settings?.homeBlogSubtitle}
|
||||
className="w-full bg-slate-950 border border-slate-700 rounded-xl p-3 text-white focus:outline-none focus:border-indigo-500"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="border-t border-slate-700 pt-6">
|
||||
<label className="text-sm font-medium text-slate-400 block mb-3">Mode de sélection des articles</label>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<label className={`flex flex-col p-4 rounded-xl border cursor-pointer transition-all ${settings?.homeBlogSelection === 'latest' ? 'bg-indigo-600/10 border-indigo-500' : 'bg-slate-950 border-slate-700 hover:border-slate-500'}`}>
|
||||
<input type="radio" name="homeBlogSelection" value="latest" defaultChecked={settings?.homeBlogSelection === 'latest'} className="sr-only" />
|
||||
<span className="text-white font-bold text-sm">Les plus récents</span>
|
||||
<span className="text-xs text-slate-500 mt-1">Affiche automatiquement les X derniers articles.</span>
|
||||
</label>
|
||||
<label className={`flex flex-col p-4 rounded-xl border cursor-pointer transition-all ${settings?.homeBlogSelection === 'manual' ? 'bg-indigo-600/10 border-indigo-500' : 'bg-slate-950 border-slate-700 hover:border-slate-500'}`}>
|
||||
<input type="radio" name="homeBlogSelection" value="manual" defaultChecked={settings?.homeBlogSelection === 'manual'} className="sr-only" />
|
||||
<span className="text-white font-bold text-sm">Sélection manuelle</span>
|
||||
<span className="text-xs text-slate-500 mt-1">Choisissez précisément les articles à mettre en avant.</span>
|
||||
</label>
|
||||
<label className={`flex flex-col p-4 rounded-xl border cursor-pointer transition-all ${settings?.homeBlogSelection === 'category' ? 'bg-indigo-600/10 border-indigo-500' : 'bg-slate-950 border-slate-700 hover:border-slate-500'}`}>
|
||||
<input type="radio" name="homeBlogSelection" value="category" defaultChecked={settings?.homeBlogSelection === 'category'} className="sr-only" />
|
||||
<span className="text-white font-bold text-sm">Par catégorie</span>
|
||||
<span className="text-xs text-slate-500 mt-1">Affiche les articles appartenant à certaines catégories.</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 gap-6">
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium text-slate-400">Nombre maximum d'articles</label>
|
||||
<input
|
||||
type="number"
|
||||
name="homeBlogCount"
|
||||
defaultValue={settings?.homeBlogCount}
|
||||
min="1" max="12"
|
||||
className="w-full bg-slate-950 border border-slate-700 rounded-xl p-3 text-white focus:outline-none focus:border-indigo-500"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Manual Selection UI */}
|
||||
<div className="space-y-3">
|
||||
<label className="text-sm font-medium text-slate-400">Articles sélectionnés (si mode manuel)</label>
|
||||
<div className="grid grid-cols-1 gap-2 max-h-60 overflow-y-auto p-2 bg-slate-950 rounded-xl border border-slate-700">
|
||||
{allPosts.map(post => (
|
||||
<button
|
||||
key={post.id}
|
||||
type="button"
|
||||
onClick={() => togglePostId(post.id)}
|
||||
className={`flex items-center justify-between p-3 rounded-lg text-sm transition-all ${
|
||||
selectedPostIds.includes(post.id)
|
||||
? 'bg-indigo-600/20 border-indigo-500/50 text-white'
|
||||
: 'text-slate-400 hover:bg-slate-900'
|
||||
}`}
|
||||
>
|
||||
<span>{post.title}</span>
|
||||
{selectedPostIds.includes(post.id) && <span className="text-indigo-400 font-bold text-xs">SÉLECTIONNÉ</span>}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Category Selection UI */}
|
||||
<div className="space-y-3">
|
||||
<label className="text-sm font-medium text-slate-400">Catégories d'articles (si mode catégorie)</label>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{BLOG_CATEGORIES.map(cat => (
|
||||
<button
|
||||
key={cat}
|
||||
type="button"
|
||||
onClick={() => toggleBlogCategory(cat)}
|
||||
className={`px-4 py-2 rounded-full border text-xs transition-all ${
|
||||
selectedBlogCategories.includes(cat)
|
||||
? 'bg-purple-600 border-purple-500 text-white'
|
||||
: 'bg-slate-950 border-slate-700 text-slate-400 hover:border-slate-500'
|
||||
}`}
|
||||
>
|
||||
{cat}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium text-slate-400">Twitter (X) URL</label>
|
||||
<div className="relative">
|
||||
<LinkIcon className="absolute left-3 top-3.5 w-4 h-4 text-slate-500" />
|
||||
<input
|
||||
name="twitterUrl"
|
||||
defaultValue={settings?.twitterUrl}
|
||||
placeholder="https://twitter.com/..."
|
||||
className="w-full bg-slate-950 border border-slate-700 rounded-xl p-3 pl-10 text-white focus:outline-none focus:border-indigo-500"
|
||||
/>
|
||||
|
||||
{/* Section Contact */}
|
||||
<div className="bg-slate-900/50 border border-slate-700 rounded-2xl overflow-hidden">
|
||||
<div className="p-4 bg-slate-800/50 border-b border-slate-700 flex items-center gap-2">
|
||||
<Mail className="w-5 h-5 text-emerald-400" />
|
||||
<h2 className="font-semibold text-white">Coordonnées de Contact</h2>
|
||||
</div>
|
||||
<div className="p-6 grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium text-slate-400">Email de support</label>
|
||||
<div className="relative">
|
||||
<Mail className="absolute left-3 top-3.5 w-4 h-4 text-slate-500" />
|
||||
<input
|
||||
name="contactEmail"
|
||||
defaultValue={settings?.contactEmail}
|
||||
className="w-full bg-slate-950 border border-slate-700 rounded-xl p-3 pl-10 text-white focus:outline-none focus:border-indigo-500"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium text-slate-400">Téléphone de contact</label>
|
||||
<div className="relative">
|
||||
<Phone className="absolute left-3 top-3.5 w-4 h-4 text-slate-500" />
|
||||
<input
|
||||
name="contactPhone"
|
||||
defaultValue={settings?.contactPhone}
|
||||
className="w-full bg-slate-950 border border-slate-700 rounded-xl p-3 pl-10 text-white focus:outline-none focus:border-indigo-500"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="md:col-span-2 space-y-2">
|
||||
<label className="text-sm font-medium text-slate-400">Adresse physique</label>
|
||||
<div className="relative">
|
||||
<MapPin className="absolute left-3 top-3.5 w-4 h-4 text-slate-500" />
|
||||
<input
|
||||
name="address"
|
||||
defaultValue={settings?.address}
|
||||
className="w-full bg-slate-950 border border-slate-700 rounded-xl p-3 pl-10 text-white focus:outline-none focus:border-indigo-500"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium text-slate-400">Instagram URL</label>
|
||||
<div className="relative">
|
||||
<LinkIcon className="absolute left-3 top-3.5 w-4 h-4 text-slate-500" />
|
||||
<input
|
||||
name="instagramUrl"
|
||||
defaultValue={settings?.instagramUrl}
|
||||
placeholder="https://instagram.com/..."
|
||||
className="w-full bg-slate-950 border border-slate-700 rounded-xl p-3 pl-10 text-white focus:outline-none focus:border-indigo-500"
|
||||
/>
|
||||
|
||||
{/* Section Réseaux Sociaux */}
|
||||
<div className="bg-slate-900/50 border border-slate-700 rounded-2xl overflow-hidden">
|
||||
<div className="p-4 bg-slate-800/50 border-b border-slate-700 flex items-center gap-2">
|
||||
<Share2 className="w-5 h-5 text-blue-400" />
|
||||
<h2 className="font-semibold text-white">Réseaux Sociaux</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium text-slate-400">LinkedIn URL</label>
|
||||
<div className="relative">
|
||||
<LinkIcon className="absolute left-3 top-3.5 w-4 h-4 text-slate-500" />
|
||||
<input
|
||||
name="linkedinUrl"
|
||||
defaultValue={settings?.linkedinUrl}
|
||||
placeholder="https://linkedin.com/in/..."
|
||||
className="w-full bg-slate-950 border border-slate-700 rounded-xl p-3 pl-10 text-white focus:outline-none focus:border-indigo-500"
|
||||
/>
|
||||
<div className="p-6 grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium text-slate-400">Facebook URL</label>
|
||||
<div className="relative">
|
||||
<Share2 className="absolute left-3 top-3.5 w-4 h-4 text-slate-500" />
|
||||
<input
|
||||
name="facebookUrl"
|
||||
defaultValue={settings?.facebookUrl}
|
||||
placeholder="https://facebook.com/..."
|
||||
className="w-full bg-slate-950 border border-slate-700 rounded-xl p-3 pl-10 text-white focus:outline-none focus:border-indigo-500"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium text-slate-400">Twitter (X) URL</label>
|
||||
<div className="relative">
|
||||
<Share2 className="absolute left-3 top-3.5 w-4 h-4 text-slate-500" />
|
||||
<input
|
||||
name="twitterUrl"
|
||||
defaultValue={settings?.twitterUrl}
|
||||
placeholder="https://twitter.com/..."
|
||||
className="w-full bg-slate-950 border border-slate-700 rounded-xl p-3 pl-10 text-white focus:outline-none focus:border-indigo-500"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium text-slate-400">Instagram URL</label>
|
||||
<div className="relative">
|
||||
<Share2 className="absolute left-3 top-3.5 w-4 h-4 text-slate-500" />
|
||||
<input
|
||||
name="instagramUrl"
|
||||
defaultValue={settings?.instagramUrl}
|
||||
placeholder="https://instagram.com/..."
|
||||
className="w-full bg-slate-950 border border-slate-700 rounded-xl p-3 pl-10 text-white focus:outline-none focus:border-indigo-500"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium text-slate-400">LinkedIn URL</label>
|
||||
<div className="relative">
|
||||
<Share2 className="absolute left-3 top-3.5 w-4 h-4 text-slate-500" />
|
||||
<input
|
||||
name="linkedinUrl"
|
||||
defaultValue={settings?.linkedinUrl}
|
||||
placeholder="https://linkedin.com/in/..."
|
||||
className="w-full bg-slate-950 border border-slate-700 rounded-xl p-3 pl-10 text-white focus:outline-none focus:border-indigo-500"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{currentTab === 'emails' && (
|
||||
<div className="space-y-6 animate-in fade-in slide-in-from-bottom-2 duration-300">
|
||||
{/* Section Mail */}
|
||||
<div className="bg-slate-900/50 border border-slate-700 rounded-2xl overflow-hidden">
|
||||
<div className="p-4 bg-slate-800/50 border-b border-slate-700 flex items-center gap-2">
|
||||
<Mail className="w-5 h-5 text-orange-400" />
|
||||
<h2 className="font-semibold text-white">Gestion des Emails</h2>
|
||||
</div>
|
||||
<div className="p-6 space-y-8">
|
||||
{/* Password Reset */}
|
||||
<div className="space-y-4">
|
||||
<h3 className="text-sm font-bold text-indigo-400 uppercase tracking-wider">Réinitialisation de mot de passe</h3>
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium text-slate-400">Objet de l'email</label>
|
||||
<input
|
||||
name="resetPasswordSubject"
|
||||
defaultValue={settings?.resetPasswordSubject}
|
||||
className="w-full bg-slate-950 border border-slate-700 rounded-xl p-3 text-white focus:outline-none focus:border-indigo-500"
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium text-slate-400">Modèle d'email</label>
|
||||
<RichTextEditor
|
||||
value={resetPasswordTemplate}
|
||||
onChange={setResetPasswordTemplate}
|
||||
placeholder="Contenu de l'email..."
|
||||
/>
|
||||
<p className="text-[10px] text-slate-500">
|
||||
Variables : <code className="text-indigo-400">{"{name}"}</code>, <code className="text-indigo-400">{"{resetUrl}"}</code>, <code className="text-indigo-400">{"{siteName}"}</code>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="border-t border-slate-800"></div>
|
||||
|
||||
{/* Account Verification */}
|
||||
<div className="space-y-4">
|
||||
<h3 className="text-sm font-bold text-emerald-400 uppercase tracking-wider">Vérification de compte</h3>
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium text-slate-400">Objet de l'email</label>
|
||||
<input
|
||||
name="verifyEmailSubject"
|
||||
defaultValue={settings?.verifyEmailSubject}
|
||||
className="w-full bg-slate-950 border border-slate-700 rounded-xl p-3 text-white focus:outline-none focus:border-indigo-500"
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<label className="text-sm font-medium text-slate-400">Modèle d'email</label>
|
||||
<RichTextEditor
|
||||
value={verifyEmailTemplate}
|
||||
onChange={setVerifyEmailTemplate}
|
||||
placeholder="Contenu de l'email..."
|
||||
/>
|
||||
<p className="text-[10px] text-slate-500">
|
||||
Variables : <code className="text-indigo-400">{"{name}"}</code>, <code className="text-indigo-400">{"{verifyUrl}"}</code>, <code className="text-indigo-400">{"{siteName}"}</code>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="flex justify-end">
|
||||
<button
|
||||
@@ -424,3 +526,4 @@ export default function SettingsPage() {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user