Skip to content

Commit

Permalink
Merge branch 'develop' into feat/tanstack-query
Browse files Browse the repository at this point in the history
  • Loading branch information
rithviknishad committed Dec 10, 2024
2 parents 094dc48 + b25ecd0 commit e48d37c
Show file tree
Hide file tree
Showing 24 changed files with 565 additions and 663 deletions.
419 changes: 25 additions & 394 deletions package-lock.json

Large diffs are not rendered by default.

10 changes: 4 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@
"browserslist-useragent-regexp": "^4.1.3",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "^1.0.0",
"cmdk": "^1.0.4",
"cross-env": "^7.0.3",
"cypress": "^13.16.1",
"dayjs": "^1.11.13",
Expand All @@ -85,8 +85,7 @@
"hi-profiles": "^1.1.0",
"i18next": "^23.16.4",
"i18next-browser-languagedetector": "^8.0.0",
"i18next-http-backend": "^2.6.2",
"lodash-es": "^4.17.21",
"i18next-http-backend": "^3.0.1",
"next-themes": "^0.4.4",
"postcss-loader": "^8.1.1",
"qrcode.react": "^4.1.0",
Expand All @@ -95,7 +94,7 @@
"react-copy-to-clipboard": "^5.1.0",
"react-dom": "18.3.1",
"react-google-recaptcha": "^3.1.0",
"react-i18next": "^15.1.1",
"react-i18next": "^15.1.3",
"react-infinite-scroll-component": "^6.1.0",
"react-pdf": "^9.1.1",
"react-webcam": "^7.2.0",
Expand All @@ -115,7 +114,6 @@
"@types/events": "^3.0.3",
"@types/google.maps": "^3.58.1",
"@types/jsdom": "^21.1.7",
"@types/lodash-es": "^4.17.12",
"@types/node": "^22.9.0",
"@types/react": "^18.3.12",
"@types/react-copy-to-clipboard": "^5.0.7",
Expand Down Expand Up @@ -182,4 +180,4 @@
"node": ">=22.11.0"
},
"packageManager": "[email protected]"
}
}
8 changes: 8 additions & 0 deletions public/locale/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,14 @@
"ROUNDS_TYPE__NORMAL": "Brief Update",
"ROUNDS_TYPE__TELEMEDICINE": "Tele-medicine Log",
"ROUNDS_TYPE__VENTILATOR": "Detailed Update",
"SAMPLE_TEST_HISTORY__APPROVED": "Approved",
"SAMPLE_TEST_HISTORY__COMPLETED": "Completed",
"SAMPLE_TEST_HISTORY__RECEIVED_AT_LAB": "Received At Lab",
"SAMPLE_TEST_HISTORY__REQUEST_SUBMITTED": "Request Submitted",
"SAMPLE_TEST_RESULT__AWAITING": "Awaiting",
"SAMPLE_TEST_RESULT__INVALID": "Invalid",
"SAMPLE_TEST_RESULT__NEGATIVE": "Negative",
"SAMPLE_TEST_RESULT__POSITIVE": "Positive",
"SLEEP__EXCESSIVE": "Excessive",
"SLEEP__NO_SLEEP": "No sleep",
"SLEEP__SATISFACTORY": "Satisfactory",
Expand Down
22 changes: 20 additions & 2 deletions src/Utils/Notifications.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Stack, alert, defaultModules } from "@pnotify/core";
import * as PNotifyMobile from "@pnotify/mobile";
import { camelCase, startCase } from "lodash-es";

defaultModules.set(PNotifyMobile, {});

Expand Down Expand Up @@ -35,6 +34,25 @@ const notify = (text, type) => {
});
};

/**
* Formats input string to a more human readable format
* @param {string} key - The key to format
* @returns {string} The formatted key
* @example
* formatKey("patient_name") => "Patient Name"
*/
const formatKey = (key) => {
return key
.replace(/[^a-zA-Z0-9]+/g, " ") // Replace non-alphanumeric characters with a space
.trim()
.split(" ")
.map(
(word) =>
word.charAt(0).toLocaleUpperCase() + word.slice(1).toLocaleLowerCase(),
) // Capitalize the first letter of each word and lowercase the rest
.join(" ");
};

const notifyError = (error) => {
let errorMsg = "";
if (typeof error === "string" || !error) {
Expand All @@ -44,7 +62,7 @@ const notifyError = (error) => {
errorMsg = error.detail;
} else {
for (let [key, value] of Object.entries(error)) {
let keyName = startCase(camelCase(key));
let keyName = formatKey(key);
if (Array.isArray(value)) {
const uniques = [...new Set(value)];
errorMsg += `${keyName} - ${uniques.splice(0, 5).join(", ")}`;
Expand Down
15 changes: 15 additions & 0 deletions src/Utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -544,3 +544,18 @@ export const fahrenheitToCelsius = (fahrenheit: number) => {
export const keysOf = <T extends object>(obj: T) => {
return Object.keys(obj) as (keyof T)[];
};

// Utility to check if a value is "empty"
export const isEmpty = (value: unknown) => {
return value === "" || value == undefined;
};

// equivalent to lodash omitBy
export function omitBy<T extends Record<string, unknown>>(
obj: T,
predicate: (value: unknown) => boolean,
): Partial<T> {
return Object.fromEntries(
Object.entries(obj).filter(([_, value]) => !predicate(value)),
) as Partial<T>;
}
7 changes: 3 additions & 4 deletions src/components/Common/ExcelFIleDragAndDrop.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { forIn } from "lodash-es";
import { useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import * as XLSX from "xlsx";
Expand Down Expand Up @@ -68,9 +67,9 @@ export default function ExcelFileDragAndDrop({
const data = XLSX.utils.sheet_to_json(worksheet, { defval: "" });
//converts the date to string
data.forEach((row: any) => {
forIn(row, (value: any, key: string) => {
if (value instanceof Date) {
row[key] = value.toISOString().split("T")[0];
Object.keys(row).forEach((key) => {
if (row[key] instanceof Date) {
row[key] = row[key].toISOString().split("T")[0];
}
});
});
Expand Down
2 changes: 1 addition & 1 deletion src/components/Common/Page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export default function Page(props: PageProps) {

let padding = "";
if (!props.noImplicitPadding) {
if (!props.hideBack || props.componentRight) padding = "py-3 md:p-6";
if (!props.hideBack || props.componentRight) padding = "py-3 md:px-6";
else padding = "px-6 py-5";
}

Expand Down
21 changes: 10 additions & 11 deletions src/components/Facility/Investigations/Reports/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import _ from "lodash";
import { useCallback, useReducer, useState } from "react";
import { useTranslation } from "react-i18next";

Expand Down Expand Up @@ -179,16 +178,16 @@ const InvestigationReports = ({ id }: any) => {
),
);

const investigationList = _.chain(data)
.flatMap((i) => i?.data?.results)
.compact()
.flatten()
.map((i) => ({
...i,
name: `${i.name} ${i.groups[0].name && " | " + i.groups[0].name} `,
}))
.unionBy("external_id")
.value();
const investigationList = Array.from(
data
.flatMap((i) => i?.data?.results || [])
.map((i) => ({
...i,
name: `${i.name} ${i.groups[0].name ? " | " + i.groups[0].name : ""}`,
}))
.reduce((map, item) => map.set(item.external_id, item), new Map())
.values(),
);

dispatch({ type: "set_investigations", payload: investigationList });
dispatch({
Expand Down
84 changes: 62 additions & 22 deletions src/components/Facility/Investigations/Reports/utils.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,70 @@
import _ from "lodash";
import { findIndex, memoize } from "lodash-es";
import {
Investigation,
InvestigationResponse,
} from "@/components/Facility/Investigations/Reports/types";

import { InvestigationResponse } from "@/components/Facility/Investigations/Reports/types";
const memoize = <T extends (...args: any[]) => any>(fn: T): T => {
const cache = new Map<string, ReturnType<T>>();
const MAX_CACHE_SIZE = 1000;
return ((...args: Parameters<T>): ReturnType<T> => {
const key = args
.map((arg) =>
typeof arg === "object"
? arg instanceof Date
? arg.getTime().toString()
: JSON.stringify(Object.entries(arg).sort())
: String(arg),
)
.join("|");
if (!cache.has(key)) {
if (cache.size >= MAX_CACHE_SIZE) {
const firstKey: any = cache.keys().next().value;
cache.delete(firstKey);
}
cache.set(key, fn(...args));
}
return cache.get(key)!;
}) as T;
};

export const transformData = memoize((data: InvestigationResponse) => {
const sessions = _.chain(data)
.map((value: any) => {
return {
...value.session_object,
facility_name: value.consultation_object?.facility_name,
facility_id: value.consultation_object?.facility,
};
})
.uniqBy("session_external_id")
.orderBy("session_created_date", "desc")
.value();
const groupByInvestigation = _.chain(data)
.groupBy("investigation_object.external_id")
.values()
.value();
const sessions = Array.from(
new Map(
data.map((value: any) => [
value.session_object.session_external_id,
{
...value.session_object,
facility_name: value.consultation_object?.facility_name,
facility_id: value.consultation_object?.facility,
},
]),
).values(),
).sort(
(a, b) =>
new Date(b.session_created_date).getTime() -
new Date(a.session_created_date).getTime(),
);

const groupByInvestigation = Object.values(
data.reduce(
(acc, value: Investigation) => {
const key = value.investigation_object.external_id;
if (!acc[key]) acc[key] = [];
acc[key].push(value);
return acc;
},
{} as { [key: string]: Investigation[] },
),
);

const sessionMap = new Map(
sessions.map((session, index) => [session.session_external_id, index]),
);
const reqData = groupByInvestigation.map((value: any) => {
const sessionValues = Array.from({ length: sessions.length });
value.forEach((val: any) => {
const sessionIndex = findIndex(sessions, [
"session_external_id",
val.session_object.session_external_id,
]);
const sessionIndex =
sessionMap.get(val.session_object.session_external_id) ?? -1;
if (sessionIndex > -1) {
sessionValues[sessionIndex] = {
min: val.investigation_object.min_value,
Expand Down Expand Up @@ -58,6 +97,7 @@ export const transformData = memoize((data: InvestigationResponse) => {
sessionValues,
};
});

return { sessions, data: reqData };
});

Expand Down
45 changes: 33 additions & 12 deletions src/components/Facility/Investigations/ShowInvestigation.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import _ from "lodash";
import { set } from "lodash-es";
import { useCallback, useReducer } from "react";
import { useTranslation } from "react-i18next";

Expand All @@ -12,6 +10,8 @@ import routes from "@/Utils/request/api";
import request from "@/Utils/request/request";
import useQuery from "@/Utils/request/useQuery";

// import { setNestedValueSafely } from "@/Utils/utils";

const initialState = {
changedFields: {},
initialValues: {},
Expand Down Expand Up @@ -92,8 +92,25 @@ export default function ShowInvestigation(props: ShowInvestigationProps) {
});

const handleValueChange = (value: any, name: string) => {
const keys = name.split(".");
// Validate keys to prevent prototype pollution - coderabbit suggested
if (
keys.some((key) =>
["__proto__", "constructor", "prototype"].includes(key),
)
) {
return;
}

const changedFields = { ...state.changedFields };
set(changedFields, name, value);
let current = changedFields;
for (let i = 0; i < keys.length - 1; i++) {
const key = keys[i];
if (!current[key]) current[key] = {};
current = current[key];
}

current[keys[keys.length - 1]] = value;
dispatch({ type: "set_changed_fields", changedFields });
};

Expand Down Expand Up @@ -151,15 +168,19 @@ export default function ShowInvestigation(props: ShowInvestigationProps) {
};

const handleUpdateCancel = useCallback(() => {
const changedValues = _.chain(state.initialValues)
.map((val: any, _key: string) => ({
id: val?.id,
initialValue: val?.notes || val?.value || null,
value: val?.value || null,
notes: val?.notes || null,
}))
.reduce((acc: any, cur: any) => ({ ...acc, [cur.id]: cur }), {})
.value();
const changedValues = Object.keys(state.initialValues).reduce(
(acc: any, key: any) => {
const val = state.initialValues[key];
acc[key] = {
id: val?.id,
initialValue: val?.notes || val?.value || null,
value: val?.value || null,
notes: val?.notes || null,
};
return acc;
},
{},
);
dispatch({ type: "set_changed_fields", changedFields: changedValues });
}, [state.initialValues]);

Expand Down
20 changes: 18 additions & 2 deletions src/components/Facility/Investigations/Table.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { set } from "lodash-es";
import { useState } from "react";

import { SelectFormField } from "@/components/Form/FormFields/SelectFormField";
Expand Down Expand Up @@ -60,7 +59,24 @@ export const TestTable = ({ title, data, state, dispatch }: any) => {

const handleValueChange = (value: any, name: string) => {
const form = { ...state };
set(form, name, value);
const keys = name.split(".");

// Validate keys to prevent prototype pollution - coderabbit suggested
if (
keys.some((key) =>
["__proto__", "constructor", "prototype"].includes(key),
)
) {
return;
}

let current = form;
for (let i = 0; i < keys.length - 1; i++) {
const key = keys[i];
if (!current[key]) current[key] = {};
current = current[key];
}
current[keys[keys.length - 1]] = value;
dispatch({ type: "set_form", form });
};

Expand Down
Loading

0 comments on commit e48d37c

Please sign in to comment.