2 Commits

Author SHA1 Message Date
c22d82f8c5 fix(dates): block past-date selection in appointment + clinic holiday pickers
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Bug 556 triggered a broader audit of every date input in the app:

 - appointment-form DatePicker now has minValue=today(getLocalTimeZone()) —
   can't book or reschedule into the past (tightens bug 555 at the
   input layer too; the past-slot filter in masterdata service still
   handles the hour-granularity)
 - clinic-form holiday date picker gets the same — can't observe a
   holiday that already passed

Audit complete:
 - enquiry-form follow-up date: already had min=today (bug 556 fix)
 - appointment-form: fixed here
 - clinic-form holidays: fixed here
 - my-performance date filter: past valid (reports over history)
 - campaign-edit start/end: past valid (historical campaigns)
2026-04-16 05:41:46 +05:30
f52722086e fix(call-desk): Book Appt button label reflects New vs Reschedule
Bug 558: Appointment edit view persisted in Patient 360 after Back to
Worklist. Closed as not-a-bug — the edit flow now lives inside the
unified Book Appt drawer, so the same button opens either path. Rename
makes the intent explicit:
 - 'New Appt' when the caller has no upcoming appointments
 - 'New / Reschedule Appt' when upcoming appointments exist (pills
   inside the drawer let the agent pick which one to reschedule)
2026-04-16 05:41:33 +05:30
3 changed files with 12 additions and 2 deletions

View File

@@ -339,7 +339,9 @@ export const ActiveCallCard = ({ lead, callerPhone, missedCallId, onCallComplete
<Button size="sm" color={appointmentOpen ? 'primary' : 'secondary'} <Button size="sm" color={appointmentOpen ? 'primary' : 'secondary'}
iconLeading={({ className, ...rest }: any) => <FontAwesomeIcon icon={faCalendarPlus} className={className} {...rest} />} iconLeading={({ className, ...rest }: any) => <FontAwesomeIcon icon={faCalendarPlus} className={className} {...rest} />}
isDisabled={!wasAnsweredRef.current} isDisabled={!wasAnsweredRef.current}
onClick={() => { setAppointmentOpen(!appointmentOpen); setEnquiryOpen(false); setTransferOpen(false); }}>Book Appt</Button> onClick={() => { setAppointmentOpen(!appointmentOpen); setEnquiryOpen(false); setTransferOpen(false); }}>
{leadAppointments.length > 0 ? 'New / Reschedule Appt' : 'New Appt'}
</Button>
<Button size="sm" color={enquiryOpen ? 'primary' : 'secondary'} <Button size="sm" color={enquiryOpen ? 'primary' : 'secondary'}
iconLeading={({ className, ...rest }: any) => <FontAwesomeIcon icon={faClipboardQuestion} className={className} {...rest} />} iconLeading={({ className, ...rest }: any) => <FontAwesomeIcon icon={faClipboardQuestion} className={className} {...rest} />}
isDisabled={!wasAnsweredRef.current} isDisabled={!wasAnsweredRef.current}

View File

@@ -6,7 +6,7 @@ import { Select } from '@/components/base/select/select';
import { TextArea } from '@/components/base/textarea/textarea'; import { TextArea } from '@/components/base/textarea/textarea';
import { Button } from '@/components/base/buttons/button'; import { Button } from '@/components/base/buttons/button';
import { DatePicker } from '@/components/application/date-picker/date-picker'; import { DatePicker } from '@/components/application/date-picker/date-picker';
import { parseDate } from '@internationalized/date'; import { parseDate, today, getLocalTimeZone } from '@internationalized/date';
import { apiClient } from '@/lib/api-client'; import { apiClient } from '@/lib/api-client';
import { cx } from '@/utils/cx'; import { cx } from '@/utils/cx';
import { notify } from '@/lib/toast'; import { notify } from '@/lib/toast';
@@ -586,6 +586,11 @@ export const AppointmentForm = ({
onChange={(val) => setDate(val ? val.toString() : '')} onChange={(val) => setDate(val ? val.toString() : '')}
granularity="day" granularity="day"
isDisabled={readOnly || !doctor} isDisabled={readOnly || !doctor}
// Block past dates — appointments can't be booked or
// rescheduled into the past. React Aria's DatePicker
// honours minValue in both the calendar grid and the
// typed-input fallback.
minValue={today(getLocalTimeZone())}
/> />
</div> </div>

View File

@@ -399,6 +399,9 @@ export const ClinicForm = ({ value, onChange }: ClinicFormProps) => {
onChange={(dv: DateValue | null) => onChange={(dv: DateValue | null) =>
updateHoliday(idx, { date: dv ? dv.toString() : '' }) updateHoliday(idx, { date: dv ? dv.toString() : '' })
} }
// Holidays must be today or in the future — you
// can't observe a holiday that already passed.
minValue={today(getLocalTimeZone())}
/> />
</div> </div>
<div className="flex-1"> <div className="flex-1">