@dhis2/analytics 28.1.3 → 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.
- package/build/cjs/__demo__/InterpretationsUnit.stories.js +9 -6
- package/build/cjs/__fixtures__/interpretationsMockData.js +204 -0
- package/build/cjs/components/Interpretations/DashboardItemInterpretations/DashboardInterpretationThread.js +56 -0
- package/build/cjs/components/Interpretations/DashboardItemInterpretations/DashboardItemInterpretations.js +54 -0
- package/build/cjs/components/Interpretations/DashboardItemInterpretations/index.js +12 -0
- package/build/cjs/components/Interpretations/InterpretationModal/Comment.js +12 -17
- package/build/cjs/components/Interpretations/InterpretationModal/CommentAddForm.js +20 -34
- package/build/cjs/components/Interpretations/InterpretationModal/CommentDeleteButton.js +11 -36
- package/build/cjs/components/Interpretations/InterpretationModal/CommentUpdateForm.js +11 -27
- package/build/cjs/components/Interpretations/InterpretationModal/InterpretationModal.js +11 -68
- package/build/cjs/components/Interpretations/InterpretationModal/InterpretationThread.js +11 -24
- package/build/cjs/components/Interpretations/InterpretationsProvider/InterpretationsManager.js +275 -0
- package/build/cjs/components/Interpretations/InterpretationsProvider/InterpretationsProvider.js +28 -0
- package/build/cjs/components/Interpretations/InterpretationsProvider/__tests__/groupInterpretationIdsByDate.spec.js +37 -0
- package/build/cjs/components/Interpretations/InterpretationsProvider/__tests__/hooks.spec.js +565 -0
- package/build/cjs/components/Interpretations/InterpretationsProvider/groupInterpretationIdsByDate.js +16 -0
- package/build/cjs/components/Interpretations/InterpretationsProvider/hooks.js +278 -0
- package/build/cjs/components/Interpretations/InterpretationsProvider/index.js +12 -0
- package/build/cjs/components/Interpretations/InterpretationsUnit/InterpretationForm.js +25 -30
- package/build/cjs/components/Interpretations/InterpretationsUnit/InterpretationList.js +8 -38
- package/build/cjs/components/Interpretations/InterpretationsUnit/InterpretationsUnit.js +22 -73
- package/build/cjs/components/Interpretations/common/Interpretation/Interpretation.js +20 -34
- package/build/cjs/components/Interpretations/common/Interpretation/InterpretationDeleteButton.js +10 -12
- package/build/cjs/components/Interpretations/common/Interpretation/InterpretationUpdateForm.js +13 -24
- package/build/cjs/components/Interpretations/common/Message/MessageEditorContainer.js +3 -3
- package/build/cjs/index.js +72 -63
- package/build/cjs/locales/en/translations.json +10 -1
- package/build/es/__demo__/InterpretationsUnit.stories.js +9 -6
- package/build/es/__fixtures__/interpretationsMockData.js +198 -0
- package/build/es/components/Interpretations/DashboardItemInterpretations/DashboardInterpretationThread.js +48 -0
- package/build/es/components/Interpretations/DashboardItemInterpretations/DashboardItemInterpretations.js +45 -0
- package/build/es/components/Interpretations/DashboardItemInterpretations/index.js +1 -0
- package/build/es/components/Interpretations/InterpretationModal/Comment.js +14 -19
- package/build/es/components/Interpretations/InterpretationModal/CommentAddForm.js +21 -35
- package/build/es/components/Interpretations/InterpretationModal/CommentDeleteButton.js +11 -35
- package/build/es/components/Interpretations/InterpretationModal/CommentUpdateForm.js +12 -28
- package/build/es/components/Interpretations/InterpretationModal/InterpretationModal.js +12 -69
- package/build/es/components/Interpretations/InterpretationModal/InterpretationThread.js +11 -24
- package/build/es/components/Interpretations/InterpretationsProvider/InterpretationsManager.js +268 -0
- package/build/es/components/Interpretations/InterpretationsProvider/InterpretationsProvider.js +19 -0
- package/build/es/components/Interpretations/InterpretationsProvider/__tests__/groupInterpretationIdsByDate.spec.js +35 -0
- package/build/es/components/Interpretations/InterpretationsProvider/__tests__/hooks.spec.js +561 -0
- package/build/es/components/Interpretations/InterpretationsProvider/groupInterpretationIdsByDate.js +9 -0
- package/build/es/components/Interpretations/InterpretationsProvider/hooks.js +258 -0
- package/build/es/components/Interpretations/InterpretationsProvider/index.js +1 -0
- package/build/es/components/Interpretations/InterpretationsUnit/InterpretationForm.js +26 -31
- package/build/es/components/Interpretations/InterpretationsUnit/InterpretationList.js +8 -38
- package/build/es/components/Interpretations/InterpretationsUnit/InterpretationsUnit.js +23 -75
- package/build/es/components/Interpretations/common/Interpretation/Interpretation.js +21 -35
- package/build/es/components/Interpretations/common/Interpretation/InterpretationDeleteButton.js +11 -13
- package/build/es/components/Interpretations/common/Interpretation/InterpretationUpdateForm.js +14 -25
- package/build/es/components/Interpretations/common/Message/MessageEditorContainer.js +3 -3
- package/build/es/index.js +3 -1
- package/build/es/locales/en/translations.json +10 -1
- package/package.json +1 -1
- package/build/cjs/components/Interpretations/common/Interpretation/useLike.js +0 -56
- 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, {
|
|
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 [
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
-
|
|
32
|
+
currentUserName: currentUser.name,
|
|
37
33
|
dataTest: "interpretation-form"
|
|
38
34
|
}, showRichTextEditor ? /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(RichTextEditor, {
|
|
39
|
-
disabled:
|
|
35
|
+
disabled: loading,
|
|
40
36
|
inputPlaceholder: inputPlaceholder,
|
|
41
|
-
onChange:
|
|
42
|
-
value:
|
|
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:
|
|
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:
|
|
51
|
+
disabled: loading,
|
|
55
52
|
onClick: () => {
|
|
56
|
-
|
|
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
|
-
|
|
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(
|
|
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
|
-
},
|
|
57
|
-
key:
|
|
58
|
-
|
|
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
|
-
|
|
64
|
-
onUpdated: refresh,
|
|
37
|
+
dashboardRedirectUrl: dashboardRedirectUrl,
|
|
65
38
|
disabled: disabled,
|
|
66
|
-
|
|
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
|
-
|
|
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, {
|
|
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
|
|
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
|
|
14
|
+
onInterpretationClick,
|
|
28
15
|
onReplyIconClick,
|
|
29
16
|
disabled,
|
|
30
|
-
renderId,
|
|
31
17
|
dashboardRedirectUrl
|
|
32
|
-
}
|
|
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
|
-
|
|
39
|
-
|
|
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([["
|
|
27
|
+
className: _JSXStyle.dynamic([["2008120072", [spacers.dp16, colors.grey400, colors.white, spacers.dp32, colors.grey900]]]) + " " + (cx('container', {
|
|
71
28
|
expanded: isExpanded
|
|
72
29
|
}) || "")
|
|
73
|
-
},
|
|
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([["
|
|
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([["
|
|
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([["
|
|
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
|
-
})),
|
|
91
|
-
|
|
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
|
-
|
|
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: "
|
|
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};}`,
|
|
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
|
};
|