From 8a8cff4c4c4e0b83e40edacc4d2e9149c2b55711 Mon Sep 17 00:00:00 2001 From: Matt Date: Tue, 12 May 2026 23:37:30 +0200 Subject: [PATCH] fix(compiler): migrate custom-fields-manager to useQuery MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit set-state-in-effect: 44 → 43. Eight admin list/load sites migrated total this session; the remaining ~43 hits are predominantly the dialog/form open→reset pattern (intentional setState-in-effect when a dialog opens to populate fields from props). Cleanest fix is key-based remount of the dialog body; tracked in BACKLOG as a focused refactor pass. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../custom-fields/custom-fields-manager.tsx | 45 +++++++++---------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/src/components/admin/custom-fields/custom-fields-manager.tsx b/src/components/admin/custom-fields/custom-fields-manager.tsx index 15bd7106..cbc625b6 100644 --- a/src/components/admin/custom-fields/custom-fields-manager.tsx +++ b/src/components/admin/custom-fields/custom-fields-manager.tsx @@ -1,6 +1,7 @@ 'use client'; -import { useState, useCallback, useEffect } from 'react'; +import { useState } from 'react'; +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { type ColumnDef } from '@tanstack/react-table'; import { Pencil, Trash2, Plus } from 'lucide-react'; @@ -33,27 +34,29 @@ const FIELD_TYPE_LABELS: Record = { // ─── Component ──────────────────────────────────────────────────────────────── +const FIELDS_QUERY_KEY = ['admin', 'custom-fields'] as const; + export function CustomFieldsManager() { + const queryClient = useQueryClient(); const [activeTab, setActiveTab] = useState('client'); - const [fields, setFields] = useState([]); - const [loading, setLoading] = useState(true); const [formOpen, setFormOpen] = useState(false); const [editingField, setEditingField] = useState(null); - const [deletingId, setDeletingId] = useState(null); - const fetchFields = useCallback(async () => { - setLoading(true); - try { - const res = await apiFetch<{ data: CustomFieldDefinition[] }>('/api/v1/admin/custom-fields'); - setFields(res.data); - } finally { - setLoading(false); - } - }, []); + const { data: fields = [], isLoading: loading } = useQuery({ + queryKey: FIELDS_QUERY_KEY, + queryFn: () => + apiFetch<{ data: CustomFieldDefinition[] }>('/api/v1/admin/custom-fields').then( + (r) => r.data, + ), + }); - useEffect(() => { - void fetchFields(); - }, [fetchFields]); + const fetchFields = () => queryClient.invalidateQueries({ queryKey: FIELDS_QUERY_KEY }); + + const deleteMutation = useMutation({ + mutationFn: (id: string) => apiFetch(`/api/v1/admin/custom-fields/${id}`, { method: 'DELETE' }), + onSuccess: () => fetchFields(), + }); + const deletingId = deleteMutation.isPending ? deleteMutation.variables : null; const filteredFields = fields.filter((f) => f.entityType === activeTab); @@ -67,14 +70,8 @@ export function CustomFieldsManager() { setFormOpen(true); } - async function handleDelete(id: string) { - setDeletingId(id); - try { - await apiFetch(`/api/v1/admin/custom-fields/${id}`, { method: 'DELETE' }); - await fetchFields(); - } finally { - setDeletingId(null); - } + function handleDelete(id: string) { + deleteMutation.mutate(id); } function getDeleteDescription(field: CustomFieldDefinition): string {