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

프로필 수정 페이지 #257

Merged
merged 31 commits into from
Apr 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
f7a37c7
📝chore: cursor 스타일 추가
100Gyeon Mar 17, 2022
8b52461
✨feat: 라우팅 관련 처리 (마이페이지에서 수정하기 버튼 누르면 프로필 수정 페이지로 이동하도록)
100Gyeon Mar 17, 2022
682a48a
🎨design: 프로필 수정 페이지 퍼블리싱
100Gyeon Mar 17, 2022
993d880
✨feat: 프로필 수정 바텀 시트 추가
100Gyeon Mar 17, 2022
5a94c7e
🐛fix: 바텀 시트 영역 벗어나는 문제 해결
100Gyeon Mar 17, 2022
9dd4837
🎨design: 퍼블리싱 보충
100Gyeon Mar 17, 2022
b2d3274
✨feat: 로그인된 유저 정보 띄우기
100Gyeon Mar 17, 2022
d462b66
🐛fix: 화면 넘치는 부분 수정
100Gyeon Mar 17, 2022
c4540f8
✨feat: My 키워드 페이지도 라우터에 추가
100Gyeon Mar 17, 2022
0c73166
Merge branch 'dev' of https://github.com/Neogasogaeseo/Naega-Web into…
100Gyeon Mar 18, 2022
8aeae28
Merge branch 'dev' of https://github.com/Neogasogaeseo/Naega-Web into…
100Gyeon Mar 20, 2022
2107541
Merge branch 'dev' of https://github.com/Neogasogaeseo/Naega-Web into…
100Gyeon Mar 21, 2022
6050ff2
Merge branch 'dev' of https://github.com/Neogasogaeseo/Naega-Web into…
100Gyeon Mar 21, 2022
8c3d224
Merge branch 'dev' of https://github.com/Neogasogaeseo/Naega-Web into…
100Gyeon Mar 22, 2022
e37318b
Merge branch 'dev' of https://github.com/Neogasogaeseo/Naega-Web into…
100Gyeon Mar 23, 2022
280ec76
Merge branch 'dev' of https://github.com/Neogasogaeseo/Naega-Web into…
100Gyeon Mar 24, 2022
431c863
📝chore: 연필 아이콘 추가
100Gyeon Mar 25, 2022
e378cc0
Merge branch 'dev' of https://github.com/Neogasogaeseo/Naega-Web into…
100Gyeon Mar 27, 2022
d32c9e9
📝chore: Common 들어간 부분 지우기
100Gyeon Mar 31, 2022
1d5c279
🎨design: input 스타일링
100Gyeon Mar 31, 2022
5fffa18
📝chore: 인풋 스타일링 디테일 수정
100Gyeon Mar 31, 2022
49c749b
📝chore: 가입, 프로필 수정에서 공통 속성으로 사용하기 위해 join이라는 단어 제거
100Gyeon Mar 31, 2022
edd9990
✨feat: input 조건 검사 추가
100Gyeon Mar 31, 2022
e74b4b6
✨feat: 수정 완료 시 토스트 띄우기
100Gyeon Mar 31, 2022
13dd6f7
💅🏻style: import 구문 순서 변경
100Gyeon Apr 1, 2022
f482b24
🎨design: 마이페이지에서 키워드 전체보기로 이동하는 부분 추가
100Gyeon Apr 1, 2022
2d3d9da
🔨refactor: 코드 리뷰 반영 (Edit 제거)
100Gyeon Apr 1, 2022
29f9886
🔨refactor: 라우터 깔끔하게 정리
100Gyeon Apr 1, 2022
4a32860
🔨refactor: 코드 리뷰 반영
100Gyeon Apr 1, 2022
c706862
📝chore: ProfileEdit에서 MyPageEdit으로 수정
100Gyeon Apr 1, 2022
a3cf4b0
🔨refactor: 코드 리뷰 반영 (useEffect 쪼개기, 조건 검사하는 부분 수정)
100Gyeon Apr 2, 2022
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
3 changes: 3 additions & 0 deletions src/assets/icons/ic_crown.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/assets/icons/ic_edit.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/assets/icons/ic_edit_profile.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/assets/icons/ic_input_pencil.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions src/assets/icons/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,7 @@ export { default as icTrash } from './ic_trash.svg';
export { ReactComponent as IcMeatball } from './ic_meatball.svg';
export { ReactComponent as IcSetting } from './ic_setting.svg';
export { ReactComponent as IcBell } from './ic_bell.svg';
export { default as icEdit } from './ic_edit.svg';
export { default as icEditProfile } from './ic_edit_profile.svg';
export { default as icInputPencil } from './ic_input_pencil.svg';
export { default as icCrown } from './ic_crown.svg';
4 changes: 2 additions & 2 deletions src/presentation/components/JoinForm/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ function JoinForm() {
<CommonLabel content="아이디" marginTop="44px" marginBottom="20px" />
<CommonInput
width="100%"
isJoinConditionPassed={isJoinConditionPassed.id}
isConditionPassed={isJoinConditionPassed.id}
errorMsg={errorMsg}
placeholder="neososeo_team"
onChange={(value) => {
Expand All @@ -99,7 +99,7 @@ function JoinForm() {
<CommonLabel content="이름" marginTop="44px" marginBottom="20px" />
<CommonInput
width="100%"
isJoinConditionPassed={isJoinConditionPassed.name}
isConditionPassed={isJoinConditionPassed.name}
placeholder="이름을 입력해주세요"
onChange={(value) => {
setInputName(value);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { useNavigate } from 'react-router-dom';

import BottomSheet from '..';
import { icEdit } from '@assets/icons';

type MyPageEditBottomSheetProps = {
isOpened: boolean;
closeBottomSheet: () => void;
type: string;
userID?: string;
};

function MyPageEditBottomSheet(props: MyPageEditBottomSheetProps) {
const { isOpened, closeBottomSheet, type, userID } = props;
const navigate = useNavigate();

const navigateToEditPage = () => {
navigate(`/edit/${type}/${userID}`);
};

return (
<BottomSheet
buttonList={[
{
icon: icEdit,
label: '수정하기',
onClick: navigateToEditPage,
},
]}
closeBottomSheet={closeBottomSheet}
isOpened={isOpened}
/>
);
}

export default MyPageEditBottomSheet;
5 changes: 4 additions & 1 deletion src/presentation/components/common/BottomSheet/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const StBlackBlur = styled.div<{ isClosing: boolean }>`

export const StWrapper = styled.div<{ isClosing: boolean }>`
position: fixed;
width: min(100vw, 400px);
width: min(100vw, 390px);
border-top-left-radius: 32px;
border-top-right-radius: 32px;
background-color: ${COLOR.WHITE};
Expand All @@ -39,6 +39,8 @@ export const StButton = styled.div`
display: flex;
align-items: center;
gap: 8px;
cursor: pointer;
width: fit-content;
color: ${COLOR.GRAY_7};
${FONT_STYLES.R_16_BODY}
`;
Expand All @@ -53,6 +55,7 @@ export const StButtonWrapper = styled.div`
`;

export const StCancelButton = styled.div`
cursor: pointer;
text-align: center;
border-top: 1px solid ${COLOR.GRAY_3};
padding-top: 16px;
Expand Down
6 changes: 3 additions & 3 deletions src/presentation/components/common/Input/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ interface CommonInputProps {
maxLength?: number;
value?: string;
defaultValue?: string;
isJoinConditionPassed?: boolean;
isConditionPassed?: boolean;
img?: string;
onChange?: (value: string) => void;
onSubmit?: (e: React.FormEvent<HTMLFormElement>) => void;
Expand All @@ -25,7 +25,7 @@ function CommonInput(props: CommonInputProps) {
maxLength,
value,
defaultValue,
isJoinConditionPassed,
isConditionPassed,
onChange,
onSubmit,
img,
Expand Down Expand Up @@ -63,7 +63,7 @@ function CommonInput(props: CommonInputProps) {
<StSubmitButton disabled={submitButtonDisabled}>{submitButtonValue}</StSubmitButton>
)}
</StInputWrapper>
{!isJoinConditionPassed && isInput !== '' && errorMsg && <StErrorMsg>{errorMsg}</StErrorMsg>}
{!isConditionPassed && isInput !== '' && errorMsg && <StErrorMsg>{errorMsg}</StErrorMsg>}
</StCommonInput>
);
}
Expand Down
1 change: 1 addition & 0 deletions src/presentation/components/common/Navigation/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const StCommonNavigation = styled.div`

export const StBack = styled.img`
margin-left: 14px;
cursor: pointer;
`;

export const StTitle = styled.div`
Expand Down
23 changes: 23 additions & 0 deletions src/presentation/pages/Edit/DeleteKeyword/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { useParams } from 'react-router-dom';

import CommonNavigation from '@components/common/Navigation';
import { StMyKeywordDelete, StMyKeywordHeader } from './style';

function MyKeywordDelete() {
const { userID } = useParams();

if (!userID) return <></>;

return (
<>
<CommonNavigation title="My 키워드" />
<StMyKeywordDelete>
<StMyKeywordHeader>
<span>My 키워드</span>
</StMyKeywordHeader>
</StMyKeywordDelete>
Comment on lines +17 to +18
Copy link
Member

Choose a reason for hiding this comment

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

요 사이에 키워드 리스트 와야 할 것 같은데 혹시 아직 안한 건지 제가 잘못 이해한건지 궁금합니다!!

Copy link
Member Author

@100Gyeon 100Gyeon Apr 1, 2022

Choose a reason for hiding this comment

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

제대로 이해한 거 맞고 아직 미완입니다 !!
바텀시트에서 다른 링크로 넘어가는 부분까지 넣고 싶어서 페이지 윗부분만 살짝 만들었어요
남은 부분은 다음 PR에 올릴게유 😉

Copy link
Member

Choose a reason for hiding this comment

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

넴💟💟

</>
);
}

export default MyKeywordDelete;
14 changes: 14 additions & 0 deletions src/presentation/pages/Edit/DeleteKeyword/style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import styled from 'styled-components';

import { COLOR } from '@styles/common/color';

export const StMyKeywordDelete = styled.div``;

export const StMyKeywordHeader = styled.div`
height: 76px;
background-color: ${COLOR.GRAY_1};
padding: 42px 20px 19px 24px;
display: flex;
align-items: center;
justify-content: space-between;
`;
111 changes: 111 additions & 0 deletions src/presentation/pages/Edit/Profile/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import React, { useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';

import { useToast } from '@hooks/useToast';
import { useLoginUser } from '@hooks/useLoginUser';
import CommonInput from '@components/common/Input';
import CommonLabel from '@components/common/Label';
import CommonNavigation from '@components/common/Navigation';
import FileUpload from '@components/common/FileUpload';
import { StInputWrapper, StMyProfileEdit, StProfileImg } from './style';
import { IcMypageEdit } from '@assets/icons';
import { imgEmptyProfile } from '@assets/images';

function MyProfileEdit() {
const navigate = useNavigate();
const { fireToast } = useToast();
const { username, userID, profileImage } = useLoginUser();
const [image, setImage] = useState<File | null>(null);
const [inputId, setInputId] = useState('');
const [inputName, setInputName] = useState('');
const [errorMsg, setErrorMsg] = useState('');
const [isEditConditionPassed, setIsEditConditionPassed] = useState({
id: false,
name: false,
});

useEffect(() => {
const idCheck = /^[a-z]+[a-z|0-9|.|_]{4,15}$/;
setIsEditConditionPassed({
...isEditConditionPassed,
id: idCheck.test(inputId),
});

if (!idCheck.test(inputId)) {
setErrorMsg('*영문 소문자, 숫자, 특수문자(._) 4~15자 이내');
}

if (!/^[a-z]/.test(inputId)) {
setErrorMsg('*아이디의 첫 글자는 영문 소문자');
}
}, [inputId]);

useEffect(() => {
setIsEditConditionPassed({
...isEditConditionPassed,
name: inputName !== '',
});
}, [inputName]);

const editProfile = (e: React.MouseEvent<HTMLButtonElement>) => {
e.preventDefault();
try {
const form = new FormData();
form.append('profileId', inputId);
form.append('name', inputName);
image && form.append('image', image);
// 나중에 여기 put 추가할 예정
fireToast({ content: '수정 완료' });
} catch (error) {
console.error(error);
navigate('/');
}
};

return (
<>
<CommonNavigation title="프로필 수정" />
<StMyProfileEdit>
<StProfileImg>
<FileUpload width="118px" height="118px" setFile={setImage} borderRadius="50%">
<>
<img src={profileImage || imgEmptyProfile} />
<IcMypageEdit />
</>
</FileUpload>
</StProfileImg>
<StInputWrapper>
<CommonLabel content="아이디" marginTop="52px" marginBottom="20px" />
<CommonInput
width="100%"
isConditionPassed={isEditConditionPassed.id}
onChange={(value) => {
setInputId(value);
}}
errorMsg={errorMsg}
placeholder={userID}
maxLength={15}
/>
<CommonLabel content="이름" marginTop="46px" marginBottom="20px" />
<CommonInput
width="100%"
isConditionPassed={isEditConditionPassed.name}
onChange={(value) => {
setInputName(value);
}}
errorMsg={errorMsg}
placeholder={username}
/>
</StInputWrapper>
<button
onClick={editProfile}
disabled={!Object.values(isEditConditionPassed).every((condition) => condition === true)}
>
완료
</button>
</StMyProfileEdit>
</>
);
}

export default MyProfileEdit;
74 changes: 74 additions & 0 deletions src/presentation/pages/Edit/Profile/style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import styled from 'styled-components';

import { CORAL_MAIN_BUTTON } from '@styles/common/button';
import { COLOR } from '@styles/common/color';
import { FONT_STYLES } from '@styles/common/font-style';
import { icEmail, icInputPencil } from '@assets/icons';

export const StMyProfileEdit = styled.div`
padding: 0 20px;

& > div > button {
display: block;
margin: 0 auto;
margin-top: 52px;
}

& > button {
width: 100%;
border-radius: 16px;
padding: 20px 0;
margin-top: 178px;
margin-bottom: 48px;
${FONT_STYLES.M_16_TITLE};
color: ${COLOR.WHITE};
background-color: ${COLOR.GRAY_3};

:not(:disabled) {
${CORAL_MAIN_BUTTON};
}
}
`;

export const StProfileImg = styled.div`
position: relative;
width: fit-content;
margin: 0 auto;
margin-top: 52px;

img {
width: 118px;
height: 118px;
border-radius: 50%;
}

svg {
position: absolute;
bottom: 0;
right: 0;
width: 32.29px;
height: 32.29px;
}
`;

const iconEmail = icEmail;
const iconInputPencil = icInputPencil;

export const StInputWrapper = styled.div`
& > div:nth-of-type(2n + 1) {
margin-left: 4px;
}

& div:nth-child(2) > form > input {
background-image: url(${iconEmail}), url(${iconInputPencil});
background-position: 12px, calc(100% - 20px);
background-repeat: no-repeat, no-repeat;
padding-left: 36px;
}

& div:last-child > form > input {
background-image: url(${iconInputPencil});
background-position: calc(100% - 20px);
background-repeat: no-repeat;
}
`;
Loading