From b3627406f7ce986c65dd74798420ed8c96e26b03 Mon Sep 17 00:00:00 2001
From: Kira Claw
Date: Mon, 16 Feb 2026 08:33:14 -0600
Subject: [PATCH] Add error handling and loading states to App component
- Added error state for API failures with user-friendly messages
- Added loading state to indicate when operations are in progress
- Wrapped all async operations (fetchFiles, loadFile, handleUpload) in try/catch
- Added visual error banner with red styling
- Added Loading indicator
- Disabled controls during loading states
- Validates data response format before rendering charts
---
frontend/src/App.jsx | 87 ++++++++++++++++++++++++++++++++++++++------
1 file changed, 76 insertions(+), 11 deletions(-)
diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx
index 585ebb3..0e569ea 100644
--- a/frontend/src/App.jsx
+++ b/frontend/src/App.jsx
@@ -8,29 +8,66 @@ function App() {
const [files, setFiles] = useState([]);
const [data, setData] = useState([]);
const [selectedFile, setSelectedFile] = useState("");
+ const [loading, setLoading] = useState(false);
+ const [error, setError] = useState(null);
useEffect(() => {
- axios.get(`${API}/files`).then((res) => setFiles(res.data.files));
+ fetchFiles();
}, []);
- const loadFile = (filename) => {
+ const fetchFiles = async () => {
+ try {
+ setError(null);
+ const res = await axios.get(`${API}/files`);
+ setFiles(res.data.files);
+ } catch (err) {
+ setError("Failed to load file list. Is the backend running?");
+ }
+ };
+
+ const loadFile = async (filename) => {
if (!filename) {
setSelectedFile("");
setData([]);
return;
}
+ setLoading(true);
+ setError(null);
setSelectedFile(filename);
- axios.get(`${API}/data/${filename}`).then((res) => setData(res.data));
+ try {
+ const res = await axios.get(`${API}/data/${filename}`);
+ if (Array.isArray(res.data)) {
+ setData(res.data);
+ } else if (res.data.error) {
+ setError(`File error: ${res.data.error}`);
+ setData([]);
+ } else {
+ setError("Invalid data format from server");
+ setData([]);
+ }
+ } catch (err) {
+ setError(`Failed to load data for "${filename}"`);
+ setData([]);
+ } finally {
+ setLoading(false);
+ }
};
const handleUpload = async (e) => {
const file = e.target.files?.[0];
if (!file) return;
- const formData = new FormData();
- formData.append("file", file);
- await axios.post(`${API}/upload`, formData);
- const res = await axios.get(`${API}/files`);
- setFiles(res.data.files);
+ setLoading(true);
+ setError(null);
+ try {
+ const formData = new FormData();
+ formData.append("file", file);
+ await axios.post(`${API}/upload`, formData);
+ await fetchFiles();
+ } catch (err) {
+ setError("Failed to upload file");
+ } finally {
+ setLoading(false);
+ }
};
return (
@@ -40,14 +77,42 @@ function App() {
Calories in vs. calories burned per week
+ {error && (
+
+ ⚠️ {error}
+
+ )}
+
+ {loading && (
+
+ Loading...
+
+ )}
+
Select File
-
- {data.length > 0 && }
+ {data.length > 0 && !loading && }
);
}