From c92c5bd1549ba1dcdd22ceb29dcd6e32fa4643cb Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=ED=95=9C=EB=8F=99=ED=98=84?= <hando1220@ajou.ac.kr>
Date: Mon, 31 Mar 2025 22:51:10 +0900
Subject: [PATCH] =?UTF-8?q?feat:=20=EC=A1=B0=ED=9A=8C=20=ED=8E=98=EC=9D=B4?=
 =?UTF-8?q?=EC=A7=80=20=ED=82=A4=EC=9B=8C=EB=93=9C=20=EA=B2=80=EC=83=89=20?=
 =?UTF-8?q?API=20=EC=97=B0=EB=8F=99?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 src/pages/forwarding/List.tsx | 39 ++++++++++++++++++++++++++++-------
 src/pages/routing/List.tsx    | 39 ++++++++++++++++++++++++++++-------
 2 files changed, 62 insertions(+), 16 deletions(-)

diff --git a/src/pages/forwarding/List.tsx b/src/pages/forwarding/List.tsx
index 446bd0c..19b7a7a 100644
--- a/src/pages/forwarding/List.tsx
+++ b/src/pages/forwarding/List.tsx
@@ -1,5 +1,5 @@
 import { useEffect, useState } from 'react';
-import { Link } from 'react-router';
+import { Link, useSearchParams } from 'react-router';
 import { Filter, Plus, Pencil, Trash } from 'lucide-react';
 import { toast } from 'sonner';
 import { useAuthStore } from '@/stores/authStore';
@@ -23,11 +23,15 @@ import {
 
 export default function ForwardingList() {
   const { authFetch, selectedProject } = useAuthStore();
+  const [searchParams, setSearchParams] = useSearchParams();
   const [forwardings, setForwardings] = useState<Forwarding[] | null>(null);
   const [selectedForwarding, setSelectedForwarding] = useState<Forwarding | null>(null);
 
   useEffect(() => {
-    authFetch(`/api/forwardings?projectId=${selectedProject?.id}`)
+    const apiSearchParams = new URLSearchParams(searchParams);
+    apiSearchParams.set('projectId', selectedProject?.id || '');
+
+    authFetch(`/api/forwardings?${apiSearchParams.toString()}`)
       .then((response) => {
         if (!response.ok) throw Error(`포트포워딩 목록 조회 실패: ${response.status}`);
 
@@ -40,7 +44,7 @@ export default function ForwardingList() {
         console.error(error);
         toast.error('포트포워딩 정보를 조회할 수 없습니다.');
       });
-  }, [authFetch, selectedProject]);
+  }, [authFetch, selectedProject, searchParams]);
 
   const handleDelete = () => {
     if (selectedForwarding === null) throw Error('selectedForwarding is null');
@@ -81,11 +85,30 @@ export default function ForwardingList() {
       </div>
       <Card>
         <CardContent>
-          <div className="flex w-full items-center space-x-2 mb-4">
-            <Filter className="mr-3" />
-            <Input placeholder="이름, 포트, 인스턴스 IP로 검색..." />
-            <Button variant="secondary">검색</Button>
-          </div>
+          <form
+            onSubmit={(e) => {
+              e.preventDefault();
+              const formData = new FormData(e.currentTarget);
+              const query = formData.get('query')?.toString();
+              if (query) {
+                setSearchParams({ query });
+              } else {
+                setSearchParams({});
+              }
+            }}
+          >
+            <div className="flex w-full items-center space-x-2 mb-4">
+              <Filter className="mr-3" />
+              <Input
+                name="query"
+                placeholder="이름, 포트, 인스턴스 IP로 검색..."
+                defaultValue={searchParams.get('query') || ''}
+              />
+              <Button type="submit" variant="secondary">
+                검색
+              </Button>
+            </div>
+          </form>
           <Table>
             <TableHeader>
               <TableRow>
diff --git a/src/pages/routing/List.tsx b/src/pages/routing/List.tsx
index ab57550..c169ec5 100644
--- a/src/pages/routing/List.tsx
+++ b/src/pages/routing/List.tsx
@@ -1,5 +1,5 @@
 import { useEffect, useState } from 'react';
-import { Link } from 'react-router';
+import { Link, useSearchParams } from 'react-router';
 import { Filter, Plus, Check, X, Pencil, Trash } from 'lucide-react';
 import { toast } from 'sonner';
 import { Button } from '@/components/ui/button';
@@ -24,11 +24,15 @@ import { Routing } from '@/types/routing';
 
 export default function RoutingList() {
   const { authFetch, selectedProject } = useAuthStore();
+  const [searchParams, setSearchParams] = useSearchParams();
   const [routings, setRoutings] = useState<Routing[] | null>(null);
   const [selectedRouting, setSelectedRouting] = useState<Routing | null>(null);
 
   useEffect(() => {
-    authFetch(`/api/routings?projectId=${selectedProject?.id}`)
+    const apiSearchParams = new URLSearchParams(searchParams);
+    apiSearchParams.set('projectId', selectedProject?.id || '');
+
+    authFetch(`/api/routings?${apiSearchParams.toString()}`)
       .then((response) => {
         if (!response.ok) throw Error(`라우팅 목록 조회 실패: ${response.status}`);
 
@@ -41,7 +45,7 @@ export default function RoutingList() {
         console.error(error);
         toast.error('라우팅 정보를 조회할 수 없습니다.');
       });
-  }, [authFetch, selectedProject]);
+  }, [authFetch, selectedProject, searchParams]);
 
   const handleDelete = () => {
     if (selectedRouting === null) throw Error('selectedRouting is null');
@@ -82,11 +86,30 @@ export default function RoutingList() {
       </div>
       <Card>
         <CardContent>
-          <div className="flex w-full items-center space-x-2 mb-4">
-            <Filter className="mr-3" />
-            <Input placeholder="이름, 도메인, 인스턴스 IP로 검색..." />
-            <Button variant="secondary">검색</Button>
-          </div>
+          <form
+            onSubmit={(e) => {
+              e.preventDefault();
+              const formData = new FormData(e.currentTarget);
+              const query = formData.get('query')?.toString();
+              if (query) {
+                setSearchParams({ query });
+              } else {
+                setSearchParams({});
+              }
+            }}
+          >
+            <div className="flex w-full items-center space-x-2 mb-4">
+              <Filter className="mr-3" />
+              <Input
+                name="query"
+                placeholder="이름, 도메인, 인스턴스 IP로 검색..."
+                defaultValue={searchParams.get('query') || ''}
+              />
+              <Button type="submit" variant="secondary">
+                검색
+              </Button>
+            </div>
+          </form>
           <Table>
             <TableHeader>
               <TableRow>
-- 
GitLab