-
Notifications
You must be signed in to change notification settings - Fork 38
[이상달] refactor/sprint8 #221
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
Merged
addiescode-sj
merged 16 commits into
codeit-bootcamp-frontend:React-이상달
from
asksa1256:React-이상달-sprint8-rf
Aug 6, 2025
The head ref may contain hidden characters: "React-\uC774\uC0C1\uB2EC-sprint8-rf"
Merged
Changes from 12 commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
4cc8f9c
style: Footer 반응형 수정
asksa1256 496a761
refactor: 메인 페이지 배너 컴포넌트화
asksa1256 a35a5da
refactor: 메인 페이지 섹션 컴포넌트화
asksa1256 0e9d350
refactor: 배너 컴포넌트 linkBtn -> linkTo로 속성 및 타입변경
asksa1256 5c50d71
refactor: 로그인, 회원가입 - 간편 로그인 컴포넌트화
asksa1256 b75e800
refactor: text, password input field 컴포넌트 생성 및 로그인 페이지에 적용
asksa1256 684affa
refactor: 폼 필드 타입 생성
asksa1256 b2961cf
refactor: 회원가입 페이지 InputField, passwordField 적용
asksa1256 724eb36
fix: 로그인, 회원가입 에러메시지 안 뜨는 현상 수정 (formRef를 필드가 각자 호출해서 발생한 문제)
asksa1256 6331a41
refactor: 로그인, 회원가입 공통 로직 커스텀 훅(useAuthForm)으로 분리
asksa1256 f7cb57d
style: 로그인, 회원가입 폼 로고 반응형 수정
asksa1256 7839168
refactor: BannerStyle 분리
asksa1256 04d105e
refactor(BannerStyle): css vars -> 스크립트 변수로 스타일 정의 및 적용
asksa1256 15b385b
refactor: Banner 합성 기반 구조로 변경
asksa1256 cdbb48e
fix: 배너 ariaLabel 속성 적용 위치 수정
asksa1256 e77643c
refactor: 로그인, 회원가입 버튼의 isSubmitting 조건에 따른 텍스트 렌더링 유틸 함수 생성
asksa1256 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| /** @jsxImportSource @emotion/react */ | ||
| import { ReactNode } from "react"; | ||
| import { useNavigate } from "react-router-dom"; | ||
| import Button from "@/components/ui/Button"; | ||
| import BannerStyle from "./BannerStyle"; | ||
|
|
||
| interface BannerProps { | ||
| title: string | ReactNode; | ||
| imgSrc: string; | ||
| imgAlt: string; | ||
| linkTo?: string; | ||
| ariaLabel?: string; | ||
| lazyLoading?: boolean; | ||
| } | ||
|
|
||
| const Banner = ({ | ||
| title, | ||
| linkTo, | ||
| imgSrc, | ||
| imgAlt, | ||
| ariaLabel, | ||
| lazyLoading, | ||
| }: BannerProps) => { | ||
| const navigate = useNavigate(); | ||
|
|
||
| return ( | ||
| <div css={BannerStyle} aria-label={ariaLabel}> | ||
| <div className="banner-container"> | ||
| <div className="banner-info"> | ||
| <h2 className="banner-title">{title}</h2> | ||
| {linkTo && ( | ||
| <Button | ||
| onClick={() => navigate(linkTo)} | ||
| aria-label="상품 페이지로 이동" | ||
| variant="bannerPrimary" | ||
| size="lg" | ||
| > | ||
| 구경하러 가기 | ||
| </Button> | ||
| )} | ||
| </div> | ||
| <img | ||
| className="banner-img" | ||
| loading={lazyLoading ? "lazy" : "eager"} | ||
| src={imgSrc} | ||
| alt={imgAlt} | ||
| /> | ||
| </div> | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| export default Banner; | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,128 @@ | ||
| /** @jsxImportSource @emotion/react */ | ||
| import { css } from "@emotion/react"; | ||
| import { BREAKPOINTS } from "@/constants/responsive"; | ||
|
|
||
| const BannerStyle = css` | ||
| min-height: 540px; | ||
| background: var(--background-blue); | ||
| color: var(--gray700); | ||
asksa1256 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| text-align: center; | ||
|
|
||
| .banner-container { | ||
| display: flex; | ||
| flex-direction: column; | ||
| justify-content: space-between; | ||
| height: 100%; | ||
| min-height: 540px; | ||
| } | ||
|
|
||
| .banner-hero { | ||
| background: var(--background-blue-light); | ||
| } | ||
|
|
||
| .banner-title { | ||
| font-size: var(--banner-font-size); | ||
| margin-bottom: 18px; | ||
| word-break: keep-all; | ||
|
|
||
| @media (min-width: ${BREAKPOINTS.tablet}px) { | ||
| margin-bottom: 24px; | ||
| } | ||
|
|
||
| @media (min-width: ${BREAKPOINTS.desktop}px) { | ||
| margin-bottom: 32px; | ||
| } | ||
| } | ||
|
|
||
| .banner-info { | ||
| padding-top: 120px; | ||
| } | ||
|
|
||
| .banner-hero .banner-info { | ||
| display: flex; | ||
| flex-direction: column; | ||
| align-items: center; | ||
| margin: 0 auto; | ||
| padding-top: 48px; | ||
| max-width: 240px; | ||
| } | ||
|
|
||
| .banner-info .btn-lg { | ||
| display: block; | ||
| width: 100%; | ||
| font-size: var(--banner-btn-font-size); | ||
| line-height: 24px; | ||
| max-width: 356px; | ||
| } | ||
|
|
||
| .banner-img { | ||
| width: 100%; | ||
| max-width: 744px; | ||
| margin: 0 auto; | ||
| } | ||
|
|
||
| @media (min-width: 640px) { | ||
| .banner-hero .banner-info { | ||
| padding: 84px 0 210px; | ||
| max-width: none; | ||
| } | ||
| } | ||
|
|
||
| @media (min-width: ${BREAKPOINTS.tablet}px) { | ||
| :root { | ||
| --banner-btn-font-size: 20px; | ||
| } | ||
|
|
||
| .banner { | ||
| height: 926px; | ||
| } | ||
| .banner.banner-hero { | ||
| height: 770px; | ||
| } | ||
|
|
||
| .banner-info .btn-lg { | ||
| line-height: 32px; | ||
| } | ||
| } | ||
|
|
||
| @media (min-width: ${BREAKPOINTS.desktop}px) { | ||
| .banner-container { | ||
| width: var(--container-width); | ||
| margin: 0 auto; | ||
| } | ||
|
|
||
| .banner, | ||
| .banner.banner-hero { | ||
| height: 540px; | ||
| } | ||
|
|
||
| .banner-hero .banner-info { | ||
| align-items: flex-start; | ||
| } | ||
|
|
||
| .banner-container { | ||
| flex-direction: row; | ||
| justify-content: center; | ||
| align-items: flex-end; | ||
| } | ||
|
|
||
| .banner-info { | ||
| padding-bottom: 10.75rem; | ||
| } | ||
| .banner-hero .banner-info { | ||
| padding-bottom: 6.25rem; | ||
| } | ||
|
|
||
| .banner-title { | ||
| text-align: left; | ||
| } | ||
| } | ||
|
|
||
| @supports (font-size: clamp(1rem, 2vw, 3rem)) { | ||
| :root { | ||
| --banner-font-size: clamp(32px, 5vw, 40px); | ||
| } | ||
| } | ||
| `; | ||
|
|
||
| export default BannerStyle; | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,88 @@ | ||
| /** @jsxImportSource @emotion/react */ | ||
| import FormStyle from "./FormStyle"; | ||
| import { Link } from "react-router-dom"; | ||
| import Button from "@/components/ui/Button"; | ||
| import SocialLogin from "@/components/SocialLogin/SocialLogin"; | ||
| import logoImg from "@/assets/images/logo.svg"; | ||
| import loginUser from "@/services/post/loginUser"; | ||
| import InputField from "../ui/Form/InputField"; | ||
| import PasswordField from "../ui/Form/PasswordField"; | ||
| import useAuthForm from "@/hooks/useAuthForm"; | ||
|
|
||
| const LoginForm = () => { | ||
| const { | ||
| formRef, | ||
| isSubmitting, | ||
| submitError, | ||
| handleBlur, | ||
| validateForm, | ||
| isFormValid, | ||
| fieldErrors, | ||
| handleSubmit, | ||
| } = useAuthForm({ | ||
| onSubmit: async (userData) => { | ||
| await loginUser(userData); | ||
| }, | ||
| }); | ||
|
|
||
| return ( | ||
| <form | ||
| className="form" | ||
| ref={formRef} | ||
| onSubmit={validateForm} | ||
| css={FormStyle} | ||
| > | ||
| <div className="form-logo"> | ||
| <Link to="/" aria-label="새로고침"> | ||
| <img src={logoImg} alt="판다마켓 로고" width="396" height="132" /> | ||
| </Link> | ||
| </div> | ||
|
|
||
| <div className="form-contents"> | ||
| <InputField | ||
| label="이메일" | ||
| inputId="userEmail" | ||
| type="email" | ||
| name="email" | ||
| placeholder="이메일" | ||
| required | ||
| onBlur={handleBlur} | ||
| fieldError={fieldErrors.email} | ||
| /> | ||
| <PasswordField | ||
| label="비밀번호" | ||
| inputId="userPassword" | ||
| name="password" | ||
| placeholder="비밀번호" | ||
| onBlur={handleBlur} | ||
| fieldError={fieldErrors.password} | ||
| /> | ||
|
|
||
| <Button | ||
| type="submit" | ||
| className="btn-lg btn-primary" | ||
| id="loginBtn" | ||
| disabled={!isFormValid} | ||
| variant="primary" | ||
| size="lg" | ||
| onClick={handleSubmit} | ||
| > | ||
| {isSubmitting ? "로그인중..." : "로그인"} | ||
asksa1256 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| </Button> | ||
|
|
||
| {submitError && <p>{`${submitError}`}</p>} | ||
|
|
||
| <SocialLogin /> | ||
|
|
||
| <div className="form-footer"> | ||
| 판다마켓이 처음이신가요? | ||
| <Link className="form-footer-link" to="/signUp"> | ||
| 회원가입 | ||
| </Link> | ||
| </div> | ||
| </div> | ||
| </form> | ||
| ); | ||
| }; | ||
|
|
||
| export default LoginForm; | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,106 @@ | ||
| /** @jsxImportSource @emotion/react */ | ||
| import { Link } from "react-router-dom"; | ||
| import logoImg from "@/assets/images/logo.svg"; | ||
| import Button from "@/components/ui/Button"; | ||
| import SocialLogin from "@/components/SocialLogin/SocialLogin"; | ||
| import InputField from "@/components/ui/Form/InputField"; | ||
| import PasswordField from "@/components/ui/Form/PasswordField"; | ||
| import FormStyle from "./FormStyle"; | ||
| import useAuthForm from "@/hooks/useAuthForm"; | ||
| import createUser from "@/services/post/createUser"; | ||
|
|
||
| const SignUpForm = () => { | ||
| const { | ||
| formRef, | ||
| isSubmitting, | ||
| submitError, | ||
| handleBlur, | ||
| validateForm, | ||
| isFormValid, | ||
| fieldErrors, | ||
| handleSubmit, | ||
| } = useAuthForm({ | ||
| onSubmit: async (userData) => { | ||
| await createUser(userData); | ||
| }, | ||
| }); | ||
|
|
||
| return ( | ||
| <form | ||
| className="form" | ||
| method="POST" | ||
| ref={formRef} | ||
| onSubmit={validateForm} | ||
| css={FormStyle} | ||
| > | ||
| <div className="form-logo"> | ||
| <Link to="/" aria-label="새로고침"> | ||
| <img src={logoImg} alt="판다마켓 로고" width="396" height="132" /> | ||
| </Link> | ||
| </div> | ||
|
|
||
| <div className="form-contents"> | ||
| <InputField | ||
| label="이메일" | ||
| inputId="userEmail" | ||
| type="email" | ||
| name="email" | ||
| placeholder="이메일" | ||
| required | ||
| onBlur={handleBlur} | ||
| fieldError={fieldErrors.email} | ||
| /> | ||
| <InputField | ||
| label="닉네임" | ||
| inputId="userNickname" | ||
| type="text" | ||
| name="nickname" | ||
| placeholder="닉네임" | ||
| required | ||
| onBlur={handleBlur} | ||
| fieldError={fieldErrors.nickname} | ||
| /> | ||
| <PasswordField | ||
| label="비밀번호" | ||
| inputId="userPassword" | ||
| name="password" | ||
| placeholder="비밀번호" | ||
| onBlur={handleBlur} | ||
| fieldError={fieldErrors.password} | ||
| /> | ||
| <PasswordField | ||
| label="비밀번호 확인" | ||
| inputId="userPasswordChk" | ||
| name="passwordCheck" | ||
| placeholder="비밀번호 확인" | ||
| onBlur={handleBlur} | ||
| fieldError={fieldErrors.passwordCheck} | ||
| /> | ||
|
|
||
| <Button | ||
| type="submit" | ||
| variant="primary" | ||
| size="lg" | ||
| id="signupBtn" | ||
| disabled={!isFormValid} | ||
| onClick={handleSubmit} | ||
| > | ||
| {isSubmitting ? "회원가입중..." : "회원가입"} | ||
asksa1256 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| </Button> | ||
|
|
||
| {submitError && <p>{`${submitError}`}</p>} | ||
|
|
||
| <SocialLogin /> | ||
|
|
||
| <div className="form-footer"> | ||
| 이미 회원이신가요? | ||
| <Link className="form-footer-link" to="/login"> | ||
| 로그인 | ||
| </Link> | ||
| </div> | ||
| </div> | ||
| </form> | ||
| ); | ||
| }; | ||
|
|
||
| export default SignUpForm; | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.