A
Anonymous

Styled Table Container - Copy this React, Mui Component to your project

import React, { useState } from "react"; import Header from "../components/Header"; import { Container, Typography, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Paper, Chip, Avatar, Button, Dialog, DialogTitle, DialogContent, DialogActions, TextField, FormControl, InputLabel, Select, MenuItem, IconButton, Box, ThemeProvider, createTheme } from "@mui/material"; import { styled } from "@mui/system"; import { FaUser, FaPlus, FaPaperclip, FaTrash, FaSearch, FaSortAmountUp, FaSortAmountDown } from "react-icons/fa"; const theme = createTheme({ palette: { primary: { main: "#1976d2", dark: "#115293" } } }); const StyledTableCell = styled(TableCell)(({ theme }) => ({ fontWeight: "bold", backgroundColor: theme.palette.primary.main, color: theme.palette.common.white, })); const StyledTitle = styled(Typography)(({ theme }) => ({ background: `linear-gradient(45deg, ${theme.palette.primary.main} 30%, ${theme.palette.primary.dark} 90%)`, color: theme.palette.common.white, padding: theme.spacing(2), borderRadius: theme.spacing(1), boxShadow: "0 3px 5px 2px rgba(33, 150, 243, .3)", textAlign: "center", fontWeight: "bold" })); export default function RFMs() { const [open, setOpen] = useState(false); const [isEditing, setIsEditing] = useState(false); const [editingId, setEditingId] = useState(null); const [searchTerm, setSearchTerm] = useState(""); const [statusFilter, setStatusFilter] = useState("all"); const [dateSort, setDateSort] = useState("none"); // "none", "asc", "desc" const [attachmentDialogOpen, setAttachmentDialogOpen] = useState(false); const [selectedFiles, setSelectedFiles] = useState({ file1: null, file2: null, file3: null, file4: null }); const [attachmentDate, setAttachmentDate] = useState(new Date().toISOString().split("T")[0]); const [newData, setNewData] = useState({ number: "", name: "", user: "John Doe", date: "", status: "Pending" }); const [data, setData] = useState([ { id: 1, number: "001", name: "Project Alpha", user: "John Doe", date: "", status: "Pending", }, { id: 2, number: "002", name: "Project Beta", user: "John Doe", date: "2024-01-16", status: "Received", }, { id: 3, number: "003", name: "Project Gamma", user: "John Doe", date: "", status: "Pending", }, ]); const filteredAndSortedData = data .filter(item => { const matchesSearch = item.name.toLowerCase().includes(searchTerm.toLowerCase()) || item.number.toLowerCase().includes(searchTerm.toLowerCase()) || item.status.toLowerCase().includes(searchTerm.toLowerCase()); const matchesStatus = statusFilter === "all" ? true : item.status.toLowerCase() === statusFilter.toLowerCase(); return matchesSearch && matchesStatus; }) .sort((a, b) => { if (dateSort === "none" || (!a.date && !b.date)) return 0; if (!a.date) return 1; if (!b.date) return -1; const dateA = new Date(a.date); const dateB = new Date(b.date); return dateSort === "asc" ? dateA - dateB : dateB - dateA; }); const toggleDateSort = () => { const sortStates = { none: "asc", asc: "desc", desc: "none" }; setDateSort(prevSort => sortStates[prevSort]); }; const handleClickOpen = () => { setOpen(true); setIsEditing(false); setNewData({ number: "", name: "", user: "John Doe", date: "", status: "Pending" }); }; const handleEdit = (row) => { setIsEditing(true); setEditingId(row.id); setNewData({ number: row.number, name: row.name, user: row.user, date: row.date, status: row.status }); setOpen(true); }; const handleDelete = (id) => { setData(data.filter(item => item.id !== id)); }; const handleClose = () => { setOpen(false); setIsEditing(false); setEditingId(null); }; const handleAttachmentDialogOpen = () => { setAttachmentDialogOpen(true); }; const handleAttachmentDialogClose = () => { setAttachmentDialogOpen(false); setSelectedFiles({ file1: null, file2: null, file3: null, file4: null }); }; const handleFileChange = (event, fileKey) => { setSelectedFiles(prev => ({ ...prev, [fileKey]: event.target.files[0] })); }; const handleAttachmentDateChange = (event) => { setAttachmentDate(event.target.value); }; const handleInputChange = (event) => { const { name, value } = event.target; setNewData(prev => ({ ...prev, [name]: value, date: value === "Pending" ? "" : prev.date })); }; const handleSubmit = () => { if (isEditing) { setData(data.map(item => item.id === editingId ? { ...item, ...newData } : item )); } else { const newItem = { id: data.length + 1, ...newData, date: newData.status === "Pending" ? "" : newData.date, }; setData([...data, newItem]); } handleClose(); }; const handleAttachmentSubmit = () => { const allFilesUploaded = Object.values(selectedFiles).every(file => file !== null); const newStatus = allFilesUploaded ? "Received" : "Pending"; setData(data.map(item => { if (item.id === editingId) { return { ...item, status: newStatus, date: newStatus === "Pending" ? "" : attachmentDate }; } return item; })); handleAttachmentDialogClose(); }; const getStatusColor = (status) => { switch (status.toLowerCase()) { case "pending": return "warning"; case "received": return "success"; default: return "default"; } }; return ( <> <Header/> <ThemeProvider theme={theme}> <div> <Box sx={{ p: 2 }}> <StyledTitle variant="h4" component="div"> User RFM </StyledTitle> </Box> <Container maxWidth={false} sx={{ mt: 4, mb: 4 }}> <Box sx={{ mb: 3, display: "flex", gap: 2 }}> <TextField sx={{ flex: 1 }} variant="outlined" placeholder="Search by name, number, or status..." value={searchTerm} onChange={(e) => setSearchTerm(e.target.value)} InputProps={{ startAdornment: <FaSearch style={{ marginRight: "8px" }} /> }} /> <FormControl sx={{ minWidth: 120 }}> <InputLabel>Status Filter</InputLabel> <Select value={statusFilter} label="Status Filter" onChange={(e) => setStatusFilter(e.target.value)} > <MenuItem value="all">All</MenuItem> <MenuItem value="pending">Pending</MenuItem> <MenuItem value="received">Received</MenuItem> </Select> </FormControl> <Button color="primary" startIcon={<FaPlus />} onClick={handleClickOpen} variant="outlined" > Add RFM </Button> </Box> <TableContainer component={Paper} elevation={3}> <Table sx={{ minWidth: 650 }} aria-label="data display table"> <TableHead> <TableRow> <StyledTableCell>Number</StyledTableCell> <StyledTableCell>Name</StyledTableCell> <StyledTableCell>Material</StyledTableCell> <StyledTableCell>User</StyledTableCell> <StyledTableCell> <Box sx={{ display: "flex", alignItems: "center", cursor: "pointer" }} onClick={toggleDateSort}> Date {dateSort === "asc" && <FaSortAmountUp style={{ marginLeft: "8px" }} />} {dateSort === "desc" && <FaSortAmountDown style={{ marginLeft: "8px" }} />} </Box> </StyledTableCell> <StyledTableCell>Status</StyledTableCell> <StyledTableCell>Actions</StyledTableCell> </TableRow> </TableHead> <TableBody> {filteredAndSortedData.map((row) => ( <TableRow key={row.id} sx={{ "&:last-child td, &:last-child th": { border: 0 } }} > <TableCell>{row.number}</TableCell> <TableCell>{row.name}</TableCell> <TableCell>materials</TableCell> <TableCell> <div style={{ display: "flex", alignItems: "center", gap: "8px" }}> <Avatar src={row.avatar} alt={row.user} sx={{ width: 32, height: 32 }} > <FaUser /> </Avatar> {row.user} </div> </TableCell> <TableCell>{row.date ? new Date(row.date).toLocaleDateString() : ""}</TableCell> <TableCell> <Chip label={row.status} color={getStatusColor(row.status)} size="small" /> </TableCell> <TableCell> <IconButton color="primary" onClick={() => { setEditingId(row.id); handleAttachmentDialogOpen(); }} size="small" > <FaPaperclip /> </IconButton> {row.status === "Pending" && ( <IconButton color="error" onClick={() => handleDelete(row.id)} size="small" > <FaTrash /> </IconButton> )} </TableCell> </TableRow> ))} </TableBody> </Table> </TableContainer> </Container> <Dialog open={open} onClose={handleClose}> <DialogTitle>{isEditing ? "Edit Project" : "Add New RFM"}</DialogTitle> <DialogContent> <TextField autoFocus margin="dense" name="number" label="RFM Number" type="text" fullWidth variant="outlined" value={newData.number} onChange={handleInputChange} sx={{ mb: 2 }} /> <TextField margin="dense" name="name" label="RFMName" type="text" fullWidth variant="outlined" value={newData.name} onChange={handleInputChange} sx={{ mb: 2 }} /> {newData.status !== "Pending" && ( <TextField margin="dense" name="date" label="Date" type="date" fullWidth variant="outlined" value={newData.date} onChange={handleInputChange} sx={{ mb: 2 }} InputLabelProps={{ shrink: true }} /> )} <FormControl fullWidth> <InputLabel>Status</InputLabel> <Select name="status" value={newData.status} label="Status" onChange={handleInputChange} > <MenuItem value="Pending">Pending</MenuItem> <MenuItem value="Received">Received</MenuItem> </Select> </FormControl> </DialogContent> <DialogActions> <Button onClick={handleClose}>Cancel</Button> <Button onClick={handleSubmit} variant="contained"> {isEditing ? "Update" : "Add"} </Button> </DialogActions> </Dialog> <Dialog open={attachmentDialogOpen} onClose={handleAttachmentDialogClose}> <DialogTitle>Upload RFM Files </DialogTitle> <DialogContent> <Box sx={{ mb: 2 }}> <TextField margin="dense" label="Date" type="date" fullWidth variant="outlined" value={attachmentDate} onChange={handleAttachmentDateChange} sx={{ mb: 2 }} InputLabelProps={{ shrink: true }} /> <Typography variant="subtitle1" gutterBottom> RFQ:</Typography> <input type="file" onChange={(e) => handleFileChange(e, "file1")} style={{ marginBottom: "10px" }} /> <Typography variant="subtitle1" gutterBottom>Invoice:</Typography> <input type="file" onChange={(e) => handleFileChange(e, "file2")} style={{ marginBottom: "10px" }} /> <Typography variant="subtitle1" gutterBottom>Study File:</Typography> <input type="file" onChange={(e) => handleFileChange(e, "file3")} style={{ marginBottom: "10px" }} /> <Typography variant="subtitle1" gutterBottom>Inspection Sheet:</Typography> <input type="file" onChange={(e) => handleFileChange(e, "file4")} /> </Box> </DialogContent> <DialogActions> <Button onClick={handleAttachmentDialogClose}>Cancel</Button> <Button variant="contained" onClick={handleAttachmentSubmit}> Upload </Button> </DialogActions> </Dialog> </div> </ThemeProvider> </> ); };

Prompt

About

StyledTableContainer - Create a dynamic table with columns for vocab number, quantity, and price. Add rows easily and submit with a cl. Get component free!

Share

Last updated 1 month ago