refactor: simplify Topbar component and remove unused code
- Removed breadcrumb functionality and related code from Topbar. - Consolidated mobile and desktop sidebar toggle logic. - Adjusted icon sizes and styles for consistency. - Cleaned up unused imports and props in Topbar. refactor: enhance DoctorDetailPage session editor UI - Improved layout and styling of session editor for better usability. - Removed advanced settings toggle and integrated relevant fields directly. - Added visual indicators for session slots and rest periods. refactor: streamline DoctorsPage component - Removed bulk selection functionality and related state management. - Simplified rendering logic for doctor list and adjusted table structure. - Cleaned up unused imports and components for better readability. refactor: optimize UsersPage component - Removed bulk selection and deletion functionality. - Simplified user table structure and adjusted column spans. - Cleaned up unused state and imports for improved clarity.
This commit is contained in:
@@ -5,8 +5,6 @@ import {
|
||||
MagnifyingGlassIcon, PlusIcon, EyeIcon, TrashIcon, ArrowPathIcon,
|
||||
CheckCircleIcon, XCircleIcon, TableCellsIcon, Squares2X2Icon,
|
||||
} from '@heroicons/react/24/outline';
|
||||
import { StarIcon as StarSolid } from '@heroicons/react/24/solid';
|
||||
import { StarIcon } from '@heroicons/react/24/outline';
|
||||
import { XMarkIcon } from '@heroicons/react/24/outline';
|
||||
import { toast } from 'sonner';
|
||||
import { api } from '../lib/api';
|
||||
@@ -87,18 +85,6 @@ function DoctorAvatar({ name, id, image, size = 'sm' }: {
|
||||
);
|
||||
}
|
||||
|
||||
function StarRating({ rate }: { rate: number }) {
|
||||
return (
|
||||
<span className="stars" dir="ltr">
|
||||
{Array.from({ length: 5 }).map((_, i) =>
|
||||
i < Math.round(rate)
|
||||
? <StarSolid key={i} style={{ width: 13, height: 13 }} />
|
||||
: <StarIcon key={i} style={{ width: 13, height: 13, color: 'var(--border-2)' }} />
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
// ── Main Page ─────────────────────────────────────────────────────────────
|
||||
|
||||
export default function DoctorsPage() {
|
||||
@@ -112,17 +98,14 @@ export default function DoctorsPage() {
|
||||
const [status, setStatus] = useState('');
|
||||
const [specialtyId, setSpecialty] = useState('');
|
||||
const [view, setView] = useState<'table' | 'grid'>('table');
|
||||
const [selected, setSelected] = useState<string[]>([]);
|
||||
const [deleteTarget, setDeleteTarget] = useState<AdminDoctor | null>(null);
|
||||
const [confirmBulkDel, setConfirmBulkDel] = useState(false);
|
||||
const [bulkDeleting, setBulkDeleting] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const t = setTimeout(() => { setSearch(searchInput); setPage(1); }, 350);
|
||||
return () => clearTimeout(t);
|
||||
}, [searchInput]);
|
||||
|
||||
useEffect(() => { setPage(1); setSelected([]); }, [status, specialtyId]);
|
||||
useEffect(() => { setPage(1); }, [status, specialtyId]);
|
||||
|
||||
// ── Queries ──
|
||||
|
||||
@@ -182,26 +165,6 @@ export default function DoctorsPage() {
|
||||
onError: (e: Error) => toast.error(e.message),
|
||||
});
|
||||
|
||||
// ── Bulk ──
|
||||
|
||||
const allSelected = items.length > 0 && items.every((d) => selected.includes(d.uuid));
|
||||
const toggleAll = () => setSelected(allSelected ? [] : items.map((d) => d.uuid));
|
||||
const toggleOne = (uuid: string) =>
|
||||
setSelected((prev) => prev.includes(uuid) ? prev.filter((id) => id !== uuid) : [...prev, uuid]);
|
||||
|
||||
const handleBulkDelete = async () => {
|
||||
setBulkDeleting(true);
|
||||
let count = 0;
|
||||
for (const uuid of selected) {
|
||||
try { await api.delete(`/api/v1/doctor/${uuid}`); count++; } catch {}
|
||||
}
|
||||
setBulkDeleting(false);
|
||||
setConfirmBulkDel(false);
|
||||
setSelected([]);
|
||||
toast.success(`${formatNumber(count)} پزشک حذف شد`);
|
||||
qc.invalidateQueries({ queryKey: ['admin-doctors'] });
|
||||
qc.invalidateQueries({ queryKey: ['doctors-stats'] });
|
||||
};
|
||||
|
||||
const kpiCards = [
|
||||
{ label: 'کل پزشکان', value: stats?.total, bg: 'var(--surface-3)', color: 'var(--text-2)' },
|
||||
@@ -293,33 +256,12 @@ export default function DoctorsPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Bulk bar */}
|
||||
{selected.length > 0 && (
|
||||
<div style={{
|
||||
padding: '10px 16px', background: 'var(--primary-soft)',
|
||||
borderBottom: '1px solid var(--border)',
|
||||
display: 'flex', alignItems: 'center', gap: 12,
|
||||
}}>
|
||||
<span style={{ fontSize: 13, color: 'var(--primary-700)', fontWeight: 600 }}>
|
||||
{formatNumber(selected.length)} پزشک انتخاب شده
|
||||
</span>
|
||||
<div style={{ display: 'flex', gap: 8, marginRight: 'auto' }}>
|
||||
<button className="btn danger sm" onClick={() => setConfirmBulkDel(true)}>حذف انتخابشدهها</button>
|
||||
<button className="btn ghost sm" onClick={() => setSelected([])}>لغو</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Table view */}
|
||||
{view === 'table' && (
|
||||
<div className="table-wrap">
|
||||
<table className="t">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style={{ width: 42 }}>
|
||||
<input type="checkbox" checked={allSelected} onChange={toggleAll}
|
||||
style={{ accentColor: 'var(--primary)', cursor: 'pointer' }} />
|
||||
</th>
|
||||
<th>پزشک</th>
|
||||
<th>تخصص</th>
|
||||
<th>درجه</th>
|
||||
@@ -332,7 +274,7 @@ export default function DoctorsPage() {
|
||||
<tbody>
|
||||
{doctorsQ.isLoading && Array.from({ length: 6 }).map((_, i) => (
|
||||
<tr key={i}>
|
||||
{Array.from({ length: 8 }).map((_, j) => (
|
||||
{Array.from({ length: 7 }).map((_, j) => (
|
||||
<td key={j}>
|
||||
<div className="skeleton" style={{ height: 14, borderRadius: 6, width: j === 1 ? '70%' : '55%' }} />
|
||||
</td>
|
||||
@@ -342,7 +284,7 @@ export default function DoctorsPage() {
|
||||
|
||||
{!doctorsQ.isLoading && items.length === 0 && (
|
||||
<tr>
|
||||
<td colSpan={8}>
|
||||
<td colSpan={7}>
|
||||
<div className="empty">هیچ پزشکی یافت نشد</div>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -350,11 +292,6 @@ export default function DoctorsPage() {
|
||||
|
||||
{!doctorsQ.isLoading && items.map((doc) => (
|
||||
<tr key={doc.uuid} style={{ cursor: 'pointer' }} onClick={() => navigate(`/admin/doctors/${doc.uuid}`)}>
|
||||
<td onClick={(e) => e.stopPropagation()}>
|
||||
<input type="checkbox" checked={selected.includes(doc.uuid)}
|
||||
onChange={() => toggleOne(doc.uuid)}
|
||||
style={{ accentColor: 'var(--primary)', cursor: 'pointer' }} />
|
||||
</td>
|
||||
<td>
|
||||
<div className="cell-user">
|
||||
<DoctorAvatar name={doc.name} id={doc.id} image={doc.profile_image} />
|
||||
@@ -380,12 +317,7 @@ export default function DoctorsPage() {
|
||||
</span>
|
||||
)}
|
||||
</td>
|
||||
<td>
|
||||
<div className="flex" style={{ gap: 5 }}>
|
||||
<StarRating rate={doc.rate} />
|
||||
<b style={{ fontSize: 12.5 }}>{doc.rate.toFixed(1)}</b>
|
||||
</div>
|
||||
</td>
|
||||
<td><b style={{ fontSize: 12.5 }}>{doc.rate.toFixed(1)}</b></td>
|
||||
<td style={{ fontFamily: 'monospace', direction: 'ltr', textAlign: 'right' }} className="muted">
|
||||
{doc.mobile ?? '—'}
|
||||
</td>
|
||||
@@ -461,10 +393,7 @@ export default function DoctorsPage() {
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex" style={{ justifyContent: 'space-between', fontSize: 12.5 }}>
|
||||
<span className="flex" style={{ gap: 5 }}>
|
||||
<StarRating rate={doc.rate} />
|
||||
<b>{doc.rate.toFixed(1)}</b>
|
||||
</span>
|
||||
<b>{doc.rate.toFixed(1)}</b>
|
||||
<span className="muted">{formatDate(doc.created_at)}</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -491,16 +420,6 @@ export default function DoctorsPage() {
|
||||
onCancel={() => setDeleteTarget(null)}
|
||||
/>
|
||||
|
||||
<ConfirmDialog
|
||||
open={confirmBulkDel}
|
||||
title="حذف گروهی"
|
||||
message={`آیا از حذف ${formatNumber(selected.length)} پزشک انتخابشده اطمینان دارید؟`}
|
||||
confirmLabel={`حذف ${formatNumber(selected.length)} پزشک`}
|
||||
danger
|
||||
loading={bulkDeleting}
|
||||
onConfirm={handleBulkDelete}
|
||||
onCancel={() => setConfirmBulkDel(false)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user