@dhis2/analytics 21.8.2 → 21.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -147,20 +147,6 @@
147
147
  "Fixed periods": "Fixed periods",
148
148
  "Selected Periods": "Selected Periods",
149
149
  "No periods selected": "No periods selected",
150
- "January": "January",
151
- "February": "February",
152
- "March": "March",
153
- "April": "April",
154
- "May": "May",
155
- "June": "June",
156
- "July": "July",
157
- "August": "August",
158
- "September": "September",
159
- "October": "October",
160
- "November": "November",
161
- "December": "December",
162
- "Week {{weekNumber}}": "Week {{weekNumber}}",
163
- "Bi-Week {{biWeekNumber}}": "Bi-Week {{biWeekNumber}}",
164
150
  "Daily": "Daily",
165
151
  "Weekly": "Weekly",
166
152
  "Weekly (Start Wednesday)": "Weekly (Start Wednesday)",
@@ -11,6 +11,8 @@ var _predefinedDimensions = require("../predefinedDimensions.js");
11
11
 
12
12
  var _AdaptiveClippingController = require("./AdaptiveClippingController.js");
13
13
 
14
+ var _addToTotalIfNumber = require("./addToTotalIfNumber.js");
15
+
14
16
  var _parseValue = require("./parseValue.js");
15
17
 
16
18
  var _pivotTableConstants = require("./pivotTableConstants.js");
@@ -611,10 +613,7 @@ class PivotTableEngine {
611
613
  dataFields.forEach(field => {
612
614
  const headerIndex = this.dimensionLookup.dataHeaders[field];
613
615
  const value = (0, _parseValue.parseValue)(dataRow[headerIndex]);
614
-
615
- if (value && !isNaN(value)) {
616
- totalCell[field] = (totalCell[field] || 0) + value;
617
- }
616
+ totalCell[field] = (0, _addToTotalIfNumber.addToTotalIfNumber)(value, totalCell[field]);
618
617
  });
619
618
  }
620
619
 
@@ -633,10 +632,7 @@ class PivotTableEngine {
633
632
  dataFields.forEach(field => {
634
633
  const headerIndex = this.dimensionLookup.dataHeaders[field];
635
634
  const value = (0, _parseValue.parseValue)(dataRow[headerIndex]);
636
-
637
- if (value && !isNaN(value)) {
638
- percentageTotal[field] = (percentageTotal[field] || 0) + value;
639
- }
635
+ percentageTotal[field] = (0, _addToTotalIfNumber.addToTotalIfNumber)(value, percentageTotal[field]);
640
636
  });
641
637
 
642
638
  if (totals.columnSubtotal) {
@@ -651,10 +647,7 @@ class PivotTableEngine {
651
647
  dataFields.forEach(field => {
652
648
  const headerIndex = this.dimensionLookup.dataHeaders[field];
653
649
  const value = (0, _parseValue.parseValue)(dataRow[headerIndex]);
654
-
655
- if (value && !isNaN(value)) {
656
- percentageTotal[field] = (percentageTotal[field] || 0) + value;
657
- }
650
+ percentageTotal[field] = (0, _addToTotalIfNumber.addToTotalIfNumber)(value, percentageTotal[field]);
658
651
  });
659
652
  }
660
653
 
@@ -670,10 +663,7 @@ class PivotTableEngine {
670
663
  dataFields.forEach(field => {
671
664
  const headerIndex = this.dimensionLookup.dataHeaders[field];
672
665
  const value = (0, _parseValue.parseValue)(dataRow[headerIndex]);
673
-
674
- if (value && !isNaN(value)) {
675
- percentageTotal[field] = (percentageTotal[field] || 0) + value;
676
- }
666
+ percentageTotal[field] = (0, _addToTotalIfNumber.addToTotalIfNumber)(value, percentageTotal[field]);
677
667
  });
678
668
  }
679
669
  }
@@ -690,10 +680,7 @@ class PivotTableEngine {
690
680
  dataFields.forEach(field => {
691
681
  const headerIndex = this.dimensionLookup.dataHeaders[field];
692
682
  const value = (0, _parseValue.parseValue)(dataRow[headerIndex]);
693
-
694
- if (value && !isNaN(value)) {
695
- percentageTotal[field] = (percentageTotal[field] || 0) + value;
696
- }
683
+ percentageTotal[field] = (0, _addToTotalIfNumber.addToTotalIfNumber)(value, percentageTotal[field]);
697
684
  });
698
685
 
699
686
  if (totals.rowSubtotal) {
@@ -708,10 +695,7 @@ class PivotTableEngine {
708
695
  dataFields.forEach(field => {
709
696
  const headerIndex = this.dimensionLookup.dataHeaders[field];
710
697
  const value = (0, _parseValue.parseValue)(dataRow[headerIndex]);
711
-
712
- if (value && !isNaN(value)) {
713
- percentageTotal[field] = (percentageTotal[field] || 0) + value;
714
- }
698
+ percentageTotal[field] = (0, _addToTotalIfNumber.addToTotalIfNumber)(value, percentageTotal[field]);
715
699
  });
716
700
  }
717
701
 
@@ -727,10 +711,7 @@ class PivotTableEngine {
727
711
  dataFields.forEach(field => {
728
712
  const headerIndex = this.dimensionLookup.dataHeaders[field];
729
713
  const value = (0, _parseValue.parseValue)(dataRow[headerIndex]);
730
-
731
- if (value && !isNaN(value)) {
732
- percentageTotal[field] = (percentageTotal[field] || 0) + value;
733
- }
714
+ percentageTotal[field] = (0, _addToTotalIfNumber.addToTotalIfNumber)(value, percentageTotal[field]);
734
715
  });
735
716
  }
736
717
  }
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+
3
+ var _addToTotalIfNumber = require("../addToTotalIfNumber.js");
4
+
5
+ const tests = [{
6
+ testName: 'negative value',
7
+ value: -1,
8
+ total: undefined,
9
+ expected: -1
10
+ }, {
11
+ testName: 'zero value',
12
+ value: 0,
13
+ total: undefined,
14
+ expected: 0
15
+ }, {
16
+ testName: 'positive value',
17
+ value: 1,
18
+ total: undefined,
19
+ expected: 1
20
+ }, {
21
+ testName: 'null value',
22
+ value: null,
23
+ total: undefined,
24
+ expected: undefined
25
+ }, {
26
+ testName: 'undefined value',
27
+ value: undefined,
28
+ total: undefined,
29
+ expected: undefined
30
+ }, {
31
+ testName: 'string value',
32
+ value: 'string',
33
+ total: undefined,
34
+ expected: undefined
35
+ }, {
36
+ testName: 'negative value with existing total',
37
+ value: -1,
38
+ total: 100,
39
+ expected: 99
40
+ }, {
41
+ testName: 'zero value with existing total',
42
+ value: 0,
43
+ total: 100,
44
+ expected: 100
45
+ }, {
46
+ testName: 'positive value with existing total',
47
+ value: 1,
48
+ total: 100,
49
+ expected: 101
50
+ }, {
51
+ testName: 'null value with existing total',
52
+ value: null,
53
+ total: 100,
54
+ expected: 100
55
+ }, {
56
+ testName: 'undefined value with existing total',
57
+ value: undefined,
58
+ total: 100,
59
+ expected: 100
60
+ }, {
61
+ testName: 'string value with existing total',
62
+ value: 'string',
63
+ total: 100,
64
+ expected: 100
65
+ }];
66
+ describe('addToTotalIfNumber', () => {
67
+ tests.forEach(t => {
68
+ it(t.testName, () => {
69
+ expect((0, _addToTotalIfNumber.addToTotalIfNumber)(t.value, t.total)).toEqual(t.expected);
70
+ });
71
+ });
72
+ });
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.addToTotalIfNumber = void 0;
7
+
8
+ const addToTotalIfNumber = (value, total) => typeof value === 'number' && Number.isFinite(value) ? (total !== null && total !== void 0 ? total : 0) + value : total;
9
+
10
+ exports.addToTotalIfNumber = addToTotalIfNumber;
@@ -1,7 +1,16 @@
1
+ import { useConfig, useDataQuery } from '@dhis2/app-runtime';
1
2
  import PropTypes from 'prop-types';
2
3
  import React from 'react';
3
4
  import { DIMENSION_ID_PERIOD } from '../../modules/predefinedDimensions.js';
4
5
  import PeriodTransfer from './PeriodTransfer.js';
6
+ const userSettingsQuery = {
7
+ userSettings: {
8
+ resource: 'userSettings',
9
+ params: {
10
+ key: ['keyUiLocale']
11
+ }
12
+ }
13
+ };
5
14
 
6
15
  const PeriodDimension = ({
7
16
  onSelect,
@@ -9,6 +18,25 @@ const PeriodDimension = ({
9
18
  rightFooter,
10
19
  excludedPeriodTypes
11
20
  }) => {
21
+ const {
22
+ systemInfo
23
+ } = useConfig();
24
+ const result = useDataQuery(userSettingsQuery);
25
+ const {
26
+ calendar = 'gregory'
27
+ } = systemInfo;
28
+ const {
29
+ data: {
30
+ userSettings: {
31
+ keyUiLocale: locale
32
+ } = {}
33
+ } = {}
34
+ } = result;
35
+ const periodsSettings = {
36
+ calendar,
37
+ locale
38
+ };
39
+
12
40
  const selectPeriods = periods => {
13
41
  onSelect({
14
42
  dimensionId: DIMENSION_ID_PERIOD,
@@ -21,7 +49,8 @@ const PeriodDimension = ({
21
49
  initialSelectedPeriods: selectedPeriods,
22
50
  rightFooter: rightFooter,
23
51
  dataTest: 'period-dimension',
24
- excludedPeriodTypes: excludedPeriodTypes
52
+ excludedPeriodTypes: excludedPeriodTypes,
53
+ periodsSettings: periodsSettings
25
54
  });
26
55
  };
27
56
 
@@ -2,6 +2,7 @@ import _JSXStyle from "styled-jsx/style";
2
2
 
3
3
  function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
4
4
 
5
+ import { getNowInCalendar } from '@dhis2/multi-calendar-dates';
5
6
  import { TabBar, Tab, Transfer } from '@dhis2/ui';
6
7
  import PropTypes from 'prop-types';
7
8
  import React, { useState } from 'react';
@@ -22,11 +23,15 @@ const PeriodTransfer = ({
22
23
  dataTest,
23
24
  initialSelectedPeriods,
24
25
  rightFooter,
25
- excludedPeriodTypes
26
+ excludedPeriodTypes,
27
+ periodsSettings
26
28
  }) => {
27
29
  const defaultRelativePeriodType = excludedPeriodTypes.includes(MONTHLY) ? getRelativePeriodsOptionsById(QUARTERLY) : getRelativePeriodsOptionsById(MONTHLY);
28
- const defaultFixedPeriodType = excludedPeriodTypes.includes(MONTHLY) ? getFixedPeriodsOptionsById(QUARTERLY) : getFixedPeriodsOptionsById(MONTHLY);
29
- const defaultFixedPeriodYear = new Date().getFullYear();
30
+ const defaultFixedPeriodType = excludedPeriodTypes.includes(MONTHLY) ? getFixedPeriodsOptionsById(QUARTERLY, periodsSettings) : getFixedPeriodsOptionsById(MONTHLY, periodsSettings);
31
+ const now = getNowInCalendar(periodsSettings.calendar); // use ".eraYear" rather than ".year" because in Ethiopian calendar, eraYear is what our users expect to see (for other calendars, it doesn't matter)
32
+ // there is still a pending decision in Temporal regarding which era to use by default: https://github.com/js-temporal/temporal-polyfill/blob/9350ee7dd0d29f329fc097debf923a517c32f813/lib/calendar.ts#L1964
33
+
34
+ const defaultFixedPeriodYear = now.eraYear || now.year;
30
35
 
31
36
  const fixedPeriodConfig = year => ({
32
37
  offset: year - defaultFixedPeriodYear,
@@ -48,7 +53,7 @@ const PeriodTransfer = ({
48
53
  const onIsRelativeClick = state => {
49
54
  if (state !== isRelative) {
50
55
  setIsRelative(state);
51
- setAllPeriods(state ? getRelativePeriodsOptionsById(relativeFilter.periodType).getPeriods() : getFixedPeriodsOptionsById(fixedFilter.periodType).getPeriods(fixedPeriodConfig(Number(fixedFilter.year))));
56
+ setAllPeriods(state ? getRelativePeriodsOptionsById(relativeFilter.periodType).getPeriods() : getFixedPeriodsOptionsById(fixedFilter.periodType, periodsSettings).getPeriods(fixedPeriodConfig(Number(fixedFilter.year))));
52
57
  }
53
58
  };
54
59
 
@@ -101,7 +106,7 @@ const PeriodTransfer = ({
101
106
 
102
107
  const onSelectFixedPeriods = filter => {
103
108
  setFixedFilter(filter);
104
- setAllPeriods(getFixedPeriodsOptionsById(filter.periodType).getPeriods(fixedPeriodConfig(Number(filter.year))));
109
+ setAllPeriods(getFixedPeriodsOptionsById(filter.periodType, periodsSettings).getPeriods(fixedPeriodConfig(Number(filter.year)), periodsSettings));
105
110
  };
106
111
 
107
112
  const renderEmptySelection = () => /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("p", {
@@ -147,7 +152,11 @@ const PeriodTransfer = ({
147
152
 
148
153
  PeriodTransfer.defaultProps = {
149
154
  initialSelectedPeriods: [],
150
- excludedPeriodTypes: []
155
+ excludedPeriodTypes: [],
156
+ periodsSettings: {
157
+ calendar: 'gregory',
158
+ locale: 'en'
159
+ }
151
160
  };
152
161
  PeriodTransfer.propTypes = {
153
162
  onSelect: PropTypes.func.isRequired,
@@ -157,6 +166,10 @@ PeriodTransfer.propTypes = {
157
166
  id: PropTypes.string,
158
167
  name: PropTypes.string
159
168
  })),
169
+ periodsSettings: PropTypes.shape({
170
+ calendar: PropTypes.string,
171
+ locale: PropTypes.string
172
+ }),
160
173
  rightFooter: PropTypes.node
161
174
  };
162
175
  export default PeriodTransfer;
@@ -1,6 +1,19 @@
1
1
  import { shallow } from 'enzyme';
2
2
  import React from 'react';
3
3
  import PeriodDimension from '../PeriodDimension.js';
4
+ jest.mock('@dhis2/app-runtime', () => ({
5
+ useConfig: () => ({
6
+ systemInfo: {}
7
+ }),
8
+ useDataQuery: () => ({
9
+ data: {
10
+ userSettings: {
11
+ keyUiLocale: 'en'
12
+ }
13
+ }
14
+ })
15
+ }));
16
+ afterEach(jest.clearAllMocks);
4
17
  describe('The Period Dimension component', () => {
5
18
  let props;
6
19
  let shallowPeriodDimension;
@@ -6,6 +6,12 @@ exports[`The Period Dimension component matches the snapshot 1`] = `
6
6
  excludedPeriodTypes={Array []}
7
7
  initialSelectedPeriods={Array []}
8
8
  onSelect={[Function]}
9
+ periodsSettings={
10
+ Object {
11
+ "calendar": "gregory",
12
+ "locale": "en",
13
+ }
14
+ }
9
15
  rightFooter={<React.Fragment />}
10
16
  />
11
17
  `;