임동욱 임동욱 09-22
feat: 검색이 있는 모든 목록에 [검색 초기화]를 두고 기존 [초기화]를 그 이름으로 바꾼다
게시판(공지·FAQ·1:1문의)·콘텐츠(쇼츠·만화·퀴즈)·꾸미기 아이템·금칙어·공통코드 그룹 목록에
새로 추가하고, 포인트 적립·기준의 [초기화]는 [검색 초기화]로 바꾼다. 모두 목록 컨테이너를
다시 마운트해 입력 중인 검색어까지 비우고 기본 주소로 돌아간다. 검색이 없는 앱 메뉴·관리자
메뉴 목록은 대상이 아니고, 가맹몰 관리는 앞서 요청으로 뺀 상태를 유지한다.

Co-Authored-By: Claude Opus 5 
@54cf18e8e0af506047329ae4bfcccff3c0560288
app/(protected)/(basic)/boards/_components/board-post-list.tsx
--- app/(protected)/(basic)/boards/_components/board-post-list.tsx
+++ app/(protected)/(basic)/boards/_components/board-post-list.tsx
@@ -4,6 +4,7 @@
 import { useState, type ReactNode } from 'react';
 import { useBlockingAction } from '@/app/_hooks/use-blocking-action';
 import { FoxButton } from '@fox/core/components/fox-button';
+import { FoxButtonGroup } from '@fox/core/components/fox-button-group';
 import { FoxIconButton } from '@fox/core/components/fox-icon-button';
 import { FoxListContainer } from '@fox/core/components/fox-list-container';
 import { FoxSelectText } from '@fox/core/components/fox-select-text';
@@ -12,6 +13,7 @@
 import type { BoardPost, BoardType } from '@/lib/domain/board-post';
 import type { CommonCode } from '@/lib/domain/common-code';
 import {
+  BOARD_PATHS,
   BOARD_PAGE_SIZE_OPTIONS,
   BOARD_SEARCH_FIELDS,
   FILTER_ALL,
@@ -67,9 +69,18 @@
     router.replace(buildBoardPostHref(boardType, query, { ...patch, page: 1 }));
   }
 
+  // 검색 초기화 — 주소를 되돌리는 것만으론 아직 적용 안 한 입력값이 남는다. 목록 컨테이너를
+  // 다시 마운트해 검색 상자의 초안까지 비운다.
+  const [resetCount, setResetCount] = useState(0);
+  function resetSearch() {
+    setResetCount((count) => count + 1);
+    router.replace(BOARD_PATHS[boardType]);
+  }
+
   return (
     <>
       <FoxListContainer<BoardPost>
+        key={resetCount}
         title={title}
         breadcrumb={breadcrumb}
         caption={title}
@@ -114,17 +125,20 @@
         searchField={query.searchField}
         keyword={query.keyword}
         toolbarActions={
-          canCreate ? (
-            <FoxButton
-              type="primary"
-              size="md"
-              leadingIcon={<i className="fox-ico fox-ico-Plus" aria-hidden="true" />}
-              label="신규 등록"
-              onAction={() => setIsCreateOpen(true)}
-            />
-          ) : (
-            extraToolbar
-          )
+          <FoxButtonGroup size="md">
+            <FoxButton type="default" size="md" label="검색 초기화" onAction={resetSearch} />
+            {canCreate ? (
+              <FoxButton
+                type="primary"
+                size="md"
+                leadingIcon={<i className="fox-ico fox-ico-Plus" aria-hidden="true" />}
+                label="신규 등록"
+                onAction={() => setIsCreateOpen(true)}
+              />
+            ) : (
+              extraToolbar
+            )}
+          </FoxButtonGroup>
         }
         filter={
           <div className={styles.filter}>
app/(protected)/(basic)/contents/_components/content-list-shell.tsx
--- app/(protected)/(basic)/contents/_components/content-list-shell.tsx
+++ app/(protected)/(basic)/contents/_components/content-list-shell.tsx
@@ -1,7 +1,7 @@
 'use client';
 
 import { useRouter } from 'next/navigation';
-import type { ReactNode } from 'react';
+import { useState, type ReactNode } from 'react';
 import { FoxButton } from '@fox/core/components/fox-button';
 import { FoxButtonGroup } from '@fox/core/components/fox-button-group';
 import { FoxSelectText } from '@fox/core/components/fox-select-text';
@@ -17,6 +17,7 @@
   buildContentHref,
   contentBreadcrumb,
   contentCreatePath,
+  contentListPath,
   type ContentPageSize,
   type ContentQuery,
   type ContentSortOption,
@@ -60,8 +61,17 @@
     router.push(buildContentHref(kind, query, patch));
   }
 
+  // 검색 초기화 — 주소를 되돌리는 것만으론 아직 적용 안 한 입력값이 남는다. 목록 컨테이너를
+  // 다시 마운트해 검색 상자의 초안까지 비운다.
+  const [resetCount, setResetCount] = useState(0);
+  function resetSearch() {
+    setResetCount((count) => count + 1);
+    router.replace(contentListPath(kind));
+  }
+
   return (
     <FoxListContainer<T>
+      key={resetCount}
       title={`콘텐츠 목록 (${CONTENT_KIND_LABEL[kind]})`}
       breadcrumb={contentBreadcrumb(kind)}
       caption={`${CONTENT_KIND_LABEL[kind]} 콘텐츠 목록`}
@@ -118,6 +128,7 @@
       searchPlaceholder="검색어를 입력하세요."
       toolbarActions={
         <FoxButtonGroup size="md">
+          <FoxButton type="default" size="md" label="검색 초기화" onAction={resetSearch} />
           {extraActions}
           <FoxButton
             type="primary"
app/(protected)/(basic)/decoration-items/_components/decoration-item-list.tsx
--- app/(protected)/(basic)/decoration-items/_components/decoration-item-list.tsx
+++ app/(protected)/(basic)/decoration-items/_components/decoration-item-list.tsx
@@ -3,6 +3,7 @@
 import { useRouter } from 'next/navigation';
 import { useState } from 'react';
 import { FoxButton } from '@fox/core/components/fox-button';
+import { FoxButtonGroup } from '@fox/core/components/fox-button-group';
 import {
   FoxListContainer,
   type FoxListColumn,
@@ -29,6 +30,7 @@
   type DecorationItemPageSize,
   type DecorationItemQuery,
   type DecorationItemSearchField,
+  DECORATION_ITEMS_PATH,
 } from '@/lib/domain/decoration-item-query';
 import { DecorationItemCreateModal } from './decoration-item-create-modal';
 import { DecorationItemRowActions } from './decoration-item-row-actions';
@@ -77,6 +79,14 @@
   /** 목록 조건이 바뀌면 늘 1페이지로 되돌린다 — 이전 페이지 번호는 새 조건에서 의미가 다르다. */
   function go(patch: Partial<DecorationItemQuery>) {
     router.replace(buildDecorationItemHref(query, { ...patch, page: 1 }));
+  }
+
+  // 검색 초기화 — 주소를 되돌리는 것만으론 아직 적용 안 한 입력값이 남는다. 목록 컨테이너를
+  // 다시 마운트해 검색 상자의 초안까지 비운다.
+  const [resetCount, setResetCount] = useState(0);
+  function resetSearch() {
+    setResetCount((count) => count + 1);
+    router.replace(DECORATION_ITEMS_PATH);
   }
 
   const columns: FoxListColumn<DecorationItem>[] = [
@@ -155,6 +165,7 @@
   return (
     <>
       <FoxListContainer<DecorationItem>
+        key={resetCount}
         title="꾸미기 아이템 목록"
         breadcrumb={[
           { label: '홈', href: '/' },
@@ -205,13 +216,16 @@
         searchField={query.searchField}
         keyword={query.keyword}
         toolbarActions={
-          <FoxButton
-            type="primary"
-            size="md"
-            leadingIcon={<i className="fox-ico fox-ico-Plus" aria-hidden="true" />}
-            label="신규 등록"
-            onAction={() => setIsCreateOpen(true)}
-          />
+          <FoxButtonGroup size="md">
+            <FoxButton type="default" size="md" label="검색 초기화" onAction={resetSearch} />
+            <FoxButton
+              type="primary"
+              size="md"
+              leadingIcon={<i className="fox-ico fox-ico-Plus" aria-hidden="true" />}
+              label="신규 등록"
+              onAction={() => setIsCreateOpen(true)}
+            />
+          </FoxButtonGroup>
         }
         page={currentPage}
         totalPages={totalPages}
app/(protected)/(basic)/points/accumulated/_components/point-account-list.tsx
--- app/(protected)/(basic)/points/accumulated/_components/point-account-list.tsx
+++ app/(protected)/(basic)/points/accumulated/_components/point-account-list.tsx
@@ -65,6 +65,15 @@
     router.replace(buildPointAccountHref(query, { ...patch, page: 1 }));
   }
 
+  // 검색 초기화 — 주소를 되돌리는 것만으론 아직 적용 안 한 입력값이 남는다. 목록 컨테이너를
+  // 다시 마운트해 검색 상자의 초안까지 비운다.
+  const [resetCount, setResetCount] = useState(0);
+  function resetSearch() {
+    setSchoolNameDraft('');
+    setResetCount((count) => count + 1);
+    router.replace(POINT_ACCOUNTS_PATH);
+  }
+
   function selectedNumber(value: number | null) {
     return value === null ? FILTER_ALL : String(value);
   }
@@ -140,6 +149,7 @@
   return (
     <>
       <FoxListContainer<PointAccount>
+        key={resetCount}
         title="누적포인트 관리 목록"
         breadcrumb={[
           { label: '홈', href: '/' },
@@ -219,15 +229,7 @@
         keyword={query.keyword}
         searchPlaceholder="검색어를 입력하세요."
         toolbarActions={
-          <FoxButton
-            type="default"
-            size="md"
-            label="초기화"
-            onAction={() => {
-              setSchoolNameDraft('');
-              router.replace(POINT_ACCOUNTS_PATH);
-            }}
-          />
+          <FoxButton type="default" size="md" label="검색 초기화" onAction={resetSearch} />
         }
         page={currentPage}
         totalPages={totalPages}
app/(protected)/(basic)/points/standards/_components/point-standard-list.tsx
--- app/(protected)/(basic)/points/standards/_components/point-standard-list.tsx
+++ app/(protected)/(basic)/points/standards/_components/point-standard-list.tsx
@@ -55,6 +55,14 @@
     router.replace(buildPointStandardHref(query, { ...patch, page: 1 }));
   }
 
+  // 검색 초기화 — 주소를 되돌리는 것만으론 아직 적용 안 한 입력값이 남는다. 목록 컨테이너를
+  // 다시 마운트해 검색 상자의 초안까지 비운다.
+  const [resetCount, setResetCount] = useState(0);
+  function resetSearch() {
+    setResetCount((count) => count + 1);
+    router.replace(POINT_STANDARDS_PATH);
+  }
+
   const columns: FoxListColumn<PointStandard>[] = [
     {
       key: 'no',
@@ -125,6 +133,7 @@
   return (
     <>
       <FoxListContainer<PointStandard>
+        key={resetCount}
       title="포인트 기준관리 목록"
       breadcrumb={[
         { label: '홈', href: '/' },
@@ -156,12 +165,7 @@
       searchPlaceholder="검색어를 입력하세요."
       toolbarActions={
         <FoxButtonGroup size="md">
-          <FoxButton
-            type="default"
-            size="md"
-            label="초기화"
-            onAction={() => router.replace(POINT_STANDARDS_PATH)}
-          />
+          <FoxButton type="default" size="md" label="검색 초기화" onAction={resetSearch} />
           <FoxButton
             type="primary"
             size="md"
app/(protected)/(basic)/system/banned-words/_components/banned-word-list.tsx
--- app/(protected)/(basic)/system/banned-words/_components/banned-word-list.tsx
+++ app/(protected)/(basic)/system/banned-words/_components/banned-word-list.tsx
@@ -14,6 +14,7 @@
 import { useBlockingAction } from '@/app/_hooks/use-blocking-action';
 import { formatOptionalValue, type BannedWord } from '@/lib/domain/banned-word';
 import {
+  BANNED_WORDS_PATH,
   BANNED_WORD_NEW_PATH,
   BANNED_WORD_PAGE_SIZE_OPTIONS,
   buildBannedWordHref,
@@ -45,6 +46,14 @@
 
   function go(patch: Partial<BannedWordQuery>) {
     router.replace(buildBannedWordHref(query, { ...patch, page: 1 }));
+  }
+
+  // 검색 초기화 — 주소를 되돌리는 것만으론 아직 적용 안 한 입력값이 남는다. 목록 컨테이너를
+  // 다시 마운트해 검색 상자의 초안까지 비운다.
+  const [resetCount, setResetCount] = useState(0);
+  function resetSearch() {
+    setResetCount((count) => count + 1);
+    router.replace(BANNED_WORDS_PATH);
   }
 
   function runDelete(word: BannedWord) {
@@ -112,6 +121,7 @@
   return (
     <>
       <FoxListContainer<BannedWord>
+        key={resetCount}
         title="금칙어관리"
         breadcrumb={[
           { label: '홈', href: '/' },
@@ -143,6 +153,7 @@
         searchPlaceholder="금칙어를 입력하세요."
         toolbarActions={
           <>
+            <FoxButton type="default" size="md" label="검색 초기화" onAction={resetSearch} />
             <FoxButton
               type="secondary"
               size="md"
app/(protected)/(basic)/system/codes/_components/code-management.tsx
--- app/(protected)/(basic)/system/codes/_components/code-management.tsx
+++ app/(protected)/(basic)/system/codes/_components/code-management.tsx
@@ -3,6 +3,7 @@
 import { useRouter } from 'next/navigation';
 import { useState } from 'react';
 import { FoxButton } from '@fox/core/components/fox-button';
+import { FoxButtonGroup } from '@fox/core/components/fox-button-group';
 import { FoxHeadingGroup } from '@fox/core/components/fox-heading-group';
 import {
   FoxListContainer,
@@ -19,6 +20,7 @@
 import {
   COMMON_CODE_PAGE_SIZE,
   COMMON_CODE_SEARCH_FIELD_OPTIONS,
+  COMMON_CODES_PATH,
   buildCommonCodeHref,
   type CommonCodeQuery,
   type CommonCodeSearchField,
@@ -96,6 +98,14 @@
 
   function go(patch: Partial<CommonCodeQuery>) {
     router.replace(buildCommonCodeHref(query, patch));
+  }
+
+  // 검색 초기화 — 주소를 되돌리는 것만으론 아직 적용 안 한 입력값이 남는다. 목록 컨테이너를
+  // 다시 마운트해 검색 상자의 초안까지 비운다.
+  const [resetCount, setResetCount] = useState(0);
+  function resetSearch() {
+    setResetCount((count) => count + 1);
+    router.replace(COMMON_CODES_PATH);
   }
 
   /**
@@ -239,6 +249,7 @@
         <section className={styles.panel}>
           <FoxHeadingGroup title="공통코드 목록" />
           <FoxListContainer<CommonCodeGroup>
+            key={resetCount}
             caption="공통코드 목록"
             columns={groupColumns}
             rows={groups}
@@ -252,13 +263,16 @@
             searchField={query.searchField}
             keyword={query.keyword}
             toolbarActions={
-              <FoxButton
-                type="primary"
-                size="md"
-                leadingIcon={<i className="fox-ico fox-ico-Plus" aria-hidden="true" />}
-                label="신규 등록"
-                onAction={() => setModal({ kind: 'group-create' })}
-              />
+              <FoxButtonGroup size="md">
+                <FoxButton type="default" size="md" label="검색 초기화" onAction={resetSearch} />
+                <FoxButton
+                  type="primary"
+                  size="md"
+                  leadingIcon={<i className="fox-ico fox-ico-Plus" aria-hidden="true" />}
+                  label="신규 등록"
+                  onAction={() => setModal({ kind: 'group-create' })}
+                />
+              </FoxButtonGroup>
             }
             onRowSelect={(row) => go({ comCd: row.comCd })}
             page={groupPage}
app/(protected)/(basic)/system/merchant-details/_components/merchant-detail-list.tsx
--- app/(protected)/(basic)/system/merchant-details/_components/merchant-detail-list.tsx
+++ app/(protected)/(basic)/system/merchant-details/_components/merchant-detail-list.tsx
@@ -351,7 +351,7 @@
           </div>
           <FoxButtonGroup size="md">
             <FoxButton type="secondary" size="md" label="적용" onAction={applyFilters} />
-            <FoxButton type="default" size="md" label="초기화" onAction={resetFilters} />
+            <FoxButton type="default" size="md" label="검색 초기화" onAction={resetFilters} />
           </FoxButtonGroup>
         </div>
       }
Add a comment
List