Unable to set up razorpay payment gateway - javascript
I have built a checkout page where on clicking the pay button a payment page should render. But due to some issue I can't find why?
The checkout page:
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
import Link from 'next/link'
import React, { useState, useEffect } from 'react'
import Head from 'next/head'
import Script from 'next/script'
import { AiFillMinusCircle, AiFillPlusCircle } from 'react-icons/ai'
import { BsFillBagCheckFill } from 'react-icons/bs'
import { ToastContainer, toast } from 'react-toastify'
import 'react-toastify/dist/ReactToastify.css';
const Checkout = ({ cart, clearCart, subTotal, addToCart, removeFromCart }) => {
const [name, setName] = useState('')
const [email, setEmail] = useState('')
const [address, setAddress] = useState('')
const [phone, setPhone] = useState('')
const [pincode, setPincode] = useState('')
const [city, setCity] = useState('')
const [state, setState] = useState('')
const [disabled, setDisabled] = useState(true)
const [user, setUser] = useState({ value: null })
useEffect(() => {
const myuser = JSON.parse(localStorage.getItem('myuser'));
if (myuser && myuser.token) {
setUser(myuser)
setEmail(myuser.email)
fetchData(myuser.token)
}
}, [])
useEffect(() => {
if (name.length > 3 && email.length > 3 && address.length > 3 && phone.length > 3 && pincode.length > 3) {
setDisabled(false)
}
else {
setDisabled(true)
}
}, [name, email, address, phone, pincode])
const fetchData = async (token) => {
let data = { token: token }
let a = await fetch(`${process.env.NEXT_PUBLIC_HOST}/api/getuser`, {
method: 'POST', // or 'PUT'
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
})
let res = await a.json()
setName(res.name)
setAddress(res.address)
setPincode(res.pincode)
setPhone(res.phone)
getPinCode(res.pincode)
}
const getPinCode = async (pincode) => {
let url = 'https://api.postalpincode.in/pincode/' + pincode
let pins = await fetch(url, {
Method: 'GET'
})
let pinJson = await pins.json()
if (pinJson[0].Status == 'Success') {
setState(pinJson[0].PostOffice[0].State)
setCity(pinJson[0].PostOffice[0].District)
}
else {
setState('')
setCity('')
}
}
const handleChange = async (e) => {
if (e.target.name == 'name') {
setName(e.target.value)
}
else if (e.target.name == 'email') {
setEmail(e.target.value)
}
else if (e.target.name == 'address') {
setAddress(e.target.value)
}
else if (e.target.name == 'phone') {
setPhone(e.target.value)
}
else if (e.target.name == 'pincode') {
setPincode(e.target.value)
if (e.target.value.length == 6) {
getPinCode(e.target.value)
}
}
}
const initializeRazorpay = () => {
return new Promise((resolve) => {
const script = document.createElement("script");
script.src = "https://checkout.razorpay.com/v1/checkout.js";
console.log("intialzeRazorpay")
script.onload = () => {
resolve(true);
};
script.onerror = () => {
resolve(false);
};
document.body.appendChild(script);
});
};
const makePayment = async () => {
const res = await initializeRazorpay();
let oid = Math.floor(Math.random() * Date.now());
if (!res) {
alert("Your are offline.... Razorpay SDK Failed to load");
return;
}
const pdata = { cart, subTotal: subTotal, oid, email: email, name, address, pincode, phone, state, city };
let data = await fetch(`${process.env.NEXT_PUBLIC_HOST}/api/pretransaction`, {
method: 'POST', // or 'PUT'
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(pdata),
})
if (!data.success) {
toast.error(data.err, {
position: "top-center",
autoClose: 3000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined,
});
}
else {
var options = {
key: process.env.RAZORPAY_KEY, // Enter the Key ID generated from the Dashboard
name: "Pixelwear",
currency: "INR",
amount: data.amount,
order_id: data.id,
description: "Thank You for your test donation",
image: "/logo.png",
handler: function (response) {
// Validate payment at server - using webhooks is a better idea
alert(response.razorpay_payment_id)
alert(response.razorpay_order_id);
alert(response.razorpay_signature);
},
prefill: {
name: name,
email: email,
contact: phone,
},
};
const paymentObject = new window.Razorpay(options);
paymentObject.open();
}
};
return (
<>
<div className='container px-2 sm:m-auto'>
<ToastContainer
position="top-center"
autoClose={5000}
hideProgressBar={false}
newestOnTop={false}
closeOnClick
rtl={false}
pauseOnFocusLoss
draggable
pauseOnHover
/>
<Head><meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, maximum-scale=1.0" /></Head>
<h1 className='font-bold text-3xl my-8 text-center'>Checkout</h1>
<h2 className='font-semibold text-xl'>1. Delivery Details</h2>
<div className="mx-auto flex my-2">
<div className="px-2 w-1/2">
<div className="mb-4">
<label htmlFor="name" className="leading-7 text-sm text-gray-600">Name</label>
<input value={name} onChange={handleChange} type="text" id="name" name="name" className="w-full bg-white rounded border border-gray-300 focus:border-indigo-500 focus:ring-2 focus:ring-indigo-200 text-base outline-none text-gray-700 py-1 px-3 leading-8 transition-colors duration-200 ease-in-out" />
</div>
</div>
<div className="px-2 w-1/2">
<div className="mb-4">
<label htmlFor="email" className="leading-7 text-sm text-gray-600">Email</label>
{user && user.token ? <input value={user.email} type="email" id="email" name="email" className="w-full bg-white rounded border border-gray-300 focus:border-indigo-500 focus:ring-2 focus:ring-indigo-200 text-base outline-none text-gray-700 py-1 px-3 leading-8 transition-colors duration-200 ease-in-out" readOnly /> : <input value={email} onChange={handleChange} type="email" id="email" name="email" className="w-full bg-white rounded border border-gray-300 focus:border-indigo-500 focus:ring-2 focus:ring-indigo-200 text-base outline-none text-gray-700 py-1 px-3 leading-8 transition-colors duration-200 ease-in-out" />}
</div>
</div>
</div>
<div className="px-2 w-full">
<div className="mb-4">
<label htmlFor="address" className="leading-7 text-sm text-gray-600">Address</label>
<textarea onChange={handleChange} value={address} name="address" id="address" cols="30" rows="2" className="w-full bg-white rounded border border-gray-300 focus:border-indigo-500 focus:ring-2 focus:ring-indigo-200 text-base outline-none text-gray-700 py-1 px-3 leading-8 transition-colors duration-200 ease-in-out"></textarea>
</div>
</div>
<div className="mx-auto flex my-2">
<div className="px-2 w-1/2">
<div className="mb-4">
<label htmlFor="phone" className="leading-7 text-sm text-gray-600">Phone</label>
<input value={phone} onChange={handleChange} placeholder="Your 10 digit phone number" type="phone" id="phone" name="phone" className="w-full bg-white rounded border border-gray-300 focus:border-indigo-500 focus:ring-2 focus:ring-indigo-200 text-base outline-none text-gray-700 py-1 px-3 leading-8 transition-colors duration-200 ease-in-out" />
</div>
</div>
<div className="px-2 w-1/2">
<div className="mb-4">
<label htmlFor="pincode" className="leading-7 text-sm text-gray-600">Pincode</label>
<input value={pincode} onChange={handleChange} type="text" id="pincode" name="pincode" className="w-full bg-white rounded border border-gray-300 focus:border-indigo-500 focus:ring-2 focus:ring-indigo-200 text-base outline-none text-gray-700 py-1 px-3 leading-8 transition-colors duration-200 ease-in-out" />
</div>
</div>
</div>
<div className="mx-auto flex my-2">
<div className="px-2 w-1/2">
<div className="mb-4">
<label htmlFor="state" className="leading-7 text-sm text-gray-600">State</label>
<input onChange={handleChange} value={state} type="text" id="state" name="state" className="w-full bg-white rounded border border-gray-300 focus:border-indigo-500 focus:ring-2 focus:ring-indigo-200 text-base outline-none text-gray-700 py-1 px-3 leading-8 transition-colors duration-200 ease-in-out" />
</div>
</div>
<div className="px-2 w-1/2">
<div className="mb-4">
<label htmlFor="city" className="leading-7 text-sm text-gray-600">District</label>
<input onChange={handleChange} value={city} type="text" id="city" name="city" className="w-full bg-white rounded border border-gray-300 focus:border-indigo-500 focus:ring-2 focus:ring-indigo-200 text-base outline-none text-gray-700 py-1 px-3 leading-8 transition-colors duration-200 ease-in-out" />
</div>
</div>
</div>
<h2 className='font-semibold text-xl'>2. Review Cart Items & Pay</h2>
<div className="sideCart bg-blue-100 p-6 m-2">
<ol className='list-decimal font-semibold'>
{Object.keys(cart).length == 0 && <div className='my-4 font-semibold'>Your cart is Empty!</div>}
{Object.keys(cart).map((k) => {
return <li key={k}>
<div className="item flex my-5">
<div className='font-semibold'>{cart[k].name} ({cart[k].size}/{cart[k].variant})</div>
<div className='flex items-center justify-center w-1/3 font-semibold text-lg'>
<AiFillMinusCircle onClick={() => { removeFromCart(k, 1, cart[k].price, cart[k].name, cart[k].size, cart[k].variant, cart[k].category, cart[k].img) }} className='cursor-pointer text-blue-500' /><span className='mx-2 text-sm' >{cart[k].qty}</span>
<AiFillPlusCircle onClick={() => { addToCart(k, 1, cart[k].price, cart[k].name, cart[k].size, cart[k].variant, cart[k].category, cart[k].img) }} className='cursor-pointer text-blue-500' /></div>
</div>
</li>
})}
</ol>
<span className="font-bold">Subtotal: ₹{subTotal}</span>
</div>
<div className="mx-4">
<Link href={'/checkout'} ><button disabled={disabled} onClick={makePayment} className="disabled:bg-indigo-300 flex mr-2 text-white bg-indigo-500 border-0 py-2 px-2 focus:outline-none hover:bg-indigo-600 rounded text-sm"><BsFillBagCheckFill className='m-1' />Pay ₹{subTotal}</button></Link>
</div>
</div>
</>
)
}
export default Checkout
pretransaction page:
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
import Order from "../../models/Order"
import Product from "../../models/Product"
import connectDb from "../../middleware/mongoose"
require('dotenv').config()
const Razorpay = require("razorpay");
const shortid = require("shortid");
const handler = async (req, res) => {
if (req.method == 'POST') {
//Check if the pincode is serviceable
let url = 'https://api.postalpincode.in/pincode/' + req.body.pincode
let pins = await fetch(url, {
Method: 'GET'
})
let pinJson = await pins.json()
if (pinJson[0].Status != 'Success') {
res.status(200).json({ success: false, "error": "The pincode you have entered is not serviceable.", cartClear: false })
return
}
//Check if the cart is tampered
let product, sumTotal = 0;
let cart = req.body.cart;
if (req.body.subTotal <= 0) {
res.status(200).json({ success: false, "error": "Your Cart is empty. Please build your cart and try again!", cartClear: false })
return
}
for (let item in cart) {
product = await Product.findOne({ slug: item })
sumTotal += cart[item].price * cart[item].qty
//Check if the cart items are out of stock
if (product.availableQty < cart[item].qty) {
res.status(200).json({ success: false, "error": "Some items in your cart are out of stock.", cartClear: true })
return
}
if (product.price != cart[item].price) {
res.status(200).json({ success: false, "error": "price of some items in cart have changed", cartClear: true })
return
}
}
if (sumTotal != req.body.subTotal) {
res.status(200).json({ success: false, "error": "price of some items in cart have changed", cartClear: true })
return
}
//Check if the details are valid
if (req.body.phone.length !== 10 || !Number.isInteger(Number(req.body.phone))) {
res.status(200).json({ success: false, "error": "Please enter your 10 digit phone number", cartClear: false })
return
}
if (req.body.pincode.length !== 6 || !Number.isInteger(Number(req.body.pincode))) {
res.status(200).json({ success: false, "error": "Please enter your 6 digit pincode", cartClear: false })
return
}
const razorpay = new Razorpay({
key_id: process.env.RAZORPAY_KEY,
key_secret: process.env.RAZORPAY_SECRET,
});
const payment_capture = 1;
const amount = req.body.subTotal;
const currency = "INR";
const options = {
amount: (amount * 100).toString(),
currency,
receipt: shortid.generate(),
payment_capture,
};
try {
const response = await razorpay.orders.create(options);
// Initiate an order corresponding to the order id
let order = new Order({
email: req.body.email,
name: req.body.name,
phone: req.body.phone,
orderId: response.id,
address: req.body.address,
district: req.body.city,
state: req.body.state,
pincode: req.body.pincode,
amount: req.body.subTotal,
products: req.body.cart,
})
await order.save()
res.status(200).json({
success: true,
id: response.id,
currency: response.currency,
amount: response.amount,
});
return
} catch (err) {
console.log(err);
res.status(400).json({ success: false , err: err});
return
}
}
}
export default connectDb(handler);
Everything is working fine, but when I click on the pay button the razorpay page is not rendering.
And in the console it is showing one error, Invalid HMR message: {"event":"serverOnlyChanges","pages":["/api/pretransaction"]}.
Console Image
How to fix this error?
Related
Submitting form in react modal not working - no event triggered
I leverage the npm package react-modal (https://www.npmjs.com/package/react-modal). I want to submit a form that resides within the modal. For some reason when clicking on 'Abschicken', nothing happens. The handleSubmitfunction is never triggered as I do not see any console logs. What do I miss here? import { useState, useRef } from "react"; import Modal from "react-modal"; import LogoHori from "../../../public/images/logo_hori.png"; import Image from "next/image"; const customStyles = { content: { top: "50%", left: "50%", right: "auto", bottom: "auto", marginRight: "-50%", transform: "translate(-50%, -50%)", position: "absolute", }, overlay: { zIndex: 1000 }, }; Modal.setAppElement("#__next"); // Make sure to bind modal to your appElement (https://reactcommunity.org/react-modal/accessibility/) const ContactModal = ({ buttonStyles }) => { const [modalIsOpen, setIsOpen] = useState(false); const [isValidEmail, setIsValidEmail] = useState(true); const [successfulSubmission, setSuccessfulSubmission] = useState(""); const lastNameInputElement = useRef(); const firstNameInputElement = useRef(); const emailInputElement = useRef(); const messageInputElement = useRef(); const validate = (email) => { const expression = /(?!.*\.{2})^([a-z\d!#$%&'*+\-\/=?^_`{|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+(\.[a-z\d!#$%&'*+\-\/=?^_`{|}~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+)*|"((([\t]*\r\n)?[\t]+)?([\x01-\x08\x0b\x0c\x0e-\x1f\x7f\x21\x23-\x5b\x5d-\x7e\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|\\[\x01-\x09\x0b\x0c\x0d-\x7f\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))*(([\t]*\r\n)?[\t]+)?")#(([a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|[a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF][a-z\d\-._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]*[a-z\d\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])\.)+([a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]|[a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF][a-z\d\-._~\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]*[a-z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])\.?$/i; return expression.test(String(email).toLowerCase()); }; function openModal() { setIsOpen(true); } function afterOpenModal() { // references are now sync'd and can be accessed. } function closeModal() { setIsOpen(false); } const handleSubmit = async (event) => { console.log("clicked"); event.preventDefault(); const data = { lastName: lastNameInputElement.current?.value, firstName: firstNameInputElement.current?.value, email: emailInputElement.current?.value, message: messageInputElement.current?.value, }; if (!validate(data.email)) { setIsValidEmail(false); return; } setIsValidEmail(true); console.log(data); const requestOptions = { method: "POST", headers: { "Content-Type": "application/json", Accept: "application/json", }, body: JSON.stringify(data), }; try { const result = await fetch( "https://someEndpoint", requestOptions ); if (result.status == 200) { setSuccessfulSubmission(true); setTimeout(closeModal, 5000); } else { throw new Error(); } } catch { console.log(error); setSuccessfulSubmission(false); } }; return ( <div> <button className={buttonStyles} onClick={openModal}> Anfrage </button> <Modal isOpen={modalIsOpen} onAfterOpen={afterOpenModal} onRequestClose={closeModal} style={customStyles} contentLabel="Nido Surf" > <div className="w-[300px] md:w-[600px]"> <Image src={LogoHori} alt="nido-surf-logo" width={300} /> <form action="Post" onSubmit={handleSubmit} className="mt-5 flex flex-col justify-between"> <label htmlFor="name" className="font-bold mb-2"> Nachname </label> <input ref={lastNameInputElement} className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 focus:outline-none focus:shadow-outline" id="name" type="text" placeholder="Nachname" /> <label htmlFor="firstname" className="font-bold my-2"> Vorname </label> <input ref={firstNameInputElement} className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 focus:outline-none focus:shadow-outline" id="firstname" type="text" placeholder="Vorname" /> <label htmlFor="email" className="font-bold my-2"> Email-Adresse </label> <input ref={emailInputElement} className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 focus:outline-none focus:shadow-outline" id="email" type="text" placeholder="Email-Adresse" /> {!isValidEmail && ( <p className="text-secondary-red-200"> Deine Email-Adresse ist ungültig! </p> )} <label htmlFor="message" className="font-bold my-2"> Nachricht </label> <textarea ref={messageInputElement} className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 focus:outline-none focus:shadow-outline" name="message" id="message" cols="30" rows="10" ></textarea> </form> <div className="mt-5 flex gap-x-4 justify-center items-center"> <button type="submit" className="w-full text-white rounded-md py-4 hover:bg-secondary-green-300 bg-secondary-green-400" > Senden </button> <button className="w-full text-white rounded-md py-4 hover:bg-secondary-red-100 bg-secondary-red-300" onClick={closeModal} > Abbrechen </button> </div> </div> </Modal> </div> ); }; export default ContactModal;
It's not triggering the submit event because your button is not inside the form. Move the below div above the closing tag of form. Also, notice this type="button" on the second button: <div className="mt-5 flex gap-x-4 justify-center items-center"> <button type="submit" className="w-full text-white rounded-md py-4 hover:bg-secondary-green-300 bg-secondary-green-400" > Senden </button> <button className="w-full text-white rounded-md py-4 hover:bg-secondary-red-100 bg-secondary-red-300" onClick={closeModal} type="button" > Abbrechen </button> </div>
fetched data from firestore as initial value of useState it gives me udefined value
I want to set the fetched data from firestore as initial value of useState but it gives me undefined value because I want to update user profile and I don't know the user edits or updates which property because I want to keep the other properties of the user the same, only change the edited one. I've tried this code, but it gives me this error: Uncaught (in promise) FirebaseError: Function updateDoc() called with invalid data. Unsupported field value: undefined (found in field surname in document users/DQjpLaKYVgVuH9TeqNomIEyuMJB2) import React, { useState, useEffect } from 'react'; import { useAuthState } from 'react-firebase-hooks/auth'; import { doc, onSnapshot, updateDoc } from "firebase/firestore"; import { auth, db } from '../../firebase'; export default function Form({ setEditForm }) { const [user, setUser] = useState([]); const [currentUser] = useAuthState(auth); // fetching user information from firestore useEffect(() => { const getUser = async () => { const docRef = await doc(db, 'users', currentUser.uid) try { await onSnapshot(docRef, (doc) => { setUser({ ...doc.data(), id: doc.id }) }) } catch (e) { console.log(e) } } getUser() }, []) const [name, setName] = useState(user.firstName); const [surname, setSurname] = useState(user.surname); const [biography, setBiography] = useState(user.biography); const [location, setLocation] = useState(user.location); // updating user's profile const updateProfile = async (e) => { e.preventDefault(); const docRef = doc(db, 'users', currentUser.uid); await updateDoc(docRef, { firstName: name, surname: surname, biography: biography, location: location }) } console.log(user) return ( <form onSubmit={updateProfile} className="flex flex-col w-4/6 lg:w-3/6" > <div className="lg:flex lg:flex-row lg:justify-between lg:gap-6"> <div className="lg:flex lg:flex-col lg:w-1/2"> <h2 className="text-left text-[#4699C2] font-bold py-2">Name: </h2> <div className="border border-gray-300 rounded-md"> <input type="text" placeholder={name} value={name} onChange={(e) => setName(e.target.value)} className="w-full py-2 px-4 opacity-50 focus:opacity-100" /> </div> </div> <div className="lg:flex lg:flex-col lg:w-1/2"> <h2 className="text-left text-[#4699C2] font-bold py-2">Surname: </h2> <div className="border border-gray-300 rounded-md"> <input type="text" placeholder={surname} value={surname} onChange={(e) => setSurname(e.target.value)} className="opacity-50 px-4 focus:opacity-100 w-full py-2" /> </div> </div> </div> <h2 className="text-left text-[#4699C2] font-bold py-2">Biograhpy: </h2> <div className="border border-gray-300 rounded-md"> <textarea onChange={(e) => setBiography(e.target.value)} className="opacity-50 px-4 focus:opacity-100 w-full py-4" > {biography} </textarea> </div> <h2 className="text-left text-[#4699C2] font-bold py-2">Location: </h2> <div className="border border-gray-300 rounded-md"> <input placeholder={location} value={location} onChange={(e) => setLocation(e.target.value)} className="opacity-50 px-4 focus:opacity-100 w-full py-2" /> </div> <div className="flex flex-row justify-center py-4"> <input type="submit" value="SAVE" className="bg-[#4699C2] text-white fong-bold w-24 py-3 rounded-full mx-4 font-bold hover:bg-[#026FC2] hover:shadow-lg focus:bg-[#026FC2] focus:shadow-lg focus:outline-none focus:ring-0 active:bg-[#026FC2] active:shadow-lg transition duration-150 ease-in-out" /> <input onClick={() => { setEditForm(false); }} type="reset" value="CANCEL" className="bg-[#4699C2] cursor-pointer lg:bg-white hover:bg-[#026FC2] hover:text-white hover:shadow-lg focus:bg-[#026FC2] focus:shadow-lg focus:outline-none focus:ring-0 focus:text-white active:bg-[#026FC2] active:shadow-lg transition duration-150 ease-in-out text-white lg:text-[#4699C2] lg:border lg:border-[#4699C2] fong-bold w-24 py-3 rounded-full font-bold" /> </div> </form> ); }
Answering this as community wiki, As suggested by #yograjtandel, instead of storing the response in one single state, first declare all the states like name, biography, surname, etc... to null. then in useState set all the states ex. setName(doc.data().Name).
How to return multiple function in react in JSX format
I'm trying to return a few functions in react but I'm unable to perform as I wanted. return ( loadingMessage(), errorMessage(), loginForm(), performRedirect() ) } I want to return my functions as above but when try this my app directly calls the last function performRedirect(). I don't know whether am I running this correctly or not. please find the whole code below. import React, { useState } from "react"; import { Link, Navigate } from "react-router-dom"; import {signin, authenticate, isAutheticated} from "../auth/helper/index" const Login = () => { const [values, setValues] = useState({ username: "", password: "", error: "", loading: false, didRedirect: false, }); const {username, password, error, loading, didRedirect} = values; const {user} = isAutheticated(); const handleChange = name => event => { setValues({ ...values, error: false, [name]: event.target.value }); }; const onSubmit = event => { event.preventDefault(); setValues({ ...values, error: false, loading: true }); signin({ username, password }) .then(data => { if (data.error) { setValues({ ...values, error: data.error, loading: false }); } else { authenticate(data, () => { setValues({ ...values, didRedirect: true }); }); } }) .catch(console.log("signin request failed", error, user)); }; const performRedirect = () => { //TODO: do a redirect here if (didRedirect) { if (user && user.role === 1) { return <p>redirect to admin</p>; } else { return <p>redirect to user dashboard</p>; } } if (isAutheticated()) { return <Navigate to="/" />; } }; const loadingMessage = () => { return ( loading && ( <div className="alert alert-info"> <h2>Loading...</h2> </div> ) ); }; const errorMessage = () => { return ( <div className="row"> <div className="col-md-6 offset-sm-3 text-left"> <div className="alert alert-danger" style={{ display: error ? "" : "none" }} > {error} </div> </div> </div> ); }; const loginForm = () => { return ( <div className='bg-gray-200'> <div className="flex items-center h-screen w-full"> <div className="w-80 bg-white rounded-2xl p-6 m-0 md:max-w-sm md:mx-auto border border-slate-300 shadow-sm"> <div align='center' className='mt-3 mb-3 items-center content-center'> <img src={require('./../data/logo.jpg')} width="120px"/></div> <span className="block w-full text-xl uppercase font-bold mb-4 text-center">Sign in to EMS </span> <form className="mb-0" action="/" method="post"> <div className="mb-4 md:w-full"> <label for="email" className="block text-xs mb-1 text-left text-gray-500">Username</label> <input onChange={handleChange("username")} className="bg-gray-100 w-full border rounded-2xl px-4 py-2 outline-none focus:shadow-outline text-left text-xs" type="text" name="username" id="username" placeholder="Username" value={username}/> </div> <div className="mb-6 md:w-full relative"> <div className='flex w-full'> <label for="password" className="block text-xs mb-1 text-center text-gray-500">Password</label> <a className="text-xs text-right text-[#58a6ff] absolute right-0" href="/login">Forgot password?</a></div> <input onChange={handleChange("password")} className="bg-gray-100 w-full border rounded-2xl px-4 py-2 outline-none focus:shadow-outline text-left text-xs" type="password" name="password" id="password" placeholder="Password" value={password}/> </div> <div className="mb-6 md:w-full relative"> <div className='flex w-full'> <p className="block text-xs mb-1 text-center text-gray-500">{JSON.stringify(values)}</p> </div> <button className="bg-green-500 hover:bg-green-700 shadow-lg text-white uppercase text-sm font-semibold px-4 py-2 rounded-2xl text-center items-center w-full" onClick={onSubmit}>Login</button> </form> </div> </div> </div> ); }; return ( loadingMessage(), errorMessage(), loginForm(), performRedirect() ) } export default Login Please someone help me on this?
You can modify your return statement with an array value [] like below return [ loadingMessage(), errorMessage(), loginForm(), performRedirect() ] Another way, you can render those JSX functions by {} and wrap them into <React.Fragment></React.Fragment> (Or simpler version <></>) return ( <React.Fragment> {loadingMessage()} {errorMessage()} {loginForm()} {performRedirect()} </React.Fragment>)
like this: return ( <> {loadingMessage()} {errorMessage()} {loginForm()} {performRedirect()} </> )
How to make Dropdown in ReactJs from Query and get the value
Sorry if I ask again, I try to make dropdown from array in my database then use the dropdown to take the value I want looping the array to the dropdown in here but still not showed //tipe akademik //define state const [postsTipe, setPostsTipe] = useState([]); //useEffect hook useEffect(() => { //panggil method "fetchData" fectDataTipe(); }, []); //function "fetchData" const fectDataTipe = async () => { //fetching const responseTipe = await axios.get('http://localhost:3000/api/tipe_akademik'); //get response data const dataTipe = await responseTipe.data.data; //assign response data to state "posts" setPostsTipe(dataTipe); } const Dropdown = () => { // dropdown props const [dropdownPopoverShow, setDropdownPopoverShow] = React.useState(false); const btnDropdownRef = React.createRef(); const popoverDropdownRef = React.createRef(); const openDropdownPopover = () => { createPopper(btnDropdownRef.current, popoverDropdownRef.current, { placement: "bottom-start", }); setDropdownPopoverShow(true); }; const closeDropdownPopover = () => { setDropdownPopoverShow(false); }; return ( <> <a className="text-blueGray-500 block" href="#pablo" ref={btnDropdownRef} onClick={(e) => { e.preventDefault(); dropdownPopoverShow ? closeDropdownPopover() : openDropdownPopover(); }} > <div class="relative inline-block text-left"> <div> <button type="button" class="inline-flex justify-center w-full rounded-md border border-gray-300 shadow-sm px-4 py-2 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-100 focus:ring-indigo-500" id="menu-button" aria-expanded="true" aria-haspopup="true"> Tipe Akademik </button> </div> </div> </a> <div ref={popoverDropdownRef} className={ (dropdownPopoverShow ? "block " : "hidden ") + "bg-white text-base z-50 float-left py-2 list-none text-left rounded shadow-lg min-w-48" } > {postsTipe.map((kategori)=> { return(<> <a href="#pablo" className={ "text-sm py-2 px-4 font-normal block w-full whitespace-nowrap bg-transparent text-blueGray-700" } onClick={(e) => e.preventDefault()} > {kategori.tipe_akademik} </a> /</> )})} </div> </> ); }; export default Dropdown; Then I call it to my input form with import from dropdown and I want take the value in form and its still wrong. I dont know how to take the the value from import the dropdown named TipeDropdown import TipeDropdown from "components/Dropdowns/Dropdown"; method "storePost" const storePost = async (e) => { e.preventDefault(); //send data to server await axios.post('http://localhost:3000/api/akademik_a/store', { tipeA: TipeA, }) .then(() => { //redirect history.push('/admin/dafgur'); }) .catch((error) => { //assign validation on state setValidation(error.response.data); }) }; export default function InputAkademik({ color }) { return ( <> <form onSubmit={ storePost } <input className="border-0 px-3 py-3 placeholder-blueGray-300 text-blueGray-600 bg-white rounded text-sm shadow focus:outline-none focus:ring w-full ease-linear transition-all duration-150" placeholder="" /> <div className="field mt-5"> <label className="label">Tipe Akademik</label> <div className="controls"> <TipeDropdown value={TipeA} onChange={(e) => setTipe(e.target.value)}/> <input type="text" className="border-0 px-3 py-3 placeholder-blueGray-300 text-blueGray-600 bg-white rounded text-sm shadow focus:outline-none focus:ring w-full ease-linear transition-all duration-150" placeholder="" value={TipeInput} onChange={(e) => TipeInput(e.target.value)} /> </div> </div> </div> </> ); };
Actions must be plain objects. Use custom middleware for async actions in dispatch
I am trying to create a signout and login functionality for my application. I added redux to do this, but I am getting the error mentioned in the title. Here is my code: App.js This is my main component and here is my Router for the app import { BrowserRouter as Router, Switch, Route } from "react-router-dom"; import { Provider } from "react-redux"; import store from "./Redux/store"; import { Login } from "./Components/Login"; import Signup from "./Components/Signup"; import { MainTheme } from "./Components/MainTheme"; function App() { return ( <Provider store={store}> <Router> <Switch> <Route path="/login" exact component={Login} /> <Route path="/signup" exact component={Signup} /> <Route path="/" exact component={MainTheme} /> </Switch> </Router> </Provider> ); } export default App; Signup.js Is the component for Signup and is where the error appears. Specifically in my function called in mapDispatchToProps import { connect } from "react-redux"; import { userPostFetch } from "../../Redux/actions"; const Signup = ({ userPostFetch }) => { const handleSubmit = (e) => { e.preventDefault(); const signupFrm = e.target; const user = { username: signupFrm.username.value, email: signupFrm.email.value, password: signupFrm.password.value, confPassword: signupFrm.confPassword.value, }; userPostFetch(user); }; return ( <div className="min-h-screen flex items-center justify-center bg-gray-50 py-12 px-4 sm:px-6 lg:px-8"> <div className="max-w-md w-full space-y-8"> <div> <h2 className="mt-6 text-center text-3xl font-extrabold text-gray-900"> Sign up </h2> </div> <form className="mt-8 space-y-6" onSubmit={handleSubmit}> <input type="hidden" name="remember" value="true" /> <div className="rounded-md shadow-sm -space-y-px"> <div> <label htmlFor="username" className="sr-only"> Username </label> <input id="username" name="username" type="text" required className="appearance-none rounded-none relative block w-full px-3 py-2 border border-gray-300 placeholder-gray-500 text-gray-900 rounded-t-md focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 focus:z-10 sm:text-sm" placeholder="Username" /> </div> <div> <label htmlFor="email-address" className="sr-only"> Email address </label> <input id="email-address" name="email" type="email" autoComplete="email" required className="appearance-none rounded-none relative block w-full px-3 py-2 border border-gray-300 placeholder-gray-500 text-gray-900 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 focus:z-10 sm:text-sm" placeholder="Email address" /> </div> <div> <label htmlFor="password" className="sr-only"> Password </label> <input id="password" name="password" type="password" autoComplete="current-password" required className="appearance-none rounded-none relative block w-full px-3 py-2 border border-gray-300 placeholder-gray-500 text-gray-900 focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 focus:z-10 sm:text-sm" placeholder="Password" /> </div> <div> <label htmlFor="confirm-password" className="sr-only"> Confirm Password </label> <input id="confirm-password" name="confPassword" type="password" required className="appearance-none rounded-none relative block w-full px-3 py-2 border border-gray-300 placeholder-gray-500 text-gray-900 rounded-b-md focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 focus:z-10 sm:text-sm" placeholder="Confirm Password" /> </div> </div> <div> <button className="group relative w-full flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"> <span className="absolute left-0 inset-y-0 flex items-center pl-3"> {/* Heroicon name: lock-closed */} <svg className="h-5 w-5 text-indigo-500 group-hover:text-indigo-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true" > <path fillRule="evenodd" d="M5 9V7a5 5 0 0110 0v2a2 2 0 012 2v5a2 2 0 01-2 2H5a2 2 0 01-2-2v-5a2 2 0 012-2zm8-2v2H7V7a3 3 0 016 0z" clipRule="evenodd" /> </svg> </span> Sign in </button> </div> </form> </div> </div> ); }; **The error is in this function** const mapDispatchToProps = (dispatch) => ({ userPostFetch: (userInfo) => { dispatch(userPostFetch(userInfo)); }, }); export default connect(null, mapDispatchToProps)(Signup); Actions.js The action for the functionality export const userPostFetch = (user) => { return (dispatch) => { return fetch("http://0.0.0.0:3001/signup", { method: "POST", headers: { "Content-Type": "application/json", Accept: "application/json", }, body: JSON.stringify({ user }), }) .then((resp) => resp.json()) .then((data) => { if (data.error) { // Here you should have logic to handle invalid creation of a user. // This assumes your Rails API will return a JSON object with a key of // 'message' if there is an error with creating the user, i.e. invalid username (data.error.code === 11000) ? console.log(`Code: ${data.error.code} = ${data.error.KeyPatter} duplicado`) : console.log(`Code: ${data.error.code}`); } else { localStorage.setItem("token", data.token); dispatch(loginUser(data.user)); } }); }; }; const loginUser = (userObj) => ({ type: "LOGIN_USER", payload: userObj, }); store.js The intial state of the store and the reducer import { createStore } from "redux"; const initialState = { currentUser: {}, }; const reducer = (state = initialState, action) => { switch (action.type) { case "LOGIN_USER": return { ...state, currentUser: action.payload }; default: return state; } } export default createStore(reducer); The error gets after click the submit button. I think that i need use a middleware but I really don't know how or what must I do?
Just used redux-thunk for solution: sudo npm i redux-thunk store.js (modified) import { createStore, applyMiddleware } from "redux"; import thunk from "redux-thunk" const initialState = { currentUser: {}, }; const reducer = (state = initialState, action) => { switch (action.type) { case "LOGIN_USER": return { ...state, currentUser: action.payload }; default: return state; } } export default createStore(reducer, applyMiddleware(thunk));