displaying a sucess message using email.js - reactjs

I'm wondering how I can display a "message sent successfully" message after the user has submitted the form?
Any help would be greatly appreciated. Right now the message is sent but there is no success message displayed.
export const Contact = (props) => {
const [{ name, email, message }, setState] = useState(initialState)
const handleChange = (e) => {
const { name, value } = e.target
setState((prevState) => ({ ...prevState, [name]: value }))
}
const clearState = () => setState({ ...initialState })
const handleSubmit = (e) => {
e.preventDefault()
console.log(name, email, message)
emailjs
.sendForm(
'service_8cyr6cf', 'template_0koo5jf', e.target, 'TtcKG0LCV4-mP5FnV'
)
.then(
(result) => {
console.log(result.text)
clearState()
},
(error) => {
console.log(error.text)
}
)
}

emailjs only handles the sending email part. If you want to display something on your UI, you need to create some HTML to display it.
Something like:
export const Contact = (props) => {
const [{ name, email, message }, setState] = useState(initialState)
const [statusMessage, setStatusMessage] = useState("");
const handleChange = (e) => {
const { name, value } = e.target
setState((prevState) => ({ ...prevState, [name]: value }))
}
const clearState = () => setState({ ...initialState })
const handleSubmit = (e) => {
e.preventDefault()
console.log(name, email, message)
emailjs
.sendForm(
'service_8cyr6cf', 'template_0koo5jf', e.target, 'TtcKG0LCV4-mP5FnV'
)
.then(
(result) => {
console.log(result.text, result.status);
clearState();
setStatusMessage("Email sent success");
},
(error) => {
console.log(error.text);
setStatusMessage(`${error.text} happened`);
}
)
}
return
(
<div>
<form></form>
<p>{statusMessage}</p>
</div>
)

Related

user.displayName not showing on react firebase app

const [user, setUser] = useState({});
const [pass, setPass] = useState('')
const [name, setName] = useState('')
const [isLoading, setIsLoading] = useState(true)
const auth = getAuth();
const inputHandler = e => {
setUser(e?.target.value)
}
const passHandler = e => {
setPass(e?.target.value)
}
const nameHandler = e => {
setName(e?.target.value)
}
const toggleLogin = event => {
setIsLogIn(!event.target.checked);
}
const signUpHandler = (e) => {
signUp(user, pass)
.then(result => {
setUserName();
history.push(url)
// console.log(url)
})
.finally(() => {
setIsLoading(false)
})
.catch((error) => {
setError(error.message)
// ..
});
e.preventDefault()
}
const signUp = (user, pass) => {
setIsLoading(true)
return createUserWithEmailAndPassword(auth, user, pass)
}
useEffect(() => {
onAuthStateChanged(auth, (user) => {
if (user) {
setUser(user)
// console.log("auth changed",user.email)
} else {
setUser({})
}
setIsLoading(false)
});
}, [auth])
const setUserName = () => {
updateProfile(auth.currentUser, {
displayName: name
});
Before displayName property being updated its redirecting to the route it came from. Is this happening for asynchronous nature?
I'm trying to set the displayName property on the navbar.displayName is getting set but not showing on ui, but showing after when I refresh the page. How can I fix this issue?

clear all form input box after submit form using reactjs

want to clear all input box form after submit data
here is my code:
function GSetup() {
const [gName, setGName] = useState("");
const dispatch = useDispatch();
useEffect(() => {
dispatch(getGNames());
}, [dispatch]);
const onSubmitHandler = (e) => {
e.preventDefault();
dispatch(
addGName(
{
gn_name: gName,
su_id: userInfo._id
}
)
);
};
return ( ​);
}
I use this setState on onSubmitHandler function but its not working
this.setState({
gn_name: ''
});
try this way
function GSetup() {
const [gName, setGName] = useState("");
const dispatch = useDispatch();
useEffect(() => {
dispatch(getGNames());
}, [dispatch]);
const onSubmitHandler = (e) => {
e.preventDefault();
dispatch(
addGName(
{
gn_name: gName,
su_id: userInfo._id
}
)
);
setGName('')
};
return ( ​);
}
this.setState({}) does not work outside of classComponent

Handle async operation in Redux

I am trying to render post.paragraph coming from the Redux store.
This is the code I am using:
const postDetails = useSelector((state) => state.postDetails);
const { loading, post, error } = postDetails;
const editorContent = post ?
EditorState.createWithContent(convertFromRaw(JSON.parse(post.paragraph))) :
EditorState.createEmpty();
const [editorState, setEditorState] = useState({ editorState: editorContent });
const handleEditorChange = (editorState) => { setEditorState({ editorState }) }
const submitHandler = (e) => {
e.preventDefault();
dispatch(
updatePost({
_id: id,
title,
image,
images,
paragraph: JSON.stringify(
convertToRaw(editorState.editorState.getCurrentContent())
),
})
);
};
<Editor
editorState={editorState.editorState}
onEditorStateChange={handleEditorChange}
/>
Though it seems like it takes time for post.paragraph to display therefore my app fails. In fact, if I console.log(post.paragraph) I get "undefined" twice and only then I get my post.paragraph displayed.
To fix the issue i tried to put everything in an if statement like this:
const postDetails = useSelector((state) => state.postDetails);
const { loading, post, error } = postDetails;
const content = (async (err, res) => {
const editorContent = await post.paragraph;
if (post.paragraph) {
res.send({ editorContent: EditorState.createWithContent(convertFromRaw(JSON.parse(post.paragraph))) });
} else {
res.send({ editorContent: EditorState.createEmpty()});
}
return editorContent;
})
const [editorState, setEditorState] = useState({ editorState: content });
const handleEditorChange = (editorState) => { setEditorState({ editorState }) }
const submitHandler = (e) => {
e.preventDefault();
dispatch(
updatePost({
_id: id,
title,
image,
images,
paragraph: JSON.stringify(
convertToRaw(editorState.editorState.getCurrentContent())
),
})
);
};
<Editor
editorState={editorState.editorState}
onEditorStateChange={handleEditorChange}
/>
But now the error I get is the following:
I also tried the following, but i get the same error:
const postDetails = useSelector((state) => state.postDetails);
const { loading, post, error } = postDetails;
const editorContent = !loading ?
EditorState.createWithContent(convertFromRaw(JSON.parse(post.paragraph))) :
EditorState.createEmpty();
const [editorState, setEditorState] = useState({ editorState: editorContent });
const handleEditorChange = (editorState) => { setEditorState({ editorState }) }
const submitHandler = (e) => {
e.preventDefault();
dispatch(
updatePost({
_id: id,
title,
image,
images,
paragraph: JSON.stringify(
convertToRaw(editorState.editorState.getCurrentContent())
),
})
);
};
<Editor
editorState={editorState.editorState}
onEditorStateChange={handleEditorChange}
/>
How should I tackle this async request? Many thanks!

Refactor a functional component with React hooks

I have several functional components which share the same logic. So I would like to refactor them using React hooks. All of them make some calls to the server on mount to check if the order has been paid. If yes, paid state is set to true , and a file is being downloaded. On submit I check if paid state is set to true, if yes, the same file is being downloaded, if not, a new order is created and a user is being redirected to a page with a payment form.
I have already extracted all functions (getOrder(), getPaymentState(), createOrder(), initPayment() and downloadFile()) which make API calls to the server. How can I further optimize this code, so that I could move checkOrder(), checkPayment(), downloadPDF() and newOrder() outside the component to use the same logic with other components as well?
Here is my component:
const Form = () => {
const [paid, setPaid] = useState(false);
const [submitting, setSubmitting] = useState(false);
const [loading, setLoading] = useState(false);
const [data, setData] = useState({});
const checkOrder = async () => {
let search = new URLSearchParams(window.location.search);
let success = search.get("Success");
if (success) {
try {
const data = await getOrder();
setData(data);
checkPayment(data);
} catch (err) {
alert(err.message)
}
}
};
const checkPayment = async values => {
try {
const paid = await getPaymentState();
setPaid(paid);
downloadPDF(values);
} catch (err) {
alert(err.message)
}
};
const downloadPDF = async values => {
setLoading(true);
let downloadData = {
email: values.email,
phone: values.phone
}
const response = await downloadFile(downloadData, sendURL);
setLoading(false);
window.location.assign(response.pdf);
}
const newOrder = async values => {
setSubmitting(true);
const order = await createOrder(values, description, sum);
const paymentUrl = await initPayment(order, description, sum, returnURL);
setSubmitting(false);
window.location.assign(paymentUrl);
}
const onSubmit = async values => {
if (paid) {
try {
downloadPDF(data);
} catch (err) {
console.log(err);
}
} else {
try {
newOrder(values)
} catch (err) {
alert(err.message)
}
}
};
useEffect(() => {
checkOrder();
}, []);
return (
)
}
EDIT 1: I also need to be able to pass some data to this hook: downloadData, sendURL, description, sum and returnURL, which will be different in each case. downloadData then needs to be populated with some data from the values.
I would appreciate if you could point me at the right direction. I'm just learning React and I would really like to find the correct way to do this.
EDIT 2: I've posted my own answer with the working code based on the previous answers. It's not final, because I still need to move downloadPDF() outside the component and pass downloadData to it, but when I do so, I get an error, that values are undefined. If anybody can help me with that, I will accept it as an answer.
I made a quick refactor of the code and put it in a custom hook, it looks like search param is the key for when the effect needs to run.
const useCheckPayment = (search) => {
const [paid, setPaid] = useState(false);
const [submitting, setSubmitting] = useState(false);
const [loading, setLoading] = useState(false);
const [data, setData] = useState({});
const checkOrder = useCallback(async () => {
let paramSearch = new URLSearchParams(search);
let success = paramSearch.get('Success');
if (success) {
try {
//why not just pass it, makes getOrder a little less impure
const data = await getOrder(paramSearch);
setData(data);
checkPayment(data);
} catch (err) {
alert(err.message);
}
}
}, [checkPayment, search]);
const checkPayment = useCallback(async (values) => {
try {
const paid = await getPaymentState();
setPaid(paid);
downloadPDF(values);
} catch (err) {
alert(err.message);
}
}, []);
const downloadPDF = async (values) => {
setLoading(true);
const response = await downloadFile();
setLoading(false);
window.location.assign(response.pdf);
};
const newOrder = async (values) => {
setSubmitting(true);
const order = await createOrder();
const paymentUrl = await initPayment(order);
setSubmitting(false);
window.location.assign(paymentUrl);
};
const onSubmit = useCallback(
async (values) => {
if (paid) {
try {
downloadPDF(data);
} catch (err) {
console.log(err);
}
} else {
try {
newOrder(values);
} catch (err) {
alert(err.message);
}
}
},
[data, paid]
);
useEffect(() => {
checkOrder();
}, [checkOrder]); //checkOrder will change when search changes and effect is called again
return { onSubmit, submitting, loading };
};
const Form = () => {
const { onSubmit, submitting, loading } = useCheckPayment(
window.location.search
);
return '';
};
You can extract out all the generic things from within the Form component into a custom Hook and return the required values from this hook
The values which are dependencies and will vary according to the component this is being called from can be passed as arguments to the hook. Also the hook can return a onSubmit function to which you can pass on the downloadData
const useOrderHook = ({returnURL, sendURL, }) => {
const [paid, setPaid] = useState(false);
const [submitting, setSubmitting] = useState(false);
const [loading, setLoading] = useState(false);
const [data, setData] = useState({});
const checkOrder = async () => {
let search = new URLSearchParams(window.location.search);
let success = search.get("Success");
if (success) {
try {
const data = await getOrder();
setData(data);
checkPayment(data);
} catch (err) {
alert(err.message)
}
}
};
const checkPayment = async values => {
try {
const paid = await getPaymentState();
setPaid(paid);
downloadPDF(values);
} catch (err) {
alert(err.message)
}
};
const downloadPDF = async values => {
setLoading(true);
let downloadData = {
email: values.email,
phone: values.phone
}
const response = await downloadFile(downloadData, sendURL);
setLoading(false);
window.location.assign(response.pdf);
}
const newOrder = async (values, description, sum) => {
setSubmitting(true);
const order = await createOrder(values, description, sum);
const paymentUrl = await initPayment(order, description, sum, returnURL);
setSubmitting(false);
window.location.assign(paymentUrl);
}
const onSubmit = async ({values, downloadData: data, description, sum}) => {
if (paid) {
try {
downloadPDF(data);
} catch (err) {
console.log(err);
}
} else {
try {
newOrder(values, description, sum)
} catch (err) {
alert(err.message)
}
}
};
useEffect(() => {
checkOrder();
}, []);
return {onSubmit, loading, submitting, paid, data };
}
Now you can use this hook in component like Form as follows
const Form = () => {
const {onSubmit, newOrder, loading, submitting, paid, data } = useOrderHook({returnUrl: 'someUrl', sendURL: 'Some send URL'})
const handleSubmit = (values) => {
// since this function is called, you can get the values from its closure.
const data = {email: values.email, phone: values.phone}
onSubmit({ data, values, description, sum})// pass in the required values for onSubmit here. you can do the same when you actually call newOrder from somewhere
}
// this is how you pass on handleSubmit to React-final-form
return <Form
onSubmit={handleSubmit }
render={({ handleSubmit }) => {
return <form onSubmit={handleSubmit}>...fields go here...</form>
}}
/>
}
Based on the answers above I came up with the following code.
The hook:
const useCheckPayment = ({initialValues, sendUrl, successUrl, description, sum, downloadPDF}) => {
const [paid, setPaid] = useState(false);
const [loading, setLoading] = useState(false);
const [submitting, setSubmitting] = useState(false);
const [data, setData] = useState(initialValues);
const checkOrder = useCallback(
async () => {
let search = new URLSearchParams(window.location.search);
let success = search.get('Success');
if (success) {
try {
const data = await getOrder(search);
setData(data);
checkPayment(search);
} catch (err) {
alert(err.message);
}
}
}, [checkPayment]
);
const checkPayment = useCallback(
async (search) => {
try {
const paid = await getPaymentState(search);
setPaid(paid);
document.getElementById('myForm').dispatchEvent(new Event('submit', { cancelable: true }))
} catch (err) {
alert(err.message);
}
}, []
);
const newOrder = useCallback(
async (values) => {
setSubmitting(true);
const order = await createOrder(values, description, sum);
const paymentUrl = await initPayment(order, description, sum, successUrl);
setSubmitting(false);
window.location.assign(paymentUrl);
}, [description, sum, successUrl]
);
const downloadPDF = async (values, downloadData) => {
setLoading(true);
const response = await downloadFile(downloadData, sendUrl);
setLoading(false);
window.location.assign(response.pdf);
};
const onSubmit = useCallback(
async ({ values, downloadData }) => {
if (paid) {
try {
downloadPDF(values, downloadData);
} catch (err) {
console.log(err);
}
} else {
try {
newOrder(values);
} catch (err) {
alert(err.message);
}
}
},
[paid, downloadPDF, newOrder]
);
useEffect(() => {
checkOrder();
}, [checkOrder]);
return { onSubmit, submitting };
};
The component:
const sendUrl = 'https://app.example.com/send'
const successUrl = 'https://example.com/success'
const description = 'Download PDF file'
const sum = '100'
const Form = () => {
const handleSubmit = (values) => {
const downloadData = {
email: values.email,
phone: values.phone
}
onSubmit({ downloadData, values })
}
const { onSubmit, submitting } = useCheckPayment(
{sendUrl, successUrl, description, sum}
);
return (
<Form
onSubmit={handleSubmit}
render={({ handleSubmit }) => (
<form onSubmit={handleSubmit}></form>
)}
/>
)
}

How to Handle Error using try catch using React State with Arrow functions

I am new to React, I am trying to implement some error validation with a react arrow function but got no luck all day.
The catch works and I can print the errors, but I dont know how to link the errors I am printing inside errorsHandler() to the other const where the form is for styling and warnings.
const errorsHandler= fieldErrors => {
if (fieldErrors) {
fieldErrors.forEach(err => {
const errorFieldName= err.field;
const errorDescription = err.message;
console.log('Field', errorFieldName, 'Description', errorDescription);
// Field name Description name already exists
});
}
};
export const defaultGroupModel = {
description: '',
active: true,
name: '',
}
const GroupFormModal = ({ editId, editGroup, onSave}) => {
const [groupState, setGroupState] = useState(defaultGroupModel);
useEffect(() => {
if (editGroup) {
setGroupState(editGroup);
}
}, [editGroup]);
const handleChange = ({ target: { value, name} }) => {
setGroupState({ ...groupState, [name]: value });
};
return ( (...) <Form onSubmit={e => onSave(e, groupState)} onReset={onReset}> (...);
};
const mapDispatchToProps = dispatch => ({
onSave: (e, group) => {
e.preventDefault();
if (group.id) {
dispatch(updateGroup(group));
} else {
dispatch(createGroup(group)).catch(error => {
errorsHandler(error.data.fieldErrors);
});
}
},
});
export default connect(
mapStateToProps,
mapDispatchToProps,
)(GroupFormModal);
I have tried to create an [errorState, setErrorState] and use useEffect inside the errorsHandler but get Invalid Hook. How can I have the handle inside the catch to be in the same context as the form ?
Thank you in advance
There are few things you can do here. First, use mapDispatchToProps to wrap inside dispatch your action's creators (without then and catch)
const mapDispatchToProps = dispatch =>({
updateGroup : group => dispatch(updateGroup(group)),
createGroup : group => dispatch(createGroup(group))
})
Now you can set an internal state to reflect those errors
const Component = ({ updateGroup, createGroup }) =>{
const [errors, setErrors] = useState(false)
const onSave = (group,e) =>{
createGroup(group)
.then(res => console.log('everything ok'))
.catch(err => setError(err) /* now you have the errors inside your component*/)
}
return <form onSubmit={ e => onSave(group,e)) }> /*...*/ </form>
}

Resources