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