diff --git a/src/common/constants.tsx b/src/common/constants.tsx index fcfc2619663..8fda21a820f 100644 --- a/src/common/constants.tsx +++ b/src/common/constants.tsx @@ -9,6 +9,7 @@ export const LocalStorageKeys = { accessToken: "care_access_token", refreshToken: "care_refresh_token", patientTokenKey: "care_patient_token", + loginPreference: "care_login_preference", }; export interface OptionsType { diff --git a/src/components/Auth/Login.tsx b/src/components/Auth/Login.tsx index e1398cfdce7..55590bc1635 100644 --- a/src/components/Auth/Login.tsx +++ b/src/components/Auth/Login.tsx @@ -1,7 +1,7 @@ import careConfig from "@careConfig"; import { useMutation } from "@tanstack/react-query"; import { Link, useQueryParams } from "raviger"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import ReCaptcha from "react-google-recaptcha"; import { useTranslation } from "react-i18next"; import { isValidPhoneNumber } from "react-phone-number-input"; @@ -31,6 +31,8 @@ import BrowserWarning from "@/components/ErrorPages/BrowserWarning"; import { useAuthContext } from "@/hooks/useAuthUser"; +import { LocalStorageKeys } from "@/common/constants"; + import FiltersCache from "@/Utils/FiltersCache"; import ViewCache from "@/Utils/ViewCache"; import routes from "@/Utils/request/api"; @@ -96,6 +98,11 @@ const Login = (props: LoginProps) => { const [otpError, setOtpError] = useState(""); const [otpValidationError, setOtpValidationError] = useState(""); + // Remember the last login mode + useEffect(() => { + localStorage.setItem(LocalStorageKeys.loginPreference, loginMode); + }, [loginMode]); + // Staff Login Mutation const staffLoginMutation = useMutation({ mutationFn: async (data: LoginFormData) => { diff --git a/src/components/Common/LoginHeader.tsx b/src/components/Common/LoginHeader.tsx index 3daa043bd83..32ebc669799 100644 --- a/src/components/Common/LoginHeader.tsx +++ b/src/components/Common/LoginHeader.tsx @@ -74,7 +74,14 @@ export const LoginHeader = () => { diff --git a/src/components/Facility/ConsultationDetails/QuestionnaireResponsesList.tsx b/src/components/Facility/ConsultationDetails/QuestionnaireResponsesList.tsx index a9cb31b9307..0284403e013 100644 --- a/src/components/Facility/ConsultationDetails/QuestionnaireResponsesList.tsx +++ b/src/components/Facility/ConsultationDetails/QuestionnaireResponsesList.tsx @@ -17,50 +17,27 @@ import { RESULTS_PER_PAGE_LIMIT } from "@/common/constants"; import routes from "@/Utils/request/api"; import query from "@/Utils/request/query"; import { formatDateTime, properCase } from "@/Utils/utils"; -import { AllergyIntoleranceRequest } from "@/types/emr/allergyIntolerance/allergyIntolerance"; -import { DiagnosisRequest } from "@/types/emr/diagnosis/diagnosis"; import { Encounter } from "@/types/emr/encounter"; -import { MedicationRequest } from "@/types/emr/medicationRequest"; -import { MedicationStatementRequest } from "@/types/emr/medicationStatement"; -import { SymptomRequest } from "@/types/emr/symptom/symptom"; +import { ResponseValue } from "@/types/questionnaire/form"; import { Question } from "@/types/questionnaire/question"; import { QuestionnaireResponse } from "@/types/questionnaire/questionnaireResponse"; -import { CreateAppointmentQuestion } from "@/types/scheduling/schedule"; interface Props { encounter?: Encounter; patientId: string; } -type ResponseValueType = { - value?: - | string - | number - | boolean - | Date - | Encounter - | AllergyIntoleranceRequest[] - | MedicationRequest[] - | MedicationStatementRequest[] - | SymptomRequest[] - | DiagnosisRequest[] - | CreateAppointmentQuestion; - value_quantity?: { - value: number; - }; -}; - interface QuestionResponseProps { question: Question; response?: { - values: ResponseValueType[]; + values: ResponseValue[]; note?: string; question_id: string; }; } export function formatValue( - value: ResponseValueType["value"], + value: ResponseValue["value"], type: string, ): string { if (!value) return ""; @@ -120,7 +97,7 @@ function QuestionGroup({ }: { group: Question; responses: { - values: ResponseValueType[]; + values: ResponseValue[]; note?: string; question_id: string; }[]; diff --git a/src/components/Location/LocationSearch.tsx b/src/components/Location/LocationSearch.tsx new file mode 100644 index 00000000000..9525e18294d --- /dev/null +++ b/src/components/Location/LocationSearch.tsx @@ -0,0 +1,85 @@ +import { useQuery } from "@tanstack/react-query"; +import { useState } from "react"; + +import { + Command, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, +} from "@/components/ui/command"; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from "@/components/ui/popover"; + +import query from "@/Utils/request/query"; +import { LocationList } from "@/types/location/location"; +import locationApi from "@/types/location/locationApi"; + +interface LocationSearchProps { + facilityId: string; + mode?: "kind" | "location"; + onSelect: (location: LocationList) => void; + disabled?: boolean; + value?: LocationList | null; +} + +export function LocationSearch({ + facilityId, + mode, + onSelect, + disabled, + value, +}: LocationSearchProps) { + const [open, setOpen] = useState(false); + const [search, setSearch] = useState(""); + + const { data: locations } = useQuery({ + queryKey: ["locations", facilityId, mode, search], + queryFn: query(locationApi.list, { + pathParams: { facility_id: facilityId }, + queryParams: { mode, search }, + }), + enabled: facilityId !== "preview", + }); + + return ( + + +
+ {value?.name || "Select location..."} +
+
+ + + + No locations found. + + {locations?.results.map((location) => ( + { + onSelect(location); + setOpen(false); + }} + > + {location.name} + + ))} + + + +
+ ); +} diff --git a/src/components/Patient/PatientInfoCard.tsx b/src/components/Patient/PatientInfoCard.tsx index 9ea75adc2c8..3f2a2234a6f 100644 --- a/src/components/Patient/PatientInfoCard.tsx +++ b/src/components/Patient/PatientInfoCard.tsx @@ -203,6 +203,43 @@ export default function PatientInfoCard(props: PatientInfoCardProps) { + {props.encounter.current_location && ( + + +
+ + + {props.encounter.current_location.name} + + +
+
+ +
+

+ Current Location +

+

+ {props.encounter.current_location.name} +

+

+ {props.encounter.current_location.description} +

+
+ +
+
+ )}
diff --git a/src/components/Questionnaire/QuestionTypes/AppointmentQuestion.tsx b/src/components/Questionnaire/QuestionTypes/AppointmentQuestion.tsx index ee9174f00e7..dec289eedf4 100644 --- a/src/components/Questionnaire/QuestionTypes/AppointmentQuestion.tsx +++ b/src/components/Questionnaire/QuestionTypes/AppointmentQuestion.tsx @@ -62,7 +62,7 @@ export function AppointmentQuestion({ [ { type: "appointment", - value: [appointment] as unknown as ResponseValue["value"], + value: [appointment], }, ], questionnaireResponse.question_id, diff --git a/src/components/Questionnaire/QuestionTypes/DateTimeQuestion.tsx b/src/components/Questionnaire/QuestionTypes/DateTimeQuestion.tsx index 8eb00eb8f33..4432477b82b 100644 --- a/src/components/Questionnaire/QuestionTypes/DateTimeQuestion.tsx +++ b/src/components/Questionnaire/QuestionTypes/DateTimeQuestion.tsx @@ -55,7 +55,7 @@ export function DateTimeQuestion({ [ { type: "dateTime", - value: date.toISOString(), + value: date, }, ], questionnaireResponse.question_id, @@ -75,7 +75,7 @@ export function DateTimeQuestion({ [ { type: "dateTime", - value: date.toISOString(), + value: date, }, ], questionnaireResponse.question_id, diff --git a/src/components/Questionnaire/QuestionTypes/EncounterQuestion.tsx b/src/components/Questionnaire/QuestionTypes/EncounterQuestion.tsx index 315221b64de..1383cf8f398 100644 --- a/src/components/Questionnaire/QuestionTypes/EncounterQuestion.tsx +++ b/src/components/Questionnaire/QuestionTypes/EncounterQuestion.tsx @@ -125,7 +125,7 @@ export function EncounterQuestion({ // Create the response value with the encounter request const responseValue: ResponseValue = { type: "encounter", - value: [encounterRequest] as unknown as typeof responseValue.value, + value: [encounterRequest], }; updateQuestionnaireResponseCB( diff --git a/src/components/Questionnaire/QuestionTypes/LocationQuestion.tsx b/src/components/Questionnaire/QuestionTypes/LocationQuestion.tsx new file mode 100644 index 00000000000..ed60dbe4b7e --- /dev/null +++ b/src/components/Questionnaire/QuestionTypes/LocationQuestion.tsx @@ -0,0 +1,116 @@ +import { format } from "date-fns"; +import React, { useState } from "react"; + +import { Input } from "@/components/ui/input"; + +import { LocationSearch } from "@/components/Location/LocationSearch"; + +import { LocationAssociationQuestion } from "@/types/location/association"; +import { LocationList } from "@/types/location/location"; +import { + QuestionnaireResponse, + ResponseValue, +} from "@/types/questionnaire/form"; +import { Question } from "@/types/questionnaire/question"; + +interface LocationQuestionProps { + question: Question; + questionnaireResponse: QuestionnaireResponse; + updateQuestionnaireResponseCB: ( + values: ResponseValue[], + questionId: string, + note?: string, + ) => void; + disabled?: boolean; + facilityId: string; + locationId: string; + encounterId: string; +} + +export function LocationQuestion({ + questionnaireResponse, + updateQuestionnaireResponseCB, + disabled, + facilityId, + encounterId, +}: LocationQuestionProps) { + const [selectedLocation, setSelectedLocation] = useState( + null, + ); + + const values = + (questionnaireResponse.values?.[0] + ?.value as unknown as LocationAssociationQuestion[]) || []; + + const association = values[0] ?? {}; + + const handleUpdateAssociation = ( + updates: Partial, + ) => { + const newAssociation: LocationAssociationQuestion = { + id: association?.id || null, + encounter: encounterId, + start_datetime: association?.start_datetime || new Date().toISOString(), + end_datetime: null, + status: "active", + location: association?.location || "", + meta: {}, + created_by: null, + updated_by: null, + ...updates, + }; + + updateQuestionnaireResponseCB( + [{ type: "location_association", value: [newAssociation] }], + questionnaireResponse.question_id, + ); + }; + + const handleLocationSelect = (location: LocationList) => { + setSelectedLocation(location); + handleUpdateAssociation({ location: location.id }); + }; + + return ( +
+
+
+ + +
+ + {selectedLocation && ( +
+ + + handleUpdateAssociation({ + start_datetime: new Date(e.target.value).toISOString(), + }) + } + disabled={disabled} + className="h-9" + /> +
+ )} +
+
+ ); +} diff --git a/src/components/Questionnaire/QuestionTypes/QuestionInput.tsx b/src/components/Questionnaire/QuestionTypes/QuestionInput.tsx index deec52da280..e82b50b09d4 100644 --- a/src/components/Questionnaire/QuestionTypes/QuestionInput.tsx +++ b/src/components/Questionnaire/QuestionTypes/QuestionInput.tsx @@ -20,6 +20,7 @@ import { ChoiceQuestion } from "./ChoiceQuestion"; import { DateTimeQuestion } from "./DateTimeQuestion"; import { DiagnosisQuestion } from "./DiagnosisQuestion"; import { EncounterQuestion } from "./EncounterQuestion"; +import { LocationQuestion } from "./LocationQuestion"; import { MedicationRequestQuestion } from "./MedicationRequestQuestion"; import { MedicationStatementQuestion } from "./MedicationStatementQuestion"; import { NotesInput } from "./NotesInput"; @@ -167,6 +168,18 @@ export function QuestionInput({ ); } return null; + case "location_association": + if (encounterId) { + return ( + + ); + } + return null; } return null; diff --git a/src/components/Questionnaire/QuestionnaireEditor.tsx b/src/components/Questionnaire/QuestionnaireEditor.tsx index 2a76b57ce8d..2637d5c9880 100644 --- a/src/components/Questionnaire/QuestionnaireEditor.tsx +++ b/src/components/Questionnaire/QuestionnaireEditor.tsx @@ -70,6 +70,17 @@ interface QuestionnaireEditorProps { id?: string; } +const STRUCTURED_QUESTION_TYPES = [ + { value: "allergy_intolerance", label: "Allergy Intolerance" }, + { value: "medication_request", label: "Medication Request" }, + { value: "medication_statement", label: "Medication Statement" }, + { value: "symptom", label: "Symptom" }, + { value: "diagnosis", label: "Diagnosis" }, + { value: "encounter", label: "Encounter" }, + { value: "appointment", label: "Appointment" }, + { value: "location_association", label: "Location Association" }, +] as const; + export default function QuestionnaireEditor({ id }: QuestionnaireEditorProps) { const navigate = useNavigate(); const [activeTab, setActiveTab] = useState<"edit" | "preview">("edit"); @@ -860,19 +871,11 @@ function QuestionEditor({ - - Allergy Intolerance - - - Medication Request - - - Medication Statement - - Symptom - Diagnosis - Encounter - Appointment + {STRUCTURED_QUESTION_TYPES.map((type) => ( + + {type.label} + + ))}
diff --git a/src/components/Questionnaire/QuestionnaireForm.tsx b/src/components/Questionnaire/QuestionnaireForm.tsx index a7da1010ba2..6c8716058de 100644 --- a/src/components/Questionnaire/QuestionnaireForm.tsx +++ b/src/components/Questionnaire/QuestionnaireForm.tsx @@ -262,7 +262,7 @@ export function QuestionnaireForm({ // Continue with existing submission logic... const requests: BatchRequest[] = []; if (encounterId && patientId) { - const context = { patientId, encounterId }; + const context = { facilityId, patientId, encounterId }; // First, collect all structured data requests if encounterId is provided formsWithValidation.forEach((form) => { form.responses.forEach((response) => { @@ -303,11 +303,18 @@ export function QuestionnaireForm({ ) .map((response) => ({ question_id: response.question_id, - values: response.values.map((value) => ({ - ...(value.value_code - ? { value_code: value.value_code } - : { value: String(value.value) }), - })), + values: response.values.map((value) => { + if (value.type === "dateTime" && value.value) { + return { + ...value, + value: value.value.toISOString(), + }; + } + if (value.value_code) { + return { value_code: value.value_code }; + } + return { value: String(value.value) }; + }), note: response.note, body_site: response.body_site, method: response.method, diff --git a/src/components/Questionnaire/QuestionnaireSearch.tsx b/src/components/Questionnaire/QuestionnaireSearch.tsx index f2227944d5a..70fb2e613c7 100644 --- a/src/components/Questionnaire/QuestionnaireSearch.tsx +++ b/src/components/Questionnaire/QuestionnaireSearch.tsx @@ -47,6 +47,7 @@ export function QuestionnaireSearch({ ...conditionalAttribute(!!subjectType, { subject_type: subjectType, }), + status: "active", }, }), }); diff --git a/src/components/Questionnaire/data/StructuredFormData.tsx b/src/components/Questionnaire/data/StructuredFormData.tsx index 918d2a1561f..78d10fcb982 100644 --- a/src/components/Questionnaire/data/StructuredFormData.tsx +++ b/src/components/Questionnaire/data/StructuredFormData.tsx @@ -120,6 +120,26 @@ const symptom_questionnaire: QuestionnaireDetail = { tags: [], }; +const location_association_questionnaire: QuestionnaireDetail = { + id: "location_association", + slug: "location_association", + version: "0.0.1", + title: "Location Association", + status: "active", + subject_type: "patient", + questions: [ + { + id: "location_association", + text: "Location Association", + type: "structured", + structured_type: "location_association", + link_id: "1.1", + required: true, + }, + ], + tags: [], +}; + export const FIXED_QUESTIONNAIRES: Record = { encounter: encounterQuestionnaire, medication_request: medication_request_questionnaire, @@ -127,4 +147,5 @@ export const FIXED_QUESTIONNAIRES: Record = { medication_statement: medication_statement_questionnaire, diagnosis: diagnosis_questionnaire, symptom: symptom_questionnaire, + location_association: location_association_questionnaire, }; diff --git a/src/components/Questionnaire/show.tsx b/src/components/Questionnaire/show.tsx index 8df7b174cb5..5977b61eae7 100644 --- a/src/components/Questionnaire/show.tsx +++ b/src/components/Questionnaire/show.tsx @@ -304,10 +304,10 @@ export function QuestionnaireShow({ id }: QuestionnaireShowProps) { diff --git a/src/components/Questionnaire/structured/handlers.ts b/src/components/Questionnaire/structured/handlers.ts index 86fd15d4e96..47b020347f9 100644 --- a/src/components/Questionnaire/structured/handlers.ts +++ b/src/components/Questionnaire/structured/handlers.ts @@ -3,6 +3,8 @@ import { RequestTypeFor, } from "@/components/Questionnaire/structured/types"; +import { LocationAssociationQuestion } from "@/types/location/association"; +import locationApi from "@/types/location/locationApi"; import { StructuredQuestionType } from "@/types/questionnaire/question"; interface StructuredHandlerContext { @@ -23,7 +25,7 @@ type StructuredHandler = { }>; }; -const handlers: { +export const structuredHandlers: { [K in StructuredQuestionType]: StructuredHandler; } = { allergy_intolerance: { @@ -114,8 +116,11 @@ const handlers: { }, }, encounter: { - getRequests: (encounters, { patientId, encounterId }) => { + getRequests: (encounters, { facilityId, patientId, encounterId }) => { if (!encounterId) return []; + if (!facilityId) { + throw new Error("Cannot create encounter without a facility"); + } return encounters.map((encounter) => { const body: RequestTypeFor<"encounter"> = { organizations: [], @@ -126,7 +131,7 @@ const handlers: { hospitalization: encounter.hospitalization, priority: encounter.priority, external_identifier: encounter.external_identifier, - facility: encounter.facility.id, + facility: facilityId, }; return { @@ -154,10 +159,43 @@ const handlers: { ]; }, }, + location_association: { + getRequests: ( + locationAssociations: LocationAssociationQuestion[], + { facilityId, encounterId }, + ) => { + if (!locationAssociations.length) { + return []; + } + + if (!facilityId) { + throw new Error( + "Cannot create location association without a facility", + ); + } + + return locationAssociations.map((locationAssociation) => { + return { + url: locationApi.createAssociation.path + .replace("{facility_external_id}", facilityId) + .replace("{location_external_id}", locationAssociation.location), + method: locationApi.createAssociation.method, + body: { + encounter: encounterId, + start_datetime: locationAssociation.start_datetime, + end_datetime: locationAssociation.end_datetime, + status: locationAssociation.status, + meta: locationAssociation.meta, + }, + reference_id: `location_association_${locationAssociation}`, + }; + }); + }, + }, }; export const getStructuredRequests = ( type: T, data: DataTypeFor[], context: StructuredHandlerContext, -) => handlers[type].getRequests(data, context); +) => structuredHandlers[type].getRequests(data, context); diff --git a/src/components/Questionnaire/structured/types.ts b/src/components/Questionnaire/structured/types.ts index 457afc1af45..03bc5f87a5b 100644 --- a/src/components/Questionnaire/structured/types.ts +++ b/src/components/Questionnaire/structured/types.ts @@ -1,9 +1,13 @@ import { AllergyIntoleranceRequest } from "@/types/emr/allergyIntolerance/allergyIntolerance"; import { DiagnosisRequest } from "@/types/emr/diagnosis/diagnosis"; -import { Encounter, EncounterEditRequest } from "@/types/emr/encounter"; +import { EncounterEditRequest } from "@/types/emr/encounter"; import { MedicationRequest } from "@/types/emr/medicationRequest"; import { MedicationStatementRequest } from "@/types/emr/medicationStatement"; import { SymptomRequest } from "@/types/emr/symptom/symptom"; +import { + LocationAssociationQuestion, + LocationAssociationWrite, +} from "@/types/location/association"; import { StructuredQuestionType } from "@/types/questionnaire/question"; import { AppointmentCreateRequest, @@ -17,8 +21,9 @@ export interface StructuredDataMap { symptom: SymptomRequest; diagnosis: DiagnosisRequest; medication_statement: MedicationStatementRequest; - encounter: Encounter; + encounter: EncounterEditRequest; appointment: CreateAppointmentQuestion; + location_association: LocationAssociationQuestion; } // Map structured types to their request types @@ -30,6 +35,7 @@ export interface StructuredRequestMap { medication_statement: { datapoints: MedicationStatementRequest[] }; encounter: EncounterEditRequest; appointment: AppointmentCreateRequest; + location_association: LocationAssociationWrite; } export type RequestTypeFor = diff --git a/src/types/emr/encounter.ts b/src/types/emr/encounter.ts index fdcffa02149..f63a118a83f 100644 --- a/src/types/emr/encounter.ts +++ b/src/types/emr/encounter.ts @@ -1,5 +1,6 @@ import { Patient } from "@/types/emr/newPatient"; import { FacilityOrganization } from "@/types/facilityOrganization/facilityOrganization"; +import { LocationList } from "@/types/location/location"; import { UserBase } from "@/types/user/user"; export const ENCOUNTER_ADMIT_SOURCE = [ @@ -136,6 +137,7 @@ export interface Encounter { encounter_class_history: EncounterClassHistory; status_history: StatusHistory; organizations: FacilityOrganization[]; + current_location: LocationList; } export interface EncounterEditRequest { diff --git a/src/types/location/association.ts b/src/types/location/association.ts new file mode 100644 index 00000000000..4397a665a25 --- /dev/null +++ b/src/types/location/association.ts @@ -0,0 +1,22 @@ +export interface LocationAssociation { + meta: Record; + id: string | null; + encounter: string; + start_datetime: string; + end_datetime: string | null; + status: string; + created_by: string | null; + updated_by: string | null; +} + +export interface LocationAssociationQuestion extends LocationAssociation { + location: string; +} + +export interface LocationAssociationWrite { + encounter: string; + start_datetime: string; + end_datetime?: string | null; + status: string; + meta?: Record; +} diff --git a/src/types/location/locationApi.ts b/src/types/location/locationApi.ts index db826371cdb..d58b6392bf6 100644 --- a/src/types/location/locationApi.ts +++ b/src/types/location/locationApi.ts @@ -2,6 +2,7 @@ import { HttpMethod, Type } from "@/Utils/request/api"; import { PaginatedResponse } from "@/Utils/request/types"; import { FacilityOrganization } from "@/types/facilityOrganization/facilityOrganization"; +import { LocationAssociation, LocationAssociationWrite } from "./association"; import { LocationDetail, LocationList, LocationWrite } from "./location"; export default { @@ -44,4 +45,31 @@ export default { TRes: Type(), TBody: Type<{ organization: string }>(), }, + listAssociations: { + path: "/api/v1/facility/{facility_external_id}/location/{location_external_id}/association/", + method: HttpMethod.GET, + TRes: Type>(), + }, + createAssociation: { + path: "/api/v1/facility/{facility_external_id}/location/{location_external_id}/association/", + method: HttpMethod.POST, + TRes: Type(), + TBody: Type(), + }, + getAssociation: { + path: "/api/v1/facility/{facility_external_id}/location/{location_external_id}/association/{external_id}/", + method: HttpMethod.GET, + TRes: Type(), + }, + updateAssociation: { + path: "/api/v1/facility/{facility_external_id}/location/{location_external_id}/association/{external_id}/", + method: HttpMethod.PUT, + TRes: Type(), + TBody: Type(), + }, + deleteAssociation: { + path: "/api/v1/facility/{facility_external_id}/location/{location_external_id}/association/{external_id}/", + method: HttpMethod.DELETE, + TRes: Type(), + }, }; diff --git a/src/types/questionnaire/form.ts b/src/types/questionnaire/form.ts index e634aa749fc..07cec713f51 100644 --- a/src/types/questionnaire/form.ts +++ b/src/types/questionnaire/form.ts @@ -1,44 +1,39 @@ import { AllergyIntoleranceRequest } from "@/types/emr/allergyIntolerance/allergyIntolerance"; import { DiagnosisRequest } from "@/types/emr/diagnosis/diagnosis"; -import { Encounter } from "@/types/emr/encounter"; +import { EncounterEditRequest } from "@/types/emr/encounter"; import { MedicationRequest } from "@/types/emr/medicationRequest"; import { MedicationStatementRequest } from "@/types/emr/medicationStatement"; import { SymptomRequest } from "@/types/emr/symptom/symptom"; +import { LocationAssociationQuestion } from "@/types/location/association"; import { Code } from "@/types/questionnaire/code"; import { Quantity } from "@/types/questionnaire/quantity"; import { StructuredQuestionType } from "@/types/questionnaire/question"; import { CreateAppointmentQuestion } from "@/types/scheduling/schedule"; -export type ResponseValue = { - type: - | "string" - | "number" - | "boolean" - | "dateTime" - | "allergy_intolerance" - | "medication_request" - | "medication_statement" - | "symptom" - | "diagnosis" - | "encounter" - | "appointment"; - - value?: - | string - | number - | boolean - | Date - | AllergyIntoleranceRequest[] - | MedicationRequest[] - | MedicationStatementRequest[] - | SymptomRequest[] - | DiagnosisRequest[] - | Encounter - | CreateAppointmentQuestion; +/** + * A short hand for defining response value types + */ +type RV = { value_code?: Code; value_quantity?: Quantity; + type: T; + value: V; }; +export type ResponseValue = + | RV<"string", string | undefined> + | RV<"number", number | undefined> + | RV<"boolean", boolean | undefined> + | RV<"dateTime", Date | undefined> + | RV<"allergy_intolerance", AllergyIntoleranceRequest[]> + | RV<"medication_request", MedicationRequest[]> + | RV<"medication_statement", MedicationStatementRequest[]> + | RV<"location_association", LocationAssociationQuestion[]> + | RV<"symptom", SymptomRequest[]> + | RV<"diagnosis", DiagnosisRequest[]> + | RV<"encounter", EncounterEditRequest[]> + | RV<"appointment", CreateAppointmentQuestion[]>; + export interface QuestionnaireResponse { question_id: string; structured_type: StructuredQuestionType | null; diff --git a/src/types/questionnaire/question.ts b/src/types/questionnaire/question.ts index 1297033349f..cc16b086bc7 100644 --- a/src/types/questionnaire/question.ts +++ b/src/types/questionnaire/question.ts @@ -23,7 +23,8 @@ export type StructuredQuestionType = | "symptom" | "diagnosis" | "encounter" - | "appointment"; + | "appointment" + | "location_association"; type EnableWhenNumeric = { operator: "greater" | "less" | "greater_or_equals" | "less_or_equals";