B6: SPA navigation after case creation (useNavigate instead of window.location.href)

B7: stop AdminDashboard refetching the case list on selection change

selectedCaseId was both read and written inside the list-loading effect and
listed in its deps, causing a second fetch on first render and after every
filter reset. Auto-select now uses a functional state update, so the effect
no longer depends on selectedCaseId; editForm stays in sync via the existing
selectedCase effect.
This commit is contained in:
root
2026-07-25 13:04:19 +00:00
parent 8b3a2cbf7e
commit 3a0d2b0c2d
2 changed files with 17 additions and 9 deletions
@@ -1,4 +1,5 @@
import React, { useState } from "react"; import React, { useState } from "react";
import { useNavigate } from "react-router-dom";
import Step1Child from "./Step1Child"; import Step1Child from "./Step1Child";
import Step2Health from "./Step2Health"; import Step2Health from "./Step2Health";
import Step2bPsychotype from "./Step2bPsychotype"; import Step2bPsychotype from "./Step2bPsychotype";
@@ -16,6 +17,7 @@ const INITIAL_DATA = {
}; };
const CaseForm = ({ isMobile = false }) => { const CaseForm = ({ isMobile = false }) => {
const navigate = useNavigate();
const [currentStep, setCurrentStep] = useState(1); const [currentStep, setCurrentStep] = useState(1);
const [formData, setFormData] = useState(INITIAL_DATA); const [formData, setFormData] = useState(INITIAL_DATA);
const [errors, setErrors] = useState([]); const [errors, setErrors] = useState([]);
@@ -117,8 +119,9 @@ const CaseForm = ({ isMobile = false }) => {
const result = await response.json(); const result = await response.json();
// Перенаправляем на страницу анализа с ID карточки // Перенаправляем на страницу анализа с ID карточки.
window.location.href = `/analysis/${result.id}`; // SPA-переход: полная перезагрузка теряла состояние приложения.
navigate(`/analysis/${result.id}`);
} catch (err) { } catch (err) {
setErrors([err.message || "Ошибка при отправке данных"]); setErrors([err.message || "Ошибка при отправке данных"]);
+10 -5
View File
@@ -76,11 +76,16 @@ function AdminDashboard() {
throw new Error(`Не удалось загрузить список кейсов (${response.status})`); throw new Error(`Не удалось загрузить список кейсов (${response.status})`);
} }
const payload = await response.json(); const payload = await response.json();
setCases(payload.items || []); const items = payload.items || [];
setCases(items);
setTotal(payload.total || 0); setTotal(payload.total || 0);
if ((payload.items || []).length && !selectedCaseId) { // Auto-select the first row only when nothing is selected yet.
setSelectedCaseId(payload.items[0].id); // Functional update so this effect does not have to read (and depend
setEditForm(payload.items[0]); // on) selectedCaseId — depending on it caused a second fetch on first
// render and after every filter reset. editForm is kept in sync by the
// selectedCase effect below.
if (items.length) {
setSelectedCaseId((current) => current || items[0].id);
} }
} catch (err) { } catch (err) {
if (err.name !== 'AbortError') { if (err.name !== 'AbortError') {
@@ -93,7 +98,7 @@ function AdminDashboard() {
loadCases(); loadCases();
return () => controller.abort(); return () => controller.abort();
}, [filters.ageMax, filters.ageMin, filters.status, page, selectedCaseId]); }, [filters.ageMax, filters.ageMin, filters.status, page]);
useEffect(() => { useEffect(() => {
const controller = new AbortController(); const controller = new AbortController();