onValidated is not a function when trying to subscribe user to mailchimp - javascript

I am using "react-mailchimp-subscribe" to integrate with MailChimp and enable users to signup to a mailchimp mailing list upon completing an submitting my form.
However, I get the error:
Uncaught TypeError: onValidated is not a function
When I trigger the function that should submit the form info to MailChimp.
Here is a sample of my code:
import MailchimpSubscribe from "react-mailchimp-subscribe";
...
const CustomForm = ({
className,
topOuterDivider,
bottomOuterDivider,
topDivider,
bottomDivider,
hasBgColor,
invertColor,
split,
status,
message,
onValidated,
...props
}) => {
...
const [email, setEmail] = useState('');
const [fullName, setFullName] = useState('');
const handleSubmit = (e) => {
console.log('handlesubmit triggered')
e.preventDefault();
email &&
fullName &&
email.indexOf("#") > -1 &&
onValidated({
EMAIL: email,
MERGE1: fullName,
});
}
...
<form onSubmit={(e) => handleSubmit(e)}>
<h3>
{status === "success"
? "You have successfully joined the mailing list"
: "Join our mailing list by completing the form below"
}
</h3>
<div className="cta-action">
<Input
id="email"
type="email"
label="Subscribe"
labelHidden hasIcon="right"
placeholder="Your email address"
onChange={e => setEmail(e.target.value)}
value={email}
isRequired
>
</Input>
<Input
id="name"
type="text"
label="Subscribe"
labelHidden hasIcon="right"
placeholder="Your full name"
onChange={e => setFullName(e.target.value)}
value={fullName}
isRequired
>
</Input>
<Input
type="submit"
formValues={[email, fullName]}
/>
</div>
</form>
This is the parent component passing down props to the above:
import React from "react";
import MailchimpSubscribe from "react-mailchimp-subscribe";
const MailchimpFormContainer = props => {
const postURL = `https://*li$%.list-manage.com/subscribe/post?u=${process.env.REACT_APP_MAILCHIMP_U}$id=${process.env.REACT_APP_MAILCHIMP_ID}`;
return (
<div>
<MailchimpSubscribe
url={postURL}
render={({ subscribe, status, message }) => (
<CustomForm
status={status}
message={message}
onValidated={ formData => subscribe(formData) }
/>
)}
/>
</div>
);
};

Related

How to display User name in profile page - react / firebase

I have made a signup/login/logout page which works perfectly fine, however I wanted to add an additional field in the register page for user name, and I wanted the username to display in the profile page.
I was able to inset the username field into the register page, and I have a name section on the profile page which also shows up when the profile page loads, however, when I input a user name in the register page, it does not appear in the profile page.
Can anyone please help me figure this out? I really appreciate the help everyone. My first post here :) just recently started my developer journey
// register.js
import { useState } from "react";
import "./forms.css";
import { auth } from "./firebase";
import { useNavigate, Link } from "react-router-dom";
import {
createUserWithEmailAndPassword,
sendEmailVerification,
} from "firebase/auth";
import { useAuthValue } from "./AuthContext";
function Register() {
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
const [error, setError] = useState("");
const navigate = useNavigate();
const { setTimeActive } = useAuthValue();
const validatePassword = () => {
let isValid = true;
if (password !== "" && confirmPassword !== "") {
if (password !== confirmPassword) {
isValid = false;
setError("Passwords does not match");
}
}
return isValid;
};
const register = (e) => {
e.preventDefault();
setError("");
if (validatePassword()) {
// Create a new user with email and password using firebase
createUserWithEmailAndPassword(auth, email, password)
.then(() => {
sendEmailVerification(auth.currentUser)
.then(() => {
setTimeActive(true);
navigate("/verify-email");
})
.catch((err) => alert(err.message));
})
.catch((err) => setError(err.message));
}
setName("");
setEmail("");
setPassword("");
setConfirmPassword("");
};
return (
<div className="center">
<div className="auth">
<h1>Register Account</h1>
{error && <div className="auth__error">{error}</div>}
<form onSubmit={register} name="registration_form">
<input
type="name"
value={name}
placeholder="Enter your user name"
required
onChange={(e) => setName(e.target.value)}
/>
<input
type="email"
value={email}
placeholder="Enter your email"
required
onChange={(e) => setEmail(e.target.value)}
/>
<input
type="password"
value={password}
required
placeholder="Enter your password"
onChange={(e) => setPassword(e.target.value)}
/>
<input
type="password"
value={confirmPassword}
required
placeholder="Confirm password"
onChange={(e) => setConfirmPassword(e.target.value)}
/>
<button type="submit">Register</button>
</form>
<span>
Already have an account?
<Link to="/login">login</Link>
</span>
</div>
</div>
);
}
export default Register;
import "./profile.css";
import { useAuthValue } from "./AuthContext";
import { signOut } from "firebase/auth";
import { auth } from "./firebase";
function Profile() {
const { currentUser } = useAuthValue();
return (
<div className="center">
<div className="profile">
<h1>Profile</h1>
<p>
<strong>Name: </strong>
{currentUser?.name}
</p>
<p>
<strong>Email: </strong>
{currentUser?.email}
</p>
<p>
<strong>Email verified: </strong>
{`${currentUser?.emailVerified}`}
</p>
<span onClick={() => signOut(auth)}>Sign Out</span>
</div>
</div>
);
}
export default Profile;

how to avoid execute two button click functions from one button click?

I'm trying to implement a toggle function to users sign in and sign up with two buttons (button 1, button 2). Problem is that regardless of which button I click it executes the toggle function. It seems one button click executes both onclick functions.
import React, { useEffect, useState } from "react";
import LockIcon from "#mui/icons-material/Lock";
import VisibilityIcon from "#mui/icons-material/Visibility";
import { GoogleLogin } from "#react-oauth/google";
import jwt_decode from "jwt-decode";
import { useDispatch } from "react-redux";
import { useNavigate } from "react-router-dom";
import "./authStyles.css";
import { signUp, signIn } from "../../action/auth/authAction";
const initialStateForm = {
fName: "",
lName: "",
email: "",
password: "",
confirmPassword: "",
};
const Auth = () => {
const [showPassword, setShowPassword] = useState(true);
const [isSignup, setIsSignup] = useState(false);
const [formData, setFormData] = useState(initialStateForm);
const dispatch = useDispatch();
const navigate = useNavigate();
const switchMode = () => {
setIsSignup((prevIsSignup) => !prevIsSignup);
setShowPassword(false);
console.log("switchMode " + isSignup);
};
const handleSubmit = (e) => {
e.preventDefault();
console.log("handleSubmit " + isSignup);
// if (isSignup) {
// dispatch(signUp(formData));
// } else {
// dispatch(signIn(formData));
// }
};
const handleChnage = (e) => {
e.preventDefault();
setFormData({ ...formData, [e.target.name]: e.target.value });
};
const handleShowPassword = () => {
setShowPassword((prevShowPassword) => !prevShowPassword);
};
const googleSuccess = async (res) => {
const decodeUser = jwt_decode(res.credential);
dispatch({ type: "AUTH", payload: decodeUser });
navigate("/");
};
const googleFailure = (error) => {
console.log(error);
console.log("Google sign in is unsuccessfull");
};
return (
<div>
<div className="sign-form-container">
<LockIcon></LockIcon>
<span>{isSignup ? `Sign Up` : `Sign In`}</span>
{isSignup && (
<>
<input
type="text"
id="fName"
name="fName"
placeholder="First Name"
onChange={handleChnage}
/>
<input
type="text"
id="lName"
name="lName"
placeholder="Last Name"
onChange={handleChnage}
/>
</>
)}
<input
type="email"
id="email"
name="email"
placeholder="Email"
onChange={handleChnage}
/>
<input
type={showPassword ? `password` : `text`}
id="password"
name="password"
placeholder="Password"
onChange={handleChnage}
/>
<VisibilityIcon onClick={handleShowPassword} />
{isSignup && (
<>
<input
type="password"
id="confirmPassword"
name="confirmPassword"
placeholder="Confirm password"
onChange={handleChnage}
/>
</>
)}
<GoogleLogin
onSuccess={googleSuccess}
onFailure={googleFailure}
cookiePolicy="single_host_origin"
></GoogleLogin>
<button type="button" onClick={handleSubmit}> //button 1
{isSignup ? `Sign Up` : `Sign In`}
</button>
<button type="button" onClick={switchMode}> // button 2
{isSignup
? "Already have an account ? Sign In"
: "Don't have and account? Sign Up"}
</button>
</div>
</div>
);
};
export default Auth;
One button needs to execute the respective function only. Not both functions. How to avoid this problem?
Try to nest the elements into a form and declare the first button as type=submit:
return (
<div>
<form className='sign-form-container' onSubmit={handleSubmit}>
...
<button type='submit'>
{isSignup ? `Sign Up` : `Sign In`}
</button>
<button type='button' onClick={switchMode}>
{isSignup
? 'Already have an account ? Sign In'
: "Don't have and account? Sign Up"}
</button>
</form>
</div>
);

where to call the Axios post request in reactjs

I have a form,thats data are saved in the state to be sent to the backend server.
i am handling the form with handleSubmit function and useEffect hook, where the handleSubmit prevents the form from being submitted unless it calls the validation function, in the useEffect I check if there are any errors using if condition and then console.log my data.
now I want to post the data hold in the state -the state is sent as a props to me- but I am confused whether to put the request in the HandleSubmit function or in the useEffect inside the body of the if condition.
import react, { Component, useState, useEffect } from 'react';
import {useNavigate } from 'react-router-dom';
import axios from 'axios';
import './sign.css';
const SignA = (props) => {
const navigate = useNavigate();
const [formErrors, setFormErrors] = useState({});
const [isSubmit, setIsSubmit] = useState(false);
const handleSubmit = (err) => {
err.preventDefault();
setFormErrors(validate(props.data));
setIsSubmit(true);
}
useEffect(() => {
console.log(Object.keys(formErrors).length);
if (Object.keys(formErrors).length === 0 && isSubmit) {
console.log('console the props data', props.data)
//here is where I think the post request should be put
if (isSubmit) {
return (navigate('/profileadmin'))
}
}
}, [formErrors])
const validate = (values) => {
const errors = {};
const regex = /^[^\s#]+#[^\s#]+\.[^\s#]{2,}$/i;
if (!values.firstname) {
errors.firstname = 'firstname is required!';
}
if (!values.lastname) {
errors.lastname = 'lastname is required!';
}
if (!values.mobile) {
errors.mobile = 'mobile is required!';
}
if (!values.email) {
errors.email = 'email is required!';
} else if (!regex.test(values.email)) {
errors.email = 'this is not a valid email format!'
}
return errors;
}
return (
<div className='signup'>
<form onSubmit={handleSubmit} >
<div className="container">
<h1>Sign Up</h1>
<div className="name">
<div>
<input
type="text"
placeholder="First name"
name="firstname"
id='firstName'
value={props.data.firstname}
onChange={props.change}
/>
</div>
<div>
<input
type="text"
placeholder="Last name"
name="lastname"
value={props.data.lastname}
onChange={props.change}
/>
</div>
</div>
<p className='errorMsg'>{formErrors.firstname}</p>
<p className='errorMsg'>{formErrors.lastname}</p>
<br />
<div>
<input
type="text"
placeholder="Business mobile number"
name="mobile"
value={props.data.mobile}
onChange={props.change}
/>
<p className='errorMsg'>{formErrors.mobile}</p>
<br />
<input
type="text"
placeholder="Email Adress"
name="email"
value={props.data.email}
onChange={props.change}
/>
<p className='errorMsg'>{formErrors.email}</p>
<br />
</div>
</div>
<br />
<div className="checkbox">
<label>
<input type="checkbox" className="check" />i’ve read and agree with <a href="url" >Terms of service</a>
</label>
</div>
<div className="clearfix">
<button type="submit" className="signupbtn">Sign Up</button>
</div>
</div>
</form >
</div >
)
}
export default SignA;
this is the request
axios.post('', props.data)
.then(res => console.log('post res', res))
.catch(error => {
console.error('There was an error in post request!', error);
});
You don't necessarily need useEffect here.
Here is how you can implement such thing:
Declare a state to hold form values:
const [formData, setFormData] = useState({})
Declare function to set the state:
const handleChange = (name, value) => {
setFormData({...formData, [name]: value})
}
Input onChange to capture:
// handleChange has two parameters
<input
type="text"
placeholder="First name"
name="firstname"
id='firstName'
value={props.data.firstname}
onChange={(event) => handleChange('firstName', event.target.value)}
/>
function for calling post axios post request
const handleSubmit = () => {
//check for validations code here
// if validations are right then post request here
// this will give you all the fields like firstName: "", lastName: ""
let requestBody = {
...formData
}
axios.post("url", requestBody).then((res)=> {
//your code here
})
}

Prevent to send form if there is an error

A sandbox with my components : https://codesandbox.io/s/fancy-star-7gite
Hello, I've tried to code in React.js a contact form which check if values of inputs are good and send it to a mailbox via email.js. Sample of the validation's file(validateInfo.jsx):
if(!values.email) {
errors.email= "Enter an e-mail";
} else if (!/\S+#\S+\.\S+/.test(values.email)){
errors.email= "Enter a valid email";
}
But at the submission of the form even if the values are wrong, it sends the form. I want to prevent it.
To transport the form to a mailbox I've created a hook to manage the sending of the information in the form (useContact.jsx):
import {useState, useEffect} from 'react'
import emailjs from "emailjs-com";
import {template} from "./template";
import {userId} from "./userid";
export const useContact = (callback, validate) => {
const [values, setValues] = useState({
email:'',
emailConf:'',
userName:'',
phone:'',
})
const [errors, setErrors] = useState({})
const [isSubmitting, setIsSubmitting] = useState(false)
const handleChange = e =>{
const {name, value}= e.target
setValues({
...values,
[name]: value
})
}
function handleSubmit(e) {
e.preventDefault()
setIsSubmitting(true)
setErrors(validate(values))
emailjs.sendForm('gmail', template, e.target, userId)
.then((result) => {
console.log(result)
}, (errors) => {
console.log(errors);
});
e.target.reset();
localStorage.clear();
}
useEffect(() =>{
if(Object.keys(errors).length === 0 && isSubmitting)
{
callback();
}
},[errors])
return {handleChange, handleSubmit, values, errors};
}
The form (ContactInfo.jsx):
import './Contact.css';
import { useContact } from "./useContact";
import validate from './validateInfo';
export default function ContactInfo({submitForm}) {
const {handleChange, values, handleSubmit, errors}
= useContact(
submitForm,
validate
)
return (<>
<div className="contact-container">
<div className="contactForm" >
<form className="Contact" onSubmit={handleSubmit} >
<input
id="email"
name="email"
type="email"
value={values.email}
onChange={handleChange}
className="form-input"
placeholder="E-mail"
minLength= '5'
maxLength ='50'
autoComplete="off"/>
{errors.email && <p> {errors.email} </p>}
<input
name="emailConf"
id="emailConf"
type="email"
value={values.emailConf}
onChange={handleChange}
className="form-input"
minLength= '5'
maxLength='50'
autoComplete="off"
placeholder="E-mail confirmation"/>
{errors.emailConf && <p> {errors.emailConf} </p>}
<input
name="userName"
id="userName"
value={values.userName}
onChange={handleChange}
className="form-input"
maxLength='50'
autoComplete="off"
placeholder="Name"/>
<input
name="phone"
id="phone"
type="tel"
value={values.phone}
onChange={handleChange}
className="form-input"
maxLength='10'
autoComplete="off"
placeholder="Phone Number"/>
{errors.phone && <p> {errors.phone} </p>}
<textarea
className="message"
name="message"
maxLength='500'
placeholder="Write your message here..." />
<button className="submit-Btn" type="submit">
Send
</button>
</form>
</div>
</div>
</>
);
}
Thank you for helping me if you want more informations tell me =).
You are missing a condition in submit method. You are not validating whether there is any error in validation. It should be as follows. Updated the codesandbox as well
function handleSubmit(e) {
e.preventDefault();
setIsSubmitting(true);
setErrors(validate(values));
if (validate(values) === {}) {
emailjs.sendForm("gmail", template, e.target, userId).then(
(result) => {
console.log(result);
},
(errors) => {
console.log(errors);
}
);
e.target.reset();
localStorage.clear();
}
}

disable form submit button until user checks recaptcha checkbox

I'm trying to disable my form's submit button until the user clicks the Google Recaptcha checkbox 'I am not a robot'
Is there anyway to do this or do I need to download a React component specific to Google Recaptcha?
Here is my simple component that contains the Google Recaptcha:
const RecaptchaComponent = () => {
useEffect(() => {
// Add reCaptcha
const script = document.createElement("script");
script.src = "https://www.google.com/recaptcha/api.js"
document.body.appendChild(script);
}, [])
return (
<div
className="g-recaptcha"
data-sitekey="6LeS8_IdfdfLtQzwUgNV4545454lhvglswww14U"
></div>
)
};
And here is my form's onSubmit code:
const GameForm = () => (
<div className="app">
<Formik
initialValues={{
email: "",
name: "",
title: ""
}}
onSubmit={(values) => {
//new Promise(resolve => setTimeout(resolve, 500));
axios({
method: "POST",
url: "api/gameform",
data: JSON.stringify(values),
});
}}
>
{props => {
const {
values,
isSubmitting,
handleSubmit,
} = props;
return (
<form onSubmit={handleSubmit}>
<div>Your Game</div>
<label htmlFor="title">
Game Title:
</label>
<Field
id="title"
type="text"
values={values.title}
/>
<label htmlFor="name">
Name:
</label>
<Field
id="name"
type="text"
value={values.name}
/>
<label htmlFor="email">
Email:
</label>
<Field
id="email"
name="email"
type="email"
value={values.email}
/>
<div>
<ReCAPTCHA
sitekey="6LeS8_IUAAAAAhteegfgwwewqe223"
onChange={useCallback(() => setDisableSubmit(false))}
/>
</div>
<div>
<Button type="submit">
Submit
</Button>
</div>
</form>
);
}}
</Formik>
</div>
);
You don't need to use the react component, but it's easier.
export const MyForm = () => {
const [disableSubmit,setDisableSubmit] = useState(true);
return (
... rest of your form
<ReCAPTCHA
sitekey="6LeS8_IdfdfLtQzwUgNV4545454lhvglswww14U"
onChange={useCallback(() => setDisableSubmit(false))}
/>
<button type="submit" disabled={disableSubmit}>Submit</button>
)
}
EDIT:
One of my biggest pet peeves is seeing React tutorials where authors encourage devs to use functions that return JSX instead of just using functional components.
Formik's "children as a function" pattern is gross (react-router-dom does the same thing) - it should be a component:
const GameForm = () => {
return <Formik ...your props>{props => <YourForm {...props}/>}</Formik>
}
const YourForm = (props) => {
const [disableSubmit,setDisableSubmit] = useState(true);
... everything inside the child function in `GameForm`
}

Categories

Resources