Skip to content

Commit

Permalink
fix(preference): add icon and able to expand
Browse files Browse the repository at this point in the history
- add icons on preference settings
- redirect the login activities preference

[issueid: #104]
  • Loading branch information
niyibi250 committed Nov 24, 2024
1 parent 0d3869b commit b54478d
Show file tree
Hide file tree
Showing 17 changed files with 407 additions and 114 deletions.
1 change: 1 addition & 0 deletions %ProgramData%/Microsoft/Windows/UUS/State/_active.uusver
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1309.2410.30012.0
13 changes: 11 additions & 2 deletions app/auth/login/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import OrgLogin from '@/components/Login/OrgLogin';
import UserLogin from '@/components/Login/UserLogin';
import TwoFactorScreen from '../two-factor';
import { LOGIN_MUTATION, ORG_LOGIN_MUTATION } from '@/graphql/mutations/login.mutation';
import { ApolloError, useApolloClient, useMutation } from '@apollo/client';
import AsyncStorage from '@react-native-async-storage/async-storage';
Expand Down Expand Up @@ -84,8 +85,10 @@ export default function SignInOrganization() {

const onSubmit = async (userInput: any) => {
try {
console.log(userInput)
const orgToken = await AsyncStorage.getItem('orgToken');
userInput.orgToken = orgToken;
await AsyncStorage.setItem('user_email', userInput.email);

await LoginUser({
variables: {
Expand All @@ -97,7 +100,7 @@ export default function SignInOrganization() {
return;
}

if (data.loginUser) {
if (data.loginUser && !data.loginUser.otpRequired) {
const token = data.loginUser.token;

if (data.loginUser.user.role === 'trainee') {
Expand All @@ -118,7 +121,13 @@ export default function SignInOrganization() {
return;
}

} else {
}
else if(data.loginUser.otpRequired)
{
router.push('/auth/two-factor')
return
}
else {
await AsyncStorage.setItem('authToken', data.loginUser.token);
router.push('/dashboard');
}
Expand Down
158 changes: 158 additions & 0 deletions app/auth/two-factor/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import { useState, useEffect, useRef } from "react";
import {View,Text,TextInput,TouchableOpacity,KeyboardAvoidingView,useColorScheme,} from "react-native";
import { useMutation, gql } from "@apollo/client";
import { Href, useLocalSearchParams, useRouter } from 'expo-router';
import AsyncStorage from "@react-native-async-storage/async-storage";
import { useToast } from 'react-native-toast-notifications';
import { useTranslation } from 'react-i18next';


export const LOGIN_WITH_2FA = gql`
mutation LoginWithTwoFactorAuthentication($email: String!, $otp: String!) {
loginWithTwoFactorAuthentication(email: $email, otp: $otp) {
token
user {
id
role
email
profile {
id
firstName
lastName
name
address
city
country
phoneNumber
biography
avatar
cover
}
}
message
}
}
`;

const TwoFactorScreen = () => {
const [input, setInput] = useState<string[]>(Array(6).fill(""));
const [error, setError] = useState<string>("");
const {t} = useTranslation();
const [loading, setLoading] = useState<boolean>(false);
const colorScheme = useColorScheme();
const inputRefs = useRef<TextInput[]>([]);
const params = useLocalSearchParams<{ redirect?: string; logout: string }>();
const router = useRouter();
const toast = useToast();


const [loginWithTwoFactorAuthentication] = useMutation(LOGIN_WITH_2FA, {
onCompleted: async (data) => {
const response = data.loginWithTwoFactorAuthentication;
const token = response.token;
if (response.user.role === 'trainee') {
await AsyncStorage.setItem('authToken', token);

while (router.canGoBack()) {
router.back();
}

params.redirect
? router.push(`${params.redirect}` as Href<string | object>)
: router.push('/dashboard');
return;
} else {
toast.show(t('toasts.auth.loginErr'), {
type: 'danger',
});
return;
}
},
onError: (error) => {
setLoading(false)
setError(error.message || "Verification Failed");
toast.show(`Verification Failed: ${error.message}`, {type: 'danger',placement: 'top',duration: 4000,animationType: 'slide-in',});
setInput(Array(6).fill(""));
},
});


const verifyOtp = async () => {
const email = await AsyncStorage.getItem('user_email');

if (input.some((val) => !val)) {
setError("Please enter all digits");
return;
}

setLoading(true);

try {
await loginWithTwoFactorAuthentication({
variables: {
email,
otp: input.join("")
},
});
setLoading(false)
} catch {
setLoading(false);
}
};

const handleInputChange = (index: number, value: string) => {
console.log('typeeeee')
if (!/^\d*$/.test(value)) return;

const newInput = [...input];
newInput[index] = value;
setInput(newInput);

if (value && index < input.length - 1) {
inputRefs.current[index + 1]?.focus();
}

};

const handleBackspace = (index: number, value: string) => {
if (!value && index > 0) {
inputRefs.current[index - 1]?.focus();
}
};

return (
<KeyboardAvoidingView className="h-full mx-5 flex flex-col justify-top items-center">
<View className={`w-full h-fit mt-16 bg-white dark:bg-gray-800 rounded-lg p-6 shadow ${colorScheme === "dark" ? "bg-gray-100" : "dark:bg-gray-900"}`}>
<Text className={`text-center text-2xl font-Inter-Bold ${colorScheme === "dark" ? "text-gray-100" : "text-gray-800"}`}>Verification Required</Text>
<Text className={`text-center font-Inter-Bold text-lg ${colorScheme === "dark" ? "text-gray-400" : "text-gray-600"} mt-2`}>Enter the verification code</Text>
<Text className={`text-center font-bold mt-1 ${colorScheme === "dark" ? "text-gray-400" : "text-gray-600"}`}>[email protected]</Text>
<View className="flex-row justify-between mt-6 items-center gap-3">
{input.map((value, index) => (
<TextInput
key={index}
ref={(el) => (inputRefs.current[index] = el!)}
value={value}
maxLength={1}
keyboardType="numeric"
onChangeText={(val) => handleInputChange(index, val)}
onKeyPress={({ nativeEvent }) =>
nativeEvent.key === "Backspace" && handleBackspace(index, value)
}
className={`w-10 h-10 text-center text-lg font-semibold border ${colorScheme === "dark" ? "bg-gray-700 text-gray-100 border-gray-600" : "bg-white text-gray-800"} rounded`}
/>
))}
</View>

<TouchableOpacity
onPress={verifyOtp}
disabled={loading || input.some((val) => !val)}
className={`mt-6 py-3 px-4 rounded ${loading || input.some((val) => !val) ? "bg-gray-400" : "bg-[#8667F2]"}`}
>
<Text className="text-center">{loading ? "Verifying..." : "Verify Code"}</Text>
</TouchableOpacity>
</View>
</KeyboardAvoidingView>
);
};

export default TwoFactorScreen;
Binary file added assets/Preference_icons/down_arrow.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/Preference_icons/forward-pref-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions assets/Preference_icons/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
declare module '*.png' {
const content: any;
export default content;
}


7 changes: 7 additions & 0 deletions assets/Preference_icons/preference_icons.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import forward_pref_icon from '@/assets/Preference_icons/forward-pref-icon.png'
import down_arrow from '@/assets/Preference_icons/down_arrow.png'

export {
forward_pref_icon,
down_arrow
}
2 changes: 1 addition & 1 deletion components/Login/OrgLogin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export default function OrgLogin({ onSubmit }: OrgLoginProps) {
initialValues: {} as FormValues,
onSubmit: async (values) => {
setLoading(true);
await onSubmit(values);
onSubmit(values);
setLoading(false);
},
validationSchema: OrgLoginSchema,
Expand Down
2 changes: 1 addition & 1 deletion components/Login/UserLogin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export default function UserLogin({ onSubmit }: userLoginProps) {
initialValues: {email: '', password: '' } as FormValues,
onSubmit: async (values: FormValues) => {
setLoading(true);
await onSubmit(values);
onSubmit(values);
setLoading(false);
},
validationSchema: UserLoginSchema,
Expand Down
Loading

0 comments on commit b54478d

Please sign in to comment.