diff --git a/src/platform/src/common/components/Dropdowns/OrganizationDropdown.jsx b/src/platform/src/common/components/Dropdowns/OrganizationDropdown.jsx index f69a688875..32e875f188 100644 --- a/src/platform/src/common/components/Dropdowns/OrganizationDropdown.jsx +++ b/src/platform/src/common/components/Dropdowns/OrganizationDropdown.jsx @@ -38,17 +38,39 @@ const OrganizationDropdown = () => { // Initialize active group if missing useEffect(() => { + // If we're still fetching, do nothing yet if (isFetchingActiveGroup) return; + const storedGroup = localStorage.getItem('activeGroup'); if (storedGroup) { - const defaultGroup = JSON.parse(storedGroup); - dispatch(setOrganizationName(defaultGroup.grp_title)); + try { + // Attempt to parse the stored group + const defaultGroup = JSON.parse(storedGroup); + + // Check if defaultGroup and its properties exist + if (defaultGroup && defaultGroup.grp_title) { + dispatch(setOrganizationName(defaultGroup.grp_title)); + } else { + // If the stored data is missing expected fields, remove it + localStorage.removeItem('activeGroup'); + console.warn( + 'activeGroup in localStorage is missing grp_title, removing it...', + ); + } + } catch (error) { + // If JSON parsing fails, remove the invalid item + console.error('Error parsing activeGroup from localStorage:', error); + localStorage.removeItem('activeGroup'); + } } else if (!activeGroupId && activeGroups.length > 0) { + // No activeGroup in localStorage, so pick the first available group const defaultGroup = activeGroups[0]; localStorage.setItem('activeGroup', JSON.stringify(defaultGroup)); - dispatch(setOrganizationName(defaultGroup.grp_title)); + if (defaultGroup && defaultGroup.grp_title) { + dispatch(setOrganizationName(defaultGroup.grp_title)); + } } - }, [activeGroupId, activeGroups, dispatch]); + }, [isFetchingActiveGroup, activeGroupId, activeGroups, dispatch]); const handleUpdatePreferences = useCallback( async (group) => { diff --git a/src/platform/src/common/components/Modal/dataDownload/modules/AddLocations.jsx b/src/platform/src/common/components/Modal/dataDownload/modules/AddLocations.jsx index 787c672f05..122e45bf5b 100644 --- a/src/platform/src/common/components/Modal/dataDownload/modules/AddLocations.jsx +++ b/src/platform/src/common/components/Modal/dataDownload/modules/AddLocations.jsx @@ -60,8 +60,18 @@ const AddLocations = ({ onClose }) => { // Retrieve user ID from localStorage and memoize it const userID = useMemo(() => { - const user = localStorage.getItem('loggedUser'); - return user ? JSON.parse(user)?._id : null; + const storedUser = localStorage.getItem('loggedUser'); + if (!storedUser) { + return null; + } + + try { + const parsedUser = JSON.parse(storedUser); + return parsedUser?._id ?? null; + } catch (error) { + console.error('Error parsing loggedUser from localStorage:', error); + return null; + } }, []); /** diff --git a/src/platform/src/common/components/Modal/dataDownload/modules/SelectMore.jsx b/src/platform/src/common/components/Modal/dataDownload/modules/SelectMore.jsx index 89bb6c6f30..2b8a6570b7 100644 --- a/src/platform/src/common/components/Modal/dataDownload/modules/SelectMore.jsx +++ b/src/platform/src/common/components/Modal/dataDownload/modules/SelectMore.jsx @@ -60,8 +60,18 @@ const SelectMore = ({ onClose }) => { // Retrieve user ID from localStorage and memoize it const userID = useMemo(() => { - const user = localStorage.getItem('loggedUser'); - return user ? JSON.parse(user)?._id : null; + const storedUser = localStorage.getItem('loggedUser'); + if (!storedUser) { + return null; + } + + try { + const parsedUser = JSON.parse(storedUser); + return parsedUser?._id ?? null; + } catch (error) { + console.error('Error parsing "loggedUser" from localStorage:', error); + return null; + } }, []); // Extract selected site IDs from user preferences diff --git a/src/platform/src/common/components/Settings/Teams/InviteForm.jsx b/src/platform/src/common/components/Settings/Teams/InviteForm.jsx index 82730159e2..73c80b22d3 100644 --- a/src/platform/src/common/components/Settings/Teams/InviteForm.jsx +++ b/src/platform/src/common/components/Settings/Teams/InviteForm.jsx @@ -61,7 +61,8 @@ const TeamInviteForm = ({ open, closeModal }) => { const handleSubmit = (e) => { e.preventDefault(); - if (emails[0] === '') { + // Basic validation: check if the first email input is empty + if (!emails[0]) { setIsError({ isError: true, message: 'Please enter an email', @@ -71,45 +72,84 @@ const TeamInviteForm = ({ open, closeModal }) => { } setLoading(true); + + // Check if all emails are valid const isValid = emails.every((email) => isValidEmail(email)); if (isValid) { + // Safely retrieve and parse 'activeGroup' from localStorage + const storedActiveGroup = localStorage.getItem('activeGroup'); + if (!storedActiveGroup) { + // If it's not found, handle accordingly + setIsError({ + isError: true, + message: 'No active group found in localStorage', + type: 'error', + }); + setLoading(false); + return; + } + + let activeGroup; try { - const activeGroup = JSON.parse(localStorage.getItem('activeGroup')); - if (!activeGroup) { - throw new Error('No active group found'); - } - inviteUserToGroupTeam(activeGroup._id, emails) - .then((response) => { - setIsError({ - isError: true, - message: response.message, - type: 'success', - }); - - setTimeout(() => { - setLoading(false); - setEmails(['']); - setEmailErrors([]); - closeModal(); - }, 3000); - }) - .catch((error) => { - setIsError({ - isError: true, - message: error?.response?.data?.errors?.message, - type: 'error', - }); - setLoading(false); - }); + activeGroup = JSON.parse(storedActiveGroup); } catch (error) { - console.error(error); + console.error('Error parsing "activeGroup" from localStorage:', error); + setIsError({ + isError: true, + message: 'Invalid data in localStorage for "activeGroup"', + type: 'error', + }); + // Optionally remove the invalid item to prevent repeated errors + // localStorage.removeItem('activeGroup'); + setLoading(false); + return; + } + + if (!activeGroup || !activeGroup._id) { + setIsError({ + isError: true, + message: 'No valid active group found', + type: 'error', + }); setLoading(false); return; } + + // Proceed with your invite action + inviteUserToGroupTeam(activeGroup._id, emails) + .then((response) => { + setIsError({ + isError: true, + message: response.message, + type: 'success', + }); + + setTimeout(() => { + setLoading(false); + setEmails(['']); + setEmailErrors([]); + closeModal(); + }, 3000); + }) + .catch((error) => { + setIsError({ + isError: true, + message: + error?.response?.data?.errors?.message || 'Something went wrong', + type: 'error', + }); + setLoading(false); + }); } else { - // Display an error message or handle invalid emails + // Handle invalid emails + setLoading(false); console.log('Invalid emails:', emailErrors); + setIsError({ + isError: true, + message: 'One or more emails are invalid', + type: 'error', + }); } }; diff --git a/src/platform/src/common/components/SideBar/AuthenticatedSidebar.jsx b/src/platform/src/common/components/SideBar/AuthenticatedSidebar.jsx index 248f4bdd24..d4e2d5f978 100644 --- a/src/platform/src/common/components/SideBar/AuthenticatedSidebar.jsx +++ b/src/platform/src/common/components/SideBar/AuthenticatedSidebar.jsx @@ -72,9 +72,27 @@ const AuthenticatedSideBar = () => { const collocationOpenState = localStorage.getItem('collocationOpen'); const analyticsOpenState = localStorage.getItem('analyticsOpen'); - if (collocationOpenState) - setCollocationOpen(JSON.parse(collocationOpenState)); - if (analyticsOpenState) setAnalyticsOpen(JSON.parse(analyticsOpenState)); + if (collocationOpenState) { + try { + setCollocationOpen(JSON.parse(collocationOpenState)); + } catch (error) { + console.error( + 'Error parsing "collocationOpen" from localStorage:', + error, + ); + } + } + + if (analyticsOpenState) { + try { + setAnalyticsOpen(JSON.parse(analyticsOpenState)); + } catch (error) { + console.error( + 'Error parsing "analyticsOpen" from localStorage:', + error, + ); + } + } }, []); // Save dropdown states to localStorage diff --git a/src/platform/src/common/components/SideBar/SideBarDrawer.jsx b/src/platform/src/common/components/SideBar/SideBarDrawer.jsx index 0c8f97eb36..5be505e844 100644 --- a/src/platform/src/common/components/SideBar/SideBarDrawer.jsx +++ b/src/platform/src/common/components/SideBar/SideBarDrawer.jsx @@ -25,9 +25,21 @@ const SideBarDrawer = () => { const router = useRouter(); const userInfo = useSelector((state) => state.login.userInfo); const [isLoading, setIsLoading] = useState(false); - const [collocationOpen, setCollocationOpen] = useState(() => - JSON.parse(localStorage.getItem('collocationOpen') || 'false'), - ); + const [collocationOpen, setCollocationOpen] = useState(() => { + try { + const storedValue = localStorage.getItem('collocationOpen'); + if (!storedValue || storedValue === 'undefined') { + return false; + } + return JSON.parse(storedValue); + } catch (error) { + console.error( + 'Error parsing "collocationOpen" from localStorage:', + error, + ); + return false; + } + }); const drawerClasses = useMemo( () => (togglingDrawer ? 'w-72' : 'w-0'), diff --git a/src/platform/src/core/utils/protectedRoute.js b/src/platform/src/core/utils/protectedRoute.js index 7df4e81298..902c9f2296 100644 --- a/src/platform/src/core/utils/protectedRoute.js +++ b/src/platform/src/core/utils/protectedRoute.js @@ -35,11 +35,20 @@ export const withPermission = (Component, requiredPermission) => { useEffect(() => { if (typeof window !== 'undefined') { const storedUserGroup = localStorage.getItem('activeGroup'); - const parsedUserGroup = storedUserGroup - ? JSON.parse(storedUserGroup) - : {}; - const currentRole = parsedUserGroup?.role; + let parsedUserGroup = {}; + + if (storedUserGroup) { + try { + parsedUserGroup = JSON.parse(storedUserGroup); + } catch (error) { + console.error( + 'Error parsing "activeGroup" from localStorage:', + error, + ); + } + } + const currentRole = parsedUserGroup?.role; const hasPermission = currentRole?.role_permissions?.some( (permission) => permission.permission === requiredPermission, ); @@ -57,13 +66,22 @@ export const withPermission = (Component, requiredPermission) => { export const checkAccess = (requiredPermission) => { if (requiredPermission && typeof window !== 'undefined') { const storedGroupObj = localStorage.getItem('activeGroup'); - const currentRole = storedGroupObj ? JSON.parse(storedGroupObj).role : null; + let currentRole = null; + + if (storedGroupObj) { + try { + const parsedGroup = JSON.parse(storedGroupObj); + currentRole = parsedGroup?.role || null; + } catch (error) { + console.error('Error parsing "activeGroup" from localStorage:', error); + } + } const permissions = currentRole?.role_permissions?.map( (item) => item.permission, ); - return permissions?.includes(requiredPermission) ?? false; } + return false; }; diff --git a/src/platform/src/pages/Home/index.jsx b/src/platform/src/pages/Home/index.jsx index d2457eb2cf..b5d9f6775a 100644 --- a/src/platform/src/pages/Home/index.jsx +++ b/src/platform/src/pages/Home/index.jsx @@ -58,6 +58,28 @@ const createSteps = (handleModal, handleCardClick) => [ }, ]; +const useUserData = () => { + const userData = useMemo(() => { + if (typeof window === 'undefined') { + return null; + } + + const storedUser = localStorage.getItem('loggedUser'); + if (!storedUser || storedUser === 'undefined') { + return null; + } + + try { + return JSON.parse(storedUser); + } catch (error) { + console.error('Error parsing "loggedUser" from localStorage:', error); + return null; + } + }, []); + + return userData; +}; + const Home = () => { const dispatch = useDispatch(); @@ -72,18 +94,7 @@ const Home = () => { const totalSteps = 4; // Safely retrieve user data from localStorage - const userData = useMemo(() => { - if (typeof window !== 'undefined') { - const storedUser = localStorage.getItem('loggedUser'); - try { - return storedUser ? JSON.parse(storedUser) : null; - } catch (error) { - console.error('Error parsing user data from localStorage:', error); - return null; - } - } - return null; - }, []); + const userData = useUserData(); // Handlers const handleModal = useCallback(() => { diff --git a/src/platform/src/pages/settings/Tabs/OrganizationProfile.jsx b/src/platform/src/pages/settings/Tabs/OrganizationProfile.jsx index 09b6551f50..d0258cb28a 100644 --- a/src/platform/src/pages/settings/Tabs/OrganizationProfile.jsx +++ b/src/platform/src/pages/settings/Tabs/OrganizationProfile.jsx @@ -83,19 +83,30 @@ const OrganizationProfile = () => { useEffect(() => { setLoading(true); + + let activeGroupId = null; const storedActiveGroup = localStorage.getItem('activeGroup'); - const storedActiveGroupID = - storedActiveGroup && JSON.parse(storedActiveGroup)._id; - // get group information - try { - dispatch(fetchGroupInfo(storedActiveGroupID)); - } catch (error) { - console.error(`Error fetching group info: ${error}`); - } finally { - setLoading(false); + if (storedActiveGroup) { + try { + const parsedActiveGroup = JSON.parse(storedActiveGroup); + activeGroupId = parsedActiveGroup?._id || null; + } catch (error) { + console.error('Error parsing "activeGroup" from localStorage:', error); + } } - }, []); + + // If we have a valid ID, fetch group info + if (activeGroupId) { + try { + dispatch(fetchGroupInfo(activeGroupId)); + } catch (error) { + console.error(`Error fetching group info: ${error}`); + } + } + + setLoading(false); + }, [dispatch]); useEffect(() => { if (orgInfo) { @@ -118,19 +129,36 @@ const OrganizationProfile = () => { const handleSubmit = (e) => { e.preventDefault(); setLoading(true); + + // Safely parse 'activeGroup' from localStorage + let activeGroupId = null; const storedActiveGroup = localStorage.getItem('activeGroup'); - const storedActiveGroupID = - storedActiveGroup && JSON.parse(storedActiveGroup)._id; - if (!storedActiveGroupID) { + + if (storedActiveGroup) { + try { + const parsedGroup = JSON.parse(storedActiveGroup); + activeGroupId = parsedGroup?._id || null; + } catch (error) { + console.error('Error parsing "activeGroup" from localStorage:', error); + + setLoading(false); + return; + } + } + + // If no valid ID, stop here + if (!activeGroupId) { setLoading(false); return; } + try { - updateGroupDetailsApi(storedActiveGroupID, orgData) - .then((response) => { + // Update group details with the parsed ID + updateGroupDetailsApi(activeGroupId, orgData) + .then(() => { try { - dispatch(fetchGroupInfo(storedActiveGroupID)); - + // Fetch updated group info + dispatch(fetchGroupInfo(activeGroupId)); setIsError({ isError: true, message: 'Organization details successfully updated', @@ -152,6 +180,7 @@ const OrganizationProfile = () => { setLoading(false); }); } catch (error) { + // Catch any unexpected errors in the try block console.error(`Error updating user cloudinary photo: ${error}`); setIsError({ isError: true, @@ -235,7 +264,7 @@ const OrganizationProfile = () => { setUpdatedProfilePicture(croppedUrl); setOrgData({ ...orgData, grp_image: croppedUrl }); }) - .catch((error) => { + .catch(() => { setIsError({ isError: true, message: 'Something went wrong', @@ -245,78 +274,125 @@ const OrganizationProfile = () => { }; const handleProfileImageUpdate = async () => { - if (updatedProfilePicture) { - const formData = new FormData(); - formData.append('file', updatedProfilePicture); - formData.append( - 'upload_preset', - process.env.NEXT_PUBLIC_CLOUDINARY_PRESET, - ); - formData.append('folder', 'organization_profiles'); - - setProfileUploading(true); - await cloudinaryImageUpload(formData) - .then(async (responseData) => { - setOrgData({ ...orgData, grp_image: responseData.secure_url }); - const storedActiveGroup = localStorage.getItem('activeGroup'); - const storedActiveGroupID = - storedActiveGroup && JSON.parse(storedActiveGroup)._id; - - return await updateGroupDetailsApi(storedActiveGroupID, { - grp_image: responseData.secure_url, - }) - .then((responseData) => { - try { - dispatch(fetchGroupInfo(storedActiveGroupID)); - // updated user alert - setIsError({ - isError: true, - message: 'Organization image successfully added', - type: 'success', - }); - setUpdatedProfilePicture(''); - } catch (error) { - console.log(error); - } finally { - setProfileUploading(false); - } - }) - .catch((err) => { - // updated user failure alert - setIsError({ - isError: true, - message: err.message, - type: 'error', - }); - setUpdatedProfilePicture(''); - setProfileUploading(false); - }); - }) - .catch((err) => { - // unable to save image error - setUpdatedProfilePicture(''); - setProfileUploading(false); - setIsError({ - isError: true, - message: err.message, - type: 'error', - }); + if (!updatedProfilePicture) return; + + const formData = new FormData(); + formData.append('file', updatedProfilePicture); + formData.append('upload_preset', process.env.NEXT_PUBLIC_CLOUDINARY_PRESET); + formData.append('folder', 'organization_profiles'); + + setProfileUploading(true); + + try { + // 1. Upload the image to Cloudinary + const responseData = await cloudinaryImageUpload(formData); + + // 2. Update the orgData state with the new image URL + setOrgData((prev) => ({ + ...prev, + grp_image: responseData.secure_url, + })); + + // 3. Safely parse 'activeGroup' from localStorage + let activeGroupId = null; + const storedActiveGroup = localStorage.getItem('activeGroup'); + if (storedActiveGroup) { + try { + const parsedGroup = JSON.parse(storedActiveGroup); + activeGroupId = parsedGroup?._id || null; + } catch (error) { + console.error( + 'Error parsing "activeGroup" from localStorage:', + error, + ); + } + } + + // If there's no valid ID, stop here + if (!activeGroupId) { + setProfileUploading(false); + setIsError({ + isError: true, + message: 'No valid group ID found in localStorage.', + type: 'error', + }); + return; + } + + // 4. Update group details with the new image + try { + await updateGroupDetailsApi(activeGroupId, { + grp_image: responseData.secure_url, + }); + + // 5. Fetch updated group info + dispatch(fetchGroupInfo(activeGroupId)); + + // 6. Show success message + setIsError({ + isError: true, + message: 'Organization image successfully added', + type: 'success', + }); + + // 7. Reset local states + setUpdatedProfilePicture(''); + } catch (error) { + console.error('Error updating organization details:', error); + setIsError({ + isError: true, + message: error.message, + type: 'error', }); + setUpdatedProfilePicture(''); + } finally { + setProfileUploading(false); + } + } catch (error) { + // Handle any error from cloudinaryImageUpload + console.error('Error uploading to Cloudinary:', error); + setUpdatedProfilePicture(''); + setProfileUploading(false); + setIsError({ + isError: true, + message: error.message, + type: 'error', + }); } }; const deleteProfileImage = () => { + // Reset local states setUpdatedProfilePicture(''); - setOrgData({ ...orgData, grp_image: '' }); + setOrgData((prev) => ({ ...prev, grp_image: '' })); + // Safely retrieve and parse 'activeGroup' + let activeGroupId = null; const storedActiveGroup = localStorage.getItem('activeGroup'); - const storedActiveGroupID = - storedActiveGroup && JSON.parse(storedActiveGroup)._id; + if (storedActiveGroup) { + try { + const parsedGroup = JSON.parse(storedActiveGroup); + activeGroupId = parsedGroup?._id || null; + } catch (error) { + console.error('Error parsing "activeGroup" from localStorage:', error); + } + } + + // If no valid ID, we can’t proceed with API call + if (!activeGroupId) { + setIsError({ + isError: true, + message: 'No valid group ID found in localStorage.', + type: 'error', + }); + return; + } - updateGroupDetailsApi(storedActiveGroupID, { grp_image: '' }) - .then((response) => { + // Update group details with an empty image + updateGroupDetailsApi(activeGroupId, { grp_image: '' }) + .then(() => { try { - dispatch(fetchGroupInfo(storedActiveGroupID)); + dispatch(fetchGroupInfo(activeGroupId)); setShowDeleteProfileModal(false); setIsError({ isError: true, @@ -324,7 +400,7 @@ const OrganizationProfile = () => { type: 'success', }); } catch (error) { - console.log(error); + console.log('Error fetching group info:', error); } }) .catch((error) => { diff --git a/src/platform/src/pages/settings/Tabs/Profile.jsx b/src/platform/src/pages/settings/Tabs/Profile.jsx index 0f71043677..82c39450fc 100644 --- a/src/platform/src/pages/settings/Tabs/Profile.jsx +++ b/src/platform/src/pages/settings/Tabs/Profile.jsx @@ -87,23 +87,36 @@ const Profile = () => { }; useEffect(() => { - const user = JSON.parse(localStorage.getItem('loggedUser')); + // Prevent running on the server + if (typeof window === 'undefined') return; + + // Attempt to retrieve the "loggedUser" from localStorage + const storedUser = localStorage.getItem('loggedUser'); + let parsedUser = null; + + if (storedUser && storedUser !== 'undefined') { + try { + parsedUser = JSON.parse(storedUser); + } catch (error) { + console.error('Error parsing "loggedUser" from localStorage:', error); + } + } - if (user) { + // If parsing succeeded and we have user data + if (parsedUser) { if (!userInfo) { - dispatch(setUserInfo(user)); + dispatch(setUserInfo(parsedUser)); } - setUserData({ - firstName: user.firstName || '', - lastName: user.lastName || '', - email: user.email || '', - phone: user.phone || '', - jobTitle: user.jobTitle || '', - country: user.country || '', - timezone: user.timezone || '', - description: user.description || '', - profilePicture: user.profilePicture || '', + firstName: parsedUser.firstName || '', + lastName: parsedUser.lastName || '', + email: parsedUser.email || '', + phone: parsedUser.phone || '', + jobTitle: parsedUser.jobTitle || '', + country: parsedUser.country || '', + timezone: parsedUser.timezone || '', + description: parsedUser.description || '', + profilePicture: parsedUser.profilePicture || '', }); } else { setIsError({ @@ -112,7 +125,7 @@ const Profile = () => { type: 'error', }); } - }, []); + }, [userInfo, dispatch]); const handleChange = (e) => { setUserData({ ...userData, [e.target.id]: e.target.value }); @@ -122,27 +135,49 @@ const Profile = () => { e.preventDefault(); setLoading(true); - const loggedUser = JSON.parse(localStorage.getItem('loggedUser')); + // Safely parse the "loggedUser" from localStorage + let loggedUser = null; + const storedUser = localStorage.getItem('loggedUser'); + + if (storedUser && storedUser !== 'undefined') { + try { + loggedUser = JSON.parse(storedUser); + } catch (error) { + console.error('Error parsing "loggedUser" from localStorage:', error); + + setLoading(false); + return; + } + } + + // If we still don't have a valid user, stop here if (!loggedUser) { setLoading(false); return; } const { _id: userID } = loggedUser; + try { + // 1. Update user creation details await updateUserCreationDetails(userData, userID); + // 2. Retrieve updated user info from the server const res = await getUserDetails(userID, userToken); - const updatedUser = res.users[0]; + const updatedUser = res?.users?.[0]; if (!updatedUser) { throw new Error('User details not updated'); } + // 3. Merge the updated user info with the ID const updatedData = { _id: userID, ...updatedUser }; + + // 4. Store the updated user data in localStorage and Redux localStorage.setItem('loggedUser', JSON.stringify(updatedData)); dispatch(setUserInfo(updatedData)); + // 5. Optional: Check if certain fields are present for profile completion if ( userData.firstName && userData.lastName && @@ -153,6 +188,7 @@ const Profile = () => { handleProfileCompletion(3); } + // 6. Show success message setIsError({ isError: true, message: 'User details successfully updated', @@ -171,17 +207,44 @@ const Profile = () => { }; const handleCancel = () => { - const user = JSON.parse(localStorage.getItem('loggedUser')); + // Safely parse the "loggedUser" from localStorage + let parsedUser = null; + const storedUser = localStorage.getItem('loggedUser'); + if (storedUser && storedUser !== 'undefined') { + try { + parsedUser = JSON.parse(storedUser); + } catch (error) { + console.error('Error parsing "loggedUser" from localStorage:', error); + } + } + + // If no valid user, reset to empty fields or handle accordingly + if (!parsedUser) { + setUserData({ + firstName: '', + lastName: '', + email: '', + phone: '', + jobTitle: '', + country: '', + timezone: '', + description: '', + profilePicture: '', + }); + return; + } + + // Update local state with user data setUserData({ - firstName: user.firstName || '', - lastName: user.lastName || '', - email: user.email || '', - phone: user.phone || '', - jobTitle: user.jobTitle || '', - country: user.country || '', - timezone: user.timezone || '', - description: user.description || '', - profilePicture: user.profilePicture || '', + firstName: parsedUser.firstName || '', + lastName: parsedUser.lastName || '', + email: parsedUser.email || '', + phone: parsedUser.phone || '', + jobTitle: parsedUser.jobTitle || '', + country: parsedUser.country || '', + timezone: parsedUser.timezone || '', + description: parsedUser.description || '', + profilePicture: parsedUser.profilePicture || '', }); }; @@ -246,7 +309,7 @@ const Profile = () => { setUpdatedProfilePicture(croppedUrl); setUserData({ ...userData, profilePicture: croppedUrl }); }) - .catch((error) => { + .catch(() => { setIsError({ isError: true, message: 'Something went wrong', @@ -256,75 +319,111 @@ const Profile = () => { }; const handleProfileImageUpdate = async () => { - if (updatedProfilePicture) { - const formData = new FormData(); - formData.append('file', updatedProfilePicture); - formData.append( - 'upload_preset', - process.env.NEXT_PUBLIC_CLOUDINARY_PRESET, + if (!updatedProfilePicture) return; + + const formData = new FormData(); + formData.append('file', updatedProfilePicture); + formData.append('upload_preset', process.env.NEXT_PUBLIC_CLOUDINARY_PRESET); + formData.append('folder', 'profiles'); + + setProfileUploading(true); + + try { + // 1. Upload to Cloudinary + const responseData = await cloudinaryImageUpload(formData); + + // 2. Update local userData state + setUserData((prev) => ({ + ...prev, + profilePicture: responseData.secure_url, + })); + + // 3. Safely parse "loggedUser" for user ID + let userID = null; + const storedUser = localStorage.getItem('loggedUser'); + if (storedUser && storedUser !== 'undefined') { + try { + const parsedUser = JSON.parse(storedUser); + userID = parsedUser?._id || null; + } catch (error) { + console.error('Error parsing "loggedUser" from localStorage:', error); + // localStorage.removeItem('loggedUser'); + } + } + + if (!userID) { + throw new Error('No valid user ID found in localStorage'); + } + + // 4. Update user details with the new profile picture + await updateUserCreationDetails( + { profilePicture: responseData.secure_url }, + userID, ); - formData.append('folder', 'profiles'); - - setProfileUploading(true); - await cloudinaryImageUpload(formData) - .then(async (responseData) => { - setUserData({ ...userData, profilePicture: responseData.secure_url }); - const userID = JSON.parse(localStorage.getItem('loggedUser'))?._id; - return await updateUserCreationDetails( - { profilePicture: responseData.secure_url }, - userID, - ) - .then((responseData) => { - localStorage.setItem( - 'loggedUser', - JSON.stringify({ _id: userID, ...userData }), - ); - dispatch(setUserInfo({ _id: userID, ...userData })); - // updated user alert - setIsError({ - isError: true, - message: 'Profile image successfully added', - type: 'success', - }); - setUpdatedProfilePicture(''); - setProfileUploading(false); - }) - .catch((err) => { - // updated user failure alert - setIsError({ - isError: true, - message: err.message, - type: 'error', - }); - setUpdatedProfilePicture(''); - setProfileUploading(false); - }); - }) - .catch((err) => { - // unable to save image error - setUpdatedProfilePicture(''); - setProfileUploading(false); - setIsError({ - isError: true, - message: err.message, - type: 'error', - }); - }); + + // 5. Update localStorage and Redux store with new data + const updatedData = { + _id: userID, + ...userData, + profilePicture: responseData.secure_url, + }; + localStorage.setItem('loggedUser', JSON.stringify(updatedData)); + dispatch(setUserInfo(updatedData)); + + // 6. Success message + setIsError({ + isError: true, + message: 'Profile image successfully added', + type: 'success', + }); + + setUpdatedProfilePicture(''); + setProfileUploading(false); + } catch (err) { + console.error('Error uploading/updating profile image:', err); + setUpdatedProfilePicture(''); + setProfileUploading(false); + setIsError({ + isError: true, + message: err.message, + type: 'error', + }); } }; const deleteProfileImage = () => { setUpdatedProfilePicture(''); - setUserData({ ...userData, profilePicture: '' }); + setUserData((prev) => ({ ...prev, profilePicture: '' })); + + // Safely parse "loggedUser" for user ID + let userID = null; + const storedUser = localStorage.getItem('loggedUser'); + if (storedUser && storedUser !== 'undefined') { + try { + const parsedUser = JSON.parse(storedUser); + userID = parsedUser?._id || null; + } catch (error) { + console.error('Error parsing "loggedUser" from localStorage:', error); + } + } - const userID = JSON.parse(localStorage.getItem('loggedUser'))?._id; + if (!userID) { + setIsError({ + isError: true, + message: 'No valid user ID found in localStorage.', + type: 'error', + }); + return; + } + + // Update the user profile image to empty updateUserCreationDetails({ profilePicture: '' }, userID) - .then((response) => { - localStorage.setItem( - 'loggedUser', - JSON.stringify({ ...userData, profilePicture: '', _id: userID }), - ); - dispatch(setUserInfo({ ...userData, profilePicture: '', _id: userID })); + .then(() => { + // Update localStorage and Redux + const updatedData = { ...userData, profilePicture: '', _id: userID }; + localStorage.setItem('loggedUser', JSON.stringify(updatedData)); + dispatch(setUserInfo(updatedData)); + setShowDeleteProfileModal(false); setIsError({ isError: true, diff --git a/src/platform/src/pages/settings/index.jsx b/src/platform/src/pages/settings/index.jsx index 23d2bb91eb..ceb0998c55 100644 --- a/src/platform/src/pages/settings/index.jsx +++ b/src/platform/src/pages/settings/index.jsx @@ -32,36 +32,48 @@ const Settings = () => { useEffect(() => { setLoading(true); + const storedActiveGroup = localStorage.getItem('activeGroup'); - if (!storedActiveGroup) return setLoading(false); + if (!storedActiveGroup) { + setLoading(false); + return; + } + + let parsedActiveGroup = null; + try { + parsedActiveGroup = JSON.parse(storedActiveGroup); + } catch (error) { + console.error('Error parsing "activeGroup" from localStorage:', error); + + setLoading(false); + return; + } - setUserGroup(JSON.parse(storedActiveGroup)); - const activeGroupId = - storedActiveGroup && JSON.parse(storedActiveGroup)._id; + // Now we have a valid parsedActiveGroup object + setUserGroup(parsedActiveGroup); + + const activeGroupId = parsedActiveGroup?._id; const storedUserPermissions = - storedActiveGroup && JSON.parse(storedActiveGroup).role.role_permissions; + parsedActiveGroup?.role?.role_permissions || []; - if (storedUserPermissions && storedUserPermissions.length > 0) { + if (storedUserPermissions.length > 0) { setUserPermissions(storedUserPermissions); } else { setUserPermissions([]); dispatch(setChartTab(0)); } - try { - getAssignedGroupMembers(activeGroupId) - .then((response) => { - setTeamMembers(response.group_members); - }) - .catch((error) => { - console.error(`Error fetching user details: ${error}`); - }); - } catch (error) { - console.error(`Error fetching user details: ${error}`); - } finally { - setLoading(false); - } - }, [userInfo, preferences]); + getAssignedGroupMembers(activeGroupId) + .then((response) => { + setTeamMembers(response.group_members); + }) + .catch((error) => { + console.error(`Error fetching user details: ${error}`); + }) + .finally(() => { + setLoading(false); + }); + }, [userInfo, preferences, dispatch]); return (