Styled Table Container - Copy this React, Mui Component to your project
const FileUpload: React.FC<FileUploadProps> = ({ projectid, setName, emails, }) => { const [files, setFiles] = useState<File[]>([]); const [filesList, setFilesList] = useState<UploadedFile[]>([]); const [category, setCategory] = useState(""); const [customCategory, setCustomCategory] = useState(""); const [showCustomInput, setShowCustomInput] = useState(false); const [cloudFrontUrls, setCloudFrontUrls] = useState<string[]>([]); const [error, setError] = useState(""); const [previewUrls, setPreviewUrls] = useState<string[]>([]); const [emailAdresses, setEmailAddress] = useState(""); const [dropdownOpen, setDropdownOpen] = useState(false); const [showFullFileName, setShowFullFileName] = useState<{ [key: number]: boolean; }>({}); const [loading, setLoading] = useState(false); const [open, setOpen] = useState(false); const [isChecked, setIsChecked] = useState(false); const [mails, setEmails] = useState<string[]>([]); const [showEmailField, setShowEmailField] = useState(false); const [isSubmitButton, setIsSubmitButton] = useState(false); const { proj_id, set_name } = useParams<{ proj_id: string; set_name: string; }>(); const [assessmentData, setAssessmentData] = useState<AssessmentData>({ projectid: proj_id || "", set_name: set_name || "", emailIds: JSON.parse(localStorage.getItem("emailIds") || "[]"), assessmentdetails: [ { assessmentdate: `${new Date().toISOString().split("T")[0]}`, projectstatus: "", reasonforchange: "", qnadetails: [], created_by: `${sessionStorage.getItem("PBT_FIRSTNAME") || ""} ${ sessionStorage.getItem("PBT_LASTNAME") || "" }`, modified_by: "", }, ], }); useEffect(() => { fetchFiles(); }, []); const fetchFiles = async () => { try { const response = await axiosInstance.get( `${process.env.REACT_APP_ASSESSMENT_SERVICE_BASE_URL}/files/${projectid}/${setName}` ); const fileRecords: FileRecord[] = response.data || []; const allFiles = fileRecords.flatMap((record) => record.files); setFilesList(allFiles); console.log(allFiles); } catch (error) { console.error("Error fetching files:", error); } }; console.log(filesList[0]); const allowedFileTypes = [ "application/pdf", "text/plain", "application/msword", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "application/vnd.openxmlformats-officedocument.presentationml.presentation", ]; const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => { const selectedFiles = Array.from(e.target.files || []); const validFiles = selectedFiles.filter((file: File) => allowedFileTypes.includes(file.type) ); if (validFiles.length !== selectedFiles.length) { setError( "Some files have invalid types. Only PDF, TXT, DOC, DOCX,PPTX files are allowed." ); } else { setError(""); } setFiles(validFiles as File[]); }; const handleCheckboxChange = () => { setIsChecked(!isChecked); }; const handleEmailChange = (e: React.ChangeEvent<HTMLInputElement>) => { setEmailAddress(e.target.value); }; const handleCategoryChange = (e: any) => { const selectCategory = e.target.value; if (selectCategory === "Other") { setShowCustomInput(true); setCategory(""); } else { setShowCustomInput(false); setCategory(selectCategory); } }; const handleCustomCategoryChange = ( e: React.ChangeEvent<HTMLInputElement> ) => { setCustomCategory(e.target.value); }; const handleCustomCategorySubmit = ( e: React.KeyboardEvent<HTMLInputElement> ) => { setCategory(customCategory); }; const handleFileUpload = async (withEmail: boolean) => { if (files.length === 0) { setError("No files selected."); return; } if (!projectid) { setError("Project ID is required."); return; } if (!setName) { setError("Set name is required."); return; } console.log(category); let uploadedUrls: string[] = []; let sendingUrls: string[] = []; const previewUrls: string[] = []; setLoading(true); try { for (const file of files) { const formData = new FormData(); formData.append("Files", file); formData.append("category", category); console.log(file); formData.append("projectid", projectid); formData.append("set_name", setName); const response = await axiosInstance.post( `${process.env.REACT_APP_ASSESSMENT_SERVICE_BASE_URL}/upload/${projectid}/${setName}`, formData, { headers: { "Content-Type": "multipart/form-data", }, } ); if (response.data) { toast.success("File successfully uploaded"); // window.location.reload(); console.log(formData); console.log(response); uploadedUrls.push(response.data.cloudFrontUrls); previewUrls.push(URL.createObjectURL(file)); console.log(uploadedUrls); } } if (withEmail) { const emailPayload = { projectid, setName, toEmail: emails, emailType: "file", files: uploadedUrls, }; const res = await axiosInstance.post( `${process.env.REACT_APP_EMAIL_SERVICE_BASE_URL}/email`, emailPayload, { headers: { "Content-Type": "application/json", }, } ); if (res.data) { toast.success( "Email sent successfully. Thank you, check your email." ); } } window.location.reload(); setLoading(false); } catch (error: any) { console.error("Error uploading file:", error); if (error.response && error.response.data) { console.log(error.response.data); setError(error.response.data); console.log(error); } else { setError("Error uploading file."); } } setCloudFrontUrls(uploadedUrls); setPreviewUrls(previewUrls); setDropdownOpen(false); fetchFiles(); // setError(""); console.log("Files uploaded successfully:", uploadedUrls); console.log(setPreviewUrls); }; const handleButtonClick = async () => { setShowEmailField(true); }; const handleDelete = async (_id: string) => { await axiosInstance.delete( `${process.env.REACT_APP_ASSESSMENT_SERVICE_BASE_URL}/delete/${_id}` ); toast.success("File deleted successfully"); fetchFiles(); }; const handleDownload = async (_id: string) => { console.log("Downloading file with id:", _id); const response = await axiosInstance.get( `${process.env.REACT_APP_ASSESSMENT_SERVICE_BASE_URL}/files/download/${_id}`, { responseType: "blob", } ); // Extract filename from the response headers const contentDisposition = response.headers['content-disposition']; let filename = "file.pdf"; // Default filename if (contentDisposition) { const filenameMatch = contentDisposition.match(/filename="(.+)"/); if (filenameMatch.length === 2) { filename = filenameMatch[1]; } } const url = window.URL.createObjectURL(new Blob([response.data])); const link = document.createElement("a"); link.href = url; link.setAttribute("download", filename); document.body.appendChild(link); link.click(); document.body.removeChild(link); const handleDownload = async (_id: string) => { console.log("Downloading file with id:", _id); const response = await axiosInstance.get( `${process.env.REACT_APP_ASSESSMENT_SERVICE_BASE_URL}/files/download/${_id}`, { responseType: "blob", } ); const url = window.URL.createObjectURL(new Blob([response.data])); const link = document.createElement("a"); link.href = url; link.setAttribute("download", "file.pdf"); // or extract the file name from the response document.body.appendChild(link); link.click(); }; const getFileName = (url: string) => { return url.split("/").pop(); }; const toggleFullFileName = (index: number) => { setShowFullFileName((prevState) => ({ [index]: !prevState[index], })); }; const getFileIcon = (fileType: any): JSX.Element => { switch (fileType) { case "pdf": return <FaFilePdf style={{ color: "red" }} />; case "docx": case "application/vnd.openxmlformats-officedocument.wordprocessingml.document": return <FaFileWord style={{ color: "blue" }} />; case "pptx": case "application/vnd.openxmlformats-officedocument.presentationml.presentation": return <FaFilePowerpoint style={{ color: "orange" }} />; case "txt": return <FaFileAlt style={{ color: "green" }} />; default: return <FaFile style={{ color: "gray" }} />; } }; const getFileType = (url: string): string => { const fileName = url.split("/").pop(); if (fileName) { const fileType = fileName .split(".") .pop() ?.replace(/[^a-zA-Z].*$/, ""); return fileType || ""; } return ""; }; const CustomTextField = styled(TextField)({ '& .MuiInput-underline:before': { borderBottomColor: 'initial', }, '& .MuiInput-underline:hover:before': { borderBottomColor: ' #074173', }, '& .MuiInput-underline:after': { borderBottomColor: ' #074173', }, }); const useStyles = makeStyles((theme) => ({ modalBox: { position: "absolute", top: "50%", left: "50%", transform: "translate(-50%, -50%)", background: "#ddd", boxShadow: theme.shadows[5], padding: theme.spacing(2, 4, 3), outline: "none", height: "40vh", borderRadius: "4px", }, emailField: { display: "flex", flexDirection: "column", gap: theme.spacing(2), }, buttonEmail: { display: "flex", justifyContent: "space-between", }, emailTag: { display: "flex", alignItems: "center", gap: theme.spacing(1), }, label: { color: " #074173", background: "white", fontSize: "0.7rem", border: "0.3px solid #ddd", }, })); const classes = useStyles(); const [itemToDelete, setItemToDelete] = useState<string | null>(null); const handleDeleteClick = (itemId: any) => { setItemToDelete(itemId); setOpen(true); }; const handleDel = () => { if (itemToDelete !== null) { handleDelete(itemToDelete); setOpen(false); } }; const handleConfirmDelete = (_id: string) => { handleDelete(_id); setOpen(false); }; const close = () => { setOpen(false); }; const [anchorEl, setAnchorEl] = useState(null); const handleClick = (event:any) => { setAnchorEl(event.currentTarget); }; const handleClose = () => { setAnchorEl(null); }; const handleRemoveEmail = async (index: number) => { const emailToRemove = emails[index]; try { const response = await axiosInstance.delete( `${process.env.REACT_APP_ASSESSMENT_SERVICE_BASE_URL}/deleteEmail/${proj_id}/${set_name}`, { data: { emailId: emailToRemove } } ); if (response.data.message) { toast.success(response.data.message); setEmails(emails.filter((_, i) => i !== index)); localStorage.removeItem("emailData"); } } catch (error) { console.error("Error deleting email:", error); toast.error("Failed to delete email"); } }; const handleSaveEmails = async () => { const projectKey = `${assessmentData.projectid}_${assessmentData.set_name}`; const storedData = JSON.parse(localStorage.getItem("emailData") || "{}"); const existingEmailIds = storedData[projectKey] || []; // Merge and deduplicate email IDs const emailSet = new Set([...existingEmailIds, ...emails]); const updatedEmailIds = Array.from(emailSet); // Store the updated email IDs in localStorage storedData[projectKey] = updatedEmailIds; localStorage.setItem("emailData", JSON.stringify(storedData)); alert("Email IDs saved successfully!"); setEmails(updatedEmailIds); setShowEmailField(false); // Send the combined email IDs to the backend if (assessmentData.projectid && assessmentData.set_name) { try { const response = await axiosInstance.post( `${process.env.REACT_APP_ASSESSMENT_SERVICE_BASE_URL}/create-projectassesment`, { projectid: assessmentData.projectid, set_name: assessmentData.set_name, emailIds: updatedEmailIds, } ); console.log("Response from API:", response); if (response.data) { toast.success("Email IDs updated successfully"); } } catch (error) { console.error("Error updating email IDs:", error); toast.error("Failed to update email IDs"); } } }; const handleCloseModal = () => { setShowEmailField(false); }; const css = useStyles(); return ( <div style={{ padding: "24px" }}> <div style={{ backgroundColor: "#074173", padding: "1.3rem", borderRadius: "3px", translate: "-25px -25px", width: "101%", }} ></div> <div style={{ display: "flex", alignItems: "center", gap: "16px" }}> <FormControl style={{ margin: "8px", minWidth: "200px" }}> <InputLabel style={{ translate: "-9px" }}>Select Category</InputLabel> <Select style={{ translate: "-9px 8px" }} onChange={(event) => handleCategoryChange(event)} inputProps={{ classes: { underline: { "&:before": { borderBottomColor: "#074173", }, "&:hover:not(.Mui-disabled):before": { borderBottomColor: "#074173", // Color on hover }, "&:after": { borderBottomColor: "#074173", // Default color when focused }, }, }, }} > <MenuItem value="">Select Category</MenuItem> <MenuItem value="Proposal">Proposal</MenuItem> <MenuItem value="SoW - Development1">SoW - Development1</MenuItem> <MenuItem value="SoW - Development2">SoW - Development2</MenuItem> <MenuItem value="SoW - Support">SoW - Support</MenuItem> <MenuItem value="SoW Details Extraction"> SoW Details Extraction </MenuItem> </Select> </FormControl> <div style={{ display: "flex", alignItems: "center", gap: "16px", translate: "0px 8px", }} > <label htmlFor="file-upload" style={{ display: "flex", alignItems: "center", cursor: "pointer", backgroundColor: "#024f75", color: "white", padding: "10px 20px", borderRadius: "5px", }} > <svg xmlns="http://www.w3.org/2000/svg" fill="white" viewBox="0 0 24 24" width="24px" height="24px" > <path d="M0 0h24v24H0z" fill="none" /> <CiFileOn style={{ fontSize: "4vh", color: "white" }} strokeWidth={1} /> </svg> <span style={{ marginLeft: "10px" ,fontSize: "1rem", }}>CHOOSE FILE</span> </label> <input id="file-upload" type="file" multiple style={{ display: "none" }} onChange={handleFileChange} /> </div> <Button variant="contained" onClick={handleClick} style={{ backgroundColor: "#024f75", width: "120px", height: "43px", translate: "4px 8px", color: "white", }} > Upload </Button> <Menu anchorEl={anchorEl} open={Boolean(anchorEl)} onClose={handleClose} style={{ marginLeft: "120px", translate: "0px -25px" }} > <MenuItem onClick={() => handleFileUpload(false)}> Upload Only </MenuItem> <MenuItem onClick={() => handleFileUpload(true)}> Upload with Email </MenuItem> </Menu> <div style={{ display: "inline-block", position: "relative" }}> <input type="checkbox" checked={isChecked} style={{ translate: "130px 30px" }} onChange={handleCheckboxChange} /> <input type="button" onClick={handleButtonClick} disabled={!isChecked} value="Email Alert" style={{ display: "flex", alignItems: "center", justifyContent: "center", fontSize: "1rem", padding: "12px 30px", cursor: isChecked ? "pointer" : "not-allowed", border: "1px solid #ccc", borderRadius: "4px", // backgroundColor: isChecked ? "#074173" : "rgba(7, 65, 115, 0.61)", backgroundColor: isChecked ? "#074173" : "#ddd", zIndex: 1, translate: "160px -2px", height: "100x", color: "white", paddingLeft: "20px", }} /> <MdEmail style={{ position: "absolute", right: "10px", top: "50%", fontSize: "17px", zIndex: 2, pointerEvents: "none", translate: " 160px -2px", color: "white", }} /> </div> </div> {error && <p style={{ color: "red" }}>{error}</p>} {loading && !error && ( <div style={{ color: " #074173", textAlign: "center", fontSize: "3.5vh",zIndex:'0' }} > <div style={{ position: "relative", translate: "96vh", }}> {" "} <RingLoader color="rgb(1, 96, 90)" size={25} /> </div> <div style={{ display: "flex", alignItems: "center", translate: "80vh" }} > <p style={{color:'#074173'}}>Please Wait, it takes time </p> <ScaleLoader color=" #074173" height={15} width={2} margin={2} /> </div> </div> )} <div style={{ translate: "780px -65px" }}></div> <div> <Modal isOpen={showEmailField} onRequestClose={handleCloseModal} contentLabel="Email" className="model" style={{ content: { width: "1000px" } }} > <div className={classes.modalBox}> <div className={classes.emailField}> <label htmlFor="email" style={{ translate: "0px 20px", fontSize: "16px", color: " #074173", fontWeight: "bolder", }} > Enter Email Id : </label> <div style={{ width: "500px" }}> <ReactMultiEmail placeholder="Email Address" emails={emails} className="reactMultiEmail" style={{ translate: "0px 25px", height: "100px", maxHeight: "99px", overflowY: "auto", border: "0.5px solid #074173", backgroundColor: "white", scrollbarColor: "#074173 white", }} onChange={(_emails) => { setEmails(_emails); }} getLabel={(email, index, removeEmail) => { return ( <div key={index} className={classes.emailTag}> <div>{email}</div> <IconButton onClick={() => handleRemoveEmail(index)}> <CloseIcon /> </IconButton> </div> ); }} /> <div className={classes.buttonEmail}> <Button variant="contained" color="primary" startIcon={<SaveIcon />} onClick={handleSaveEmails} style={{ backgroundColor: " #074173", translate: "0px 40px", }} > Save Email </Button> <Button variant="contained" color="primary" startIcon={<CloseIcon style={{ fontWeight: "bold" }} />} onClick={handleCloseModal} style={{ translate: "0px 40px", backgroundColor: " #074173", }} > Close </Button> </div> </div> </div> </div> </Modal> </div> <TableContainer component={Paper} style={{ marginTop: "16px", overflowX: "hidden" }} > <Table> <TableHead> <TableRow> <TableCell style={{ translate: "50px", fontSize: "15px", padding: "10px 16px", }} > Document Category </TableCell> <TableCell style={{ translate: "70px", fontSize: "15px", padding: "10px 16px", }} > File </TableCell> <TableCell style={{ translate: "80px", fontSize: "15px", padding: "10px 16px", }} > Actions </TableCell> </TableRow> </TableHead> <TableBody> {filesList && filesList.map((file, index) => ( <TableRow key={file._id} style={{ backgroundColor: index % 2 === 0 ? "#ddd" : "white", height: "30px", }} > <TableCell style={{ translate: "50px", padding: "10px 16px" }} > {file.category} </TableCell> <TableCell style={{ padding: "2px 10px" }}> {file.url && file.url.map((url, urlIndex) => ( <div key={urlIndex}> <Tooltip title={getFileName(url) || ""} placement="top" classes={{ tooltip: css.label }} > <IconButton style={{ backgroundColor: "transparent" }} onClick={() => window.open(url, "_blank")} > <span style={{ fontSize: "17px" }}> {getFileIcon(getFileType(url))} </span> <span style={{ fontSize: "13px" }}> {getFileName(url)?.slice(0, 20)}... </span> </IconButton> </Tooltip> </div> ))} </TableCell> <TableCell style={{ padding: "4px 16px", translate: "55px" }}> <IconButton onClick={() => handleDeleteClick(file._id)}> <RiDeleteBin6Line color="rgb(0, 26, 110)" /> </IconButton> <Dialog open={open} onClose={close} slotProps={{ backdrop: { style: { backgroundColor: "transparent", }, }, paper: { style: { width: "253px", height: "120px", borderRadius: "4px", translate: "290px", overflow: "hidden", boxShadow: "none", border: "1px solid grey", }, }, }} > <DialogTitle style={{ fontSize: "1rem", translate: "-17px", }} > Confirm Deletion </DialogTitle> <DialogContent style={{ overflow: "hidden", translate: "0px -7px", }} > <DialogContentText style={{ whiteSpace: "nowrap", fontSize: "0.8rem", translate: "-17px", }} > Are you sure you want to delete this file? </DialogContentText> </DialogContent> <DialogActions> <Button onClick={close} style={{ translate: "20px -14px", color: "#074173", backgroundColor: "transparent", }} > No </Button> <Button onClick={handleDel} style={{ translate: "0px -14px", color: "#074173", backgroundColor: "transparent", }} > Yes </Button> </DialogActions> </Dialog> <IconButton onClick={() => handleDownload(file._id)}> {/* <GetAppIcon color="primary" /> */} <RiDownload2Line color="rgb(0, 26, 110)" /> </IconButton> </TableCell> </TableRow> ))} </TableBody> </Table> </TableContainer> </div> ); }; export default FileUpload; corrcet the syntax only