Skip to content

Commit 9764e52

Browse files
committed
feat: 로그인 기능 구현
- zustand 스토어를 통해 로그인 변수 관리 - 컴파운드 컴포넌트 패턴 적용 - 공용 input 최대 너비 제한 제거
1 parent 5ca0f00 commit 9764e52

File tree

12 files changed

+145
-43
lines changed

12 files changed

+145
-43
lines changed

src/components/common/InputForm.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ interface Props extends HTMLProps<HTMLInputElement> {
99

1010
const InputForm: React.FC<Props> = ({ title, placeholder, hint, onChange, ...rest }) => {
1111
return (
12-
<label className="form-control w-full max-w-xs">
12+
<label className="form-control w-full">
1313
<div className="label">
1414
<span className="label-text">{title}</span>
1515
</div>
16-
<input placeholder={placeholder} className="input input-bordered w-full max-w-xs" onChange={onChange} {...rest} />
16+
<input placeholder={placeholder} className="input input-bordered w-full" onChange={onChange} {...rest} />
1717
<div className="label">
1818
<span className="label-text-alt">{hint}</span>
1919
</div>

src/components/common/VerticalLogo.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
const VerticalLogo = () => {
22
return (
3-
<svg width="173" height="132" viewBox="0 0 173 132" fill="none" xmlns="http://www.w3.org/2000/svg">
3+
<svg
4+
className={'shrink-0'}
5+
width="173"
6+
height="132"
7+
viewBox="0 0 173 132"
8+
fill="none"
9+
xmlns="http://www.w3.org/2000/svg"
10+
>
411
<path
512
d="M101.162 42.3332C98.9018 42.3332 96.3478 42.3332 93.5461 42.5167C86.4412 42.9754 76.8287 42.165 74.8474 32.1346C72.0302 17.8842 80.2031 6.20248 79.3518 9.04646C72.3398 32.3946 85.2493 37.9143 95.6667 40.7736C98.809 41.6298 100.574 41.8286 103.344 37.5626C106.905 32.1041 110.109 21.9055 107.57 16.9209C102.292 6.66119 82.6643 5.42268 83.8407 1.06498C85.1874 -3.88904 63.4083 8.74065 64.5228 32.7004C65.1575 46.3392 77.4169 52.1648 98.9947 44.7643C101.177 44.0151 101.162 42.3485 101.162 42.3485V42.3332Z"
613
fill="#B8EA00"
Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,20 @@
11
import InputForm from '../common/InputForm.tsx';
2+
import { useLoginState } from '../../stores/loginStore.ts';
23

34
const EmailInput = () => {
4-
return <InputForm title={'Email'} placeholder={'이메일을 입력하세요'} hint={'Hint Text'} onChange={() => {}} />;
5+
const { email, emailHandler } = useLoginState();
6+
7+
return (
8+
<InputForm
9+
defaultValue={email}
10+
title={'Email'}
11+
placeholder={'이메일을 입력하세요'}
12+
hint={'Hint Text'}
13+
onChange={(e) => emailHandler(e.target.value)}
14+
type={'email'}
15+
name={'email'}
16+
/>
17+
);
518
};
619

720
export default EmailInput;
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { useLoginState } from '../../stores/loginStore.ts';
2+
3+
const LoginButton = () => {
4+
const { email, password } = useLoginState();
5+
6+
const onClick = () => {
7+
console.log('email: ', email);
8+
console.log('password: ', password);
9+
};
10+
11+
return (
12+
<button type={'submit'} onClick={onClick} className="btn btn-outline btn-primary w-full">
13+
SIGN IN
14+
</button>
15+
);
16+
};
17+
18+
export default LoginButton;

src/components/login/LoginForm.tsx

Lines changed: 2 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,11 @@
1-
import { ChangeEventHandler, createContext, FC, ReactNode, useState } from 'react';
1+
import { FC, ReactNode } from 'react';
22

33
interface Props {
44
children: ReactNode;
55
}
66

7-
interface LoginFormState {
8-
email: string;
9-
password: string;
10-
}
11-
12-
interface State {
13-
formChangeHandler: ChangeEventHandler<HTMLInputElement>;
14-
loginFormState: LoginFormState;
15-
}
16-
17-
export const LoginContext = createContext<State>();
18-
197
const LoginForm: FC<Props> = ({ children }) => {
20-
const [formState, setFormState] = useState<LoginFormState>({
21-
email: '',
22-
password: '',
23-
});
24-
25-
const formChangeHandler: ChangeEventHandler<HTMLInputElement> = (e) => {
26-
const name = e.target.name as 'email' | 'password';
27-
const value = e.target.value;
28-
setFormState((prev) => ({
29-
...prev,
30-
[name]: value,
31-
}));
32-
};
33-
34-
return (
35-
<LoginContext.Provider
36-
value={{
37-
loginFormState: formState,
38-
formChangeHandler,
39-
}}
40-
>
41-
<form>{children}</form>
42-
</LoginContext.Provider>
43-
);
8+
return <form className={'flex w-full flex-col gap-4'}>{children}</form>;
449
};
4510

4611
export default LoginForm;
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { FC, ReactNode } from 'react';
2+
3+
interface Props {
4+
children: ReactNode;
5+
}
6+
7+
const LoginFormActions: FC<Props> = ({ children }) => {
8+
return <div className={'flex w-full flex-col gap-2'}>{children}</div>;
9+
};
10+
11+
export default LoginFormActions;
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { FC, ReactNode } from 'react';
2+
3+
interface Props {
4+
children: ReactNode;
5+
}
6+
7+
const LoginNavigation: FC<Props> = ({ children }) => {
8+
return <div className={'flex flex-row justify-between'}>{children}</div>;
9+
};
10+
11+
export default LoginNavigation;
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { FC } from 'react';
2+
import { Link } from 'react-router-dom';
3+
4+
interface LoginNavigationLinkProps {
5+
text: string;
6+
to: string;
7+
}
8+
9+
const LoginNavigationLink: FC<LoginNavigationLinkProps> = ({ text, to }) => {
10+
return (
11+
<Link className={'text-xs font-medium'} to={to}>
12+
{text}
13+
</Link>
14+
);
15+
};
16+
17+
export default LoginNavigationLink;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import InputForm from '../common/InputForm.tsx';
2+
import { useLoginState } from '../../stores/loginStore.ts';
3+
4+
const PasswordInput = () => {
5+
const { password, passwordHandler } = useLoginState();
6+
7+
return (
8+
<InputForm
9+
defaultValue={password}
10+
title={'Password'}
11+
placeholder={'패스워드를 입력해 주세요.'}
12+
hint={'Hint text.'}
13+
onChange={(e) => passwordHandler(e.target.value)}
14+
name={'password'}
15+
type={'password'}
16+
/>
17+
);
18+
};
19+
20+
export default PasswordInput;

src/layouts/LoginPageLayout.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,13 @@ interface Props {
55
}
66

77
const LoginPageLayout: FC<Props> = ({ children }) => {
8-
return <div>{children}</div>;
8+
return (
9+
<main className={'flex h-screen w-screen items-center justify-center'}>
10+
<div className={'flex h-full w-full max-w-md flex-col items-center justify-around overflow-hidden px-8 py-8'}>
11+
{children}
12+
</div>
13+
</main>
14+
);
915
};
1016

1117
export default LoginPageLayout;

0 commit comments

Comments
 (0)