This commit is contained in:
2026-04-11 23:30:14 +02:00
parent 10ca8c3e8c
commit b73939d381
1574 changed files with 621 additions and 57974 deletions

View File

@@ -19,7 +19,8 @@
"pg": "^8.20.0",
"prisma": "^7.7.0",
"react": "19.2.4",
"react-dom": "19.2.4"
"react-dom": "19.2.4",
"react-hot-toast": "^2.6.0"
},
"devDependencies": {
"@tailwindcss/postcss": "^4",
@@ -4528,6 +4529,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/goober": {
"version": "2.1.18",
"resolved": "https://registry.npmjs.org/goober/-/goober-2.1.18.tgz",
"integrity": "sha512-2vFqsaDVIT9Gz7N6kAL++pLpp41l3PfDuusHcjnGLfR6+huZkl6ziX+zgVC3ZxpqWhzH6pyDdGrCeDhMIvwaxw==",
"license": "MIT",
"peerDependencies": {
"csstype": "^3.0.10"
}
},
"node_modules/gopd": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
@@ -6578,6 +6588,23 @@
"react": "^19.2.4"
}
},
"node_modules/react-hot-toast": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/react-hot-toast/-/react-hot-toast-2.6.0.tgz",
"integrity": "sha512-bH+2EBMZ4sdyou/DPrfgIouFpcRLCJ+HoCA32UoAYHn6T3Ur5yfcDCeSr5mwldl6pFOsiocmrXMuoCJ1vV8bWg==",
"license": "MIT",
"dependencies": {
"csstype": "^3.1.3",
"goober": "^2.1.16"
},
"engines": {
"node": ">=10"
},
"peerDependencies": {
"react": ">=16",
"react-dom": ">=16"
}
},
"node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",

View File

@@ -20,7 +20,8 @@
"pg": "^8.20.0",
"prisma": "^7.7.0",
"react": "19.2.4",
"react-dom": "19.2.4"
"react-dom": "19.2.4",
"react-hot-toast": "^2.6.0"
},
"devDependencies": {
"@tailwindcss/postcss": "^4",

View File

@@ -29,6 +29,7 @@ model User {
model Business {
id String @id @default(uuid())
name String
slug String? @unique
category String
location String
description String @db.Text

View File

@@ -2,6 +2,7 @@ import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
import Sidebar from "@/components/Sidebar";
import { Toaster } from 'react-hot-toast';
const inter = Inter({ subsets: ["latin"] });
@@ -18,6 +19,7 @@ export default function RootLayout({
return (
<html lang="fr">
<body className={inter.className}>
<Toaster position="bottom-right" />
<div className="flex min-h-screen">
<Sidebar />
<main className="admin-content flex-1">

View File

@@ -5,6 +5,7 @@ import { useRouter } from 'next/navigation';
import { createBlogPost, updateBlogPost } from '@/app/actions/blog';
import { Loader2, ArrowLeft, Save } from 'lucide-react';
import Link from 'next/link';
import { toast } from 'react-hot-toast';
interface Props {
initialData?: {
@@ -38,10 +39,11 @@ export default function BlogForm({ initialData }: Props) {
: await createBlogPost(data);
if (result.success) {
toast.success(initialData ? "Article mis à jour" : "Article publié avec succès");
router.push('/blog');
router.refresh();
} else {
alert(result.error);
toast.error(result.error || "Une erreur est survenue");
}
});
};

View File

@@ -3,6 +3,7 @@
import { useTransition } from 'react';
import { deleteBlogPost } from '@/app/actions/blog';
import { Trash2, Loader2 } from 'lucide-react';
import { toast } from 'react-hot-toast';
export default function DeleteBlogButton({ id }: { id: string }) {
const [isPending, startTransition] = useTransition();
@@ -11,7 +12,11 @@ export default function DeleteBlogButton({ id }: { id: string }) {
if (confirm("Supprimer cet article ?")) {
startTransition(async () => {
const result = await deleteBlogPost(id);
if (!result.success) alert(result.error);
if (result.success) {
toast.success("Article supprimé");
} else {
toast.error(result.error || "Erreur lors de la suppression");
}
});
}
};

View File

@@ -3,6 +3,7 @@
import { useTransition } from 'react';
import { deleteComment } from '@/app/actions/comment';
import { Trash2, Loader2 } from 'lucide-react';
import { toast } from 'react-hot-toast';
interface Props {
id: string;
@@ -15,8 +16,10 @@ export default function DeleteCommentButton({ id }: Props) {
if (confirm("Êtes-vous sûr de vouloir supprimer ce commentaire ?")) {
startTransition(async () => {
const result = await deleteComment(id);
if (!result.success) {
alert(result.error);
if (result.success) {
toast.success("Commentaire supprimé");
} else {
toast.error(result.error || "Erreur lors de la suppression");
}
});
}

View File

@@ -3,6 +3,7 @@
import { useTransition } from 'react';
import { deleteInterview } from '@/app/actions/interview';
import { Trash2, Loader2 } from 'lucide-react';
import { toast } from 'react-hot-toast';
export default function DeleteInterviewButton({ id }: { id: string }) {
const [isPending, startTransition] = useTransition();
@@ -11,7 +12,11 @@ export default function DeleteInterviewButton({ id }: { id: string }) {
if (confirm("Supprimer cette interview ?")) {
startTransition(async () => {
const result = await deleteInterview(id);
if (!result.success) alert(result.error);
if (result.success) {
toast.success("Interview supprimée");
} else {
toast.error(result.error || "Erreur lors de la suppression");
}
});
}
};

View File

@@ -3,6 +3,7 @@
import { useState, useTransition } from 'react';
import { setFeaturedBusiness, removeFeaturedBusiness } from '@/app/actions/business';
import { Star, X, Loader2, Save } from 'lucide-react';
import { toast } from 'react-hot-toast';
interface Props {
business: {
@@ -31,9 +32,10 @@ export default function FeaturedModal({ business }: Props) {
startTransition(async () => {
const result = await setFeaturedBusiness(business.id, data);
if (result.success) {
toast.success("Entrepreneur du mois mis à jour !");
setIsOpen(false);
} else {
alert(result.error);
toast.error(result.error || "Une erreur est survenue");
}
});
};
@@ -42,7 +44,12 @@ export default function FeaturedModal({ business }: Props) {
if (confirm("Retirer cet entrepreneur du titre 'Entrepreneur du mois' ?")) {
startTransition(async () => {
const result = await removeFeaturedBusiness(business.id);
if (result.success) setIsOpen(false);
if (result.success) {
toast.success("Titre révoqué");
setIsOpen(false);
} else {
toast.error(result.error);
}
});
}
};

View File

@@ -6,6 +6,7 @@ import { createInterview, updateInterview } from '@/app/actions/interview';
import { Loader2, ArrowLeft, Save, Video, FileText } from 'lucide-react';
import Link from 'next/link';
import { InterviewType } from '@prisma/client';
import { toast } from 'react-hot-toast';
interface Props {
initialData?: any;
@@ -37,10 +38,11 @@ export default function InterviewForm({ initialData }: Props) {
: await createInterview(data);
if (result.success) {
toast.success(initialData ? "Interview mise à jour" : "Interview créée avec succès");
router.push('/blog');
router.refresh();
} else {
alert(result.error);
toast.error(result.error || "Une erreur est survenue");
}
});
};

View File

@@ -3,6 +3,7 @@
import { useTransition } from 'react';
import { toggleVerification } from '@/app/actions/business';
import { CheckCircle, XCircle, Loader2 } from 'lucide-react';
import { toast } from 'react-hot-toast';
interface Props {
id: string;
@@ -15,8 +16,10 @@ export default function ToggleVerifyButton({ id, verified }: Props) {
const handleToggle = () => {
startTransition(async () => {
const result = await toggleVerification(id, verified);
if (!result.success) {
alert(result.error);
if (result.success) {
toast.success(verified ? "Vérification révoquée" : "Entreprise validée");
} else {
toast.error(result.error || "Une erreur est survenue");
}
});
};