feat(mobile): auth callback screen consumes magic-link tokens
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
import { useLocalSearchParams, useRouter } from 'expo-router';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { ActivityIndicator, StyleSheet, Text, View } from 'react-native';
|
||||
|
||||
import { supabase } from '../../lib/supabase';
|
||||
import { colors } from '../../theme/colors';
|
||||
|
||||
// Supabase magic-link emails redirect to netralax://auth/callback with
|
||||
// the tokens in either the URL fragment (#access_token=...&refresh_token=...)
|
||||
// or the query string depending on the provider. Expo Router parses the
|
||||
// query string into useLocalSearchParams. The hash portion would require
|
||||
// expo-linking; we accept both shapes for safety.
|
||||
export default function AuthCallback() {
|
||||
const params = useLocalSearchParams<{
|
||||
access_token?: string;
|
||||
refresh_token?: string;
|
||||
error?: string;
|
||||
error_description?: string;
|
||||
}>();
|
||||
const router = useRouter();
|
||||
const [status, setStatus] = useState<'working' | 'error'>('working');
|
||||
const [message, setMessage] = useState<string>('');
|
||||
|
||||
useEffect(() => {
|
||||
void (async () => {
|
||||
if (params.error) {
|
||||
setStatus('error');
|
||||
setMessage(params.error_description ?? params.error);
|
||||
return;
|
||||
}
|
||||
if (!params.access_token || !params.refresh_token) {
|
||||
setStatus('error');
|
||||
setMessage('Magic-Link-URL enthielt keine Tokens.');
|
||||
return;
|
||||
}
|
||||
const { error } = await supabase.auth.setSession({
|
||||
access_token: params.access_token,
|
||||
refresh_token: params.refresh_token,
|
||||
});
|
||||
if (error) {
|
||||
setStatus('error');
|
||||
setMessage(error.message);
|
||||
return;
|
||||
}
|
||||
router.replace('/(app)/chats');
|
||||
})();
|
||||
}, [params, router]);
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
{status === 'working' ? (
|
||||
<>
|
||||
<ActivityIndicator color={colors.accent} size="large" />
|
||||
<Text style={styles.text}>Du wirst angemeldet…</Text>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Text style={styles.errorTitle}>Anmeldung fehlgeschlagen</Text>
|
||||
<Text style={styles.text}>{message}</Text>
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
backgroundColor: colors.bg,
|
||||
padding: 24,
|
||||
gap: 16,
|
||||
},
|
||||
text: { color: colors.textMuted, fontSize: 14, textAlign: 'center' },
|
||||
errorTitle: { color: colors.danger, fontSize: 18, fontWeight: '600' },
|
||||
});
|
||||
Reference in New Issue
Block a user