183 lines
8.0 KiB
TypeScript
183 lines
8.0 KiB
TypeScript
import React, { useState, useEffect } from 'react';
|
||
import api from '../services/api';
|
||
|
||
export default function CMS() {
|
||
const [banners, setBanners] = useState<any[]>([]);
|
||
const [testimonials, setTestimonials] = useState<any[]>([]);
|
||
const [activeTab, setActiveTab] = useState<'banners' | 'testimonials'>('banners');
|
||
|
||
// Form States
|
||
const [newTitle, setNewTitle] = useState('');
|
||
const [newSubtitle, setNewSubtitle] = useState('');
|
||
const [newImageUrl, setNewImageUrl] = useState('');
|
||
|
||
const [vetName, setVetName] = useState('');
|
||
const [clinicName, setClinicName] = useState('');
|
||
const [quote, setQuote] = useState('');
|
||
|
||
useEffect(() => {
|
||
fetchData();
|
||
}, []);
|
||
|
||
const fetchData = async () => {
|
||
try {
|
||
const [bannersRes, testimonialsRes] = await Promise.all([
|
||
api.get('/admin/cms/hero-banners').catch(() => ({ data: [] })),
|
||
api.get('/admin/cms/vet-testimonials').catch(() => ({ data: [] })),
|
||
]);
|
||
setBanners(bannersRes.data || []);
|
||
setTestimonials(testimonialsRes.data || []);
|
||
} catch (err) {
|
||
console.error('Failed to fetch CMS data:', err);
|
||
}
|
||
};
|
||
|
||
const handleAddBanner = async (e: React.FormEvent) => {
|
||
e.preventDefault();
|
||
try {
|
||
await api.post('/admin/cms/hero-banners', {
|
||
title: newTitle,
|
||
subtitle: newSubtitle,
|
||
imageUrl: newImageUrl || '/assets/images/hero-section-image.png',
|
||
isActive: true,
|
||
});
|
||
setNewTitle('');
|
||
setNewSubtitle('');
|
||
setNewImageUrl('');
|
||
fetchData();
|
||
alert('بنر با موفقیت ایجاد شد');
|
||
} catch (err) {
|
||
alert('خطا در ایجاد بنر');
|
||
}
|
||
};
|
||
|
||
const handleAddTestimonial = async (e: React.FormEvent) => {
|
||
e.preventDefault();
|
||
try {
|
||
await api.post('/admin/cms/vet-testimonials', {
|
||
vetName,
|
||
clinicName,
|
||
quote,
|
||
rating: 5,
|
||
isActive: true,
|
||
});
|
||
setVetName('');
|
||
setClinicName('');
|
||
setQuote('');
|
||
fetchData();
|
||
alert('نظر دامپزشک ثبت شد');
|
||
} catch (err) {
|
||
alert('خطا در ایجاد نظر دامپزشک');
|
||
}
|
||
};
|
||
|
||
const handleDeleteBanner = async (id: string) => {
|
||
if (!confirm('آیا از حذف بنر مطمئن هستید؟')) return;
|
||
await api.delete(`/admin/cms/hero-banners/${id}`);
|
||
fetchData();
|
||
};
|
||
|
||
const handleDeleteTestimonial = async (id: string) => {
|
||
if (!confirm('آیا از حذف نظر مطمئن هستید؟')) return;
|
||
await api.delete(`/admin/cms/vet-testimonials/${id}`);
|
||
fetchData();
|
||
};
|
||
|
||
return (
|
||
<div className="p-6 font-vazir" dir="rtl">
|
||
<h1 className="text-2xl font-bold mb-6 text-gray-800">مدیریت محتوای پویا (CMS) — بنرها و نظرات دامپزشکان</h1>
|
||
|
||
<div className="flex gap-4 mb-6 border-b border-gray-200">
|
||
<button
|
||
onClick={() => setActiveTab('banners')}
|
||
className={`pb-3 px-4 font-bold border-b-2 transition-colors ${activeTab === 'banners' ? 'border-blue-600 text-blue-600' : 'border-transparent text-gray-500'}`}
|
||
>
|
||
بنرهای هیرو
|
||
</button>
|
||
<button
|
||
onClick={() => setActiveTab('testimonials')}
|
||
className={`pb-3 px-4 font-bold border-b-2 transition-colors ${activeTab === 'testimonials' ? 'border-blue-600 text-blue-600' : 'border-transparent text-gray-500'}`}
|
||
>
|
||
نظرات دامپزشکان
|
||
</button>
|
||
</div>
|
||
|
||
{activeTab === 'banners' && (
|
||
<div>
|
||
<form onSubmit={handleAddBanner} className="bg-white p-6 rounded-2xl shadow-sm border border-gray-100 mb-8 max-w-2xl space-y-4">
|
||
<h3 className="font-bold text-lg text-gray-700">افزودن بنر جدید</h3>
|
||
<div>
|
||
<label className="block text-xs font-bold text-gray-600 mb-1">عنوان اصلی بنر</label>
|
||
<input required value={newTitle} onChange={e => setNewTitle(e.target.value)} className="w-full border rounded-xl p-2.5 text-sm" placeholder="تخصص آلمانی در خدمت سلامت پت..." />
|
||
</div>
|
||
<div>
|
||
<label className="block text-xs font-bold text-gray-600 mb-1">زیرعنوان / توضیحات</label>
|
||
<textarea value={newSubtitle} onChange={e => setNewSubtitle(e.target.value)} className="w-full border rounded-xl p-2.5 text-sm" rows={2} placeholder="توضیحات بنر..." />
|
||
</div>
|
||
<div>
|
||
<label className="block text-xs font-bold text-gray-600 mb-1">آدرس تصویر (URL)</label>
|
||
<input value={newImageUrl} onChange={e => setNewImageUrl(e.target.value)} className="w-full border rounded-xl p-2.5 text-sm" placeholder="/assets/images/..." />
|
||
</div>
|
||
<button type="submit" className="bg-blue-600 text-white font-bold px-6 py-2.5 rounded-xl hover:bg-blue-700 text-sm">
|
||
ثبت بنر جدید
|
||
</button>
|
||
</form>
|
||
|
||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
{banners.map((b: any) => (
|
||
<div key={b.id} className="bg-white p-4 rounded-2xl border border-gray-200 flex justify-between items-start">
|
||
<div>
|
||
<h4 className="font-bold text-gray-900">{b.title}</h4>
|
||
<p className="text-xs text-gray-500 mt-1">{b.subtitle}</p>
|
||
</div>
|
||
<button onClick={() => handleDeleteBanner(b.id)} className="text-red-500 text-xs font-bold bg-red-50 px-3 py-1.5 rounded-lg hover:bg-red-100">
|
||
حذف
|
||
</button>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{activeTab === 'testimonials' && (
|
||
<div>
|
||
<form onSubmit={handleAddTestimonial} className="bg-white p-6 rounded-2xl shadow-sm border border-gray-100 mb-8 max-w-2xl space-y-4">
|
||
<h3 className="font-bold text-lg text-gray-700">افزودن نظر دامپزشک</h3>
|
||
<div className="grid grid-cols-2 gap-4">
|
||
<div>
|
||
<label className="block text-xs font-bold text-gray-600 mb-1">نام دامپزشک</label>
|
||
<input required value={vetName} onChange={e => setVetName(e.target.value)} className="w-full border rounded-xl p-2.5 text-sm" placeholder="دکتر علی محمدی" />
|
||
</div>
|
||
<div>
|
||
<label className="block text-xs font-bold text-gray-600 mb-1">نام کلینیک / بیمارستان</label>
|
||
<input value={clinicName} onChange={e => setClinicName(e.target.value)} className="w-full border rounded-xl p-2.5 text-sm" placeholder="کلینیک دامپزشکی پایتخت" />
|
||
</div>
|
||
</div>
|
||
<div>
|
||
<label className="block text-xs font-bold text-gray-600 mb-1">متن نظر و تجربه علمی</label>
|
||
<textarea required value={quote} onChange={e => setQuote(e.target.value)} className="w-full border rounded-xl p-2.5 text-sm" rows={3} placeholder="تجربه استفاده از Canhydrox GAG..." />
|
||
</div>
|
||
<button type="submit" className="bg-blue-600 text-white font-bold px-6 py-2.5 rounded-xl hover:bg-blue-700 text-sm">
|
||
ثبت نظر جدید
|
||
</button>
|
||
</form>
|
||
|
||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
{testimonials.map((t: any) => (
|
||
<div key={t.id} className="bg-white p-4 rounded-2xl border border-gray-200 flex justify-between items-start">
|
||
<div>
|
||
<h4 className="font-bold text-gray-900">{t.vetName} — <span className="text-blue-600">{t.clinicName}</span></h4>
|
||
<p className="text-xs text-gray-600 mt-2 font-medium">"{t.quote}"</p>
|
||
</div>
|
||
<button onClick={() => handleDeleteTestimonial(t.id)} className="text-red-500 text-xs font-bold bg-red-50 px-3 py-1.5 rounded-lg hover:bg-red-100">
|
||
حذف
|
||
</button>
|
||
</div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
);
|
||
}
|