diff --git a/apps/Frontend/src/components/appointments/appointment-form.tsx b/apps/Frontend/src/components/appointments/appointment-form.tsx index b5a5b9e..5e43337 100644 --- a/apps/Frontend/src/components/appointments/appointment-form.tsx +++ b/apps/Frontend/src/components/appointments/appointment-form.tsx @@ -21,14 +21,7 @@ import { SelectTrigger, SelectValue, } from "@/components/ui/select"; -import { Calendar } from "@/components/ui/calendar"; -import { - Popover, - PopoverContent, - PopoverTrigger, -} from "@/components/ui/popover"; -import { CalendarIcon, Clock } from "lucide-react"; -import { cn } from "@/lib/utils"; +import { Clock } from "lucide-react"; import { useQuery } from "@tanstack/react-query"; import { useAuth } from "@/hooks/use-auth"; import { useDebounce } from "use-debounce"; @@ -40,6 +33,7 @@ import { Staff, UpdateAppointment, } from "@repo/db/types"; +import { DateInputField } from "@/components/ui/dateInputField"; interface AppointmentFormProps { appointment?: Appointment; @@ -121,7 +115,7 @@ export function AppointmentForm({ // Format the date and times for the form const defaultValues: Partial = appointment ? { - userId: user?.id, + userId: user?.id, patientId: appointment.patientId, title: appointment.title, date: @@ -140,7 +134,7 @@ export function AppointmentForm({ } : parsedStoredData ? { - userId: user?.id, + userId: user?.id, patientId: Number(parsedStoredData.patientId), date: parsedStoredData.date ? typeof parsedStoredData.date === "string" @@ -159,8 +153,8 @@ export function AppointmentForm({ ? parsedStoredData.staff : (staffMembers?.[0]?.id ?? undefined), } - : { - userId: user?.id ?? 0, + : { + userId: user?.id ?? 0, date: new Date(), title: "", startTime: "09:00", @@ -379,50 +373,11 @@ export function AppointmentForm({ )} /> - ( - - Date - - - - - - - - { - if (date) { - field.onChange(date); - } - }} - disabled={(date: Date) => - date < new Date(new Date().setHours(0, 0, 0, 0)) - } - /> - - - - - )} + label="Date" + disablePast />
diff --git a/apps/Frontend/src/components/claims/claim-edit-modal.tsx b/apps/Frontend/src/components/claims/claim-edit-modal.tsx index 4fa900a..0a5c665 100644 --- a/apps/Frontend/src/components/claims/claim-edit-modal.tsx +++ b/apps/Frontend/src/components/claims/claim-edit-modal.tsx @@ -201,17 +201,19 @@ export default function ClaimEditModal({ )}

Billed Amount: $ - {line.totalBilled.toFixed(2)} + {Number(line.totalBilled).toFixed(2)}

))}
Total Billed Amount: $ {claim.serviceLines - .reduce( - (total, line) => total + line.totalBilled?.toNumber(), - 0 - ) + .reduce((total, line) => { + const billed = line.totalBilled + ? parseFloat(line.totalBilled as any) + : 0; + return total + billed; + }, 0) .toFixed(2)}
diff --git a/apps/Frontend/src/components/patients/patient-form.tsx b/apps/Frontend/src/components/patients/patient-form.tsx index 8b63ef7..fa65308 100644 --- a/apps/Frontend/src/components/patients/patient-form.tsx +++ b/apps/Frontend/src/components/patients/patient-form.tsx @@ -19,17 +19,7 @@ import { } from "@/components/ui/select"; import { useEffect, useMemo } from "react"; import { forwardRef, useImperativeHandle } from "react"; -import { - Popover, - PopoverContent, - PopoverTrigger, -} from "@/components/ui/popover"; -import { Calendar } from "../ui/calendar"; -import { CalendarIcon } from "lucide-react"; -import { format } from "date-fns"; -import { Button } from "../ui/button"; -import { cn } from "@/lib/utils"; -import { formatLocalDate, parseLocalDate } from "@/utils/dateUtils"; +import { formatLocalDate } from "@/utils/dateUtils"; import { InsertPatient, insertPatientSchema, @@ -38,6 +28,7 @@ import { updatePatientSchema, } from "@repo/db/types"; import { z } from "zod"; +import { DateInputField } from "@/components/ui/dateInputField"; interface PatientFormProps { patient?: Patient; @@ -180,54 +171,11 @@ export const PatientForm = forwardRef( )} /> - ( - - Date of Birth * - - - - - - - - { - if (date) { - const localDate = formatLocalDate(date); // keep yyyy-MM-dd - field.onChange(localDate); - } - }} - disabled={ - (date) => date > new Date() // Prevent future dates - } - /> - - - - - )} + label="Date of Birth *" + disableFuture /> -
- - - updateField("receivedDate", e.target.value) + { + if (date) { + const localDate = formatLocalDate(date); + updateField("receivedDate", localDate); + } else { + updateField("receivedDate", null); } - /> -
+ }} + disableFuture + />
diff --git a/apps/Frontend/src/components/ui/button.tsx b/apps/Frontend/src/components/ui/button.tsx index 36496a2..58de958 100644 --- a/apps/Frontend/src/components/ui/button.tsx +++ b/apps/Frontend/src/components/ui/button.tsx @@ -1,8 +1,8 @@ -import * as React from "react" -import { Slot } from "@radix-ui/react-slot" -import { cva, type VariantProps } from "class-variance-authority" +import * as React from "react"; +import { Slot } from "@radix-ui/react-slot"; +import { cva, type VariantProps } from "class-variance-authority"; -import { cn } from "@/lib/utils" +import { cn } from "@/lib/utils"; const buttonVariants = cva( "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", @@ -18,6 +18,9 @@ const buttonVariants = cva( "bg-secondary text-secondary-foreground hover:bg-secondary/80", ghost: "hover:bg-accent hover:text-accent-foreground", link: "text-primary underline-offset-4 hover:underline", + warning: "bg-yellow-600 text-white hover:bg-yellow-700", + success: "bg-green-600 text-white hover:bg-green-700", + info: "bg-blue-600 text-white hover:bg-blue-700", }, size: { default: "h-10 px-4 py-2", @@ -31,26 +34,26 @@ const buttonVariants = cva( size: "default", }, } -) +); export interface ButtonProps extends React.ButtonHTMLAttributes, VariantProps { - asChild?: boolean + asChild?: boolean; } const Button = React.forwardRef( ({ className, variant, size, asChild = false, ...props }, ref) => { - const Comp = asChild ? Slot : "button" + const Comp = asChild ? Slot : "button"; return ( - ) + ); } -) -Button.displayName = "Button" +); +Button.displayName = "Button"; -export { Button, buttonVariants } +export { Button, buttonVariants }; diff --git a/apps/Frontend/src/components/ui/dateInput.tsx b/apps/Frontend/src/components/ui/dateInput.tsx new file mode 100644 index 0000000..904d361 --- /dev/null +++ b/apps/Frontend/src/components/ui/dateInput.tsx @@ -0,0 +1,92 @@ +import { useState } from "react"; +import { format } from "date-fns"; +import { Calendar } from "@/components/ui/calendar"; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "@/components/ui/popover"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { CalendarIcon } from "lucide-react"; +import { cn } from "@/lib/utils"; + +interface DateInputProps { + label?: string; + value: Date | null; + onChange: (date: Date | null) => void; + disableFuture?: boolean; + disablePast?: boolean; +} + +export function DateInput({ + label, + value, + onChange, + disableFuture = false, + disablePast = false, +}: DateInputProps) { + const [inputValue, setInputValue] = useState( + value ? format(value, "MM/dd/yyyy") : "" + ); + + const handleInputChange = (e: React.ChangeEvent) => { + let val = e.target.value.replace(/\D/g, ""); + if (val.length >= 5) { + val = `${val.slice(0, 2)}/${val.slice(2, 4)}/${val.slice(4, 8)}`; + } else if (val.length >= 3) { + val = `${val.slice(0, 2)}/${val.slice(2, 4)}`; + } + setInputValue(val); + + if (val.length === 10) { + const [mm, dd, yyyy] = val.split("/") ?? []; + if (mm && dd && yyyy) { + const parsed = new Date(+yyyy, +mm - 1, +dd); + if (!isNaN(parsed.getTime())) { + onChange(parsed); + } + } + } + }; + + return ( +
+ {label && } +
+ + + + + + + { + if (date) { + setInputValue(format(date, "MM/dd/yyyy")); + onChange(date); + } + }} + disabled={ + disableFuture + ? { after: new Date() } + : disablePast + ? { before: new Date() } + : undefined + } + /> + + +
+
+ ); +} diff --git a/apps/Frontend/src/components/ui/dateInputField.tsx b/apps/Frontend/src/components/ui/dateInputField.tsx new file mode 100644 index 0000000..dcb40fa --- /dev/null +++ b/apps/Frontend/src/components/ui/dateInputField.tsx @@ -0,0 +1,46 @@ +import { format } from "date-fns"; +import { + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/components/ui/form"; +import { DateInput } from "@/components/ui/dateInput"; +import { parseLocalDate } from "@/utils/dateUtils"; + +interface DateInputFieldProps { + control: any; + name: string; + label: string; + disableFuture?: boolean; + disablePast?: boolean; +} + +export function DateInputField({ + control, + name, + label, + disableFuture, + disablePast, +}: DateInputFieldProps) { + return ( + ( + + {label} + + field.onChange(date ? format(date, "yyyy-MM-dd") : null) + } + disableFuture={disableFuture} + disablePast={disablePast} + /> + + + )} + /> + ); +} diff --git a/apps/Frontend/src/pages/insurance-eligibility-page.tsx b/apps/Frontend/src/pages/insurance-eligibility-page.tsx index f98cf06..2c98476 100644 --- a/apps/Frontend/src/pages/insurance-eligibility-page.tsx +++ b/apps/Frontend/src/pages/insurance-eligibility-page.tsx @@ -12,18 +12,10 @@ import { CardTitle, } from "@/components/ui/card"; import { Label } from "@/components/ui/label"; -import { CalendarIcon, CheckCircle, LoaderCircleIcon } from "lucide-react"; +import { CheckCircle, LoaderCircleIcon } from "lucide-react"; import { useAuth } from "@/hooks/use-auth"; import { useToast } from "@/hooks/use-toast"; import { PatientTable } from "@/components/patients/patient-table"; -import { format } from "date-fns"; -import { Calendar } from "@/components/ui/calendar"; -import { - Popover, - PopoverContent, - PopoverTrigger, -} from "@/components/ui/popover"; -import { cn } from "@/lib/utils"; import { apiRequest, queryClient } from "@/lib/queryClient"; import { useAppDispatch, useAppSelector } from "@/redux/hooks"; import { @@ -33,6 +25,7 @@ import { import { SeleniumTaskBanner } from "@/components/ui/selenium-task-banner"; import { formatLocalDate, parseLocalDate } from "@/utils/dateUtils"; import { InsertPatient, Patient } from "@repo/db/types"; +import { DateInput } from "@/components/ui/dateInput"; export default function InsuranceEligibilityPage() { const { user } = useAuth(); @@ -54,7 +47,7 @@ export default function InsuranceEligibilityPage() { // Insurance eligibility check form fields const [memberId, setMemberId] = useState(""); - const [dateOfBirth, setDateOfBirth] = useState(); + const [dateOfBirth, setDateOfBirth] = useState(null); const [firstName, setFirstName] = useState(""); const [lastName, setLastName] = useState(""); const [isCheckingEligibility, setIsCheckingEligibility] = useState(false); @@ -75,7 +68,7 @@ export default function InsuranceEligibilityPage() { setMemberId(""); setFirstName(""); setLastName(""); - setDateOfBirth(undefined); + setDateOfBirth(null); } }, [selectedPatient]); @@ -264,33 +257,12 @@ export default function InsuranceEligibilityPage() {
- - - - - - - date > new Date()} - /> - - +