@dhis2/analytics 28.1.2 → 29.0.0

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.
Files changed (59) hide show
  1. package/build/cjs/__demo__/InterpretationsUnit.stories.js +9 -6
  2. package/build/cjs/__fixtures__/interpretationsMockData.js +204 -0
  3. package/build/cjs/components/Interpretations/DashboardItemInterpretations/DashboardInterpretationThread.js +56 -0
  4. package/build/cjs/components/Interpretations/DashboardItemInterpretations/DashboardItemInterpretations.js +54 -0
  5. package/build/cjs/components/Interpretations/DashboardItemInterpretations/index.js +12 -0
  6. package/build/cjs/components/Interpretations/InterpretationModal/Comment.js +12 -17
  7. package/build/cjs/components/Interpretations/InterpretationModal/CommentAddForm.js +20 -34
  8. package/build/cjs/components/Interpretations/InterpretationModal/CommentDeleteButton.js +11 -36
  9. package/build/cjs/components/Interpretations/InterpretationModal/CommentUpdateForm.js +11 -27
  10. package/build/cjs/components/Interpretations/InterpretationModal/InterpretationModal.js +11 -68
  11. package/build/cjs/components/Interpretations/InterpretationModal/InterpretationThread.js +11 -24
  12. package/build/cjs/components/Interpretations/InterpretationsProvider/InterpretationsManager.js +275 -0
  13. package/build/cjs/components/Interpretations/InterpretationsProvider/InterpretationsProvider.js +28 -0
  14. package/build/cjs/components/Interpretations/InterpretationsProvider/__tests__/groupInterpretationIdsByDate.spec.js +37 -0
  15. package/build/cjs/components/Interpretations/InterpretationsProvider/__tests__/hooks.spec.js +565 -0
  16. package/build/cjs/components/Interpretations/InterpretationsProvider/groupInterpretationIdsByDate.js +16 -0
  17. package/build/cjs/components/Interpretations/InterpretationsProvider/hooks.js +278 -0
  18. package/build/cjs/components/Interpretations/InterpretationsProvider/index.js +12 -0
  19. package/build/cjs/components/Interpretations/InterpretationsUnit/InterpretationForm.js +25 -30
  20. package/build/cjs/components/Interpretations/InterpretationsUnit/InterpretationList.js +8 -38
  21. package/build/cjs/components/Interpretations/InterpretationsUnit/InterpretationsUnit.js +22 -73
  22. package/build/cjs/components/Interpretations/common/Interpretation/Interpretation.js +20 -34
  23. package/build/cjs/components/Interpretations/common/Interpretation/InterpretationDeleteButton.js +10 -12
  24. package/build/cjs/components/Interpretations/common/Interpretation/InterpretationUpdateForm.js +13 -24
  25. package/build/cjs/components/Interpretations/common/Message/MessageEditorContainer.js +3 -3
  26. package/build/cjs/index.js +72 -63
  27. package/build/cjs/locales/en/translations.json +10 -1
  28. package/build/cjs/modules/pivotTable/getHeaderForDisplay.js +1 -1
  29. package/build/es/__demo__/InterpretationsUnit.stories.js +9 -6
  30. package/build/es/__fixtures__/interpretationsMockData.js +198 -0
  31. package/build/es/components/Interpretations/DashboardItemInterpretations/DashboardInterpretationThread.js +48 -0
  32. package/build/es/components/Interpretations/DashboardItemInterpretations/DashboardItemInterpretations.js +45 -0
  33. package/build/es/components/Interpretations/DashboardItemInterpretations/index.js +1 -0
  34. package/build/es/components/Interpretations/InterpretationModal/Comment.js +14 -19
  35. package/build/es/components/Interpretations/InterpretationModal/CommentAddForm.js +21 -35
  36. package/build/es/components/Interpretations/InterpretationModal/CommentDeleteButton.js +11 -35
  37. package/build/es/components/Interpretations/InterpretationModal/CommentUpdateForm.js +12 -28
  38. package/build/es/components/Interpretations/InterpretationModal/InterpretationModal.js +12 -69
  39. package/build/es/components/Interpretations/InterpretationModal/InterpretationThread.js +11 -24
  40. package/build/es/components/Interpretations/InterpretationsProvider/InterpretationsManager.js +268 -0
  41. package/build/es/components/Interpretations/InterpretationsProvider/InterpretationsProvider.js +19 -0
  42. package/build/es/components/Interpretations/InterpretationsProvider/__tests__/groupInterpretationIdsByDate.spec.js +35 -0
  43. package/build/es/components/Interpretations/InterpretationsProvider/__tests__/hooks.spec.js +561 -0
  44. package/build/es/components/Interpretations/InterpretationsProvider/groupInterpretationIdsByDate.js +9 -0
  45. package/build/es/components/Interpretations/InterpretationsProvider/hooks.js +258 -0
  46. package/build/es/components/Interpretations/InterpretationsProvider/index.js +1 -0
  47. package/build/es/components/Interpretations/InterpretationsUnit/InterpretationForm.js +26 -31
  48. package/build/es/components/Interpretations/InterpretationsUnit/InterpretationList.js +8 -38
  49. package/build/es/components/Interpretations/InterpretationsUnit/InterpretationsUnit.js +23 -75
  50. package/build/es/components/Interpretations/common/Interpretation/Interpretation.js +21 -35
  51. package/build/es/components/Interpretations/common/Interpretation/InterpretationDeleteButton.js +11 -13
  52. package/build/es/components/Interpretations/common/Interpretation/InterpretationUpdateForm.js +14 -25
  53. package/build/es/components/Interpretations/common/Message/MessageEditorContainer.js +3 -3
  54. package/build/es/index.js +3 -1
  55. package/build/es/locales/en/translations.json +10 -1
  56. package/build/es/modules/pivotTable/getHeaderForDisplay.js +1 -1
  57. package/package.json +1 -1
  58. package/build/cjs/components/Interpretations/common/Interpretation/useLike.js +0 -56
  59. package/build/es/components/Interpretations/common/Interpretation/useLike.js +0 -50
@@ -0,0 +1,258 @@
1
+ import { useCallback, useContext, useEffect, useMemo, useReducer, useRef, useState } from 'react';
2
+ import { getCommentAccess, getInterpretationAccess } from '../common/getInterpretationAccess.js';
3
+ import { InterpretationsContext } from './InterpretationsProvider.js';
4
+ const SET_LOADING = 'SET_LOADING';
5
+ const SET_ERROR = 'SET_ERROR';
6
+ const SET_DATA = 'SET_DATA';
7
+ const RESET = 'RESET';
8
+ const initialLoadingState = {
9
+ loading: false,
10
+ error: undefined,
11
+ data: undefined
12
+ };
13
+ function loadingReducer(state, action) {
14
+ switch (action.type) {
15
+ case SET_LOADING:
16
+ return {
17
+ ...state,
18
+ loading: true
19
+ };
20
+ case SET_ERROR:
21
+ return {
22
+ ...state,
23
+ error: action.payload,
24
+ loading: false
25
+ };
26
+ case SET_DATA:
27
+ return {
28
+ data: action.payload,
29
+ error: undefined,
30
+ loading: false
31
+ };
32
+ case RESET:
33
+ return {
34
+ ...initialLoadingState
35
+ };
36
+ default:
37
+ return state;
38
+ }
39
+ }
40
+ export const useInterpretationsManager = () => {
41
+ const interpretationsManager = useContext(InterpretationsContext);
42
+ if (!interpretationsManager) {
43
+ throw new Error('Called useInterpretationsManager() from outside an InterpretationsProvider');
44
+ }
45
+ return interpretationsManager;
46
+ };
47
+ export const useInterpretationsCurrentUser = () => {
48
+ const interpretationsManager = useInterpretationsManager();
49
+ return interpretationsManager.getCurrentUser();
50
+ };
51
+ export const useInterpretationsList = (type, id) => {
52
+ const prevTypeRef = useRef(null);
53
+ const prevIdRef = useRef(null);
54
+ const interpretationsManager = useInterpretationsManager();
55
+ const [state, dispatch] = useReducer(loadingReducer, initialLoadingState);
56
+ const fetchList = useCallback(async () => {
57
+ dispatch({
58
+ type: SET_LOADING
59
+ });
60
+ try {
61
+ const data = await interpretationsManager.loadInterpretationsForVisualization(type, id);
62
+ dispatch({
63
+ type: SET_DATA,
64
+ payload: data
65
+ });
66
+ } catch (error) {
67
+ console.error(error);
68
+ dispatch({
69
+ type: SET_ERROR,
70
+ payload: error
71
+ });
72
+ }
73
+ }, [interpretationsManager, type, id, dispatch]);
74
+
75
+ // Ensure manager updates get propagated to the state
76
+ useEffect(() => {
77
+ const unsubscribe = interpretationsManager.subscribeToInterpretationsListUpdates(interpretationIdsByDate => {
78
+ dispatch({
79
+ type: SET_DATA,
80
+ payload: interpretationIdsByDate
81
+ });
82
+ });
83
+ return unsubscribe;
84
+ }, [interpretationsManager]);
85
+
86
+ // Fetch when mounting or after a reset
87
+ useEffect(() => {
88
+ if (type && id && !state.loading && !state.data && !state.error) {
89
+ fetchList();
90
+ }
91
+ }, [fetchList, state, type, id]);
92
+
93
+ // Handle active item changes and clearance
94
+ useEffect(() => {
95
+ const prevType = prevTypeRef.current;
96
+ const prevId = prevIdRef.current;
97
+ const isTypeChange = prevType && type && prevType !== type;
98
+ const isIdChange = prevId && id && prevId !== id;
99
+ const isTypeClearance = prevType && !type;
100
+ const isIdClearance = prevId && !id;
101
+ if (isTypeChange || isIdChange || isTypeClearance || isIdClearance) {
102
+ dispatch({
103
+ type: RESET
104
+ });
105
+ }
106
+ if (isTypeClearance || isIdClearance) {
107
+ interpretationsManager.clearInterpretations();
108
+ }
109
+ prevTypeRef.current = type;
110
+ prevIdRef.current = id;
111
+ }, [interpretationsManager, type, id]);
112
+ return state;
113
+ };
114
+ export const useActiveInterpretation = id => {
115
+ const prevIdRef = useRef(null);
116
+ const interpretationsManager = useInterpretationsManager();
117
+ const [state, dispatch] = useReducer(loadingReducer, initialLoadingState);
118
+ const fetchInterpretation = useCallback(async () => {
119
+ dispatch({
120
+ type: SET_LOADING
121
+ });
122
+ try {
123
+ const data = await interpretationsManager.loadActiveInterpretation(id);
124
+ dispatch({
125
+ type: SET_DATA,
126
+ payload: data
127
+ });
128
+ } catch (error) {
129
+ console.error(error);
130
+ dispatch({
131
+ type: SET_ERROR,
132
+ payload: error
133
+ });
134
+ }
135
+ }, [interpretationsManager, id, dispatch]);
136
+
137
+ // Ensure manager updates get propagated to the state
138
+ useEffect(() => {
139
+ const unsubscribe = interpretationsManager.subscribeToInterpretationUpdates(id, interpretation => {
140
+ dispatch({
141
+ type: SET_DATA,
142
+ payload: interpretation
143
+ });
144
+ });
145
+ return unsubscribe;
146
+ }, [interpretationsManager, id]);
147
+
148
+ // Fetch when mounting or after a reset
149
+ useEffect(() => {
150
+ if (id && !state.loading && !state.data && !state.error) {
151
+ fetchInterpretation();
152
+ }
153
+ }, [fetchInterpretation, state, id]);
154
+
155
+ // Handle active item changes and clearance
156
+ useEffect(() => {
157
+ const prevId = prevIdRef.current;
158
+ const isIdChange = prevId && id && prevId !== id;
159
+ const isIdClearance = prevId && !id;
160
+ if (isIdChange || isIdClearance) {
161
+ dispatch({
162
+ type: RESET
163
+ });
164
+ }
165
+ if (isIdClearance) {
166
+ interpretationsManager.clearActiveInterpretation();
167
+ }
168
+ prevIdRef.current = id;
169
+ }, [id, interpretationsManager]);
170
+ return state;
171
+ };
172
+ export const useInterpretation = id => {
173
+ const interpretationsManager = useInterpretationsManager();
174
+ const [interpretation, setInterpretation] = useState(interpretationsManager.getInterpretation(id));
175
+ useEffect(() => {
176
+ const unsubscribe = interpretationsManager.subscribeToInterpretationUpdates(id, newInterpretation => {
177
+ setInterpretation(newInterpretation);
178
+ });
179
+ return unsubscribe;
180
+ }, [interpretationsManager, id]);
181
+ return interpretation;
182
+ };
183
+ export const useLike = id => {
184
+ const interpretationsManager = useInterpretationsManager();
185
+ const [{
186
+ loading: toggleLikeInProgress,
187
+ data: interpretation
188
+ }, dispatch] = useReducer(loadingReducer, {
189
+ ...initialLoadingState,
190
+ data: interpretationsManager.getInterpretation(id)
191
+ });
192
+ const toggleLike = useCallback(async () => {
193
+ dispatch({
194
+ type: SET_LOADING
195
+ });
196
+ try {
197
+ const data = await interpretationsManager.toggleInterpretationLike(id);
198
+ dispatch({
199
+ type: SET_DATA,
200
+ payload: data
201
+ });
202
+ } catch (error) {
203
+ console.error(error);
204
+ dispatch({
205
+ type: SET_ERROR,
206
+ payload: error
207
+ });
208
+ }
209
+ }, [id, interpretationsManager]);
210
+ const isLikedByCurrentUser = useMemo(() => {
211
+ const currentUser = interpretationsManager.getCurrentUser();
212
+ return interpretation.likedBy.some(likedBy => likedBy.id === currentUser.id);
213
+ }, [interpretation, interpretationsManager]);
214
+ return {
215
+ isLikedByCurrentUser,
216
+ toggleLike,
217
+ toggleLikeInProgress
218
+ };
219
+ };
220
+ export const useInterpretationAccess = interpretation => {
221
+ const currentUser = useInterpretationsCurrentUser();
222
+ const access = useMemo(() => getInterpretationAccess(interpretation, currentUser), [interpretation, currentUser]);
223
+ return access;
224
+ };
225
+ export const useCommentAccess = (comment, canComment) => {
226
+ const currentUser = useInterpretationsCurrentUser();
227
+ const access = useMemo(() => getCommentAccess(comment, canComment, currentUser), [comment, canComment, currentUser]);
228
+ return access;
229
+ };
230
+ const useInterpretationsManagerMutation = (methodName, options = {}) => {
231
+ const interpretationsManager = useInterpretationsManager();
232
+ const [state, dispatch] = useReducer(loadingReducer, initialLoadingState);
233
+ const doAsyncCallback = useCallback(async () => {
234
+ dispatch({
235
+ type: SET_LOADING
236
+ });
237
+ try {
238
+ const data = await interpretationsManager[methodName](options);
239
+ dispatch({
240
+ type: SET_DATA,
241
+ payload: data
242
+ });
243
+ } catch (error) {
244
+ console.error(error);
245
+ dispatch({
246
+ type: SET_ERROR,
247
+ payload: error
248
+ });
249
+ }
250
+ }, [interpretationsManager, methodName, options]);
251
+ return [doAsyncCallback, state];
252
+ };
253
+ export const useCreateInterpretation = options => useInterpretationsManagerMutation('createInterpretation', options);
254
+ export const useUpdateInterpretationText = options => useInterpretationsManagerMutation('updateInterpretationText', options);
255
+ export const useDeleteInterpretation = options => useInterpretationsManagerMutation('deleteInterpretation', options);
256
+ export const useAddCommentToActiveInterpretation = options => useInterpretationsManagerMutation('addCommentToActiveInterpretation', options);
257
+ export const useUpdateCommentForActiveInterpretation = options => useInterpretationsManagerMutation('updateCommentForActiveInterpretation', options);
258
+ export const useDeleteCommentFromActiveInterpretation = options => useInterpretationsManagerMutation('deleteCommentFromActiveInterpretation', options);
@@ -0,0 +1 @@
1
+ export { InterpretationsProvider } from './InterpretationsProvider.js';
@@ -1,59 +1,56 @@
1
- import { useDataMutation } from '@dhis2/app-runtime';
2
1
  import i18n from '@dhis2/d2-i18n';
3
2
  import { Button, Input } from '@dhis2/ui';
4
3
  import PropTypes from 'prop-types';
5
- import React, { useRef, useState } from 'react';
4
+ import React, { useCallback, useState } from 'react';
6
5
  import { RichTextEditor } from '../../RichText/index.js';
7
6
  import { MessageEditorContainer, MessageButtonStrip } from '../common/index.js';
7
+ import { useCreateInterpretation, useInterpretationsCurrentUser } from '../InterpretationsProvider/hooks.js';
8
8
  export const InterpretationForm = ({
9
9
  type,
10
10
  id,
11
- currentUser,
12
11
  disabled,
13
- showNoTimeDimensionHelpText,
14
- onSave
12
+ showNoTimeDimensionHelpText
15
13
  }) => {
16
14
  const [showRichTextEditor, setShowRichTextEditor] = useState(false);
17
- const [interpretationText, setInterpretationText] = useState('');
18
- const saveMutationRef = useRef({
19
- resource: `interpretations/${type}/${id}`,
20
- type: 'create',
21
- data: ({
22
- interpretationText
23
- }) => interpretationText
24
- });
15
+ const [text, setText] = useState('');
16
+ const onComplete = useCallback(() => {
17
+ setShowRichTextEditor(false);
18
+ setText('');
19
+ }, []);
20
+ const currentUser = useInterpretationsCurrentUser();
25
21
  const [save, {
26
- loading: saveMutationInProgress
27
- }] = useDataMutation(saveMutationRef.current, {
28
- onComplete: () => {
29
- setShowRichTextEditor(false);
30
- setInterpretationText('');
31
- onSave();
32
- }
22
+ loading,
23
+ error
24
+ }] = useCreateInterpretation({
25
+ type,
26
+ id,
27
+ text,
28
+ onComplete
33
29
  });
34
30
  const inputPlaceholder = i18n.t('Write an interpretation');
35
31
  return /*#__PURE__*/React.createElement(MessageEditorContainer, {
36
- currentUser: currentUser,
32
+ currentUserName: currentUser.name,
37
33
  dataTest: "interpretation-form"
38
34
  }, showRichTextEditor ? /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(RichTextEditor, {
39
- disabled: saveMutationInProgress,
35
+ disabled: loading,
40
36
  inputPlaceholder: inputPlaceholder,
41
- onChange: setInterpretationText,
42
- value: interpretationText,
37
+ onChange: setText,
38
+ value: text,
39
+ errorText: error ? i18n.t('Could not post interpretation') : '',
43
40
  helpText: showNoTimeDimensionHelpText ? i18n.t('Other people viewing this interpretation in the future may see more data.') : undefined
44
41
  }), /*#__PURE__*/React.createElement(MessageButtonStrip, null, /*#__PURE__*/React.createElement(Button, {
45
42
  primary: true,
46
43
  small: true,
47
- loading: saveMutationInProgress,
44
+ loading: loading,
48
45
  onClick: () => save({
49
- interpretationText
46
+ interpretationText: text
50
47
  })
51
48
  }, i18n.t('Post interpretation')), /*#__PURE__*/React.createElement(Button, {
52
49
  secondary: true,
53
50
  small: true,
54
- disabled: saveMutationInProgress,
51
+ disabled: loading,
55
52
  onClick: () => {
56
- setInterpretationText('');
53
+ setText('');
57
54
  setShowRichTextEditor(false);
58
55
  }
59
56
  }, i18n.t('Cancel')))) : /*#__PURE__*/React.createElement(Input, {
@@ -63,10 +60,8 @@ export const InterpretationForm = ({
63
60
  }));
64
61
  };
65
62
  InterpretationForm.propTypes = {
66
- currentUser: PropTypes.object,
67
63
  disabled: PropTypes.bool,
68
64
  id: PropTypes.string,
69
65
  showNoTimeDimensionHelpText: PropTypes.bool,
70
- type: PropTypes.string,
71
- onSave: PropTypes.func
66
+ type: PropTypes.string
72
67
  };
@@ -5,43 +5,20 @@ import moment from 'moment';
5
5
  import PropTypes from 'prop-types';
6
6
  import React from 'react';
7
7
  import { Interpretation } from '../common/index.js';
8
- const sortByCreatedDateDesc = (a, b) => {
9
- const dateA = a.created;
10
- const dateB = b.created;
11
- if (dateA < dateB) {
12
- return 1;
13
- }
14
- if (dateA > dateB) {
15
- return -1;
16
- }
17
- return 0;
18
- };
19
8
  export const InterpretationList = ({
20
- currentUser,
21
- interpretations,
9
+ interpretationIdsByDate,
22
10
  onInterpretationClick,
23
- onLikeToggled,
24
11
  onReplyIconClick,
25
- refresh,
26
12
  disabled,
27
13
  dashboardRedirectUrl
28
14
  }) => {
29
15
  const {
30
16
  fromServerDate
31
17
  } = useTimeZoneConversion();
32
- const interpretationsByDate = interpretations.reduce((groupedInterpretations, interpretation) => {
33
- const date = interpretation.created.split('T')[0];
34
- if (date in groupedInterpretations) {
35
- groupedInterpretations[date].push(interpretation);
36
- } else {
37
- groupedInterpretations[date] = [interpretation];
38
- }
39
- return groupedInterpretations;
40
- }, {});
41
18
  return /*#__PURE__*/React.createElement("ol", {
42
19
  "data-test": "interpretations-list",
43
20
  className: _JSXStyle.dynamic([["4058400613", [spacers.dp8, spacers.dp8, spacers.dp16, colors.grey800, spacers.dp12, spacers.dp12, spacers.dp32, spacers.dp4]]]) + " " + "interpretation-groups"
44
- }, Object.keys(interpretationsByDate).sort().reverse().map(date => /*#__PURE__*/React.createElement("li", {
21
+ }, Object.keys(interpretationIdsByDate).map(date => /*#__PURE__*/React.createElement("li", {
45
22
  key: date,
46
23
  className: _JSXStyle.dynamic([["4058400613", [spacers.dp8, spacers.dp8, spacers.dp16, colors.grey800, spacers.dp12, spacers.dp12, spacers.dp32, spacers.dp4]]])
47
24
  }, /*#__PURE__*/React.createElement("div", {
@@ -53,28 +30,21 @@ export const InterpretationList = ({
53
30
  className: _JSXStyle.dynamic([["4058400613", [spacers.dp8, spacers.dp8, spacers.dp16, colors.grey800, spacers.dp12, spacers.dp12, spacers.dp32, spacers.dp4]]]) + " " + "date-header"
54
31
  }, moment(fromServerDate(date)).format('ll'))), /*#__PURE__*/React.createElement("ol", {
55
32
  className: _JSXStyle.dynamic([["4058400613", [spacers.dp8, spacers.dp8, spacers.dp16, colors.grey800, spacers.dp12, spacers.dp12, spacers.dp32, spacers.dp4]]]) + " " + "interpretation-list"
56
- }, interpretationsByDate[date].sort(sortByCreatedDateDesc).map(interpretation => /*#__PURE__*/React.createElement(Interpretation, {
57
- key: interpretation.id,
58
- interpretation: interpretation,
59
- currentUser: currentUser,
60
- onClick: onInterpretationClick,
61
- onLikeToggled: onLikeToggled,
33
+ }, interpretationIdsByDate[date].map(interpretationId => /*#__PURE__*/React.createElement(Interpretation, {
34
+ key: interpretationId,
35
+ id: interpretationId,
62
36
  onReplyIconClick: onReplyIconClick,
63
- onDeleted: refresh,
64
- onUpdated: refresh,
37
+ dashboardRedirectUrl: dashboardRedirectUrl,
65
38
  disabled: disabled,
66
- dashboardRedirectUrl: dashboardRedirectUrl
39
+ onClick: onInterpretationClick
67
40
  }))))), /*#__PURE__*/React.createElement(_JSXStyle, {
68
41
  id: "4058400613",
69
42
  dynamic: [spacers.dp8, spacers.dp8, spacers.dp16, colors.grey800, spacers.dp12, spacers.dp12, spacers.dp32, spacers.dp4]
70
43
  }, [`.date-section.__jsx-style-dynamic-selector{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;gap:${spacers.dp8};-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin-bottom:${spacers.dp8};}`, `.date-header.__jsx-style-dynamic-selector{font-size:14px;font-weight:500;line-height:${spacers.dp16};color:${colors.grey800};}`, `.interpretation-groups.__jsx-style-dynamic-selector{margin:0;padding:0;padding-top:${spacers.dp12};list-style:none;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;gap:${spacers.dp12};}`, `.interpretation-list.__jsx-style-dynamic-selector{margin:0;padding-left:${spacers.dp32};list-style:none;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;gap:${spacers.dp4};}`]));
71
44
  };
72
45
  InterpretationList.propTypes = {
73
- currentUser: PropTypes.object.isRequired,
74
- interpretations: PropTypes.array.isRequired,
75
- refresh: PropTypes.func.isRequired,
46
+ interpretationIdsByDate: PropTypes.objectOf(PropTypes.arrayOf(PropTypes.string)).isRequired,
76
47
  onInterpretationClick: PropTypes.func.isRequired,
77
- onLikeToggled: PropTypes.func.isRequired,
78
48
  onReplyIconClick: PropTypes.func.isRequired,
79
49
  dashboardRedirectUrl: PropTypes.string,
80
50
  disabled: PropTypes.bool
@@ -1,122 +1,70 @@
1
1
  import _JSXStyle from "styled-jsx/style";
2
- import { useDataQuery } from '@dhis2/app-runtime';
3
2
  import i18n from '@dhis2/d2-i18n';
4
- import { CircularLoader, IconChevronDown24, IconChevronUp24, colors, spacers } from '@dhis2/ui';
3
+ import { CircularLoader, IconChevronDown24, IconChevronUp24, colors, spacers, NoticeBox } from '@dhis2/ui';
5
4
  import cx from 'classnames';
6
5
  import PropTypes from 'prop-types';
7
- import React, { useCallback, useEffect, useState, useImperativeHandle, forwardRef } from 'react';
6
+ import React, { useState } from 'react';
7
+ import { useInterpretationsList } from '../InterpretationsProvider/hooks.js';
8
8
  import { InterpretationForm } from './InterpretationForm.js';
9
9
  import { InterpretationList } from './InterpretationList.js';
10
- const interpretationsQuery = {
11
- interpretations: {
12
- resource: 'interpretations',
13
- params: ({
14
- type,
15
- id
16
- }) => ({
17
- fields: ['access[write,manage]', 'id', 'createdBy[id,displayName]', 'created', 'text', 'comments[id]', 'likes', 'likedBy[id]'],
18
- filter: `${type}.id:eq:${id}`
19
- })
20
- }
21
- };
22
- export const InterpretationsUnit = /*#__PURE__*/forwardRef(({
23
- currentUser,
10
+ export const InterpretationsUnit = ({
24
11
  type,
25
12
  id,
26
13
  visualizationHasTimeDimension = true,
27
- onInterpretationClick = Function.prototype,
14
+ onInterpretationClick,
28
15
  onReplyIconClick,
29
16
  disabled,
30
- renderId,
31
17
  dashboardRedirectUrl
32
- }, ref) => {
18
+ }) => {
33
19
  const [isExpanded, setIsExpanded] = useState(true);
34
- const [interpretations, setInterpretations] = useState([]);
35
20
  const showNoTimeDimensionHelpText = type === 'eventVisualization' && !visualizationHasTimeDimension;
36
21
  const {
22
+ data: interpretationIdsByDate,
37
23
  loading,
38
- fetching,
39
- refetch
40
- } = useDataQuery(interpretationsQuery, {
41
- lazy: true,
42
- onComplete: data => setInterpretations(data.interpretations.interpretations)
43
- });
44
- const onCompleteAction = useCallback(() => {
45
- refetch({
46
- type,
47
- id
48
- });
49
- }, [type, id, refetch]);
50
- useImperativeHandle(ref, () => ({
51
- refresh: onCompleteAction
52
- }), [onCompleteAction]);
53
- useEffect(() => {
54
- if (id) {
55
- refetch({
56
- type,
57
- id
58
- });
59
- }
60
- }, [type, id, renderId, refetch]);
61
- const onLikeToggled = ({
62
- id,
63
- likedBy
64
- }) => {
65
- const interpretation = interpretations.find(interp => interp.id === id);
66
- interpretation.likedBy = likedBy;
67
- interpretation.likes = likedBy.length;
68
- };
24
+ error
25
+ } = useInterpretationsList(type, id);
69
26
  return /*#__PURE__*/React.createElement("div", {
70
- className: _JSXStyle.dynamic([["4120713286", [spacers.dp16, colors.grey400, colors.white, spacers.dp32, colors.grey900]]]) + " " + (cx('container', {
27
+ className: _JSXStyle.dynamic([["2008120072", [spacers.dp16, colors.grey400, colors.white, spacers.dp32, colors.grey900]]]) + " " + (cx('container', {
71
28
  expanded: isExpanded
72
29
  }) || "")
73
- }, fetching && !loading && /*#__PURE__*/React.createElement("div", {
74
- className: _JSXStyle.dynamic([["4120713286", [spacers.dp16, colors.grey400, colors.white, spacers.dp32, colors.grey900]]]) + " " + "fetching-loader"
75
- }, /*#__PURE__*/React.createElement(CircularLoader, {
76
- small: true
77
- })), /*#__PURE__*/React.createElement("div", {
30
+ }, /*#__PURE__*/React.createElement("button", {
78
31
  onClick: () => setIsExpanded(!isExpanded),
79
- className: _JSXStyle.dynamic([["4120713286", [spacers.dp16, colors.grey400, colors.white, spacers.dp32, colors.grey900]]]) + " " + "header"
32
+ className: _JSXStyle.dynamic([["2008120072", [spacers.dp16, colors.grey400, colors.white, spacers.dp32, colors.grey900]]]) + " " + "header"
80
33
  }, /*#__PURE__*/React.createElement("span", {
81
- className: _JSXStyle.dynamic([["4120713286", [spacers.dp16, colors.grey400, colors.white, spacers.dp32, colors.grey900]]]) + " " + "title"
34
+ className: _JSXStyle.dynamic([["2008120072", [spacers.dp16, colors.grey400, colors.white, spacers.dp32, colors.grey900]]]) + " " + "title"
82
35
  }, i18n.t('Interpretations')), isExpanded ? /*#__PURE__*/React.createElement(IconChevronUp24, {
83
36
  color: colors.grey700
84
37
  }) : /*#__PURE__*/React.createElement(IconChevronDown24, {
85
38
  color: colors.grey700
86
39
  })), isExpanded && /*#__PURE__*/React.createElement(React.Fragment, null, loading && /*#__PURE__*/React.createElement("div", {
87
- className: _JSXStyle.dynamic([["4120713286", [spacers.dp16, colors.grey400, colors.white, spacers.dp32, colors.grey900]]]) + " " + "loader"
40
+ className: _JSXStyle.dynamic([["2008120072", [spacers.dp16, colors.grey400, colors.white, spacers.dp32, colors.grey900]]]) + " " + "loader"
88
41
  }, /*#__PURE__*/React.createElement(CircularLoader, {
89
42
  small: true
90
- })), interpretations && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(InterpretationForm, {
91
- currentUser: currentUser,
43
+ })), error && /*#__PURE__*/React.createElement(NoticeBox, {
44
+ error: true,
45
+ title: i18n.t('Error loading interpretations')
46
+ }, error.message || i18n.t('Could not load interpretations')), interpretationIdsByDate && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(InterpretationForm, {
92
47
  type: type,
93
48
  id: id,
94
- onSave: onCompleteAction,
95
49
  disabled: disabled,
96
50
  showNoTimeDimensionHelpText: showNoTimeDimensionHelpText
97
51
  }), /*#__PURE__*/React.createElement(InterpretationList, {
98
- currentUser: currentUser,
99
- interpretations: interpretations,
52
+ interpretationIdsByDate: interpretationIdsByDate,
100
53
  onInterpretationClick: onInterpretationClick,
101
- onLikeToggled: onLikeToggled,
102
54
  onReplyIconClick: onReplyIconClick,
103
- refresh: onCompleteAction,
104
55
  disabled: disabled,
105
56
  dashboardRedirectUrl: dashboardRedirectUrl
106
57
  }))), /*#__PURE__*/React.createElement(_JSXStyle, {
107
- id: "4120713286",
58
+ id: "2008120072",
108
59
  dynamic: [spacers.dp16, colors.grey400, colors.white, spacers.dp32, colors.grey900]
109
- }, [`.container.__jsx-style-dynamic-selector{position:relative;padding:${spacers.dp16};border-bottom:1px solid ${colors.grey400};background-color:${colors.white};}`, ".fetching-loader.__jsx-style-dynamic-selector{position:absolute;inset:0px;background-color:rgba(255,255,255,0.8);display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;z-index:1;}", `.expanded.__jsx-style-dynamic-selector{padding-bottom:${spacers.dp32};}`, ".loader.__jsx-style-dynamic-selector{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;}", ".header.__jsx-style-dynamic-selector{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;cursor:pointer;}", `.title.__jsx-style-dynamic-selector{font-size:16px;font-weight:500;line-height:21px;color:${colors.grey900};}`]));
110
- });
111
- InterpretationsUnit.displayName = 'InterpretationsUnit';
60
+ }, [`.container.__jsx-style-dynamic-selector{position:relative;padding:${spacers.dp16};border-bottom:1px solid ${colors.grey400};background-color:${colors.white};}`, `.expanded.__jsx-style-dynamic-selector{padding-bottom:${spacers.dp32};}`, ".loader.__jsx-style-dynamic-selector{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;}", ".header.__jsx-style-dynamic-selector{all:unset;inline-size:100%;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;cursor:pointer;}", `.title.__jsx-style-dynamic-selector{font-size:16px;font-weight:500;line-height:21px;color:${colors.grey900};}`]));
61
+ };
112
62
  InterpretationsUnit.propTypes = {
113
- currentUser: PropTypes.object.isRequired,
114
63
  id: PropTypes.string.isRequired,
115
64
  type: PropTypes.string.isRequired,
65
+ onInterpretationClick: PropTypes.func.isRequired,
116
66
  dashboardRedirectUrl: PropTypes.string,
117
67
  disabled: PropTypes.bool,
118
- renderId: PropTypes.number,
119
68
  visualizationHasTimeDimension: PropTypes.bool,
120
- onInterpretationClick: PropTypes.func,
121
69
  onReplyIconClick: PropTypes.func
122
70
  };