feat: refactor ResourceExceptionsPanel and related hooks; remove unused availability logic and simplify resource detail management
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { PencilIcon } from '@heroicons/react/24/outline';
|
||||
import PageHeader from '../components/ui/PageHeader';
|
||||
import ConfirmDialog from '../components/ui/ConfirmDialog';
|
||||
@@ -44,7 +44,6 @@ const SUBJECT_LABEL: Record<string, string> = {
|
||||
*/
|
||||
export default function ResourceDetailPage() {
|
||||
const { resourceUuid } = useParams<{ resourceUuid: string }>();
|
||||
const navigate = useNavigate();
|
||||
const [urlState, setUrlState] = useUrlState({ tab: 'info' });
|
||||
const tab = (TABS.some((t) => t.id === urlState.tab) ? urlState.tab : 'info') as TabId;
|
||||
|
||||
@@ -52,14 +51,14 @@ export default function ResourceDetailPage() {
|
||||
const { addresses } = useAddresses();
|
||||
const { types } = useResourceTypes();
|
||||
const { skills } = useSkills();
|
||||
const { update, remove, setSkills, setCategories } = useResources();
|
||||
const { update, setSkills, setCategories } = useResources();
|
||||
const { offerings, save: saveServices } = useResourceServices(resourceUuid);
|
||||
const { items: serviceOptions } = useAllServiceItems();
|
||||
const { can } = usePermissions();
|
||||
const canUpdate = can('appointment_settings', 'update');
|
||||
|
||||
const [editOpen, setEditOpen] = useState(false);
|
||||
const [confirmDelete, setConfirmDelete] = useState(false);
|
||||
const [confirmDeactivate, setConfirmDeactivate] = useState(false);
|
||||
|
||||
// حالتهای بارگذاری و نبودِ منبع هم داخل پوستهٔ تنظیمات میمانند، وگرنه منوی کناری
|
||||
// یک لحظه میپرد و دوباره برمیگردد.
|
||||
@@ -110,8 +109,12 @@ export default function ResourceDetailPage() {
|
||||
resource={resource}
|
||||
canUpdate={canUpdate}
|
||||
toggling={update.isPending}
|
||||
onToggleActive={() => update.mutate({ uuid: resource.uuid, d: { active: !resource.active } })}
|
||||
onDelete={() => setConfirmDelete(true)}
|
||||
// فعال کردن بیخطر است و مستقیم انجام میشود؛ غیرفعال کردن منبع را از
|
||||
// نوبتدهی بیرون میبرد، پس تأیید میگیرد.
|
||||
onToggleActive={() => {
|
||||
if (resource.active) setConfirmDeactivate(true);
|
||||
else update.mutate({ uuid: resource.uuid, d: { active: true } });
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -153,23 +156,20 @@ export default function ResourceDetailPage() {
|
||||
|
||||
{tab === 'blocks' && <ResourceBlocksPanel resourceUuid={resourceUuid} canUpdate={canUpdate} />}
|
||||
|
||||
{/* حذف موفق یعنی این صفحه دیگر منبعی ندارد؛ ماندن روی آن یک «منبع یافت نشد» است. */}
|
||||
<ConfirmDialog
|
||||
open={confirmDelete}
|
||||
title="حذف منبع"
|
||||
message={`آیا از حذف «${resource.name}» مطمئن هستید؟ این کار برگشتپذیر نیست.`}
|
||||
confirmLabel="حذف"
|
||||
open={confirmDeactivate}
|
||||
title="غیرفعال کردن منبع"
|
||||
message={`«${resource.name}» پس از غیرفعال شدن در جستجوی وقت و رزرو نوبت ظاهر نمیشود. نوبتهای ثبتشده سرِ جایشان میمانند.`}
|
||||
confirmLabel="غیرفعال کن"
|
||||
danger
|
||||
loading={remove.isPending}
|
||||
loading={update.isPending}
|
||||
onConfirm={() =>
|
||||
remove.mutate(resource.uuid, {
|
||||
onSuccess: () => {
|
||||
setConfirmDelete(false);
|
||||
navigate('/admin/resources');
|
||||
},
|
||||
})
|
||||
update.mutate(
|
||||
{ uuid: resource.uuid, d: { active: false } },
|
||||
{ onSuccess: () => setConfirmDeactivate(false) },
|
||||
)
|
||||
}
|
||||
onCancel={() => setConfirmDelete(false)}
|
||||
onCancel={() => setConfirmDeactivate(false)}
|
||||
/>
|
||||
|
||||
<ResourceFormModal
|
||||
@@ -200,18 +200,16 @@ function Row({ label, children }: { label: string; children: React.ReactNode })
|
||||
}
|
||||
|
||||
/**
|
||||
* اطلاعات منبع + دو اقدامِ سطح-منبع.
|
||||
* اطلاعات منبع + وضعیت فعال/غیرفعالش.
|
||||
*
|
||||
* فعال/غیرفعال و حذف پیشتر دکمههای ردیفِ جدول بودند. جدول حالا فقط فهرست است و
|
||||
* هر اقدام کنارِ همان چیزی نشسته که تغییرش میدهد؛ حذف هم پایین و جدا از بقیه است
|
||||
* تا با «ویرایش» و «غیرفعال» یکجا هموزن دیده نشود.
|
||||
* حذفِ منبع عمداً در رابط کاربری نیست: منبع به نوبتهای ثبتشده گره خورده و راهِ
|
||||
* درستِ «دیگر لازمش ندارم» غیرفعال کردن است، نه پاک کردن.
|
||||
*/
|
||||
function InfoTab({ resource, canUpdate, toggling, onToggleActive, onDelete }: {
|
||||
function InfoTab({ resource, canUpdate, toggling, onToggleActive }: {
|
||||
resource: ClinicResource;
|
||||
canUpdate: boolean;
|
||||
toggling: boolean;
|
||||
onToggleActive: () => void;
|
||||
onDelete: () => void;
|
||||
}) {
|
||||
const attributes = Object.entries(resource.attributes ?? {});
|
||||
|
||||
@@ -270,23 +268,13 @@ function InfoTab({ resource, canUpdate, toggling, onToggleActive, onDelete }: {
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
className={resource.active ? 'btn secondary' : 'btn primary'}
|
||||
className={resource.active ? 'btn danger' : 'btn primary'}
|
||||
disabled={toggling}
|
||||
onClick={onToggleActive}
|
||||
>
|
||||
{resource.active ? 'غیرفعال کردن' : 'فعال کردن'}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* پسزمینه عمداً خنثی میماند: `.btn.danger` خودش `--danger-bg` است و روی
|
||||
ردیفِ همرنگ نامرئی میشد. مرزِ قرمز بهتنهایی هشدار را میرساند. */}
|
||||
<div className="toggle-row" style={{ marginTop: 10, borderColor: 'var(--danger)' }}>
|
||||
<div>
|
||||
<div className="tr-title">حذف منبع</div>
|
||||
<div className="tr-desc">برگشتپذیر نیست. اگر فقط موقتاً لازمش ندارید، غیرفعالش کنید.</div>
|
||||
</div>
|
||||
<button type="button" className="btn danger" onClick={onDelete}>حذف</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user