Consider the below UI.
You can see a heading, Logo Uploaded and Organisation logo
Logo Uploaded are the general logo of the application
Organisation logo is the single logo uploaded specific to the org
LogoComponent.jsx
import React, { useEffect, useState } from "react";
import { Card } from "reactstrap";
import UploadLogo from "./UploadLogo";
import axios from "axios";
import BASE_URL from "../../config/urls";
import DeleteIcon from "#material-ui/icons/Delete";
import { IconButton } from "#material-ui/core";
import { makeStyles } from "#material-ui/core/styles";
import UploadLogoOfOrg from "./UploadLogoOfOrg";
const useStyles = makeStyles((theme) => ({
DeleteIcon: {
fontSize: "15px",
color: "black",
},
}));
export default function OrgLogoCard({ orgId }) {
const classes = useStyles();
const [logos, setLogos] = useState([]);
const [orgLogo, setOrgLogo] = useState("");
useEffect(() => {
axios
.get(`${BASE_URL}client/get-logo-org?_id=${orgId}`, {
headers: {
"Content-Type": "multipart/form-data",
"x-access-token": localStorage.getItem("vyoriusUserAuth"),
},
})
.then((res) => setLogos(res.data))
.catch((err) => {
console.log(err);
});
axios
.get(`${BASE_URL}client/get-logo-of-org?_id=${orgId}`, {
headers: {
"x-access-token": localStorage.getItem("vyoriusUserAuth"),
},
})
.then((res) => setOrgLogo(res.data))
.catch((err) => {
console.log(err);
});
}, []);
const addLogo = (logo) => {
setLogos([...logos, logo]);
};
const deleteIcon = (logo) => {
axios
.post(
`${BASE_URL}client/remove-logo-org`,
{
_id: orgId,
logo,
},
{
headers: {
"x-access-token": localStorage.getItem("vyoriusUserAuth"),
},
}
)
.then((_) => {
setLogos(logos.filter((l) => l != logo));
})
.catch((err) => {
console.log(err, err?.response?.data);
alert("Can not remove logo at the moment!");
});
};
return (
<Card className="m-2 p-2 border-0">
<div className="d-flex">
<h6 className="mr-2 ml-2">Logo Uploaded</h6>{" "}
<UploadLogo orgId={orgId} addLogo={addLogo} />
</div>
<div>{logos.length == 0 && "There is no logo!"}</div>
<div className="d-flex p-2 flex-wrap">
{logos.map((ele, index) => (
<div key={index} className="position-relative">
<img
className="mr-1 mt-1"
src={ele}
alt=""
style={{
height: "40px",
width: "80px",
}}
/>
<div
style={{
top: "-10px",
right: "0px",
}}
className="position-absolute"
>
<IconButton
onClick={() => deleteIcon(ele)}
color="secondary"
aria-label="delete"
size="small"
>
<DeleteIcon className={classes.DeleteIcon} fontSize="inherit" />
</IconButton>
</div>
</div>
))}
</div>
<div className="d-flex mt-4">
<h6 className="mr-2 ml-2">Organization logo</h6>{" "}
<UploadLogoOfOrg
orgId={orgId}
addLogo={(loc) => setOrgLogo(loc)}
/>
</div>
<div className="d-flex">
<img
className="mr-1 mt-1"
src={orgLogo}
alt=""
style={{
height: "40px",
width: "80px",
}}
/>
</div>
</Card>
);
}
UploadLogo.jsx
import React from "react";
import AddAPhotoIcon from "#material-ui/icons/AddAPhoto";
import axios from "axios";
import { BASE_URL } from "../../config/urls";
import { connect } from "react-redux";
import { makeStyles } from "#material-ui/core/styles";
const useStyles = makeStyles((theme) => ({
AddAPhotoIcon: {
height: "1rem",
marginTop: "-10px",
color: "black",
},
}));
// isOrgLogo - logo of the org
function UploadOrgLogos({ userInfo, addLogo, orgId }) {
const classes = useStyles();
return (
<form>
<label
htmlFor="file-input"
style={{
cursor: "pointer",
}}
>
<AddAPhotoIcon className={classes.AddAPhotoIcon} color="primary" />
</label>
<input
style={{
display: "none",
}}
id="file-input"
type="file"
onChange={(e) => {
if (!e.target.files[0]) return;
// if there is no user
// TODO: add toast notification
if (!userInfo || !userInfo.email) {
console.log("User is not in redux!");
}
const role = userInfo.userRole.find(
(role) => role.organization == orgId
);
if (!role || role.role != "SuperAdmin") {
alert("Not a super admin!");
return;
} else {
console.log("A super admin!");
}
let formData = new FormData();
formData.append("file", e.target.files[0]);
formData.append("folder", "org-logos");
formData.append("fileId", "org-logo");
formData.append("bucket", "vyoriusdronesdatabase");
formData.append("_id", orgId);
axios
.post(`${BASE_URL}client/add-logo-org`, formData, {
headers: {
"Content-Type": "multipart/form-data",
"x-access-token": localStorage.getItem("vyoriusUserAuth"),
},
})
.then((res) => addLogo(res.data))
.catch((err) => {
console.log(err);
alert("Error in uploading file...");
});
}}
/>
</form>
);
}
const mapStateToProps = ({ login_details }) => {
return {
userInfo: login_details.login_detail,
};
};
// HMR
export default connect(mapStateToProps, null)(UploadOrgLogos);
UploadLogoOfOrg.jsx
import React from "react";
import AddAPhotoIcon from "#material-ui/icons/AddAPhoto";
import axios from "axios";
import { BASE_URL } from "../../config/urls";
import { connect } from "react-redux";
import { makeStyles } from "#material-ui/core/styles";
const useStyles = makeStyles((theme) => ({
AddAPhotoIcon: {
height: "1rem",
marginTop: "-10px",
color: "black",
},
}));
function UploadOrgLogos({ userInfo, addLogo, orgId }) {
const classes = useStyles();
return (
<form>
<label
htmlFor="file-input"
style={{
cursor: "pointer",
}}
>
<AddAPhotoIcon className={classes.AddAPhotoIcon} color="primary" />
</label>
<input
style={{
display: "none",
}}
id="file-input"
type="file"
onChange={(e) => {
if (!e.target.files[0]) return;
// if there is no user
// TODO: add toast notification
if (!userInfo || !userInfo.email) {
console.log("User is not in redux!");
}
const role = userInfo.userRole.find(
(role) => role.organization == orgId
);
if (!role || role.role != "SuperAdmin") {
alert("Not a super admin!");
return;
} else {
console.log("A super admin!");
}
let formData = new FormData();
formData.append("file", e.target.files[0]);
formData.append("folder", "org-logos");
formData.append("fileId", "org-logo");
formData.append("bucket", "vyoriusdronesdatabase");
formData.append("_id", orgId);
axios
.post(`${BASE_URL}client/add-logo-of-org`, formData, {
headers: {
"Content-Type": "multipart/form-data",
"x-access-token": localStorage.getItem("vyoriusUserAuth"),
},
})
.then((res) => addLogo(res.data))
.catch((err) => {
console.log(err);
alert("Error in uploading file...");
});
}}
/>
</form>
);
}
const mapStateToProps = ({ login_details }) => {
return {
userInfo: login_details.login_detail,
};
};
// HMR
export default connect(mapStateToProps, null)(UploadOrgLogos);
Clicking on any one of them, the request is being sent to client/add-logo-org. If I remove <UploadLogo orgId={orgId} addLogo={addLogo} / from LogoComponent.jsx then its working fine.
Edited
If I swap <UploadLogoOfOrg orgId={orgId} addLogo={(loc) => setOrgLogo(loc)} /> with <UploadLogo orgId={orgId} addLogo={addLogo} /> then all request are being sent on /client/add-logo-of-org.
My own ans
The problem is resolved, in both component <input id="file-input">, this file-input is was causing the issue. I changed it in one component from file-input to file-input-1 and it worked fine.
#SayyedDawood
Related
I am creating a progress bar using the package - react-step-progress-bar
My progress bar code is as below (This is just the standard code of the package)
For simplicity, i am just creating two steps
import React, { useEffect } from "react";
import "react-step-progress-bar/styles.css";
import { ProgressBar, Step } from "react-step-progress-bar";
const LoadingBar = (props) => {
console.log('Logging inside loading bar',props.progressBar)
return (
<div className="w-[50%] z-50">
<ProgressBar
percent={props.progressBar}
fillBackground="linear-gradient(to right, #fefb72, #f0bb31)"
>
<Step transition="scale">
{({ accomplished }) => (
<img
style={{ filter: `grayscale(${accomplished ? 0 : 80}%)`, transform: "" }}
width="60"
src="/loadingBar/verifiedHashFiles.png"
alt=""
/>
)}
</Step>
<Step transition="scale">
{({ accomplished }) => (
<img
style={{ filter: `grayscale(${accomplished ? 0 : 80}%)`, transform: "" }}
width="60"
src="/loadingBar/verifiedTransaction.png"
alt=""
/>
)}
</Step>
</ProgressBar>
</div>
)
}
export default LoadingBar
I am using this to create a progressive bar in the way below in my home page
import axios from 'axios';
import React, { useContext, useEffect, useState, useCallback } from 'react'
import cuid from "cuid";
import { DataContext } from '../Context/DataContext';
import { Dropzone, FileVerificationFailed, FileVerificationSuccessful } from '../Components'
import "react-step-progress-bar/styles.css";
import LoadingBar from './LoadingBar';
export function Home() {
const [progressBar, setprogressBar] = useState(0);
const sendFileToIPFS = async (e) => {
e.preventDefault();
if (fileImg) {
try {
const formData = new FormData();
formData.append("file", fileImg);
const resFile = await axios({
method: "post",
url: "https://api.pinata.cloud/pinning/pinFileToIPFS",
data: formData,
headers: {
'pinata_api_key': `${process.env.REACT_APP_PINATA_API_KEY}`,
'pinata_secret_api_key': `${process.env.REACT_APP_PINATA_API_SECRET}`,
"Content-Type": "multipart/form-data"
},
});
setprogressBar(50)
if (certificateData.find(uploadedFile => uploadedFile.CID === resFile.data.IpfsHash)) {
setQRurl(certificateData.find(uploadedFile => uploadedFile.CID === resFile.data.IpfsHash).QRurl)
console.log('Verified')
setVerified(true)
}
else {
console.log('Failed')
setVerificationFailed(true)
unpin(resFile.data.IpfsHash)
}
setprogressBar(100)
} catch (error) {
console.log("File to IPFS: ")
console.log(error)
}
}
}
return (
....
{progressBar!=0 && (<div className='absolute ml-[5%] mt-[5%] h-[60%] w-[60%] z-50'>
<div className='flex justify-center'>
<LoadingBar progressBar={progressBar} />
</div>
</div>)}
....
50% never gets set or logged but the bar gets to 100% directly and logs it
How do i execute this?
Please help
I am able to post and get data but unable to delete must be a problem with an id that I am passing to the delete note function.
these are my files:
Note.js
import React, {useState} from 'react';
import DeleteIcon from '#material-ui/icons/Delete';
import EditIcon from '#material-ui/icons/Edit';
import SaveIcon from '#material-ui/icons/Save';
function Note(props) {
function handleClick() {
props.onDelete(props.id);
}
const[edit, setEdit]=useState(false);
function editTrue() {
setEdit(!edit);
}
return(
<div className={!edit ? "note" : "note1"}>
<h1 contentEditable={edit && "true"} spellCheck="true">{props.title}</h1>
<hr/>
<p />
<p contentEditable={edit && "true"} spellCheck="true">{props.content}</p>
{!edit && <button onClick={handleClick}><DeleteIcon /></button>}
{edit ? <button onClick={editTrue}> <SaveIcon /> </button> : <button onClick={editTrue}><EditIcon /></button>}
</div>
);
}
export default Note;
App.js
import React, { useState, useEffect } from 'react';
//import { DragDropContext } from 'react-beautiful-dnd';
import Header from './Header';
import Footer from './Footer';
import Note from './Note';
import CreateArea from './CreateArea'
function App() {
const [notes, setNotes] = useState([]);
useEffect(() => {
fetch('https://react-hooks-update-ec587-default-rtdb.firebaseio.com/notes.json')
.then(response => response.json())
.then(responseData => {
const loadedNotes = [];
for( const key in responseData ) {
loadedNotes.push({
id: key,
title: responseData[key].title,
content: responseData[key].content
});
}
setNotes(loadedNotes);
});
}, []);
function addNote(newNote) {
fetch('https://react-hooks-update-ec587-default-rtdb.firebaseio.com/notes.json', {
method: 'POST',
body: JSON.stringify(newNote),
headers: { 'content-Type': 'application/json' }
}).then(response => {
return response.json();
}).then(responseData => {
setNotes(prevNotes => [
...prevNotes,
{ id: responseData.name, ...newNote }
]);
});
}
function deleteNote(noteId) {
fetch(`https://react-hooks-update-ec587-default-rtdb.firebaseio.com/notes/${noteId}.json`,
{
method: 'DELETE'
}
).then(response => {
setNotes(prevNotes => {
return prevNotes.filter((noteItem, index) => {
return index !== noteId;
});
});
});
}
return(
<div>
<Header />
<CreateArea
onAdd={addNote}
/>
{notes.map((noteItem, index) => {
return (
<Note
key={index}
id={index}
title={noteItem.title}
content={noteItem.content}
onDelete={deleteNote}
/>
);
})}
<Footer />
</div>
);
}
export default App;
what changes I can do?
when I run my file delete operation is working locally but it does not delete the note from the database
I am able to post and get data but unable to delete must be a problem with an id that I am passing to the delete note function.
May be in deleteNote in fetch url remove .json:
fetch(`https://react-hooks-update-ec587-default-rtdb.firebaseio.com/notes/${noteId}`)
I've two different prices,
when i check the checkbox for second price,
the state show and display the second price properly
but when i press the pay button of that product with second price, it will send the first price
instead of what I've checked which was second price.
so i want increment both prices separately when i checked the check box and
it sends the specific price to the payment process
import React, { useState, useEffect } from "react";
import {
getProducts,
getBraintreeClientToken,
processPayment,
createOrder
} from "./apiCore";
import { emptyCart } from "./cartHelpers";
import { isAuthenticated } from "../auth";
import { Link } from "react-router-dom";
import "braintree-web";
import DropIn from "braintree-web-drop-in-react";
import { makeStyles } from '#material-ui/core/styles';
import TextField from '#material-ui/core/TextField';
const useStyles = makeStyles((theme) => ({
root: {
'& > *': {
margin: theme.spacing(1),
width: '25ch',
},
},
}));
const Checkout = ({ products, setRun = f => f, run = undefined }) => {
const classes = useStyles();
const [data, setData] = useState({
loading: false,
success: false,
clientToken: null,
error: "",
instance: {},
address: "",
mobile:""
});
>>>>>> const [price, setPrice]= useState(() => () => getTotal())
>>>>>> const [isChecked, setIsChecked]= useState(false);
const userId = isAuthenticated() && isAuthenticated().user._id;
const token = isAuthenticated() && isAuthenticated().token;
const getToken = (userId, token) => {
getBraintreeClientToken(userId, token).then(data => {
if (data.error) {
setData({ ...data, error: data.error });
} else {
setData({ clientToken: data.clientToken });
}
});
};
useEffect(() => {
getToken(userId, token);
}, []);
const handleAddress = event => {
setData({ ...data, address: event.target.value });
};
const handleMobile = event => {
setData({ ...data, mobile: event.target.value });
};
>>>>>> const getTotal = () => {
>>>>>> return products.reduce((currentValue, nextValue) => {
>>>>>> return currentValue + nextValue.count * nextValue.price;
>>>>>>
>>>>>> }, 0);
>>>>>> };
>>>>>> const getTotal2 = () => {
>>>>>> return products.reduce((currentValue, nextValue) => {
>>>>>> return currentValue + nextValue.count * nextValue.price2;
>>>>>> }, 0);
>>>>>> };**
const showCheckout = () => {
return isAuthenticated() ? (
<div>{showDropIn()}</div>
) : (
<Link to="/signin">
<button className="btn btn-primary">Sign in to checkout</button>
</Link>
);
};
let deliveryAddress = data.address
let deliveryMobile = data.mobile
const buy = () => {
setData({ loading: true });
// send the nonce to your server
// nonce = data.instance.requestPaymentMethod()
let nonce;
let getNonce = data.instance
.requestPaymentMethod()
.then(data => {
// console.log(data);
nonce = data.nonce;
// once you have nonce (card type, card number) send nonce as 'paymentMethodNonce'
// and also total to be charged
// console.log(
// "send nonce and total to process: ",
// nonce,
// getTotal(products)
// );
>>>>>> **const paymentData = {
>>>>>> paymentMethodNonce: nonce,
>>>>>> amount: getTotal(products)
>>>>>> };**
processPayment(userId, token, paymentData)
.then(response => {
console.log(response);
// empty cart
// create order
const createOrderData = {
products: products,
transaction_id: response.transaction.id,
amount: response.transaction.amount,
address: deliveryAddress,
mobile: deliveryMobile
};
createOrder(userId, token, createOrderData)
.then(response => {
emptyCart(() => {
setRun(!run); // run useEffect in parent Cart
console.log(
"payment success and empty cart"
);
setData({
loading: false,
success: true
});
});
})
.catch(error => {
console.log(error);
setData({ loading: false });
});
})
.catch(error => {
console.log(error);
setData({ loading: false });
});
})
.catch(error => {
// console.log("dropin error: ", error);
setData({ ...data, error: error.message });
});
};
const showDropIn = () => (
<div onBlur={() => setData({ ...data, error: "" })}>
{data.clientToken !== null && products.length > 0 ? (
<div>
<div className="gorm-group mb-3">
<label className="text-muted">Delivery address:</label>
<textarea
onChange={handleAddress}
className="form-control"
value={data.address}
placeholder="Type your delivery address here..."
/>
</div>
<div className="gorm-group mb-3">
<label className="text-muted">mobile number:</label>
<form className={classes.root} noValidate autoComplete="off">
<TextField placeholder="mobile number" onChange={handleMobile} type="text" value={data.mobile} id="outlined-basic" label="mobile" variant="outlined" />
</form>
</div>
<DropIn
options={{
authorization: data.clientToken,
paypal: {
flow: "vault"
}
}}
onInstance={instance => (data.instance = instance)}
/>
<button onClick={buy} className="btn btn-success btn-block">
Pay
</button>
</div>
) : null}
</div>
);
const showError = error => (
<div
className="alert alert-danger"
style={{ display: error ? "" : "none" }}
>
{error}
</div>
);
const showSuccess = success => (
<div
className="alert alert-info"
style={{ display: success ? "" : "none" }}
>
Thanks! Your payment was successful!
</div>
);
const showLoading = loading =>
loading && <h2 className="text-danger">Loading...</h2>;
return (
<div>
>>>>>> **<form>
>>>>>> <h1>قیمت کل: {isChecked ? getTotal2() : getTotal()} </h1>
>>>>>> <label>نیم لیتر :</label>
>>>>> <input type="checkbox"
>>>>>> checked={isChecked}
>>>>>> onChange={(e)=>{setIsChecked(e.target.checked)}}/>
>>>>>> </form>**
{showLoading(data.loading)}
{showSuccess(data.success)}
{showError(data.error)}
{showCheckout()}
</div>
);
};
export default Checkout;
my card component
import React, { useState, version,useEffect } from 'react';
import { Link, Redirect } from 'react-router-dom';
import ShowImage from './ShowImage';
import moment from 'moment';
import { addItem, updateItem, removeItem } from './cartHelpers';
import logo from '../images/logo.svg'
//material ui
import Card from '#material-ui/core/Card';
import CardContent from '#material-ui/core/CardContent';
import { makeStyles } from '#material-ui/core/styles';
import Button from '#material-ui/core/Button';
import Grid from '#material-ui/core/Grid'
import { Typography } from '#material-ui/core';
import CardHeader from '#material-ui/core/CardHeader';
import CardMedia from '#material-ui/core/CardMedia';
import CardActions from '#material-ui/core/CardActions';
import Collapse from '#material-ui/core/Collapse';
import Avatar from '#material-ui/core/Avatar';
import IconButton from '#material-ui/core/IconButton';
import MoreVertIcon from '#material-ui/icons/MoreVert';
import FormControlLabel from '#material-ui/core/FormControlLabel';
import Menu from '#material-ui/core/Menu';
import MenuItem from '#material-ui/core/MenuItem';
import { create } from 'jss';
import rtl from 'jss-rtl';
import { StylesProvider, jssPreset } from '#material-ui/core/styles';
const jss = create({ plugins: [...jssPreset().plugins, rtl()] });
const useStyles = makeStyles((theme) => ({
stock: {
marginBottom: '1rem'
},
Button: {
...theme.typography.button,
padding: '.3rem',
minWidth: 10,
},
media: {
height: 0,
paddingTop: '56.25%', // 16:9
},
title: {
backgroundColor: '#D8D8D8'
},
grid: {
padding: '0'
},
cardFont:{
...theme.typography.body,
textAlign:'right',
marginTop:'.8rem',
marginRight:'1rem'
},productName:{
...theme.typography.body,
textAlign:'right',
},
cardButton:{
marginLeft:'1.4rem'
}
}));
const Cardd = ({
product,
showViewProductButton = true,
showAddToCartButton = true,
cartUpdate = false,
showRemoveProductButton = false,
setRun = f => f,
run = undefined
// changeCartSize
}) => {
const [redirect, setRedirect] = useState(false);
const [count, setCount] = useState(product.count);
//material ui
const [anchorEl, setAnchorEl] = React.useState(null);
const handleClick = (event) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
// console.log(price)
const classes = useStyles()
const showViewButton = showViewProductButton => {
return (
showViewProductButton && (
<Link to={`/product/${product._id}`} className="mr-2">
<Button className={classes.Button} size="small" variant="contained">مشاهده محصول</Button>
</Link>
)
);
};
const addToCart = () => {
// console.log('added');
addItem(product, setRedirect(true));
};
const shouldRedirect = redirect => {
if (redirect) {
return <Redirect to="/cart" />;
}
};
const showAddToCartBtn = showAddToCartButton => {
return (
showAddToCartButton && (
<Button className={classes.Button} size="small" onClick={addToCart} variant="contained" color="primary" disableElevation>
اضافه کردن به سبد
</Button>
)
);
};
const showStock = quantity => {
return quantity > 0 ? (
<Button disabled size="small" className={classes.stock}>موجود </Button>
) : (
<Button className={classes.stock}>ناموجود </Button>
);
};
const handleChange = productId => event => {
setRun(!run); // run useEffect in parent Cart
setCount(event.target.value < 1 ? 1 : event.target.value);
if (event.target.value >= 1) {
updateItem(productId, event.target.value);
}
};
const showCartUpdateOptions = cartUpdate => {
return (
cartUpdate && (
<div>
<div className="input-group mb-3">
<div className="input-group-prepend">
<span className="input-group-text">تعداد</span>
</div>
<input type="number" className="form-control" value={count} onChange={handleChange(product._id)} />
</div>
</div>
)
);
};
const showRemoveButton = showRemoveProductButton => {
return (
showRemoveProductButton && (
<Button className={classes.Button} size="small" variant="contained" color="secondary" disableElevation
onClick={() => {
removeItem(product._id);
setRun(!run); // run useEffect in parent Cart
}}
>
حذف محصول
</Button>
)
);
};
return (
<Grid container direction='column' >
<Grid item >
<Card style={{margin:'1rem'}}>
<Grid item className={classes.title}>
<Typography className={classes.productName} variant='h6'>
{product.name}
</Typography>
</Grid>
<CardHeader
avatar={
<Avatar alt="Remy Sharp" src={logo} className={classes.green}>
</Avatar>
}
action={
<IconButton aria-label="settings">
<MoreVertIcon />
</IconButton>
}
title="روغنک"
subheader="September 14, 2016"
/>
<CardContent className={classes.grid} >
{shouldRedirect(redirect)}
<ShowImage item={product} url="product" />
<StylesProvider jss={jss}>
<Typography className={classes.cardFont} variant="body2" component="p">
{product.description.substring(0, 100)}
</Typography>
</StylesProvider>
<div>
<Button aria-controls="simple-menu" aria-haspopup="true" onClick={handleClick}>
Open Menu
</Button>
<Menu
id="simple-menu"
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={handleClose}
>
<MenuItem onClick={handleClose}>Profile</MenuItem>
<MenuItem onClick={handleClose}>My account</MenuItem>
<MenuItem onClick={handleClose}>Logout</MenuItem>
</Menu>
</div>
<Typography className={classes.cardFont} variant="body2" component="p">
$یک لیتر {product.price}
</Typography>
<Typography className={classes.cardFont} variant="body2" component="p">
$نیم لیتر {product.price2}
</Typography>
<Typography className={classes.cardFont} variant="body2" component="p">
Category: {product.category && product.category.name}
</Typography>
<Typography className={classes.cardFont} variant="body2" component="p">
Added on {moment(product.createdAt).fromNow()}
</Typography>
<Typography className={classes.cardFont} variant="body2" component="p">
{showStock(product.quantity)}
</Typography>
<br />
<Grid container >
<Grid item className={classes.cardButton} >
{showViewButton(showViewProductButton)}
</Grid>
<Grid item className={classes.cardButton}>
{showAddToCartBtn(showAddToCartButton)}
</Grid>
<Grid item className={classes.cardButton}>
{showRemoveButton(showRemoveProductButton)}
</Grid>
</Grid>
{showCartUpdateOptions(cartUpdate)}
</CardContent>
</Card>
</Grid>
</Grid>
// <div className="card ">
// <div className="card-header card-header-1 ">{product.name}</div>
// <div className="card-body">
// {shouldRedirect(redirect)}
// <ShowImage item={product} url="product" />
// <p className="card-p mt-2">{product.description.substring(0, 100)} </p>
// <p className="card-p black-10">$ {product.price}</p>
// <p className="black-9">Category: {product.category && product.category.name}</p>
// <p className="black-8">Added on {moment(product.createdAt).fromNow()}</p>
// {showStock(product.quantity)}
// <br />
// {showViewButton(showViewProductButton)}
// {showAddToCartBtn(showAddToCartButton)}
// {showRemoveButton(showRemoveProductButton)}
// {showCartUpdateOptions(cartUpdate)}
// </div>
// </div>
);
};
export default Cardd;
CartHelper component
export const addItem = (item = [], count = 0, next = f => f) => {
let cart = [];
if (typeof window !== 'undefined') {
if (localStorage.getItem('cart')) {
cart = JSON.parse(localStorage.getItem('cart'));
}
cart.push({
...item,
count: 1
});
// remove duplicates
// build an Array from new Set and turn it back into array using Array.from
// so that later we can re-map it
// new set will only allow unique values in it
// so pass the ids of each object/product
// If the loop tries to add the same value again, it'll get ignored
// ...with the array of ids we got on when first map() was used
// run map() on it again and return the actual product from the cart
cart = Array.from(new Set(cart.map(p => p._id))).map(id => {
return cart.find(p => p._id === id);
});
localStorage.setItem('cart', JSON.stringify(cart));
next();
}
};
export const itemTotal = () => {
if (typeof window !== 'undefined') {
if (localStorage.getItem('cart')) {
return JSON.parse(localStorage.getItem('cart')).length;
}
}
return 0;
};
export const getCart = () => {
if (typeof window !== 'undefined') {
if (localStorage.getItem('cart')) {
return JSON.parse(localStorage.getItem('cart'));
}
}
return [];
};
export const updateItem = (productId, count) => {
let cart = [];
if (typeof window !== 'undefined') {
if (localStorage.getItem('cart')) {
cart = JSON.parse(localStorage.getItem('cart'));
}
cart.map((product, i) => {
if (product._id === productId) {
cart[i].count = count;
}
});
localStorage.setItem('cart', JSON.stringify(cart));
}
};
export const removeItem = productId => {
let cart = [];
if (typeof window !== 'undefined') {
if (localStorage.getItem('cart')) {
cart = JSON.parse(localStorage.getItem('cart'));
}
cart.map((product, i) => {
if (product._id === productId) {
cart.splice(i, 1);
}
});
localStorage.setItem('cart', JSON.stringify(cart));
}
return cart;
};
export const emptyCart = next => {
if (typeof window !== 'undefined') {
localStorage.removeItem('cart');
next();
}
};
I have this working on a page and a form, I am able to create a post, but I want to create the post with some default values and automatically take you to the edit page on a button press.
I am using next js aws-cdk, amplify, graphql,
The error I am getting is this
Variable 'post' has coerced Null value for NonNull type 'PostInput!'
I can't seem to figure out why I can create a post from a page button click but not from a button click in a component and reroute me to the edit page
this is the code that is working
create-post.js
// pages/create-post.js
import { withAuthenticator } from "#aws-amplify/ui-react";
import { useState } from "react";
import { API } from "aws-amplify";
import { v4 as uuid } from "uuid";
import { useRouter } from "next/router";
import SimpleMDE from "react-simplemde-editor";
import "easymde/dist/easymde.min.css";
import { createPost } from "../graphql";
const initialState = { title: "", content: "" };
function CreatePost() {
const [post, setPost] = useState(initialState);
const { title, content } = post;
const router = useRouter();
function onChange(e) {
console.log(e.target.name + " " + e.target.value);
setPost(() => ({ ...post, [e.target.name]: e.target.value }));
console.log(post);
}
async function createNewPost() {
if (!title || !content) return;
const id = uuid();
post.id = id;
console.log(post);
await API.graphql({
query: createPost,
variables: { post },
authMode: "AMAZON_COGNITO_USER_POOLS",
});
router.push(`/posts/${id}`);
}
return (
<div style={containerStyle}>
<h2>Create new Post</h2>
<input
onChange={onChange}
name="title"
placeholder="Title"
value={post.title}
style={inputStyle}
/>
<div>
{/* <input
onChange={onChange}
name="ingredients"
placeholder="Ingredient"
value={post.ingredients}
style={inputStyle}
/> */}
<p>cups</p>
<input name="measurments" type="radio" value="cups" />
<p>tablespoons</p>
<input name="measurments" type="radio" value="tablespoons" />
<p>ML</p>
<input name="measurments" type="radio" value="ml" />
<p>Weight</p>
<input name="measurments" type="radio" value="weight" />
</div>
<SimpleMDE
value={post.content}
onChange={(value) => setPost({ ...post, content: value })}
/>
<button style={buttonStyle} onClick={createNewPost}>
Create Post
</button>
</div>
);
}
const inputStyle = {
marginBottom: 10,
height: 35,
width: 300,
padding: 8,
fontSize: 16,
};
const containerStyle = { padding: "0px 40px" };
const buttonStyle = {
width: 300,
backgroundColor: "white",
border: "1px solid",
height: 35,
marginBottom: 20,
cursor: "pointer",
};
export default withAuthenticator(CreatePost);
graphql.js
export const getPostById = /* GraphQL */ `
query getPostById($postId: ID!) {
getPostById(postId: $postId) {
id
title
content
owner
}
}
`;
export const listPosts = /* GraphQL */ `
query ListPosts {
listPosts {
id
title
content
owner
}
}
`;
export const postsByUsername = /* GraphQL */ `
query PostsByUsername {
postsByUsername {
id
title
content
owner
}
}
`;
export const createPost = /* GraphQL */ `
mutation CreatePost($post: PostInput!) {
createPost(post: $post) {
id
title
content
owner
}
}
`;
export const updatePost = /* GraphQL */ `
mutation UpdatePost($post: UpdatePostInput!) {
updatePost(post: $post) {
id
title
content
ingredients
}
}
`;
export const deletePost = /* GraphQL */ `
mutation DeletePost($postId: ID!) {
deletePost(postId: $postId)
}
`;
this is the code that isn't working
hello compoenent
THIS IS THE PART THAT IS NOT WORKING
import { withAuthenticator } from "#aws-amplify/ui-react";
import { Auth, Hub, API } from "aws-amplify";
// import { API } from "aws-amplify";
import { useRouter } from "next/router";
import { v4 as uuid } from "uuid";
import { createPost } from "../graphql";
const initialState = { title: "Title Here", content: "Content Here" };
function Hello() {
async function createNewPost() {
// if (!title || !content || !ingredients) return;
const id = uuid();
initialState.id = id;
console.log(initialState);
await API.graphql({
query: createPost,
variables: initialState,
authMode: "AMAZON_COGNITO_USER_POOLS",
});
router.push(`/edit-post/${id}`);
}
return (
<button style={buttonStyle} onClick={createNewPost}>
Create Post
</button>
);
}
const buttonStyle = {
width: 300,
backgroundColor: "white",
border: "1px solid",
height: 35,
marginBottom: 20,
cursor: "pointer",
};
export default withAuthenticator(Hello);
app with button to click
import "../configureAmplify";
import "../styles/globals.css";
import styles from "../styles/Home.module.css";
import "../configureAmplify";
import Link from "next/link";
import { useState, useEffect } from "react";
import { Auth, Hub, API } from "aws-amplify";
// import { API } from "aws-amplify";
import { v4 as uuid } from "uuid";
import { createPost } from "../graphql";
import Hello from "../components/hello";
function MyApp({ Component, pageProps }) {
const [signedInUser, setSignedInUser] = useState(false);
//const [post, setPost] = useState(initialState);
//const { title, content, ingredients } = post;
//setPost(initialState);
useEffect(() => {
authListener();
});
async function authListener() {
Hub.listen("auth", (data) => {
switch (data.payload.event) {
case "signIn":
return setSignedInUser(true);
case "signOut":
return setSignedInUser(false);
}
});
try {
await Auth.currentAuthenticatedUser();
setSignedInUser(true);
} catch (err) {}
}
return (
<div>
<nav style={navStyle}>
<Link href="/">
<span style={linkStyle}>Home</span>
</Link>
<Hello />
{signedInUser && (
<Link href="/my-posts">
<span style={linkStyle}>My Posts</span>
</Link>
)}
<Link href="/profile">
<span style={linkStyle}>Profile</span>
</Link>
</nav>
<div style={bodyStyle}>
<Component {...pageProps} />
</div>
</div>
);
}
const navStyle = { padding: 20, borderBottom: "1px solid #ddd" };
const bodyStyle = { minHeight: "calc(100vh - 190px)", padding: "20px 40px" };
const linkStyle = { marginRight: 20, cursor: "pointer" };
export default MyApp;
After using a form and inserting new data this error show up.
This is my code:
import React from "react";
import { Form, Input, Button } from "antd";
import { connect } from "react-redux";
import axios from "axios";
import hashHistory from './hashHistory';
const FormItem = Form.Item;
class CustomForm extends React.Component {
handleFormSubmit = async (event, requestType, articleID) => {
event.preventDefault();
const postObj = {
title: event.target.elements.title.value,
content: event.target.elements.content.value
}
axios.defaults.xsrfHeaderName = "X-CSRFTOKEN";
axios.defaults.xsrfCookieName = "csrftoken";
axios.defaults.headers = {
"Content-Type": "application/json",
Authorization: `Token ${this.props.token}`,
};
if (requestType === "post") {
await axios.post("http://192.168.196.49:8000/api/create/", postObj)
.then(res => {
if (res.status === 201) {
//this.props.history.push(`/articles/`);
//this.props.hashHistory.push('/');
//hashHistory.push(String('/articles/'))
this.props.history.push({
pathname: "/"
})
}
})
} else if (requestType === "put") {
await axios.put(`http://192.168.196.49:8000/api/${articleID}/update/`, postObj)
.then(res => {
if (res.status === 200) {
//this.props.history.push(`/articles/`);
//this.props.hashHistory.push('/');
//hashHistory.push(String('/articles/'))
this.props.history.push({
pathname: "/"
})
}
})
}
};
render() {
console.log("debug:", this.props)
return (
<div>
<Form
onSubmit={event =>
this.handleFormSubmit(
event,
this.props.requestType,
this.props.articleID
)
}
>
<FormItem label="Título">
<Input name="title" placeholder="Put a title here" />
</FormItem>
<FormItem label="Comentario">
<Input name="content" placeholder="Enter some content ..." />
</FormItem>
<FormItem>
<Button type="primary" htmlType="submit">
{this.props.btnText}
</Button>
</FormItem>
</Form>
</div>
);
}
}
const mapStateToProps = state => {
return {
token: state.token
};
};
export default connect(mapStateToProps)(CustomForm);
Routes
<Route exact path="/articles/" component={ArticleList} />{" "}
<Route exact path="/articles/:articleID/" component={ArticleDetail} />{" "}
Error message:
TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received type undefined
The data is storing correcty to the database, but just after submiting there is this error.
My original code was using history.push but tried hashHistory.push.
I am using redux in the proyect.
Verision using:
react-router 5.1.2
history 4.9.0
Try make a module hashHistory:
// hashHistory.js
import { createHashHistory } from 'history'; // worked for the OP
export default createHashHistory({});
And use it:
const history = createHashHistory();
// ....
// **EDIT** This should work
history.push("/articles/")
You can use withRouter to push history in props.
import { withRouter } from 'react-router';
const SpecialButton = withRouter(({ history, path, text }) => {
return (
<Button
onClick={() => { history.push(path); }}
>
{text}
</Button>
)
});
This was the solution that works (may be is not the best one...)
code:
import React from "react";
import { Form, Input, Button } from "antd";
import { connect } from "react-redux";
import axios from "axios";
import { createHashHistory } from 'history'
const FormItem = Form.Item;
class CustomForm extends React.Component {
handleFormSubmit = async (event, requestType, articleID) => {
event.preventDefault();
const postObj = {
title: event.target.elements.title.value,
content: event.target.elements.content.value
}
axios.defaults.xsrfHeaderName = "X-CSRFTOKEN";
axios.defaults.xsrfCookieName = "csrftoken";
axios.defaults.headers = {
"Content-Type": "application/json",
Authorization: `Token ${this.props.token}`,
};
const history = createHashHistory();
if (requestType === "post") {
console.log("debug_1.1_Form_post_history: ", history )
await axios.post("http://192.168.196.49:8000/api/create/", postObj)
.then(res => {
if (res.status === 201) {
history.push("/articles/")
}
})
} else if (requestType === "put") {
console.log("debug_1.2_Form_put_history: ", history )
await axios.put(`http://192.168.196.49:8000/api/${articleID}/update/`, postObj)
.then(res => {
if (res.status === 200) {
console.log("debug_1.3_Form_put_this.props: ", this.props)
history.push("/articles/");
}
})
}
};
render() {
return (
<div>
<Form
onSubmit={event =>
this.handleFormSubmit(
event,
this.props.requestType,
this.props.articleID
)
}
>
<FormItem label="Title">
<Input name="title" placeholder="Put a title here" />
</FormItem>
<FormItem label="Content">
<Input name="content" placeholder="Enter some content ..." />
</FormItem>
<FormItem>
<Button type="primary" htmlType="submit">
{this.props.btnText}
</Button>
</FormItem>
</Form>
</div>
);
}
}
const mapStateToProps = state => {
return {
token: state.token
};
};
export default connect(mapStateToProps)(CustomForm);