Skip to content

Commit

Permalink
enhanced with suggestions
Browse files Browse the repository at this point in the history
  • Loading branch information
SwanandBhuskute committed Nov 14, 2024
1 parent 7f75a18 commit cc88800
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 30 deletions.
11 changes: 8 additions & 3 deletions src/Utils/stringUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,16 @@ export const camelCase = (str: string) => {
.replace(/([A-Z])/g, (match) => match.toLowerCase());
};

// Capitalize the first letter of each word in a string
export const startCase = (str: string) => {
// Capitalize the first letter of each word in a string, handling edge cases
export const startCase = (str: string): string => {
if (!str) return "";

return str
.toLowerCase()
.replace(/\s+/g, " ")
.trim()
.split(" ")
.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
.map((word) => (word ? word[0].toUpperCase() + word.slice(1) : ""))
.join(" ");
};

Expand Down
33 changes: 22 additions & 11 deletions src/components/Facility/Investigations/Reports/utils.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
import { InvestigationResponse } from "@/components/Facility/Investigations/Reports/types";

const memoize = <T extends (...args: any[]) => any>(fn: T): T => {
const cache: Record<string, ReturnType<T>> = {};
const cache = new Map<string, ReturnType<T>>();
const MAX_CACHE_SIZE = 1000;
return ((...args: Parameters<T>): ReturnType<T> => {
const key = JSON.stringify(args);
if (!cache[key]) {
cache[key] = fn(...args);
const key = args
.map((arg) =>
typeof arg === "object"
? 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[key];
return cache.get(key)!;
}) as T;
};

Expand Down Expand Up @@ -41,15 +52,14 @@ export const transformData = memoize((data: InvestigationResponse) => {
),
);

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 = sessions.findIndex(
(session) =>
session.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 @@ -82,6 +92,7 @@ export const transformData = memoize((data: InvestigationResponse) => {
sessionValues,
};
});

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

Expand Down
22 changes: 20 additions & 2 deletions src/components/Facility/Investigations/ShowInvestigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,28 @@ export default function ShowInvestigation(props: ShowInvestigationProps) {
let current = changedFields;
for (let i = 0; i < keys.length - 1; i++) {
const key = keys[i];
if (!current[key]) current[key] = {};

// Protect against prototype pollution by skipping unsafe keys - crai
if (key === "__proto__" || key === "constructor" || key === "prototype") {
continue;
}

// Use Object.create(null) to prevent accidental inheritance from Object prototype - coderabbit
current[key] = current[key] || Object.create(null);
current = current[key];
}
current[keys[keys.length - 1]] = value;

const lastKey = keys[keys.length - 1];

// Final key assignment, ensuring no prototype pollution vulnerability - coderabbit
if (
lastKey !== "__proto__" &&
lastKey !== "constructor" &&
lastKey !== "prototype"
) {
current[lastKey] = value;
}

dispatch({ type: "set_changed_fields", changedFields });
};

Expand Down
11 changes: 11 additions & 0 deletions src/components/Facility/Investigations/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,17 @@ export const TestTable = ({ title, data, state, dispatch }: any) => {
const handleValueChange = (value: any, name: string) => {
const form = { ...state };
const keys = name.split(".");

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

let current = form;
for (let i = 0; i < keys.length - 1; i++) {
const key = keys[i];
Expand Down
33 changes: 19 additions & 14 deletions src/components/Patient/PatientRegister.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import careConfig from "@careConfig";
import { navigate } from "raviger";
import { useCallback, useReducer, useRef, useState } from "react";
import { useCallback, useEffect, useReducer, useRef, useState } from "react";
import { useTranslation } from "react-i18next";

import CareIcon from "@/CAREUI/icons/CareIcon";
Expand Down Expand Up @@ -185,6 +185,24 @@ export const parseOccupationFromExt = (occupation: Occupation) => {
return occupationObject?.id;
};

const useDebounce = (callback: (...args: any[]) => void, delay: number) => {
const callbackRef = useRef(callback);
useEffect(() => {
callbackRef.current = callback;
}, [callback]);

const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const debouncedCallback = (...args: any[]) => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
timeoutRef.current = setTimeout(() => {
callbackRef.current(...args);
}, delay);
};
return debouncedCallback;
};

export const PatientRegister = (props: PatientRegisterProps) => {
const submitController = useRef<AbortController>();
const authUser = useAuthUser();
Expand Down Expand Up @@ -746,19 +764,6 @@ export const PatientRegister = (props: PatientRegisterProps) => {
});
};

const useDebounce = (callback: (...args: any[]) => void, delay: number) => {
const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const debouncedCallback = (...args: any[]) => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
}
timeoutRef.current = setTimeout(() => {
callback(...args);
}, delay);
};
return debouncedCallback;
};

const duplicateCheck = useDebounce(async (phoneNo: string) => {
if (
phoneNo &&
Expand Down

0 comments on commit cc88800

Please sign in to comment.