208 lines
8.6 KiB
TypeScript
208 lines
8.6 KiB
TypeScript
'use client';
|
|
|
|
import React, { useState, type FormEvent, type ChangeEvent, useEffect, useTransition } from 'react'
|
|
import { useAuthStore } from '@/zustand/authStore';
|
|
import { redirect } from 'next/navigation';
|
|
import StepEnterPassword from '@/features/auth/components/StepEnterPassword';
|
|
import StepEnterNumber from '@/features/auth/components/StepEnterNumber';
|
|
import StepEnterOtp from '@/features/auth/components/StepEnterOtp';
|
|
import { AUTH_PAGE_ELEMENT, AUTH_STEP } from '@/enums';
|
|
import { useCountdown } from '@/hooks/useCountdown';
|
|
import StepNewPassword from '@/features/auth/components/StepNewPassword';
|
|
import AuthFormWrapper from '@/features/auth/components/AuthFormWrapper';
|
|
import { useLogin } from '@/hooks/auth/useLogin';
|
|
import { useSignup } from '@/hooks/auth/useSignup';
|
|
import { useCheckUserExistsLazy } from '@/hooks/auth/useCheckUserExists';
|
|
import { useOtpRequest } from '@/hooks/auth/useOtpRequest';
|
|
import { useOtpValidation } from '@/hooks/auth/useOtpValidation';
|
|
import { useResetPassword } from '@/hooks/auth/useResetPassword';
|
|
|
|
type Props = object
|
|
|
|
function AuthIndex({ }: Props) {
|
|
const [number, setNumber] = useState("");
|
|
const [password, setPassword] = useState("");
|
|
const [passwordRepeat, setPasswordRepeat] = useState("");
|
|
const [otp, setOtp] = useState("");
|
|
const [showPassword, setShowPassword] = useState(false);
|
|
const [showPasswordRepeat, setShowPasswordRepeat] = useState(false);
|
|
const [rememberMe, setRememberMe] = useState(false);
|
|
const [step, setStep] = useState(AUTH_STEP.ENTER_NUMBER);
|
|
const { timerRunning, secondsLeft, restart, stop } = useCountdown(step === AUTH_STEP.ENTER_OTP);
|
|
const [isPending, startTransition] = useTransition();
|
|
|
|
const isAuthenticated = useAuthStore((state) => state.isAuthenticated)
|
|
const loginMutation = useLogin()
|
|
const signupMutation = useSignup()
|
|
const { run: runUserExistCheck } = useCheckUserExistsLazy()
|
|
const { run: runOtpRequest } = useOtpRequest();
|
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
const { run: runOtpValidation } = useOtpValidation();
|
|
const { run: runResetPassword } = useResetPassword();
|
|
|
|
const resetStates = () => {
|
|
setNumber('');
|
|
setPassword('');
|
|
setPasswordRepeat('');
|
|
setOtp('');
|
|
setShowPassword(false);
|
|
setShowPasswordRepeat(false);
|
|
setRememberMe(false);
|
|
stop();
|
|
}
|
|
|
|
useEffect(() => {
|
|
if (isAuthenticated) {
|
|
redirect("/");
|
|
}
|
|
}, [isAuthenticated])
|
|
|
|
useEffect(() => {
|
|
if (step === AUTH_STEP.ENTER_OTP) {
|
|
startTransition(() => {
|
|
setOtp('');
|
|
console.log("REQUEST OTP")
|
|
runOtpRequest(number);
|
|
});
|
|
}
|
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
}, [step]);
|
|
|
|
const onChange = (e: ChangeEvent<HTMLInputElement>) => {
|
|
if (e.target.name == AUTH_PAGE_ELEMENT.INPUT_PHONE) {
|
|
setNumber(() => e.target.value)
|
|
}
|
|
else if (e.target.name == AUTH_PAGE_ELEMENT.INPUT_PASSWORD) {
|
|
setPassword(() => e.target.value)
|
|
}
|
|
else if (e.target.name == AUTH_PAGE_ELEMENT.INPUT_PASSWORD_REPEAT) {
|
|
setPasswordRepeat(() => e.target.value)
|
|
}
|
|
else if (e.target.name == AUTH_PAGE_ELEMENT.INPUT_REMEMBER_ME) {
|
|
setRememberMe((state) => !state)
|
|
}
|
|
else if (e.target.name.startsWith(AUTH_PAGE_ELEMENT.INPUT_OTP)) {
|
|
const index = +e.target.name.split('-')[2];
|
|
const prev = otp.padEnd(6).split('');
|
|
prev[index] = e.target.value;
|
|
const next = prev.join('');
|
|
if (otp.length >= 6 && next.trim().length >= otp.length) return;
|
|
setOtp(next.trimEnd());
|
|
}
|
|
}
|
|
|
|
const onClick = async (e: React.MouseEvent<HTMLButtonElement, MouseEvent> | React.MouseEvent<HTMLInputElement, MouseEvent>) => {
|
|
e.stopPropagation();
|
|
const target = e.target as HTMLButtonElement;
|
|
|
|
if (target.id === AUTH_PAGE_ELEMENT.TOGGLE_PASSWORD) {
|
|
setShowPassword((state) => !state);
|
|
}
|
|
if (target.id === AUTH_PAGE_ELEMENT.TOGGLE_REPEAT_PASSWORD) {
|
|
setShowPasswordRepeat((state) => !state);
|
|
}
|
|
else if (target.id === AUTH_PAGE_ELEMENT.RESET_PASSWORD) {
|
|
setShowPassword(false);
|
|
setShowPasswordRepeat(false);
|
|
setPassword('');
|
|
setPasswordRepeat('');
|
|
setStep(() => AUTH_STEP.ENTER_OTP)
|
|
}
|
|
else if (target.id === AUTH_PAGE_ELEMENT.RESEND_OTP) {
|
|
if (!timerRunning) {
|
|
startTransition(async () => {
|
|
try {
|
|
await runOtpRequest(number);
|
|
restart();
|
|
} catch {
|
|
console.error("Could not ask for otp")
|
|
}
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
const onSubmit = async (e: FormEvent<HTMLFormElement>) => {
|
|
e.preventDefault();
|
|
startTransition(async () => {
|
|
try {
|
|
if (step == AUTH_STEP.ENTER_NUMBER) {
|
|
|
|
if (await runUserExistCheck(number)) {
|
|
setStep(AUTH_STEP.ENTER_PASSWORD)
|
|
} else {
|
|
setStep(AUTH_STEP.ENTER_OTP);
|
|
}
|
|
}
|
|
else if (step == AUTH_STEP.ENTER_PASSWORD) {
|
|
try {
|
|
await loginMutation.mutateAsync({ phone: number, password })
|
|
console.log("Logged in")
|
|
redirect("/")
|
|
}
|
|
catch (e) {
|
|
console.error("Wrong credentials: ", e)
|
|
}
|
|
}
|
|
else if (step == AUTH_STEP.ENTER_OTP) {
|
|
// if (!await runOtpValidation({ phone: number, otp })) {
|
|
// setOtp('');
|
|
// console.error('Wrong otp');
|
|
// }
|
|
stop();
|
|
console.log(await runUserExistCheck(number));
|
|
if (await runUserExistCheck(number)) {
|
|
console.log("1")
|
|
setStep(AUTH_STEP.ENTER_RESET_PASSWORD)
|
|
} else {
|
|
console.log("2")
|
|
setStep(AUTH_STEP.ENTER_NEW_PASSWORD)
|
|
}
|
|
}
|
|
else if (step == AUTH_STEP.ENTER_RESET_PASSWORD) {
|
|
console.log("Password changed")
|
|
try {
|
|
await runResetPassword({
|
|
phone: number,
|
|
newPassword: password,
|
|
otp
|
|
})
|
|
resetStates();
|
|
setStep(AUTH_STEP.ENTER_NUMBER)
|
|
} catch (ex) {
|
|
console.error('Password reset failed: ', ex)
|
|
}
|
|
}
|
|
else if (step == AUTH_STEP.ENTER_NEW_PASSWORD) {
|
|
try {
|
|
await signupMutation.mutateAsync({ phone: number, password })
|
|
console.log("Signed up")
|
|
redirect("/")
|
|
}
|
|
catch (e) {
|
|
console.error("Could not signup: ", e)
|
|
}
|
|
}
|
|
} catch (ex) {
|
|
console.error(ex)
|
|
}
|
|
});
|
|
}
|
|
|
|
const stepMap = {
|
|
[AUTH_STEP.ENTER_NUMBER]: <StepEnterNumber pending={isPending} onChange={onChange} value={number} />,
|
|
[AUTH_STEP.ENTER_PASSWORD]: <StepEnterPassword pending={isPending} onChange={onChange} onClick={onClick} value={password} passwordVisible={showPassword} rememberMe={rememberMe} />,
|
|
[AUTH_STEP.ENTER_OTP]: <StepEnterOtp pending={isPending} onChange={onChange} onClick={onClick} phoneNumber={number} value={otp} timerRunning={timerRunning} secondsLeft={secondsLeft} />,
|
|
[AUTH_STEP.ENTER_NEW_PASSWORD]: <StepNewPassword pending={isPending} onChange={onChange} onClick={onClick} value={password} repeatValue={passwordRepeat} passwordVisible={showPassword} repeatPasswordVisible={showPasswordRepeat} />,
|
|
[AUTH_STEP.ENTER_RESET_PASSWORD]: <StepNewPassword isReset pending={isPending} onChange={onChange} onClick={onClick} value={password} repeatValue={passwordRepeat} passwordVisible={showPassword} repeatPasswordVisible={showPasswordRepeat} />,
|
|
}
|
|
|
|
return (
|
|
<AuthFormWrapper isPending={isPending} onSubmit={onSubmit}>
|
|
{stepMap[step] || 'say what now?'}
|
|
</AuthFormWrapper>
|
|
)
|
|
}
|
|
|
|
export default AuthIndex
|