@dhis2/analytics 23.11.1 → 23.12.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 (74) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/build/cjs/components/Interpretations/InterpretationModal/Comment.js +64 -0
  3. package/build/cjs/components/Interpretations/InterpretationModal/CommentAddForm.js +93 -0
  4. package/build/cjs/components/Interpretations/InterpretationModal/CommentDeleteButton.js +62 -0
  5. package/build/cjs/components/Interpretations/InterpretationModal/CommentUpdateForm.js +95 -0
  6. package/build/cjs/components/Interpretations/InterpretationModal/InterpretationModal.js +187 -0
  7. package/build/cjs/components/Interpretations/InterpretationModal/InterpretationThread.js +100 -0
  8. package/build/cjs/components/Interpretations/InterpretationModal/index.js +13 -0
  9. package/build/cjs/components/Interpretations/InterpretationModal/useModalContentWidth.js +39 -0
  10. package/build/cjs/components/Interpretations/InterpretationsUnit/InterpretationForm.js +94 -0
  11. package/build/cjs/components/Interpretations/InterpretationsUnit/InterpretationList.js +94 -0
  12. package/build/cjs/components/Interpretations/InterpretationsUnit/InterpretationsUnit.js +135 -0
  13. package/build/cjs/components/Interpretations/InterpretationsUnit/index.js +13 -0
  14. package/build/cjs/components/Interpretations/common/Interpretation/Interpretation.js +110 -0
  15. package/build/cjs/components/Interpretations/common/Interpretation/InterpretationDeleteButton.js +58 -0
  16. package/build/cjs/components/Interpretations/common/Interpretation/InterpretationSharingLink.js +50 -0
  17. package/build/cjs/components/Interpretations/common/Interpretation/InterpretationUpdateForm.js +108 -0
  18. package/build/cjs/components/Interpretations/common/Interpretation/index.js +21 -0
  19. package/build/cjs/components/Interpretations/common/Interpretation/useLike.js +53 -0
  20. package/build/cjs/components/Interpretations/common/Message/Message.js +55 -0
  21. package/build/cjs/components/Interpretations/common/Message/MessageButtonStrip.js +33 -0
  22. package/build/cjs/components/Interpretations/common/Message/MessageEditorContainer.js +42 -0
  23. package/build/cjs/components/Interpretations/common/Message/MessageIconButton.js +67 -0
  24. package/build/cjs/components/Interpretations/common/Message/MessageInput.js +31 -0
  25. package/build/cjs/components/Interpretations/common/Message/MessageStatsBar.js +33 -0
  26. package/build/cjs/components/Interpretations/common/Message/index.js +53 -0
  27. package/build/cjs/components/Interpretations/common/RichTextEditor/RichTextEditor.js +262 -0
  28. package/build/cjs/components/Interpretations/common/RichTextEditor/index.js +13 -0
  29. package/build/cjs/components/Interpretations/common/RichTextEditor/markdownHandler.js +148 -0
  30. package/build/cjs/components/Interpretations/common/RichTextEditor/styles/RichTextEditor.style.js +21 -0
  31. package/build/cjs/components/Interpretations/common/UserMention/UserList.js +48 -0
  32. package/build/cjs/components/Interpretations/common/UserMention/UserMentionWrapper.js +226 -0
  33. package/build/cjs/components/Interpretations/common/UserMention/styles/UserMentionWrapper.style.js +30 -0
  34. package/build/cjs/components/Interpretations/common/UserMention/useUserSearchResults.js +78 -0
  35. package/build/cjs/components/Interpretations/common/index.js +44 -0
  36. package/build/cjs/index.js +16 -0
  37. package/build/cjs/locales/en/translations.json +32 -1
  38. package/build/es/components/Interpretations/InterpretationModal/Comment.js +45 -0
  39. package/build/es/components/Interpretations/InterpretationModal/CommentAddForm.js +70 -0
  40. package/build/es/components/Interpretations/InterpretationModal/CommentDeleteButton.js +47 -0
  41. package/build/es/components/Interpretations/InterpretationModal/CommentUpdateForm.js +73 -0
  42. package/build/es/components/Interpretations/InterpretationModal/InterpretationModal.js +165 -0
  43. package/build/es/components/Interpretations/InterpretationModal/InterpretationThread.js +79 -0
  44. package/build/es/components/Interpretations/InterpretationModal/index.js +1 -0
  45. package/build/es/components/Interpretations/InterpretationModal/useModalContentWidth.js +28 -0
  46. package/build/es/components/Interpretations/InterpretationsUnit/InterpretationForm.js +71 -0
  47. package/build/es/components/Interpretations/InterpretationsUnit/InterpretationList.js +78 -0
  48. package/build/es/components/Interpretations/InterpretationsUnit/InterpretationsUnit.js +112 -0
  49. package/build/es/components/Interpretations/InterpretationsUnit/index.js +1 -0
  50. package/build/es/components/Interpretations/common/Interpretation/Interpretation.js +87 -0
  51. package/build/es/components/Interpretations/common/Interpretation/InterpretationDeleteButton.js +43 -0
  52. package/build/es/components/Interpretations/common/Interpretation/InterpretationSharingLink.js +33 -0
  53. package/build/es/components/Interpretations/common/Interpretation/InterpretationUpdateForm.js +85 -0
  54. package/build/es/components/Interpretations/common/Interpretation/index.js +2 -0
  55. package/build/es/components/Interpretations/common/Interpretation/useLike.js +45 -0
  56. package/build/es/components/Interpretations/common/Message/Message.js +41 -0
  57. package/build/es/components/Interpretations/common/Message/MessageButtonStrip.js +21 -0
  58. package/build/es/components/Interpretations/common/Message/MessageEditorContainer.js +30 -0
  59. package/build/es/components/Interpretations/common/Message/MessageIconButton.js +54 -0
  60. package/build/es/components/Interpretations/common/Message/MessageInput.js +16 -0
  61. package/build/es/components/Interpretations/common/Message/MessageStatsBar.js +21 -0
  62. package/build/es/components/Interpretations/common/Message/index.js +6 -0
  63. package/build/es/components/Interpretations/common/RichTextEditor/RichTextEditor.js +240 -0
  64. package/build/es/components/Interpretations/common/RichTextEditor/index.js +1 -0
  65. package/build/es/components/Interpretations/common/RichTextEditor/markdownHandler.js +128 -0
  66. package/build/es/components/Interpretations/common/RichTextEditor/styles/RichTextEditor.style.js +9 -0
  67. package/build/es/components/Interpretations/common/UserMention/UserList.js +33 -0
  68. package/build/es/components/Interpretations/common/UserMention/UserMentionWrapper.js +202 -0
  69. package/build/es/components/Interpretations/common/UserMention/styles/UserMentionWrapper.style.js +17 -0
  70. package/build/es/components/Interpretations/common/UserMention/useUserSearchResults.js +63 -0
  71. package/build/es/components/Interpretations/common/index.js +3 -0
  72. package/build/es/index.js +2 -0
  73. package/build/es/locales/en/translations.json +32 -1
  74. package/package.json +2 -1
@@ -83,6 +83,38 @@
83
83
  "line list": "line list",
84
84
  "map": "map",
85
85
  "visualization": "visualization",
86
+ "Edit": "Edit",
87
+ "Write a reply": "Write a reply",
88
+ "Post reply": "Post reply",
89
+ "Could not update comment": "Could not update comment",
90
+ "Enter comment text": "Enter comment text",
91
+ "Update": "Update",
92
+ "Viewing interpretation: {{visualisationName}}": "Viewing interpretation: {{visualisationName}}",
93
+ "Could not load interpretation": "Could not load interpretation",
94
+ "The interpretation couldn’t be displayed. Try again or contact your system administrator.": "The interpretation couldn’t be displayed. Try again or contact your system administrator.",
95
+ "Hide interpretation": "Hide interpretation",
96
+ "Write an interpretation": "Write an interpretation",
97
+ "Post interpretation": "Post interpretation",
98
+ "Interpretations": "Interpretations",
99
+ "Unlike": "Unlike",
100
+ "Like": "Like",
101
+ "Reply": "Reply",
102
+ "Share": "Share",
103
+ "See interpretation": "See interpretation",
104
+ "Manage sharing": "Manage sharing",
105
+ "Could not update interpretation": "Could not update interpretation",
106
+ "Enter interpretation text": "Enter interpretation text",
107
+ "Bold text": "Bold text",
108
+ "Italic text": "Italic text",
109
+ "Link to a URL": "Link to a URL",
110
+ "Mention a user": "Mention a user",
111
+ "Add emoji": "Add emoji",
112
+ "Preview": "Preview",
113
+ "Back to write mode": "Back to write mode",
114
+ "Too many results. Try refining the search.": "Too many results. Try refining the search.",
115
+ "Search for a user": "Search for a user",
116
+ "Searching for \"{{searchText}}\"": "Searching for \"{{searchText}}\"",
117
+ "No results found": "No results found",
86
118
  "Created by": "Created by",
87
119
  "Anyone": "Anyone",
88
120
  "Only you": "Only you",
@@ -123,7 +155,6 @@
123
155
  "New line list": "New line list",
124
156
  "Options": "Options",
125
157
  "Hide": "Hide",
126
- "Update": "Update",
127
158
  "{{count}} org units": "{{count}} org unit",
128
159
  "{{count}} org units_plural": "{{count}} org units",
129
160
  "{{count}} levels": "{{count}} level",
@@ -0,0 +1,45 @@
1
+ import i18n from '@dhis2/d2-i18n';
2
+ import { IconEdit16 } from '@dhis2/ui';
3
+ import PropTypes from 'prop-types';
4
+ import React, { useState } from 'react';
5
+ import { Message, MessageIconButton, MessageStatsBar } from '../common/index.js';
6
+ import { CommentDeleteButton } from './CommentDeleteButton.js';
7
+ import { CommentUpdateForm } from './CommentUpdateForm.js';
8
+
9
+ const Comment = _ref => {
10
+ let {
11
+ comment,
12
+ currentUser,
13
+ interpretationId,
14
+ onThreadUpdated
15
+ } = _ref;
16
+ const [isUpdateMode, setIsUpdateMode] = useState(false);
17
+ return isUpdateMode ? /*#__PURE__*/React.createElement(CommentUpdateForm, {
18
+ close: () => setIsUpdateMode(false),
19
+ commentId: comment.id,
20
+ interpretationId: interpretationId,
21
+ onComplete: () => onThreadUpdated(false),
22
+ text: comment.text,
23
+ currentUser: currentUser
24
+ }) : /*#__PURE__*/React.createElement(Message, {
25
+ text: comment.text,
26
+ created: comment.created,
27
+ username: comment.createdBy.displayName
28
+ }, /*#__PURE__*/React.createElement(MessageStatsBar, null, comment.access.update && /*#__PURE__*/React.createElement(MessageIconButton, {
29
+ iconComponent: IconEdit16,
30
+ tooltipContent: i18n.t('Edit'),
31
+ onClick: () => setIsUpdateMode(true)
32
+ }), comment.access.delete && /*#__PURE__*/React.createElement(CommentDeleteButton, {
33
+ commentId: comment.id,
34
+ interpretationId: interpretationId,
35
+ onComplete: () => onThreadUpdated(true)
36
+ })));
37
+ };
38
+
39
+ Comment.propTypes = {
40
+ comment: PropTypes.object.isRequired,
41
+ currentUser: PropTypes.object.isRequired,
42
+ interpretationId: PropTypes.string.isRequired,
43
+ onThreadUpdated: PropTypes.func.isRequired
44
+ };
45
+ export { Comment };
@@ -0,0 +1,70 @@
1
+ import { useDataMutation } from '@dhis2/app-runtime';
2
+ import i18n from '@dhis2/d2-i18n';
3
+ import { Button } from '@dhis2/ui';
4
+ import PropTypes from 'prop-types';
5
+ import React, { useRef, useState } from 'react';
6
+ import { RichTextEditor, MessageEditorContainer, MessageButtonStrip, MessageInput } from '../common/index.js';
7
+ export const CommentAddForm = _ref => {
8
+ let {
9
+ interpretationId,
10
+ currentUser,
11
+ onSave,
12
+ focusRef
13
+ } = _ref;
14
+ const [showRichTextEditor, setShowRichTextEditor] = useState(false);
15
+ const [commentText, setCommentText] = useState('');
16
+ const saveMutationRef = useRef({
17
+ resource: "interpretations/".concat(interpretationId, "/comments"),
18
+ type: 'create',
19
+ data: _ref2 => {
20
+ let {
21
+ commentText
22
+ } = _ref2;
23
+ return commentText;
24
+ }
25
+ });
26
+ const [save, {
27
+ loading
28
+ }] = useDataMutation(saveMutationRef.current, {
29
+ onComplete: () => {
30
+ setShowRichTextEditor(false);
31
+ setCommentText('');
32
+ onSave();
33
+ }
34
+ });
35
+ const inputPlaceholder = i18n.t('Write a reply');
36
+ return /*#__PURE__*/React.createElement(MessageEditorContainer, {
37
+ currentUser: currentUser
38
+ }, showRichTextEditor ? /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(RichTextEditor, {
39
+ inputPlaceholder: inputPlaceholder,
40
+ onChange: setCommentText,
41
+ value: commentText,
42
+ ref: focusRef,
43
+ disabled: loading
44
+ }), /*#__PURE__*/React.createElement(MessageButtonStrip, null, /*#__PURE__*/React.createElement(Button, {
45
+ primary: true,
46
+ small: true,
47
+ onClick: () => save({
48
+ commentText
49
+ }),
50
+ loading: loading
51
+ }, i18n.t('Post reply')), /*#__PURE__*/React.createElement(Button, {
52
+ secondary: true,
53
+ small: true,
54
+ disabled: loading,
55
+ onClick: () => {
56
+ setCommentText('');
57
+ setShowRichTextEditor(false);
58
+ }
59
+ }, i18n.t('Cancel')))) : /*#__PURE__*/React.createElement(MessageInput, {
60
+ onFocus: () => setShowRichTextEditor(true),
61
+ placeholder: inputPlaceholder,
62
+ ref: focusRef
63
+ }));
64
+ };
65
+ CommentAddForm.propTypes = {
66
+ currentUser: PropTypes.object.isRequired,
67
+ focusRef: PropTypes.object.isRequired,
68
+ interpretationId: PropTypes.string.isRequired,
69
+ onSave: PropTypes.func
70
+ };
@@ -0,0 +1,47 @@
1
+ import { useDataMutation } from '@dhis2/app-runtime';
2
+ import i18n from '@dhis2/d2-i18n';
3
+ import { IconDelete16 } from '@dhis2/ui';
4
+ import PropTypes from 'prop-types';
5
+ import React from 'react';
6
+ import { MessageIconButton } from '../common/index.js';
7
+ const mutation = {
8
+ resource: 'interpretations',
9
+ id: _ref => {
10
+ let {
11
+ interpretationId,
12
+ commentId
13
+ } = _ref;
14
+ return "".concat(interpretationId, "/comments/").concat(commentId);
15
+ },
16
+ type: 'delete'
17
+ };
18
+
19
+ const CommentDeleteButton = _ref2 => {
20
+ let {
21
+ commentId,
22
+ interpretationId,
23
+ onComplete
24
+ } = _ref2;
25
+ const [remove, {
26
+ loading
27
+ }] = useDataMutation(mutation, {
28
+ onComplete,
29
+ variables: {
30
+ commentId,
31
+ interpretationId
32
+ }
33
+ });
34
+ return /*#__PURE__*/React.createElement(MessageIconButton, {
35
+ tooltipContent: i18n.t('Delete'),
36
+ iconComponent: IconDelete16,
37
+ onClick: remove,
38
+ disabled: loading
39
+ });
40
+ };
41
+
42
+ CommentDeleteButton.propTypes = {
43
+ commentId: PropTypes.string.isRequired,
44
+ interpretationId: PropTypes.string.isRequired,
45
+ onComplete: PropTypes.func.isRequired
46
+ };
47
+ export { CommentDeleteButton };
@@ -0,0 +1,73 @@
1
+ import _JSXStyle from "styled-jsx/style";
2
+ import { useDataMutation } from '@dhis2/app-runtime';
3
+ import i18n from '@dhis2/d2-i18n';
4
+ import { Button, spacers, colors } from '@dhis2/ui';
5
+ import PropTypes from 'prop-types';
6
+ import React, { useState, useRef } from 'react';
7
+ import { MessageEditorContainer, RichTextEditor, MessageButtonStrip } from '../common/index.js';
8
+ export const CommentUpdateForm = _ref => {
9
+ let {
10
+ interpretationId,
11
+ commentId,
12
+ currentUser,
13
+ text,
14
+ close,
15
+ onComplete
16
+ } = _ref;
17
+ const [commentText, setCommentText] = useState(text || '');
18
+ const updateMutationRef = useRef({
19
+ resource: "interpretations/".concat(interpretationId, "/comments/").concat(commentId),
20
+ type: 'update',
21
+ partial: false,
22
+ data: _ref2 => {
23
+ let {
24
+ commentText
25
+ } = _ref2;
26
+ return commentText;
27
+ }
28
+ });
29
+ const [update, {
30
+ loading,
31
+ error
32
+ }] = useDataMutation(updateMutationRef.current, {
33
+ onComplete: () => {
34
+ onComplete();
35
+ close();
36
+ }
37
+ });
38
+ const errorText = error ? error.message || i18n.t('Could not update comment') : '';
39
+ return /*#__PURE__*/React.createElement("div", {
40
+ className: _JSXStyle.dynamic([["2690082310", [spacers.dp8, spacers.dp8, colors.grey100]]]) + " " + "message"
41
+ }, /*#__PURE__*/React.createElement(MessageEditorContainer, {
42
+ currentUser: currentUser
43
+ }, /*#__PURE__*/React.createElement(RichTextEditor, {
44
+ inputPlaceholder: i18n.t('Enter comment text'),
45
+ onChange: setCommentText,
46
+ value: commentText,
47
+ disabled: loading,
48
+ errorText: errorText
49
+ }), /*#__PURE__*/React.createElement(MessageButtonStrip, null, /*#__PURE__*/React.createElement(Button, {
50
+ loading: loading,
51
+ primary: true,
52
+ small: true,
53
+ onClick: () => update({
54
+ commentText
55
+ })
56
+ }, i18n.t('Update')), /*#__PURE__*/React.createElement(Button, {
57
+ disabled: loading,
58
+ secondary: true,
59
+ small: true,
60
+ onClick: close
61
+ }, i18n.t('Cancel')))), /*#__PURE__*/React.createElement(_JSXStyle, {
62
+ id: "2690082310",
63
+ dynamic: [spacers.dp8, spacers.dp8, colors.grey100]
64
+ }, [".message.__jsx-style-dynamic-selector{padding:0 ".concat(spacers.dp8, " ").concat(spacers.dp8, ";background-color:").concat(colors.grey100, ";border-radius:5px;}")]));
65
+ };
66
+ CommentUpdateForm.propTypes = {
67
+ close: PropTypes.func.isRequired,
68
+ commentId: PropTypes.string.isRequired,
69
+ currentUser: PropTypes.object.isRequired,
70
+ interpretationId: PropTypes.string.isRequired,
71
+ onComplete: PropTypes.func.isRequired,
72
+ text: PropTypes.string
73
+ };
@@ -0,0 +1,165 @@
1
+ import _JSXStyle from "styled-jsx/style";
2
+ import { useDataQuery } from '@dhis2/app-runtime';
3
+ import i18n from '@dhis2/d2-i18n';
4
+ import { Modal, ModalActions, ModalContent, NoticeBox, Button, spacers, colors, Layer, CenteredContent, CircularLoader } from '@dhis2/ui';
5
+ import cx from 'classnames';
6
+ import PropTypes from 'prop-types';
7
+ import React, { useEffect, useState } from 'react';
8
+ import { InterpretationThread } from './InterpretationThread.js';
9
+ import { useModalContentWidth } from './useModalContentWidth.js';
10
+ const modalCSS = {
11
+ styles: /*#__PURE__*/React.createElement(_JSXStyle, {
12
+ id: "422732072"
13
+ }, ["aside.jsx-422732072{max-width:calc(100vw - 128px) !important;max-height:calc(100vh - 128px) !important;width:auto !important;height:auto !important;overflow-y:hidden;}", "aside.hidden.jsx-422732072{display:none;}", "aside.jsx-422732072>div>div{max-height:none;}"]),
14
+ className: "jsx-422732072"
15
+ };
16
+
17
+ function getModalContentCSS(width) {
18
+ return {
19
+ styles: /*#__PURE__*/React.createElement(_JSXStyle, {
20
+ id: "1689110567",
21
+ dynamic: [width]
22
+ }, ["div.__jsx-style-dynamic-selector{width:".concat(width, "px;}")]),
23
+ className: _JSXStyle.dynamic([["1689110567", [width]]])
24
+ };
25
+ }
26
+
27
+ const query = {
28
+ interpretation: {
29
+ resource: 'interpretations',
30
+ id: _ref => {
31
+ let {
32
+ id
33
+ } = _ref;
34
+ return id;
35
+ },
36
+ params: {
37
+ fields: ['access', 'id', 'text', 'created', 'user[id,displayName]', 'likes', 'likedBy', 'comments[access,id,text,created,createdBy[id,displayName]]']
38
+ }
39
+ }
40
+ };
41
+
42
+ const InterpretationModal = _ref2 => {
43
+ let {
44
+ currentUser,
45
+ isVisualizationLoading,
46
+ visualization,
47
+ onResponsesReceived,
48
+ downloadMenuComponent,
49
+ onClose,
50
+ onInterpretationUpdate,
51
+ interpretationId,
52
+ initialFocus,
53
+ pluginComponent: VisualizationPlugin
54
+ } = _ref2;
55
+ const modalContentWidth = useModalContentWidth();
56
+ const modalContentCSS = getModalContentCSS(modalContentWidth);
57
+ const [isDirty, setIsDirty] = useState(false);
58
+ const {
59
+ data,
60
+ error,
61
+ loading,
62
+ fetching,
63
+ refetch
64
+ } = useDataQuery(query, {
65
+ lazy: true
66
+ });
67
+ const interpretation = data === null || data === void 0 ? void 0 : data.interpretation;
68
+ const shouldRenderModalContent = !error && interpretation;
69
+ const shouldCssHideModal = loading || isVisualizationLoading;
70
+
71
+ const handleClose = () => {
72
+ if (isDirty) {
73
+ onInterpretationUpdate();
74
+ setIsDirty(false);
75
+ }
76
+
77
+ onClose();
78
+ };
79
+
80
+ const onThreadUpdated = affectsInterpretation => {
81
+ if (affectsInterpretation) {
82
+ setIsDirty(true);
83
+ }
84
+
85
+ refetch({
86
+ id: interpretationId
87
+ });
88
+ };
89
+
90
+ const onInterpretationDeleted = () => {
91
+ setIsDirty(false);
92
+ onInterpretationUpdate();
93
+ onClose();
94
+ };
95
+
96
+ useEffect(() => {
97
+ if (interpretationId) {
98
+ refetch({
99
+ id: interpretationId
100
+ });
101
+ }
102
+ }, [interpretationId]);
103
+ 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, {
104
+ fluid: true,
105
+ onClose: handleClose,
106
+ className: cx(modalCSS.className, {
107
+ hidden: shouldCssHideModal
108
+ })
109
+ }, /*#__PURE__*/React.createElement("h1", {
110
+ className: _JSXStyle.dynamic([["3636222142", [colors.grey900, spacers.dp24, spacers.dp4, spacers.dp4]]]) + " " + "title"
111
+ }, /*#__PURE__*/React.createElement("span", {
112
+ className: _JSXStyle.dynamic([["3636222142", [colors.grey900, spacers.dp24, spacers.dp4, spacers.dp4]]]) + " " + "ellipsis"
113
+ }, i18n.t('Viewing interpretation: {{visualisationName}}', {
114
+ visualisationName: visualization.displayName,
115
+ nsSeparator: '^^'
116
+ }))), /*#__PURE__*/React.createElement(ModalContent, {
117
+ className: modalContentCSS.className
118
+ }, /*#__PURE__*/React.createElement("div", {
119
+ className: _JSXStyle.dynamic([["3636222142", [colors.grey900, spacers.dp24, spacers.dp4, spacers.dp4]]]) + " " + "container"
120
+ }, error && /*#__PURE__*/React.createElement(NoticeBox, {
121
+ error: true,
122
+ title: i18n.t('Could not load interpretation')
123
+ }, error.message || i18n.t('The interpretation couldn’t be displayed. Try again or contact your system administrator.')), shouldRenderModalContent && /*#__PURE__*/React.createElement("div", {
124
+ className: _JSXStyle.dynamic([["3636222142", [colors.grey900, spacers.dp24, spacers.dp4, spacers.dp4]]]) + " " + "row"
125
+ }, /*#__PURE__*/React.createElement("div", {
126
+ className: _JSXStyle.dynamic([["3636222142", [colors.grey900, spacers.dp24, spacers.dp4, spacers.dp4]]]) + " " + "visualisation-wrap"
127
+ }, /*#__PURE__*/React.createElement(VisualizationPlugin, {
128
+ filters: {
129
+ relativePeriodDate: interpretation.created
130
+ },
131
+ visualization: visualization,
132
+ onResponsesReceived: onResponsesReceived,
133
+ className: _JSXStyle.dynamic([["3636222142", [colors.grey900, spacers.dp24, spacers.dp4, spacers.dp4]]])
134
+ })), /*#__PURE__*/React.createElement("div", {
135
+ className: _JSXStyle.dynamic([["3636222142", [colors.grey900, spacers.dp24, spacers.dp4, spacers.dp4]]]) + " " + "thread-wrap"
136
+ }, /*#__PURE__*/React.createElement(InterpretationThread, {
137
+ currentUser: currentUser,
138
+ fetching: fetching,
139
+ interpretation: interpretation,
140
+ onInterpretationDeleted: onInterpretationDeleted,
141
+ onThreadUpdated: onThreadUpdated,
142
+ initialFocus: initialFocus,
143
+ downloadMenuComponent: downloadMenuComponent
144
+ }))))), /*#__PURE__*/React.createElement(ModalActions, null, /*#__PURE__*/React.createElement(Button, {
145
+ disabled: fetching,
146
+ onClick: handleClose
147
+ }, i18n.t('Hide interpretation'))), modalCSS.styles, modalContentCSS.styles, /*#__PURE__*/React.createElement(_JSXStyle, {
148
+ id: "3636222142",
149
+ dynamic: [colors.grey900, spacers.dp24, spacers.dp4, spacers.dp4]
150
+ }, [".title.__jsx-style-dynamic-selector{color:".concat(colors.grey900, ";margin:0px;padding:").concat(spacers.dp24, " 0 ").concat(spacers.dp4, ";}"), ".ellipsis.__jsx-style-dynamic-selector{display:inline-block;font-size:20px;font-weight:500;line-height:24px;white-space:nowrap;width:100%;overflow:hidden;text-overflow:ellipsis;}", ".container.__jsx-style-dynamic-selector{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;}", ".row.__jsx-style-dynamic-selector{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;gap:16px;}", ".visualisation-wrap.__jsx-style-dynamic-selector{-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;}", ".thread-wrap.__jsx-style-dynamic-selector{padding-right:".concat(spacers.dp4, ";-webkit-flex-basis:300px;-ms-flex-preferred-size:300px;flex-basis:300px;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;overflow-y:auto;}")])));
151
+ };
152
+
153
+ InterpretationModal.propTypes = {
154
+ currentUser: PropTypes.object.isRequired,
155
+ downloadMenuComponent: PropTypes.oneOfType([PropTypes.object, PropTypes.func]).isRequired,
156
+ interpretationId: PropTypes.string.isRequired,
157
+ isVisualizationLoading: PropTypes.bool.isRequired,
158
+ pluginComponent: PropTypes.oneOfType([PropTypes.object, PropTypes.func]).isRequired,
159
+ visualization: PropTypes.object.isRequired,
160
+ onClose: PropTypes.func.isRequired,
161
+ onResponsesReceived: PropTypes.func.isRequired,
162
+ initialFocus: PropTypes.bool,
163
+ onInterpretationUpdate: PropTypes.func
164
+ };
165
+ export { InterpretationModal };
@@ -0,0 +1,79 @@
1
+ import _JSXStyle from "styled-jsx/style";
2
+ import { IconClock16, colors } from '@dhis2/ui';
3
+ import cx from 'classnames';
4
+ import moment from 'moment';
5
+ import PropTypes from 'prop-types';
6
+ import React, { useRef, useEffect } from 'react';
7
+ import { Interpretation } from '../common/index.js';
8
+ import { Comment } from './Comment.js';
9
+ import { CommentAddForm } from './CommentAddForm.js';
10
+
11
+ const InterpretationThread = _ref => {
12
+ let {
13
+ currentUser,
14
+ fetching,
15
+ interpretation,
16
+ onInterpretationDeleted,
17
+ initialFocus,
18
+ onThreadUpdated,
19
+ downloadMenuComponent: DownloadMenu
20
+ } = _ref;
21
+ const focusRef = useRef();
22
+ useEffect(() => {
23
+ if (initialFocus && focusRef.current) {
24
+ window.requestAnimationFrame(() => {
25
+ focusRef.current.focus();
26
+ });
27
+ }
28
+ }, [initialFocus, focusRef.current]);
29
+ return /*#__PURE__*/React.createElement("div", {
30
+ className: "jsx-2924001448" + " " + (cx('container', {
31
+ fetching
32
+ }) || "")
33
+ }, /*#__PURE__*/React.createElement("div", {
34
+ className: "jsx-2924001448" + " " + 'scrollbox'
35
+ }, /*#__PURE__*/React.createElement("div", {
36
+ className: "jsx-2924001448" + " " + 'title'
37
+ }, /*#__PURE__*/React.createElement(IconClock16, {
38
+ color: colors.grey700
39
+ }), moment(interpretation.created).format('LLL')), /*#__PURE__*/React.createElement(DownloadMenu, {
40
+ relativePeriodDate: interpretation.created,
41
+ className: "jsx-2924001448"
42
+ }), /*#__PURE__*/React.createElement(Interpretation, {
43
+ currentUser: currentUser,
44
+ interpretation: interpretation,
45
+ onReplyIconClick: () => {
46
+ var _focusRef$current;
47
+
48
+ return (_focusRef$current = focusRef.current) === null || _focusRef$current === void 0 ? void 0 : _focusRef$current.focus();
49
+ },
50
+ onUpdated: () => onThreadUpdated(true),
51
+ onDeleted: onInterpretationDeleted
52
+ }), /*#__PURE__*/React.createElement("div", {
53
+ className: "jsx-2924001448" + " " + 'comments'
54
+ }, interpretation.comments.map(comment => /*#__PURE__*/React.createElement(Comment, {
55
+ key: comment.id,
56
+ comment: comment,
57
+ currentUser: currentUser,
58
+ interpretationId: interpretation.id,
59
+ onThreadUpdated: onThreadUpdated
60
+ }))), /*#__PURE__*/React.createElement(CommentAddForm, {
61
+ currentUser: currentUser,
62
+ interpretationId: interpretation.id,
63
+ onSave: () => onThreadUpdated(true),
64
+ focusRef: focusRef
65
+ })), /*#__PURE__*/React.createElement(_JSXStyle, {
66
+ id: "2924001448"
67
+ }, [".container.jsx-2924001448{position:relative;overflow:hidden;max-height:calc(100vh - 285px);display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;}", ".container.fetching.jsx-2924001448::before{content:'';position:absolute;inset:0px;background-color:rgba(255,255,255,0.8);}", ".container.fetching.jsx-2924001448::after{content:'';position:absolute;top:calc(50% - 12px);left:calc(50% - 12px);width:24px;height:24px;border-width:4px;border-style:solid;border-color:rgba(110,122,138,0.15) rgba(110,122,138,0.15) rgb(20,124,215);border-image:initial;border-radius:50%;-webkit-animation:1s linear 0s infinite normal none running rotation-jsx-2924001448;animation:1s linear 0s infinite normal none running rotation-jsx-2924001448;}", ".scrollbox.jsx-2924001448{overflow-y:auto;-webkit-scroll-behavior:smooth;-moz-scroll-behavior:smooth;-ms-scroll-behavior:smooth;scroll-behavior:smooth;}", ".title.jsx-2924001448{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;gap:var(--spacers-dp8);color:var(--colors-grey900);font-size:14px;line-height:18px;}", ".comments.jsx-2924001448{padding-left:16px;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;padding-top:var(--spacers-dp4);gap:var(--spacers-dp4);}", "@-webkit-keyframes rotation-jsx-2924001448{0%{-webkit-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0);}100%{-webkit-transform:rotate(360deg);-ms-transform:rotate(360deg);transform:rotate(360deg);}}", "@keyframes rotation-jsx-2924001448{0%{-webkit-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0);}100%{-webkit-transform:rotate(360deg);-ms-transform:rotate(360deg);transform:rotate(360deg);}}"]));
68
+ };
69
+
70
+ InterpretationThread.propTypes = {
71
+ currentUser: PropTypes.object.isRequired,
72
+ downloadMenuComponent: PropTypes.oneOfType([PropTypes.object, PropTypes.func]).isRequired,
73
+ fetching: PropTypes.bool.isRequired,
74
+ interpretation: PropTypes.object.isRequired,
75
+ onInterpretationDeleted: PropTypes.func.isRequired,
76
+ initialFocus: PropTypes.bool,
77
+ onThreadUpdated: PropTypes.func
78
+ };
79
+ export { InterpretationThread };
@@ -0,0 +1 @@
1
+ export { InterpretationModal } from './InterpretationModal.js';
@@ -0,0 +1,28 @@
1
+ import { useState, useEffect } from 'react';
2
+ import { useDebounce } from '../../../modules/utils.js';
3
+ const MODAL_SIDE_PADDING = 2 * 24;
4
+ const MODAL_SIDE_MARGINS = 2 * 128;
5
+
6
+ const computeModalContentWidth = windowWidth => {
7
+ return windowWidth - MODAL_SIDE_MARGINS - MODAL_SIDE_PADDING;
8
+ };
9
+
10
+ export const useModalContentWidth = () => {
11
+ const [windowWidth, setWindowWidth] = useState(window.innerWidth);
12
+ const debouncedWindowWidth = useDebounce(windowWidth, 150);
13
+ const [modalContentWidth, setModalContentWidth] = useState(computeModalContentWidth(windowWidth));
14
+ useEffect(() => {
15
+ const onResize = () => {
16
+ setWindowWidth(window.innerWidth);
17
+ };
18
+
19
+ window.addEventListener('resize', onResize);
20
+ return () => {
21
+ window.removeEventListener('resize', onResize);
22
+ };
23
+ }, []);
24
+ useEffect(() => {
25
+ setModalContentWidth(computeModalContentWidth(debouncedWindowWidth));
26
+ }, [debouncedWindowWidth]);
27
+ return modalContentWidth;
28
+ };
@@ -0,0 +1,71 @@
1
+ import { useDataMutation } from '@dhis2/app-runtime';
2
+ import i18n from '@dhis2/d2-i18n';
3
+ import { Button, Input } from '@dhis2/ui';
4
+ import PropTypes from 'prop-types';
5
+ import React, { useRef, useState } from 'react';
6
+ import { RichTextEditor, MessageEditorContainer, MessageButtonStrip } from '../common/index.js';
7
+ export const InterpretationForm = _ref => {
8
+ let {
9
+ type,
10
+ id,
11
+ currentUser,
12
+ disabled,
13
+ onSave
14
+ } = _ref;
15
+ const [showRichTextEditor, setShowRichTextEditor] = useState(false);
16
+ const [interpretationText, setInterpretationText] = useState('');
17
+ const saveMutationRef = useRef({
18
+ resource: "interpretations/".concat(type, "/").concat(id),
19
+ type: 'create',
20
+ data: _ref2 => {
21
+ let {
22
+ interpretationText
23
+ } = _ref2;
24
+ return interpretationText;
25
+ }
26
+ });
27
+ const [save, {
28
+ loading: saveMutationInProgress
29
+ }] = useDataMutation(saveMutationRef.current, {
30
+ onComplete: () => {
31
+ setShowRichTextEditor(false);
32
+ setInterpretationText('');
33
+ onSave();
34
+ }
35
+ });
36
+ const inputPlaceholder = i18n.t('Write an interpretation');
37
+ return /*#__PURE__*/React.createElement(MessageEditorContainer, {
38
+ currentUser: currentUser
39
+ }, showRichTextEditor ? /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(RichTextEditor, {
40
+ disabled: saveMutationInProgress,
41
+ inputPlaceholder: inputPlaceholder,
42
+ onChange: setInterpretationText,
43
+ value: interpretationText
44
+ }), /*#__PURE__*/React.createElement(MessageButtonStrip, null, /*#__PURE__*/React.createElement(Button, {
45
+ primary: true,
46
+ small: true,
47
+ disabled: saveMutationInProgress,
48
+ onClick: () => save({
49
+ interpretationText
50
+ })
51
+ }, i18n.t('Post interpretation')), /*#__PURE__*/React.createElement(Button, {
52
+ secondary: true,
53
+ small: true,
54
+ disabled: saveMutationInProgress,
55
+ onClick: () => {
56
+ setInterpretationText('');
57
+ setShowRichTextEditor(false);
58
+ }
59
+ }, i18n.t('Cancel')))) : /*#__PURE__*/React.createElement(Input, {
60
+ onFocus: () => setShowRichTextEditor(true),
61
+ placeholder: inputPlaceholder,
62
+ disabled: disabled
63
+ }));
64
+ };
65
+ InterpretationForm.propTypes = {
66
+ currentUser: PropTypes.object,
67
+ disabled: PropTypes.bool,
68
+ id: PropTypes.string,
69
+ type: PropTypes.string,
70
+ onSave: PropTypes.func
71
+ };