This is my login component made by ReactJS with TypeScript. I am bit new to GraphQL. Can someone please help me to sort out this.
I am getting the error as "Variable "$data" is not defined" from the server.
interface SignInInput {
email: string;
password: string;
}
interface SignInResponse {
signIn: {
token: string;
}
}
const SignInInputInitValues: SignInInput = {
email: "",
password: "",
};
const MUTATIONS = gql
`mutation {
loginClinician(data: $data) {
token
data {
id
firstName
}
}
}`;
const SignIn: FunctionComponent = () => {
const setToken = tokenStore(state => state.setToken);
const [ signIn, { loading }] = useMutation<SignInResponse, { data: SignInInput }>(MUTATIONS);
const validate = (values): FormikErrors<SignInInput> => {
const errors: FormikErrors<SignInInput> = {};
if (!values.email) {
errors.email = "Required";
} else if (!emailRegex.test(values.email)) {
errors.email = "Invalid Email Address";
}
if (!values.password) {
errors.password = "Required";
}
if (values.password && values.password.length < 6) {
errors.password = "Your password should have at least 6 characters";
}
return errors;
};
const submitForm = async(credentials: SignInInput) => {
console.log(credentials)
try {
const { data } = await signIn({ variables: { data: credentials }});
setToken(data.signIn.token);
} catch (e) {
e.graphQLErrors.forEach((error) => {
message.error(error.message, 3);
});
}
};
return (
<div className="container">
<div className="card login__common--card">
<div className="text__center">
<img src={Logo} />
</div>
<h3 className="heading-section">Log In</h3>
<Formik
initialValues={SignInInputInitValues}
validate={validate}
onSubmit={submitForm}
>
{({
values,
errors,
handleChange,
handleSubmit,
}) => (
<Form
colon={false}
layout="vertical"
onFinish={handleSubmit}
>
<Form.Item
label="Admin's ID"
help={errors.email}
validateStatus={errors.email ? "error" : ""}
>
<Input
size={SIZE}
name="email"
value={values.email}
onChange={handleChange}
/>
</Form.Item>
<Form.Item
label="Password"
help={errors.password}
validateStatus={errors.password ? "error" : ""}
>
<Input.Password
name="password"
value={values.password}
onChange={handleChange}
type="password"
size={SIZE}
/>
</Form.Item>
<Form.Item colon={false}>
<Row>
<Button
type="primary"
htmlType="submit"
loading={loading}
size={SIZE}
block
className="auth__common--btn"
>
Log In
</Button>
</Row>
</Form.Item>
<div className="text__center">
Forgot password?{" "}
<Link to="/forgot-password">Reset Here</Link>
</div>
</Form>
)}
</Formik>
</div>
</div>
);
};
export default SignIn;
Not sure how I can pass data to my mutation. If someone can help me to sort this out that would be really helpful.
You need to define the variables at the beginning of the gql. So yould would need to modify your gql to sth. like this:
const MUTATIONS = gql
`mutation($data: SignInInput!) {
loginClinician(data:$data) {
token
data {
id
firstName
}
}
}`;
Related
I'm looking to implement the form validation using react-hook. However, I'm facing some trouble in doing so as I've also added some stuff on my own under the handleSubmit and I'm not really sure how to go about it.
export default function Contact() {
const [message, setMessage] = useState(false);
const [alert, setAlert] = useState(true);
const { register, errors} = useForm();
const [showElement, setShowElement] = React.useState(false);
const handleSubmit = (e) => {
e.preventDefault();
emailjs.sendForm('', '', e.target, '')
.then((result) => {
console.log(result.text);
}, (error) => {
console.log(error.text);
});
e.target.reset();
setMessage(true);
setShowElement(true);
setTimeout(function () {
setShowElement(false);
}, 4000);
};
const onSubmit= data=>{
console.log(data);
}
return (
<div className="right">
<h2>Contact Me</h2>
<form onSubmit={handleSubmit} id="contactform">
<input type="text" placeholder="Name" name="name" ref={register({required: true, minLength: 2})}
required />
<button type="submit">Send</button>
</form>
{showElement ? (
<div className="submitmsg">
{message && (
<span> Messaged received. I'll respond to your query ASAP! </span>
)}
</div>
) : (
<div> </div>
)}{" "}
</div>
)
}
Thank you!
React hook form provides the handeSubmit method that receives the form data after validations. Also, you must use the errors object to show errors in the UI.
Here is the sandbox link: https://codesandbox.io/s/exciting-dust-df5ft?file=/src/App.js
I have updated your code accordingly:
import { useState } from "react";
import React from "react";
import emailjs from "emailjs-com";
import { useForm } from "react-hook-form";
export default function Contact() {
const [message, setMessage] = useState(false);
const {
register,
handleSubmit,
formState: { errors }
} = useForm();
const [showElement, setShowElement] = React.useState(false);
const onSubmit = (data) => {
emailjs
.send(
"service_t1ccrgq",
"template_gmmcyzr",
data,
"user_d0vUwhmqvbIYhEsyZF8tu"
)
.then(
(result) => {
console.log(result.text);
},
(error) => {
console.log(error.text);
}
);
setMessage(true);
setShowElement(true);
setTimeout(function () {
setShowElement(false);
}, 4000);
};
return (
<div className="contact" id="contact">
<div className="left">
<img className="contactme" src="asset/email.gif" />
</div>
<div className="right">
<h2>Contact Me</h2>
<form onSubmit={handleSubmit(onSubmit)} id="contactform">
<input
type="text"
placeholder="Name"
name="name"
{...register("name", {
required: "Name is Required",
minLength: {
value: 3,
message: "Should be greater than 3 characters"
}
})}
/>
<input
type="tel"
placeholder="Mobile Number"
name="mobile"
{...register("mobile", {
required: "Mobile Number is Required",
minLength: {
value: 3,
message: "Should be greater than 3 characters"
}
})}
/>
<input
type="text"
placeholder="Email"
name="email"
{...register("email", {
required: "Email is Required",
minLength: {
value: 3,
message: "Should be greater than 3 characters"
}
})}
/>
<textarea
placeholder="Message"
required
name="message"
{...register("message", {
required: "Message is Required",
minLength: {
value: 3,
message: "Should be greater than 3 characters"
}
})}
></textarea>
<button type="submit">Send</button>
</form>
{showElement ? (
<div className="submitmsg">
{message && (
<span> Messaged received. I'll respond to your query ASAP! </span>
)}
</div>
) : (
<div> </div>
)}{" "}
</div>
{errors.name && (
<div>
<span>{errors.name.message}</span>
</div>
)}
{errors.message && (
<div>
<span>{errors.message.message}</span>
</div>
)}
{errors.email && (
<div>
<span>{errors.email.message}</span>
</div>
)}
{errors.mobile && (
<div>
<span>{errors.mobile.message}</span>
</div>
)}
</div>
);
}
You have to first initialize handleSubmit as below.
const {handleSubmit} = useForm();
Then in the form, onSubmit should be as below.
<form onSubmit={handleSubmit(onSubmit)}>
"onSubmit" is the method that is used to write the code in submitting form.
Regards.
In your code, it should be as below.
const onSubmit = (e) => {
e.preventDefault();
emailjs.sendForm('', '', e.target, '')
.then((result) => {
console.log(result.text);
}, (error) => {
console.log(error.text);
});
e.target.reset();
setMessage(true);
setShowElement(true);
setTimeout(function () {
setShowElement(false);
}, 4000);
};
i want to integrate backend codes i.e. rest api to front end reactjs code. i have tried usingaxios . pls help i am new to react.
the code is below:
import React, { useState } from "react";
import "./Register.css";
import { useHistory } from "react-router-dom";
import axios from "axios";
function Register() {
const history = useHistory();
const [data, setData] = useState({
name: "",
phone: "",
password: "",
confirmpassword: "",
});
const [nameErr, setNameErr] = useState({});
const [phoneErr, setPhoneErr] = useState({});
const [passwordErr, setPasswordErr] = useState({});
const [confirmPasswordErr, setConfirmPasswordErr] = useState({});
const InputEvent = (event) => {
const { name, value } = event.target;
setData((preVal) => {
return {
...preVal,
[name]: value,
};
});
};
const formSubmit = (e) => {
e.preventDefault();
const isValid = formValidation();
if (isValid) {
//if form is valid, route
history.push("/myvehicles");
}
};
const formValidation = () => {
const nameErr = {};
const phoneErr = {};
const passwordErr = {};
const confirmPasswordErr = {};
let isValid = true;
if (data.name.trim().length < 4) {
nameErr.nameShort = "name is short";
isValid = false;
}
if (data.phone.trim().length < 10) {
phoneErr.phoneerror = "phone number must have 10 digits";
}
if (data.password.trim().length < 4) {
passwordErr.passwordShort = "password must be 8 characters";
isValid = false;
}
if (!(data.confirmpassword === data.password)) {
confirmPasswordErr.confirmPasswordError = "password must be same";
isValid = false;
}
setNameErr(nameErr);
setPhoneErr(phoneErr);
setPasswordErr(passwordErr);
setConfirmPasswordErr(confirmPasswordErr);
return isValid;
};
axios.post(`https://localhost:5000/`, { InputEvent }).then((res) => {
console.log(res);
console.log(res.data);
});
return (
<div className="signup__container">
<div className="signup__containerInfo">
<h1 className="h1__swari">सवारी नविकरणको लागि</h1>
<hr />
</div>
<form className="register__form" onSubmit={formSubmit}>
<h5 className="h5__form"> Name</h5>
<input
type="text"
placeholder="पुरा नाम लेख्नुहोस्"
name="name"
value={data.name}
onChange={InputEvent}
/>
{Object.keys(nameErr).map((key) => {
return (
<div className="error__msg" style={{ color: "red" }}>
{nameErr[key]}
</div>
);
})}
<h5 className="h5__form"> phone </h5>
<input
type="text"
placeholder="फोन लेख्नुहोस्"
name="phone"
value={data.phone}
onChange={InputEvent}
/>
{Object.keys(phoneErr).map((key) => {
return (
<div className="error__msg" style={{ color: "red" }}>
{phoneErr[key]}
</div>
);
})}
<h5 className="h5__form"> Password </h5>
<input
type="Password"
placeholder="पासवर्ड लेख्नुहोस्s"
name="password"
value={data.password}
onChange={InputEvent}
/>
{Object.keys(passwordErr).map((key) => {
return (
<div className="error__msg" style={{ color: "red" }}>
{passwordErr[key]}
</div>
);
})}
<h5 className="h5__form"> Confirm Password </h5>
<input
type="Password"
placeholder="पुन: पासवर्ड लेख्नुहोस्"
name="confirmpassword"
value={data.confirmpassword}
onChange={InputEvent}
/>
{Object.keys(confirmPasswordErr).map((key) => {
return (
<div className="error__msg" style={{ color: "red" }}>
{confirmPasswordErr[key]}
</div>
);
})}
<p>
<button type="submit" className="signup__registerButton">
Register Now
</button>
</p>
</form>
</div>
);
}
export default Register;
the code is as above . i want the register auth which is token based and wanted to call from the backend and the also send form values to the backend how can i do it?
I am using Material UI stepper and on each step I have different components. I am trying to validate each step using Yup and have used Formik but the instead of validating it moves on to next step. How can I validate this on every step and can get all the data of each step at last.
import React from 'react';
..
import FormStep1 from './FormStep1';
import FormStep2 from './FormStep2';
function getSteps() {
return ['Select general campaign settings', 'Ads setting', 'Upload Ad contents', 'Review and Submit'];
}
function getStepContent(stepIndex, handleStepSubmit, handleNext) {
switch (stepIndex) {
case 0:
return <FormStep1 onSubmit={handleStepSubmit} onNext={handleNext}/>;
case 1:
return <FormStep2 />;
case 2:
return 'No need to worry abt this!';
default:
return 'Unknown stepIndex';
}
}
const IobdCampCreate = () => {
const classes = useStyles();
const [activeStep, setActiveStep] = React.useState(0);
const [state, setState] = React.useState({
steps: [
{ name: 'Select general campaign settings', data: {} },
{ name: 'form2', data: {} }
],
activeStep: 0,
});
const handleNext = () => {
setActiveStep((prevActiveStep) => prevActiveStep + 1);
};
const handleBack = () => {
setActiveStep((prevActiveStep) => prevActiveStep - 1);
};
const handleReset = () => {
setActiveStep(0);
};
const handleStepSubmit = (stepIndex, data) => {
console.log("-------", stepIndex, data)
setState((prevState) => ({
...prevState,
activeStep: prevState.activeStep + 1,
steps: prevState.steps.map((step, index) => {
if (stepIndex !== index) {
return step;
}
return {
...step,
data
}
})
}))
}
return (
<React.Fragment>
<div className={classes.root}>
<Stepper activeStep={activeStep} alternativeLabel>
{state.steps.map((label) => (
<Step key={label.name}>
<StepLabel>{label.name}</StepLabel>
</Step>
))}
</Stepper>
<div>
{activeStep === state.steps.length ? (
<div>
<Typography className={classes.instructions}>All steps completed</Typography>
<Button onClick={handleReset}>Reset</Button>
</div>
) : (
<div>
<div className={classes.instructions}>
{getStepContent(activeStep, handleStepSubmit,handleNext )}
</div>
<div>
<Button
disabled={activeStep === 0}
onClick={handleBack}
className={classes.backButton}
>
Back
</Button>
<Button variant="contained" color="primary" onClick={handleNext}>
{activeStep === state.steps.length - 1 ? 'Finish' : 'Next'}
</Button>
</div>
</div>
)}
</div>
</div>
</React.Fragment>
);
};
export default IobdCampCreate;
Here is a the formstep1.js
import React from 'react';
import { Formik } from 'formik';
const FormStep1 = (props) => (
<div>
<h3>Form A</h3>
<Formik
initialValues={{ email: '', password: '' }}
validate={values => {
const errors = {};
if (!values.email) {
errors.email = 'Required';
} else if (
!/^[A-Z0-9._%+-]+#[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(values.email)
) {
errors.email = 'Invalid email address';
}
return errors;
}}
onSubmit={(values) => {
props.onSubmit(0, values);
}}
>
{({
values,
errors,
touched,
handleChange,
handleBlur,
handleSubmit,
isSubmitting,
/* and other goodies */
}) => (
<form onSubmit={handleSubmit}>
<input
type="email"
name="email"
onChange={handleChange}
onBlur={handleBlur}
value={values.email}
/>
{errors.email && touched.email && errors.email}
<input
type="password"
name="password"
onChange={handleChange}
onBlur={handleBlur}
value={values.password}
/>
{errors.password && touched.password && errors.password}
<button variant="contained" color="primary" type="submit" >
Next
</button>
</form>
)}
</Formik>
</div>
);
export default FormStep1;
I am a React beginner and have been trying to make a custom error handler hook for my contact form.
I have done everything I knew, but I cannot get it to fire submit a message or error message. I am not sure what type should be for callback and validation in UseForm.tsx, and I don't know if the ValidateLogin interface is correct.
This is my code:
UseForm.tsx:
import React, {useState, useEffect} from "react";
const UseForm = (callback:any, validate:any) => {
const [contact, setContact] = useState({
name: "",
email: "",
title: "",
content: ""
});
const [errors, setErrors] = useState({
name: "",
email: "",
title: "",
content: ""
});
const [isSubmitting, setIsSubmitting] = useState(false);
function handleChange(e: React.ChangeEvent<HTMLInputElement> | React.ChangeEvent<HTMLTextAreaElement>) {
const {name, value} = e.target
setContact({...contact, [name]: value})
}
const handleSubmit = (e:React.ChangeEvent<HTMLFormElement>) => {
e.preventDefault();
setErrors(validate(contact));
setIsSubmitting(true);
};
useEffect(() => {
if (Object.keys(errors).length === 0 && isSubmitting) {
callback();
}
}, [errors]);
return {
handleChange,
handleSubmit,
contact,
errors
};
};
export default UseForm
ValidateLogin.tsx:
interface Contact {
email: string;
name: string
title:string
content:string
}
type Error = Partial<Contact>
const ValidateLogin = (contact: Contact) => {
let errors: Error= {};
if (!contact.email) {
} else if (!/\S+#\S+\.\S+/.test(contact.email)) {
errors.email = "Email address is invalid";
}
if (!contact.name) {
errors.name = "Name is required";
}
if (!contact.title) {
errors.title = "Title is required";
}
if (!contact.content) {
errors.content = "Content is required";
}
return errors;
}
export default ValidateLogin
Contact.tsx:
import React from "react";
import {useStep} from "react-hooks-helper";
import useForm from "../components/UseForm"
import validate from "../components/ValidateLogin";
const Contact: React.FC = () => {
const {handleChange, handleSubmit, contact, errors} = useForm(
submit,
validate
);
function submit() {
console.log("Submitted Succesfully");
}
const {index, navigation: {previous, next},} = useStep({steps: 4});
return (
<div className="contact">
<div className="contact-inner">
<form onSubmit={handleSubmit} noValidate>
{index === 0 && <label>
<input onChange={handleChange} value={contact.name} type="text" name="name"
placeholder="Please enter your name"/>
{!errors.name && <p className="error">{errors.name}</p>}
</label>}
{index === 1 && <label htmlFor="email">
<input onChange={handleChange} value={contact.email} type="email" name="email"
placeholder="Please enter your email"/>
{errors.email && <p className="error">{errors.email}</p>}
</label>}
{index === 2 && <label>
<input onChange={handleChange} value={contact.title} type="text" name="title"
placeholder="Please enter the title"/>
{errors.title && <p className="error">{errors.title}</p>}
</label>}
{index === 3 && <label>
<textarea onChange={handleChange} value={contact.content} className="content" name="content"
placeholder="Please enter your message"/>
{errors.content && <p className="error">{errors.content}</p>}
</label>}
</form>
<div className="buttons">
{index === 0 ? <button onClick={previous} disabled>Previous</button> :
<button onClick={previous}>Previous</button>}
{index === 3 ? <button type="submit">Submit</button> : <button onClick={next}>Next</button>}
</div>
</div>
</div>
)
}
export default Contact
Currently working on an app where we have a contact list with id and list name. Clicking on the contact list name will bring to a detailed page listing all contacts within the said contact listname.
On this page a button is set to show input fields to add more contacts. These contacts are then added using mutations.
Once the mutation is done, the contact list detail component failed to render and causing error of undefined (for map operators), however refreshing the page clearly shows the contact is successfully added. Here are the code snippets:
ManageContact component, access via /contacts/manage/:id route
....
class ManageContact extends Component {
state = {
showAddForm: false
};
handleAddContactBtn = () => {
this.setState({ showAddForm: !this.state.showAddForm });
};
render() {
const { showAddForm } = this.state;
return (
<Query
query={findContactList}
variables={{ id: this.props.match.params.id }}
>
{({ loading, error, data:{findContactList} }) => {
if (loading) return "loading";
if (error) return "error";
console.log(findContactList)
const renderContacts = findContactList => {
const { contacts } = findContactList;
return contacts.map((contact, index) => {
return (
<Row key={contact._id}>
<Col s={3}>{contact.firstName}</Col>
<Col s={3}>{contact.lastName}</Col>
<Col s={3}>{contact.email}</Col>
<Col s={3}>
<Button>
<Icon>edit</Icon>
</Button>
<Button>
<Icon>delete_forever</Icon>
</Button>
</Col>
</Row>
);
});
};
return (
<Fragment>
<h3>{findContactList.listName}</h3>
<Row>
<Button onClick={this.handleAddContactBtn} className="right">
<Icon>{showAddForm ? "close" : "person_add"}</Icon>
</Button>
</Row>
{renderContacts(findContactList)}
{showAddForm ? (
<RecipientList contactListID={findContactList._id} onFinishCreateContact={() => this.handleAddContactBtn()}/>
) : null}
</Fragment>
);
}}
</Query>
);
}
}
export default ManageContact;
And here is the RecipientList component, where mutation to add contacts are performed:
...
import {
createContactMutation,
findContactList,
userContactListQuery
} from "../../../graphql";
class RecipientList extends Component {
state = {
firstName: "",
lastName: "",
email: ""
};
createContact = async () => {
const {
createContactMutation,
contactListID,
onFinishCreateContact
} = this.props;
const { firstName, lastName, email } = this.state;
onFinishCreateContact()
try {
await createContactMutation({
variables: {
contactListID,
firstName,
lastName,
email
},
refetchQueries: [
{ query: userContactListQuery },
{ query: findContactList, variables:{ id: contactListID }}
]
});
} catch (err) {
console.log(err);
}
};
handleInputChange = e => {
this.setState({ [e.target.name]: e.target.value });
};
renderRecipientAddForm = () => {
const { firstName, lastName, email } = this.state;
return (
<Row>
<Col s={3}>
<Input
label="First Name"
name="firstName"
value={`${firstName}`}
onChange={this.handleInputChange}
/>
</Col>
<Col s={3}>
<Input
label="Last Name"
name="lastName"
value={`${lastName}`}
onChange={this.handleInputChange}
/>
</Col>
<Col s={3}>
<Input
label="Email"
name="email"
value={`${email}`}
onChange={this.handleInputChange}
/>
</Col>
<Col s={3}>
<Button onClick={this.createContact}>+</Button>
</Col>
</Row>
);
};
render() {
return <span>{this.renderRecipientAddForm()}</span>;
}
}
export default graphql(createContactMutation, {
name: "createContactMutation"
})(RecipientList);
I have been trying to use refetchqueries but it keeps failing. I know when i console log after the mutation, i get the data being undefined, which is needed for the map operator within ManageContact component.
Any ideas on what i did wrong?