updating to use clerk auth with new routing to signin page by default

This commit is contained in:
Will Baumbach
2025-08-05 15:34:07 -05:00
parent 409f15f233
commit 10815a9a81
17 changed files with 1670 additions and 247 deletions

12
app/(auth)/_layout.tsx Normal file
View File

@@ -0,0 +1,12 @@
import { useAuth } from '@clerk/clerk-expo'
import { Redirect, Stack } from 'expo-router'
export default function AuthRoutesLayout() {
const { isSignedIn } = useAuth()
if (isSignedIn) {
return <Redirect href={'/'} />
}
return <Stack screenOptions={{ headerShown: false }} />
}

31
app/(auth)/sign-in.tsx Normal file
View File

@@ -0,0 +1,31 @@
import { SignIn } from '@clerk/clerk-react'
import { dark } from '@clerk/themes'
import React from 'react'
import { StyleSheet, View } from 'react-native'
export default function SignInScreen() {
return (
<View style={styles.container}>
<SignIn
appearance={{
theme: dark,
variables: {
colorPrimary: '#747b83ff',
colorBackground: '#25292e',
colorInput: '#383e46ff'
}
}}
signUpUrl='/sign-up'
/>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#25292e',
padding: 5,
alignItems: 'center'
}
})

31
app/(auth)/sign-up.tsx Normal file
View File

@@ -0,0 +1,31 @@
import { SignUp } from '@clerk/clerk-expo/web'
import { dark } from '@clerk/themes'
import * as React from 'react'
import { StyleSheet, View } from 'react-native'
export default function SignUpScreen() {
return (
<View style={styles.container}>
<SignUp
appearance={{
theme: dark,
variables: {
colorPrimary: '#747b83ff',
colorBackground: '#25292e',
colorInput: '#383e46ff'
}
}}
signInUrl='/sign-in'
/>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#25292e',
padding: 5,
alignItems: 'center'
}
})

View File

@@ -21,7 +21,7 @@ export default function TabLayout() {
}}
>
<Tabs.Screen
name='index'
name='home'
options={{
title: 'Home',
headerShown: false,
@@ -35,7 +35,6 @@ export default function TabLayout() {
options={{
title: 'Posts',
headerShown: false,
tabBarItemStyle: { display: isAdmin ? 'flex' : 'none' },
tabBarIcon: ({ color, focused }) => (
<Ionicons name={focused ? 'rocket-sharp' : 'rocket-outline'} size={24} color={color} />
)

View File

@@ -1,13 +1,25 @@
import { useUser } from '@clerk/clerk-react'
import React from 'react'
import { StyleSheet, TouchableOpacity, View } from 'react-native'
import { useSession } from '../ctx'
import { Image, StyleSheet, Text, View } from 'react-native'
import { SignOutButton } from '../components/SignOutButton'
export default function PostsScreen() {
const { logout } = useSession()
const user = useUser().user
console.log(user?.emailAddresses)
return (
<View style={styles.wrapper}>
<TouchableOpacity onPress={() => logout()}>Logout</TouchableOpacity>
<View>
<Image></Image>
</View>
<View style={styles.nameContainer}>
<Text style={styles.text}>
{user?.firstName} {user?.lastName}
</Text>
<Text style={styles.text}>{user?.emailAddresses[0].emailAddress}</Text>
</View>
<View style={styles.buttonLayout}>
<SignOutButton></SignOutButton>
</View>
</View>
)
}
@@ -17,5 +29,16 @@ const styles = StyleSheet.create({
flex: 1,
backgroundColor: '#25292e',
padding: 5
},
nameContainer: { display: 'flex', alignItems: 'center' },
text: {
color: 'white',
fontSize: 16,
marginTop: 6
},
buttonLayout: {
flex: 1,
alignItems: 'center',
marginTop: 12
}
})

View File

@@ -1,29 +1,27 @@
import { ClerkProvider, SignedIn, SignedOut } from '@clerk/clerk-expo'
import { tokenCache } from '@clerk/clerk-expo/token-cache'
import { Stack } from 'expo-router'
import { SessionProvider, useSession } from './ctx'
import { SplashScreenController } from './splash'
import React from 'react'
export default function Root() {
// Set up the auth context and render our layout inside of it.
return (
<SessionProvider>
<SplashScreenController />
<ClerkProvider tokenCache={tokenCache}>
<RootNavigator />
</SessionProvider>
</ClerkProvider>
)
}
// Separate this into a new component so it can access the SessionProvider context later
function RootNavigator() {
const { session } = useSession()
return (
<Stack>
<Stack.Protected guard={!!session}>
<Stack screenOptions={{ headerShown: false }}>
<SignedIn>
<Stack.Screen options={{ headerShown: false }} name='(tabs)' />
</Stack.Protected>
<Stack.Protected guard={!session}>
<Stack.Screen options={{ headerShown: false }} name='login' />
</Stack.Protected>
</SignedIn>
<SignedOut>
<Stack.Screen options={{ headerShown: false }} name='(auth)' />
</SignedOut>
</Stack>
)
}

View File

@@ -0,0 +1,35 @@
import { useClerk } from '@clerk/clerk-expo'
import * as Linking from 'expo-linking'
import { StyleSheet, Text, TouchableOpacity } from 'react-native'
export const SignOutButton = () => {
// Use `useClerk()` to access the `signOut()` function
const { signOut } = useClerk()
const handleSignOut = async () => {
try {
await signOut()
// Redirect to your desired page
Linking.openURL(Linking.createURL('/'))
} catch (err) {
// See https://clerk.com/docs/custom-flows/error-handling
// for more info on error handling
console.error(JSON.stringify(err, null, 2))
}
}
return (
<TouchableOpacity onPress={handleSignOut} style={styles.button}>
<Text>Sign out</Text>
</TouchableOpacity>
)
}
const styles = StyleSheet.create({
button: {
width: '40%',
height: '5%',
backgroundColor: 'rgba(192, 196, 199, 1)',
borderRadius: 5,
alignItems: 'center',
justifyContent: 'center'
}
})

View File

@@ -1,46 +0,0 @@
import { createContext, use, type PropsWithChildren } from 'react'
import { useStorageState } from './useStorageState'
const AuthContext = createContext<{
login: () => void
logout: () => void
session?: string | null
isLoading: boolean
}>({
login: () => null,
logout: () => null,
session: null,
isLoading: false
})
// This hook can be used to access the user info.
export function useSession() {
const value = use(AuthContext)
if (!value) {
throw new Error('useSession must be wrapped in a <SessionProvider />')
}
return value
}
export function SessionProvider({ children }: PropsWithChildren) {
const [[isLoading, session], setSession] = useStorageState('session')
return (
<AuthContext
value={{
login: () => {
// Perform sign-in logic here
setSession('admin')
},
logout: () => {
setSession(null)
},
session,
isLoading
}}
>
{children}
</AuthContext>
)
}

18
app/index.tsx Normal file
View File

@@ -0,0 +1,18 @@
import { SignedIn, SignedOut, useUser } from '@clerk/clerk-expo'
import { Redirect } from 'expo-router'
import { View } from 'react-native'
export default function Page() {
const { user } = useUser()
return (
<View>
<SignedIn>
<Redirect href={'/home'} />
</SignedIn>
<SignedOut>
<Redirect href={'/(auth)/sign-in'} />
</SignedOut>
</View>
)
}

View File

@@ -1,12 +1,9 @@
import { router } from 'expo-router'
import React from 'react'
import { StyleSheet, Text, TextInput, TouchableOpacity, View } from 'react-native'
import { useSession } from './ctx'
export default function LoginScreen() {
const [username, setUsername] = React.useState('')
const [password, setPassword] = React.useState('')
const { login } = useSession()
return (
<View style={styles.container}>
@@ -30,22 +27,19 @@ export default function LoginScreen() {
<TouchableOpacity
style={styles.button}
onPress={() => {
login()
if (localStorage.getItem('session') === 'success') {
router.replace('/')
}
console.log('test')
}}
>
<Text style={{ color: '#fff', fontWeight: 'bold' }}>Login</Text>
</TouchableOpacity>
<TouchableOpacity
{/* <TouchableOpacity
style={styles.signup}
onPress={() => {
router.navigate('/signup')
}}
>
<Text style={{ color: '#fff' }}>Sign Up</Text>
</TouchableOpacity>
</TouchableOpacity> */}
</View>
</View>
)

View File

@@ -1,15 +0,0 @@
import React from 'react'
import { StyleSheet, View } from 'react-native'
export default function SignupScreen() {
return <View style={styles.container}></View>
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#25292e',
justifyContent: 'center',
alignItems: 'center'
}
})

View File

@@ -1,12 +0,0 @@
import { SplashScreen } from 'expo-router'
import { useSession } from './ctx'
export function SplashScreenController() {
const { isLoading } = useSession()
if (!isLoading) {
SplashScreen.hideAsync()
}
return null
}