-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
[FE][Feat] #59 : AuthModal ์ปดํฌ๋ํธ
- Loading branch information
Showing
11 changed files
with
474 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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,139 @@ | ||
import React, { useState } from 'react'; | ||
import { Modal } from '@/component/common/modal/Modal'; | ||
|
||
interface IAuthModalProps { | ||
/** ๋ชจ๋ฌ์ด ์ด๋ ค ์๋์ง ์ฌ๋ถ๋ฅผ ๋ํ๋ ๋๋ค. */ | ||
isOpen: boolean; | ||
/** ๋ชจ๋ฌ์ ๋ซ๋ ํจ์์ ๋๋ค. */ | ||
onClose: () => void; | ||
/** ๋ชจ๋ฌ์ ํ์ ์ ๊ฒฐ์ ํ๋ ๊ฐ์ผ๋ก, 'login' ๋๋ 'register'๋ฅผ ๊ฐ์ง๋๋ค. */ | ||
type: 'login' | 'register'; | ||
} | ||
|
||
export const AuthModal = (props: IAuthModalProps) => { | ||
const [loginData, setLoginData] = useState({ | ||
id: '', | ||
pw: '', | ||
}); | ||
|
||
const [registerData, setRegisterData] = useState({ | ||
id: '', | ||
email: '', | ||
name: '', | ||
pw: '', | ||
confirmPw: '', | ||
}); | ||
|
||
const [modalType, setModalType] = useState<'login' | 'register'>(props.type); | ||
|
||
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => { | ||
const { name, value } = e.target; | ||
|
||
if (modalType === 'login') { | ||
setLoginData(prevState => ({ | ||
...prevState, | ||
[name]: value, | ||
})); | ||
} else { | ||
setRegisterData(prevState => ({ | ||
...prevState, | ||
[name]: value, | ||
})); | ||
} | ||
}; | ||
|
||
const handleLoginClick = () => { | ||
console.log('๋ก๊ทธ์ธ ๋ฐ์ดํฐ:', loginData); | ||
}; | ||
|
||
const handleSignUpClick = () => { | ||
if (registerData.pw !== registerData.confirmPw) { | ||
alert('๋น๋ฐ๋ฒํธ๊ฐ ์ผ์นํ์ง ์์ต๋๋ค.'); | ||
return; | ||
} | ||
console.log('ํ์๊ฐ์ ๋ฐ์ดํฐ:', registerData); | ||
}; | ||
|
||
const switchToRegister = () => { | ||
setModalType('register'); | ||
}; | ||
|
||
const switchToLogin = () => { | ||
setModalType('login'); | ||
}; | ||
|
||
return ( | ||
<Modal isOpen={props.isOpen} onClose={props.onClose}> | ||
{modalType === 'login' ? ( | ||
<> | ||
<Modal.Header content="Log In" onClose={props.onClose} /> | ||
<Modal.Input | ||
title="ID" | ||
name="id" | ||
placeholder="ID" | ||
value={loginData.id} | ||
onChange={handleChange} | ||
/> | ||
<Modal.Input | ||
title="PW" | ||
name="pw" | ||
placeholder="PW" | ||
value={loginData.pw} | ||
onChange={handleChange} | ||
/> | ||
<Modal.Footer | ||
text="๋ก๊ทธ์ธ" | ||
onClick={handleLoginClick} | ||
text2="ํ์๊ฐ์ " | ||
onClick2={switchToRegister} | ||
/> | ||
</> | ||
) : ( | ||
<> | ||
<Modal.Header content="Sign Up" onClose={props.onClose} /> | ||
<Modal.Input | ||
title="ID" | ||
name="id" | ||
placeholder="์ฌ์ฉํ ID๋ฅผ ์ ๋ ฅํด์ฃผ์ธ์." | ||
value={registerData.id} | ||
onChange={handleChange} | ||
/> | ||
<Modal.Input | ||
title="Email" | ||
name="email" | ||
placeholder="Email ์ฃผ์๋ฅผ ์ ๋ ฅํด์ฃผ์ธ์." | ||
value={registerData.email} | ||
onChange={handleChange} | ||
/> | ||
<Modal.Input | ||
title="Name" | ||
name="name" | ||
placeholder="์ด๋ฆ์ ์ ๋ ฅํด์ฃผ์ธ์." | ||
value={registerData.name} | ||
onChange={handleChange} | ||
/> | ||
<Modal.Input | ||
title="PW" | ||
name="pw" | ||
placeholder="์ฌ์ฉํ ๋น๋ฐ๋ฒํธ๋ฅผ ์ ๋ ฅํด์ฃผ์ธ์." | ||
value={registerData.pw} | ||
onChange={handleChange} | ||
/> | ||
<Modal.Input | ||
title="" | ||
name="confirmPw" | ||
placeholder="๋น๋ฐ๋ฒํธ๋ฅผ ํ ๋ฒ ๋ ์ ๋ ฅํด์ฃผ์ธ์." | ||
value={registerData.confirmPw} | ||
onChange={handleChange} | ||
/> | ||
<Modal.Footer | ||
text="ํ์๊ฐ์ " | ||
onClick={handleSignUpClick} | ||
text2="๋ก๊ทธ์ธ" | ||
onClick2={switchToLogin} | ||
/> | ||
</> | ||
)} | ||
</Modal> | ||
); | ||
}; |
This file contains 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,27 @@ | ||
import React from 'react'; | ||
import { ModalHeader } from '@/component/common/modal/ModalHeader'; | ||
import { ModalInput } from '@/component/common/modal/ModalInput'; | ||
import { ModalFooter } from '@/component/common/modal/ModalFooter'; | ||
|
||
interface IModalProps { | ||
/** ๋ชจ๋ฌ์ด ์ด๋ ค ์๋์ง ์ฌ๋ถ๋ฅผ ๋ํ๋ ๋๋ค. */ | ||
isOpen: boolean; | ||
/** ๋ชจ๋ฌ ๋ด์์ ๋ ๋๋งํ ์์ ์์๋ค์ ๋๋ค. */ | ||
children: React.ReactNode; | ||
} | ||
|
||
export const Modal = (props: IModalProps) => { | ||
if (!props.isOpen) return null; | ||
|
||
return ( | ||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-20"> | ||
<div className="relative w-[22rem] max-w-lg rounded-2xl bg-white px-6 shadow-lg"> | ||
{props.children} | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
Modal.Header = ModalHeader; | ||
Modal.Footer = ModalFooter; | ||
Modal.Input = ModalInput; |
This file contains 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,29 @@ | ||
interface IModalFooterProps { | ||
/** ๋ฉ์ธ ๋ฒํผ์ ํ ์คํธ์ ๋๋ค. */ | ||
text: string; | ||
/** ๋ฉ์ธ ๋ฒํผ ํด๋ฆญ ์ ํธ์ถ๋๋ ํจ์์ ๋๋ค. */ | ||
onClick?: () => void; | ||
/** ๋ณด์กฐ ๋ฒํผ์ ํ ์คํธ์ ๋๋ค (์ ํ ์ฌํญ) */ | ||
text2?: string; | ||
/** ๋ณด์กฐ ๋ฒํผ ํด๋ฆญ ์ ํธ์ถ๋๋ ํจ์์ ๋๋ค (์ ํ ์ฌํญ) */ | ||
onClick2?: () => void; | ||
} | ||
|
||
export const ModalFooter = (props: IModalFooterProps) => ( | ||
<div className="flex w-full flex-row-reverse items-center justify-start gap-5 rounded-lg bg-white py-4 shadow-sm"> | ||
<button | ||
type="button" | ||
className="bg-blueGray-600 h-[40px] rounded-lg px-4 py-2 text-sm font-semibold text-white hover:bg-blue-800" | ||
onClick={props.onClick} | ||
> | ||
{props.text} | ||
</button> | ||
{props.text2 ? ( | ||
<button type="button" className="text-grayscale-400 text-xs" onClick={props.onClick2}> | ||
{props.text2} | ||
</button> | ||
) : ( | ||
'' | ||
)} | ||
</div> | ||
); |
This file contains 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,18 @@ | ||
import { MdClear } from 'react-icons/md'; | ||
import { Button } from '../button/Button'; | ||
|
||
interface IModalHeaderProps { | ||
/** ๋ชจ๋ฌ ํค๋์ ์ ๋ชฉ ํ ์คํธ์ ๋๋ค. */ | ||
content: string; | ||
/** ๋ชจ๋ฌ์ ๋ซ๋ ํจ์์ ๋๋ค. */ | ||
onClose: () => void; | ||
} | ||
|
||
export const ModalHeader = (props: IModalHeaderProps) => ( | ||
<div className="flex flex-row items-start justify-between border-gray-200 py-4"> | ||
<h2 className="h-7 text-lg font-bold leading-7">{props.content}</h2> | ||
<Button onClick={props.onClose}> | ||
<MdClear /> | ||
</Button> | ||
</div> | ||
); |
This file contains 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,25 @@ | ||
interface IModalInputProps { | ||
/** ์ ๋ ฅ ํ๋์ ์ ๋ชฉ์ ๋๋ค. */ | ||
title: string; | ||
/** ์ ๋ ฅ ํ๋์ ์ด๋ฆ ์์ฑ์ ๋๋ค. */ | ||
name: string; | ||
/** ์ ๋ ฅ ํ๋์ placeholder ํ ์คํธ์ ๋๋ค. */ | ||
placeholder: string; | ||
/** ์ ๋ ฅ ํ๋์ ํ์ฌ ๊ฐ์ ๋๋ค. */ | ||
value: string; | ||
/** ์ ๋ ฅ ํ๋ ๊ฐ์ด ๋ณ๊ฒฝ๋ ๋ ํธ์ถ๋๋ ํจ์์ ๋๋ค. */ | ||
onChange: (e: React.ChangeEvent<HTMLInputElement>) => void; | ||
} | ||
|
||
export const ModalInput = (props: IModalInputProps) => ( | ||
<div className="flex flex-row items-center justify-between py-2"> | ||
<p className="font-medium">{props.title}</p> | ||
<input | ||
className="border-grayscale-75 text-grayscale-50 h-[32px] w-[250px] rounded-md border px-3 focus:outline-none focus:ring-1 focus:ring-blue-500" | ||
name={props.name} | ||
placeholder={props.placeholder} | ||
value={props.value} | ||
onChange={props.onChange} | ||
/> | ||
</div> | ||
); |
This file contains 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,10 @@ | ||
import { useState } from 'react'; | ||
|
||
export const useModal = () => { | ||
const [isOpen, setIsOpen] = useState<boolean>(false); | ||
|
||
const onOpen = () => setIsOpen(true); | ||
const onClose = () => setIsOpen(false); | ||
|
||
return { isOpen, onOpen, onClose }; | ||
}; |
This file contains 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,59 @@ | ||
import React from 'react'; | ||
import { Meta, Story } from '@storybook/react'; | ||
import { useModal } from '@/hooks/useModal'; | ||
import { AuthModal } from '@/component/authmodal/AuthModal'; | ||
|
||
export default { | ||
title: 'Components/AuthModal', | ||
component: AuthModal, | ||
parameters: { | ||
layout: 'fullscreen', | ||
}, | ||
tags: ['autodocs'], | ||
} as Meta<typeof AuthModal>; | ||
|
||
const LoginModalTemplate: Story = args => { | ||
const { onClose } = useModal(); | ||
|
||
return <AuthModal {...args} onClose={onClose} />; | ||
}; | ||
|
||
const RegisterModalTemplate: Story = args => { | ||
const { onClose } = useModal(); | ||
|
||
return <AuthModal {...args} onClose={onClose} />; | ||
}; | ||
|
||
export const LoginModal = LoginModalTemplate.bind({}); | ||
LoginModal.args = { | ||
isOpen: true, | ||
type: 'login', | ||
}; | ||
LoginModal.parameters = { | ||
docs: { | ||
description: { | ||
story: '๋ก๊ทธ์ธ ๋ชจ๋ฌ ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋งํฉ๋๋ค.', | ||
}, | ||
}, | ||
backgrounds: { | ||
default: 'gray', | ||
values: [{ name: 'gray', value: '#f3f4f6' }], | ||
}, | ||
}; | ||
|
||
export const RegisterModal = RegisterModalTemplate.bind({}); | ||
RegisterModal.args = { | ||
isOpen: true, | ||
type: 'register', | ||
}; | ||
RegisterModal.parameters = { | ||
docs: { | ||
description: { | ||
story: 'ํ์๊ฐ์ ๋ชจ๋ฌ ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋งํฉ๋๋ค.', | ||
}, | ||
}, | ||
backgrounds: { | ||
default: 'gray', | ||
values: [{ name: 'gray', value: '#f3f4f6' }], | ||
}, | ||
}; |
Oops, something went wrong.