improve: use react-query for caching
This commit is contained in:
@@ -1,70 +1,60 @@
|
||||
// src/components/PathManager.js
|
||||
|
||||
import React, { useEffect, useState, useRef } from "react";
|
||||
import { fetch_ } from "../utils/requestUtils";
|
||||
import config from "../config";
|
||||
import { useCreatePath, usePaths } from "../utils/path-queries";
|
||||
import { useQueryClient } from "react-query";
|
||||
import "./PathManager.css";
|
||||
import {fetch_} from "../utils/request-utils";
|
||||
import config from "../config";
|
||||
|
||||
const PathManager = ({ currentPathId = 1, onPathChange }) => {
|
||||
const [currentPath, setCurrentPath] = useState([{ name: "Root", id: 1 }]);
|
||||
//const [currentPath, setCurrentPath] = useState(buildPath(currentPathId));
|
||||
const [currentId, setCurrentId] = useState(currentPathId);
|
||||
const [subPaths, setSubPaths] = useState([]);
|
||||
const [searchTerm, setSearchTerm] = useState("");
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [dropdownActive, setDropdownActive] = useState(false);
|
||||
|
||||
const inputRef = useRef();
|
||||
|
||||
const buildPath = async (path_id) => {
|
||||
const path = [];
|
||||
let current_id = path_id;
|
||||
while (current_id) {
|
||||
const pathData = await fetch_(`${config.BACKEND_HOST}/api/path/${current_id}`, {},{
|
||||
use_cache: true,
|
||||
use_token: false,
|
||||
});
|
||||
current_id = pathData.parent_id;
|
||||
path.unshift(pathData);
|
||||
const queryClient = useQueryClient();
|
||||
const { data: subPaths, isLoading: isSubPathsLoading, error: subPathsError } = usePaths(currentPathId);
|
||||
const createPath = useCreatePath();
|
||||
|
||||
const buildPath = async (pathId) => {
|
||||
const path = [];
|
||||
let current_id = pathId;
|
||||
while (current_id) {
|
||||
try {
|
||||
const pathData = await queryClient.fetchQuery(
|
||||
["path", current_id],
|
||||
() => fetch_(`${config.BACKEND_HOST}/api/path/${current_id}`)
|
||||
);
|
||||
if (!pathData) break;
|
||||
path.unshift({ name: pathData.name, id: pathData.id });
|
||||
current_id = pathData.parent_id;
|
||||
} catch (error) {
|
||||
console.error(`Failed to fetch path with id ${current_id}:`, error);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
fetchSubPaths(currentId);
|
||||
}, [currentId]);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const init = async () => {
|
||||
const pth = await buildPath(currentPathId);
|
||||
setCurrentPath(pth);
|
||||
const path = await buildPath(currentPathId);
|
||||
setCurrentPath(path);
|
||||
};
|
||||
init();
|
||||
|
||||
}, [currentPathId]);
|
||||
|
||||
const fetchSubPaths = (pathId) => {
|
||||
setLoading(true);
|
||||
fetch_(`${config.BACKEND_HOST}/api/path/parent/${pathId}`, {}, {
|
||||
use_cache: false,
|
||||
use_token: true
|
||||
})
|
||||
.then((data) => setSubPaths(data))
|
||||
.catch((error) => console.error("Failed to fetch subdirectories:", error))
|
||||
.finally(() => setLoading(false));
|
||||
};
|
||||
}, [currentPathId, queryClient]);
|
||||
|
||||
const handlePathClick = (pathId, pathIndex) => {
|
||||
const newPath = currentPath.slice(0, pathIndex + 1);
|
||||
setCurrentPath(newPath);
|
||||
setCurrentId(pathId);
|
||||
onPathChange(pathId);
|
||||
};
|
||||
|
||||
const handleSubPathSelect = (subPath) => {
|
||||
const updatedPath = [...currentPath, { name: subPath.name, id: subPath.id }];
|
||||
setCurrentPath(updatedPath);
|
||||
setCurrentId(subPath.id);
|
||||
onPathChange(subPath.id);
|
||||
setSearchTerm("");
|
||||
setDropdownActive(false);
|
||||
@@ -75,32 +65,44 @@ const PathManager = ({ currentPathId = 1, onPathChange }) => {
|
||||
alert("Directory name cannot be empty.");
|
||||
return;
|
||||
}
|
||||
fetch_(`${config.BACKEND_HOST}/api/path/`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ name: searchTerm.trim(), parent_id: currentId }),
|
||||
}, { use_cache: false, use_token: true })
|
||||
.then((newDir) => {
|
||||
setSubPaths([...subPaths, newDir]);
|
||||
setSearchTerm("");
|
||||
alert("Directory created successfully!");
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Failed to create directory:", error);
|
||||
alert("Failed to create directory.");
|
||||
});
|
||||
|
||||
createPath.mutate(
|
||||
{ name: searchTerm.trim(), parent_id: currentPathId },
|
||||
{
|
||||
onSuccess: (newDir) => {
|
||||
queryClient.setQueryData(["path", newDir.id], newDir);
|
||||
queryClient.invalidateQueries(["paths", currentPathId]);
|
||||
setSearchTerm("");
|
||||
alert("Directory created successfully.");
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error("Failed to create directory:", error);
|
||||
alert("Failed to create directory.");
|
||||
},
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const handleInputFocus = () => setDropdownActive(true);
|
||||
|
||||
const handleInputBlur = () => {
|
||||
setTimeout(() => setDropdownActive(false), 150);
|
||||
};
|
||||
|
||||
const filteredSubPaths = subPaths.filter((path) =>
|
||||
path.name.toLowerCase().includes(searchTerm.toLowerCase())
|
||||
);
|
||||
const filteredSubPaths = subPaths
|
||||
? subPaths.filter((path) =>
|
||||
path.name.toLowerCase().includes(searchTerm.toLowerCase())
|
||||
)
|
||||
: [];
|
||||
|
||||
const handleKeyDown = (e) => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
handleAddDirectory();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
<div className="path-manager">
|
||||
<div className="path-manager-header">
|
||||
<div className="current-path">
|
||||
@@ -129,13 +131,14 @@ const PathManager = ({ currentPathId = 1, onPathChange }) => {
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
onFocus={handleInputFocus}
|
||||
onBlur={handleInputBlur}
|
||||
onKeyDown={handleKeyDown}
|
||||
/>
|
||||
</div>
|
||||
<div className="control">
|
||||
<button
|
||||
className="button is-small is-primary"
|
||||
onClick={handleAddDirectory}
|
||||
disabled={loading || !searchTerm.trim()}
|
||||
disabled={isSubPathsLoading || !searchTerm.trim()}
|
||||
type="button"
|
||||
>
|
||||
Create "{searchTerm}"
|
||||
@@ -163,6 +166,8 @@ const PathManager = ({ currentPathId = 1, onPathChange }) => {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{isSubPathsLoading && <p>Loading...</p>}
|
||||
{subPathsError && <p>Error loading subdirectories.</p>}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user