Skip to content

Commit

Permalink
Merge pull request #995 from 78-artilleryman/part3-윤병현-week15
Browse files Browse the repository at this point in the history
[윤병현] week15
  • Loading branch information
greenblues1190 authored Apr 21, 2024
2 parents c128186 + 39b6f27 commit 2d784f7
Show file tree
Hide file tree
Showing 9 changed files with 395 additions and 54 deletions.
10 changes: 10 additions & 0 deletions public/Icons/google.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 12 additions & 0 deletions public/Icons/kakaolg.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions src/components/signinPage/ErrorMesage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from "react";
import styled from "styled-components";

const Error = styled.p`
color: #ff5b56;
font-size: 14px;
font-weight: 400;
`;

function ErrorMesage({ text }: { text: string | undefined }) {
return <Error>{text}</Error>;
}

export default ErrorMesage;
59 changes: 24 additions & 35 deletions src/components/signinPage/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,20 @@ import React, { InputHTMLAttributes, RefObject, useRef, useState } from "react";
import styled from "styled-components";
import setPwOff from "@/public/Icons/eye-off.svg";
import setPwOn from "@/public/Icons/eye-on.svg";
import { useForm } from "react-hook-form";
import { FieldErrors, UseFormRegisterReturn, useForm } from "react-hook-form";
import ErrorMesage from "./ErrorMesage";

type InputStyledProps = {
$error?: boolean;
};

const Layout = styled.div`
width: 400px;
width: 100%;
display: flex;
flex-direction: column;
gap: 12px;
position: relative;
margin-bottom: 6px;
`;

const Label = styled.label`
Expand Down Expand Up @@ -45,64 +47,51 @@ const ImgPosition = styled.div`
right: 18px;
`;

const ErrorMesage = styled.p`
color: #ff5b56;
font-size: 14px;
font-weight: 400;
`;

interface InputProps extends InputHTMLAttributes<HTMLInputElement> {
id: string;
placeholder: string;
error?: boolean;
label: string;
errors: FieldErrors;
label?: string;
validation?: UseFormRegisterReturn;
}

function Input({ id, type = "text", placeholder, error, label }: InputProps) {
function Input({
id,
type = "text",
placeholder,
errors,
label,
validation,
}: InputProps) {
const [pwState, setPwState] = useState(false);
const passwordRef = useRef<HTMLInputElement>(null);

const {
register,
formState: { errors },
} = useForm();
const error = errors[id];

const toggleEyesButton = () => {
if (passwordRef.current) {
if (pwState) {
passwordRef.current.type = "text";
setPwState(false);
} else {
passwordRef.current.type = "password";
setPwState(true);
}
}
setPwState((prev) => !prev);
};

return (
<>
<Layout>
<Label htmlFor={id}>{label}</Label>
<InputForm
type={type}
{...register(id, { required: true })}
id={id}
type={pwState ? "password" : "text"}
placeholder={placeholder}
ref={passwordRef}
$error={error}
$error={!!error}
{...validation}
/>
{type === "password" && (
<ImgPosition onClick={toggleEyesButton}>
{pwState ? (
<Image src={setPwOff} alt="Pw-off" />
) : (
<Image src={setPwOn} alt="Pw-on" />
) : (
<Image src={setPwOff} alt="Pw-off" />
)}
</ImgPosition>
)}
</Layout>
{errors.category?.type === "required" && (
<ErrorMesage>필수 입력사항입니다.</ErrorMesage>
)}
{errors && <ErrorMesage text={error?.message?.toString()} />}
</>
);
}
Expand Down
12 changes: 8 additions & 4 deletions src/components/signinPage/LogoBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ const Text = styled.p`
font-size: 16px;
font-weight: 400;
line-height: 24px; /* 150% */
margin-bottom: 30px;
`;

const LinkStyle = {
Expand All @@ -26,16 +25,21 @@ const LinkStyle = {
fontWeight: 600,
};

function LogoBox() {
interface LogoBox {
text: string;
linkText: string;
}

function LogoBox({ text, linkText }: LogoBox) {
return (
<Layout>
<Link href={`/`}>
<Image src={logo} alt="logo" width={210} height={38}></Image>
</Link>
<Text>
회원이 아니신가요?{" "}
{text}{" "}
<Link style={LinkStyle} href={`/`}>
회원 가입하기
{linkText}
</Link>
</Text>
</Layout>
Expand Down
47 changes: 47 additions & 0 deletions src/components/signinPage/SocialBox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import Image from "next/image";
import React from "react";
import googleIcon from "@/public/Icons/google.svg";
import kakao from "@/public/Icons/kakaolg.svg";
import styled from "styled-components";
import Link from "next/link";

const Layout = styled.div`
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 24px;
margin: 0 auto;
border-radius: 8px;
border: 1px solid var(--Linkbrary-gray20, #ccd5e3);
background: var(--Linkbrary-gray10, #e7effb);
`;

const Text = styled.p`
color: var(--Linkbrary-gray100, #373740);
font-size: 14px;
font-weight: 400;
`;

const SocialLinks = styled.div`
display: flex;
gap: 16px;
`;

function SocialBox({ text }: { text: string }) {
return (
<Layout>
<Text>{text}</Text>
<SocialLinks>
<Link href="https://www.google.com">
<Image src={googleIcon} alt="google"></Image>
</Link>
<Link href="https://www.kakaocorp.com/page">
<Image src={kakao} alt="kakao"></Image>
</Link>
</SocialLinks>
</Layout>
);
}

export default SocialBox;
91 changes: 76 additions & 15 deletions src/pages/signin/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@ import styled from "styled-components";
import SubmitBtn from "@/src/components/signinPage/SubmitBtn";
import LogoBox from "@/src/components/signinPage/LogoBox";
import { useForm } from "react-hook-form";
import SocialBox from "@/src/components/signinPage/SocialBox";
import ErrorMesage from "@/src/components/signinPage/ErrorMesage";
import { loginRequest } from "@/src/utils/Api";
import { useRouter } from "next/router";

const BackGround = styled.div`
width: 100%;
padding: 150px 0px 253px 0px;
padding: 100px 0px 200px 0px;
margin: 0 auto;
background: var(--Linkbrary-bg, #f0f6ff);
`;
Expand All @@ -18,33 +22,90 @@ const Layout = styled.div`
flex-direction: column;
align-items: center;
margin: 0 auto;
gap: 30px;
@media (max-width: 767px) {
width: 325px;
}
`;

const Form = styled.form`
width: 100%;
display: flex;
flex-direction: column;
gap: 30px;
`;

function SigninPage() {
const router = useRouter();

const {
register,
formState: { errors },
handleSubmit,
setError,
} = useForm({ mode: "onBlur" });

const emailValidation = register("userEmail", {
required: {
value: true,
message: "이메일을 입력해 주세요",
},
pattern: {
value: /^\S+@\S+$/i,
message: "올바른 이메일 주소가 아닙니다.",
},
});

const passwordValidation = register("userPw", {
required: {
value: true,
message: "비밀번호를 입력해 주세요",
},
});

const onSubmit = async (data: any) => {
const res = await loginRequest(data);

if (res) {
const { data } = res;
window.localStorage.setItem("accessToken", data.accessToken);
router.push("/folder");
} else {
setError("userEmail", { message: "이메일을 확인해주세요" });
setError("userPw", { message: "비밀번호를 확인해주세요" });
}
};

return (
<BackGround>
<Layout>
<LogoBox />
<Form action="">
<Input
label="이메일"
id="user_email"
type="email"
placeholder="이메일을 입력해 주세요"
></Input>
<Input
label="비밀번호"
id="user_pw"
type="password"
placeholder="비밀번호를 입력해 주세요"
></Input>
<LogoBox text="회원이 아니신가요?" linkText="회원 가입하기" />
<Form onSubmit={handleSubmit(onSubmit)}>
<div>
<Input
label="이메일"
id="userEmail"
type="email"
placeholder="이메일을 입력해 주세요"
validation={emailValidation}
errors={errors}
/>
</div>

<div>
<Input
label="비밀번호"
id="userPw"
type="password"
placeholder="비밀번호를 입력해 주세요"
validation={passwordValidation}
errors={errors}
/>
</div>
<SubmitBtn>로그인</SubmitBtn>
</Form>
<SocialBox text="소셜 로그인" />
</Layout>
</BackGround>
);
Expand Down
Loading

0 comments on commit 2d784f7

Please sign in to comment.