mirror of
https://github.com/urosran/cally.git
synced 2025-08-26 06:09:40 +00:00
LOgging in with qr code added
This commit is contained in:
@ -1,6 +1,8 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<uses-permission android:name="android.permission.CAMERA"/>
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
|
||||
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
|
@ -2,5 +2,5 @@
|
||||
<string name="app_name">Cally - Planner</string>
|
||||
<string name="expo_splash_screen_resize_mode" translatable="false">contain</string>
|
||||
<string name="expo_splash_screen_status_bar_translucent" translatable="false">false</string>
|
||||
<string name="expo_system_ui_user_interface_style" translatable="false">automatic</string>
|
||||
<string name="expo_system_ui_user_interface_style" translatable="false">light</string>
|
||||
</resources>
|
@ -41,3 +41,7 @@ allprojects {
|
||||
maven { url 'https://www.jitpack.io' }
|
||||
}
|
||||
}
|
||||
// @generated begin expo-camera-import - expo prebuild (DO NOT MODIFY) sync-f244f4f3d8bf7229102e8f992b525b8602c74770
|
||||
def expoCameraMavenPath = new File(["node", "--print", "require.resolve('expo-camera/package.json')"].execute(null, rootDir).text.trim(), "../android/maven")
|
||||
allprojects { repositories { maven { url(expoCameraMavenPath) } } }
|
||||
// @generated end expo-camera-import
|
10
app.json
10
app.json
@ -6,7 +6,7 @@
|
||||
"orientation": "portrait",
|
||||
"icon": "./assets/images/icon.png",
|
||||
"scheme": "myapp",
|
||||
"userInterfaceStyle": "automatic",
|
||||
"userInterfaceStyle": "light",
|
||||
"splash": {
|
||||
"image": "./assets/images/splash.png",
|
||||
"resizeMode": "contain",
|
||||
@ -43,6 +43,14 @@
|
||||
"useFrameworks": "static"
|
||||
}
|
||||
}
|
||||
],
|
||||
[
|
||||
"expo-camera",
|
||||
{
|
||||
"cameraPermission": "Allow $(PRODUCT_NAME) to access your camera",
|
||||
"microphonePermission": "Allow $(PRODUCT_NAME) to access your microphone",
|
||||
"recordAudioAndroid": true
|
||||
}
|
||||
]
|
||||
],
|
||||
"experiments": {
|
||||
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
62
components/pages/settings/user_settings_views/UserMenu.tsx
Normal file
62
components/pages/settings/user_settings_views/UserMenu.tsx
Normal 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;
|
@ -35,9 +35,9 @@ exports.createSubUser = onRequest(async (request, response) => {
|
||||
|
||||
logger.info("Processing user creation", {requestBody: request.body.data});
|
||||
|
||||
const {userType, firstName, lastName, email, password} = request.body.data;
|
||||
const {userType, firstName, lastName, email, password, familyId} = request.body.data;
|
||||
|
||||
if (!email || !password || !firstName || !lastName || !userType) {
|
||||
if (!email || !password || !firstName || !lastName || !userType || !familyId) {
|
||||
logger.warn("Missing required fields in request body", {requestBody: request.body.data});
|
||||
response.status(400).json({error: "Missing required fields"});
|
||||
return;
|
||||
@ -56,7 +56,7 @@ exports.createSubUser = onRequest(async (request, response) => {
|
||||
}
|
||||
|
||||
const userProfile = {
|
||||
userType, name: `${firstName} ${lastName}`, email, uid: userRecord.uid,
|
||||
userType, firstName, lastName, familyId, email, uid: userRecord.uid
|
||||
};
|
||||
|
||||
try {
|
||||
@ -78,3 +78,22 @@ exports.createSubUser = onRequest(async (request, response) => {
|
||||
response.status(500).json({data: {error: error.message}});
|
||||
}
|
||||
});
|
||||
|
||||
exports.generateCustomToken = onRequest(async (request, response) => {
|
||||
try {
|
||||
const {userId} = request.body.data;
|
||||
|
||||
console.log("Generating custom token for userId", {userId});
|
||||
|
||||
if (!userId) {
|
||||
response.status(400).json({error: 'Missing userId'});
|
||||
return;
|
||||
}
|
||||
|
||||
const customToken = await getAuth().createCustomToken(userId);
|
||||
response.status(200).json({data: {token: customToken}});
|
||||
} catch (error) {
|
||||
console.error("Error generating custom token", {error: error.message});
|
||||
response.status(500).json({error: "Failed to generate custom token"});
|
||||
}
|
||||
});
|
||||
|
@ -16,6 +16,7 @@ export interface User {
|
||||
email: string
|
||||
password: string
|
||||
familyId?: string
|
||||
uid?: string
|
||||
}
|
||||
|
||||
export interface ParentProfile extends UserProfile {
|
||||
|
@ -12,8 +12,9 @@ export const useCreateSubUser = () => {
|
||||
mutationFn: async ({email, ...userProfile}: { email: string } & UserProfile) => {
|
||||
if (profileType === ProfileType.PARENT) {
|
||||
return await functions().httpsCallable("createSubUser")({
|
||||
...userProfile,
|
||||
email,
|
||||
userProfile: {...userProfile, familyId: profileData?.familyId}
|
||||
familyId: profileData?.familyId
|
||||
})
|
||||
} else {
|
||||
throw Error("Can't create sub-users as a non-parent.")
|
||||
@ -21,6 +22,7 @@ export const useCreateSubUser = () => {
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({queryKey: ["getChildrenByParentId"]})
|
||||
queryClient.invalidateQueries({queryKey: ["familyMembers"]})
|
||||
}
|
||||
});
|
||||
}
|
21
hooks/firebase/useLoginWithQrCode.ts
Normal file
21
hooks/firebase/useLoginWithQrCode.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import {useMutation} from "react-query";
|
||||
import functions, {FirebaseFunctionsTypes} from '@react-native-firebase/functions';
|
||||
import auth from "@react-native-firebase/auth";
|
||||
|
||||
export const useLoginWithQrCode = () => {
|
||||
return useMutation({
|
||||
mutationKey: ["loginWithQrCode"],
|
||||
mutationFn: async ({userId}: { userId: string }) => {
|
||||
try {
|
||||
const res = await functions().httpsCallable("generateCustomToken")({userId}) as FirebaseFunctionsTypes.HttpsCallableResult<{
|
||||
token: string
|
||||
}>
|
||||
console.log(res)
|
||||
await auth().signInWithCustomToken(res?.data?.token)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
throw Error("Failed to login with QR code.")
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
@ -956,23 +956,31 @@ PODS:
|
||||
- BVLinearGradient (2.8.3):
|
||||
- React-Core
|
||||
- DoubleConversion (1.1.6)
|
||||
- EXBarCodeScanner (13.0.1):
|
||||
- EXImageLoader
|
||||
- ExpoModulesCore
|
||||
- ZXingObjC/OneD
|
||||
- ZXingObjC/PDF417
|
||||
- EXConstants (16.0.2):
|
||||
- ExpoModulesCore
|
||||
- EXImageLoader (4.7.0):
|
||||
- ExpoModulesCore
|
||||
- React-Core
|
||||
- EXJSONUtils (0.13.1)
|
||||
- EXManifests (0.14.3):
|
||||
- ExpoModulesCore
|
||||
- Expo (51.0.34):
|
||||
- ExpoModulesCore
|
||||
- expo-dev-client (4.0.24):
|
||||
- expo-dev-client (4.0.27):
|
||||
- EXManifests
|
||||
- expo-dev-launcher
|
||||
- expo-dev-menu
|
||||
- expo-dev-menu-interface
|
||||
- EXUpdatesInterface
|
||||
- expo-dev-launcher (4.0.26):
|
||||
- expo-dev-launcher (4.0.27):
|
||||
- DoubleConversion
|
||||
- EXManifests
|
||||
- expo-dev-launcher/Main (= 4.0.26)
|
||||
- expo-dev-launcher/Main (= 4.0.27)
|
||||
- expo-dev-menu
|
||||
- expo-dev-menu-interface
|
||||
- ExpoModulesCore
|
||||
@ -998,7 +1006,7 @@ PODS:
|
||||
- ReactCommon/turbomodule/bridging
|
||||
- ReactCommon/turbomodule/core
|
||||
- Yoga
|
||||
- expo-dev-launcher/Main (4.0.26):
|
||||
- expo-dev-launcher/Main (4.0.27):
|
||||
- DoubleConversion
|
||||
- EXManifests
|
||||
- expo-dev-launcher/Unsafe
|
||||
@ -1027,7 +1035,7 @@ PODS:
|
||||
- ReactCommon/turbomodule/bridging
|
||||
- ReactCommon/turbomodule/core
|
||||
- Yoga
|
||||
- expo-dev-launcher/Unsafe (4.0.26):
|
||||
- expo-dev-launcher/Unsafe (4.0.27):
|
||||
- DoubleConversion
|
||||
- EXManifests
|
||||
- expo-dev-menu
|
||||
@ -1055,10 +1063,10 @@ PODS:
|
||||
- ReactCommon/turbomodule/bridging
|
||||
- ReactCommon/turbomodule/core
|
||||
- Yoga
|
||||
- expo-dev-menu (5.0.20):
|
||||
- expo-dev-menu (5.0.21):
|
||||
- DoubleConversion
|
||||
- expo-dev-menu/Main (= 5.0.20)
|
||||
- expo-dev-menu/ReactNativeCompatibles (= 5.0.20)
|
||||
- expo-dev-menu/Main (= 5.0.21)
|
||||
- expo-dev-menu/ReactNativeCompatibles (= 5.0.21)
|
||||
- glog
|
||||
- hermes-engine
|
||||
- RCT-Folly (= 2024.01.01.00)
|
||||
@ -1079,7 +1087,7 @@ PODS:
|
||||
- ReactCommon/turbomodule/core
|
||||
- Yoga
|
||||
- expo-dev-menu-interface (1.8.3)
|
||||
- expo-dev-menu/Main (5.0.20):
|
||||
- expo-dev-menu/Main (5.0.21):
|
||||
- DoubleConversion
|
||||
- EXManifests
|
||||
- expo-dev-menu-interface
|
||||
@ -1105,7 +1113,7 @@ PODS:
|
||||
- ReactCommon/turbomodule/bridging
|
||||
- ReactCommon/turbomodule/core
|
||||
- Yoga
|
||||
- expo-dev-menu/ReactNativeCompatibles (5.0.20):
|
||||
- expo-dev-menu/ReactNativeCompatibles (5.0.21):
|
||||
- DoubleConversion
|
||||
- glog
|
||||
- hermes-engine
|
||||
@ -1126,7 +1134,7 @@ PODS:
|
||||
- ReactCommon/turbomodule/bridging
|
||||
- ReactCommon/turbomodule/core
|
||||
- Yoga
|
||||
- expo-dev-menu/SafeAreaView (5.0.20):
|
||||
- expo-dev-menu/SafeAreaView (5.0.21):
|
||||
- DoubleConversion
|
||||
- ExpoModulesCore
|
||||
- glog
|
||||
@ -1148,7 +1156,7 @@ PODS:
|
||||
- ReactCommon/turbomodule/bridging
|
||||
- ReactCommon/turbomodule/core
|
||||
- Yoga
|
||||
- expo-dev-menu/Vendored (5.0.20):
|
||||
- expo-dev-menu/Vendored (5.0.21):
|
||||
- DoubleConversion
|
||||
- expo-dev-menu/SafeAreaView
|
||||
- glog
|
||||
@ -1172,6 +1180,10 @@ PODS:
|
||||
- Yoga
|
||||
- ExpoAsset (10.0.10):
|
||||
- ExpoModulesCore
|
||||
- ExpoCamera (15.0.16):
|
||||
- ExpoModulesCore
|
||||
- ZXingObjC/OneD
|
||||
- ZXingObjC/PDF417
|
||||
- ExpoFileSystem (17.0.1):
|
||||
- ExpoModulesCore
|
||||
- ExpoFont (12.0.10):
|
||||
@ -2713,12 +2725,19 @@ PODS:
|
||||
- React-Core
|
||||
- SocketRocket (0.7.0)
|
||||
- Yoga (0.0.0)
|
||||
- ZXingObjC/Core (3.6.9)
|
||||
- ZXingObjC/OneD (3.6.9):
|
||||
- ZXingObjC/Core
|
||||
- ZXingObjC/PDF417 (3.6.9):
|
||||
- ZXingObjC/Core
|
||||
|
||||
DEPENDENCIES:
|
||||
- boost (from `../node_modules/react-native/third-party-podspecs/boost.podspec`)
|
||||
- BVLinearGradient (from `../node_modules/react-native-linear-gradient`)
|
||||
- DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`)
|
||||
- EXBarCodeScanner (from `../node_modules/expo-barcode-scanner/ios`)
|
||||
- EXConstants (from `../node_modules/expo-constants/ios`)
|
||||
- EXImageLoader (from `../node_modules/expo-image-loader/ios`)
|
||||
- EXJSONUtils (from `../node_modules/expo-json-utils/ios`)
|
||||
- EXManifests (from `../node_modules/expo-manifests/ios`)
|
||||
- Expo (from `../node_modules/expo`)
|
||||
@ -2727,6 +2746,7 @@ DEPENDENCIES:
|
||||
- expo-dev-menu (from `../node_modules/expo-dev-menu`)
|
||||
- expo-dev-menu-interface (from `../node_modules/expo-dev-menu-interface/ios`)
|
||||
- ExpoAsset (from `../node_modules/expo-asset/ios`)
|
||||
- ExpoCamera (from `../node_modules/expo-camera/ios`)
|
||||
- ExpoFileSystem (from `../node_modules/expo-file-system/ios`)
|
||||
- ExpoFont (from `../node_modules/expo-font/ios`)
|
||||
- ExpoHead (from `../node_modules/expo-router/ios`)
|
||||
@ -2835,6 +2855,7 @@ SPEC REPOS:
|
||||
- PromisesSwift
|
||||
- RecaptchaInterop
|
||||
- SocketRocket
|
||||
- ZXingObjC
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
boost:
|
||||
@ -2843,8 +2864,12 @@ EXTERNAL SOURCES:
|
||||
:path: "../node_modules/react-native-linear-gradient"
|
||||
DoubleConversion:
|
||||
:podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec"
|
||||
EXBarCodeScanner:
|
||||
:path: "../node_modules/expo-barcode-scanner/ios"
|
||||
EXConstants:
|
||||
:path: "../node_modules/expo-constants/ios"
|
||||
EXImageLoader:
|
||||
:path: "../node_modules/expo-image-loader/ios"
|
||||
EXJSONUtils:
|
||||
:path: "../node_modules/expo-json-utils/ios"
|
||||
EXManifests:
|
||||
@ -2861,6 +2886,8 @@ EXTERNAL SOURCES:
|
||||
:path: "../node_modules/expo-dev-menu-interface/ios"
|
||||
ExpoAsset:
|
||||
:path: "../node_modules/expo-asset/ios"
|
||||
ExpoCamera:
|
||||
:path: "../node_modules/expo-camera/ios"
|
||||
ExpoFileSystem:
|
||||
:path: "../node_modules/expo-file-system/ios"
|
||||
ExpoFont:
|
||||
@ -3017,15 +3044,18 @@ SPEC CHECKSUMS:
|
||||
BoringSSL-GRPC: 1e2348957acdbcad360b80a264a90799984b2ba6
|
||||
BVLinearGradient: 880f91a7854faff2df62518f0281afb1c60d49a3
|
||||
DoubleConversion: 76ab83afb40bddeeee456813d9c04f67f78771b5
|
||||
EXBarCodeScanner: e2dd9b42c1b522a2adc9202b1dfbc64cb34456d1
|
||||
EXConstants: 409690fbfd5afea964e5e9d6c4eb2c2b59222c59
|
||||
EXImageLoader: ab589d67d6c5f2c33572afea9917304418566334
|
||||
EXJSONUtils: 30c17fd9cc364d722c0946a550dfbf1be92ef6a4
|
||||
EXManifests: c1fab4c3237675e7b0299ea8df0bcb14baca4f42
|
||||
Expo: 963ef4ae102e4f4ac114a8510d70127c44adffbf
|
||||
expo-dev-client: 44e9bb8afbf444bc380c606475030fe8929de203
|
||||
expo-dev-launcher: 012fd9aea425d902b5404e75e58d0bacf8e2542f
|
||||
expo-dev-menu: 045ace71676316ecac9bff8c2ac34fa4d8ef8392
|
||||
expo-dev-client: 85deba11af998ea86e62093b17fce56aa2c6f26b
|
||||
expo-dev-launcher: fe4f2c0a0aa627449eeaec5f9f11e04090f97c40
|
||||
expo-dev-menu: 5b14897ecce3a8cf9e9cf9109344c2c192a3766a
|
||||
expo-dev-menu-interface: be32c09f1e03833050f0ee290dcc86b3ad0e73e4
|
||||
ExpoAsset: 323700f291684f110fb55f0d4022a3362ea9f875
|
||||
ExpoCamera: 929be541d1c1319fcf32f9f5d9df8b97804346b5
|
||||
ExpoFileSystem: 80bfe850b1f9922c16905822ecbf97acd711dc51
|
||||
ExpoFont: 00756e6c796d8f7ee8d211e29c8b619e75cbf238
|
||||
ExpoHead: fcb28a68ed4ba28f177394d2dfb8a0a8824cd103
|
||||
@ -3127,6 +3157,7 @@ SPEC CHECKSUMS:
|
||||
RNSVG: 4590aa95758149fa27c5c83e54a6a466349a1688
|
||||
SocketRocket: abac6f5de4d4d62d24e11868d7a2f427e0ef940d
|
||||
Yoga: bd92064a0d558be92786820514d74fc4dddd1233
|
||||
ZXingObjC: 8898711ab495761b2dbbdec76d90164a6d7e14c5
|
||||
|
||||
PODFILE CHECKSUM: 50f618790da7cbbfd5c5e988b7f9370bd45d34a6
|
||||
|
||||
|
@ -55,6 +55,10 @@
|
||||
<key>NSAllowsLocalNetworking</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>Allow $(PRODUCT_NAME) to access your camera</string>
|
||||
<key>NSMicrophoneUsageDescription</key>
|
||||
<string>Allow $(PRODUCT_NAME) to access your microphone</string>
|
||||
<key>NSUserActivityTypes</key>
|
||||
<array>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route</string>
|
||||
@ -65,6 +69,7 @@
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route</string>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route</string>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route</string>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route</string>
|
||||
</array>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>SplashScreen</string>
|
||||
@ -89,7 +94,7 @@
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UIUserInterfaceStyle</key>
|
||||
<string>Automatic</string>
|
||||
<string>Light</string>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
</dict>
|
||||
|
@ -39,9 +39,11 @@
|
||||
"@react-navigation/native": "^6.0.2",
|
||||
"date-fns": "^3.6.0",
|
||||
"expo": "~51.0.24",
|
||||
"expo-barcode-scanner": "~13.0.1",
|
||||
"expo-build-properties": "~0.12.4",
|
||||
"expo-camera": "~15.0.16",
|
||||
"expo-constants": "~16.0.2",
|
||||
"expo-dev-client": "~4.0.21",
|
||||
"expo-dev-client": "~4.0.27",
|
||||
"expo-font": "~12.0.9",
|
||||
"expo-linking": "~6.3.1",
|
||||
"expo-router": "~3.5.20",
|
||||
@ -62,6 +64,7 @@
|
||||
"react-native-gifted-charts": "^1.4.41",
|
||||
"react-native-linear-gradient": "^2.8.3",
|
||||
"react-native-onboarding-swiper": "^1.3.0",
|
||||
"react-native-qrcode-svg": "^6.3.2",
|
||||
"react-native-reanimated": "~3.10.1",
|
||||
"react-native-safe-area-context": "4.10.5",
|
||||
"react-native-screens": "3.31.1",
|
||||
|
Reference in New Issue
Block a user