feat(admin): catalog groups and appointment segments editors
Tasks 04 and 05 shipped working engines that a clinic could only reach through the API. Both now have the panel that makes them usable. Groups tab - Inline min/max per group, saved on blur, with the meaning of an empty maximum spelled out next to the field rather than left as folklore - Incompatible / prerequisite rows; the prerequisite-cycle 422 surfaces the server's own message, which is more precise than anything generic - A live preview that calls the same service-selection/validate the public site calls, debounced 400ms. Two separate calculations would eventually show the operator and the patient different numbers - The breakdown table shows which item was counted as the anchor and which as additional, so a surprising total explains itself Segments tab - Sequence, duration source, patient-present and mergeable per segment, plus resource requirements with an explanation attached to each occupancy mode - A timeline bar whose widths are proportional to duration, with segments the patient is absent for drawn faded. That contrast is the whole point of task 05: the waiting segment holds the room but frees the operator - "No eligible resource" renders with a link to add one — an error with no route forward is a dead end Task 05's checklist had been left on "not started" this whole time even though its code shipped with the task; it is now filled in against reality. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -18,6 +18,8 @@ import { usePermissions } from '../hooks/usePermissions';
|
||||
import ServiceTariffModal from '../components/ServiceTariffModal';
|
||||
import ServiceInsuranceModal from '../components/ServiceInsuranceModal';
|
||||
import ServiceItemFormModal from '../components/ServiceItemFormModal';
|
||||
import ServiceGroupsTab from '../components/ServiceGroupsTab';
|
||||
import ServiceSegmentsTab from '../components/ServiceSegmentsTab';
|
||||
|
||||
interface Tariff {
|
||||
uuid: string;
|
||||
@@ -51,6 +53,8 @@ const TABS = [
|
||||
{ id: 'info', label: 'اطلاعات سرویس' },
|
||||
{ id: 'tariffs', label: 'تعرفهها' },
|
||||
{ id: 'insurance', label: 'بیمهها' },
|
||||
{ id: 'groups', label: 'گروهها و آیتمها' },
|
||||
{ id: 'segments', label: 'بخشهای نوبت' },
|
||||
{ id: 'goods', label: 'کالاهای مرتبط' },
|
||||
{ id: 'history', label: 'لاگ تغییرات' },
|
||||
] as const;
|
||||
@@ -537,6 +541,8 @@ function ServiceDetailPageInner() {
|
||||
{tab === 'info' && <InfoTab item={item} />}
|
||||
{tab === 'tariffs' && <TariffsTab item={item} onManage={() => setTariffOpen(true)} canUpdate={canUpdate} />}
|
||||
{tab === 'insurance' && <InsuranceTab item={item} onManage={() => setInsuranceOpen(true)} canUpdate={canUpdate} />}
|
||||
{tab === 'groups' && <ServiceGroupsTab serviceUuid={item.uuid} canEdit={canUpdate} />}
|
||||
{tab === 'segments' && <ServiceSegmentsTab serviceUuid={item.uuid} canEdit={canUpdate} />}
|
||||
{tab === 'goods' && <GoodsTab item={item} onEdit={() => setEditOpen(true)} canUpdate={canUpdate} />}
|
||||
{tab === 'history' && <HistoryTab item={item} />}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user