-
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.
- 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.