Skip to content

Commit

Permalink
Merge pull request #273 from boostcampwm-2024/feature/fe/#14-bottomsh…
Browse files Browse the repository at this point in the history
…eet-content

[FE][Feat] #14 : bottomsheet 관련 로그인, 회원가입
  • Loading branch information
juwon5272 authored Nov 26, 2024
2 parents 20f96e6 + 5fc5f04 commit b3f79c1
Show file tree
Hide file tree
Showing 7 changed files with 191 additions and 85 deletions.
10 changes: 7 additions & 3 deletions frontend/src/api/dto/auth.dto.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
export class LoginResEntity {
token: string | undefined;

userId: string | undefined;
data: {
token: string | undefined;
userId: string | undefined;
} = {
token: undefined,
userId: undefined,
};
}

export class RegisterResEntity {
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/api/dto/channel.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ export class channelListEntity {
name: string | undefined;

generated_at: string | undefined;

guest_count: number | undefined;
}

export class getUserChannelsResEntity {
Expand Down
24 changes: 16 additions & 8 deletions frontend/src/component/authmodal/AuthModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export const AuthModal = (props: IAuthModalProps) => {
});

const [modalType, setModalType] = useState<'login' | 'register'>(props.type);
const [error, setError] = useState('');

const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target;
Expand All @@ -46,42 +47,46 @@ export const AuthModal = (props: IAuthModalProps) => {
};

const switchToRegister = () => {
setError('');
setModalType('register');
};

const switchToLogin = () => {
setError('');
setModalType('login');
};

const handleLoginClick = () => {
doLogin(loginData.id, loginData.pw)
.then(el => {
if (el.data?.token && el.data?.userId) {
saveLocalData(AppConfig.KEYS.LOGIN_TOKEN, el.data.token);
saveLocalData(AppConfig.KEYS.LOGIN_USER, el.data.userId);
if (el.data?.data.token && el.data?.data.userId) {
saveLocalData(AppConfig.KEYS.LOGIN_TOKEN, el.data?.data.token);
saveLocalData(AppConfig.KEYS.LOGIN_USER, el.data?.data.userId);
}
setError('');
props.onClose();

window.location.reload();
})
.catch(() => {
alert('아이디와 비밀번호를 다시 확인해주세요.');
setError('아이디 혹은 비밀번호를 다시 확인해주세요.');
});
};

const handleSignUpClick = () => {
if (registerData.pw !== registerData.confirmPw) {
alert('비밀번호가 일치하지 않습니다.');
setError('비밀번호가 일치하지 않습니다.');
return;
}
doRegister(registerData.id, registerData.name, registerData.pw, registerData.email)
.then(el => {
if (el.data) {
alert('회원가입에 성공했습니다. 로그인해주세요.');
switchToLogin();
}
})
.catch(() => {
alert(
'회원가입에 실패했습니다. 다시 확인해주세요.\nid는 4자 이상, 비밀번호는 6자리 이상이어야 합니다.',
setError(
`회원가입에 실패했습니다. 다시 확인해주세요.\nid는 4자 이상, 비밀번호는 6자리 이상이어야 합니다.`,
);
});
};
Expand All @@ -105,6 +110,7 @@ export const AuthModal = (props: IAuthModalProps) => {
value={loginData.pw}
onChange={handleChange}
/>
{error ? <p className="pt-2 text-sm font-normal text-red-500">{error}</p> : ''}
<Modal.Footer
text="로그인"
onClick={handleLoginClick}
Expand Down Expand Up @@ -150,6 +156,8 @@ export const AuthModal = (props: IAuthModalProps) => {
value={registerData.confirmPw}
onChange={handleChange}
/>
{error ? <p className="pt-2 text-sm font-normal text-red-500">{error}</p> : ''}

<Modal.Footer
text="회원가입"
onClick={handleSignUpClick}
Expand Down
101 changes: 67 additions & 34 deletions frontend/src/component/bottomsheet/BottomSheet.tsx
Original file line number Diff line number Diff line change
@@ -1,53 +1,86 @@
import React from 'react';
import { useBottomSheet } from '@/hooks/useBottomSheet';
import React, { useState, useRef } from 'react';

interface IBottomSheetProps {
minHeight: number;
maxHeight: number;
backgroundColor: string;
children: React.ReactNode;
}

/**
* `BottomSheet` 컴포넌트는 하단에서 올라오는 시트 형태의 UI를 제공합니다.
*
* @param {IBottomSheetProps} props - `children`을 포함한 컴포넌트 속성
* @param {number} props.minHeight - Bottom Sheet의 최소 높이를 화면 비율로 나타냅니다 (0.0 - 1.0).
* @param {number} props.maxHeight - Bottom Sheet의 최대 높이를 화면 비율로 나타냅니다 (0.0 - 1.0).
* @param {ReactNode} props.children - Bottom Sheet 내부에 렌더링할 콘텐츠입니다.
* @returns {ReactNode} - 하단 시트를 렌더링합니다.
*
* @remarks
* - 드래그 동작을 통해 시트를 열고 닫을 수 있습니다.
* - `useBottomSheet` 훅을 사용하여 위치 및 드래그 동작을 관리합니다.
* - `minHeight`는 Bottom Sheet가 닫힌 상태의 높이 비율을 나타냅니다.
* - `maxHeight`는 Bottom Sheet가 열린 상태의 최대 높이 비율을 나타냅니다.
*
* @example
* ```tsx
* <BottomSheet minHeight={0.5} maxHeight={0.85}>
* <div className="p-4">
* <h2>예시 콘텐츠</h2>
* <p>BottomSheet의 children</p>
* </div>
* </BottomSheet>
* ```
*/

export const BottomSheet = (props: IBottomSheetProps) => {
const { sheet } = useBottomSheet({ minHeight: props.minHeight, maxHeight: props.maxHeight });
export const BottomSheet = ({
minHeight,
maxHeight,
backgroundColor,
children,
}: IBottomSheetProps) => {
const [sheetHeight, setSheetHeight] = useState(minHeight);
const startY = useRef(0);
const startHeight = useRef(minHeight);

const handleStart = (y: number) => {
startY.current = y;
startHeight.current = sheetHeight;
};

const handleMove = (y: number) => {
const deltaY = startY.current - y;
const newHeight = startHeight.current + deltaY / window.innerHeight;
setSheetHeight(Math.max(minHeight, Math.min(maxHeight, newHeight)));
};

const handleTouchStart = (e: React.TouchEvent) => {
handleStart(e.touches[0].clientY);
};

const handleTouchMove = (e: React.TouchEvent) => {
handleMove(e.touches[0].clientY);
};

const handleMouseMove = (e: MouseEvent) => {
handleMove(e.clientY);
};

const handleMouseUp = () => {
window.removeEventListener('mousemove', handleMouseMove);
window.removeEventListener('mouseup', handleMouseUp);
};

const handleMouseDown = (e: React.MouseEvent) => {
handleStart(e.clientY);
window.addEventListener('mousemove', handleMouseMove);
window.addEventListener('mouseup', handleMouseUp);
};

const handleClose = () => {
setSheetHeight(minHeight);
};

return (
<div
ref={sheet}
className="bg-grayscale-25 shadow-dark fixed left-0 right-0 z-[1000] flex h-full flex-col rounded-t-lg transition-transform duration-700"
className="fixed bottom-0 left-0 right-0 z-50 rounded-t-2xl bg-white shadow-lg transition-transform duration-700 ease-out"
style={{
top: `calc(100% - ${props.minHeight * 100}%)`,
backgroundColor: `${backgroundColor}`,
height: `${sheetHeight * 100}vh`,
transform: `translateY(${(1 - sheetHeight) * 100}%)`,
}}
onTouchStart={handleTouchStart}
onTouchMove={handleTouchMove}
onMouseDown={handleMouseDown}
>
<div className="flex items-center justify-center pb-1 pt-2">
<div className="h-1.5 w-12 rounded-full bg-gray-300" />
</div>
{props.children}
<div className="flex items-center justify-end pb-1 pr-5 pt-2">
<button
type="button"
className="bg-grayscale-180 h-[30px] w-[30px] rounded-full text-lg font-semibold text-gray-500"
onClick={handleClose}
>
<p className="text-grayscale-850"></p>
</button>
</div>

<div className="h-full overflow-auto">{children}</div>
</div>
);
};
17 changes: 14 additions & 3 deletions frontend/src/component/content/Content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { useNavigate } from 'react-router-dom';

interface IContentProps {
title: string;
time: string;
person: number;
link: string;
time: string;
}

/**
Expand All @@ -30,6 +30,16 @@ interface IContentProps {
*/

export const Content = (props: IContentProps) => {
const formattedDate = new Date(props.time).toLocaleDateString('ko-KR', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
});

const formattedTime = new Date(props.time).toLocaleTimeString('ko-KR', {
hour: '2-digit',
minute: '2-digit',
});
const navigate = useNavigate();
return (
<div
Expand All @@ -41,8 +51,9 @@ export const Content = (props: IContentProps) => {
<div>
<header className="border-gray-200 pb-1 text-lg">{props.title}</header>
<section className="flex items-center text-sm leading-5 text-gray-500">
<time className="mr-4">시간</time>
<span className="mr-6">{props.time}</span>
<time className="mr-4">
{formattedDate} {formattedTime}
</time>
{props.person > 0 && (
<>
<MdGroup className="mr-2 h-5 w-5" aria-label="인원수 아이콘" />
Expand Down
Loading

0 comments on commit b3f79c1

Please sign in to comment.