Skip to content

Commit ce8adca

Browse files
Merge pull request #221 from asksa1256/React-이상달-sprint8-rf
[이상달] refactor/sprint8
2 parents a3c000e + e77643c commit ce8adca

22 files changed

Lines changed: 1009 additions & 788 deletions

src/components/Banner/Banner.tsx

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/** @jsxImportSource @emotion/react */
2+
import { ReactNode } from "react";
3+
import { useNavigate } from "react-router-dom";
4+
import Button from "@/components/ui/Button";
5+
import BannerStyle from "./BannerStyle";
6+
7+
interface BannerInfoProps {
8+
align: string;
9+
children: ReactNode;
10+
}
11+
12+
const BannerInfo = ({ children, align }: BannerInfoProps) => {
13+
return <div className="banner-info">{children}</div>;
14+
};
15+
16+
interface BannerButtonProps {
17+
linkTo: string;
18+
children: ReactNode;
19+
ariaLabel?: string;
20+
}
21+
22+
const BannerButton = ({
23+
linkTo,
24+
children = "구경하러 가기",
25+
ariaLabel,
26+
}: BannerButtonProps) => {
27+
const navigate = useNavigate();
28+
29+
return (
30+
<Button
31+
onClick={() => navigate(linkTo)}
32+
aria-label={ariaLabel}
33+
variant="bannerPrimary"
34+
size="lg"
35+
>
36+
{children}
37+
</Button>
38+
);
39+
};
40+
41+
interface BannerImageProps {
42+
imgSrc: string;
43+
imgAlt: string;
44+
lazyLoading?: boolean;
45+
align?: string;
46+
}
47+
48+
const BannerImage = ({
49+
imgSrc,
50+
imgAlt,
51+
lazyLoading,
52+
align,
53+
}: BannerImageProps) => {
54+
return (
55+
<img
56+
className="banner-img"
57+
loading={lazyLoading ? "lazy" : "eager"}
58+
src={imgSrc}
59+
alt={imgAlt}
60+
/>
61+
);
62+
};
63+
64+
interface BannerProps {
65+
title: string | ReactNode;
66+
imgSrc: string;
67+
imgAlt: string;
68+
linkTo?: string;
69+
ariaLabel?: string;
70+
lazyLoading?: boolean;
71+
infoAlign?: string;
72+
imgAlign?: string;
73+
}
74+
75+
const Banner = ({
76+
title,
77+
linkTo,
78+
imgSrc,
79+
imgAlt,
80+
ariaLabel,
81+
lazyLoading,
82+
infoAlign = "left",
83+
imgAlign = "right",
84+
}: BannerProps) => {
85+
return (
86+
<div css={BannerStyle} aria-label={ariaLabel}>
87+
<div className="banner-container">
88+
<BannerInfo align={infoAlign}>
89+
<h2 className="banner-title">{title}</h2>
90+
{linkTo && <BannerButton linkTo={linkTo}>구경하러 가기</BannerButton>}
91+
</BannerInfo>
92+
<BannerImage
93+
imgSrc={imgSrc}
94+
imgAlt={imgAlt}
95+
lazyLoading={lazyLoading}
96+
align={imgAlign}
97+
/>
98+
</div>
99+
</div>
100+
);
101+
};
102+
103+
Banner.Info = BannerInfo;
104+
Banner.Button = BannerButton;
105+
Banner.Image = BannerImage;
106+
107+
export default Banner;
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/** @jsxImportSource @emotion/react */
2+
import { css } from "@emotion/react";
3+
import { BREAKPOINTS } from "@/constants/responsive";
4+
import { COLORS } from "@/styles/colors";
5+
import { FONT_SIZES } from "@/styles/fontSizes";
6+
7+
const BannerStyle = css`
8+
min-height: 540px;
9+
background: ${COLORS.background.blue};
10+
color: ${COLORS.gray[700]};
11+
text-align: center;
12+
13+
.banner-container {
14+
display: flex;
15+
flex-direction: column;
16+
justify-content: space-between;
17+
height: 100%;
18+
min-height: 540px;
19+
}
20+
21+
.banner-hero {
22+
background: ${COLORS.background.lightBlue};
23+
}
24+
25+
.banner-title {
26+
margin-bottom: 18px;
27+
word-break: keep-all;
28+
29+
@media (min-width: ${BREAKPOINTS.tablet}px) {
30+
margin-bottom: 24px;
31+
}
32+
33+
@media (min-width: ${BREAKPOINTS.desktop}px) {
34+
margin-bottom: 32px;
35+
}
36+
}
37+
38+
.banner-info {
39+
padding-top: 120px;
40+
}
41+
42+
.banner-hero .banner-info {
43+
display: flex;
44+
flex-direction: column;
45+
align-items: center;
46+
margin: 0 auto;
47+
padding-top: 48px;
48+
max-width: 240px;
49+
}
50+
51+
.banner-info .btn-lg {
52+
display: block;
53+
width: 100%;
54+
font-size: ${FONT_SIZES[18]};
55+
line-height: 24px;
56+
max-width: 356px;
57+
}
58+
59+
.banner-img {
60+
width: 100%;
61+
max-width: 744px;
62+
margin: 0 auto;
63+
}
64+
65+
@media (min-width: 640px) {
66+
.banner-hero .banner-info {
67+
padding: 84px 0 210px;
68+
max-width: none;
69+
}
70+
}
71+
72+
@media (min-width: ${BREAKPOINTS.tablet}px) {
73+
.banner {
74+
height: 926px;
75+
}
76+
.banner.banner-hero {
77+
height: 770px;
78+
}
79+
80+
.banner-info .btn-lg {
81+
line-height: 32px;
82+
font-size: ${FONT_SIZES[20]};
83+
}
84+
}
85+
86+
@media (min-width: ${BREAKPOINTS.desktop}px) {
87+
.banner-container {
88+
width: var(--container-width);
89+
margin: 0 auto;
90+
}
91+
92+
.banner,
93+
.banner.banner-hero {
94+
height: 540px;
95+
}
96+
97+
.banner-hero .banner-info {
98+
align-items: flex-start;
99+
}
100+
101+
.banner-container {
102+
flex-direction: row;
103+
justify-content: center;
104+
align-items: flex-end;
105+
}
106+
107+
.banner-info {
108+
padding-bottom: 10.75rem;
109+
}
110+
.banner-hero .banner-info {
111+
padding-bottom: 6.25rem;
112+
}
113+
114+
.banner-title {
115+
text-align: left;
116+
}
117+
}
118+
119+
@supports (font-size: clamp(1rem, 2vw, 3rem)) {
120+
.banner-title {
121+
font-size: clamp(32px, 5vw, 40px);
122+
}
123+
}
124+
`;
125+
126+
export default BannerStyle;

src/components/Form/LoginForm.tsx

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/** @jsxImportSource @emotion/react */
2+
import FormStyle from "./FormStyle";
3+
import { Link } from "react-router-dom";
4+
import Button from "@/components/ui/Button";
5+
import SocialLogin from "@/components/SocialLogin/SocialLogin";
6+
import logoImg from "@/assets/images/logo.svg";
7+
import loginUser from "@/services/post/loginUser";
8+
import InputField from "../ui/Form/InputField";
9+
import PasswordField from "../ui/Form/PasswordField";
10+
import useAuthForm from "@/hooks/useAuthForm";
11+
import { renderButtonTextByState } from "@/utils/renderButtonText";
12+
13+
const LoginForm = () => {
14+
const {
15+
formRef,
16+
isSubmitting,
17+
submitError,
18+
handleBlur,
19+
validateForm,
20+
isFormValid,
21+
fieldErrors,
22+
handleSubmit,
23+
} = useAuthForm({
24+
onSubmit: async (userData) => {
25+
await loginUser(userData);
26+
},
27+
});
28+
29+
return (
30+
<form
31+
className="form"
32+
ref={formRef}
33+
onSubmit={validateForm}
34+
css={FormStyle}
35+
>
36+
<div className="form-logo">
37+
<Link to="/" aria-label="새로고침">
38+
<img src={logoImg} alt="판다마켓 로고" width="396" height="132" />
39+
</Link>
40+
</div>
41+
42+
<div className="form-contents">
43+
<InputField
44+
label="이메일"
45+
inputId="userEmail"
46+
type="email"
47+
name="email"
48+
placeholder="이메일"
49+
required
50+
onBlur={handleBlur}
51+
fieldError={fieldErrors.email}
52+
/>
53+
<PasswordField
54+
label="비밀번호"
55+
inputId="userPassword"
56+
name="password"
57+
placeholder="비밀번호"
58+
onBlur={handleBlur}
59+
fieldError={fieldErrors.password}
60+
/>
61+
62+
<Button
63+
type="submit"
64+
className="btn-lg btn-primary"
65+
id="loginBtn"
66+
disabled={!isFormValid}
67+
variant="primary"
68+
size="lg"
69+
onClick={handleSubmit}
70+
>
71+
{renderButtonTextByState(isSubmitting, "로그인")}
72+
</Button>
73+
74+
{submitError && <p>{`${submitError}`}</p>}
75+
76+
<SocialLogin />
77+
78+
<div className="form-footer">
79+
판다마켓이 처음이신가요?
80+
<Link className="form-footer-link" to="/signUp">
81+
회원가입
82+
</Link>
83+
</div>
84+
</div>
85+
</form>
86+
);
87+
};
88+
89+
export default LoginForm;

0 commit comments

Comments
 (0)