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:
@@ -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(
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
50
src/utils.js
50
src/utils.js
@@ -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;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user