feat(patient-status schema updated)- applied changes
This commit is contained in:
@@ -77,7 +77,6 @@ async function createOrUpdatePatientByInsuranceId(options: {
|
|||||||
gender: "",
|
gender: "",
|
||||||
phone: "",
|
phone: "",
|
||||||
userId,
|
userId,
|
||||||
status: "inactive",
|
|
||||||
insuranceId,
|
insuranceId,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -219,7 +218,7 @@ router.post(
|
|||||||
|
|
||||||
if (patient && patient.id !== undefined) {
|
if (patient && patient.id !== undefined) {
|
||||||
const newStatus =
|
const newStatus =
|
||||||
seleniumResult.eligibility === "Y" ? "active" : "inactive";
|
seleniumResult.eligibility === "Y" ? "ACTIVE" : "INACTIVE";
|
||||||
await storage.updatePatient(patient.id, { status: newStatus });
|
await storage.updatePatient(patient.id, { status: newStatus });
|
||||||
outputResult.patientUpdateStatus = `Patient status updated to ${newStatus}`;
|
outputResult.patientUpdateStatus = `Patient status updated to ${newStatus}`;
|
||||||
|
|
||||||
@@ -647,7 +646,7 @@ router.post(
|
|||||||
|
|
||||||
// Update patient status based on seleniumResult.eligibility
|
// Update patient status based on seleniumResult.eligibility
|
||||||
const newStatus =
|
const newStatus =
|
||||||
seleniumResult?.eligibility === "Y" ? "active" : "inactive";
|
seleniumResult?.eligibility === "Y" ? "ACTIVE" : "INACTIVE";
|
||||||
await storage.updatePatient(updatedPatient.id, { status: newStatus });
|
await storage.updatePatient(updatedPatient.id, { status: newStatus });
|
||||||
resultItem.patientUpdateStatus = `Patient status updated to ${newStatus}`;
|
resultItem.patientUpdateStatus = `Patient status updated to ${newStatus}`;
|
||||||
|
|
||||||
|
|||||||
@@ -24,11 +24,14 @@ import {
|
|||||||
InsertPatient,
|
InsertPatient,
|
||||||
insertPatientSchema,
|
insertPatientSchema,
|
||||||
Patient,
|
Patient,
|
||||||
|
PatientStatus,
|
||||||
|
patientStatusOptions,
|
||||||
UpdatePatient,
|
UpdatePatient,
|
||||||
updatePatientSchema,
|
updatePatientSchema,
|
||||||
} from "@repo/db/types";
|
} from "@repo/db/types";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { DateInputField } from "@/components/ui/dateInputField";
|
import { DateInputField } from "@/components/ui/dateInputField";
|
||||||
|
import { PatientStatusSchema } from "@repo/db/usedSchemas";
|
||||||
|
|
||||||
interface PatientFormProps {
|
interface PatientFormProps {
|
||||||
patient?: Patient;
|
patient?: Patient;
|
||||||
@@ -84,7 +87,7 @@ export const PatientForm = forwardRef<PatientFormRef, PatientFormProps>(
|
|||||||
policyHolder: "",
|
policyHolder: "",
|
||||||
allergies: "",
|
allergies: "",
|
||||||
medicalConditions: "",
|
medicalConditions: "",
|
||||||
status: "active",
|
status: "UNKNOWN",
|
||||||
userId: user?.id,
|
userId: user?.id,
|
||||||
};
|
};
|
||||||
}, [isEditing, patient, extractedInfo, user?.id]);
|
}, [isEditing, patient, extractedInfo, user?.id]);
|
||||||
@@ -297,13 +300,21 @@ export const PatientForm = forwardRef<PatientFormRef, PatientFormProps>(
|
|||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="status"
|
name="status"
|
||||||
render={({ field }) => (
|
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>
|
<FormItem>
|
||||||
<FormLabel>Status *</FormLabel>
|
<FormLabel>Status *</FormLabel>
|
||||||
<Select
|
<Select
|
||||||
onValueChange={field.onChange}
|
value={(field.value as PatientStatus) ?? "UNKNOWN"}
|
||||||
value={field.value}
|
onValueChange={(v) =>
|
||||||
defaultValue="active"
|
field.onChange(v as PatientStatus)
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
@@ -311,13 +322,17 @@ export const PatientForm = forwardRef<PatientFormRef, PatientFormProps>(
|
|||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectItem value="active">Active</SelectItem>
|
{options.map((v) => (
|
||||||
<SelectItem value="inactive">Inactive</SelectItem>
|
<SelectItem key={v} value={v}>
|
||||||
|
{toLabel(v)}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<FormField
|
<FormField
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ import { Checkbox } from "@/components/ui/checkbox";
|
|||||||
import { formatDateToHumanReadable } from "@/utils/dateUtils";
|
import { formatDateToHumanReadable } from "@/utils/dateUtils";
|
||||||
import { Patient, UpdatePatient } from "@repo/db/types";
|
import { Patient, UpdatePatient } from "@repo/db/types";
|
||||||
import { PatientFinancialsModal } from "./patient-financial-modal";
|
import { PatientFinancialsModal } from "./patient-financial-modal";
|
||||||
|
import { getPageNumbers } from "@/utils/pageNumberGenerator";
|
||||||
|
|
||||||
interface PatientApiResponse {
|
interface PatientApiResponse {
|
||||||
patients: Patient[];
|
patients: Patient[];
|
||||||
@@ -309,25 +310,6 @@ export function PatientTable({
|
|||||||
return colorClasses[id % colorClasses.length];
|
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 (
|
return (
|
||||||
<div className="bg-white shadow rounded-lg overflow-hidden">
|
<div className="bg-white shadow rounded-lg overflow-hidden">
|
||||||
<div className="overflow-x-auto">
|
<div className="overflow-x-auto">
|
||||||
@@ -440,18 +422,26 @@ export function PatientTable({
|
|||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<div className="col-span-1">
|
<div className="col-span-1">
|
||||||
<span
|
{patient.status === "ACTIVE" && (
|
||||||
className={cn(
|
<span className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800">
|
||||||
"inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium",
|
Active
|
||||||
patient.status === "active"
|
|
||||||
? "bg-green-100 text-green-800"
|
|
||||||
: "bg-red-100 text-red-800"
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{patient.status === "active" ? "Active" : "Inactive"}
|
|
||||||
</span>
|
</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>
|
</div>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
|
||||||
<TableCell className="text-right">
|
<TableCell className="text-right">
|
||||||
<div className="flex justify-end space-x-2">
|
<div className="flex justify-end space-x-2">
|
||||||
{allowDelete && (
|
{allowDelete && (
|
||||||
@@ -573,15 +563,18 @@ export function PatientTable({
|
|||||||
<p>
|
<p>
|
||||||
<span className="text-gray-500">Status:</span>{" "}
|
<span className="text-gray-500">Status:</span>{" "}
|
||||||
<span
|
<span
|
||||||
className={`${
|
className={cn(
|
||||||
currentPatient.status === "active"
|
currentPatient.status === "ACTIVE"
|
||||||
? "text-green-600"
|
? "text-green-600"
|
||||||
: "text-red-600"
|
: currentPatient.status === "INACTIVE"
|
||||||
} font-medium`}
|
? "text-red-600"
|
||||||
|
: "text-gray-600", // UNKNOWN or fallback
|
||||||
|
"font-medium"
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
{currentPatient.status
|
{currentPatient.status
|
||||||
? currentPatient.status.charAt(0).toUpperCase() +
|
? currentPatient.status.charAt(0).toUpperCase() +
|
||||||
currentPatient.status.slice(1)
|
currentPatient.status.slice(1).toLowerCase()
|
||||||
: "Unknown"}
|
: "Unknown"}
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -251,7 +251,6 @@ export default function InsuranceStatusPage() {
|
|||||||
gender: "",
|
gender: "",
|
||||||
phone: "",
|
phone: "",
|
||||||
userId: user?.id ?? 1,
|
userId: user?.id ?? 1,
|
||||||
status: "active",
|
|
||||||
insuranceId: memberId,
|
insuranceId: memberId,
|
||||||
};
|
};
|
||||||
await addPatientMutation.mutateAsync(newPatient);
|
await addPatientMutation.mutateAsync(newPatient);
|
||||||
|
|||||||
@@ -254,7 +254,6 @@ export default function PatientsPage() {
|
|||||||
gender: "",
|
gender: "",
|
||||||
phone: "",
|
phone: "",
|
||||||
userId: user?.id ?? 1,
|
userId: user?.id ?? 1,
|
||||||
status: "active",
|
|
||||||
insuranceId: data.memberId || "",
|
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?
|
policyHolder String?
|
||||||
allergies String?
|
allergies String?
|
||||||
medicalConditions String?
|
medicalConditions String?
|
||||||
status String @default("active")
|
status PatientStatus @default(UNKNOWN)
|
||||||
userId Int
|
userId Int
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
user User @relation(fields: [userId], references: [id])
|
user User @relation(fields: [userId], references: [id])
|
||||||
@@ -65,6 +65,12 @@ model Patient {
|
|||||||
@@index([createdAt])
|
@@index([createdAt])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum PatientStatus {
|
||||||
|
ACTIVE
|
||||||
|
INACTIVE
|
||||||
|
UNKNOWN
|
||||||
|
}
|
||||||
|
|
||||||
model Appointment {
|
model Appointment {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
patientId Int
|
patientId Int
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
import { PatientUncheckedCreateInputObjectSchema } from "@repo/db/usedSchemas";
|
import {
|
||||||
|
PatientStatusSchema,
|
||||||
|
PatientUncheckedCreateInputObjectSchema,
|
||||||
|
} from "@repo/db/usedSchemas";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
import { makeEnumOptions } from "../utils";
|
||||||
|
|
||||||
export type Patient = z.infer<typeof PatientUncheckedCreateInputObjectSchema>;
|
export type Patient = z.infer<typeof PatientUncheckedCreateInputObjectSchema>;
|
||||||
|
|
||||||
@@ -28,6 +32,17 @@ export const insuranceIdSchema = z.preprocess(
|
|||||||
.nullable()
|
.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 = (
|
export const insertPatientSchema = (
|
||||||
PatientUncheckedCreateInputObjectSchema as unknown as z.ZodObject<any>
|
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.
|
// 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/AppointmentUncheckedCreateInput.schema';
|
||||||
export * from '../shared/schemas/objects/PatientUncheckedCreateInput.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/UserUncheckedCreateInput.schema';
|
||||||
export * from '../shared/schemas/objects/StaffUncheckedCreateInput.schema'
|
export * from '../shared/schemas/objects/StaffUncheckedCreateInput.schema'
|
||||||
export * from '../shared/schemas/objects/ClaimUncheckedCreateInput.schema'
|
export * from '../shared/schemas/objects/ClaimUncheckedCreateInput.schema'
|
||||||
|
|||||||
Reference in New Issue
Block a user