I want to display the card when I submit data for the card. But I have to refresh the page to see changes I want to auto-refresh that card component on submitting data.
I have used use effect for that but still, it's not working. The value becoming true but data is not displayed. Still, I have to refresh the page. How can i solve this issue?
import { TextField, Box, Typography, Button, Link, DialogContent, CircularProgress, Dialog, DialogTitle, DialogContentText, DialogActions } from '#mui/material';
import React, { useEffect } from 'react';
import Cards from 'react-credit-cards';
import 'react-credit-cards/es/styles-compiled.css';
import { useContext, useState } from "react";
import { CardData } from '../../services/user-controller';
import { StatusCodes } from 'http-status-codes';
import { addCard, cardDelete, getCardList } from '../../services/card-controller';
import { ApplicationContext } from '../../context/applicationCtx';
import { nanoid } from 'nanoid';
import CancelIcon from '#mui/icons-material/Cancel';
import styles from "./mystyle.module.css"
import loadCardList from "../../pages/auth/main-app.js"
export default function PaymentForm() {
const {
getCardsList_CTX, setCardList_CTX, getReloadModuleData, setReloadModuleData
} = useContext(ApplicationContext);
const [error, setError] = useState('');
const [getLoaderState, setLoaderState] = useState(false);
const [cardClick, setCardClick] = useState(false);
const [cardNumber, setCardNumber] = useState('');
const [cardName, setCardName] = useState('');
const [cardExpiry, setCardExpiry] = useState('');
const [cardCvv, setCardCvv] = useState('');
const [focus, setFocus] = useState('');
const [cardId, setCardId] = useState('');
// const [inpval, setInpval] = useState('');
const [cardn, setCardn] = useState('');
const [carde, setCarde] = useState('');
const [open, setOpen] = useState(false);
const [deleteCard, setDeleteCard] = useState(null);
const [reloadData,setReloadData] = useState(false);
const handleClickOpen = (card) => {
setOpen(true);
setDeleteCard(card)
};
const handleClose = () => {
setOpen(false);
};
const handleDeleteCard = async function (){
let cardNum = `000000000000${deleteCard.cardNo.substring(4,8)}`
try {
setLoaderState(true);
let response = await cardDelete({
"cardNo": cardNum,
"expiryMonth": deleteCard.expiryMonth,
"expiryYear": deleteCard.expiryYear
})
if(response.status === 200 || response.status === 202 ){
setLoaderState(false);
setOpen(false)
}
} catch (err) {
setLoaderState(false);
if (err.data) {
//TODO:: ADD ERROR MESSAGES setStepLicenseKey({ ...getStepLicenseKey, errorMsg: err.data.message, hasError: true });
}else {
if (err.errorMsg) {
// setStepLicenseKey(err)
console.log(err.errorMsg)
} else {
console.error("UNKNOWN ERROR", err);
}
}
}
}
const handleChange = prop => (e) => {
switch (prop) {
case 'cardNumber':
setCardNumber(e.target.value)
break;
case 'cardName':
setCardName(e.target.value)
break;
case 'cardExpiry':
setCardExpiry(e.target.value)
break;
case 'cardCvv':
setCardCvv(e.target.value)
break;
case 'cardId':
setCardId(e.target.value)
break;
default:
break;
}
}
const handleInputFocus = (e) => {
setFocus( e.target.name );
}
const handleCardClick = (cardDetail, i) => {
setCardClick(true)
}
const delCancel = () => {
setCardClick(false)
}
const verifyInputs = async function () {
try {
setLoaderState(true);
const month = cardExpiry.substring(0, 2);
const year = `20${cardExpiry.substring(2)}`;
let response = await addCard({
"cardHolderName": cardName,
"cardNo": cardNumber,
"cvv": cardCvv,
"expiryMonth": month,
"expiryYear": year,
"cardId": cardNumber
})
if(response.status === StatusCodes.BAD_REQUEST){
setError(response.data.message)
}
// console.log(response,'rt')
else if (response.status === StatusCodes.OK) {
console.log(response)
setLoaderState(false)
setReloadData(true)
loadCardList();
} else {
setLoaderState(false)
throw (response);
}
} catch (err) {
setLoaderState(false);
if (err.data) {
//TODO:: ADD ERROR MESSAGES setStepLicenseKey({ ...getStepLicenseKey, errorMsg: err.data.message, hasError: true });
}
else {
if (err.errorMsg) {
// setStepLicenseKey(err)
console.log(err.errorMsg)
} else {
console.error("UNKNOWN ERROR", err);
}
}
}
}
// console.log(getCardsList_CTX,'yy')
useEffect(()=>{
if(reloadData == true){
getCardList();
}
console.log(reloadData)
},[reloadData])
return (
<>
<Box display="flex" sx={{
"width":"1459px","height":"44px","backgroundColor":"#F9FAFA","position":"relative","top":"0px",left:'77px',
}}></Box>
{/* TODO ADD CARDS HERE */}
<Box display="flex" sx={{
"width":"621px","height":"192px","position":"relative","top":"121px",left:'99px',gap:'10px'
}}>
{getCardsList_CTX.map((card, index)=>{
return (
<Box width="292px" height="184px" className={styles.card} onClick={() => handleCardClick(card, index)}>
{/* <CancelIcon color="error" sx={{ zIndex: 1, position: 'relative', left: '74%', top: '1%' }} /> */}
<Cards
key={nanoid()}
cvc={card.cvv}
expiry={`${card.expiryMonth < 9 ? '0' + card.expiryMonth : card.expiryMonth}${card.expiryYear.toString().substring(2)}`}
name={card.cardHolderName}
number={`000000000000${card.cardNo.substring(4)}`}
issuer={'visa'}
preview={true}
/>
{/* <Box position="absolute" width="100%" minHeight="100%" maxHeight="100%" bgcolor="red" zIndex='1'>
</Box> */}
<Box position="absolute" zIndex='2' onClick={() => {handleClickOpen(card)}}>
<CancelIcon sx={{ zIndex: 1,"position":"absolute","left":"263px","top":"-180px",color:"#dbd4d4",cursor:'pointer' }} />
</Box>
</Box>
)
}) }
</Box>
<Box sx={{ "width": "1536px", "height": "1px", "backgroundColor": "#ece5e5", "position": "absolute", "top": "385px" }}></Box>
<Typography mt={5} variant="h3" component="h2" sx={{ "position": "absolute", "top": "24px", "fontSize": "29px", "left": "97px" }}>
PAYMENT METHOD
</Typography>
<Typography mt={5} variant="h3" component="h2" sx={{ "position": "absolute", "top": "69px", "fontSize": "24px", "left": "108px", color: '#9C9C9C' }}>
YOUR SAVED CARDS
</Typography>
<Box style={{ "position": "absolute", "display": "flex", "top": "431px", "left": "418px" }} id="PaymentForm">
<Typography mt={5} variant="h3" component="h2" sx={{ whiteSpace:'nowrap', "position": "absolute", "top": "-79px", "fontSize": "20px", "left": "307px", color: '#9C9C9C' }}>
ENTER CARD DETAILS - SAVE/DELETE
</Typography>
<Cards
cvc={cardCvv}
expiry={cardExpiry}
focused={focus}
name={cardName}
number={cardNumber}
sx={{ "marginRight": "12px" }}
/>
<form style={{ width: '333px', marginLeft: '18px' }}>
<TextField type="tel"
name="number"
placeholder="Card Number"
onChange={handleChange('cardNumber')}
onFocus={handleInputFocus} id="outlined-basic" label="Card Number" variant="outlined"
sx={{ width: '340px' }}
inputProps={{ maxLength: 16 }}
/>
<TextField
type="tel"
name="name"
placeholder="Name"
onChange={handleChange('cardName')}
onFocus={handleInputFocus}
id="outlined-basic" label="Card Holder" variant="outlined"
sx={{ "marginTop": "12px", width: '340px' }}
/>
<Box sx={{ "display": "flex", "marginTop": "12px", width: '359px' }}>
<TextField
type="tel"
name="expiry"
placeholder="Expiry"
onChange={handleChange('cardExpiry')}
onFocus={handleInputFocus}
id="outlined-basic" label="Expiry" variant="outlined"
sx={{ "display": "flex", marginRight: '16px', width: '340px' }}
inputProps={{ maxLength: 4 }}
/>
<TextField
type="tel"
name="cvc"
placeholder="CVV"
onChange={handleChange('cardCvv')}
onFocus={handleInputFocus}
id="outlined-basic" label="CVV" variant="outlined"
inputProps={{ maxLength: 3 }}
sx={{ marginRight: '19px' }}
/>
</Box>
</form>
<Typography mt={5} variant="h3" component="h2" sx={{ whiteSpace:'nowrap', "position": "absolute", "top": "160px", "fontSize": "10px", "left": "312px", color: 'red',textTransform:'uppercase',fontWeight: 'bold',letterSpacing:'2px' }}>
{error}
</Typography>
<Button disabled={getLoaderState} onClick={verifyInputs} variant="contained" disableElevation sx={{ mt: 1, pr: 2 ,"marginTop":"219px","width":"159px","height":"43px","marginLeft":"-241px"}} >
Save Card {getLoaderState ? <CircularProgress size="1.2em" sx={{ "position": "absolute", right: "0", mr: 2 }} /> : ""}
</Button>
{/* Payment Card Delete */}
<Dialog
open={open}
onClose={handleClose}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">
{"Delete Payment Card"}
</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
Are you sure you want to delete your card({deleteCard !== null ? deleteCard.cardNo : ''}), you can't retrive it later on.
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={handleClose} sx={{ color: 'red' }}>Cancel</Button>
<Button onClick={handleDeleteCard}>
Proceed
</Button>
</DialogActions>
</Dialog>
</Box>
</>
);
}
You need to notify the context that the content has updated. As for React Contact api you would need to change the state of the provider.
Here is an article that shows how to use the context api.
https://kentcdodds.com/blog/how-to-use-react-context-effectively
Related
I'm working on a React router project and I can't seem to pass my function up to the App component. I've tried using the useLocation hook, but that only worked for receiving props from the App component. Any help is greatly appreciated, code is as follows:
File structure:
src:
-- App.jsx
-- Forms.jsx
-- Orders.jsx
App.jsx
import { useEffect, useState } from 'react';
import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom';
import { Button, Typography } from '#mui/material';
import Form from './Form.jsx';
import Orders from './Orders.jsx';
import Error from './Error.jsx';
import './App.css';
const starterOrders = [
{
firstName: 'Billy',
lastName: 'Gibbons',
orderId: 'ZZTop0000001',
productName: 'Hat',
quantity: 2,
price: 14.99,
},
{
firstName: 'Dusty',
lastName: 'Hill',
orderId: 'ZZTop0000002',
productName: 'Shirt',
quantity: 1,
price: 19.99,
},
{
firstName: 'Frank',
lastName: 'Beard',
orderId: 'ZZTop0000003',
productName: 'Hat',
quantity: 2,
price: 29.98,
},
{
firstName: 'David',
lastName: 'Bowie',
orderId: 'UndrPr3ssr81',
productName: 'Sweatshirt',
quantity: 1,
price: 29.98,
},
];
const navBackgroundStyles = {
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
backgroundColor: 'rgb(255, 255, 255)',
};
function App() {
const [orders, setOrders] = useState(starterOrders);
useEffect(() => {
const cachedData = window.localStorage.getItem('ORDERS_ARRAY');
if (cachedData?.length) {
setOrders(JSON.parse(cachedData));
}
}, [])
const newOrderFunc = (order) => {
setOrders((prevOrders) => {
const newOrders = [order, ...prevOrders]
window.localStorage.setItem("ORDERS_ARRAY", JSON.stringify(newOrders));
return newOrders;
});
};
return (
<Router>
<div style={navBackgroundStyles}>
<div>
<Typography
sx={{
marginLeft: '1rem',
fontSize: '2rem',
color: 'rgb(33, 150, 243)',
}}
>
Clothing Co.
</Typography>
</div>
<div>
<Link to="/" state={{ onSaveOrderData: newOrderFunc }}>
<Button sx={{ marginRight: '1rem' }} variant="text">
Place Order
</Button>
</Link>
<Link to="/orders" state={{ orders: orders }}>
<Button sx={{ marginRight: '1rem' }} variant="text">
Orders
</Button>
</Link>
</div>
</div>
<Routes>
<Route path="/" element={<Form />} />
<Route path="/orders" element={<Orders />} />
<Route path="/*" element={<Error />} />
</Routes>
</Router>
);
}
export default App;
Form.jsx
import { useEffect, useState } from 'react';
import { useLocation } from 'react-router-dom';
import {
Alert,
Box,
Button,
InputAdornment,
InputLabel,
MenuItem,
OutlinedInput,
Select,
Slide,
TextField,
} from '#mui/material';
export default function Form({ onSaveOrderData }) {
const location = useLocation();
const saveFunction = location.state?.onSaveOrderData;
const [isActive, setIsActive] = useState(false);
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const [product, setProduct] = useState('');
const [quantity, setQuantity] = useState('');
const [price, setPrice] = useState('');
const quantityMenu = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// Generate random Order IDs
const makeId = () => {
var result = '';
var characters =
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (let i = 0; i < 12; i++) {
result += characters.charAt(
Math.floor(Math.random() * characters.length)
);
}
return result;
};
// Converts product value integer to product name
const productName = () => {
switch (product) {
case 1:
return 'Shirt';
case 2:
return 'Hat';
case 3:
return 'Sweatshirt';
}
};
// Calculates order cost on change of product or quantity state
useEffect(() => {
if (quantity > 0) {
switch (product) {
case 1:
setPrice((19.99 * quantity).toFixed(2));
break;
case 2:
setPrice((14.99 * quantity).toFixed(2));
break;
case 3:
setPrice((29.98 * quantity).toFixed(2));
break;
}
}
}, [product, quantity]);
// Sends new order to App, resets form fields
const submitHandler = (e) => {
e.preventDefault();
const newOrder = {
firstName: firstName,
lastName: lastName,
orderId: makeId(),
productName: productName(),
quantity: quantity,
price: price,
};
setIsActive(true);
saveFunction(newOrder);
setFirstName('');
setLastName('');
setProduct('');
setQuantity('');
setPrice('');
};
return (
<div
style={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
height: '90vh'
}}
>
<div style={{ position: 'fixed', top: '60px', right: '10px' }}>
<Slide direction="left" in={isActive} mountOnEnter unmountOnExit>
<Alert
severity="success"
onClose={() => setIsActive(false)}
style={{ display: isActive ? 'flex' : 'none' }}
>
Thank you for your order!
</Alert>
</Slide>
</div>
<Box
sx={{
padding: '2rem',
width: 'fit-content',
border: '1px solid rgb(148, 148, 148)',
borderRadius: '5px',
backgroundColor: 'rgb(255, 255, 255)',
}}
>
<TextField
label="First Name"
variant="standard"
fullWidth
sx={{ marginRight: '5px' }}
value={firstName}
onChange={(e) => setFirstName(e.target.value)}
/>
<TextField
label="Last Name"
variant="standard"
fullWidth
sx={{ marginRight: '5px' }}
value={lastName}
onChange={(e) => setLastName(e.target.value)}
/>
<InputLabel
style={{
display: 'block',
margin: '1rem 0 0',
color: 'rgb(102, 102, 102)',
}}
>
Product
</InputLabel>
<Select
fullWidth
value={product}
onChange={(e) => setProduct(e.target.value)}
>
<MenuItem value="">
<em>Select product</em>
</MenuItem>
<MenuItem value={1}>Shirt</MenuItem>
<MenuItem value={2}>Hat</MenuItem>
<MenuItem value={3}>Sweatshirt</MenuItem>
</Select>
<InputLabel
style={{
display: 'inline-block',
margin: '1rem 0 0',
color: 'rgb(102, 102, 102)',
}}
>
Quantity
</InputLabel>
<Select
fullWidth
value={quantity}
onChange={(e) => setQuantity(e.target.value)}
>
<MenuItem value="">
<em>Select quantity</em>
</MenuItem>
{quantityMenu.map((item) => {
return (
<MenuItem key={item} value={item}>
{item}
</MenuItem>
);
})}
</Select>
<InputLabel
htmlFor="outlined-adornment-amount"
sx={{ margin: '1rem 0 0' }}
>
Amount
</InputLabel>
<OutlinedInput
fullWidth
value={price}
startAdornment={<InputAdornment position="start">$</InputAdornment>}
inputProps={{ readOnly: true }}
/>
<Button
variant="outlined"
fullWidth
sx={{
marginTop: '1.25rem',
fontSize: '1rem',
color: 'dark',
}}
onClick={submitHandler}
>
Place Order
</Button>
</Box>
</div>
);
}
Orders.jsx
import React from 'react';
import { useLocation } from 'react-router-dom';
import {
Paper,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
Typography,
} from '#mui/material';
export default function Orders({orders}) {
const location = useLocation();
const ordersList = location.state?.orders;
return (
<TableContainer component={Paper}>
<Typography variant="h1">Orders</Typography>
<Table sx={{ minWidth: 600 }} aria-label="simple table">
<TableHead>
<TableRow>
<TableCell>First Name</TableCell>
<TableCell>Last Name</TableCell>
<TableCell>Order ID</TableCell>
<TableCell>Product Name</TableCell>
<TableCell>Quantity</TableCell>
<TableCell>Price</TableCell>
</TableRow>
</TableHead>
<TableBody>
{ordersList.map((order) => (
<TableRow
key={order.orderId}
sx={{ '&:last-child td, &:last-child th': { border: 0 } }}
>
<TableCell scope="row">{order.firstName}</TableCell>
<TableCell scope="row">{order.lastName}</TableCell>
<TableCell>{order.orderId}</TableCell>
<TableCell>{order.productName}</TableCell>
<TableCell>{order.quantity}</TableCell>
<TableCell>{'$' + `${order.price}`}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
);
}
So far, I've tried using the useLocation hook as I did in the Orders component, as seen below. Truth be told, the destructured props are both greyed out so it doesn't look like they're being used. I followed a tutorial for passing state from App to component and it seemed to work for the Orders component.
Orders.jsx
export default function Orders({orders}) {
const location = useLocation();
const ordersList = location.state?.orders;
Form.jsx
export default function Form({ onSaveOrderData }) {
const location = useLocation();
const saveFunction = location.state?.onSaveOrderData;
I am making the infinite scroll in react js , but i am having problem setting the posts value whenever i refresh the page the posts length is 0 whereas it should have been 10.
But after the first reload if i don't reload and just change something in code ( lets say add console.log ) and save it then the whole infinite scroll starts working but if i reload then it stops working
Please help.
Feed.js
import { Box, CircularProgress, Stack, Typography } from "#mui/material";
import Post from "./Post";
import About from "./About";
import { useEffect, useRef, useState } from "react";
import { getInfiniteScroll } from "../apis/posts";
import { useNavigate } from "react-router-dom";
const Feed = () => {
// const posts = useSelector((state) => state.allPosts.posts);
const [posts, setPosts] = useState([]);
const [skip, setSkip] = useState(0);
const [isEnd, setIsEnd] = useState(false);
const ref = useRef();
useEffect(() => {
fetchPosts();
ref.current?.addEventListener("scroll", handleScroll);
// return () => ref.current?.removeEventListener("scroll", handleScroll);
}, [skip]);
const fetchPosts = async () => {
try {
const { data, error } = await getInfiniteScroll(skip);
if (error) {
console.log(error);
return;
}
if (data?.length === 0) {
setIsEnd(true);
return;
}
// setPosts(data);
setPosts([...posts, ...data]);
console.log(posts.length);
} catch (error) {
console.log(error.message);
}
};
const handleScroll = (e) => {
const { offsetHeight, scrollTop, scrollHeight } = e.target;
if (offsetHeight + scrollTop >= scrollHeight) {
console.log(posts?.length);
setSkip(posts?.length);
}
console.log("skip : ", skip);
};
return (
<Box flex={4} sx={{ padding: { xs: "0", sm: "0px 20px " } }}>
<Box
ref={ref}
// onScroll={handleScroll}
sx={{
width: { xs: "100%", sm: "105% " },
marginBottom: "50px",
height: "600px",
overflow: "scroll",
overflowX: "hidden",
}}>
{posts.length > 0 ? (
posts.map((post) => <Post key={post._id} {...post} />)
) : (
<Box
sx={{
display: "flex",
justifyContent: "center",
alignSelf: "center",
marginTop: "200px",
}}>
<CircularProgress
sx={{
alignSelf: "center",
}}
/>
</Box>
)}
</Box>
<Box
sx={{
display: { sm: "none", xs: "block" },
justifyContent: "center",
alignItems: "center",
paddingBottom: "50px",
}}>
<About />
</Box>
</Box>
);
};
export default Feed;
Posts.js
import {
Avatar,
Card,
CardActions,
CardContent,
CardHeader,
CardMedia,
Checkbox,
IconButton,
} from "#mui/material";
import ShareIcon from "#mui/icons-material/Share";
import MoreVertIcon from "#mui/icons-material/MoreVert";
import Favorite from "#mui/icons-material/Favorite";
import { FavoriteBorder } from "#mui/icons-material";
import { useNavigate } from "react-router-dom";
import SmartText from "../Helpers/SmartText";
import { capitalize } from "../Helpers/Capitalize";
const Post = ({ _id, desc, title, photo, caption, updatedAt }) => {
const navigate = useNavigate();
return (
<Card sx={{ marginBottom: "20px" }}>
<CardHeader
avatar={
<Avatar sx={{ bgcolor: "red" }} aria-label="recipe">
{Array.from(title)[0]}
</Avatar>
}
action={
<IconButton aria-label="settings">
<MoreVertIcon />
</IconButton>
}
title={capitalize(title)}
subheader={updatedAt}
onClick={() => {
navigate("/posts/singlePost/" + _id);
}}
sx={{ cursor: "pointer" }}
/>
<CardMedia component="img" height="20%" image={photo} alt="Paella dish" />
<CardContent>
<SmartText text={desc} />
{/* <Typography variant="body2" color="text.secondary">
{post.desc}
</Typography> */}
</CardContent>
<CardActions disableSpacing>
<IconButton aria-label="add to favorites">
<Checkbox
icon={<FavoriteBorder />}
checkedIcon={<Favorite sx={{ color: "red" }} />}
/>
</IconButton>
<IconButton aria-label="share">
<ShareIcon />
</IconButton>
{/* <ExpandMore
expand={expanded}
aria-expanded={expanded}
aria-label="show more"
>
<ExpandMoreIcon />
</ExpandMore> */}
</CardActions>
</Card>
);
};
export default Post;
api/posts.js
export const getInfiniteScroll = async (skip) => {
try {
const res = await fetch(`/api/posts/infiniteScroll?skip=${skip}`, {
method: "GET",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
});
return await res.json();
} catch (error) {
throw new Error(error);
}
};
backend/postController.js
exports.getInfinitePost = async (req, res) => {
const skip = req.query.skip ? Number(req.query.skip) : 0;
const DEFAULT_LIMIT = 10;
try {
const posts = await Post.find({}).skip(skip).limit(DEFAULT_LIMIT);
res.status(201).json({ data: posts, success: true });
} catch (error) {
res.status(400).json({ message: error });
}
};
So In my react application I have filtered option dialog. When a user select filter option and there is no related data, the dialog prompts No objects found based on your filter, try changing filter criteria and below this text I have a button called back to reset the filters. To do so I have defined a function resetAllFilters inside this function I called setStatusFilters.
But when I call resetAllFilters function I got Uncaught TypeError: setStatusFilters is not a function at resetAllFilters
Here is my code.
import { Search } from "#mui/icons-material";
import { Divider, Grid, List, Stack, Typography } from "#mui/material";
import React, { useEffect, useState, useMemo } from "react";
import TextInput from "../../../components/input/TextInput";
import Loading from "../../../components/loading/Loading";
import { filterObjects, filterSearch } from "../../../data/helpers/Helpers";
import TrackingFilterContainer from "../containers/TrackingFilterContainer";
import ObjectListItem from "./ObjectListItem";
import {
makeDefaultFilterState,
makeFilterOptionsObj,
} from "../../../data/helpers/Helpers";
import Button from "../../../components/button/Button";
const classes = {
Root: {
height: "100vh",
},
SearchInput: (theme) => ({
mt: "5%",
// ml: "5%",
p: 0.7,
borderRadius: "5px",
width: "100%",
bgcolor: "white",
"& input": {
overflow: "hidden",
textOverflow: "ellipsis",
},
"& svg": {
mr: "2.5%",
},
[theme.breakpoints.down("md")]: {
mt: 0,
pl: 1.5,
bgcolor: "background.primary",
},
}),
SearchLogo: { color: "misc.hint" },
Divider: (theme) => ({
mt: "2.5%",
width: "100%",
mb: 3,
[theme.breakpoints.down("md")]: {
display: "none",
},
}),
FilterWrapper: {
// mt: "3%",
px: "2%",
pt: "5%",
pb: "3%",
columnGap: "3%",
},
ListWrapper: {
// mt: "1.5%",
height: "100%",
overflow: "auto",
"&::-webkit-scrollbar": {
width: "3px",
},
"&::-webkit-scrollbar-thumb": {
borderRadius: "8px",
backgroundColor: "misc.hint",
},
},
};
function ObjectList({
search,
setSearch,
trackingObjects,
loading,
error,
selectedObj,
setSelectedObj,
statusFilters,
setStatusCheckboxFilters,
setStatusFilters,
}) {
const handleClick = React.useCallback((obj) => {
setSelectedObj(obj);
}, []);
console.log(statusFilters, "object");
const resultObjs = filterSearch(
filterObjects(trackingObjects, statusFilters),
search
);
const [res, setReset] = useState(false);
const reset = () => setReset(!setStatusFilters);
const objsWithLocations = resultObjs.filter(
({ location }) =>
location?.[0] !== null &&
location?.[0] !== undefined &&
location?.[1] !== null &&
location?.[1] !== undefined
);
const defaultFilterState = useMemo(
() => makeDefaultFilterState(trackingObjects),
[trackingObjects]
);
const filterOptionsObj = useMemo(
() => makeFilterOptionsObj(trackingObjects),
[trackingObjects]
);
const resetAllFilters = () => {
setStatusFilters([]);
};
// console.log('objsWithLocations', objsWithLocations);
return (
<Grid container direction="column" sx={classes.Root} wrap="nowrap">
<Stack
sx={{
flexDirection: { xs: "row", md: "column" },
alignItems: { xs: "center", md: "flex-start" },
justifyContent: { xs: "space-between", md: "flex-start" },
px: 1.0,
mb: 2,
}}
>
<TextInput
autoComplete="off"
variant="standard"
placeholder="Search for an object...."
value={search}
onValueChange={setSearch}
InputProps={{
startAdornment: <Search sx={classes.SearchLogo} />,
disableUnderline: true,
}}
sx={classes.SearchInput}
/>
<Divider sx={classes.Divider} />
<TrackingFilterContainer
defaultFilterState={defaultFilterState}
filterOptionsObj={filterOptionsObj}
/>
</Stack>
{loading && !resultObjs?.length && <Loading />}
{error && (
<Typography
variant="h5"
color="text.secondary"
mx="auto"
mt="5%"
width="45%"
textAlign="center"
>
{error}
</Typography>
)}
{!loading && objsWithLocations?.length === 0 ? (
<Typography
variant="h5"
color="text.secondary"
mx="auto"
mt="5%"
width="45%"
textAlign="center"
// onClick={() => defaultFilterState()}
>
No objects found based on your filter, try changing filter criteria
<Button
variant="text"
text="Back"
sx={{
fontSize: "24px",
p: 0,
verticalAlign: "baseline",
ml: "6px",
textTransform: "none",
}}
onClick={() => resetAllFilters()}
/>
</Typography>
) : (
<List sx={classes.ListWrapper}>
{objsWithLocations.map((obj) => (
<ObjectListItem
key={obj.trackingObjectId}
object={obj}
handleClick={handleClick}
isActive={selectedObj?.trackingObjectId === obj.trackingObjectId}
/>
))}
</List>
)}
</Grid>
);
}
export default ObjectList;
// export default React.memo(ObjectList);
Here is ObjectList.js rendered
import {Grid} from "#mui/material";
import {useNavigate} from "react-router-dom";
import {useTheme} from "#mui/material/styles";
import useMediaQuery from "#mui/material/useMediaQuery";
import React, {useEffect, useState} from "react";
import {TrackingPageItems} from "../../data/constants/TrackingObject";
import Map from "./map/Map";
import MobileNavigate from "./mobileNavigate/MobileNavigate";
import ObjectList from "./objectList/ObjectList";
import ObjectOne from "./objectOne/ObjectOne";
import buildSocketIoConnection from "../../data/socket.io/client";
import API from "../../data/api/API";
import {handleError} from "../../data/helpers/apiHelpers";
import {checkAuthStatus} from "../../data/helpers/Helpers";
import {filterObjects, filterSearch} from "../../data/helpers/Helpers";
function TrackingPage({
trackingObjects,
updateTrackingObjects,
setTrackingObjects,
selectedObject,
setSelectedObject,
...props
}) {
const [objectListSearch, setObjectListSearch] = useState("");
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down("md"));
const [selectedTab, setSelectedTab] = useState(TrackingPageItems.LIST);
const [loading, setLoading] = useState(true);
const [error, setError] = useState("");
const navigate = useNavigate();
const handleTabChange = (newTab) => {
setSelectedTab(newTab);
};
useEffect(() => {
const userInfoString = localStorage.getItem("userInfo");
const userInfo = JSON.parse(userInfoString);
const token = userInfo?.token;
let possibleSocketIoConnection = null;
if (token) {
possibleSocketIoConnection = buildSocketIoConnection(token, updateTrackingObjects);
} else {
console.error("No token provided. Won't connect to socket.io server");
}
return () => {
setSelectedObject(null);
possibleSocketIoConnection?.closeConnection?.();
};
}, []);
const fetchObjectList = React.useCallback((firstTime = false) => {
firstTime && setLoading(true);
API.object
.getObjectList()
.then((objs) => {
// console.log('TrackingObjects', objs.data);
setTrackingObjects(objs.data);
})
.catch((err) => {
console.log(err);
checkAuthStatus(err.response?.status, navigate);
setError(handleError(err, "getObjectList"));
})
.finally(() => {
firstTime && setLoading(false)
});
}, []);
useEffect(() => {
fetchObjectList(!trackingObjects?.length);
// const interval = setInterval(fetchObjectList, 20000);
// return () => clearInterval(interval);
}, []);
const resultObjs = filterSearch(filterObjects(trackingObjects, props.statusFilters), objectListSearch);
return (
<>
<MobileNavigate selectedTab={selectedTab} handleTabChange={handleTabChange} />
<Grid container direction="row" spacing={1}>
{(!isMobile || (isMobile && selectedTab === TrackingPageItems.LIST)) && (
<Grid item container direction="column" xs={12} md={3}>
{selectedObject ? (
<ObjectOne trackingObjects={trackingObjects} selectedObj={selectedObject} setSelectedObj={setSelectedObject} />
) : (
<ObjectList
search={objectListSearch}
setSearch={setObjectListSearch}
selectedObj={selectedObject}
setSelectedObj={setSelectedObject}
trackingObjects={trackingObjects}
loading={loading}
error={error}
{...props}
/>
)}
</Grid>
)}
{(!isMobile || (isMobile && selectedTab === TrackingPageItems.MAP)) && (
<Grid item container direction="column" xs={12} md={9}>
<Map
loading={loading}
selectedObj={selectedObject}
setSelectedObj={setSelectedObject}
trackingObjects={resultObjs}
{...props}
/>
</Grid>
)}
</Grid>
</>
);
}
export default React.memo(TrackingPage);
How can I solve this error?
I am building a form where I have to login into the user by their phone number on CLICKING the send code button I got an error TypeError: Object(...) is not a function where it says that window is not a function can anybody solve my problem.
Error Image
Here is some of my code
import * as React from "react";
import { useState } from "react";
import Avatar from "#mui/material/Avatar";
import Button from "#mui/material/Button";
import ButtonGroup from "#mui/material/ButtonGroup";
import CssBaseline from "#mui/material/CssBaseline";
import TextField from "#mui/material/TextField";
import FormControlLabel from "#mui/material/FormControlLabel";
import Checkbox from "#mui/material/Checkbox";
import Link from "#mui/material/Link";
import Paper from "#mui/material/Paper";
import Box from "#mui/material/Box";
import Grid from "#mui/material/Grid";
import LockOutlinedIcon from "#mui/icons-material/LockOutlined";
import Typography from "#mui/material/Typography";
import { createTheme, ThemeProvider } from "#mui/material/styles";
import background from "../staticfiles/signin-background.jpg";
import "react-phone-input-2/lib/style.css";
import { auth, db, captcha } from "../config/Config";
import { RecaptchaVerifier } from "firebase/auth";
import { Link as RouterLink } from "react-router-dom";
import { useHistory } from "react-router-dom";
import socialMediaAuth from "../service/auth";
function Copyright(props) {
return (
<Typography
variant="body2"
color="text.secondary"
align="center"
{...props}
>
{"Copyright © "}
<Link color="inherit" href="https://mui.com/">
Your Website
</Link>{" "}
{new Date().getFullYear()}
{"."}
</Typography>
);
}
const theme = createTheme();
export default function SignInUserPhone() {
let history = useHistory();
const [PhoneNumber, setPhoenNumber] = useState("");
const [VerificationCode, setVerificationCode] = useState("");
const [error, setError] = useState("");
const handleSubmit = (event) => {
event.preventDefault();
console.log(PhoneNumber);
console.log(error);
};
const handleSubmit2 = (e) => {
e.preventDefault();
console.log(VerificationCode);
};
const handleOnClick = async (provider) => {
const res = await socialMediaAuth(provider);
await db
.collection("SignedUpUsersData")
.doc(res.uid)
.set({
Email: res.email,
Name: res.displayName,
})
.then(() => {
history.push("/");
})
.catch((err) => setError(err.message));
};
const handleUserButton = (event) => {
event.preventDefault();
history.push("/signinuser");
};
const handleSellerButton = (event) => {
event.preventDefault();
history.push("/signinseller");
};
auth.languageCode = "it";
const setUpCaptcha = () => {
window.recaptchaVerifier = auth().RecaptchaVerifier("recaptcha-container", {
size: "invisible",
callback: (response) => {
// reCAPTCHA solved, allow signInWithPhoneNumber.
console.log(response);
console.log("Ok recapthca sloved");
onSignInSubmit();
},
});
};
const onSignInSubmit = (e) => {
e.preventDefault();
setUpCaptcha();
const phoneNumber = PhoneNumber;
const appVerifier = window.recaptchaVerifier;
auth()
.signInWithPhoneNumber(PhoneNumber, appVerifier)
.then((confirmationResult) => {
// SMS sent. Prompt user to type the code from the message, then sign the
// user in with confirmationResult.confirm(code).
window.confirmationResult = confirmationResult;
console.log(confirmationResult);
// ...
})
.catch((error) => {
// Error; SMS not sent
// ...
console.log(error.message);
//( Or, if you haven't stored the widget ID:
});
};
return (
<ThemeProvider theme={theme}>
<Grid container component="main" sx={{ height: "100vh" }}>
<CssBaseline />
<Grid
item
xs={false}
sm={4}
md={7}
sx={{
backgroundImage: `url(${background})`,
backgroundRepeat: "no-repeat",
backgroundColor: (t) =>
t.palette.mode === "light"
? t.palette.grey[50]
: t.palette.grey[900],
backgroundSize: "cover",
backgroundPosition: "center",
}}
/>
<Grid item xs={12} sm={8} md={5} component={Paper} elevation={6} square>
<Box
sx={{
my: 8,
mx: 4,
display: "flex",
flexDirection: "column",
alignItems: "center",
}}
>
<Avatar sx={{ m: 1, bgcolor: "secondary.main" }}>
<LockOutlinedIcon />
</Avatar>
<Typography component="h1" variant="h5">
Sign in With Phone Number
</Typography>
<Box
sx={{
my: 4,
mx: 4,
display: "flex",
flexDirection: "column",
alignItems: "center",
}}
>
<ButtonGroup size="large" disableElevation variant="contained">
<Button onClick={handleSellerButton}>SELLER</Button>
<Button onClick={handleUserButton}>USER</Button>
</ButtonGroup>
</Box>
<Box
component="form"
noValidate
onSubmit={onSignInSubmit}
sx={{ mt: 1 }}
>
<TextField
margin="normal"
required
fullWidth
id="email"
label="Phone Number"
name="Phone"
autoComplete="phoenumber"
value={PhoneNumber}
onChange={(phone) => setPhoenNumber(phone.target.value)}
/>
<div id="recaptcha-container"></div>
<Button
type="submit"
fullWidth
variant="contained"
sx={{ mt: 3, mb: 2 }}
onSubmit={onSignInSubmit}
id="sign-in-button"
>
Send Code
</Button>
<Grid container>
<Grid item xs></Grid>
<Grid item>
<Link
component={RouterLink}
to="/signup"
href="#"
variant="body2"
>
{"Don't have an account? Sign Up"}
</Link>
</Grid>
</Grid>
</Box>
{error && <div>{error}</div>}
<Box
component="form"
noValidate
onSubmit={handleSubmit2}
sx={{ mt: 1 }}
>
<TextField
margin="normal"
required
fullWidth
id="email"
label="Verification Code"
name="Verification"
autoComplete="Verification"
value={VerificationCode}
onChange={(verification) =>
setVerificationCode(verification.target.value)
}
/>
<Button
type="submit"
fullWidth
variant="contained"
sx={{ mt: 3, mb: 2 }}
>
Submit
</Button>
<Copyright sx={{ mt: 5 }} />
</Box>
</Box>
</Grid>
</Grid>
</ThemeProvider>
);
}
All the files are correctly exported from config js cause sign in with email and password and sign in with social media are working
React uses a virtual DOM so doesn't have the same access to window as writing a website with pure javascript. So accessing the window object will often cause issues.
This does seem to be a duplicate of this answer though. That might help you fix the bug
How can I send the value of the checkbox to the checkout.js page? This is the PaymentForm page. I tried my best but it's not working correctly. Basically, I want to use the PaymentForm fields in checkout.js page because my submit button is there.
PaymentForm.js
import React from 'react';
import Typography from '#material-ui/core/Typography';
import Grid from '#material-ui/core/Grid';
import TextField from '#material-ui/core/TextField';
import FormControlLabel from '#material-ui/core/FormControlLabel';
import Checkbox from '#material-ui/core/Checkbox';
import { createStyles } from '#material-ui/core/styles';
import StripeCheckout from 'react-stripe-checkout'
import 'react-toastify/dist/ReactToastify.css';
const styles = createStyles({
formControlLabel: {
fontSize: '1.5rem',
'& label': { fontSize: '5rem' }
}
});
const handleToken = (token) => {
console.log(token);
}
const PaymentForm = ({ PaymentForm, changePaymentForm }) => {
const [state, setState] = React.useState({
checkedA: false,
});
const handleChange = (event) => {
setState({ ...state, [event.target.name]: event.target.checked });
};
return (
<React.Fragment>
<Typography variant="h4" gutterBottom>
Payment method
</Typography><br />
<Grid container spacing={3}>
<Grid item xs={12}>
<FormControlLabel
control={<Checkbox checked={state.checkedA} onChange={handleChange} name="checkedA"/>}
label={<Typography style={styles.formControlLabel}>Cash on delivery</Typography>}
/>
</Grid>
<Grid item xs={12}>
<StripeCheckout
stripeKey="pk_test_51I9XPQAesAg2GfzQyVB7VgP0IbmWwgcfeFJSuCpB2kbNu60AFTbFhC7dxwje8YF4w2ILMJ6o2InB9ENczpd4dCSa00e09XoDbw"
token={handleToken}
amount={2 * 100}
name="All Products"
/>
</Grid>
</Grid>
</React.Fragment>
);
};
export default PaymentForm;
Checkout.js
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
import CssBaseline from '#material-ui/core/CssBaseline';
import AppBar from '#material-ui/core/AppBar';
import Toolbar from '#material-ui/core/Toolbar';
import Paper from '#material-ui/core/Paper';
import Stepper from '#material-ui/core/Stepper';
import Step from '#material-ui/core/Step';
import StepLabel from '#material-ui/core/StepLabel';
import Button from '#material-ui/core/Button';
import Link from '#material-ui/core/Link';
import Typography from '#material-ui/core/Typography';
import axios from '../../axios-orders';
import AddressForm from './CheckoutForm';
import PaymentForm from './PaymentForm';
import Review from './Review';
const useStyles = makeStyles((theme) => ({
appBar: {
position: 'relative',
},
layout: {
width: 'auto',
marginLeft: theme.spacing(2),
marginRight: theme.spacing(2),
[theme.breakpoints.up(1000 + theme.spacing(2) * 2)]: {
width: 1100,
marginLeft: 'auto',
marginRight: 'auto',
},
},
paper: {
marginTop: theme.spacing(3),
marginBottom: theme.spacing(3),
padding: theme.spacing(2),
[theme.breakpoints.up(700 + theme.spacing(3) * 2)]: {
marginTop: theme.spacing(6),
marginBottom: theme.spacing(6),
padding: theme.spacing(3),
backgroundColor: 'rgb(248, 246, 244)',
},
},
stepper: {
padding: theme.spacing(5, 0, 5),
fontWeight: 'bold',
backgroundColor: 'rgb(248, 246, 244)',
},
buttons: {
display: 'flex',
justifyContent: 'flex-end',
},
button: {
marginTop: theme.spacing(3),
marginLeft: theme.spacing(1),
border: "none"
},
}));
const steps = ['Shipping address', 'Payment details', 'Review your order'];
function Copyright() {
return (
<Typography variant="body2" color="textSecondary" align="center">
{'Copyright © '}
<Link color="inherit" href="https://material-ui.com/">
Your Website
</Link>{' '}
{new Date().getFullYear()}
{'.'}
</Typography>
);
}
function getStepContent(step, formValues = null, changeFormValue = null, paymentValues = null, changePaymentValue = null) {
switch (step) {
case 0:
return <AddressForm addressValues={formValues} changeAddressValue={changeFormValue} />;
case 1:
return <PaymentForm PaymentForm={paymentValues} changePaymentForm={changePaymentValue}/>;
case 2:
return <Review />;
default:
throw new Error('Unknown step');
}
}
export default function Checkout(props) {
const classes = useStyles();
const [addressFormValues, setAddressFormValues] = React.useState({});
const [paymentFormValues, setPaymentFormValues] = React.useState({});
const [paymentFormNewValues, setPaymentFormNewValues] = React.useState({});
const [activeStep, setActiveStep] = React.useState(0);
if(paymentFormValues === true){
setPaymentFormNewValues('Cash')
}
if(paymentFormValues === false){
setPaymentFormNewValues('Online')
}
console.log('[paymentFormNewValues: ]', paymentFormNewValues)
console.log('[paymentFormValues: ]', paymentFormValues)
const handleNext = () => {
setActiveStep(activeStep + 1);
axios.post('/UserPortal/CartItems/checkout_details_check.php', {
customer_id: localStorage.getItem('Id'),
})
.then((response) => {
if(response.data === null)
{
axios.post('/UserPortal/CartItems/checkout_details.php', {
customer_id: localStorage.getItem('Id'),
firstname: addressFormValues.firstname,
lastname: addressFormValues.lastname,
address: addressFormValues.address,
city: addressFormValues.city,
state: addressFormValues.state
})
.then((response) => {
console.log(response.data);
})
}
else{
axios.post('/UserPortal/CartItems/checkout_details_update.php', {
customer_id: localStorage.getItem('Id'),
firstname: addressFormValues.firstname,
lastname: addressFormValues.lastname,
address: addressFormValues.address,
city: addressFormValues.city,
state: addressFormValues.state,
payment_method: paymentFormNewValues
})
.then((response) => {
console.log(response.data);
})
}
})
};
const handleBack = () => {
setActiveStep(activeStep - 1);
};
const changeAddressFormValue = (key, value) => {
let values = { ...addressFormValues };
values[key] = value;
setAddressFormValues(values);
};
const changePaymentFormValue = (key, value) => {
let values = { ...addressFormValues };
values[key] = value;
setPaymentFormValues(values);
};
return (
<React.Fragment>
<CssBaseline />
<AppBar position="absolute" color="default" className={classes.appBar}></AppBar>
<main className={classes.layout}>
<Paper className={classes.paper}>
<Typography component="h1" variant="h3" align="center">
Checkout
</Typography>
<Stepper activeStep={activeStep} className={classes.stepper}>
{steps.map((label) => (
<Step key={label}>
<StepLabel><Typography component="h1" variant="h5" align="center">
{label} </Typography></StepLabel>
</Step>
))}
</Stepper>
<React.Fragment>
{activeStep === steps.length ? (
<React.Fragment>
<Typography variant="h5" gutterBottom>
Thank you for your order.
</Typography>
<Typography variant="subtitle1">
Your order number is #2001539. We have emailed your order
confirmation, and will
send you an update when your order has shipped.
</Typography>
</React.Fragment>
) : (
<React.Fragment>
{activeStep === 0 ? getStepContent(activeStep, addressFormValues, changeAddressFormValue , paymentFormValues, changePaymentFormValue) : getStepContent(activeStep)}
{ <div className={classes.buttons}>
{ activeStep !== 0 && (
<Button variant="contained" style={{outline: 'none'}}
className={classes.button}
onClick={handleBack}
>
Back
</Button>
)}
<Button style={{outline: 'none'}}
variant="contained"
color="secondary"
onClick={handleNext}
className={classes.button}
>
{activeStep === steps.length - 1 ? 'Place order' : 'Next'}
</Button>
</div> }
</React.Fragment>
)}
</React.Fragment>
</Paper>
<Copyright />
</main>
</React.Fragment>
);
}
It seems you have checked the activeStep wrong.
Maybe the right code must be like the following:
<React.Fragment>
{activeStep !== 0 ?getStepContent(activeStep, addressFormValues, changeAddressFormValue , paymentFormValues, changePaymentFormValue) : getStepContent(activeStep)}
Do you ever consider using Context API?
React Context API
But also you can use create a checkboxValue with useState in Checkout.js and pass setCheckBoxValue to PaymentForm in getStepContent as prop. When checkbox checked trigger setCheckBoxValue and it will trigger parent component's state (Checkbox).