Skip to content

Commit

Permalink
updates on comments, moving debounce and nested code to proper files
Browse files Browse the repository at this point in the history
  • Loading branch information
SwanandBhuskute committed Nov 21, 2024
1 parent 87dbee1 commit e2abfa6
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 50 deletions.
Binary file removed src/Utils/.Notifications.js.swp
Binary file not shown.
2 changes: 1 addition & 1 deletion src/Utils/Notifications.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Stack, alert, defaultModules } from "@pnotify/core";
import * as PNotifyMobile from "@pnotify/mobile";

import { camelCase, startCase } from "./utils";
import { camelCase, startCase } from "@/Utils/utils";

defaultModules.set(PNotifyMobile, {});

Expand Down
52 changes: 31 additions & 21 deletions src/Utils/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { useEffect, useRef } from "react";

import { PatientModel } from "@/components/Patient/models";

import { AREACODES, IN_LANDLINE_AREA_CODES } from "@/common/constants";
Expand Down Expand Up @@ -569,23 +567,35 @@ export const camelCase = (str: string) => {
.replace(/^[A-Z]/, (c) => c.toLowerCase());
};

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

const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
const debouncedCallback = (...args: string[]) => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current);
export function setNestedValueSafely(
obj: Record<string, any>,
path: string,
value: any,
) {
const keys = path.split(".");
let current = obj;

for (let i = 0; i < keys.length - 1; i++) {
const key = keys[i];

// Protect against prototype pollution by skipping unsafe keys
if (key === "__proto__" || key === "constructor" || key === "prototype") {
continue;
}
timeoutRef.current = setTimeout(() => {
callbackRef.current(...args);
}, delay);
};
return debouncedCallback;
};

// Use Object.create(null) to prevent accidental inheritance from Object prototype
current[key] = current[key] || Object.create(null);
current = current[key];
}

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

// Final key assignment, ensuring no prototype pollution vulnerability
if (
lastKey !== "__proto__" &&
lastKey !== "constructor" &&
lastKey !== "prototype"
) {
current[lastKey] = value;
}
}
26 changes: 2 additions & 24 deletions src/components/Facility/Investigations/ShowInvestigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import * as Notification from "@/Utils/Notifications";
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: {},
Expand Down Expand Up @@ -91,31 +92,8 @@ export default function ShowInvestigation(props: ShowInvestigationProps) {

const handleValueChange = (value: any, name: string) => {
const changedFields = { ...state.changedFields };
const keys = name.split(".");
let current = changedFields;
for (let i = 0; i < keys.length - 1; i++) {
const key = keys[i];

// 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];
}

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;
}
setNestedValueSafely(changedFields, name, value);

dispatch({ type: "set_changed_fields", changedFields });
};
Expand Down
6 changes: 4 additions & 2 deletions src/components/Patient/DiagnosesFilter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import { ICD11DiagnosisModel } from "@/components/Diagnosis/types";
import { getDiagnosesByIds } from "@/components/Diagnosis/utils";
import AutocompleteMultiSelectFormField from "@/components/Form/FormFields/AutocompleteMultiselect";

import useDebounce from "@/hooks/useDebounce";

import { Error } from "@/Utils/Notifications";
import routes from "@/Utils/request/api";
import useQuery from "@/Utils/request/useQuery";
import { mergeQueryOptions, useDebounce } from "@/Utils/utils";
import { mergeQueryOptions } from "@/Utils/utils";

export const FILTER_BY_DIAGNOSES_KEYS = [
"diagnoses",
Expand Down Expand Up @@ -70,7 +72,7 @@ export default function DiagnosesFilter(props: Props) {

const debouncedQuery = useDebounce((query: string) => {
refetch({ query: { query } });
}, 0);
}, 300);

return (
<AutocompleteMultiSelectFormField
Expand Down
4 changes: 2 additions & 2 deletions src/components/Patient/PatientRegister.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import { UserModel } from "@/components/Users/models";

import useAppHistory from "@/hooks/useAppHistory";
import useAuthUser from "@/hooks/useAuthUser";
import useDebounce from "@/hooks/useDebounce";

import {
BLOOD_GROUPS,
Expand Down Expand Up @@ -84,7 +85,6 @@ import {
includesIgnoreCase,
parsePhoneNumber,
scrollTo,
useDebounce,
} from "@/Utils/utils";

export type PatientForm = PatientModel &
Expand Down Expand Up @@ -778,7 +778,7 @@ export const PatientRegister = (props: PatientRegisterProps) => {
}
}
}
}, 0);
}, 300);

const handleDialogClose = (action: string) => {
if (action === "transfer") {
Expand Down
22 changes: 22 additions & 0 deletions src/hooks/useDebounce.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { useEffect, useRef } from "react";

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

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

0 comments on commit e2abfa6

Please sign in to comment.