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

마이페이지 프로필 이름 수정, 비밀번호 변경 기능 추가 (프로필 이미지 기능 X) #38

Merged
merged 6 commits into from
Jun 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 7 additions & 2 deletions src/pages/login-signup/components/utils/useSignUpForm.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { apiSignUp } from '../../../../api/apiModule';
import { apiSignUp, apiUploadImage } from '../../../../api/apiModule';
import defaultProfileImgMaker from '../../../../utils/defaultProfileImgMaker';

// 회원가입 폼 제출 기능을 수행하는 함수입니다.
// useNavigate를 사용하여 폼 제출 시 다른 페이지로 이동하도록 구현했습니다.
Expand Down Expand Up @@ -42,8 +43,12 @@ function useSignUpForm() {

try {
await apiSignUp({ email, nickname, password }); // 회원가입 API 호출
navigate('/login'); // 회원가입 성공 시 로그인 페이지로 이동

const profileImgUrl = defaultProfileImgMaker({ name: nickname }); // 프로필 이미지 생성
await apiUploadImage({ image: profileImgUrl }); // 프로필 이미지 저장 API 호출

setIsModalOpen(true); // 성공 시 모달 창 띄우기
navigate('/login'); // 회원가입 성공 시 로그인 페이지로 이동
} catch (error) {
setIsErrorModalOpen(true);
setError('중복된 이메일입니다.');
Expand Down
13 changes: 13 additions & 0 deletions src/pages/login-signup/login/Login.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,22 @@
import { useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import styles from './Login.module.scss';
import Logo from '../components/Logo/Logo';
import LoginForm from '../components/LoginForm/LoginForm';
import LInkText from '../components/LinkText/LinkText';

function Login() {
const navigate = useNavigate();

useEffect(() => {
const accessToken = localStorage.getItem('Token');

if (accessToken) {
// AccessToken이 존재하면 '/mydashboard' 페이지로 이동
navigate('/mydashboard');
}
}, [navigate]); // navigate를 의존성 배열에 추가

return (
<div className={styles.Layout}>
<Logo Text="오늘도 만나서 반가워요!" />
Expand Down
13 changes: 13 additions & 0 deletions src/pages/login-signup/signup/SignUp.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,22 @@
import { useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import styles from './SignUp.module.scss';
import Logo from '../components/Logo/Logo';
import SignUpForm from '../components/SignUpForm/SignUpForm';
import LInkText from '../components/LinkText/LinkText';

function SignUp() {
const navigate = useNavigate();

useEffect(() => {
const accessToken = localStorage.getItem('Token');

if (accessToken) {
// AccessToken이 존재하면 '/mydashboard' 페이지로 이동
navigate('/mydashboard');
}
}, [navigate]); // navigate를 의존성 배열에 추가

return (
<div className={styles.Layout}>
<Logo Text="첫 방문을 환영합니다!" />
Expand Down
27 changes: 19 additions & 8 deletions src/pages/mypage/MyPage.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,36 @@
import { useNavigate } from 'react-router-dom';
import styles from './MyPage.module.scss';
import ProfileEdit from './components/ProfileEdit/ProfileEdit';
import PasswordEdit from './components/PasswordEdit/PasswordEdit';
import ArrowIcon from '../../../public/icon/arrow_forward.svg';
import SideBar from '../../components/sidebar/sidebar';
import MyPageHeader from './components/Header/Header';

// navBar, sideBar 부분은 컴포넌트로 추가할 예정입니다.

function MyPage() {
const navigate = useNavigate();

const handleBackButton = () => {
navigate('/mydashboard');
};

return (
<div className={styles.myPageLayout}>
<SideBar />
<div className={styles.MyPageContainer}>
<MyPageHeader />
<div className={styles.pageBackContainer}>
<img
className={styles.pageBackIcon}
src={ArrowIcon}
alt="왼쪽 바라보는 화살표 이미지"
/>
<span className={styles.pageBackText}>돌아가기</span>
<button
className={styles.backButton}
type="button"
onClick={handleBackButton}
>
<img
className={styles.pageBackIcon}
src={ArrowIcon}
alt="왼쪽 바라보는 화살표 이미지"
/>
<span className={styles.pageBackText}>돌아가기</span>
</button>
</div>
<ProfileEdit />
<PasswordEdit />
Expand Down
4 changes: 4 additions & 0 deletions src/pages/mypage/components/Button/Button.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,8 @@

border-radius: 4px;
background: $violet_5534DA;

&:disabled {
background: $gray_9FA6B2;
}
}
15 changes: 13 additions & 2 deletions src/pages/mypage/components/Button/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
import styles from './Button.module.scss';

// 각 변경 사항을 최종 제출하는 버튼입니다.
// ProfileEdit, PasswordEdit 컴포넌트에서 사용됩니다.
// ButtonText, onClick, disabled 를 각 부모 컴포넌트에서 받아옵니다.

type ButtonProps = {
ButtonText: string;
onClick: (e: React.MouseEvent<HTMLButtonElement>) => void;
disabled: boolean;
};

function Button({ ButtonText }: ButtonProps) {
function Button({ ButtonText, onClick, disabled }: ButtonProps) {
return (
<div className={styles.buttonContainer}>
<button className={styles.button} type="submit">
<button
className={styles.button}
type="submit"
onClick={onClick}
disabled={disabled}
>
{ButtonText}
</button>
</div>
Expand Down
13 changes: 13 additions & 0 deletions src/pages/mypage/components/Header/Header.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,16 @@
justify-content: center;
gap: 12px;
}

.profileContainer {
display: flex;
align-items: center;
justify-content: center;
gap: 12px;
}

.userName {
color: $black_333236, #333236;
font-size: 16px;
font-weight: 500;
}
26 changes: 26 additions & 0 deletions src/pages/mypage/components/ImageButton/ImageButton.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
@import '/src/styles/global.scss';
@import '/src/styles/media.scss';

.imageAddButton {
position: relative;
display: flex;
width: 182px;
height: 182px;
justify-content: center;
align-items: center;
flex-shrink: 0;

border-radius: 6px;
background: #f5f5f5;
}

.plusImage {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);

width: 30px;
height: 30px;
flex-shrink: 0;
}
43 changes: 43 additions & 0 deletions src/pages/mypage/components/ImageButton/ImageButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { useRef } from 'react';
import styles from './ImageButton.module.scss';
import PlusImage from '../../../../../public/icon/add_blue.svg';

interface ImageButtonProps {
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
}

function ImageButton({ onChange }: ImageButtonProps) {
const fileInputRef = useRef<HTMLInputElement | null>(null);

// 버튼 클릭 이벤트 핸들러
const handleClick = () => {
if (fileInputRef.current) {
fileInputRef.current.click(); // 파일 입력 요소를 클릭하도록 트리거
}
};

return (
<div>
<button
className={styles.imageAddButton}
type="button"
onClick={handleClick}
>
<img
className={styles.plusImage}
src={PlusImage}
alt="플러스 모양 이미지"
/>
</button>
<input
type="file"
ref={fileInputRef}
style={{ display: 'none' }} // 입력 요소 숨기기
accept="image/*" // 이미지 파일만 허용
onChange={onChange} // 파일이 선택되면 onChange 호출
/>
</div>
);
}

export default ImageButton;
16 changes: 16 additions & 0 deletions src/pages/mypage/components/InputLayout/InputLayout.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@
&:focus {
border: 1px solid $violet_5534DA;
}

&:disabled {
color: $gray_9FA6B2;
}
}

.profileInputSection {
Expand All @@ -47,3 +51,15 @@
@include inputSection;
width: 564px;
}

.error {
border: 1px solid $red_D6173A;
}

.errorMessage {
color: $red_D6173A;
font-size: 14px;
font-weight: 400;

margin-top: 5px;
}
25 changes: 24 additions & 1 deletion src/pages/mypage/components/InputLayout/InputLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import classNames from 'classnames';
import styles from './InputLayout.module.scss';

// Input 구역을 담당하는 컴포넌트입니다.
// 부모 컴포넌트에서 원하는 Props를 받아옵니다.
// 부모 컴포넌트에서 readOnly, disabled, onChange, onBlur, error를 원하는 상태로 정의합니다.
// 상태 정의에 따라서 다른 스타일을 적용합니다.

type InputLayoutProps = {
id: string;
name: string;
Expand All @@ -9,6 +14,12 @@ type InputLayoutProps = {
placeholder: string;
topMargin: boolean;
isProfile: boolean;
value: string;
readOnly: boolean;
disabled: boolean;
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void;
onBlur: (e: React.FocusEvent<HTMLInputElement>) => void;
error: string;
};

function InputLayout({
Expand All @@ -19,8 +30,13 @@ function InputLayout({
placeholder,
topMargin,
isProfile,
value,
onChange,
onBlur,
readOnly,
disabled,
error,
}: InputLayoutProps) {
// classNames로 Input의 스타일을 다르게 적용
const inputContainerClass = classNames({
[styles.topInputContainer]: topMargin,
[styles.normalInputContainer]: !topMargin,
Expand All @@ -29,6 +45,7 @@ function InputLayout({
const inputSectionClass = classNames({
[styles.profileInputSection]: isProfile,
[styles.passwordInputSection]: !isProfile,
[styles.error]: error,
});

return (
Expand All @@ -42,7 +59,13 @@ function InputLayout({
name={name}
type={type}
placeholder={placeholder}
value={value}
onChange={onChange}
onBlur={onBlur}
readOnly={readOnly}
disabled={disabled}
/>
{error && <p className={styles.errorMessage}>{error}</p>}
</div>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@
font-size: 24px;
font-weight: 700;

margin-top: 32px;
margin-bottom: 10px;
margin-bottom: 32px;
}

.inputContainer {
Expand Down
Loading
Loading