Restart app work
This commit is contained in:
parent
2ff34dba52
commit
4f49bb279c
10 changed files with 357 additions and 53 deletions
9
justfile
9
justfile
|
|
@ -21,3 +21,12 @@ dev:
|
|||
|
||||
update-types:
|
||||
npx supabase gen types typescript --project-id "mhcafqvzbrrwvahpvvzd" --schema public > ui/src/types/database.types.ts && cp ui/src/types/database.types.ts api/src/database.types.ts
|
||||
|
||||
expo-install-all:
|
||||
cd xtablo-expo && npx expo install -- --legacy-peer-deps
|
||||
|
||||
expo-install package:
|
||||
cd xtablo-expo && npx expo install {{package}} -- --legacy-peer-deps
|
||||
|
||||
expo-start:
|
||||
cd xtablo-expo && npx expo start
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
import React, { useState } from "react";
|
||||
import { StyleSheet, View, Text } from "react-native";
|
||||
import { StyleSheet, View, Text, Image } from "react-native";
|
||||
import { Button, Input } from "@rn-vui/themed";
|
||||
import { useAuth } from "@/stores/auth";
|
||||
import { Link } from "expo-router";
|
||||
import { Mail, Lock } from "lucide-react-native";
|
||||
import { GoogleLoginButton } from "@/components/GoogleLoginButton";
|
||||
import { AppleLoginButton } from "@/components/AppleLoginButton";
|
||||
|
||||
export default function Auth() {
|
||||
const [email, setEmail] = useState("");
|
||||
|
|
@ -13,42 +16,54 @@ export default function Auth() {
|
|||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text style={styles.title}>Welcome Back!</Text>
|
||||
<Text style={styles.subtitle}>Sign in to your account</Text>
|
||||
<View style={[styles.verticallySpaced, styles.mt40]}>
|
||||
<Image source={require("@/assets/images/logo.jpg")} style={styles.logo} />
|
||||
<Text style={styles.title}>Connexion XTablo</Text>
|
||||
<Text style={styles.subtitle}>Connectez-vous à votre compte</Text>
|
||||
<View style={[styles.verticallySpaced, styles.mt10]}>
|
||||
<Input
|
||||
label="Email"
|
||||
leftIcon={{ type: "font-awesome", name: "envelope" }}
|
||||
label="Adresse email"
|
||||
leftIcon={<Mail size={20} color="#666" />}
|
||||
onChangeText={(text) => setEmail(text)}
|
||||
value={email}
|
||||
placeholder="email@address.com"
|
||||
placeholder="jean@dupont.com"
|
||||
autoCapitalize={"none"}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.verticallySpaced}>
|
||||
<Input
|
||||
label="Password"
|
||||
leftIcon={{ type: "font-awesome", name: "lock" }}
|
||||
label="Mot de passe"
|
||||
leftIcon={<Lock size={20} color="#666" />}
|
||||
onChangeText={(text) => setPassword(text)}
|
||||
value={password}
|
||||
secureTextEntry={true}
|
||||
placeholder="Password"
|
||||
placeholder="Mot de passe"
|
||||
autoCapitalize={"none"}
|
||||
/>
|
||||
</View>
|
||||
<View style={[styles.verticallySpaced, styles.mt20]}>
|
||||
<Button
|
||||
title="Sign in"
|
||||
title="Se connecter"
|
||||
disabled={authLoading}
|
||||
onPress={() => login(email, password)}
|
||||
buttonStyle={styles.button}
|
||||
titleStyle={styles.buttonTitle}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.separatorContainer}>
|
||||
<View style={styles.separator} />
|
||||
<Text style={styles.separatorText}>ou</Text>
|
||||
<View style={styles.separator} />
|
||||
</View>
|
||||
<View style={styles.verticallySpaced}>
|
||||
<GoogleLoginButton />
|
||||
</View>
|
||||
<View style={[styles.verticallySpaced, styles.mt5]}>
|
||||
<AppleLoginButton />
|
||||
</View>
|
||||
<View style={styles.linkContainer}>
|
||||
<Text style={styles.linkText}>Don't have an account? </Text>
|
||||
<Text style={styles.linkText}>Pas encore de compte ? </Text>
|
||||
<Link href="/signup" style={styles.link}>
|
||||
Sign Up
|
||||
S'inscrire
|
||||
</Link>
|
||||
</View>
|
||||
</View>
|
||||
|
|
@ -59,33 +74,46 @@ const styles = StyleSheet.create({
|
|||
container: {
|
||||
flex: 1,
|
||||
justifyContent: "center",
|
||||
padding: 24,
|
||||
padding: 16,
|
||||
backgroundColor: "#f5f5f5", // Light grey background
|
||||
},
|
||||
logo: {
|
||||
width: 80,
|
||||
height: 80,
|
||||
alignSelf: "center",
|
||||
marginBottom: 8,
|
||||
borderRadius: 40,
|
||||
},
|
||||
title: {
|
||||
fontSize: 32,
|
||||
fontSize: 24,
|
||||
fontWeight: "bold",
|
||||
textAlign: "center",
|
||||
marginBottom: 10,
|
||||
marginBottom: 3,
|
||||
color: "#333",
|
||||
},
|
||||
subtitle: {
|
||||
fontSize: 16,
|
||||
fontSize: 14,
|
||||
textAlign: "center",
|
||||
marginBottom: 40,
|
||||
marginBottom: 16,
|
||||
color: "#666",
|
||||
},
|
||||
verticallySpaced: {
|
||||
paddingTop: 8, // Increased padding
|
||||
paddingBottom: 8, // Increased padding
|
||||
paddingTop: 2,
|
||||
paddingBottom: 2,
|
||||
alignSelf: "stretch",
|
||||
},
|
||||
mt20: {
|
||||
marginTop: 20,
|
||||
marginTop: 12,
|
||||
},
|
||||
mt40: {
|
||||
marginTop: 40, // Increased top margin for the first input
|
||||
},
|
||||
mt10: {
|
||||
marginTop: 6,
|
||||
},
|
||||
mt5: {
|
||||
marginTop: 3,
|
||||
},
|
||||
button: {
|
||||
paddingVertical: 12,
|
||||
borderRadius: 8, // Rounded corners
|
||||
|
|
@ -95,10 +123,25 @@ const styles = StyleSheet.create({
|
|||
fontWeight: "bold",
|
||||
color: "#fff", // Ensure text is visible on colored button
|
||||
},
|
||||
separatorContainer: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
marginVertical: 12,
|
||||
},
|
||||
separator: {
|
||||
flex: 1,
|
||||
height: 1,
|
||||
backgroundColor: "#ddd",
|
||||
},
|
||||
separatorText: {
|
||||
marginHorizontal: 15,
|
||||
color: "#666",
|
||||
fontSize: 14,
|
||||
},
|
||||
linkContainer: {
|
||||
flexDirection: "row",
|
||||
justifyContent: "center",
|
||||
marginTop: 20,
|
||||
marginTop: 12,
|
||||
},
|
||||
linkText: {
|
||||
color: "#666",
|
||||
|
|
|
|||
|
|
@ -1,10 +1,14 @@
|
|||
import React, { useState } from "react";
|
||||
import { StyleSheet, View, Text } from "react-native";
|
||||
import { StyleSheet, View, Text, Image } from "react-native";
|
||||
import { Button, Input } from "@rn-vui/themed";
|
||||
import { useAuth } from "@/stores/auth";
|
||||
import { Link } from "expo-router";
|
||||
import { Mail, Lock, User, Building2 } from "lucide-react-native";
|
||||
|
||||
export default function SignUp() {
|
||||
const [firstName, setFirstName] = useState("");
|
||||
const [lastName, setLastName] = useState("");
|
||||
const [companyName, setCompanyName] = useState("");
|
||||
const [email, setEmail] = useState("");
|
||||
const [password, setPassword] = useState("");
|
||||
|
||||
|
|
@ -13,42 +17,76 @@ export default function SignUp() {
|
|||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text style={styles.title}>Create Account</Text>
|
||||
<Text style={styles.subtitle}>Join us!</Text>
|
||||
<View style={[styles.verticallySpaced, styles.mt40]}>
|
||||
<Image source={require("@/assets/images/logo.jpg")} style={styles.logo} />
|
||||
<Text style={styles.title}>Créer un compte XTablo</Text>
|
||||
<Text style={styles.subtitle}>Rejoignez-nous !</Text>
|
||||
<View style={[styles.verticallySpaced, styles.mt10]}>
|
||||
<Input
|
||||
label="Email"
|
||||
leftIcon={{ type: "font-awesome", name: "envelope" }}
|
||||
onChangeText={(text) => setEmail(text)}
|
||||
value={email}
|
||||
placeholder="email@address.com"
|
||||
autoCapitalize={"none"}
|
||||
label="Prénom"
|
||||
leftIcon={<User size={20} color="#666" />}
|
||||
onChangeText={(text) => setFirstName(text)}
|
||||
value={firstName}
|
||||
placeholder="Jean"
|
||||
autoCapitalize={"words"}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.verticallySpaced}>
|
||||
<Input
|
||||
label="Password"
|
||||
leftIcon={{ type: "font-awesome", name: "lock" }}
|
||||
label="Nom"
|
||||
leftIcon={<User size={20} color="#666" />}
|
||||
onChangeText={(text) => setLastName(text)}
|
||||
value={lastName}
|
||||
placeholder="Dupont"
|
||||
autoCapitalize="words"
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.verticallySpaced}>
|
||||
<Input
|
||||
label="Nom de l'entreprise"
|
||||
leftIcon={<Building2 size={20} color="#666" />}
|
||||
onChangeText={(text) => setCompanyName(text)}
|
||||
value={companyName}
|
||||
placeholder="Mon Entreprise"
|
||||
autoCapitalize="words"
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.verticallySpaced}>
|
||||
<Input
|
||||
label="Adresse email"
|
||||
leftIcon={<Mail size={20} color="#666" />}
|
||||
onChangeText={(text) => setEmail(text)}
|
||||
value={email}
|
||||
placeholder="jean@dupont.com"
|
||||
autoCapitalize="none"
|
||||
keyboardType="email-address"
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.verticallySpaced}>
|
||||
<Input
|
||||
label="Mot de passe"
|
||||
leftIcon={<Lock size={20} color="#666" />}
|
||||
onChangeText={(text) => setPassword(text)}
|
||||
value={password}
|
||||
secureTextEntry={true}
|
||||
placeholder="Password"
|
||||
autoCapitalize={"none"}
|
||||
secureTextEntry
|
||||
placeholder="Mot de passe"
|
||||
autoCapitalize="none"
|
||||
/>
|
||||
</View>
|
||||
<View style={[styles.verticallySpaced, styles.mt20]}>
|
||||
<Button
|
||||
title="Sign up"
|
||||
title="S'inscrire"
|
||||
disabled={authLoading}
|
||||
onPress={() => signUp(email, password)}
|
||||
onPress={() =>
|
||||
signUp(email, password, firstName, lastName, companyName)
|
||||
}
|
||||
buttonStyle={styles.button}
|
||||
titleStyle={styles.buttonTitle}
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.linkContainer}>
|
||||
<Text style={styles.linkText}>Already have an account? </Text>
|
||||
<Text style={styles.linkText}>Vous avez déjà un compte ? </Text>
|
||||
<Link href="/login" style={styles.link}>
|
||||
Sign In
|
||||
Se connecter
|
||||
</Link>
|
||||
</View>
|
||||
</View>
|
||||
|
|
@ -60,33 +98,46 @@ const styles = StyleSheet.create({
|
|||
container: {
|
||||
flex: 1,
|
||||
justifyContent: "center",
|
||||
padding: 24,
|
||||
padding: 16,
|
||||
backgroundColor: "#f5f5f5", // Light grey background
|
||||
},
|
||||
logo: {
|
||||
width: 80,
|
||||
height: 80,
|
||||
alignSelf: "center",
|
||||
marginBottom: 8,
|
||||
borderRadius: 40,
|
||||
},
|
||||
title: {
|
||||
fontSize: 32,
|
||||
fontSize: 24,
|
||||
fontWeight: "bold",
|
||||
textAlign: "center",
|
||||
marginBottom: 10,
|
||||
marginBottom: 3,
|
||||
color: "#333",
|
||||
},
|
||||
subtitle: {
|
||||
fontSize: 16,
|
||||
fontSize: 14,
|
||||
textAlign: "center",
|
||||
marginBottom: 40,
|
||||
marginBottom: 16,
|
||||
color: "#666",
|
||||
},
|
||||
verticallySpaced: {
|
||||
paddingTop: 8,
|
||||
paddingBottom: 8,
|
||||
paddingTop: 2,
|
||||
paddingBottom: 2,
|
||||
alignSelf: "stretch",
|
||||
},
|
||||
mt20: {
|
||||
marginTop: 20,
|
||||
marginTop: 12,
|
||||
},
|
||||
mt40: {
|
||||
marginTop: 40,
|
||||
},
|
||||
mt10: {
|
||||
marginTop: 6,
|
||||
},
|
||||
mt5: {
|
||||
marginTop: 3,
|
||||
},
|
||||
button: {
|
||||
paddingVertical: 12,
|
||||
borderRadius: 8,
|
||||
|
|
@ -96,10 +147,25 @@ const styles = StyleSheet.create({
|
|||
fontWeight: "bold",
|
||||
color: "#fff",
|
||||
},
|
||||
separatorContainer: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
marginVertical: 12,
|
||||
},
|
||||
separator: {
|
||||
flex: 1,
|
||||
height: 1,
|
||||
backgroundColor: "#ddd",
|
||||
},
|
||||
separatorText: {
|
||||
marginHorizontal: 15,
|
||||
color: "#666",
|
||||
fontSize: 14,
|
||||
},
|
||||
linkContainer: {
|
||||
flexDirection: "row",
|
||||
justifyContent: "center",
|
||||
marginTop: 20,
|
||||
marginTop: 12,
|
||||
},
|
||||
linkText: {
|
||||
color: "#666",
|
||||
|
|
|
|||
BIN
xtablo-expo/assets/images/google.png
Normal file
BIN
xtablo-expo/assets/images/google.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.6 KiB |
BIN
xtablo-expo/assets/images/logo.jpg
Normal file
BIN
xtablo-expo/assets/images/logo.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 42 KiB |
59
xtablo-expo/components/AppleLoginButton.tsx
Normal file
59
xtablo-expo/components/AppleLoginButton.tsx
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
import React from "react";
|
||||
import { StyleSheet, View, Text, TouchableOpacity } from "react-native";
|
||||
import { useAuth } from "@/stores/auth";
|
||||
import { Svg, Path } from "react-native-svg";
|
||||
|
||||
const AppleIcon = ({ color = "#fff", size = 20 }) => (
|
||||
<Svg width={size} height={size} viewBox="0 0 24 24" fill="none">
|
||||
<Path
|
||||
d="M12.152 6.896c-.948 0-2.415-1.078-3.96-1.04-2.04.027-3.91 1.183-4.961 3.014-2.117 3.675-.546 9.103 1.519 12.09 1.013 1.454 2.208 3.09 3.792 3.039 1.52-.065 2.09-.987 3.935-.987 1.831 0 2.35.987 3.96.948 1.653-.026 2.681-1.507 3.694-2.961 1.169-1.69 1.648-3.327 1.679-3.418-.039-.013-3.182-1.221-3.22-4.857-.026-3.04 2.48-4.494 2.597-4.559-1.429-2.09-3.623-2.324-4.39-2.376-2-.156-3.675 1.09-4.646 1.09z"
|
||||
fill={color}
|
||||
/>
|
||||
<Path
|
||||
d="M15.53 3.83c.843-1.012 1.4-2.427 1.245-3.83-1.207.052-2.662.805-3.532 1.818-.78.896-1.454 2.338-1.273 3.714 1.338.104 2.715-.688 3.559-1.701z"
|
||||
fill={color}
|
||||
/>
|
||||
</Svg>
|
||||
);
|
||||
|
||||
export const AppleLoginButton = () => {
|
||||
const loginWithApple = useAuth((state) => state.loginWithApple);
|
||||
const authLoading = useAuth((state) => state.loading);
|
||||
|
||||
return (
|
||||
<TouchableOpacity
|
||||
style={styles.button}
|
||||
onPress={() => loginWithApple()}
|
||||
disabled={authLoading}
|
||||
>
|
||||
<View style={styles.contentWrapper}>
|
||||
<AppleIcon color="#fff" size={20} />
|
||||
<Text style={styles.text}>Continuer avec Apple</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
button: {
|
||||
backgroundColor: "#000000",
|
||||
borderRadius: 8,
|
||||
height: 48,
|
||||
paddingHorizontal: 12,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
alignSelf: "stretch",
|
||||
},
|
||||
contentWrapper: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
},
|
||||
text: {
|
||||
color: "#ffffff",
|
||||
fontSize: 14,
|
||||
fontWeight: "600",
|
||||
textAlign: "center",
|
||||
marginLeft: 12,
|
||||
},
|
||||
});
|
||||
54
xtablo-expo/components/GoogleLoginButton.tsx
Normal file
54
xtablo-expo/components/GoogleLoginButton.tsx
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
import React from "react";
|
||||
import { StyleSheet, View, Text, TouchableOpacity, Image } from "react-native";
|
||||
import { useAuth } from "@/stores/auth";
|
||||
|
||||
export const GoogleLoginButton = () => {
|
||||
const loginWithGoogle = useAuth((state) => state.loginWithGoogle);
|
||||
const authLoading = useAuth((state) => state.loading);
|
||||
|
||||
return (
|
||||
<TouchableOpacity
|
||||
style={styles.button}
|
||||
onPress={() => loginWithGoogle()}
|
||||
disabled={authLoading}
|
||||
>
|
||||
<View style={styles.contentWrapper}>
|
||||
<Image
|
||||
source={require("@/assets/images/google.png")}
|
||||
style={styles.icon}
|
||||
/>
|
||||
<Text style={styles.text}>Continuer avec Google</Text>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
button: {
|
||||
backgroundColor: "#ffffff",
|
||||
borderColor: "#747775",
|
||||
borderWidth: 1,
|
||||
borderRadius: 8,
|
||||
height: 48,
|
||||
paddingHorizontal: 12,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
alignSelf: "stretch",
|
||||
},
|
||||
contentWrapper: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
},
|
||||
icon: {
|
||||
height: 20,
|
||||
width: 20,
|
||||
marginRight: 12,
|
||||
},
|
||||
text: {
|
||||
color: "#1f1f1f",
|
||||
fontSize: 14,
|
||||
fontWeight: "500",
|
||||
textAlign: "center",
|
||||
},
|
||||
});
|
||||
11
xtablo-expo/package-lock.json
generated
11
xtablo-expo/package-lock.json
generated
|
|
@ -31,6 +31,7 @@
|
|||
"expo-symbols": "~0.4.4",
|
||||
"expo-system-ui": "~5.0.7",
|
||||
"expo-web-browser": "~14.1.6",
|
||||
"lucide-react-native": "^0.525.0",
|
||||
"react": "19.0.0",
|
||||
"react-dom": "19.0.0",
|
||||
"react-native": "0.79.2",
|
||||
|
|
@ -8450,6 +8451,16 @@
|
|||
"yallist": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/lucide-react-native": {
|
||||
"version": "0.525.0",
|
||||
"resolved": "https://registry.npmjs.org/lucide-react-native/-/lucide-react-native-0.525.0.tgz",
|
||||
"integrity": "sha512-f9iIdoZJCDIXhzAMQCNgaiWdiq42ls5ieXvVXwlNHN1q7c5zC1n1U0yOVu6J0oNSF8zvYqY3pK3UPOX+T2YpIQ==",
|
||||
"peerDependencies": {
|
||||
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||
"react-native": "*",
|
||||
"react-native-svg": "^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/make-dir": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz",
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
"expo-symbols": "~0.4.4",
|
||||
"expo-system-ui": "~5.0.7",
|
||||
"expo-web-browser": "~14.1.6",
|
||||
"lucide-react-native": "^0.525.0",
|
||||
"react": "19.0.0",
|
||||
"react-dom": "19.0.0",
|
||||
"react-native": "0.79.2",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { create } from "zustand";
|
||||
import { Session } from "@supabase/supabase-js";
|
||||
import { supabase } from "@/lib/supabase";
|
||||
import * as WebBrowser from "expo-web-browser";
|
||||
|
||||
interface AuthState {
|
||||
session: Session | null;
|
||||
|
|
@ -8,10 +9,20 @@ interface AuthState {
|
|||
initialize: () => Promise<void>;
|
||||
setSession: (session: Session | null) => void;
|
||||
login: (email: string, password: string) => Promise<void>;
|
||||
signUp: (email: string, password: string) => Promise<void>;
|
||||
signUp: (
|
||||
email: string,
|
||||
password: string,
|
||||
firstName: string,
|
||||
lastName: string,
|
||||
companyName: string
|
||||
) => Promise<void>;
|
||||
loginWithGoogle: () => Promise<void>;
|
||||
loginWithApple: () => Promise<void>;
|
||||
signOut: () => Promise<void>;
|
||||
}
|
||||
|
||||
WebBrowser.maybeCompleteAuthSession();
|
||||
|
||||
export const useAuth = create<AuthState>((set) => ({
|
||||
session: null,
|
||||
loading: true,
|
||||
|
|
@ -26,10 +37,60 @@ export const useAuth = create<AuthState>((set) => ({
|
|||
await supabase.auth.signInWithPassword({ email, password });
|
||||
set({ loading: false });
|
||||
},
|
||||
signUp: async (email: string, password: string) => {
|
||||
await supabase.auth.signUp({ email, password });
|
||||
signUp: async (
|
||||
email: string,
|
||||
password: string,
|
||||
firstName: string,
|
||||
lastName: string,
|
||||
companyName: string
|
||||
) => {
|
||||
await supabase.auth.signUp({
|
||||
email,
|
||||
password,
|
||||
options: {
|
||||
data: {
|
||||
firstName,
|
||||
lastName,
|
||||
companyName,
|
||||
},
|
||||
},
|
||||
});
|
||||
set({ loading: false });
|
||||
},
|
||||
loginWithGoogle: async () => {
|
||||
const { data, error } = await supabase.auth.signInWithOAuth({
|
||||
provider: "google",
|
||||
options: {
|
||||
redirectTo: "exp://localhost:8081/--/(home)/(tabs)",
|
||||
},
|
||||
});
|
||||
|
||||
if (error) {
|
||||
console.error("Google login error:", error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.url) {
|
||||
await WebBrowser.openBrowserAsync(data.url);
|
||||
}
|
||||
},
|
||||
loginWithApple: async () => {
|
||||
const { data, error } = await supabase.auth.signInWithOAuth({
|
||||
provider: "apple",
|
||||
options: {
|
||||
redirectTo: "exp://localhost:8081/--/(home)/(tabs)",
|
||||
},
|
||||
});
|
||||
|
||||
if (error) {
|
||||
console.error("Apple login error:", error);
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.url) {
|
||||
await WebBrowser.openBrowserAsync(data.url);
|
||||
}
|
||||
},
|
||||
signOut: async () => {
|
||||
await supabase.auth.signOut();
|
||||
set({ loading: false });
|
||||
|
|
|
|||
Loading…
Reference in a new issue