Skip to content

Commit

Permalink
[Feature/BAR-175] 계정설정 페이지 구현 (#54)
Browse files Browse the repository at this point in the history
* feat: 끄적이는 페이지 개발 초안

* feat: 계정설정 폼 UI 구조 설계

* feat: 계정설정 UI구현

* feat: 프로필 이미지 호버 기능 구현

* feat: 카드 cta 추가

* style: 스크롤바 제거

* feat: 복사 기능 구현

* style: 스타일링 디테일 추가

* feat: 끄적이는 post mutation 작성

* refactor: 리모델링

* refactor: 오늘 끄적인 문장 분리

* feat: 오늘 끄적이는 카드 연결

* feat: 끄적이는 submit 처리

* style: WriteInput 포지션 스타일링

* refactor: 폴더 구조 정리

* refactor: 컴포넌트 추상화 정리

* feat: setting 모달 구현 및 삭제 기능 구현

* feat: [WIP] 수정 삭제 pt1

* feat: 계정 타입 구현

* feat: submit 밸리데이션 추가

* feat: CTA 액션 개발

* feat: file 인풋 연결

* feat: [WIP]

* style: 프로필 이미지 삭제 디밍 UI 구현

* feat: 프로필 업로드 기능 완성

* refactor: 폴더 구조 정리

* feat: 탈퇴 모달 구현

* feat: 탈퇴 모달 완성

* feat: API 연결 완료

* style: 누락된 error border 적용

* feat: 프로필 수정 api 파일 형식 로직 변경

* fix: @dmswl98 리뷰 반영

* fix: 더미 데이터 삭제
  • Loading branch information
wonjin-dev authored Feb 14, 2024
1 parent 34fa595 commit cb9ca0f
Show file tree
Hide file tree
Showing 34 changed files with 1,018 additions and 81 deletions.
2 changes: 1 addition & 1 deletion pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Layout from '@components/Layout';

const Intro = () => {
return <Layout headerType="intro" isFooter></Layout>;
return <Layout headerType="intro" isShowFooter></Layout>;
};

export default Intro;
63 changes: 1 addition & 62 deletions pages/main/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,67 +13,6 @@ import 참고하는TabContent from '@domain/참고하는/components';
import { useInput } from '@hooks/useInput';
import { COLORS } from '@styles/tokens';

const DUMMY = [
{
createdAt: '2024-01-23',
temporalMemos: [
{
id: 4,
content: '끄적이는 메모 컨텐츠',
correctionContent: null,
isCorrected: false,
isArchived: false,
createdAt: '2024-01-23T15:15:18.678231',
},
{
id: 5,
content: '끄적이는 메모 컨텐츠',
correctionContent: null,
isCorrected: false,
isArchived: false,
createdAt: '2024-01-23T15:15:18.695559',
},
{
id: 6,
content: '끄적이는 메모 컨텐츠',
correctionContent: null,
isCorrected: false,
isArchived: false,
createdAt: '2024-01-23T15:15:18.715172',
},
],
},
{
createdAt: '2024-01-20',
temporalMemos: [
{
id: 1,
content: '끄적이는 메모 컨텐츠',
correctionContent: null,
isCorrected: false,
isArchived: false,
createdAt: '2024-01-20T15:15:18.678231',
},
{
id: 2,
content: '끄적이는 메모 컨텐츠',
correctionContent: null,
isCorrected: false,
isArchived: false,
createdAt: '2024-01-20T15:15:18.695559',
},
{
id: 3,
content: '끄적이는 메모 컨텐츠',
correctionContent: null,
isCorrected: false,
isArchived: false,
createdAt: '2024-01-20T15:15:18.715172',
},
],
},
];

const MainPage = () => {
const { todayMemos, history } = useGetWriteHistory();
const { mutate: submitTemporalMemo } = useCreateTemporalMemo();
Expand All @@ -95,7 +34,7 @@ const MainPage = () => {
<div className={styles.container}>
<div className={styles.content}>
<WriteGuide />
<TemporalMemoHistoryTable data={[...DUMMY, ...history]} />
<TemporalMemoHistoryTable data={history} />
<TodayTemoralMemos memos={todayMemos[0]?.temporalMemos} />
<div className={styles.inputWrapper}>
<WriteInput
Expand Down
139 changes: 139 additions & 0 deletions pages/profile/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import Image from 'next/image';
import { type ChangeEvent, useMemo, useState } from 'react';

import Icon from '@components/Icon';
import Layout from '@components/Layout';
import ExitModal from '@domain/계정설정/components/ExitModal';
import ProfileForm from '@domain/계정설정/components/Form';
import * as styles from '@domain/계정설정/index.css';
import useExitAccount from '@domain/계정설정/mutations/useExitAccount';
import useUpdateProfileImage from '@domain/계정설정/mutations/useUpdateProfileImage';
import useGetProfile from '@domain/계정설정/queries/useGetProfile';
import useModal from '@hooks/useModal';

const ProfilePage = () => {
const my = useGetProfile();
const exitModalProps = useModal();
const { mutate: exitAccount } = useExitAccount();
const { updateImage: updateProfileImage, deleteImage: deleteProfileImage } =
useUpdateProfileImage();
const [profileImg, setProfileImg] = useState<string>();
const [isHover, setIsHover] = useState(false);
const [exitCause, setExitCause] = useState<string | null>(null);

const profileImage = useMemo(() => {
if (!my.profileImageUrl) {
return (
<Icon
icon={'profile'}
width={96}
height={96}
wrapperClassName={styles.profileImageWrapper}
postfix={<Icon icon={'picture'} width={32} height={32} />}
postfixClassName={styles.profileImagePostfix}
/>
);
}

return (
<Image
src={my.profileImageUrl}
alt="프로필 이미지"
width={96}
height={96}
/>
);
}, [my.profileImageUrl]);

const handleProfileImageChange = (e: ChangeEvent<HTMLInputElement>) => {
if (!e.target.files) return;

const file = e.target.files[0];
const reader = new FileReader();

reader.onloadend = () => setProfileImg(`${reader.result}`);
reader.readAsDataURL(file);

setTimeout(() => {
updateProfileImage.mutate(`${reader.result}`);
}, 10);
};

const handleDeleteUploadedImage = () => {
setProfileImg(undefined);
deleteProfileImage.mutate();
};

return (
<Layout isShowFooter>
<div className={styles.container}>
<div className={styles.profileWrapper}>
{profileImg ? (
<div
style={{ position: 'relative' }}
onBlur={() => setIsHover(false)}
>
<img
src={profileImg}
alt="업로드 된 프로필 이미지"
width={96}
height={96}
className={styles.uploadPostImg}
onMouseEnter={() => setIsHover(true)}
/>

{isHover ? (
<div
className={styles.profileDim}
onMouseLeave={() => setIsHover(false)}
>
<button onClick={handleDeleteUploadedImage}>
<Icon icon={'closeActive'} width={32} height={32} />
</button>
</div>
) : null}
</div>
) : (
<label htmlFor="profile-input">
{profileImage}
<input
type="file"
id="profile-input"
accept="image/*"
onChange={handleProfileImageChange}
style={{ display: 'none' }}
/>
</label>
)}
</div>
<ProfileForm
name={my.name}
nickname={my.nickname}
authType={my.oAuthServiceType}
email={my.email}
/>
<div className={styles.textButtonWrapper}>
{/* TODO: 로그아웃 연결 */}
<button className={styles.textButton}>로그아웃</button>
<button
className={styles.textButton}
onClick={exitModalProps.handleOpen}
>
회원탈퇴
</button>
</div>
</div>

{exitModalProps.isOpen && (
<ExitModal
selectCause={exitCause}
exitMutate={exitAccount}
onContentClick={(cause: string) => setExitCause(cause)}
onModalCloseClick={exitModalProps.handleClose}
/>
)}
</Layout>
);
};

export default ProfilePage;
10 changes: 10 additions & 0 deletions src/assets/icons/Google2.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions src/assets/icons/Kakao2.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/Naver2.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/check-box-active.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/check-box.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/close-active.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/error.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions src/assets/icons/picture.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
34 changes: 28 additions & 6 deletions src/components/Icon/index.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,51 @@
import { type ReactNode } from 'react';

import { iconFactory, type Icons } from '../../constants/icon';

interface IconProps {
icon: Icons;
wrapperClassName?: string;
className?: string;
postfixClassName?: string;
color?: string;
width?: number;
height?: number;
postfix?: ReactNode;
onHover?: VoidFunction;
}

const Icon = ({
icon,
wrapperClassName,
className,
postfixClassName,
color,
width = 24,
height = 24,
postfix,
onHover,
}: IconProps) => {
const SvgIcon = iconFactory[icon];
if (!wrapperClassName && !postfix)
return (
<SvgIcon
className={className}
color={color}
width={width}
height={height}
/>
);

return (
<SvgIcon
className={className}
color={color}
width={width}
height={height}
/>
<div className={wrapperClassName} onMouseEnter={onHover}>
<SvgIcon
className={className}
color={color}
width={width}
height={height}
/>
{postfix && <div className={postfixClassName}>{postfix}</div>}
</div>
);
};

Expand Down
12 changes: 6 additions & 6 deletions src/components/Layout/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,22 @@ import Header from './components/Header';
import * as styles from './style.css';

interface LayoutProps {
isHeader?: boolean;
isShowHeader?: boolean;
headerType?: HeaderType;
isFooter?: boolean;
isShowFooter?: boolean;
backgroundColor?: string;
}

const Layout = ({
children,
isHeader = true,
isShowHeader = true,
headerType = 'normal',
isFooter = false,
isShowFooter = false,
backgroundColor = COLORS['Grey/White'],
}: PropsWithChildren<LayoutProps>) => {
return (
<>
{isHeader && <Header type={headerType} />}
{isShowHeader && <Header type={headerType} />}
<main
className={styles.mainWrapper}
style={assignInlineVars({
Expand All @@ -33,7 +33,7 @@ const Layout = ({
>
{children}
</main>
{isFooter && <Footer />}
{isShowFooter && <Footer />}
</>
);
};
Expand Down
2 changes: 1 addition & 1 deletion src/components/Layout/style.css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ export const backgroundColorMain = createVar();

export const mainWrapper = style({
backgroundColor: backgroundColorMain,
marginTop: '64px',
paddingTop: '64px',
maxWidth: '1200px',
margin: '0 auto',
});
Expand Down
Loading

0 comments on commit cb9ca0f

Please sign in to comment.