Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 67 additions & 37 deletions src/components/FileUpload.tsx
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -14,6 +14,8 @@ const FileUpload: React.FC<FileUploadProps> = ({ uploadUrl }) => {
const [error, setError] = useState<string | null>(null);
const [success, setSuccess] = useState<string | null>(null);
const [loading, setLoading] = useState(false);
const [uploadProgress, setUploadProgress] = useState<number>(0);


const handleFileChange = (files: File[]) => {
if (files.length > 0) {
Expand All @@ -25,46 +27,74 @@ const FileUpload: React.FC<FileUploadProps> = ({ 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);
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 = () => {
Expand Down Expand Up @@ -111,7 +141,7 @@ const FileUpload: React.FC<FileUploadProps> = ({ uploadUrl }) => {
</div>

<Button loading={loading} loaderProps={{ type: 'dots' }} onClick={handleUpload} style={{ marginTop: 10 }} disabled={loading}>Upload</Button>

<Progress value={uploadProgress}></Progress>
{success && (
<Notification color="green" onClose={() => setSuccess(null)} style={{ marginTop: 10 }}>
{success}
Expand Down
4 changes: 2 additions & 2 deletions src/components/PreviewCard.tsx
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down
7 changes: 4 additions & 3 deletions src/components/SearchBar.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -10,9 +10,10 @@ import { parseAsArrayOf, parseAsString, useQueryState } from "nuqs";

interface SearchBarWithFilterProps {
setSearch: React.Dispatch<React.SetStateAction<boolean>>;
distinctLocations: string[];
}

function SearchBarWithFilter({ setSearch }: SearchBarWithFilterProps) {
function SearchBarWithFilter({ setSearch, distinctLocations}: SearchBarWithFilterProps) {
const [searchTerm, setSearchTerm] = useQueryState(
"notes",
parseAsString.withDefault(""),
Expand Down Expand Up @@ -86,7 +87,7 @@ function SearchBarWithFilter({ setSearch }: SearchBarWithFilterProps) {
className="filter-select"
>
<option value="">All Locations</option>
{location.map((locationName, idx) => (
{distinctLocations.map((locationName, idx) => (
<option value={locationName.toLowerCase()} key={idx}>
{locationName}
</option>
Expand Down
13 changes: 0 additions & 13 deletions src/data/dataFilters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down
16 changes: 15 additions & 1 deletion src/routes/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ export default function Root() {
const [filteredData, setFilteredData] = useState<MCAPFileInformation[]>();
const [selectedRow, setSelectedRow] = useState<string>("");
const [selectedData, setSelectedData] = useState<MCAPFileInformation>();
const [distinctLocations, setDistinctLocations] = useState<string[]>([]);


const [searchTerm] = useQueryState("notes", parseAsString.withDefault(""));
const [selectedId] = useQueryState("id", parseAsString.withDefault(""));
Expand Down Expand Up @@ -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(() => {
Expand Down Expand Up @@ -142,7 +156,7 @@ export default function Root() {
/>
</div>

<SearchBar setSearch={setSearch} />
<SearchBar setSearch={setSearch} distinctLocations={distinctLocations}/>
</div>
<PreviewCard selectedRow={selectedRow} selectedData={selectedData} />
</>
Expand Down