feat: 手机号
This commit is contained in:
parent
727ebcb483
commit
e2cd78f6a0
@ -115,13 +115,13 @@ const Code = ({ phone }: CodeProps) => {
|
|||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
<View style={styles.contentContainer}>
|
<View style={styles.contentContainer}>
|
||||||
<View style={styles.headerContainer}>
|
<View style={styles.headerContainer}>
|
||||||
<ThemedText style={styles.title}>
|
<ThemedText style={styles.title} color="textSecondary" size="xl" weight="bold">
|
||||||
{t("auth.telLogin.codeTitle", { ns: 'login' })}
|
{t("auth.telLogin.codeTitle", { ns: 'login' })}
|
||||||
</ThemedText>
|
</ThemedText>
|
||||||
<ThemedText style={styles.subtitle}>
|
<ThemedText style={styles.subtitle} type="sfPro" color="textPrimary" size="sm">
|
||||||
{t("auth.telLogin.secondTitle", { ns: 'login' })}
|
{t("auth.telLogin.secondTitle", { ns: 'login' })}
|
||||||
</ThemedText>
|
</ThemedText>
|
||||||
<ThemedText style={styles.phoneNumber}>
|
<ThemedText color="bgSecondary" size="sm" weight="bold">
|
||||||
{phone}
|
{phone}
|
||||||
</ThemedText>
|
</ThemedText>
|
||||||
</View>
|
</View>
|
||||||
@ -144,13 +144,13 @@ const Code = ({ phone }: CodeProps) => {
|
|||||||
/>
|
/>
|
||||||
<View style={[styles.errorContainer, { opacity: error ? 1 : 0 }]}>
|
<View style={[styles.errorContainer, { opacity: error ? 1 : 0 }]}>
|
||||||
<Error />
|
<Error />
|
||||||
<ThemedText style={styles.errorText}>
|
<ThemedText style={styles.errorText} size="xxs" color="bgSecondary" type="inter">
|
||||||
{error}
|
{error}
|
||||||
</ThemedText>
|
</ThemedText>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<View style={styles.footerContainer}>
|
<View style={styles.footerContainer}>
|
||||||
<ThemedText style={styles.footerText}>
|
<ThemedText size="sm" color="textPrimary" type="sfPro">
|
||||||
{t("auth.telLogin.sendAgain", { ns: 'login' })}
|
{t("auth.telLogin.sendAgain", { ns: 'login' })}
|
||||||
</ThemedText>
|
</ThemedText>
|
||||||
<TouchableOpacity onPress={() => {
|
<TouchableOpacity onPress={() => {
|
||||||
@ -158,10 +158,16 @@ const Code = ({ phone }: CodeProps) => {
|
|||||||
sendVerificationCode()
|
sendVerificationCode()
|
||||||
}
|
}
|
||||||
}}>
|
}}>
|
||||||
<ThemedText style={[
|
<ThemedText
|
||||||
styles.resendText,
|
style={[
|
||||||
countdown > 0 && styles.disabledResendText
|
styles.resendText,
|
||||||
]}>
|
countdown > 0 && styles.disabledResendText
|
||||||
|
]}
|
||||||
|
size="sm"
|
||||||
|
color="bgSecondary"
|
||||||
|
type="inter"
|
||||||
|
weight="bold"
|
||||||
|
>
|
||||||
{countdown > 0 ? `${countdown}s${t("auth.telLogin.resend", { ns: 'login' })}` : t("auth.telLogin.resend", { ns: 'login' })}
|
{countdown > 0 ? `${countdown}s${t("auth.telLogin.resend", { ns: 'login' })}` : t("auth.telLogin.resend", { ns: 'login' })}
|
||||||
</ThemedText>
|
</ThemedText>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
@ -185,23 +191,13 @@ const styles = StyleSheet.create({
|
|||||||
marginBottom: 16,
|
marginBottom: 16,
|
||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
fontSize: 24,
|
|
||||||
fontWeight: '600',
|
|
||||||
marginBottom: 8,
|
marginBottom: 8,
|
||||||
paddingTop: 4,
|
paddingTop: 4,
|
||||||
color: '#111827',
|
|
||||||
},
|
},
|
||||||
subtitle: {
|
subtitle: {
|
||||||
fontSize: 16,
|
|
||||||
color: '#4B5563',
|
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
marginBottom: 4,
|
marginBottom: 4,
|
||||||
},
|
},
|
||||||
phoneNumber: {
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: '500',
|
|
||||||
color: '#E2793F',
|
|
||||||
},
|
|
||||||
otpContainer: {
|
otpContainer: {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
height: 80,
|
height: 80,
|
||||||
@ -228,9 +224,6 @@ const styles = StyleSheet.create({
|
|||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
},
|
},
|
||||||
errorText: {
|
errorText: {
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: '500',
|
|
||||||
color: '#E2793F',
|
|
||||||
marginLeft: 8,
|
marginLeft: 8,
|
||||||
},
|
},
|
||||||
footerContainer: {
|
footerContainer: {
|
||||||
@ -238,12 +231,7 @@ const styles = StyleSheet.create({
|
|||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
marginTop: 8,
|
marginTop: 8,
|
||||||
},
|
},
|
||||||
footerText: {
|
|
||||||
color: '#6B7280',
|
|
||||||
},
|
|
||||||
resendText: {
|
resendText: {
|
||||||
color: '#E2793F',
|
|
||||||
fontWeight: '500',
|
|
||||||
marginLeft: 4,
|
marginLeft: 4,
|
||||||
},
|
},
|
||||||
disabledResendText: {
|
disabledResendText: {
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import { fetchApi } from "@/lib/server-api-util";
|
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { ActivityIndicator, TextInput, TouchableOpacity, View } from "react-native";
|
import { View } from "react-native";
|
||||||
import { ThemedText } from "../ThemedText";
|
|
||||||
import { Steps } from "./phoneLogin";
|
import { Steps } from "./phoneLogin";
|
||||||
|
import Button from "./ui/Button";
|
||||||
|
import TextInput from "./ui/TextInput";
|
||||||
|
|
||||||
interface LoginProps {
|
interface LoginProps {
|
||||||
setSteps: (steps: Steps) => void;
|
setSteps: (steps: Steps) => void;
|
||||||
@ -18,67 +18,30 @@ const Phone = ({ setSteps, setPhone, phone, updateUrlParam }: LoginProps) => {
|
|||||||
const [error, setError] = useState<string>('');
|
const [error, setError] = useState<string>('');
|
||||||
|
|
||||||
const sendVerificationCode = async () => {
|
const sendVerificationCode = async () => {
|
||||||
if (!/^1[3-9]\d{9}$/.test(phone)) {
|
setSteps('code')
|
||||||
setError(t("auth.telLogin.phoneInvalid", { ns: 'login' }));
|
updateUrlParam("status", "code");
|
||||||
return;
|
return
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
setIsLoading(true);
|
|
||||||
|
|
||||||
await fetchApi(`/iam/veritification-code`, {
|
|
||||||
method: 'POST',
|
|
||||||
body: JSON.stringify({ phone: phone }),
|
|
||||||
})
|
|
||||||
setSteps('code')
|
|
||||||
updateUrlParam("status", "code");
|
|
||||||
setIsLoading(false);
|
|
||||||
} catch (error) {
|
|
||||||
setPhone("")
|
|
||||||
setIsLoading(false);
|
|
||||||
// console.error(t("auth.telLogin.sendCodeError", { ns: 'login' }), error);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return <View>
|
return <View>
|
||||||
{/* 手机号输入框 */}
|
{/* 手机号输入框 */}
|
||||||
<View className="mb-5">
|
<View className="mb-5">
|
||||||
<View className="w-full flex flex-row justify-between">
|
|
||||||
<ThemedText className="text-base !text-textPrimary mb-2 ml-2">
|
|
||||||
{t('auth.telLogin.title', { ns: 'login' })}
|
|
||||||
</ThemedText>
|
|
||||||
<ThemedText className="text-sm !text-textPrimary mb-2 ml-2">
|
|
||||||
{error}
|
|
||||||
</ThemedText>
|
|
||||||
</View>
|
|
||||||
<TextInput
|
<TextInput
|
||||||
className="border border-gray-300 rounded-2xl p-3 text-base bg-inputBackground"
|
label={t('auth.telLogin.title', { ns: 'login' })}
|
||||||
placeholder={t('auth.telLogin.phoneRequired', { ns: 'login' })}
|
placeholder={t('auth.telLogin.phoneRequired', { ns: 'login' })}
|
||||||
placeholderTextColor="#ccc"
|
|
||||||
value={phone}
|
|
||||||
onChangeText={(text) => {
|
onChangeText={(text) => {
|
||||||
setPhone(text);
|
setPhone(text);
|
||||||
setError('');
|
setError('');
|
||||||
}}
|
}}
|
||||||
keyboardType="email-address"
|
keyboardType="email-address"
|
||||||
autoCapitalize="none"
|
autoCapitalize="none"
|
||||||
|
value={phone}
|
||||||
|
error={error}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
{/* 发送验证码 */}
|
{/* 发送验证码 */}
|
||||||
<TouchableOpacity
|
<Button isLoading={isLoading} handleLogin={sendVerificationCode} text={t('auth.telLogin.sendCode', { ns: 'login' })} />
|
||||||
className={`w-full bg-[#E2793F] rounded-full text-[#fff] p-4 items-center mb-6 ${isLoading ? 'opacity-70' : ''}`}
|
|
||||||
onPress={sendVerificationCode}
|
|
||||||
disabled={isLoading}
|
|
||||||
>
|
|
||||||
{isLoading ? (
|
|
||||||
<ActivityIndicator color="#fff" />
|
|
||||||
) : (
|
|
||||||
<ThemedText className="!text-white font-semibold">
|
|
||||||
{t('auth.telLogin.sendCode', { ns: 'login' })}
|
|
||||||
</ThemedText>
|
|
||||||
)}
|
|
||||||
</TouchableOpacity>
|
|
||||||
</View>
|
</View>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -15,7 +15,9 @@ const PhoneLogin = ({ updateUrlParam }: LoginProps) => {
|
|||||||
|
|
||||||
return <View>
|
return <View>
|
||||||
{
|
{
|
||||||
steps === "phone" ? <Phone setSteps={setSteps} setPhone={setPhone} phone={phone} updateUrlParam={updateUrlParam} /> : <Code phone={phone} />
|
steps === "phone"
|
||||||
|
? <Phone setSteps={setSteps} setPhone={setPhone} phone={phone} updateUrlParam={updateUrlParam} />
|
||||||
|
: <Code phone={phone} />
|
||||||
}
|
}
|
||||||
</View>
|
</View>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,13 +1,16 @@
|
|||||||
|
import { Fonts } from "@/constants/Fonts";
|
||||||
import { Ionicons } from "@expo/vector-icons";
|
import { Ionicons } from "@expo/vector-icons";
|
||||||
import { useLocalSearchParams, useRouter } from "expo-router";
|
import { useLocalSearchParams, useRouter } from "expo-router";
|
||||||
import { useEffect, useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { ActivityIndicator, StyleSheet, TextInput, TouchableOpacity, View } from 'react-native';
|
import { StyleSheet, TouchableOpacity, View } from 'react-native';
|
||||||
import { useAuth } from "../../contexts/auth-context";
|
import { useAuth } from "../../contexts/auth-context";
|
||||||
import { fetchApi } from "../../lib/server-api-util";
|
import { fetchApi } from "../../lib/server-api-util";
|
||||||
import { User } from "../../types/user";
|
import { User } from "../../types/user";
|
||||||
import { ThemedText } from "../ThemedText";
|
import { ThemedText } from "../ThemedText";
|
||||||
import PrivacyModal from "../owner/qualification/privacy";
|
import PrivacyModal from "../owner/qualification/privacy";
|
||||||
|
import Button from "./ui/Button";
|
||||||
|
import TextInput from "./ui/TextInput";
|
||||||
|
|
||||||
interface LoginProps {
|
interface LoginProps {
|
||||||
updateUrlParam: (status: string, value: string) => void;
|
updateUrlParam: (status: string, value: string) => void;
|
||||||
@ -146,100 +149,53 @@ const SignUp = ({ updateUrlParam, setError, setShowPassword, showPassword, setSh
|
|||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<View style={styles.container}>
|
||||||
{/* 邮箱输入 */}
|
{/* 邮箱输入 */}
|
||||||
<View style={styles.inputContainer}>
|
<TextInput
|
||||||
<ThemedText style={styles.inputLabel}>
|
label={t('auth.login.email', { ns: 'login' })}
|
||||||
{t('auth.login.email', { ns: 'login' })}
|
placeholder={t('auth.login.accountPlaceholder', { ns: 'login' })}
|
||||||
</ThemedText>
|
onChangeText={(text) => {
|
||||||
<View style={styles.inputWrapper}>
|
setEmail(text);
|
||||||
<TextInput
|
setError('123');
|
||||||
style={styles.textInput}
|
}}
|
||||||
placeholder={t('auth.login.accountPlaceholder', { ns: 'login' })}
|
autoCapitalize="none"
|
||||||
placeholderTextColor="#ccc"
|
keyboardType="email-address"
|
||||||
value={email}
|
value={email}
|
||||||
onChangeText={(value) => {
|
/>
|
||||||
setEmail(value)
|
|
||||||
setError('123')
|
|
||||||
}}
|
|
||||||
keyboardType="email-address"
|
|
||||||
autoCapitalize="none"
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
{/* 密码输入 */}
|
{/* 密码输入 */}
|
||||||
<View style={styles.inputContainer}>
|
<TextInput
|
||||||
<ThemedText style={styles.inputLabel}>
|
label={t('auth.login.password', { ns: 'login' })}
|
||||||
{t('auth.login.password', { ns: 'login' })}
|
placeholder={t('auth.login.passwordPlaceholder', { ns: 'login' })}
|
||||||
</ThemedText>
|
autoCapitalize="none"
|
||||||
<View style={styles.passwordInputContainer}>
|
value={password}
|
||||||
<TextInput
|
onChangeText={(value) => {
|
||||||
style={[styles.textInput, { flex: 1 }]}
|
handlePasswordChange(value)
|
||||||
placeholder={t('auth.login.passwordPlaceholder', { ns: 'login' })}
|
setError('123')
|
||||||
placeholderTextColor="#ccc"
|
}}
|
||||||
value={password}
|
secureTextEntry={!showPassword}
|
||||||
onChangeText={(value) => {
|
type="password"
|
||||||
handlePasswordChange(value)
|
setShowPassword={setShowPassword}
|
||||||
setError('123')
|
showPassword={showPassword}
|
||||||
}}
|
/>
|
||||||
secureTextEntry={!showPassword}
|
|
||||||
/>
|
|
||||||
<TouchableOpacity
|
|
||||||
onPress={() => setShowPassword(!showPassword)}
|
|
||||||
style={styles.eyeIcon}
|
|
||||||
>
|
|
||||||
<Ionicons
|
|
||||||
name={showPassword ? 'eye' : 'eye-off'}
|
|
||||||
size={20}
|
|
||||||
color="#666"
|
|
||||||
/>
|
|
||||||
</TouchableOpacity>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
{/* 确认密码 */}
|
{/* 确认密码 */}
|
||||||
<View style={[styles.inputContainer, { marginBottom: 24 }]}>
|
<TextInput
|
||||||
<ThemedText style={styles.inputLabel}>
|
label={t('auth.signup.confirmPassword', { ns: 'login' })}
|
||||||
{t('auth.signup.confirmPassword', { ns: 'login' })}
|
placeholder={t('auth.signup.confirmPasswordPlaceholder', { ns: 'login' })}
|
||||||
</ThemedText>
|
autoCapitalize="none"
|
||||||
<View style={styles.passwordInputContainer}>
|
value={confirmPassword}
|
||||||
<TextInput
|
onChangeText={(value) => {
|
||||||
style={[styles.textInput, { flex: 1 }]}
|
handleConfirmPasswordChange(value)
|
||||||
placeholder={t('auth.signup.confirmPasswordPlaceholder', { ns: 'login' })}
|
setError('123')
|
||||||
placeholderTextColor="#ccc"
|
}}
|
||||||
value={confirmPassword}
|
secureTextEntry={!showSecondPassword}
|
||||||
onChangeText={(value) => {
|
type="password"
|
||||||
handleConfirmPasswordChange(value)
|
setShowPassword={setShowSecondPassword}
|
||||||
setError('123')
|
showPassword={showSecondPassword}
|
||||||
}}
|
/>
|
||||||
secureTextEntry={!showSecondPassword}
|
|
||||||
/>
|
|
||||||
<TouchableOpacity
|
|
||||||
onPress={() => setShowSecondPassword(!showSecondPassword)}
|
|
||||||
style={styles.eyeIcon}
|
|
||||||
>
|
|
||||||
<Ionicons
|
|
||||||
name={showSecondPassword ? 'eye' : 'eye-off'}
|
|
||||||
size={20}
|
|
||||||
color="#666"
|
|
||||||
/>
|
|
||||||
</TouchableOpacity>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
{/* 注册按钮 */}
|
{/* 注册按钮 */}
|
||||||
<TouchableOpacity
|
<Button isLoading={loading} handleLogin={handleSubmit} text={t("auth.signup.signupButton", { ns: 'login' })} />
|
||||||
style={[styles.signupButton, loading && { opacity: 0.7 }]}
|
|
||||||
onPress={handleSubmit}
|
|
||||||
disabled={loading}
|
|
||||||
>
|
|
||||||
{loading ? (
|
|
||||||
<ActivityIndicator color="#fff" />
|
|
||||||
) : (
|
|
||||||
<ThemedText style={styles.signupButtonText}>
|
|
||||||
{t("auth.signup.signupButton", { ns: 'login' })}
|
|
||||||
</ThemedText>
|
|
||||||
)}
|
|
||||||
</TouchableOpacity>
|
|
||||||
<View style={styles.termsContainer}>
|
<View style={styles.termsContainer}>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
@ -259,68 +215,68 @@ const SignUp = ({ updateUrlParam, setError, setShowPassword, showPassword, setSh
|
|||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
{checked && (
|
{checked && (
|
||||||
<Ionicons name="checkmark" size={14} color="white" />
|
<Ionicons name="checkmark" size={14} color={Fonts['textSecondary']} />
|
||||||
)}
|
)}
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
<View style={styles.termsTextContainer}>
|
<View style={styles.termsTextContainer}>
|
||||||
<ThemedText style={styles.termsText}>
|
<ThemedText style={styles.termsText} type="sfPro">
|
||||||
{t("auth.telLogin.agree", { ns: 'login' })}
|
{t("auth.telLogin.agree", { ns: 'login' })}
|
||||||
</ThemedText>
|
</ThemedText>
|
||||||
<TouchableOpacity onPress={() => {
|
<TouchableOpacity onPress={() => {
|
||||||
setModalType('terms');
|
setModalType('terms');
|
||||||
setPrivacyModalVisible(true);
|
setPrivacyModalVisible(true);
|
||||||
}}>
|
}}>
|
||||||
<ThemedText style={styles.termsLink}>
|
<ThemedText style={styles.termsLink} type="sfPro">
|
||||||
{t("auth.telLogin.terms", { ns: 'login' })}
|
{t("auth.telLogin.terms", { ns: 'login' })}
|
||||||
</ThemedText>
|
</ThemedText>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
<ThemedText style={styles.termsText}>
|
<ThemedText style={styles.termsText} type="sfPro">
|
||||||
{t("auth.telLogin.and", { ns: 'login' })}
|
{t("auth.telLogin.and", { ns: 'login' })}
|
||||||
</ThemedText>
|
</ThemedText>
|
||||||
<TouchableOpacity onPress={() => {
|
<TouchableOpacity onPress={() => {
|
||||||
setModalType('privacy');
|
setModalType('privacy');
|
||||||
setPrivacyModalVisible(true);
|
setPrivacyModalVisible(true);
|
||||||
}}>
|
}}>
|
||||||
<ThemedText style={styles.termsLink}>
|
<ThemedText style={styles.termsLink} type="sfPro">
|
||||||
{t("auth.telLogin.privacyPolicy", { ns: 'login' })}
|
{t("auth.telLogin.privacyPolicy", { ns: 'login' })}
|
||||||
</ThemedText>
|
</ThemedText>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
<ThemedText style={styles.termsText}>
|
<ThemedText style={styles.termsText} type="sfPro">
|
||||||
{t("auth.telLogin.and", { ns: 'login' })}
|
{t("auth.telLogin.and", { ns: 'login' })}
|
||||||
</ThemedText>
|
</ThemedText>
|
||||||
<TouchableOpacity onPress={() => {
|
<TouchableOpacity onPress={() => {
|
||||||
setModalType('user');
|
setModalType('user');
|
||||||
setPrivacyModalVisible(true);
|
setPrivacyModalVisible(true);
|
||||||
}}>
|
}}>
|
||||||
<ThemedText style={styles.termsLink}>
|
<ThemedText style={styles.termsLink} type="sfPro">
|
||||||
{t("auth.telLogin.userAgreement", { ns: 'login' })}
|
{t("auth.telLogin.userAgreement", { ns: 'login' })}
|
||||||
</ThemedText>
|
</ThemedText>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
<ThemedText style={styles.termsText}>
|
<ThemedText style={styles.termsText} type="sfPro">
|
||||||
{t("auth.telLogin.and", { ns: 'login' })}
|
{t("auth.telLogin.and", { ns: 'login' })}
|
||||||
</ThemedText>
|
</ThemedText>
|
||||||
<TouchableOpacity onPress={() => {
|
<TouchableOpacity onPress={() => {
|
||||||
setModalType('ai');
|
setModalType('ai');
|
||||||
setPrivacyModalVisible(true);
|
setPrivacyModalVisible(true);
|
||||||
}}>
|
}}>
|
||||||
<ThemedText style={styles.termsLink}>
|
<ThemedText style={styles.termsLink} type="sfPro">
|
||||||
{t("auth.telLogin.aiAgreement", { ns: 'login' })}
|
{t("auth.telLogin.aiAgreement", { ns: 'login' })}
|
||||||
</ThemedText>
|
</ThemedText>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
<ThemedText style={styles.termsText}>
|
<ThemedText style={styles.termsText} type="sfPro">
|
||||||
{t("auth.telLogin.agreement", { ns: 'login' })}
|
{t("auth.telLogin.agreement", { ns: 'login' })}
|
||||||
</ThemedText>
|
</ThemedText>
|
||||||
<ThemedText style={styles.termsLink}>
|
<ThemedText style={styles.termsLink} type="sfPro">
|
||||||
{t("common.name")}
|
{t("common.name")}
|
||||||
</ThemedText>
|
</ThemedText>
|
||||||
<ThemedText style={styles.termsText}>
|
<ThemedText style={styles.termsText} type="sfPro">
|
||||||
{t("auth.telLogin.getPhone", { ns: 'login' })}
|
{t("auth.telLogin.getPhone", { ns: 'login' })}
|
||||||
</ThemedText>
|
</ThemedText>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
{/* 已有账号 */}
|
{/* 已有账号 */}
|
||||||
<View style={styles.loginContainer}>
|
<View style={styles.loginContainer} >
|
||||||
<ThemedText style={styles.loginText}>
|
<ThemedText type="sfPro" color="textPrimary" size="sm">
|
||||||
{t("auth.signup.haveAccount", { ns: 'login' })}
|
{t("auth.signup.haveAccount", { ns: 'login' })}
|
||||||
</ThemedText>
|
</ThemedText>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
@ -328,7 +284,7 @@ const SignUp = ({ updateUrlParam, setError, setShowPassword, showPassword, setSh
|
|||||||
updateUrlParam("status", "login");
|
updateUrlParam("status", "login");
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ThemedText style={styles.loginLink}>
|
<ThemedText type="sfPro" color="bgSecondary" weight="bold" size="sm">
|
||||||
{t("auth.signup.login", { ns: 'login' })}
|
{t("auth.signup.login", { ns: 'login' })}
|
||||||
</ThemedText>
|
</ThemedText>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
@ -395,17 +351,17 @@ const styles = StyleSheet.create({
|
|||||||
checkbox: {
|
checkbox: {
|
||||||
width: 20,
|
width: 20,
|
||||||
height: 20,
|
height: 20,
|
||||||
borderRadius: 10,
|
borderRadius: 6,
|
||||||
borderWidth: 2,
|
borderWidth: 1,
|
||||||
borderColor: '#E5E7EB',
|
borderColor: Fonts['textPrimary'],
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
marginRight: 8,
|
marginRight: 8,
|
||||||
marginTop: 2,
|
marginTop: 2,
|
||||||
},
|
},
|
||||||
checkboxChecked: {
|
checkboxChecked: {
|
||||||
backgroundColor: '#E2793F',
|
backgroundColor: Fonts["bgCheck"],
|
||||||
borderColor: '#E2793F',
|
borderColor: Fonts['bgCheck'],
|
||||||
},
|
},
|
||||||
termsTextContainer: {
|
termsTextContainer: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
@ -414,29 +370,20 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
termsText: {
|
termsText: {
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
color: '#1F2937',
|
color: Fonts["textPrimary"],
|
||||||
lineHeight: 20,
|
lineHeight: 20,
|
||||||
},
|
},
|
||||||
termsLink: {
|
termsLink: {
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
color: '#E2793F',
|
color: Fonts['bgSecondary'],
|
||||||
lineHeight: 20,
|
lineHeight: 20
|
||||||
},
|
},
|
||||||
loginContainer: {
|
loginContainer: {
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
marginTop: 24,
|
marginTop: 24,
|
||||||
},
|
gap: 4,
|
||||||
loginText: {
|
}
|
||||||
fontSize: 14,
|
|
||||||
color: '#1F2937',
|
|
||||||
},
|
|
||||||
loginLink: {
|
|
||||||
color: '#E2793F',
|
|
||||||
fontSize: 14,
|
|
||||||
fontWeight: '600',
|
|
||||||
marginLeft: 4,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default SignUp;
|
export default SignUp;
|
||||||
@ -14,6 +14,7 @@ interface CustomTextInputProps {
|
|||||||
type?: 'default' | 'password';
|
type?: 'default' | 'password';
|
||||||
containerStyle?: StyleProp<ViewStyle>;
|
containerStyle?: StyleProp<ViewStyle>;
|
||||||
style?: StyleProp<TextStyle>;
|
style?: StyleProp<TextStyle>;
|
||||||
|
error?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
type TextInputProps = RNTextInputProps & CustomTextInputProps;
|
type TextInputProps = RNTextInputProps & CustomTextInputProps;
|
||||||
@ -27,6 +28,7 @@ const TextInput = ({
|
|||||||
setError,
|
setError,
|
||||||
showPassword,
|
showPassword,
|
||||||
setShowPassword,
|
setShowPassword,
|
||||||
|
error,
|
||||||
style,
|
style,
|
||||||
containerStyle,
|
containerStyle,
|
||||||
...props
|
...props
|
||||||
@ -34,9 +36,18 @@ const TextInput = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={[styles.inputContainer, containerStyle]}>
|
<View style={[styles.inputContainer, containerStyle]}>
|
||||||
<ThemedText style={styles.inputLabel}>
|
<View className="w-full flex flex-row justify-between">
|
||||||
{label}
|
<ThemedText style={styles.inputLabel}>
|
||||||
</ThemedText>
|
{label}
|
||||||
|
</ThemedText>
|
||||||
|
{
|
||||||
|
error &&
|
||||||
|
<ThemedText color="bgSecondary" size="xxs">
|
||||||
|
{error}
|
||||||
|
</ThemedText>
|
||||||
|
}
|
||||||
|
</View>
|
||||||
|
|
||||||
<View style={styles.inputTextContainer}>
|
<View style={styles.inputTextContainer}>
|
||||||
<RNTextInput
|
<RNTextInput
|
||||||
style={[styles.textInput, style]}
|
style={[styles.textInput, style]}
|
||||||
|
|||||||
@ -26,6 +26,7 @@ export const Fonts = {
|
|||||||
// color
|
// color
|
||||||
bgPrimary: '#FFB645',
|
bgPrimary: '#FFB645',
|
||||||
bgSecondary: '#E2793F',
|
bgSecondary: '#E2793F',
|
||||||
|
bgCheck: "#FADBA1",
|
||||||
bgInput: '#FFF8DE',
|
bgInput: '#FFF8DE',
|
||||||
textPrimary: '#AC7E35',
|
textPrimary: '#AC7E35',
|
||||||
textSecondary: '#4C320C',
|
textSecondary: '#4C320C',
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user