Here's the product.js code:
import { Button } from 'primereact/button';
const Product = ({product, onIncrement, onDecrement}) => {
return(
<div className='p-card border-white flex flex-column w-13rem m-3'>
<img src={`data:image/png;base64,${product.image}`} alt='img' className='border-round-sm h-9rem' />
<div className='p-card-title flex flex-column align-items-center py-2 m-0'>
<div>{product.name}</div>
<div>€{product.price}</div>
</div>
<div className='p-card-content flex justify-content-center py-0'>
<Button className="p-button-success m-1 px-3" onClick={()=>onIncrement(product)}>Aggiungi</Button>
<Button className="p-button-danger m-1 px-3" onClick={()=>onDecrement(product)}>Rimuovi</Button>
</div>
<div className='flex flex-column pt-2 pb-3'>
<div className='flex justify-content-center'>Quantità: {product.quantity}</div>
<div className='flex justify-content-center'>Totale: €{product.total}</div>
</div>
</div>
);
}
export default Product;
And here's the insertproductform.js code:
import { useState , useRef, useContext } from "react";
import { InputText } from 'primereact/inputtext';
import {InputNumber} from 'primereact/inputnumber';
import axios from 'axios';
import { Toast } from 'primereact/toast';
import { InputTextarea } from 'primereact/inputtextarea';
import InsertProductImageForm from "./insertproductimageform";
import { Dialog } from "primereact/dialog";
import { Button } from "primereact/button";
import imagedefault from "../../../media/logo.png";
import { ContextProductList } from "../../store";
const Form = () => {
const toast = useRef(null);
const [visibleInsertImage, setVisibleInsertImage] = useState(false);
const [productList, setProductList] = useContext(ContextProductList);
const [name, setName] = useState('');
const [price, setPrice] = useState(0);
const [image, setImage] = useState(null);
const [description, setDescription] = useState('');
const setInputStateNull = () => {
setName("");
setPrice(0);
setImage(null);
setDescription("");
}
const handleSubmit = async (event) => {
event.preventDefault();
const product = {name, price, description};
const formData = new FormData();
formData.append('product', JSON.stringify(product));
if(image === null){
const imageDefault = new File([imagedefault], 'logo.png', { type: 'image/*' });
formData.append('image', imageDefault);
} else {
formData.append('image', image);
}
await axios.post("http://localhost:8080/product/addProduct", formData, {
headers: {
'Content-Type': 'multipart/form-data',
'Accept': 'application/json'
},
params: product,
body : image
}).then((response) => {
setInputStateNull();
if ( response.status === 200 ){
response.data={...response.data, quantity:0, total: 0}
setProductList([...productList, response.data]);
toast.current.show({ severity: 'success', summary: 'Inserimento effettuato', detail: "Inserimento eseguito con successo.", life: 3000 });
} else {
const error = 'Inserimento fallito errore: ' + response.status;
toast.current.show({ severity: 'error', summary: 'Inserimento fallito', detail: error, life: 3000 });
}
}).catch(() => {
setInputStateNull();
toast.current.show({ severity: 'error', summary: 'Inserimento fallito', detail: "Inserimento fallito errore generico.", life: 3000 });
});
}
return(
<>
<form className='flex flex-column justify-content-center' onSubmit={handleSubmit}>
<InputText value={name} onChange={(e) => setName(e.target.value)} placeholder="Nome" required />
<InputNumber value={price} min="0" onValueChange={(e) => setPrice(e.target.value)} showButtons buttonLayout="horizontal"
decrementButtonClassName="p-button-danger"
placeholder="Inserire prezzo prodotto"
incrementButtonClassName="p-button-success"
incrementButtonIcon="pi pi-plus"
decrementButtonIcon="pi pi-minus"
mode="currency"
currency="EUR"
step={0.25}
required
/>
<InputTextarea id="descrizioneProdotto" value={description} onChange={(e) => setDescription(e.target.value)} required placeholder="Descrizione" />
{
image !== null ?
<img src={image.objectURL} style={{alignSelf:"center"}} width="200" height="200" alt="Immagine"/>
:
<div style={{alignSelf:"center"}}>Inserire immagine</div>
}
<Button icon='pi pi-upload' style={{alignSelf:"center"}} className='p-button-rounded p-button-success' onClick={(event) => {event.preventDefault(); setVisibleInsertImage(true)}}/>
<button type="submit">Inserisci</button>
</form>
<Toast ref={toast} />
<Dialog className="w-6 h-30rem" header='Inserisci Immagine' draggable={false} visible={visibleInsertImage} onHide={()=> setVisibleInsertImage(false)}>
<InsertProductImageForm onHide={()=> setVisibleInsertImage(false)} setImage={(e)=> setImage(e)}/>
</Dialog>
</>
);
}
export default Form;
I wanna set a default image, in this case logo.png, if the user dosen't put an image when he insert a new product, it almost work but it goes like this: On the left i inserted a product with an image and it works very well, on the right i inserted a new product without selecting an image, i think it catched the default image but it dosen't render it
How can i solve it? (I'm using MongdoDB, instead of MySQL)
Sorry for my bad english.
Related
I am trying to login a page on button click and on "Enter" keydown event also, but the keydown portion of the code is not working. It return an error that the user is not found, which mean it's the catch error block that gets called. But on the button click portion, which is similar to the keydown portion code, everything works fine.
Here is the code.
import Axios from "axios";
import { useState, useRef, useEffect } from "react";
import { useNavigate } from "react-router-dom";
const LogIn = () => {
const milliseconds = 3600000;
localStorage.setItem("twoHours", JSON.stringify(milliseconds));
const userRef = useRef();
const navigate = useNavigate();
const [input, setInput] = useState("");
const [errorMessage, setErrorMessage] = useState("");
const [error, setError] = useState(false);
const [keyCode, setKeyCode] = useState("");
useEffect(() => {
userRef.current.focus();
}, []);
useEffect(() => {
document.body.addEventListener("keydown", keyDown);
}, []);
async function keyDown(event: KeyboardEvent) {
if (event.code === "Enter") {
try {
const data = await Axios.post("http://localhost:3500/examAuth", {
login: input,
});
setError(false);
setErrorMessage("");
navigate("/examSection", { state: { user: data.data } });
} catch (error: any) {
setError(true);
setErrorMessage(error.response.data.message);
console.log(error);
}
}
}
const handleSubmit = async () => {
try {
const data = await Axios.post("http://localhost:3500/examAuth", {
login: input,
});
setError(false);
navigate("/examSection", { state: { user: data.data } });
setErrorMessage("");
} catch (error: any) {
setError(true);
setErrorMessage(error.response.data.message);
console.log(error);
}
};
return (
<>
<div className="">
<div className="w-1/6 mx-auto mt-10">
<img src="images/editedConst.png" alt="" />
</div>
<div className="flex flex-col gap-2 w-3/4 mx-auto mt-10">
<label
className="text-yellow-700 text-xl w-2/4 mx-auto"
htmlFor="logIn"
>
Login
</label>
<input
ref={userRef}
className="input w-2/4 mx-auto"
autoComplete="off"
autoSave="off"
type="text"
value={input}
name="login"
placeholder="application number"
onChange={(e) => setInput(e.target.value.trim().toUpperCase())}
required
/>
{error && (
<p className="mt-1 mx-auto w-2/4 text-red-500">{errorMessage}</p>
)}
</div>
<div className="flex justify-center w-2/4 mx-auto mt-8">
<button
className="btn shadow shadow-yellow-800"
onClick={handleSubmit}
>
Log In
</button>
</div>
</div>
</>
);
};
export default LogIn;
I cant seem to find out what I am doing wrong.
There's only one answer: wrap your inputs in <form>. Then you can listen to it's event on submission and prevent default and / or place your logic. This approach has innumerable advantages (Password managers support and accessibility) to name two most obvious. Don't try to reinvent the wheel.
I have created a state using react hook useState() at line 28 which is const [input, setInput] = useState('');. Then I updated the state by calling the setInput() at line 45 in the createTodo function at line 32. But when the function is executing, the state is not updating. There is no error on the console. I also added a console.log() after the state updating statement and the console.log() also executing but state is not updating.
My codes are given below.
App.jsx
import React, { useEffect, useState } from 'react';
import { AiOutlinePlus } from 'react-icons/ai';
import ToDo from './ToDo';
import { db } from './firebase';
import {
addDoc,
collection,
deleteDoc,
doc,
onSnapshot,
query,
updateDoc,
} from 'firebase/firestore';
const style = {
bg: `h-screen w-screen p-4 bg-gradient-to-r from-[#2F80ED] to-[#1CB5E0]`,
container: `bg-slate-100 max-w-[500px] w-full m-auto rounded-md shadow-xl p-4`,
heading: `text-3xl font-bold text-center text-gray-800 p-2`,
form: `flex justify-between`,
input: `border p-2 w-full text-xl`,
button: `border p-4 ml-2 bg-purple-500 text-slate-100`,
count: `text-center p-2`,
};
const App = () => {
const [todos, setTodos] = useState([]);
const [input, setInput] = useState(''); // this is the state
// ************ firebase operations ************
// create
const createTodo = async event => {
event.preventDefault();
if (input === '') {
alert('Please add some text');
return;
}
// crating data to firebase
await addDoc(collection(db, 'todos'), {
text: input,
completed: false,
});
setInput(''); // here state is not updating
};
// read
useEffect(() => {
const q = query(collection(db, 'todos'));
const unsubscribe = onSnapshot(q, querySnapshot => {
let todosArr = [];
querySnapshot.forEach(doc => {
todosArr.push({ ...doc.data(), id: doc.id });
});
setTodos(todosArr);
});
return () => unsubscribe();
}, []);
// update
const toggleComplete = async todo => {
await updateDoc(doc(db, 'todos', todo.id), {
completed: !todo.completed,
});
};
// delete
const todoDelete = async id => {
await deleteDoc(doc(db, 'todos', id));
};
return (
<div className={style.bg}>
<div className={style.container}>
<h2 className={style.heading}>ToDo CRUD with Firebase</h2>
<form onSubmit={createTodo} className={style.form}>
<input
type="text"
className={style.input}
placeholder="ToDo"
onChange={event => setInput(event.target.value)}
/>
<button className={style.button}>
<AiOutlinePlus size={30} />
</button>
</form>
<ul>
{todos.map((todo, index) => (
<ToDo
key={index}
todo={todo}
toggleComplete={toggleComplete}
todoDelete={todoDelete}
/>
))}
</ul>
{todos.length === 0 ? null : (
<p className={style.count}>{`You have ${todos.length} todos`}</p>
)}
</div>
</div>
);
};
export default App;
Please have a look. How can I solve this problem?
You are missing value={input} in your input element
<input
type="text"
className={style.input}
placeholder="ToDo"
value={input} <-- this
onChange={event => setInput(event.target.value)}
/>
<input
type="text"
className={style.input}
placeholder="ToDo"
**value={input}**
onChange={event => setInput(event.target.value)}
/>
https://reactjs.org/docs/forms.html#:~:text=An%20input%20form%20element%20whose,called%20a%20%E2%80%9Ccontrolled%20component%E2%80%9D.&text=Since%20the%20value%20attribute%20is,state%20the%20source%20of%20truth.
I have created a page named Product Detail. On this page, there is a delivered button, I want this button to reduce the quantity of the product by 1 whenever it will be clicked. However, it's working but after clicking the button there is an error coming. I have attached the error screenshot for your convenience. I have tried several times to solve the error but I couldn't find any solution. Is there anyone to help me out with that error, please?
Thanks in advance.
Error screenshots:
https://i.ibb.co/CwmG0d5/image.jpg
1. Product detail code
import React from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import useProductDetail from '../../hooks/useProductDetail';
import './ProductDetail.css';
const ProductDetail = () => {
const { productId } = useParams();
const [product, setProduct] = useProductDetail(productId);
const { quantity } = product;
const navigate = useNavigate();
const navigateToManageInventory = () => {
navigate("/manage");
};
// event handler for delivered button
const handleQuantity = () => {
let newQuantity = quantity - 1;
const newProduct = { ...product, quantity: newQuantity };
setProduct(newProduct);
const url = `http://localhost:5000/product/${productId}`;
console.log(url);
fetch(url, {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(newProduct),
});
};
return (
<div className="container">
<h3 className="text-center my-4">Product Details</h3>
<div className="product-container mx-auto rounded-3 shadow">
<div className="text-center my-3">
<img width={250} src={product.picture} alt="" />
</div>
<div className="product-info px-4">
<h6 className="text-muted">Product Id: {productId}</h6>
<h3>{product.name}</h3>
<p>
<b>Price:</b> ${product.price}
</p>
<p>
<b>Quantity:</b> {product.quantity}{" "}
<small className="text-muted">pcs</small>
</p>
<p>
<b>Supplier:</b> {product.supplier}
</p>
<p>{product.description}</p>
</div>
<div className="d-flex justify-content-center">
<button
onClick={() => handleQuantity(productId)}
className="w-50 btn btn-primary mt-3"
>
Delivered
</button>
</div>
</div>
<div className="text-center">
<button
onClick={navigateToManageInventory}
className="my-5 btn btn-primary"
>
Manage Inventories
</button>
</div>
</div>
);
};
export default ProductDetail;
2. Product detail (custom hook)
import { useEffect, useState } from 'react';
const useProductDetail = (productId) => {
const [product, setProduct] = useState({});
useEffect(() => {
const url = `http://localhost:5000/product/${productId}`;
fetch(url)
.then(res => res.json())
.then(data => setProduct(data));
}, [productId]);
return [product, setProduct];
};
export default useProductDetail;
3. Server-side code
app.put('/product/:id', async (req, res) => {
const id = req.params.id;
const quantity = req.body;
const options = { upsert: true };
const updateDor = {
_id: id,
name: product.name,
price: product.price,
description: product.description,
quantity: quantity.quantity,
supplier: product.supplier,
picture: product.picture
};
const result = await productCollection.updateOne(query, updateDor, options);
res.send(result);
});
When I try to register a new user all data are passed except "avatar", even if that avatar is regularly uploaded on my Cloudinary.
Don't even know what is the problem in and tried to find answer on google but unsuccessfully, so any help is very welcome :D
Here is some code, if need more tell me in a comment and I'll send you
Cannot finish my site, don't know what to do...
// frontend Register component
import React, { Fragment, useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import MetaData from '../layout/MetaData';
import { useAlert } from 'react-alert';
import { useDispatch, useSelector } from 'react-redux';
import { register, clearErrors } from '../../actions/userActions';
const Register = () => {
const navigate = useNavigate();
const [user, setUser] = useState({
name: '',
email: '',
password: '',
});
const { name, email, password } = user;
const [avatar, setAvatar] = useState('');
const [avatarPreview, setAvatarPreview] = useState(
'/images/default_avatar.jpg'
);
const alert = useAlert();
const dispatch = useDispatch();
const { isAuthenticated, error, loading } = useSelector(
(state) => state.auth
);
useEffect(() => {
if (isAuthenticated) {
navigate('/');
}
if (error) {
alert.error(error);
dispatch(clearErrors());
}
}, [dispatch, alert, isAuthenticated, error, navigate]);
const submitHandler = (e) => {
e.preventDefault();
const formData = new FormData();
formData.set('name', name);
formData.set('email', email);
formData.set('password', password);
formData.set('avatar', avatar);
dispatch(register(formData));
};
const onChange = (e) => {
if (e.target.name === 'avatar') {
const reader = new FileReader();
reader.onload = () => {
if (reader.readyState === 2) {
setAvatarPreview(reader.result);
setAvatar(reader.result);
}
};
reader.readAsDataURL(e.target.files[0]);
} else {
setUser({ ...user, [e.target.name]: e.target.value });
}
};
return (
<Fragment>
<MetaData title={'Register User'} />
<div className='row wrapper'>
<div className='col-10 col-lg-5'>
<form
className='shadow-lg'
onSubmit={submitHandler}
encType='multipart/form-data'
>
<h1 className='mb-3'>Register</h1>
<div className='form-group'>
<label htmlFor='email_field'>Name</label>
<input
type='name'
id='name_field'
className='form-control'
name='name'
value={name}
onChange={onChange}
/>
</div>
<div className='form-group'>
<label htmlFor='email_field'>Email</label>
<input
type='email'
id='email_field'
className='form-control'
name='email'
value={email}
onChange={onChange}
/>
</div>
<div className='form-group'>
<label htmlFor='password_field'>Password</label>
<input
type='password'
id='password_field'
className='form-control'
name='password'
value={password}
onChange={onChange}
/>
</div>
<div className='form-group'>
<label htmlFor='avatar_upload'>Avatar</label>
<div className='d-flex align-items-center'>
<div>
<figure className='avatar mr-3 item-rtl'>
<img
src={avatarPreview}
className='rounded-circle'
alt='Avatar Preview'
/>
</figure>
</div>
<div className='custom-file'>
<input
type='file'
name='avatar'
className='custom-file-input'
id='customFile'
accept='iamges/*'
onChange={onChange}
/>
<label className='custom-file-label' htmlFor='customFile'>
Choose Avatar
</label>
</div>
</div>
</div>
<button
id='register_button'
type='submit'
className='btn btn-block py-3'
disabled={loading ? true : false}
>
REGISTER
</button>
</form>
</div>
</div>
</Fragment>
);
};
export default Register;
// backend Register a user => /api/v1/register
exports.registerUser = catchAsyncErrors(async (req, res, next) => {
const result = await cloudinary.v2.uploader.upload(req.body.avatar, {
folder: 'avatars',
width: 150,
crop: 'scale',
});
const { name, email, password } = req.body;
const user = await User.create({
name,
email,
password,
avatar: {
public_id: result.public_id,
url: result.secure_url,
},
});
sendToken(user, 200, res);
});
This block of code:
const data = {
user_id: userID,
comment: comment
};
const url = `http://localhost:5000/blog/comments${category}/${slug}`;
const headers = { "Access-Control-Allow-Origin": "*" };
axios.post(url, data, headers).then(resp => {
console.log(resp.data.message);
});
}
is giving me this error:
Unhandled Rejection (TypeError): cyclic object value
from what I've gathered so far "cyclic object value" refers to javascript objects that at some point refer to itself hence throws an error. From the code above it's not very obvious how I accomplished such error.
I would appreciated any pointers here.
Attempt to provide a minimal example:
Post.jsx:
import React, { useState, useEffect } from "react";
import { useGlobalContext } from "../context";
import { Link } from "react-router-dom";
import AddComment from "./AddComment";
import axios from "axios";
const Post = props => {
const { userID, trace, setTrace, isAuthenticated } = useGlobalContext();
const [obj, setObj] = useState([]);
const [comments, setComments] = useState([]);
const [comment, setComment] = useState("");
const [showLoginWarning, setShowLoginWarning] = useState(false);
const { firstColumn, secondColumn, slug, category } = props;
const handleComment = e => {
e.preventDefault();
if (!isAuthenticated) {
setShowLoginWarning(true);
} else {
const data = {
user_id: userID,
comment: comment
};
const url = `http://localhost:5000/blog/comments${category}/${slug}`;
const headers = { "Access-Control-Allow-Origin": "*" };
axios
.post(url, data, headers)
.then(resp => {
console.log(resp.data.message);
})
.catch(err => {
console.log(err);
});
}
};
useEffect(() => {
setTrace(category + `/${slug}`);
//console.log(trace);
let obj = firstColumn.filter(post => post.slug === slug);
if (obj.length === 0) {
obj = secondColumn.filter(post => post.slug === slug);
}
setObj(obj);
const headers = { "Access-Control-Allow-Origin": "*" };
const url = `http://localhost:5000/blog/comments${trace}/${slug}`;
axios
.get(url)
.then(resp => {
setComments(resp.data.message);
console.log(resp.data.message);
})
.catch(err => {
console.log(err);
});
}, []);
useEffect(() => {
const timeout = setTimeout(() => {
setShowLoginWarning(false);
}, 7000);
}, [showLoginWarning]);
const img_file = `http://localhost:5000/blog/fetch_image/post/${slug}`;
return (
<div style={{ marginTop: "40px" }} className="container">
<div className="columns">
<div className="column is-four-fifths">
<div className="content">
{obj.map(prop => (
<div key={prop.id}>
<h4 className="title is-4">
<img src={img_file} alt={prop.title} />
<br />
{prop.title}
<small>{prop.timestamp}</small>
</h4>
<br />
<p>{prop.post}</p>
</div>
))}
</div>
</div>
<div className="column">
<br />
<Link to={category} className="button is-link" id="backbtn">
Back
</Link>
</div>
</div>
<section className="section">
<h1 className="title">Section</h1>
<h2 className="subtitle">
A simple container to divide your page into <strong>sections</strong>,
like the one you're currently reading.
</h2>
<AddComment
onComment={handleComment}
showLoginWarning={showLoginWarning}
onChange={setComment}
/>
</section>
</div>
);
};
export default Post;
AddComment.jsx:
import React from "react";
const AddComment = props => {
const { showLoginWarning, onComment, onChange } = props;
return (
<>
{showLoginWarning && (
<div className="notification is-warning">
<strong>You need to be logged in to comment.</strong>
</div>
)}
<section id="textareaSection" className="section">
<form onSubmit={onComment}>
<div className="field">
<div className="control">
<textarea
className="textarea"
cols="2"
rows="2"
placeholder="What's On Your Mind ?"
onChange={onChange}
/>
<button
type="submit"
style={{ float: "right", marginTop: "1em" }}
className="button is-link"
>
Post
</button>
</div>
</div>
</form>
</section>
</>
);
};
export default AddComment;
index.js:
import React from "react";
import ReactDOM from "react-dom";
import "./assets/bulma/css/bulma.css";
import "./assets/stylesheet.css";
import Post from "./Post";
import reportWebVitals from "./reportWebVitals";
import { AppProvider } from "./context";
ReactDOM.render(
<React.StrictMode>
<AppProvider>
<Post />
</AppProvider>
</React.StrictMode>,
document.getElementById("root")
);
reportWebVitals();