refactor: remove ResourceBookingPage and related components; update references in AppointmentsPage and ScheduleSection
This commit is contained in:
@@ -1,39 +0,0 @@
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||||
import { render, screen, act } from '@testing-library/react';
|
||||
import HoldCountdown from './HoldCountdown';
|
||||
|
||||
describe('HoldCountdown', () => {
|
||||
beforeEach(() => vi.useFakeTimers());
|
||||
afterEach(() => vi.useRealTimers());
|
||||
|
||||
const nowSeconds = () => Math.floor(Date.now() / 1000);
|
||||
|
||||
it('counts down from the server expiry', () => {
|
||||
render(<HoldCountdown expiresAt={nowSeconds() + 125} onExpired={() => {}} />);
|
||||
|
||||
expect(screen.getByText(/2:05/)).toBeInTheDocument();
|
||||
|
||||
act(() => { vi.advanceTimersByTime(5000); });
|
||||
|
||||
expect(screen.getByText(/2:00/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
/** ⭐ رزروی که در سکوت منقضی شود، اپراتور را با یک ۴۰۹ بیتوضیح تنها میگذارد. */
|
||||
it('reports expiry to the parent exactly once it lapses', () => {
|
||||
const onExpired = vi.fn();
|
||||
render(<HoldCountdown expiresAt={nowSeconds() + 2} onExpired={onExpired} />);
|
||||
|
||||
expect(onExpired).not.toHaveBeenCalled();
|
||||
|
||||
act(() => { vi.advanceTimersByTime(3000); });
|
||||
|
||||
expect(onExpired).toHaveBeenCalled();
|
||||
expect(screen.getByText('مهلت تمام شد')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('switches to the urgent style under a minute', () => {
|
||||
const { container } = render(<HoldCountdown expiresAt={nowSeconds() + 30} onExpired={() => {}} />);
|
||||
|
||||
expect(container.querySelector('.badge.red')).not.toBeNull();
|
||||
});
|
||||
});
|
||||
@@ -1,56 +0,0 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
interface Props {
|
||||
expiresAt: number;
|
||||
onExpired: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* شمارش معکوس مهلت رزرو موقت.
|
||||
*
|
||||
* بدون این، اپراتور نمیداند چقدر وقت دارد و رزرو در سکوت منقضی میشود — بعد کلیک
|
||||
* «ثبت» یک ۴۰۹ میگیرد که هیچجا توضیحش را ندیده.
|
||||
*
|
||||
* مبنا `expires_at` سرور است، نه شمارندهای که از لحظهٔ رندر شروع شود: ساعت مرورگر و
|
||||
* تأخیر شبکه هر دو میتوانند چند ثانیه اختلاف بسازند و آن چند ثانیه دقیقاً همانجایی
|
||||
* است که رزرو از دست میرود.
|
||||
*/
|
||||
export default function HoldCountdown({ expiresAt, onExpired }: Props) {
|
||||
const [remaining, setRemaining] = useState(() => expiresAt - Math.floor(Date.now() / 1000));
|
||||
|
||||
useEffect(() => {
|
||||
const tick = () => {
|
||||
const left = expiresAt - Math.floor(Date.now() / 1000);
|
||||
setRemaining(left);
|
||||
|
||||
if (left <= 0) onExpired();
|
||||
};
|
||||
|
||||
tick();
|
||||
const timer = setInterval(tick, 1000);
|
||||
|
||||
return () => clearInterval(timer);
|
||||
}, [expiresAt, onExpired]);
|
||||
|
||||
if (remaining <= 0) {
|
||||
return (
|
||||
<span className="badge red">
|
||||
<span className="bdot" />
|
||||
مهلت تمام شد
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
const minutes = Math.floor(remaining / 60);
|
||||
const seconds = remaining % 60;
|
||||
|
||||
// زیر یک دقیقه هشدار میگیرد؛ همان لحظهای که اپراتور باید تصمیمش را بگیرد.
|
||||
const urgent = remaining < 60;
|
||||
|
||||
return (
|
||||
<span className={urgent ? 'badge red' : 'badge amber'}>
|
||||
<span className="bdot" />
|
||||
مهلت ثبت: {minutes}:{String(seconds).padStart(2, '0')}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
@@ -86,9 +86,9 @@ const MODE_LABELS: Record<BookingMeta['booking_mode'], string> = {
|
||||
};
|
||||
|
||||
/**
|
||||
* حالتهای قابل انتخاب برای پزشک. `resource` عمداً اینجا نیست: نوبتدهی منبعمحور از
|
||||
* تنظیمات پزشک برداشته شده و مسیر خودش (صفحهٔ «نوبت منبعمحور» و تقویم هر منبع) را
|
||||
* دارد. انتخابش برگشتناپذیر بود و محیط را قفل میکرد.
|
||||
* حالتهای قابل انتخاب برای پزشک. `resource` عمداً اینجا نیست: انتخابش برگشتناپذیر
|
||||
* بود و محیط را قفل میکرد، پس از تنظیمات پزشک برداشته شد. صفحهٔ «نوبت منبعمحور» هم
|
||||
* در ۲۰۲۶-۰۸-۰۸ حذف شد؛ رکوردهای قدیمی فقط خواندنی اعلام میشوند (پایین همین فایل).
|
||||
*/
|
||||
const BOOKING_MODE_CARDS: ReadonlyArray<readonly [BookingMeta['booking_mode'], string, string]> = [
|
||||
['slot', 'نوبتدهی اسلاتی', 'شما بازههای کاری و «مدت هر نوبت» را مشخص میکنید؛ سیستم بازه را به نوبتهای هماندازه تقسیم میکند. مناسب ویزیتهای با زمان یکسان.'],
|
||||
|
||||
Reference in New Issue
Block a user