Skip to content

Commit

Permalink
fix: handle ISO time stamps from backend
Browse files Browse the repository at this point in the history
  • Loading branch information
tomzemp committed Oct 14, 2024
1 parent e0e220b commit 9722a21
Show file tree
Hide file tree
Showing 21 changed files with 681 additions and 281 deletions.
8 changes: 4 additions & 4 deletions i18n/en.pot
Original file line number Diff line number Diff line change
Expand Up @@ -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-09-25T13:24:25.324Z\n"
"PO-Revision-Date: 2024-09-25T13:24:25.324Z\n"
"POT-Creation-Date: 2024-10-14T16:17:34.694Z\n"
"PO-Revision-Date: 2024-10-14T16:17:34.694Z\n"

msgid "Not authorized"
msgstr "Not authorized"
Expand Down Expand Up @@ -351,8 +351,8 @@ msgstr "User"
msgid "Change"
msgstr "Change"

msgid "audit dates are given in {{- timezone}} time"
msgstr "audit dates are given in {{- timezone}} time"
msgid "audit dates are given in {{- timeZone}} time"
msgstr "audit dates are given in {{- timeZone}} time"

msgid "Unmark for follow-up"
msgstr "Unmark for follow-up"
Expand Down
10 changes: 4 additions & 6 deletions src/bottom-bar/form-expiry-info.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ export default function FormExpiryInfo() {
} = useLockedContext()

const { systemInfo = {} } = useConfig()
const { calendar = 'gregory', serverTimeZoneId: timezone = 'Etc/UTC' } =
systemInfo
const { serverTimeZoneId: timezone = 'Etc/UTC' } = systemInfo
// the lock date is returned in ISO calendar
const relativeTime = getRelativeTime({
startDate: lockDate,
calendar,
calendar: 'gregory',
timezone,
})
const dateTime = `${lockDate} (${timezone})`
Expand All @@ -43,9 +43,7 @@ export default function FormExpiryInfo() {

<span>
{i18n.t('Closes {{-relativeTime}}', {
relativeTime: relativeTime
? relativeTime
: dateTime,
relativeTime,
})}
</span>
</span>
Expand Down
7 changes: 2 additions & 5 deletions src/bottom-bar/form-expiry-info.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,15 @@ describe('FormExpiryInfo', () => {
expect(getByText('Closes in 2 hours')).toBeInTheDocument()
})

it('shows absolute time for lockedDate, if not locked, there is a lockDate, and calendar not gregory', () => {
it('shows relative time for lockedDate, if not locked, there is a lockDate, and calendar not gregory', () => {
useConfig.mockImplementation(() => ({
systemInfo: {
serverTimeZoneId: 'Africa/Addis_Ababa',
calendar: 'ethiopian',
},
}))
const { getByText } = render(<FormExpiryInfo />)

expect(
getByText('Closes 2024-03-15T14:15:00 (Africa/Addis_Ababa)')
).toBeInTheDocument()
expect(getByText('Closes in 2 hours')).toBeInTheDocument()
})

it('corrects relative time for time zone differences', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,12 +122,15 @@ export const PeriodSelectorBarItem = () => {
const endDate = selectedPeriod?.endDate
const displayName = selectedPeriod?.displayName

// date comparison
// date comparison (both in system calendar)
if (
isDateAGreaterThanDateB(endDate, dateLimit, {
inclusive: true,
calendar,
})
isDateAGreaterThanDateB(
{ date: endDate, calendar },
{ date: dateLimit, calendar },
{
inclusive: true,
}
)
) {
resetPeriod(periodId, displayName)
}
Expand Down
14 changes: 7 additions & 7 deletions src/context-selection/period-selector-bar-item/use-periods.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,14 @@ export default function usePeriods({

// we want to display the last period of the previous year if it
// stretches into the current year
// date comparison
// date comparison (both are system calendar)
if (
lastPeriodOfPrevYear &&
isDateALessThanDateB(
`${year}-01-01`,
lastPeriodOfPrevYear.endDate,
{ date: `${year}-01-01`, calendar },
{ date: lastPeriodOfPrevYear.endDate, calendar },
{
inclusive: true,
calendar,
}
)
) {
Expand All @@ -97,10 +96,11 @@ export default function usePeriods({
if (
firstPeriodNextYear &&
// `${year + 1}-01-01` > firstPeriodNextYear.startDate
// date comparison (both in system calendar)
isDateAGreaterThanDateB(
`${year + 1}-01-01`,
firstPeriodNextYear.startDate,
{ inclusive: false, calendar }
{ date: `${year + 1}-01-01`, calendar },
{ date: firstPeriodNextYear.startDate, calendar },
{ inclusive: false }
)
) {
periods.push(firstPeriodNextYear)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ export default function YearNavigator({
onYearChange,
calendar,
}) {
// console.log('maxYear', maxYear)
const startYear = startingYears[calendar] ?? startingYears.default
return (
<div className={classes.container}>
Expand Down
25 changes: 14 additions & 11 deletions src/data-workspace/data-details-sidebar/audit-log.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { useConfig } from '@dhis2/app-runtime'
import i18n from '@dhis2/d2-i18n'
import {
CircularLoader,
Expand All @@ -14,7 +13,11 @@ import {
} from '@dhis2/ui'
import PropTypes from 'prop-types'
import React from 'react'
import { ExpandableUnit, useConnectionStatus } from '../../shared/index.js'
import {
ExpandableUnit,
useConnectionStatus,
DateText,
} from '../../shared/index.js'
import styles from './audit-log.module.css'
import useDataValueContext from './use-data-value-context.js'
import useOpenState from './use-open-state.js'
Expand All @@ -25,8 +28,7 @@ export default function AuditLog({ item }) {
const { offline } = useConnectionStatus()
const { open, setOpen, openRef } = useOpenState(item)
const dataValueContext = useDataValueContext(item, openRef.current)
const { systemInfo = {} } = useConfig()
const { serverTimeZoneId: timezone = 'Etc/UTC' } = systemInfo
const timeZone = Intl.DateTimeFormat()?.resolvedOptions()?.timeZone

if (!offline && (!open || dataValueContext.isLoading)) {
return (
Expand Down Expand Up @@ -110,11 +112,12 @@ export default function AuditLog({ item }) {
return (
<DataTableRow key={key}>
<DataTableCell>
{created
? `${created
.substring(0, 16)
.replace('T', ' ')}`
: null}
{created ? (
<DateText
date={created}
includeTimeZone={false}
/>
) : null}
</DataTableCell>
<DataTableCell>{user}</DataTableCell>
<DataTableCell>
Expand Down Expand Up @@ -142,8 +145,8 @@ export default function AuditLog({ item }) {
{audits.length > 0 && (
<div className={styles.timeZoneNote}>
{i18n.t(
'audit dates are given in {{- timezone}} time',
{ timezone }
'audit dates are given in {{- timeZone}} time',
{ timeZone }
)}
</div>
)}
Expand Down
65 changes: 35 additions & 30 deletions src/data-workspace/data-details-sidebar/audit-log.test.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,10 @@
import { waitFor } from '@testing-library/react'
import { waitFor, within } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import React from 'react'
import { render } from '../../test-utils/index.js'
import AuditLog from './audit-log.js'
import useDataValueContext from './use-data-value-context.js'

jest.mock('@dhis2/app-runtime', () => ({
...jest.requireActual('@dhis2/app-runtime'),
useConfig: jest.fn(() => ({
systemInfo: { serverTimeZoneId: 'Africa/Cairo' },
})),
}))

jest.mock('./use-data-value-context.js', () => ({
__esModule: true,
default: jest.fn(),
Expand Down Expand Up @@ -74,26 +67,26 @@ describe('<AuditLog />', () => {

// @TODO: Enable and fix when working on:
// https://dhis2.atlassian.net/browse/TECH-1281
it.skip('renders the item audit log once loaded', async () => {
it('renders the item audit log once loaded', async () => {
const audits = [
{
auditType: 'UPDATE',
created: new Date('2021-01-01').toISOString(),
auditType: 'DELETE',
created: new Date('2021-03-01').toISOString(),
modifiedBy: 'Firstname Lastname',
prevValue: '19',
value: '21',
},
{
auditType: 'UPDATE',
created: new Date('2021-02-01').toISOString(),
modifiedBy: 'Firstname2 Lastname2',
prevValue: '19',
value: '21',
},
{
auditType: 'DELETE',
created: new Date('2021-03-01').toISOString(),
auditType: 'UPDATE',
created: new Date('2021-01-01').toISOString(),
modifiedBy: 'Firstname3 Lastname3',
value: '',
value: '19',
},
]

Expand All @@ -113,26 +106,38 @@ describe('<AuditLog />', () => {
expect(queryByRole('progressbar')).not.toBeInTheDocument()
})

expect(getByRole('list')).toBeInTheDocument()
expect(getAllByRole('listitem')).toHaveLength(audits.length)
// the number of rows is: the length of audits + 1 (for header row)
const auditRows = getAllByRole('row')

const firstChangeEl = getByText('Firstname Lastname set to 19', {
selector: '.entry:nth-child(3):last-child .entryMessage',
})
expect(firstChangeEl).toBeInTheDocument()
expect(auditRows).toHaveLength(audits.length + 1)

const secondChangeEl = getByText(
'Firstname2 Lastname2 updated to 21 (was 19)',
{ selector: '.entry:nth-child(2) .entryMessage' }
const firstChangeName = within(auditRows[1]).getByText(
'Firstname Lastname',
{}
)
expect(secondChangeEl).toBeInTheDocument()
expect(firstChangeName).toBeInTheDocument()
const firstChangeValue = within(auditRows[1]).getByText('21', {})
expect(firstChangeValue).toBeInTheDocument()

const thirdChangeEl = getByText(
'Firstname3 Lastname3 deleted (was 21)',
{ selector: '.entry:nth-child(1) .entryMessage' }
const secondChangeName = within(auditRows[2]).getByText(
'Firstname2 Lastname2',
{}
)
expect(thirdChangeEl).toBeInTheDocument()
expect(secondChangeName).toBeInTheDocument()
const secondChangeValue = within(auditRows[2]).getByText('21', {})
expect(secondChangeValue).toBeInTheDocument()

const thirdChangeName = within(auditRows[3]).getByText(
'Firstname3 Lastname3',
{}
)
expect(thirdChangeName).toBeInTheDocument()
const thirdChangeValue = within(auditRows[3]).getByText('19', {})
expect(thirdChangeValue).toBeInTheDocument()

// check that note about time zone appears
expect('audit dates are given in Africa/Cairo time').toBeInTheDocument()
expect(
getByText('audit dates are given in UTC time')
).toBeInTheDocument()
})
})
18 changes: 5 additions & 13 deletions src/data-workspace/data-details-sidebar/basic-information.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,20 @@ import { useConfig } from '@dhis2/app-runtime'
import i18n from '@dhis2/d2-i18n'
import { Tooltip, IconFlag16, colors } from '@dhis2/ui'
import React from 'react'
import { getRelativeTime } from '../../shared/index.js'
import { getRelativeTime, DateText } from '../../shared/index.js'
import FollowUpButton from './basic-information-follow-up-button.js'
import styles from './basic-information.module.css'
import ItemPropType from './item-prop-type.js'

const BasicInformation = ({ item }) => {
const { systemInfo = {} } = useConfig()
const { calendar = 'gregory', serverTimeZoneId: timezone = 'Etc/UTC' } =
systemInfo

const lastUpdatedString = item.lastUpdated
? `${item.lastUpdated} (${timezone})`
: null
const { serverTimeZoneId: timezone = 'Etc/UTC' } = systemInfo

// if item.lastUpdated is "undefined", getRelativeTime returns null
// and this will not be displayed
const timeAgo = getRelativeTime({
startDate: item.lastUpdated,
calendar,
calendar: 'gregory',
timezone,
})

Expand Down Expand Up @@ -63,14 +58,11 @@ const BasicInformation = ({ item }) => {
</li>
<li>
{item.lastUpdated && (
<Tooltip content={lastUpdatedString}>
{/* timeAgo will be null if non-Gregory calendar. TO DO: update */}
<Tooltip content={<DateText date={item.lastUpdated} />}>
{i18n.t(
'Last updated {{- timeAgo}} by {{- name}}',
{
timeAgo: timeAgo
? timeAgo
: lastUpdatedString,
timeAgo,
name: item.storedBy,
}
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ describe('<BasicInformation />', () => {
expect(getByText('a minute ago', { exact: false })).toBeInTheDocument()
})

it('renders when item was last updated (absolute time stamp with time zone) if non-gregory calendar', () => {
it('renders relative time with non-gregory calendar', () => {
useConfig.mockImplementation(() => ({
systemInfo: {
serverTimeZoneId: 'Africa/Abidjan',
Expand All @@ -115,7 +115,7 @@ describe('<BasicInformation />', () => {

expect(getByText(item.storedBy, { exact: false })).toBeInTheDocument()
expect(
getByText('2022-06-28T14:51:14.435 (Africa/Abidjan)', {
getByText('a minute ago', {
exact: false,
})
).toBeInTheDocument()
Expand Down
24 changes: 16 additions & 8 deletions src/data-workspace/data-details-sidebar/history-line-chart.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,20 +49,28 @@ function sortHistoryByStartDate(history, calendar = 'gregory') {
}).startDate

// date comparison
// date comparison (both in system calendar)
if (
isDateAGreaterThanDateB(leftStartDate, rightStartDate, {
calendar,
inclusive: false,
})
isDateAGreaterThanDateB(
{ date: leftStartDate, calendar },
{ date: rightStartDate, calendar },
{
inclusive: false,
}
)
) {
return 1
}

if (
isDateALessThanDateB(leftStartDate, rightStartDate, {
calendar,
inclusive: false,
})
// date comparison (both are system calendar)
isDateALessThanDateB(
{ date: leftStartDate, calendar },
{ date: rightStartDate, calendar },
{
inclusive: false,
}
)
) {
return -1
}
Expand Down
Loading

0 comments on commit 9722a21

Please sign in to comment.