Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#2697 captcha to feedback from submission #2792

Merged
merged 18 commits into from
Sep 1, 2022
4 changes: 2 additions & 2 deletions verification/curator-service/api/openapi/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1125,14 +1125,14 @@ paths:
post:
summary: Sends feedback email to global.health
tags: [User]
operationId: feeback
operationId: feedback
requestBody:
description: Email and message of User
required: true
content:
application/json:
schema:
description: Message send to global.health sa feedback
description: Message sent to global.health as feedback
type: object
properties:
message:
Expand Down
11 changes: 8 additions & 3 deletions verification/curator-service/api/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -411,16 +411,21 @@ async function makeApp() {
const { message } = req.body;

try {
emailClient.send(
await emailClient.send(
[env.EMAIL_USER_ADDRESS],
'Feedback regarding Covid-19 curator portal',
message,
);
res.status(200).send({ message: 'Email sent successfully' });
return res
.status(200)
.json({ message: 'Email sent successfully' });
} catch (err) {
const error = err as Error;
logger.error(error);
return res.sendStatus(500);
return res.status(500).json({
message:
'Unfortunately, an error occurred. Please, try again later.',
});
}
},
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, { useEffect, useState } from 'react';
import Button from '@material-ui/core/Button';
import TextField from '@material-ui/core/TextField';
import Dialog from '@material-ui/core/Dialog';
Expand All @@ -8,14 +8,14 @@ import DialogContentText from '@material-ui/core/DialogContentText';
import DialogTitle from '@material-ui/core/DialogTitle';
import { useFormik } from 'formik';
import * as Yup from 'yup';
import { useStyles } from './styled';
import axios from 'axios';
import { useAppSelector } from '../../hooks/redux';
import { selectUser } from '../../redux/auth/selectors';
import { SnackbarAlert } from '../SnackbarAlert/index';

interface FeedbackEmailDialogProps {
isOpen: boolean;
handleClose: () => void;
closeFeedbackModal: () => void;
}

export interface FeedbackFormValues {
Expand All @@ -25,13 +25,27 @@ export interface FeedbackFormValues {

const FeedbackEmailDialog = ({
isOpen,
handleClose,
closeFeedbackModal,
}: FeedbackEmailDialogProps): JSX.Element => {
const classes = useStyles();
const user = useAppSelector(selectUser);

const maxSizeMessage = 800;

const [alertInformationOpen, setAlertInformationOpen] =
useState<boolean>(false);
const [alertInformationMessage, setAlertInformationMessage] =
useState<string>('');
const [alertInformationType, setAlertInformationType] = useState<
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In cases like this you can also add all those state variables under one state object. This way you later have to only call setState once providing all the values instead of three times

'success' | 'error' | ''
>('');

useEffect(() => {
return () => {
formik.setErrors({});
};
// eslint-disable-next-line
}, [isOpen]);

const validationFormSchema = Yup.object().shape({
message: Yup.string()
.max(maxSizeMessage, 'Message is too long.')
Expand All @@ -46,25 +60,40 @@ const FeedbackEmailDialog = ({
validateOnChange: true,
onSubmit: async (values) => {
try {
const response = await axios.post('/feedback', {
message: `From: ${user?.email}<br><br>${values.message}`,
});
console.log(response);
await axios
.post('/feedback', {
message: `From: ${user?.email}<br><br>${values.message}`,
})
.then((response) => {
setAlertInformationType('success');
setAlertInformationMessage(response.data.message);
setAlertInformationOpen(true);
});
} catch (error) {
console.error(error);
setAlertInformationMessage(
error.response.data.message ||
'Unfortunately, an error occurred. Please, try again later.',
);
setAlertInformationType('error');
setAlertInformationOpen(true);
throw error;
}

handleClose();
closeFeedbackModal();
},
});

// -------------------
// isOpen = true;
// -------------------
return (
<div>
<Dialog open={isOpen} onClose={handleClose} fullWidth maxWidth="md">
<>
<Dialog
open={isOpen}
onClose={closeFeedbackModal}
fullWidth
maxWidth="md"
>
<DialogTitle>Send Feedback</DialogTitle>
<DialogContent>
<form onSubmit={formik.handleSubmit}>
Expand Down Expand Up @@ -92,13 +121,20 @@ const FeedbackEmailDialog = ({
/>
</DialogContentText>
<DialogActions>
<Button onClick={handleClose}>Cancel</Button>
<Button onClick={closeFeedbackModal}>Cancel</Button>
<Button type="submit">Send</Button>
</DialogActions>
</form>
</DialogContent>
</Dialog>
</div>
<SnackbarAlert
isOpen={alertInformationOpen}
onClose={() => setAlertInformationOpen(false)}
message={alertInformationMessage}
type={alertInformationType || 'info'}
durationMs={4000}
/>
</>
);
};

Expand Down

This file was deleted.

10 changes: 5 additions & 5 deletions verification/curator-service/ui/src/components/Footer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ const Footer = ({ drawerOpen }: FooterProps): JSX.Element => {
const classes = useStyles();
const [feedbackModalOpen, setFeedbackModalOpen] = useState(false);

const handleClickOpen = () => {
const openFeedbackModal = () => {
setFeedbackModalOpen(true);
};

const handleClose = () => {
const closeFeedbackModal = () => {
setFeedbackModalOpen(false);
};

Expand Down Expand Up @@ -122,14 +122,14 @@ const Footer = ({ drawerOpen }: FooterProps): JSX.Element => {
<Typography
display="inline"
className={classes.feedbackButton}
onClick={() => handleClickOpen()}
onClick={openFeedbackModal}
>
Feedback
</Typography>
<FeedbackEmailDialog
isOpen={feedbackModalOpen}
handleClose={handleClose}
></FeedbackEmailDialog>
closeFeedbackModal={closeFeedbackModal}
/>
</section>
</footer>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,6 @@ export const useStyles = makeStyles((theme: Theme) => ({
fontSize: '14px',
margin: '0 20px',
color: theme.palette.primary.main,
'&:hover': {
cursor: 'pointer',
},
cursor: 'pointer',
},
}));
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,27 @@ beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());

jest.mock('react-google-recaptcha', () => {
const React = require('react');
const RecaptchaV2 = React.forwardRef((props, ref) => {
React.useImperativeHandle(ref, () => ({
reset: jest.fn(),
execute: jest.fn(),
executeAsync: jest.fn(() => 'token'),
}));
return (
<input
ref={ref}
type="checkbox"
data-testid="mock-v2-captcha-element"
{...props}
/>
);
});

return RecaptchaV2;
});

describe('<LandingPage />', () => {
test('shows all content', async () => {
render(<LandingPage />);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,17 +97,23 @@ export default function SignInForm({
},
validationSchema,
onSubmit: async (values) => {
const token =
(await recaptchaRef.current?.executeAsync()) as string;
recaptchaRef.current?.reset();
if (!recaptchaRef.current) return;

dispatch(
signInWithEmailAndPassword({
email: values.email,
password: values.password,
token,
}),
);
// eslint-disable-next-line no-useless-catch
try {
const token =
(await recaptchaRef.current.executeAsync()) as string;
recaptchaRef.current.reset();
dispatch(
signInWithEmailAndPassword({
email: values.email,
password: values.password,
token,
}),
);
} catch (error) {
throw error;
}
},
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { useFormik } from 'formik';
import * as Yup from 'yup';
import { useAppDispatch } from '../../hooks/redux';
import { signUpWithEmailAndPassword } from '../../redux/auth/thunk';

import { makeStyles, Theme } from '@material-ui/core/styles';
import FormControlLabel from '@material-ui/core/FormControlLabel';
import FormHelperText from '@material-ui/core/FormHelperText';
Expand Down Expand Up @@ -154,20 +153,25 @@ export default function SignUpForm({
},
validationSchema,
onSubmit: async (values) => {
maciej-zarzeczny marked this conversation as resolved.
Show resolved Hide resolved
if (!recaptchaRef.current) return;
const { email, password, isNewsletterChecked } = values;
// eslint-disable-next-line no-useless-catch
try {
const token =
(await recaptchaRef.current.executeAsync()) as string;
recaptchaRef.current.reset();

const token =
(await recaptchaRef.current?.executeAsync()) as string;
recaptchaRef.current?.reset();

dispatch(
signUpWithEmailAndPassword({
email,
password,
newsletterAccepted: isNewsletterChecked,
token,
}),
);
dispatch(
signUpWithEmailAndPassword({
email,
password,
newsletterAccepted: isNewsletterChecked,
token,
}),
);
} catch (error) {
throw error;
}
},
});

Expand Down