diff --git a/package-lock.json b/package-lock.json
index 7c88ac3..bd1a048 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@ukhomeoffice/asl-components",
- "version": "13.5.2",
+ "version": "13.6.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@ukhomeoffice/asl-components",
- "version": "13.5.2",
+ "version": "13.6.1",
"license": "MIT",
"dependencies": {
"@ukhomeoffice/asl-constants": "^2.1.5",
@@ -7721,12 +7721,13 @@
}
},
"node_modules/micromatch": {
- "version": "4.0.5",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
- "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+ "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "braces": "^3.0.2",
+ "braces": "^3.0.3",
"picomatch": "^2.3.1"
},
"engines": {
@@ -15239,12 +15240,12 @@
}
},
"micromatch": {
- "version": "4.0.5",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
- "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+ "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
"dev": true,
"requires": {
- "braces": "^3.0.2",
+ "braces": "^3.0.3",
"picomatch": "^2.3.1"
}
},
diff --git a/package.json b/package.json
index 2bab429..0c7e7cc 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@ukhomeoffice/asl-components",
- "version": "13.6.0",
+ "version": "13.6.1",
"description": "React components for ASL layouts and elements",
"main": "src/index.jsx",
"styles": "styles/index.scss",
diff --git a/src/condition-reminders/index.jsx b/src/condition-reminders/index.jsx
index e89a4f2..86b2f1b 100644
--- a/src/condition-reminders/index.jsx
+++ b/src/condition-reminders/index.jsx
@@ -1,30 +1,49 @@
import React from 'react';
-import { format } from 'date-fns';
+import { formatDate, DATE_FORMAT } from '../utils';
import { Inset } from '../';
-function ConditionReminders({ reminders, dateFormat = 'dd/MM/yyyy' }) {
- if (!reminders || reminders.length < 1) {
+const SINGULAR_CONTENT = {
+ notice: 'A deadline and automated reminders have been set for this condition',
+ deadline_list_intro: 'This condition has a deadline set for:',
+ deadline_list_outro:
+ 'Licence holders will receive reminders 1 month before, 1 week before' +
+ ' and on the deadline date. ASRU will receive a reminder when the' +
+ ' deadline has passed.'
+};
+
+const PLURAL_CONTENT = {
+ notice: 'Deadlines and automated reminders have been set for this condition',
+ deadline_list_intro: 'This condition has deadlines set for:',
+ deadline_list_outro:
+ 'Licence holders will receive reminders 1 month before, 1 week before' +
+ ' and on each deadline date. ASRU will receive reminders when each' +
+ ' deadline has passed.'
+};
+
+function ConditionReminders({ reminders, dateFormat = DATE_FORMAT.short }) {
+ const activeReminders = (reminders ?? []).filter(reminder => reminder.deadline);
+
+ if (activeReminders.length < 1) {
return null;
}
+ const content = activeReminders.length === 1 ? SINGULAR_CONTENT : PLURAL_CONTENT;
+
return (
-
Automated reminders have been set for this condition
+
{content.notice}
- Show when reminders have been scheduled
+ Show when deadlines and reminders have been scheduled
- This condition has a reminder scheduled for:
+ {content.deadline_list_intro}
{
reminders.map(reminder => (
- - {format(reminder.deadline, dateFormat)}
+ - {formatDate(reminder.deadline, dateFormat)}
))
}
-
- Licence holders will receive reminders a month before, a week before and on the day the condition
- is due to be met. ASRU will receive a reminder when the deadline has passed.
-
+ {content.deadline_list_outro}
diff --git a/src/condition-reminders/index.spec.jsx b/src/condition-reminders/index.spec.jsx
new file mode 100644
index 0000000..4801fde
--- /dev/null
+++ b/src/condition-reminders/index.spec.jsx
@@ -0,0 +1,64 @@
+import { shallow, render } from 'enzyme';
+import React from 'react';
+import ConditionReminders from './index';
+import {describe, expect, test} from '@jest/globals'
+import {v4 as uuid} from 'uuid'
+
+function reminderWithDeadline(deadline) {
+ return {
+ id: uuid(),
+ deadline
+ }
+}
+
+describe('ConditionReminders component', () => {
+ test('Empty reminders should render nothing', () => {
+ for (const reminders of [null, []]) {
+ const wrapper = shallow();
+ expect(wrapper.isEmptyRender()).toBe(true);
+ }
+ })
+
+ test('Reminders without a deadline should be ignored', () => {
+ const reminders = [{id: uuid()}]
+ const wrapper = shallow();
+ expect(wrapper.isEmptyRender()).toBe(true);
+ })
+
+ test('When there is one reminder the copy should be singular', () => {
+ const reminders = [reminderWithDeadline("2025-01-01")]
+ const wrapper = render();
+ expect(wrapper.text())
+ .toContain(
+ "A deadline and automated reminders have been set for this condition"
+ );
+ expect(wrapper.text())
+ .toContain("This condition has a deadline set for:");
+ expect(wrapper.text())
+ .toContain(
+ "Licence holders will receive reminders 1 month before," +
+ " 1 week before and on the deadline date. ASRU will receive a reminder" +
+ " when the deadline has passed."
+ );
+ })
+
+ test('When there are two reminders the copy should be plural', () => {
+ const reminders = [
+ reminderWithDeadline("2025-01-01"),
+ reminderWithDeadline("2025-02-02")
+ ]
+ const wrapper = render();
+ expect(wrapper.text())
+ .toContain(
+ "Deadlines and automated reminders have been set for this condition"
+ );
+ expect(wrapper.text())
+ .toContain("This condition has deadlines set for:");
+ expect(wrapper.text())
+ .toContain(
+ "Licence holders will receive reminders 1 month before, " +
+ "1 week before and on each deadline date. ASRU will receive reminders " +
+ "when each deadline has passed."
+ );
+ })
+})
diff --git a/src/utils.js b/src/utils.js
index bfde3ac..b4880a4 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -1,6 +1,7 @@
const { stringify, parse } = require('qs');
const get = require('lodash/get');
const url = require('url');
+const { format: dateFormatter } = require('date-fns');
const getValue = ({ row, schema, key }) => {
const accessor = schema.accessor || key;
@@ -36,8 +37,23 @@ const getSort = (column, state) => ({
ascending: state.column === column ? !state.ascending : true
});
+const DATE_FORMAT = {
+ long: 'd MMMM yyyy',
+ short: 'd/M/yyyy'
+};
+
+const formatDate = (date, format = DATE_FORMAT.long) => {
+ try {
+ return date ? dateFormatter(date, format) : '-';
+ } catch (err) {
+ return 'Invalid date entered';
+ }
+};
+
module.exports = {
getValue,
queryStringFromState,
- getSort
+ getSort,
+ formatDate,
+ DATE_FORMAT
};
diff --git a/src/utils.spec.js b/src/utils.spec.js
new file mode 100644
index 0000000..d6dc0f0
--- /dev/null
+++ b/src/utils.spec.js
@@ -0,0 +1,18 @@
+const { formatDate, DATE_FORMAT } = require('./utils');
+
+describe('formatDate', () => {
+ test('formats a valid date', () => {
+ expect(formatDate('2024-01-01', DATE_FORMAT.short)).toBe('1/1/2024');
+ });
+
+ test('returns "-" for empty dates', () => {
+ expect(formatDate(null, DATE_FORMAT.short)).toBe('-');
+ expect(formatDate(undefined, DATE_FORMAT.short)).toBe('-');
+ expect(formatDate('', DATE_FORMAT.short)).toBe('-');
+ });
+
+ test('returns "Invalid date entered" for invlaid dates', () => {
+ expect(formatDate('not a date', DATE_FORMAT.short)).toBe('Invalid date entered');
+ expect(formatDate('24-01-01', DATE_FORMAT.short)).toBe('Invalid date entered');
+ });
+});