Files
helix-engage/src/components/application/date-picker/date-picker.tsx
saridsa2 dd8e05b343 feat: appointments v2 + patients redesign + call history agent filter + datepicker placement
Appointments v2:
 - Lean 6-column table (eye icon, patient 2-line, date+time 2-line,
   doctor+dept 2-line, status badge, reminder button)
 - Detail side panel on eye click (read-only: all fields + patient phone
   via PhoneActionCell)
 - Reschedule flow: pencil in panel → modal confirm → dedicated
   ReschedulePanel with department/doctor/date/slot/complaint fields
 - Cancel flow: modal confirm before cancelling
 - WhatsApp reminder button for upcoming booked appointments
 - DatePicker popoverPlacement prop for narrow panels (opens upward)

Patients page redesign:
 - Phone column uses PhoneActionCell (clickable to dial)
 - Email split into own column
 - Actions column replaced by hamburger menu (SMS + WhatsApp)
 - View (eye) button removed — row click opens profile panel

Call History agent filter:
 - Missed calls excluded from agent's personal history
 - Chain name parsing for agent matching
 - "Missed" filter option hidden for agents
 - Subtitle: "134 completed" (no "0 missed")

DatePicker:
 - New popoverPlacement prop forwarded to AriaPopover
 - Default "bottom start", use "top start" in constrained panels

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 20:51:57 +05:30

93 lines
4.3 KiB
TypeScript

import type { FC } from "react";
import { getLocalTimeZone, today } from "@internationalized/date";
import { useControlledState } from "@react-stately/utils";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faCalendar } from "@fortawesome/pro-duotone-svg-icons";
const CalendarIcon: FC<{ className?: string }> = ({ className }) => <FontAwesomeIcon icon={faCalendar} className={className} />;
import { useDateFormatter } from "react-aria";
import type { DatePickerProps as AriaDatePickerProps, DateValue } from "react-aria-components";
import { DatePicker as AriaDatePicker, Dialog as AriaDialog, Group as AriaGroup, Popover as AriaPopover } from "react-aria-components";
import { Button } from "@/components/base/buttons/button";
import { cx } from "@/utils/cx";
import { Calendar } from "./calendar";
const highlightedDates = [today(getLocalTimeZone())];
interface DatePickerProps extends AriaDatePickerProps<DateValue> {
/** The function to call when the apply button is clicked. */
onApply?: () => void;
/** The function to call when the cancel button is clicked. */
onCancel?: () => void;
/** Override popover placement — use "top start" in narrow panels
* where "bottom start" would overflow the viewport. */
popoverPlacement?: 'bottom start' | 'top start' | 'top end' | 'bottom end';
}
export const DatePicker = ({ value: valueProp, defaultValue, onChange, onApply, onCancel, popoverPlacement, ...props }: DatePickerProps) => {
const formatter = useDateFormatter({
month: "short",
day: "numeric",
year: "numeric",
});
const [value, setValue] = useControlledState(valueProp, defaultValue || null, onChange);
const formattedDate = value ? formatter.format(value.toDate(getLocalTimeZone())) : "Select date";
return (
<AriaDatePicker shouldCloseOnSelect={false} {...props} value={value} onChange={setValue}>
<AriaGroup>
<Button size="md" color="secondary" iconLeading={CalendarIcon}>
{formattedDate}
</Button>
</AriaGroup>
<AriaPopover
offset={8}
placement={popoverPlacement ?? "bottom start"}
shouldFlip
className={({ isEntering, isExiting }) =>
cx(
"origin-(--trigger-anchor-point) will-change-transform",
isEntering &&
"duration-150 ease-out animate-in fade-in placement-right:slide-in-from-left-0.5 placement-top:slide-in-from-bottom-0.5 placement-bottom:slide-in-from-top-0.5",
isExiting &&
"duration-100 ease-in animate-out fade-out placement-right:slide-out-to-left-0.5 placement-top:slide-out-to-bottom-0.5 placement-bottom:slide-out-to-top-0.5",
)
}
>
<AriaDialog className="rounded-2xl bg-primary shadow-xl ring ring-secondary_alt">
{({ close }) => (
<>
<div className="flex px-6 py-5">
<Calendar highlightedDates={highlightedDates} />
</div>
<div className="grid grid-cols-2 gap-3 border-t border-secondary p-4">
<Button
size="md"
color="secondary"
onClick={() => {
onCancel?.();
close();
}}
>
Cancel
</Button>
<Button
size="md"
color="primary"
onClick={() => {
onApply?.();
close();
}}
>
Apply
</Button>
</div>
</>
)}
</AriaDialog>
</AriaPopover>
</AriaDatePicker>
);
};