Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat] 비밀번호 재설정 QA #228

Merged
merged 19 commits into from
Oct 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions src/common/component/Button/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import { ButtonHTMLAttributes, ReactNode } from 'react';
import { ButtonHTMLAttributes } from 'react';

import { Size } from '@/common/type/design';

import { buttonStyle, sizeStyle, variantStyle } from './Button.style';

export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
children: ReactNode;
variant?: 'primary' | 'secondary' | 'text' | 'action';
onClick?: () => void;
size?: Extract<Size, 'large' | 'medium' | 'small'>;
}

Expand Down
8 changes: 6 additions & 2 deletions src/common/hook/useTimer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,14 @@ export const useTimer = (initialTime: number, message: string) => {
const [remainTime, setRemainTime] = useState(initialTime);
const ref = useRef<Timeout>();

const handleTrigger = useCallback(() => {
const trigger = useCallback(() => {
setIsTriggered(true);
}, []);

const reset = useCallback(() => {
setRemainTime(initialTime);
}, []);

useEffect(() => {
ref.current = setInterval(() => {
if (remainTime > 0) {
Expand All @@ -29,5 +33,5 @@ export const useTimer = (initialTime: number, message: string) => {
return () => clearInterval(ref.current);
}, [remainTime]);

return { remainTime, isTriggered, handleTrigger };
return { remainTime, isTriggered, trigger, reset };
};
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import BlockIcon from '@/page/archiving/index/component/TimeBlockModal/component
import BlockBox from '@/page/archiving/index/component/TimeBlockModal/component/Box/BlockBox';
import { BLOCK_ICON } from '@/page/archiving/index/component/TimeBlockModal/constant/iconBlock';

import WorkSapceInfo from '@/shared/component/WorkSpaceModal/info/WorkSpaceInfo';
import WorkSapceInfo from '@/shared/component/workSpaceModal/info/WorkSpaceInfo';
import { useBlockContext } from '@/shared/hook/common/useBlockContext';

interface BlockModalProps {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { formatDatePost } from '@/page/archiving/index/component/TimeBlockModal/
import { getRandomColor } from '@/page/archiving/index/util/color';

import { Files } from '@/shared/api/time-blocks/team/time-block/type';
import WorkSapceInfo from '@/shared/component/WorkSpaceModal/info/WorkSpaceInfo';
import WorkSapceInfo from '@/shared/component/workSpaceModal/info/WorkSpaceInfo';
import { useBlockContext } from '@/shared/hook/common/useBlockContext';
import { useCloseModal } from '@/shared/store/modal';
import { useToastAction } from '@/shared/store/toast';
Expand Down
32 changes: 19 additions & 13 deletions src/page/login/password/auth/PasswordAuthPage.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
import { formStyle, pageStyle, timestyle } from '@/page/login/password/auth/PasswordAuthPage.style';
import { useResendMailMutation } from '@/page/login/password/auth/hook/useResendMailMutation';
import { formatTime } from '@/page/signUp/info/util/formatTime';

import { useCallback, useState } from 'react';
import { useNavigate } from 'react-router-dom';

Expand All @@ -13,9 +9,14 @@ import SupportingText from '@/common/component/SupportingText/SupportingText';
import { useInput } from '@/common/hook/useInput';
import { useTimer } from '@/common/hook/useTimer';

import { formStyle, pageStyle, timestyle } from '@/page/login/password/auth/PasswordAuthPage.style';
import { useResendMailMutation } from '@/page/login/password/auth/hook/useResendMailMutation';
import { formatTime } from '@/page/signUp/info/util/formatTime';

import { EMAIL_REMAIN_TIME, PLACEHOLDER, SUPPORTING_TEXT } from '@/shared/constant/form';
import { PATH } from '@/shared/constant/path';
import { useVerifyCodeMutation } from '@/shared/hook/api/useVerifyCodeMutation';
import { useToastAction } from '@/shared/store/toast';
import { validateCode, validateEmail } from '@/shared/util/validate';

const PasswordAuthPage = () => {
Expand All @@ -26,22 +27,27 @@ const PasswordAuthPage = () => {
const {
remainTime,
isTriggered: isMailSent,
handleTrigger: handleSend,
trigger: handleSend,
reset: handleResetTimer,
} = useTimer(EMAIL_REMAIN_TIME, SUPPORTING_TEXT.EMAIL_EXPIRED);

const navigate = useNavigate();
const { mutate: resendMailMutation } = useResendMailMutation(email);
const { mutate, isError } = useVerifyCodeMutation(email, authCode);

const handleMailSend = useCallback(() => {
if (validateEmail(email)) {
resendMailMutation(undefined, {
onSuccess: () => {
handleSend();
},
});
const { createToast } = useToastAction();

const handleMailSend = () => {
if (!validateEmail(email)) {
createToast(SUPPORTING_TEXT.EMAIL_INVALID, 'error');

return;
}
}, [email, resendMailMutation, handleSend]);
handleSend();
handleResetTimer();

resendMailMutation();
};

const handleVerifyCode = useCallback(() => {
if (validateCode(authCode)) {
Expand Down
52 changes: 28 additions & 24 deletions src/page/login/password/reset/PasswordResetPage.tsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,42 @@
import { formStyle, pageStyle } from '@/page/login/password/reset/PasswordResetPage.style';
import { useResetPasswordMutation } from '@/page/login/password/reset/hook/useResetPasswordMutation';

import { useState } from 'react';
import { useLocation, useNavigate } from 'react-router-dom';

import Button from '@/common/component/Button/Button';
import Flex from '@/common/component/Flex/Flex';
import Heading from '@/common/component/Heading/Heading';
import Input from '@/common/component/Input/Input';

import { formStyle, pageStyle } from '@/page/login/password/reset/PasswordResetPage.style';
import { useResetPasswordMutation } from '@/page/login/password/reset/hook/api/useResetPasswordMutation';
import { usePasswordForm } from '@/page/login/password/reset/hook/common/usePasswordForm';

import { PLACEHOLDER } from '@/shared/constant/form';
import { PATH } from '@/shared/constant/path';

const PasswordResetPage = () => {
const [updatePassword, setUpdatePassword] = useState('');
const [updatePasswordConfirm, setUpdatePasswordConfirm] = useState('');
const navigate = useNavigate();

const { state } = useLocation();
const { mutate } = useResetPasswordMutation();

const handlePasswordChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setUpdatePassword(e.target.value);
};
const { mutate } = useResetPasswordMutation();

const handlePasswordConfirmChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setUpdatePasswordConfirm(e.target.value);
};
const {
form,
handlePasswordChange,
handlePasswordValidate,
isPasswordCheckerError,
isPasswordError,
passwordCheckerSupportingTxt,
passwordSupportingTxt,
} = usePasswordForm();

const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();

mutate(
{
email: state,
password: updatePassword,
passwordChecker: updatePasswordConfirm,
password: form.updatedPassword,
passwordChecker: form.updatedPasswordChecker,
},
Comment on lines +38 to +39
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

확실히 form으로 묶으니 전달하고자 하는 바를 명확하게 알 수 있어서 좋네요💯!!

{
onSuccess: () => {
Expand All @@ -52,22 +54,24 @@ const PasswordResetPage = () => {
<Flex styles={{ direction: 'column', width: '100%', gap: '1.6rem', justify: 'space-between' }}>
<Input
variant="underline"
type="password"
placeholder={PLACEHOLDER.PASSWORD}
value={updatePassword}
onChange={handlePasswordChange}
value={form.updatedPassword}
isError={isPasswordError}
supportingText={passwordSupportingTxt}
onChange={(e) => handlePasswordChange('updatedPassword', e)}
/>
<Input
variant="underline"
type="password"
placeholder={PLACEHOLDER.PASSWORD_CONFIRM}
value={updatePasswordConfirm}
onChange={handlePasswordConfirmChange}
value={form.updatedPasswordChecker}
isError={isPasswordCheckerError}
supportingText={passwordCheckerSupportingTxt}
onChange={(e) => handlePasswordChange('updatedPasswordChecker', e)}
/>
</Flex>
<Button
type="submit"
variant="primary"
size="large"
disabled={updatePassword.length === 0 || updatePassword !== updatePasswordConfirm}>
<Button type="submit" variant="primary" size="large" disabled={!handlePasswordValidate()}>
완료
</Button>
</form>
Expand Down
68 changes: 68 additions & 0 deletions src/page/login/password/reset/hook/common/usePasswordForm.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { useCallback, useState } from 'react';

import { PASSWORD_VALID_FORMAT, SUPPORTING_TEXT } from '@/shared/constant/form';

type Password = 'updatedPassword' | 'updatedPasswordChecker';

export const usePasswordForm = () => {
const [form, setForm] = useState({
updatedPassword: '',
updatedPasswordChecker: '',
});

const handlePasswordChange = useCallback((key: Password, e: React.ChangeEvent<HTMLInputElement>) => {
const { value } = e.target;

setForm((prev) => ({
...prev,
[key]: value,
}));
}, []);

const handlePasswordValidate = useCallback(() => {
const isPasswordValid = PASSWORD_VALID_FORMAT.test(form.updatedPassword);

const isConfirmPasswordValid = form.updatedPassword === form.updatedPasswordChecker;

return form.updatedPassword && form.updatedPasswordChecker && isPasswordValid && isConfirmPasswordValid;
}, [form.updatedPassword, form.updatedPasswordChecker]);

// 에러에 맞는 supporting text 반환
const handlePasswordMessage = useCallback((password: string) => {
if (password === '') {
return SUPPORTING_TEXT.PASSWORD;
}

if (!PASSWORD_VALID_FORMAT.test(password)) {
return SUPPORTING_TEXT.PASSWORD_INVALID;
}
}, []);

const handlePasswordCheckerMessage = useCallback((password: string, passwordChecker: string) => {
if (passwordChecker === '') {
return SUPPORTING_TEXT.PASSWORD;
}

if (password !== passwordChecker) {
return SUPPORTING_TEXT.PASSWORD_NO_EQUAL;
}
}, []);

const isPasswordError = !!form.updatedPassword && !handlePasswordValidate();
const isPasswordCheckerError = !!form.updatedPasswordChecker && !handlePasswordValidate();
const passwordSupportingTxt = form.updatedPassword && handlePasswordMessage(form.updatedPassword);
const passwordCheckerSupportingTxt =
form.updatedPasswordChecker && handlePasswordCheckerMessage(form.updatedPassword, form.updatedPasswordChecker);

return {
form,
handlePasswordChange,
handlePasswordValidate,
handlePasswordMessage,
handlePasswordCheckerMessage,
isPasswordError,
isPasswordCheckerError,
passwordSupportingTxt,
passwordCheckerSupportingTxt,
};
};
16 changes: 8 additions & 8 deletions src/page/signUp/info/component/InfoForm/InfoForm.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,3 @@
import { formStyle, identifyStyle, timeStyle } from '@/page/signUp/info/component/InfoForm/InfoForm.style';
import UnivSelectTriggerButton from '@/page/signUp/info/component/UnivSelectTriggerButton/Button';
import { useSendMailMutation } from '@/page/signUp/info/hook/api/useSendMailMutation';
import { useInfoForm } from '@/page/signUp/info/hook/common/useInfoForm';
import { useTimer } from '@/page/signUp/info/hook/common/useTimer';
import { formatTime } from '@/page/signUp/info/util/formatTime';

import ArrowDown from '@/common/asset/svg/arrow-down.svg?react';
import ArrowUp from '@/common/asset/svg/arrow-up.svg?react';
import Button from '@/common/component/Button/Button';
Expand All @@ -13,6 +6,13 @@ import Input from '@/common/component/Input/Input';
import Select from '@/common/component/Select/Select';
import { useOutsideClick } from '@/common/hook';

import { formStyle, identifyStyle, timeStyle } from '@/page/signUp/info/component/InfoForm/InfoForm.style';
import UnivSelectTriggerButton from '@/page/signUp/info/component/UnivSelectTriggerButton/Button';
import { useSendMailMutation } from '@/page/signUp/info/hook/api/useSendMailMutation';
import { useInfoForm } from '@/page/signUp/info/hook/common/useInfoForm';
import { useTimer } from '@/page/signUp/info/hook/common/useTimer';
import { formatTime } from '@/page/signUp/info/util/formatTime';

import {
AUTHCODE_MAXLENGTH,
EMAIL_REMAIN_TIME,
Expand Down Expand Up @@ -139,7 +139,7 @@ const InfoForm = () => {
<Button
css={{ padding: '1rem 1.6rem', width: '13rem' }}
size="large"
onClick={verityCodeMutate}
onClick={() => verityCodeMutate()}
disabled={!validateCode(info.authCode)}>
인증하기
</Button>
Expand Down
2 changes: 1 addition & 1 deletion src/shared/component/Modal/ModalContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Modal from '@/common/component/Modal/Modal';
import { BlockFlow } from '@/page/archiving/index/component/TimeBlockModal';

import DeleteModal from '@/shared/component/DeleteModal/DeleteModal';
import { WorkSpaceFlow } from '@/shared/component/WorkSpaceModal';
import { WorkSpaceFlow } from '@/shared/component/workSpaceModal';
import { BlockProvider } from '@/shared/hook/common/useBlockContext';
import { WorkSpaceProvider } from '@/shared/hook/common/useWorkSpaceContext';
import { useCloseModal, useModalContentType, useModalIsOpen } from '@/shared/store/modal';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import {
arrowStyle,
selectButtonStyle,
selectedTextStyle,
} from '@/shared/component/WorkSpaceModal/category/WorkSpaceCategory.style';
import WorkSapceInfo from '@/shared/component/WorkSpaceModal/info/WorkSpaceInfo';
import { buttonStyle, sectionStyle } from '@/shared/component/WorkSpaceModal/name/WorkSpaceName.style';
} from '@/shared/component/workSpaceModal/category/WorkSpaceCategory.style';
import WorkSapceInfo from '@/shared/component/workSpaceModal/info/WorkSpaceInfo';
import { buttonStyle, sectionStyle } from '@/shared/component/workSpaceModal/name/WorkSpaceName.style';
import useCategoryListQuery from '@/shared/hook/api/useCategoryListQuery';
import { useWorkSpaceContext } from '@/shared/hook/common/useWorkSpaceContext';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import WorkSpaceCompleteImg from '@/common/asset/svg/ic_complete.svg?react';
import Flex from '@/common/component/Flex/Flex';

import WorkSapceInfo from '@/shared/component/WorkSpaceModal/info/WorkSpaceInfo';
import { sectionStyle } from '@/shared/component/WorkSpaceModal/name/WorkSpaceName.style';
import WorkSapceInfo from '@/shared/component/workSpaceModal/info/WorkSpaceInfo';
import { sectionStyle } from '@/shared/component/workSpaceModal/name/WorkSpaceName.style';

interface WorkSpaceCompleteProps {
isVisible: boolean;
Expand Down
8 changes: 4 additions & 4 deletions src/shared/component/workSpaceModal/image/WorkSpaceImage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ import {
imageAddStyle,
imageBoxStyle,
imageDeleteStyle,
} from '@/shared/component/WorkSpaceModal/image/WorkSpaceImage.style';
import useImageUpload from '@/shared/component/WorkSpaceModal/image/hook/useImageUpload';
import WorkSapceInfo from '@/shared/component/WorkSpaceModal/info/WorkSpaceInfo';
import { sectionStyle } from '@/shared/component/WorkSpaceModal/name/WorkSpaceName.style';
} from '@/shared/component/workSpaceModal/image/WorkSpaceImage.style';
import useImageUpload from '@/shared/component/workSpaceModal/image/hook/useImageUpload';
import WorkSapceInfo from '@/shared/component/workSpaceModal/info/WorkSpaceInfo';
import { sectionStyle } from '@/shared/component/workSpaceModal/name/WorkSpaceName.style';
import { usePostTeamMutation } from '@/shared/hook/api/usePostTeamMutation';
import { useWorkSpaceContext } from '@/shared/hook/common/useWorkSpaceContext';

Expand Down
8 changes: 4 additions & 4 deletions src/shared/component/workSpaceModal/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import WorkSpaceCategory from '@/shared/component/WorkSpaceModal/category/WorkSpaceCategory';
import WorkSpaceComplete from '@/shared/component/WorkSpaceModal/complete/WorkSpaceComplete';
import WorkSpaceImage from '@/shared/component/WorkSpaceModal/image/WorkSpaceImage';
import WorkSpaceName from '@/shared/component/WorkSpaceModal/name/WorkSpaceName';
import WorkSpaceCategory from '@/shared/component/workSpaceModal/category/WorkSpaceCategory';
import WorkSpaceComplete from '@/shared/component/workSpaceModal/complete/WorkSpaceComplete';
import WorkSpaceImage from '@/shared/component/workSpaceModal/image/WorkSpaceImage';
import WorkSpaceName from '@/shared/component/workSpaceModal/name/WorkSpaceName';
import { useWorkSpaceContext } from '@/shared/hook/common/useWorkSpaceContext';

export const WorkSpaceFlow = () => {
Expand Down
2 changes: 1 addition & 1 deletion src/shared/component/workSpaceModal/info/WorkSpaceInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Flex from '@/common/component/Flex/Flex';
import Heading from '@/common/component/Heading/Heading';
import Text from '@/common/component/Text/Text';

import { headingStyle, textStyle, topStyle } from '@/shared/component/WorkSpaceModal/info/WorkSpaceInfo.style';
import { headingStyle, textStyle, topStyle } from '@/shared/component/workSpaceModal/info/WorkSpaceInfo.style';
import { STEPS, STEPS_BY_CATEGORY } from '@/shared/constant';

interface WorkSpaceInfoProps {
Expand Down
4 changes: 2 additions & 2 deletions src/shared/component/workSpaceModal/name/WorkSpaceName.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import Button from '@/common/component/Button/Button';
import Flex from '@/common/component/Flex/Flex';
import Input from '@/common/component/Input/Input';

import WorkSapceInfo from '@/shared/component/WorkSpaceModal/info/WorkSpaceInfo';
import WorkSapceInfo from '@/shared/component/workSpaceModal/info/WorkSpaceInfo';
import {
buttonStyle,
inputWrapperStyle,
sectionStyle,
} from '@/shared/component/WorkSpaceModal/name/WorkSpaceName.style';
} from '@/shared/component/workSpaceModal/name/WorkSpaceName.style';
import { useWorkSpaceContext } from '@/shared/hook/common/useWorkSpaceContext';

interface WorkSpaceNameProps {
Expand Down
Loading
Loading