Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
# [100.11.0](https://github.com/dhis2/settings-app/compare/v100.10.0...v100.11.0) (2025-11-18)


### Features

* add orgUnitCentroidsInEventsAnalytics to analytics settings ([cb81cde](https://github.com/dhis2/settings-app/commit/cb81cdee9014f97bdd6ddd6d743ea9ec8a43f661))
* add orgUnitCentroidsInEventsAnalytics to analytics settings ([e5c0ecf](https://github.com/dhis2/settings-app/commit/e5c0ecf84a5cd857eeae9ce30fcbbc9f4fa322f3))

# [100.10.0](https://github.com/dhis2/settings-app/compare/v100.9.1...v100.10.0) (2025-09-25)


Expand Down
100 changes: 77 additions & 23 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: 2025-09-24T08:44:28.347Z\n"
"PO-Revision-Date: 2025-09-24T08:44:28.348Z\n"
"POT-Creation-Date: 2025-12-17T08:41:50.755Z\n"
"PO-Revision-Date: 2025-12-17T08:41:50.755Z\n"

msgid "Failed to load: {{error}}"
msgstr "Failed to load: {{error}}"
Expand Down Expand Up @@ -167,12 +167,78 @@ msgstr "Name"
msgid "Password"
msgstr "Password"

msgid "Daily"
msgstr "Daily"

msgid "Weekly"
msgstr "Weekly"

msgid "Monthly"
msgstr "Monthly"

msgid "Bi-monthly"
msgstr "Bi-monthly"

msgid "Yearly"
msgstr "Yearly"

msgid "Bi-weekly"
msgstr "Bi-weekly"

msgid "Quarterly"
msgstr "Quarterly"

msgid "Six-monthly"
msgstr "Six-monthly"

msgid "Weekly (start {{day}})"
msgstr "Weekly (start {{day}})"

msgid "Financial year (start {{month}})"
msgstr "Financial year (start {{month}})"

msgid "Six-monthly (start {{month}})"
msgstr "Six-monthly (start {{month}})"

msgid "Quarterly (start {{month}})"
msgstr "Quarterly (start {{month}})"

msgid "Days"
msgstr "Days"

msgid "Weeks"
msgstr "Weeks"

msgid "Bi-weeks"
msgstr "Bi-weeks"

msgid "Months"
msgstr "Months"

msgid "Bi-months"
msgstr "Bi-months"

msgid "Quarters"
msgstr "Quarters"

msgid "Six months"
msgstr "Six months"

msgid "Years"
msgstr "Years"

msgid "Other"
msgstr "Other"

msgid "Settings updated"
msgstr "Settings updated"

msgid "There was a problem updating settings. Changes have not been saved."
msgstr "There was a problem updating settings. Changes have not been saved."

msgid "Period types available in analytics apps"
msgstr "Period types available in analytics apps"

msgid "General"
msgstr "General"

Expand Down Expand Up @@ -301,30 +367,9 @@ msgstr "Infrastructural data elements"
msgid "Infrastructural period type"
msgstr "Infrastructural period type"

msgid "Daily"
msgstr "Daily"

msgid "Weekly"
msgstr "Weekly"

msgid "Monthly"
msgstr "Monthly"

msgid "Bi-monthly"
msgstr "Bi-monthly"

msgid "Quarterly"
msgstr "Quarterly"

msgid "Six-monthly"
msgstr "Six-monthly"

msgid "Six-monthly April"
msgstr "Six-monthly April"

msgid "Yearly"
msgstr "Yearly"

msgid "Financial-April"
msgstr "Financial-April"

Expand Down Expand Up @@ -478,6 +523,12 @@ msgstr "Hide monthly periods"
msgid "Hide bimonthly periods"
msgstr "Hide bimonthly periods"

msgid "Period types"
msgstr "Period types"

msgid "Allowed period types"
msgstr "Allowed period types"

msgid "Financial year relative period start month"
msgstr "Financial year relative period start month"

Expand Down Expand Up @@ -909,6 +960,9 @@ msgstr "Enable Gist Overview"
msgid "Clean idle jobs after (in milliseconds)"
msgstr "Clean idle jobs after (in milliseconds)"

msgid "Use centroids for organisation unit polygons in event analytics"
msgstr "Use centroids for organisation unit polygons in event analytics"

msgctxt "Application title"
msgid "__MANIFEST_APP_TITLE"
msgstr "System Settings"
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "settings-app",
"version": "100.10.0",
"version": "100.11.0",
"description": "",
"license": "BSD-3-Clause",
"private": true,
Expand Down Expand Up @@ -34,5 +34,6 @@
"material-ui": "0.20.2",
"prop-types": "^15.7.2",
"rxjs": "5.5.7"
}
},
"packageManager": "[email protected]+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
}
215 changes: 215 additions & 0 deletions src/period-types/PeriodTypes.component.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
import { useDataQuery } from '@dhis2/app-runtime'
import i18n from '@dhis2/d2-i18n'
import { CenteredContent, CircularLoader } from '@dhis2/ui'
import { getInstance as getD2 } from 'd2'
import CheckboxMaterial from 'material-ui/Checkbox'
import React, { useState, useCallback } from 'react'
import settingsActions from '../settingsActions.js'
import styles from './PeriodTypes.module.css'

const query = {
periodTypes: {
resource: 'periodTypes',
},
dataOutputPeriodTypes: {
resource: 'configuration/dataOutputPeriodTypes',
},
}

const formatPeriodTypeName = (name) => {
const simpleLabels = {
Daily: i18n.t('Daily'),
Weekly: i18n.t('Weekly'),
Monthly: i18n.t('Monthly'),
BiMonthly: i18n.t('Bi-monthly'),
Yearly: i18n.t('Yearly'),
BiWeekly: i18n.t('Bi-weekly'),
Quarterly: i18n.t('Quarterly'),
SixMonthly: i18n.t('Six-monthly'),
}

if (simpleLabels[name]) {
return simpleLabels[name]
}

const monthMap = {
April: 'April',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these should be translated

July: 'July',
Oct: 'October',
Nov: 'November',
}

if (name.startsWith('Weekly')) {
const day = name.replace('Weekly', '')
return day
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the day won't be translated here, so you'd need to also create a dayMap and add translations for the weekdays

? i18n.t('Weekly (start {{day}})', { day })
: simpleLabels.Weekly
}

if (name.startsWith('Financial')) {
const monthAbbrev = name.replace('Financial', '')
const month = monthMap[monthAbbrev] || monthAbbrev
return i18n.t('Financial year (start {{month}})', { month })
}

if (name.startsWith('SixMonthly')) {
const monthAbbrev = name.replace('SixMonthly', '')
const month = monthMap[monthAbbrev] || monthAbbrev
return monthAbbrev
? i18n.t('Six-monthly (start {{month}})', { month })
: simpleLabels.SixMonthly
}

if (name.startsWith('Quarterly')) {
const monthAbbrev = name.replace('Quarterly', '')
const month = monthMap[monthAbbrev] || monthAbbrev
return monthAbbrev
? i18n.t('Quarterly (start {{month}})', { month })
: simpleLabels.Quarterly
}

return name
.split(/(?=[A-Z])/)
.join(' ')
.trim()
}

const getGroupLabel = (frequencyOrder) => {
const labels = {
1: i18n.t('Days'),
7: i18n.t('Weeks'),
14: i18n.t('Bi-weeks'),
30: i18n.t('Months'),
60: i18n.t('Bi-months'),
91: i18n.t('Quarters'),
182: i18n.t('Six months'),
365: i18n.t('Years'),
}
return labels[frequencyOrder] || i18n.t('Other')
}

const groupByFrequency = (periodTypes) => {
const groups = {}
periodTypes.forEach((pt) => {
const freq = pt.frequencyOrder
if (!groups[freq]) {
groups[freq] = {
label: getGroupLabel(freq),
frequencyOrder: freq,
periodTypes: [],
}
}
groups[freq].periodTypes.push(pt)
})
return Object.values(groups).sort(
(a, b) => a.frequencyOrder - b.frequencyOrder
)
}

const PeriodTypes = () => {
const { loading, data, refetch } = useDataQuery(query)
const [updating, setUpdating] = useState(false)

const handlePeriodTypeToggle = useCallback(
async (periodTypeName, isCurrentlyEnabled) => {
setUpdating(true)
try {
const d2 = await getD2()
const api = d2.Api.getApi()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we use useDataMutation ? or is that not working for some reason. I think it would be better not to fetch with app-runtime tooling and post with d2 (also would prefer to not use d2 in any new code that is not relying heavily on existing settings app code)

const allowedPeriodTypes = data?.dataOutputPeriodTypes || []
const currentAllowedSet = new Set(
allowedPeriodTypes.map((pt) =>
typeof pt === 'string' ? pt : pt.name
)
)

if (isCurrentlyEnabled) {
currentAllowedSet.delete(periodTypeName)
} else {
currentAllowedSet.add(periodTypeName)
}

const updatedPeriodTypes = Array.from(currentAllowedSet).map(
(name) => ({ name })
)

await api.post(
'configuration/dataOutputPeriodTypes',
updatedPeriodTypes
)

await refetch()
settingsActions.showSnackbarMessage(i18n.t('Settings updated'))
} catch (err) {
console.error('Failed to update period types:', err)
settingsActions.showSnackbarMessage(
i18n.t(
'There was a problem updating settings. Changes have not been saved.'
)
)
} finally {
setUpdating(false)
}
},
[data, refetch]
)

if (loading) {
return (
<CenteredContent>
<CircularLoader />
</CenteredContent>
)
}

const allPeriodTypes = data?.periodTypes?.periodTypes || []
const allowedPeriodTypes = data?.dataOutputPeriodTypes || []
const allowedSet = new Set(
allowedPeriodTypes.map((pt) => (typeof pt === 'string' ? pt : pt.name))
)
const groupedPeriodTypes = groupByFrequency(allPeriodTypes)

return (
<div className={styles.wrapper}>
<p className={styles.sectionLabel}>
{i18n.t('Period types available in analytics apps')}
</p>
<div className={styles.groupsWrapper}>
{groupedPeriodTypes.map((group) => (
<div key={group.frequencyOrder} className={styles.group}>
<p className={styles.groupLabel}>{group.label}</p>
<div className={styles.checkboxList}>
{group.periodTypes.map((periodType) => {
const isEnabled = allowedSet.has(
periodType.name
)
return (
<div
key={periodType.name}
className={styles.checkboxItem}
>
<CheckboxMaterial
checked={isEnabled}
disabled={updating}
label={formatPeriodTypeName(
periodType.name
)}
onCheck={() =>
handlePeriodTypeToggle(
periodType.name,
isEnabled
)
}
/>
</div>
)
})}
</div>
</div>
))}
</div>
</div>
)
}

export default PeriodTypes
Loading
Loading