frontend tailwind half working without external styling
This commit is contained in:
@@ -1,7 +1,28 @@
|
||||
import { useState } from "react";
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog";
|
||||
import { AppointmentForm } from "./appointment-form";
|
||||
import { Appointment, InsertAppointment, UpdateAppointment, Patient } from "@shared/schema";
|
||||
// import { Appointment, InsertAppointment, UpdateAppointment, Patient } from "@repo/db/shared/schemas";
|
||||
import { AppointmentUncheckedCreateInputObjectSchema, PatientUncheckedCreateInputObjectSchema } from "@repo/db/shared/schemas";
|
||||
|
||||
import {z} from "zod";
|
||||
type Appointment = z.infer<typeof AppointmentUncheckedCreateInputObjectSchema>;
|
||||
|
||||
const insertAppointmentSchema = (AppointmentUncheckedCreateInputObjectSchema as unknown as z.ZodObject<any>).omit({
|
||||
id: true,
|
||||
createdAt: true,
|
||||
});
|
||||
type InsertAppointment = z.infer<typeof insertAppointmentSchema>;
|
||||
|
||||
const updateAppointmentSchema = (AppointmentUncheckedCreateInputObjectSchema as unknown as z.ZodObject<any>).omit({
|
||||
id: true,
|
||||
createdAt: true,
|
||||
}).partial();
|
||||
type UpdateAppointment = z.infer<typeof updateAppointmentSchema>;
|
||||
|
||||
const PatientSchema = (PatientUncheckedCreateInputObjectSchema as unknown as z.ZodObject<any>).omit({
|
||||
appointments: true,
|
||||
});
|
||||
type Patient = z.infer<typeof PatientSchema>;
|
||||
|
||||
interface AddAppointmentModalProps {
|
||||
open: boolean;
|
||||
|
||||
@@ -1,9 +1,30 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { z } from "zod";
|
||||
import { format } from "date-fns";
|
||||
import { InsertAppointment, UpdateAppointment, Appointment, Patient } from "@shared/schema";
|
||||
// import { InsertAppointment, UpdateAppointment, Appointment, Patient } from "@repo/db/shared/schemas";
|
||||
import { AppointmentUncheckedCreateInputObjectSchema, PatientUncheckedCreateInputObjectSchema } from "@repo/db/shared/schemas";
|
||||
|
||||
import {z} from "zod";
|
||||
type Appointment = z.infer<typeof AppointmentUncheckedCreateInputObjectSchema>;
|
||||
|
||||
const insertAppointmentSchema = (AppointmentUncheckedCreateInputObjectSchema as unknown as z.ZodObject<any>).omit({
|
||||
id: true,
|
||||
createdAt: true,
|
||||
});
|
||||
type InsertAppointment = z.infer<typeof insertAppointmentSchema>;
|
||||
|
||||
const updateAppointmentSchema = (AppointmentUncheckedCreateInputObjectSchema as unknown as z.ZodObject<any>).omit({
|
||||
id: true,
|
||||
createdAt: true,
|
||||
}).partial();
|
||||
type UpdateAppointment = z.infer<typeof updateAppointmentSchema>;
|
||||
|
||||
const PatientSchema = (PatientUncheckedCreateInputObjectSchema as unknown as z.ZodObject<any>).omit({
|
||||
appointments: true,
|
||||
});
|
||||
type Patient = z.infer<typeof PatientSchema>;
|
||||
|
||||
|
||||
// Define staff members (should match those in appointments-page.tsx)
|
||||
const staffMembers = [
|
||||
@@ -36,7 +57,6 @@ import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover
|
||||
import { CalendarIcon, Clock } from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
// Create a schema for appointment validation
|
||||
const appointmentSchema = z.object({
|
||||
patientId: z.coerce.number().positive(),
|
||||
title: z.string().optional(),
|
||||
@@ -52,7 +72,7 @@ const appointmentSchema = z.object({
|
||||
type: z.string().min(1, "Appointment type is required"),
|
||||
notes: z.string().optional(),
|
||||
status: z.string().default("scheduled"),
|
||||
staff: z.string().default(staffMembers[0].id),
|
||||
staff: z.string().default(staffMembers?.[0]?.id ?? "default-id"),
|
||||
});
|
||||
|
||||
export type AppointmentFormValues = z.infer<typeof appointmentSchema>;
|
||||
@@ -96,8 +116,8 @@ export function AppointmentForm({
|
||||
patientId: appointment.patientId,
|
||||
title: appointment.title,
|
||||
date: new Date(appointment.date),
|
||||
startTime: appointment.startTime.slice(0, 5), // HH:MM from HH:MM:SS
|
||||
endTime: appointment.endTime.slice(0, 5), // HH:MM from HH:MM:SS
|
||||
startTime: typeof appointment.startTime === 'string' ? appointment.startTime.slice(0, 5) : "",
|
||||
endTime: typeof appointment.endTime === 'string' ? appointment.endTime.slice(0, 5) : "",
|
||||
type: appointment.type,
|
||||
notes: appointment.notes || "",
|
||||
status: appointment.status || "scheduled",
|
||||
@@ -112,7 +132,7 @@ export function AppointmentForm({
|
||||
type: parsedStoredData.type || "checkup",
|
||||
status: parsedStoredData.status || "scheduled",
|
||||
notes: parsedStoredData.notes || "",
|
||||
staff: parsedStoredData.staff || staffMembers[0].id,
|
||||
staff: parsedStoredData.staff || (staffMembers?.[0]?.id ?? "default-id")
|
||||
}
|
||||
: {
|
||||
date: new Date(),
|
||||
@@ -187,7 +207,7 @@ export function AppointmentForm({
|
||||
|
||||
// If there's no staff information in the notes, add it
|
||||
if (!notes.includes('Appointment with')) {
|
||||
notes = notes ? `${notes}\nAppointment with ${selectedStaff.name}` : `Appointment with ${selectedStaff.name}`;
|
||||
notes = notes ? `${notes}\nAppointment with ${selectedStaff?.name}` : `Appointment with ${selectedStaff?.name}`;
|
||||
}
|
||||
|
||||
onSubmit({
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import { useState } from "react";
|
||||
import { format } from "date-fns";
|
||||
import { Appointment, Patient } from "@shared/schema";
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
@@ -11,13 +9,13 @@ import {
|
||||
} from "@/components/ui/table";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import {
|
||||
MoreHorizontal,
|
||||
Edit,
|
||||
Trash2,
|
||||
import {
|
||||
MoreHorizontal,
|
||||
Edit,
|
||||
Trash2,
|
||||
Eye,
|
||||
Calendar,
|
||||
Clock
|
||||
Clock,
|
||||
} from "lucide-react";
|
||||
import {
|
||||
DropdownMenu,
|
||||
@@ -27,6 +25,21 @@ import {
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
// import { Appointment, Patient } from "@repo/db/shared/schemas";
|
||||
import {
|
||||
AppointmentUncheckedCreateInputObjectSchema,
|
||||
PatientUncheckedCreateInputObjectSchema,
|
||||
} from "@repo/db/shared/schemas";
|
||||
|
||||
import { z } from "zod";
|
||||
type Appointment = z.infer<typeof AppointmentUncheckedCreateInputObjectSchema>;
|
||||
|
||||
const PatientSchema = (
|
||||
PatientUncheckedCreateInputObjectSchema as unknown as z.ZodObject<any>
|
||||
).omit({
|
||||
appointments: true,
|
||||
});
|
||||
type Patient = z.infer<typeof PatientSchema>;
|
||||
|
||||
interface AppointmentTableProps {
|
||||
appointments: Appointment[];
|
||||
@@ -35,21 +48,34 @@ interface AppointmentTableProps {
|
||||
onDelete: (id: number) => void;
|
||||
}
|
||||
|
||||
export function AppointmentTable({
|
||||
appointments,
|
||||
patients,
|
||||
onEdit,
|
||||
onDelete
|
||||
export function AppointmentTable({
|
||||
appointments,
|
||||
patients,
|
||||
onEdit,
|
||||
onDelete,
|
||||
}: AppointmentTableProps) {
|
||||
// Helper function to get patient name
|
||||
const getPatientName = (patientId: number) => {
|
||||
const patient = patients.find(p => p.id === patientId);
|
||||
return patient ? `${patient.firstName} ${patient.lastName}` : "Unknown Patient";
|
||||
const patient = patients.find((p) => p.id === patientId);
|
||||
return patient
|
||||
? `${patient.firstName} ${patient.lastName}`
|
||||
: "Unknown Patient";
|
||||
};
|
||||
|
||||
// Helper function to get status badge
|
||||
const getStatusBadge = (status: string) => {
|
||||
const statusConfig: Record<string, { variant: "default" | "secondary" | "destructive" | "outline" | "success"; label: string }> = {
|
||||
const statusConfig: Record<
|
||||
string,
|
||||
{
|
||||
variant:
|
||||
| "default"
|
||||
| "secondary"
|
||||
| "destructive"
|
||||
| "outline"
|
||||
| "success";
|
||||
label: string;
|
||||
}
|
||||
> = {
|
||||
scheduled: { variant: "default", label: "Scheduled" },
|
||||
confirmed: { variant: "secondary", label: "Confirmed" },
|
||||
completed: { variant: "success", label: "Completed" },
|
||||
@@ -57,20 +83,20 @@ export function AppointmentTable({
|
||||
"no-show": { variant: "outline", label: "No Show" },
|
||||
};
|
||||
|
||||
const config = statusConfig[status] || { variant: "default", label: status };
|
||||
|
||||
return (
|
||||
<Badge variant={config.variant as any}>
|
||||
{config.label}
|
||||
</Badge>
|
||||
);
|
||||
const config = statusConfig[status] || {
|
||||
variant: "default",
|
||||
label: status,
|
||||
};
|
||||
|
||||
return <Badge variant={config.variant as any}>{config.label}</Badge>;
|
||||
};
|
||||
|
||||
// Sort appointments by date and time (newest first)
|
||||
const sortedAppointments = [...appointments].sort((a, b) => {
|
||||
const dateComparison = new Date(b.date).getTime() - new Date(a.date).getTime();
|
||||
const dateComparison =
|
||||
new Date(b.date).getTime() - new Date(a.date).getTime();
|
||||
if (dateComparison !== 0) return dateComparison;
|
||||
return a.startTime.localeCompare(b.startTime);
|
||||
return a.startTime.toString().localeCompare(b.startTime.toString());
|
||||
});
|
||||
|
||||
return (
|
||||
@@ -108,15 +134,20 @@ export function AppointmentTable({
|
||||
<TableCell>
|
||||
<div className="flex items-center">
|
||||
<Clock className="mr-2 h-4 w-4 text-muted-foreground" />
|
||||
{appointment.startTime.slice(0, 5)} - {appointment.endTime.slice(0, 5)}
|
||||
{appointment.startTime instanceof Date
|
||||
? appointment.startTime.toISOString().slice(11, 16)
|
||||
: appointment.startTime.slice(0, 5)}{" "}
|
||||
-
|
||||
{appointment.endTime instanceof Date
|
||||
? appointment.endTime.toISOString().slice(11, 16)
|
||||
: appointment.endTime.slice(0, 5)}
|
||||
{/* {appointment.startTime.slice(0, 5)} - {appointment.endTime.slice(0, 5)} */}
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell className="capitalize">
|
||||
{appointment.type.replace('-', ' ')}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{getStatusBadge(appointment.status!)}
|
||||
{appointment.type.replace("-", " ")}
|
||||
</TableCell>
|
||||
<TableCell>{getStatusBadge(appointment.status!)}</TableCell>
|
||||
<TableCell className="text-right">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
@@ -132,8 +163,14 @@ export function AppointmentTable({
|
||||
Edit
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem
|
||||
onClick={() => onDelete(appointment.id)}
|
||||
<DropdownMenuItem
|
||||
onClick={() => {
|
||||
if (typeof appointment.id === "number") {
|
||||
onDelete(appointment.id);
|
||||
} else {
|
||||
console.error("Invalid appointment ID");
|
||||
}
|
||||
}}
|
||||
className="text-destructive focus:text-destructive"
|
||||
>
|
||||
<Trash2 className="mr-2 h-4 w-4" />
|
||||
@@ -149,4 +186,4 @@ export function AppointmentTable({
|
||||
</Table>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,28 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { Button } from "../ui/button";
|
||||
import { Input } from "../ui/input";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "../ui/select";
|
||||
} from "@/components/ui/select";
|
||||
import { format, parse } from "date-fns";
|
||||
import { Patient } from "@shared/schema";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "../ui/card";
|
||||
import { Label } from "../ui/label";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { X, Calendar as CalendarIcon } from "lucide-react";
|
||||
import { useToast } from "../../hooks/use-toast";
|
||||
import { Calendar } from "../ui/calendar";
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
|
||||
import { useToast } from "@/hooks/use-toast";
|
||||
import { Calendar } from "@/components/ui/calendar";
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
|
||||
// import { Patient } from "@repo/db/shared/schemas";
|
||||
import { PatientUncheckedCreateInputObjectSchema } from "@repo/db/shared/schemas";
|
||||
import {z} from "zod";
|
||||
|
||||
const PatientSchema = (PatientUncheckedCreateInputObjectSchema as unknown as z.ZodObject<any>).omit({
|
||||
appointments: true,
|
||||
});
|
||||
type Patient = z.infer<typeof PatientSchema>;
|
||||
|
||||
interface ClaimFormProps {
|
||||
patientId: number;
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { ClaimForm } from "./claim-form";
|
||||
import { Patient } from "@shared/schema";
|
||||
// import { Patient } from "@repo/db/shared/schemas";
|
||||
import { PatientUncheckedCreateInputObjectSchema } from "@repo/db/shared/schemas";
|
||||
import {z} from "zod";
|
||||
|
||||
const PatientSchema = (PatientUncheckedCreateInputObjectSchema as unknown as z.ZodObject<any>).omit({
|
||||
appointments: true,
|
||||
});
|
||||
type Patient = z.infer<typeof PatientSchema>;
|
||||
|
||||
interface ClaimModalProps {
|
||||
open: boolean;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Link, useLocation } from "wouter";
|
||||
import { Search, LayoutDashboard, Users, Calendar, FileText, Settings } from "lucide-react";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { LayoutDashboard, Users, Calendar, FileText, Settings } from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
interface SidebarProps {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Bell, Menu, Search } from "lucide-react";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Bell, Menu} from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
|
||||
@@ -9,10 +9,32 @@ import {
|
||||
DialogFooter,
|
||||
} from "@/components/ui/dialog";
|
||||
import { PatientForm } from "./patient-form";
|
||||
import { InsertPatient, Patient, UpdatePatient } from "@shared/schema";
|
||||
import { useToast } from "@/hooks/use-toast";
|
||||
import { X, Calendar } from "lucide-react";
|
||||
import { useLocation } from "wouter";
|
||||
// import { InsertPatient, Patient, UpdatePatient } from "@repo/db/shared/schemas";
|
||||
import { PatientUncheckedCreateInputObjectSchema } from "@repo/db/shared/schemas";
|
||||
import {z} from "zod";
|
||||
|
||||
const PatientSchema = (PatientUncheckedCreateInputObjectSchema as unknown as z.ZodObject<any>).omit({
|
||||
appointments: true,
|
||||
});
|
||||
type Patient = z.infer<typeof PatientSchema>;
|
||||
|
||||
const insertPatientSchema = (PatientUncheckedCreateInputObjectSchema as unknown as z.ZodObject<any>).omit({
|
||||
id: true,
|
||||
createdAt: true,
|
||||
});
|
||||
type InsertPatient = z.infer<typeof insertPatientSchema>;
|
||||
|
||||
const updatePatientSchema = (PatientUncheckedCreateInputObjectSchema as unknown as z.ZodObject<any>).omit({
|
||||
id: true,
|
||||
createdAt: true,
|
||||
userId: true,
|
||||
}).partial();
|
||||
|
||||
type UpdatePatient = z.infer<typeof updatePatientSchema>;
|
||||
|
||||
|
||||
interface AddPatientModalProps {
|
||||
open: boolean;
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { z } from "zod";
|
||||
import { insertPatientSchema, InsertPatient, Patient, updatePatientSchema, UpdatePatient } from "@shared/schema";
|
||||
import { PatientUncheckedCreateInputObjectSchema } from "@repo/db/shared/schemas";
|
||||
// import { insertPatientSchema, InsertPatient, Patient, updatePatientSchema, UpdatePatient } from "@repo/db/shared/schemas";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import {
|
||||
Form,
|
||||
@@ -21,6 +22,26 @@ import {
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
|
||||
const PatientSchema = (PatientUncheckedCreateInputObjectSchema as unknown as z.ZodObject<any>).omit({
|
||||
appointments: true,
|
||||
});
|
||||
type Patient = z.infer<typeof PatientSchema>;
|
||||
|
||||
const insertPatientSchema = (PatientUncheckedCreateInputObjectSchema as unknown as z.ZodObject<any>).omit({
|
||||
id: true,
|
||||
createdAt: true,
|
||||
});
|
||||
type InsertPatient = z.infer<typeof insertPatientSchema>;
|
||||
|
||||
const updatePatientSchema = (PatientUncheckedCreateInputObjectSchema as unknown as z.ZodObject<any>).omit({
|
||||
id: true,
|
||||
createdAt: true,
|
||||
userId: true,
|
||||
}).partial();
|
||||
|
||||
type UpdatePatient = z.infer<typeof updatePatientSchema>;
|
||||
|
||||
|
||||
interface PatientFormProps {
|
||||
patient?: Patient;
|
||||
extractedInfo?: {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { useState } from "react";
|
||||
import { Patient } from "@shared/schema";
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
@@ -26,6 +25,15 @@ import {
|
||||
PaginationNext,
|
||||
PaginationPrevious,
|
||||
} from "@/components/ui/pagination";
|
||||
// import { Patient } from "@repo/db/shared/schemas";
|
||||
import { PatientUncheckedCreateInputObjectSchema } from "@repo/db/shared/schemas";
|
||||
import {z} from "zod";
|
||||
|
||||
const PatientSchema = (PatientUncheckedCreateInputObjectSchema as unknown as z.ZodObject<any>).omit({
|
||||
appointments: true,
|
||||
});
|
||||
type Patient = z.infer<typeof PatientSchema>;
|
||||
|
||||
|
||||
interface PatientTableProps {
|
||||
patients: Patient[];
|
||||
|
||||
@@ -15,6 +15,8 @@ const badgeVariants = cva(
|
||||
destructive:
|
||||
"border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80",
|
||||
outline: "text-foreground",
|
||||
success: "border-transparent bg-success text-success-foreground hover:bg-success/80", // ✅ Added success variant
|
||||
warning: "border-transparent bg-warning text-warning-foreground hover:bg-warning/80", // ✅ Added warning variant
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
|
||||
@@ -4,9 +4,25 @@ import {
|
||||
useMutation,
|
||||
UseMutationResult,
|
||||
} from "@tanstack/react-query";
|
||||
import { insertUserSchema, User as SelectUser, InsertUser } from "@shared/schema";
|
||||
// import { insertUserSchema, User as SelectUser, InsertUser } from "@repo/db/shared/schemas";
|
||||
import { UserUncheckedCreateInputObjectSchema } from "@repo/db/shared/schemas";
|
||||
import {z} from "zod";
|
||||
import { getQueryFn, apiRequest, queryClient } from "../lib/queryClient";
|
||||
import { useToast } from "../hooks/use-toast";
|
||||
import { useToast } from "@/hooks/use-toast";
|
||||
|
||||
type SelectUser = z.infer<typeof UserUncheckedCreateInputObjectSchema>;
|
||||
|
||||
const insertUserSchema = (UserUncheckedCreateInputObjectSchema as unknown as z.ZodObject<{
|
||||
username: z.ZodString;
|
||||
password: z.ZodString;
|
||||
}>).pick({
|
||||
username: true,
|
||||
password: true,
|
||||
});
|
||||
|
||||
type InsertUser = z.infer<typeof insertUserSchema>;
|
||||
|
||||
|
||||
|
||||
type AuthContextType = {
|
||||
user: SelectUser | null;
|
||||
@@ -17,7 +33,11 @@ type AuthContextType = {
|
||||
registerMutation: UseMutationResult<SelectUser, Error, InsertUser>;
|
||||
};
|
||||
|
||||
type LoginData = Pick<InsertUser, "username" | "password">;
|
||||
// type LoginData = Pick<InsertUser, "username" | "password">;
|
||||
type LoginData = {
|
||||
username: InsertUser["username"];
|
||||
password: InsertUser["password"];
|
||||
};
|
||||
|
||||
export const AuthContext = createContext<AuthContextType | null>(null);
|
||||
export function AuthProvider({ children }: { children: ReactNode }) {
|
||||
|
||||
@@ -3,7 +3,7 @@ import * as React from "react"
|
||||
import type {
|
||||
ToastActionElement,
|
||||
ToastProps,
|
||||
} from "../components/ui/toast"
|
||||
} from "@/components/ui/toast"
|
||||
|
||||
const TOAST_LIMIT = 1
|
||||
const TOAST_REMOVE_DELAY = 1000000
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
@import "tailwindcss";
|
||||
@import "@repo/tailwind-config";
|
||||
@import "@repo/ui/styles.css";
|
||||
@import "@repo/ui/styles.css";
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useAuth } from "../hooks/use-auth";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import { Loader2 } from "lucide-react";
|
||||
import { Redirect, Route } from "wouter";
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { createRoot } from 'react-dom/client'
|
||||
import './index.css'
|
||||
import App from './App.tsx'
|
||||
import App from './App'
|
||||
|
||||
document.title = "DentalConnect - Patient Management System";
|
||||
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { useState, useRef, useEffect } from "react";
|
||||
import { useQuery, useMutation } from "@tanstack/react-query";
|
||||
import { format, addDays, startOfToday, addMinutes } from "date-fns";
|
||||
import { TopAppBar } from "../components/layout/top-app-bar";
|
||||
import { Sidebar } from "../components/layout/sidebar";
|
||||
import { AddAppointmentModal } from "../components/appointments/add-appointment-modal";
|
||||
import { ClaimModal } from "../components/claims/claim-modal";
|
||||
import { Button } from "../components/ui/button";
|
||||
import { z } from "zod";
|
||||
import { format, addDays, parse, startOfToday, startOfDay, addMinutes, isEqual } from "date-fns";
|
||||
import { TopAppBar } from "@/components/layout/top-app-bar";
|
||||
import { Sidebar } from "@/components/layout/sidebar";
|
||||
import { AddAppointmentModal } from "@/components/appointments/add-appointment-modal";
|
||||
import { ClaimModal } from "@/components/claims/claim-modal";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Calendar as CalendarIcon,
|
||||
Plus,
|
||||
Users,
|
||||
ChevronLeft,
|
||||
ChevronRight,
|
||||
RefreshCw,
|
||||
@@ -17,17 +17,42 @@ import {
|
||||
Trash2,
|
||||
FileText
|
||||
} from "lucide-react";
|
||||
import { useToast } from "../hooks/use-toast";
|
||||
import { Calendar } from "../components/ui/calendar";
|
||||
import { apiRequest, queryClient } from "../lib/queryClient";
|
||||
import { useAuth } from "../hooks/use-auth";
|
||||
import { Card, CardContent, CardHeader, CardDescription, CardTitle } from "../components/ui/card";
|
||||
import { useToast } from "@/hooks/use-toast";
|
||||
import { z } from "zod";
|
||||
import { Calendar } from "@/components/ui/calendar";
|
||||
import { AppointmentUncheckedCreateInputObjectSchema, PatientUncheckedCreateInputObjectSchema } from "@repo/db/shared/schemas";
|
||||
// import { Appointment, InsertAppointment, UpdateAppointment, Patient } from "@repo/db/shared/schemas";
|
||||
import { apiRequest, queryClient } from "@/lib/queryClient";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import { Card, CardContent, CardHeader, CardDescription, CardTitle } from "@/components/ui/card";
|
||||
import { DndProvider, useDrag, useDrop } from 'react-dnd';
|
||||
import { HTML5Backend } from 'react-dnd-html5-backend';
|
||||
import { Menu, Item, useContextMenu } from 'react-contexify';
|
||||
import 'react-contexify/ReactContexify.css';
|
||||
import { useLocation } from "wouter";
|
||||
|
||||
//creating types out of schema auto generated.
|
||||
type Appointment = z.infer<typeof AppointmentUncheckedCreateInputObjectSchema>;
|
||||
|
||||
const insertAppointmentSchema = (AppointmentUncheckedCreateInputObjectSchema as unknown as z.ZodObject<any>).omit({
|
||||
id: true,
|
||||
createdAt: true,
|
||||
});
|
||||
type InsertAppointment = z.infer<typeof insertAppointmentSchema>;
|
||||
|
||||
const updateAppointmentSchema = (AppointmentUncheckedCreateInputObjectSchema as unknown as z.ZodObject<any>).omit({
|
||||
id: true,
|
||||
createdAt: true,
|
||||
}).partial();
|
||||
type UpdateAppointment = z.infer<typeof updateAppointmentSchema>;
|
||||
|
||||
const PatientSchema = (PatientUncheckedCreateInputObjectSchema as unknown as z.ZodObject<any>).omit({
|
||||
appointments: true,
|
||||
});
|
||||
type Patient = z.infer<typeof PatientSchema>;
|
||||
|
||||
|
||||
|
||||
// Define types for scheduling
|
||||
interface TimeSlot {
|
||||
time: string;
|
||||
@@ -42,13 +67,13 @@ interface Staff {
|
||||
}
|
||||
|
||||
interface ScheduledAppointment {
|
||||
id: number;
|
||||
id?: number;
|
||||
patientId: number;
|
||||
patientName: string;
|
||||
staffId: string;
|
||||
date: string;
|
||||
startTime: string;
|
||||
endTime: string;
|
||||
date: string | Date; // Allow both string and Date
|
||||
startTime: string | Date; // Allow both string and Date
|
||||
endTime: string | Date; // Allow both string and Date
|
||||
status: string | null;
|
||||
type: string;
|
||||
}
|
||||
@@ -63,7 +88,7 @@ export default function AppointmentsPage() {
|
||||
const [isClaimModalOpen, setIsClaimModalOpen] = useState(false);
|
||||
const [claimAppointmentId, setClaimAppointmentId] = useState<number | null>(null);
|
||||
const [claimPatientId, setClaimPatientId] = useState<number | null>(null);
|
||||
const [editingAppointment, setEditingAppointment] = useState<any | undefined>(undefined);
|
||||
const [editingAppointment, setEditingAppointment] = useState<Appointment | undefined>(undefined);
|
||||
const [selectedDate, setSelectedDate] = useState<Date>(startOfToday());
|
||||
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
|
||||
const [location] = useLocation();
|
||||
@@ -96,10 +121,10 @@ export default function AppointmentsPage() {
|
||||
|
||||
// Fetch appointments
|
||||
const {
|
||||
data: appointments,
|
||||
data: appointments = [] as Appointment[],
|
||||
isLoading: isLoadingAppointments,
|
||||
refetch: refetchAppointments,
|
||||
} = useQuery<any>({
|
||||
} = useQuery<Appointment[]>({
|
||||
queryKey: ["/api/appointments"],
|
||||
enabled: !!user,
|
||||
});
|
||||
@@ -108,7 +133,7 @@ export default function AppointmentsPage() {
|
||||
const {
|
||||
data: patients = [],
|
||||
isLoading: isLoadingPatients,
|
||||
} = useQuery<any>({
|
||||
} = useQuery<Patient[]>({
|
||||
queryKey: ["/api/patients"],
|
||||
enabled: !!user,
|
||||
});
|
||||
@@ -167,8 +192,7 @@ export default function AppointmentsPage() {
|
||||
if (newPatientId) {
|
||||
const patientId = parseInt(newPatientId);
|
||||
// Find the patient in our list
|
||||
const patient = patients.find((p: { id: number }) => p.id === patientId) ?? undefined;
|
||||
|
||||
const patient = (patients as Patient[]).find(p => p.id === patientId);
|
||||
|
||||
if (patient) {
|
||||
toast({
|
||||
@@ -177,7 +201,6 @@ export default function AppointmentsPage() {
|
||||
});
|
||||
|
||||
// Select first available staff member
|
||||
|
||||
const staffId = staffMembers[0]!.id;
|
||||
|
||||
// Find first time slot today (9:00 AM is a common starting time)
|
||||
@@ -207,7 +230,7 @@ export default function AppointmentsPage() {
|
||||
|
||||
// Create appointment mutation
|
||||
const createAppointmentMutation = useMutation({
|
||||
mutationFn: async (appointment: any) => {
|
||||
mutationFn: async (appointment: InsertAppointment) => {
|
||||
const res = await apiRequest("POST", "/api/appointments", appointment);
|
||||
return await res.json();
|
||||
},
|
||||
@@ -230,7 +253,7 @@ export default function AppointmentsPage() {
|
||||
|
||||
// Update appointment mutation
|
||||
const updateAppointmentMutation = useMutation({
|
||||
mutationFn: async ({ id, appointment }: { id: number; appointment: any }) => {
|
||||
mutationFn: async ({ id, appointment }: { id: number; appointment: UpdateAppointment }) => {
|
||||
const res = await apiRequest("PUT", `/api/appointments/${id}`, appointment);
|
||||
return await res.json();
|
||||
},
|
||||
@@ -274,7 +297,7 @@ export default function AppointmentsPage() {
|
||||
});
|
||||
|
||||
// Handle appointment submission (create or update)
|
||||
const handleAppointmentSubmit = (appointmentData: any) => {
|
||||
const handleAppointmentSubmit = (appointmentData: InsertAppointment | UpdateAppointment) => {
|
||||
// Make sure the date is for the selected date
|
||||
const updatedData = {
|
||||
...appointmentData,
|
||||
@@ -285,13 +308,13 @@ export default function AppointmentsPage() {
|
||||
if (editingAppointment && 'id' in editingAppointment && typeof editingAppointment.id === 'number') {
|
||||
updateAppointmentMutation.mutate({
|
||||
id: editingAppointment.id,
|
||||
appointment: updatedData as any,
|
||||
appointment: updatedData as unknown as UpdateAppointment,
|
||||
});
|
||||
} else {
|
||||
// This is a new appointment
|
||||
if (user) {
|
||||
createAppointmentMutation.mutate({
|
||||
...updatedData as any,
|
||||
...updatedData as unknown as InsertAppointment,
|
||||
userId: user.id
|
||||
});
|
||||
}
|
||||
@@ -299,7 +322,7 @@ export default function AppointmentsPage() {
|
||||
};
|
||||
|
||||
// Handle edit appointment
|
||||
const handleEditAppointment = (appointment: any) => {
|
||||
const handleEditAppointment = (appointment: Appointment) => {
|
||||
setEditingAppointment(appointment);
|
||||
setIsAddModalOpen(true);
|
||||
};
|
||||
@@ -319,21 +342,19 @@ export default function AppointmentsPage() {
|
||||
const formattedDate = format(selectedDate, 'MMMM d, yyyy');
|
||||
|
||||
// Filter appointments for the selected date
|
||||
const selectedDateAppointments = appointments.filter((apt: { date: string }) =>
|
||||
const selectedDateAppointments = appointments.filter(apt =>
|
||||
apt.date === format(selectedDate, 'yyyy-MM-dd')
|
||||
);
|
||||
|
||||
|
||||
// Add debugging logs
|
||||
console.log("Selected date:", format(selectedDate, 'yyyy-MM-dd'));
|
||||
console.log("All appointments:", appointments);
|
||||
console.log("Filtered appointments for selected date:", selectedDateAppointments);
|
||||
|
||||
|
||||
|
||||
// Process appointments for the scheduler view
|
||||
const processedAppointments: ScheduledAppointment[] = selectedDateAppointments.map((apt: any) => {
|
||||
const processedAppointments: ScheduledAppointment[] = selectedDateAppointments.map(apt => {
|
||||
// Find patient name
|
||||
const patient = patients.find((p: any) => p.id === apt.patientId);
|
||||
const patient = patients.find(p => p.id === apt.patientId);
|
||||
const patientName = patient ? `${patient.firstName} ${patient.lastName}` : 'Unknown Patient';
|
||||
|
||||
// Try to determine the staff from the notes or title
|
||||
@@ -376,7 +397,9 @@ export default function AppointmentsPage() {
|
||||
const processed = {
|
||||
...apt,
|
||||
patientName,
|
||||
staffId
|
||||
staffId,
|
||||
status: apt.status ?? null, // Default to null if status is undefined
|
||||
date: apt.date instanceof Date ? apt.date.toISOString() : apt.date, // Ensure d
|
||||
};
|
||||
|
||||
console.log("Processed appointment:", processed);
|
||||
@@ -393,7 +416,8 @@ export default function AppointmentsPage() {
|
||||
// In a real application, you might want to show multiple or stack them
|
||||
const appointmentsAtSlot = processedAppointments.filter(apt => {
|
||||
// Fix time format comparison - the database adds ":00" seconds to the time
|
||||
const dbTime = apt.startTime.substring(0, 5); // Get just HH:MM, removing seconds
|
||||
const dbTime = typeof apt.startTime === 'string' ? apt.startTime.substring(0, 5) : '';
|
||||
|
||||
const timeMatches = dbTime === timeSlot.time;
|
||||
const staffMatches = apt.staffId === staffId;
|
||||
|
||||
@@ -417,7 +441,7 @@ export default function AppointmentsPage() {
|
||||
|
||||
// Handle moving an appointment to a new time slot and staff
|
||||
const handleMoveAppointment = (appointmentId: number, newTimeSlot: TimeSlot, newStaffId: string) => {
|
||||
const appointment = appointments.find((a:any) => a.id === appointmentId);
|
||||
const appointment = appointments.find(a => a.id === appointmentId);
|
||||
if (!appointment) return;
|
||||
|
||||
// Calculate new end time (30 minutes from start)
|
||||
@@ -434,7 +458,7 @@ export default function AppointmentsPage() {
|
||||
|
||||
// Update appointment data
|
||||
// Make sure we handle the time format correctly - backend expects HH:MM but stores as HH:MM:SS
|
||||
const updatedAppointment: any = {
|
||||
const updatedAppointment: UpdateAppointment = {
|
||||
...appointment,
|
||||
startTime: newTimeSlot.time, // Already in HH:MM format
|
||||
endTime: endTime, // Already in HH:MM format
|
||||
@@ -475,7 +499,6 @@ export default function AppointmentsPage() {
|
||||
return (
|
||||
<div
|
||||
ref={drag as unknown as React.RefObject<HTMLDivElement>} // Type assertion to make TypeScript happy
|
||||
|
||||
className={`${staff.color} border border-white shadow-md text-white rounded p-1 text-xs h-full overflow-hidden cursor-move relative ${
|
||||
isDragging ? 'opacity-50' : 'opacity-100'
|
||||
}`}
|
||||
@@ -483,14 +506,14 @@ export default function AppointmentsPage() {
|
||||
onClick={(e) => {
|
||||
// Only allow edit on click if we're not dragging
|
||||
if (!isDragging) {
|
||||
const fullAppointment = appointments.find((a:any) => a.id === appointment.id);
|
||||
const fullAppointment = appointments.find(a => a.id === appointment.id);
|
||||
if (fullAppointment) {
|
||||
e.stopPropagation();
|
||||
handleEditAppointment(fullAppointment);
|
||||
}
|
||||
}
|
||||
}}
|
||||
onContextMenu={(e) => handleContextMenu(e, appointment.id)}
|
||||
onContextMenu={(e) => handleContextMenu(e, appointment.id ?? 0)}
|
||||
>
|
||||
<div className="font-bold truncate flex items-center gap-1">
|
||||
<Move className="h-3 w-3" />
|
||||
@@ -531,8 +554,6 @@ export default function AppointmentsPage() {
|
||||
return (
|
||||
<td
|
||||
ref={drop as unknown as React.RefObject<HTMLTableCellElement>}
|
||||
|
||||
|
||||
key={`${timeSlot.time}-${staffId}`}
|
||||
className={`px-1 py-1 border relative h-14 ${isOver && canDrop ? 'bg-green-100' : ''}`}
|
||||
>
|
||||
@@ -583,7 +604,7 @@ export default function AppointmentsPage() {
|
||||
<Menu id={APPOINTMENT_CONTEXT_MENU_ID} animation="fade">
|
||||
<Item
|
||||
onClick={({ props }) => {
|
||||
const fullAppointment = appointments.find((a:any) => a.id === props.appointmentId);
|
||||
const fullAppointment = appointments.find(a => a.id === props.appointmentId);
|
||||
if (fullAppointment) {
|
||||
handleEditAppointment(fullAppointment);
|
||||
}
|
||||
@@ -596,14 +617,14 @@ export default function AppointmentsPage() {
|
||||
</Item>
|
||||
<Item
|
||||
onClick={({ props }) => {
|
||||
const fullAppointment = appointments.find((a:any) => a.id === props.appointmentId);
|
||||
const fullAppointment = appointments.find(a => a.id === props.appointmentId);
|
||||
if (fullAppointment) {
|
||||
// Set the appointment and patient IDs for the claim modal
|
||||
setClaimAppointmentId(fullAppointment.id);
|
||||
setClaimAppointmentId(fullAppointment.id ?? null);
|
||||
setClaimPatientId(fullAppointment.patientId);
|
||||
|
||||
// Find the patient name for the toast notification
|
||||
const patient = patients.find((p:any) => p.id === fullAppointment.patientId);
|
||||
const patient = patients.find(p => p.id === fullAppointment.patientId);
|
||||
const patientName = patient ? `${patient.firstName} ${patient.lastName}` : `Patient #${fullAppointment.patientId}`;
|
||||
|
||||
// Show a toast notification
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { z } from "zod";
|
||||
import { UserCreateOneSchema } from "@repo/db/shared";
|
||||
import { UserUncheckedCreateInputObjectSchema } from "@repo/db/shared/schemas";
|
||||
// import { insertUserSchema } from "@repo/db/shared/schemas";
|
||||
import { useState } from "react";
|
||||
import { useAuth } from "../hooks/use-auth";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import { Redirect } from "wouter";
|
||||
import { Button } from "../components/ui/button";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Form,
|
||||
FormControl,
|
||||
@@ -13,18 +14,25 @@ import {
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from "../components/ui/form";
|
||||
import { Input } from "../components/ui/input";
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "../components/ui/tabs";
|
||||
import { Checkbox } from "../components/ui/checkbox";
|
||||
import { Card, CardContent } from "../components/ui/card";
|
||||
} from "@/components/ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import { BriefcaseMedical, CheckCircle, Torus } from "lucide-react";
|
||||
import { CheckedState } from "@radix-ui/react-checkbox";
|
||||
|
||||
const loginSchema = UserCreateOneSchema.extend({
|
||||
const insertUserSchema = (UserUncheckedCreateInputObjectSchema as unknown as z.ZodObject<any>).pick({
|
||||
username: true,
|
||||
password: true,
|
||||
});
|
||||
|
||||
const loginSchema = (insertUserSchema as unknown as z.ZodObject<any>).extend({
|
||||
rememberMe: z.boolean().optional(),
|
||||
});
|
||||
|
||||
const registerSchema = UserCreateOne.extend({
|
||||
|
||||
const registerSchema = (insertUserSchema as unknown as z.ZodObject<any>).extend({
|
||||
confirmPassword: z.string().min(6, {
|
||||
message: "Password must be at least 6 characters long",
|
||||
}),
|
||||
@@ -143,7 +151,7 @@ export default function AuthPage() {
|
||||
<div className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
id="remember-me"
|
||||
checked={field.value}
|
||||
checked={field.value as CheckedState}
|
||||
onCheckedChange={field.onChange}
|
||||
/>
|
||||
<label
|
||||
@@ -216,6 +224,8 @@ export default function AuthPage() {
|
||||
placeholder="••••••••"
|
||||
type="password"
|
||||
{...field}
|
||||
value={typeof field.value === 'string' ? field.value : ''}
|
||||
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
@@ -230,7 +240,7 @@ export default function AuthPage() {
|
||||
<FormItem className="flex items-start space-x-2 mt-4">
|
||||
<FormControl>
|
||||
<Checkbox
|
||||
checked={field.value}
|
||||
checked={field.value as CheckedState}
|
||||
onCheckedChange={field.onChange}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
import { useState } from "react";
|
||||
import { useQuery, useMutation } from "@tanstack/react-query";
|
||||
import { format } from "date-fns";
|
||||
import { TopAppBar } from "../components/layout/top-app-bar";
|
||||
import { Sidebar } from "../components/layout/sidebar";
|
||||
import { StatCard } from "../components/ui/stat-card";
|
||||
import { PatientTable } from "../components/patients/patient-table";
|
||||
import { AddPatientModal } from "../components/patients/add-patient-modal";
|
||||
import { AddAppointmentModal } from "../components/appointments/add-appointment-modal";
|
||||
import { Card, CardContent } from "../components/ui/card";
|
||||
import { Button } from "../components/ui/button";
|
||||
import { useToast } from "../hooks/use-toast";
|
||||
import { useAuth } from "../hooks/use-auth";
|
||||
import { apiRequest, queryClient } from "../lib/queryClient";
|
||||
import { InsertPatient, Patient, UpdatePatient, Appointment, InsertAppointment, UpdateAppointment } from "@repo/db/schema";
|
||||
import { TopAppBar } from "@/components/layout/top-app-bar";
|
||||
import { Sidebar } from "@/components/layout/sidebar";
|
||||
import { StatCard } from "@/components/ui/stat-card";
|
||||
import { PatientTable } from "@/components/patients/patient-table";
|
||||
import { AddPatientModal } from "@/components/patients/add-patient-modal";
|
||||
import { AddAppointmentModal } from "@/components/appointments/add-appointment-modal";
|
||||
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useToast } from "@/hooks/use-toast";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import { apiRequest, queryClient } from "@/lib/queryClient";
|
||||
import { AppointmentUncheckedCreateInputObjectSchema, PatientUncheckedCreateInputObjectSchema } from "@repo/db/shared/schemas";
|
||||
// import { InsertPatient, Patient, UpdatePatient, Appointment, InsertAppointment, UpdateAppointment } from "@repo/db/shared/schemas";
|
||||
import { Users, Calendar, CheckCircle, CreditCard, Plus, Clock } from "lucide-react";
|
||||
import { Link } from "wouter";
|
||||
import {
|
||||
@@ -21,7 +22,43 @@ import {
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from "../components/ui/dialog";
|
||||
} from "@/components/ui/dialog";
|
||||
import {z} from "zod";
|
||||
|
||||
//creating types out of schema auto generated.
|
||||
type Appointment = z.infer<typeof AppointmentUncheckedCreateInputObjectSchema>;
|
||||
|
||||
const insertAppointmentSchema = (AppointmentUncheckedCreateInputObjectSchema as unknown as z.ZodObject<any>).omit({
|
||||
id: true,
|
||||
createdAt: true,
|
||||
});
|
||||
type InsertAppointment = z.infer<typeof insertAppointmentSchema>;
|
||||
|
||||
const updateAppointmentSchema = (AppointmentUncheckedCreateInputObjectSchema as unknown as z.ZodObject<any>).omit({
|
||||
id: true,
|
||||
createdAt: true,
|
||||
}).partial();
|
||||
type UpdateAppointment = z.infer<typeof updateAppointmentSchema>;
|
||||
|
||||
const PatientSchema = (PatientUncheckedCreateInputObjectSchema as unknown as z.ZodObject<any>).omit({
|
||||
appointments: true,
|
||||
});
|
||||
type Patient = z.infer<typeof PatientSchema>;
|
||||
|
||||
const insertPatientSchema = (PatientUncheckedCreateInputObjectSchema as unknown as z.ZodObject<any>).omit({
|
||||
id: true,
|
||||
createdAt: true,
|
||||
});
|
||||
type InsertPatient = z.infer<typeof insertPatientSchema>;
|
||||
|
||||
const updatePatientSchema = (PatientUncheckedCreateInputObjectSchema as unknown as z.ZodObject<any>).omit({
|
||||
id: true,
|
||||
createdAt: true,
|
||||
userId: true,
|
||||
}).partial();
|
||||
|
||||
type UpdatePatient = z.infer<typeof updatePatientSchema>;
|
||||
|
||||
|
||||
export default function Dashboard() {
|
||||
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
|
||||
@@ -174,7 +211,7 @@ export default function Dashboard() {
|
||||
|
||||
// Handle appointment submission (create or update)
|
||||
const handleAppointmentSubmit = (appointmentData: InsertAppointment | UpdateAppointment) => {
|
||||
if (selectedAppointment) {
|
||||
if (selectedAppointment && typeof selectedAppointment.id === 'number') {
|
||||
updateAppointmentMutation.mutate({
|
||||
id: selectedAppointment.id,
|
||||
appointment: appointmentData as UpdateAppointment,
|
||||
@@ -274,7 +311,7 @@ export default function Dashboard() {
|
||||
{patient ? `${patient.firstName} ${patient.lastName}` : 'Unknown Patient'}
|
||||
</h3>
|
||||
<div className="text-sm text-gray-500 flex items-center space-x-2">
|
||||
<span>{appointment.startTime} - {appointment.endTime}</span>
|
||||
<span>{new Date(appointment.startTime).toLocaleString()} - {new Date(appointment.endTime).toLocaleString()}</span>
|
||||
<span>•</span>
|
||||
<span>{appointment.type.charAt(0).toUpperCase() + appointment.type.slice(1)}</span>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Card, CardContent } from "../components/ui/card";
|
||||
import { Card, CardContent } from "@/components/ui/card";
|
||||
import { AlertCircle } from "lucide-react";
|
||||
|
||||
export default function NotFound() {
|
||||
|
||||
@@ -1,18 +1,41 @@
|
||||
import { useState, useMemo, useRef } from "react";
|
||||
import { useQuery, useMutation } from "@tanstack/react-query";
|
||||
import { TopAppBar } from "../components/layout/top-app-bar";
|
||||
import { Sidebar } from "../components/layout/sidebar";
|
||||
import { PatientTable } from "../components/patients/patient-table";
|
||||
import { AddPatientModal } from "../components/patients/add-patient-modal";
|
||||
import { PatientSearch, SearchCriteria } from "../components/patients/patient-search";
|
||||
import { FileUploadZone } from "../components/file-upload/file-upload-zone";
|
||||
import { Button } from "../components/ui/button";
|
||||
import { TopAppBar } from "@/components/layout/top-app-bar";
|
||||
import { Sidebar } from "@/components/layout/sidebar";
|
||||
import { PatientTable } from "@/components/patients/patient-table";
|
||||
import { AddPatientModal } from "@/components/patients/add-patient-modal";
|
||||
import { PatientSearch, SearchCriteria } from "@/components/patients/patient-search";
|
||||
import { FileUploadZone } from "@/components/file-upload/file-upload-zone";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Plus, RefreshCw, File, FilePlus } from "lucide-react";
|
||||
import { useToast } from "../hooks/use-toast";
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "../components/ui/card";
|
||||
import { Patient, InsertPatient, UpdatePatient } from "@shared/schema";
|
||||
import { apiRequest, queryClient } from "../lib/queryClient";
|
||||
import { useAuth } from "../hooks/use-auth";
|
||||
import { useToast } from "@/hooks/use-toast";
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { PatientUncheckedCreateInputObjectSchema } from "@repo/db/shared/schemas";
|
||||
// import { Patient, InsertPatient, UpdatePatient } from "@repo/db/shared/schemas";
|
||||
import { apiRequest, queryClient } from "@/lib/queryClient";
|
||||
import { useAuth } from "@/hooks/use-auth";
|
||||
import {z} from "zod";
|
||||
|
||||
|
||||
const PatientSchema = (PatientUncheckedCreateInputObjectSchema as unknown as z.ZodObject<any>).omit({
|
||||
appointments: true,
|
||||
});
|
||||
type Patient = z.infer<typeof PatientSchema>;
|
||||
|
||||
const insertPatientSchema = (PatientUncheckedCreateInputObjectSchema as unknown as z.ZodObject<any>).omit({
|
||||
id: true,
|
||||
createdAt: true,
|
||||
});
|
||||
type InsertPatient = z.infer<typeof insertPatientSchema>;
|
||||
|
||||
const updatePatientSchema = (PatientUncheckedCreateInputObjectSchema as unknown as z.ZodObject<any>).omit({
|
||||
id: true,
|
||||
createdAt: true,
|
||||
userId: true,
|
||||
}).partial();
|
||||
|
||||
type UpdatePatient = z.infer<typeof updatePatientSchema>;
|
||||
|
||||
|
||||
// Type for the ref to access modal methods
|
||||
type AddPatientModalRef = {
|
||||
|
||||
Reference in New Issue
Block a user