Skip to content

Commit

Permalink
Merge pull request #375 from boostcampwm-2024/feature/fe/#374-HostVie…
Browse files Browse the repository at this point in the history
…w-Ordered-List

[FE][Feat] #374 : HostView 사용자 정렬 기능 구현
  • Loading branch information
effozen authored Dec 3, 2024
2 parents d4c89d4 + 97d4144 commit c475db4
Show file tree
Hide file tree
Showing 14 changed files with 157 additions and 119 deletions.
2 changes: 1 addition & 1 deletion frontend/src/assets/endmarker.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion frontend/src/assets/footprint.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion frontend/src/assets/mylocation.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion frontend/src/assets/startmarker.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 8 additions & 5 deletions frontend/src/component/common/dropdown/Dropdown.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { ReactNode } from 'react';
import { ReactNode, useMemo } from 'react';
import { v4 as uuidv4 } from 'uuid';
import { DropdownTrigger } from '@/component/common/dropdown/DropdownTrigger.tsx';
import { DropdownItem } from '@/component/common/dropdown/DropdownItem.tsx';
import { DropdownMenu } from '@/component/common/dropdown/DropdownMenu.tsx';
import { ToggleProvider } from '@/component/common/dropdown/DropdownContext.tsx';
import { DropdownInstanceContext } from '@/context/DropdownInstanceContext';

interface IDropdownProps {
/** 드롭다운 컴포넌트 내부에 들어갈 컨텐츠 */
Expand Down Expand Up @@ -34,10 +35,12 @@ interface IDropdownProps {
*/

export const Dropdown = (props: IDropdownProps) => {
const id = useMemo(() => uuidv4(), []); // 각 Dropdown 인스턴스에 고유 ID 생성

return (
<aside className="relative flex w-fit flex-col">
<ToggleProvider>{props.children}</ToggleProvider>
</aside>
<DropdownInstanceContext.Provider value={id}>
<aside className="relative flex w-fit flex-col">{props.children}</aside>
</DropdownInstanceContext.Provider>
);
};

Expand Down
25 changes: 0 additions & 25 deletions frontend/src/component/common/dropdown/DropdownContext.tsx

This file was deleted.

18 changes: 12 additions & 6 deletions frontend/src/component/common/dropdown/DropdownMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ReactNode, useContext, useRef, useEffect } from 'react';
import classNames from 'classnames';
import { ToggleContext } from '@/component/common/dropdown/DropdownContext';
import { ToggleContext } from '@/context/DropdownContext.tsx';
import { DropdownInstanceContext } from '@/context/DropdownInstanceContext';

interface IDropdownMenuProps {
/** 드롭다운 메뉴가 열려있는지 여부 */
Expand All @@ -27,7 +28,9 @@ interface IDropdownMenuProps {
*/

export const DropdownMenu = (props: IDropdownMenuProps) => {
const { isOpen, toggle } = useContext(ToggleContext);
const { openDropdownId, setOpenDropdownId } = useContext(ToggleContext);
const dropdownId = useContext(DropdownInstanceContext);
const isOpen = openDropdownId === dropdownId;
const ref = useRef<HTMLUListElement | null>(null);

const handleOutSideClick = (event: MouseEvent) => {
Expand All @@ -43,23 +46,26 @@ export const DropdownMenu = (props: IDropdownMenuProps) => {
!ref.current.contains(target) &&
target.dataset.component !== 'DropdownTrigger'
) {
toggle();
setOpenDropdownId(null); // 외부 클릭 시 드롭다운 닫기
}
};

useEffect(() => {
document.addEventListener('click', handleOutSideClick);
if (isOpen) {
document.addEventListener('click', handleOutSideClick);
} else {
document.removeEventListener('click', handleOutSideClick);
}
return () => {
document.removeEventListener('click', handleOutSideClick);
};
}, []);
}, [isOpen]);

return (
isOpen && (
<ul
ref={ref}
className={classNames(
// 추후 애니메이션 조건부 적용을 위해서 classNames 사용
'align-center',
'animate-smoothAppear',
'absolute',
Expand Down
13 changes: 10 additions & 3 deletions frontend/src/component/common/dropdown/DropdownTrigger.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ReactNode, useContext } from 'react';
import classNames from 'classnames';
import { ToggleContext } from '@/component/common/dropdown/DropdownContext';
import { ToggleContext } from '@/context/DropdownContext.tsx';
import { DropdownInstanceContext } from '@/context/DropdownInstanceContext';

interface IDropdownTriggerProps {
/** 버튼 내부에 들어갈 컨텐츠 */
Expand Down Expand Up @@ -28,10 +29,16 @@ interface IDropdownTriggerProps {
*/

export const DropdownTrigger = (props: IDropdownTriggerProps) => {
const { toggle } = useContext(ToggleContext);
const { openDropdownId, setOpenDropdownId } = useContext(ToggleContext);
const dropdownId = useContext(DropdownInstanceContext);
const isOpen = openDropdownId === dropdownId;

const handleOnClick = () => {
toggle();
if (isOpen) {
setOpenDropdownId(null); // 이미 열려 있으면 닫기
} else {
setOpenDropdownId(dropdownId); // 이 드롭다운 열기
}
};

return (
Expand Down
3 changes: 1 addition & 2 deletions frontend/src/component/content/Content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ export const Content = (props: IContentProps) => {
className="relative flex w-full flex-row items-center justify-between px-4 py-5"
onClick={goToHostViewPage}
>
{/* <div className="relative flex w-full flex-row justify-between px-4 py-5"> */}
<div>
<header className="border-gray-200 pb-1 text-start text-base font-normal">
{props.title}
Expand All @@ -102,7 +101,7 @@ export const Content = (props: IContentProps) => {
<div
className="relative"
onClick={e => {
e.stopPropagation();
e.stopPropagation(); // 부모의 onClick 이벤트 방지
}}
>
<Dropdown>
Expand Down
25 changes: 14 additions & 11 deletions frontend/src/component/layout/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,24 @@ import { Outlet } from 'react-router-dom';
import { LayoutHeader } from '@/component/layout/header/LayoutHeader.tsx';
import { HeaderDropdownProvider } from '@/component/header/HeaderDropdownProvider.tsx';
import { LayoutFooterProvider } from '@/component/layout/footer/LayoutFooterProvider';
import { ToggleProvider } from '@/context/DropdownContext.tsx';
import { LayoutFooter } from './footer/LayoutFooter';

export const Layout = () => {
return (
<HeaderDropdownProvider>
<main>
{/* LayoutHeader는 HeaderContext를 사용하므로 LayoutHeaderProvider로 감쌈 */}
<LayoutHeader />
<ToggleProvider>
<HeaderDropdownProvider>
<main>
{/* LayoutHeader는 HeaderContext를 사용하므로 LayoutHeaderProvider로 감쌈 */}
<LayoutHeader />

{/* LayoutFooterProvider로 Outlet을 감싸서 FooterContext도 제공 */}
<LayoutFooterProvider>
<Outlet />
<LayoutFooter />
</LayoutFooterProvider>
</main>
</HeaderDropdownProvider>
{/* LayoutFooterProvider로 Outlet을 감싸서 FooterContext도 제공 */}
<LayoutFooterProvider>
<Outlet />
<LayoutFooter />
</LayoutFooterProvider>
</main>
</HeaderDropdownProvider>
</ToggleProvider>
);
};
24 changes: 24 additions & 0 deletions frontend/src/context/DropdownContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// DropdownContext.tsx
import { createContext, ReactNode, useState, useMemo } from 'react';

export interface IToggleContext {
openDropdownId: string | null;
setOpenDropdownId: (id: string | null) => void;
}

interface IToggleProviderProps {
children: ReactNode;
}

export const ToggleContext = createContext<IToggleContext>({
openDropdownId: null,
setOpenDropdownId: () => {},
});

export const ToggleProvider = ({ children }: IToggleProviderProps) => {
const [openDropdownId, setOpenDropdownId] = useState<string | null>(null);

const value = useMemo(() => ({ openDropdownId, setOpenDropdownId }), [openDropdownId]);

return <ToggleContext.Provider value={value}>{children}</ToggleContext.Provider>;
};
3 changes: 3 additions & 0 deletions frontend/src/context/DropdownInstanceContext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { createContext } from 'react';

export const DropdownInstanceContext = createContext<string | null>(null);
14 changes: 14 additions & 0 deletions frontend/src/pages/HostView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,20 @@ export const HostView = () => {
.then(res => {
if (!res.data) throw new Error('🚀 Fetch Error: responsed undefined');
const transfromedData = transformTypeFromResToInfo(res.data);

const orderedGuest: IGuest[] = [];

markerDefaultColor.forEach(color => {
const guest = transfromedData.guests.find(
guestData => guestData.markerStyle.color === color,
);
if (guest) {
orderedGuest.push(guest);
}
});

transfromedData.guests = orderedGuest;

setChannelInfo(transfromedData);
})
.catch((err: any) => {
Expand Down
Loading

0 comments on commit c475db4

Please sign in to comment.