canina/frontend/admin-panel/src/pages/CMS.tsx

183 lines
8.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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>
);
}