diff --git a/src/components/admin/admin-cards-section.tsx b/src/components/admin/admin-cards-section.tsx
index 3e1ae35..bc4c6e6 100644
--- a/src/components/admin/admin-cards-section.tsx
+++ b/src/components/admin/admin-cards-section.tsx
@@ -22,7 +22,6 @@ import { CardBadges } from "@/components/card-badges";
import { ColumnFilterCombobox } from "@/components/column-filter-combobox";
import { PaginationControls } from "@/components/data-table/pagination-controls";
import { Button } from "@/components/ui/button";
-import { Input } from "@/components/ui/input";
import {
Table,
TableBody,
@@ -39,7 +38,8 @@ import {
DialogFooter,
} from "@/components/ui/dialog";
import { AdminFeedback } from "@/components/admin/admin-feedback";
-import { Plus, Pencil, Trash2, Search } from "lucide-react";
+import { Plus, Pencil, Trash2 } from "lucide-react";
+import { CollectionSearchInput } from "@/components/collection-search-input";
import { useTranslations } from "@/i18n/client";
import { useCollectionUrlFilters } from "@/hooks/use-collection-url-filters";
import { useCardBadgeLabels } from "@/hooks/use-card-badge-labels";
@@ -242,18 +242,14 @@ export function AdminCardsSection({
onSuccessDismiss={() => setSuccess(null)}
/>
-
-
-
- updateFilters({ search: e.target.value, page: 1 })
- }
- className="pl-9"
- aria-label={t("admin.cards.search")}
- />
-
+
+ applyAdminFilters({ search: value }, { immediate: true })
+ }
+ label={t("admin.cards.search")}
+ placeholder={t("admin.cards.search")}
+ />
void;
- label: string;
- placeholder: string;
-}) {
- const [inputValue, setInputValue] = useState(urlValue);
- const [prevUrlValue, setPrevUrlValue] = useState(urlValue);
- // Tracks the value we last sent via onSearch — distinguishes our own
- // URL updates from external navigation/resets.
- const [sentValue, setSentValue] = useState(urlValue);
- const debounceRef = useRef | null>(null);
-
- // getDerivedStateFromProps: sync input when URL changes externally.
- if (prevUrlValue !== urlValue) {
- setPrevUrlValue(urlValue);
- if (sentValue !== urlValue) {
- setInputValue(urlValue);
- }
- }
-
- function handleChange(newValue: string) {
- setInputValue(newValue);
- if (debounceRef.current) clearTimeout(debounceRef.current);
- debounceRef.current = setTimeout(() => {
- setSentValue(newValue);
- onSearch(newValue);
- }, 300);
- }
-
- return (
-
- );
-}
-
const SORT_COLUMN_KEYS = [
"player",
"team",
@@ -308,7 +253,7 @@ export function CardTable({
return (
-
updateFilters({ search: value }, { immediate: true })
diff --git a/src/components/collection-search-input.tsx b/src/components/collection-search-input.tsx
new file mode 100644
index 0000000..01100f5
--- /dev/null
+++ b/src/components/collection-search-input.tsx
@@ -0,0 +1,53 @@
+"use client";
+
+import { useRef, useState } from "react";
+import { SearchField } from "@/components/search-field";
+
+/**
+ * Champ de recherche collection/admin : état local + debounce 300 ms,
+ * puis sync URL via le callback parent (`immediate: true` recommandé).
+ */
+export function CollectionSearchInput({
+ urlValue,
+ onSearch,
+ label,
+ placeholder,
+ className,
+}: {
+ urlValue: string;
+ onSearch: (value: string) => void;
+ label: string;
+ placeholder: string;
+ className?: string;
+}) {
+ const [inputValue, setInputValue] = useState(urlValue);
+ const [prevUrlValue, setPrevUrlValue] = useState(urlValue);
+ const [sentValue, setSentValue] = useState(urlValue);
+ const debounceRef = useRef | null>(null);
+
+ if (prevUrlValue !== urlValue) {
+ setPrevUrlValue(urlValue);
+ if (sentValue !== urlValue) {
+ setInputValue(urlValue);
+ }
+ }
+
+ function handleChange(newValue: string) {
+ setInputValue(newValue);
+ if (debounceRef.current) clearTimeout(debounceRef.current);
+ debounceRef.current = setTimeout(() => {
+ setSentValue(newValue);
+ onSearch(newValue);
+ }, 300);
+ }
+
+ return (
+
+ );
+}