fix: add blackout dates validation for non supported browsers (#203)

* fix: add blackout dates validation for non supported browsers

* refactor: update functions name
This commit is contained in:
Awais Ansari
2021-10-25 19:16:48 +05:00
committed by GitHub
parent 7464aa59bc
commit bfda00a8b9
5 changed files with 121 additions and 24 deletions

View File

@@ -24,13 +24,24 @@ function LegacyConfigForm({
const legacyFormValidationSchema = Yup.object().shape({
blackoutDates: Yup.array(
Yup.object().shape({
startDate: Yup.date().required(intl.formatMessage(messages.blackoutStartDateRequired)),
endDate: Yup.date().required(intl.formatMessage(messages.blackoutEndDateRequired)).when('startDate', {
startDate: Yup.string().checkFormat(
intl.formatMessage(messages.blackoutStartDateInValidFormat), 'date',
).required(intl.formatMessage(messages.blackoutStartDateRequired)),
endDate: Yup.string().checkFormat(
intl.formatMessage(messages.blackoutEndDateInValidFormat), 'date',
).required(intl.formatMessage(messages.blackoutEndDateRequired)).when('startDate', {
is: (startDate) => startDate,
then: Yup.date().min(Yup.ref('startDate'), intl.formatMessage(messages.blackoutEndDateInPast)),
then: Yup.string().compare(intl.formatMessage(messages.blackoutEndDateInPast), 'date'),
}),
startTime: Yup.string().checkFormat(
intl.formatMessage(messages.blackoutStartTimeInValidFormat), 'time',
),
endTime: Yup.string().checkFormat(
intl.formatMessage(messages.blackoutEndTimeInValidFormat), 'time',
).when('startTime', {
is: (startTime) => startTime,
then: Yup.string().compare(intl.formatMessage(messages.blackoutEndTimeInPast), 'time'),
}),
startTime: Yup.string(),
endTime: Yup.string().compare(intl.formatMessage(messages.blackoutEndTimeInPast)),
}),
),
discussionTopics: Yup.array(

View File

@@ -270,6 +270,26 @@ const messages = defineMessages({
defaultMessage: 'End time cannot be before start time',
description: 'Tells the user that the blackout end time cannot be in past and cannot be before start time',
},
blackoutStartTimeInValidFormat: {
id: 'authoring.blackoutDates.startTime.inValidFormat',
defaultMessage: 'Enter a valid start time',
description: 'Tells the user that the blackout start time format is in valid',
},
blackoutEndTimeInValidFormat: {
id: 'authoring.blackoutDates.endTime.inValidFormat',
defaultMessage: 'Enter a valid end time',
description: 'Tells the user that the blackout end time format is in valid',
},
blackoutStartDateInValidFormat: {
id: 'authoring.blackoutDates.startDate.inValidFormat',
defaultMessage: 'Enter a valid start Date',
description: 'Tells the user that the blackout start date format is in valid',
},
blackoutEndDateInValidFormat: {
id: 'authoring.blackoutDates.endDate.inValidFormat',
defaultMessage: 'Enter a valid end date',
description: 'Tells the user that the blackout end date format is in valid',
},
deleteAltText: {
id: 'authoring.topics.delete',
defaultMessage: 'Delete Topic',

View File

@@ -1,7 +1,6 @@
import moment from 'moment';
import _ from 'lodash';
import { getIn } from 'formik';
import { blackoutDatesStatus as constants } from '../data/constants';
export const filterItemFromObject = (array, key, value) => (
@@ -27,14 +26,29 @@ export const checkStatus = ([startDate, endDate]) => {
return status;
};
export const formatDate = (date, time) => (time ? `${date}T${time}` : date);
export const validTimeFormats = ['hh:mm A', 'HH:mm'];
export const mergeDateTime = (date, time) => ((date && time) ? `${date}T${time}` : date);
export const isSameDay = (startDate, endDate) => moment(startDate).isSame(endDate, 'day');
export const isSameMonth = (startDate, endDate) => moment(startDate).isSame(endDate, 'month');
export const isSameYear = (startDate, endDate) => moment(startDate).isSame(endDate, 'year');
export const getTime = (dateTime) => dateTime.split('T')[1] || '';
export const hasValidDateFormat = (date) => moment(date, ['MM/DD/YYYY', 'YYYY-MM-DD'], true).isValid();
export const hasValidTimeFormat = (time) => time && moment(time, validTimeFormats, true).isValid();
export const normalizeTime = (time) => time && moment(time, validTimeFormats, true).format('HH:mm');
export const normalizeDate = (date) => moment(
date, ['MM/DD/YYYY', 'YYYY-MM-DDTHH:mm', 'YYYY-MM-DD'], true,
).format('YYYY-MM-DD');
export const decodeDateTime = (date, time) => {
const nDate = normalizeDate(date);
const nTime = normalizeTime(time);
return moment(mergeDateTime(nDate, nTime));
};
export const sortBlackoutDatesByStatus = (data, status, order) => (
_.orderBy(data.filter(date => date.status === status),
[(obj) => moment(formatDate(obj.startDate, obj.startTime))], [order])
[(obj) => decodeDateTime(obj.startDate, obj.startTime)], [order])
);
export const formatBlackoutDates = ({
@@ -47,8 +61,8 @@ export const formatBlackoutDates = ({
const isTimeAvailable = Boolean(startTime && endTime);
const mStartDate = moment(startDate);
const mEndDate = moment(endDate);
const mStartDateTime = moment(`${startDate}T${startTime}`);
const mEndDateTime = moment(`${endDate}T${endTime}`);
const mStartDateTime = decodeDateTime(startDate, startTime);
const mEndDateTime = decodeDateTime(endDate, endTime);
if (hasSameDay && !isTimeAvailable) {
formattedDate = mStartDate.format('MMMM D, YYYY');

View File

@@ -1,10 +1,16 @@
import { getConfig, camelCaseObject } from '@edx/frontend-platform';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import _ from 'lodash';
import moment from 'moment';
import { v4 as uuid } from 'uuid';
import { checkStatus, sortBlackoutDatesByStatus, formatDate } from '../app-config-form/utils';
import {
checkStatus,
sortBlackoutDatesByStatus,
mergeDateTime,
normalizeDate,
normalizeTime,
getTime,
} from '../app-config-form/utils';
import { blackoutDatesStatus as constants } from './constants';
function normalizeLtiConfig(data) {
@@ -43,10 +49,10 @@ export function normalizeBlackoutDates(data) {
const normalizeData = data.map(([startDate, endDate]) => ({
id: uuid(),
startDate: moment(startDate).format('YYYY-MM-DD'),
startTime: startDate.split('T')[1] || '',
endDate: moment(endDate).format('YYYY-MM-DD'),
endTime: endDate.split('T')[1] || '',
startDate: normalizeDate(startDate),
startTime: getTime(startDate),
endDate: normalizeDate(endDate),
endTime: getTime(endDate),
status: checkStatus([startDate, endDate]),
}));
@@ -119,10 +125,16 @@ function normalizeApps(data) {
};
}
export function denormalizeBlackoutDate(date) {
export function denormalizeBlackoutDate(blackoutPeriod) {
return [
formatDate(date.startDate, date.startTime),
formatDate(date.endDate, date.endTime),
mergeDateTime(
normalizeDate(blackoutPeriod.startDate),
normalizeTime(blackoutPeriod.startTime),
),
mergeDateTime(
normalizeDate(blackoutPeriod.endDate),
normalizeTime(blackoutPeriod.endTime),
),
];
}

View File

@@ -3,12 +3,14 @@ import { useContext, useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useMediaQuery } from 'react-responsive';
import * as Yup from 'yup';
import moment from 'moment';
import { RequestStatus } from './data/constants';
import { getCourseAppSettingValue, getLoadingStatus } from './pages-and-resources/data/selectors';
import { fetchCourseAppSettings, updateCourseAppSetting } from './pages-and-resources/data/thunks';
import { PagesAndResourcesContext } from './pages-and-resources/PagesAndResourcesProvider';
import {
hasValidDateFormat, hasValidTimeFormat, decodeDateTime,
} from './pages-and-resources/discussions/app-config-form/utils';
export const executeThunk = async (thunk, dispatch, getState) => {
await thunk(dispatch, getState);
@@ -91,13 +93,28 @@ export function setupYupExtensions() {
});
});
Yup.addMethod(Yup.string, 'compare', function compare(message) {
Yup.addMethod(Yup.string, 'compare', function compare(message, type) {
return this.test('isGreater', message, function isGreater() {
if (!this.parent || !this.parent.startTime || !this.parent.endTime) {
// This function compare 2 dates or 2 times. It return no error if dateInstance/timeInstance is empty
// of if startTime or endTime is not present for time comparesion
// or startDate or endDate is not present for date comparesion
if (!this.parent
|| (!(this.parent.startTime && this.parent.endTime) && type === 'time')
|| (!(this.parent.startDate && this.parent.endDate) && type === 'date')
) {
return true;
}
const isInvalidStartDateTime = moment(`${moment(this.parent.startDate).format('YYYY-MM-DD')}T${this.parent.startTime}`)
.isSameOrAfter(moment(`${moment(this.parent.endDate).format('YYYY-MM-DD')}T${this.parent.endTime}`));
const startDateTime = decodeDateTime(this.parent.startDate, this.parent.startTime);
const endDateTime = decodeDateTime(this.parent.endDate, this.parent.endTime);
let isInvalidStartDateTime;
if (type === 'date') {
isInvalidStartDateTime = startDateTime.isAfter(endDateTime);
} else if (type === 'time') {
isInvalidStartDateTime = startDateTime.isSameOrAfter(endDateTime);
}
if (isInvalidStartDateTime) {
throw this.createError({
@@ -108,4 +125,27 @@ export function setupYupExtensions() {
return true;
});
});
Yup.addMethod(Yup.string, 'checkFormat', function checkFormat(message, type) {
return this.test('isValidFormat', message, function isValidFormat() {
if (!this.originalValue) {
return true;
}
let isValid;
if (type === 'date') {
isValid = hasValidDateFormat(this.originalValue);
} else if (type === 'time') {
isValid = hasValidTimeFormat(this.originalValue);
}
if (!isValid) {
throw this.createError({
path: `${this.path}`,
error: message,
});
}
return true;
});
});
}