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

마이페이지 화면구성을 진행합니다. #20

Open
wants to merge 26 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
13747c7
feat(Mypage): 마이페이지 페이지 골격 구성
jaychang99 Aug 12, 2023
5a3840a
Merge branch 'feature/page-structure-setup' into feature/page-mypage
jaychang99 Aug 12, 2023
591901e
feat: ProfileImage 에 사이즈 추가할 수 있도록 변경
jaychang99 Aug 12, 2023
502adc5
feat(MyPage): 마이페이지 상단 프로필까지 퍼블리싱
jaychang99 Aug 12, 2023
5ab490f
feat(Mypage): 마이페이지 내 정보 및 상세 영역, 단체 정보 제외 퍼블리싱 완료
jaychang99 Aug 12, 2023
482aabe
feat(Mypage): 마이페이지 스타일 변경
jaychang99 Aug 12, 2023
da35927
sync: Merge branch 'develop'
jaychang99 Aug 27, 2023
cf9fd89
fix(Mypage): 마이페이지 내 정보 수정 버튼 공통 컴포넌트로 대체
jaychang99 Aug 27, 2023
8b22a4c
fix(Button): 버튼이 외부 className 도 받을 수 있도록 수정
jaychang99 Aug 27, 2023
10c112b
feat(MyPage): 마이페이지 수정 페이지 기본 레이아웃 구현
jaychang99 Aug 27, 2023
d3cd3de
fix(TextInput): 비동기 api 호출에 의한 value 변화를 감지하지 못하는 문제 수정
jaychang99 Aug 27, 2023
6e4121b
feat(MyPage): 마이페이지 정보 수정 페이지 생년월일 제외 레이아웃 및 모킹 구성 완료
jaychang99 Aug 27, 2023
3329978
feat(MyPage): 삭제 확인 페이지 생성 완료
jaychang99 Aug 27, 2023
105e8f2
refactor(Mypage): 세부기능별 폴더구조 개편
jaychang99 Aug 27, 2023
7bca95d
refactor: Props 받지 않는데 정의된 곳 제거
jaychang99 Aug 27, 2023
a3b78d1
feat(Mypage): 회원탈퇴 완료 페이지 생성
jaychang99 Aug 27, 2023
5f3a591
feat(Mypage): 마이페이지의 '내 정보 수정' 버튼을 primary 버튼에서 text 버튼으로 격하'
jaychang99 Aug 27, 2023
548d79a
feat(Mypage): 마이페이지 메인에 가입된 단체 없을 때 CTA 영역 추가
jaychang99 Aug 27, 2023
cb3acf0
feat(Mypage): 마이페이지 메인에서도 initial mockup data 로 정보 불러올 수 있도록 세팅
jaychang99 Aug 27, 2023
2bc49d8
feat(Dropdown): 드롭다운의 최대 높이를 설정하여, 이를 넘어갈 시 스크롤되도록 할 수 있는 옵션 추가
jaychang99 Sep 5, 2023
e8d1403
feat(MyPage): 마이페이지에 출생년도 설정 드롭다운 추가
jaychang99 Sep 5, 2023
c6a2adc
feat(MyPage): 마이페이지에 로그아웃 버튼 추가
jaychang99 Sep 6, 2023
4530b29
sync: Merge branch 'develop'
jaychang99 Sep 16, 2023
f3077aa
refactor(Dropdown): boolean 화 해주는 코드 간략화
jaychang99 Sep 16, 2023
c2a52a8
refactor: 내부적인 링크 이동 url 모두 constants/link.ts 에서 상수로 관리
jaychang99 Sep 16, 2023
2c0427e
refactor(Mypage): 탈퇴하기 버튼에 Button 의 danger prop 이용하는 것으로 변경
jaychang99 Sep 19, 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
11 changes: 11 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"@types/node": "20.4.3",
"@types/react": "18.2.15",
"@types/react-dom": "18.2.7",
"dayjs": "1.11.9",
"emotion-reset": "^3.0.1",
"eslint-config-next": "13.4.12",
"next": "13.4.12",
Expand Down
3 changes: 2 additions & 1 deletion src/components/button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const Button = ({
fullWidth = false,
loading = false,
onClick,
className,
danger = false, // 버튼을 빨간색으로 표시
...props
}: Props) => {
Expand Down Expand Up @@ -50,7 +51,7 @@ const Button = ({
icon={icon}
onMouseDown={handleMouseDown}
onMouseUp={handleMouseUp}
className={isActive ? "active" : ""}
className={isActive ? `active ${className}` : className}
>
{loading && <Loader />}
{icon}
Expand Down
21 changes: 17 additions & 4 deletions src/components/dropdown/Dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,18 @@ interface Props extends HTMLAttributes<HTMLDivElement> {
placeHolder?: string;
children: React.ReactNode;
onSelectValueChange?: (value: string) => void;
selectContainerMaxHeight?: number;
disabled?: boolean;
}

const Dropdown = ({
children,
label,
value,
onSelectValueChange,
selectContainerMaxHeight,
name,
placeHolder = "Select an option",
onSelectValueChange,
disabled = false,
}: Props) => {
const [isOpen, setIsOpen] = useState(false);
Expand Down Expand Up @@ -74,7 +76,11 @@ const Dropdown = ({
}, [children, selectedOptionValue, onSelectValueChange, value]);

return (
<EmotionWrapper isOpen={isOpen} isCompleted={selectedOptionValue ? true : false}>
<EmotionWrapper
isOpen={isOpen}
isCompleted={!!selectedOptionValue}
selectContainerMaxHeight={selectContainerMaxHeight}
>
{label && <span className="label">{label}</span>}
<div className="selected-option" onClick={toggleDropdown}>
{selectedOptionValue ? (
Expand Down Expand Up @@ -114,7 +120,11 @@ const Dropdown = ({
Dropdown.Option = DropdownOption;
export default Dropdown;

const EmotionWrapper = styled.div<{ isOpen: boolean; isCompleted: boolean }>`
const EmotionWrapper = styled.div<{
isOpen: boolean;
isCompleted: boolean;
selectContainerMaxHeight?: number;
}>`
position: relative;
font-size: 14px;
width: 100%;
Expand Down Expand Up @@ -155,7 +165,7 @@ const EmotionWrapper = styled.div<{ isOpen: boolean; isCompleted: boolean }>`
top: 120%;
left: 0;
width: 100%;
overflow-y: auto;
overflow-y: ${({ selectContainerMaxHeight }) => (selectContainerMaxHeight ? "scroll" : "auto")};
border: 0.5px solid ${({ theme }) => theme.color.gray500};
border-radius: 6px;
background-color: white;
Expand All @@ -167,6 +177,9 @@ const EmotionWrapper = styled.div<{ isOpen: boolean; isCompleted: boolean }>`
opacity 0.3s ease-in-out,
height 0.3s ease-in-out;

${({ selectContainerMaxHeight }) =>
selectContainerMaxHeight && `max-height: ${selectContainerMaxHeight}px`};
z-index: 10;
max-height: 15vh;
overflow: auto;
}
Expand Down
4 changes: 1 addition & 3 deletions src/components/header/HeaderDesktop.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import styled from "@emotion/styled";
import ProfileImage from "components/profileImage/ProfileImage";

interface Props {}

const HeaderDesktop = ({}: Props) => {
const HeaderDesktop = () => {
return (
<EmotionWrapper>
<div className="nav-content">
Expand Down
4 changes: 1 addition & 3 deletions src/components/header/HeaderMobile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ import styled from "@emotion/styled";
import ProfileImage from "components/profileImage/ProfileImage";
import Image from "next/image";

interface Props {}

const HeaderMobile = ({}: Props) => {
const HeaderMobile = () => {
return (
<EmotionWrapper>
<Image src="/images/icons/arrow-left.svg" width={24} height={24} alt="왼쪽 화살표 아이콘" />
Expand Down
4 changes: 1 addition & 3 deletions src/components/header/Hero.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import styled from "@emotion/styled";
import { LAYOUT_MARGIN } from "constant/layoutMargin";

interface Props {}

const Hero = ({}: Props) => {
const Hero = () => {
return (
<EmotionWrapper>
<div className="content-wrapper">
Expand Down
15 changes: 15 additions & 0 deletions src/components/icons/IconEmptyOutlined.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const IconEmptyOutlined = () => {
return (
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M4 6V5C4 4.73478 4.10536 4.48043 4.29289 4.29289C4.48043 4.10536 4.73478 4 5 4H6M11 4H13M18 4H19C19.2652 4 19.5196 4.10536 19.7071 4.29289C19.8946 4.48043 20 4.73478 20 5V6M20 11V13M20 18V19C20 19.2652 19.8946 19.5196 19.7071 19.7071C19.5196 19.8946 19.2652 20 19 20H18M13 20H11M6 20H5C4.73478 20 4.48043 19.8946 4.29289 19.7071C4.10536 19.5196 4 19.2652 4 19V18M4 13V11"
stroke="#333333"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
);
};

export default IconEmptyOutlined;
15 changes: 15 additions & 0 deletions src/components/icons/IconWarningOutlined.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const IconWarningOutlined = () => {
return (
<svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M18 13.4998V16.4998M18 22.4998V22.5148M7.49992 28.4998H28.4999C28.9894 28.4963 29.4706 28.3732 29.9015 28.1411C30.3324 27.909 30.7 27.5749 30.9722 27.1681C31.2444 26.7613 31.4129 26.2941 31.4631 25.8072C31.5132 25.3203 31.4435 24.8285 31.2599 24.3748L20.6099 5.99978C20.3505 5.53088 19.9702 5.14002 19.5085 4.86786C19.0469 4.59569 18.5208 4.45215 17.9849 4.45215C17.449 4.45215 16.9229 4.59569 16.4613 4.86786C15.9997 5.14002 15.6194 5.53088 15.3599 5.99978L4.70992 24.3748C4.52983 24.8181 4.45842 25.2982 4.50164 25.7747C4.54487 26.2513 4.70148 26.7107 4.9584 27.1144C5.21531 27.5181 5.56508 27.8545 5.97851 28.0955C6.39193 28.3365 6.85701 28.4751 7.33492 28.4998"
stroke="black"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
);
};

export default IconWarningOutlined;
5 changes: 5 additions & 0 deletions src/components/inputs/TextInput/TextInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ const TextInput: React.FC<Props> = ({
}
}, [enteredValue, status, onTextChange]);

useEffect(() => {
// 비동기 API 호출로 인한 value 변경 시에만 실행
setEnteredValue(value);
}, [value]);

return (
<EmotionWrapper>
{label && <span className="label">{label}</span>}
Expand Down
4 changes: 1 addition & 3 deletions src/components/navbar/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ import styled from "@emotion/styled";
import { LAYOUT_MARGIN } from "constant/layoutMargin";
import { NAVBAR_HEIGHT } from "constant/navbarHeight";

interface Props {}

const Navbar = ({}: Props) => {
const Navbar = () => {
return <EmotionWrapper>Navbar</EmotionWrapper>;
};

Expand Down
22 changes: 22 additions & 0 deletions src/constant/link.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* 이 파일에서는 링크 경로를 관리합니다.
* autoComplete 및 검색에 도움이 되도록 `LINK_` 로 시작하는 이름을 사용합니다.
*/

// 메인 페이지 경로
export const LINK_MAIN_PAGE = "/";

// 로그인 페이지 경로
export const LINK_LOGIN_PAGE = "/login";

// 마이 페이지
export const LINK_MYPAGE = "/mypage";

// 내 정보 수정 페이지
export const LINK_MYPAGE_EDIT = "/mypage/edit";

// 계정 탈퇴 페이지
export const LINK_ACCOUNT_DELETE = "/mypage/delete";

// 계정 탈퇴 성공 시 이동할 경로
export const LINK_ACCOUNT_DELETE_SUCCESS = "/mypage/delete/success";
Empty file removed src/feature/.gitkeep
Empty file.
5 changes: 5 additions & 0 deletions src/feature/mypage/common/constants/genderLookupTable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export const GENDER_LOOKUP_TABLE = {
M: "남성",
F: "여성",
U: "선택 안함",
};
8 changes: 8 additions & 0 deletions src/feature/mypage/common/mockup/MockupMypage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { TUser } from "feature/mypage/mypage.edit/types/TMypageFormValues";

export const MOCKUP_MYPAGE_INITIAL_VALUES: TUser = {
nickname: "홍길동",
introduction: "안녕하세요. 저는 홍길동입니다.",
birthYear: "1990",
gender: "M",
};
51 changes: 51 additions & 0 deletions src/feature/mypage/mypage.delete/components/MypageDeleteAlert.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import styled from "@emotion/styled";
import IconWarningOutlined from "components/icons/IconWarningOutlined";

const MypageDeleteAlert = () => {
return (
<EmotionWrapper>
<IconWarningOutlined />

<p className="warning-title">회원 탈퇴 시, 아래의 정보가 삭제됩니다. </p>
<ul>
<li className="deleted-item">회원 정보</li>
<li className="deleted-item">내가 속한 단체의 소속상태</li>
</ul>
<p className="warning-disclaimer">
단, 내가 생성한 맛집, 투표, 모임 정보 등은 유지되며, 생성자의 정보에 &apos;탈퇴한 유저&apos;
라고 표시됩니다.{" "}
</p>
</EmotionWrapper>
);
};

export default MypageDeleteAlert;

const EmotionWrapper = styled.div`
display: flex;
flex-direction: column;
align-items: center;

.warning-title {
font-size: 16px;
font-weight: 700;
margin-top: 32px;
margin-bottom: 24px;
}

.deleted-item {
margin-bottom: 4px;

&:before {
content: "•";
margin-right: 8px;
}
}

.warning-disclaimer {
font-size: 12px;
margin-top: 32px;
color: ${({ theme }) => theme.color.gray400};
line-height: 1.5;
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import styled from "@emotion/styled";
import Button from "components/button/Button";
import TextInput from "components/inputs/TextInput/TextInput";
import { LINK_ACCOUNT_DELETE_SUCCESS } from "constant/link";
import { validateDeleteConfirmMessage } from "feature/mypage/mypage.delete/functions/validateDeleteConfirmMessage";
import { TTextInputItem } from "feature/mypage/mypage.delete/types/TTextInputItem";
import { useRouter } from "next/router";
import { useCallback, useState } from "react";

const MypageDeleteConfirmForm = () => {
const { push } = useRouter();

const [confirmFormValues, setConfirmFormValues] = useState<TTextInputItem>({
value: "",
isValid: false,
});

const handleChangeConfirmValue = useCallback((value: string, isValid: boolean) => {
setConfirmFormValues({
value,
isValid,
});
}, []);

const handleSubmitDeleteAccount = () => {
// TODO: Modal, toast 등으로 피드백 처리
if (!confirmFormValues.isValid) {
alert("탈퇴 메시지를 확인해주세요");
return;
}
// TODO: API 연동 , 여기서 실제 탈퇴 API 호출 후 성공 시 아래 링크로 이동
push(LINK_ACCOUNT_DELETE_SUCCESS);
};

return (
<EmotionWrapper>
<TextInput
label="아래에 '탈퇴' 라고 입력하세요"
placeholder="탈퇴"
onTextChange={handleChangeConfirmValue}
conditionCheckList={[validateDeleteConfirmMessage]}
/>
<Button danger fullWidth onClick={handleSubmitDeleteAccount}>
탈퇴하기
</Button>
</EmotionWrapper>
);
};

export default MypageDeleteConfirmForm;

const EmotionWrapper = styled.div`
margin-top: 64px;

button {
margin-top: 32px;
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const validateDeleteConfirmMessage = {
condition: (value: string): boolean => {
if (value !== "탈퇴") return false;
return true;
},
messageOnError: "'탈퇴' 를 입력해주세요.",
};
5 changes: 5 additions & 0 deletions src/feature/mypage/mypage.delete/types/TTextInputItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// TODO: 추후 공통 폴더로 이동하면 좋을 것 같음.
export type TTextInputItem = {
value: string;
isValid: boolean;
};
16 changes: 16 additions & 0 deletions src/feature/mypage/mypage.delete/views/ViewMypageDelete.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import styled from "@emotion/styled";
import MypageDeleteAlert from "feature/mypage/mypage.delete/components/MypageDeleteAlert";
import MypageDeleteConfirmForm from "feature/mypage/mypage.delete/components/MypageDeleteConfirmForm";

const ViewMypageDelete = () => {
return (
<EmotionWrapper>
<MypageDeleteAlert />
<MypageDeleteConfirmForm />
</EmotionWrapper>
);
};

export default ViewMypageDelete;

const EmotionWrapper = styled.div``;
Loading