Hello here is my problem, I have implemented a table that table fill when I choose some suggestion. The table contains three columns of (product, qty, balance and add button) So when I click add button it displays some popup form.
So I want to do when adding some quantity in the popup menu and after that click the add button it will reduce from the balance field in the table according to the selected product. Below is the table array.
import React, { useState } from "react"
import {
Grid,
Table,
TableContainer,
TableHead,
TableRow,
TableCell,
Paper,
TableBody,
Button
} from "#material-ui/core"
import AddItem from "./AddItem"
import { useStyles } from "../../../../styles/classes"
export default function ItemsList({
cart,
handleChange,
handleBlur,
values,
setFieldValue,
volumes
}) {
const [open, setOpen] = useState(false)
const [productId, setProductId] = useState("")
const [factoryId, setFactoryId] = useState("")
const handleClickOpen = (productId, factoryId) => {
setProductId(productId)
setFactoryId(factoryId)
setOpen(true)
}
const handleClose = (value) => {
setOpen(false)
}
const addToList = (factory) => {
setOpen(false)
const product = cart.find(
(item) => item.productId === Number(productId)
)
const item = {
productId: productId,
productName: product.productName,
containerNo: values.containerNo,
sealNo: values.sealNo,
qty: values.qty,
factoryId: factory.id,
factory: factory.name,
printDate: values.printDate,
printTime: values.printTime,
palletNo: values.palletNo,
}
const idx = values.volumes.findIndex(e=>e.number === Number(values.noOfContainers))
console.log(idx)
const current = values.volumes[idx].data;
current.push(item)
setFieldValue(`volumes[${idx}].data`,current)
//sum of qty in loaded volumes for this product
values.invoiceItems.forEach((item, idx) => {
item.balance = (Number(item.balance) - Number(values.qty))
})
setFieldValue('invoiceItems', values.invoiceItems)
}
const classes = useStyles()
return (
<Grid item md={12} sm={12} xs={12}>
<TableContainer component={Paper} >
<Table className={classes.table} size="small">
<TableHead>
<TableRow>
<TableCell align="left">Product</TableCell>
<TableCell align="left">Quantity</TableCell>
<TableCell align="left">Balance</TableCell>
<TableCell align="left">Add</TableCell>
</TableRow>
</TableHead>
<TableBody>
{cart.map((row, i) => (
<TableRow key={i}>
<TableCell align="left">{row.productName}</TableCell>
<TableCell align="left">{row.qty}</TableCell>
<TableCell align="left">{row.balance}</TableCell>
<TableCell align="left">
<Button
variant="outlined"
size="small"
color="secondary"
onClick={() => {
handleClickOpen(row.productId)
}}>
add
</Button>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
<AddItem
open={open}
onClose={handleClose}
handleChange={handleChange}
handleBlur={handleBlur}
values={values}
addToList={addToList}
volumes={volumes}
/>
</Grid>
)
}
import React, { useState} from "react"
import {
Grid,
Card,
CardContent,
CardActions,
Button,
CardHeader,
} from "#material-ui/core"
import Alert from "#material-ui/lab/Alert"
import axios from 'axios'
//validation
import { Formik, Form } from "formik"
import * as Yup from 'yup'
import { useStyles } from "../../../styles/classes"
import ItemList from "./subComponents/ItemsList"
import MetaData from "./subComponents/MetaData"
import ContainerList from "./subComponents/ContainerList"
import {useInitialValues} from '../../../hooks/useLoadingInfoData'
// validation schema
let validationSchema = Yup.object().shape({
volumes: Yup.string().required(),
})
export default function LoadingInfo(props) {
const classes = useStyles()
const [initialValues, setInitialValues] = useInitialValues()
const [volumes, setVolumes] = useState([])
const [alert, setAlert] = useState({
showAlert: false,
severity: "success",
message: "",
})
// create method
const submit = async (e, { resetForm }) => {
try {
await axios.post("/loadingInfo", e)
resetForm()
setAlert({
showAlert: true,
severity: "success",
message: "Loading Information created successfully!",
})
} catch (error){
if (error.response.status === 422) {
setAlert({
showAlert: true,
severity: 'error',
message: 'Loading information already exists!',
})
} else {
setAlert({
showAlert: true,
severity: 'error',
message: 'Loading information creation failed!',
})
}
}
}
return (
<Grid container className={classes.root} spacing={1}>
<Grid item xs={12} sm={12} md={12}>
<Formik
initialValues={initialValues}
onSubmit={submit}
validationSchema={validationSchema}
enableReinitialize>
{({
isValid,
dirty,
values,
handleChange,
handleBlur,
setFieldValue,
errors,
}) => {
return (
<Form>
<Card variant="outlined" style={{marginBottom: '1rem'}}>
<CardHeader title="Loading Information"></CardHeader>
<CardContent>
<Grid container spacing={1}>
<MetaData
values={values}
handleChange={handleChange}
handleBlur={handleBlur}
setAlert={setAlert}
setFieldValue={setFieldValue}
/>
<ItemList
cart={values.invoiceItems}
values={values}
handleChange={handleChange}
handleBlur={handleBlur}
setFieldValue={setFieldValue}
volumes={volumes}
/>
</Grid>
</CardContent>
</Card>
<Card variant="outlined">
<CardContent>
{values.volumes.map( (data , idx) =>
<ContainerList values={data} idx={idx} setFieldValue={setFieldValue}/>
)}
</CardContent>
<CardActions>
<Button
variant="contained"
color="primary"
type="submit"
disabled={!dirty || !isValid}>
create
</Button>
</CardActions>
</Card>
</Form>
)
}}
</Formik>
</Grid>
<Grid></Grid>
{alert.showAlert && (
<Grid item md={12}>
<Alert
severity={alert.severity}
onClose={() =>
setAlert({
...alert,
showAlert: false,
})
}>
{alert.message}
</Alert>
</Grid>
)}
</Grid>
)
}
Related
Actually I am facing three issues that is
I have used useState and trying to toggle between icons & button but vise versa is not happening
If I call the edit Icon it All table the Edit Icon are changing to other save button
Once I am on edit I need to target the paticular row only
All above three table will be handled by one change but How i am not sure
Here is the code
import React, { useState } from 'react';
import { ReactComponent as EditIcon } from '../../../assets/icons/edit-icon.svg';
import './ProductLineTable.css';
import { ReactComponent as AddIcon } from '../../../assets/icons/add-icon.svg';
import {
Typography,
Table,
TableHead,
TableRow,
TableCell,
TableContainer,
TableBody,
Button,
Input,
InputAdornment,
TextField
} from '#material-ui/core';
export const data= [
{ id:1,Name:'test1',Class: 6Gender:'M'},
{ id:2,Name:'test1',Class: 6Gender:'M'},
{ id:3,Name:'test1',Class: 6Gender:'M'},
];
const Table = props => {
const [isEdit, setIsEdit] = useState(false);
const editClick=()=>{
setIsEdit(true);
}
const cancelClick=()=>{
setIsEdit(false);
}
return (
<>
<TableContainer className='product-line-table'>
<Table>
{data.map((k, index) => (
<TableRow key={k.Id}>
<TableCell>
<Typography>
{isEdit ? (
<TextField
data-test='firstname-input'
// label='Enter Product Code'
className='form-input user-search-textbox'
value={k.Name}
// onChange={e => {
// handleChange(e, index, 'Product');
// }}
/>
) : (
k.Name
)}
</Typography>
</TableCell>
<TableCell>
<Typography>{k.Class}</Typography>
</TableCell>
<TableCell>
<Typography>{k.Gender}</Typography>
</TableCell>
<TableCell align='center'>
<Typography>
{isEdit ? (
<>
<Button
variant='contained'
color='primary'
size='small'
onClick={() => {
cancelClick
}}
>
Save
</Button>
<Button
color='secondary'
variant='outlined'
type='reset'
size='small'
className='user-reset-btn'
onClick={() => {
cancelClick
}}
>
Cancel
</Button>
</>
) : (
<Button
onClick={editClick}
>
<EditIcon />
</Button>
)}
</Typography>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
</>
);
};
export default Table;
I am using react-material-dashboard to view stats for the Admin.
I want to show all my users in a table to view in the admin dashboard. I am using Express to get the users from my DB but when I run in the browser I get a GET http://localhost:3001/api/fetchUsers 404 (Not Found) error.
How can I display all my users in my react-material-dashboard?
What am I doing wrong?
here is my structure:
CustomersListResults.js:
import { useState, useEffect } from 'react';
import PerfectScrollbar from 'react-perfect-scrollbar';
import {
Box,
Card,
Table,
TableCell,
TableHead,
TablePagination,
TableRow,
} from '#material-ui/core';
import Axios from 'axios';
const CustomerListResults = () => {
const [limit, setLimit] = useState(10);
const [page, setPage] = useState(0);
useEffect(() => {
Axios.get('http://localhost:3001/api/fetchUsers').then((response) => {
console.log(response);
});
}, []);
const handleLimitChange = (event) => {
setLimit(event.target.value);
};
const handlePageChange = (event, newPage) => {
setPage(newPage);
};
return (
<Card>
<PerfectScrollbar>
<Box sx={{ minWidth: 1050 }}>
<Table>
<TableHead>
<TableRow>
<TableCell>
Account
</TableCell>
<TableCell>
Name
</TableCell>
<TableCell>
Email
</TableCell>
<TableCell>
Location
</TableCell>
<TableCell>
Phone
</TableCell>
<TableCell>
Registration date
</TableCell>
<TableCell>
Action
</TableCell>
</TableRow>
</TableHead>
</Table>
</Box>
</PerfectScrollbar>
<TablePagination
component="div"
count={5}
onPageChange={handlePageChange}
onRowsPerPageChange={handleLimitChange}
page={page}
rowsPerPage={limit}
rowsPerPageOptions={[5, 10, 25]}
/>
</Card>
);
};
export default CustomerListResults;
CustomersList:
import { Helmet } from 'react-helmet';
import { Box, Container } from '#material-ui/core';
import CustomerListResults from '../components/customer/CustomerListResults';
import CustomerListToolbar from '../components/customer/CustomerListToolbar';
const CustomerList = () => (
<>
<Helmet>
<title>Customers | </title>
</Helmet>
<Box
sx={{
backgroundColor: 'background.default',
minHeight: '100%',
py: 3
}}
>
<Container maxWidth={false}>
<CustomerListToolbar />
<Box sx={{ pt: 3 }}>
<CustomerListResults />
</Box>
</Container>
</Box>
</>
);
export default CustomerList;
My Server API:
//API To Get All Users
app.get("api/fetchUsers", (req, res) => {
db.query("SELECT * FROM users", (req, res) => {
if (err){
console.log(err)
}else{
console.log(result);
res.send(result)
}
});
});
Change in below line, add / in start:
app.get("/api/fetchUsers", (req, res) => {})
I'm trying to bind to a nested array to text inputs from a form. There are 6 blocks and each block contains 3 values. I have initially populated the array for mapping by using:
new Array(6).fill(['','',''])
and rendering the values using 2 loops. One for the 6 blocks and the other 3 values inside each block. The 3 values are the ones binding to the form. I refer to each of the inputs using the second parameter of the map function which is the index.
Here is the code in its entirety.
import {
Card,
CardContent,
CardHeader,
CardMedia,
TextField,
Grid,
Typography,
Button,
} from "#material-ui/core";
import axios from "axios";
import { useState } from "react";
import { useHistory } from "react-router";
export default function CreateEditQuestion() {
const answerPack = new Array(6).fill(["", "", ""]);
const [question, setQuestion] = useState("");
const [answers, setAnswer] = useState(answerPack);
const [TimeAllowed, setTimeAllowed] = useState(30);
const [Score, setScore] = useState(1);
const [Date, setDate] = useState("");
const history = useHistory();
const handleAnswerSet = (value, answerIndex, answerTextIndex) => {
var updatedAnswer = answers;
updatedAnswer[answerIndex][answerTextIndex] = value;
setAnswer(updatedAnswer);
};
const handleSubmit = () => {
let data = {
question,
answer_set: answers,
time_allowed: TimeAllowed,
score_value: Score,
date: Date,
};
for (const [key, value] of Object.entries({ question, Date })) {
if (value.trim().length == 0) {
alert(`${key} has not been filled in`);
return false;
}
}
axios
.post(
"https://localhost:8000/question",
data
)
.then((resp) => {
alert("Succesfully added Question");
history.push("/question");
})
.catch((err) => {
console.log(err);
});
};
return (
<>
<h1>Create Question</h1>
<Card elevation={1}>
<CardHeader></CardHeader>
<CardContent>
<div>
<TextField
fullWidth
label="Question"
variant="outlined"
onChange={(e) => {
setQuestion(e.target.value);
}}
></TextField>
</div>
<Grid container direction={"row"} spacing={4}>
{answers.map((answerTexts, i) => {
return (
<Grid key={i} item md={4} width={50}>
{answerTexts.map((text, j) => {
return (
<div style={{ width: "70%", marginTop: "30px" }}>
<TextField
fullWidth
label={`Answer ${i + 1} - ${j + 1}`}
onChange={(ev) => {
handleAnswerSet(ev.target.value, i, j);
}}
variant="outlined"
/>
<br />
</div>
);
})}
</Grid>
);
})}
</Grid>
<Grid container direction={"row"} spacing={4}>
<Grid item md={5} width={80}>
<Typography variant="h6" gutterBottom gutterTop>
Extra Options
</Typography>
<TextField
label={"Time Allowed : "}
variant="outlined"
defaultValue={TimeAllowed}
onChange={(ev) => {
setTimeAllowed(ev.target.value);
}}
/>{" "}
<TextField
label="Score"
variant="outlined"
defaultValue={Score}
onChange={(ev) => {
setScore(ev.target.value);
}}
/>
</Grid>
<Grid item md={5} width={100}>
<Typography variant="h6" gutterBottom gutterTop>
Question Date
</Typography>
<TextField
type="date"
onChange={(ev) => {
setDate(ev.target.value);
}}
/>
</Grid>
</Grid>
<div align="center">
<Button
onClick={() => {
handleSubmit();
}}
variant="contained"
color="primary"
>
Submit Question
</Button>
</div>
</CardContent>
</Card>
</>
);
}
Problem:
On each block, changing any value also changes all the other corresponding inputs in other blocks, so if the first input on the first block is changed, then all other first inputs in the other blocks also get changed,e.g(changing answer 1-1 also changes 2-1,3-1,4-1, etc). I could not trace why. Only the corresponding values should be changed
This is the function responsible for setting the values.
const handleAnswerSet = (value, answerIndex, answerTextIndex) => {
var updatedAnswer = answers;
updatedAnswer[answerIndex][answerTextIndex] = value;
setAnswer(updatedAnswer);
};
I'm opening a dialog component when i click the DELETE function button on my users list. When i click it, should show the dialog component. My problem is why i can't open it. I'm using redux to pass data to it.
Pls see this codesandbox link
CLICK HERE
import { dialogConstants } from "../constants";
export const initialState = {
title: null,
details: null,
isOpen: null
};
const dialogReducer = (state = initialState, action) => {
console.log(action.payload);
switch (action.type) {
case dialogConstants.SET_DIALOG_DETAILS:
return {
...state,
isOpen: action.payload.isOpen,
title: action.payload.title,
details: action.payload.details
};
default:
return state;
}
};
export default dialogReducer;
You are not importing Dialogs in user.js. So when you click button your dialog will not open. Try this:
In user.js:
...
import DeleteDialog from "./dialog";
import { useDispatch } from "react-redux";
import { deleteUser } from "./actions";
export default function User() {
const dispatch = useDispatch();
const [selectedUser, setSelectedUser] = React.useState({});
const [open, setDialogOpen] = React.useState(false);
const handleOnDelete = user => {
setSelectedUser(user);
setDialogOpen(true);
};
const handleOnAgree = () => {
// do action to handle on agree deleting an user
dispatch(deleteUser({ title: "Delete User", details: selectedUser }));
setDialogOpen(false);
};
return (
<div>
<Paper>
<TableContainer>
<Table stickyHeader aria-label="sticky table">
<TableHead>
<TableRow>
<TableCell>First Name</TableCell>
<TableCell>Last Name</TableCell>
<TableCell>Email Address</TableCell>
<TableCell>Actions</TableCell>
<TableCell />
</TableRow>
</TableHead>
<TableBody>
<TableRow>
<TableCell>JJJ</TableCell>
<TableCell>BBB</TableCell>
<TableCell>enfoie</TableCell>
<TableCell>
<Button variant="contained">Edit</Button>
<Button
variant="contained"
onClick={() => handleOnDelete({ id: 1, name: "JJJ" })}
>
Delete
</Button>
</TableCell>
</TableRow>
</TableBody>
</Table>
</TableContainer>
</Paper>
<DeleteDialog
user={selectedUser}
open={open}
onAgree={handleOnAgree}
onDisagree={() => setDialogOpen(false)}
/>
</div>
);
}
In dialog.js:
import React from "react";
import Button from "#material-ui/core/Button";
import Dialog from "#material-ui/core/Dialog";
import DialogActions from "#material-ui/core/DialogActions";
import DialogTitle from "#material-ui/core/DialogTitle";
import Slide from "#material-ui/core/Slide";
const Transition = React.forwardRef(function Transition(props, ref) {
return <Slide direction="up" ref={ref} {...props} />;
});
const DeleteDialog = ({ user, open, onAgree, onDisagree }) => {
return (
<div>
<Dialog
open={open}
TransitionComponent={Transition}
keepMounted
onClose={onDisagree}
aria-labelledby="alert-dialog-slide-title"
aria-describedby="alert-dialog-slide-description"
>
<DialogTitle id="alert-dialog-slide-title">
<span style={{ fontWeight: "bold" }}>
{" "}
User: {user.name} - {user.id}
</span>
</DialogTitle>
<DialogActions>
<Button variant="contained" size="small" onClick={onDisagree}>
Cancel
</Button>
<Button variant="contained" size="small" onClick={onAgree}>
Confirm
</Button>
</DialogActions>
</Dialog>
</div>
);
};
export default DeleteDialog;
I have the father which is Productos and a child called EditarProductos. I want to pass producto.id to EditarProductos.
Here is Productos:
import {Button, TableHead, TableRow, TableCell, TableBody, Table} from '#material-ui/core'
import { withStyles, makeStyles } from '#material-ui/core/styles';
import InsertarProductos from './InsertarProductos';
import Grid from '#material-ui/core/Grid';
import EditIcon from '#material-ui/icons/Edit';
import DeleteIcon from '#material-ui/icons/Delete';
import EditarProductos from './EditarProductos';
const StyledTableCell = withStyles((theme) => ({
head: {
backgroundColor: theme.palette.common.black,
color: theme.palette.common.white,
},
body: {
fontSize: 14,
},
}))(TableCell);
const StyledTableRow = withStyles((theme) => ({
root: {
'&:nth-of-type(odd)': {
backgroundColor: theme.palette.background.default,
},
},
}))(TableRow);
function Productos(props) {
const [productos, setProductos] = useState([]);
var id='';
useEffect(() => {
const getProductos = async () => {
const res = await fetch("/productos", {
method: 'GET',
headers: {'Content-Type': 'application/json'},
})
//console.log(res);
const response = await res.json();
setProductos(response);
}
getProductos();
})
function editar(producto){
console.log("entro 1");
//console.log(producto.id);
id = producto.id;
console.log(id);
return <EditarProductos productoEdit = {id}/>;
}
function eliminar(producto){
console.log(producto.id);
id=producto.id;
deleteProductos();
window.location.reload();
}
const deleteProductos = async () => {
console.log("entro");
console.log(id);
const res = await fetch("/productos", {
method: 'DELETE',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
id: id
})
})
const response = await res.json();
}
const useStyles = makeStyles({
table: {
minWidth: 700,
},
});
//console.log(plot);
const mystlye = {
minWidth: "50%",
minHeight: 50
};
//
const classes = useStyles();
return (
<div>
<br />
<Grid container spacing={3}>
<Grid item xs={3}></Grid>
<Grid item xs={3}></Grid>
<Grid item xs={3}></Grid>
<Grid item xs={3}>
<InsertarProductos productoInsert="fer"/>
</Grid>
</Grid>
<br />
<Table className={classes.table}>
<TableHead>
<TableRow>
<StyledTableCell>ID</StyledTableCell>
<StyledTableCell>Nombre</StyledTableCell>
<StyledTableCell>Precio de Compra</StyledTableCell>
<StyledTableCell>Precio de Venta</StyledTableCell>
<StyledTableCell>Cantidad</StyledTableCell>
<StyledTableCell>Categoria</StyledTableCell>
<StyledTableCell>Extras</StyledTableCell>
</TableRow>
</TableHead>
<TableBody>
{productos.map((producto) =>
<TableRow className="data-row">
<StyledTableCell>{producto.id}</StyledTableCell>
<StyledTableCell>{producto.nombre}</StyledTableCell>
<StyledTableCell>{producto.precio_compra}</StyledTableCell>
<StyledTableCell>{producto.precio_venta}</StyledTableCell>
<StyledTableCell>{producto.cantidad}</StyledTableCell>
<StyledTableCell>{producto.categorias_id}</StyledTableCell>
<StyledTableCell>
<Button variant="outlined" onClick={() => editar(producto)}>
<EditIcon />
</Button>
<Button variant="outlined" onClick={() => eliminar(producto)} ><DeleteIcon /> </Button>
</StyledTableCell>
</TableRow>
)}
</TableBody>
</Table>
</div>
);
}
export default Productos;
If I try to pass the id inside the button, it starts to print the id multiple times like in a loop.
EditarProductos is never reached and the id isn't passed. Could someone help me fix my problem, please?
PD: In EditarProductos I'm trying to print id like this:
console.log(props.productoEdit);
You can't return (and render) UI elements like this. You can rather set the id of a product to display though. Using the is you can conditionally render EditarProductos into the UI. You'll likely also want/need a way to reset this when the dialog is dismissed/closed.
The following is one way to do this:
function Productos(props) {
const [productos, setProductos] = useState([]);
const [id, setId] = useState(null); // create state variable
...
function editar(producto){
console.log("entro 1");
console.log(producto.id);
setId(producto.id);
}
function onEditarClose() {
setId(null);
}
...
return (
<div>
{id &&
// conditionally render in UI the dialog
<EditarProductos onClose={onEditarClose} productoEdit={id} />
}
<br />
<Grid container spacing={3}>
<Grid item xs={3}></Grid>
<Grid item xs={3}></Grid>
<Grid item xs={3}></Grid>
<Grid item xs={3}>
<InsertarProductos productoInsert="fer"/>
</Grid>
</Grid>
<br />
<Table className={classes.table}>
<TableHead>
<TableRow>
<StyledTableCell>ID</StyledTableCell>
<StyledTableCell>Nombre</StyledTableCell>
<StyledTableCell>Precio de Compra</StyledTableCell>
<StyledTableCell>Precio de Venta</StyledTableCell>
<StyledTableCell>Cantidad</StyledTableCell>
<StyledTableCell>Categoria</StyledTableCell>
<StyledTableCell>Extras</StyledTableCell>
</TableRow>
</TableHead>
<TableBody>
{productos.map((producto) =>
<TableRow className="data-row">
<StyledTableCell>{producto.id}</StyledTableCell>
<StyledTableCell>{producto.nombre}</StyledTableCell>
<StyledTableCell>{producto.precio_compra}</StyledTableCell>
<StyledTableCell>{producto.precio_venta}</StyledTableCell>
<StyledTableCell>{producto.cantidad}</StyledTableCell>
<StyledTableCell>{producto.categorias_id}</StyledTableCell>
<StyledTableCell>
<Button variant="outlined" onClick={() => editar(producto)}>
<EditIcon />
</Button>
<Button variant="outlined" onClick={() => eliminar(producto)} ><DeleteIcon /> </Button>
</StyledTableCell>
</TableRow>
)}
</TableBody>
</Table>
</div>
);
}