diff --git a/i18n/en.pot b/i18n/en.pot index 0a8628ab2..3c65b3573 100644 --- a/i18n/en.pot +++ b/i18n/en.pot @@ -5,8 +5,8 @@ msgstr "" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -"POT-Creation-Date: 2024-10-14T16:17:34.694Z\n" -"PO-Revision-Date: 2024-10-14T16:17:34.694Z\n" +"POT-Creation-Date: 2024-10-16T08:10:10.883Z\n" +"PO-Revision-Date: 2024-10-16T08:10:10.883Z\n" msgid "Not authorized" msgstr "Not authorized" @@ -54,9 +54,6 @@ msgstr "1 value failed to save" msgid "{{numberOfErrors}} values failed to save" msgstr "{{numberOfErrors}} values failed to save" -msgid "This form closes and will be locked at {{-dateTime}}" -msgstr "This form closes and will be locked at {{-dateTime}}" - msgid "Closes {{-relativeTime}}" msgstr "Closes {{-relativeTime}}" @@ -598,6 +595,9 @@ msgstr "" "Something went wrong while setting the form's completion to " "\"{{completed}}\": {{errorMessage}}" +msgid "Invalid date ({{date}})" +msgstr "Invalid date ({{date}})" + msgid "{{title}} (disabled)" msgstr "{{title}} (disabled)" diff --git a/src/bottom-bar/form-expiry-info.js b/src/bottom-bar/form-expiry-info.js index 108865fc6..cdacd55c9 100644 --- a/src/bottom-bar/form-expiry-info.js +++ b/src/bottom-bar/form-expiry-info.js @@ -3,7 +3,7 @@ import { IconInfo16, colors, Tooltip } from '@dhis2/ui' import cx from 'classnames' import React from 'react' import i18n from '../locales/index.js' -import { useLockedContext, getRelativeTime } from '../shared/index.js' +import { useLockedContext, getRelativeTime, DateText } from '../shared/index.js' import styles from './main-tool-bar.module.css' export default function FormExpiryInfo() { @@ -20,16 +20,14 @@ export default function FormExpiryInfo() { calendar: 'gregory', timezone, }) - const dateTime = `${lockDate} (${timezone})` return ( <> {!locked && lockDate && ( + } > { // NOTE: the passed date is assumed to be in ISO + // check that date is parsable as ISO + const parsedDate = new Date(date) + if (isNaN(parsedDate)) { + return {i18n.t('Invalid date ({{date}})', { date })} + } + // we first correct for time zone const dateClient = fromServerDate(date) @@ -49,13 +56,13 @@ export const DateText = ({ date, includeTimeZone }) => { // we put it in the system setting for the date display return ( -

+ {formatDate({ dateString: inSystemCalendarDateString, dateFormat, includeTimeZone, })} -

+
) } diff --git a/src/shared/date/date-text.test.js b/src/shared/date/date-text.test.js index 176e53fea..dd610dcb3 100644 --- a/src/shared/date/date-text.test.js +++ b/src/shared/date/date-text.test.js @@ -1,3 +1,4 @@ +/* eslint-disable max-params */ import { useConfig } from '@dhis2/app-runtime' import React from 'react' import { render } from '../../test-utils/index.js' @@ -19,120 +20,128 @@ describe('DateText', () => { jest.clearAllMocks() }) it.each([ - { - inputDate: '2024-10-14T19:10:57.836', - dateFormat: 'yyyy-mm-dd', - calendar: 'gregory', - serverTimeZone: 'Etc/UTC', - includeTimeZone: false, - output: '2024-10-14 19:10', - }, - { - inputDate: '2024-10-14T19:10:57.836', - dateFormat: 'yyyy-mm-dd', - calendar: 'gregory', - serverTimeZone: 'Etc/UTC', - includeTimeZone: true, - output: '2024-10-14 19:10 (UTC)', - }, - { - inputDate: '2024-10-14T19:10:57.836', - dateFormat: 'dd-mm-yyyy', - calendar: 'gregory', - serverTimeZone: 'Etc/UTC', - includeTimeZone: false, - output: '14-10-2024 19:10', - }, - { - inputDate: '2024-10-14T19:10:57.836', - dateFormat: 'dd-mm-yyyy', - calendar: 'gregory', - serverTimeZone: 'Etc/UTC', - includeTimeZone: true, - output: '14-10-2024 19:10 (UTC)', - }, - { - inputDate: '2024-10-14T19:10:57.836', - dateFormat: 'yyyy-mm-dd', - calendar: 'gregory', - serverTimeZone: 'Asia/Vientiane', - includeTimeZone: true, - output: '2024-10-14 12:10 (UTC)', - }, - { - inputDate: '2024-10-14T19:10:57.836', - dateFormat: 'yyyy-mm-dd', - calendar: 'gregory', - serverTimeZone: 'Atlantic/Cape_Verde', - includeTimeZone: true, - output: '2024-10-14 20:10 (UTC)', - }, - { - inputDate: '2024-10-14T19:10:57.836', - dateFormat: 'yyyy-mm-dd', - calendar: 'gregory', - serverTimeZone: 'Etc/UTC', - includeTimeZone: null, - output: '2024-10-14 19:10', - }, - { - inputDate: '2024-10-14T19:10:57.836', - dateFormat: 'yyyy-mm-dd', - calendar: 'ethiopian', - serverTimeZone: 'Etc/UTC', - includeTimeZone: false, - output: '2017-02-04 19:10', - }, - { - inputDate: '2024-10-14T19:10:57.836', - dateFormat: 'yyyy-mm-dd', - calendar: 'ethiopian', - serverTimeZone: 'Africa/Addis_Ababa', - includeTimeZone: false, - output: '2017-02-04 16:10', - }, - { - inputDate: '2024-10-14T19:10:57.836', - dateFormat: 'yyyy-mm-dd', - calendar: 'ethiopian', - serverTimeZone: 'Africa/Addis_Ababa', - includeTimeZone: true, - output: '2017-02-04 16:10 (UTC)', - }, - { - inputDate: '2024-10-14T19:10:57.836', - dateFormat: 'yyyy-mm-dd', - calendar: 'nepali', - serverTimeZone: 'Etc/UTC', - includeTimeZone: false, - output: '2081-06-28 19:10', - }, - { - inputDate: '2024-10-14T19:10:57.836', - dateFormat: 'yyyy-mm-dd', - calendar: 'nepali', - serverTimeZone: 'Asia/Kathmandu', - includeTimeZone: false, - output: '2081-06-28 13:25', - }, - { - inputDate: '2024-10-14T19:10:57.836', - dateFormat: 'dd-mm-yyyy', - calendar: 'nepali', - serverTimeZone: 'Asia/Kathmandu', - includeTimeZone: false, - output: '28-06-2081 13:25', - }, + [ + '2024-10-14T19:10:57.836', + 'yyyy-mm-dd', + 'gregory', + 'Etc/UTC', + false, + '2024-10-14 19:10', + ], + [ + '2024-10-14T19:10:57.836', + 'yyyy-mm-dd', + 'gregory', + 'Etc/UTC', + true, + '2024-10-14 19:10 (UTC)', + ], + [ + '2024-10-14T19:10:57.836', + 'dd-mm-yyyy', + 'gregory', + 'Etc/UTC', + false, + '14-10-2024 19:10', + ], + [ + '2024-10-14T19:10:57.836', + 'dd-mm-yyyy', + 'gregory', + 'Etc/UTC', + true, + '14-10-2024 19:10 (UTC)', + ], + [ + '2024-10-14T19:10:57.836', + 'yyyy-mm-dd', + 'gregory', + 'Asia/Vientiane', + true, + '2024-10-14 12:10 (UTC)', + ], + [ + '2024-10-14T19:10:57.836', + 'yyyy-mm-dd', + 'gregory', + 'Atlantic/Cape_Verde', + true, + '2024-10-14 20:10 (UTC)', + ], + [ + '2024-10-14T19:10:57.836', + 'yyyy-mm-dd', + 'gregory', + 'Etc/UTC', + null, + '2024-10-14 19:10', + ], + [ + '2024-10-14T19:10:57.836', + 'yyyy-mm-dd', + 'ethiopian', + 'Etc/UTC', + false, + '2017-02-04 19:10', + ], + [ + '2024-10-14T19:10:57.836', + 'yyyy-mm-dd', + 'ethiopian', + 'Africa/Addis_Ababa', + false, + '2017-02-04 16:10', + ], + [ + '2024-10-14T19:10:57.836', + 'yyyy-mm-dd', + 'ethiopian', + 'Africa/Addis_Ababa', + true, + '2017-02-04 16:10 (UTC)', + ], + [ + '2024-10-14T19:10:57.836', + 'yyyy-mm-dd', + 'nepali', + 'Etc/UTC', + false, + '2081-06-28 19:10', + ], + [ + '2024-10-14T19:10:57.836', + 'yyyy-mm-dd', + 'nepali', + 'Asia/Kathmandu', + false, + '2081-06-28 13:25', + ], + [ + '2024-10-14T19:10:57.836', + 'dd-mm-yyyy', + 'nepali', + 'Asia/Kathmandu', + false, + '28-06-2081 13:25', + ], + [ + '2017-13-05T19:10:57.836', + 'yyyy-mm-dd', + 'gregory', + 'Etc/UTC', + false, + 'Invalid date (2017-13-05T19:10:57.836)', + ], ])( - 'should display %s given: format is %s, calendar is %s, server time zone is %s, and includeTimeZone is %s', - ({ + 'with input of %s format is %s, calendar is %s, server time zone is %s, and includeTimeZone is %s. Should display %s', + ( inputDate, dateFormat, calendar, serverTimeZone, includeTimeZone, - output, - }) => { + output + ) => { useConfig.mockReturnValueOnce({ systemInfo: { serverTimeZoneId: serverTimeZone,