From 7fff2999f7856fec462dc762c3a39fcc73a9fb26 Mon Sep 17 00:00:00 2001
From: JavidSumra
Date: Thu, 17 Oct 2024 08:58:32 +0530
Subject: [PATCH 1/9] Add field validation to resolve the Update Profile Issue
---
package-lock.json | 138 +--------------------------
src/Components/Users/UserProfile.tsx | 53 +++++++++-
2 files changed, 54 insertions(+), 137 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index aa99337d8d6..a0fee9a566c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -115,6 +115,7 @@
"apps/care_livekit_fe": {
"name": "care-livekit",
"version": "0.0.1",
+ "extraneous": true,
"license": "ISC",
"dependencies": {
"@livekit/components-react": "^2.6.2",
@@ -1779,11 +1780,6 @@
"node": ">=6.9.0"
}
},
- "node_modules/@bufbuild/protobuf": {
- "version": "1.10.0",
- "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-1.10.0.tgz",
- "integrity": "sha512-QDdVFLoN93Zjg36NoQPZfsVH9tZew7wKDKyV5qRdj8ntT4wQCOradQjRaTdwMhWUYsgKsvCINKKm87FdEk96Ag=="
- },
"node_modules/@colors/colors": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz",
@@ -2647,64 +2643,6 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
- "node_modules/@livekit/components-core": {
- "version": "0.11.9",
- "resolved": "https://registry.npmjs.org/@livekit/components-core/-/components-core-0.11.9.tgz",
- "integrity": "sha512-LPE1BZ+YTaqsVqGy/GAlpiO5rEI8XpEaf1TQcGdZN1BCBas9hTHt7/aHMbHQJ0K5xuAFQx8is6dFe451T4qXIQ==",
- "dependencies": {
- "@floating-ui/dom": "1.6.11",
- "loglevel": "1.9.1",
- "rxjs": "7.8.1"
- },
- "engines": {
- "node": ">=18"
- },
- "peerDependencies": {
- "livekit-client": "^2.5.7",
- "tslib": "^2.6.2"
- }
- },
- "node_modules/@livekit/components-react": {
- "version": "2.6.5",
- "resolved": "https://registry.npmjs.org/@livekit/components-react/-/components-react-2.6.5.tgz",
- "integrity": "sha512-G3BpBlKy+lWTV9MH3/oBTBC17Z8CWqZ9GnjcG/xmYI0IvqmY89tVWph7cj2Bq0taniA+mD3U9EMPr68fOb1m1g==",
- "dependencies": {
- "@livekit/components-core": "0.11.9",
- "clsx": "2.1.1",
- "usehooks-ts": "3.1.0"
- },
- "engines": {
- "node": ">=18"
- },
- "peerDependencies": {
- "@livekit/krisp-noise-filter": "^0.2.12",
- "livekit-client": "^2.5.7",
- "react": ">=18",
- "react-dom": ">=18",
- "tslib": "^2.6.2"
- },
- "peerDependenciesMeta": {
- "@livekit/krisp-noise-filter": {
- "optional": true
- }
- }
- },
- "node_modules/@livekit/components-styles": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/@livekit/components-styles/-/components-styles-1.1.4.tgz",
- "integrity": "sha512-QCupn7tQ/dy/WZclrfsgtDe8peiGYS6Ied1IGkKOysaXo04l90t62SIUTKyxgd0dNDhUDC0p34qCggGZs/44lQ==",
- "engines": {
- "node": ">=18"
- }
- },
- "node_modules/@livekit/protocol": {
- "version": "1.24.0",
- "resolved": "https://registry.npmjs.org/@livekit/protocol/-/protocol-1.24.0.tgz",
- "integrity": "sha512-9dCsqnkMn7lvbI4NGh18zhLDsrXyUcpS++TEFgEk5Xv1WM3R2kT3EzqgL1P/mr3jaabM6rJ8wZA/KJLuQNpF5w==",
- "dependencies": {
- "@bufbuild/protobuf": "^1.10.0"
- }
- },
"node_modules/@mapbox/node-pre-gyp": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz",
@@ -6195,10 +6133,6 @@
"node": ">=6"
}
},
- "node_modules/care-livekit": {
- "resolved": "apps/care_livekit_fe",
- "link": true
- },
"node_modules/caseless": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
@@ -10932,26 +10866,6 @@
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
- "node_modules/livekit-client": {
- "version": "2.5.9",
- "resolved": "https://registry.npmjs.org/livekit-client/-/livekit-client-2.5.9.tgz",
- "integrity": "sha512-oDpK6SKYB1F+mNO+25DA0bF0cD2XoOJeD8ji4YQpzDBQv2IxeyKrQhoqXAqrYgIKuiMNkImSf+yg2v7EHSl4Og==",
- "dependencies": {
- "@livekit/protocol": "1.24.0",
- "events": "^3.3.0",
- "loglevel": "^1.8.0",
- "sdp-transform": "^2.14.1",
- "ts-debounce": "^4.0.0",
- "tslib": "2.7.0",
- "typed-emitter": "^2.1.0",
- "webrtc-adapter": "^9.0.0"
- }
- },
- "node_modules/livekit-client/node_modules/tslib": {
- "version": "2.7.0",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz",
- "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA=="
- },
"node_modules/load-plugin": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/load-plugin/-/load-plugin-6.0.3.tgz",
@@ -11052,7 +10966,8 @@
"node_modules/lodash.debounce": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
- "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="
+ "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==",
+ "dev": true
},
"node_modules/lodash.isplainobject": {
"version": "4.0.6",
@@ -11138,18 +11053,6 @@
"node": ">=8"
}
},
- "node_modules/loglevel": {
- "version": "1.9.1",
- "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.9.1.tgz",
- "integrity": "sha512-hP3I3kCrDIMuRwAwHltphhDM1r8i55H33GgqjXbrisuJhF4kRhW1dNuxsRklp4bXl8DSdLaNLuiL4A/LWRfxvg==",
- "engines": {
- "node": ">= 0.6.0"
- },
- "funding": {
- "type": "tidelift",
- "url": "https://tidelift.com/funding/github/npm/loglevel"
- }
- },
"node_modules/long": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz",
@@ -16101,14 +16004,6 @@
"resolved": "https://registry.npmjs.org/sdp/-/sdp-3.2.0.tgz",
"integrity": "sha512-d7wDPgDV3DDiqulJjKiV2865wKsJ34YI+NDREbm+FySq6WuKOikwyNQcm+doLAZ1O6ltdO0SeKle2xMpN3Brgw=="
},
- "node_modules/sdp-transform": {
- "version": "2.14.2",
- "resolved": "https://registry.npmjs.org/sdp-transform/-/sdp-transform-2.14.2.tgz",
- "integrity": "sha512-icY6jVao7MfKCieyo1AyxFYm1baiM+fA00qW/KrNNVlkxHAd34riEKuEkUe4bBb3gJwLJZM+xT60Yj1QL8rHiA==",
- "bin": {
- "sdp-verify": "checker.js"
- }
- },
"node_modules/semver": {
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
@@ -17329,11 +17224,6 @@
"typescript": ">=4.2.0"
}
},
- "node_modules/ts-debounce": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/ts-debounce/-/ts-debounce-4.0.0.tgz",
- "integrity": "sha512-+1iDGY6NmOGidq7i7xZGA4cm8DAa6fqdYcvO5Z6yBevH++Bdo9Qt/mN0TzHUgcCcKv1gmh9+W5dHqz8pMWbCbg=="
- },
"node_modules/ts-interface-checker": {
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
@@ -17501,14 +17391,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/typed-emitter": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/typed-emitter/-/typed-emitter-2.1.0.tgz",
- "integrity": "sha512-g/KzbYKbH5C2vPkaXGu8DJlHrGKHLsM25Zg9WuC9pMGfuvT+X25tZQWo5fK1BjBm8+UrVE9LDCvaY0CQk+fXDA==",
- "optionalDependencies": {
- "rxjs": "*"
- }
- },
"node_modules/typedarray": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
@@ -18043,20 +17925,6 @@
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
- "node_modules/usehooks-ts": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/usehooks-ts/-/usehooks-ts-3.1.0.tgz",
- "integrity": "sha512-bBIa7yUyPhE1BCc0GmR96VU/15l/9gP1Ch5mYdLcFBaFGQsdmXkvjV0TtOqW1yUd6VjIwDunm+flSciCQXujiw==",
- "dependencies": {
- "lodash.debounce": "^4.0.8"
- },
- "engines": {
- "node": ">=16.15.0"
- },
- "peerDependencies": {
- "react": "^16.8.0 || ^17 || ^18"
- }
- },
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
diff --git a/src/Components/Users/UserProfile.tsx b/src/Components/Users/UserProfile.tsx
index 22f2a0e2607..5ca5c0221b4 100644
--- a/src/Components/Users/UserProfile.tsx
+++ b/src/Components/Users/UserProfile.tsx
@@ -1,4 +1,4 @@
-import { useState, useReducer, FormEvent } from "react";
+import { useState, useReducer, FormEvent, useMemo } from "react";
import { GENDER_TYPES } from "../../Common/constants";
import { validateEmailAddress } from "../../Common/validation";
import * as Notification from "../../Utils/Notifications.js";
@@ -182,6 +182,51 @@ export default function UserProfile() {
},
);
+ const hasChanges = useMemo(() => {
+ if (!userData) return false;
+
+ const fieldsToCheck: (keyof EditForm)[] = [
+ "altPhoneNumber",
+ "date_of_birth",
+ "doctor_experience_commenced_on",
+ "doctor_medical_council_registration",
+ "email",
+ "firstName",
+ "gender",
+ "lastName",
+ "phoneNumber",
+ "qualification",
+ "video_connect_link",
+ "weekly_working_hours",
+ ];
+
+ return fieldsToCheck.some((field) => {
+ if (field === "date_of_birth") {
+ return (
+ dayjs(states.form[field]).format("YYYY-MM-DD") !==
+ dayjs(userData[field]).format("YYYY-MM-DD")
+ );
+ }
+ if (field === "doctor_experience_commenced_on") {
+ const userDataYears = dayjs().diff(dayjs(userData[field]), "years");
+ return Number(states.form[field]) !== Number(userDataYears);
+ }
+ if (field === "weekly_working_hours")
+ return Number(states.form[field]) !== Number(userData[field]);
+ if (field === "firstName")
+ return states.form[field] !== userData.first_name;
+ if (field === "lastName")
+ return states.form[field] !== userData.last_name;
+ if (field === "phoneNumber")
+ return states.form[field] !== userData.phone_number;
+ if (field === "altPhoneNumber")
+ return states.form[field] !== userData.alt_phone_number;
+ if (field === "video_connect_link")
+ return states.form[field] !== userData[field] && !!states.form[field];
+ return states.form[field] !== userData[field];
+ });
+ }, [states.form, userData]);
+
const validateNewPassword = (password: string) => {
if (
password.length < 8 ||
@@ -788,7 +833,11 @@ export default function UserProfile() {
-
+
From 5fee85e55cb07e6d1132448a6c33369e6ef084be Mon Sep 17 00:00:00 2001
From: JavidSumra
Date: Thu, 17 Oct 2024 11:09:40 +0530
Subject: [PATCH 2/9] refactor(profile): migrated change detection from useMemo
to useEffect for cleaner comparison logic
---
src/Components/Users/UserProfile.tsx | 60 +++++++---------------------
1 file changed, 14 insertions(+), 46 deletions(-)
diff --git a/src/Components/Users/UserProfile.tsx b/src/Components/Users/UserProfile.tsx
index 5ca5c0221b4..a0739a4db38 100644
--- a/src/Components/Users/UserProfile.tsx
+++ b/src/Components/Users/UserProfile.tsx
@@ -1,4 +1,4 @@
-import { useState, useReducer, FormEvent, useMemo } from "react";
+import { useState, useReducer, FormEvent, useEffect } from "react";
import { GENDER_TYPES } from "../../Common/constants";
import { validateEmailAddress } from "../../Common/validation";
import * as Notification from "../../Utils/Notifications.js";
@@ -117,6 +117,8 @@ export default function UserProfile() {
isChecking: false,
isUpdateAvailable: false,
});
+ const [hasChanges, setHasChanges] = useState(false);
+ const [isFieldLoaded, setIsFieldLoaded] = useState(false);
const authUser = useAuthUser();
@@ -172,6 +174,7 @@ export default function UserProfile() {
type: "set_form",
form: formData,
});
+ setHasChanges(false);
},
});
@@ -182,51 +185,6 @@ export default function UserProfile() {
},
);
- const hasChanges = useMemo(() => {
- if (!userData) return false;
-
- const fieldsToCheck: (keyof EditForm)[] = [
- "altPhoneNumber",
- "date_of_birth",
- "doctor_experience_commenced_on",
- "doctor_medical_council_registration",
- "email",
- "firstName",
- "gender",
- "lastName",
- "phoneNumber",
- "qualification",
- "video_connect_link",
- "weekly_working_hours",
- ];
-
- return fieldsToCheck.some((field) => {
- if (field === "date_of_birth") {
- return (
- dayjs(states.form[field]).format("YYYY-MM-DD") !==
- dayjs(userData[field]).format("YYYY-MM-DD")
- );
- }
- if (field === "doctor_experience_commenced_on") {
- const userDataYears = dayjs().diff(dayjs(userData[field]), "years");
- return Number(states.form[field]) !== Number(userDataYears);
- }
- if (field === "weekly_working_hours")
- return Number(states.form[field]) !== Number(userData[field]);
- if (field === "firstName")
- return states.form[field] !== userData.first_name;
- if (field === "lastName")
- return states.form[field] !== userData.last_name;
- if (field === "phoneNumber")
- return states.form[field] !== userData.phone_number;
- if (field === "altPhoneNumber")
- return states.form[field] !== userData.alt_phone_number;
- if (field === "video_connect_link")
- return states.form[field] !== userData[field] && !!states.form[field];
- return states.form[field] !== userData[field];
- });
- }, [states.form, userData]);
-
const validateNewPassword = (password: string) => {
if (
password.length < 8 ||
@@ -369,8 +327,18 @@ export default function UserProfile() {
type: "set_form",
form: { ...states.form, [event.name]: event.value },
});
+ setIsFieldLoaded(true);
};
+ useEffect(() => {
+ if (showEdit && isFieldLoaded) {
+ setHasChanges(true);
+ } else {
+ setIsFieldLoaded(false);
+ setHasChanges(false);
+ }
+ }, [handleFieldChange]);
+
const getDate = (value: any) =>
value && dayjs(value).isValid() && dayjs(value).toDate();
From 7b775a3482fe299988a27c21c39e411a0dd0e47a Mon Sep 17 00:00:00 2001
From: JavidSumra
Date: Thu, 17 Oct 2024 12:52:07 +0530
Subject: [PATCH 3/9] Discard package-lock.json file
---
package-lock.json | 138 +++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 135 insertions(+), 3 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index a0fee9a566c..aa99337d8d6 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -115,7 +115,6 @@
"apps/care_livekit_fe": {
"name": "care-livekit",
"version": "0.0.1",
- "extraneous": true,
"license": "ISC",
"dependencies": {
"@livekit/components-react": "^2.6.2",
@@ -1780,6 +1779,11 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@bufbuild/protobuf": {
+ "version": "1.10.0",
+ "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-1.10.0.tgz",
+ "integrity": "sha512-QDdVFLoN93Zjg36NoQPZfsVH9tZew7wKDKyV5qRdj8ntT4wQCOradQjRaTdwMhWUYsgKsvCINKKm87FdEk96Ag=="
+ },
"node_modules/@colors/colors": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz",
@@ -2643,6 +2647,64 @@
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
+ "node_modules/@livekit/components-core": {
+ "version": "0.11.9",
+ "resolved": "https://registry.npmjs.org/@livekit/components-core/-/components-core-0.11.9.tgz",
+ "integrity": "sha512-LPE1BZ+YTaqsVqGy/GAlpiO5rEI8XpEaf1TQcGdZN1BCBas9hTHt7/aHMbHQJ0K5xuAFQx8is6dFe451T4qXIQ==",
+ "dependencies": {
+ "@floating-ui/dom": "1.6.11",
+ "loglevel": "1.9.1",
+ "rxjs": "7.8.1"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "livekit-client": "^2.5.7",
+ "tslib": "^2.6.2"
+ }
+ },
+ "node_modules/@livekit/components-react": {
+ "version": "2.6.5",
+ "resolved": "https://registry.npmjs.org/@livekit/components-react/-/components-react-2.6.5.tgz",
+ "integrity": "sha512-G3BpBlKy+lWTV9MH3/oBTBC17Z8CWqZ9GnjcG/xmYI0IvqmY89tVWph7cj2Bq0taniA+mD3U9EMPr68fOb1m1g==",
+ "dependencies": {
+ "@livekit/components-core": "0.11.9",
+ "clsx": "2.1.1",
+ "usehooks-ts": "3.1.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@livekit/krisp-noise-filter": "^0.2.12",
+ "livekit-client": "^2.5.7",
+ "react": ">=18",
+ "react-dom": ">=18",
+ "tslib": "^2.6.2"
+ },
+ "peerDependenciesMeta": {
+ "@livekit/krisp-noise-filter": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@livekit/components-styles": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/@livekit/components-styles/-/components-styles-1.1.4.tgz",
+ "integrity": "sha512-QCupn7tQ/dy/WZclrfsgtDe8peiGYS6Ied1IGkKOysaXo04l90t62SIUTKyxgd0dNDhUDC0p34qCggGZs/44lQ==",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@livekit/protocol": {
+ "version": "1.24.0",
+ "resolved": "https://registry.npmjs.org/@livekit/protocol/-/protocol-1.24.0.tgz",
+ "integrity": "sha512-9dCsqnkMn7lvbI4NGh18zhLDsrXyUcpS++TEFgEk5Xv1WM3R2kT3EzqgL1P/mr3jaabM6rJ8wZA/KJLuQNpF5w==",
+ "dependencies": {
+ "@bufbuild/protobuf": "^1.10.0"
+ }
+ },
"node_modules/@mapbox/node-pre-gyp": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz",
@@ -6133,6 +6195,10 @@
"node": ">=6"
}
},
+ "node_modules/care-livekit": {
+ "resolved": "apps/care_livekit_fe",
+ "link": true
+ },
"node_modules/caseless": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
@@ -10866,6 +10932,26 @@
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
+ "node_modules/livekit-client": {
+ "version": "2.5.9",
+ "resolved": "https://registry.npmjs.org/livekit-client/-/livekit-client-2.5.9.tgz",
+ "integrity": "sha512-oDpK6SKYB1F+mNO+25DA0bF0cD2XoOJeD8ji4YQpzDBQv2IxeyKrQhoqXAqrYgIKuiMNkImSf+yg2v7EHSl4Og==",
+ "dependencies": {
+ "@livekit/protocol": "1.24.0",
+ "events": "^3.3.0",
+ "loglevel": "^1.8.0",
+ "sdp-transform": "^2.14.1",
+ "ts-debounce": "^4.0.0",
+ "tslib": "2.7.0",
+ "typed-emitter": "^2.1.0",
+ "webrtc-adapter": "^9.0.0"
+ }
+ },
+ "node_modules/livekit-client/node_modules/tslib": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz",
+ "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA=="
+ },
"node_modules/load-plugin": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/load-plugin/-/load-plugin-6.0.3.tgz",
@@ -10966,8 +11052,7 @@
"node_modules/lodash.debounce": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
- "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==",
- "dev": true
+ "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="
},
"node_modules/lodash.isplainobject": {
"version": "4.0.6",
@@ -11053,6 +11138,18 @@
"node": ">=8"
}
},
+ "node_modules/loglevel": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.9.1.tgz",
+ "integrity": "sha512-hP3I3kCrDIMuRwAwHltphhDM1r8i55H33GgqjXbrisuJhF4kRhW1dNuxsRklp4bXl8DSdLaNLuiL4A/LWRfxvg==",
+ "engines": {
+ "node": ">= 0.6.0"
+ },
+ "funding": {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/loglevel"
+ }
+ },
"node_modules/long": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz",
@@ -16004,6 +16101,14 @@
"resolved": "https://registry.npmjs.org/sdp/-/sdp-3.2.0.tgz",
"integrity": "sha512-d7wDPgDV3DDiqulJjKiV2865wKsJ34YI+NDREbm+FySq6WuKOikwyNQcm+doLAZ1O6ltdO0SeKle2xMpN3Brgw=="
},
+ "node_modules/sdp-transform": {
+ "version": "2.14.2",
+ "resolved": "https://registry.npmjs.org/sdp-transform/-/sdp-transform-2.14.2.tgz",
+ "integrity": "sha512-icY6jVao7MfKCieyo1AyxFYm1baiM+fA00qW/KrNNVlkxHAd34riEKuEkUe4bBb3gJwLJZM+xT60Yj1QL8rHiA==",
+ "bin": {
+ "sdp-verify": "checker.js"
+ }
+ },
"node_modules/semver": {
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
@@ -17224,6 +17329,11 @@
"typescript": ">=4.2.0"
}
},
+ "node_modules/ts-debounce": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/ts-debounce/-/ts-debounce-4.0.0.tgz",
+ "integrity": "sha512-+1iDGY6NmOGidq7i7xZGA4cm8DAa6fqdYcvO5Z6yBevH++Bdo9Qt/mN0TzHUgcCcKv1gmh9+W5dHqz8pMWbCbg=="
+ },
"node_modules/ts-interface-checker": {
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
@@ -17391,6 +17501,14 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/typed-emitter": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/typed-emitter/-/typed-emitter-2.1.0.tgz",
+ "integrity": "sha512-g/KzbYKbH5C2vPkaXGu8DJlHrGKHLsM25Zg9WuC9pMGfuvT+X25tZQWo5fK1BjBm8+UrVE9LDCvaY0CQk+fXDA==",
+ "optionalDependencies": {
+ "rxjs": "*"
+ }
+ },
"node_modules/typedarray": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
@@ -17925,6 +18043,20 @@
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
},
+ "node_modules/usehooks-ts": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/usehooks-ts/-/usehooks-ts-3.1.0.tgz",
+ "integrity": "sha512-bBIa7yUyPhE1BCc0GmR96VU/15l/9gP1Ch5mYdLcFBaFGQsdmXkvjV0TtOqW1yUd6VjIwDunm+flSciCQXujiw==",
+ "dependencies": {
+ "lodash.debounce": "^4.0.8"
+ },
+ "engines": {
+ "node": ">=16.15.0"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17 || ^18"
+ }
+ },
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
From 391dcab244286e67f17514cc9b1995d93e3cba73 Mon Sep 17 00:00:00 2001
From: JavidSumra
Date: Thu, 17 Oct 2024 15:26:45 +0530
Subject: [PATCH 4/9] fix: prevent isDirty from updating on load due to phone
number validation
---
src/Components/Users/UserProfile.tsx | 29 +++++++++++++++-------------
1 file changed, 16 insertions(+), 13 deletions(-)
diff --git a/src/Components/Users/UserProfile.tsx b/src/Components/Users/UserProfile.tsx
index a0739a4db38..d4f440f5a94 100644
--- a/src/Components/Users/UserProfile.tsx
+++ b/src/Components/Users/UserProfile.tsx
@@ -1,4 +1,4 @@
-import { useState, useReducer, FormEvent, useEffect } from "react";
+import { useState, useReducer, FormEvent } from "react";
import { GENDER_TYPES } from "../../Common/constants";
import { validateEmailAddress } from "../../Common/validation";
import * as Notification from "../../Utils/Notifications.js";
@@ -117,8 +117,7 @@ export default function UserProfile() {
isChecking: false,
isUpdateAvailable: false,
});
- const [hasChanges, setHasChanges] = useState(false);
- const [isFieldLoaded, setIsFieldLoaded] = useState(false);
+ const [dirty, setDirty] = useState(false);
const authUser = useAuthUser();
@@ -174,7 +173,7 @@ export default function UserProfile() {
type: "set_form",
form: formData,
});
- setHasChanges(false);
+ setDirty(false);
},
});
@@ -323,21 +322,25 @@ export default function UserProfile() {
};
const handleFieldChange = (event: FieldChangeEvent) => {
+ console.log(event);
+ console.log(userData);
dispatch({
type: "set_form",
form: { ...states.form, [event.name]: event.value },
});
- setIsFieldLoaded(true);
- };
- useEffect(() => {
- if (showEdit && isFieldLoaded) {
- setHasChanges(true);
+ const isMobileNumberModified =
+ (event.name === "phoneNumber" || event.name === "altPhoneNumber") &&
+ (event.value == userData?.alt_phone_number ||
+ event.value == userData?.phone_number);
+
+ if (isMobileNumberModified) {
+ console.log(states.form);
+ setDirty(false);
} else {
- setIsFieldLoaded(false);
- setHasChanges(false);
+ setDirty(true);
}
- }, [handleFieldChange]);
+ };
const getDate = (value: any) =>
value && dayjs(value).isValid() && dayjs(value).toDate();
@@ -804,7 +807,7 @@ export default function UserProfile() {
From e39adc5b93d620f510b3ba1520c26f247688771e Mon Sep 17 00:00:00 2001
From: JavidSumra
Date: Thu, 17 Oct 2024 15:29:47 +0530
Subject: [PATCH 5/9] removed unnecessary console logging
---
src/Components/Users/UserProfile.tsx | 3 ---
1 file changed, 3 deletions(-)
diff --git a/src/Components/Users/UserProfile.tsx b/src/Components/Users/UserProfile.tsx
index d4f440f5a94..f3e2a78ef57 100644
--- a/src/Components/Users/UserProfile.tsx
+++ b/src/Components/Users/UserProfile.tsx
@@ -322,8 +322,6 @@ export default function UserProfile() {
};
const handleFieldChange = (event: FieldChangeEvent) => {
- console.log(event);
- console.log(userData);
dispatch({
type: "set_form",
form: { ...states.form, [event.name]: event.value },
@@ -335,7 +333,6 @@ export default function UserProfile() {
event.value == userData?.phone_number);
if (isMobileNumberModified) {
- console.log(states.form);
setDirty(false);
} else {
setDirty(true);
From 1c3c76932fc97b26c9aab6786b3d50f5524cc397 Mon Sep 17 00:00:00 2001
From: JavidSumra
Date: Thu, 17 Oct 2024 20:16:49 +0530
Subject: [PATCH 6/9] fix: removed 'useEffect' from 'PhoneNumberFormField.tsx'
Component
---
.../Form/FormFields/PhoneNumberFormField.tsx | 4 ----
src/Components/Users/UserProfile.tsx | 12 +-----------
2 files changed, 1 insertion(+), 15 deletions(-)
diff --git a/src/Components/Form/FormFields/PhoneNumberFormField.tsx b/src/Components/Form/FormFields/PhoneNumberFormField.tsx
index c46d2690ad3..ccdf1799fbc 100644
--- a/src/Components/Form/FormFields/PhoneNumberFormField.tsx
+++ b/src/Components/Form/FormFields/PhoneNumberFormField.tsx
@@ -92,10 +92,6 @@ export default function PhoneNumberFormField(props: Props) {
}
}, [setValue]);
- useEffect(() => {
- setValue(field.value || "+91");
- }, []);
-
return (
From 7700550ba51f583b97f7415bb1d343d702d90835 Mon Sep 17 00:00:00 2001
From: JavidSumra
Date: Tue, 22 Oct 2024 04:12:59 +0530
Subject: [PATCH 7/9] fix: Update a condition to check falsy value
---
src/Components/Form/FormFields/PhoneNumberFormField.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/Components/Form/FormFields/PhoneNumberFormField.tsx b/src/Components/Form/FormFields/PhoneNumberFormField.tsx
index ccdf1799fbc..270ad00e9bb 100644
--- a/src/Components/Form/FormFields/PhoneNumberFormField.tsx
+++ b/src/Components/Form/FormFields/PhoneNumberFormField.tsx
@@ -178,7 +178,7 @@ const formatPhoneNumber = (
value: string | undefined,
types: PhoneNumberType[],
) => {
- if (value == null) {
+ if (!value) {
return "+91 ";
}
From 950ce0aa9ad87c9d0e4cb82e07d1038001094ca0 Mon Sep 17 00:00:00 2001
From: JavidSumra
Date: Tue, 22 Oct 2024 21:03:59 +0530
Subject: [PATCH 8/9] fix style for overflow export button
---
src/Components/Patient/ManagePatients.tsx | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/src/Components/Patient/ManagePatients.tsx b/src/Components/Patient/ManagePatients.tsx
index c6bc3352115..5f5f4876e86 100644
--- a/src/Components/Patient/ManagePatients.tsx
+++ b/src/Components/Patient/ManagePatients.tsx
@@ -838,7 +838,7 @@ export const PatientManager = () => {
-
+
{
}}
>
- Doctor Connect
+ Doctor Connect
)}
@@ -913,7 +913,6 @@ export const PatientManager = () => {
className="mr-5 w-full lg:w-fit"
>
- Export
) : (
Date: Sat, 26 Oct 2024 15:18:45 +0530
Subject: [PATCH 9/9] changing track files
---
src/components/Users/UserProfile.tsx | 1023 ++++++++++++++++++++++++++
1 file changed, 1023 insertions(+)
create mode 100644 src/components/Users/UserProfile.tsx
diff --git a/src/components/Users/UserProfile.tsx b/src/components/Users/UserProfile.tsx
new file mode 100644
index 00000000000..7aa3c9eff34
--- /dev/null
+++ b/src/components/Users/UserProfile.tsx
@@ -0,0 +1,1023 @@
+import { useState, useReducer, FormEvent } from "react";
+import { GENDER_TYPES, LocalStorageKeys } from "@/common/constants";
+import { validateEmailAddress } from "@/common/validation";
+import * as Notification from "../../Utils/Notifications";
+import LanguageSelector from "@/components/Common/LanguageSelector";
+import TextFormField from "../Form/FormFields/TextFormField";
+import ButtonV2, { Submit } from "@/components/Common/components/ButtonV2";
+import {
+ classNames,
+ dateQueryString,
+ formatDate,
+ formatDisplayName,
+ isValidUrl,
+ parsePhoneNumber,
+ sleep,
+} from "@/Utils/utils";
+import CareIcon from "../../CAREUI/icons/CareIcon";
+import PhoneNumberFormField from "../Form/FormFields/PhoneNumberFormField";
+import { FieldChangeEvent } from "../Form/FormFields/Utils";
+import { SelectFormField } from "../Form/FormFields/SelectFormField";
+import { GenderType, SkillModel, UpdatePasswordForm } from "./models";
+import UpdatableApp, { checkForUpdate } from "@/components/Common/UpdatableApp";
+import dayjs from "../../Utils/dayjs";
+import useAuthUser, { useAuthContext } from "@/common/hooks/useAuthUser";
+import { PhoneNumberValidator } from "../Form/FieldValidators";
+import useQuery from "../../Utils/request/useQuery";
+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";
+import AvatarEditable from "@/components/Common/AvatarEditable";
+import Page from "@/components/Common/components/Page";
+import Loading from "@/components/Common/Loading";
+import AvatarEditModal from "@/components/Common/AvatarEditModal";
+import uploadFile from "@/Utils/request/uploadFile";
+import careConfig from "@careConfig";
+
+type EditForm = {
+ firstName: string;
+ lastName: string;
+ date_of_birth: Date | null | string;
+ gender: GenderType;
+ email: string;
+ video_connect_link: string | undefined;
+ phoneNumber: string;
+ altPhoneNumber: string;
+ user_type: string | undefined;
+ qualification: string | undefined;
+ doctor_experience_commenced_on: number | string | undefined;
+ doctor_medical_council_registration: string | undefined;
+ weekly_working_hours: string | null | undefined;
+};
+type ErrorForm = {
+ firstName: string;
+ lastName: string;
+ date_of_birth: string | null;
+ gender: string;
+ email: string;
+ video_connect_link: string | undefined;
+ phoneNumber: string;
+ altPhoneNumber: string;
+ user_type: string | undefined;
+ qualification: string | undefined;
+ doctor_experience_commenced_on: number | string | undefined;
+ doctor_medical_council_registration: string | undefined;
+ weekly_working_hours: string | undefined;
+};
+type State = {
+ form: EditForm;
+ errors: ErrorForm;
+};
+type Action =
+ | { type: "set_form"; form: EditForm }
+ | { type: "set_error"; errors: ErrorForm };
+
+const initForm: EditForm = {
+ firstName: "",
+ lastName: "",
+ date_of_birth: null,
+ gender: "Male",
+ video_connect_link: "",
+ email: "",
+ phoneNumber: "",
+ altPhoneNumber: "",
+ user_type: "",
+ qualification: undefined,
+ doctor_experience_commenced_on: undefined,
+ doctor_medical_council_registration: undefined,
+ weekly_working_hours: undefined,
+};
+
+const initError: ErrorForm = Object.assign(
+ {},
+ ...Object.keys(initForm).map((k) => ({ [k]: "" })),
+);
+
+const initialState: State = {
+ form: { ...initForm },
+ errors: { ...initError },
+};
+
+const editFormReducer = (state: State, action: Action) => {
+ switch (action.type) {
+ case "set_form": {
+ return {
+ ...state,
+ form: action.form,
+ };
+ }
+ case "set_error": {
+ return {
+ ...state,
+ errors: action.errors,
+ };
+ }
+ }
+};
+
+export default function UserProfile() {
+ const { t } = useTranslation();
+ const { signOut, refetchUser } = useAuthContext();
+ const [states, dispatch] = useReducer(editFormReducer, initialState);
+ const [editAvatar, setEditAvatar] = useState(false);
+ const [updateStatus, setUpdateStatus] = useState({
+ isChecking: false,
+ isUpdateAvailable: false,
+ });
+ const [dirty, setDirty] = useState(false);
+
+ const authUser = useAuthUser();
+
+ const [changePasswordForm, setChangePasswordForm] = useState<{
+ username: string;
+ old_password: string;
+ new_password_1: string;
+ new_password_2: string;
+ }>({
+ username: authUser.username,
+ old_password: "",
+ new_password_1: "",
+ new_password_2: "",
+ });
+
+ const [changePasswordErrors] = useState<{
+ old_password: string;
+ password_confirmation: string;
+ }>({
+ old_password: "",
+ password_confirmation: "",
+ });
+
+ const [showEdit, setShowEdit] = useState(false);
+ const {
+ data: userData,
+ loading: isUserLoading,
+ refetch: refetchUserData,
+ } = useQuery(routes.currentUser, {
+ onResponse: (result) => {
+ if (!result || !result.res || !result.data) return;
+
+ const formData: EditForm = {
+ firstName: result.data.first_name,
+ lastName: result.data.last_name,
+ date_of_birth: result.data.date_of_birth || null,
+ gender: result.data.gender || "Male",
+ email: result.data.email,
+ video_connect_link: result.data.video_connect_link,
+ phoneNumber: result.data.phone_number?.toString() || "",
+ altPhoneNumber: result.data.alt_phone_number?.toString() || "",
+ user_type: result.data.user_type,
+ qualification: result.data.qualification,
+ doctor_experience_commenced_on: dayjs().diff(
+ dayjs(result.data.doctor_experience_commenced_on),
+ "years",
+ ),
+ doctor_medical_council_registration:
+ result.data.doctor_medical_council_registration,
+ weekly_working_hours: result.data.weekly_working_hours,
+ };
+ dispatch({
+ type: "set_form",
+ form: formData,
+ });
+ setDirty(false);
+ },
+ });
+
+ const { data: skillsView, loading: isSkillsLoading } = useQuery(
+ routes.userListSkill,
+ {
+ pathParams: { username: authUser.username },
+ },
+ );
+
+ const validateNewPassword = (password: string) => {
+ if (
+ password.length < 8 ||
+ !/\d/.test(password) ||
+ password === password.toUpperCase() ||
+ password === password.toLowerCase()
+ ) {
+ return false;
+ }
+ return true;
+ };
+
+ const validateForm = () => {
+ const errors = { ...initError };
+ let invalidForm = false;
+ Object.keys(states.form).forEach((field) => {
+ switch (field) {
+ case "firstName":
+ case "lastName":
+ case "gender":
+ if (!states.form[field]) {
+ errors[field] = t("field_required");
+ invalidForm = true;
+ }
+ return;
+ case "date_of_birth":
+ if (!states.form[field]) {
+ errors[field] = "Enter a valid date of birth";
+ invalidForm = true;
+ } else if (
+ !dayjs(states.form[field]).isValid() ||
+ dayjs(states.form[field]).isAfter(dayjs().subtract(17, "year"))
+ ) {
+ errors[field] = "Enter a valid date of birth";
+ invalidForm = true;
+ }
+ return;
+ case "phoneNumber":
+ // eslint-disable-next-line no-case-declarations
+ const phoneNumber = parsePhoneNumber(states.form[field]);
+
+ // eslint-disable-next-line no-case-declarations
+ let is_valid = false;
+ if (phoneNumber) {
+ is_valid = PhoneNumberValidator()(phoneNumber) === undefined;
+ }
+
+ if (!states.form[field] || !is_valid) {
+ errors[field] = "Please enter valid phone number";
+ invalidForm = true;
+ }
+ return;
+ case "altPhoneNumber":
+ // eslint-disable-next-line no-case-declarations
+ let alt_is_valid = false;
+ if (states.form[field] && states.form[field] !== "+91") {
+ const altPhoneNumber = parsePhoneNumber(states.form[field]);
+ if (altPhoneNumber) {
+ alt_is_valid =
+ PhoneNumberValidator(["mobile"])(altPhoneNumber) === undefined;
+ }
+ }
+
+ if (
+ states.form[field] &&
+ states.form[field] !== "+91" &&
+ !alt_is_valid
+ ) {
+ errors[field] = "Please enter valid mobile number";
+ invalidForm = true;
+ }
+ return;
+ case "email":
+ if (!states.form[field]) {
+ errors[field] = t("field_required");
+ invalidForm = true;
+ } else if (!validateEmailAddress(states.form[field])) {
+ errors[field] = "Enter a valid email address";
+ invalidForm = true;
+ }
+ return;
+ case "doctor_experience_commenced_on":
+ if (states.form.user_type === "Doctor" && !states.form[field]) {
+ errors[field] = t("field_required");
+ invalidForm = true;
+ } else if (
+ (states.form.user_type === "Doctor" &&
+ Number(states.form.doctor_experience_commenced_on) >= 100) ||
+ Number(states.form.doctor_experience_commenced_on) < 0
+ ) {
+ errors[field] =
+ "Doctor experience should be at least 0 years and less than 100 years.";
+ invalidForm = true;
+ }
+ return;
+ case "qualification":
+ if (
+ (states.form.user_type === "Doctor" ||
+ states.form.user_type === "Nurse") &&
+ !states.form[field]
+ ) {
+ errors[field] = t("field_required");
+ invalidForm = true;
+ }
+ return;
+ case "doctor_medical_council_registration":
+ if (states.form.user_type === "Doctor" && !states.form[field]) {
+ errors[field] = t("field_required");
+ invalidForm = true;
+ }
+ return;
+ case "weekly_working_hours":
+ if (
+ states.form[field] &&
+ (Number(states.form[field]) < 0 ||
+ Number(states.form[field]) > 168 ||
+ !/^\d+$/.test(states.form[field] ?? ""))
+ ) {
+ errors[field] =
+ "Average weekly working hours must be a number between 0 and 168";
+ invalidForm = true;
+ }
+ return;
+ case "video_connect_link":
+ if (states.form[field]) {
+ if (isValidUrl(states.form[field]) === false) {
+ errors[field] = "Please enter a valid url";
+ invalidForm = true;
+ }
+ }
+ return;
+ }
+ });
+ dispatch({ type: "set_error", errors });
+ return !invalidForm;
+ };
+
+ const handleFieldChange = (event: FieldChangeEvent) => {
+ dispatch({
+ type: "set_form",
+ form: { ...states.form, [event.name]: event.value },
+ });
+ setDirty(true);
+ };
+
+ const getDate = (value: any) =>
+ value && dayjs(value).isValid() && dayjs(value).toDate();
+
+ const fieldProps = (name: string) => {
+ return {
+ name,
+ id: name,
+ value: (states.form as any)[name],
+ onChange: handleFieldChange,
+ error: (states.errors as any)[name],
+ };
+ };
+
+ const handleSubmit = async (e: FormEvent) => {
+ e.preventDefault();
+ const validForm = validateForm();
+ if (validForm) {
+ const data = {
+ username: authUser.username,
+ first_name: states.form.firstName,
+ last_name: states.form.lastName,
+ email: states.form.email,
+ video_connect_link: states.form.video_connect_link,
+ phone_number: parsePhoneNumber(states.form.phoneNumber) ?? "",
+ alt_phone_number: parsePhoneNumber(states.form.altPhoneNumber) ?? "",
+ gender: states.form.gender,
+ date_of_birth: dateQueryString(states.form.date_of_birth),
+ qualification:
+ states.form.user_type === "Doctor" ||
+ states.form.user_type === "Nurse"
+ ? states.form.qualification
+ : undefined,
+ doctor_experience_commenced_on:
+ states.form.user_type === "Doctor"
+ ? dayjs()
+ .subtract(
+ parseInt(
+ (states.form.doctor_experience_commenced_on as string) ??
+ "0",
+ ),
+ "years",
+ )
+ .format("YYYY-MM-DD")
+ : undefined,
+ doctor_medical_council_registration:
+ states.form.user_type === "Doctor"
+ ? states.form.doctor_medical_council_registration
+ : undefined,
+ weekly_working_hours:
+ states.form.weekly_working_hours &&
+ states.form.weekly_working_hours !== ""
+ ? states.form.weekly_working_hours
+ : null,
+ };
+ const { res } = await request(routes.partialUpdateUser, {
+ pathParams: { username: authUser.username },
+ body: data,
+ });
+ if (res?.ok) {
+ Notification.Success({
+ msg: "Details updated successfully",
+ });
+ await refetchUserData();
+ setShowEdit(false);
+ }
+ }
+ };
+
+ const isLoading = isUserLoading || isSkillsLoading;
+
+ if (isLoading) {
+ return ;
+ }
+
+ const checkUpdates = async () => {
+ setUpdateStatus({ ...updateStatus, isChecking: true });
+ await new Promise((resolve) => setTimeout(resolve, 500));
+ if ((await checkForUpdate()) != null) {
+ setUpdateStatus({
+ isUpdateAvailable: true,
+ isChecking: false,
+ });
+ } else {
+ setUpdateStatus({
+ isUpdateAvailable: false,
+ isChecking: false,
+ });
+ Notification.Success({
+ msg: "No update available",
+ });
+ }
+ };
+
+ const changePassword = async (e: any) => {
+ e.preventDefault();
+ //validating form
+ if (
+ changePasswordForm.new_password_1 !== changePasswordForm.new_password_2
+ ) {
+ Notification.Error({
+ msg: "Passwords are different in new password and confirmation password column.",
+ });
+ } else if (!validateNewPassword(changePasswordForm.new_password_1)) {
+ Notification.Error({
+ msg: "Entered New Password is not valid, please check!",
+ });
+ } else if (
+ changePasswordForm.new_password_1 === changePasswordForm.old_password
+ ) {
+ Notification.Error({
+ msg: "New password is same as old password, Please enter a different new password.",
+ });
+ } else {
+ const form: UpdatePasswordForm = {
+ old_password: changePasswordForm.old_password,
+ username: authUser.username,
+ new_password: changePasswordForm.new_password_1,
+ };
+ const { res, data, error } = await request(routes.updatePassword, {
+ body: form,
+ });
+ if (res?.ok) {
+ Notification.Success({ msg: data?.message });
+ } else if (!error) {
+ Notification.Error({
+ msg: "There was some error. Please try again in some time.",
+ });
+ }
+ setChangePasswordForm({
+ ...changePasswordForm,
+ new_password_1: "",
+ new_password_2: "",
+ old_password: "",
+ });
+ }
+ };
+
+ const handleAvatarUpload = async (file: File, onError: () => void) => {
+ const formData = new FormData();
+ formData.append("profile_picture", file);
+ const url = `${careConfig.apiUrl}/api/v1/users/${authUser.username}/profile_picture/`;
+
+ uploadFile(
+ url,
+ formData,
+ "POST",
+ {
+ Authorization:
+ "Bearer " + localStorage.getItem(LocalStorageKeys.accessToken),
+ },
+ async (xhr: XMLHttpRequest) => {
+ if (xhr.status === 200) {
+ await sleep(1000);
+ refetchUser();
+ Notification.Success({ msg: "Profile picture updated." });
+ setEditAvatar(false);
+ }
+ },
+ null,
+ () => {
+ onError();
+ },
+ );
+ };
+
+ const handleAvatarDelete = async (onError: () => void) => {
+ const { res } = await request(routes.deleteProfilePicture, {
+ pathParams: { username: authUser.username },
+ });
+ if (res?.ok) {
+ Notification.Success({ msg: "Profile picture deleted" });
+ await refetchUser();
+ setEditAvatar(false);
+ } else {
+ onError();
+ }
+ };
+
+ return (
+
+ setEditAvatar(false)}
+ />
+
+
+
+ {t("local_body")}, {t("district")}, {t("state")}{" "}
+ {t("are_non_editable_fields")}.
+
+
+
setEditAvatar(!editAvatar)}
+ className="h-20 w-20"
+ />
+
+
+ {authUser?.first_name} {authUser?.last_name}
+
+
+ @{authUser?.username}
+
+
+
+
+ setShowEdit(!showEdit)}
+ type="button"
+ id="edit-cancel-profile-button"
+ >
+ {showEdit ? t("cancel") : t("edit_user_profile")}
+
+
+
+ {t("sign_out")}
+
+
+
+
+ {!showEdit && !isLoading && (
+
+
+
+
-
+ {t("username")}
+
+ -
+ {userData?.username || "-"}
+
+
+
+
-
+ {t("phone_number")}
+
+ -
+ {userData?.phone_number || "-"}
+
+
+
+
+
-
+ {t("whatsapp_number")}
+
+ -
+ {userData?.alt_phone_number || "-"}
+
+
+
+
-
+ {t("email")}
+
+ -
+ {userData?.email || "-"}
+
+
+
+
-
+ {t("first_name")}
+
+ -
+ {userData?.first_name || "-"}
+
+
+
+
-
+ {t("last_name")}
+
+ -
+ {userData?.last_name || "-"}
+
+
+
+
-
+ {t("date_of_birth")}
+
+ -
+ {userData?.date_of_birth
+ ? formatDate(userData?.date_of_birth)
+ : "-"}
+
+
+
+
-
+ {t("access_level")}
+
+ -
+
+ {userData?.user_type || "-"}
+
+
+
+
-
+ {t("gender")}
+
+ -
+ {userData?.gender || "-"}
+
+
+
+
-
+ {t("local_body")}
+
+ -
+ {userData?.local_body_object?.name || "-"}
+
+
+
+
-
+ {t("district")}
+
+ -
+ {userData?.district_object?.name || "-"}
+
+
+
+
-
+ {t("state")}
+
+ -
+ {userData?.state_object?.name || "-"}
+
+
+
+
-
+ {t("skills")}
+
+
-
+
+ {skillsView?.results?.length
+ ? skillsView.results?.map((skill: SkillModel) => {
+ return (
+
+
+ {skill.skill_object.name}
+
+
+ );
+ })
+ : "-"}
+
+
+
+
+
-
+ {t("average_weekly_working_hours")}
+
+ -
+ {userData?.weekly_working_hours ?? "-"}
+
+
+
+
+
+ )}
+ {showEdit && (
+
+ )}
+
+
+
+
+
+
+
+ {t("language_selection")}
+
+
+ {t("set_your_local_language")}
+
+
+
+
+
+
+
+
+
+
+
+ {t("software_update")}
+
+
+ {t("check_for_available_update")}
+
+
+
+ {updateStatus.isUpdateAvailable && (
+
+
+
+
+ {t("update_available")}
+
+
+
+ )}
+
+ {!updateStatus.isUpdateAvailable && (
+
+ {" "}
+
+
+ {updateStatus.isChecking
+ ? t("checking_for_update")
+ : t("check_for_update")}
+
+
+ )}
+
+
+
+ );
+}