From e511d4dc4a38efa8cc337e67afb5a5680f344fa0 Mon Sep 17 00:00:00 2001 From: Christine <132790780+aesteri@users.noreply.github.com> Date: Wed, 21 May 2025 20:55:13 -0700 Subject: [PATCH 1/3] added distinct location values in search query option --- src/components/PreviewCard.tsx | 4 ++-- src/components/SearchBar.tsx | 7 ++++--- src/data/dataFilters.ts | 13 ------------- src/routes/root.tsx | 16 +++++++++++++++- 4 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/components/PreviewCard.tsx b/src/components/PreviewCard.tsx index aea5158..9362431 100644 --- a/src/components/PreviewCard.tsx +++ b/src/components/PreviewCard.tsx @@ -1,6 +1,6 @@ import { useState } from "react"; -import EditInfo from "./EditInfo"; -import DeleteData from "./DeleteData"; +import EditInfo from "@/components/EditInfo"; +import DeleteData from "@/components/DeleteData"; //import MatFileUpload from "./MatFileUpload"; // used for uploading mat and h5 files import { diff --git a/src/components/SearchBar.tsx b/src/components/SearchBar.tsx index 0d4ce98..5d39b98 100644 --- a/src/components/SearchBar.tsx +++ b/src/components/SearchBar.tsx @@ -1,7 +1,7 @@ import React from "react"; // Lists of available filter options -import { eventType, location, carModel } from "@/data/dataFilters"; +import { eventType, carModel } from "@/data/dataFilters"; import "@/css/SearchBar.css"; import { Button, MultiSelect } from "@mantine/core"; import { parseAsArrayOf, parseAsString, useQueryState } from "nuqs"; @@ -10,9 +10,10 @@ import { parseAsArrayOf, parseAsString, useQueryState } from "nuqs"; interface SearchBarWithFilterProps { setSearch: React.Dispatch>; + distinctLocations: string[]; } -function SearchBarWithFilter({ setSearch }: SearchBarWithFilterProps) { +function SearchBarWithFilter({ setSearch, distinctLocations}: SearchBarWithFilterProps) { const [searchTerm, setSearchTerm] = useQueryState( "notes", parseAsString.withDefault(""), @@ -86,7 +87,7 @@ function SearchBarWithFilter({ setSearch }: SearchBarWithFilterProps) { className="filter-select" > - {location.map((locationName, idx) => ( + {distinctLocations.map((locationName, idx) => ( diff --git a/src/data/dataFilters.ts b/src/data/dataFilters.ts index 0753bdc..5df6db4 100644 --- a/src/data/dataFilters.ts +++ b/src/data/dataFilters.ts @@ -11,19 +11,6 @@ export const eventType: string[] = [ "Autocross", // Event type for autocross tests. ]; -/** - * Represents the list of possible locations. - * - * These are predefined locations where events have occurred. - * This constant can be used for filtering data or displaying location options in Storybook components. - */ -export const location: string[] = [ - "MRDC", // Location for the MRDC event. - "Michigan", // Location for the Michigan event. - "Rome", // Location for the Rome event. - "SCC", // Location for the SCC event. -]; - /** * Represents the list of possible car models. * diff --git a/src/routes/root.tsx b/src/routes/root.tsx index 2265aa8..9bb4292 100644 --- a/src/routes/root.tsx +++ b/src/routes/root.tsx @@ -9,6 +9,8 @@ export default function Root() { const [filteredData, setFilteredData] = useState(); const [selectedRow, setSelectedRow] = useState(""); const [selectedData, setSelectedData] = useState(); + const [distinctLocations, setDistinctLocations] = useState([]); + const [searchTerm] = useQueryState("notes", parseAsString.withDefault("")); const [selectedId] = useQueryState("id", parseAsString.withDefault("")); @@ -102,6 +104,18 @@ export default function Root() { }, ); setFilteredData(sortedData); + + const allLocationsIncludingNulls: (string | null | undefined)[] = data.map( + (item: MCAPFileInformation) => item.location + ); + const extractedLocations: string[] = allLocationsIncludingNulls.filter( + (loc): loc is string => { + return loc != null && loc.trim() !== ""; + } + ); + const uniqueLocations = Array.from(new Set(extractedLocations)); + + setDistinctLocations(uniqueLocations); }; useEffect(() => { @@ -142,7 +156,7 @@ export default function Root() { /> - + From e30aa9315f1c1cb20e5481b904fc16ac589e3265 Mon Sep 17 00:00:00 2001 From: Christine <132790780+aesteri@users.noreply.github.com> Date: Wed, 21 May 2025 21:12:02 -0700 Subject: [PATCH 2/3] added progress bar --- src/components/FileUpload.tsx | 106 ++++++++++++++++++++++------------ 1 file changed, 69 insertions(+), 37 deletions(-) diff --git a/src/components/FileUpload.tsx b/src/components/FileUpload.tsx index 5dd43e6..643d16d 100644 --- a/src/components/FileUpload.tsx +++ b/src/components/FileUpload.tsx @@ -1,5 +1,5 @@ import React, { useState } from "react"; -import { Modal, Button, Notification, FileInput } from "@mantine/core"; +import { Modal, Button, Notification, FileInput, Progress} from "@mantine/core"; import "@/css/FileUpload.css"; // File upload Modal and Button @@ -14,6 +14,8 @@ const FileUpload: React.FC = ({ uploadUrl }) => { const [error, setError] = useState(null); const [success, setSuccess] = useState(null); const [loading, setLoading] = useState(false); + const [uploadProgress, setUploadProgress] = useState(0); + const handleFileChange = (files: File[]) => { if (files.length > 0) { @@ -25,46 +27,76 @@ const FileUpload: React.FC = ({ uploadUrl }) => { setLoading(true); setError(null); setSuccess(null); - if (selectedFiles.length > 0) { - try { - const formData = new FormData(); - selectedFiles.forEach((file) => { - formData.append('files', file); - }); + setUploadProgress(0); + const xhr = new XMLHttpRequest(); + const formData = new FormData(); + selectedFiles.forEach((file) => { + formData.append('files', file, file.name); + }); + + xhr.upload.onprogress = (event) => { + if (event.lengthComputable) { + const percentComplete = Math.round((event.loaded / event.total) * 100); + setUploadProgress(percentComplete); + } + }; + + xhr.onloadstart = () => { + setUploadProgress(0); + }; + + xhr.onload = () => { + setLoading(false); + if (xhr.status >= 200 && xhr.status < 300) { try { - const response = await fetch(uploadUrl, { - method: 'POST', - body: formData, - }); - - if (!response.ok) { - if (response.status === 503) { - const errorMsg = await response.text(); - setError( - `Failed to upload: ${errorMsg} \nTry again in a few minutes!`, - ); - } else { - const errorMsg = await response.text(); - setError(`Failed to upload: ${errorMsg}`); - } - } else { - const result = await response.json(); - setSuccess("File uploaded successfully!"); - console.log("Upload successful:", result); - } - } catch (error) { - console.error("Error uploading files:", error); - setError("An error occurred during file upload."); + const result = JSON.parse(xhr.responseText); + setSuccess("File(s) uploaded successfully!"); + console.log("Upload successful:", result); + setSelectedFiles([]); + setUploadProgress(100); + setTimeout(() => setUploadProgress(0), 2000); + } catch (e) { + console.error("Error parsing server response:", e); + setError("Uploaded successfully, but couldn't parse server response."); + setUploadProgress(0); } - - setSelectedFiles([]); - } catch (error) { - console.error("Upload failed:", error); - setError("An error occurred while uploading. Please try again."); + } else { + let errorMsg = xhr.responseText || `Server responded with status ${xhr.status}`; + if (xhr.status === 503) { + errorMsg = `${errorMsg} \nTry again in a few minutes!`; + } + setError(`Failed to upload: ${errorMsg}`); + console.error("Upload failed with status:", xhr.status, xhr.responseText); + setUploadProgress(0); } + }; + + xhr.onerror = () => { + setLoading(false); + setError("An error occurred during the upload. Please check your network connection and try again."); + console.error("XHR onerror triggered"); + setUploadProgress(0); + }; + + xhr.onabort = () => { + setLoading(false); + setError("Upload was aborted."); + console.log("XHR onabort triggered"); + setUploadProgress(0); + }; + + try { + xhr.open('POST', uploadUrl, true); + // If your server requires specific headers (e.g., for authentication), set them here: + // xhr.setRequestHeader('Authorization', 'Bearer YOUR_TOKEN'); + xhr.send(formData); + } catch (e) { + setLoading(false); + setError("An unexpected error occurred before sending the request."); + console.error("Error opening or sending XHR:", e); + setUploadProgress(0); } - setLoading(false); }; const toggleModal = () => { @@ -111,7 +143,7 @@ const FileUpload: React.FC = ({ uploadUrl }) => { - + {success && ( setSuccess(null)} style={{ marginTop: 10 }}> {success} From 336de3e1f5c307a3a849dc12af8e03271e5df9f5 Mon Sep 17 00:00:00 2001 From: Christine <132790780+aesteri@users.noreply.github.com> Date: Wed, 21 May 2025 21:12:57 -0700 Subject: [PATCH 3/3] added progress bar --- src/components/FileUpload.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/components/FileUpload.tsx b/src/components/FileUpload.tsx index 643d16d..1ba236a 100644 --- a/src/components/FileUpload.tsx +++ b/src/components/FileUpload.tsx @@ -88,8 +88,6 @@ const FileUpload: React.FC = ({ uploadUrl }) => { try { xhr.open('POST', uploadUrl, true); - // If your server requires specific headers (e.g., for authentication), set them here: - // xhr.setRequestHeader('Authorization', 'Bearer YOUR_TOKEN'); xhr.send(formData); } catch (e) { setLoading(false);