feat: implement core platform features including business directory, admin dashboard, authentication, and API infrastructure
Some checks failed
Build and Push App / build (push) Failing after 16m2s
Some checks failed
Build and Push App / build (push) Failing after 16m2s
This commit is contained in:
131
admin/src/components/LegalEditor.tsx
Normal file
131
admin/src/components/LegalEditor.tsx
Normal file
@@ -0,0 +1,131 @@
|
||||
"use client";
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import { LegalDocument } from '@prisma/client';
|
||||
import RichTextEditor from './RichTextEditor';
|
||||
import { updateLegalDocument } from '@/app/actions/legal';
|
||||
import { toast } from 'react-hot-toast';
|
||||
import { FileText, Save, Loader2 } from 'lucide-react';
|
||||
|
||||
interface Props {
|
||||
initialCgu: LegalDocument | null;
|
||||
initialCgv: LegalDocument | null;
|
||||
}
|
||||
|
||||
export default function LegalEditor({ initialCgu, initialCgv }: Props) {
|
||||
const [activeTab, setActiveTab] = useState<'CGU' | 'CGV'>('CGU');
|
||||
const [cgu, setCgu] = useState({
|
||||
title: initialCgu?.title || "Conditions Générales d'Utilisation",
|
||||
content: initialCgu?.content || ""
|
||||
});
|
||||
const [cgv, setCgv] = useState({
|
||||
title: initialCgv?.title || "Conditions Générales de Vente",
|
||||
content: initialCgv?.content || ""
|
||||
});
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
|
||||
const currentDoc = activeTab === 'CGU' ? cgu : cgv;
|
||||
|
||||
const handleUpdate = (field: string, value: string) => {
|
||||
if (activeTab === 'CGU') {
|
||||
setCgu(prev => ({ ...prev, [field]: value }));
|
||||
} else {
|
||||
setCgv(prev => ({ ...prev, [field]: value }));
|
||||
}
|
||||
};
|
||||
|
||||
const handleSave = async () => {
|
||||
setIsSaving(true);
|
||||
try {
|
||||
const result = await updateLegalDocument(activeTab, currentDoc.title, currentDoc.content);
|
||||
if (result.success) {
|
||||
toast.success(`${activeTab} mis à jour avec succès`);
|
||||
} else {
|
||||
toast.error(result.error || "Une erreur est survenue");
|
||||
}
|
||||
} catch (error) {
|
||||
toast.error("Erreur de connexion au serveur");
|
||||
} finally {
|
||||
setIsSaving(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="flex bg-slate-900/50 p-1 rounded-xl border border-slate-800 w-fit">
|
||||
<button
|
||||
onClick={() => setActiveTab('CGU')}
|
||||
className={`px-6 py-2 rounded-lg text-sm font-medium transition-all ${
|
||||
activeTab === 'CGU'
|
||||
? 'bg-indigo-600 text-white shadow-lg'
|
||||
: 'text-slate-400 hover:text-white hover:bg-slate-800'
|
||||
}`}
|
||||
>
|
||||
CGU
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setActiveTab('CGV')}
|
||||
className={`px-6 py-2 rounded-lg text-sm font-medium transition-all ${
|
||||
activeTab === 'CGV'
|
||||
? 'bg-indigo-600 text-white shadow-lg'
|
||||
: 'text-slate-400 hover:text-white hover:bg-slate-800'
|
||||
}`}
|
||||
>
|
||||
CGV
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="card">
|
||||
<div className="flex items-center justify-between mb-6">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-10 h-10 bg-indigo-600/20 text-indigo-400 rounded-xl flex items-center justify-center">
|
||||
<FileText className="w-5 h-5" />
|
||||
</div>
|
||||
<div>
|
||||
<h2 className="text-xl font-bold text-white">Modifier {activeTab}</h2>
|
||||
<p className="text-sm text-slate-400">Dernière mise à jour : {new Date().toLocaleDateString('fr-FR')}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
onClick={handleSave}
|
||||
disabled={isSaving}
|
||||
className="btn-primary flex items-center gap-2"
|
||||
>
|
||||
{isSaving ? <Loader2 className="w-4 h-4 animate-spin" /> : <Save className="w-4 h-4" />}
|
||||
Enregistrer les modifications
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-slate-400 mb-1.5 ml-1">Titre du document</label>
|
||||
<input
|
||||
type="text"
|
||||
value={currentDoc.title}
|
||||
onChange={(e) => handleUpdate('title', e.target.value)}
|
||||
className="w-full bg-slate-900 border border-slate-700 rounded-xl px-4 py-3 text-white focus:ring-2 focus:ring-indigo-500 outline-none transition-all"
|
||||
placeholder="Ex: Conditions Générales d'Utilisation"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-slate-400 mb-1.5 ml-1">Contenu</label>
|
||||
<RichTextEditor
|
||||
value={currentDoc.content}
|
||||
onChange={(val) => handleUpdate('content', val)}
|
||||
placeholder={`Commencez à rédiger vos ${activeTab}...`}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bg-amber-500/10 border border-amber-500/30 p-4 rounded-xl flex items-center gap-3 text-amber-500">
|
||||
<div className="shrink-0 w-8 h-8 rounded-full bg-amber-500/20 flex items-center justify-center">!</div>
|
||||
<p className="text-sm font-medium">
|
||||
Attention : Les modifications seront immédiatement visibles pour tous les utilisateurs sur le site public une fois enregistrées.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user