Skip to content

Commit

Permalink
feat: 병합 충돌 해결
Browse files Browse the repository at this point in the history
  • Loading branch information
ooherin committed Nov 14, 2024
2 parents 27cfb48 + 88a1ace commit a7766a5
Show file tree
Hide file tree
Showing 44 changed files with 645 additions and 288 deletions.
21 changes: 21 additions & 0 deletions frontend/playwright/tests/mock/signIn.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { test } from '@playwright/test';

import { ROUTE_PATH } from '@/constants/routePath';

test('이메일을 통해 로그인을 할 수 있다.', async ({ page }) => {
await page.goto(ROUTE_PATH.signIn);
await page.getByText('비밀번호를 잊으셨나요?').click();
await page.getByLabel('이메일').click();
await page.getByLabel('이메일').fill('[email protected]');
await page.getByRole('button', { name: '전송' }).click();
await page.getByLabel('다음').click();
await page.getByLabel('검증 코드').click();
await page.getByLabel('검증 코드').fill('[email protected]');
await page.getByRole('button', { name: '확인' }).click();
await page.getByLabel('다음').click();
await page.getByLabel('새 비밀번호', { exact: true }).click();
await page.getByLabel('새 비밀번호', { exact: true }).fill('wagd12');
await page.getByLabel('새 비밀번호', { exact: true }).press('Tab');
await page.getByLabel('새 비밀번호 확인').fill('wagd12');
await page.getByRole('button', { name: '확인' }).click();
});
2 changes: 1 addition & 1 deletion frontend/src/apis/checklist.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const getChecklists = async (isLikeFiltered: boolean = false) => {
url: BASE_URL + (isLikeFiltered ? ENDPOINT.CHECKLISTS_LIKE_V1 : ENDPOINT.CHECKLISTS_V1),
});
const data = await response.json();
return data.checklists.map(mapObjNullToUndefined).slice(0, 10);
return data.checklists.map(mapObjNullToUndefined);
};

export const postChecklist = async (checklist: ChecklistPostForm) => {
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/apis/url.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const ENDPOINT = {
CHECKLIST_CUSTOM: '/custom-checklist',
CHECKLIST_ID: (id: number) => `/checklists/${id}`,
CHECKLIST_ID_V1: (id: number) => `/v1/checklists/${id}`,

// like
LIKE: (id: number | ':id') => `/checklists/${id}/like`,
// category
Expand All @@ -35,6 +36,9 @@ export const ENDPOINT = {
USER_VALID: '/token-exist',
USER_ACCESS_TOKEN_REISSUE: '/accessToken/reissue',
TOKEN: '/token',
RESET_PASSWORD_SEND_MAIL: '/v1/password-reset/send-code',
RESET_PASSWORD_CONFIRM_CODE: '/v1/password-reset/confirm',
RESET_PASSWORD: '/v1/password-reset',
//subway
SUBWAY: (position: Position) => `/stations/nearest?latitude=${position.latitude}&longitude=${position.longitude}`,
};
16 changes: 13 additions & 3 deletions frontend/src/apis/user.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import fetcher from '@/apis/fetcher';
import { BASE_URL, ENDPOINT } from '@/apis/url';
import { User, UserTokenValid } from '@/types/user';
import { ResetPasswordArgs, User, UserTokenValid } from '@/types/user';

export const postOAuthLogin = async (code: string, redirectUri: string) => {
const response = await fetcher.post({ url: BASE_URL + ENDPOINT.OAUTH_LOGIN, body: { code, redirectUri } });
Expand Down Expand Up @@ -47,7 +47,6 @@ export const postSignUp = async ({ name, email, password }: { name: string; emai
method: 'POST',
body: JSON.stringify({ name, email, password }),
credentials: 'include',
headers: { 'Content-Type': 'application/json' },
});
};

Expand All @@ -56,6 +55,17 @@ export const postSignIn = async ({ email, password }: { email: string; password:
url: `${BASE_URL}${ENDPOINT.SIGN_IN}`,
body: { email, password },
credentials: 'include',
headers: { 'Content-Type': 'application/json' },
});
};

export const postResetPasswordMail = async (email: ResetPasswordArgs['email']) => {
return await fetcher.post({ url: `${BASE_URL}${ENDPOINT.RESET_PASSWORD_SEND_MAIL}`, body: { email } });
};

export const postResetPasswordCode = async ({ email, code }: Pick<ResetPasswordArgs, 'email' | 'code'>) => {
return await fetcher.post({ url: `${BASE_URL}${ENDPOINT.RESET_PASSWORD_CONFIRM_CODE}`, body: { email, code } });
};

export const postResetPassword = async ({ email, code, newPassword }: ResetPasswordArgs) => {
return await fetcher.post({ url: `${BASE_URL}${ENDPOINT.RESET_PASSWORD}`, body: { email, code, newPassword } });
};
14 changes: 8 additions & 6 deletions frontend/src/components/ChecklistDetail/RoomInfoSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import LikeButton from '@/components/_common/Like/LikeButton';
import AddressMap from '@/components/_common/Map/AddressMap';
import SubwayStations from '@/components/_common/Subway/SubwayStations';
import { IncludedMaintenancesData } from '@/constants/roomInfo';
import { flexColumn, flexRow, flexSpaceBetween, title2, title3, title4 } from '@/styles/common';
import { flexColumn, flexRow, flexSpaceBetween, title2, title3 } from '@/styles/common';
import { Option } from '@/types/option';
import { RoomInfo } from '@/types/room';
import { SubwayStation } from '@/types/subway';
Expand Down Expand Up @@ -88,10 +88,11 @@ const RoomInfoSection = ({ nearSubways, room, options, checklistId, isLiked }: P
<S.Row>
<S.Label>
<Room aria-label="방 구조 / 방 평수" />
방 구조 <br />/ 방 평수
방 구조 <br />방 평수
</S.Label>
<S.Text>
{formattedUndefined(structure, 'string')} <br />/ {formattedUndefined(size)}
{formattedUndefined(structure, 'string')} <br />
{formattedUndefined(size)}
</S.Text>
</S.Row>

Expand Down Expand Up @@ -121,10 +122,12 @@ const RoomInfoSection = ({ nearSubways, room, options, checklistId, isLiked }: P
<S.Row>
<S.Label>
<Calendar aria-label="계약 기간 / 입주 가능일" />
계약 기간 <br />/ 입주 가능일
계약 기간 <br />
입주 가능일
</S.Label>
<S.Text>
{formattedUndefined(contractTerm)}개월 계약 <br />/{formattedUndefined(occupancyMonth)}{occupancyPeriod}
{formattedUndefined(contractTerm)}개월 계약 <br />
{formattedUndefined(occupancyMonth)}{occupancyPeriod}
</S.Text>
</S.Row>

Expand Down Expand Up @@ -237,7 +240,6 @@ const S = {
MoneyText: styled.div`
width: 100%;
/* ${title4} */
${title3}
${flexRow}
${flexSpaceBetween}
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/components/Main/ArticlePreviewCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const ArticlePreviewCard = ({ index, article }: Props) => {
const navigate = useNavigate();
const { articleId, keyword, title } = article;

const { color600, color200 } = getSeqColor(index);
const { color500, color200 } = getSeqColor(index);

const handleClickArticle = () => {
navigate(ROUTE_PATH.articleOne(articleId));
Expand All @@ -31,12 +31,12 @@ const ArticlePreviewCard = ({ index, article }: Props) => {
tabIndex={1}
aria-label="클릭하면 해당 아티클 페이지로 이동합니다"
>
<S.Keyword bgColor={theme.palette.background} color={color600}>
<S.Keyword bgColor={theme.palette.background} color={color500}>
{keyword}
</S.Keyword>
<S.Title>{title}</S.Title>
<S.ArrowButton>
<ArrowRight stroke={color600} aria-hidden="true" />
<ArrowRight stroke={color500} aria-hidden="true" />
</S.ArrowButton>
</S.Container>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ const DaumAddressModal = () => {

const { searchSubwayStationsByAddress } = useRoomInfoNonValidated();

const handleAddress = () => {
openModal();
const handleClickAddress = () => {
loadExternalScriptWithCallback('daumAddress', openPostcodeEmbed);
openModal();
};

const openPostcodeEmbed = () => {
Expand All @@ -50,7 +50,7 @@ const DaumAddressModal = () => {
return (
<>
<S.AddressButton
onClick={handleAddress}
onClick={handleClickAddress}
label="주소 검색"
size="full"
isSquare={true}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { IncludedMaintenancesData } from '@/constants/roomInfo';
import roomInfoStore from '@/store/roomInfoStore';

const IncludedMaintenances = () => {
// TODO : nonValidated 에서 관리해야함. 일단은 놔뒀음.
// TODO: nonValidated 에서 관리해야함. 일단은 놔뒀음.

const includedMaintenances = useStore(roomInfoStore, state => state.includedMaintenances).rawValue;
const actions = useStore(roomInfoStore, state => state.actions);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const RoomFloor = () => {
floor.set('');
}
};

return (
<FormField>
<FormField.Label label="층수" htmlFor="floor" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { useState } from 'react';
import { useNavigate } from 'react-router-dom';

import { BangBangIcon, BangGgoodTextIcon } from '@/assets/assets';
import Button from '@/components/_common/Button/Button';
import FlexBox from '@/components/_common/FlexBox/FlexBox';
import FormField from '@/components/_common/FormField/FormField';
import Header from '@/components/_common/Header/Header';
import CS from '@/components/ResetPassword/style';
import { ROUTE_PATH } from '@/constants/routePath';
import usePostResetPasswordCode from '@/hooks/query/usePostResetPasswordCode';
import useValidateInput from '@/hooks/useValidateInput';
import { ResetPasswordArgs } from '@/types/user';

interface Props {
args: Pick<ResetPasswordArgs, 'email'>;
onNext: (value: Pick<ResetPasswordArgs, 'email' | 'code'>) => void;
}

const EmailVerificationCodeStep = ({ args: { email }, onNext }: Props) => {
const [isComplete, setIsComplete] = useState(false);
const [postErrorMessage, setPostErrorMessage] = useState('');
const { mutate: postResetCode } = usePostResetPasswordCode();

const {
value: code,
getErrorMessage: getCodeErrors,
onChange: onChangeCode,
isValidated: isCodeValid,
} = useValidateInput({
initialValue: '',
validates: [],
});

const handleClickSubmit = () =>
postResetCode(
{ email, code },
{
onSuccess: () => setIsComplete(true),
onError: error => setPostErrorMessage(error.message),
},
);

const handleClickNext = () => onNext({ code, email });

const canMove = isCodeValid && isComplete;

const handleKeyDown = (event: React.KeyboardEvent) => {
if (event.key === 'Enter' && canMove) {
onNext({ code, email });
}
};

const navigate = useNavigate();
const handleClickBackward = () => navigate(ROUTE_PATH.root);

return (
<>
<Header left={<Header.Backward onClick={handleClickBackward} />} />
<CS.Wrapper>
<CS.LogoBox>
<BangBangIcon />
<BangGgoodTextIcon aria-label="방끗 로고" />
</CS.LogoBox>
<CS.Box>
<CS.Label>비밀번호 찾기</CS.Label>
<FormField onKeyDown={handleKeyDown}>
<FormField.Label label="검증 코드" htmlFor="code" />
<FlexBox.Horizontal justify="flex-start" align="center">
<FormField.Input
maxLength={254}
value={code}
id="code"
name="code"
onChange={onChangeCode}
style={{ width: '25rem' }}
/>
<div>
<CS.SendButton onClick={handleClickSubmit} disabled={canMove}>
확인
</CS.SendButton>
</div>
</FlexBox.Horizontal>
{getCodeErrors() && <FormField.ErrorMessage value={getCodeErrors()} />}
</FormField>
{postErrorMessage && <FormField.ErrorMessage value={postErrorMessage} />}
<Button label="다음" size="full" isSquare={true} color="dark" onClick={handleClickNext} disabled={!canMove} />
</CS.Box>
</CS.Wrapper>
</>
);
};

export default EmailVerificationCodeStep;
102 changes: 102 additions & 0 deletions frontend/src/components/ResetPassword/ResetPasswordStep.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { useNavigate } from 'react-router-dom';

import { BangBangIcon, BangGgoodTextIcon } from '@/assets/assets';
import Button from '@/components/_common/Button/Button';
import FlexBox from '@/components/_common/FlexBox/FlexBox';
import FormField from '@/components/_common/FormField/FormField';
import Header from '@/components/_common/Header/Header';
import CS from '@/components/ResetPassword/style';
import { ROUTE_PATH } from '@/constants/routePath';
import useValidateInput from '@/hooks/useValidateInput';
import { ResetPasswordArgs } from '@/types/user';
import { validatePassword, validatePasswordConfirm } from '@/utils/authValidation';

interface Props {
args: Pick<ResetPasswordArgs, 'email' | 'code'>;
onNext: (value: ResetPasswordArgs) => void;
}

const SendVerificationEmailStep = ({ args: { email, code }, onNext }: Props) => {
const {
value: password,
getErrorMessage: getPasswordErrors,
onChange: onChangePassword,
isValidated: isPasswordValid,
} = useValidateInput({
initialValue: '',
validates: [validatePassword],
});

const {
value: passwordConfirm,
getErrorMessage: getPasswordConfirmError,
onChange: onChangePasswordConfirm,
isValidated: isPasswordConfirmValidad,
} = useValidateInput({
initialValue: '',
validates: [(value: string) => validatePasswordConfirm(value, password)],
});

const canMove = isPasswordValid && isPasswordConfirmValidad;

const handleClickNext = () => onNext({ email, code, newPassword: password });
const handleKeyDown = (event: React.KeyboardEvent) => {
if (event.key === 'Enter' && canMove) {
handleClickNext();
}
};

const navigate = useNavigate();
const handleClickBackward = () => navigate(ROUTE_PATH.root);

return (
<>
<Header left={<Header.Backward onClick={handleClickBackward} />} />
<CS.Wrapper>
<CS.LogoBox>
<BangBangIcon />
<BangGgoodTextIcon aria-label="방끗 로고" />
</CS.LogoBox>
<CS.Box>
<CS.Label>비밀번호 찾기</CS.Label>
<FormField onKeyDown={handleKeyDown}>
<FormField.Label label="새 비밀번호" htmlFor="password" />
<FlexBox.Horizontal justify="flex-start" align="center">
<FormField.Input
maxLength={254}
value={password}
id="password"
name="password"
onChange={onChangePassword}
/>
</FlexBox.Horizontal>
{getPasswordErrors() && <FormField.ErrorMessage value={getPasswordErrors()} />}
</FormField>
<FormField onKeyDown={handleKeyDown}>
<FormField.Label label="새 비밀번호 확인" htmlFor="passwordConfirm" />
<FlexBox.Horizontal justify="flex-start" align="center">
<FormField.Input
id="passwordConfirm"
maxLength={254}
value={passwordConfirm}
name="passwordConfirm"
onChange={onChangePasswordConfirm}
/>
</FlexBox.Horizontal>
{getPasswordConfirmError() && <FormField.ErrorMessage value={getPasswordConfirmError()} />}
</FormField>
<Button
label="확인"
size="full"
isSquare={true}
color={'dark'}
onClick={handleClickNext}
disabled={!canMove}
/>
</CS.Box>
</CS.Wrapper>
</>
);
};

export default SendVerificationEmailStep;
Loading

0 comments on commit a7766a5

Please sign in to comment.