formik for validation and post request - node.js

const classes = useStyles();
const initialValues = {
email: '',
fullName: '',
subject: '',
massage: '',
}
const onSubmit = (values) =>{
console.log("values")
axios
.post(`http://localhost:5000/sendmail/contact` , values)
.then((res) => console.log(res))
.catch((errors) => console.log(errors));
};
const formik = useFormik({
initialValues,
validationSchema,
onSubmit,
})
<form onSubmit={formik.handleSubmit}>
<Grid className={classes.GridContactHeading}>
<Typography variant="h4">Contact us</Typography>
</Grid>
<Grid className={classes.GridContactSubHeading}>
<Typography variant="h5">Feel free to ask for details, don't save any questions!</Typography>
</Grid>
<Grid container justifyContent="center">
<Grid item sm={8} md={6} className={classes.GridText1}>
<TextField
required
name='fullName'
label='Full Name'
onChange={formik.handleChange}
value={formik.values.fullName}
className={classes.TextFieldContact}
/>
{formik.errors.fullName ? <div>{formik.errors.fullName}</div> : null}
</Grid>
<Grid item sm={8} md={6} className={classes.GridText2}>
<TextField
required
id="email"
name="email"
label="Email"
fullWidth
onChange={formik.handleChange}
value={formik.values.email}
className={classes.TextFieldContact }
/>
{formik.errors.fullName ? <div>{formik.errors.email}</div> : null}
</Grid>
</Grid>
<Grid className={classes.GridText3}>
<TextField
required
id="subject"
name="subject"
label="Subject"
fullWidth
onChange={formik.handleChange}
value={formik.values.subject}
className={classes.TextFieldContact}
/>
{formik.errors.fullName ? <div>{formik.errors.subject}</div> : null}
</Grid>
<Grid className={classes.GridText3}>
<TextareaAutosize
placeholder="Massage"
minRows={15}
className={classes.AutoSizeTextfield}
id="massage"
name="massage"
onChange={formik.handleChange}
value={formik.values.massage}
/>
{formik.errors.massage ? <div>{formik.errors.massage}</div> : null}
</Grid>
<Grid>
<Button type="submit" variant="contained" color="primary" style={{marginTop:"20px", marginBottom: "20px"}} >
Send Massage
</Button>
</Grid>
</form>
i have created form and validate using formik and yup and now i have to send it to the backend as apost request and get an email but here onsubmit part doesnt work

I have a hunch that your onSubmit function is conflicting with Formik's onSubmit function. That, or your validationSchema needs to be directly declared in your useFormik object. I edited it just a bit with some format changes.
validationSchema: Yup.object({
email: Yup.string('Enter your email').email('Enter a valid
email').required('Email is required'),
fullName: Yup.string('Enter your FullName').trim()
.required('Full Name is required'),
subject: Yup.string('Enter your Subject').trim().required('subject is required'),
message: Yup.string('Enter your Message').trim().required('Message is required')
})

Please check your validationSchema logic. If this log line is not printed on submit event click, most probably the form is invalid. So check your validationSchema first. and why do you pass params to yup.string() method. https://www.npmjs.com/package/yup#string

Related

Formik on submit not called with Nextjs13

i created a form in nextjs13 using Formik, Material UI and Yup, but upon click the submit buttom the form get append to the url as queries and the onSubmit button is never called.
i already have use client at the top of my page, yet the validation and onsubmit is not working
below is my form, i cant realy figure out what am doing wrongly
<Formik
validationSchema={validationSchame}
initialValues={{
username: "",
password: "",
}}
onSubmit={async (values, formikHelpers) => {
console.log(values);
}}
>
{({ errors }) => {
return (
<Form>
<Grid item sx={{ marginBottom: 1 }}>
<Field
sx={{ width: "300px" }}
name="username"
as={StyledRedditTextField}
placeholder="Username"
label="Username"
size="medium"
/>
</Grid>
<Grid item>
<Field
sx={{ width: "300px", marginBottom: 2 }}
name="password"
as={StyledRedditTextField}
placeholder="Password"
label="Password"
size="medium"
type="password"
/>
</Grid>
<Grid item>
<Button
type="submit"
variant="contained"
color="primary"
sx={{ width: "300px" }}
size="large"
>
Sign In
</Button>
</Grid>
</Form>
);
}}
</Formik>

How to save the Mobile Stepper progress on click of next button

I want to save the progress state of Mobile Stepper, so that when user logged out, the user can resume from the place where he left. If progress bar is filled 2% then when next time the user login he should resume from 2% not from 0.
Here is the code:
import React, { useState, useReducer, useEffect } from "react";
import { Button, Typography, Grid, CircularProgress, Paper } from '#mui/material/';
import guardianOptions from '../../../constants/guardianOptions.js';
import studentClasses from '../../../constants/studentClasses.js';
import Stepper from '#mui/material/Stepper';
import Step from '#mui/material/Step';
import StepLabel from '#mui/material/StepLabel';
import MobileStepper from '#mui/material/MobileStepper';
import StepContent from '#mui/material/StepContent';
import { makeStyles, withStyles, createStyles } from '#mui/styles';
import { purple } from '#mui/material/colors';
import TextField from '#mui/material/TextField';
import useStyles from './styles';
import InputLabel from '#mui/material/InputLabel';
import MenuItem from '#mui/material/MenuItem';
import FormHelperText from '#mui/material/FormHelperText';
import FormControl from '#mui/material/FormControl';
import Select from '#mui/material/Select';
const User= (props) => {
const { activeStep: lastActiveStep, userId } = props;
const classes = useStyles();
const [guardianType, setGuardianType] = useState(0);
const [activeStep, setActiveStep] = useState(lastActiveStep || 0);
const [guardianRelationOptions, setGuardianRelationOptions] = useState(0);
const [guardianDetailsForm, setGuardianDetailsForm] = useReducer(
(state, newState) => ({ ...state, ...newState }),
{}
);
const [studentDetailsForm, setStudentDetailsForm] = useReducer(
(state, newState) => ({ ...state, ...newState }),
{ s_firstName: '', s_lastName: '', s_age: '', s_class: '' }
);
React.useEffect(() => {
async function updateActiveStep() {
// this is just pseudo code - whatever your endpoint looks like
await window.fetch('http://localhost:8080/api/user/:userId', {
method: 'PUT',
body: JSON.stringify({activeStep})
})
}
updateActiveStep()
}, [activeStep]);
function getSteps(){
return [<b style={{color:'purple'}}>'Personal Details'</b>,
<b style={{color:'purple'}}>'Relation'</b>,
<b style={{color:'purple'}}>'Guardian Details'</b>];
}
const steps = getSteps();
function onGuardianTypeChangeChange(event) {
// setAge(event.target.value);
setGuardianType(event.target.value);
let _guardianRelationOptions = guardianOptions.find(options => options.value === event.target.value);
setGuardianRelationOptions(_guardianRelationOptions.relationships);
}
const handleGuardianDeatilsInput = evt => {
const name = evt.target.name;
const newValue = evt.target.value;
setGuardianDetailsForm({ [name]: newValue });
};
const handleGuardianDetailsSubmit = evt => {
evt.preventDefault();
let data = { guardianDetailsForm };
props.onGuardianDetails(guardianDetailsForm)
console.log(data + "new user");
// console.log( props.onGuardianDetails(guardianDetailsForm) + "gana bajao");
setActiveStep((prevActiveStep) => prevActiveStep+1);
setGuardianDetailsForm();
}
function getStepContent(step) {
switch (step) {
case 0: if (!props.user.s_firstName) {
return (<div>
<form id ="form-step0" className={classes.root} onSubmit={handleGuardianDetailsSubmit} noValidate autoComplete="off">
<TextField
id="outlined-basic"
name="s_firstName"
label="First Name"
variant="outlined"
defaultValue={guardianDetailsForm.s_firstName}
onChange={handleGuardianDeatilsInput} />
<TextField
id="outlined-basic"
name="s_lastName"
label="Last Name"
variant="outlined"
defaultValue={guardianDetailsForm.s_lastName}
onChange={handleGuardianDeatilsInput} />
<TextField
id="outlined-number"
label="Age"
name="s_age"
defaultValue={guardianDetailsForm.s_age}
type="number"
InputLabelProps={{
shrink: true,
}}
onChange={handleGuardianDeatilsInput}
variant="outlined"
/>
<FormControl variant="outlined" className={classes.formControl}
sx={{ m: 1, minWidth: 120 }}>
<InputLabel id="demo-simple-select-outlined-label">Class</InputLabel>
<Select
labelId="demo-simple-select-outlined-label"
id="demo-simple-select-outlined"
value={guardianDetailsForm.s_class}
onChange={handleGuardianDeatilsInput}
label="Class"
name="s_class"
>
{studentClasses.map(c =>
<MenuItem key={c.value} value={c.value}>{c.name}</MenuItem>
)}
</Select>
{/* <Button variant="contained" type="submit" color="primary" >NEXT</Button> */}
</FormControl>
</form>
</div> )}
;
case 1: if (!props.user.g_relationship) {
return ( <div>
<form id="form-step1" className={classes.root} onSubmit={handleGuardianDetailsSubmit} noValidate autoComplete="off">
<FormControl variant="outlined" className={classes.formControl}
sx={{ m: 1, minWidth: 120 }}>
<InputLabel id="demo-simple-select-outlined-label">Relationship</InputLabel>
<Select
labelId="demo-simple-select-outlined-label"
id="demo-simple-select-outlined"
onChange={onGuardianTypeChangeChange}
label="Relationship"
>
{guardianOptions.map(type =>
<MenuItem key={type.value} value={type.value}>{type.name}</MenuItem>
)}
</Select>
</FormControl>
{guardianRelationOptions ?
<FormControl variant="outlined" className={classes.formControl}
sx={{ m: 1, minWidth: 120 }}>
<InputLabel id="demo-simple-select-outlined-label">Relation</InputLabel>
<Select
labelId="demo-simple-select-outlined-label"
id="demo-simple-select-outlined"
// value={age}
name="g_relationship"
value={guardianDetailsForm.g_relationship}
onChange={handleGuardianDeatilsInput}
label="Relation"
>
{guardianRelationOptions.map(type =>
<MenuItem key={type.value} value={type.value}>{type.name}</MenuItem>
)}
</Select>
</FormControl> : null
}
{!g_relationship} onClick={() => props.onGuardianDetails({g_relationship})}>NEXT</Button> */}
{/* <Button variant="contained" color="primary" type="submit">NEXT</Button> */}
</form>
</div> )}
;
case 2:
return ( <div>
<form id="form-step2" className={classes.root} onSubmit={handleGuardianDetailsSubmit} noValidate autoComplete="off">
<TextField
id="outlined-basic"
name="g_firstName"
label="First Name"
variant="outlined"
defaultValue={guardianDetailsForm.g_firstName}
onChange={handleGuardianDeatilsInput} />
<TextField
id="outlined-basic"
name="g_lastName"
label="Last Name"
variant="outlined"
defaultValue={guardianDetailsForm.g_lastName}
onChange={handleGuardianDeatilsInput} />
<TextField
id="outlined-number"
label="Age"
name="g_age"
defaultValue={guardianDetailsForm.g_age}
type="number"
InputLabelProps={{
shrink: true,
}}
onChange={handleGuardianDeatilsInput}
variant="outlined"
/>
</form>
</div>)
;
default:
return 'welcome lets fill the progress.' ;
}
}
return (
<div className={classes.root} align="center">
<div className = {classes.actionsContainer}>
<Paper square elevation={0}>
<Typography>{getStepContent(activeStep)}</Typography>
</Paper>
<MobileStepper
variant="progress"
steps= {4}
position="bottom"
activeStep={activeStep}
sx={{ minWidth: 400, flexGrow: 1 }}
nextButton={
<>
<Button size="small" onClick={handleGuardianDetailsSubmit} type="submit"
form={`form-step${activeStep}`}>
{activeStep === steps.length-1? 'Finish' : 'Next'}
</Button>
</>
}
/>
</div>
</div>
);
}
export default User;
If user refreshes or reload the page, he should see the progress from where he has left.
#Tanya
So you are saying that your user can authorize. When this happens do you receive any data about the user? Can you update the user data via POST or PUT request? If so, I'd store the active step with this data.
Assuming you have some user data that you receive when the user signs in:
// user - user data
export default function BuildAdStepper({user}) {
const { activeStep: lastActiveStep, userId } = user
const classes = useStyles();
const theme = useTheme();
const [activeStep, setActiveStep] = React.useState(lastActiveStep || 0);
React.useEffect(() => {
async function updateActiveStep() {
// this is just pseudo code - whatever your endpoint looks like
await window.fetch('/yourEndpoint/:userId', {
method: 'PUT',
body: JSON.stringify({activeStep})
})
}
updateActiveStep()
}, [activeStep])
/* ... rest of your component * /
}

How to use different image on mobile in ReactJs Slick

Is there any way to use mobile image different from the desktop mode in react slick slider? I can use display none for breakpoints but what I want to learn, Is there any different way to do it?
const Hero = () => {
const classes = useStyle();
const { push } = useRouter();
const [sliderState, setSliderState] = useState(heroSliderData);
const [my_swiper, set_my_swiper] = useState({});
return (
<section className={classes.section}>
<Grid style={{ width:"100%", padding: "0px" }}>
<Swiper
loop={true}
navigation={true}
onInit={(ev) => {
set_my_swiper(ev);
}}
>
{sliderState.map(({ id, mainheading, mainheading2, subheading, subheading2, buttontext, image }) => (
<SwiperSlide key={id}>
<Grid item className={classes.hero}>
<img className={classes.heroimg} src={image} style={{ position:"relative"}} />
<Grid item xs={12} style={{ position:"absolute", top:"30%", left:"0", right:"0", textAlign: "center" }}>
<Typography variant="h1" className={classes.h1}>
{mainheading}<br />
{mainheading2}
</Typography>
</Grid>
<Grid item xs={12} style={{ position:"absolute", top:"42%", left:"0", right:"0", textAlign: "center" }}>
<Typography variant="h2" className={classes.h2}>
{subheading}
<br/>
{subheading2}
</Typography>
</Grid>
<Grid item xs={12} style={{ position:"absolute", top:"52%", left:"0", right:"0", textAlign: "center" }}>
<Button
variant="contained"
onClick={() => push("/teklif-al")}
className={classes.teklifal}
>
{buttontext}
</Button>
</Grid>
</Grid>
</SwiperSlide>
))}
</Swiper>
</Grid>
</section>
);
};
This is my code that I am working on it
Have you tried to use an IF clause to show and hide images?
See docs of React Slick.
import React, { Component } from "react";
import Slider from "react-slick";
export default class MultipleItems extends Component {
render() {
const settings = {
dots: true,
infinite: true,
speed: 500,
slidesToShow: 3,
slidesToScroll: 3
};
return (
<div>
<h2> Multiple items </h2>
<Slider {...settings}>
<div>
<h3>1</h3>
</div>
<div>
<h3>2</h3>
</div>
<div>
<h3>3</h3>
</div>
<div>
<h3>4</h3>
</div>
<div>
<h3>5</h3>
</div>
<div>
<h3>6</h3>
</div>
<div>
<h3>7</h3>
</div>
<div>
<h3>8</h3>
</div>
<div>
<h3>9</h3>
</div>
</Slider>
</div>
);
}
}
And modify like this:
import React, { Component } from "react";
import Slider from "react-slick";
export default class MultipleItems extends Component {
const showOnMobile = document.innerWidth < 769;
render() {
const settings = {
dots: true,
infinite: true,
speed: 500,
slidesToShow: 3,
slidesToScroll: 3
};
return (
<div>
<h2> Multiple items </h2>
<Slider {...settings}>
{showOnMobile &&
<div>
<h3>1</h3>
</div>
}
<div>
<h3>2</h3>
</div>
<div>
<h3>3</h3>
</div>
<div>
<h3>4</h3>
</div>
<div>
<h3>5</h3>
</div>
<div>
<h3>6</h3>
</div>
<div>
<h3>7</h3>
</div>
<div>
<h3>8</h3>
</div>
<div>
<h3>9</h3>
</div>
</Slider>
</div>
);
}
}

can't upload images using react to backend using axios and nodejs

I try to upload a photo from React and save it in a public folder on the backend and then display the filename in the MySql database
After trying it through Postman, the photo has been successfully uploaded and appears and produces a json like this
{"image":"/img/14d714a9ed97fb92db657b9518e89a1e.png",
"id_produk":23,
"id_user":19,
"Nama_toko":"Nihongo Mantappu",
"Nama_Produk":"Butter",
"Deskripsi":"Mentega Blueband 50g",
"Price":5000,
"Jumlah_stock":7},
but when I tried it in React it only produced this
{"image":"/img/",
"id_produk":29,
"id_user":19,
"Nama_toko":"Nihongo Mantappu",
"Nama_Produk":"Beras Cinajur",
"Deskripsi":"Beras Cianjur 1kg",
"Price":500000,"Jumlah_stock":20}
so that when i check the database on the image it becomes empty
here the code for upload image
import React from 'react'
import jwt_decode from 'jwt-decode';
import 'bootstrap/dist/css/bootstrap.min.css';
import NavbarPenjual from '../../Component/NavbarPenjual';
import {addproduk} from '../../View/UserFunctions';
import { Form,Col, Button } from 'react-bootstrap';
class TambahProduk extends React.Component{
constructor(){
super()
this.state={
id_user:'',
Nama_toko:'',
Nama_produk: '',
Harga:'',
image: '',
Deskripsi: '',
Jumlah_produk: '',
error:{}
}
this.onChange=this.onChange.bind(this)
this.onSubmit=this.onSubmit.bind(this)
}
onChange(e){
this.setState({[e.target.name]:e.target.value})
}
componentDidMount(){
const token = localStorage.getItem('usertoken')
const decoded= token ? jwt_decode(token) : null;
this.setState({
id_user:decoded.id_user,
Nama_toko:decoded.Nama_toko
})
}
onSubmit(e){
e.preventDefault()
const newProduk={
id_user:this.state.id_user,
Nama_toko:this.state.Nama_toko,
Nama_Produk: this.state.Nama_Produk,
Price:this.state.Price,
image: this.state.image,
Deskripsi: this.state.Deskripsi,
Jumlah_stock: this.state.Jumlah_stock,
}
console.log(newProduk)
addproduk(newProduk).then(res =>{
//localStorage.setItem('usertoken',res.data.token);
this.props.history.push(`/DashboardPenjual`)
}).catch(err=>{
console.log(err)
alert("gagal")
})
}
render(){
return(
<div>
<NavbarPenjual/>
<Form className="container"style={{marginTop:28}} noValidate onSubmit={this.onSubmit}>
<h2>Tambah Produk</h2>
<Form.Row controlId="exampleForm.ControlInput1">
<Form.Label column lg={2}>
Nama Produk
</Form.Label>
<br/>
<Col>
<Form.Control
type="text"
placeholder="Masukan Nama Produk"
name="Nama_Produk"
value={this.state.Nama_Produk}
onChange={this.onChange}
/>
</Col>
</Form.Row>
<br/>
<Form.Row controlId="exampleForm.ControlInput1">
<Form.Label column lg={2}>
Harga Produk
</Form.Label>
<br/>
<Col>
<Form.Control type="text"
placeholder="Masukan Harga Produk"
name="Price"
value={this.state.Price}
onChange={this.onChange}
/>
</Col>
</Form.Row>
<br/>
<Form.Row controlId="exampleForm.ControlInput1">
<Form.Label column lg={2}>
Jumlah Produk
</Form.Label>
<br/>
<Col>
<Form.Control
type="text"
placeholder="Masukan Jumlah Produk"
name="Jumlah_stock"
value={this.state.Jumlah_stock}
onChange={this.onChange}
/>
</Col>
</Form.Row>
<br/>
<Form.Row controlId="exampleForm.ControlInput1">
<Col>
<Form.Group controlId="exampleForm.ControlTextarea1">
<Form.Label>Deskripsi Produk</Form.Label>
<br/>
<Form.Control
as="textarea"
rows="3"
name="Deskripsi"
value={this.state.Deskripsi}
onChange={this.onChange}
/>
</Form.Group>
</Col>
</Form.Row>
<br/>
<Form.Row controlId="exampleForm.ControlInput1">
<Form.Group>
<Form.File
id="exampleFormControlFile1"
label="Masukan Foto Produk"
type="image"
name="image"
value={this.state.image}
onChange={this.onChange}
/>
</Form.Group>
</Form.Row>
<br/>
<button
type="submit"
className="btn btn-lg btn-primary btn-block"
>Submit</button>
<Form.Row controlId="exampleForm.ControlInput1" style={{ visibility: "hidden" }}>
<Col>
<Form.Group controlId="exampleForm.ControlInput1">
<br/>
<Form.Control
as="text"
name="id_user"
value={this.state.id_user}
onChange={this.onChange}
/>
</Form.Group>
</Col>
</Form.Row>
<Form.Row controlId="exampleForm.ControlInput1" style={{ visibility: "hidden" }}>
<Col>
<Form.Group controlId="exampleForm.ControlTextarea1">
<br/>
<Form.Control disabled
as="area"
name="Nama_toko"
value={this.state.Nama_toko}
onChange={this.onChange}
/>
</Form.Group>
</Col>
</Form.Row>
</Form>
</div>
)
}
}
export default TambahProduk;
this is part of the axios userfuction for add product
export const addproduk = newProduk =>{
return axios
.post('product/addproduk',{
id_user:newProduk.id_user,
Nama_toko:newProduk.Nama_toko,
Nama_Produk:newProduk.Nama_Produk,
image: newProduk.image,
Deskripsi:newProduk.Deskripsi,
Price:newProduk.Price,
Jumlah_stock:newProduk.Jumlah_stock
})
.then(res=>{
console.log("produk di tambahkan")
return res
})
.catch(err=>{
console.log(err);
return err;
})
}
How do I get uploaded like when I use Postman?
Image is not an value, it's a file. So, in the onChange function you assigned the image.target.name as value
Try like this :
event.target.name === "image"? event.target.files[0] : event.target.value;

How to create onSubmit with Material-UI

So I'm fairly new to node.js / react / material-ui. I've been following a guide to try setting up a website and have been getting on pretty well. I decided to include material-ui for snazzy components (not part of the guide) and then got stuck because I can't seem to fire custom functions whilst using a themed ui.
With the below code, I can create everything fine if I ditch the 'classes' props. I can add my function and everything works. But I obviously lose all my styling if I do this.
const styles = theme => ({
// Styling - omitted
});
const Login = (props) => {
const {classes} = props;
return(
<div>
<Paper className={classes.root}>
<form className={classes.container} noValidate autoComplete="off">
<TextField
id="email"
label="Email"
className={classes.textField}
InputProps={{
className: classes.input
}}
type="email"
name="email"
autoComplete="email"
margin="normal"
variant="outlined"
required
autoFocus
/>
<TextField
id="outlined"
label="Password"
className={classes.textField}
InputProps={{
className: classes.input
}}
type="password"
autoComplete="current-password"
margin="normal"
variant="outlined"
required
/>
<Typography className={classes.divider} />
<Button
type="submit"
variant="contained"
color="inherit"
className={classes.button}
>
Login
</Button>
</form>
</Paper>
</div>
);
}
Login.propTypes = {
classes: PropTypes.object.isRequired,
};
export default withStyles(styles)(Login);
I'm trying to combine the styling as well as being able to fire a custom function to submit the form data. Does anyone have any thoughts?
The class property/ styles shouldn't have any effect on form submission custom function. If you think that ditching the 'class props' you can get a custom function to work - post your code so we can help you further. [Your code is missing submit function]
Here is one way to add custom submit function
const Login = (props) => {
const {classes} = props;
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
function handleSubmit(event) {
event.preventDefault();
console.log( 'Email:', email, 'Password: ', password);
// You should see email and password in console.
// ..code to submit form to backend here...
}
return( <div >
<Paper className={classes.root}>
<form className={classes.container} onSubmit={handleSubmit} >
<TextField
....
value={email}
onInput={ e=>setEmail(e.target.value)}
.....
/>
<TextField
....
value={password}
onInput={ e=>setPassword(e.target.value)}
....
/>
<Typography className={classes.divider} />
<Button
type="submit"
....
className={classes.button}
>
Login
</Button>
</form>
</Paper>
</div>
);

Resources