From 605e0a3e3ade265be490a9494e6f6e13d6077aff Mon Sep 17 00:00:00 2001 From: bicochan Date: Fri, 1 Aug 2025 15:52:51 +0900 Subject: [PATCH 1/3] =?UTF-8?q?[apps/cs]=20feat:=20=ED=86=B5=ED=95=A9=20?= =?UTF-8?q?=EA=B2=80=EC=83=89=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=9E=91?= =?UTF-8?q?=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cs/app/(with-base-layout)/search/page.tsx | 2 + .../cs/src/pages/search/api/search-service.ts | 21 ++ apps/cs/src/pages/search/index.ts | 1 + .../pages/search/model/search-interface.ts | 45 ++++ apps/cs/src/pages/search/ui/search-page.tsx | 240 ++++++++++++++++++ apps/cs/src/shared/config/api.ts | 1 + 6 files changed, 310 insertions(+) create mode 100644 apps/cs/app/(with-base-layout)/search/page.tsx create mode 100644 apps/cs/src/pages/search/api/search-service.ts create mode 100644 apps/cs/src/pages/search/index.ts create mode 100644 apps/cs/src/pages/search/model/search-interface.ts create mode 100644 apps/cs/src/pages/search/ui/search-page.tsx diff --git a/apps/cs/app/(with-base-layout)/search/page.tsx b/apps/cs/app/(with-base-layout)/search/page.tsx new file mode 100644 index 000000000..2b74c1283 --- /dev/null +++ b/apps/cs/app/(with-base-layout)/search/page.tsx @@ -0,0 +1,2 @@ +import { SearchPage } from "@/pages/search"; +export default SearchPage; diff --git a/apps/cs/src/pages/search/api/search-service.ts b/apps/cs/src/pages/search/api/search-service.ts new file mode 100644 index 000000000..5bb99e7d1 --- /dev/null +++ b/apps/cs/src/pages/search/api/search-service.ts @@ -0,0 +1,21 @@ +import { client } from "@/shared/api"; +import type { + SearchParams, + SearchResult, + SearchService, +} from "../model/search-interface"; +import { ENDPOINT } from "@/shared/config"; + +export class SearchApiService implements SearchService { + public async searchPost(params: SearchParams): Promise { + const response = await client.get( + ENDPOINT.BOARD_SERVICE.SEARCH_POST, + { + params, + }, + ); + return response.data; + } +} + +export const SearchApi = new SearchApiService(); diff --git a/apps/cs/src/pages/search/index.ts b/apps/cs/src/pages/search/index.ts new file mode 100644 index 000000000..c5e44be12 --- /dev/null +++ b/apps/cs/src/pages/search/index.ts @@ -0,0 +1 @@ +export { SearchPage } from "./ui/search-page"; diff --git a/apps/cs/src/pages/search/model/search-interface.ts b/apps/cs/src/pages/search/model/search-interface.ts new file mode 100644 index 000000000..7afb1e9fc --- /dev/null +++ b/apps/cs/src/pages/search/model/search-interface.ts @@ -0,0 +1,45 @@ +import type { PageableList, PageableParams } from "@/shared/model"; + +export interface SearchParams extends PageableParams { + keywordType?: string; + keyword?: string; + siteId?: string; +} + +export interface Post { + bbsId: number; + bbsNm: string; + pstNo: number; + pstTtl: string; + pstCn: string; + inqNocs: number; + wrtrNm: string; + wrtrCplc: string; + regDt: string; + rgtrNm: string; +} + +export interface Board { + bbsId: number; + bbsNm: string; + fullMenuPath: string; + urlPath: string; + posts: Post[]; +} + +export interface Contents { + contsSn: number; + contsTtl: string; + contsCn: string; + fullMenuPath: string; + urlPath: string; +} + +export interface SearchResult { + boardList: PageableList; + contsList: Contents[]; +} + +export interface SearchService { + searchPost(params: SearchParams): Promise; +} diff --git a/apps/cs/src/pages/search/ui/search-page.tsx b/apps/cs/src/pages/search/ui/search-page.tsx new file mode 100644 index 000000000..23a70b85e --- /dev/null +++ b/apps/cs/src/pages/search/ui/search-page.tsx @@ -0,0 +1,240 @@ +"use client"; + +import Link from "next/link"; +import { useState } from "react"; +import { useSearchParams } from "next/navigation"; +import { useQuery } from "@tanstack/react-query"; +import { + Button, + Input, + Tabs, + TabsContent, + TabsList, + TabsTrigger, +} from "@common/components"; +import { ENDPOINT, SITE_ID } from "@/shared/config"; +import { SearchApi } from "../api/search-service"; +import type { Board, Post, Contents } from "../model/search-interface"; + +const RENDER_LIMIT = 5; + +function SearchPage() { + const searchParams = useSearchParams(); + const keywordParam = searchParams?.get("keyword"); + + const [keyword, setKeyword] = useState(keywordParam ?? ""); + const [tab, setTab] = useState("all"); + + const { data } = useQuery({ + queryKey: [ENDPOINT.BOARD_SERVICE.SEARCH_POST, keyword], + queryFn: () => SearchApi.searchPost({ keyword: keyword, siteId: SITE_ID }), + }); + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + const formData = new FormData(e.target as HTMLFormElement); + setKeyword(formData.get("keyword") as string); + }; + + return ( +
+

통합검색

+
+ + + + +
+
+

+ 검색어 '{keyword}'로 + 검색한 결과입니다. +

+
+
+ +
+ + + 전체 ( + {data?.contsList?.length ?? + 0 + (data?.boardList?.totalElements ?? 0)} + 건) + + + 웹페이지 ({data?.contsList?.length ?? 0}건) + + + 게시판 ({data?.boardList?.totalElements ?? 0}건) + + +
+ +
+
+

+ 웹페이지 ({data?.contsList?.length ?? 0}건) +

+ {renderContents(data?.contsList)} + {(data?.contsList?.length ?? 0) > RENDER_LIMIT && ( + + )} +
+
+

+ 게시판 ({data?.boardList?.totalElements ?? 0}건) +

+ {renderPost(data?.boardList.content)} + {(data?.boardList?.totalElements ?? 0) > RENDER_LIMIT && ( + + )} +
+
+
+ + {renderContents(data?.contsList, 100)} + + + {renderPost(data?.boardList.content, 100)} + +
+
+
+
+ ); +} + +interface ContentItemProps { + content: Contents; +} + +function ContentItem({ content }: ContentItemProps) { + return ( +
  • + + {content.fullMenuPath} +
    + +

    +

    + +
  • + ); +} + +function renderContents(contents?: Contents[], limit = RENDER_LIMIT) { + if (!contents || !contents.length) return null; + return ( + <> + {contents.map((content, index) => { + if (limit <= index) return null; + + return ( +
      + +
    + ); + })} + + ); +} + +interface PostItemProps { + post: Post; + board: Board; +} + +function PostItem({ post, board }: PostItemProps) { + const postUrl = !!board.urlPath ? `${board.urlPath}/${post.pstNo}` : ""; + return ( +
  • + + {board.fullMenuPath} +
    + +

    +

    + +
  • + ); +} + +function renderPost(boards?: Board[], limit = RENDER_LIMIT) { + if (!boards || !boards.length) return null; + + let remainingPosts = limit; + + return ( + <> + {boards.map((board) => { + if (remainingPosts <= 0) return null; + + const postsToShow = Math.min(board.posts.length, remainingPosts); + if (postsToShow <= 0) return null; + + remainingPosts -= postsToShow; + + return ( +
      + {board.posts.slice(0, postsToShow).map((post) => ( + + ))} +
    + ); + })} + + ); +} + +export { SearchPage }; diff --git a/apps/cs/src/shared/config/api.ts b/apps/cs/src/shared/config/api.ts index ce6f61381..5f79ff2da 100644 --- a/apps/cs/src/shared/config/api.ts +++ b/apps/cs/src/shared/config/api.ts @@ -63,6 +63,7 @@ export const ENDPOINT = { POSTS: "/board-service/api/v1/posts", POSTS_COMMENTS: "/board-service/api/v1/posts-cmnts", POST_EVALUATION: "/board-service/api/v1/pstEvl", + SEARCH_POST: "/board-service/api/v1/isearch/pst", }, }; From 98cc45162d022d28e31f2aaf3061a66c1e0dcfd3 Mon Sep 17 00:00:00 2001 From: bicochan Date: Fri, 1 Aug 2025 16:14:01 +0900 Subject: [PATCH 2/3] =?UTF-8?q?[apps/cs]=20feat:=20=EA=B2=80=EC=83=89=20?= =?UTF-8?q?=EC=8B=9C=20=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0=20=EC=97=85?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/cs/src/pages/search/ui/search-page.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/cs/src/pages/search/ui/search-page.tsx b/apps/cs/src/pages/search/ui/search-page.tsx index 23a70b85e..efa25132e 100644 --- a/apps/cs/src/pages/search/ui/search-page.tsx +++ b/apps/cs/src/pages/search/ui/search-page.tsx @@ -2,7 +2,7 @@ import Link from "next/link"; import { useState } from "react"; -import { useSearchParams } from "next/navigation"; +import { useRouter, useSearchParams } from "next/navigation"; import { useQuery } from "@tanstack/react-query"; import { Button, @@ -19,6 +19,7 @@ import type { Board, Post, Contents } from "../model/search-interface"; const RENDER_LIMIT = 5; function SearchPage() { + const router = useRouter(); const searchParams = useSearchParams(); const keywordParam = searchParams?.get("keyword"); @@ -34,6 +35,10 @@ function SearchPage() { e.preventDefault(); const formData = new FormData(e.target as HTMLFormElement); setKeyword(formData.get("keyword") as string); + + const params = new URLSearchParams(searchParams?.toString()); + params.set("keyword", formData.get("keyword") as string); + router.replace(`?${params.toString()}`); }; return ( From aabd81057183ee6d562d485d0ea00589f64fd855 Mon Sep 17 00:00:00 2001 From: bicochan Date: Sat, 2 Aug 2025 02:42:20 +0900 Subject: [PATCH 3/3] =?UTF-8?q?[common/features]=20refactor:=20=ED=86=B5?= =?UTF-8?q?=ED=95=A9=20=EA=B2=80=EC=83=89=20=EA=B8=B0=EB=8A=A5=20=EA=B3=B5?= =?UTF-8?q?=ED=86=B5=20=EA=B8=B0=EB=8A=A5=EC=9C=BC=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/(with-base-layout)/search/layout.tsx | 28 ++++++++ .../app/(with-base-layout)/search/page.tsx | 0 apps/common/features/middleware.ts | 4 -- .../src/pages/search/api/search-service.ts | 0 .../features}/src/pages/search/index.ts | 0 .../pages/search/model/search-interface.ts | 0 .../src/pages/search/ui/search-page.tsx | 6 +- apps/common/features/src/shared/config/api.ts | 1 + .../src/widgets/post/ui/post-action.tsx | 5 +- .../features/src/widgets/post/ui/post.tsx | 14 ++++ .../api/board-statistics-service.ts | 5 +- .../model/board-statistics-interface.ts | 5 +- .../ui/board-statistics-page.tsx | 2 +- apps/cs/src/shared/config/api.ts | 1 - package.json | 2 +- .../common/components/src/ui/header/index.tsx | 64 ++++++++++--------- .../components/src/ui/header/search-form.tsx | 32 ++++++++++ 17 files changed, 126 insertions(+), 43 deletions(-) create mode 100644 apps/common/features/app/(with-base-layout)/search/layout.tsx rename apps/{cs => common/features}/app/(with-base-layout)/search/page.tsx (100%) rename apps/{cs => common/features}/src/pages/search/api/search-service.ts (100%) rename apps/{cs => common/features}/src/pages/search/index.ts (100%) rename apps/{cs => common/features}/src/pages/search/model/search-interface.ts (100%) rename apps/{cs => common/features}/src/pages/search/ui/search-page.tsx (98%) create mode 100644 packages/common/components/src/ui/header/search-form.tsx diff --git a/apps/common/features/app/(with-base-layout)/search/layout.tsx b/apps/common/features/app/(with-base-layout)/search/layout.tsx new file mode 100644 index 000000000..7fc1dfc1f --- /dev/null +++ b/apps/common/features/app/(with-base-layout)/search/layout.tsx @@ -0,0 +1,28 @@ +"use client"; + +import { useQuery } from "@tanstack/react-query"; +import { MenuApi } from "@/entities/menu"; +import { useMenuStore } from "@/shared/lib"; +import { ENDPOINT } from "@/shared/config"; +import { PageLayout } from "@/shared/ui/page-layout"; + +export default function SearchLayout({ + children, +}: { + children: React.ReactNode; +}) { + const currentMenuInfo = useMenuStore((state) => state.currentMenuInfo); + const { data } = useQuery({ + queryKey: [ENDPOINT.CMS_SERVICE.MENUS, currentMenuInfo?.menuCd], + queryFn: () => + MenuApi.getMenuInfo(currentMenuInfo?.menuCd.toString() ?? ""), + enabled: !!currentMenuInfo, + }); + const menuPaths = data?.menuPath?.split(">").map((path) => path.trim()); + + return ( + + {children} + + ); +} diff --git a/apps/cs/app/(with-base-layout)/search/page.tsx b/apps/common/features/app/(with-base-layout)/search/page.tsx similarity index 100% rename from apps/cs/app/(with-base-layout)/search/page.tsx rename to apps/common/features/app/(with-base-layout)/search/page.tsx diff --git a/apps/common/features/middleware.ts b/apps/common/features/middleware.ts index 018aab11a..e428dfa74 100644 --- a/apps/common/features/middleware.ts +++ b/apps/common/features/middleware.ts @@ -13,7 +13,6 @@ export function middleware(req: NextRequest) { const newUrl = `${serverApiUrl}${pathname.replace("/server", "")}${ queryParams ? `?${queryParams}` : "" }`; - console.log(`[Middleware] Rewriting from '/server' path to: ${newUrl}`); return NextResponse.rewrite(new URL(newUrl)); } @@ -26,9 +25,6 @@ export function middleware(req: NextRequest) { if (token) requestHeaders.set(CLAIM_NAME, token); if (userId) requestHeaders.set(AUTH_USER_ID, userId); - console.log( - `[Middleware] Rewriting from '/attach-service' path to: ${newUrl}`, - ); return NextResponse.rewrite(new URL(newUrl), { headers: requestHeaders, }); diff --git a/apps/cs/src/pages/search/api/search-service.ts b/apps/common/features/src/pages/search/api/search-service.ts similarity index 100% rename from apps/cs/src/pages/search/api/search-service.ts rename to apps/common/features/src/pages/search/api/search-service.ts diff --git a/apps/cs/src/pages/search/index.ts b/apps/common/features/src/pages/search/index.ts similarity index 100% rename from apps/cs/src/pages/search/index.ts rename to apps/common/features/src/pages/search/index.ts diff --git a/apps/cs/src/pages/search/model/search-interface.ts b/apps/common/features/src/pages/search/model/search-interface.ts similarity index 100% rename from apps/cs/src/pages/search/model/search-interface.ts rename to apps/common/features/src/pages/search/model/search-interface.ts diff --git a/apps/cs/src/pages/search/ui/search-page.tsx b/apps/common/features/src/pages/search/ui/search-page.tsx similarity index 98% rename from apps/cs/src/pages/search/ui/search-page.tsx rename to apps/common/features/src/pages/search/ui/search-page.tsx index efa25132e..407d2301c 100644 --- a/apps/cs/src/pages/search/ui/search-page.tsx +++ b/apps/common/features/src/pages/search/ui/search-page.tsx @@ -12,11 +12,13 @@ import { TabsList, TabsTrigger, } from "@common/components"; -import { ENDPOINT, SITE_ID } from "@/shared/config"; +import { ENDPOINT } from "@/shared/config"; import { SearchApi } from "../api/search-service"; import type { Board, Post, Contents } from "../model/search-interface"; +import { getCookie } from "@/shared/lib"; const RENDER_LIMIT = 5; +const siteId = getCookie("site-id-key") ?? ""; function SearchPage() { const router = useRouter(); @@ -28,7 +30,7 @@ function SearchPage() { const { data } = useQuery({ queryKey: [ENDPOINT.BOARD_SERVICE.SEARCH_POST, keyword], - queryFn: () => SearchApi.searchPost({ keyword: keyword, siteId: SITE_ID }), + queryFn: () => SearchApi.searchPost({ keyword: keyword, siteId }), }); const handleSubmit = (e: React.FormEvent) => { diff --git a/apps/common/features/src/shared/config/api.ts b/apps/common/features/src/shared/config/api.ts index 4fef249d5..67b8948d7 100644 --- a/apps/common/features/src/shared/config/api.ts +++ b/apps/common/features/src/shared/config/api.ts @@ -44,6 +44,7 @@ export const ENDPOINT = { POSTS_USER: "/board-service/api/v1/posts/user", POSTS_COMMENTS: "/board-service/api/v1/posts-cmnts", POST_EVALUATION: "/board-service/api/v1/pstEvl", + SEARCH_POST: "/board-service/api/v1/isearch/pst", }, }; diff --git a/apps/common/features/src/widgets/post/ui/post-action.tsx b/apps/common/features/src/widgets/post/ui/post-action.tsx index a2160d2e9..695ddb721 100644 --- a/apps/common/features/src/widgets/post/ui/post-action.tsx +++ b/apps/common/features/src/widgets/post/ui/post-action.tsx @@ -12,6 +12,8 @@ type PostActionProps = { handleDelete: () => Promise; }; +const basePath = process.env.NODE_ENV === "production" ? "/cms" : ""; + function PostAction({ registerId, children, handleDelete }: PostActionProps) { const router = useRouter(); const pathname = usePathname(); @@ -19,6 +21,7 @@ function PostAction({ registerId, children, handleDelete }: PostActionProps) { const { copyText, copied } = useClipboard(); const bbsInfo = useMenuStore((state) => state.bbsInfo); const userInfo = useUserStore((state) => state.userInfo); + const postPageLink = `${basePath}/${bbsInfo?.bbsTypeCd.toLowerCase()}/${bbsInfo?.bbsId}`; const actionButtonAuthrt = userInfo?.adminRoleYn === "Y" || userInfo?.userUnqId === registerId; @@ -60,7 +63,7 @@ function PostAction({ registerId, children, handleDelete }: PostActionProps) { size="lg" color="white" type="button" - onClick={() => router.back()} + onClick={() => router.push(postPageLink)} > 목록 diff --git a/apps/common/features/src/widgets/post/ui/post.tsx b/apps/common/features/src/widgets/post/ui/post.tsx index 7c1c4c3b6..b8928a3e2 100644 --- a/apps/common/features/src/widgets/post/ui/post.tsx +++ b/apps/common/features/src/widgets/post/ui/post.tsx @@ -13,6 +13,7 @@ import { Skeleton, } from "@common/components"; import { AttachmentApi } from "@/entities/attachment"; +import { BoardApi } from "@/entities/board"; import { PostApi } from "@/entities/post"; import { useAlertStore, @@ -31,10 +32,17 @@ function Post({ bbsId, pstNo }: { bbsId: string; pstNo: string }) { const alert = useAlertStore((state) => state.setMessage); const userInfo = useUserStore((state) => state.userInfo); const bbsInfo = useMenuStore((state) => state.bbsInfo); + const setBbsInfo = useMenuStore((state) => state.setBbsInfo); const [filename, setFilename] = useState(""); const [evlScr, setEvlScr] = useState(5); + const { data: boardInfo } = useQuery({ + queryKey: [bbsId], + queryFn: () => BoardApi.getBoardInfo(bbsId), + enabled: !bbsInfo, + }); + const { data: postData } = useQuery({ queryKey: [ENDPOINT.BOARD_SERVICE.POSTS_USER, bbsId, pstNo], queryFn: () => PostApi.getPostInfo(parseInt(bbsId), parseInt(pstNo)), @@ -142,6 +150,12 @@ function Post({ bbsId, pstNo }: { bbsId: string; pstNo: string }) { } }, [downloadResponse]); + useEffect(() => { + if (!boardInfo) return; + if (bbsInfo) return; + setBbsInfo(boardInfo); + }, [boardInfo, bbsInfo]); + return ( <> diff --git a/apps/cs/src/pages/board-statistics/api/board-statistics-service.ts b/apps/cs/src/pages/board-statistics/api/board-statistics-service.ts index 1897e39ba..03291223c 100644 --- a/apps/cs/src/pages/board-statistics/api/board-statistics-service.ts +++ b/apps/cs/src/pages/board-statistics/api/board-statistics-service.ts @@ -1,5 +1,5 @@ -import { client } from "@/shared/api"; -import { ENDPOINT } from "@/shared/config"; +// import { client } from "@/shared/api"; +// import { ENDPOINT } from "@/shared/config"; import { type BoardStatisticsParams, type BoardStatistics, @@ -37,6 +37,7 @@ class BoardStatisticsApiService implements BoardStatisticsService { async getBoardStatistics( params: BoardStatisticsParams, ): Promise { + console.log("params: ", params); try { // 실제 API 연동 시 아래 코드 사용 // const response = await client.get( diff --git a/apps/cs/src/pages/board-statistics/model/board-statistics-interface.ts b/apps/cs/src/pages/board-statistics/model/board-statistics-interface.ts index 8ec52dabf..1f113475f 100644 --- a/apps/cs/src/pages/board-statistics/model/board-statistics-interface.ts +++ b/apps/cs/src/pages/board-statistics/model/board-statistics-interface.ts @@ -1,4 +1,7 @@ -import type { PageableList, PageableParams } from "@/shared/model"; +import type { + // PageableList, + PageableParams, +} from "@/shared/model"; export interface BoardStatisticsParams extends PageableParams { keywordType?: string; diff --git a/apps/cs/src/pages/board-statistics/ui/board-statistics-page.tsx b/apps/cs/src/pages/board-statistics/ui/board-statistics-page.tsx index d879c34d6..13dcbe812 100644 --- a/apps/cs/src/pages/board-statistics/ui/board-statistics-page.tsx +++ b/apps/cs/src/pages/board-statistics/ui/board-statistics-page.tsx @@ -26,7 +26,7 @@ import { SelectValue, } from "@common/components"; import { SiteSelect } from "@/entities/site"; -import { ENDPOINT } from "@/shared/config"; +// import { ENDPOINT } from "@/shared/config"; import { NoData } from "@/shared/ui/no-data"; import { InputDateRangePicker } from "@/shared/ui/input-date-range-picker"; import { BoardStatisticsApi } from "../api/board-statistics-service"; diff --git a/apps/cs/src/shared/config/api.ts b/apps/cs/src/shared/config/api.ts index 5f79ff2da..ce6f61381 100644 --- a/apps/cs/src/shared/config/api.ts +++ b/apps/cs/src/shared/config/api.ts @@ -63,7 +63,6 @@ export const ENDPOINT = { POSTS: "/board-service/api/v1/posts", POSTS_COMMENTS: "/board-service/api/v1/posts-cmnts", POST_EVALUATION: "/board-service/api/v1/pstEvl", - SEARCH_POST: "/board-service/api/v1/isearch/pst", }, }; diff --git a/package.json b/package.json index 89154a13d..f468722e7 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "packages/*" ], "scripts": { - "build": "turbo run build", + "build": "turbo run build --filter=!dm", "build:common": "turbo run build --filter=@common/*", "dev": "turbo run dev", "dev:cs": "turbo run dev --filter=cs", diff --git a/packages/common/components/src/ui/header/index.tsx b/packages/common/components/src/ui/header/index.tsx index f7637b7f0..52028da32 100644 --- a/packages/common/components/src/ui/header/index.tsx +++ b/packages/common/components/src/ui/header/index.tsx @@ -22,6 +22,7 @@ import { import { Button } from "../button"; import { SidebarTrigger } from "../sidebar"; import { Skeleton } from "../skeleton"; +import { SearchForm } from "./search-form"; const appConfig = getConfig(); const siteId = appConfig.SITE_ID ?? ""; @@ -135,36 +136,39 @@ export function Header({ viewOnly }: { viewOnly?: boolean }) { - {mounted ? ( - isLoggedIn && ( - - - - - - 프로필 설정 -
    -

    최종접속일

    -

    {userInfo?.lastLoginDate}

    -
    -
    -

    접속 IP

    -

    -
    - 로그아웃 -
    -
    - ) - ) : ( - - )} +
    + + {mounted ? ( + isLoggedIn && ( + + + + + + 프로필 설정 +
    +

    최종접속일

    +

    {userInfo?.lastLoginDate}

    +
    +
    +

    접속 IP

    +

    +
    + 로그아웃 +
    +
    + ) + ) : ( + + )} +
    ); } diff --git a/packages/common/components/src/ui/header/search-form.tsx b/packages/common/components/src/ui/header/search-form.tsx new file mode 100644 index 000000000..66ffbadb1 --- /dev/null +++ b/packages/common/components/src/ui/header/search-form.tsx @@ -0,0 +1,32 @@ +import { Button } from "../button"; +import { Input } from "../input"; + +export function SearchForm() { + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + const formData = new FormData(e.target as HTMLFormElement); + const keyword = formData.get("keyword") as string; + + if (keyword && keyword.trim().length > 0) { + window.location.href = `/cms/search?keyword=${encodeURIComponent(keyword)}`; + } + }; + + return ( +
    + + + + ); +}