gestion des messages page 404
This commit is contained in:
@@ -29,6 +29,7 @@ export async function getSiteSettings() {
|
|||||||
homeBlogIds: [],
|
homeBlogIds: [],
|
||||||
homeBlogCategories: [],
|
homeBlogCategories: [],
|
||||||
homeCategories: ["Technologie & IT", "Agriculture & Agrobusiness", "Mode & Textile", "Cosmétique & Beauté"],
|
homeCategories: ["Technologie & IT", "Agriculture & Agrobusiness", "Mode & Textile", "Cosmétique & Beauté"],
|
||||||
|
notFoundQuotes: ["L'échec est une étape vers la réussite, mais une erreur 404 est juste une impasse."],
|
||||||
resetPasswordSubject: "Réinitialisation de votre mot de passe - Afrohub",
|
resetPasswordSubject: "Réinitialisation de votre mot de passe - Afrohub",
|
||||||
resetPasswordTemplate: `<div style="font-family: sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; border: 1px solid #e5e7eb; border-radius: 8px;">
|
resetPasswordTemplate: `<div style="font-family: sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; border: 1px solid #e5e7eb; border-radius: 8px;">
|
||||||
<h2 style="color: #0d9488; text-align: center;">{siteName}</h2>
|
<h2 style="color: #0d9488; text-align: center;">{siteName}</h2>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import React, { useState, useEffect, useTransition } from 'react';
|
import React, { useState, useEffect, useTransition } from 'react';
|
||||||
import { Save, Globe, Mail, Phone, MapPin, Share2, Link as LinkIcon, Loader2, Newspaper, Briefcase } from 'lucide-react';
|
import { Save, Globe, Mail, Phone, MapPin, Share2, Link as LinkIcon, Loader2, Newspaper, Briefcase, Plus, Trash2 } from 'lucide-react';
|
||||||
import { getSiteSettings, updateSiteSettings } from '@/app/actions/settings';
|
import { getSiteSettings, updateSiteSettings } from '@/app/actions/settings';
|
||||||
import { toast } from 'react-hot-toast';
|
import { toast } from 'react-hot-toast';
|
||||||
import { getBlogPosts } from '@/app/actions/actualites';
|
import { getBlogPosts } from '@/app/actions/actualites';
|
||||||
@@ -46,6 +46,7 @@ export default function SettingsPage({
|
|||||||
const [selectedPostIds, setSelectedPostIds] = useState<string[]>([]);
|
const [selectedPostIds, setSelectedPostIds] = useState<string[]>([]);
|
||||||
const [selectedHomeCategories, setSelectedHomeCategories] = useState<string[]>([]);
|
const [selectedHomeCategories, setSelectedHomeCategories] = useState<string[]>([]);
|
||||||
const [selectedBlogCategories, setSelectedBlogCategories] = useState<string[]>([]);
|
const [selectedBlogCategories, setSelectedBlogCategories] = useState<string[]>([]);
|
||||||
|
const [notFoundQuotes, setNotFoundQuotes] = useState<string[]>([]);
|
||||||
const [resetPasswordTemplate, setResetPasswordTemplate] = useState('');
|
const [resetPasswordTemplate, setResetPasswordTemplate] = useState('');
|
||||||
const [verifyEmailTemplate, setVerifyEmailTemplate] = useState('');
|
const [verifyEmailTemplate, setVerifyEmailTemplate] = useState('');
|
||||||
|
|
||||||
@@ -65,6 +66,7 @@ export default function SettingsPage({
|
|||||||
setSelectedPostIds(settingsData?.homeBlogIds || []);
|
setSelectedPostIds(settingsData?.homeBlogIds || []);
|
||||||
setSelectedHomeCategories(settingsData?.homeCategories || []);
|
setSelectedHomeCategories(settingsData?.homeCategories || []);
|
||||||
setSelectedBlogCategories(settingsData?.homeBlogCategories || []);
|
setSelectedBlogCategories(settingsData?.homeBlogCategories || []);
|
||||||
|
setNotFoundQuotes(settingsData?.notFoundQuotes || ["L'échec est une étape vers la réussite, mais une erreur 404 est juste une impasse."]);
|
||||||
setResetPasswordTemplate(settingsData?.resetPasswordTemplate || '');
|
setResetPasswordTemplate(settingsData?.resetPasswordTemplate || '');
|
||||||
setVerifyEmailTemplate(settingsData?.verifyEmailTemplate || '');
|
setVerifyEmailTemplate(settingsData?.verifyEmailTemplate || '');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -99,6 +101,7 @@ export default function SettingsPage({
|
|||||||
homeBlogIds: selectedPostIds,
|
homeBlogIds: selectedPostIds,
|
||||||
homeBlogCategories: selectedBlogCategories,
|
homeBlogCategories: selectedBlogCategories,
|
||||||
homeCategories: selectedHomeCategories,
|
homeCategories: selectedHomeCategories,
|
||||||
|
notFoundQuotes: notFoundQuotes.filter(q => q.trim() !== ''),
|
||||||
resetPasswordSubject: formData.get('resetPasswordSubject'),
|
resetPasswordSubject: formData.get('resetPasswordSubject'),
|
||||||
resetPasswordTemplate: resetPasswordTemplate,
|
resetPasswordTemplate: resetPasswordTemplate,
|
||||||
verifyEmailSubject: formData.get('verifyEmailSubject'),
|
verifyEmailSubject: formData.get('verifyEmailSubject'),
|
||||||
@@ -133,6 +136,22 @@ export default function SettingsPage({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleAddQuote = () => {
|
||||||
|
setNotFoundQuotes(prev => [...prev, '']);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleUpdateQuote = (index: number, value: string) => {
|
||||||
|
setNotFoundQuotes(prev => {
|
||||||
|
const updated = [...prev];
|
||||||
|
updated[index] = value;
|
||||||
|
return updated;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRemoveQuote = (index: number) => {
|
||||||
|
setNotFoundQuotes(prev => prev.filter((_, i) => i !== index));
|
||||||
|
};
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-center p-20">
|
<div className="flex items-center justify-center p-20">
|
||||||
@@ -205,6 +224,57 @@ export default function SettingsPage({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Section Page 404 - Phrases */}
|
||||||
|
<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 justify-between">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<Globe className="w-5 h-5 text-rose-400" />
|
||||||
|
<h2 className="font-semibold text-white">Phrases de la Page 404</h2>
|
||||||
|
</div>
|
||||||
|
<span className="text-xs bg-rose-500/10 text-rose-400 border border-rose-500/20 px-2.5 py-1 rounded-full font-bold">
|
||||||
|
{notFoundQuotes.length} configurée{notFoundQuotes.length > 1 ? 's' : ''}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="p-6 space-y-4">
|
||||||
|
<p className="text-sm text-slate-400">
|
||||||
|
Configurez ici les différentes phrases ou citations qui s'afficheront de manière aléatoire sur la page d'erreur 404.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="space-y-3">
|
||||||
|
{notFoundQuotes.map((quote, index) => (
|
||||||
|
<div key={index} className="flex items-center gap-2">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={quote}
|
||||||
|
onChange={(e) => handleUpdateQuote(index, e.target.value)}
|
||||||
|
placeholder="Saisissez une citation..."
|
||||||
|
className="flex-grow bg-slate-950 border border-slate-700 rounded-xl p-3 text-white focus:outline-none focus:border-indigo-500 text-sm"
|
||||||
|
/>
|
||||||
|
{notFoundQuotes.length > 1 && (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => handleRemoveQuote(index)}
|
||||||
|
className="p-3 bg-slate-950 border border-slate-700 hover:border-rose-500/50 text-slate-400 hover:text-rose-400 rounded-xl transition-all"
|
||||||
|
title="Supprimer cette phrase"
|
||||||
|
>
|
||||||
|
<Trash2 className="w-4 h-4" />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={handleAddQuote}
|
||||||
|
className="inline-flex items-center gap-2 px-4 py-2.5 bg-slate-800 hover:bg-slate-700 border border-slate-700 text-slate-200 rounded-xl text-sm font-bold transition-all"
|
||||||
|
>
|
||||||
|
<Plus className="w-4 h-4" />
|
||||||
|
Ajouter une phrase
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Section Page d'Accueil - Secteurs */}
|
{/* Section Page d'Accueil - Secteurs */}
|
||||||
<div className="bg-slate-900/50 border border-slate-700 rounded-2xl overflow-hidden">
|
<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">
|
<div className="p-4 bg-slate-800/50 border-b border-slate-700 flex items-center gap-2">
|
||||||
|
|||||||
@@ -1,8 +1,17 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import { Home, ArrowLeft, Search } from 'lucide-react';
|
import { Home, Search } from 'lucide-react';
|
||||||
|
import { getSiteSettings } from '../lib/settings';
|
||||||
|
|
||||||
|
export default async function NotFound() {
|
||||||
|
const settings = await getSiteSettings();
|
||||||
|
const quotes = (settings as any)?.notFoundQuotes && (settings as any).notFoundQuotes.length > 0
|
||||||
|
? (settings as any).notFoundQuotes
|
||||||
|
: ["L'échec est une étape vers la réussite, mais une erreur 404 est juste une impasse."];
|
||||||
|
|
||||||
|
// Sélection d'une phrase aléatoire
|
||||||
|
const randomQuote = quotes[Math.floor(Math.random() * quotes.length)];
|
||||||
|
|
||||||
export default function NotFound() {
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-white flex items-center justify-center px-4 sm:px-6 lg:px-8 py-24">
|
<div className="min-h-screen bg-white flex items-center justify-center px-4 sm:px-6 lg:px-8 py-24">
|
||||||
<div className="max-w-md w-full text-center">
|
<div className="max-w-md w-full text-center">
|
||||||
@@ -41,10 +50,11 @@ export default function NotFound() {
|
|||||||
|
|
||||||
<div className="mt-12 pt-12 border-t border-gray-100">
|
<div className="mt-12 pt-12 border-t border-gray-100">
|
||||||
<p className="text-sm text-gray-400 italic">
|
<p className="text-sm text-gray-400 italic">
|
||||||
"L'échec est une étape vers la réussite, mais une erreur 404 est juste une impasse."
|
"{randomQuote}"
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,8 @@ export async function getSiteSettings() {
|
|||||||
homeBlogSelection: "latest",
|
homeBlogSelection: "latest",
|
||||||
homeBlogIds: [],
|
homeBlogIds: [],
|
||||||
homeBlogCategories: [],
|
homeBlogCategories: [],
|
||||||
homeCategories: ["Technologie & IT", "Agriculture & Agrobusiness", "Mode & Textile", "Cosmétique & Beauté"]
|
homeCategories: ["Technologie & IT", "Agriculture & Agrobusiness", "Mode & Textile", "Cosmétique & Beauté"],
|
||||||
|
notFoundQuotes: ["L'échec est une étape vers la réussite, mais une erreur 404 est juste une impasse."]
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
2
next-env.d.ts
vendored
2
next-env.d.ts
vendored
@@ -1,6 +1,6 @@
|
|||||||
/// <reference types="next" />
|
/// <reference types="next" />
|
||||||
/// <reference types="next/image-types/global" />
|
/// <reference types="next/image-types/global" />
|
||||||
import "./.next/types/routes.d.ts";
|
import "./.next/dev/types/routes.d.ts";
|
||||||
|
|
||||||
// NOTE: This file should not be edited
|
// NOTE: This file should not be edited
|
||||||
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|
||||||
|
|||||||
@@ -332,6 +332,7 @@ model SiteSetting {
|
|||||||
deleteAccountTemplate String @default("<div style=\"font-family: sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; border: 1px solid #e5e7eb; border-radius: 8px;\"><h2 style=\"color: #dc2626; text-align: center;\">{siteName}</h2><p>Bonjour {name},</p><p>Votre demande de suppression de compte a bien été prise en compte. Votre compte sera définitivement supprimé le <strong>{deletionDate}</strong>.</p><p>Si vous changez d'avis, vous pouvez réactiver votre compte avant cette date en cliquant sur le bouton ci-dessous :</p><div style=\"text-align: center; margin: 30px 0;\"><a href=\"{reactivateUrl}\" style=\"background-color: #0d9488; color: white; padding: 12px 24px; text-decoration: none; border-radius: 6px; font-weight: bold;\">Réactiver mon compte</a></div><p>Passé ce délai, toutes vos données seront définitivement effacées.</p><hr style=\"border: 0; border-top: 1px solid #e5e7eb; margin: 20px 0;\"><p style=\"font-size: 12px; color: #6b7280; text-align: center;\">© 2025 {siteName}. Tous droits réservés.</p></div>")
|
deleteAccountTemplate String @default("<div style=\"font-family: sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; border: 1px solid #e5e7eb; border-radius: 8px;\"><h2 style=\"color: #dc2626; text-align: center;\">{siteName}</h2><p>Bonjour {name},</p><p>Votre demande de suppression de compte a bien été prise en compte. Votre compte sera définitivement supprimé le <strong>{deletionDate}</strong>.</p><p>Si vous changez d'avis, vous pouvez réactiver votre compte avant cette date en cliquant sur le bouton ci-dessous :</p><div style=\"text-align: center; margin: 30px 0;\"><a href=\"{reactivateUrl}\" style=\"background-color: #0d9488; color: white; padding: 12px 24px; text-decoration: none; border-radius: 6px; font-weight: bold;\">Réactiver mon compte</a></div><p>Passé ce délai, toutes vos données seront définitivement effacées.</p><hr style=\"border: 0; border-top: 1px solid #e5e7eb; margin: 20px 0;\"><p style=\"font-size: 12px; color: #6b7280; text-align: center;\">© 2025 {siteName}. Tous droits réservés.</p></div>")
|
||||||
reactivateAccountSubject String @default("Réactivation de votre compte - Afrohub")
|
reactivateAccountSubject String @default("Réactivation de votre compte - Afrohub")
|
||||||
reactivateAccountTemplate String @default("<div style=\"font-family: sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; border: 1px solid #e5e7eb; border-radius: 8px;\"><h2 style=\"color: #0d9488; text-align: center;\">{siteName}</h2><p>Bonjour {name},</p><p>Nous avons bien reçu votre demande de réactivation de compte.</p><p><strong>Raison invoquée :</strong><br>{reason}</p><p>Votre compte est désormais actif. Vous pouvez vous connecter à nouveau.</p><hr style=\"border: 0; border-top: 1px solid #e5e7eb; margin: 20px 0;\"><p style=\"font-size: 12px; color: #6b7280; text-align: center;\">© 2025 {siteName}. Tous droits réservés.</p></div>")
|
reactivateAccountTemplate String @default("<div style=\"font-family: sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; border: 1px solid #e5e7eb; border-radius: 8px;\"><h2 style=\"color: #0d9488; text-align: center;\">{siteName}</h2><p>Bonjour {name},</p><p>Nous avons bien reçu votre demande de réactivation de compte.</p><p><strong>Raison invoquée :</strong><br>{reason}</p><p>Votre compte est désormais actif. Vous pouvez vous connecter à nouveau.</p><hr style=\"border: 0; border-top: 1px solid #e5e7eb; margin: 20px 0;\"><p style=\"font-size: 12px; color: #6b7280; text-align: center;\">© 2025 {siteName}. Tous droits réservés.</p></div>")
|
||||||
|
notFoundQuotes String[] @default(["L'échec est une étape vers la réussite, mais une erreur 404 est juste une impasse."])
|
||||||
}
|
}
|
||||||
|
|
||||||
model OneShotPlan {
|
model OneShotPlan {
|
||||||
|
|||||||
Reference in New Issue
Block a user