When a user registers it should show the spinner and send them to the dashboard page. I have it set to 8 seconds to allow plenty of time for backend but it still doesn't show. Below is the code.I have state set and using a useeffect setting a timeout and a ternary operator to navigate to the dashboard in the jsx
const CREATE_USER = gql`
mutation CreateUser($userInput: UserInput!, $profileInput: ProfileInput) {
createUser(userInput: $userInput, profileInput: $profileInput) {
token
userId
tokenExpiration
}
}
`;
const Register = (props) => {
let navigate = useNavigate();
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
setIsLoading(false);
setTimeout(() => {}, 8000);
},[]);
//dont need context yet
const context = useContext(AuthContext);
const [errors, setErrors] = useState([]);
function loginUserCallback() {
login();
}
//1. record values from input here
//2. send it in empty, and hook returns with k/v pairs
const { onChange, onSubmit, values } = useForm(loginUserCallback, {
email: "",
password: "",
firstName: "",
lastName: "",
dob: "",
city: "",
state: "",
bio: "",
occupation: "",
});
//3. separate values
//replace with values.email... etc
const userInput = {
email: values.email,
password: values.password,
firstName: values.firstName,
lastName: values.lastName,
dob: values.dob,
city: values.city,
state: values.state,
};
const profileInput = {
bio: values.bio,
occupation: values.occupation,
};
const [login, { loading }] = useMutation(CREATE_USER, {
update(proxy, { data: { createUser: userData } }) {
context.login(userData);
navigate("/dashboard");
},
onError({ graphQLErrors }) {
setErrors(graphQLErrors);
},
//4. send as variables to backend
variables: {
userInput: userInput,
profileInput: profileInput,
},
});
if (loading) {
<h1>error loading</h1>;
}
return (
<>
{isLoading ? <Loading /> : <Dashboard />}
<img
src="https://floatui.com/logo.svg"
width={150}
className="mx-auto"
alt="logo"
/>
<div className="text-center font-semibold font-serif mt-4">REGISTER</div>
<form onSubmit={onSubmit}>
<div className="max-w-md px-4 mx-auto mt-12">
<label htmlFor="email" className="block py-2 text-gray-500">
Email
</label>
<input
name="email"
type="text"
placeholder="email"
id="email"
className="w-full mt-2 px-3 py-2 text-gray-500 bg-transparent outline-none border focus:border-indigo-600 shadow-sm rounded-lg"
required
onChange={onChange}
/>
</div>
<div className="max-w-md px-4 mx-auto mt-12">
<label htmlFor="password" className="block py-2 text-gray-500">
Password
</label>
<input
name="password"
type="text"
placeholder="password"
id="password"
className="w-full mt-2 px-3 py-2 bg-transparent outline-none border focus:border-indigo-600 shadow-sm rounded-lg"
onChange={onChange}
required
/>
</div>
<div className="max-w-md px-4 mx-auto mt-12">
<label htmlFor="firstName" className="block py-2 text-gray-500">
First Name
</label>
<input
name="firstName"
type="text"
placeholder="firstName"
id="firstName"
className="w-full mt-2 px-3 py-2 text-gray-500 bg-transparent outline-none border focus:border-indigo-600 shadow-sm rounded-lg"
onChange={onChange}
required
/>
</div>
<div className="max-w-md px-4 mx-auto mt-12">
<label htmlFor="lastName" className="block py-2 text-gray-500">
lastName
</label>
<input
type="text"
name="lastName"
placeholder="lastName"
id="lastName"
className="w-full mt-2 px-3 py-2 text-gray-500 bg-transparent outline-none border focus:border-indigo-600 shadow-sm rounded-lg"
onChange={onChange}
required
/>
</div>
<div className="max-w-md px-4 mx-auto mt-12">
<label htmlFor="Date of Birth" className="block py-2 text-gray-500">
Date of Birth
</label>
<input
name="dob"
type="date"
placeholder="dob"
id="dob"
className="w-full mt-2 px-3 py-2 text-gray-500 bg-transparent outline-none border focus:border-indigo-600 shadow-sm rounded-lg"
onChange={onChange}
required
/>
</div>
<div className="max-w-md px-4 mx-auto mt-12">
<label htmlFor="city" className="block py-2 text-gray-500">
City
</label>
<input
name="city"
type="text"
placeholder="city"
id="city"
className="w-full mt-2 px-3 py-2 text-gray-500 bg-transparent outline-none border focus:border-indigo-600 shadow-sm rounded-lg"
onChange={onChange}
required
/>
</div>
<div className="max-w-md px-4 mx-auto mt-12">
<label htmlFor="state" className="block py-2 text-gray-500">
State
</label>
<input
name="state"
type="text"
placeholder="state"
id="state"
className="w-full mt-2 px-3 py-2 text-gray-500 bg-transparent outline-none border focus:border-indigo-600 shadow-sm rounded-lg"
onChange={onChange}
required
/>
</div>
<div className="max-w-md px-4 mx-auto mt-12">
<label htmlFor="occupation" className="block py-2 text-gray-500">
Occupation
</label>
<input
name="occupation"
type="text"
placeholder="occupation"
id="occupation"
className="w-full mt-2 px-3 py-2 text-gray-500 bg-transparent outline-none border focus:border-indigo-600 shadow-sm rounded-lg"
onChange={onChange}
required
/>
</div>
<div className="max-w-md px-4 mx-auto mt-12">
<label htmlFor="state" className="block py-2 text-gray-500">
Bio
</label>
<textarea
name="bio"
type="text"
placeholder="bio"
id="state"
rows="4"
col="50"
className="w-full mt-2 px-3 py-2 text-gray-500 bg-transparent outline-none border focus:border-indigo-600 shadow-sm rounded-lg"
onChange={onChange}
required
/>
</div>
<div className="flex justify-center">
<button className="mt-5 px-6 py-2 text-white duration-150 bg-indigo-600 rounded-lg hover:bg-indigo-700 active:shadow-lg">
REGISTER
</button>
</div>
</form>
</>
);
};
export default Register;
The reason why the spinner is not showing up is because the loadingvariable from usemutation is not correctly handled.
In the code, the loading variable is destructured from the useMutation hook as follows:
const [login, { loading }] = useMutation(CREATE_USER, {...})
However, when you check if loadingistrue in the return statement, you do not return any component or text. Instead, you just have a comment. Therefore, even though the loading variable may be true, no spinner is actually displayed.
To fix this, you should return a loading spinner, such as:
if (loading) {
return <Loading />;
}
This will cause the Loading component to be displayed while the mutation is being processed.
Additionally, in the useEffect hook, you are not actually doing anything after the 8-second timeout. To display the spinner for 8 seconds, you should update the useEffect hook as follows:
useEffect(() => {
setTimeout(() => {
setIsLoading(false);
}, 8000);
}, []);
This will change the value of isLoading to false after 8 seconds, causing the Dashboard component to be displayed.
Overall, your Register component should look something like this:
const Register = (props) => {
const navigate = useNavigate();
const [isLoading, setIsLoading] = useState(true);
const context = useContext(AuthContext);
const [errors, setErrors] = useState([]);
useEffect(() => {
setTimeout(() => {
setIsLoading(false);
}, 8000);
}, []);
const { onChange, onSubmit, values } = useForm(loginUserCallback, {
email: "",
password: "",
firstName: "",
lastName: "",
dob: "",
city: "",
state: "",
bio: "",
occupation: "",
});
const userInput = {
email: values.email,
password: values.password,
firstName: values.firstName,
lastName: values.lastName,
dob: values.dob,
city: values.city,
state: values.state,
};
const profileInput = {
bio: values.bio,
occupation: values.occupation,
};
const [login, { loading }] = useMutation(CREATE_USER, {
update(proxy, { data: { createUser: userData } }) {
context.login(userData);
navigate("/dashboard");
},
onError({ graphQLErrors }) {
setErrors(graphQLErrors);
},
variables: {
userInput: userInput,
profileInput: profileInput,
},
});
if (loading) {
return <Loading />;
}
return (
<>
{isLoading ? <Loading /> : <Dashboard />}
<img
src="https://floatui.com/logo.svg"
width={150}
className="mx-auto"
alt="logo"
/>
<div className="text-center font-semibold font-serif mt-4">REGISTER</div>
<form onSubmit={onSubmit}>
...
</form>
</>
);
};
Related
Guys I am trying to update the image i.e base64 string data everything works fine even before submitting the data new image is also displayed correctly but when I submit data it won't update the image
here is my code
import React, { useEffect } from 'react'
import Sidebar_com from '../components/Sidebar_com';
import { useState } from 'react'
import { ToastContainer, toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import FileBase from 'react-file-base64'
import { update_Category, getCategoriesData, getCategoryById } from '#/services/admin'
import Router from 'next/router';
import Image from 'next/image';
export async function getStaticProps({ params }) {
const CategoryData = await getCategoryById(params.id);
return {
props: { CategoryData }
}
}
export async function getStaticPaths() {
const category = await getCategoriesData()
return {
paths: category.map(cate => {
return {
params: { id: String(cate._id) }
};
}),
fallback: false
};
}
export default function updateCategory({ CategoryData }) {
const [cateData, setCateData] = useState(CategoryData);
const [imageData, setImageData] = useState(cateData.image || null);
const handleImageChange = (base64) => {
setImageData(base64);
};
const handleInputChange = (e) => {
if (e.target.type === "checkbox") {
setCateData({ ...cateData, [e.target.name]: e.target.checked });
} else {
setCateData({ ...cateData, [e.target.name]: e.target.value });
}
};
const updateNow = async () =>
{
const res = await update_Category(cateData)
if (res.msg) {
toast.success(res.msg);
Router.push('/admin/categories');
}
else {
toast.error(res.error);
}
}
const handleSubmit = async (e) => {
e.preventDefault();
setCateData({...cateData , image : imageData}, updateNow())
}
return (
<div className='w-full h-screen bg-slate-900 flex'>
<Sidebar_com />
<div className='w-10/12 h-full text-white flex flex-col items-center overflow-auto'>
<div className='w-full p-4 mt-10 mb-4 flex items-center justify-center'>
<h1 className='text-4xl font-semibold tracking-widest border-b p-2 uppercase'>Add Category</h1>
</div>
<form className='text-white' onSubmit={handleSubmit}>
<div class="mb-6">
<label for="email" class="block mb-2 text-sm font-medium text-white dark:text-white">Category Name</label>
<input name='name' value={cateData.name} onChange={handleInputChange} type="text" id="email" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-orange-600 focus:border-orange-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-orange-500 dark:focus:border-orange-500" placeholder="Category name" required />
</div>
<div class="mb-6">
<label for="password" class="block mb-2 text-sm font-medium text-white dark:text-white">Category Slug</label>
<input name='slug' value={cateData.slug} onChange={handleInputChange} type="text" id="password" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-orange-500 focus:border-orange-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-orange-500 dark:focus:border-orange-500" required placeholder='Slug' />
</div>
<div class="flex items-start mb-6">
<div class="flex items-center h-5">
<input name='featured' onChange={handleInputChange} checked={cateData.featured} id="remember" type="checkbox" class="w-4 h-4 border border-gray-300 rounded bg-gray-50 focus:ring-3 focus:ring-orange-300 dark:bg-gray-700 dark:border-gray-600 dark:focus:ring-orange-600 dark:ring-offset-gray-800 dark:focus:ring-offset-gray-800" />
</div>
<label for="remember" class="ml-2 text-sm font-medium text-white dark:text-gray-300">Featured Product</label>
</div>
<div class="mb-6">
<label for="message" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Description</label>
<textarea name='description' value={cateData.description} onChange={handleInputChange} id="message" rows="4" class="block p-2.5 w-full text-sm text-gray-900 bg-gray-50 rounded-lg border border-gray-300 focus:ring-orange-500 focus:border-orange-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-orange-500 dark:focus:border-orange-500" placeholder="Leave a comment..."></textarea>
</div>
{cateData.image &&
<div>
<Image width={300} height={200} src={cateData.image} alt="no image" />
</div>
}
<div class="mb-6">
<label for="password" class="block mb-2 text-sm font-medium text-white dark:text-white">Category Image</label>
<FileBase onDone={({ base64 }) => handleImageChange(base64)} type="text" id="password" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-orange-500 focus:border-orange-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-orange-500 dark:focus:border-orange-500" required placeholder='Slug' />
</div>
<button type="submit" class="text-white bg-orange-600 hover:bg-orange-600 focus:ring-4 focus:outline-none focus:ring-orange-600 font-medium rounded-lg text-sm w-full sm:w-auto px-5 py-2.5 text-center dark:bg-orange-600 dark:hover:bg-orange-600 dark:focus:ring-orange-600">Submit</button>
</form>
</div>
<ToastContainer />
</div>
)
}[enter image description here][1]
look at this I change the image as well as name of category , name changed perfectly but image remain old
is there any way to fix this issue
I think you have a typo in your handleSubmit. It should be:
const handleSubmit = async (e) => {
e.preventDefault();
setCateData({...cateData , image : imageData});
updateNow();
}
BUT, you are using cateData state in your updateNow function which will not be up to date so you better pass the data as parameter.
I'm new to Next.js and I have encountered an error as below:
Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
Check the render method of `Formik`.
my Login component
export const Login = () => {
const { LoginUser, isFetching, loginError } = useContext(UserContext)
console.log(loginError)
return (
<>
<Formik
validationSchema={LoginValidationSchema}
initialValues={{
email: "",
password: "",
}}
onSubmit={(values) => {
LoginUser(values);
console.log(values)
}}
>
{() => (
<>
<div className='w-full relative h-screen max-h-screen'>
<div className='absolute py-2'>
<Link href="/" className="text-3xl font-bold py-2">title</Link>
</div>
<Form className='w-full h-full flex flex-col justify-center items-center'>
<div className='flex flex-col bg-gray-200 mx-1 xsm:px-10 px-5 py-5 w-auto xsm:w-[350px] rounded'>
<div className='border-b-[2px] border-gray-400 py-2'>
<h1 className='font-semibold text-3xl'>Welcome back</h1>
<h1 className='font-light text-xl'>Login</h1>
</div>
<div className='flex flex-col'>
<div className='flex mt-2 flex-col'>
<label className='font-semibold' htmlFor="email">Email</label>
<Field type="email" className="px-3 outline-none focus:ring-2 ring-offset-2 ring-offset-gray-200 ring-btnColor font-semibold rounded py-2 bg-white" name="email" id="email" placeholder="Email" />
<ErrorMessage component="p" className='text-red-600 font-semibold' name="email" />
</div>
<div className='flex mt-2 flex-col'>
<label className='font-semibold' htmlFor="password">Password</label>
<Field type="password" className="px-3 outline-none focus:ring-2 ring-offset-2 ring-offset-gray-200 ring-btnColor font-semibold rounded py-2 bg-white" name="password" id="password" placeholder="Password" />
<ErrorMessage component="p" className='text-red-600 font-semibold' name="password" />
</div>
<Link href="/login/forgot_password" className='px-1 py-2 font-medium hover:underline hover:text-btnColor w-fit' >Forgot password</Link>
<button type='submit' disabled={isFetching} className="font-semibold select-none mt-4 text-white rounded px-2 py-2 bg-btnColor disabled:opacity-40 disabled:cursor-not-allowed">{isFetching ? "Submitting" : "Submit"}</button>
</div>
<p className='font-semibold mt-3'>If you don't have an account <Link href="auth/signup" className='text-btnColor hover:text-indigo-500'>signup</Link></p>
</div>
</Form>
</div>
</>
)}
</Formik>
</>
)
}
I don't understand what the error message is implying, I am exporting the login component by default, and I have no other exports, when I remove the formik component and use the normal form and input's the last part of the error becomes Check the render method of `Login` instead of Check the render method of `Formik`
I have changes react-router-dom where other pages can display the content correctly.
However, I cannot see the content on this page even I change the return elements simply to login page
Could anyone tell me what is wrong with it? thank you very much!!
import { Link } from 'react-router-dom'
import * as ROUTES from '../constants/routes.js'
import FirebaseContext from '../context/firebase'
import { getAuth, signInWithEmailAndPassword } from "firebase/auth";
export default function Login() {
React.useEffect(() => {
document.title= "Login - Instagram"
}, [])
const [email, setEmail] = React.useState("")
const [error, setError] = React.useState("")
const [pwd, setPwd] = React.useState("")
const { firebase } = React.useContext(FirebaseContext)
const [values, setValues] = React.useState({
username: "",
password: ""
})
const isInvalid = values.username === "" || values.password === ""
const handleSubmit = async (e) => {
e.preventdefault()
const auth = getAuth();
signInWithEmailAndPassword(auth, email, pwd)
.then((userCredential) => {
// Signed in
const user = userCredential.user;
console.log(user)
})
.catch((error) => {
setEmail('');
setPwd('');
setError(error.message);
});
}
console.log(error)
console.log(firebase)
const handleChange = e => {
setValues({
...values,
[e.target.name]: e.target.value
})
}
return (
<div className="container flex mx-auto max-w-screen-md items-center h-screen">
<div className="flex w-3/5">
<img src="/images/iphone-with-profile.jpg" alt="iPhone with Instagram app" />
</div>
<div className="flex flex-col w-2/5">
<div className="w-full max-w-xs">
<form onSubmit={handleSubmit} method="POST" className="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4">
<h1 className="flex justify-center w-full">
<img src="/public/logo.png" alt="Instagram" className="mt-2 w-6/12 mb-4" />
</h1>
<input
id="username"
type="text"
name="username"
placeholder="Email address"
className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
value={values.username}
onChange={handleChange}
/>
<br />
<br />
<input
className="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 mb-3 leading-tight focus:outline-none focus:shadow-outline"
id="password"
type="password"
placeholder="Password"
name="password"
value={values.password}
onChange={handleChange}
/>
<br />
<button
className={`bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded w-full focus:outline-none focus:shadow-outline ${isInvalid && 'cursor-not-allowed opacity-50'}`}
type="button"
>
Sign In
</button>
</form>
</div>
<div className="flex justify-center items-center flex-col w-full bg-white p-4 border">
<p className="text-sm">Don't have an account?{` `}
<Link to={ROUTES.SIGN_UP} className="font-bold">
Sign up
</Link>
</p>
</div>
</div>
</div>
)
}```
I understand that React's useState hook is an asynchronous method, hence why it has a callback. However, I want to make the initial user input update (state is updated after only after second input) the state when the handleChange method is triggered. How do I do that -- update react without delay?
code:
import React, { useState, createRef } from "react";
import { Link } from "react-router-dom";
import { useSelector, useDispatch } from 'react-redux';
import DocumentHead from "../DocumentHead";
import Button from "../Button";
import phoneLady from "../../assets/images/phoneLady.jpg";
import setBgImage from "../../utils/setBgImage"
export default function register() {
const pageName = "Regsiter";
const [form, setForm] = useState({
title: "",
firstName: "",
lastName: "",
emailAddress: "",
phoneNumber: "",
dateOfBirth: "",
organization: "",
password: "",
confirmPassword: "",
finalFormIsSlidedIn: false,
buttonIsDisabled: true,
termsAndConditionsIsChecked: false,
});
const handleChange = (e) => {
const target = e.target;
const name = target.name
const value = target.type === 'checkbox' ? target.checked : target.value
setForm((state) => {
return {
...state,
[name]: value
}
}, console.log(form))
}
const handleSubmit = (e) => {
e.preventDefault();
}
return (
<>
<DocumentHead title={pageName} />
<section>
<div id="orderbook-form">
<form className="h-full">
<div className="pt-20 pb-10 px-12">
<h1 id="orderbook-home" className="text-center mb-10 leading-6 md:hidden">
<Link to="/" className="text-gray-400">Orderbook Online</Link>
</h1>
<div className="px-4 sm:px-0 mb-3">
<h2 className="text-lg font-medium leading-6 pb-3 sm:pb-2">
Nice to meet you,
</h2>
<p className="mt-1 text-sm text-gray-600">
create an account to start using
Orderbook
</p>
</div>
<div className="grid grid-cols-1 gap-5">
<div
id="registration-steps"
className="col-span-12"
>
{/*Registration -- First step*/}
<div
id="first-step-fields"
className="col-span-12 grid grid-cols-1 gap-4"
>
<div className="col-span-12">
<select
id="title"
name="title"
autoComplete="title"
className="mt-1 focus:ring-white block w-full sm:text-sm bg-gray-300 form-field"
value={form.value}
onChange={(e) => handleChange(e)}
>
<option defaultValue="Please choose">
Please choose
</option>
<option value="Mr">
Mr
</option>
<option value="Miss">
Miss
</option>
<option value="Mrs">
Mrs
</option>
<option value="Ms">
Ms
</option>
<option value="Dr">
Dr
</option>
<option value="Other">
Other
</option>
</select>
</div>
<div className="col-span-12 grid grid-cols-2 gap-4">
{/*Fix grid*/}
<div className="col-span-1">
<input
type="text"
name="firstName"
value={form.firstName}
id="first-name"
autoComplete="first-name"
placeholder="First name"
className="mt-1 focus:ring-white block w-full sm:text-sm bg-gray-300 form-field"
onChange={(e) => handleChange(e)}
/>
</div>
{/*fix grid*/}
<div className="col-span-1">
<input
type="text"
name="lastName"
value={form.lastName}
id="last-name"
autoComplete="last-name"
placeholder="Last name"
className="mt-1 focus:ring-white block w-full sm:text-sm bg-gray-300 form-field"
onChange={(e) => handleChange(e)}
/>
</div>
</div>
<div className="col-span-12">
<input
type="text"
name="emailAddress"
value={form.emailAddress}
id="email-address"
autoComplete="email"
placeholder="Email address"
className="mt-1 focus:ring-white block w-full sm:text-sm bg-gray-300 form-field"
required
onChange={(e) => handleChange(e)}
/>
</div>
<div className="col-span-12 text-right">
<span
id="next-field-button"
className={`form-slide-button ${
form.finalFormIsSlidedIn
? "hidden"
: ""
}`}
onClick={() =>
slideFinalFormIn()
}
>
Next{" "}
<i
className="fa fa-long-arrow-right"
aria-hidden="true"
></i>
</span>
</div>
</div>
{/*Registration -- Final step*/}
<div
id="final-step-fields"
className="grid gap-4"
ref={finalFormStepRef}
>
<div className="col-span-12">
<input
type="tel"
name="phoneNumber"
id="phone-number"
value={form.phoneNumber}
pattern="[0-9]{4}-[0-9]{3}-[0-9]{4}"
autoComplete="phone-number"
placeholder="Phone number"
className="mt-1 focus:ring-white block w-full sm:text-sm bg-gray-300 form-field"
required
onChange={(e) => handleChange(e)}
/>
</div>
<div className="col-span-12">
<input
type="text"
id="data-of-birth"
name="dateOfBirth"
value={form.dateOfBirth}
autoComplete="date-of-birth"
placeholder="Date of birth (MM/DD/YYYY)"
className="mt-1 focus:ring-white block w-full sm:text-sm bg-gray-300 form-field"
onFocus={(e) =>
(e.target.type =
"date")
}
onBlur={(e) =>
(e.target.type =
"text")
}
onChange={(e) => handleChange(e)}
/>
</div>
{/*<div className="col-span-12">
<input
type="text"
id="organization"
name="organization"
value={form.organization}
autoComplete="organization"
placeholder="Organization/Company"
className="mt-1 focus:ring-white block w-full sm:text-sm bg-gray-300 form-field"
onChange={(e) => handleChange(e)}
/>
</div>*/}
<div className="col-span-12 grid grid-cols-2 gap-4">
<div className="col-span-1">
<input
type="password"
id="password"
name="password"
value={form.password}
autoComplete="password"
placeholder="Password"
className="mt-1 focus:ring-white block w-full sm:text-sm bg-gray-300 form-field"
required
onChange={(e) => handleChange(e)}
/>
</div>
<div className="col-span-1">
<input
type="password"
id="confirm-password"
name="confirmPassword"
value={form.confirmPassword}
autoComplete="confirm-password"
placeholder="Confirm password"
className="mt-1 focus:ring-white block w-full sm:text-sm bg-gray-300 form-field"
required
onChange={(e) => handleChange(e)}
/>
</div>
</div>
<div className="col-span-12 text-left">
<span
id="previous-field-button"
className="form-slide-button"
onClick={() =>
slideFinalFormOut()
}
>
<i
className="fa fa-long-arrow-left"
aria-hidden="true"
></i>{" "}
Previous
</span>
</div>
</div>
</div>
<div className="col-span-12">
<div className="flex items-start">
<div className="flex items-center h-5">
<input
id="terms-and-conditions"
name="termsAndConditionsIsChecked"
type="checkbox"
className="focus:ring-white h-4 w-4 text-indigo-600 border-black rounded"
required
onChange={(e) => handleChange(e)}
/>
</div>
<div className="ml-3 text-sm">
<label
htmlFor="terms-and-conditions"
className="font-medium text-black"
>
By signing up, you agree
to
</label>{" "}
<Link to="/">
Orderbookâs Terms of Use
& Privacy Policy
</Link>
</div>
</div>
</div>
<div className="col-span-12 mt-1">
<Button
type="submit"
title="Sign up"
buttonClass="register-button auth-button"
buttonDisabled={
form.buttonIsDisabled
? true
: ""
}
/>
</div>
<div
id="login-existing-account"
className="col-span-12 mt-1 account-signal"
>
<div className="text-center">
Already have an account?{" "}
<Link to="/login">Log in</Link>
</div>
</div>
</div>
</div>
</form>
</div>
</section>
</>
);
}
I think you can not reach to top 0, you can use a form library for less render and manage all states wisely, please check hook-form
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
I have 5 different inputs for taking OTP. and I am using 6 useState hook to get their value.
Now I want to store those 5 input value in the 6th variable I'm passing to my redux store.
I tried this way but it returns an object and also use parseInt but it doesn't work.
const [otp, setOtp] = useState(null);
const [digitOne, setDigitOne] = useState(null);
const [digitTwo, setDigitTwo] = useState(null);
const [digitThree, setDigitThree] = useState(null);
const [digitFour, setDigitFour] = useState(null);
const [digitFive, setDigitFive] = useState(null);
const handleSubmit = (e) => {
e.preventDefault();
const otp = { digitOne, digitTwo, digitThree, digitFour, digitFive };
console.log(digitOne, digitTwo, digitThree, digitFour, digitFive);
dispatch(checkVerification({ user_info, otp })).then(() => {
console.log(otp);
});
};
return (
<form
onSubmit={handleSubmit}
className="flex flex-col justify-start w-full mt-lg "
>
<div className="flex flex-row justify-between mx-auto max-w-screen-xs space-x-2">
<input
type="text"
className="text-xl w-10 text-center bg-transparent border-t-0 border-l-0 border-r-0 focus:ring-0 focus:border-gray-400 border-b border-gray-400 h-10 "
pattern="[0-9]"
maxLength={1}
value={digitOne}
onChange={(e) => setDigitOne(e.target.value)}
/>
<input
type="text"
className="text-xl w-10 text-center bg-transparent border-t-0 border-l-0 border-r-0 focus:ring-0 focus:border-gray-400 border-b border-gray-400 h-10 "
pattern="[0-9]"
maxLength={1}
value={digitTwo}
onChange={(e) => setDigitTwo(e.target.value)}
/>
<input
type="text"
className="text-xl w-10 text-center bg-transparent border-t-0 border-l-0 border-r-0 focus:ring-0 focus:border-gray-400 border-b border-gray-400 h-10 "
pattern="[0-9]"
maxLength={1}
value={digitThree}
onChange={(e) => setDigitThree(e.target.value)}
/>
<input
type="text"
className="text-xl w-10 text-center bg-transparent border-t-0 border-l-0 border-r-0 focus:ring-0 focus:border-gray-400 border-b border-gray-400 h-10 "
pattern="[0-9]"
maxLength={1}
value={digitFour}
onChange={(e) => setDigitFour(e.target.value)}
/>
<input
type="text"
className="text-xl w-10 text-center bg-transparent border-t-0 border-l-0 border-r-0 focus:ring-0 focus:border-gray-400 border-b border-gray-400 h-10 "
pattern="[0-9]"
maxLength={1}
value={digitFive}
onChange={(e) => setDigitFive(e.target.value)}
/>
</div>
<button className="uppercase flex-grow mt-6 p-2 bg-red-500 text-white px-4 rounded mx-lg">
proceed
</button>
</form>
);
Actions
import ApiInstance from "../../Api/root";
import store from "../store";
import { CHECK_VERIFIED } from "../Types/CustomerVerificationTypes";
import {
CUSTOMER_LOGIN_SUCCESS,
GET_CUSTOMER_LOGIN,
} from "../Types/CustomerLoginTypes";
export const checkVerification =
({ user_info, otp }) =>
async (dispatch, getState) => {
const deviceId = getState().device.device.data.device.id;
localStorage.setItem("id", deviceId);
console.log(otp);
const res = await ApiInstance.get(
`customers/otp/verification?mobile_number=${user_info.mobile_number}&country_code=${user_info.country_code}&otp=${otp}&device_id=${deviceId}`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
}
)
.then((res) => {
console.log("Auth Token", res.data);
dispatch({
type: CHECK_VERIFIED,
payload: res.data,
});
// todo only if API Call is success
if (res.data.success) {
localStorage.setItem("authToken", res.data.token);
} else {
alert("Entered OTP is wrong, Try Again");
}
})
.catch((error) => {
console.error(error);
});
};
Also I've set maxLength of input to 1 but How do I move one input to another after user puts a number?
Add The Following Code To Move A The Curosor To Next Input After Adding A Input. Please Validate Cause it will take some time to reproduce and test the answer. anywas you can do this by using the .focus() function on the element.:
const [otp, setOtp] = useState(null);
const [digitOne, setDigitOne] = useState(null);
const [digitTwo, setDigitTwo] = useState(null);
const [digitThree, setDigitThree] = useState(null);
const [digitFour, setDigitFour] = useState(null);
const [digitFive, setDigitFive] = useState(null);
const handleSubmit = (e) => {
e.preventDefault();
const otp = { digitOne, digitTwo, digitThree, digitFour, digitFive };
console.log(digitOne, digitTwo, digitThree, digitFour, digitFive);
dispatch(checkVerification({ user_info, otp })).then(() => {
console.log(otp);
});
};
return (
<form
onSubmit={handleSubmit}
className="flex flex-col justify-start w-full mt-lg "
>
<div className="flex flex-row justify-between mx-auto max-w-screen-xs space-x-2">
<input
type="text"
className="text-xl w-10 text-center bg-transparent border-t-0 border-l-0 border-r-0 focus:ring-0 focus:border-gray-400 border-b border-gray-400 h-10 "
pattern="[0-9]"
maxLength={1}
value={digitOne}
onChange={(e) => {
setDigitOne(e.target.value)
document.getElementById('digitTwo').focus()
}}
id="digOne"
/>
<input
type="text"
className="text-xl w-10 text-center bg-transparent border-t-0 border-l-0 border-r-0 focus:ring-0 focus:border-gray-400 border-b border-gray-400 h-10 "
pattern="[0-9]"
maxLength={1}
value={digitTwo}
id="digitTwo"
onChange={(e) => {
setDigitTwo(e.target.value)
document.getElementById('digitThree').focus()
}}
/>
<input
type="text"
className="text-xl w-10 text-center bg-transparent border-t-0 border-l-0 border-r-0 focus:ring-0 focus:border-gray-400 border-b border-gray-400 h-10 "
pattern="[0-9]"
maxLength={1}
value={digitThree}
id="digitThree"
onChange={(e) => {
setDigitThree(e.target.value)
document.getElementById('digitFour').focus()
}}
enter code here
/>
<input
type="text"
className="text-xl w-10 text-center bg-transparent border-t-0 border-l-0 border-r-0 focus:ring-0 focus:border-gray-400 border-b border-gray-400 h-10 "
pattern="[0-9]"
maxLength={1}
value={digitFour}
id="digitFour"
onChange={(e) => {
setDigitFour(e.target.value)
document.getElementById('digitFive').focus()
}}
enter code here
/>
<input
type="text"
className="text-xl w-10 text-center bg-transparent border-t-0 border-l-0 border-r-0 focus:ring-0 focus:border-gray-400 border-b border-gray-400 h-10 "
pattern="[0-9]"
maxLength={1}
value={digitFive}
id="digitFive"
onChange={(e) => {
setDigitFIve(e.target.value)
}}
/>
</div>
<button className="uppercase flex-grow mt-6 p-2 bg-red-500 text-white px-4 rounded mx-lg">
proceed
</button>
</form>
);
Please Mark It As Correct If It Works!
Kamestart