argous 1.2.222 → 1.2.224
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/dist/api/index.d.ts +2 -0
- package/dist/api/index.js +36 -1
- package/dist/components/ArgousComplexTable/ArgousComplexTable.d.ts +9 -1
- package/dist/components/ArgousComplexTable/ArgousComplexTable.js +7 -7
- package/dist/components/BarraFerramentas/BarraFerramentas.d.ts +4 -1
- package/dist/components/BarraFerramentas/BarraFerramentas.js +48 -26
- package/dist/components/Document/Icons.d.ts +193 -0
- package/dist/components/Document/Icons.js +269 -0
- package/dist/components/Document/ModalVisualizacaoDocumentos.d.ts +8 -0
- package/dist/components/Document/ModalVisualizacaoDocumentos.js +84 -0
- package/dist/components/Document/Visualizacao.d.ts +12 -0
- package/dist/components/Document/Visualizacao.js +205 -0
- package/dist/components/Document/icons/ai.svg +20 -0
- package/dist/components/Document/icons/audio.svg +16 -0
- package/dist/components/Document/icons/avi.svg +15 -0
- package/dist/components/Document/icons/css.svg +47 -0
- package/dist/components/Document/icons/csv.svg +37 -0
- package/dist/components/Document/icons/dbf.svg +30 -0
- package/dist/components/Document/icons/doc.svg +47 -0
- package/dist/components/Document/icons/dwg.svg +32 -0
- package/dist/components/Document/icons/exe.svg +20 -0
- package/dist/components/Document/icons/file.svg +11 -0
- package/dist/components/Document/icons/fla.svg +23 -0
- package/dist/components/Document/icons/html.svg +23 -0
- package/dist/components/Document/icons/image.svg +16 -0
- package/dist/components/Document/icons/iso.svg +40 -0
- package/dist/components/Document/icons/jpg.svg +33 -0
- package/dist/components/Document/icons/js.svg +40 -0
- package/dist/components/Document/icons/json.svg +45 -0
- package/dist/components/Document/icons/mod.svg +41 -0
- package/dist/components/Document/icons/mp3.svg +36 -0
- package/dist/components/Document/icons/mp4.svg +25 -0
- package/dist/components/Document/icons/pdf.svg +35 -0
- package/dist/components/Document/icons/png.svg +30 -0
- package/dist/components/Document/icons/ppt.svg +31 -0
- package/dist/components/Document/icons/psd.svg +50 -0
- package/dist/components/Document/icons/rtf.svg +35 -0
- package/dist/components/Document/icons/search.svg +20 -0
- package/dist/components/Document/icons/svg.svg +34 -0
- package/dist/components/Document/icons/txt.svg +29 -0
- package/dist/components/Document/icons/video.svg +17 -0
- package/dist/components/Document/icons/xls.svg +31 -0
- package/dist/components/Document/icons/xml.svg +25 -0
- package/dist/components/Document/icons/zip.svg +24 -0
- package/dist/components/Document/icons/zip1.svg +18 -0
- package/dist/components/Document/index.d.ts +3 -0
- package/dist/components/Document/index.js +21 -0
- package/dist/components/Programa/Annotations/Annotation.d.ts +19 -0
- package/dist/components/Programa/Annotations/Annotation.js +316 -0
- package/dist/components/Programa/Annotations/AnnotationsList.d.ts +3 -0
- package/dist/components/Programa/Annotations/AnnotationsList.js +50 -0
- package/dist/components/Programa/Annotations/Input/FileInput.d.ts +6 -0
- package/dist/components/Programa/Annotations/Input/FileInput.js +147 -0
- package/dist/components/Programa/Annotations/Input/Input.d.ts +3 -0
- package/dist/components/Programa/Annotations/Input/Input.js +218 -0
- package/dist/components/Programa/Annotations/Input/PrivacySelection.d.ts +7 -0
- package/dist/components/Programa/Annotations/Input/PrivacySelection.js +65 -0
- package/dist/components/Programa/Annotations/Input/ReplyInformation.d.ts +5 -0
- package/dist/components/Programa/Annotations/Input/ReplyInformation.js +78 -0
- package/dist/components/Programa/Annotations/Input/UsersAutocomplete.d.ts +7 -0
- package/dist/components/Programa/Annotations/Input/UsersAutocomplete.js +139 -0
- package/dist/components/Programa/Annotations/index.d.ts +23 -0
- package/dist/components/Programa/Annotations/index.js +195 -0
- package/dist/components/Programa/Annotations/utils.d.ts +18 -0
- package/dist/components/Programa/Annotations/utils.js +46 -0
- package/dist/components/Programa/Programa.d.ts +3 -1
- package/dist/components/Programa/Programa.js +20 -6
- package/dist/components/index.d.ts +3 -1
- package/dist/components/index.js +1 -0
- package/dist/utils/index.d.ts +47 -0
- package/dist/utils/index.js +104 -4
- package/lib/api/index.js +24 -6
- package/lib/components/ArgousComplexTable/ArgousComplexTable.d.ts +9 -1
- package/lib/components/ArgousComplexTable/ArgousComplexTable.js +6 -4
- package/lib/components/BarraFerramentas/BarraFerramentas.d.ts +4 -1
- package/lib/components/BarraFerramentas/BarraFerramentas.js +92 -50
- package/lib/components/Document/Icons.js +169 -0
- package/lib/components/Document/ModalVisualizacaoDocumentos.js +64 -0
- package/lib/components/Document/Visualizacao.js +104 -0
- package/lib/components/Document/icons/ai.svg +20 -0
- package/lib/components/Document/icons/audio.svg +16 -0
- package/lib/components/Document/icons/avi.svg +15 -0
- package/lib/components/Document/icons/css.svg +47 -0
- package/lib/components/Document/icons/csv.svg +37 -0
- package/lib/components/Document/icons/dbf.svg +30 -0
- package/lib/components/Document/icons/doc.svg +47 -0
- package/lib/components/Document/icons/dwg.svg +32 -0
- package/lib/components/Document/icons/exe.svg +20 -0
- package/lib/components/Document/icons/file.svg +11 -0
- package/lib/components/Document/icons/fla.svg +23 -0
- package/lib/components/Document/icons/html.svg +23 -0
- package/lib/components/Document/icons/image.svg +16 -0
- package/lib/components/Document/icons/iso.svg +40 -0
- package/lib/components/Document/icons/jpg.svg +33 -0
- package/lib/components/Document/icons/js.svg +40 -0
- package/lib/components/Document/icons/json.svg +45 -0
- package/lib/components/Document/icons/mod.svg +41 -0
- package/lib/components/Document/icons/mp3.svg +36 -0
- package/lib/components/Document/icons/mp4.svg +25 -0
- package/lib/components/Document/icons/pdf.svg +35 -0
- package/lib/components/Document/icons/png.svg +30 -0
- package/lib/components/Document/icons/ppt.svg +31 -0
- package/lib/components/Document/icons/psd.svg +50 -0
- package/lib/components/Document/icons/rtf.svg +35 -0
- package/lib/components/Document/icons/search.svg +20 -0
- package/lib/components/Document/icons/svg.svg +34 -0
- package/lib/components/Document/icons/txt.svg +29 -0
- package/lib/components/Document/icons/video.svg +17 -0
- package/lib/components/Document/icons/xls.svg +31 -0
- package/lib/components/Document/icons/xml.svg +25 -0
- package/lib/components/Document/icons/zip.svg +24 -0
- package/lib/components/Document/icons/zip1.svg +18 -0
- package/lib/components/Document/index.d.ts +3 -0
- package/lib/components/Document/index.js +3 -0
- package/lib/components/Programa/Annotations/Annotation.js +274 -0
- package/lib/components/Programa/Annotations/AnnotationsList.js +30 -0
- package/lib/components/Programa/Annotations/Input/FileInput.js +96 -0
- package/lib/components/Programa/Annotations/Input/Input.js +190 -0
- package/lib/components/Programa/Annotations/Input/PrivacySelection.js +72 -0
- package/lib/components/Programa/Annotations/Input/ReplyInformation.js +86 -0
- package/lib/components/Programa/Annotations/Input/UsersAutocomplete.js +122 -0
- package/lib/components/Programa/Annotations/index.js +136 -0
- package/lib/components/Programa/Annotations/utils.js +30 -0
- package/lib/components/Programa/Programa.d.ts +3 -1
- package/lib/components/Programa/Programa.js +20 -5
- package/lib/components/index.d.ts +3 -1
- package/lib/components/index.js +3 -1
- package/lib/utils/index.ts +112 -0
- package/package.json +3 -1
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import { AnnotationsContext } from '.';
|
|
2
|
+
import { EXTRA_SMALL_SIZE, MEDIUM_SIZE, SMALL_SIZE, LIGHT_GREY_COLOR, MEDIUM_GREY_COLOR, AVATAR_SIZE, ViewedIcon, UNIMED_GREEN_COLOR, AnswerIcon } from './utils';
|
|
3
|
+
import { getProgramAnnotations } from '../../../api';
|
|
4
|
+
import { ArgousAvatar, IconsComponent, ModalVisualizacaoDocumentos } from '../../../components';
|
|
5
|
+
import { useModal } from '../../../utils';
|
|
6
|
+
import { Button, Divider, Grid, Typography, makeStyles } from '@material-ui/core';
|
|
7
|
+
import moment from 'moment';
|
|
8
|
+
import React, { useContext } from 'react';
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
const ANSWER_USER_MIN_WIDTH = 159.78;
|
|
12
|
+
|
|
13
|
+
const useStyles = makeStyles((theme) => ({
|
|
14
|
+
annotationContainer: {
|
|
15
|
+
padding: SMALL_SIZE,
|
|
16
|
+
border: `2px solid ${LIGHT_GREY_COLOR(theme.palette.type)}`,
|
|
17
|
+
'&:not(:last-child)': {
|
|
18
|
+
marginBottom: MEDIUM_SIZE
|
|
19
|
+
},
|
|
20
|
+
'&:last-child': {
|
|
21
|
+
borderBottom: 0
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
annotationHeader: {
|
|
25
|
+
display: 'flex',
|
|
26
|
+
justifyContent: 'space-between'
|
|
27
|
+
},
|
|
28
|
+
annotationUser: {
|
|
29
|
+
display: 'flex',
|
|
30
|
+
gap: SMALL_SIZE,
|
|
31
|
+
'&>div:nth-child(1)': {
|
|
32
|
+
width: AVATAR_SIZE,
|
|
33
|
+
height: AVATAR_SIZE
|
|
34
|
+
},
|
|
35
|
+
'&>div:nth-child(2)': {
|
|
36
|
+
display: 'flex',
|
|
37
|
+
justifyContent: 'center',
|
|
38
|
+
flexDirection: 'column',
|
|
39
|
+
gap: EXTRA_SMALL_SIZE,
|
|
40
|
+
'&>h6': {
|
|
41
|
+
lineHeight: 1
|
|
42
|
+
},
|
|
43
|
+
'&>p': {
|
|
44
|
+
lineHeight: 1,
|
|
45
|
+
fontSize: '.75rem',
|
|
46
|
+
fontWeight: 500,
|
|
47
|
+
color: MEDIUM_GREY_COLOR(theme.palette.type)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
annotationBody: {
|
|
52
|
+
'&>div:nth-child(1)': {
|
|
53
|
+
padding: '10px 0',
|
|
54
|
+
overflow: 'hidden'
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
annotationFooter: {
|
|
58
|
+
display: 'flex',
|
|
59
|
+
gap: SMALL_SIZE,
|
|
60
|
+
paddingTop: SMALL_SIZE,
|
|
61
|
+
minHeight: 43
|
|
62
|
+
},
|
|
63
|
+
buttonsDiv: {
|
|
64
|
+
display: 'flex',
|
|
65
|
+
justifyContent: 'flex-end',
|
|
66
|
+
gap: SMALL_SIZE
|
|
67
|
+
},
|
|
68
|
+
markedUsers: {
|
|
69
|
+
display: 'flex',
|
|
70
|
+
flexWrap: 'wrap',
|
|
71
|
+
gap: SMALL_SIZE
|
|
72
|
+
},
|
|
73
|
+
markedUser: {
|
|
74
|
+
position: 'relative',
|
|
75
|
+
'&>div:nth-child(1)': {
|
|
76
|
+
width: AVATAR_SIZE,
|
|
77
|
+
height: AVATAR_SIZE
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
avatarViewedIcon: {
|
|
81
|
+
position: 'absolute',
|
|
82
|
+
bottom: -2,
|
|
83
|
+
right: -8,
|
|
84
|
+
width: 18,
|
|
85
|
+
height: 18,
|
|
86
|
+
color: UNIMED_GREEN_COLOR
|
|
87
|
+
},
|
|
88
|
+
answer: {
|
|
89
|
+
alignItems: 'flex-start',
|
|
90
|
+
padding: SMALL_SIZE,
|
|
91
|
+
gap: SMALL_SIZE
|
|
92
|
+
},
|
|
93
|
+
answerUserDiv: {
|
|
94
|
+
display: 'flex',
|
|
95
|
+
gap: SMALL_SIZE,
|
|
96
|
+
minWidth: ANSWER_USER_MIN_WIDTH,
|
|
97
|
+
'&>div:nth-child(1)': {
|
|
98
|
+
position: 'relative',
|
|
99
|
+
'&>div:nth-child(1)': {
|
|
100
|
+
width: AVATAR_SIZE,
|
|
101
|
+
height: AVATAR_SIZE
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
'&>div:nth-child(2)': {
|
|
105
|
+
display: 'flex',
|
|
106
|
+
justifyContent: 'center',
|
|
107
|
+
flexDirection: 'column',
|
|
108
|
+
gap: EXTRA_SMALL_SIZE,
|
|
109
|
+
'&>h6': {
|
|
110
|
+
lineHeight: 1
|
|
111
|
+
},
|
|
112
|
+
'&>p': {
|
|
113
|
+
lineHeight: 1,
|
|
114
|
+
fontSize: '.75rem',
|
|
115
|
+
fontWeight: 500,
|
|
116
|
+
color: MEDIUM_GREY_COLOR(theme.palette.type)
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
avatarAnswerIcon: {
|
|
121
|
+
position: 'absolute',
|
|
122
|
+
top: -2,
|
|
123
|
+
left: -8,
|
|
124
|
+
width: 18,
|
|
125
|
+
height: 18,
|
|
126
|
+
color: UNIMED_GREEN_COLOR
|
|
127
|
+
},
|
|
128
|
+
answerTextDiv: {
|
|
129
|
+
width: '100%',
|
|
130
|
+
maxWidth: '100%',
|
|
131
|
+
[theme.breakpoints.up('sm')]: {
|
|
132
|
+
maxWidth: `calc(100% - ${ANSWER_USER_MIN_WIDTH}px - ${SMALL_SIZE}px)`
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
divider: {
|
|
136
|
+
height: 2
|
|
137
|
+
}
|
|
138
|
+
}));
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
export const ANNOTATION_ID_INDEX = 0;
|
|
142
|
+
export const ANNOTATION_PARENT_ID_INDEX = 1;
|
|
143
|
+
export const ANNOTATION_USER_INDEX = 2;
|
|
144
|
+
export const ANNOTATION_PROGRAM_CODE_INDEX = 3;
|
|
145
|
+
export const ANNOTATION_PARAMETERS_INDEX = 4;
|
|
146
|
+
export const ANNOTATION_DATE_INDEX = 5;
|
|
147
|
+
export const ANNOTATION_TEXT_INDEX = 6;
|
|
148
|
+
export const ANNOTATION_DOCUMENT_ID_INDEX = 7;
|
|
149
|
+
export const ANNOTATION_ANSWERS_INDEX = 8;
|
|
150
|
+
export const ANNOTATION_MARKED_USERS_INDEX = 9;
|
|
151
|
+
export const ANNOTATION_PRIVACY_TYPE_INDEX = 10;
|
|
152
|
+
export const ANNOTATION_CODE_INDEX = 11;
|
|
153
|
+
export const ANNOTATION_DOCUMENT_MIME_TYPE_INDEX = 12;
|
|
154
|
+
export const ANNOTATION_DOCUMENT_URL_INDEX = 13;
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
const Annotation = ({ annotation }) => {
|
|
158
|
+
|
|
159
|
+
const classes = useStyles();
|
|
160
|
+
const { createModal } = useModal();
|
|
161
|
+
const fileView = createModal(ModalVisualizacaoDocumentos);
|
|
162
|
+
const { openAnnotationParameters, handleDialogClose, scrollDialogToBottom, dispatch } = useContext(AnnotationsContext);
|
|
163
|
+
|
|
164
|
+
const user = { id: (annotation[ANNOTATION_USER_INDEX]?.[0] || -1), name: (annotation[ANNOTATION_USER_INDEX]?.[1] || '') };
|
|
165
|
+
const date = (annotation[ANNOTATION_DATE_INDEX]) ? moment(annotation[ANNOTATION_DATE_INDEX]).format('DD/MM/YYYY HH:mm:ss') : '';
|
|
166
|
+
const text = annotation[ANNOTATION_TEXT_INDEX];
|
|
167
|
+
const answers = (annotation[ANNOTATION_ANSWERS_INDEX] || []);
|
|
168
|
+
const markedUsers = (annotation[ANNOTATION_MARKED_USERS_INDEX] || []);
|
|
169
|
+
const annotationParameters = (annotation[ANNOTATION_PARAMETERS_INDEX] || {});
|
|
170
|
+
const file = {
|
|
171
|
+
id: annotation[ANNOTATION_DOCUMENT_ID_INDEX],
|
|
172
|
+
type: annotation[ANNOTATION_DOCUMENT_MIME_TYPE_INDEX],
|
|
173
|
+
url: annotation[ANNOTATION_DOCUMENT_URL_INDEX]
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
const reply = (event) => {
|
|
177
|
+
dispatch({ field: 'selectedAnnotation', value: annotation });
|
|
178
|
+
setTimeout(() => scrollDialogToBottom(event), 0);
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
const access = (event) => {
|
|
182
|
+
(openAnnotationParameters && (typeof openAnnotationParameters === 'function')) && openAnnotationParameters(event, annotationParameters);
|
|
183
|
+
handleDialogClose();
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
const handleFileClick = async (event) => {
|
|
187
|
+
const response = await getProgramAnnotations({ snToken: true });
|
|
188
|
+
if (response?.status) {
|
|
189
|
+
await fileView({ nome: 'Documento da anotação', linkPronto: file.url, tokenSistema: response?.token });
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
return <div className={classes.annotationContainer}>
|
|
195
|
+
<div className={classes.annotationHeader}>
|
|
196
|
+
<div className={classes.annotationUser}>
|
|
197
|
+
<ArgousAvatar alt={`${user.name} avatar`} idUsuario={user.id} nome={user.name} />
|
|
198
|
+
<div>
|
|
199
|
+
<Typography variant='subtitle2'>{user.name}</Typography>
|
|
200
|
+
<Typography variant='body2'>{date}</Typography>
|
|
201
|
+
</div>
|
|
202
|
+
</div>
|
|
203
|
+
<div>
|
|
204
|
+
{(file.id) && <IconsComponent mimeType={file.type} height={AVATAR_SIZE} onClick={handleFileClick} style={{ cursor: 'pointer' }} />}
|
|
205
|
+
</div>
|
|
206
|
+
</div>
|
|
207
|
+
<div className={classes.annotationBody}>
|
|
208
|
+
<div>
|
|
209
|
+
<Typography variant='body2'>{text}</Typography>
|
|
210
|
+
</div>
|
|
211
|
+
<div>
|
|
212
|
+
{answers.map((answer, answerIndex) => <Answer key={`answer-${answerIndex}`} {...{ answer }} />)}
|
|
213
|
+
</div>
|
|
214
|
+
</div>
|
|
215
|
+
<Divider className={classes.divider} />
|
|
216
|
+
<Grid container justifyContent={(markedUsers.length) ? 'space-between' : 'flex-end'} className={classes.annotationFooter}>
|
|
217
|
+
{(!!markedUsers.length) && (
|
|
218
|
+
<Grid item xs={12} sm='auto' className={classes.markedUsers}>
|
|
219
|
+
{markedUsers.map((user, userIndex) => <MarkedUser key={`marked-user-${user?.idUsuario}`} {...{ user }} />)}
|
|
220
|
+
</Grid>
|
|
221
|
+
)}
|
|
222
|
+
<Grid item xs={12} sm='auto' className={classes.buttonsDiv}>
|
|
223
|
+
<Button fullWidth variant='outlined' size='small' onClick={access}>Acessar</Button>
|
|
224
|
+
<Button fullWidth color='primary' variant='contained' size='small' onClick={reply}>Responder</Button>
|
|
225
|
+
</Grid>
|
|
226
|
+
</Grid>
|
|
227
|
+
</div>;
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
export default Annotation;
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
const Answer = ({ answer }) => {
|
|
235
|
+
|
|
236
|
+
const classes = useStyles();
|
|
237
|
+
const user = { id: (answer?.usuario?.[0] || -1), name: (answer?.usuario?.[1] || '') };
|
|
238
|
+
const date = (answer?.dtAnotacao) ? moment(answer?.dtAnotacao).format('DD/MM/YYYY HH:mm:ss') : '';
|
|
239
|
+
const text = answer?.dsAnotacao;
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
return <div>
|
|
243
|
+
<Divider className={classes.divider} />
|
|
244
|
+
<Grid container className={classes.answer}>
|
|
245
|
+
<div className={classes.answerUserDiv}>
|
|
246
|
+
<div>
|
|
247
|
+
<ArgousAvatar alt={`${user.name} avatar`} idUsuario={user.id} nome={user.name} />
|
|
248
|
+
<AnswerIcon className={classes.avatarAnswerIcon} />
|
|
249
|
+
</div>
|
|
250
|
+
<div>
|
|
251
|
+
<Typography variant='subtitle2'>{user.name}</Typography>
|
|
252
|
+
<Typography variant='body2'>{date}</Typography>
|
|
253
|
+
</div>
|
|
254
|
+
</div>
|
|
255
|
+
<div className={classes.answerTextDiv}>
|
|
256
|
+
<Typography variant='body2'>{text}</Typography>
|
|
257
|
+
</div>
|
|
258
|
+
</Grid>
|
|
259
|
+
</div>;
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
const MarkedUser = (props) => {
|
|
264
|
+
|
|
265
|
+
const classes = useStyles();
|
|
266
|
+
const user = { id: (props?.user?.idUsuario || -1), name: (props?.user?.nmUsuario || '') };
|
|
267
|
+
const viewDate = props?.user?.dtVisualizacao;
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
return <div className={classes.markedUser}>
|
|
271
|
+
<ArgousAvatar alt={`${user.name} avatar`} idUsuario={user.id} nome={user.name} />
|
|
272
|
+
{(viewDate) && <ViewedIcon className={classes.avatarViewedIcon} />}
|
|
273
|
+
</div>;
|
|
274
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { AnnotationsContext } from '.';
|
|
2
|
+
import Annotation from './Annotation';
|
|
3
|
+
import { LIGHT_GREY_COLOR } from './utils';
|
|
4
|
+
import { useTheme } from '@material-ui/core';
|
|
5
|
+
import React, { useContext } from 'react';
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
const AnnotationsList = () => {
|
|
9
|
+
|
|
10
|
+
const theme = useTheme();
|
|
11
|
+
const { list } = useContext(AnnotationsContext);
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<div
|
|
16
|
+
style={{
|
|
17
|
+
maxHeight: '60vh',
|
|
18
|
+
overflow: 'hidden auto',
|
|
19
|
+
borderBottom: `2px solid ${LIGHT_GREY_COLOR(theme.palette.type)}`
|
|
20
|
+
}}
|
|
21
|
+
>
|
|
22
|
+
{list.annotations.map((annotation, annotationIndex) => (
|
|
23
|
+
<Annotation key={`annotation-${annotation?.[0]}`} {...{ annotation }} />
|
|
24
|
+
))}
|
|
25
|
+
</div>
|
|
26
|
+
);
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
export default AnnotationsList;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { AnnotationsContext } from '..';
|
|
2
|
+
import { IconsComponent } from '../../../../components';
|
|
3
|
+
import { printScreen as getPrintScreen } from '../../../../utils';
|
|
4
|
+
import { CloseIcon, EXTRA_SMALL_SIZE, MEDIUM_SIZE, SMALL_SIZE, ELLIPSIS_TEXT_STYLE, LARGE_SIZE } from '../utils';
|
|
5
|
+
import { Button, IconButton, Typography, makeStyles } from '@material-ui/core';
|
|
6
|
+
import React, { useContext, useRef } from 'react';
|
|
7
|
+
import { IoDocumentAttachOutline, IoImageOutline } from 'react-icons/io5';
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
const useStyles = makeStyles({
|
|
11
|
+
fileInputContainer: {
|
|
12
|
+
width: '100%',
|
|
13
|
+
display: 'flex',
|
|
14
|
+
flexDirection: 'column',
|
|
15
|
+
alignItems: 'flex-end',
|
|
16
|
+
gap: SMALL_SIZE,
|
|
17
|
+
'&>input': {
|
|
18
|
+
display: 'none'
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
fileInputButtonsDiv: {
|
|
22
|
+
display: 'flex',
|
|
23
|
+
alignItems: 'center',
|
|
24
|
+
gap: SMALL_SIZE
|
|
25
|
+
},
|
|
26
|
+
file: {
|
|
27
|
+
display: 'flex',
|
|
28
|
+
alignItems: 'center',
|
|
29
|
+
gap: EXTRA_SMALL_SIZE,
|
|
30
|
+
maxWidth: '100%',
|
|
31
|
+
'&>p': {
|
|
32
|
+
...ELLIPSIS_TEXT_STYLE
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
const FileInput = ({ file, onChange }) => {
|
|
39
|
+
|
|
40
|
+
const classes = useStyles();
|
|
41
|
+
const { printScreen, loading, dispatch } = useContext(AnnotationsContext);
|
|
42
|
+
const inputRef = useRef(null);
|
|
43
|
+
const canAddPrintScreen = !(file === printScreen?.file);
|
|
44
|
+
const disabled = (loading.save || loading.file);
|
|
45
|
+
|
|
46
|
+
const printScreenClick = async (event) => {
|
|
47
|
+
dispatch({ type: 'loading', field: 'file', value: true });
|
|
48
|
+
|
|
49
|
+
let file;
|
|
50
|
+
if (printScreen?.file) file = printScreen?.file;
|
|
51
|
+
else {
|
|
52
|
+
const response = await getPrintScreen({ event });
|
|
53
|
+
if (response?.status) {
|
|
54
|
+
dispatch({ field: 'printScreen', value: response });
|
|
55
|
+
file = response?.file;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
(file) && onChange(event, file);
|
|
60
|
+
dispatch({ type: 'loading', field: 'file', value: false });
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
return <div className={classes.fileInputContainer}>
|
|
65
|
+
<input ref={inputRef} type='file' onChange={e => (e?.target?.files?.length) && onChange(e, e.target.files[0])} />
|
|
66
|
+
{(file) && <File {...{ file, disabled, classes }} onDelete={e => onChange(e, undefined)} />}
|
|
67
|
+
<div className={classes.fileInputButtonsDiv}>
|
|
68
|
+
<IconButton {...{ disabled }} onClick={() => (inputRef.current) && inputRef.current.click()} style={{ padding: EXTRA_SMALL_SIZE }}>
|
|
69
|
+
<IoDocumentAttachOutline size={MEDIUM_SIZE} />
|
|
70
|
+
</IconButton>
|
|
71
|
+
{(canAddPrintScreen) && (
|
|
72
|
+
<Button
|
|
73
|
+
{...{ disabled }}
|
|
74
|
+
size='small'
|
|
75
|
+
variant='outlined'
|
|
76
|
+
startIcon={<IoImageOutline />}
|
|
77
|
+
onClick={printScreenClick}
|
|
78
|
+
>
|
|
79
|
+
Captura de tela
|
|
80
|
+
</Button>
|
|
81
|
+
)}
|
|
82
|
+
</div>
|
|
83
|
+
</div>;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
export default FileInput;
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
const File = ({ file, disabled, onDelete, classes }) => <div className={classes.file}>
|
|
91
|
+
<IconsComponent fileName={file?.name} mimeType={file?.type} height={LARGE_SIZE} />
|
|
92
|
+
<Typography>{file?.name}</Typography>
|
|
93
|
+
<IconButton {...{ disabled }} size='small' onClick={e => (typeof onDelete === 'function') && onDelete(e)}>
|
|
94
|
+
<CloseIcon />
|
|
95
|
+
</IconButton>
|
|
96
|
+
</div>;
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import FileInput from './FileInput';
|
|
2
|
+
import PrivacySelection from './PrivacySelection';
|
|
3
|
+
import ReplyInformation from './ReplyInformation';
|
|
4
|
+
import UsersAutocomplete from './UsersAutocomplete';
|
|
5
|
+
import { AnnotationsContext } from '..';
|
|
6
|
+
import { prepareFile, saveProgramAnnotation } from '../../../../api';
|
|
7
|
+
import { ANNOTATION_ANSWERS_INDEX, ANNOTATION_DATE_INDEX, ANNOTATION_ID_INDEX, ANNOTATION_PARAMETERS_INDEX, ANNOTATION_PROGRAM_CODE_INDEX, ANNOTATION_TEXT_INDEX, ANNOTATION_USER_INDEX } from '../Annotation';
|
|
8
|
+
import { EXTRA_SMALL_SIZE, SMALL_SIZE, LARGE_SIZE, LIGHT_GREY_COLOR } from '../utils';
|
|
9
|
+
import { Button, CircularProgress, Input as MaterialInput, makeStyles } from '@material-ui/core';
|
|
10
|
+
import React, { useContext, useEffect, useRef, useState } from 'react';
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
const useStyles = makeStyles(theme => ({
|
|
14
|
+
inputContainer: {
|
|
15
|
+
display: 'flex',
|
|
16
|
+
flexDirection: 'column',
|
|
17
|
+
gap: SMALL_SIZE
|
|
18
|
+
},
|
|
19
|
+
materialInput: {
|
|
20
|
+
padding: EXTRA_SMALL_SIZE,
|
|
21
|
+
backgroundColor: theme.palette.background.default,
|
|
22
|
+
border: `1px solid ${LIGHT_GREY_COLOR(theme.palette.type)}`,
|
|
23
|
+
'&>textarea': {
|
|
24
|
+
minHeight: (LARGE_SIZE + SMALL_SIZE)
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
buttonsDiv: {
|
|
28
|
+
display: 'flex',
|
|
29
|
+
justifyContent: 'flex-end',
|
|
30
|
+
gap: SMALL_SIZE,
|
|
31
|
+
'&>button': {
|
|
32
|
+
minHeight: 30,
|
|
33
|
+
lineHeight: 1
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}));
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
const initialStatePrivacyType = '0';
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
const Input = () => {
|
|
43
|
+
|
|
44
|
+
const classes = useStyles();
|
|
45
|
+
const materialInputRef = useRef(null);
|
|
46
|
+
const { list, annotationParameters, selectedAnnotation, code, loading, dispatch } = useContext(AnnotationsContext);
|
|
47
|
+
const replying = !!selectedAnnotation.length;
|
|
48
|
+
|
|
49
|
+
const [text, setText] = useState('');
|
|
50
|
+
const [file, setFile] = useState('');
|
|
51
|
+
const [markedUsers, setMarkedUsers] = useState([]);
|
|
52
|
+
const [privacyType, setPrivacyType] = useState(initialStatePrivacyType);
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
function resetStates() {
|
|
56
|
+
setText('');
|
|
57
|
+
setFile('');
|
|
58
|
+
setMarkedUsers([]);
|
|
59
|
+
setPrivacyType(initialStatePrivacyType);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const cancelReply = () => {
|
|
63
|
+
dispatch({ field: 'selectedAnnotation', value: [] });
|
|
64
|
+
resetStates();
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const addAnnotation = ({ answer, newAnnotation = [] }) => {
|
|
68
|
+
if (!newAnnotation.length) return;
|
|
69
|
+
|
|
70
|
+
let newList = [...list.annotations];
|
|
71
|
+
|
|
72
|
+
if (answer) {
|
|
73
|
+
const parentIndex = newList.findIndex((annotation) => (annotation[ANNOTATION_ID_INDEX] === answer));
|
|
74
|
+
if (parentIndex === -1) return;
|
|
75
|
+
|
|
76
|
+
let newParentAnnotation = [...newList[parentIndex]];
|
|
77
|
+
let newAnswers = [...newParentAnnotation[ANNOTATION_ANSWERS_INDEX]];
|
|
78
|
+
const newAnswer = {
|
|
79
|
+
dsAnotacao: newAnnotation[ANNOTATION_TEXT_INDEX],
|
|
80
|
+
dtAnotacao: newAnnotation[ANNOTATION_DATE_INDEX],
|
|
81
|
+
idAnotacao: newAnnotation[ANNOTATION_ID_INDEX],
|
|
82
|
+
idAnotacaoPai: answer,
|
|
83
|
+
parametros: newAnnotation[ANNOTATION_PARAMETERS_INDEX],
|
|
84
|
+
pgCode: newAnnotation[ANNOTATION_PROGRAM_CODE_INDEX],
|
|
85
|
+
usuario: newAnnotation[ANNOTATION_USER_INDEX]
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
newAnswers.push(newAnswer);
|
|
89
|
+
newParentAnnotation.splice(ANNOTATION_ANSWERS_INDEX, 1, newAnswers);
|
|
90
|
+
newList.splice(parentIndex, 1, newParentAnnotation);
|
|
91
|
+
} else {
|
|
92
|
+
newList.unshift(newAnnotation);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
dispatch({ type: 'list', field: 'annotations', value: newList });
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const saveAnnotation = async (event) => {
|
|
99
|
+
dispatch({ type: 'loading', field: 'save', value: true });
|
|
100
|
+
|
|
101
|
+
let methodParameters = {
|
|
102
|
+
pgCode: code,
|
|
103
|
+
dsAnotacao: text,
|
|
104
|
+
idAnotacaoPai: (selectedAnnotation.length) ? selectedAnnotation[ANNOTATION_ID_INDEX] : undefined,
|
|
105
|
+
parametros: annotationParameters,
|
|
106
|
+
tpPrivacidade: privacyType,
|
|
107
|
+
idRecebimento: undefined,
|
|
108
|
+
usuarioRelacionado: markedUsers.map(([id]) => id)
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
if (file) {
|
|
112
|
+
const { idRecebimento } = await prepareFile(file);
|
|
113
|
+
methodParameters.idRecebimento = idRecebimento;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const response = await saveProgramAnnotation(methodParameters);
|
|
117
|
+
if (response?.status) {
|
|
118
|
+
cancelReply();
|
|
119
|
+
addAnnotation({ answer: selectedAnnotation[ANNOTATION_ID_INDEX], newAnnotation: response?.anotacao });
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
dispatch({ type: 'loading', field: 'save', value: false });
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
const setUpReply = () => {
|
|
126
|
+
(materialInputRef.current) && materialInputRef.current.focus();
|
|
127
|
+
setFile('');
|
|
128
|
+
setMarkedUsers([]);
|
|
129
|
+
setPrivacyType(initialStatePrivacyType);
|
|
130
|
+
};
|
|
131
|
+
useEffect(() => (replying) && setUpReply(), [replying]);
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
return <div className={classes.inputContainer}>
|
|
135
|
+
{(replying) && <ReplyInformation {...{ selectedAnnotation }} />}
|
|
136
|
+
<div>
|
|
137
|
+
<MaterialInput
|
|
138
|
+
fullWidth
|
|
139
|
+
multiline
|
|
140
|
+
inputRef={materialInputRef}
|
|
141
|
+
placeholder='Escreva a sua anotação'
|
|
142
|
+
disabled={loading.save}
|
|
143
|
+
value={text}
|
|
144
|
+
onChange={(event) => setText(event.target.value)}
|
|
145
|
+
className={classes.materialInput}
|
|
146
|
+
/>
|
|
147
|
+
</div>
|
|
148
|
+
{(!replying) && (
|
|
149
|
+
<>
|
|
150
|
+
<div className={classes.buttonsDiv}>
|
|
151
|
+
<FileInput {...{ file }} onChange={(_, value) => setFile(value)} />
|
|
152
|
+
</div>
|
|
153
|
+
<div className={classes.buttonsDiv}>
|
|
154
|
+
<UsersAutocomplete
|
|
155
|
+
disabled={loading.save}
|
|
156
|
+
value={markedUsers}
|
|
157
|
+
onChange={(event, value, reason, details) => setMarkedUsers(value)}
|
|
158
|
+
/>
|
|
159
|
+
</div>
|
|
160
|
+
<div className={classes.buttonsDiv}>
|
|
161
|
+
<PrivacySelection
|
|
162
|
+
disabled={loading.save}
|
|
163
|
+
value={privacyType}
|
|
164
|
+
onChange={event => setPrivacyType(event.target.value)}
|
|
165
|
+
/>
|
|
166
|
+
</div>
|
|
167
|
+
</>
|
|
168
|
+
)}
|
|
169
|
+
<div className={classes.buttonsDiv}>
|
|
170
|
+
{(replying) && (
|
|
171
|
+
<Button color='default' variant='contained' size='small' onClick={cancelReply}>
|
|
172
|
+
Cancelar
|
|
173
|
+
</Button>
|
|
174
|
+
)}
|
|
175
|
+
<Button
|
|
176
|
+
color='primary'
|
|
177
|
+
variant='contained'
|
|
178
|
+
size='small'
|
|
179
|
+
disabled={!text.length || loading.save}
|
|
180
|
+
onClick={saveAnnotation}
|
|
181
|
+
style={{ width: (replying) ? 97.13 : 72.45 }}
|
|
182
|
+
>
|
|
183
|
+
{(loading.save) ? <CircularProgress color='primary' size={22} /> : (replying) ? 'Responder' : 'Anotar'}
|
|
184
|
+
</Button>
|
|
185
|
+
</div>
|
|
186
|
+
</div>;
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
export default Input;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { EXTRA_SMALL_SIZE, MEDIUM_SIZE, privacyTypeOptions } from '../utils';
|
|
2
|
+
import { MenuItem, TextField, Typography, makeStyles } from '@material-ui/core';
|
|
3
|
+
import React from 'react';
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
const useStyles = makeStyles({
|
|
7
|
+
selectTextField: {
|
|
8
|
+
'&>div>svg': {
|
|
9
|
+
right: EXTRA_SMALL_SIZE
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
menuItem: {
|
|
13
|
+
display: 'flex',
|
|
14
|
+
gap: EXTRA_SMALL_SIZE,
|
|
15
|
+
padding: EXTRA_SMALL_SIZE
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
const PrivacySelection = ({ value = '', onChange = () => '', disabled = false }) => {
|
|
21
|
+
|
|
22
|
+
const classes = useStyles();
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<TextField
|
|
27
|
+
{...{ value, onChange, disabled }}
|
|
28
|
+
select
|
|
29
|
+
variant='filled'
|
|
30
|
+
InputProps={{
|
|
31
|
+
disableUnderline: true,
|
|
32
|
+
style: {
|
|
33
|
+
borderRadius: 4,
|
|
34
|
+
height: '100%'
|
|
35
|
+
}
|
|
36
|
+
}}
|
|
37
|
+
SelectProps={{
|
|
38
|
+
SelectDisplayProps: {
|
|
39
|
+
style: {
|
|
40
|
+
display: 'flex',
|
|
41
|
+
alignItems: 'center',
|
|
42
|
+
gap: EXTRA_SMALL_SIZE,
|
|
43
|
+
padding: `${EXTRA_SMALL_SIZE}px ${(EXTRA_SMALL_SIZE * 2) + 24}px ${EXTRA_SMALL_SIZE}px ${EXTRA_SMALL_SIZE}px`
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
MenuProps: {
|
|
47
|
+
variant: 'menu',
|
|
48
|
+
MenuListProps: {
|
|
49
|
+
style: { padding: `${EXTRA_SMALL_SIZE}px 0` }
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}}
|
|
53
|
+
className={classes.selectTextField}
|
|
54
|
+
>
|
|
55
|
+
{privacyTypeOptions.map((privacyType) => {
|
|
56
|
+
|
|
57
|
+
const value = privacyType[0];
|
|
58
|
+
const label = privacyType[1];
|
|
59
|
+
const ICON = privacyType[2];
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
return <MenuItem key={`${value}-menu-item`} {...{ value }} className={classes.menuItem}>
|
|
63
|
+
{(ICON) && <ICON size={MEDIUM_SIZE} />}
|
|
64
|
+
<Typography variant='body2'>{label}</Typography>
|
|
65
|
+
</MenuItem>;
|
|
66
|
+
})}
|
|
67
|
+
</TextField>
|
|
68
|
+
);
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
export default PrivacySelection;
|