@dhis2/analytics 24.10.3 → 24.10.4

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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## [24.10.4](https://github.com/dhis2/analytics/compare/v24.10.3...v24.10.4) (2024-04-02)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * interpretations panel renders with flashing when liking or unliking an interpretation ([#1643](https://github.com/dhis2/analytics/issues/1643)) ([4148bf9](https://github.com/dhis2/analytics/commit/4148bf9ae1c8aa386abd7b2b7ad2c01636d8b06d)), closes [#1600](https://github.com/dhis2/analytics/issues/1600)
7
+
1
8
  ## [24.10.3](https://github.com/dhis2/analytics/compare/v24.10.2...v24.10.3) (2024-03-20)
2
9
 
3
10
 
@@ -90,7 +90,7 @@ const InterpretationModal = _ref2 => {
90
90
  });
91
91
  const interpretation = data === null || data === void 0 ? void 0 : data.interpretation;
92
92
  const shouldRenderModalContent = !error && interpretation;
93
- const shouldCssHideModal = loading || isVisualizationLoading;
93
+ const loadingInProgress = loading || isVisualizationLoading;
94
94
 
95
95
  const handleClose = () => {
96
96
  if (isDirty) {
@@ -111,6 +111,15 @@ const InterpretationModal = _ref2 => {
111
111
  });
112
112
  };
113
113
 
114
+ const onLikeToggled = _ref3 => {
115
+ let {
116
+ likedBy
117
+ } = _ref3;
118
+ setIsDirty(true);
119
+ interpretation.likedBy = likedBy;
120
+ interpretation.likes = likedBy.length;
121
+ };
122
+
114
123
  const onInterpretationDeleted = () => {
115
124
  setIsDirty(false);
116
125
  onInterpretationUpdate();
@@ -124,11 +133,11 @@ const InterpretationModal = _ref2 => {
124
133
  });
125
134
  }
126
135
  }, [interpretationId, refetch]);
127
- return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, shouldCssHideModal && /*#__PURE__*/_react.default.createElement(_ui.Layer, null, /*#__PURE__*/_react.default.createElement(_ui.CenteredContent, null, /*#__PURE__*/_react.default.createElement(_ui.CircularLoader, null))), /*#__PURE__*/_react.default.createElement(_ui.Modal, {
136
+ return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, loadingInProgress && /*#__PURE__*/_react.default.createElement(_ui.Layer, null, /*#__PURE__*/_react.default.createElement(_ui.CenteredContent, null, /*#__PURE__*/_react.default.createElement(_ui.CircularLoader, null))), /*#__PURE__*/_react.default.createElement(_ui.Modal, {
128
137
  fluid: true,
129
138
  onClose: handleClose,
130
139
  className: (0, _classnames.default)(modalCSS.className, {
131
- hidden: shouldCssHideModal
140
+ hidden: loadingInProgress
132
141
  }),
133
142
  dataTest: "interpretation-modal"
134
143
  }, /*#__PURE__*/_react.default.createElement("h1", {
@@ -166,7 +175,8 @@ const InterpretationModal = _ref2 => {
166
175
  onInterpretationDeleted: onInterpretationDeleted,
167
176
  onThreadUpdated: onThreadUpdated,
168
177
  initialFocus: initialFocus,
169
- downloadMenuComponent: downloadMenuComponent
178
+ downloadMenuComponent: downloadMenuComponent,
179
+ onLikeToggled: onLikeToggled
170
180
  }))))), /*#__PURE__*/_react.default.createElement(_ui.ModalActions, null, /*#__PURE__*/_react.default.createElement(_ui.Button, {
171
181
  disabled: fetching,
172
182
  onClick: handleClose
@@ -37,6 +37,7 @@ const InterpretationThread = _ref => {
37
37
  fetching,
38
38
  interpretation,
39
39
  onInterpretationDeleted,
40
+ onLikeToggled,
40
41
  initialFocus,
41
42
  onThreadUpdated,
42
43
  downloadMenuComponent: DownloadMenu
@@ -76,7 +77,8 @@ const InterpretationThread = _ref => {
76
77
  return (_focusRef$current = focusRef.current) === null || _focusRef$current === void 0 ? void 0 : _focusRef$current.focus();
77
78
  },
78
79
  onUpdated: () => onThreadUpdated(true),
79
- onDeleted: onInterpretationDeleted
80
+ onDeleted: onInterpretationDeleted,
81
+ onLikeToggled: onLikeToggled
80
82
  }), /*#__PURE__*/_react.default.createElement("div", {
81
83
  className: "jsx-615306698" + " " + 'comments'
82
84
  }, interpretation.comments.map(comment => /*#__PURE__*/_react.default.createElement(_Comment.Comment, {
@@ -101,6 +103,7 @@ InterpretationThread.propTypes = {
101
103
  fetching: _propTypes.default.bool.isRequired,
102
104
  interpretation: _propTypes.default.object.isRequired,
103
105
  onInterpretationDeleted: _propTypes.default.func.isRequired,
106
+ onLikeToggled: _propTypes.default.func.isRequired,
104
107
  downloadMenuComponent: _propTypes.default.oneOfType([_propTypes.default.object, _propTypes.default.func]),
105
108
  initialFocus: _propTypes.default.bool,
106
109
  onThreadUpdated: _propTypes.default.func
@@ -41,6 +41,7 @@ const InterpretationList = _ref => {
41
41
  currentUser,
42
42
  interpretations,
43
43
  onInterpretationClick,
44
+ onLikeToggled,
44
45
  onReplyIconClick,
45
46
  refresh,
46
47
  disabled
@@ -79,6 +80,7 @@ const InterpretationList = _ref => {
79
80
  interpretation: interpretation,
80
81
  currentUser: currentUser,
81
82
  onClick: onInterpretationClick,
83
+ onLikeToggled: onLikeToggled,
82
84
  onReplyIconClick: onReplyIconClick,
83
85
  onDeleted: refresh,
84
86
  onUpdated: refresh,
@@ -95,6 +97,7 @@ InterpretationList.propTypes = {
95
97
  interpretations: _propTypes.default.array.isRequired,
96
98
  refresh: _propTypes.default.func.isRequired,
97
99
  onInterpretationClick: _propTypes.default.func.isRequired,
100
+ onLikeToggled: _propTypes.default.func.isRequired,
98
101
  onReplyIconClick: _propTypes.default.func.isRequired,
99
102
  disabled: _propTypes.default.bool
100
103
  };
@@ -55,13 +55,14 @@ const InterpretationsUnit = /*#__PURE__*/(0, _react.forwardRef)((_ref2, ref) =>
55
55
  renderId
56
56
  } = _ref2;
57
57
  const [isExpanded, setIsExpanded] = (0, _react.useState)(true);
58
+ const [interpretations, setInterpretations] = (0, _react.useState)([]);
58
59
  const {
59
- data,
60
60
  loading,
61
61
  fetching,
62
62
  refetch
63
63
  } = (0, _appRuntime.useDataQuery)(interpretationsQuery, {
64
- lazy: true
64
+ lazy: true,
65
+ onComplete: data => setInterpretations(data.interpretations.interpretations)
65
66
  });
66
67
  const onCompleteAction = (0, _react.useCallback)(() => {
67
68
  refetch({
@@ -80,6 +81,17 @@ const InterpretationsUnit = /*#__PURE__*/(0, _react.forwardRef)((_ref2, ref) =>
80
81
  });
81
82
  }
82
83
  }, [type, id, renderId, refetch]);
84
+
85
+ const onLikeToggled = _ref3 => {
86
+ let {
87
+ id,
88
+ likedBy
89
+ } = _ref3;
90
+ const interpretation = interpretations.find(interp => interp.id === id);
91
+ interpretation.likedBy = likedBy;
92
+ interpretation.likes = likedBy.length;
93
+ };
94
+
83
95
  return /*#__PURE__*/_react.default.createElement("div", {
84
96
  className: _style.default.dynamic([["4120713286", [_ui.spacers.dp16, _ui.colors.grey400, _ui.colors.white, _ui.spacers.dp32, _ui.colors.grey900]]]) + " " + ((0, _classnames.default)('container', {
85
97
  expanded: isExpanded
@@ -101,7 +113,7 @@ const InterpretationsUnit = /*#__PURE__*/(0, _react.forwardRef)((_ref2, ref) =>
101
113
  className: _style.default.dynamic([["4120713286", [_ui.spacers.dp16, _ui.colors.grey400, _ui.colors.white, _ui.spacers.dp32, _ui.colors.grey900]]]) + " " + "loader"
102
114
  }, /*#__PURE__*/_react.default.createElement(_ui.CircularLoader, {
103
115
  small: true
104
- })), data && /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_InterpretationForm.InterpretationForm, {
116
+ })), interpretations && /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_InterpretationForm.InterpretationForm, {
105
117
  currentUser: currentUser,
106
118
  type: type,
107
119
  id: id,
@@ -109,8 +121,9 @@ const InterpretationsUnit = /*#__PURE__*/(0, _react.forwardRef)((_ref2, ref) =>
109
121
  disabled: disabled
110
122
  }), /*#__PURE__*/_react.default.createElement(_InterpretationList.InterpretationList, {
111
123
  currentUser: currentUser,
112
- interpretations: data.interpretations.interpretations,
124
+ interpretations: interpretations,
113
125
  onInterpretationClick: onInterpretationClick,
126
+ onLikeToggled: onLikeToggled,
114
127
  onReplyIconClick: onReplyIconClick,
115
128
  refresh: onCompleteAction,
116
129
  disabled: disabled
@@ -35,7 +35,8 @@ const Interpretation = _ref => {
35
35
  onUpdated,
36
36
  onDeleted,
37
37
  disabled,
38
- onReplyIconClick
38
+ onReplyIconClick,
39
+ onLikeToggled
39
40
  } = _ref;
40
41
  const [isUpdateMode, setIsUpdateMode] = (0, _react.useState)(false);
41
42
  const [showSharingDialog, setShowSharingDialog] = (0, _react.useState)(false);
@@ -46,7 +47,10 @@ const Interpretation = _ref => {
46
47
  } = (0, _useLike.useLike)({
47
48
  interpretation,
48
49
  currentUser,
49
- onComplete: onUpdated
50
+ onComplete: likedBy => onLikeToggled({
51
+ id: interpretation.id,
52
+ likedBy
53
+ })
50
54
  });
51
55
  const shouldShowButton = !!onClick && !disabled;
52
56
  return isUpdateMode ? /*#__PURE__*/_react.default.createElement(_InterpretationUpdateForm.InterpretationUpdateForm, {
@@ -107,6 +111,7 @@ Interpretation.propTypes = {
107
111
  currentUser: _propTypes.default.object.isRequired,
108
112
  interpretation: _propTypes.default.object.isRequired,
109
113
  onDeleted: _propTypes.default.func.isRequired,
114
+ onLikeToggled: _propTypes.default.func.isRequired,
110
115
  onReplyIconClick: _propTypes.default.func.isRequired,
111
116
  onUpdated: _propTypes.default.func.isRequired,
112
117
  disabled: _propTypes.default.bool,
@@ -27,12 +27,22 @@ const useLike = _ref => {
27
27
  const [like, {
28
28
  loading: likeLoading
29
29
  }] = (0, _appRuntime.useDataMutation)(likeMutationRef.current, {
30
- onComplete
30
+ onComplete: () => {
31
+ const newLikedBy = interpretation.likedBy.concat({
32
+ id: currentUser.id
33
+ });
34
+ setIsLikedByCurrentUser(true);
35
+ onComplete(newLikedBy);
36
+ }
31
37
  });
32
38
  const [unlike, {
33
39
  loading: unlikeLoading
34
40
  }] = (0, _appRuntime.useDataMutation)(unlikeMutationRef.current, {
35
- onComplete
41
+ onComplete: () => {
42
+ const newLikedBy = interpretation.likedBy.filter(lb => lb.id !== currentUser.id);
43
+ setIsLikedByCurrentUser(false);
44
+ onComplete(newLikedBy);
45
+ }
36
46
  });
37
47
  const [isLikedByCurrentUser, setIsLikedByCurrentUser] = (0, _react.useState)(false);
38
48
 
@@ -68,7 +68,7 @@ const InterpretationModal = _ref2 => {
68
68
  });
69
69
  const interpretation = data === null || data === void 0 ? void 0 : data.interpretation;
70
70
  const shouldRenderModalContent = !error && interpretation;
71
- const shouldCssHideModal = loading || isVisualizationLoading;
71
+ const loadingInProgress = loading || isVisualizationLoading;
72
72
 
73
73
  const handleClose = () => {
74
74
  if (isDirty) {
@@ -89,6 +89,15 @@ const InterpretationModal = _ref2 => {
89
89
  });
90
90
  };
91
91
 
92
+ const onLikeToggled = _ref3 => {
93
+ let {
94
+ likedBy
95
+ } = _ref3;
96
+ setIsDirty(true);
97
+ interpretation.likedBy = likedBy;
98
+ interpretation.likes = likedBy.length;
99
+ };
100
+
92
101
  const onInterpretationDeleted = () => {
93
102
  setIsDirty(false);
94
103
  onInterpretationUpdate();
@@ -102,11 +111,11 @@ const InterpretationModal = _ref2 => {
102
111
  });
103
112
  }
104
113
  }, [interpretationId, refetch]);
105
- return /*#__PURE__*/React.createElement(React.Fragment, null, shouldCssHideModal && /*#__PURE__*/React.createElement(Layer, null, /*#__PURE__*/React.createElement(CenteredContent, null, /*#__PURE__*/React.createElement(CircularLoader, null))), /*#__PURE__*/React.createElement(Modal, {
114
+ return /*#__PURE__*/React.createElement(React.Fragment, null, loadingInProgress && /*#__PURE__*/React.createElement(Layer, null, /*#__PURE__*/React.createElement(CenteredContent, null, /*#__PURE__*/React.createElement(CircularLoader, null))), /*#__PURE__*/React.createElement(Modal, {
106
115
  fluid: true,
107
116
  onClose: handleClose,
108
117
  className: cx(modalCSS.className, {
109
- hidden: shouldCssHideModal
118
+ hidden: loadingInProgress
110
119
  }),
111
120
  dataTest: "interpretation-modal"
112
121
  }, /*#__PURE__*/React.createElement("h1", {
@@ -144,7 +153,8 @@ const InterpretationModal = _ref2 => {
144
153
  onInterpretationDeleted: onInterpretationDeleted,
145
154
  onThreadUpdated: onThreadUpdated,
146
155
  initialFocus: initialFocus,
147
- downloadMenuComponent: downloadMenuComponent
156
+ downloadMenuComponent: downloadMenuComponent,
157
+ onLikeToggled: onLikeToggled
148
158
  }))))), /*#__PURE__*/React.createElement(ModalActions, null, /*#__PURE__*/React.createElement(Button, {
149
159
  disabled: fetching,
150
160
  onClick: handleClose
@@ -15,6 +15,7 @@ const InterpretationThread = _ref => {
15
15
  fetching,
16
16
  interpretation,
17
17
  onInterpretationDeleted,
18
+ onLikeToggled,
18
19
  initialFocus,
19
20
  onThreadUpdated,
20
21
  downloadMenuComponent: DownloadMenu
@@ -54,7 +55,8 @@ const InterpretationThread = _ref => {
54
55
  return (_focusRef$current = focusRef.current) === null || _focusRef$current === void 0 ? void 0 : _focusRef$current.focus();
55
56
  },
56
57
  onUpdated: () => onThreadUpdated(true),
57
- onDeleted: onInterpretationDeleted
58
+ onDeleted: onInterpretationDeleted,
59
+ onLikeToggled: onLikeToggled
58
60
  }), /*#__PURE__*/React.createElement("div", {
59
61
  className: "jsx-615306698" + " " + 'comments'
60
62
  }, interpretation.comments.map(comment => /*#__PURE__*/React.createElement(Comment, {
@@ -78,6 +80,7 @@ InterpretationThread.propTypes = {
78
80
  fetching: PropTypes.bool.isRequired,
79
81
  interpretation: PropTypes.object.isRequired,
80
82
  onInterpretationDeleted: PropTypes.func.isRequired,
83
+ onLikeToggled: PropTypes.func.isRequired,
81
84
  downloadMenuComponent: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
82
85
  initialFocus: PropTypes.bool,
83
86
  onThreadUpdated: PropTypes.func
@@ -26,6 +26,7 @@ export const InterpretationList = _ref => {
26
26
  currentUser,
27
27
  interpretations,
28
28
  onInterpretationClick,
29
+ onLikeToggled,
29
30
  onReplyIconClick,
30
31
  refresh,
31
32
  disabled
@@ -64,6 +65,7 @@ export const InterpretationList = _ref => {
64
65
  interpretation: interpretation,
65
66
  currentUser: currentUser,
66
67
  onClick: onInterpretationClick,
68
+ onLikeToggled: onLikeToggled,
67
69
  onReplyIconClick: onReplyIconClick,
68
70
  onDeleted: refresh,
69
71
  onUpdated: refresh,
@@ -78,6 +80,7 @@ InterpretationList.propTypes = {
78
80
  interpretations: PropTypes.array.isRequired,
79
81
  refresh: PropTypes.func.isRequired,
80
82
  onInterpretationClick: PropTypes.func.isRequired,
83
+ onLikeToggled: PropTypes.func.isRequired,
81
84
  onReplyIconClick: PropTypes.func.isRequired,
82
85
  disabled: PropTypes.bool
83
86
  };
@@ -33,13 +33,14 @@ export const InterpretationsUnit = /*#__PURE__*/forwardRef((_ref2, ref) => {
33
33
  renderId
34
34
  } = _ref2;
35
35
  const [isExpanded, setIsExpanded] = useState(true);
36
+ const [interpretations, setInterpretations] = useState([]);
36
37
  const {
37
- data,
38
38
  loading,
39
39
  fetching,
40
40
  refetch
41
41
  } = useDataQuery(interpretationsQuery, {
42
- lazy: true
42
+ lazy: true,
43
+ onComplete: data => setInterpretations(data.interpretations.interpretations)
43
44
  });
44
45
  const onCompleteAction = useCallback(() => {
45
46
  refetch({
@@ -58,6 +59,17 @@ export const InterpretationsUnit = /*#__PURE__*/forwardRef((_ref2, ref) => {
58
59
  });
59
60
  }
60
61
  }, [type, id, renderId, refetch]);
62
+
63
+ const onLikeToggled = _ref3 => {
64
+ let {
65
+ id,
66
+ likedBy
67
+ } = _ref3;
68
+ const interpretation = interpretations.find(interp => interp.id === id);
69
+ interpretation.likedBy = likedBy;
70
+ interpretation.likes = likedBy.length;
71
+ };
72
+
61
73
  return /*#__PURE__*/React.createElement("div", {
62
74
  className: _JSXStyle.dynamic([["4120713286", [spacers.dp16, colors.grey400, colors.white, spacers.dp32, colors.grey900]]]) + " " + (cx('container', {
63
75
  expanded: isExpanded
@@ -79,7 +91,7 @@ export const InterpretationsUnit = /*#__PURE__*/forwardRef((_ref2, ref) => {
79
91
  className: _JSXStyle.dynamic([["4120713286", [spacers.dp16, colors.grey400, colors.white, spacers.dp32, colors.grey900]]]) + " " + "loader"
80
92
  }, /*#__PURE__*/React.createElement(CircularLoader, {
81
93
  small: true
82
- })), data && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(InterpretationForm, {
94
+ })), interpretations && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(InterpretationForm, {
83
95
  currentUser: currentUser,
84
96
  type: type,
85
97
  id: id,
@@ -87,8 +99,9 @@ export const InterpretationsUnit = /*#__PURE__*/forwardRef((_ref2, ref) => {
87
99
  disabled: disabled
88
100
  }), /*#__PURE__*/React.createElement(InterpretationList, {
89
101
  currentUser: currentUser,
90
- interpretations: data.interpretations.interpretations,
102
+ interpretations: interpretations,
91
103
  onInterpretationClick: onInterpretationClick,
104
+ onLikeToggled: onLikeToggled,
92
105
  onReplyIconClick: onReplyIconClick,
93
106
  refresh: onCompleteAction,
94
107
  disabled: disabled
@@ -14,7 +14,8 @@ export const Interpretation = _ref => {
14
14
  onUpdated,
15
15
  onDeleted,
16
16
  disabled,
17
- onReplyIconClick
17
+ onReplyIconClick,
18
+ onLikeToggled
18
19
  } = _ref;
19
20
  const [isUpdateMode, setIsUpdateMode] = useState(false);
20
21
  const [showSharingDialog, setShowSharingDialog] = useState(false);
@@ -25,7 +26,10 @@ export const Interpretation = _ref => {
25
26
  } = useLike({
26
27
  interpretation,
27
28
  currentUser,
28
- onComplete: onUpdated
29
+ onComplete: likedBy => onLikeToggled({
30
+ id: interpretation.id,
31
+ likedBy
32
+ })
29
33
  });
30
34
  const shouldShowButton = !!onClick && !disabled;
31
35
  return isUpdateMode ? /*#__PURE__*/React.createElement(InterpretationUpdateForm, {
@@ -84,6 +88,7 @@ Interpretation.propTypes = {
84
88
  currentUser: PropTypes.object.isRequired,
85
89
  interpretation: PropTypes.object.isRequired,
86
90
  onDeleted: PropTypes.func.isRequired,
91
+ onLikeToggled: PropTypes.func.isRequired,
87
92
  onReplyIconClick: PropTypes.func.isRequired,
88
93
  onUpdated: PropTypes.func.isRequired,
89
94
  disabled: PropTypes.bool,
@@ -19,12 +19,22 @@ const useLike = _ref => {
19
19
  const [like, {
20
20
  loading: likeLoading
21
21
  }] = useDataMutation(likeMutationRef.current, {
22
- onComplete
22
+ onComplete: () => {
23
+ const newLikedBy = interpretation.likedBy.concat({
24
+ id: currentUser.id
25
+ });
26
+ setIsLikedByCurrentUser(true);
27
+ onComplete(newLikedBy);
28
+ }
23
29
  });
24
30
  const [unlike, {
25
31
  loading: unlikeLoading
26
32
  }] = useDataMutation(unlikeMutationRef.current, {
27
- onComplete
33
+ onComplete: () => {
34
+ const newLikedBy = interpretation.likedBy.filter(lb => lb.id !== currentUser.id);
35
+ setIsLikedByCurrentUser(false);
36
+ onComplete(newLikedBy);
37
+ }
28
38
  });
29
39
  const [isLikedByCurrentUser, setIsLikedByCurrentUser] = useState(false);
30
40
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dhis2/analytics",
3
- "version": "24.10.3",
3
+ "version": "24.10.4",
4
4
  "main": "./build/cjs/index.js",
5
5
  "module": "./build/es/index.js",
6
6
  "exports": {