refactor(App, navigation): migrate to Expo Router and clean up navigation structure
- Updated App entry point to utilize Expo Router, simplifying the navigation setup. - Removed legacy navigation components and services to streamline the codebase. - Adjusted package.json to reflect the new entry point and updated dependencies for compatibility. - Enhanced overall application structure by consolidating navigation logic and improving maintainability.
This commit is contained in:
@@ -11,19 +11,15 @@ import {
|
||||
ActivityIndicator,
|
||||
} from 'react-native';
|
||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
|
||||
import { useRouter } from 'expo-router';
|
||||
import { MaterialCommunityIcons } from '@expo/vector-icons';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import { colors, spacing, borderRadius, shadows, fontSizes } from '../../theme';
|
||||
import { RootStackParamList } from '../../navigation/types';
|
||||
import { authService, resolveAuthApiError } from '../../services/authService';
|
||||
import { showPrompt } from '../../services/promptService';
|
||||
|
||||
type ForgotPasswordNavigationProp = NativeStackNavigationProp<RootStackParamList, 'Auth'>;
|
||||
|
||||
export const ForgotPasswordScreen: React.FC = () => {
|
||||
const navigation = useNavigation<ForgotPasswordNavigationProp>();
|
||||
const router = useRouter();
|
||||
const [email, setEmail] = useState('');
|
||||
const [verificationCode, setVerificationCode] = useState('');
|
||||
const [newPassword, setNewPassword] = useState('');
|
||||
@@ -95,7 +91,7 @@ export const ForgotPasswordScreen: React.FC = () => {
|
||||
});
|
||||
if (ok) {
|
||||
showPrompt({ title: '重置成功', message: '密码已重置,请重新登录', type: 'success' });
|
||||
navigation.goBack();
|
||||
router.back();
|
||||
}
|
||||
} catch (error: any) {
|
||||
showPrompt({ title: '重置失败', message: resolveAuthApiError(error, '请稍后重试'), type: 'error' });
|
||||
@@ -192,7 +188,7 @@ export const ForgotPasswordScreen: React.FC = () => {
|
||||
{loading ? <ActivityIndicator size="small" color="#fff" /> : <Text style={styles.submitButtonText}>重置密码</Text>}
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity style={styles.backButton} onPress={() => navigation.goBack()}>
|
||||
<TouchableOpacity style={styles.backButton} onPress={() => router.back()}>
|
||||
<Text style={styles.backButtonText}>返回登录</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
@@ -22,24 +22,22 @@ import {
|
||||
StatusBar,
|
||||
} from 'react-native';
|
||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
|
||||
import { useRouter } from 'expo-router';
|
||||
import { MaterialCommunityIcons } from '@expo/vector-icons';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import { colors, spacing, borderRadius, shadows, fontSizes } from '../../theme';
|
||||
import { useAuthStore } from '../../stores';
|
||||
import { RootStackParamList } from '../../navigation/types';
|
||||
import * as hrefs from '../../navigation/hrefs';
|
||||
import { useResponsive, useResponsiveValue } from '../../hooks';
|
||||
import { showPrompt } from '../../services/promptService';
|
||||
|
||||
type LoginNavigationProp = NativeStackNavigationProp<RootStackParamList, 'Auth'>;
|
||||
|
||||
// 分栏布局断点
|
||||
const SPLIT_BREAKPOINT = 768;
|
||||
|
||||
export const LoginScreen: React.FC = () => {
|
||||
const navigation = useNavigation<LoginNavigationProp>();
|
||||
const router = useRouter();
|
||||
const login = useAuthStore((state) => state.login);
|
||||
const isAuthenticated = useAuthStore((state) => state.isAuthenticated);
|
||||
const storeError = useAuthStore((state) => state.error);
|
||||
const setStoreError = useAuthStore((state) => state.setError);
|
||||
|
||||
@@ -131,6 +129,12 @@ export const LoginScreen: React.FC = () => {
|
||||
}
|
||||
}, [storeError]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isAuthenticated) {
|
||||
router.replace(hrefs.hrefHome());
|
||||
}
|
||||
}, [isAuthenticated, router]);
|
||||
|
||||
const clearError = () => {
|
||||
setErrorMsg(null);
|
||||
setStoreError(null);
|
||||
@@ -158,7 +162,7 @@ export const LoginScreen: React.FC = () => {
|
||||
|
||||
// 跳转到注册页
|
||||
const handleGoToRegister = () => {
|
||||
navigation.navigate('Register' as any);
|
||||
router.push(hrefs.hrefAuthRegister());
|
||||
};
|
||||
|
||||
// 渲染左侧面板(Logo和品牌信息)- 优化大屏布局
|
||||
@@ -297,7 +301,10 @@ export const LoginScreen: React.FC = () => {
|
||||
</View>
|
||||
|
||||
{/* 忘记密码 */}
|
||||
<TouchableOpacity style={styles.forgotPassword} onPress={() => navigation.navigate('ForgotPassword' as any)}>
|
||||
<TouchableOpacity
|
||||
style={styles.forgotPassword}
|
||||
onPress={() => router.push(hrefs.hrefAuthForgot())}
|
||||
>
|
||||
<Text style={styles.forgotPasswordText}>忘记密码?</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
|
||||
@@ -10,28 +10,24 @@ import {
|
||||
} from 'react-native';
|
||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||
import { MaterialCommunityIcons } from '@expo/vector-icons';
|
||||
import { useRoute, useNavigation, RouteProp } from '@react-navigation/native';
|
||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
|
||||
import { RootStackParamList } from '../../navigation/types';
|
||||
import { useRouter, useLocalSearchParams } from 'expo-router';
|
||||
import { qrcodeApi } from '../../services/authService';
|
||||
import { colors, spacing, fontSizes, borderRadius } from '../../theme';
|
||||
|
||||
type QRCodeConfirmRouteProp = RouteProp<RootStackParamList, 'QRCodeConfirm'>;
|
||||
type NavigationProp = NativeStackNavigationProp<RootStackParamList>;
|
||||
import { AppBackButton } from '../../components/common';
|
||||
|
||||
export const QRCodeConfirmScreen: React.FC = () => {
|
||||
const route = useRoute<QRCodeConfirmRouteProp>();
|
||||
const navigation = useNavigation<NavigationProp>();
|
||||
const { sessionId } = route.params;
|
||||
const router = useRouter();
|
||||
const { sessionId: sessionIdParam } = useLocalSearchParams<{ sessionId?: string }>();
|
||||
const sessionId = sessionIdParam || '';
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [userInfo, setUserInfo] = useState<{ id: string; nickname: string; avatar: string } | null>(null);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
// 扫码
|
||||
handleScan();
|
||||
}, []);
|
||||
if (!sessionId) return;
|
||||
void handleScan();
|
||||
}, [sessionId]);
|
||||
|
||||
const handleScan = async () => {
|
||||
try {
|
||||
@@ -42,7 +38,7 @@ export const QRCodeConfirmScreen: React.FC = () => {
|
||||
const errorMsg = err.response?.data?.message || '扫码失败';
|
||||
setError(errorMsg);
|
||||
Alert.alert('扫码失败', errorMsg, [
|
||||
{ text: '确定', onPress: () => navigation.goBack() }
|
||||
{ text: '确定', onPress: () => router.back() }
|
||||
]);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
@@ -54,7 +50,7 @@ export const QRCodeConfirmScreen: React.FC = () => {
|
||||
setLoading(true);
|
||||
await qrcodeApi.confirm(sessionId);
|
||||
Alert.alert('登录成功', '网页端已登录', [
|
||||
{ text: '确定', onPress: () => navigation.goBack() }
|
||||
{ text: '确定', onPress: () => router.back() }
|
||||
]);
|
||||
} catch (err: any) {
|
||||
const errorMsg = err.response?.data?.message || '确认登录失败';
|
||||
@@ -70,7 +66,7 @@ export const QRCodeConfirmScreen: React.FC = () => {
|
||||
} catch (err) {
|
||||
// 忽略取消错误
|
||||
}
|
||||
navigation.goBack();
|
||||
router.back();
|
||||
};
|
||||
|
||||
if (loading && !userInfo) {
|
||||
@@ -90,7 +86,7 @@ export const QRCodeConfirmScreen: React.FC = () => {
|
||||
<View style={styles.errorContainer}>
|
||||
<MaterialCommunityIcons name="alert-circle" size={64} color={colors.error.main} />
|
||||
<Text style={styles.errorText}>{error}</Text>
|
||||
<TouchableOpacity style={styles.backButton} onPress={() => navigation.goBack()}>
|
||||
<TouchableOpacity style={styles.backButton} onPress={() => router.back()}>
|
||||
<Text style={styles.backButtonText}>返回</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
@@ -101,9 +97,7 @@ export const QRCodeConfirmScreen: React.FC = () => {
|
||||
return (
|
||||
<SafeAreaView style={styles.container}>
|
||||
<View style={styles.header}>
|
||||
<TouchableOpacity onPress={handleCancel} style={styles.closeButton}>
|
||||
<MaterialCommunityIcons name="close" size={24} color="#666" />
|
||||
</TouchableOpacity>
|
||||
<AppBackButton onPress={handleCancel} icon="close" style={styles.closeButton} iconColor="#666" />
|
||||
<Text style={styles.headerTitle}>确认登录</Text>
|
||||
<View style={styles.placeholder} />
|
||||
</View>
|
||||
|
||||
@@ -22,25 +22,23 @@ import {
|
||||
StatusBar,
|
||||
} from 'react-native';
|
||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||
import { useNavigation } from '@react-navigation/native';
|
||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
|
||||
import { useRouter } from 'expo-router';
|
||||
import { MaterialCommunityIcons } from '@expo/vector-icons';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import { colors, spacing, borderRadius, shadows, fontSizes } from '../../theme';
|
||||
import { authService, resolveAuthApiError } from '../../services/authService';
|
||||
import { useAuthStore } from '../../stores';
|
||||
import { RootStackParamList } from '../../navigation/types';
|
||||
import * as hrefs from '../../navigation/hrefs';
|
||||
import { useResponsive, useResponsiveValue } from '../../hooks';
|
||||
import { showPrompt } from '../../services/promptService';
|
||||
|
||||
type RegisterNavigationProp = NativeStackNavigationProp<RootStackParamList, 'Auth'>;
|
||||
|
||||
// 分栏布局断点
|
||||
const SPLIT_BREAKPOINT = 768;
|
||||
|
||||
export const RegisterScreen: React.FC = () => {
|
||||
const navigation = useNavigation<RegisterNavigationProp>();
|
||||
const router = useRouter();
|
||||
const register = useAuthStore((state) => state.register);
|
||||
const isAuthenticated = useAuthStore((state) => state.isAuthenticated);
|
||||
|
||||
// 响应式布局
|
||||
const { isLandscape, width } = useResponsive();
|
||||
@@ -48,6 +46,12 @@ export const RegisterScreen: React.FC = () => {
|
||||
// 是否使用分栏布局
|
||||
const isSplitLayout = width >= SPLIT_BREAKPOINT;
|
||||
|
||||
useEffect(() => {
|
||||
if (isAuthenticated) {
|
||||
router.replace(hrefs.hrefHome());
|
||||
}
|
||||
}, [isAuthenticated, router]);
|
||||
|
||||
const [username, setUsername] = useState('');
|
||||
const [nickname, setNickname] = useState('');
|
||||
const [email, setEmail] = useState('');
|
||||
@@ -238,7 +242,7 @@ export const RegisterScreen: React.FC = () => {
|
||||
|
||||
// 跳转到登录页
|
||||
const handleGoToLogin = () => {
|
||||
navigation.navigate('Login' as any);
|
||||
router.push(hrefs.hrefAuthLogin());
|
||||
};
|
||||
|
||||
// 渲染左侧面板(Logo和品牌信息)- 优化大屏布局
|
||||
|
||||
Reference in New Issue
Block a user