feat(patient-status schema updated)- applied changes
This commit is contained in:
@@ -77,7 +77,6 @@ async function createOrUpdatePatientByInsuranceId(options: {
|
||||
gender: "",
|
||||
phone: "",
|
||||
userId,
|
||||
status: "inactive",
|
||||
insuranceId,
|
||||
};
|
||||
|
||||
@@ -219,7 +218,7 @@ router.post(
|
||||
|
||||
if (patient && patient.id !== undefined) {
|
||||
const newStatus =
|
||||
seleniumResult.eligibility === "Y" ? "active" : "inactive";
|
||||
seleniumResult.eligibility === "Y" ? "ACTIVE" : "INACTIVE";
|
||||
await storage.updatePatient(patient.id, { status: newStatus });
|
||||
outputResult.patientUpdateStatus = `Patient status updated to ${newStatus}`;
|
||||
|
||||
@@ -647,7 +646,7 @@ router.post(
|
||||
|
||||
// Update patient status based on seleniumResult.eligibility
|
||||
const newStatus =
|
||||
seleniumResult?.eligibility === "Y" ? "active" : "inactive";
|
||||
seleniumResult?.eligibility === "Y" ? "ACTIVE" : "INACTIVE";
|
||||
await storage.updatePatient(updatedPatient.id, { status: newStatus });
|
||||
resultItem.patientUpdateStatus = `Patient status updated to ${newStatus}`;
|
||||
|
||||
|
||||
@@ -24,11 +24,14 @@ import {
|
||||
InsertPatient,
|
||||
insertPatientSchema,
|
||||
Patient,
|
||||
PatientStatus,
|
||||
patientStatusOptions,
|
||||
UpdatePatient,
|
||||
updatePatientSchema,
|
||||
} from "@repo/db/types";
|
||||
import { z } from "zod";
|
||||
import { DateInputField } from "@/components/ui/dateInputField";
|
||||
import { PatientStatusSchema } from "@repo/db/usedSchemas";
|
||||
|
||||
interface PatientFormProps {
|
||||
patient?: Patient;
|
||||
@@ -84,7 +87,7 @@ export const PatientForm = forwardRef<PatientFormRef, PatientFormProps>(
|
||||
policyHolder: "",
|
||||
allergies: "",
|
||||
medicalConditions: "",
|
||||
status: "active",
|
||||
status: "UNKNOWN",
|
||||
userId: user?.id,
|
||||
};
|
||||
}, [isEditing, patient, extractedInfo, user?.id]);
|
||||
@@ -297,27 +300,39 @@ export const PatientForm = forwardRef<PatientFormRef, PatientFormProps>(
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="status"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Status *</FormLabel>
|
||||
<Select
|
||||
onValueChange={field.onChange}
|
||||
value={field.value}
|
||||
defaultValue="active"
|
||||
>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select status" />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
<SelectItem value="active">Active</SelectItem>
|
||||
<SelectItem value="inactive">Inactive</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
render={({ field }) => {
|
||||
const options = Object.values(
|
||||
patientStatusOptions
|
||||
) as PatientStatus[]; // ['ACTIVE','INACTIVE','UNKNOWN']
|
||||
const toLabel = (v: PatientStatus) =>
|
||||
v[0] + v.slice(1).toLowerCase(); // ACTIVE -> Active
|
||||
|
||||
return (
|
||||
<FormItem>
|
||||
<FormLabel>Status *</FormLabel>
|
||||
<Select
|
||||
value={(field.value as PatientStatus) ?? "UNKNOWN"}
|
||||
onValueChange={(v) =>
|
||||
field.onChange(v as PatientStatus)
|
||||
}
|
||||
>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select status" />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
{options.map((v) => (
|
||||
<SelectItem key={v} value={v}>
|
||||
{toLabel(v)}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
|
||||
@@ -39,6 +39,7 @@ import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { formatDateToHumanReadable } from "@/utils/dateUtils";
|
||||
import { Patient, UpdatePatient } from "@repo/db/types";
|
||||
import { PatientFinancialsModal } from "./patient-financial-modal";
|
||||
import { getPageNumbers } from "@/utils/pageNumberGenerator";
|
||||
|
||||
interface PatientApiResponse {
|
||||
patients: Patient[];
|
||||
@@ -309,25 +310,6 @@ export function PatientTable({
|
||||
return colorClasses[id % colorClasses.length];
|
||||
};
|
||||
|
||||
function getPageNumbers(current: number, total: number): (number | "...")[] {
|
||||
const delta = 2;
|
||||
const range: (number | "...")[] = [];
|
||||
const left = Math.max(2, current - delta);
|
||||
const right = Math.min(total - 1, current + delta);
|
||||
|
||||
range.push(1);
|
||||
if (left > 2) range.push("...");
|
||||
|
||||
for (let i = left; i <= right; i++) {
|
||||
range.push(i);
|
||||
}
|
||||
|
||||
if (right < total - 1) range.push("...");
|
||||
if (total > 1) range.push(total);
|
||||
|
||||
return range;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="bg-white shadow rounded-lg overflow-hidden">
|
||||
<div className="overflow-x-auto">
|
||||
@@ -440,18 +422,26 @@ export function PatientTable({
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<div className="col-span-1">
|
||||
<span
|
||||
className={cn(
|
||||
"inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium",
|
||||
patient.status === "active"
|
||||
? "bg-green-100 text-green-800"
|
||||
: "bg-red-100 text-red-800"
|
||||
)}
|
||||
>
|
||||
{patient.status === "active" ? "Active" : "Inactive"}
|
||||
</span>
|
||||
{patient.status === "ACTIVE" && (
|
||||
<span className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">
|
||||
Active
|
||||
</span>
|
||||
)}
|
||||
|
||||
{patient.status === "INACTIVE" && (
|
||||
<span className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-red-100 text-red-800">
|
||||
Inactive
|
||||
</span>
|
||||
)}
|
||||
|
||||
{patient.status === "UNKNOWN" && (
|
||||
<span className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-gray-200 text-gray-700">
|
||||
Unknown
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</TableCell>
|
||||
|
||||
<TableCell className="text-right">
|
||||
<div className="flex justify-end space-x-2">
|
||||
{allowDelete && (
|
||||
@@ -573,15 +563,18 @@ export function PatientTable({
|
||||
<p>
|
||||
<span className="text-gray-500">Status:</span>{" "}
|
||||
<span
|
||||
className={`${
|
||||
currentPatient.status === "active"
|
||||
className={cn(
|
||||
currentPatient.status === "ACTIVE"
|
||||
? "text-green-600"
|
||||
: "text-red-600"
|
||||
} font-medium`}
|
||||
: currentPatient.status === "INACTIVE"
|
||||
? "text-red-600"
|
||||
: "text-gray-600", // UNKNOWN or fallback
|
||||
"font-medium"
|
||||
)}
|
||||
>
|
||||
{currentPatient.status
|
||||
? currentPatient.status.charAt(0).toUpperCase() +
|
||||
currentPatient.status.slice(1)
|
||||
currentPatient.status.slice(1).toLowerCase()
|
||||
: "Unknown"}
|
||||
</span>
|
||||
</p>
|
||||
|
||||
@@ -251,7 +251,6 @@ export default function InsuranceStatusPage() {
|
||||
gender: "",
|
||||
phone: "",
|
||||
userId: user?.id ?? 1,
|
||||
status: "active",
|
||||
insuranceId: memberId,
|
||||
};
|
||||
await addPatientMutation.mutateAsync(newPatient);
|
||||
|
||||
@@ -254,7 +254,6 @@ export default function PatientsPage() {
|
||||
gender: "",
|
||||
phone: "",
|
||||
userId: user?.id ?? 1,
|
||||
status: "active",
|
||||
insuranceId: data.memberId || "",
|
||||
};
|
||||
|
||||
|
||||
56
migratedb.txt
Normal file
56
migratedb.txt
Normal file
@@ -0,0 +1,56 @@
|
||||
1.
|
||||
```
|
||||
npx prisma migrate dev --create-only --name add_patient_status_enum
|
||||
```
|
||||
|
||||
2.
|
||||
```
|
||||
|
||||
-- Create the enum type (quoted name keeps exact case)
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'PatientStatus') THEN
|
||||
CREATE TYPE "PatientStatus" AS ENUM ('ACTIVE', 'INACTIVE', 'UNKNOWN');
|
||||
END IF;
|
||||
END$$;
|
||||
|
||||
-- 1) Add new enum column (nullable for backfill)
|
||||
ALTER TABLE "Patient"
|
||||
ADD COLUMN IF NOT EXISTS "status_new" "PatientStatus";
|
||||
|
||||
-- 2) Backfill from old text column to enum (case-insensitive)
|
||||
UPDATE "Patient"
|
||||
SET "status_new" = CASE
|
||||
WHEN "status" IS NULL THEN 'UNKNOWN'::"PatientStatus"
|
||||
WHEN lower("status") = 'active' THEN 'ACTIVE'::"PatientStatus"
|
||||
WHEN lower("status") = 'inactive' THEN 'INACTIVE'::"PatientStatus"
|
||||
ELSE 'UNKNOWN'::"PatientStatus"
|
||||
END
|
||||
WHERE "status_new" IS NULL;
|
||||
|
||||
-- 3) Safety: ensure no NULLs remain
|
||||
DO $$
|
||||
DECLARE cnt INTEGER;
|
||||
BEGIN
|
||||
SELECT count(*) INTO cnt FROM "Patient" WHERE "status_new" IS NULL;
|
||||
IF cnt > 0 THEN
|
||||
RAISE EXCEPTION 'Migration abort: % rows have NULL status_new', cnt;
|
||||
END IF;
|
||||
END$$;
|
||||
|
||||
-- 4) Make new column NOT NULL and set DB default to UNKNOWN
|
||||
ALTER TABLE "Patient"
|
||||
ALTER COLUMN "status_new" SET DEFAULT 'UNKNOWN',
|
||||
ALTER COLUMN "status_new" SET NOT NULL;
|
||||
|
||||
-- 5) Drop old column and rename new -> status
|
||||
ALTER TABLE "Patient" DROP COLUMN IF EXISTS "status";
|
||||
ALTER TABLE "Patient" RENAME COLUMN "status_new" TO "status";
|
||||
|
||||
```
|
||||
|
||||
|
||||
3.
|
||||
```
|
||||
npx prisma migrate dev
|
||||
```
|
||||
@@ -52,7 +52,7 @@ model Patient {
|
||||
policyHolder String?
|
||||
allergies String?
|
||||
medicalConditions String?
|
||||
status String @default("active")
|
||||
status PatientStatus @default(UNKNOWN)
|
||||
userId Int
|
||||
createdAt DateTime @default(now())
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
@@ -65,6 +65,12 @@ model Patient {
|
||||
@@index([createdAt])
|
||||
}
|
||||
|
||||
enum PatientStatus {
|
||||
ACTIVE
|
||||
INACTIVE
|
||||
UNKNOWN
|
||||
}
|
||||
|
||||
model Appointment {
|
||||
id Int @id @default(autoincrement())
|
||||
patientId Int
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import { PatientUncheckedCreateInputObjectSchema } from "@repo/db/usedSchemas";
|
||||
import {
|
||||
PatientStatusSchema,
|
||||
PatientUncheckedCreateInputObjectSchema,
|
||||
} from "@repo/db/usedSchemas";
|
||||
import { z } from "zod";
|
||||
import { makeEnumOptions } from "../utils";
|
||||
|
||||
export type Patient = z.infer<typeof PatientUncheckedCreateInputObjectSchema>;
|
||||
|
||||
@@ -28,6 +32,17 @@ export const insuranceIdSchema = z.preprocess(
|
||||
.nullable()
|
||||
);
|
||||
|
||||
//patient status
|
||||
export type PatientStatus = z.infer<typeof PatientStatusSchema>;
|
||||
|
||||
// enum → select options
|
||||
export const patientStatusOptions =
|
||||
makeEnumOptions<
|
||||
typeof PatientStatusSchema extends z.ZodTypeAny
|
||||
? z.infer<typeof PatientStatusSchema>
|
||||
: string
|
||||
>(PatientStatusSchema);
|
||||
|
||||
export const insertPatientSchema = (
|
||||
PatientUncheckedCreateInputObjectSchema as unknown as z.ZodObject<any>
|
||||
)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// using this, as the browser load only the required files , not whole db/shared/schemas/ files.
|
||||
export * from '../shared/schemas/objects/AppointmentUncheckedCreateInput.schema';
|
||||
export * from '../shared/schemas/objects/PatientUncheckedCreateInput.schema';
|
||||
export * from '../shared/schemas/enums/PatientStatus.schema';
|
||||
export * from '../shared/schemas/objects/UserUncheckedCreateInput.schema';
|
||||
export * from '../shared/schemas/objects/StaffUncheckedCreateInput.schema'
|
||||
export * from '../shared/schemas/objects/ClaimUncheckedCreateInput.schema'
|
||||
|
||||
Reference in New Issue
Block a user