Skip to content

Commit

Permalink
BHBC-866: Date improvements (#134)
Browse files Browse the repository at this point in the history
  • Loading branch information
NickPhura authored Mar 17, 2021
1 parent 54d22e1 commit a74d15f
Show file tree
Hide file tree
Showing 11 changed files with 103 additions and 25 deletions.
4 changes: 2 additions & 2 deletions app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@
"@material-ui/lab": "latest",
"@material-ui/pickers": "~3.2.10",
"@material-ui/styles": "~4.10.0",
"@mdi/js": "^5.9.55",
"@mdi/react": "^1.4.0",
"@mdi/js": "~5.9.55",
"@mdi/react": "~1.4.0",
"@react-keycloak/web": "~2.1.0",
"@react-leaflet/core": "~1.0.2",
"@rjsf/core": "~2.4.1",
Expand Down
14 changes: 13 additions & 1 deletion app/src/constants/dateFormats.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
// See BC Gov standards: https://www2.gov.bc.ca/gov/content/governments/services-for-government/policies-procedures/web-content-development-guides/writing-for-the-web/web-style-guide/numbers
/**
* Date formats.
*
* See BC Gov standards: https://www2.gov.bc.ca/gov/content/governments/services-for-government/policies-procedures/web-content-development-guides/writing-for-the-web/web-style-guide/numbers
*/
export enum DATE_FORMAT {
ShortDateFormat = 'YYYY-MM-DD', //2020-01-05
ShortDateTimeFormat = 'YYYY-MM-DD, H:mm a', //2020-01-05, 3:30 pm
Expand All @@ -9,3 +13,11 @@ export enum DATE_FORMAT {
LongDateFormat = 'dddd, MMMM D, YYYY, H:mm a', //Monday, January 5, 2020, 3:30 pm
LongDateTimeFormat = 'dddd, MMMM D, YYYY, H:mm a' //Monday, January 5, 2020, 3:30 pm
}

/**
* Used to set the `min` and `max` values for `type="date"` fields.
*/
export enum DATE_LIMIT {
min = '1900-01-01',
max = '2100-12-31'
}
12 changes: 8 additions & 4 deletions app/src/features/projects/components/ProjectCoordinatorForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,14 @@ export const ProjectCoordinatorInitialValues: IProjectCoordinatorForm = {
};

export const ProjectCoordinatorYupSchema = yup.object().shape({
first_name: yup.string().required('Required'),
last_name: yup.string().required('Required'),
email_address: yup.string().email('Must be a valid email address').required('Required'),
coordinator_agency: yup.string().required('Required'),
first_name: yup.string().max(50, 'Cannot exceed 50 characters').required('Required'),
last_name: yup.string().max(50, 'Cannot exceed 50 characters').required('Required'),
email_address: yup
.string()
.max(500, 'Cannot exceed 500 characters')
.email('Must be a valid email address')
.required('Required'),
coordinator_agency: yup.string().max(300, 'Cannot exceed 300 characters').required('Required'),
share_contact_details: yup.string().required('Required')
});

Expand Down
12 changes: 7 additions & 5 deletions app/src/features/projects/components/ProjectDetailsForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ import { FormControl, FormHelperText, Grid, InputLabel, MenuItem, Select, TextFi
import MultiAutocompleteFieldVariableSize, {
IMultiAutocompleteFieldOption
} from 'components/fields/MultiAutocompleteFieldVariableSize';
import { DATE_LIMIT } from 'constants/dateFormats';
import { useFormikContext } from 'formik';
import React from 'react';
import { getEndDateStringValidator, getStartDateStringValidator } from 'utils/YupValidations';
import * as yup from 'yup';

export interface IProjectDetailsForm {
Expand All @@ -26,12 +28,10 @@ export const ProjectDetailsFormInitialValues: IProjectDetailsForm = {
};

export const ProjectDetailsFormYupSchema = yup.object().shape({
project_name: yup.string().required('Required'),
project_name: yup.string().max(50, 'Cannot exceed 50 characters').required('Required'),
project_type: yup.string().required('Required'),
start_date: yup.date().required('Required'),
end_date: yup.date().when('start_date', (start_date: any, schema: any) => {
return start_date && schema.min(start_date, 'End Date is before Start Date');
})
start_date: getStartDateStringValidator().required('Required'),
end_date: getEndDateStringValidator('start_date')
});

export interface IProjectDetailsFormProps {
Expand Down Expand Up @@ -116,6 +116,7 @@ const ProjectDetailsForm: React.FC<IProjectDetailsFormProps> = (props) => {
required={true}
value={values.start_date}
type="date"
inputProps={{ min: DATE_LIMIT.min, max: DATE_LIMIT.max }}
onChange={handleChange}
error={touched.start_date && Boolean(errors.start_date)}
helperText={errors.start_date}
Expand All @@ -132,6 +133,7 @@ const ProjectDetailsForm: React.FC<IProjectDetailsFormProps> = (props) => {
variant="outlined"
value={values.end_date}
type="date"
inputProps={{ min: DATE_LIMIT.min, max: DATE_LIMIT.max }}
onChange={handleChange}
error={touched.end_date && Boolean(errors.end_date)}
helperText={errors.end_date}
Expand Down
15 changes: 7 additions & 8 deletions app/src/features/projects/components/ProjectFundingItemForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ import {
Typography
} from '@material-ui/core';
import { IMultiAutocompleteFieldOption } from 'components/fields/MultiAutocompleteFieldVariableSize';
import { DATE_LIMIT } from 'constants/dateFormats';
import { Formik, FormikHelpers } from 'formik';
import React from 'react';
import { getEndDateStringValidator, getStartDateStringValidator } from 'utils/YupValidations';
import * as yup from 'yup';
import { IInvestmentActionCategoryOption } from './ProjectFundingForm';

Expand Down Expand Up @@ -46,20 +48,15 @@ export const ProjectFundingFormArrayItemYupSchema = yup.object().shape({
.transform((value) => (isNaN(value) && null) || value)
.required('Required'),
investment_action_category: yup.number().required('Required'),
agency_project_id: yup.string(),
agency_project_id: yup.string().max(50, 'Cannot exceed 50 characters'),
funding_amount: yup
.number()
.transform((value) => (isNaN(value) && null) || value)
.typeError('Must be a number')
.min(0, 'Must be a positive number')
.required('Required'),
start_date: yup.date().required('Required'),
end_date: yup
.date()
.when('start_date', (start_date: any, schema: any) => {
return start_date && schema.min(start_date, 'End Date is before Start Date');
})
.required('Required')
start_date: getStartDateStringValidator().required('Required'),
end_date: getEndDateStringValidator('start_date')
});

export interface IProjectFundingItemFormProps {
Expand Down Expand Up @@ -227,6 +224,7 @@ const ProjectFundingItemForm: React.FC<IProjectFundingItemFormProps> = (props) =
required={true}
value={values.start_date}
type="date"
inputProps={{ min: DATE_LIMIT.min, max: DATE_LIMIT.max }}
onChange={handleChange}
error={touched.start_date && Boolean(errors.start_date)}
helperText={errors.start_date}
Expand All @@ -244,6 +242,7 @@ const ProjectFundingItemForm: React.FC<IProjectFundingItemFormProps> = (props) =
required={true}
value={values.end_date}
type="date"
inputProps={{ min: DATE_LIMIT.min, max: DATE_LIMIT.max }}
onChange={handleChange}
error={touched.end_date && Boolean(errors.end_date)}
helperText={errors.end_date}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export const ProjectLocationFormInitialValues: IProjectLocationForm = {

export const ProjectLocationFormYupSchema = yup.object().shape({
regions: yup.array().of(yup.string()).min(1).required('Required'),
location_description: yup.string()
location_description: yup.string().max(3000, 'Cannot exceed 3000 characters')
});

export interface IProjectLocationFormProps {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ export const ProjectObjectivesFormInitialValues: IProjectObjectivesForm = {
export const ProjectObjectivesFormYupSchema = yup.object().shape({
objectives: yup
.string()
.max(3000, 'Cannot exceed 3000 characters.')
.required('You must provide objectives for the project.'),
caveats: yup.string().max(3000, 'Cannot exceed 3000 characters.')
.max(3000, 'Cannot exceed 3000 characters')
.required('You must provide objectives for the project'),
caveats: yup.string().max(3000, 'Cannot exceed 3000 characters')
});

/**
Expand Down
2 changes: 1 addition & 1 deletion app/src/features/projects/components/ProjectPermitForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export const ProjectPermitFormInitialValues: IProjectPermitForm = {
export const ProjectPermitFormYupSchema = yup.object().shape({
permits: yup.array().of(
yup.object().shape({
permit_number: yup.string().required('Required'),
permit_number: yup.string().max(100, 'Cannot exceed 100 characters').required('Required'),
sampling_conducted: yup.string().required('Required')
})
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,8 @@ exports[`ProjectDetailsForm renders correctly with default empty values 1`] = `
aria-invalid="false"
class="MuiInputBase-input MuiOutlinedInput-input"
id="start_date"
max="2100-12-31"
min="1900-01-01"
name="start_date"
required=""
type="date"
Expand Down Expand Up @@ -402,6 +404,8 @@ exports[`ProjectDetailsForm renders correctly with default empty values 1`] = `
aria-invalid="false"
class="MuiInputBase-input MuiOutlinedInput-input"
id="end_date"
max="2100-12-31"
min="1900-01-01"
name="end_date"
type="date"
value=""
Expand Down Expand Up @@ -874,6 +878,8 @@ exports[`ProjectDetailsForm renders correctly with existing details values 1`] =
aria-invalid="false"
class="MuiInputBase-input MuiOutlinedInput-input"
id="start_date"
max="2100-12-31"
min="1900-01-01"
name="start_date"
required=""
type="date"
Expand Down Expand Up @@ -915,6 +921,8 @@ exports[`ProjectDetailsForm renders correctly with existing details values 1`] =
aria-invalid="false"
class="MuiInputBase-input MuiOutlinedInput-input"
id="end_date"
max="2100-12-31"
min="1900-01-01"
name="end_date"
type="date"
value="2021-04-14"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,8 @@ exports[`ProjectFundingItemForm renders correctly with default empty values 1`]
aria-invalid="false"
class="MuiInputBase-input MuiOutlinedInput-input"
id="start_date"
max="2100-12-31"
min="1900-01-01"
name="start_date"
required=""
type="date"
Expand Down Expand Up @@ -331,6 +333,8 @@ exports[`ProjectFundingItemForm renders correctly with default empty values 1`]
aria-invalid="false"
class="MuiInputBase-input MuiOutlinedInput-input"
id="end_date"
max="2100-12-31"
min="1900-01-01"
name="end_date"
required=""
type="date"
Expand Down Expand Up @@ -758,6 +762,8 @@ exports[`ProjectFundingItemForm renders correctly with existing funding item val
aria-invalid="false"
class="MuiInputBase-input MuiOutlinedInput-input"
id="start_date"
max="2100-12-31"
min="1900-01-01"
name="start_date"
required=""
type="date"
Expand Down Expand Up @@ -807,6 +813,8 @@ exports[`ProjectFundingItemForm renders correctly with existing funding item val
aria-invalid="false"
class="MuiInputBase-input MuiOutlinedInput-input"
id="end_date"
max="2100-12-31"
min="1900-01-01"
name="end_date"
required=""
type="date"
Expand Down Expand Up @@ -1234,6 +1242,8 @@ exports[`ProjectFundingItemForm renders correctly with existing funding item val
aria-invalid="false"
class="MuiInputBase-input MuiOutlinedInput-input"
id="start_date"
max="2100-12-31"
min="1900-01-01"
name="start_date"
required=""
type="date"
Expand Down Expand Up @@ -1283,6 +1293,8 @@ exports[`ProjectFundingItemForm renders correctly with existing funding item val
aria-invalid="false"
class="MuiInputBase-input MuiOutlinedInput-input"
id="end_date"
max="2100-12-31"
min="1900-01-01"
name="end_date"
required=""
type="date"
Expand Down Expand Up @@ -1639,6 +1651,8 @@ exports[`ProjectFundingItemForm renders correctly with existing funding item val
aria-invalid="false"
class="MuiInputBase-input MuiOutlinedInput-input"
id="start_date"
max="2100-12-31"
min="1900-01-01"
name="start_date"
required=""
type="date"
Expand Down Expand Up @@ -1688,6 +1702,8 @@ exports[`ProjectFundingItemForm renders correctly with existing funding item val
aria-invalid="false"
class="MuiInputBase-input MuiOutlinedInput-input"
id="end_date"
max="2100-12-31"
min="1900-01-01"
name="end_date"
required=""
type="date"
Expand Down
37 changes: 37 additions & 0 deletions app/src/utils/YupValidations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import moment from 'moment';
import * as yup from 'yup';

const getBaseDateStringValidator = () => {
return yup.string().test('is-valid-date', 'Invalid date', (value) => {
if (!value) {
return true;
}

return moment(value, 'YYYY-MM-DD', true).isValid();
});
};

export const getStartDateStringValidator = () => {
return getBaseDateStringValidator();
};

export const getEndDateStringValidator = (startDateName: string) => {
return getBaseDateStringValidator().test(
'is-end-date-after-start-date',
'End Date is before Start Date',
function (value) {
if (!value) {
// end date is null, no validation required
return true;
}

if (!moment(this.parent[startDateName], 'YYYY-MM-DD', true).isValid()) {
// cant validate end_date if start_date is invalid
return true;
}

// compare valid start and end dates
return moment(this.parent.start_date, 'YYYY-MM-DD').isBefore(moment(value, 'YYYY-MM-DD'));
}
);
};

0 comments on commit a74d15f

Please sign in to comment.