Repository: ohcnetwork/care_fe
Pull request #12376: Fix explicit type casting and add proper types
Author: login: yash-learner
Labels: name: reviewed
description: reviewed by a core member
Created: 2025-05-21T11:59:50Z | Merged: 2025-05-22T07:25:29Z

## Proposed Changes

- Clean up not present field `specimen_type` from `TypeTestedSpec` and form
- Avoid explicit type casting
- Add proper types to many fields and match with backend types


@ohcnetwork/care-fe-code-reviewers

## Merge Checklist

- [ ] Add specs that demonstrate bug / test a new feature.
- [ ] Update [product documentation](https://docs.ohc.network).
- [ ] Ensure that UI text is kept in I18n files.
- [ ] Prep screenshot or demo video for changelog entry, and attach it to issue.
- [ ] Request for Peer Reviews
- [ ] Completion of QA in Mobile Devices
- [ ] Completion of QA in Desktop Devices



Diff:
diff --git a/public/locale/en.json b/public/locale/en.json
index 223bbff3010..6705d994366 100644
--- a/public/locale/en.json
+++ b/public/locale/en.json
@@ -3915,6 +3915,7 @@
   "vaccine_name": "Vaccine name",
   "valid_from": "Valid From",
   "valid_from_after_valid_untill": "Valid From must be before Valid Untill",
+  "valid_integer_required": "Please enter a valid integer",
   "valid_otp_found": "Valid OTP found, Navigating to Appointments",
   "valid_period": "Valid Period",
   "valid_till_equal_or_after_valid_from": "Valid till must be equal to or after valid from date",
diff --git a/src/pages/Facility/services/serviceRequests/ServiceRequestShow.tsx b/src/pages/Facility/services/serviceRequests/ServiceRequestShow.tsx
index 8c4d85f6cff..24eb3446dc2 100644
--- a/src/pages/Facility/services/serviceRequests/ServiceRequestShow.tsx
+++ b/src/pages/Facility/services/serviceRequests/ServiceRequestShow.tsx
@@ -159,7 +159,7 @@ export default function ServiceRequestShow({
         accession_identifier: "", // Will be generated by the server
         received_time: null,
         collection: {
-          method: requirement.collection,
+          method: requirement.collection || null,
           body_site: null,
           collector: null,
           collected_date_time: null,
diff --git a/src/pages/Facility/services/serviceRequests/components/SpecimenForm.tsx b/src/pages/Facility/services/serviceRequests/components/SpecimenForm.tsx
index bad596741c0..596f82e5ea8 100644
--- a/src/pages/Facility/services/serviceRequests/components/SpecimenForm.tsx
+++ b/src/pages/Facility/services/serviceRequests/components/SpecimenForm.tsx
@@ -71,7 +71,7 @@ export function SpecimenForm({
       accession_identifier: "",
       received_time: null,
       collection: {
-        method: specimenDefinition.collection,
+        method: specimenDefinition.collection || null,
         body_site: null,
         collector: currentUserId || null, // Use user ID, default to null if not available yet
         collected_date_time: new Date().toISOString(),
diff --git a/src/pages/Facility/settings/activityDefinition/ActivityDefinitionForm.tsx b/src/pages/Facility/settings/activityDefinition/ActivityDefinitionForm.tsx
index 96c17b4bcdf..002615891a6 100644
--- a/src/pages/Facility/settings/activityDefinition/ActivityDefinitionForm.tsx
+++ b/src/pages/Facility/settings/activityDefinition/ActivityDefinitionForm.tsx
@@ -291,10 +291,7 @@ function ActivityDefinitionFormContent({
                   },
                   {
                     label: t("container"),
-                    value:
-                      s.type_tested?.container?.description ||
-                      s.type_tested?.specimen_type?.display ||
-                      undefined,
+                    value: s.type_tested?.container?.description || undefined,
                   },
                   {
                     label: t("minimum_volume"),
@@ -745,7 +742,6 @@ function ActivityDefinitionFormContent({
                                 label: t("container"),
                                 value:
                                   spec.type_tested?.container?.description ??
-                                  spec.type_tested?.specimen_type?.display ??
                                   undefined,
                               },
                               {
diff --git a/src/pages/Facility/settings/specimen-definitions/CreateSpecimenDefinition.tsx b/src/pages/Facility/settings/specimen-definitions/CreateSpecimenDefinition.tsx
index baa2d5125fc..bceecf3e63d 100644
--- a/src/pages/Facility/settings/specimen-definitions/CreateSpecimenDefinition.tsx
+++ b/src/pages/Facility/settings/specimen-definitions/CreateSpecimenDefinition.tsx
@@ -39,7 +39,7 @@ export function CreateSpecimenDefinition({
     createSpecimenDefinition({
       ...data,
       patient_preparation:
-        data.patient_preparation?.filter((item) => item !== null) || [],
+        data.patient_preparation?.filter((item) => item && item.code) || [],
     });
   };
   return (
diff --git a/src/pages/Facility/settings/specimen-definitions/SpecimenDefinitionDetail.tsx b/src/pages/Facility/settings/specimen-definitions/SpecimenDefinitionDetail.tsx
index f00b8948f78..c818114957c 100644
--- a/src/pages/Facility/settings/specimen-definitions/SpecimenDefinitionDetail.tsx
+++ b/src/pages/Facility/settings/specimen-definitions/SpecimenDefinitionDetail.tsx
@@ -184,14 +184,6 @@ export function SpecimenDefinitionDetail({
                     : t("no")}
                 </Badge>
               </div>
-              {specimenDefinition.type_tested.specimen_type && (
-                <div>
-                  <p className="text-sm font-medium text-gray-400">
-                    {t("specimen_type")}
-                  </p>
-                  <p>{specimenDefinition.type_tested.specimen_type.display}</p>
-                </div>
-              )}
               {/* Additional Information */}
               {specimenDefinition.type_tested.requirement && (
                 <div>
diff --git a/src/pages/Facility/settings/specimen-definitions/SpecimenDefinitionForm.tsx b/src/pages/Facility/settings/specimen-definitions/SpecimenDefinitionForm.tsx
index 176b4c385e4..0194e2e578b 100644
--- a/src/pages/Facility/settings/specimen-definitions/SpecimenDefinitionForm.tsx
+++ b/src/pages/Facility/settings/specimen-definitions/SpecimenDefinitionForm.tsx
@@ -1,7 +1,7 @@
 import { zodResolver } from "@hookform/resolvers/zod";
+import { t } from "i18next";
 import { PlusCircle, XCircle } from "lucide-react";
 import { navigate } from "raviger";
-import React from "react";
 import { useForm } from "react-hook-form";
 import { useTranslation } from "react-i18next";
 import * as z from "zod";
@@ -32,54 +32,51 @@ import ComboboxQuantityInput from "@/components/Common/ComboboxQuantityInput";
 import ValueSetSelect from "@/components/Questionnaire/ValueSetSelect";
 
 import useCurrentFacility from "@/pages/Facility/utils/useCurrentFacility";
-import { Code } from "@/types/base/code/code";
+import { Code, CodeSchema } from "@/types/base/code/code";
 import {
   Preference,
   RETENTION_TIME_UNITS,
   SPECIMEN_DEFINITION_UNITS_CODES,
   Status,
 } from "@/types/emr/specimenDefinition/specimenDefinition";
-import {
-  SpecimenDefinitionCreate,
-  SpecimenDefinitionUpdate,
-} from "@/types/emr/specimenDefinition/specimenDefinition";
+import { SpecimenDefinitionCreate } from "@/types/emr/specimenDefinition/specimenDefinition";
 
 const typeTestedSchema = z.object({
   is_derived: z.boolean(),
-  specimen_type: z.any(), // Code type
   preference: z.nativeEnum(Preference),
   container: z
     .object({
       description: z.string().nullable(),
       capacity: z
         .object({
-          value: z.number().nullable(),
-          unit: z.any(), // Code type
+          value: z.number(),
+          unit: CodeSchema,
         })
+        .optional()
         .nullable(),
       minimum_volume: z
         .object({
           quantity: z
             .object({
-              value: z.number().optional().nullable(),
-              unit: z.any(), // Code type
+              value: z.number(),
+              unit: CodeSchema,
             })
             .optional()
             .nullable(),
           string: z.string().optional().nullable(),
         })
-        .optional()
         .nullable(),
-      cap: z.any().nullable(), // Code type
+      cap: CodeSchema.optional().nullable(),
       preparation: z.string().nullable(),
     })
     .nullable(),
   requirement: z.string().nullable(),
   retention_time: z
     .object({
-      value: z.number().nullable(),
-      unit: z.any(), // Code type
+      value: z.number().int({ message: t("valid_integer_required") }),
+      unit: CodeSchema,
     })
+    .optional()
     .nullable(),
   single_use: z.boolean().nullable(),
 });
@@ -88,14 +85,14 @@ const formSchema = z.object({
   title: z.string().min(1, "Title is required"),
   slug: z.string().min(1, "Slug is required"),
   status: z.nativeEnum(Status),
-  description: z.string().optional(),
+  description: z.string().min(1, t("field_required")),
   derived_from_uri: z
     .string()
     .url({ message: "Please enter a valid URL" })
     .nullable(),
-  type_collected: z.any().nullable(), // Code type
-  patient_preparation: z.array(z.any()).min(0), // Code type array
-  collection: z.any().nullable(), // Code type
+  type_collected: CodeSchema,
+  patient_preparation: z.array(CodeSchema).min(0),
+  collection: CodeSchema.nullable(),
   type_tested: typeTestedSchema.nullable(),
 });
 
@@ -103,14 +100,12 @@ type FormValues = z.infer<typeof formSchema>;
 
 interface SpecimenDefinitionFormProps {
   initialData?: SpecimenDefinitionCreate;
-  specimenDefinitionId?: string;
-  onSubmit: (data: SpecimenDefinitionCreate | SpecimenDefinitionUpdate) => void;
+  onSubmit: (data: SpecimenDefinitionCreate) => void;
   isLoading?: boolean;
 }
 
 export function SpecimenDefinitionForm({
   initialData,
-  specimenDefinitionId,
   onSubmit,
   isLoading,
 }: SpecimenDefinitionFormProps) {
@@ -126,25 +121,28 @@ export function SpecimenDefinitionForm({
       status: initialData?.status || Status.active,
       description: initialData?.description || "",
       derived_from_uri: initialData?.derived_from_uri || null,
-      type_collected: initialData?.type_collected || null,
-      patient_preparation: initialData?.patient_preparation || [null],
+      type_collected: initialData?.type_collected,
+      patient_preparation: initialData?.patient_preparation || [],
       collection: initialData?.collection || null,
       type_tested: initialData?.type_tested || {
         is_derived: false,
-        specimen_type: null,
         preference: Preference.preferred,
         container: {
           description: "",
-          capacity: { value: null, unit: null },
+          capacity: initialData?.type_tested?.container?.capacity,
           minimum_volume: {
-            quantity: { value: null, unit: null },
-            string: null,
+            quantity:
+              initialData?.type_tested?.container?.minimum_volume?.quantity ||
+              null,
+            string:
+              initialData?.type_tested?.container?.minimum_volume?.string ||
+              null,
           },
-          cap: null,
+          cap: initialData?.type_tested?.container?.cap,
           preparation: "",
         },
         requirement: "",
-        retention_time: { value: null, unit: null },
+        retention_time: initialData?.type_tested?.retention_time,
         single_use: false,
       },
     },
@@ -171,7 +169,10 @@ export function SpecimenDefinitionForm({
 
   const addPatientPreparation = () => {
     const currentPreparations = form.getValues("patient_preparation");
-    form.setValue("patient_preparation", [...currentPreparations, null]);
+    form.setValue("patient_preparation", [
+      ...currentPreparations,
+      { code: "", system: "", display: "" },
+    ]);
   };
 
   const removePatientPreparation = (index: number) => {
@@ -184,27 +185,28 @@ export function SpecimenDefinitionForm({
     form.setValue("type_tested.container.minimum_volume", {
       quantity:
         type === "quantity"
-          ? { value: null, unit: SPECIMEN_DEFINITION_UNITS_CODES[0] }
+          ? { value: 0, unit: SPECIMEN_DEFINITION_UNITS_CODES[0] }
           : null,
       string: type === "text" ? "" : null,
     });
   };
 
-  const handleMinimumVolumeChange = (
-    type: "quantity" | "string",
-    value: { value: number | null; unit: Code | null } | string | null,
-  ) => {
-    if (type === "quantity") {
-      form.setValue("type_tested.container.minimum_volume", {
-        quantity: value as { value: number | null; unit: Code | null },
-        string: null,
-      });
-    } else {
-      form.setValue("type_tested.container.minimum_volume", {
-        quantity: null,
-        string: value as string,
-      });
-    }
+  const handleMinimumVolumeQuantityChange = (value: {
+    value: number | null;
+    unit: Code;
+  }) => {
+    form.setValue("type_tested.container.minimum_volume", {
+      quantity:
+        value.value !== null ? { value: value.value, unit: value.unit } : null,
+      string: null,
+    });
+  };
+
+  const handleMinimumVolumeStringChange = (value: string) => {
+    form.setValue("type_tested.container.minimum_volume", {
+      quantity: null,
+      string: value,
+    });
   };
 
   return (
@@ -215,11 +217,7 @@ export function SpecimenDefinitionForm({
           e.stopPropagation();
           form.handleSubmit(
             (data) => {
-              if (specimenDefinitionId) {
-                onSubmit(data as SpecimenDefinitionUpdate);
-              } else {
-                onSubmit(data as SpecimenDefinitionCreate);
-              }
+              onSubmit(data);
             },
             (errors) => {
               console.log("Form submission failed with errors:", errors);
@@ -470,27 +468,6 @@ export function SpecimenDefinitionForm({
                     </FormItem>
                   )}
                 />
-                <FormField
-                  control={form.control}
-                  name="type_tested.specimen_type"
-                  render={({ field }) => (
-                    <FormItem className="flex flex-col">
-                      <FormLabel>{t("specimen_type")}</FormLabel>
-                      <FormControl>
-                        <ValueSetSelect
-                          system="system-specimen_type-code"
-                          placeholder={t("select_specimen_type")}
-                          onSelect={(code) =>
-                            form.setValue("type_tested.specimen_type", code)
-                          }
-                          value={field.value}
-                          disabled={isLoading}
-                        />
-                      </FormControl>
-                      <FormMessage />
-                    </FormItem>
-                  )}
-                />
 
                 <FormField
                   control={form.control}
@@ -520,33 +497,40 @@ export function SpecimenDefinitionForm({
                     </FormItem>
                   )}
                 />
+                <div>
+                  <FormField
+                    control={form.control}
+                    name="type_tested.retention_time"
+                    render={({ field }) => (
+                      <FormItem className="flex flex-col">
+                        <FormLabel>{t("retention_time")}</FormLabel>
+                        <FormControl>
+                          <ComboboxQuantityInput
+                            quantity={
+                              field.value
+                                ? {
+                                    value: field.value.value || null,
+                                    unit: field.value.unit,
+                                  }
+                                : { value: null, unit: RETENTION_TIME_UNITS[0] }
+                            }
+                            onChange={field.onChange}
+                            disabled={isLoading}
+                            placeholder={t("enter_retention_time")}
+                            units={RETENTION_TIME_UNITS}
+                          />
+                        </FormControl>
+                      </FormItem>
+                    )}
+                  />
+                  <FormMessage>
+                    {
+                      form.formState.errors.type_tested?.retention_time?.value
+                        ?.message
+                    }
+                  </FormMessage>
+                </div>
 
-                <FormField
-                  control={form.control}
-                  name="type_tested.retention_time"
-                  render={({ field }) => (
-                    <FormItem className="flex flex-col">
-                      <FormLabel>{t("retention_time")}</FormLabel>
-                      <FormControl>
-                        <ComboboxQuantityInput
-                          quantity={
-                            field.value
-                              ? {
-                                  value: field.value.value || null,
-                                  unit: field.value.unit,
-                                }
-                              : { value: null, unit: RETENTION_TIME_UNITS[0] }
-                          }
-                          onChange={field.onChange}
-                          disabled={isLoading}
-                          placeholder={t("enter_retention_time")}
-                          units={RETENTION_TIME_UNITS}
-                        />
-                      </FormControl>
-                      <FormMessage />
-                    </FormItem>
-                  )}
-                />
                 <FormField
                   control={form.control}
                   name="type_tested.requirement"
@@ -674,16 +658,13 @@ export function SpecimenDefinitionForm({
                                   quantity={
                                     field.value
                                       ? {
-                                          value: field.value.value || null,
+                                          value: field.value.value,
                                           unit: field.value.unit,
                                         }
-                                      : {
-                                          value: null,
-                                          unit: SPECIMEN_DEFINITION_UNITS_CODES[0],
-                                        }
+                                      : undefined
                                   }
                                   onChange={(value) =>
-                                    handleMinimumVolumeChange("quantity", value)
+                                    handleMinimumVolumeQuantityChange(value)
                                   }
                                   disabled={isLoading}
                                   placeholder={t("enter_minimum_volume")}
@@ -708,8 +689,7 @@ export function SpecimenDefinitionForm({
                                   value={field.value || ""}
                                   disabled={isLoading}
                                   onChange={(e) =>
-                                    handleMinimumVolumeChange(
-                                      "string",
+                                    handleMinimumVolumeStringChange(
                                       e.target.value,
                                     )
                                   }
diff --git a/src/pages/Facility/settings/specimen-definitions/UpdateSpecimenDefinition.tsx b/src/pages/Facility/settings/specimen-definitions/UpdateSpecimenDefinition.tsx
index 9082f58feed..4b03b8696d7 100644
--- a/src/pages/Facility/settings/specimen-definitions/UpdateSpecimenDefinition.tsx
+++ b/src/pages/Facility/settings/specimen-definitions/UpdateSpecimenDefinition.tsx
@@ -5,7 +5,6 @@ import { toast } from "sonner";
 
 import mutate from "@/Utils/request/mutate";
 import query from "@/Utils/request/query";
-import { SpecimenDefinitionUpdate } from "@/types/emr/specimenDefinition/specimenDefinition";
 import specimenDefinitionApi from "@/types/emr/specimenDefinition/specimenDefinitionApi";
 
 import { SpecimenDefinitionForm } from "./SpecimenDefinitionForm";
@@ -63,9 +62,13 @@ export function UpdateSpecimenDefinition({
       <SpecimenDefinitionForm
         initialData={specimenDefinition}
         onSubmit={(data) =>
-          updateSpecimenDefinition(data as SpecimenDefinitionUpdate)
+          updateSpecimenDefinition({
+            ...data,
+            patient_preparation:
+              data.patient_preparation?.filter((item) => item && item.code) ||
+              [],
+          })
         }
-        specimenDefinitionId={specimenDefinitionId}
         isLoading={isUpdating}
       />
     </div>
diff --git a/src/types/emr/specimenDefinition/specimenDefinition.ts b/src/types/emr/specimenDefinition/specimenDefinition.ts
index 8c5c614cc90..c69da34dc38 100644
--- a/src/types/emr/specimenDefinition/specimenDefinition.ts
+++ b/src/types/emr/specimenDefinition/specimenDefinition.ts
@@ -14,13 +14,13 @@ export enum Preference {
 }
 
 export interface QuantitySpec {
-  value: number | null;
+  value: number;
   unit: Code;
 }
 
 export interface MinimumVolumeSpec {
-  quantity: QuantitySpec | null;
-  string: string | null;
+  quantity?: QuantitySpec | null;
+  string?: string | null;
 }
 
 export interface DurationSpec {
@@ -29,11 +29,11 @@ export interface DurationSpec {
 }
 
 export interface ContainerSpec {
-  description: string | null;
-  capacity: QuantitySpec | null;
-  minimum_volume: MinimumVolumeSpec | null;
-  cap: Code | null;
-  preparation: string | null;
+  description?: string | null;
+  capacity?: QuantitySpec | null;
+  minimum_volume?: MinimumVolumeSpec | null;
+  cap?: Code | null;
+  preparation?: string | null;
 }
 
 export const SPECIMEN_DEFINITION_UNITS_CODES = [
@@ -71,25 +71,23 @@ export const RETENTION_TIME_UNITS = [
 
 export interface TypeTestedSpec {
   is_derived: boolean;
-  specimen_type: Code | null;
   preference: Preference;
-  container: ContainerSpec | null;
-  requirement: string | null;
-  retention_time: DurationSpec | null;
-  single_use: boolean | null;
+  container?: ContainerSpec | null;
+  requirement?: string | null;
+  retention_time?: DurationSpec | null;
+  single_use?: boolean | null;
 }
 
 export interface SpecimenDefinition {
   id: string;
   title: string;
   slug: string;
-  derived_from_uri: string | null;
+  derived_from_uri?: string | null;
   status: Status;
-  description: string | null;
-  type_collected: Code | null;
-  patient_preparation: Code[] | null;
-  collection: Code | null;
-  facility: string;
+  description: string;
+  type_collected: Code;
+  patient_preparation?: Code[];
+  collection?: Code | null;
 }
 
 export interface SpecimenDefinitionCreate
@@ -97,11 +95,6 @@ export interface SpecimenDefinitionCreate
   type_tested: TypeTestedSpec | null;
 }
 
-export interface SpecimenDefinitionUpdate
-  extends Omit<SpecimenDefinition, "facility"> {
-  type_tested: TypeTestedSpec | null;
-}
-
 export interface SpecimenDefinitionRead extends SpecimenDefinition {
   created_by: UserBase;
   updated_by: UserBase;
diff --git a/src/types/emr/specimenDefinition/specimenDefinitionApi.ts b/src/types/emr/specimenDefinition/specimenDefinitionApi.ts
index fc9eed83cc2..d30cdc7171b 100644
--- a/src/types/emr/specimenDefinition/specimenDefinitionApi.ts
+++ b/src/types/emr/specimenDefinition/specimenDefinitionApi.ts
@@ -4,7 +4,6 @@ import { PaginatedResponse } from "@/Utils/request/types";
 import {
   SpecimenDefinitionCreate,
   SpecimenDefinitionRead,
-  SpecimenDefinitionUpdate,
 } from "./specimenDefinition";
 
 export default {
@@ -22,7 +21,7 @@ export default {
     path: "/api/v1/facility/{facilityId}/specimen_definition/{specimenDefinitionId}/",
     method: HttpMethod.PUT,
     TRes: Type<SpecimenDefinitionRead>(),
-    TBody: Type<SpecimenDefinitionUpdate>(),
+    TBody: Type<SpecimenDefinitionCreate>(),
   },
   createSpecimenDefinition: {
     path: "/api/v1/facility/{facilityId}/specimen_definition/",


Reviews:
user: login: rithviknishad
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-22T06:28:34Z
user: login: rithviknishad
state: CHANGES_REQUESTED
author_association: MEMBER
submitted_at: 2025-05-22T06:36:57Z
user: login: rithviknishad
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-22T07:25:20Z

Review comments:
diff_hunk: @@ -30,9 +30,9 @@ export interface DurationSpec {
 
 export interface ContainerSpec {
   description: string | null;
path: src/types/emr/specimenDefinition/specimenDefinition.ts
user: login: rithviknishad
body: ```suggestion
  description?: string | null;
```

<img width="670" alt="image" src="https://github.com/user-attachments/assets/d222b298-ba61-4222-8519-7a3f90098c68" />

created_at: 2025-05-22T06:19:54Z
author_association: MEMBER
diff_hunk: @@ -30,9 +30,9 @@ export interface DurationSpec {
 
 export interface ContainerSpec {
   description: string | null;
-  capacity: QuantitySpec | null;
-  minimum_volume: MinimumVolumeSpec | null;
-  cap: Code | null;
+  capacity?: QuantitySpec | null;
+  minimum_volume?: MinimumVolumeSpec | null;
+  cap?: Code | null;
   preparation: string | null;
path: src/types/emr/specimenDefinition/specimenDefinition.ts
user: login: rithviknishad
body: ```suggestion
  preparation?: string | null;
```

<img width="670" alt="image" src="https://github.com/user-attachments/assets/60645d37-964f-4be1-a1db-05fafee2f44c" />
created_at: 2025-05-22T06:20:19Z
author_association: MEMBER
diff_hunk: @@ -71,11 +71,10 @@ export const RETENTION_TIME_UNITS = [
 
 export interface TypeTestedSpec {
   is_derived: boolean;
-  specimen_type: Code | null;
   preference: Preference;
   container: ContainerSpec | null;
path: src/types/emr/specimenDefinition/specimenDefinition.ts
user: login: rithviknishad
body: ```suggestion
  container?: ContainerSpec | null;
```

<img width="515" alt="image" src="https://github.com/user-attachments/assets/f0177441-77a8-430d-b556-245afa29725d" />

created_at: 2025-05-22T06:21:25Z
author_association: MEMBER
diff_hunk: @@ -71,11 +71,10 @@ export const RETENTION_TIME_UNITS = [
 
 export interface TypeTestedSpec {
   is_derived: boolean;
-  specimen_type: Code | null;
   preference: Preference;
   container: ContainerSpec | null;
   requirement: string | null;
path: src/types/emr/specimenDefinition/specimenDefinition.ts
user: login: rithviknishad
body: ```suggestion
  requirement?: string | null;
```

<img width="515" alt="image" src="https://github.com/user-attachments/assets/8a9214fe-b41c-448c-814c-bb6e15d31cbe" />

created_at: 2025-05-22T06:21:50Z
author_association: MEMBER
diff_hunk: @@ -71,11 +71,10 @@ export const RETENTION_TIME_UNITS = [
 
 export interface TypeTestedSpec {
   is_derived: boolean;
-  specimen_type: Code | null;
   preference: Preference;
   container: ContainerSpec | null;
   requirement: string | null;
-  retention_time: DurationSpec | null;
+  retention_time?: DurationSpec | null;
   single_use: boolean | null;
path: src/types/emr/specimenDefinition/specimenDefinition.ts
user: login: rithviknishad
body: ```suggestion
  single_use?: boolean | null;
```

<img width="515" alt="image" src="https://github.com/user-attachments/assets/fc8799c2-38c3-464b-95e4-b5a060a7594d" />

created_at: 2025-05-22T06:22:21Z
author_association: MEMBER
diff_hunk: @@ -85,8 +84,8 @@ export interface SpecimenDefinition {
   slug: string;
   derived_from_uri: string | null;
path: src/types/emr/specimenDefinition/specimenDefinition.ts
user: login: rithviknishad
body: ```suggestion
  derived_from_uri?: string | null;
```

<img width="779" alt="image" src="https://github.com/user-attachments/assets/8a9163a2-2d3c-4234-bcfa-5423125718d0" />

created_at: 2025-05-22T06:25:17Z
author_association: MEMBER
diff_hunk: @@ -85,8 +84,8 @@ export interface SpecimenDefinition {
   slug: string;
   derived_from_uri: string | null;
   status: Status;
-  description: string | null;
-  type_collected: Code | null;
+  description: string;
+  type_collected: Code;
   patient_preparation: Code[] | null;
path: src/types/emr/specimenDefinition/specimenDefinition.ts
user: login: rithviknishad
body: ```suggestion
  patient_preparation?: Code[];
```

<img width="877" alt="image" src="https://github.com/user-attachments/assets/343e275a-06f5-4cd8-8b3b-2b53b9e7fa71" />

created_at: 2025-05-22T06:26:09Z
author_association: MEMBER
diff_hunk: @@ -85,8 +84,8 @@ export interface SpecimenDefinition {
   slug: string;
   derived_from_uri: string | null;
   status: Status;
-  description: string | null;
-  type_collected: Code | null;
+  description: string;
+  type_collected: Code;
   patient_preparation: Code[] | null;
   collection: Code | null;
path: src/types/emr/specimenDefinition/specimenDefinition.ts
user: login: rithviknishad
body: ```suggestion
  collection?: Code | null;
```

<img width="831" alt="image" src="https://github.com/user-attachments/assets/1c095294-02ea-479f-96fe-3d79d214f97a" />

created_at: 2025-05-22T06:26:48Z
author_association: MEMBER
diff_hunk: @@ -85,8 +84,8 @@ export interface SpecimenDefinition {
   slug: string;
   derived_from_uri: string | null;
   status: Status;
-  description: string | null;
-  type_collected: Code | null;
+  description: string;
+  type_collected: Code;
   patient_preparation: Code[] | null;
   collection: Code | null;
   facility: string;
path: src/types/emr/specimenDefinition/specimenDefinition.ts
user: login: rithviknishad
body: i don't see `facility` in any of the related specs.

```suggestion
```
created_at: 2025-05-22T06:27:46Z
author_association: MEMBER
diff_hunk: @@ -63,9 +62,14 @@ export function UpdateSpecimenDefinition({
       <SpecimenDefinitionForm
         initialData={specimenDefinition}
         onSubmit={(data) =>
-          updateSpecimenDefinition(data as SpecimenDefinitionUpdate)
+          updateSpecimenDefinition({
+            ...data,
+            id: specimenDefinitionId,
path: src/pages/Facility/settings/specimen-definitions/UpdateSpecimenDefinition.tsx
user: login: rithviknishad
body: drop `id` from update spec. this is specified in path params


```suggestion
```
created_at: 2025-05-22T06:30:25Z
author_association: MEMBER
diff_hunk: @@ -195,8 +195,12 @@ export function SpecimenDefinitionForm({
     value: { value: number | null; unit: Code | null } | string | null,
   ) => {
     if (type === "quantity") {
+      const quantityValue = value as { value: number; unit: Code };
path: src/pages/Facility/settings/specimen-definitions/SpecimenDefinitionForm.tsx
user: login: rithviknishad
body: wouldn't this still defeat the purpose? 🤔 
created_at: 2025-05-22T06:35:03Z
author_association: MEMBER
diff_hunk: @@ -88,29 +84,27 @@ const formSchema = z.object({
   title: z.string().min(1, "Title is required"),
   slug: z.string().min(1, "Slug is required"),
   status: z.nativeEnum(Status),
-  description: z.string().optional(),
+  description: z.string().min(1, "Description is required"),
path: src/pages/Facility/settings/specimen-definitions/SpecimenDefinitionForm.tsx
user: login: rithviknishad
body: 
```suggestion
  description: z.string().min(1, t("field_required")),
```
created_at: 2025-05-22T06:36:16Z
author_association: MEMBER
diff_hunk: @@ -32,54 +31,51 @@ import ComboboxQuantityInput from "@/components/Common/ComboboxQuantityInput";
 import ValueSetSelect from "@/components/Questionnaire/ValueSetSelect";
 
 import useCurrentFacility from "@/pages/Facility/utils/useCurrentFacility";
-import { Code } from "@/types/base/code/code";
+import { Code, CodeSchema } from "@/types/base/code/code";
 import {
   Preference,
   RETENTION_TIME_UNITS,
   SPECIMEN_DEFINITION_UNITS_CODES,
   Status,
 } from "@/types/emr/specimenDefinition/specimenDefinition";
-import {
-  SpecimenDefinitionCreate,
-  SpecimenDefinitionUpdate,
-} from "@/types/emr/specimenDefinition/specimenDefinition";
+import { SpecimenDefinitionCreate } from "@/types/emr/specimenDefinition/specimenDefinition";
 
 const typeTestedSchema = z.object({
   is_derived: z.boolean(),
-  specimen_type: z.any(), // Code type
   preference: z.nativeEnum(Preference),
   container: z
     .object({
       description: z.string().nullable(),
       capacity: z
         .object({
-          value: z.number().nullable(),
-          unit: z.any(), // Code type
+          value: z.number(),
+          unit: CodeSchema,
         })
+        .optional()
         .nullable(),
       minimum_volume: z
         .object({
           quantity: z
             .object({
-              value: z.number().optional().nullable(),
-              unit: z.any(), // Code type
+              value: z.number(),
+              unit: CodeSchema,
             })
             .optional()
             .nullable(),
           string: z.string().optional().nullable(),
         })
-        .optional()
         .nullable(),
-      cap: z.any().nullable(), // Code type
+      cap: CodeSchema.optional().nullable(),
       preparation: z.string().nullable(),
     })
     .nullable(),
   requirement: z.string().nullable(),
   retention_time: z
     .object({
-      value: z.number().nullable(),
-      unit: z.any(), // Code type
+      value: z.number().int({ message: "should be a valid integer" }),
path: src/pages/Facility/settings/specimen-definitions/SpecimenDefinitionForm.tsx
user: login: rithviknishad
body: i18n
created_at: 2025-05-22T06:36:30Z
author_association: MEMBER

PR comments:
user: login: coderabbitai[bot]
created_at: 2025-05-21T11:59:56Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- This is an auto-generated comment: skip review by coderabbit.ai -->

> [!IMPORTANT]
> ## Review skipped
> 
> Auto reviews are disabled on base/target branches other than the default branch.
> 
> 
> 
> Please check the settings in the CodeRabbit UI or the `.coderabbit.yaml` file in this repository. To trigger a single review, invoke the `@coderabbitai review` command.
> 
> You can disable this status message by setting the `reviews.review_status` to `false` in the CodeRabbit configuration file.

<!-- end of auto-generated comment: skip review by coderabbit.ai -->
<!-- tips_start -->

---

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=ohcnetwork/care_fe&utm_content=12376):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Explain this complex logic.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai explain this code block.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and explain its main purpose.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

### Support

Need help? Create a ticket on our [support page](https://www.coderabbit.ai/contact-us/support) for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-05-22T07:25:41Z
body: @yash-learner Your efforts have helped advance digital healthcare and TeleICU systems. :rocket: Thank you for taking the time out to make CARE better. We hope you continue to innovate and contribute; your impact is immense! :raised_hands:
author_association: NONE