diff --git a/web/admin/src/components/admin/admin-screens.tsx b/web/admin/src/components/admin/admin-screens.tsx index 2e18089..0e91226 100644 --- a/web/admin/src/components/admin/admin-screens.tsx +++ b/web/admin/src/components/admin/admin-screens.tsx @@ -605,11 +605,18 @@ export function AdminIntegrationsScreen() { }); }, [data]); + const list = gateways.length > 0 ? gateways : data?.paymentGateways ?? []; + const save = useMutation({ mutationFn: () => adminPut("/api/admin/integrations", { activePaymentGateway: activeGateway, - paymentGateways: gateways.map((g) => ({ + // Save from `list` (what's rendered/edited), not `gateways` — if the + // gateways state hasn't hydrated, `list` falls back to the fetched data, + // and edits go through updateGateway which seeds it. This keeps the + // rendered, edited, and saved arrays the same source (was dropping + // edits like the Zarinpal merchantId when gateways was empty). + paymentGateways: list.map((g) => ({ id: g.id, isEnabled: g.isEnabled, merchantId: g.id === "zarinpal" ? g.merchantId : undefined, @@ -638,11 +645,14 @@ export function AdminIntegrationsScreen() { }); const updateGateway = (id: string, patch: Partial) => { - setGateways((prev) => prev.map((g) => (g.id === id ? { ...g, ...patch } : g))); + setGateways((prev) => { + // Seed from fetched data on the first edit so an edit is never dropped + // because the state hadn't hydrated yet. + const base = prev.length > 0 ? prev : data?.paymentGateways?.map((g) => ({ ...g })) ?? []; + return base.map((g) => (g.id === id ? { ...g, ...patch } : g)); + }); }; - const list = gateways.length > 0 ? gateways : data?.paymentGateways ?? []; - return (