|
|
@@ -1,209 +1,259 @@
|
|
|
-import { View, Text, StyleSheet, Pressable } from "react-native";
|
|
|
-import { useState } from "react";
|
|
|
-import { forgetPasswordFormData, HandleForgetPasswordFormDataChange } from "../../../type";
|
|
|
-import PhoneInput from "../../../global/phone_input";
|
|
|
-import NumberInput from "../../../global/number_input";
|
|
|
-import NormalButton from "../../../global/normal_button";
|
|
|
-import NormalInput from "../../../global/normal_input";
|
|
|
+import { View, Text, StyleSheet, Pressable } from 'react-native';
|
|
|
+import { useState } from 'react';
|
|
|
+import {
|
|
|
+ forgetPasswordFormData,
|
|
|
+ HandleForgetPasswordFormDataChange
|
|
|
+} from '../../../../types/signup';
|
|
|
+import PhoneInput from '../../../global/phone_input';
|
|
|
+import NumberInput from '../../../global/number_input';
|
|
|
+import NormalButton from '../../../global/normal_button';
|
|
|
+import NormalInput from '../../../global/normal_input';
|
|
|
|
|
|
type ForgetPasswordPageProps = {
|
|
|
- forgetPasswordFormData: forgetPasswordFormData;
|
|
|
- setForgetPasswordFormData: React.Dispatch<React.SetStateAction<forgetPasswordFormData>>;
|
|
|
- setScreen: React.Dispatch<React.SetStateAction<number>>;
|
|
|
+ forgetPasswordFormData: forgetPasswordFormData;
|
|
|
+ setForgetPasswordFormData: React.Dispatch<
|
|
|
+ React.SetStateAction<forgetPasswordFormData>
|
|
|
+ >;
|
|
|
+ setScreen: React.Dispatch<React.SetStateAction<number>>;
|
|
|
};
|
|
|
|
|
|
const ForgetPasswordPage: React.FC<ForgetPasswordPageProps> = ({
|
|
|
- forgetPasswordFormData,
|
|
|
- setForgetPasswordFormData,
|
|
|
- setScreen,
|
|
|
+ forgetPasswordFormData,
|
|
|
+ setForgetPasswordFormData,
|
|
|
+ setScreen
|
|
|
}) => {
|
|
|
- const [authError, setAuthError] = useState("");
|
|
|
- const [error, setError] = useState("");
|
|
|
- const [canSendOtp, setCanSendOtp] = useState(true);
|
|
|
- const [lockPhoneInput, setLockPhoneInput] = useState(false);
|
|
|
+ const [authError, setAuthError] = useState('');
|
|
|
+ const [error, setError] = useState('');
|
|
|
+ const [canSendOtp, setCanSendOtp] = useState(true);
|
|
|
+ const [lockPhoneInput, setLockPhoneInput] = useState(false);
|
|
|
|
|
|
- const handleVerification = () => {
|
|
|
- if (!forgetPasswordFormData.otp && !forgetPasswordFormData.phone) {
|
|
|
- setAuthError("請確保所有資料都已填寫");
|
|
|
- } else if (!forgetPasswordFormData.otp) {
|
|
|
- setAuthError("請輸入OTP驗證碼");
|
|
|
- } else if (!forgetPasswordFormData.phone) {
|
|
|
- setAuthError("請輸入電話號碼");
|
|
|
- } else {
|
|
|
- setAuthError("");
|
|
|
- setForgetPasswordFormData((prevFormData) => ({
|
|
|
- ...prevFormData,
|
|
|
- otpAuthCompleted: true,
|
|
|
- }));
|
|
|
- }
|
|
|
- };
|
|
|
+ const handleVerification = () => {
|
|
|
+ if (!forgetPasswordFormData.otp && !forgetPasswordFormData.phone) {
|
|
|
+ setAuthError('請確保所有資料都已填寫');
|
|
|
+ } else if (!forgetPasswordFormData.otp) {
|
|
|
+ setAuthError('請輸入OTP驗證碼');
|
|
|
+ } else if (!forgetPasswordFormData.phone) {
|
|
|
+ setAuthError('請輸入電話號碼');
|
|
|
+ } else {
|
|
|
+ setAuthError('');
|
|
|
+ setForgetPasswordFormData((prevFormData) => ({
|
|
|
+ ...prevFormData,
|
|
|
+ otpAuthCompleted: true
|
|
|
+ }));
|
|
|
+ }
|
|
|
+ };
|
|
|
|
|
|
- const handleFormDataChange: HandleForgetPasswordFormDataChange = (field, value) => {
|
|
|
- setForgetPasswordFormData((prevFormData) => ({
|
|
|
- ...prevFormData,
|
|
|
- [field]: value,
|
|
|
- }));
|
|
|
- };
|
|
|
+ const handleFormDataChange: HandleForgetPasswordFormDataChange = (
|
|
|
+ field,
|
|
|
+ value
|
|
|
+ ) => {
|
|
|
+ setForgetPasswordFormData((prevFormData) => ({
|
|
|
+ ...prevFormData,
|
|
|
+ [field]: value
|
|
|
+ }));
|
|
|
+ };
|
|
|
|
|
|
- const handleSubmitOtp = () => {
|
|
|
- if (forgetPasswordFormData.phoneVerificationStatus) {
|
|
|
- if (canSendOtp) {
|
|
|
- setCanSendOtp(false);
|
|
|
- setLockPhoneInput(true);
|
|
|
- console.log(lockPhoneInput);
|
|
|
- //can only request otp every 60 seconds
|
|
|
- setTimeout(() => {
|
|
|
- setCanSendOtp(true);
|
|
|
- setLockPhoneInput(false);
|
|
|
- }, 60000);
|
|
|
- setAuthError("");
|
|
|
- } else {
|
|
|
- setAuthError("請等待一分鐘後再重新發送。");
|
|
|
- }
|
|
|
- } else {
|
|
|
- setAuthError("請確保所有資料都已填寫。");
|
|
|
- }
|
|
|
- };
|
|
|
+ const handleSubmitOtp = () => {
|
|
|
+ if (forgetPasswordFormData.phone.length === 8) {
|
|
|
+ if (canSendOtp) {
|
|
|
+ setCanSendOtp(false);
|
|
|
+ setLockPhoneInput(true);
|
|
|
|
|
|
- const handleFinishResetPassword = () => {
|
|
|
- if (forgetPasswordFormData.newPassword !== forgetPasswordFormData.confirmedNewPassword) {
|
|
|
- setError("請確保新密碼和確認密碼相同");
|
|
|
- } else {
|
|
|
- setError("");
|
|
|
- setScreen(1);
|
|
|
- }
|
|
|
- };
|
|
|
- return (
|
|
|
- <>
|
|
|
- <View style={styles.container}>
|
|
|
- <View style={styles.bottomContainer}>
|
|
|
- <Text style={styles.text}>驗證電話號碼後即可重置密碼</Text>
|
|
|
- <PhoneInput
|
|
|
- placeholder="輸入電話號碼"
|
|
|
- handleForgetPasswordFormDataChange={handleFormDataChange}
|
|
|
- editable={!lockPhoneInput}
|
|
|
- extendedStyle={{ opacity: !lockPhoneInput ? 1 : 0.5 }}
|
|
|
- />
|
|
|
- <View
|
|
|
- style={{
|
|
|
- display: "flex",
|
|
|
- flexDirection: "row",
|
|
|
- paddingVertical: 10,
|
|
|
- gap: 10,
|
|
|
- }}
|
|
|
- >
|
|
|
- <NumberInput
|
|
|
- placeholder="OTP驗證碼"
|
|
|
- onChangeText={(t) => handleFormDataChange("otp", t)}
|
|
|
- editable={!forgetPasswordFormData.otpAuthCompleted}
|
|
|
- extendedStyle={{ flex: 1, opacity: !forgetPasswordFormData.otpAuthCompleted ? 1 : 0.5 }}
|
|
|
- />
|
|
|
- <NormalButton
|
|
|
- title={<Text style={{ color: "#fff" }}>{lockPhoneInput ? "已發送" : "驗證"}</Text>}
|
|
|
- onPress={handleSubmitOtp}
|
|
|
- extendedStyle={{ flex: 1 / 2 }}
|
|
|
- />
|
|
|
- </View>
|
|
|
- <NormalButton
|
|
|
- title={
|
|
|
- <Text style={{ color: "#fff" }}>
|
|
|
- {forgetPasswordFormData.otpAuthCompleted == true ? "已驗證" : "驗證"}
|
|
|
- </Text>
|
|
|
- }
|
|
|
- onPress={handleVerification}
|
|
|
- extendedStyle={
|
|
|
- forgetPasswordFormData.otpAuthCompleted == true ? { backgroundColor: "#70787C" } : {}
|
|
|
- }
|
|
|
- />
|
|
|
+ //can only request otp every 60 seconds
|
|
|
+ setTimeout(() => {
|
|
|
+ setCanSendOtp(true);
|
|
|
+ setLockPhoneInput(false);
|
|
|
+ }, 60000);
|
|
|
+ setAuthError('');
|
|
|
+ } else {
|
|
|
+ setAuthError('請等待一分鐘後再重新發送。');
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ setAuthError('請確保所有資料都已填寫。');
|
|
|
+ }
|
|
|
+ };
|
|
|
|
|
|
- {authError && <Text style={styles.errorMessage}>{authError}</Text>}
|
|
|
- {lockPhoneInput && (
|
|
|
- <Pressable
|
|
|
- disabled={forgetPasswordFormData.otpAuthCompleted}
|
|
|
- onPress={() => setLockPhoneInput(false)}
|
|
|
- >
|
|
|
- <Text style={[styles.footer, forgetPasswordFormData.otpAuthCompleted && { opacity: 0.5 }]}>
|
|
|
- 修改電話號碼
|
|
|
- </Text>
|
|
|
- </Pressable>
|
|
|
- )}
|
|
|
+ const handleFinishResetPassword = () => {
|
|
|
+ if (
|
|
|
+ forgetPasswordFormData.newPassword !==
|
|
|
+ forgetPasswordFormData.confirmedNewPassword
|
|
|
+ ) {
|
|
|
+ setError('請確保新密碼和確認密碼相同');
|
|
|
+ } else {
|
|
|
+ setError('');
|
|
|
+ setScreen(1);
|
|
|
+ }
|
|
|
+ };
|
|
|
+ return (
|
|
|
+ <>
|
|
|
+ <View style={styles.container}>
|
|
|
+ <View style={styles.bottomContainer}>
|
|
|
+ <Text style={styles.text}>驗證電話號碼後即可重置密碼</Text>
|
|
|
+ <PhoneInput
|
|
|
+ placeholder="輸入電話號碼"
|
|
|
+ onChangeText={(phone) =>
|
|
|
+ setForgetPasswordFormData({
|
|
|
+ ...forgetPasswordFormData,
|
|
|
+ phone: phone
|
|
|
+ })
|
|
|
+ }
|
|
|
+ editable={!lockPhoneInput}
|
|
|
+ extendedStyle={{ opacity: !lockPhoneInput ? 1 : 0.5 }}
|
|
|
+ />
|
|
|
+ <View
|
|
|
+ style={{
|
|
|
+ display: 'flex',
|
|
|
+ flexDirection: 'row',
|
|
|
+ paddingVertical: 10,
|
|
|
+ gap: 10
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <NumberInput
|
|
|
+ placeholder="OTP驗證碼"
|
|
|
+ onChangeText={(t) => handleFormDataChange('otp', t)}
|
|
|
+ editable={!forgetPasswordFormData.otpAuthCompleted}
|
|
|
+ extendedStyle={{
|
|
|
+ flex: 1,
|
|
|
+ opacity:
|
|
|
+ !forgetPasswordFormData.otpAuthCompleted
|
|
|
+ ? 1
|
|
|
+ : 0.5
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ <NormalButton
|
|
|
+ title={
|
|
|
+ <Text style={{ color: '#fff' }}>
|
|
|
+ {lockPhoneInput ? '已發送' : '驗證'}
|
|
|
+ </Text>
|
|
|
+ }
|
|
|
+ onPress={handleSubmitOtp}
|
|
|
+ extendedStyle={{ flex: 1 / 2 }}
|
|
|
+ />
|
|
|
+ </View>
|
|
|
+ <NormalButton
|
|
|
+ title={
|
|
|
+ <Text style={{ color: '#fff' }}>
|
|
|
+ {forgetPasswordFormData.otpAuthCompleted == true
|
|
|
+ ? '已驗證'
|
|
|
+ : '驗證'}
|
|
|
+ </Text>
|
|
|
+ }
|
|
|
+ onPress={handleVerification}
|
|
|
+ extendedStyle={
|
|
|
+ forgetPasswordFormData.otpAuthCompleted == true
|
|
|
+ ? { backgroundColor: '#70787C' }
|
|
|
+ : {}
|
|
|
+ }
|
|
|
+ />
|
|
|
|
|
|
- {forgetPasswordFormData.otpAuthCompleted && (
|
|
|
- <View
|
|
|
- style={[
|
|
|
- styles.hiddenPasswordFields,
|
|
|
- forgetPasswordFormData.otpAuthCompleted ? styles.opacityFull : styles.opacityZero,
|
|
|
- ]}
|
|
|
- >
|
|
|
- <NormalInput
|
|
|
- placeholder="新密碼"
|
|
|
- onChangeText={(t) => handleFormDataChange("newPassword", t)}
|
|
|
- secureTextEntry={true}
|
|
|
- textContentType={"oneTimeCode"}
|
|
|
- />
|
|
|
- <NormalInput
|
|
|
- placeholder="確認密碼"
|
|
|
- onChangeText={(t) => handleFormDataChange("confirmedNewPassword", t)}
|
|
|
- secureTextEntry={true}
|
|
|
- textContentType={"oneTimeCode"}
|
|
|
- />
|
|
|
- <NormalButton
|
|
|
- title={<Text style={{ color: "#fff" }}>重置</Text>}
|
|
|
- onPress={handleFinishResetPassword}
|
|
|
- extendedStyle={{}}
|
|
|
- />
|
|
|
- </View>
|
|
|
- )}
|
|
|
+ {authError && (
|
|
|
+ <Text style={styles.errorMessage}>{authError}</Text>
|
|
|
+ )}
|
|
|
+ {lockPhoneInput && (
|
|
|
+ <Pressable
|
|
|
+ disabled={forgetPasswordFormData.otpAuthCompleted}
|
|
|
+ onPress={() => setLockPhoneInput(false)}
|
|
|
+ >
|
|
|
+ <Text
|
|
|
+ style={[
|
|
|
+ styles.footer,
|
|
|
+ forgetPasswordFormData.otpAuthCompleted && {
|
|
|
+ opacity: 0.5
|
|
|
+ }
|
|
|
+ ]}
|
|
|
+ >
|
|
|
+ 修改電話號碼
|
|
|
+ </Text>
|
|
|
+ </Pressable>
|
|
|
+ )}
|
|
|
|
|
|
- {error && <Text style={styles.errorMessage}>{error}</Text>}
|
|
|
- </View>
|
|
|
- </View>
|
|
|
- </>
|
|
|
- );
|
|
|
+ {forgetPasswordFormData.otpAuthCompleted && (
|
|
|
+ <View
|
|
|
+ style={[
|
|
|
+ styles.hiddenPasswordFields,
|
|
|
+ forgetPasswordFormData.otpAuthCompleted
|
|
|
+ ? styles.opacityFull
|
|
|
+ : styles.opacityZero
|
|
|
+ ]}
|
|
|
+ >
|
|
|
+ <NormalInput
|
|
|
+ placeholder="新密碼"
|
|
|
+ onChangeText={(t) =>
|
|
|
+ handleFormDataChange('newPassword', t)
|
|
|
+ }
|
|
|
+ secureTextEntry={true}
|
|
|
+ textContentType={'oneTimeCode'}
|
|
|
+ />
|
|
|
+ <NormalInput
|
|
|
+ placeholder="確認密碼"
|
|
|
+ onChangeText={(t) =>
|
|
|
+ handleFormDataChange(
|
|
|
+ 'confirmedNewPassword',
|
|
|
+ t
|
|
|
+ )
|
|
|
+ }
|
|
|
+ secureTextEntry={true}
|
|
|
+ textContentType={'oneTimeCode'}
|
|
|
+ />
|
|
|
+ <NormalButton
|
|
|
+ title={
|
|
|
+ <Text style={{ color: '#fff' }}>重置</Text>
|
|
|
+ }
|
|
|
+ onPress={handleFinishResetPassword}
|
|
|
+ extendedStyle={{}}
|
|
|
+ />
|
|
|
+ </View>
|
|
|
+ )}
|
|
|
+
|
|
|
+ {error && <Text style={styles.errorMessage}>{error}</Text>}
|
|
|
+ </View>
|
|
|
+ </View>
|
|
|
+ </>
|
|
|
+ );
|
|
|
};
|
|
|
|
|
|
const styles = StyleSheet.create({
|
|
|
- container: {
|
|
|
- flex: 1,
|
|
|
- marginHorizontal: 20,
|
|
|
- },
|
|
|
+ container: {
|
|
|
+ flex: 1,
|
|
|
+ marginHorizontal: 20
|
|
|
+ },
|
|
|
|
|
|
- titleText: {
|
|
|
- fontSize: 24,
|
|
|
- fontWeight: "300",
|
|
|
- },
|
|
|
- bottomContainer: {
|
|
|
- flex: 3,
|
|
|
- paddingBottom: 100,
|
|
|
- },
|
|
|
- breakline: {
|
|
|
- width: 24,
|
|
|
- height: 1,
|
|
|
- backgroundColor: "#000000",
|
|
|
- marginVertical: 17,
|
|
|
- },
|
|
|
- text: {
|
|
|
- fontSize: 18,
|
|
|
- paddingBottom: 10,
|
|
|
- },
|
|
|
- hiddenPasswordFields: {
|
|
|
- gap: 10,
|
|
|
- paddingTop: 10,
|
|
|
- },
|
|
|
- opacityZero: {
|
|
|
- opacity: 0,
|
|
|
- },
|
|
|
- opacityFull: {
|
|
|
- opacity: 1,
|
|
|
- },
|
|
|
- errorMessage: {
|
|
|
- fontSize: 14,
|
|
|
- color: "#ff0033",
|
|
|
- fontWeight: "400",
|
|
|
- marginLeft: 10,
|
|
|
- marginTop: 10,
|
|
|
- },
|
|
|
- footer: { color: "#02677D", fontSize: 16, paddingVertical: 10 },
|
|
|
+ titleText: {
|
|
|
+ fontSize: 24,
|
|
|
+ fontWeight: '300'
|
|
|
+ },
|
|
|
+ bottomContainer: {
|
|
|
+ flex: 3,
|
|
|
+ paddingBottom: 100
|
|
|
+ },
|
|
|
+ breakline: {
|
|
|
+ width: 24,
|
|
|
+ height: 1,
|
|
|
+ backgroundColor: '#000000',
|
|
|
+ marginVertical: 17
|
|
|
+ },
|
|
|
+ text: {
|
|
|
+ fontSize: 18,
|
|
|
+ paddingBottom: 10
|
|
|
+ },
|
|
|
+ hiddenPasswordFields: {
|
|
|
+ gap: 10,
|
|
|
+ paddingTop: 10
|
|
|
+ },
|
|
|
+ opacityZero: {
|
|
|
+ opacity: 0
|
|
|
+ },
|
|
|
+ opacityFull: {
|
|
|
+ opacity: 1
|
|
|
+ },
|
|
|
+ errorMessage: {
|
|
|
+ fontSize: 14,
|
|
|
+ color: '#ff0033',
|
|
|
+ fontWeight: '400',
|
|
|
+ marginLeft: 10,
|
|
|
+ marginTop: 10
|
|
|
+ },
|
|
|
+ footer: { color: '#02677D', fontSize: 16, paddingVertical: 10 }
|
|
|
});
|
|
|
|
|
|
export default ForgetPasswordPage;
|