mirror of
https://github.com/Sosokker/chefhai.git
synced 2025-12-19 05:54:08 +01:00
fix: switch to supabase
This commit is contained in:
parent
3c1aad96b1
commit
0a554e69d1
@ -1,27 +0,0 @@
|
|||||||
import { initializeApp } from "firebase/app";
|
|
||||||
import { getAuth } from "firebase/auth";
|
|
||||||
import { getFirestore } from "firebase/firestore";
|
|
||||||
|
|
||||||
import Constants from 'expo-constants';
|
|
||||||
|
|
||||||
const {
|
|
||||||
FIREBASE_API_KEY,
|
|
||||||
FIREBASE_AUTH_DOMAIN,
|
|
||||||
FIREBASE_PROJECT_ID,
|
|
||||||
FIREBASE_STORAGE_BUCKET,
|
|
||||||
FIREBASE_MESSAGING_SENDER_ID,
|
|
||||||
FIREBASE_APP_ID,
|
|
||||||
} = Constants.expoConfig?.extra || {};
|
|
||||||
|
|
||||||
const firebaseConfig = {
|
|
||||||
apiKey: FIREBASE_API_KEY,
|
|
||||||
authDomain: FIREBASE_AUTH_DOMAIN,
|
|
||||||
projectId: FIREBASE_PROJECT_ID,
|
|
||||||
storageBucket: FIREBASE_STORAGE_BUCKET,
|
|
||||||
messagingSenderId: FIREBASE_MESSAGING_SENDER_ID,
|
|
||||||
appId: FIREBASE_APP_ID,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const FIREBASE_APP = initializeApp(firebaseConfig);
|
|
||||||
export const FIREBASE_AUTH = getAuth(FIREBASE_APP);
|
|
||||||
export const FIREBASE_DB = getFirestore(FIREBASE_APP);
|
|
||||||
@ -1,4 +1,5 @@
|
|||||||
import { useAuth } from "@/context/auth-context";
|
import { useAuth } from "@/context/auth-context";
|
||||||
|
import "@/global.css";
|
||||||
import { Redirect } from "expo-router";
|
import { Redirect } from "expo-router";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { ActivityIndicator, View } from "react-native";
|
import { ActivityIndicator, View } from "react-native";
|
||||||
|
|||||||
@ -36,7 +36,9 @@ export default function SignupScreen() {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
await signup(name, email, password);
|
// Only pass email and password to signup, as per new auth-context
|
||||||
|
await signup(email, password);
|
||||||
|
// Optionally, save name to profile after signup here in the future
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
Alert.alert("Error", "Failed to sign up. Please try again.");
|
Alert.alert("Error", "Failed to sign up. Please try again.");
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@ -1,14 +1,13 @@
|
|||||||
import { router } from 'expo-router';
|
import { router } from "expo-router";
|
||||||
import * as SecureStore from 'expo-secure-store';
|
import * as SecureStore from "expo-secure-store";
|
||||||
import { createUserWithEmailAndPassword, signInWithEmailAndPassword, signOut, User } from 'firebase/auth';
|
import React, { createContext, useContext, useEffect, useState } from "react";
|
||||||
import React, { createContext, useContext, useEffect, useState } from 'react';
|
import { supabase } from "../services/supabase";
|
||||||
import { FIREBASE_AUTH } from '../FirebaseConfig';
|
|
||||||
|
|
||||||
type AuthContextType = {
|
type AuthContextType = {
|
||||||
isAuthenticated: boolean;
|
isAuthenticated: boolean;
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
login: (email: string, password: string) => Promise<void>;
|
login: (email: string, password: string) => Promise<void>;
|
||||||
signup: (name: string, email: string, password: string) => Promise<void>;
|
signup: (email: string, password: string) => Promise<void>;
|
||||||
logout: () => Promise<void>;
|
logout: () => Promise<void>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -17,77 +16,120 @@ const AuthContext = createContext<AuthContextType | null>(null);
|
|||||||
export function AuthProvider({ children }: { children: React.ReactNode }) {
|
export function AuthProvider({ children }: { children: React.ReactNode }) {
|
||||||
const [authState, setAuthState] = useState({
|
const [authState, setAuthState] = useState({
|
||||||
isAuthenticated: false,
|
isAuthenticated: false,
|
||||||
isLoading: true
|
isLoading: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Use a single useEffect to check authentication status only once on mount
|
// Use a single useEffect to check authentication status only once on mount
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Check if user is logged in on app start
|
// Check if user is logged in on app start
|
||||||
async function loadToken() {
|
async function loadSession() {
|
||||||
try {
|
try {
|
||||||
const token = await SecureStore.getItemAsync('userToken');
|
const sessionStr = await SecureStore.getItemAsync("sbSession");
|
||||||
// Update state only once with both values
|
let session = null;
|
||||||
|
if (sessionStr) {
|
||||||
|
session = JSON.parse(sessionStr);
|
||||||
|
}
|
||||||
setAuthState({
|
setAuthState({
|
||||||
isAuthenticated: !!token,
|
isAuthenticated: !!session,
|
||||||
isLoading: false
|
isLoading: false,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('Error loading token:', error);
|
console.log("Error loading session:", error);
|
||||||
setAuthState({
|
setAuthState({
|
||||||
isAuthenticated: false,
|
isAuthenticated: false,
|
||||||
isLoading: false
|
isLoading: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadToken();
|
loadSession();
|
||||||
}, []); // Empty dependency array ensures this runs only once
|
|
||||||
|
// Listen to Supabase auth state changes
|
||||||
|
const { data: listener } = supabase.auth.onAuthStateChange(
|
||||||
|
async (event, session) => {
|
||||||
|
if (event === "SIGNED_IN" && session) {
|
||||||
|
await SecureStore.setItemAsync("sbSession", JSON.stringify(session));
|
||||||
|
setAuthState({ isAuthenticated: true, isLoading: false });
|
||||||
|
} else if (event === "SIGNED_OUT") {
|
||||||
|
await SecureStore.deleteItemAsync("sbSession");
|
||||||
|
setAuthState({ isAuthenticated: false, isLoading: false });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
listener?.subscription.unsubscribe();
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
const login = async (email: string, password: string) => {
|
const login = async (email: string, password: string) => {
|
||||||
try {
|
try {
|
||||||
const userCredential = await signInWithEmailAndPassword(FIREBASE_AUTH, email, password);
|
setAuthState((prev) => ({ ...prev, isLoading: true }));
|
||||||
const user: User = userCredential.user;
|
const { error, data } = await supabase.auth.signInWithPassword({
|
||||||
const idToken = await user.getIdToken();
|
email,
|
||||||
await SecureStore.setItemAsync('userToken', idToken);
|
password,
|
||||||
|
});
|
||||||
|
if (error) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
if (data.session) {
|
||||||
|
await SecureStore.setItemAsync(
|
||||||
|
"sbSession",
|
||||||
|
JSON.stringify(data.session)
|
||||||
|
);
|
||||||
|
setAuthState({ ...authState, isAuthenticated: true, isLoading: false });
|
||||||
|
router.replace("../(tabs)/home");
|
||||||
|
} else {
|
||||||
setAuthState({
|
setAuthState({
|
||||||
...authState,
|
...authState,
|
||||||
isAuthenticated: true
|
isAuthenticated: false,
|
||||||
|
isLoading: false,
|
||||||
});
|
});
|
||||||
router.replace('../(tabs)/home');
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Login error:', error);
|
console.error("Login error:", error);
|
||||||
|
setAuthState((prev) => ({ ...prev, isLoading: false }));
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const signup = async (name: string, email: string, password: string) => {
|
const signup = async (email: string, password: string) => {
|
||||||
try {
|
try {
|
||||||
const userCredential = await createUserWithEmailAndPassword(FIREBASE_AUTH, email, password);
|
setAuthState((prev) => ({ ...prev, isLoading: true }));
|
||||||
const user: User = userCredential.user;
|
const { data, error } = await supabase.auth.signUp({ email, password });
|
||||||
const idToken = await user.getIdToken();
|
if (error) {
|
||||||
await SecureStore.setItemAsync('userToken', idToken);
|
throw error;
|
||||||
|
}
|
||||||
|
if (data.session) {
|
||||||
|
await SecureStore.setItemAsync(
|
||||||
|
"sbSession",
|
||||||
|
JSON.stringify(data.session)
|
||||||
|
);
|
||||||
|
setAuthState({ ...authState, isAuthenticated: true, isLoading: false });
|
||||||
|
router.replace("./(tabs)/home");
|
||||||
|
} else {
|
||||||
setAuthState({
|
setAuthState({
|
||||||
...authState,
|
...authState,
|
||||||
isAuthenticated: true
|
isAuthenticated: false,
|
||||||
|
isLoading: false,
|
||||||
});
|
});
|
||||||
router.replace('./(tabs)/home');
|
// Optionally, prompt user to check email for verification
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Signup error:', error);
|
console.error("Signup error:", error);
|
||||||
|
setAuthState((prev) => ({ ...prev, isLoading: false }));
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const logout = async () => {
|
const logout = async () => {
|
||||||
try {
|
try {
|
||||||
await signOut(FIREBASE_AUTH);
|
await supabase.auth.signOut();
|
||||||
await SecureStore.deleteItemAsync('userToken');
|
await SecureStore.deleteItemAsync("sbSession");
|
||||||
setAuthState({
|
setAuthState({ ...authState, isAuthenticated: false });
|
||||||
...authState,
|
router.replace("/");
|
||||||
isAuthenticated: false
|
|
||||||
});
|
|
||||||
router.replace('/');
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Logout error:', error);
|
console.error("Logout error:", error);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -99,7 +141,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
|||||||
isLoading: authState.isLoading,
|
isLoading: authState.isLoading,
|
||||||
login,
|
login,
|
||||||
signup,
|
signup,
|
||||||
logout
|
logout,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
@ -110,7 +152,7 @@ export function AuthProvider({ children }: { children: React.ReactNode }) {
|
|||||||
export function useAuth() {
|
export function useAuth() {
|
||||||
const context = useContext(AuthContext);
|
const context = useContext(AuthContext);
|
||||||
if (!context) {
|
if (!context) {
|
||||||
throw new Error('useAuth must be used within an AuthProvider');
|
throw new Error("useAuth must be used within an AuthProvider");
|
||||||
}
|
}
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
@ -1,8 +1,6 @@
|
|||||||
// Learn more https://docs.expo.io/guides/customizing-metro
|
const { getDefaultConfig } = require("expo/metro-config");
|
||||||
const { getDefaultConfig } = require('expo/metro-config');
|
const { withNativeWind } = require('nativewind/metro');
|
||||||
|
|
||||||
/** @type {import('expo/metro-config').MetroConfig} */
|
const config = getDefaultConfig(__dirname)
|
||||||
const config = getDefaultConfig(__dirname);
|
|
||||||
config.resolver.assetExts.push('cjs');
|
|
||||||
|
|
||||||
module.exports = config;
|
module.exports = withNativeWind(config, { input: './global.css' })
|
||||||
1150
package-lock.json
generated
1150
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -13,10 +13,12 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@expo/ngrok": "^4.1.3",
|
"@expo/ngrok": "^4.1.3",
|
||||||
"@expo/vector-icons": "^14.1.0",
|
"@expo/vector-icons": "^14.1.0",
|
||||||
|
"@react-native-async-storage/async-storage": "2.1.2",
|
||||||
"@react-navigation/bottom-tabs": "^7.3.10",
|
"@react-navigation/bottom-tabs": "^7.3.10",
|
||||||
"@react-navigation/elements": "^2.3.8",
|
"@react-navigation/elements": "^2.3.8",
|
||||||
"@react-navigation/native": "^7.1.6",
|
"@react-navigation/native": "^7.1.6",
|
||||||
"expo": "~53.0.8",
|
"@supabase/supabase-js": "2.49.5-next.1",
|
||||||
|
"expo": "^53.0.9",
|
||||||
"expo-blur": "~14.1.4",
|
"expo-blur": "~14.1.4",
|
||||||
"expo-constants": "~17.1.6",
|
"expo-constants": "~17.1.6",
|
||||||
"expo-font": "~13.3.1",
|
"expo-font": "~13.3.1",
|
||||||
@ -31,14 +33,13 @@
|
|||||||
"expo-symbols": "~0.4.4",
|
"expo-symbols": "~0.4.4",
|
||||||
"expo-system-ui": "~5.0.7",
|
"expo-system-ui": "~5.0.7",
|
||||||
"expo-web-browser": "~14.1.6",
|
"expo-web-browser": "~14.1.6",
|
||||||
"firebase": "^11.7.1",
|
|
||||||
"nativewind": "^4.1.23",
|
"nativewind": "^4.1.23",
|
||||||
"react": "19.0.0",
|
"react": "19.0.0",
|
||||||
"react-dom": "19.0.0",
|
"react-dom": "19.0.0",
|
||||||
"react-native": "0.79.2",
|
"react-native": "0.79.2",
|
||||||
"react-native-gesture-handler": "~2.24.0",
|
"react-native-gesture-handler": "~2.24.0",
|
||||||
"react-native-reanimated": "~3.17.4",
|
"react-native-reanimated": "^3.16.2",
|
||||||
"react-native-safe-area-context": "5.4.0",
|
"react-native-safe-area-context": "^5.4.0",
|
||||||
"react-native-screens": "~4.10.0",
|
"react-native-screens": "~4.10.0",
|
||||||
"react-native-web": "~0.20.0",
|
"react-native-web": "~0.20.0",
|
||||||
"react-native-webview": "13.13.5",
|
"react-native-webview": "13.13.5",
|
||||||
|
|||||||
14
services/supabase.ts
Normal file
14
services/supabase.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||||
|
import { createClient } from '@supabase/supabase-js';
|
||||||
|
|
||||||
|
const supabaseUrl = process.env.EXPO_PUBLIC_SUPABASE_PROJECT_URL as string;
|
||||||
|
const supabaseAnonKey = process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY as string;
|
||||||
|
|
||||||
|
export const supabase = createClient(supabaseUrl, supabaseAnonKey, {
|
||||||
|
auth: {
|
||||||
|
storage: AsyncStorage,
|
||||||
|
autoRefreshToken: true,
|
||||||
|
persistSession: true,
|
||||||
|
detectSessionInUrl: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
@ -4,7 +4,7 @@
|
|||||||
"strict": true,
|
"strict": true,
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": [
|
"@/*": [
|
||||||
"./*"
|
"./*",
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user