From 8e4844483dc135b5bd03ba6e690d625abc02c218 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EB=8F=99=EC=9C=A8?= Date: Thu, 28 Nov 2024 17:50:22 +0900 Subject: [PATCH 1/7] =?UTF-8?q?[Feat][FE]=20#301=20:=20Header=20=EB=A6=AC?= =?UTF-8?q?=ED=8C=A9=ED=86=A0=EB=A7=81=20=EA=B5=AC=EC=A1=B0=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/component/header/HeaderLayout.tsx | 56 +++++++++++++ .../component/header/constatnt/HeaderEnums.ts | 5 ++ .../component/header/constatnt/HeaderType.ts | 8 ++ .../component/layout/constant/HeaderConst.ts | 20 ++--- .../component/layout/header/LayoutHeader.tsx | 28 +++---- frontend/src/context/HeaderButtonContext.tsx | 52 ++++++++++++ frontend/src/pages/AddChannel.tsx | 13 ++- frontend/src/routes/IndexRoutes.tsx | 79 ++++++++++--------- 8 files changed, 196 insertions(+), 65 deletions(-) create mode 100644 frontend/src/component/header/HeaderLayout.tsx create mode 100644 frontend/src/component/header/constatnt/HeaderEnums.ts create mode 100644 frontend/src/component/header/constatnt/HeaderType.ts create mode 100644 frontend/src/context/HeaderButtonContext.tsx diff --git a/frontend/src/component/header/HeaderLayout.tsx b/frontend/src/component/header/HeaderLayout.tsx new file mode 100644 index 00000000..fc55c518 --- /dev/null +++ b/frontend/src/component/header/HeaderLayout.tsx @@ -0,0 +1,56 @@ +import React, { ReactNode } from 'react'; +import classNames from 'classnames'; +// import { IGuestData } from '@/types/channel.types.ts'; +import { HeaderIcon } from './constatnt/HeaderEnums'; +import { HeaderIconType } from './constatnt/HeaderType'; + +interface IHeaderProps { + leftButton?: HeaderIcon; + leftButtonOnclick?: () => void; + rightButton?: HeaderIcon; + rightButtonOnclick?: () => void; + title?: ReactNode; + subtitle?: string; + // items?: IGuestData[]; + className?: string; + userName?: string; +} + +export const HeaderLayout = (props: IHeaderProps) => { + return ( +
+
+
+ +
+
{props.userName}
+
{props.title}
+
+
+ +
+
{props.subtitle}
+
+ ); +}; diff --git a/frontend/src/component/header/constatnt/HeaderEnums.ts b/frontend/src/component/header/constatnt/HeaderEnums.ts new file mode 100644 index 00000000..24cd1e64 --- /dev/null +++ b/frontend/src/component/header/constatnt/HeaderEnums.ts @@ -0,0 +1,5 @@ +export enum HeaderIcon { + BACK = 'BACK', + MENU = 'MENU', + LOGOUT = 'LOGOUT', +} diff --git a/frontend/src/component/header/constatnt/HeaderType.ts b/frontend/src/component/header/constatnt/HeaderType.ts new file mode 100644 index 00000000..48e26c9f --- /dev/null +++ b/frontend/src/component/header/constatnt/HeaderType.ts @@ -0,0 +1,8 @@ +import { LuChevronLeft } from 'react-icons/lu'; +import { MdFormatListBulleted, MdLogout } from 'react-icons/md'; + +export const HeaderIconType = { + BACK: LuChevronLeft, + MENU: MdFormatListBulleted, + LOGOUT: MdLogout, +}; diff --git a/frontend/src/component/layout/constant/HeaderConst.ts b/frontend/src/component/layout/constant/HeaderConst.ts index a8fa427c..38583cab 100644 --- a/frontend/src/component/layout/constant/HeaderConst.ts +++ b/frontend/src/component/layout/constant/HeaderConst.ts @@ -1,3 +1,5 @@ +import { HeaderIcon } from '@/component/header/constatnt/HeaderEnums'; + export const HEADER_TITLE: Record = { '/add-channel/:user/draw': '에 따른 경로 설정', }; @@ -6,15 +8,15 @@ export const HEADER_SUBTITLE: Record = { '/add-channel/:user/draw': '사용자 별로 출발지/도착지(마커), 경로(그림)을 설정할 수 있습니다', }; -export const HEADER_LEFTBUTTON: Record = { - '/add-channel': 'back', - '/add-channel/:user': 'back', - '/add-channel/:user/draw': 'back', - '/channel/:channelId/host': 'back', - '/update-channel': 'back', - '/register': 'back', +export const HEADER_LEFTBUTTON: Record = { + '/add-channel': HeaderIcon.BACK, + '/add-channel/:user': HeaderIcon.BACK, + '/add-channel/:user/draw': HeaderIcon.BACK, + '/channel/:channelId/host': HeaderIcon.BACK, + '/update-channel': HeaderIcon.BACK, + '/register': HeaderIcon.BACK, }; -export const HEADER_RIGHTBUTTON: Record = { - '/channel/:channelId/host': 'dropdown', +export const HEADER_RIGHTBUTTON: Record = { + '/channel/:channelId/host': HeaderIcon.MENU, }; diff --git a/frontend/src/component/layout/header/LayoutHeader.tsx b/frontend/src/component/layout/header/LayoutHeader.tsx index 69168592..d51950c3 100644 --- a/frontend/src/component/layout/header/LayoutHeader.tsx +++ b/frontend/src/component/layout/header/LayoutHeader.tsx @@ -1,25 +1,25 @@ -import { Header } from '@/component/header/Header'; -import { NoticeText } from '@/component/text/NoticeText'; import { useLocation, useParams } from 'react-router-dom'; import { getHeaderInfo } from '@/utils/mapping/HeaderMapping'; +import { HeaderLayout } from '@/component/header/HeaderLayout'; +import { useContext } from 'react'; +import { HeaderButtonContext } from '@/context/HeaderButtonContext'; export const LayoutHeader = () => { const params = useParams>(); const urlPath = useLocation(); const headerOption = getHeaderInfo(urlPath.pathname); + const { leftButtonOnclick, rightButtonOnclick } = useContext(HeaderButtonContext); return ( -
- - {headerOption.subtitle && ( - - {headerOption.subtitle} - - )} -
+ ); }; diff --git a/frontend/src/context/HeaderButtonContext.tsx b/frontend/src/context/HeaderButtonContext.tsx new file mode 100644 index 00000000..e06e3739 --- /dev/null +++ b/frontend/src/context/HeaderButtonContext.tsx @@ -0,0 +1,52 @@ +import { createContext, useState, ReactNode, useMemo, useCallback } from 'react'; + +interface IHeaderButtonProps { + children: ReactNode; +} + +// 버튼 클릭 이벤트 타입 정의 +interface IHeaderButtonContextType { + leftButtonOnclick: () => void; + rightButtonOnclick: () => void; + setLeftButtonOnclick: (fn: () => void) => void; + setRightButtonOnclick: (fn: () => void) => void; + resetButtonContext: () => void; +} + +const defaultButtonContext: IHeaderButtonContextType = { + leftButtonOnclick: () => {}, + rightButtonOnclick: () => {}, + setLeftButtonOnclick: () => {}, + setRightButtonOnclick: () => {}, + resetButtonContext: () => {}, +}; + +export const HeaderButtonContext = createContext(defaultButtonContext); + +export const HeaderButtonProvider = (props: IHeaderButtonProps) => { + const [leftButtonOnclick, setLeftButtonOnclick] = useState<() => void>(() => () => {}); + const [rightButtonOnclick, setRightButtonOnclick] = useState<() => void>(() => () => {}); + + const setLeft = useCallback((fn: () => void) => setLeftButtonOnclick(() => fn), []); + const setRight = useCallback((fn: () => void) => setRightButtonOnclick(() => fn), []); + + const resetButtonContext = useCallback(() => { + setLeftButtonOnclick(() => () => {}); + setRightButtonOnclick(() => () => {}); + }, []); + + const value = useMemo( + () => ({ + leftButtonOnclick, + rightButtonOnclick, + setLeftButtonOnclick: setLeft, + setRightButtonOnclick: setRight, + resetButtonContext, + }), + [leftButtonOnclick, rightButtonOnclick, setLeft, setRight, resetButtonContext], + ); + + return ( + {props.children} + ); +}; diff --git a/frontend/src/pages/AddChannel.tsx b/frontend/src/pages/AddChannel.tsx index 140a0044..ecc4ad72 100644 --- a/frontend/src/pages/AddChannel.tsx +++ b/frontend/src/pages/AddChannel.tsx @@ -9,6 +9,7 @@ import { buttonActiveType } from '@/component/layout/enumTypes'; import { createChannelReqEntity } from '@/api/dto/channel.dto'; import { createChannel } from '@/api/channel.api'; import { Page } from '@/component/routebutton/enum'; +import { HeaderButtonContext } from '@/context/HeaderButtonContext'; import { InputBox } from '../component/common/InputBox'; /** @@ -46,7 +47,13 @@ export const AddChannel = () => { setFooterOnClick, resetFooterContext, } = useContext(FooterContext); + const { setLeftButtonOnclick, resetButtonContext } = useContext(HeaderButtonContext); const navigate = useNavigate(); + const goToMainPage = () => { + navigate('/'); + resetFooterContext(); + resetButtonContext(); + }; /** * 사용자 추가 함수 @@ -126,6 +133,7 @@ export const AddChannel = () => { setFooterTitle('제작 완료'); setFooterTransparency(false); setFooterActive(buttonActiveType.PASSIVE); + setLeftButtonOnclick(goToMainPage); }, []); useEffect(() => { @@ -169,10 +177,7 @@ export const AddChannel = () => { console.error('채널 생성 실패:', error); } }; - const goToMainPage = () => { - navigate('/'); - resetFooterContext(); - }; + useEffect(() => { setFooterOnClick(() => { createChannelAPI(); diff --git a/frontend/src/routes/IndexRoutes.tsx b/frontend/src/routes/IndexRoutes.tsx index 1600e3a1..4015c553 100644 --- a/frontend/src/routes/IndexRoutes.tsx +++ b/frontend/src/routes/IndexRoutes.tsx @@ -10,59 +10,62 @@ import { CurrentUserProvider } from '@/context/CurrentUserContext'; import { ChannelInfoPage } from '@/pages/ChannelInfoPage'; // ChannelInfoPage 컴포넌트 임포트 import { ChannelProvider } from '@/context/ChannelContext'; import { RequireAuth } from '@/routes/RequireAuth.tsx'; +import { HeaderButtonProvider } from '@/context/HeaderButtonContext'; export const IndexRoutes = () => ( - - - - - }> - } /> - - - - - } - /> - + + + + + + }> + } /> + - + } /> + + + + + } + /> + - - - {/* channelInfo 페이지 경로 설정 */} - - - - } - /> - + {/* channelInfo 페이지 경로 설정 */} - + } /> - } /> + + + + + + } + /> + } /> + - - - - - + + + + + ); From 996c47cd91734fd47909b187e008bb862e809658 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EB=8F=99=EC=9C=A8?= Date: Thu, 28 Nov 2024 18:08:52 +0900 Subject: [PATCH 2/7] =?UTF-8?q?[FE][Feat]=20#301=20:=20Header=20=EB=A6=AC?= =?UTF-8?q?=ED=8C=A9=ED=86=A0=EB=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../component/layout/constant/HeaderConst.ts | 3 +++ .../component/layout/header/LayoutHeader.tsx | 4 ++-- frontend/src/pages/AddChannel.tsx | 18 ++++++++++-------- frontend/src/pages/AddGuestPage.tsx | 11 +++++++++++ frontend/src/pages/ChannelInfoPage.tsx | 10 ++++++++++ frontend/src/pages/DrawRoute.tsx | 10 ++++++++-- frontend/src/pages/GuestView.tsx | 13 ++++++++++--- frontend/src/pages/HostView.tsx | 11 +++++++++-- frontend/src/utils/mapping/HeaderMapping.ts | 2 ++ 9 files changed, 65 insertions(+), 17 deletions(-) diff --git a/frontend/src/component/layout/constant/HeaderConst.ts b/frontend/src/component/layout/constant/HeaderConst.ts index 38583cab..f9442f6a 100644 --- a/frontend/src/component/layout/constant/HeaderConst.ts +++ b/frontend/src/component/layout/constant/HeaderConst.ts @@ -9,12 +9,15 @@ export const HEADER_SUBTITLE: Record = { }; export const HEADER_LEFTBUTTON: Record = { + // '/': HeaderIcon.LOGOUT, '/add-channel': HeaderIcon.BACK, '/add-channel/:user': HeaderIcon.BACK, '/add-channel/:user/draw': HeaderIcon.BACK, '/channel/:channelId/host': HeaderIcon.BACK, '/update-channel': HeaderIcon.BACK, '/register': HeaderIcon.BACK, + '/channelInfo/:channelId': HeaderIcon.BACK, + '/guest-add-channel/:channelId': HeaderIcon.BACK, }; export const HEADER_RIGHTBUTTON: Record = { diff --git a/frontend/src/component/layout/header/LayoutHeader.tsx b/frontend/src/component/layout/header/LayoutHeader.tsx index d51950c3..9f55bb84 100644 --- a/frontend/src/component/layout/header/LayoutHeader.tsx +++ b/frontend/src/component/layout/header/LayoutHeader.tsx @@ -14,8 +14,8 @@ export const LayoutHeader = () => { { setFooterOnClick, resetFooterContext, } = useContext(FooterContext); - // const { setLeftButtonOnclick, resetButtonContext } = useContext(HeaderButtonContext); + const { setLeftButtonOnclick, resetButtonContext } = useContext(HeaderButtonContext); const navigate = useNavigate(); + const goToMainPage = () => { + navigate('/'); + resetFooterContext(); + resetUsers(); + resetButtonContext(); + }; /** * 사용자 추가 함수 @@ -128,7 +134,7 @@ export const AddChannel = () => { setFooterTitle('제작 완료'); setFooterTransparency(false); setFooterActive(buttonActiveType.PASSIVE); - // setLeftButtonOnclick(goToMainPage); + setLeftButtonOnclick(goToMainPage); }, []); useEffect(() => { @@ -175,11 +181,7 @@ export const AddChannel = () => { console.error('채널 생성 실패:', error); } }; - const goToMainPage = () => { - navigate('/'); - resetFooterContext(); - resetUsers(); - }; + useEffect(() => { setFooterOnClick(() => { createChannelAPI(); diff --git a/frontend/src/pages/AddGuestPage.tsx b/frontend/src/pages/AddGuestPage.tsx index 7cfce20c..854ff68e 100644 --- a/frontend/src/pages/AddGuestPage.tsx +++ b/frontend/src/pages/AddGuestPage.tsx @@ -10,6 +10,7 @@ import { addChannelReqEntity, guestEntity } from '@/api/dto/channel.dto'; import { addGuestChannel } from '@/api/channel.api'; import { Page } from '@/component/routebutton/enum'; import { ChannelContext } from '@/context/ChannelContext'; +import { HeaderButtonContext } from '@/context/HeaderButtonContext'; import { InputBox } from '../component/common/InputBox'; /** @@ -30,11 +31,20 @@ export const AddGuestPage = () => { resetFooterContext, footerOption, } = useContext(FooterContext); + const { setLeftButtonOnclick, resetButtonContext } = useContext(HeaderButtonContext); const navigate = useNavigate(); + const goToPrevPage = () => { + navigate(-1); + resetFooterContext(); + resetUsers(); + resetButtonContext(); + }; + const goToMainPage = () => { navigate('/', { replace: true }); resetFooterContext(); resetUsers(); + resetButtonContext(); }; // marker 색상과 인덱스를 매핑하는 객체 @@ -164,6 +174,7 @@ export const AddGuestPage = () => { const initialGuests = convertGuestsToUsers(channelInfo.guests); setGuests(initialGuests); } + setLeftButtonOnclick(goToPrevPage); }, []); // 모든 사용자가 데이터를 완료했는지 확인하여 Footer 활성화 여부 결정 diff --git a/frontend/src/pages/ChannelInfoPage.tsx b/frontend/src/pages/ChannelInfoPage.tsx index 92a45215..82e12b67 100644 --- a/frontend/src/pages/ChannelInfoPage.tsx +++ b/frontend/src/pages/ChannelInfoPage.tsx @@ -7,6 +7,7 @@ import { Page } from '@/component/routebutton/enum'; import { ChannelContext } from '@/context/ChannelContext'; import { IUser, UserContext } from '@/context/UserContext'; import { guestEntity } from '@/api/dto/channel.dto'; +import { HeaderButtonContext } from '@/context/HeaderButtonContext'; import { InputBox } from '../component/common/InputBox'; const Divider = () =>
; @@ -15,10 +16,19 @@ export const ChannelInfoPage = () => { const { channelInfo } = useContext(ChannelContext); const { setFooterTransparency, resetFooterContext } = useContext(FooterContext); const { resetUsers } = useContext(UserContext); + const { setLeftButtonOnclick, resetButtonContext } = useContext(HeaderButtonContext); const navigate = useNavigate(); + const goToMainPage = () => { + navigate('/'); + resetFooterContext(); + resetUsers(); + resetButtonContext(); + }; + useEffect(() => { setFooterTransparency(true); + setLeftButtonOnclick(goToMainPage); }, []); const goToAddChannelPage = () => { diff --git a/frontend/src/pages/DrawRoute.tsx b/frontend/src/pages/DrawRoute.tsx index 1bd17afc..27a82945 100644 --- a/frontend/src/pages/DrawRoute.tsx +++ b/frontend/src/pages/DrawRoute.tsx @@ -7,16 +7,21 @@ import { buttonActiveType } from '@/component/layout/enumTypes'; import { MapProviderForDraw } from '@/component/canvasWithMap/canvasWithMapforDraw/MapProviderForDraw.tsx'; import { CurrentUserContext } from '@/context/CurrentUserContext'; import { getAddressFromCoordinates } from '@/utils/map/getAddress'; +import { HeaderButtonContext } from '@/context/HeaderButtonContext'; export const DrawRoute = () => { const { users, setUsers } = useContext(UserContext); - const { setFooterTitle, setFooterActive, setFooterOnClick } = useContext(FooterContext); + const { setFooterTitle, setFooterActive, setFooterOnClick, resetFooterContext } = + useContext(FooterContext); const { currentUser, setCurrentUser } = useContext(CurrentUserContext); - const params = useParams>(); // userName을 URL 파라미터로 가져옴 + const params = useParams>(); + const { setLeftButtonOnclick, resetButtonContext } = useContext(HeaderButtonContext); const navigate = useNavigate(); const goToRoutePage = () => { navigate(-1); + resetButtonContext(); + resetFooterContext(); }; const getUser = () => { @@ -50,6 +55,7 @@ export const DrawRoute = () => { useEffect(() => { setFooterTitle('사용자 경로 추가 완료'); setFooterActive(buttonActiveType.PASSIVE); + setLeftButtonOnclick(goToRoutePage); const user = getUser(); if (user) { // userId에 따른 Tailwind 색상 클래스를 설정 diff --git a/frontend/src/pages/GuestView.tsx b/frontend/src/pages/GuestView.tsx index 7a48dbab..e8cea204 100644 --- a/frontend/src/pages/GuestView.tsx +++ b/frontend/src/pages/GuestView.tsx @@ -1,13 +1,14 @@ -import { useEffect, useState } from 'react'; +import { useContext, useEffect, useState } from 'react'; import { IGuest } from '@/types/channel.types.ts'; import { getGuestInfo } from '@/api/channel.api.ts'; -import { useLocation } from 'react-router-dom'; +import { useLocation, useNavigate } from 'react-router-dom'; import { MapCanvasForView } from '@/component/canvasWithMap/canvasWithMapForView/MapCanvasForView.tsx'; import { IPoint } from '@/lib/types/canvasInterface.ts'; import { guestEntity } from '@/api/dto/channel.dto.ts'; import { GusetMarker } from '@/component/IconGuide/GuestMarker.tsx'; import { LoadingSpinner } from '@/component/common/loadingSpinner/LoadingSpinner.tsx'; import { getUserLocation } from '@/hooks/getUserLocation.ts'; +import { HeaderButtonContext } from '@/context/HeaderButtonContext'; export const GuestView = () => { const { lat, lng, error } = getUserLocation(); @@ -19,7 +20,12 @@ export const GuestView = () => { endPoint: { lat: 0, lng: 0 }, paths: [], }); - + const { setLeftButtonOnclick, resetButtonContext } = useContext(HeaderButtonContext); + const navigate = useNavigate(); + const goToMainPage = () => { + navigate('/'); + resetButtonContext(); + }; const location = useLocation(); const transformTypeGuestEntityToIGuest = (props: guestEntity): IGuest => { @@ -55,6 +61,7 @@ export const GuestView = () => { }; useEffect(() => { + setLeftButtonOnclick(goToMainPage); fetchGuestInfo(location.pathname.split('/')[2], location.pathname.split('/')[4]); }, []); diff --git a/frontend/src/pages/HostView.tsx b/frontend/src/pages/HostView.tsx index 9c5f5460..3e442720 100644 --- a/frontend/src/pages/HostView.tsx +++ b/frontend/src/pages/HostView.tsx @@ -2,13 +2,14 @@ import { HeaderDropdownContext } from '@/component/header/HeaderDropdownProvider import { useContext, useEffect, useState } from 'react'; import { IGuest, IChannelInfo, IGuestData } from '@/types/channel.types.ts'; import { getChannelInfo } from '@/api/channel.api.ts'; -import { useLocation } from 'react-router-dom'; +import { useLocation, useNavigate } from 'react-router-dom'; import { MapCanvasForView } from '@/component/canvasWithMap/canvasWithMapForView/MapCanvasForView.tsx'; import { IGuestDataInMapProps, IPoint } from '@/lib/types/canvasInterface.ts'; import { getChannelResEntity, guestEntity } from '@/api/dto/channel.dto.ts'; import { HostMarker } from '@/component/IconGuide/HostMarker.tsx'; import { LoadingSpinner } from '@/component/common/loadingSpinner/LoadingSpinner.tsx'; import { getUserLocation } from '@/hooks/getUserLocation.ts'; +import { HeaderButtonContext } from '@/context/HeaderButtonContext'; export const HostView = () => { const { lat, lng, error } = getUserLocation(); @@ -16,6 +17,12 @@ export const HostView = () => { const [guestsData, setGuestsData] = useState([]); const [mapProps, setMapProps] = useState([]); const [clickedId, setClickedId] = useState(''); + const { setLeftButtonOnclick, resetButtonContext } = useContext(HeaderButtonContext); + const navigate = useNavigate(); + const goToMainPage = () => { + navigate('/'); + resetButtonContext(); + }; const headerDropdownContext = useContext(HeaderDropdownContext); @@ -69,7 +76,7 @@ export const HostView = () => { useEffect(() => { headerDropdownContext.setItems([{ name: '사용자 1', id: '1', markerStyle: { color: '#000' } }]); - + setLeftButtonOnclick(goToMainPage); fetchChannelInfo(location.pathname.split('/')[2]); }, []); diff --git a/frontend/src/utils/mapping/HeaderMapping.ts b/frontend/src/utils/mapping/HeaderMapping.ts index b71ed404..a803f36d 100644 --- a/frontend/src/utils/mapping/HeaderMapping.ts +++ b/frontend/src/utils/mapping/HeaderMapping.ts @@ -10,6 +10,8 @@ const normalizePath = (path: string): string => { .replace(/\/add-channel\/[^/]+\/draw$/, '/add-channel/:user/draw') // `/add-channel/사용자1/draw` → `/add-channel/:user/draw` .replace(/\/add-channel\/[^/]+$/, '/add-channel/:user') // `/add-channel/사용자1` → `/add-channel/:user` .replace(/\/channel\/[^/]+\/host$/, '/channel/:channelId/host') // `/channel/123/host` → `/channel/:channelId/host` + .replace(/\/channelInfo\/[^/]+$/, '/channelInfo/:channelId') // `/channelInfo/123` → `/channel/:channelId` + .replace(/\/guest-add-channel\/[^/]+$/, '/guest-add-channel/:channelId') // `/guest-add-channel/123` → `/guest-add-channel/:channelId` .replace(/\/channel\/[^/]+\/guest\/[^/]+$/, '/channel/:channelId/guest/:guestId') // `/channel/123/guest/456` → `/channel/:channelId/guest/:guestId` .replace(/\/$/, '/'); // 루트 경로 유지 }; From b293c0b5488275ab580b16f603f1cb8019371234 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EB=8F=99=EC=9C=A8?= Date: Mon, 2 Dec 2024 07:16:52 +0900 Subject: [PATCH 3/7] =?UTF-8?q?[FE][Feat]=20#301=20:=20Header=20Left,Right?= =?UTF-8?q?=20Items=20=EA=B5=AC=EC=A1=B0=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/component/header/HeaderLayout.tsx | 38 ++++------- .../component/layout/constant/HeaderConst.ts | 27 ++++---- .../component/layout/header/LayoutHeader.tsx | 10 +-- frontend/src/context/HeaderButtonContext.tsx | 52 -------------- frontend/src/pages/AddChannel.tsx | 4 -- frontend/src/pages/AddGuestPage.tsx | 15 +---- frontend/src/pages/ChannelInfoPage.tsx | 10 --- frontend/src/pages/DrawRoute.tsx | 4 -- frontend/src/routes/IndexRoutes.tsx | 67 +++++++++---------- frontend/src/utils/mapping/HeaderMapping.ts | 12 ++-- 10 files changed, 70 insertions(+), 169 deletions(-) delete mode 100644 frontend/src/context/HeaderButtonContext.tsx diff --git a/frontend/src/component/header/HeaderLayout.tsx b/frontend/src/component/header/HeaderLayout.tsx index fc55c518..45e36ecc 100644 --- a/frontend/src/component/header/HeaderLayout.tsx +++ b/frontend/src/component/header/HeaderLayout.tsx @@ -1,17 +1,11 @@ import React, { ReactNode } from 'react'; import classNames from 'classnames'; -// import { IGuestData } from '@/types/channel.types.ts'; -import { HeaderIcon } from './constatnt/HeaderEnums'; -import { HeaderIconType } from './constatnt/HeaderType'; interface IHeaderProps { - leftButton?: HeaderIcon; - leftButtonOnclick?: () => void; - rightButton?: HeaderIcon; - rightButtonOnclick?: () => void; + leftItems?: ReactNode[]; + rightItems?: ReactNode[]; title?: ReactNode; subtitle?: string; - // items?: IGuestData[]; className?: string; userName?: string; } @@ -26,29 +20,21 @@ export const HeaderLayout = (props: IHeaderProps) => { >
- + {props.leftItems && + props.leftItems.map(item => ( +
{item}
+ ))}
{props.userName}
{props.title}
- +
+ {props.rightItems && + props.rightItems.map(item => ( +
{item}
+ ))} +
{props.subtitle}
diff --git a/frontend/src/component/layout/constant/HeaderConst.ts b/frontend/src/component/layout/constant/HeaderConst.ts index f9442f6a..7092bb40 100644 --- a/frontend/src/component/layout/constant/HeaderConst.ts +++ b/frontend/src/component/layout/constant/HeaderConst.ts @@ -1,4 +1,6 @@ -import { HeaderIcon } from '@/component/header/constatnt/HeaderEnums'; +import { HeaderBackButton } from '@/component/header/HeaderBackButton'; +import { HeaderDropdown } from '@/component/header/HeaderDropdown'; +import React, { ReactNode } from 'react'; export const HEADER_TITLE: Record = { '/add-channel/:user/draw': '에 따른 경로 설정', @@ -8,18 +10,17 @@ export const HEADER_SUBTITLE: Record = { '/add-channel/:user/draw': '사용자 별로 출발지/도착지(마커), 경로(그림)을 설정할 수 있습니다', }; -export const HEADER_LEFTBUTTON: Record = { - // '/': HeaderIcon.LOGOUT, - '/add-channel': HeaderIcon.BACK, - '/add-channel/:user': HeaderIcon.BACK, - '/add-channel/:user/draw': HeaderIcon.BACK, - '/channel/:channelId/host': HeaderIcon.BACK, - '/update-channel': HeaderIcon.BACK, - '/register': HeaderIcon.BACK, - '/channelInfo/:channelId': HeaderIcon.BACK, - '/guest-add-channel/:channelId': HeaderIcon.BACK, +export const HEADER_LEFTITEMS: Record = { + '/add-channel': [React.createElement(HeaderBackButton)], + '/add-channel/:user': [React.createElement(HeaderBackButton)], + '/add-channel/:user/draw': [React.createElement(HeaderBackButton)], + '/channel/:channelId/host': [React.createElement(HeaderBackButton)], + '/update-channel': [React.createElement(HeaderBackButton)], + '/register': [React.createElement(HeaderBackButton)], + '/channelInfo/:channelId': [React.createElement(HeaderBackButton)], + '/guest-add-channel/:channelId': [React.createElement(HeaderBackButton)], }; -export const HEADER_RIGHTBUTTON: Record = { - '/channel/:channelId/host': HeaderIcon.MENU, +export const HEADER_RIGHTITEMS: Record = { + '/channel/:channelId/host': [React.createElement(HeaderDropdown)], }; diff --git a/frontend/src/component/layout/header/LayoutHeader.tsx b/frontend/src/component/layout/header/LayoutHeader.tsx index 9f55bb84..6214d645 100644 --- a/frontend/src/component/layout/header/LayoutHeader.tsx +++ b/frontend/src/component/layout/header/LayoutHeader.tsx @@ -1,25 +1,19 @@ import { useLocation, useParams } from 'react-router-dom'; import { getHeaderInfo } from '@/utils/mapping/HeaderMapping'; import { HeaderLayout } from '@/component/header/HeaderLayout'; -import { useContext } from 'react'; -import { HeaderButtonContext } from '@/context/HeaderButtonContext'; export const LayoutHeader = () => { const params = useParams>(); const urlPath = useLocation(); const headerOption = getHeaderInfo(urlPath.pathname); - const { leftButtonOnclick, rightButtonOnclick } = useContext(HeaderButtonContext); - return ( ); }; diff --git a/frontend/src/context/HeaderButtonContext.tsx b/frontend/src/context/HeaderButtonContext.tsx deleted file mode 100644 index e06e3739..00000000 --- a/frontend/src/context/HeaderButtonContext.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import { createContext, useState, ReactNode, useMemo, useCallback } from 'react'; - -interface IHeaderButtonProps { - children: ReactNode; -} - -// 버튼 클릭 이벤트 타입 정의 -interface IHeaderButtonContextType { - leftButtonOnclick: () => void; - rightButtonOnclick: () => void; - setLeftButtonOnclick: (fn: () => void) => void; - setRightButtonOnclick: (fn: () => void) => void; - resetButtonContext: () => void; -} - -const defaultButtonContext: IHeaderButtonContextType = { - leftButtonOnclick: () => {}, - rightButtonOnclick: () => {}, - setLeftButtonOnclick: () => {}, - setRightButtonOnclick: () => {}, - resetButtonContext: () => {}, -}; - -export const HeaderButtonContext = createContext(defaultButtonContext); - -export const HeaderButtonProvider = (props: IHeaderButtonProps) => { - const [leftButtonOnclick, setLeftButtonOnclick] = useState<() => void>(() => () => {}); - const [rightButtonOnclick, setRightButtonOnclick] = useState<() => void>(() => () => {}); - - const setLeft = useCallback((fn: () => void) => setLeftButtonOnclick(() => fn), []); - const setRight = useCallback((fn: () => void) => setRightButtonOnclick(() => fn), []); - - const resetButtonContext = useCallback(() => { - setLeftButtonOnclick(() => () => {}); - setRightButtonOnclick(() => () => {}); - }, []); - - const value = useMemo( - () => ({ - leftButtonOnclick, - rightButtonOnclick, - setLeftButtonOnclick: setLeft, - setRightButtonOnclick: setRight, - resetButtonContext, - }), - [leftButtonOnclick, rightButtonOnclick, setLeft, setRight, resetButtonContext], - ); - - return ( - {props.children} - ); -}; diff --git a/frontend/src/pages/AddChannel.tsx b/frontend/src/pages/AddChannel.tsx index 4efbd0cb..7ee3febc 100644 --- a/frontend/src/pages/AddChannel.tsx +++ b/frontend/src/pages/AddChannel.tsx @@ -9,7 +9,6 @@ import { buttonActiveType } from '@/component/layout/enumTypes'; import { createChannelReqEntity } from '@/api/dto/channel.dto'; import { createChannel } from '@/api/channel.api'; import { Page } from '@/component/routebutton/enum'; -import { HeaderButtonContext } from '@/context/HeaderButtonContext'; import { InputBox } from '../component/common/InputBox'; /** @@ -47,13 +46,11 @@ export const AddChannel = () => { setFooterOnClick, resetFooterContext, } = useContext(FooterContext); - const { setLeftButtonOnclick, resetButtonContext } = useContext(HeaderButtonContext); const navigate = useNavigate(); const goToMainPage = () => { navigate('/'); resetFooterContext(); resetUsers(); - resetButtonContext(); }; /** @@ -134,7 +131,6 @@ export const AddChannel = () => { setFooterTitle('제작 완료'); setFooterTransparency(false); setFooterActive(buttonActiveType.PASSIVE); - setLeftButtonOnclick(goToMainPage); }, []); useEffect(() => { diff --git a/frontend/src/pages/AddGuestPage.tsx b/frontend/src/pages/AddGuestPage.tsx index 854ff68e..05582b44 100644 --- a/frontend/src/pages/AddGuestPage.tsx +++ b/frontend/src/pages/AddGuestPage.tsx @@ -10,7 +10,6 @@ import { addChannelReqEntity, guestEntity } from '@/api/dto/channel.dto'; import { addGuestChannel } from '@/api/channel.api'; import { Page } from '@/component/routebutton/enum'; import { ChannelContext } from '@/context/ChannelContext'; -import { HeaderButtonContext } from '@/context/HeaderButtonContext'; import { InputBox } from '../component/common/InputBox'; /** @@ -31,20 +30,12 @@ export const AddGuestPage = () => { resetFooterContext, footerOption, } = useContext(FooterContext); - const { setLeftButtonOnclick, resetButtonContext } = useContext(HeaderButtonContext); - const navigate = useNavigate(); - const goToPrevPage = () => { - navigate(-1); - resetFooterContext(); - resetUsers(); - resetButtonContext(); - }; + const navigate = useNavigate(); const goToMainPage = () => { - navigate('/', { replace: true }); + navigate('/'); resetFooterContext(); resetUsers(); - resetButtonContext(); }; // marker 색상과 인덱스를 매핑하는 객체 @@ -174,11 +165,11 @@ export const AddGuestPage = () => { const initialGuests = convertGuestsToUsers(channelInfo.guests); setGuests(initialGuests); } - setLeftButtonOnclick(goToPrevPage); }, []); // 모든 사용자가 데이터를 완료했는지 확인하여 Footer 활성화 여부 결정 useEffect(() => { + console.log(users); const allUsersComplete = users?.every(isUserDataComplete); if (allUsersComplete) { setFooterActive(buttonActiveType.ACTIVE); diff --git a/frontend/src/pages/ChannelInfoPage.tsx b/frontend/src/pages/ChannelInfoPage.tsx index 8738b825..8400c206 100644 --- a/frontend/src/pages/ChannelInfoPage.tsx +++ b/frontend/src/pages/ChannelInfoPage.tsx @@ -7,7 +7,6 @@ import { Page } from '@/component/routebutton/enum'; import { ChannelContext } from '@/context/ChannelContext'; import { IUser, UserContext } from '@/context/UserContext'; import { guestEntity } from '@/api/dto/channel.dto'; -import { HeaderButtonContext } from '@/context/HeaderButtonContext'; import { InputBox } from '../component/common/InputBox'; const Divider = () =>
; @@ -16,19 +15,10 @@ export const ChannelInfoPage = () => { const { channelInfo } = useContext(ChannelContext); const { setFooterTransparency, resetFooterContext } = useContext(FooterContext); const { resetUsers } = useContext(UserContext); - const { setLeftButtonOnclick, resetButtonContext } = useContext(HeaderButtonContext); const navigate = useNavigate(); - const goToMainPage = () => { - navigate('/'); - resetFooterContext(); - resetUsers(); - resetButtonContext(); - }; - useEffect(() => { setFooterTransparency(true); - setLeftButtonOnclick(goToMainPage); }, []); const goToAddChannelPage = () => { diff --git a/frontend/src/pages/DrawRoute.tsx b/frontend/src/pages/DrawRoute.tsx index 27a82945..ab16dd54 100644 --- a/frontend/src/pages/DrawRoute.tsx +++ b/frontend/src/pages/DrawRoute.tsx @@ -7,7 +7,6 @@ import { buttonActiveType } from '@/component/layout/enumTypes'; import { MapProviderForDraw } from '@/component/canvasWithMap/canvasWithMapforDraw/MapProviderForDraw.tsx'; import { CurrentUserContext } from '@/context/CurrentUserContext'; import { getAddressFromCoordinates } from '@/utils/map/getAddress'; -import { HeaderButtonContext } from '@/context/HeaderButtonContext'; export const DrawRoute = () => { const { users, setUsers } = useContext(UserContext); @@ -15,12 +14,10 @@ export const DrawRoute = () => { useContext(FooterContext); const { currentUser, setCurrentUser } = useContext(CurrentUserContext); const params = useParams>(); - const { setLeftButtonOnclick, resetButtonContext } = useContext(HeaderButtonContext); const navigate = useNavigate(); const goToRoutePage = () => { navigate(-1); - resetButtonContext(); resetFooterContext(); }; @@ -55,7 +52,6 @@ export const DrawRoute = () => { useEffect(() => { setFooterTitle('사용자 경로 추가 완료'); setFooterActive(buttonActiveType.PASSIVE); - setLeftButtonOnclick(goToRoutePage); const user = getUser(); if (user) { // userId에 따른 Tailwind 색상 클래스를 설정 diff --git a/frontend/src/routes/IndexRoutes.tsx b/frontend/src/routes/IndexRoutes.tsx index 1f1b8816..62e9daae 100644 --- a/frontend/src/routes/IndexRoutes.tsx +++ b/frontend/src/routes/IndexRoutes.tsx @@ -20,55 +20,54 @@ export const IndexRoutes = () => ( }> } /> - + + + + } + > - - - } - /> - } /> + + + + + } + /> + + + + } + /> + - - - } - /> - - + } /> - - - - - } - /> - } /> - + } /> - - {/* 정의되지 않은 경로 라우팅 */} - } /> + + {/* 정의되지 않은 경로 라우팅 */} + } /> diff --git a/frontend/src/utils/mapping/HeaderMapping.ts b/frontend/src/utils/mapping/HeaderMapping.ts index a803f36d..238601c4 100644 --- a/frontend/src/utils/mapping/HeaderMapping.ts +++ b/frontend/src/utils/mapping/HeaderMapping.ts @@ -1,6 +1,6 @@ import { - HEADER_LEFTBUTTON, - HEADER_RIGHTBUTTON, + HEADER_LEFTITEMS, + HEADER_RIGHTITEMS, HEADER_SUBTITLE, HEADER_TITLE, } from '@/component/layout/constant/HeaderConst'; @@ -20,13 +20,13 @@ export const getHeaderInfo = (path: string) => { const normalizedPath = normalizePath(path); const title = HEADER_TITLE[normalizedPath] || ''; const subtitle = HEADER_SUBTITLE[normalizedPath] || ''; - const leftButton = HEADER_LEFTBUTTON[normalizedPath] || ''; - const rightButton = HEADER_RIGHTBUTTON[normalizedPath] || ''; + const leftItems = HEADER_LEFTITEMS[normalizedPath] || ''; + const rightItems = HEADER_RIGHTITEMS[normalizedPath] || ''; return { title, subtitle, - leftButton, - rightButton, + leftItems, + rightItems, }; }; From 9ab8aca26eac0d1ddd3fe4c529c3f057c08b964e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EB=8F=99=EC=9C=A8?= Date: Mon, 2 Dec 2024 07:27:51 +0900 Subject: [PATCH 4/7] =?UTF-8?q?[FE][Fix]=20#301=20:=20build=20=EC=98=A4?= =?UTF-8?q?=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/component/header/HeaderLayout.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/component/header/HeaderLayout.tsx b/frontend/src/component/header/HeaderLayout.tsx index 45e36ecc..136f4b96 100644 --- a/frontend/src/component/header/HeaderLayout.tsx +++ b/frontend/src/component/header/HeaderLayout.tsx @@ -1,4 +1,4 @@ -import React, { ReactNode } from 'react'; +import { ReactNode } from 'react'; import classNames from 'classnames'; interface IHeaderProps { From 2fcd6e76a2c894bc752f769ed594d37df19de781 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EB=8F=99=EC=9C=A8?= Date: Mon, 2 Dec 2024 07:32:40 +0900 Subject: [PATCH 5/7] =?UTF-8?q?[FE][Feat]=20#301=20:=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=20=EC=9D=B4=EB=8F=99=20=EC=8B=9C=20footer=20=EC=B4=88?= =?UTF-8?q?=EA=B8=B0=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/component/content/Content.tsx | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/frontend/src/component/content/Content.tsx b/frontend/src/component/content/Content.tsx index 5483e14c..f1e41187 100644 --- a/frontend/src/component/content/Content.tsx +++ b/frontend/src/component/content/Content.tsx @@ -4,6 +4,7 @@ import { getChannelInfo } from '@/api/channel.api'; import { useContext } from 'react'; import { ChannelContext } from '@/context/ChannelContext'; import { Dropdown } from '../common/dropdown/Dropdown'; +import { FooterContext } from '../layout/footer/LayoutFooterProvider'; interface IContentProps { title: string; @@ -35,6 +36,7 @@ interface IContentProps { */ export const Content = (props: IContentProps) => { + const { resetFooterContext } = useContext(FooterContext); const formattedDate = new Date(props.time).toLocaleDateString('ko-KR', { year: 'numeric', month: '2-digit', @@ -61,9 +63,15 @@ export const Content = (props: IContentProps) => { const goToChannelInfoPage = () => { if (channelInfo?.id) { navigate(`/channelInfo/${channelInfo.id}`); + resetFooterContext(); } }; + const goToHostViewPage = () => { + navigate(props.link); + resetFooterContext(); + }; + const handleUpdate = () => { getUpdateChannelInfo(); goToChannelInfoPage(); @@ -71,12 +79,7 @@ export const Content = (props: IContentProps) => { return (
-