aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authoreug-vs <eug-vs@keemail.me>2020-12-04 03:19:16 +0300
committereug-vs <eug-vs@keemail.me>2020-12-04 03:19:16 +0300
commitef7a52434e5b6fbfb9c31af0172861a9e2bb0351 (patch)
treeefc6659168092e65b5fc1074c1e3b65e36c420ac /src
parent43e81090ef8301b326f9721251bad1fe10ab18f8 (diff)
downloadfamcs-kit-ef7a52434e5b6fbfb9c31af0172861a9e2bb0351.tar.gz
feat: validate form with yup
Diffstat (limited to 'src')
-rw-r--r--src/containers/BsuFantomSection/EventForm.tsx49
1 files changed, 47 insertions, 2 deletions
diff --git a/src/containers/BsuFantomSection/EventForm.tsx b/src/containers/BsuFantomSection/EventForm.tsx
index 09bb87b..9fc18b5 100644
--- a/src/containers/BsuFantomSection/EventForm.tsx
+++ b/src/containers/BsuFantomSection/EventForm.tsx
@@ -1,6 +1,9 @@
import React from 'react';
-import { Grid, TextField, Button } from '@material-ui/core';
+import _ from 'lodash';
+import cronstrue from 'cronstrue';
+import * as Yup from 'yup';
import { Formik, Form, Field } from 'formik';
+import { Grid, TextField, Button, Link } from '@material-ui/core';
import { post } from '../../requests';
import { Event } from '../../types';
@@ -15,7 +18,36 @@ interface Fields {
conferenceId: string;
}
+const describeCrontab = (crontab: string) => {
+ try {
+ return cronstrue.toString(crontab);
+ } catch {
+ return false;
+ }
+};
+
+const validationSchema = Yup.object({
+ name: Yup.string().required('This field is required'),
+ conferenceId: Yup.string().required('This field is required'),
+ attendanceId: Yup.string(),
+ schedule: Yup.string()
+ .required('This field is required')
+ .test('cron', 'Invalid crontab', value => !!describeCrontab(value || ''))
+});
+
const EventForm: React.FC<PropTypes> = ({ mutate }) => {
+
+ const describeSchedule = (schedule: string) => {
+ const description = describeCrontab(schedule);
+ if (description) return `Event will run ${_.lowerFirst(description)}`;
+ const link = <Link href="https://crontab.guru">crontab.guru</Link>;
+ return (
+ <>
+ The schedule is invalid. Check out {link} for more help with cron scheduling.
+ </>
+ );
+ };
+
const handleSubmit = (fields: Fields, { resetForm }: any) => {
const { name, schedule, attendanceId, conferenceId } = fields;
@@ -41,9 +73,10 @@ const EventForm: React.FC<PropTypes> = ({ mutate }) => {
return (
<Formik
initialValues={{ name: '', schedule: '* * * * *', attendanceId: '', conferenceId: '' }}
+ validationSchema={validationSchema}
onSubmit={handleSubmit}
>
- {({ values, errors, touched, isSubmitting }) => (
+ {({ values, errors, touched, isValid }) => (
<Form autoComplete="off">
<Grid container spacing={2}>
<Grid item sm={6} xs={12}>
@@ -51,6 +84,8 @@ const EventForm: React.FC<PropTypes> = ({ mutate }) => {
name="name"
label="Name"
value={values.name}
+ error={touched.name && !!errors.name}
+ helperText={touched.name && errors.name}
variant="outlined"
fullWidth
required
@@ -62,6 +97,10 @@ const EventForm: React.FC<PropTypes> = ({ mutate }) => {
name="schedule"
label="Schedule"
value={values.schedule}
+ error={touched.schedule && !!errors.schedule}
+ helperText={
+ (touched.schedule && errors.schedule) || "Should be a valid crontab, for example: 30 12 * * Mon"
+ }
variant="outlined"
fullWidth
required
@@ -73,6 +112,8 @@ const EventForm: React.FC<PropTypes> = ({ mutate }) => {
name="conferenceId"
label="Conference ID"
value={values.conferenceId}
+ error={touched.conferenceId && !!errors.conferenceId}
+ helperText={touched.conferenceId && errors.conferenceId}
variant="outlined"
fullWidth
required
@@ -89,9 +130,13 @@ const EventForm: React.FC<PropTypes> = ({ mutate }) => {
as={TextField}
/>
</Grid>
+ <Grid item xs={12}>
+ {describeSchedule(values.schedule)}
+ </Grid>
<Grid item sm={2} xs={12}>
<Button
type="submit"
+ disabled={!isValid}
variant="contained"
size="large"
color="primary"