Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
a10d02e
Added DialogMain, PendingBatchCard, DialogNewBatchCard Component
ZyuT0h Aug 11, 2025
2253ecd
Modified PBC to have artefactCount instead of status
ZyuT0h Aug 12, 2025
2b2a80b
Added Custom FileUpload Button and Show File List
ZyuT0h Aug 12, 2025
bcfcee1
Custom FileItem Component to show error/sucess status of file(s)
ZyuT0h Aug 12, 2025
4122d91
Fixed batch number and Added Responsiveness
ZyuT0h Aug 12, 2025
b734750
Modified to change state instead of nested dialog
ZyuT0h Aug 12, 2025
c6e5b16
Added UploadExisting State, force user to clear before adding new fil…
ZyuT0h Aug 12, 2025
934d084
Modified from showing BatchID to BatchNumber
ZyuT0h Aug 12, 2025
0fab603
Cleaned up codes
ZyuT0h Aug 13, 2025
c8ac5c9
Added Done Button to be visible only after file successfully uploaded…
ZyuT0h Aug 13, 2025
0f9242b
Modified to auto update changes of batches
ZyuT0h Aug 13, 2025
03a52dc
Modified DialogUploadFile instead of batchid shows the batchcard
ZyuT0h Aug 13, 2025
ceb4215
Added isLoading, loadingText to show loading msg while uploading
ZyuT0h Aug 13, 2025
afe19b1
Deleted DialogUpload, Changed name for DialogMain to UploadArtefact
ZyuT0h Aug 13, 2025
712adb4
Change function name from DialogName to UploadArtefact
ZyuT0h Aug 13, 2025
dfd5446
Change import from DialogMain to UploadArtefact
ZyuT0h Aug 13, 2025
963dad3
Merge pull request #29 from ArchAIve-Project/junhan
Prakhar896 Aug 13, 2025
2260577
Change File & Function Name, added toastwizard
ZyuT0h Aug 13, 2025
b89adc8
Remove redundant filtering and filter while fetching the batch
ZyuT0h Aug 13, 2025
2144243
Removed Done Button
ZyuT0h Aug 13, 2025
c8fc006
Merge pull request #30 from ArchAIve-Project/zhengyu
Prakhar896 Aug 13, 2025
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
224 changes: 224 additions & 0 deletions src/components/DataImport/ArtefactUploadView.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
import { Button, Flex, Box, Text } from "@chakra-ui/react";
import { useEffect, useRef, useState } from "react";
import { HiUpload } from "react-icons/hi";
import server from "../../networking";
import ToastWizard from "../toastWizard";
import FileItem from "./FileItem";
import { IoArrowBackCircleSharp } from "react-icons/io5";
import PendingBatchCard from "./PendingBatchCard";
import hp1 from "../../assets/hp1.png";

function ArtefactUploadView({ batch, setBatchID, onClose, fetchBatches, onBackToPending }) {
const batchID = batch?.id;
const fileInputRef = useRef(null);
const [isSubmitting, setIsSubmitting] = useState(false);
const [selectedFiles, setSelectedFiles] = useState([]);
const [fileStatuses, setFileStatuses] = useState({});

const handleButtonClick = () => {
fileInputRef.current?.click();
};

const handleFileChange = (event) => {
const files = Array.from(event.target.files);
if (files.length > 0) {
setSelectedFiles((prev) => [...prev, ...files]);
// Clear statuses for newly added files
const newStatuses = { ...fileStatuses };
files.forEach((file) => {
delete newStatuses[file.name];
});
setFileStatuses(newStatuses);
}
};

const removeFile = (fileToRemove) => {
setSelectedFiles((prev) => prev.filter((file) => file !== fileToRemove));
setFileStatuses((prev) => {
const updated = { ...prev };
delete updated[fileToRemove.name];
return updated;
});
};

const clearAll = () => {
setSelectedFiles([]);
setFileStatuses({});
};

const hasPreviousStatus = selectedFiles.some(file => fileStatuses[file.name]);

const isDisabled =
selectedFiles.length === 0 ||
isSubmitting ||
hasPreviousStatus;

const handleUpload = async () => {
if (selectedFiles.length === 0 || isSubmitting) {
ToastWizard.standard("warning", "No Files Selected", "Please choose at least one file before uploading.");
return;
}

const formData = new FormData();
selectedFiles.forEach((file) => {
formData.append("file", file);
});

if (batchID) {
formData.append("batchID", batchID);
}

setIsSubmitting(true);

try {
const res = await server.post("/dataImport/upload", formData, {
headers: { "Content-Type": "multipart/form-data" },
transformRequest: formData => formData
});

const data = res.data;
const updates = data.raw?.updates || {};
const returnedBatchID = data.raw?.batchID;

if (returnedBatchID) {
setBatchID(returnedBatchID);
}
setFileStatuses(updates);
fetchBatches();

ToastWizard.standard(
"success",
"Upload Complete",
`Uploaded files to Batch ${returnedBatchID || '<Unknown ID>'}. Ready for processing.`
);
} catch (err) {
console.log(`Non-success response in file upload to batch ${batchID || 'New Batch'}`, err)
const updates = err?.response?.data?.raw?.updates;
if (updates) {
setFileStatuses(updates);
} else {
// If no detailed errors, mark all files as failed
const fallbackStatus = {};
selectedFiles.forEach((file) => {
fallbackStatus[file.name] = "ERROR: Failed to upload.";
});
setFileStatuses(fallbackStatus);
}

ToastWizard.standard("error", "Upload Failed", "Some or all files failed to upload.");
} finally {
setIsSubmitting(false);
}
};

useEffect(() => {
return () => {
clearAll();
}
}, []);

return (
<>
<Flex mb={{ base: 4, md: 6 }}>
<Box>
<Button
variant="ghost"
size={{ base: "sm", md: "md" }}
onClick={() => {
clearAll();
setBatchID(null);
onBackToPending();
}}
>
<IoArrowBackCircleSharp />
</Button>

</Box>
<Box ml={{ base: 5, md: 4 }}>
<PendingBatchCard
batchName={batch?.name || "New Batch"}
artefactCount={batch?.artefactCount || 0}
timestamp={batch?.created || new Date().toLocaleString()}
thumbnail={batch?.thumbnail || hp1}
/>
</Box>
</Flex >
<input
type="file"
accept=".png,.jpg,jpeg"
multiple
ref={fileInputRef}
onChange={handleFileChange}
style={{ display: "none" }}
/>

<Button
leftIcon={<HiUpload />}
variant="outline"
width={{ base: "400px", md: "full" }}
justifyContent="start"
mb={4}
onClick={handleButtonClick}
>
Choose Files
</Button>

{
selectedFiles.length > 0 && (
<Box mb={4}>
<Flex justify="space-between" align="center" mb={2}>
<Text fontSize="sm" fontWeight="medium">
{selectedFiles.length} file(s) selected
</Text>
<Button size="xs" variant="ghost" colorScheme="red" onClick={clearAll}>
Remove All
</Button>
</Flex>

<Box
borderWidth="1px"
borderRadius="md"
p={2}
maxHeight="200px"
overflowY="auto"
bg="gray.50"
>
{selectedFiles.map((file, index) => (
<FileItem
key={index}
file={file}
statusMsg={fileStatuses[file.name]}
onRemove={removeFile}
/>
))}
</Box>
</Box>
)
}

{
hasPreviousStatus && (
<Text fontSize="sm" color="orange.500" mt={2}>
Click "Remove All" to upload new files.
</Text>
)
}

<Flex direction="row" justify="flex-end" gap={3} mt={4}>
<Box pl={{ base: 0, md: 4 }} pr={{ base: 0, md: 4 }} display="flex" gap={2} flexWrap="wrap">
<Button
variant="ArchPrimary"
disabled={isDisabled}
onClick={handleUpload}
loading={isSubmitting}
loadingText={batchID ? `Uploading ${selectedFiles.length} file(s)...` : `Creating batch...`}
>
{batchID ? 'Upload to Existing Batch' : 'Create New Batch and Upload'} ({selectedFiles.length})
</Button>
</Box>
</Flex >
</>
);
}

export default ArtefactUploadView;
Loading