@capytale/meta-player 0.3.4 → 0.3.6

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.
@@ -2,14 +2,17 @@ import { useCapytaleRichTextEditor } from "@capytale/capytale-rich-text-editor";
2
2
  import { useAppDispatch, useAppSelector } from "../../app/hooks";
3
3
  import {
4
4
  selectInstructions,
5
+ selectInstructionsType,
5
6
  selectMode,
6
7
  setCanSaveInstructions,
8
+ setInstructionsType,
7
9
  setIsMPDirty,
8
10
  setLexicalInstructionsState,
9
11
  } from "../activityData/activityDataSlice";
10
12
  import { forwardRef, useImperativeHandle, useMemo, useRef } from "react";
11
13
  import { Toast } from "primereact/toast";
12
14
  import settings from "../../settings";
15
+ import { Button } from "primereact/button";
13
16
 
14
17
  const InstructionsEditor: React.FC = forwardRef((_props, ref) => {
15
18
  const [Editor, getState, _canSave] = useCapytaleRichTextEditor();
@@ -31,6 +34,7 @@ const InstructionsEditor: React.FC = forwardRef((_props, ref) => {
31
34
  : undefined;
32
35
  }, [initialInstructions]);
33
36
  const initialStateOnChangeDone = useRef<boolean>(false);
37
+ const instructionsType = useAppSelector(selectInstructionsType);
34
38
 
35
39
  useImperativeHandle(ref, () => {
36
40
  return {
@@ -44,39 +48,52 @@ const InstructionsEditor: React.FC = forwardRef((_props, ref) => {
44
48
  return (
45
49
  <>
46
50
  <Toast position="bottom-right" ref={toast} />
47
- <Editor
48
- placeholderText="Écrivez la consigne ici..."
49
- htmlInitialContent={htmlInitialContent}
50
- initialEditorState={initialEditorState}
51
- jsonSizeLimit={settings.STATEMENT_MAX_SIZE}
52
- onChange={(editorState) => {
53
- dispatch(setLexicalInstructionsState(editorState));
54
- if (initialStateOnChangeDone.current) {
55
- dispatch(setIsMPDirty(true));
56
- } else {
57
- initialStateOnChangeDone.current = true;
58
- }
59
- }}
60
- onJsonSizeLimitExceeded={() => {
61
- dispatch(setCanSaveInstructions(false));
62
- toast.current!.show({
63
- summary: "Erreur",
64
- detail: `Le contenu de la consigne est trop volumineux. Veuillez le réduire avant de l'enregistrer.\nPeut-être avez-vous inséré une image trop volumineuse ?`,
65
- severity: "error",
66
- life: 10000,
67
- });
68
- }}
69
- onJsonSizeLimitMet={() => {
70
- dispatch(setCanSaveInstructions(true));
71
- toast.current!.show({
72
- summary: "Succès",
73
- detail: `Le contenu de la consigne ne dépasse plus la taille limite.`,
74
- severity: "success",
75
- life: 4000,
76
- });
77
- }}
78
- isEditable={isEditable}
79
- />
51
+ <>
52
+ {instructionsType === "none" && (
53
+ <>
54
+ <p>Pas de consigne.</p>
55
+ <Button
56
+ label="Créer une consigne"
57
+ onClick={() => dispatch(setInstructionsType("rich"))}
58
+ />
59
+ </>
60
+ )}
61
+ {instructionsType === "rich" && (
62
+ <Editor
63
+ placeholderText="Écrivez la consigne ici..."
64
+ htmlInitialContent={htmlInitialContent}
65
+ initialEditorState={initialEditorState}
66
+ jsonSizeLimit={settings.STATEMENT_MAX_SIZE}
67
+ onChange={(editorState) => {
68
+ dispatch(setLexicalInstructionsState(editorState));
69
+ if (initialStateOnChangeDone.current) {
70
+ dispatch(setIsMPDirty(true));
71
+ } else {
72
+ initialStateOnChangeDone.current = true;
73
+ }
74
+ }}
75
+ onJsonSizeLimitExceeded={() => {
76
+ dispatch(setCanSaveInstructions(false));
77
+ toast.current!.show({
78
+ summary: "Erreur",
79
+ detail: `Le contenu de la consigne est trop volumineux. Veuillez le réduire avant de l'enregistrer.\nPeut-être avez-vous inséré une image trop volumineuse ?`,
80
+ severity: "error",
81
+ life: 10000,
82
+ });
83
+ }}
84
+ onJsonSizeLimitMet={() => {
85
+ dispatch(setCanSaveInstructions(true));
86
+ toast.current!.show({
87
+ summary: "Succès",
88
+ detail: `Le contenu de la consigne ne dépasse plus la taille limite.`,
89
+ severity: "success",
90
+ life: 4000,
91
+ });
92
+ }}
93
+ isEditable={isEditable}
94
+ />
95
+ )}
96
+ </>
80
97
  </>
81
98
  );
82
99
  });
@@ -0,0 +1,91 @@
1
+ import { FC, useEffect, useMemo } from "react";
2
+ import { useDropzone } from "react-dropzone";
3
+ import styles from "./style.module.scss";
4
+ import { useAppDispatch, useAppSelector } from "../../app/hooks";
5
+ import {
6
+ selectMode,
7
+ selectPdfInstructions,
8
+ setPdfInstructions,
9
+ } from "../activityData/activityDataSlice";
10
+ import { Button } from "primereact/button";
11
+
12
+ export const PdfEditor: FC = () => {
13
+ const dispatch = useAppDispatch();
14
+ const {
15
+ getRootProps,
16
+ getInputProps,
17
+ isFocused,
18
+ isDragAccept,
19
+ isDragReject,
20
+ acceptedFiles,
21
+ } = useDropzone({
22
+ accept: {
23
+ "application/pdf": [".pdf"],
24
+ },
25
+ });
26
+ useEffect(() => {
27
+ if (acceptedFiles.length) {
28
+ dispatch(setPdfInstructions(acceptedFiles[0]));
29
+ }
30
+ }, [acceptedFiles]);
31
+ const mode = useAppSelector(selectMode);
32
+ const pdfInstructions = useAppSelector(selectPdfInstructions);
33
+ const pdfData = useMemo(
34
+ () => (pdfInstructions ? URL.createObjectURL(pdfInstructions) : null),
35
+ [pdfInstructions],
36
+ );
37
+ return (
38
+ <>
39
+ {pdfData && (
40
+ <div
41
+ style={{
42
+ width: "100%",
43
+ height: "100%",
44
+ position: "relative",
45
+ overflow: "hidden",
46
+ }}
47
+ >
48
+ <object
49
+ data={pdfData + "#?navpanes=0"}
50
+ type="application/pdf"
51
+ width="100%"
52
+ height="100%"
53
+ >
54
+ <p>
55
+ Votre navigateur ne supporte pas les PDFs, vous pouvez{" "}
56
+ <a href={pdfData}>télécharger le fichier</a> à la place.
57
+ </p>
58
+ </object>
59
+ <div className="meta-player-content-cover"></div>
60
+ {mode === "create" && (
61
+ <Button
62
+ label="Supprimer le PDF"
63
+ severity="danger"
64
+ icon="pi pi-trash"
65
+ className={styles.deleteButton}
66
+ onClick={() => dispatch(setPdfInstructions(null))}
67
+ style={{ position: "absolute", bottom: "20px", right: "20px" }}
68
+ />
69
+ )}
70
+ </div>
71
+ )}
72
+ {!pdfData && (
73
+ <div className={styles.dropzone} {...getRootProps()}>
74
+ <div
75
+ className={styles.dropzoneRectangle}
76
+ data-is-focused={isFocused}
77
+ data-is-drag-accept={isDragAccept}
78
+ data-is-drag-reject={isDragReject}
79
+ >
80
+ <input {...getInputProps()} />
81
+ <p>Déposez un PDF ici ou cliquez pour sélectionner un fichier...</p>
82
+ <i
83
+ className="pi pi-file-arrow-up"
84
+ style={{ fontSize: "2.5rem" }}
85
+ ></i>
86
+ </div>
87
+ </div>
88
+ )}
89
+ </>
90
+ );
91
+ };
@@ -0,0 +1,325 @@
1
+ import { useAppDispatch, useAppSelector } from "../../app/hooks";
2
+ import {
3
+ selectHasGradingOrComments,
4
+ selectInstructionsType,
5
+ selectMode,
6
+ selectPdfInstructions,
7
+ selectSharedNotesType,
8
+ setInstructionsType,
9
+ setSharedNotesType,
10
+ } from "../activityData/activityDataSlice";
11
+ import {
12
+ PedagoTab,
13
+ selectIsGradingVisible,
14
+ selectOrientation,
15
+ selectPedagoTab,
16
+ setPedagoTab,
17
+ toggleIsGradingVisible,
18
+ toggleIsPedagoVisible,
19
+ } from "../layout/layoutSlice";
20
+ import styles from "./style.module.scss";
21
+ import { Button } from "primereact/button";
22
+ import settings from "../../settings";
23
+ import { SelectButton } from "primereact/selectbutton";
24
+ import { FC, useMemo } from "react";
25
+ import { TabMenu } from "primereact/tabmenu";
26
+ import { classNames } from "primereact/utils";
27
+
28
+ export const PedagoCommands = () => {
29
+ const isHorizontal = useAppSelector(selectOrientation) === "horizontal";
30
+ return isHorizontal ? (
31
+ <HorizontalPedagoCommands />
32
+ ) : (
33
+ <VerticalPedagoCommands />
34
+ );
35
+ };
36
+
37
+ type DocumentSelectorHzItem = {
38
+ name: string;
39
+ value: PedagoTab;
40
+ tooltip: string;
41
+ };
42
+
43
+ type DocumentSelectorItem = DocumentSelectorHzItem & {
44
+ template: (item: any) => JSX.Element;
45
+ };
46
+
47
+ const HorizontalPedagoCommands = () => {
48
+ const mode = useAppSelector(selectMode);
49
+ const dispatch = useAppDispatch();
50
+ return (
51
+ <div className={styles.pedagoCommands}>
52
+ <div
53
+ style={{
54
+ display: "flex",
55
+ flexDirection: "row",
56
+ justifyContent: "space-between",
57
+ alignItems: "center",
58
+ width: "100%",
59
+ paddingLeft: "4px",
60
+ }}
61
+ >
62
+ {(mode === "assignment" || mode === "review") && (
63
+ <ShowHideGradingButton />
64
+ )}
65
+ <div></div>
66
+ <Button
67
+ severity="secondary"
68
+ icon="pi pi-times"
69
+ rounded
70
+ text
71
+ aria-label="Masquer les consignes"
72
+ tooltip="Masquer les consignes"
73
+ tooltipOptions={{
74
+ position: "left",
75
+ showDelay: settings.TOOLTIP_SHOW_DELAY,
76
+ }}
77
+ onClick={() => dispatch(toggleIsPedagoVisible())}
78
+ style={{ flexShrink: 0 }}
79
+ />
80
+ </div>
81
+ <HorizontalDocumentSelector />
82
+ </div>
83
+ );
84
+ };
85
+
86
+ const DocumentSelectorItemActions: FC<{
87
+ item: DocumentSelectorHzItem;
88
+ }> = ({ item }) => {
89
+ const mode = useAppSelector(selectMode);
90
+ const itemTemplate = (option: any) => {
91
+ return <i className={option.icon}></i>;
92
+ };
93
+
94
+ const instructionsType = useAppSelector(selectInstructionsType);
95
+ const sharedNotesType = useAppSelector(selectSharedNotesType);
96
+ const pdfInstructions = useAppSelector(selectPdfInstructions);
97
+ const dispatch = useAppDispatch();
98
+
99
+ return (
100
+ <>
101
+ {mode === "create" && (
102
+ <>
103
+ <div className={styles.pdfActions}>
104
+ {item.value === "pdf" && !pdfInstructions && (
105
+ <i className="pi pi-eye-slash"></i>
106
+ )}
107
+ {item.value === "pdf" && pdfInstructions && (
108
+ <i className="pi pi-file-pdf"></i>
109
+ )}
110
+ </div>
111
+ {item.value !== "pdf" && (
112
+ <SelectButton
113
+ className={styles.smallSelectButton}
114
+ value={
115
+ item.value === "instructions"
116
+ ? instructionsType
117
+ : sharedNotesType
118
+ }
119
+ onChange={(e) => {
120
+ if (item.value === "instructions") {
121
+ dispatch(setInstructionsType(e.value));
122
+ } else {
123
+ dispatch(setSharedNotesType(e.value));
124
+ }
125
+ }}
126
+ itemTemplate={itemTemplate}
127
+ optionLabel="value"
128
+ allowEmpty={false}
129
+ options={[
130
+ {
131
+ label: "Éditeur riche",
132
+ value: "rich",
133
+ icon: "pi pi-pen-to-square",
134
+ },
135
+ {
136
+ label: "Pas de consigne",
137
+ value: "none",
138
+ icon: "pi pi-eye-slash",
139
+ },
140
+ ]}
141
+ tooltip={item.tooltip}
142
+ tooltipOptions={{
143
+ position: "left",
144
+ showDelay: settings.TOOLTIP_SHOW_DELAY,
145
+ }}
146
+ />
147
+ )}
148
+ </>
149
+ )}
150
+ </>
151
+ );
152
+ };
153
+
154
+ const HorizontalDocumentSelector = () => {
155
+ const pedagoTab = useAppSelector(selectPedagoTab);
156
+ const instructionsType = useAppSelector(selectInstructionsType);
157
+ const mode = useAppSelector(selectMode);
158
+ // const pdfInstructions = useAppSelector(selectPdfInstructions);
159
+ const sharedNotesType = useAppSelector(selectSharedNotesType);
160
+ const dispatch = useAppDispatch();
161
+
162
+ const items: DocumentSelectorHzItem[] = useMemo(() => {
163
+ const allItems: DocumentSelectorHzItem[] = [];
164
+ if (mode === "create" || instructionsType !== "none") {
165
+ allItems.push({
166
+ name: "Consignes",
167
+ value: "instructions",
168
+ tooltip: "Activer/désactiver les consignes",
169
+ });
170
+ }
171
+ /* // Removed PDF for now
172
+ if (mode === "create" || pdfInstructions) {
173
+ allItems.push({
174
+ name: "PDF",
175
+ value: "pdf",
176
+ tooltip: "Activer/désactiver le PDF",
177
+ });
178
+ }
179
+ */
180
+ if (mode === "create" || sharedNotesType !== "none") {
181
+ allItems.push({
182
+ name: "Notes partagées",
183
+ value: "sharedNotes",
184
+ tooltip: "Activer/désactiver les notes partagées",
185
+ });
186
+ }
187
+ return allItems;
188
+ }, []);
189
+
190
+ return (
191
+ <div className={styles.pedagoHorizontalTabMenu}>
192
+ {items.map((item) => (
193
+ <div
194
+ className={styles.pedagoHorizontalTab}
195
+ onClick={() => dispatch(setPedagoTab(item.value))}
196
+ data-selected={item.value === pedagoTab}
197
+ key={item.value}
198
+ >
199
+ <span>{item.name}</span>
200
+ <DocumentSelectorItemActions item={item} />
201
+ </div>
202
+ ))}
203
+ </div>
204
+ );
205
+ };
206
+
207
+ const VerticalPedagoCommands = () => {
208
+ const mode = useAppSelector(selectMode);
209
+ const dispatch = useAppDispatch();
210
+ return (
211
+ <div className={styles.pedagoCommands}>
212
+ <VerticalDocumentSelector />
213
+ <div className={styles.pedagoSeparator}></div>
214
+ {(mode === "assignment" || mode === "review") && (
215
+ <ShowHideGradingButton />
216
+ )}
217
+ <Button
218
+ severity="secondary"
219
+ icon="pi pi-times"
220
+ rounded
221
+ text
222
+ aria-label="Masquer les consignes"
223
+ tooltip="Masquer les consignes"
224
+ tooltipOptions={{
225
+ position: "left",
226
+ showDelay: settings.TOOLTIP_SHOW_DELAY,
227
+ }}
228
+ onClick={() => dispatch(toggleIsPedagoVisible())}
229
+ style={{ flexShrink: 0 }}
230
+ />
231
+ </div>
232
+ );
233
+ };
234
+
235
+ const VerticalDocumentSelector = () => {
236
+ const pedagoTab = useAppSelector(selectPedagoTab);
237
+ const instructionsType = useAppSelector(selectInstructionsType);
238
+ const mode = useAppSelector(selectMode);
239
+ // const pdfInstructions = useAppSelector(selectPdfInstructions);
240
+ const sharedNotesType = useAppSelector(selectSharedNotesType);
241
+ const dispatch = useAppDispatch();
242
+
243
+ const itemRenderer = (item: DocumentSelectorItem) => (
244
+ <a
245
+ className={classNames("p-menuitem-link", styles.pedagoTab)}
246
+ onClick={() => dispatch(setPedagoTab(item.value))}
247
+ >
248
+ <span>{item.name}</span>
249
+ <DocumentSelectorItemActions item={item} />
250
+ </a>
251
+ );
252
+
253
+ const items: DocumentSelectorItem[] = useMemo(() => {
254
+ const allItems: DocumentSelectorItem[] = [];
255
+ if (mode === "create" || instructionsType !== "none") {
256
+ allItems.push({
257
+ name: "Consignes",
258
+ value: "instructions",
259
+ tooltip: "Activer/désactiver les consignes",
260
+ template: (item: any) => itemRenderer(item),
261
+ });
262
+ }
263
+ /* // Removed PDF for now
264
+ if (mode === "create" || pdfInstructions) {
265
+ allItems.push({
266
+ name: "PDF",
267
+ value: "pdf",
268
+ tooltip: "Activer/désactiver le PDF",
269
+ template: (item: any) => itemRenderer(item),
270
+ });
271
+ }
272
+ */
273
+ if (mode === "create" || sharedNotesType !== "none") {
274
+ allItems.push({
275
+ name: "Notes partagées",
276
+ value: "sharedNotes",
277
+ tooltip: "Activer/désactiver les notes partagées",
278
+ template: (item: any) => itemRenderer(item),
279
+ });
280
+ }
281
+ return allItems;
282
+ }, []);
283
+ const activeIndex = useMemo(() => {
284
+ const index = items.findIndex((item) => item.value === pedagoTab);
285
+ return index;
286
+ }, [items, pedagoTab]);
287
+
288
+ return (
289
+ <TabMenu
290
+ className={styles.pedagoTabMenu}
291
+ model={items}
292
+ activeIndex={activeIndex}
293
+ onTabChange={(e) => {
294
+ dispatch(setPedagoTab(items[e.index].value));
295
+ }}
296
+ />
297
+ );
298
+ };
299
+
300
+ const ShowHideGradingButton: React.FC = () => {
301
+ const dispatch = useAppDispatch();
302
+ const mode = useAppSelector(selectMode);
303
+ const hasGradingOrComments = useAppSelector(selectHasGradingOrComments);
304
+ const isGradingVisible = useAppSelector(selectIsGradingVisible);
305
+ const canShowGrading = hasGradingOrComments || mode === "review";
306
+
307
+ return (
308
+ <Button
309
+ size="small"
310
+ icon="pi pi-graduation-cap"
311
+ disabled={!canShowGrading}
312
+ severity={canShowGrading ? "info" : "secondary"}
313
+ aria-label="Afficher/Masquer la notation"
314
+ tooltip={canShowGrading ? "Afficher/Masquer la notation" : "Pas de note"}
315
+ tooltipOptions={{
316
+ position: "left",
317
+ showDelay: settings.TOOLTIP_SHOW_DELAY,
318
+ showOnDisabled: true,
319
+ }}
320
+ onClick={() => dispatch(toggleIsGradingVisible())}
321
+ style={{ flexShrink: 0 }}
322
+ outlined={!isGradingVisible || !canShowGrading}
323
+ />
324
+ );
325
+ };
@@ -0,0 +1,145 @@
1
+ import { useCapytaleRichTextEditor } from "@capytale/capytale-rich-text-editor";
2
+ import { useAppDispatch, useAppSelector } from "../../app/hooks";
3
+ import {
4
+ selectSharedNotesContent,
5
+ selectMode,
6
+ setCanSaveSharedNotes,
7
+ setIsMPDirty,
8
+ setLexicalSharedNotesState,
9
+ selectWorkflow,
10
+ selectSharedNotesType,
11
+ setSharedNotesType,
12
+ } from "../activityData/activityDataSlice";
13
+ import { forwardRef, useImperativeHandle, useRef, useState } from "react";
14
+ import { Toast } from "primereact/toast";
15
+ import settings from "../../settings";
16
+ import { Button } from "primereact/button";
17
+ import { Dialog } from "primereact/dialog";
18
+
19
+ const SharedNotesEditor: React.FC = forwardRef((_props, ref) => {
20
+ const [Editor, getState, _canSave] = useCapytaleRichTextEditor();
21
+ const dispatch = useAppDispatch();
22
+ const toast = useRef<Toast>(null);
23
+ const mode = useAppSelector(selectMode);
24
+ const workflow = useAppSelector(selectWorkflow);
25
+ const isEditable =
26
+ mode === "create" ||
27
+ (mode === "assignment" && workflow === "current") ||
28
+ mode === "review";
29
+ const initialEditorState = useAppSelector(selectSharedNotesContent);
30
+ const initialStateOnChangeDone = useRef<boolean>(false);
31
+ const sharedNotesType = useAppSelector(selectSharedNotesType);
32
+
33
+ const [helpDialogVisible, setHelpDialogVisible] = useState(false);
34
+
35
+ useImperativeHandle(ref, () => {
36
+ return {
37
+ save: async () => {
38
+ const state = await getState();
39
+ dispatch(setLexicalSharedNotesState(state.json));
40
+ },
41
+ };
42
+ });
43
+
44
+ return (
45
+ <>
46
+ <Toast position="bottom-right" ref={toast} />
47
+ <>
48
+ {sharedNotesType === "none" && (
49
+ <>
50
+ <p>Pas de notes partagées.</p>
51
+ <Button
52
+ label="Créer des notes partagées"
53
+ onClick={() => dispatch(setSharedNotesType("rich"))}
54
+ />
55
+ <div style={{ textAlign: "start", padding: "16px" }}>
56
+ <h3>Que sont les notes partagées ?</h3>
57
+ <p>
58
+ Les notes partagées permettent aux élèves de communiquer avec
59
+ leur enseignant. L'enseignant donne le contenu initial des notes
60
+ partagées, et les élèves peuvent le modifier, notamment pour
61
+ répondre à des questions, expliciter une démarche ou faire des
62
+ remarques sur leur travail. L'enseignant peut également modifier
63
+ les notes partagées pour répondre aux élèves.
64
+ </p>
65
+ <p>
66
+ Les notes partagées peuvent contenir du texte, des images, des
67
+ liens, etc., tout comme les consignes. La différence principale
68
+ avec les consignes est que les élèves peuvent modifier le
69
+ contenu des notes partagées. Elles sont un outil de
70
+ communication supplémentaire entre l'enseignant et les élèves.
71
+ </p>
72
+ </div>
73
+ <Button
74
+ severity="secondary"
75
+ size="small"
76
+ icon={"pi pi-question-circle"}
77
+ onClick={() => {
78
+ setHelpDialogVisible(true);
79
+ }}
80
+ outlined
81
+ label="En savoir plus"
82
+ style={{ marginBottom: "16px" }}
83
+ />
84
+ <Dialog
85
+ id="metaPlayerHelpDialog"
86
+ header="Documentation"
87
+ visible={helpDialogVisible}
88
+ onHide={() => setHelpDialogVisible(false)}
89
+ maximizable={true}
90
+ >
91
+ <iframe
92
+ src={
93
+ "https://capytale2.ac-paris.fr/wiki/doku.php?id=notes_partagees"
94
+ }
95
+ style={{ width: "100%", height: "100%" }}
96
+ title="Documentation"
97
+ />
98
+ </Dialog>
99
+ </>
100
+ )}
101
+ {sharedNotesType === "rich" && (
102
+ <Editor
103
+ placeholderText={
104
+ mode === "create"
105
+ ? "Écrivez le contenu initial des notes partagées ici..."
106
+ : "Les notes partagées sont vides, vous pouvez les remplir ici..."
107
+ }
108
+ htmlInitialContent={initialEditorState ? undefined : ""}
109
+ initialEditorState={initialEditorState || undefined}
110
+ jsonSizeLimit={settings.STATEMENT_MAX_SIZE}
111
+ onChange={(editorState) => {
112
+ dispatch(setLexicalSharedNotesState(editorState));
113
+ if (initialStateOnChangeDone.current) {
114
+ dispatch(setIsMPDirty(true));
115
+ } else {
116
+ initialStateOnChangeDone.current = true;
117
+ }
118
+ }}
119
+ onJsonSizeLimitExceeded={() => {
120
+ dispatch(setCanSaveSharedNotes(false));
121
+ toast.current!.show({
122
+ summary: "Erreur",
123
+ detail: `Le contenu des notes partagées est trop volumineux. Veuillez le réduire avant de l'enregistrer.\nPeut-être avez-vous inséré une image trop volumineuse ?`,
124
+ severity: "error",
125
+ life: 10000,
126
+ });
127
+ }}
128
+ onJsonSizeLimitMet={() => {
129
+ dispatch(setCanSaveSharedNotes(true));
130
+ toast.current!.show({
131
+ summary: "Succès",
132
+ detail: `Le contenu des notes partagées ne dépasse plus la taille limite.`,
133
+ severity: "success",
134
+ life: 4000,
135
+ });
136
+ }}
137
+ isEditable={isEditable}
138
+ />
139
+ )}
140
+ </>
141
+ </>
142
+ );
143
+ });
144
+
145
+ export default SharedNotesEditor;