185 lines
8.7 KiB
TypeScript
185 lines
8.7 KiB
TypeScript
import Handers from '@/assets/icons/svg/handers.svg';
|
|
import LoginIP1 from '@/assets/icons/svg/loginIp1.svg';
|
|
import LoginIP2 from '@/assets/icons/svg/loginIp2.svg';
|
|
import ForgetPwd from '@/components/login/forgetPwd';
|
|
import Login from '@/components/login/login';
|
|
import PhoneLogin from '@/components/login/phoneLogin';
|
|
import SignUp from '@/components/login/signUp';
|
|
import { ThemedText } from '@/components/ThemedText';
|
|
import { ThemedView } from '@/components/ThemedView';
|
|
import { useLocalSearchParams, useRouter } from 'expo-router';
|
|
import React, { useEffect, useState } from 'react';
|
|
import { useTranslation } from 'react-i18next';
|
|
import { Keyboard, KeyboardAvoidingView, LayoutChangeEvent, Platform, ScrollView, StatusBar, TouchableOpacity, View, ViewStyle, useWindowDimensions } from 'react-native';
|
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
|
|
const LoginScreen = () => {
|
|
const router = useRouter();
|
|
const { t } = useTranslation();
|
|
const { status } = useLocalSearchParams();
|
|
const [error, setError] = useState<string>('123');
|
|
const [containerHeight, setContainerHeight] = useState(0);
|
|
const { height: windowHeight } = useWindowDimensions();
|
|
// 展示首次输入密码
|
|
const [showPassword, setShowPassword] = useState(false);
|
|
// 展示二次输入密码
|
|
const [showSecondPassword, setShowSecondPassword] = useState(false);
|
|
const [keyboardOffset, setKeyboardOffset] = useState(0);
|
|
const insets = useSafeAreaInsets();
|
|
// 判断是否有白边
|
|
const statusBarHeight = StatusBar?.currentHeight ?? 0;
|
|
|
|
useEffect(() => {
|
|
const keyboardWillShowListener = Keyboard.addListener(
|
|
Platform.OS === 'ios' ? 'keyboardWillShow' : 'keyboardDidShow',
|
|
(e) => {
|
|
setKeyboardOffset(e.endCoordinates.height);
|
|
}
|
|
);
|
|
const keyboardWillHideListener = Keyboard.addListener(
|
|
Platform.OS === 'ios' ? 'keyboardWillHide' : 'keyboardDidHide',
|
|
() => {
|
|
setKeyboardOffset(0);
|
|
}
|
|
);
|
|
|
|
return () => {
|
|
keyboardWillShowListener.remove();
|
|
keyboardWillHideListener.remove();
|
|
};
|
|
}, []);
|
|
|
|
const handleLayout = (event: LayoutChangeEvent) => {
|
|
const { height } = event.nativeEvent.layout;
|
|
setContainerHeight(height);
|
|
};
|
|
|
|
const updateUrlParam = (key: string, value: string) => {
|
|
router.setParams({ [key]: value });
|
|
}
|
|
|
|
return (
|
|
<KeyboardAvoidingView
|
|
style={{ flex: 1 }}
|
|
behavior={Platform.OS === "ios" ? "padding" : "height"}
|
|
keyboardVerticalOffset={Platform.OS === 'ios' ? 0 : -statusBarHeight}
|
|
>
|
|
<ScrollView
|
|
contentContainerStyle={{
|
|
flexGrow: 1
|
|
}}
|
|
keyboardShouldPersistTaps="handled"
|
|
bounces={false}
|
|
>
|
|
<ThemedView className="flex-1 bg-bgPrimary justify-end">
|
|
<View className="flex-1">
|
|
<View
|
|
className="absolute left-1/2 z-10"
|
|
style={{
|
|
top: containerHeight > 0 ? windowHeight - containerHeight - 210 + statusBarHeight : 0,
|
|
transform: [{ translateX: -200 }, { translateY: keyboardOffset > 0 ? -keyboardOffset + statusBarHeight : -keyboardOffset }]
|
|
}}
|
|
>
|
|
{
|
|
(showPassword || showSecondPassword)
|
|
?
|
|
<LoginIP2 />
|
|
:
|
|
<LoginIP1 />
|
|
}
|
|
</View>
|
|
<View
|
|
className="absolute left-1/2 z-[1000] -translate-x-[39.5px] -translate-y-[4px]"
|
|
style={{
|
|
top: containerHeight > 0 ? windowHeight - containerHeight - 1 + statusBarHeight : 0,
|
|
transform: [{ translateX: -39.5 }, { translateY: keyboardOffset > 0 ? -4 - keyboardOffset + statusBarHeight : -4 - keyboardOffset }]
|
|
}}
|
|
>
|
|
<Handers />
|
|
</View>
|
|
</View>
|
|
<ThemedView
|
|
className="w-full bg-white pt-4 px-6 relative z-20 shadow-lg pb-5"
|
|
style={{
|
|
borderTopLeftRadius: 24,
|
|
borderTopRightRadius: 24,
|
|
shadowColor: '#000',
|
|
shadowOffset: { width: 0, height: 2 },
|
|
shadowOpacity: 0.1,
|
|
shadowRadius: 8,
|
|
elevation: 5,
|
|
paddingBottom: insets.bottom
|
|
} as ViewStyle}
|
|
onLayout={handleLayout}
|
|
>
|
|
{/* 错误提示 */}
|
|
<View className={`${error !== "123" ? 'opacity-100' : 'opacity-0'} w-full flex justify-center items-center text-primary-500 text-sm`}>
|
|
<ThemedText className="text-sm !text-textPrimary">
|
|
{error}
|
|
</ThemedText>
|
|
</View>
|
|
{(() => {
|
|
const commonProps = {
|
|
updateUrlParam,
|
|
setError,
|
|
};
|
|
|
|
const components = {
|
|
signUp: (
|
|
<SignUp
|
|
{...commonProps}
|
|
setShowPassword={setShowPassword}
|
|
showPassword={showPassword}
|
|
setShowSecondPassword={setShowSecondPassword}
|
|
showSecondPassword={showSecondPassword}
|
|
/>
|
|
),
|
|
forgetPwd: (
|
|
<ForgetPwd
|
|
{...commonProps}
|
|
/>
|
|
),
|
|
login: (
|
|
<Login
|
|
{...commonProps}
|
|
setShowPassword={setShowPassword}
|
|
showPassword={showPassword}
|
|
/>
|
|
// <PhoneLogin {...commonProps} />
|
|
),
|
|
code: (
|
|
<PhoneLogin {...commonProps} />
|
|
)
|
|
};
|
|
|
|
return components[status as keyof typeof components] || components.login;
|
|
})()}
|
|
|
|
{status == 'login' || !status &&
|
|
<View className="flex-row justify-center mt-2">
|
|
<ThemedText className="text-sm !text-textPrimary">
|
|
{status === 'login' || !status ? t('auth.agree.logintext', { ns: 'login' }) : t('auth.agree.singupText', { ns: 'login' })}
|
|
</ThemedText>
|
|
<TouchableOpacity onPress={() => { }}>
|
|
<ThemedText className="text-sm font-semibold ml-1 !text-textPrimary underline">
|
|
{t('auth.agree.terms', { ns: 'login' })}
|
|
</ThemedText>
|
|
</TouchableOpacity>
|
|
<ThemedText className="text-sm !text-textPrimary">
|
|
{t('auth.agree.join', { ns: 'login' })}
|
|
</ThemedText>
|
|
<TouchableOpacity onPress={() => { }}>
|
|
<ThemedText className="!text-textPrimary underline text-sm font-semibold ml-1">
|
|
{t('auth.agree.privacyPolicy', { ns: 'login' })}
|
|
</ThemedText>
|
|
</TouchableOpacity>
|
|
</View>
|
|
}
|
|
</ThemedView>
|
|
</ThemedView>
|
|
</ScrollView>
|
|
</KeyboardAvoidingView>
|
|
);
|
|
}
|
|
|
|
export default LoginScreen |