Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Copy to .env and fill in real values.
EXPO_PUBLIC_GOOGLE_WEB_CLIENT_ID=(string) Your Google Web Client ID
Comment thread
rstar2 marked this conversation as resolved.
Resolved
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ yarn-error.*
*.pem

# local env files
.env
.env*.local

# typescript
Expand Down
36 changes: 36 additions & 0 deletions GoogleService-Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CLIENT_ID</key>
<string>208563783798-uj5b0cm8o236k439pfqbv57r1gds98s7.apps.googleusercontent.com</string>
<key>REVERSED_CLIENT_ID</key>
<string>com.googleusercontent.apps.208563783798-uj5b0cm8o236k439pfqbv57r1gds98s7</string>
<key>API_KEY</key>
<string>AIzaSyD7eTTXkW0crVL4hVT4cn72fgzoR9Mb0co</string>
<key>GCM_SENDER_ID</key>
<string>208563783798</string>
<key>PLIST_VERSION</key>
<string>1</string>
<key>BUNDLE_ID</key>
<string>com.magicmedia.maplace</string>
<key>PROJECT_ID</key>
<string>ma-place</string>
<key>STORAGE_BUCKET</key>
<string>ma-place.firebasestorage.app</string>
<key>IS_ADS_ENABLED</key>
<false></false>
<key>IS_ANALYTICS_ENABLED</key>
<false></false>
<key>IS_APPINVITE_ENABLED</key>
<true></true>
<key>IS_GCM_ENABLED</key>
<true></true>
<key>IS_SIGNIN_ENABLED</key>
<true></true>
<key>GOOGLE_APP_ID</key>
<string>1:208563783798:ios:2359abd3461abd4fcf7757</string>
<key>DATABASE_URL</key>
<string>https://ma-place.firebaseio.com</string>
</dict>
</plist>
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,5 @@ Project created with ```pnpm dlx create-expo-app --template default@54```, then
- Create a `global.css` file
- Update `postcss.config.mjs`
- Update `metro.config.js`
- XXX
- Firebase `@react-native-firebase/app` - only working with `development build`
- auth - `@react-native-firebase/auth` and `@react-native-google-signin/google-signin`. Note that the Firebase Android app has to be with generate a SHA-fingerprint in order the Google sign-in method to work. One can be generated with `./android/gradlew signingReport` and added to the Firebase Android app [generate](https://developers.google.com/android/guides/client-auth)
Comment thread
rstar2 marked this conversation as resolved.
Resolved
10 changes: 8 additions & 2 deletions app.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
"userInterfaceStyle": "automatic",
"newArchEnabled": true,
"ios": {
"supportsTablet": true
"supportsTablet": true,
"bundleIdentifier": "com.magicmedia.maplace",
"googleServicesFile": "./GoogleService-Info.plist"
},
"android": {
"adaptiveIcon": {
Expand All @@ -19,7 +21,9 @@
"monochromeImage": "./assets/images/android-icon-monochrome.png"
},
"edgeToEdgeEnabled": true,
"predictiveBackGestureEnabled": false
"predictiveBackGestureEnabled": false,
"package": "com.magicmedia.maplace",
"googleServicesFile": "./google-services.json"
},
"web": {
"output": "static",
Expand All @@ -28,6 +32,8 @@
},
"plugins": [
"expo-router",
"@react-native-firebase/app",
"@react-native-google-signin/google-signin",
Comment thread
rstar2 marked this conversation as resolved.
Resolved
[
"expo-splash-screen",
{
Expand Down
14 changes: 11 additions & 3 deletions app/(auth)/_layout.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import { Stack } from "expo-router";
import { Stack } from "expo-router";

import "@/assets/global.css";
Comment thread
rstar2 marked this conversation as resolved.
Resolved
import { colors } from "@/constants/theme";

export default function RootLayout() {
return <Stack />;
export default function AuthLayout() {
return (
<Stack
screenOptions={{
headerShown: false,
contentStyle: { backgroundColor: colors.background },
}}
/>
);
}
168 changes: 161 additions & 7 deletions app/(auth)/sign-in.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,168 @@
import { useState } from "react";
import {
ActivityIndicator,
KeyboardAvoidingView,
Platform,
Pressable,
ScrollView,
TextInput,
View,
} from "react-native";
import { Link } from "expo-router";
import { View } from "react-native";

import Text from "@/app/components/Text";
import { friendlyAuthError, useAuth } from "@/lib/auth";
import { cn } from "@/lib/utils";

export default function SignInScreen() {
const { signIn, signInWithGoogle } = useAuth();

const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState<string | null>(null);
const [submitting, setSubmitting] = useState(false);
const [googleSubmitting, setGoogleSubmitting] = useState(false);

const canSubmit =
email.trim().length > 0 && password.length > 0 && !submitting;
Comment thread
rstar2 marked this conversation as resolved.
Resolved

// The root layout's auth gate redirects on success, so no manual navigation here.
async function handleSignIn() {
if (!canSubmit) return;
setError(null);
setSubmitting(true);
try {
await signIn(email.trim(), password);
} catch (err) {
setError(friendlyAuthError(err));
} finally {
setSubmitting(false);
}
}

async function handleGoogle() {
setError(null);
setGoogleSubmitting(true);
try {
await signInWithGoogle();
} catch (err) {
setError(friendlyAuthError(err));
} finally {
setGoogleSubmitting(false);
}
}

export default function SignIn() {
return (
<View>
<Text>SignIn</Text>
<Link href="/sign-up">Go to SignUp</Link>
<Link href="/">Home</Link>
</View>
<KeyboardAvoidingView
behavior={Platform.OS === "ios" ? "padding" : "height"}
className="auth-screen"
>
<ScrollView
className="auth-scroll"
contentContainerClassName="auth-content"
keyboardShouldPersistTaps="handled"
>
<View className="auth-brand-block">
<View className="auth-logo-wrap">
<View className="auth-logo-mark">
<Text className="auth-logo-mark-text">M</Text>
</View>
<View>
<Text className="auth-wordmark">ma-place</Text>
<Text className="auth-wordmark-sub">subscriptions</Text>
</View>
</View>
<Text className="auth-title">Welcome back</Text>
<Text className="auth-subtitle">
Sign in to manage your places and subscriptions.
</Text>
</View>

<View className="auth-card">
<View className="auth-form">
<View className="auth-field">
<Text className="auth-label">Email</Text>
<TextInput
value={email}
onChangeText={setEmail}
placeholder="you@example.com"
placeholderTextColor="rgba(0,0,0,0.35)"
keyboardType="email-address"
autoCapitalize="none"
autoComplete="email"
autoCorrect={false}
textContentType="emailAddress"
className={cn("auth-input", error && "auth-input-error")}
/>
</View>

<View className="auth-field">
<Text className="auth-label">Password</Text>
<TextInput
value={password}
onChangeText={setPassword}
placeholder="••••••••"
placeholderTextColor="rgba(0,0,0,0.35)"
secureTextEntry
autoCapitalize="none"
autoComplete="password"
autoCorrect={false}
textContentType="password"
className={cn("auth-input", error && "auth-input-error")}
/>
</View>

{error ? <Text className="auth-error">{error}</Text> : null}

<Pressable
onPress={handleSignIn}
disabled={!canSubmit}
className={cn(
"auth-button",
!canSubmit && "auth-button-disabled",
)}
>
{submitting ? (
<ActivityIndicator color="#081126" />
) : (
<Text className="auth-button-text">Sign in</Text>
)}
</Pressable>
</View>
</View>

<View className="auth-divider-row">
<View className="auth-divider-line" />
<Text className="auth-divider-text">or</Text>
<View className="auth-divider-line" />
</View>

<Pressable
onPress={handleGoogle}
disabled={googleSubmitting}
className={cn(
"auth-secondary-button",
googleSubmitting && "opacity-50",
)}
>
{googleSubmitting ? (
<ActivityIndicator color="#ea7a53" />
) : (
<Text className="auth-secondary-button-text">
Continue with Google
</Text>
)}
</Pressable>

<View className="auth-link-row">
<Text className="auth-link-copy">Don&apos;t have an account?</Text>
<Link href="/sign-up" asChild>
<Pressable>
<Text className="auth-link">Create account</Text>
</Pressable>
</Link>
</View>
</ScrollView>
</KeyboardAvoidingView>
);
}
Loading