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

[FE] Feat/#502 #503

Merged
merged 55 commits into from
Sep 27, 2023
Merged
Show file tree
Hide file tree
Changes from 53 commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
6298f48
chore: develop 브랜치에 비해 누락된 커밋 반영 (#364)
semnil5202 Aug 21, 2023
a8cf622
[FE] Refactor/#365 API 요청 로직 분리 및 컴포넌트 분리 (#368)
semnil5202 Sep 6, 2023
5eee314
[FE] refactor/#373 msw 적용 (#374)
GC-Park Sep 6, 2023
abc4701
hotfix: login 에러 해결 (#383)
GC-Park Sep 6, 2023
12613e1
[FE] Feature/#382 반응형 대응 (#387)
semnil5202 Sep 12, 2023
6f60cac
[FE] Refactor/#395 지도 타입 지정 및 Map 컴포넌트 리팩토링 (#398)
jiwonh423 Sep 13, 2023
9c56123
fix: 충돌 해결 (#403)
jiwonh423 Sep 13, 2023
5a1d2e1
[FE] Test/#369 Jest 커스텀 훅 테스트 추가 (#394)
semnil5202 Sep 14, 2023
592eba0
[FE] Refactor/#402 지도 및 핀 권한 부여 여부 확인 및 지도 수정 페이지 구현 (#410)
semnil5202 Sep 15, 2023
c82e138
[FE] Feat/#386 지도, 핀 이미지에 s3 적용 (#409)
GC-Park Sep 19, 2023
d2e5331
Hotfix/refresh token 1 (#437)
jiwonh423 Sep 19, 2023
9663453
feat: refreshToken을 재요청할때 body에 accessToken을 추가 (#438)
jiwonh423 Sep 19, 2023
c5df478
feat: getApi header 컨텐트타입 추가 (#439)
jiwonh423 Sep 19, 2023
3684967
feat: refreshToken api 요청시 헤더에 content-type 추가 (#440)
jiwonh423 Sep 19, 2023
e8f2b48
refactor: withTokenRefresh에 return문 추가 (#442)
jiwonh423 Sep 19, 2023
5e583c5
refactor: localstorage userToken getItem요청 수정 (#445)
jiwonh423 Sep 19, 2023
47e2692
refactor: refreshToken함수 예외처리 추가 (#446)
jiwonh423 Sep 19, 2023
4c2e331
hotfix: 에러상황 확인용 콘솔로그 추가 (#447)
jiwonh423 Sep 19, 2023
d5df4bb
hotfix: 재발급시 getItem 부분 수정 (#448)
jiwonh423 Sep 19, 2023
06445d4
hotfix: 재발급시 받은 데이터 저장 로직 수정 (#449)
jiwonh423 Sep 19, 2023
97c724e
hotfix: abortController 적용 (#451)
jiwonh423 Sep 20, 2023
631cb43
hotfix: abortController 여러개 적용 (#452)
jiwonh423 Sep 20, 2023
7da225e
fix: 요청 중 재요청 차단 (#453)
semnil5202 Sep 20, 2023
7f42e70
fix: abort 컨트롤러 예외 처리 수정 (#454)
semnil5202 Sep 20, 2023
41cd2b4
fix: Promise 상태로 분기처리하여 재요청 차단 (#455)
semnil5202 Sep 20, 2023
9434c4a
fix: response 타입 동일화 (#456)
semnil5202 Sep 20, 2023
3d1fa9c
console 체크 (#457)
semnil5202 Sep 20, 2023
cb89ac1
fix: console.log 추가 (#459)
semnil5202 Sep 20, 2023
d467f6e
fix: console.log response 부분 추가 (#460)
semnil5202 Sep 20, 2023
84bbbdd
Hotfix/refresh token 20 (#461)
semnil5202 Sep 20, 2023
dfc723d
fix: response clone 하여 오류 수정 (#463)
semnil5202 Sep 20, 2023
9758375
Feat/#465 logout (#467)
jiwonh423 Sep 20, 2023
a126c4b
[FE] Fix/permission 토픽 권한 수정 오류 해결 (#419)
semnil5202 Sep 20, 2023
2726581
hotfix: 로그아웃 post 데이터 타입 변경 (#468)
jiwonh423 Sep 20, 2023
d2dabd4
[FE] Feature/#435 이미지 압축 기능 구현 (#436)
GC-Park Sep 20, 2023
c26bd75
fix: 네이밍 변경 누락 오류 수정 및 네이밍 통일성 준수 (#470)
semnil5202 Sep 20, 2023
94ebcba
chore: browser-image-compression 패키지 제이슨 누락 수정 (#471)
semnil5202 Sep 20, 2023
ad3a293
[ FE ] Refactor/#404 홈페이지 및 Navbar 리팩토링 (#423)
jiwonh423 Sep 21, 2023
836e0c4
hotfix: 모아보기 누락 로직 추가 (#475)
jiwonh423 Sep 21, 2023
2684205
[FE] 토큰 재발급 로직 모든 메소드에 적용 (#474)
jiwonh423 Sep 21, 2023
94ab841
[FE] Refactor/#469 동적 임포트와 tree shaking으로 코드 스플리팅 (#476)
GC-Park Sep 21, 2023
cd9eb67
[FE] Fix/#472 토픽 수정 시 권한 수정 보류 (#477)
semnil5202 Sep 21, 2023
bc7ba08
refactor: 동적 임포트에 suspense 적용 (#478)
GC-Park Sep 21, 2023
e6aba04
fix: merge 과정 중 충돌 해결 오류 수정 (#480)
semnil5202 Sep 21, 2023
ec5ae7f
feat: default url 변경 (#483)
jiwonh423 Sep 21, 2023
7d9906d
[FE] Refactor/#481 개발 서버 QA 후 발생한 이슈 해결 (#486)
GC-Park Sep 21, 2023
ade24b9
Merge branch 'develop-FE-2' of https://github.com/woowacourse-teams/2…
jiwonh423 Sep 25, 2023
eeff372
Merge branch 'develop-FE-2' of https://github.com/woowacourse-teams/2…
jiwonh423 Sep 26, 2023
d3b13ea
refactor: 버튼 variant 확장
jiwonh423 Sep 27, 2023
9d575f5
feat: patch용 함수 구현
jiwonh423 Sep 27, 2023
f954722
feat: 회원 정보 수정 ui 구현
jiwonh423 Sep 27, 2023
ea85f0f
feat: 회원 정보 수정 로직 구현
jiwonh423 Sep 27, 2023
85cd54e
feat: 수정 성공시 localstorage 저장 정보 변경
jiwonh423 Sep 27, 2023
b06ed24
refactor: 정보 수정 반영 안되는 문제 수정
jiwonh423 Sep 27, 2023
5d5a93a
feat: 환경변수 테스트
jiwonh423 Sep 27, 2023
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
43 changes: 43 additions & 0 deletions frontend/src/apiHooks/usePatch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { patchApi } from '../apis/patchApi';
import useToast from '../hooks/useToast';
import { ContentTypeType } from '../types/Api';

interface fetchPutProps {
url: string;
payload: {};
errorMessage: string;
contentType?: ContentTypeType;
onSuccess?: () => void;
isThrow?: boolean;
}

const usePatch = () => {
const { showToast } = useToast();

const fetchPatch = async ({
url,
payload,
contentType,
errorMessage,
onSuccess,
isThrow,
}: fetchPutProps) => {
try {
const responseData = await patchApi(url, payload, contentType);

if (onSuccess) {
onSuccess();
}

return responseData;
} catch (e) {
showToast('error', errorMessage);

if (isThrow) throw e;
}
};

return { fetchPatch };
};

export default usePatch;
37 changes: 37 additions & 0 deletions frontend/src/apis/patchApi.ts
Copy link
Collaborator

Choose a reason for hiding this comment

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

생각해보니 저희가 patch가 없었군요..! 새로 만드신거 너무 좋습니다! 굿굿 !!!!

Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { DEFAULT_PROD_URL } from '../constants';
import { ContentTypeType } from '../types/Api';
import withTokenRefresh from './utils';

export const patchApi = async (
url: string,
data: {},
contentType?: ContentTypeType,
) => {
return await withTokenRefresh(async () => {
const apiUrl = `${DEFAULT_PROD_URL + url}`;
const userToken = localStorage.getItem('userToken');
const headers: any = {
'content-type': 'application/json',
};

if (userToken) {
headers['Authorization'] = `Bearer ${userToken}`;
}

if (contentType) {
headers['content-type'] = contentType;
}

const response = await fetch(apiUrl, {
method: 'PATCH',
headers,
body: JSON.stringify(data),
});

if (response.status >= 400) {
throw new Error('[SERVER] PUT 요청에 실패했습니다.');
}

return response;
});
};
4 changes: 4 additions & 0 deletions frontend/src/assets/setting.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
57 changes: 28 additions & 29 deletions frontend/src/components/MyInfo/UpdateMyInfo.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,43 @@
import { styled } from 'styled-components';
import Flex from '../common/Flex';
import ProfileDefaultImage from '../../assets/profile_defaultImage.svg';
import Box from '../common/Box';
import Space from '../common/Space';
import { ProfileProps } from '../../types/Profile';
import Button from '../common/Button';
import Text from '../common/Text';
import usePatch from '../../apiHooks/usePatch';

interface UpdateMyInfoProps {
isThereImg: boolean;
myInfoNameAndEmail: ProfileProps;
myInfo: ProfileProps;
setIsModifyMyInfo: React.Dispatch<React.SetStateAction<boolean>>;
setMyInfoNameAndEmail: React.Dispatch<React.SetStateAction<ProfileProps>>;
setMyInfo: React.Dispatch<React.SetStateAction<ProfileProps>>;
}

const UpdateMyInfo = ({
isThereImg,
myInfoNameAndEmail,
myInfo,
setIsModifyMyInfo,
setMyInfoNameAndEmail,
setMyInfo,
}: UpdateMyInfoProps) => {
const { fetchPatch } = usePatch();

const onChangeMyInfoName = (e: React.ChangeEvent<HTMLInputElement>) => {
if (e.target.value.length >= 20) return;
setMyInfoNameAndEmail({ ...myInfoNameAndEmail, name: e.target.value });
};

const onChangeMyInfoEmail = (e: React.ChangeEvent<HTMLInputElement>) => {
if (e.target.value.length >= 35) return;
setMyInfoNameAndEmail({ ...myInfoNameAndEmail, email: e.target.value });
setMyInfo({ ...myInfo, name: e.target.value });
};

const onClickModifyButton = () => {
setIsModifyMyInfo(false);
const onClickModifyButton = async () => {
await fetchPatch({
url: '/members/my/profiles',
payload: {
nickName: myInfo.name,
},
errorMessage: '회원정보 수정에 실패했습니다.',
isThrow: true,
onSuccess: () => {
localStorage.setItem('user', JSON.stringify(myInfo));
setIsModifyMyInfo(false);
},
});
};

return (
Expand All @@ -41,22 +48,14 @@ const UpdateMyInfo = ({
$justifyContent="center"
$alignItems="center"
>
{isThereImg ? (
<MyInfoImg src="https://images.unsplash.com/photo-1480429370139-e0132c086e2a?ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D&auto=format&fit=crop&w=988&q=80" />
) : (
<ProfileDefaultImage />
)}
<Space size={7} />
<MyInfoImg src={myInfo.image} />
<Space size={5} />
<Box>
<MyInfoInput
value={myInfoNameAndEmail.name}
onChange={onChangeMyInfoName}
/>
<MyInfoInput value={myInfo.name} onChange={onChangeMyInfoName} />
<Space size={0} />
<MyInfoInput
value={myInfoNameAndEmail.email}
onChange={onChangeMyInfoEmail}
/>
<Text color="black" $fontSize="small" $fontWeight="normal">
{myInfo.email}
</Text>
</Box>
<Space size={3} />
<Button variant="primary" onClick={onClickModifyButton}>
Expand Down
26 changes: 20 additions & 6 deletions frontend/src/components/MyInfo/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,25 @@ import UpdateMyInfo from './UpdateMyInfo';
import Button from '../common/Button';
import useToast from '../../hooks/useToast';
import { DEFAULT_PROD_URL } from '../../constants';
import Setting from '../../assets/setting.svg';

const user = JSON.parse(localStorage.getItem('user') || '{}');
const accessToken = localStorage.getItem('userToken');

const MyInfo = () => {
const { showToast } = useToast();

const [isThereImg, setIsThereImg] = useState<boolean>(true);
const [isModifyMyInfo, setIsModifyMyInfo] = useState<boolean>(false);
const [myInfoNameAndEmail, setMyInfoNameAndEmail] = useState<ProfileProps>({
const [myInfo, setMyInfo] = useState<ProfileProps>({
name: user.nickName,
email: user.email,
image: user.imageUrl,
});

const onClickSetting = () => {
setIsModifyMyInfo(true);
};

const onClickLogout = async (e: React.MouseEvent<HTMLButtonElement>) => {
try {
fetch(`${DEFAULT_PROD_URL}/logout`, {
Expand All @@ -48,10 +53,9 @@ const MyInfo = () => {
if (isModifyMyInfo) {
return (
<UpdateMyInfo
isThereImg={isThereImg}
myInfoNameAndEmail={myInfoNameAndEmail}
myInfo={myInfo}
setIsModifyMyInfo={setIsModifyMyInfo}
setMyInfoNameAndEmail={setMyInfoNameAndEmail}
setMyInfo={setMyInfo}
/>
);
}
Expand All @@ -64,14 +68,17 @@ const MyInfo = () => {
$justifyContent="center"
$alignItems="center"
>
<SettingContainer onClick={onClickSetting}>
<Setting />
</SettingContainer>
<MyInfoImg src={user.imageUrl} />
<Space size={5} />
<Box>
<Flex $justifyContent="space-between" $alignItems="center">
<Text color="black" $fontSize="medium" $fontWeight="bold">
{user.nickName}
</Text>
<Button variant="primary" onClick={onClickLogout}>
<Button variant="custom" onClick={onClickLogout}>
로그아웃
</Button>
</Flex>
Expand All @@ -95,4 +102,11 @@ const MyInfoImg = styled.img`
border-radius: 50%;
`;

const SettingContainer = styled.div`
position: absolute;
top: 10px;
right: 10px;
cursor: pointer;
`;

export default MyInfo;
13 changes: 11 additions & 2 deletions frontend/src/components/common/Button/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import styled from 'styled-components';
import theme from '../../../themes';

export type ButtonVariant = 'primary' | 'secondary';
export type ButtonVariant = 'primary' | 'secondary' | 'custom';
Copy link
Collaborator

Choose a reason for hiding this comment

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

오 이거 custom은 로그아웃 버튼이 너무 커서 만드신 걸까요?!!!

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

YES


export interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement> {
Expand All @@ -14,11 +14,19 @@ const variants = {
color: `${theme.color.white}`,
backgroundColor: `${theme.color.primary}`,
border: `1px solid ${theme.color.primary}`,
padding: `${theme.spacing['2']} ${theme.spacing['3']}`,
},
secondary: {
color: `${theme.color.primary}`,
backgroundColor: 'transparent',
border: `1px solid ${theme.color.primary}`,
padding: `${theme.spacing['2']} ${theme.spacing['3']}`,
},
custom: {
color: `${theme.color.white}`,
backgroundColor: `${theme.color.primary}`,
border: `1px solid ${theme.color.primary}`,
padding: `${theme.spacing['0']} ${theme.spacing['2']}`,
Copy link
Collaborator

Choose a reason for hiding this comment

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

이쯤되면 버튼도 Text 마냥 처리해야할수도..

Copy link
Collaborator

Choose a reason for hiding this comment

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

저도 밑에 달았는데 비슷한 생각입니다 세인! 새로운 버튼 생길 때마다 바꿔줄 수는 없을 것 같아서! 나중에 같이 수정해보죠 !!

},
};

Expand All @@ -31,7 +39,8 @@ const Button = styled.button<ButtonProps>`
border: ${({ variant }) => variants[variant].border};
opacity: ${({ disabled }) => (disabled ? 0.5 : 1)};
border-radius: ${({ theme }) => theme.radius.small};
padding: ${({ theme }) => `${theme.spacing['2']} ${theme.spacing['3']}`};
padding: ${({ variant }) =>
variants[variant].padding || `${theme.spacing['2']} ${theme.spacing['3']}`};
font-size: ${({ theme }) => theme.fontSize.small};

&:hover {
Expand Down
1 change: 1 addition & 0 deletions frontend/src/types/Profile.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export interface ProfileProps {
name: string;
email: string;
image: string;
}
Loading