3 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
3f551c6505 merge: barge-whisper batch — today's P1/P2 fixes + dashboard merge + pagination
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Lands 40 commits from feature/barge-whisper into master as a single marker-commit for easy rollback.

Highlights:
- Call attribution chain fix (inbound transferred calls now get the right agent.id; CDR enrichment now indexes by both UCID + monitorUCID)
- Worklist patientId + Book Appt pill patientId overlay — returning callers see their prior appointment as a reschedule pill
- Supervisor Dashboard merge: Team Performance surfaces folded in, scrollable sections, time-breakdown rendered as a table
- Data-provider pagination: KPIs no longer capped at 100 rows
- Background poll no longer flashes a Loading state
- Campaign detail: leads inline, View Leads button removed
- All Leads: stray Back button gone, Export CSV wired up
- Maint OTP modal: agent picker (Locked/Free) after OTP, no more reliance on agent-config in localStorage
- Per-tenant HELIX_SETUP_MANAGED flag hides Setup nav + banner on managed workspaces
- Supervisor AI chat panel: supervisor-specific quick actions

Revert this entire batch with: git revert -m 1 <merge-sha>
2026-04-15 19:04:21 +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">