commit dee536921eaad57be9fc9a198ad4032ac809f56e
Author: Jaroslav Hrubý <hrubyj@students.zcu.cz>
Date:   Fri May 6 09:42:17 2022 +0200

    Disabling tag buttons when adding new tag occurrence

diff --git a/webapp/components/annotation/SubTagItem.tsx b/webapp/components/annotation/SubTagItem.tsx
index d288b8d..689ad8a 100644
--- a/webapp/components/annotation/SubTagItem.tsx
+++ b/webapp/components/annotation/SubTagItem.tsx
@@ -3,6 +3,7 @@ import { Container, Row } from 'react-bootstrap';
 import { Button } from 'antd';
 import { useContext } from 'react';
 import { TagCategoryContext } from '../../contexts/TagCategoryContext';
+import { AnnotationContext } from '../../contexts/AnnotationContext';
 
 /**
  * Creates a single tag item in a tag panel.
@@ -15,6 +16,11 @@ export function SubTagItem(props: { tag: TagInfo; subTag: SubTagInfo }) {
      */
     const { selectTag } = useContext(TagCategoryContext);
 
+    /**
+     * Annotation context
+     */
+    const { submitting } = useContext(AnnotationContext);
+
     /**
      * Selects the sub tag.
      */
@@ -25,7 +31,11 @@ export function SubTagItem(props: { tag: TagInfo; subTag: SubTagInfo }) {
     return (
         <Container>
             <Row>
-                <Button onClick={onSelectSubTag} className="w-100 text-start rounded">
+                <Button
+                    onClick={onSelectSubTag}
+                    className="w-100 text-start rounded"
+                    disabled={submitting}
+                >
                     {props.subTag.name}
                 </Button>
             </Row>
diff --git a/webapp/components/annotation/TagItem.tsx b/webapp/components/annotation/TagItem.tsx
index 76321fa..d0118e0 100644
--- a/webapp/components/annotation/TagItem.tsx
+++ b/webapp/components/annotation/TagItem.tsx
@@ -5,6 +5,7 @@ import { DownOutlined, TagOutlined, UpOutlined } from '@ant-design/icons';
 import React, { useContext, useState } from 'react';
 import { SubTagItem } from './SubTagItem';
 import { TagCategoryContext } from '../../contexts/TagCategoryContext';
+import { AnnotationContext } from '../../contexts/AnnotationContext';
 
 /**
  * Creates a single tag item in a tag panel.
@@ -22,6 +23,11 @@ export function TagItem(props: { tag: TagInfo }) {
      */
     const { selectTag } = useContext(TagCategoryContext);
 
+    /**
+     * Annotation context
+     */
+    const { submitting } = useContext(AnnotationContext);
+
     /**
      * Button icon.
      */
@@ -55,13 +61,18 @@ export function TagItem(props: { tag: TagInfo }) {
                         icon={buttonIcon}
                         onClick={changeSubTagsVisibility}
                         className="w-100 text-start rounded"
+                        disabled={submitting}
                     >
                         {props.tag.name}
                         <TagOutlined style={{ color: props.tag.color ?? 'black' }} />
                     </Button>
                 )}
                 {!hasSubTags && (
-                    <Button onClick={onSelectTag} className="w-100 text-start rounded">
+                    <Button
+                        onClick={onSelectTag}
+                        className="w-100 text-start rounded"
+                        disabled={submitting}
+                    >
                         {props.tag.name}
                         <TagOutlined style={{ color: props.tag.color ?? 'black' }} />
                     </Button>
diff --git a/webapp/contexts/AnnotationContext.tsx b/webapp/contexts/AnnotationContext.tsx
index b3be87f..2f1b600 100644
--- a/webapp/contexts/AnnotationContext.tsx
+++ b/webapp/contexts/AnnotationContext.tsx
@@ -1,8 +1,9 @@
 import React, { createContext, useEffect, useState } from 'react';
 import { AnnotationInfo, ETagType, SubTagInfo, TagInfo, TagInstanceInfo } from '../api';
 import { Tag } from '../components/types/tag';
-import { annotationController } from '../controllers';
+import { annotationController, userController } from '../controllers';
 import { GetSelectionInfo } from '../utils/selectionUtils';
+import { ShowConfirmDelete, ShowToast } from '../utils/alerts';
 
 /**
  * Interface of an annotation context provider.
@@ -13,6 +14,11 @@ interface IAnnotationContextProvider {
      */
     tags: TagInstanceInfo[] | null;
 
+    /**
+     * Submitting boolean
+     */
+    submitting: boolean;
+
     /**
      * Sets new tags.
      * @param newTags An array of new tags.
@@ -71,6 +77,11 @@ export const AnnotationContext = createContext<IAnnotationContextProvider>({
      */
     tags: null,
 
+    /**
+     * Submitting boolean
+     */
+    submitting: false,
+
     /**
      * Default implementation of setTags method.
      * @param v Array of new tags.
@@ -150,11 +161,14 @@ const AnnotationProvider = (props: {
 
     const [mappedTags, setMappedTags] = useState<Tag[] | null>(null);
 
+    const [submitting, setSubmitting] = useState(false);
+
     async function markSelectedText(
         tagId: string,
         subtagId: string | null,
         instanceId: string | null
     ) {
+        setSubmitting(true);
         if (!annotation) {
             console.log('annotation not found');
             return;
@@ -170,17 +184,15 @@ const AnnotationProvider = (props: {
 
         const id = subtagId ?? tagId;
         const type: ETagType = subtagId == null ? ETagType.Tag : ETagType.Subtag;
-
-        const res = await annotationController.annotationAnnotationIdPost(
-            props.annotationId,
-            {
+        const res = await annotationController
+            .annotationAnnotationIdPost(props.annotationId, {
                 id: id,
                 instanceId,
                 type,
                 position: selectionInfo.startPositionOriginalDocument,
                 length: selectionInfo.selectionLengthOriginalDocument,
-            }
-        );
+            })
+            .catch((e) => ShowToast('Duplicitní výskyt anotace!', 'warning'));
 
         await refreshAnnotation();
     }
@@ -211,13 +223,14 @@ const AnnotationProvider = (props: {
             return;
         }
 
-        const deleteRes =
-            await annotationController.annotationAnnotationIdOccurenceIdDelete(
-                props.annotationId,
-                occurrence.occurenceId
-            );
-
-        await refreshAnnotation();
+        ShowConfirmDelete(() => {
+            annotationController
+                .annotationAnnotationIdOccurenceIdDelete(
+                    props.annotationId,
+                    occurrence.occurenceId ?? ''
+                )
+                .then(() => refreshAnnotation());
+        }, 'značku');
     };
 
     /**
@@ -268,6 +281,7 @@ const AnnotationProvider = (props: {
 
         remapAnnotations(data.data);
         setAnnotation(data.data ?? null);
+        setSubmitting(false);
     }
 
     /**
@@ -281,6 +295,7 @@ const AnnotationProvider = (props: {
         <AnnotationContext.Provider
             value={{
                 tags,
+                submitting,
                 setTags,
                 addOccurrence,
                 changeVisibility,
