improvement: datepicker component now let user choose past dates too.

This commit is contained in:
2026-05-08 14:25:44 +03:30
parent a0348e4079
commit 803564802c
5 changed files with 127 additions and 45 deletions

View File

@@ -17,7 +17,7 @@ import { ScheduleDayPicker } from '@/components/ui/common/ScheduleDayPicker';
import { Toast } from '@/components/ui/common/Toast';
import type { AppointmentPurpose } from '@/types/appointment';
import { formatApiErrorMessage } from '@/lib/formatApiError';
import { getLocalDayIsoRange, startOfLocalDay } from '@/lib/appointmentTime';
import { compareLocalDayStart, getLocalDayIsoRange, startOfLocalDay } from '@/lib/appointmentTime';
const EMPTY_PATIENT_FORM: CreatePatientInput = {
firstName: '',
@@ -48,6 +48,7 @@ export default function AppointmentsPage() {
const [bookingHour, setBookingHour] = useState(9);
const [bookingProviderId, setBookingProviderId] = useState<string | null>(null);
const [bookingProviderName, setBookingProviderName] = useState('');
const [editingAppointmentId, setEditingAppointmentId] = useState<string | null>(null);
const [savingAppointment, setSavingAppointment] = useState(false);
const [toastError, setToastError] = useState('');
@@ -58,6 +59,14 @@ export default function AppointmentsPage() {
const canEditPatients = hasPermission(currentOrganization, 'TAB_PATIENTS_EDIT');
const todayStart = useMemo(() => startOfLocalDay(new Date()), []);
const isViewingPastDay = useMemo(
() => compareLocalDayStart(scheduleDate, todayStart) < 0,
[scheduleDate, todayStart],
);
const activeEditingAppointment = useMemo(
() => appointments.find((a) => a.id === editingAppointmentId) ?? null,
[appointments, editingAppointmentId],
);
const scheduleLoadGen = useRef(0);
@@ -155,6 +164,12 @@ export default function AppointmentsPage() {
}
function handleSlotClick(hour: number, providerUserId: string, providerName: string) {
if (isViewingPastDay) {
setToastSuccess('');
setToastError('');
setToastInfo('Past appointments are view-only.');
return;
}
if (!selectedPatient) {
setToastSuccess('');
setToastError('');
@@ -164,6 +179,22 @@ export default function AppointmentsPage() {
setBookingHour(hour);
setBookingProviderId(providerUserId);
setBookingProviderName(providerName);
setEditingAppointmentId(null);
setBookingOpen(true);
}
function handleAppointmentClick(appointment: AppointmentRecord) {
if (isViewingPastDay) {
setToastSuccess('');
setToastError('');
setToastInfo('Past appointments are view-only.');
return;
}
const provider = providers.find((p) => p.userId === appointment.providerUserId);
setBookingHour(new Date(appointment.startAt).getHours());
setBookingProviderId(appointment.providerUserId);
setBookingProviderName(provider?.name ?? bookingProviderName);
setEditingAppointmentId(appointment.id);
setBookingOpen(true);
}
@@ -179,15 +210,22 @@ export default function AppointmentsPage() {
setToastSuccess('');
setToastInfo('');
try {
await appointmentsApi.create(payload);
if (activeEditingAppointment) {
await appointmentsApi.update(activeEditingAppointment.id, payload);
} else {
await appointmentsApi.create(payload);
}
setBookingOpen(false);
setToastSuccess('Appointment saved.');
setEditingAppointmentId(null);
setToastSuccess(activeEditingAppointment ? 'Appointment updated.' : 'Appointment saved.');
await loadSchedule();
} catch (err: unknown) {
const message =
err && typeof err === 'object' && 'message' in err
? String((err as { message: unknown }).message)
: 'Could not save appointment.';
: activeEditingAppointment
? 'Could not update appointment.'
: 'Could not save appointment.';
setToastError(message);
} finally {
setSavingAppointment(false);
@@ -285,10 +323,11 @@ export default function AppointmentsPage() {
day={scheduleDate}
providers={providers}
appointments={appointments}
canBook={canManageAppointments}
canBook={canManageAppointments && !isViewingPastDay}
canDelete={canManageAppointments}
onDeleteAppointment={(id) => void handleDeleteAppointment(id)}
onSlotClick={(hour, uid, name) => handleSlotClick(hour, uid, name)}
onAppointmentClick={(apt) => handleAppointmentClick(apt)}
/>
</div>
</div>
@@ -300,7 +339,11 @@ export default function AppointmentsPage() {
providerUserId={bookingProviderId}
providerName={bookingProviderName}
initialHour={bookingHour}
onClose={() => setBookingOpen(false)}
editingAppointment={activeEditingAppointment}
onClose={() => {
setBookingOpen(false);
setEditingAppointmentId(null);
}}
onSubmit={handleSaveAppointment}
loading={savingAppointment}
/>