update google app id, dan fb app id

This commit is contained in:
dios.one
2026-05-07 15:11:02 +07:00
parent fe00f9abad
commit db7231e60f
6 changed files with 223 additions and 23 deletions
+3 -1
View File
@@ -6,6 +6,7 @@
"orientation": "portrait",
"icon": "./assets/icon.png",
"userInterfaceStyle": "dark",
"scheme": "nova40",
"splash": {
"image": "./assets/splash-icon.png",
"resizeMode": "contain",
@@ -33,7 +34,8 @@
},
"plugins": [
"@react-native-firebase/app",
"@react-native-firebase/crashlytics"
"@react-native-firebase/crashlytics",
"expo-web-browser"
],
"extra": {
"eas": {
+94
View File
@@ -20,6 +20,8 @@
"@supabase/supabase-js": "^2.103.0",
"babel-preset-expo": "~54.0.10",
"expo": "~54.0.0",
"expo-auth-session": "~7.0.11",
"expo-crypto": "~15.0.9",
"expo-dev-client": "~6.0.21",
"expo-image-picker": "~17.0.11",
"expo-linear-gradient": "~15.0.8",
@@ -27,6 +29,7 @@
"expo-print": "~15.0.8",
"expo-sharing": "~14.0.8",
"expo-status-bar": "~3.0.9",
"expo-web-browser": "~15.0.11",
"react": "19.1.0",
"react-native": "0.81.5",
"react-native-gesture-handler": "~2.28.0",
@@ -5153,6 +5156,59 @@
}
}
},
"node_modules/expo-auth-session": {
"version": "7.0.11",
"resolved": "https://registry.npmjs.org/expo-auth-session/-/expo-auth-session-7.0.11.tgz",
"integrity": "sha512-AhWtt/m9rb1Po77X/VBFbeE6UTgbm2vXP2iCblUSRsHCw2qD6lO0ulKUB8Xyxy9FtoI9yrNQ1iwCNgIIgo8VYQ==",
"license": "MIT",
"dependencies": {
"expo-application": "~7.0.8",
"expo-constants": "~18.0.13",
"expo-crypto": "~15.0.9",
"expo-linking": "~8.0.12",
"expo-web-browser": "~15.0.11",
"invariant": "^2.2.4"
},
"peerDependencies": {
"react": "*",
"react-native": "*"
}
},
"node_modules/expo-auth-session/node_modules/expo-application": {
"version": "7.0.8",
"resolved": "https://registry.npmjs.org/expo-application/-/expo-application-7.0.8.tgz",
"integrity": "sha512-qFGyxk7VJbrNOQWBbE09XUuGuvkOgFS9QfToaK2FdagM2aQ+x3CvGV2DuVgl/l4ZxPgIf3b/MNh9xHpwSwn74Q==",
"license": "MIT",
"peerDependencies": {
"expo": "*"
}
},
"node_modules/expo-auth-session/node_modules/expo-constants": {
"version": "18.0.13",
"resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-18.0.13.tgz",
"integrity": "sha512-FnZn12E1dRYKDHlAdIyNFhBurKTS3F9CrfrBDJI5m3D7U17KBHMQ6JEfYlSj7LG7t+Ulr+IKaj58L1k5gBwTcQ==",
"license": "MIT",
"dependencies": {
"@expo/config": "~12.0.13",
"@expo/env": "~2.0.8"
},
"peerDependencies": {
"expo": "*",
"react-native": "*"
}
},
"node_modules/expo-crypto": {
"version": "15.0.9",
"resolved": "https://registry.npmjs.org/expo-crypto/-/expo-crypto-15.0.9.tgz",
"integrity": "sha512-SNWKa2fXx7v9gkp1h/7nqXY5XN7qgNDn3yRc2aO0gWGbeMbvob/haMxxsPFe9f51aqH5NjNCqHf2kvLhvAd8KQ==",
"license": "MIT",
"dependencies": {
"base64-js": "^1.3.0"
},
"peerDependencies": {
"expo": "*"
}
},
"node_modules/expo-dev-client": {
"version": "6.0.21",
"resolved": "https://registry.npmjs.org/expo-dev-client/-/expo-dev-client-6.0.21.tgz",
@@ -5242,6 +5298,34 @@
"react-native": "*"
}
},
"node_modules/expo-linking": {
"version": "8.0.12",
"resolved": "https://registry.npmjs.org/expo-linking/-/expo-linking-8.0.12.tgz",
"integrity": "sha512-FpXeIpFgZuxihwT9lBo86YD3y6LphBuAhN680MMxm/Y7fmsc57vimn2d3vFu68VI0+Z9w457t494mu2wvlgWTQ==",
"license": "MIT",
"dependencies": {
"expo-constants": "~18.0.13",
"invariant": "^2.2.4"
},
"peerDependencies": {
"react": "*",
"react-native": "*"
}
},
"node_modules/expo-linking/node_modules/expo-constants": {
"version": "18.0.13",
"resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-18.0.13.tgz",
"integrity": "sha512-FnZn12E1dRYKDHlAdIyNFhBurKTS3F9CrfrBDJI5m3D7U17KBHMQ6JEfYlSj7LG7t+Ulr+IKaj58L1k5gBwTcQ==",
"license": "MIT",
"dependencies": {
"@expo/config": "~12.0.13",
"@expo/env": "~2.0.8"
},
"peerDependencies": {
"expo": "*",
"react-native": "*"
}
},
"node_modules/expo-manifests": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/expo-manifests/-/expo-manifests-1.0.11.tgz",
@@ -5344,6 +5428,16 @@
"expo": "*"
}
},
"node_modules/expo-web-browser": {
"version": "15.0.11",
"resolved": "https://registry.npmjs.org/expo-web-browser/-/expo-web-browser-15.0.11.tgz",
"integrity": "sha512-r2LS4Ro6DgUPZkcaEfgt8mp9eJuoA93x11Jh7S6utFe0FEzvUNn2yFhxg8XVwESaaHGt2k5V8LuK36rsp0BeIw==",
"license": "MIT",
"peerDependencies": {
"expo": "*",
"react-native": "*"
}
},
"node_modules/expo/node_modules/@expo/cli": {
"version": "54.0.24",
"resolved": "https://registry.npmjs.org/@expo/cli/-/cli-54.0.24.tgz",
+3
View File
@@ -21,6 +21,8 @@
"@supabase/supabase-js": "^2.103.0",
"babel-preset-expo": "~54.0.10",
"expo": "~54.0.0",
"expo-auth-session": "~7.0.11",
"expo-crypto": "~15.0.9",
"expo-dev-client": "~6.0.21",
"expo-image-picker": "~17.0.11",
"expo-linear-gradient": "~15.0.8",
@@ -28,6 +30,7 @@
"expo-print": "~15.0.8",
"expo-sharing": "~14.0.8",
"expo-status-bar": "~3.0.9",
"expo-web-browser": "~15.0.11",
"react": "19.1.0",
"react-native": "0.81.5",
"react-native-gesture-handler": "~2.28.0",
+8 -4
View File
@@ -97,10 +97,12 @@ export default function LoginScreen({ navigation }) {
const handleGoogleLogin = async () => {
setGoogleLoading(true);
try {
const data = await loginWithGoogle();
if (data?.url) await Linking.openURL(data.url);
await loginWithGoogle();
goToApp();
} catch (error) {
if (!error.message?.includes('cancel')) {
showAlert('Google sign-in failed', error.message);
}
} finally {
setGoogleLoading(false);
}
@@ -109,10 +111,12 @@ export default function LoginScreen({ navigation }) {
const handleFacebookLogin = async () => {
setFacebookLoading(true);
try {
const data = await loginWithFacebook();
if (data?.url) await Linking.openURL(data.url);
await loginWithFacebook();
goToApp();
} catch (error) {
if (!error.message?.includes('cancel')) {
showAlert('Facebook sign-in failed', error.message);
}
} finally {
setFacebookLoading(false);
}
+106 -17
View File
@@ -1,6 +1,10 @@
import AsyncStorage from '@react-native-async-storage/async-storage';
import * as AuthSession from 'expo-auth-session';
import * as WebBrowser from 'expo-web-browser';
import { supabase } from './supabase';
WebBrowser.maybeCompleteAuthSession();
// ============================================
// OFFLINE-FIRST AUTH (dummy mode)
// Uses AsyncStorage when Supabase is unreachable.
@@ -203,28 +207,113 @@ export async function signInAsDemo() {
});
}
// ============================================
// Google OAuth
// To setup:
// 1. Go to https://console.cloud.google.com/apis/credentials
// 2. Create OAuth 2.0 Client ID (Web application)
// 3. Add redirect URI: https://auth.expo.io/@heyaciell/Nova40
// 4. Paste Client ID below
// ============================================
const GOOGLE_CLIENT_ID = '112566583381-29vsg1bg7ifnq5csg5o8fisdgtllb2sn.apps.googleusercontent.com';
export async function signInWithGoogle() {
if (!USE_OFFLINE) {
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'google',
options: { redirectTo: 'nova40://auth/callback' },
try {
const redirectUri = AuthSession.makeRedirectUri({ scheme: 'nova40' });
const discovery = {
authorizationEndpoint: 'https://accounts.google.com/o/oauth2/v2/auth',
tokenEndpoint: 'https://oauth2.googleapis.com/token',
};
const request = new AuthSession.AuthRequest({
clientId: GOOGLE_CLIENT_ID,
scopes: ['openid', 'profile', 'email'],
redirectUri,
responseType: AuthSession.ResponseType.Token,
});
if (error) throw error;
return data;
}
throw new Error('Google login is not available in offline mode.');
const result = await request.promptAsync(discovery);
if (result.type === 'success' && result.authentication?.accessToken) {
// Fetch user info from Google
const userInfo = await fetch('https://www.googleapis.com/userinfo/v2/me', {
headers: { Authorization: `Bearer ${result.authentication.accessToken}` },
}).then((r) => r.json());
// Create offline session with Google user data
const email = userInfo.email || 'google-user@nova40.app';
const user = makeUser(email);
// Store user if not exists
const users = await getStoredUsers();
const key = email.toLowerCase();
if (!users[key]) {
users[key] = { id: user.id, password: '__google_oauth__', provider: 'google', name: userInfo.name, picture: userInfo.picture };
await saveUsers(users);
} else {
user.id = users[key].id;
}
export async function signInWithFacebook() {
if (!USE_OFFLINE) {
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'facebook',
options: { redirectTo: 'nova40://auth/callback' },
});
if (error) throw error;
return data;
const session = makeSession(user);
await saveSession(session);
return { session, user };
}
if (result.type === 'cancel') throw new Error('Google sign-in was cancelled.');
throw new Error('Google sign-in failed.');
} catch (e) {
if (e.message?.includes('cancel')) throw e;
throw new Error(e.message || 'Google sign-in failed. Please try again.');
}
}
// ============================================
// Facebook OAuth
// To setup:
// 1. Go to https://developers.facebook.com
// 2. Create app → Facebook Login
// 3. Add redirect URI: https://auth.expo.io/@heyaciell/Nova40
// 4. Paste App ID below
// ============================================
const FACEBOOK_APP_ID = '1696508695097482';
export async function signInWithFacebook() {
try {
const redirectUri = AuthSession.makeRedirectUri({ scheme: 'nova40' });
const result = await AuthSession.startAsync({
authUrl: `https://www.facebook.com/v18.0/dialog/oauth?client_id=${FACEBOOK_APP_ID}&redirect_uri=${encodeURIComponent(redirectUri)}&response_type=token&scope=email,public_profile`,
});
if (result.type === 'success' && result.params?.access_token) {
// Fetch user info from Facebook
const userInfo = await fetch(`https://graph.facebook.com/me?fields=id,name,email,picture&access_token=${result.params.access_token}`)
.then((r) => r.json());
const email = userInfo.email || `fb-${userInfo.id}@nova40.app`;
const user = makeUser(email);
const users = await getStoredUsers();
const key = email.toLowerCase();
if (!users[key]) {
users[key] = { id: user.id, password: '__facebook_oauth__', provider: 'facebook', name: userInfo.name, picture: userInfo.picture?.data?.url };
await saveUsers(users);
} else {
user.id = users[key].id;
}
const session = makeSession(user);
await saveSession(session);
return { session, user };
}
if (result.type === 'cancel') throw new Error('Facebook sign-in was cancelled.');
throw new Error('Facebook sign-in failed.');
} catch (e) {
if (e.message?.includes('cancel')) throw e;
throw new Error(e.message || 'Facebook sign-in failed. Please try again.');
}
throw new Error('Facebook login is not available in offline mode.');
}
export function onAuthStateChange(callback) {
+8
View File
@@ -48,7 +48,11 @@ const useAuthStore = create((set) => ({
set({ loading: true, error: null });
try {
const data = await authService.signInWithGoogle();
if (data?.session) {
set({ session: data.session, user: data.session?.user ?? data.user ?? null, loading: false });
} else {
set({ loading: false });
}
return data;
} catch (e) {
set({ loading: false, error: e.message });
@@ -60,7 +64,11 @@ const useAuthStore = create((set) => ({
set({ loading: true, error: null });
try {
const data = await authService.signInWithFacebook();
if (data?.session) {
set({ session: data.session, user: data.session?.user ?? data.user ?? null, loading: false });
} else {
set({ loading: false });
}
return data;
} catch (e) {
set({ loading: false, error: e.message });