LOgging in with qr code added

This commit is contained in:
Milan Paunovic
2024-09-29 23:03:21 +02:00
parent 92f335543f
commit 5922179584
15 changed files with 820 additions and 993 deletions

View File

@ -1,22 +1,60 @@
import {Button, ButtonSize, Text, TextField, View} from "react-native-ui-lib";
import React, {useState} from "react";
import {Button, ButtonSize, Dialog, Text, TextField, View} from "react-native-ui-lib";
import React, {useEffect, useState} from "react";
import {useSignIn} from "@/hooks/firebase/useSignIn";
import {StyleSheet} from "react-native";
import Toast from 'react-native-toast-message';
import {useLoginWithQrCode} from "@/hooks/firebase/useLoginWithQrCode";
import {Camera, CameraView} from 'expo-camera';
import {BarCodeScanner} from "expo-barcode-scanner";
const SignInPage = ({setTab}: { setTab: React.Dispatch<React.SetStateAction<"register" | "login" | "reset-password">> }) => {
const [email, setEmail] = useState<string>("");
const [password, setPassword] = useState<string>("");
const [hasPermission, setHasPermission] = useState<boolean | null>(null);
const [scanned, setScanned] = useState<boolean>(false);
const [showCameraDialog, setShowCameraDialog] = useState<boolean>(false);
const {mutateAsync: signIn, error, isError} = useSignIn();
const {mutateAsync: signInWithQrCode} = useLoginWithQrCode()
const handleSignIn = async () => {
await signIn({email, password});
if(!isError) {
Toast.show({
type: "success",
text1: "Password successfully reset, please check your messages."
})
text1: "Login successful!"
});
} else {
Toast.show({
type: "error",
text1: "Error logging in",
text2: `${error}`
});
}
};
const handleQrCodeScanned = async ({ data }: { data: string }) => {
setShowCameraDialog(false);
try {
await signInWithQrCode({ userId: data });
Toast.show({
type: "success",
text1: "Login successful with QR code!"
});
} catch (err) {
Toast.show({
type: "error",
text1: "Error logging in with QR code",
text2: `${err}`
});
}
};
const getCameraPermissions = async (callback: () => void) => {
const { status } = await Camera.requestCameraPermissionsAsync();
setHasPermission(status === 'granted');
if(status === 'granted') {
callback();
}
};
@ -41,6 +79,15 @@ const SignInPage = ({setTab}: { setTab: React.Dispatch<React.SetStateAction<"re
style={{marginBottom: 20}}
backgroundColor="#fd1775"
/>
<Button
label="Login with a QR Code"
onPress={() => {
getCameraPermissions(() => setShowCameraDialog(true));
}
}
style={{marginBottom: 20}}
backgroundColor="#fd1775"
/>
{isError && <Text center style={{marginBottom: 20}}>{`${error}`}</Text>}
<View row centerH marginB-5 gap-5>
@ -76,6 +123,36 @@ const SignInPage = ({setTab}: { setTab: React.Dispatch<React.SetStateAction<"re
color="#fd1775"
/>
</View>
{/* Camera Dialog */}
<Dialog
visible={showCameraDialog}
onDismiss={() => setShowCameraDialog(false)}
bottom
width="100%"
height="70%"
containerStyle={{ padding: 0 }}
>
{hasPermission === null ? (
<Text>Requesting camera permissions...</Text>
) : !hasPermission ? (
<Text>No access to camera</Text>
) : (
<CameraView
style={{ flex: 1 }}
onBarcodeScanned={handleQrCodeScanned}
barcodeScannerSettings={{
barcodeTypes: ["qr"],
}}
/>
)}
<Button
label="Cancel"
onPress={() => setShowCameraDialog(false)}
backgroundColor="#fd1775"
style={{ margin: 10 }}
/>
</Dialog>
</View>
);
};

View File

@ -1,20 +1,34 @@
import {Avatar, Card, Colors, FloatingButton, Text, View} from "react-native-ui-lib";
import {
Avatar,
Button,
Card,
Colors,
Dialog,
FloatingButton,
PanningProvider,
Picker,
Text,
TextField,
TouchableOpacity,
View
} from "react-native-ui-lib";
import React, {useState} from "react";
import {ScrollView, StyleSheet} from "react-native";
import {PickerSingleValue} from "react-native-ui-lib/src/components/picker/types";
import {useCreateSubUser} from "@/hooks/firebase/useCreateSubUser";
import {ProfileType} from "@/contexts/AuthContext";
import {useGetFamilyMembers} from "@/hooks/firebase/useGetFamilyMembers";
import UserMenu from "@/components/pages/settings/user_settings_views/UserMenu";
const MyGroup = () => {
const [showAddUserDialog, setShowAddUserDialog] = useState(false);
const [showNewUserInfoDialog, setShowNewUserInfoDialog] = useState(false);
const [selectedStatus, setSelectedStatus] = useState<string | PickerSingleValue>('CHILD');
const [selectedStatus, setSelectedStatus] = useState<string | PickerSingleValue>(ProfileType.CHILD);
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const [email, setEmail] = useState('');
const {mutateAsync: createSubUser, isLoading: loading, isError} = useCreateSubUser();
const {mutateAsync: createSubUser, isLoading, isError} = useCreateSubUser();
const {data: familyMembers} = useGetFamilyMembers(true);
const parents = familyMembers?.filter(x => x.userType === ProfileType.PARENT) ?? [];
@ -45,13 +59,15 @@ const MyGroup = () => {
}
};
console.log(familyMembers)
return (
<View style={{flex: 1, height: "100%"}}>
<View>
<ScrollView style={styles.card}>
{(!parents.length && !children.length && !caregivers.length) && (
<Text text70 marginV-10>
No user devices added
{isLoading ? "Loading...." : "No user devices added"}
</Text>
)}
@ -73,6 +89,10 @@ const MyGroup = () => {
<Text text90
grey40>{member.userType === ProfileType.PARENT ? "Admin (You)" : "Child"}</Text>
</View>
<View flex-1/>
<UserMenu userId={member?.uid!}/>
</Card>
))}
</>
@ -105,10 +125,108 @@ const MyGroup = () => {
<FloatingButton fullWidth hideBackgroundOverlay visible
button={{label: '+ Add a user device', onPress: () => setShowAddUserDialog(true)}}/>
{/* Add user dialog here */}
<Dialog
visible={showAddUserDialog}
onDismiss={() => setShowAddUserDialog(false)}
panDirection={PanningProvider.Directions.DOWN}
>
<Card padding-25 gap-10>
<Text>
Add a new user device
</Text>
{/* New user information dialog here */}
<Button backgroundColor={"#FD1775"}><Text white>Show a QR Code</Text></Button>
<Button backgroundColor={"#05A8B6"} onPress={() => {
setShowAddUserDialog(false)
setTimeout(() => {
setShowNewUserInfoDialog(true)
}, 500)
}}><Text white>Enter email address</Text></Button>
<TouchableOpacity onPress={() => setShowAddUserDialog(false)} center><Text>Return to user
settings</Text></TouchableOpacity>
</Card>
</Dialog>
<Dialog
panDirection={PanningProvider.Directions.DOWN}
visible={showNewUserInfoDialog}
onDismiss={() => setShowNewUserInfoDialog(false)}
>
<Card padding-25 style={styles.dialogCard}>
<View row spread>
<Text text60M>
New User Information
</Text>
<TouchableOpacity onPress={() => setShowAddUserDialog(false)}>
<Text>X</Text>
</TouchableOpacity>
</View>
<View row centerV gap-20 marginV-20>
<Avatar imageStyle={{borderRadius: 10}} containerStyle={{borderRadius: 10,}} size={60}
backgroundColor={Colors.grey60}/>
<TouchableOpacity onPress={() => {
}}>
<Text style={{color: Colors.green10}}>Upload User Profile Photo</Text>
</TouchableOpacity>
</View>
<Text style={styles.label}>Member Status</Text>
<Picker
editable={!isLoading}
value={selectedStatus}
//@ts-ignore
onChange={item => setSelectedStatus(item)}
style={styles.picker}
showSearch
floatingPlaceholder
>
<Picker.Item label="Child" value={ProfileType.CHILD}/>
<Picker.Item label="Parent" value={ProfileType.PARENT}/>
<Picker.Item label="Caregiver" value={ProfileType.CAREGIVER}/>
</Picker>
<Text style={styles.label}>First Name</Text>
<TextField
editable={!isLoading}
placeholder="First name"
value={firstName}
onChangeText={setFirstName}
style={styles.inputField}
/>
<Text style={styles.label}>Last Name</Text>
<TextField
editable={!isLoading}
placeholder="Last name"
value={lastName}
onChangeText={setLastName}
style={styles.inputField}
/>
<Text style={styles.label}>Email Address</Text>
<TextField
editable={!isLoading}
placeholder="Email address"
value={email}
onChangeText={setEmail}
keyboardType="email-address"
autoCapitalize="none"
style={styles.inputField}
/>
<Button
disabled={!firstName || !lastName || !email || isLoading}
label={isLoading ? "Adding..." : "Add group member"}
backgroundColor="#FD1775"
style={{marginTop: 20}}
onPress={handleCreateSubUser}
/>
</Card>
</Dialog>
</View>
);
};

View File

@ -0,0 +1,62 @@
import React, {useState} from 'react';
import {Button, Card, Colors, Dialog, Hint, ListItem, Text, View} from 'react-native-ui-lib';
import QRCode from 'react-native-qrcode-svg';
import {PanningDirectionsEnum} from "react-native-ui-lib/src/components/panningViews/panningProvider";
const UserMenu = ({userId}:{userId: string}) => {
const [showHint, setShowHint] = useState(false);
const [showQRCodeDialog, setShowQRCodeDialog] = useState(false);
const handleShowQRCode = () => {
setShowHint(false);
setTimeout(() => {
setShowQRCodeDialog(true);
}, 500)
};
return (
<>
<Hint
onBackgroundPress={() => setShowHint(false)}
onPress={() => setShowHint(true)}
color={Colors.white}
customContent={
<View height={18}>
<ListItem
onPress={handleShowQRCode}
>
<Text>Show Login QR Code</Text>
</ListItem>
</View>
}
enableShadow
visible={showHint}
backdropColor="transparent"
>
<View>
<Button link onPress={() => setShowHint(x => !x)}>
<Text>...</Text>
</Button>
</View>
</Hint>
<Dialog
visible={showQRCodeDialog}
onDismiss={() => setShowQRCodeDialog(false)}
panDirection={PanningDirectionsEnum.DOWN}
>
<Card padding-20 center>
<Text marginB-10>Scan this QR Code to Login:</Text>
<QRCode value={userId} size={150} />
<Button
marginT-20
label="Close"
onPress={() => setShowQRCodeDialog(false)}
/>
</Card>
</Dialog>
</>
);
};
export default UserMenu;