diff --git a/src/containers/DashRoutes.tsx b/src/containers/DashRoutes.tsx index c057430b..423da373 100644 --- a/src/containers/DashRoutes.tsx +++ b/src/containers/DashRoutes.tsx @@ -42,6 +42,9 @@ const ViewTraineeRatings = React.lazy( const TtlTraineeDashboard = React.lazy( () => import('../pages/ttlTraineeDashboard'), ); +const LoginWith2fa = React.lazy( + () => import('../pages/LoginWith2fa'), +); const TraineeRatingDashboard = React.lazy( () => import('../pages/TraineeRatingDashboard'), diff --git a/src/containers/Routes.tsx b/src/containers/Routes.tsx index c7193430..6d655e50 100644 --- a/src/containers/Routes.tsx +++ b/src/containers/Routes.tsx @@ -43,6 +43,7 @@ import RemoveTokenPage from '../utils/RemoveTokenPage'; import PrivateRoute from '../utils/PrivateRoute'; import CalendarConfirmation from '../components/CalendarConfirmation'; import NotFound from '../components/NotFoundPage'; +import TwoFactorPage from '../pages/LoginWith2fa'; function MainRoutes() { return ( @@ -123,13 +124,14 @@ function MainRoutes() { + }> - + } /> + }/> { + const [input, setInput] = useState(Array(6).fill('')); + const [error, setError] = useState(''); + const [loading, setLoading] = useState(false); + const [isDark, setIsDark] = useState(false); + const { login } = useContext(UserContext); + const client = useApolloClient(); + const { t } = useTranslation(); + + const location = useLocation(); + const navigate = useNavigate(); + const { email, TwoWayVerificationToken } = location.state || {}; + useEffect(() => { + // Update document class and localStorage when theme changes + if (isDark) { + document.documentElement.classList.add('dark'); + localStorage.setItem('theme', 'dark'); + } else { + document.documentElement.classList.remove('dark'); + localStorage.setItem('theme', 'light'); + } + }, [isDark]); + + useEffect(() => { + if (!email || !TwoWayVerificationToken) { + navigate('/login'); + } + }, [email, TwoWayVerificationToken, navigate]); + + const [loginWithTwoFactorAuthentication] = useMutation( + LOGIN_WITH_2FA, + { + onCompleted: async (data) => { + const response = data.loginWithTwoFactorAuthentication; + try { + localStorage.setItem('authToken', response.token); + localStorage.setItem('user', JSON.stringify(response.user)); + await login(response); + await client.resetStore(); + toast.success(response.message); + + const rolePaths: Record = { + superAdmin: '/organizations', + admin: '/trainees', + coordinator: '/trainees', + manager: '/dashboard', + ttl: '/ttl-trainees', + trainee: '/performance', + }; + + const redirectPath = rolePaths[response.user.role] || '/dashboard'; + navigate(redirectPath, { replace: true }); + } catch (error) { + toast.error('Login Error'); + } + }, + onError: (error) => { + const errorMessage = error.message || 'Verification Failed'; + setError(errorMessage); + toast.error(errorMessage); + setInput(Array(6).fill('')); + }, + }, + ); + + const verifyOtp = async (currentInput = input) => { + if (currentInput.some((val) => !val)) { + setError('Please Enter All Digits'); + return; + } + + setLoading(true); + setError(''); + + try { + await loginWithTwoFactorAuthentication({ + variables: { + email, + otp: currentInput.join(''), + TwoWayVerificationToken, + }, + }); + } finally { + setLoading(false); + } + }; + + const handleInput = useCallback( + (index: number, value: string) => { + if (!/^\d*$/.test(value)) return; + + const newInput = [...input]; + newInput[index] = value; + setInput(newInput); + + if (value && index < input.length - 1) { + const nextInput = document.getElementById( + `otp-input-${index + 1}`, + ) as HTMLInputElement; + nextInput?.focus(); + } + + if (value && index === input.length - 1) { + const allFilled = newInput.every((val) => val !== ''); + if (allFilled) { + verifyOtp(newInput); + } + } + }, + [input], + ); + + const handleKeyDown = ( + index: number, + e: React.KeyboardEvent, + ) => { + if (e.key === 'Backspace' && !input[index] && index > 0) { + const prevInput = document.getElementById( + `otp-input-${index - 1}`, + ) as HTMLInputElement; + prevInput?.focus(); + } + }; + + const handlePaste = (e: React.ClipboardEvent) => { + e.preventDefault(); + const pastedData = e.clipboardData.getData('text').trim(); + + if (!/^\d+$/.test(pastedData)) { + setError('Only Numbers Can Be Pasted'); + return; + } + + const digits = pastedData.slice(0, 6).split(''); + const newInput = [...digits, ...Array(6 - digits.length).fill('')]; + + setInput(newInput); + + if (digits.length < 6) { + const nextEmptyIndex = digits.length; + const nextInput = document.getElementById( + `otp-input-${nextEmptyIndex}`, + ) as HTMLInputElement; + nextInput?.focus(); + } else { + verifyOtp(newInput); + } + }; + + const toggleTheme = () => { + setIsDark(!isDark); + }; + + return ( +
+
+

+ {'Verification Required'} +

+ +

+ {'Enter Verification Code'} +
+ {email} +

+ + {error && ( +
+ {error} +
+ )} + +
{ + e.preventDefault(); + verifyOtp(); + }} + > +
+ {input.map((value, index) => ( + handleInput(index, e.target.value)} + onKeyDown={(e) => handleKeyDown(index, e)} + onPaste={index === 0 ? handlePaste : undefined} + className="w-12 h-12 text-lg font-semibold text-center text-gray-800 transition-colors bg-white border rounded dark:text-gray-100 dark:border-gray-600 dark:bg-gray-700 focus:ring-2 focus:ring-blue-500 focus:border-transparent" + disabled={loading} + autoComplete="one-time-code" + required + /> + ))} +
+ + +
+
+
+ ); +}; + +export default TwoFactorPage; diff --git a/src/pages/Organization/2faMutation.tsx b/src/pages/Organization/2faMutation.tsx new file mode 100644 index 00000000..db253ac3 --- /dev/null +++ b/src/pages/Organization/2faMutation.tsx @@ -0,0 +1,26 @@ +import { gql } from '@apollo/client'; + +export const EnableTwoFactorAuth = gql` + mutation EnableTwoFactorAuth($email: String!) { + enableTwoFactorAuth(email: $email) + } +`; + + +export const LoginWithTwoFactorAuthentication= gql` +mutation LoginWithTwoFactorAuthentication($email: String!, $otp: String!, $twoWayVerificationToken: String!) { + loginWithTwoFactorAuthentication(email: $email, otp: $otp, TwoWayVerificationToken: $twoWayVerificationToken) { + message + token + user { + email + } + } +} +`; + +export const DisableTwoFactorAuth = gql` + mutation DisableTwoFactorAuth($email: String!) { + disableTwoFactorAuth(email: $email) + } +`; diff --git a/src/pages/Organization/AdminLogin.tsx b/src/pages/Organization/AdminLogin.tsx index f0c25fbe..a3a37788 100644 --- a/src/pages/Organization/AdminLogin.tsx +++ b/src/pages/Organization/AdminLogin.tsx @@ -1,337 +1,348 @@ -/* eslint-disable */ -'use client'; -import { useApolloClient, useMutation } from '@apollo/client'; -import React, { useContext, useEffect, useState } from 'react'; -import { useForm } from 'react-hook-form'; -import { useTranslation } from 'react-i18next'; -import { FaRegEnvelope, FaRegEye } from 'react-icons/fa'; -import { FiEyeOff } from 'react-icons/fi'; -import { MdLockOutline } from 'react-icons/md'; -import { - Link, - useLocation, - useNavigate, - useSearchParams, -} from 'react-router-dom'; -import { toast, ToastContent } from 'react-toastify'; -import ButtonLoading from '../../components/ButtonLoading'; -import Button from '../../components/Buttons'; -import { UserContext } from '../../hook/useAuth'; -import useDocumentTitle from '../../hook/useDocumentTitle'; -import LOGIN_MUTATION from './LoginMutation'; -import functionTree from '../../assets/Functionality_Tree.svg'; -import pulseStars from '../../assets/Property 1=Logo_flie (1).svg'; - -function AdminLogin() { - const orgToken: any = localStorage.getItem('orgToken'); - const orgName: any = localStorage.getItem('orgName'); - const [loading, setLoading] = useState(false); - - useDocumentTitle('Login'); - const { t } = useTranslation(); - const [passwordShown, setPasswordShown] = useState(false); - /* istanbul ignore next */ - const tooglePassword = () => { - setPasswordShown(!passwordShown); - }; - const { - register, - handleSubmit, - formState: { errors }, - setError, - }: any = useForm(); - const { login } = useContext(UserContext); - const navigate = useNavigate(); - const { state } = useLocation(); - const [LoginUser] = useMutation(LOGIN_MUTATION); - const client = useApolloClient(); - const [searchParams] = useSearchParams(); - - // Function to get the redirect_message from the URL and toast it - const showRedirectMessage = () => { - const redirectMessage = searchParams.get('redirect_message'); - if (redirectMessage) { - toast.error(redirectMessage); - } - }; - - // Call showRedirectMessage when the component mounts - useEffect(() => { - showRedirectMessage(); - }, [searchParams]); - - const onSubmit = async (userInput: any) => { - userInput.orgToken = orgToken; - try { - setLoading(true); - const redirect = searchParams.get('redirect'); - // const activity = await getLocation(); - await LoginUser({ - variables: { - loginInput: { - ...userInput, - // activity, //disable geolocation - }, - }, - - /* istanbul ignore next */ - onCompleted: async (data) => { - /* istanbul ignore next */ - toast.success(data.addMemberToCohort); - /* istanbul ignore next */ - login(data.loginUser); - /* istanbul ignore next */ - await client.resetStore(); - /* istanbul ignore next */ - toast.success(t(`Welcome`) as ToastContent); - /* istanbul ignore next */ - - const redirectParams=sessionStorage.getItem("redirectParams")||'' - if (data.loginUser) { - redirect - ? navigate(`${redirect}`) - : data.loginUser.user.role === 'superAdmin' - ? navigate(`/dashboard`) - : data.loginUser.user.role === 'admin' - ? navigate(`/trainees`) - : data.loginUser.user.role === 'coordinator' - ? navigate(`/trainees`) - : data.loginUser.user.role === 'manager' - ? navigate(`/dashboard`) - : data.loginUser.user.role === 'ttl' - ? navigate('/ttl-trainees') - : navigate('/performance'); - sessionStorage.removeItem("redirectParams") - } else { - navigate('/dashboard'); - } - }, - onError: (err) => { - console.log(err) - if (err.networkError) - toast.error('There was a problem contacting the server'); - else if (err.message.toLowerCase() !== 'invalid credential') { - const translateError = t( - 'Please wait to be added to a program or cohort', - ); - toast.error(translateError); - } else { - /* istanbul ignore next */ - setError('password', { - type: 'custom', - message: t('Invalid credentials'), - }); - } - }, - }); - } catch (error: any) { - /* istanbul ignore next */ - setError('password', { - type: 'custom', - message: t('Invalid credentials'), - }); - } finally { - setLoading(false); - } - }; - - const getLocation = async () => { - const location = await fetch('https://geolocation-db.com/json/') - .then(async (res) => { - const activityResponse = await res.json(); - - const activityResponseActual = { - IPv4: activityResponse.IPv4, - city: activityResponse.city, - country_code: activityResponse.country_code, - country_name: activityResponse.country_name, - latitude: - activityResponse.latitude === 'Not found' - ? null - : activityResponse.latitude, - longitude: - activityResponse.longitude === 'Not found' - ? null - : activityResponse.longitude, - postal: activityResponse.postal, - state: activityResponse.state, - }; - return activityResponseActual; - }) - .then((data) => data); - const date = new Date().toString(); - return { date, ...location } || null; - }; - - return ( -
-
-
-
- pulses -

- {t('Boost your organization')} -

-
- -
- functions -
-
-
- -
-
-
-
-

- {t('Welcome to')}{' '} - {orgName - ? orgName.charAt(0).toUpperCase() + - orgName.slice(1).toLowerCase() - : ''} -

-
-
- -
- - {t('Switch')} {t('your organization')} - -
- -
-
- {errors.password && - errors.password.message === t('Invalid credentials') ? ( -
- - {errors.password.message} - -
- ) : ( - '' - )} -
- - -
-
- {errors.email && ( - - {errors.email.message} - - )} -
- -
- - -
- {passwordShown ? ( - - ) : ( - - )} -
-
-
- {errors.password && - errors.password.message !== t('Invalid credentials') ? ( - - {errors.password.message} - - ) : ( - '' - )} -
-
-
- -
-
- - {t('Forgot Password?')} - -
-
-
- {loading ? ( - - ) : ( - - )} -
-
-
- -
- {t('First time here?')} - - {t('Register')} - - {t('your organization')} -
-
-
-
-
- ); -} - -export default AdminLogin; +/* eslint-disable */ +'use client'; +import { useApolloClient, useMutation } from '@apollo/client'; +import React, { useContext, useEffect, useState } from 'react'; +import { useForm } from 'react-hook-form'; +import { useTranslation } from 'react-i18next'; +import { FaRegEnvelope, FaRegEye } from 'react-icons/fa'; +import { FiEyeOff } from 'react-icons/fi'; +import { MdLockOutline } from 'react-icons/md'; +import { + Link, + useLocation, + useNavigate, + useSearchParams, +} from 'react-router-dom'; +import { toast, ToastContent } from 'react-toastify'; +import ButtonLoading from '../../components/ButtonLoading'; +import Button from '../../components/Buttons'; +import { UserContext } from '../../hook/useAuth'; +import useDocumentTitle from '../../hook/useDocumentTitle'; +import LOGIN_MUTATION from './LoginMutation'; +import functionTree from '../../assets/Functionality_Tree.svg'; +import pulseStars from '../../assets/Property 1=Logo_flie (1).svg'; + +function AdminLogin() { + const orgToken: any = localStorage.getItem('orgToken'); + const orgName: any = localStorage.getItem('orgName'); + const [loading, setLoading] = useState(false); + const [otpRequired, setOtpRequired] = useState(false); + const [TwoWayVerificationToken, setTwoWayVerificationToken] = useState(''); + const [otp, setOtp] = useState(''); + + useDocumentTitle('Login'); + const { t } = useTranslation(); + const [passwordShown, setPasswordShown] = useState(false); + /* istanbul ignore next */ + const tooglePassword = () => { + setPasswordShown(!passwordShown); + }; + const { + register, + handleSubmit, + formState: { errors }, + setError, + }: any = useForm(); + const { login } = useContext(UserContext); + const navigate = useNavigate(); + const [LoginUser] = useMutation(LOGIN_MUTATION); + const client = useApolloClient(); + const [searchParams] = useSearchParams(); + // Function to get the redirect_message from the URL and toast it + const showRedirectMessage = () => { + const redirectMessage = searchParams.get('redirect_message'); + if (redirectMessage) { + toast.error(redirectMessage); + } + }; + + // Call showRedirectMessage when the component mounts + useEffect(() => { + showRedirectMessage(); + }, [searchParams]); + + const onSubmit = async (userInput: any) => { + userInput.orgToken = orgToken; + try { + setLoading(true); + const redirect = searchParams.get('redirect'); + // const activity = await getLocation(); + await LoginUser({ + variables: { + loginInput: { + ...userInput, + // activity, //disable geolocation + }, + }, + + + /* istanbul ignore next */ + onCompleted: async (data) => { + if (data.loginUser.otpRequired) { + setOtpRequired(true); + setTwoWayVerificationToken(data.loginUser.TwoWayVerificationToken); + navigate('/users/LoginWith2fa', { + state: { + email: userInput.email, + TwoWayVerificationToken: data.loginUser.TwoWayVerificationToken, + },}) + + }else{ + /* istanbul ignore next */ + toast.success(data.addMemberToCohort); + /* istanbul ignore next */ + login(data.loginUser); + /* istanbul ignore next */ + await client.resetStore(); + /* istanbul ignore next */ + toast.success(t(`Welcome`) as ToastContent); + /* istanbul ignore next */ + if (data.loginUser) { + redirect + ? navigate(`${redirect}`) + : data.loginUser.user.role === 'superAdmin' + ? navigate(`/dashboard`) + : data.loginUser.user.role === 'admin' + ? navigate(`/trainees`) + : data.loginUser.user.role === 'coordinator' + ? navigate(`/trainees`) + : data.loginUser.user.role === 'manager' + ? navigate(`/dashboard`) + : data.loginUser.user.role === 'ttl' + ? navigate('/ttl-trainees') + : navigate('/performance'); + } else { + navigate('/dashboard'); + } + }}, + onError: (err) => { + /* istanbul ignore next */ + console.log(err.message); + + if (err.networkError) + toast.error('There was a problem contacting the server'); + else if (err.message.toLowerCase() !== 'invalid credential') { + const translateError = t( + 'Please wait to be added to a program or cohort', + ); + toast.error(translateError); + } else { + /* istanbul ignore next */ + setError('password', { + type: 'custom', + message: t('Invalid credentials'), + }); + } + }, + }); + } catch (error: any) { + /* istanbul ignore next */ + setError('password', { + type: 'custom', + message: t('Invalid credentials'), + }); + } finally { + setLoading(false); + } + }; + + const getLocation = async () => { + const location = await fetch('https://geolocation-db.com/json/') + .then(async (res) => { + const activityResponse = await res.json(); + + const activityResponseActual = { + IPv4: activityResponse.IPv4, + city: activityResponse.city, + country_code: activityResponse.country_code, + country_name: activityResponse.country_name, + latitude: + activityResponse.latitude === 'Not found' + ? null + : activityResponse.latitude, + longitude: + activityResponse.longitude === 'Not found' + ? null + : activityResponse.longitude, + postal: activityResponse.postal, + state: activityResponse.state, + }; + return activityResponseActual; + }) + .then((data) => data); + const date = new Date().toString(); + return { date, ...location } || null; + }; + + return ( +
+
+
+
+ pulses +

+ {t('Boost your organization')} +

+
+ +
+ functions +
+
+
+ +
+
+
+
+

+ {t('Welcome to')}{' '} + {orgName + ? orgName.charAt(0).toUpperCase() + + orgName.slice(1).toLowerCase() + : ''} +

+
+
+ +
+ + {t('Switch')} {t('your organization')} + +
+ +
+
+ {errors.password && + errors.password.message === t('Invalid credentials') ? ( +
+ + {errors.password.message} + +
+ ) : ( + '' + )} +
+ + +
+
+ {errors.email && ( + + {errors.email.message} + + )} +
+ +
+ + +
+ {passwordShown ? ( + + ) : ( + + )} +
+
+
+ {errors.password && + errors.password.message !== t('Invalid credentials') ? ( + + {errors.password.message} + + ) : ( + '' + )} +
+
+
+ +
+
+ + {t('Forgot Password?')} + +
+
+
+ {loading ? ( + + ) : ( + + )} +
+
+
+ +
+ {t('First time here?')} + + {t('Register')} + + {t('your organization')} +
+
+
+
+
+ ); +} + +export default AdminLogin; diff --git a/src/pages/Organization/LoginMutation.tsx b/src/pages/Organization/LoginMutation.tsx index 5c7eae76..ef97ad0c 100644 --- a/src/pages/Organization/LoginMutation.tsx +++ b/src/pages/Organization/LoginMutation.tsx @@ -4,6 +4,8 @@ const LOGIN_MUTATION = gql` mutation Mutation($loginInput: LoginInput) { loginUser(loginInput: $loginInput) { token + otpRequired + TwoWayVerificationToken user { id role diff --git a/src/pages/Settings.tsx b/src/pages/Settings.tsx index 74af41c7..96508e43 100644 --- a/src/pages/Settings.tsx +++ b/src/pages/Settings.tsx @@ -1,15 +1,17 @@ +/* eslint-disable */ import React, { useState, useEffect, useRef, useContext } from 'react'; import i18next from 'i18next'; import { Link } from 'react-router-dom'; import { useTranslation } from 'react-i18next'; import { Switch } from '@headlessui/react'; -import { useMutation, useQuery } from '@apollo/client'; +import { gql, useMutation, useQuery } from '@apollo/client'; import getLanguage from '../utils/getLanguage'; import useDocumentTitle from '../hook/useDocumentTitle'; import { updatePushNotifications, updateEmailNotifications, } from '../Mutations/notificationMutation'; +import { EnableTwoFactorAuth,DisableTwoFactorAuth } from './Organization/2faMutation'; import { updatedEmailNotifications, updatedPushNotifications, @@ -17,6 +19,16 @@ import { import { UserContext } from '../hook/useAuth'; import { ThemeContext } from '../hook/ThemeProvider'; +const GetProfile = gql` + query GetProfile { + getProfile { + user { + twoFactorAuth + } + } + } +`; + function Settings() { useDocumentTitle('Settings'); const { t } = useTranslation(); @@ -24,74 +36,82 @@ function Settings() { const lan = getLanguage(); const { colorTheme, setTheme } = useContext(ThemeContext); const { user } = useContext(UserContext); - const [updateEmailNotificationsMutation] = useMutation( - updateEmailNotifications, - ); - const [updatePushNotificationsMutation] = useMutation( - updatePushNotifications, - ); + + const [isTwoFactorEnabled, setIsTwoFactorEnabled] = useState(false); + const [enableTwoFactorAuth] = useMutation(EnableTwoFactorAuth); + const [disableTwoFactorAuth] = useMutation(DisableTwoFactorAuth); + const [updateEmailNotificationsMutation] = useMutation(updateEmailNotifications); + const [updatePushNotificationsMutation] = useMutation(updatePushNotifications); + + const { data: profileData } = useQuery(GetProfile, { + onCompleted: data => setIsTwoFactorEnabled(data.getProfile.user.twoFactorAuth), + }); const { data: pushData } = useQuery(updatedPushNotifications, { variables: { getUpdatedPushNotificationsId: user?.userId }, + onCompleted: data => setPushEnabled(data.getUpdatedPushNotifications), }); - const [pushEnabled, setPushEnabled] = useState( - pushData?.getUpdatedPushNotifications || false, - ); - const { data } = useQuery(updatedEmailNotifications, { + const { data: emailData } = useQuery(updatedEmailNotifications, { variables: { getUpdatedEmailNotificationsId: user?.userId }, + onCompleted: data => setEmailEnabled(data.getUpdatedEmailNotifications), }); - const [emailEnabled, setEmailEnabled] = useState( - data?.getUpdatedEmailNotifications || false, - ); - const handleThemeChange = (e: { target: { value: any } }) => { + const [pushEnabled, setPushEnabled] = useState(false); + const [emailEnabled, setEmailEnabled] = useState(false); + + const handleEnableTwoFactor = async () => { + try { + await enableTwoFactorAuth({ variables: { email: user?.email } }); + setIsTwoFactorEnabled(true); + } catch (error) { + console.error("Error enabling two-factor authentication:", error); + } + }; + + const handleDisableTwoFactor = async () => { + try { + await disableTwoFactorAuth({ variables: { email: user?.email } }); + setIsTwoFactorEnabled(false); + } catch (error) { + console.error("Error disabling two-factor authentication:", error); + } + }; + + const handleThemeChange = (e: React.ChangeEvent) => { const { value } = e.target; setTheme(value); - localStorage.setItem('color-theme', colorTheme); + localStorage.setItem('color-theme', value); }; - const defaultTheme: any = colorTheme; - const userLang = window.navigator.language; - const handleLanChange = (e: { target: { value: any } }) => { + const userLang = window.navigator.language; + const handleLanChange = (e: React.ChangeEvent) => { const { value } = e.target; - i18next.changeLanguage(value); + i18next.changeLanguage(value).catch((error) => { + console.error("Error changing language:", error); + }); }; const handleEmailNotificationChange = async () => { try { - const { data } = await updateEmailNotificationsMutation({ + await updateEmailNotificationsMutation({ variables: { updateEmailNotificationsId: user?.userId }, }); - setEmailEnabled((prevEmailEnabled: any) => !prevEmailEnabled); - return data; - } catch (error: any) { - return `Error updating email notifications:${error}`; + setEmailEnabled((prevEmailEnabled) => !prevEmailEnabled); + } catch (error) { + console.error("Error updating email notifications:", error); } }; const handlePushNotificationChange = async () => { try { - const { data: pushData } = await updatePushNotificationsMutation({ + await updatePushNotificationsMutation({ variables: { updatePushNotificationsId: user?.userId }, }); - setPushEnabled((prevPushEnabled: any) => !prevPushEnabled); - return pushData; - } catch (error: any) { - return `Error updating push notifications: ${error}`; + setPushEnabled((prevPushEnabled) => !prevPushEnabled); + } catch (error) { + console.error("Error updating push notifications:", error); } }; - useEffect(() => { - if (data?.getUpdatedEmailNotifications !== undefined) { - setEmailEnabled(data.getUpdatedEmailNotifications); - } - }, [data]); - - useEffect(() => { - if (pushData?.getUpdatedPushNotifications !== undefined) { - setPushEnabled(pushData.getUpdatedPushNotifications); - } - }, [pushData]); - useEffect(() => { if (lanRef.current) { lanRef.current.value = lan; @@ -132,9 +152,9 @@ function Settings() {