diff --git a/cypress/e2e/facility_spec/facility_creation.cy.ts b/cypress/e2e/facility_spec/facility_creation.cy.ts index 83f666995ff..6401ba7bbbe 100644 --- a/cypress/e2e/facility_spec/facility_creation.cy.ts +++ b/cypress/e2e/facility_spec/facility_creation.cy.ts @@ -58,12 +58,15 @@ describe("Facility Creation", () => { "Invalid Phone Number", ]; const bedErrorMessage = [ - "Field is required", + "This field is required", "Total capacity cannot be 0", - "Field is required", + "This field is required", ]; - const doctorErrorMessage = ["Field is required", "Field is required"]; - const triageErrorMessage = ["Field is required"]; + const doctorErrorMessage = [ + "This field is required", + "This field is required", + ]; + const triageErrorMessage = ["This field is required"]; before(() => { loginPage.loginAsDisctrictAdmin(); diff --git a/cypress/e2e/users_spec/user_creation.cy.ts b/cypress/e2e/users_spec/user_creation.cy.ts index 572b0cb95c4..91efb3aee31 100644 --- a/cypress/e2e/users_spec/user_creation.cy.ts +++ b/cypress/e2e/users_spec/user_creation.cy.ts @@ -50,8 +50,8 @@ describe("User Creation", () => { ]; const EXPECTED_PROFILE_ERROR_MESSAGES = [ - "Field is required", - "Field is required", + "This field is required", + "This field is required", "Please enter valid phone number", ]; diff --git a/cypress/pageobject/Asset/AssetCreation.ts b/cypress/pageobject/Asset/AssetCreation.ts index 9232c5966c1..331a4588c6f 100644 --- a/cypress/pageobject/Asset/AssetCreation.ts +++ b/cypress/pageobject/Asset/AssetCreation.ts @@ -200,7 +200,7 @@ export class AssetPage { verifyEmptyStatusError() { cy.get("[data-testid=asset-working-status-input] span").should( "contain", - "Field is required", + "This field is required", ); } diff --git a/src/CAREUI/display/Timeline.tsx b/src/CAREUI/display/Timeline.tsx index bbbf5e24859..7fcb57f56ea 100644 --- a/src/CAREUI/display/Timeline.tsx +++ b/src/CAREUI/display/Timeline.tsx @@ -92,9 +92,12 @@ export const TimelineNode = (props: TimelineNodeProps) => { }`}{" "} )} - {props.titleSuffix - ? props.titleSuffix - : `${props.event.type} the ${props.name || name}.`} + {props.titleSuffix || ( + <> + {`${props.event.type} the `} + {props.name || name} + + )}

{props.actions && ( diff --git a/src/CAREUI/interactive/LegendInput.tsx b/src/CAREUI/interactive/LegendInput.tsx index e4b16eb19fc..e164e4d1b4e 100644 --- a/src/CAREUI/interactive/LegendInput.tsx +++ b/src/CAREUI/interactive/LegendInput.tsx @@ -127,7 +127,7 @@ export default function LegendInput(props: InputProps) { required={props.required} autoComplete={props.autoComplete} className={classNames( - "cui-input bg-secondary-50 w-full rounded-md border-secondary-300 shadow-sm focus:border-2 focus:border-primary-500 focus:bg-secondary-100 focus:outline-none focus:ring-0", + "cui-input w-full rounded-md border-secondary-300 bg-secondary-50 shadow-sm focus:border-2 focus:border-primary-500 focus:bg-secondary-100 focus:outline-none focus:ring-0", props.size === "small" && "px-3 py-2 text-xs", (!props.size || !["small", "large"].includes(props.size)) && "px-4 py-3", diff --git a/src/CAREUI/interactive/Switch.tsx b/src/CAREUI/interactive/Switch.tsx index 0bdf39716c5..495722a0f39 100644 --- a/src/CAREUI/interactive/Switch.tsx +++ b/src/CAREUI/interactive/Switch.tsx @@ -26,7 +26,7 @@ export default function Switch({ size === "lg" && "px-4 py-3 text-base", props.selected === tab ? "border-primary-500 bg-primary-500 font-semibold text-white hover:bg-primary-600 focus:border-primary-500 focus:ring-primary-500" - : "bg-secondary-50 border-secondary-400 hover:bg-secondary-200 focus:border-primary-500 focus:ring-primary-500", + : "border-secondary-400 bg-secondary-50 hover:bg-secondary-200 focus:border-primary-500 focus:ring-primary-500", )} onClick={() => props.onChange(tab as T)} > diff --git a/src/Common/hooks/useAsyncOptions.ts b/src/Common/hooks/useAsyncOptions.ts index 1a632dc366e..a81209f34f0 100644 --- a/src/Common/hooks/useAsyncOptions.ts +++ b/src/Common/hooks/useAsyncOptions.ts @@ -38,7 +38,7 @@ export function useAsyncOptions>( ) { const dispatch = useDispatch(); const [queryOptions, setQueryOptions] = useState([]); - const [isLoading, setIsLoading] = useState(false); + const [isLoading, setIsLoading] = useState(true); const fetchOptions = useMemo( () => diff --git a/src/Common/hooks/useMSEplayer.ts b/src/Common/hooks/useMSEplayer.ts index 127fe94b9a0..5271c08fd56 100644 --- a/src/Common/hooks/useMSEplayer.ts +++ b/src/Common/hooks/useMSEplayer.ts @@ -171,9 +171,14 @@ export const useMSEMediaPlayer = ({ } else { mimeCodec = Utf8ArrayToStr(decoded_arr); } - mseSourceBuffer = mse.addSourceBuffer( - `video/mp4; codecs="${mimeCodec}"`, - ); + try { + mseSourceBuffer = mse.addSourceBuffer( + `video/mp4; codecs="${mimeCodec}"`, + ); + } catch (error) { + onError?.(error); + return; + } mseSourceBuffer.mode = "segments"; if (mseQueue.length > 0 && !mseSourceBuffer.updating) { mseSourceBuffer.addEventListener("updateend", pushPacket); diff --git a/src/Common/static/countryPhoneAndFlags.json b/src/Common/static/countryPhoneAndFlags.json index 98a43e4e043..ecc024647eb 100644 --- a/src/Common/static/countryPhoneAndFlags.json +++ b/src/Common/static/countryPhoneAndFlags.json @@ -101,7 +101,11 @@ "IL": { "flag": "🇮🇱", "name": "Israel", "code": "972" }, "IM": { "flag": "🇮🇲", "name": "Isle of Man", "code": "44-1624" }, "IN": { "flag": "🇮🇳", "name": "India", "code": "91" }, - "IO": { "flag": "🇮🇴", "name": "British Indian Ocean Territory", "code": "246" }, + "IO": { + "flag": "🇮🇴", + "name": "British Indian Ocean Territory", + "code": "246" + }, "IQ": { "flag": "🇮🇶", "name": "Iraq", "code": "964" }, "IR": { "flag": "🇮🇷", "name": "Iran", "code": "98" }, "IS": { "flag": "🇮🇸", "name": "Iceland", "code": "354" }, diff --git a/src/Components/ABDM/ABDMRecordsTab.tsx b/src/Components/ABDM/ABDMRecordsTab.tsx index f101b3ae45c..d828335cd0d 100644 --- a/src/Components/ABDM/ABDMRecordsTab.tsx +++ b/src/Components/ABDM/ABDMRecordsTab.tsx @@ -121,13 +121,13 @@ function ConsentRequestCard({ consent }: IConsentRequestCardProps) {
{consent.consent_artefacts?.length ? ( -
+
{consent.consent_artefacts?.map((artefact) => ( ))}
) : ( -
+

{consent.status === "REQUESTED" ? "Waiting for the Patient to approve the consent request" diff --git a/src/Components/Assets/AssetManage.tsx b/src/Components/Assets/AssetManage.tsx index 934a4cf0d16..a9bb6eb78ea 100644 --- a/src/Components/Assets/AssetManage.tsx +++ b/src/Components/Assets/AssetManage.tsx @@ -537,7 +537,7 @@ const AssetManage = (props: AssetManageProps) => { Last Updated - + Edit @@ -564,7 +564,7 @@ const AssetManage = (props: AssetManageProps) => { Moved By - + Moved On diff --git a/src/Components/Assets/AssetsList.tsx b/src/Components/Assets/AssetsList.tsx index adf8dd61a8e..fa609e0e3b8 100644 --- a/src/Components/Assets/AssetsList.tsx +++ b/src/Components/Assets/AssetsList.tsx @@ -121,7 +121,7 @@ const AssetsList = () => { if (!isValidURL(assetURL)) { setIsLoading(false); Notification.Error({ - msg: "Invalid QR code scanned !!!", + msg: t("invalid_asset_id_msg"), }); return; } @@ -137,7 +137,7 @@ const AssetsList = () => { if (!data) { setIsLoading(false); Notification.Error({ - msg: "Invalid QR code scanned !!!", + msg: t("invalid_asset_id_msg"), }); return; } @@ -151,17 +151,22 @@ const AssetsList = () => { } else { setIsLoading(false); Notification.Error({ - msg: "Asset not found !!!", + msg: t("asset_not_found_msg"), }); } } else { setIsLoading(false); Notification.Error({ - msg: "Invalid QR code scanned !!!", + msg: t("invalid_asset_id_msg"), }); } } catch (err) { console.log(err); + Notification.Error({ + msg: t("invalid_asset_id_msg"), + }); + } finally { + setIsLoading(false); } }; diff --git a/src/Components/Common/DateInputV2.tsx b/src/Components/Common/DateInputV2.tsx index 2e9f99de9bc..9bb10b1951b 100644 --- a/src/Components/Common/DateInputV2.tsx +++ b/src/Components/Common/DateInputV2.tsx @@ -256,7 +256,7 @@ const DateInputV2: React.FC = ({ type="text" readOnly disabled={disabled} - className={`cui-input-base cursor-pointer disabled:cursor-not-allowed ${className}`} + className={`cui-input-base cursor-pointer !px-2 disabled:cursor-not-allowed ${className}`} placeholder={placeholder ?? t("select_date")} value={value && dayjs(value).format("DD/MM/YYYY")} /> diff --git a/src/Components/Common/ExcelFIleDragAndDrop.tsx b/src/Components/Common/ExcelFIleDragAndDrop.tsx index e7e3f0e71d2..5a6719f03df 100644 --- a/src/Components/Common/ExcelFIleDragAndDrop.tsx +++ b/src/Components/Common/ExcelFIleDragAndDrop.tsx @@ -207,7 +207,7 @@ export default function ExcelFileDragAndDrop({ {selectedFile ? ( <> setPreview(true)} > ) : ( & { placeholder?: string; @@ -16,6 +17,7 @@ type Props = FormFieldBaseProps & { homeFacility?: string; userType?: UserRole; showActiveStatus?: boolean; + noResultsError?: string; }; export default function UserAutocompleteFormField(props: Props) { @@ -59,18 +61,30 @@ export default function UserAutocompleteFormField(props: Props) { ); }; + const items = options(field.value && [field.value]); + + useEffect(() => { + if (props.required && !isLoading && !items.length && props.noResultsError) { + field.handleChange(undefined as unknown as UserModel); + } + }, [isLoading, items, props.required]); + + const noResultError = + (props.required && !isLoading && !items.length && props.noResultsError) || + undefined; + return (

`${option.user_type}`} diff --git a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/AddICD11Diagnosis.tsx b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/AddICD11Diagnosis.tsx index 2476fa57ab0..39f35a4fcf4 100644 --- a/src/Components/Diagnosis/ConsultationDiagnosisBuilder/AddICD11Diagnosis.tsx +++ b/src/Components/Diagnosis/ConsultationDiagnosisBuilder/AddICD11Diagnosis.tsx @@ -71,6 +71,7 @@ export default function AddICD11Diagnosis(props: AddICD11DiagnosisProps) { )} optionLabel={(option) => option.label} optionValue={(option) => option} + minQueryLength={2} onQuery={(query) => refetch({ query: { query } })} isLoading={loading} error={hasError ? t("diagnosis_already_added") : undefined} diff --git a/src/Components/ExternalResult/ResultUpdate.tsx b/src/Components/ExternalResult/ResultUpdate.tsx index 09dc41aaca7..482c320457e 100644 --- a/src/Components/ExternalResult/ResultUpdate.tsx +++ b/src/Components/ExternalResult/ResultUpdate.tsx @@ -12,6 +12,7 @@ import useQuery from "../../Utils/request/useQuery.js"; import routes from "../../Redux/api.js"; import request from "../../Utils/request/request.js"; import { compareBy } from "../../Utils/utils.js"; +import { useTranslation } from "react-i18next"; const Loading = lazy(() => import("../Common/Loading")); @@ -57,6 +58,7 @@ const initialWard = [{ id: 0, name: "Choose Ward", number: 0 }]; export default function UpdateResult(props: any) { const { id } = props; const { goBack } = useAppHistory(); + const { t } = useTranslation(); const [state, dispatch] = useReducer(FormReducer, initialState); const [isLoading, setIsLoading] = useState(true); @@ -132,7 +134,7 @@ export default function UpdateResult(props: any) { switch (field) { case "address": if (!state.form[field]) { - errors[field] = "Field is required"; + errors[field] = t("field_required"); invalidForm = true; } return; diff --git a/src/Components/Facility/AssetCreate.tsx b/src/Components/Facility/AssetCreate.tsx index 6867857c5c6..5b1493de242 100644 --- a/src/Components/Facility/AssetCreate.tsx +++ b/src/Components/Facility/AssetCreate.tsx @@ -32,10 +32,10 @@ import { validateEmailAddress } from "../../Common/validation"; import { dateQueryString, parsePhoneNumber } from "../../Utils/utils.js"; import dayjs from "../../Utils/dayjs"; import DateFormField from "../Form/FormFields/DateFormField.js"; -import { t } from "i18next"; import useQuery from "../../Utils/request/useQuery.js"; import routes from "../../Redux/api.js"; import request from "../../Utils/request/request.js"; +import { useTranslation } from "react-i18next"; const Loading = lazy(() => import("../Common/Loading")); @@ -101,6 +101,7 @@ type AssetFormSection = const AssetCreate = (props: AssetProps) => { const { goBack } = useAppHistory(); + const { t } = useTranslation(); const { facilityId, assetId } = props; let assetClassInitial: AssetClass; @@ -212,7 +213,7 @@ const AssetCreate = (props: AssetProps) => { return; case "is_working": if (is_working === undefined) { - errors[field] = "Field is required"; + errors[field] = t("field_required"); invalidForm = true; } return; @@ -224,7 +225,7 @@ const AssetCreate = (props: AssetProps) => { return; case "support_phone": { if (!support_phone) { - errors[field] = "Field is required"; + errors[field] = t("field_required"); invalidForm = true; } // eslint-disable-next-line no-case-declarations diff --git a/src/Components/Facility/BedCapacity.tsx b/src/Components/Facility/BedCapacity.tsx index ff0ec111496..c0f239203d5 100644 --- a/src/Components/Facility/BedCapacity.tsx +++ b/src/Components/Facility/BedCapacity.tsx @@ -9,6 +9,7 @@ import useConfig from "../../Common/hooks/useConfig"; import { getBedTypes } from "../../Common/constants"; import routes from "../../Redux/api"; import request from "../../Utils/request/request"; +import { useTranslation } from "react-i18next"; interface BedCapacityProps extends CapacityModal { facilityId: string; @@ -49,6 +50,7 @@ const bedCountReducer = (state = initialState, action: any) => { }; export const BedCapacity = (props: BedCapacityProps) => { + const { t } = useTranslation(); const config = useConfig(); const { facilityId, handleClose, handleUpdate, className, id } = props; const [state, dispatch] = useReducer(bedCountReducer, initialState); @@ -127,7 +129,7 @@ export const BedCapacity = (props: BedCapacityProps) => { let invalidForm = false; Object.keys(state.form).forEach((field) => { if (!state.form[field]) { - errors[field] = "Field is required"; + errors[field] = t("field_required"); invalidForm = true; } else if ( field === "currentOccupancy" && diff --git a/src/Components/Facility/ConsultationDetails/Events/EventsList.tsx b/src/Components/Facility/ConsultationDetails/Events/EventsList.tsx index cf997dca4b3..f759559c1a1 100644 --- a/src/Components/Facility/ConsultationDetails/Events/EventsList.tsx +++ b/src/Components/Facility/ConsultationDetails/Events/EventsList.tsx @@ -30,13 +30,10 @@ export default function EventsList() { {(item, items) => ( - text[0].toUpperCase() + text.toLowerCase().slice(1), - ) - .join(" ") + " Event" + t(item.event_type.name.toLowerCase()).replaceAll( + /_/g, + " ", + ) + " Event" } event={{ type: item.change_type.replace(/_/g, " ").toLowerCase(), diff --git a/src/Components/Facility/ConsultationDetails/Events/GenericEvent.tsx b/src/Components/Facility/ConsultationDetails/Events/GenericEvent.tsx index 414b86fecbe..ca9c13c599b 100644 --- a/src/Components/Facility/ConsultationDetails/Events/GenericEvent.tsx +++ b/src/Components/Facility/ConsultationDetails/Events/GenericEvent.tsx @@ -1,4 +1,6 @@ import type { ReactNode } from "react"; +import { useTranslation } from "react-i18next"; + interface IProps { values: Record; } @@ -80,12 +82,13 @@ const formatValue = (value: unknown, key?: string): ReactNode => { }; export default function GenericEvent(props: IProps) { + const { t } = useTranslation(); return (
{Object.entries(props.values).map(([key, value]) => (
- - {key.replaceAll(/_/g, " ")} + + {t(key).replaceAll(/_/g, " ")} {formatValue(value, key)} diff --git a/src/Components/Facility/ConsultationForm.tsx b/src/Components/Facility/ConsultationForm.tsx index a94f496cfca..dc496d599f7 100644 --- a/src/Components/Facility/ConsultationForm.tsx +++ b/src/Components/Facility/ConsultationForm.tsx @@ -386,8 +386,8 @@ export const ConsultationForm = ({ facilityId, patientId, id }: Props) => { admitted: data.admitted ? String(data.admitted) : "false", admitted_to: data.admitted_to ? data.admitted_to : "", category: data.category - ? PATIENT_CATEGORIES.find((i) => i.text === data.category)?.id ?? - "" + ? (PATIENT_CATEGORIES.find((i) => i.text === data.category)?.id ?? + "") : "", patient_no: data.patient_no ?? "", OPconsultation: data.consultation_notes, @@ -453,7 +453,7 @@ export const ConsultationForm = ({ facilityId, patientId, id }: Props) => { return; case "route_to_facility": if (!state.form[field]) { - errors[field] = "Field is required"; + errors[field] = t("field_required"); invalidForm = true; } return; @@ -469,7 +469,7 @@ export const ConsultationForm = ({ facilityId, patientId, id }: Props) => { return; case "encounter_date": if (!state.form[field]) { - errors[field] = "Field is required"; + errors[field] = t("field_required"); invalidForm = true; } if ( @@ -540,7 +540,7 @@ export const ConsultationForm = ({ facilityId, patientId, id }: Props) => { return; case "consultation_notes": if (!state.form[field]) { - errors[field] = "Field is required"; + errors[field] = t("field_required"); invalidForm = true; } else if (!state.form[field].replace(/\s/g, "").length) { errors[field] = "Consultation notes can not be empty"; @@ -608,7 +608,7 @@ export const ConsultationForm = ({ facilityId, patientId, id }: Props) => { case "treating_physician": { if (state.form.suggestion !== "DD" && !state.form[field]) { - errors[field] = "Please fill treating physician"; + errors[field] = t("field_required"); invalidForm = true; break; } @@ -932,11 +932,11 @@ export const ConsultationForm = ({ facilityId, patientId, id }: Props) => { ); })}
-
+
{ @@ -1437,6 +1437,7 @@ export const ConsultationForm = ({ facilityId, patientId, id }: Props) => { userType={"Doctor"} homeFacility={facilityId} error={state.errors.treating_physician} + noResultsError={t("no_treating_physicians_available")} />
diff --git a/src/Components/Facility/Consultations/NeurologicalTables.tsx b/src/Components/Facility/Consultations/NeurologicalTables.tsx index 51d977ad32d..aac558ca8b0 100644 --- a/src/Components/Facility/Consultations/NeurologicalTables.tsx +++ b/src/Components/Facility/Consultations/NeurologicalTables.tsx @@ -36,7 +36,7 @@ const DataTable = (props: any) => { key={`${title}_${i}`} className="flex flex-col divide-x divide-secondary-200" > -
+
{x.date}
@@ -296,7 +296,7 @@ export const NeurologicalTable = (props: any) => { key={`loc_${i}`} className="min-w-max-content flex flex-col divide-x divide-secondary-200" > -
+
{x.date}
@@ -373,7 +373,7 @@ export const NeurologicalTable = (props: any) => { key={`glascow_${i}`} className="flex flex-col divide-x divide-secondary-200" > -
+
{x.date}
diff --git a/src/Components/Facility/DischargeModal.tsx b/src/Components/Facility/DischargeModal.tsx index 567c21dfbb6..fe99b4ddd53 100644 --- a/src/Components/Facility/DischargeModal.tsx +++ b/src/Components/Facility/DischargeModal.tsx @@ -151,7 +151,7 @@ const DischargeModal = ({ newErrors["discharge_notes"] = "Please enter the cause of death"; } if (!preDischargeForm.death_confirmed_doctor?.trim()) { - newErrors["death_confirmed_doctor"] = "Field is required"; + newErrors["death_confirmed_doctor"] = t("field_required"); } if (Object.entries(newErrors).length) { diff --git a/src/Components/Facility/FacilityCard.tsx b/src/Components/Facility/FacilityCard.tsx index 12a7d9d31c6..d6c2dce2b6c 100644 --- a/src/Components/Facility/FacilityCard.tsx +++ b/src/Components/Facility/FacilityCard.tsx @@ -168,7 +168,7 @@ export const FacilityCard = (props: { facility: any; userType: any }) => {
-
+
{/*
*/}
diff --git a/src/Components/Facility/FacilityUsers.tsx b/src/Components/Facility/FacilityUsers.tsx index cefa3630f33..77ca88618a6 100644 --- a/src/Components/Facility/FacilityUsers.tsx +++ b/src/Components/Facility/FacilityUsers.tsx @@ -185,7 +185,7 @@ export default function FacilityUsers(props: any) {
{user.phone_number && ( -
+
diff --git a/src/Components/Facility/Investigations/Reports/ReportTable.tsx b/src/Components/Facility/Investigations/Reports/ReportTable.tsx index 3a56db28e36..4d8779ca3ea 100644 --- a/src/Components/Facility/Investigations/Reports/ReportTable.tsx +++ b/src/Components/Facility/Investigations/Reports/ReportTable.tsx @@ -7,7 +7,7 @@ import { FC } from "react"; const ReportRow = ({ data, name, min, max }: any) => { return ( - + {name} diff --git a/src/Components/Facility/StaffCapacity.tsx b/src/Components/Facility/StaffCapacity.tsx index fc54dfcbb2d..8326ed6a323 100644 --- a/src/Components/Facility/StaffCapacity.tsx +++ b/src/Components/Facility/StaffCapacity.tsx @@ -10,6 +10,7 @@ import { DoctorModal } from "./models.js"; import useQuery from "../../Utils/request/useQuery.js"; import routes from "../../Redux/api.js"; import request from "../../Utils/request/request.js"; +import { useTranslation } from "react-i18next"; interface DoctorCapacityProps extends DoctorModal { facilityId: string; @@ -58,6 +59,7 @@ const getAllowedDoctorTypes = (existing?: DoctorModal[]) => { }; export const StaffCapacity = (props: DoctorCapacityProps) => { + const { t } = useTranslation(); const { facilityId, handleClose, handleUpdate, className, id } = props; const [state, dispatch] = useReducer(doctorCapacityReducer, initialState); const [isLoading, setIsLoading] = useState(false); @@ -94,7 +96,7 @@ export const StaffCapacity = (props: DoctorCapacityProps) => { let invalidForm = false; Object.keys(state.form).forEach((field) => { if (!state.form[field]) { - errors[field] = "Field is required"; + errors[field] = t("field_required"); invalidForm = true; } if (field === "count" && state.form[field] < 0) { diff --git a/src/Components/Facility/TransferPatientDialog.tsx b/src/Components/Facility/TransferPatientDialog.tsx index 3ead082c610..0c4af6c5d0c 100644 --- a/src/Components/Facility/TransferPatientDialog.tsx +++ b/src/Components/Facility/TransferPatientDialog.tsx @@ -9,6 +9,7 @@ import request from "../../Utils/request/request.js"; import routes from "../../Redux/api.js"; import TextFormField from "../Form/FormFields/TextFormField.js"; import { FieldChangeEvent } from "../Form/FormFields/Utils.js"; +import { useTranslation } from "react-i18next"; interface Props { patientList: Array; @@ -53,6 +54,7 @@ const patientFormReducer = (state = initialState, action: any) => { const TransferPatientDialog = (props: Props) => { const { patientList, handleOk, handleCancel, facilityId } = props; + const { t } = useTranslation(); const [isLoading, setIsLoading] = useState(false); const [state, dispatch] = useReducer(patientFormReducer, initialState); const patientOptions: Array = patientList.map((patient) => { @@ -102,7 +104,7 @@ const TransferPatientDialog = (props: Props) => { return; case "year_of_birth": if (!state.form[field]) { - errors[field] = "This field is required"; + errors[field] = t("field_required"); invalidForm = true; } diff --git a/src/Components/Facility/TriageForm.tsx b/src/Components/Facility/TriageForm.tsx index 6ad9fdd0e08..1aa0537b53c 100644 --- a/src/Components/Facility/TriageForm.tsx +++ b/src/Components/Facility/TriageForm.tsx @@ -17,6 +17,7 @@ import { dateQueryString, scrollTo } from "../../Utils/utils"; import useQuery from "../../Utils/request/useQuery"; import routes from "../../Redux/api"; import request from "../../Utils/request/request"; +import { useTranslation } from "react-i18next"; interface Props extends PatientStatsModel { facilityId: string; @@ -57,6 +58,7 @@ const triageFormReducer = (state = initialState, action: any) => { }; export const TriageForm = ({ facilityId, id }: Props) => { + const { t } = useTranslation(); const { goBack } = useAppHistory(); const [state, dispatch] = useReducer(triageFormReducer, initialState); const [isLoading, setIsLoading] = useState(false); @@ -98,7 +100,7 @@ export const TriageForm = ({ facilityId, id }: Props) => { switch (field) { case "entry_date": if (!state.form[field]) { - errors[field] = "Field is required"; + errors[field] = t("field_required"); invalidForm = true; } return; diff --git a/src/Components/Form/FieldValidators.tsx b/src/Components/Form/FieldValidators.tsx index 4933b685171..3159c6814f1 100644 --- a/src/Components/Form/FieldValidators.tsx +++ b/src/Components/Form/FieldValidators.tsx @@ -1,3 +1,5 @@ +import { t } from "i18next"; + export type FieldError = string | undefined; export type FieldValidator = (value: T, ...args: any) => FieldError; @@ -42,7 +44,7 @@ export const AnyValidator = ( return validator; }; -export const RequiredFieldValidator = (message = "Field is required") => { +export const RequiredFieldValidator = (message = t("field_required")) => { return (value: T): FieldError => { if (!value) return message; if (Array.isArray(value) && value.length === 0) return message; diff --git a/src/Components/Form/FormFields/Autocomplete.tsx b/src/Components/Form/FormFields/Autocomplete.tsx index 2fbfeacfda4..a891fc75d9a 100644 --- a/src/Components/Form/FormFields/Autocomplete.tsx +++ b/src/Components/Form/FormFields/Autocomplete.tsx @@ -18,6 +18,7 @@ type AutocompleteFormFieldProps = FormFieldBaseProps & { optionDescription?: OptionCallback; optionIcon?: OptionCallback; optionDisabled?: OptionCallback; + minQueryLength?: number; onQuery?: (query: string) => void; dropdownIcon?: React.ReactNode | undefined; isLoading?: boolean; @@ -45,6 +46,7 @@ const AutocompleteFormField = ( optionValue={props.optionValue} optionDescription={props.optionDescription} optionDisabled={props.optionDisabled} + minQueryLength={props.minQueryLength} onQuery={props.onQuery} isLoading={props.isLoading} allowRawInput={props.allowRawInput} @@ -69,6 +71,7 @@ type AutocompleteProps = { optionDescription?: OptionCallback; optionDisabled?: OptionCallback; className?: string; + minQueryLength?: number; onQuery?: (query: string) => void; requiredError?: boolean; isLoading?: boolean; @@ -95,6 +98,7 @@ type AutocompleteProps = { export const Autocomplete = (props: AutocompleteProps) => { const { t } = useTranslation(); const [query, setQuery] = useState(""); // Ensure lower case + useEffect(() => { props.onQuery?.(query); }, [query]); @@ -136,6 +140,7 @@ export const Autocomplete = (props: AutocompleteProps) => { const options = props.allowRawInput ? getOptions() : mappedOptions; const value = options.find((o) => props.value == o.value); + const filteredOptions = props.onQuery === undefined ? options.filter((o) => o.search.includes(query)) @@ -198,43 +203,48 @@ export const Autocomplete = (props: AutocompleteProps) => { - {filteredOptions.length === 0 && ( + {props.minQueryLength && query.length < props.minQueryLength ? ( +
+ {`Please enter at least ${props.minQueryLength} characters to search`} +
+ ) : filteredOptions.length === 0 ? (
No options found
- )} - {filteredOptions.map((option, index) => ( - - {({ active }) => ( -
-
- {option.label} - {option.icon} -
- {option.description && ( -
- {option.description} + ) : ( + filteredOptions.map((option, index) => ( + + {({ active }) => ( +
+
+ {option.label} + {option.icon}
- )} -
- )} -
- ))} + {option.description && ( +
+ {option.description} +
+ )} +
+ )} + + )) + )}
diff --git a/src/Components/Medicine/MedicineAdministrationSheet/AdministrationEventSeperator.tsx b/src/Components/Medicine/MedicineAdministrationSheet/AdministrationEventSeperator.tsx index fdaa48cfea2..b52f1ed85f5 100644 --- a/src/Components/Medicine/MedicineAdministrationSheet/AdministrationEventSeperator.tsx +++ b/src/Components/Medicine/MedicineAdministrationSheet/AdministrationEventSeperator.tsx @@ -4,7 +4,7 @@ export default function AdministrationEventSeperator({ date }: { date: Date }) { // Show date if it's 00:00 if (date.getHours() === 0) { return ( -
+

{formatDateTime(date, "DD/MM")}

diff --git a/src/Components/Medicine/MedicineAdministrationSheet/AdministrationTable.tsx b/src/Components/Medicine/MedicineAdministrationSheet/AdministrationTable.tsx index f7dbacd5780..4bfc59c47c0 100644 --- a/src/Components/Medicine/MedicineAdministrationSheet/AdministrationTable.tsx +++ b/src/Components/Medicine/MedicineAdministrationSheet/AdministrationTable.tsx @@ -24,9 +24,9 @@ export default function MedicineAdministrationTable({ return (
- + - {props.theads.map((item) => { return ( - ); })} {props.actions && ( - )} diff --git a/src/Components/Medicine/validators.ts b/src/Components/Medicine/validators.ts index 13460230737..a0103d11241 100644 --- a/src/Components/Medicine/validators.ts +++ b/src/Components/Medicine/validators.ts @@ -1,3 +1,4 @@ +import { t } from "i18next"; import { FieldError, RequiredFieldValidator } from "../Form/FieldValidators"; import { FormErrors } from "../Form/Utils"; import { Prescription } from "./models"; @@ -73,7 +74,7 @@ export const AdministrationDosageValidator = ( const baseDosage = getDosageValue(base_dosage); const targetDosage = getDosageValue(target_dosage); - if (!valueDosage) return "This field is required"; + if (!valueDosage) return t("field_required"); if (value?.split(" ")[1] !== base_dosage?.split(" ")[1]) return "Unit must be the same as start and target dosage's unit"; diff --git a/src/Components/Patient/DailyRounds.tsx b/src/Components/Patient/DailyRounds.tsx index 89367c6eb37..321536e80f5 100644 --- a/src/Components/Patient/DailyRounds.tsx +++ b/src/Components/Patient/DailyRounds.tsx @@ -487,7 +487,7 @@ export const DailyRounds = (props: any) => { }} /> - + { dispatch({ type: "set_state", state: newState }); diff --git a/src/Components/Symptoms/SymptomsBuilder.tsx b/src/Components/Symptoms/SymptomsBuilder.tsx index 8a904f6b441..f9c966d47bd 100644 --- a/src/Components/Symptoms/SymptomsBuilder.tsx +++ b/src/Components/Symptoms/SymptomsBuilder.tsx @@ -176,9 +176,9 @@ const SymptomEntry = (props: { const disabled = props.disabled || symptom.clinical_impression_status === "entered-in-error"; return ( -
+
-
+
import("../Common/Loading")); @@ -163,6 +164,7 @@ export const validateRule = ( }; export const UserAdd = (props: UserProps) => { + const { t } = useTranslation(); const { goBack } = useAppHistory(); const { userId } = props; @@ -355,7 +357,7 @@ export const UserAdd = (props: UserProps) => { return; case "doctor_experience_commenced_on": if (state.form.user_type === "Doctor" && !state.form[field]) { - errors[field] = "Field is required"; + errors[field] = t("field_required"); invalidForm = true; } else if ( state.form.user_type === "Doctor" && @@ -368,7 +370,7 @@ export const UserAdd = (props: UserProps) => { case "doctor_qualification": case "doctor_medical_council_registration": if (state.form.user_type === "Doctor" && !state.form[field]) { - errors[field] = "Field is required"; + errors[field] = t("field_required"); invalidForm = true; } return; @@ -605,7 +607,7 @@ export const UserAdd = (props: UserProps) => { options={  Need diff --git a/src/Components/Users/UserProfile.tsx b/src/Components/Users/UserProfile.tsx index 8a456be9bcd..dd8dadf2fb7 100644 --- a/src/Components/Users/UserProfile.tsx +++ b/src/Components/Users/UserProfile.tsx @@ -26,6 +26,7 @@ import routes from "../../Redux/api"; import request from "../../Utils/request/request"; import DateFormField from "../Form/FormFields/DateFormField"; import { validateRule } from "./UserAdd"; +import { useTranslation } from "react-i18next"; const Loading = lazy(() => import("../Common/Loading")); type EditForm = { @@ -110,6 +111,7 @@ const editFormReducer = (state: State, action: Action) => { }; export default function UserProfile() { + const { t } = useTranslation(); const { signOut } = useAuthContext(); const [states, dispatch] = useReducer(editFormReducer, initialState); const [updateStatus, setUpdateStatus] = useState({ @@ -201,7 +203,7 @@ export default function UserProfile() { case "lastName": case "gender": if (!states.form[field]) { - errors[field] = "Field is required"; + errors[field] = t("field_required"); invalidForm = true; } return; @@ -254,7 +256,7 @@ export default function UserProfile() { return; case "email": if (!states.form[field]) { - errors[field] = "This field is required"; + errors[field] = t("field_required"); invalidForm = true; } else if (!validateEmailAddress(states.form[field])) { errors[field] = "Enter a valid email address"; @@ -263,7 +265,7 @@ export default function UserProfile() { return; case "doctor_experience_commenced_on": if (states.form.user_type === "Doctor" && !states.form[field]) { - errors[field] = "Field is required"; + errors[field] = t("field_required"); invalidForm = true; } else if ( (states.form.user_type === "Doctor" && @@ -278,7 +280,7 @@ export default function UserProfile() { case "doctor_qualification": case "doctor_medical_council_registration": if (states.form.user_type === "Doctor" && !states.form[field]) { - errors[field] = "Field is required"; + errors[field] = t("field_required"); invalidForm = true; } return; diff --git a/src/Locale/en/Auth.json b/src/Locale/en/Auth.json index e99cae72f7f..58fdef42612 100644 --- a/src/Locale/en/Auth.json +++ b/src/Locale/en/Auth.json @@ -11,7 +11,6 @@ "gender": "Gender", "age": "Age", "login": "Login", - "field_required": "This field is required", "password_mismatch": "Password and confirm password must be same.", "enter_valid_age": "Please Enter Valid Age", "invalid_username": "Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.", @@ -29,7 +28,7 @@ "password_reset_success": "Password Reset successfully", "password_reset_failure": "Password Reset Failed", "reset_password": "Reset Password", - "available_in":"Available in", + "available_in": "Available in", "sign_out": "Sign Out", "back_to_login": "Back to login", "min_password_len_8": "Minimum password length 8", @@ -37,4 +36,4 @@ "req_atleast_one_uppercase": "Require at least one upper case", "req_atleast_one_lowercase": "Require at least one lower case letter", "req_atleast_one_symbol": "Require at least one symbol" -} +} \ No newline at end of file diff --git a/src/Locale/en/Bed.json b/src/Locale/en/Bed.json index b410293959b..269658be774 100644 --- a/src/Locale/en/Bed.json +++ b/src/Locale/en/Bed.json @@ -10,4 +10,4 @@ "make_multiple_beds_label": "Do you want to make multiple beds?", "number_of_beds": "Number of beds", "number_of_beds_out_of_range_error": "Number of beds cannot be greater than 100" -} \ No newline at end of file +} diff --git a/src/Locale/en/Common.json b/src/Locale/en/Common.json index 1c1e3b49ecb..0bd26305b86 100644 --- a/src/Locale/en/Common.json +++ b/src/Locale/en/Common.json @@ -110,6 +110,7 @@ "features": "Features", "pincode": "Pincode", "required": "Required", + "field_required": "This field is required", "litres": "Litres", "litres_per_day": "Litres/day", "invalid_pincode": "Invalid Pincode", diff --git a/src/Locale/en/Consultation.json b/src/Locale/en/Consultation.json index d811680d0fd..6e3846fb983 100644 --- a/src/Locale/en/Consultation.json +++ b/src/Locale/en/Consultation.json @@ -36,6 +36,7 @@ "prev_sessions": "Prev Sessions", "next_sessions": "Next Sessions", "no_changes": "No changes", + "no_treating_physicians_available": "This facility does not have any home facility doctors. Please contact your admin.", "encounter_suggestion_edit_disallowed": "Not allowed to switch to this option in edit consultation", "encounter_date_field_label__A": "Date & Time of Admission to the Facility", "encounter_date_field_label__DC": "Date & Time of Domiciliary Care commencement", @@ -44,5 +45,6 @@ "encounter_date_field_label__HI": "Date & Time of Consultation", "encounter_date_field_label__R": "Date & Time of Consultation", "back_dated_encounter_date_caution": "You are creating an encounter for", - "encounter_duration_confirmation": "The duration of this encounter would be" + "encounter_duration_confirmation": "The duration of this encounter would be", + "consultation_notes": "General Instructions (Advice)" } \ No newline at end of file diff --git a/src/Locale/en/Diagnosis.json b/src/Locale/en/Diagnosis.json index 6cb301c058e..c049e9bba6f 100644 --- a/src/Locale/en/Diagnosis.json +++ b/src/Locale/en/Diagnosis.json @@ -1,21 +1,21 @@ { - "diagnosis": "Diagnosis", - "diagnoses": "Diagnoses", - "diagnosis_already_added": "This diagnosis was already added", - "principal": "Principal", - "principal_diagnosis": "Principal diagnosis", - "unconfirmed": "Unconfirmed", - "provisional": "Provisional", - "differential": "Differential", - "confirmed": "Confirmed", - "refuted": "Refuted", - "entered-in-error": "Entered in error", - "help_unconfirmed": "There is not sufficient diagnostic and/or clinical evidence to treat this as a confirmed condition.", - "help_provisional": "This is a tentative diagnosis - still a candidate that is under consideration.", - "help_differential": "One of a set of potential (and typically mutually exclusive) diagnoses asserted to further guide the diagnostic process and preliminary treatment.", - "help_confirmed": "There is sufficient diagnostic and/or clinical evidence to treat this as a confirmed condition.", - "help_refuted": "This condition has been ruled out by subsequent diagnostic and clinical evidence.", - "help_entered-in-error": "The statement was entered in error and is not valid.", - "search_icd11_placeholder": "Search for ICD-11 Diagnoses", - "icd11_as_recommended": "As per ICD-11 recommended by WHO" -} \ No newline at end of file + "diagnosis": "Diagnosis", + "diagnoses": "Diagnoses", + "diagnosis_already_added": "This diagnosis was already added", + "principal": "Principal", + "principal_diagnosis": "Principal diagnosis", + "unconfirmed": "Unconfirmed", + "provisional": "Provisional", + "differential": "Differential", + "confirmed": "Confirmed", + "refuted": "Refuted", + "entered-in-error": "Entered in error", + "help_unconfirmed": "There is not sufficient diagnostic and/or clinical evidence to treat this as a confirmed condition.", + "help_provisional": "This is a tentative diagnosis - still a candidate that is under consideration.", + "help_differential": "One of a set of potential (and typically mutually exclusive) diagnoses asserted to further guide the diagnostic process and preliminary treatment.", + "help_confirmed": "There is sufficient diagnostic and/or clinical evidence to treat this as a confirmed condition.", + "help_refuted": "This condition has been ruled out by subsequent diagnostic and clinical evidence.", + "help_entered-in-error": "The statement was entered in error and is not valid.", + "search_icd11_placeholder": "Search for ICD-11 Diagnoses", + "icd11_as_recommended": "As per ICD-11 recommended by WHO" +} diff --git a/src/Locale/en/Facility.json b/src/Locale/en/Facility.json index 19715e7e91f..5bb0a269e87 100644 --- a/src/Locale/en/Facility.json +++ b/src/Locale/en/Facility.json @@ -55,4 +55,4 @@ "discharged_patients": "Discharged Patients", "discharged_patients_empty": "No discharged patients present in this facility", "update_facility_middleware_success": "Facility middleware updated successfully" -} \ No newline at end of file +} diff --git a/src/Locale/en/Medicine.json b/src/Locale/en/Medicine.json index c21f5fa236f..d559ef2fdbf 100644 --- a/src/Locale/en/Medicine.json +++ b/src/Locale/en/Medicine.json @@ -61,4 +61,4 @@ "PRESCRIPTION_FREQUENCY_Q4H": "4th hourly", "PRESCRIPTION_FREQUENCY_QOD": "Alternate day", "PRESCRIPTION_FREQUENCY_QWK": "Once a week" -} \ No newline at end of file +} diff --git a/src/Locale/en/Notifications.json b/src/Locale/en/Notifications.json index ad8dc0e20f1..dac9c29730f 100644 --- a/src/Locale/en/Notifications.json +++ b/src/Locale/en/Notifications.json @@ -16,5 +16,7 @@ "unsubscribe_failed": "Unsubscribe failed.", "unsubscribe": "Unsubscribe", "escape": "Escape", - "loading": "Loading..." + "loading": "Loading...", + "invalid_asset_id_msg": "Oops! The asset ID you entered does not appear to be valid.", + "asset_not_found_msg": "Oops! The asset you are looking for does not exist. Please check the asset id." } diff --git a/src/Locale/en/Users.json b/src/Locale/en/Users.json index 515c77848b4..32c6ee209c3 100644 --- a/src/Locale/en/Users.json +++ b/src/Locale/en/Users.json @@ -10,4 +10,4 @@ "average_weekly_working_hours": "Average weekly working hours", "set_average_weekly_working_hours_for": "Set Average weekly working hours for", "search_by_username": "Search by username" -} \ No newline at end of file +} diff --git a/src/Locale/kn/Auth.json b/src/Locale/kn/Auth.json index fb36b254b38..ff81099c794 100644 --- a/src/Locale/kn/Auth.json +++ b/src/Locale/kn/Auth.json @@ -23,7 +23,7 @@ "auth_login_title": "ಅಧಿಕೃತ ಲಾಗಿನ್", "forget_password": "ಪಾಸ್ವರ್ಡ್ ಮರೆತಿರಾ?", "back_to_login": "ಲಾಗಿನ್ ಪುಟಕ್ಕೆ ಹಿಂತಿರುಗಿ", - "available_in":"ಲಭ್ಯವಿರುವ ಭಾಷೆಗಳು", + "available_in": "ಲಭ್ಯವಿರುವ ಭಾಷೆಗಳು", "forget_password_instruction": "ನಿಮ್ಮ ಬಳಕೆದಾರ ಹೆಸರನ್ನು ನಮೂದಿಸಿ ಮತ್ತು ನಿಮ್ಮ ಪಾಸ್‌ವರ್ಡ್ ಅನ್ನು ಮರುಹೊಂದಿಸಲು ನಾವು ನಿಮಗೆ ಲಿಂಕ್ ಅನ್ನು ಕಳುಹಿಸುತ್ತೇವೆ.", "send_reset_link": "ಮರುಹೊಂದಿಸುವ ಲಿಂಕ್ ಕಳುಹಿಸಿ", "already_a_member": "ಈಗಾಗಲೇ ಸದಸ್ಯರೇ?", diff --git a/src/Locale/ml/Auth.json b/src/Locale/ml/Auth.json index 199bce684ec..605f013b49a 100644 --- a/src/Locale/ml/Auth.json +++ b/src/Locale/ml/Auth.json @@ -22,7 +22,7 @@ "register_page_title": "ആശുപത്രി അഡ്മിനിസ്ട്രേറ്ററായി രജിസ്റ്റർ ചെയ്യുക", "auth_login_title": "അംഗീകൃത ലോഗിൻ", "back_to_login": "ലോഗിൻ പേജിലേക്ക് മടങ്ങുക", - "available_in":"ലഭ്യമായ ഭാഷകൾ", + "available_in": "ലഭ്യമായ ഭാഷകൾ", "forget_password": "പാസ്‌വേഡ് മറന്നോ?", "forget_password_instruction": "നിങ്ങളുടെ യൂസർനെയിം/ഉപയോക്തൃനാമം നൽകുക. പാസ്‌വേഡ് പുന: സജ്ജമാക്കാൻ ഞങ്ങൾ ഒരു ലിങ്ക് അയയ്‌ക്കുന്നതായിരിക്കും.", "send_reset_link": "പുന: സജ്ജീകരണ ലിങ്ക് അയയ്‌ക്കുക", diff --git a/src/Locale/mr/Auth.json b/src/Locale/mr/Auth.json index 2154366c4f6..74d41e469c4 100644 --- a/src/Locale/mr/Auth.json +++ b/src/Locale/mr/Auth.json @@ -22,7 +22,7 @@ "register_page_title": "हॉस्पिटल व्यवस्थापक म्हणून नोंदणी करा", "auth_login_title": "अधिकृत लॉगिन", "back_to_login": "लॉगिन पृष्ठावर परत या", - "available_in":"उपलब्ध भाषा", + "available_in": "उपलब्ध भाषा", "forget_password": "पासवर्ड विसरलात?", "forget_password_instruction": "युजरनेम प्रविष्ट करा आणि आम्ही तुम्हाला पासवर्ड रीसेट करण्यासाठी एक लिंक पाठवू.", "send_reset_link": "रीसेट लिंक पाठवा", diff --git a/src/Locale/ta/Auth.json b/src/Locale/ta/Auth.json index 1d5e15f241a..d5d26caa0fc 100644 --- a/src/Locale/ta/Auth.json +++ b/src/Locale/ta/Auth.json @@ -22,7 +22,7 @@ "register_page_title": "மருத்துவமனை நிர்வாகியாக பதிவு செய்யுங்கள்", "auth_login_title": "அங்கீகரிக்கப்பட்ட உள்நுழைவு", "back_to_login": "உள்நுழைவு பக்கத்திற்குத் திரும்பு", - "available_in":"கிடைக்கும் மொழிகள்", + "available_in": "கிடைக்கும் மொழிகள்", "forget_password": "கடவுச்சொல்லை மறந்துவிட்டீர்களா?", "forget_password_instruction": "உங்கள் பயனர்பெயரை உள்ளிடவும், உங்கள் கடவுச்சொல்லை மீட்டமைக்க ஒரு இணைப்பை நாங்கள் உங்களுக்கு அனுப்புவோம்.", "send_reset_link": "மீட்டமை இணைப்பை அனுப்பவும்",
+
{t("medicine")} diff --git a/src/Components/Medicine/ResponsiveMedicineTables.tsx b/src/Components/Medicine/ResponsiveMedicineTables.tsx index 073511618f1..c3b311a68e4 100644 --- a/src/Components/Medicine/ResponsiveMedicineTables.tsx +++ b/src/Components/Medicine/ResponsiveMedicineTables.tsx @@ -37,13 +37,13 @@ export default function ResponsiveMedicineTable(props: {
+ {item} + {props.actionLabel || ""}