feat: add Procedure Duration/Time Slot settings and custom appointment type
- Add Settings > Advanced > Procedure Duration/Time Slot page with three sections: 1. Procedure Duration: CDT codes with durations (editable table, save per section) 2. Doctor Time Slot: drag-to-block visual grid (A/B/C columns, 8 AM–9 PM, edit/delete slots) 3. Hygienist Time Slot: procedure descriptions with durations - Backend: ProcedureTimeslot Prisma model, storage, and GET/PUT /api/procedure-timeslot route - DB migration: procedure_timeslot table - Appointment form: when type is "Other", show a free-text input for custom description; saved as other:<description> and decoded for display on the schedule card Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -55,6 +55,10 @@ export function AppointmentForm({
|
||||
const { user } = useAuth();
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const [prefillPatient, setPrefillPatient] = useState<Patient | null>(null);
|
||||
const [otherTypeDesc, setOtherTypeDesc] = useState<string>(() => {
|
||||
const t = appointment?.type ?? "";
|
||||
return t.startsWith("other:") ? t.slice(6) : "";
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const timeout = setTimeout(() => {
|
||||
@@ -105,7 +109,7 @@ export function AppointmentForm({
|
||||
date: parseLocalDate(appointment.date),
|
||||
startTime: appointment.startTime || "09:00", // Default "09:00"
|
||||
endTime: appointment.endTime || "09:30", // Default "09:30"
|
||||
type: appointment.type,
|
||||
type: appointment.type?.startsWith("other:") ? "other" : appointment.type,
|
||||
notes: appointment.notes || "",
|
||||
status: appointment.status || "scheduled",
|
||||
staffId:
|
||||
@@ -326,6 +330,11 @@ export function AppointmentForm({
|
||||
|
||||
const formattedDate = formatLocalDate(data.date);
|
||||
|
||||
const resolvedType =
|
||||
data.type === "other" && otherTypeDesc.trim()
|
||||
? `other:${otherTypeDesc.trim()}`
|
||||
: data.type;
|
||||
|
||||
onSubmit({
|
||||
...data,
|
||||
userId: Number(user?.id),
|
||||
@@ -335,6 +344,7 @@ export function AppointmentForm({
|
||||
date: formattedDate,
|
||||
startTime: data.startTime,
|
||||
endTime: data.endTime,
|
||||
type: resolvedType,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -559,7 +569,10 @@ export function AppointmentForm({
|
||||
<FormLabel>Appointment Type</FormLabel>
|
||||
<Select
|
||||
disabled={isLoading}
|
||||
onValueChange={field.onChange}
|
||||
onValueChange={(val) => {
|
||||
field.onChange(val);
|
||||
if (val !== "other") setOtherTypeDesc("");
|
||||
}}
|
||||
value={field.value}
|
||||
defaultValue={field.value}
|
||||
>
|
||||
@@ -581,6 +594,16 @@ export function AppointmentForm({
|
||||
<SelectItem value="other">Other</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
{field.value === "other" && (
|
||||
<Input
|
||||
className="mt-2"
|
||||
placeholder="Describe the appointment type…"
|
||||
value={otherTypeDesc}
|
||||
onChange={(e) => setOtherTypeDesc(e.target.value)}
|
||||
disabled={isLoading}
|
||||
autoFocus
|
||||
/>
|
||||
)}
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user