Add alert for scouting

Alert scouters when someone else is scouting the same team.

Signed-off-by: Emily Markova <emily.markova@gmail.com>
Change-Id: Id62ad1a96ff90ef4cba1797c21bc4063ccbdeae5
diff --git a/scouting/www/entry/entry.component.ts b/scouting/www/entry/entry.component.ts
index 230bfec..1a757a0 100644
--- a/scouting/www/entry/entry.component.ts
+++ b/scouting/www/entry/entry.component.ts
@@ -39,6 +39,8 @@
   MatchListRequestor,
   ActionsSubmitter,
 } from '@org_frc971/scouting/www/rpc';
+import {RequestCurrentScouting} from '@org_frc971/scouting/webserver/requests/messages/request_current_scouting_generated';
+import {RequestCurrentScoutingResponse} from '@org_frc971/scouting/webserver/requests/messages/request_current_scouting_response_generated';
 import {ActionHelper, ConcreteAction} from './action_helper';
 import * as pako from 'pako';
 
@@ -136,6 +138,8 @@
   penalties: number = 0;
 
   teamSelectionIsValid = false;
+  searchForDuplicateScouting: boolean = false;
+  duplicateSearchTimer: ReturnType<typeof setTimeout> | null = null;
 
   // When the user chooses to generate QR codes, we convert the flatbuffer into
   // a long string. Since we frequently have more data than we can display in a
@@ -165,8 +169,13 @@
     this.fetchMatchList();
   }
 
+  ngOnDestroy() {
+    clearInterval(this.duplicateSearchTimer);
+  }
+
   goToNextTeam() {
     this.ngOnInit();
+    this.ngOnDestroy();
     this.teamNumber = this.nextTeamNumber;
     this.nextTeamNumber = '';
   }
@@ -184,6 +193,53 @@
     }
   }
 
+  async findOthersScoutingThisRobot() {
+    const builder = new Builder();
+    const teamNumber = builder.createString(this.teamNumber);
+
+    builder.finish(
+      RequestCurrentScouting.createRequestCurrentScouting(builder, teamNumber)
+    );
+
+    const buffer = builder.asUint8Array();
+    const res = await fetch('/requests/request/current_scouting', {
+      method: 'POST',
+      body: buffer,
+    });
+
+    if (!res.ok) {
+      const resBuffer = await res.arrayBuffer();
+      const fbBuffer = new ByteBuffer(new Uint8Array(resBuffer));
+      const parsedResponse = ErrorResponse.getRootAsErrorResponse(fbBuffer);
+      const errorMessage = parsedResponse.errorMessage();
+      this.errorMessage = `Received ${res.status} ${res.statusText}: "${errorMessage}"`;
+    } else {
+      const resBuffer = await res.arrayBuffer();
+      const fbBuffer = new ByteBuffer(new Uint8Array(resBuffer));
+      const parsedResponse =
+        RequestCurrentScoutingResponse.getRootAsRequestCurrentScoutingResponse(
+          fbBuffer
+        );
+      const collectedBy = [];
+      for (let i = 0; i < parsedResponse.collectedByLength(); i++) {
+        collectedBy.push(parsedResponse.collectedBy(i).name());
+      }
+      this.duplicateSearchTimer = setInterval(() => {
+        if (this.searchForDuplicateScouting && collectedBy.length != 0) {
+          if (
+            confirm(
+              'This team is currently being scouted by ' +
+                collectedBy +
+                '. Would you like to receive more alerts?'
+            ) != true
+          ) {
+            this.searchForDuplicateScouting = false;
+          }
+        }
+      }, 10000);
+    }
+  }
+
   // This gets called when the user changes something on the Init screen.
   // It makes sure that the user can't click "Next" until the information is
   // valid, or this is for pre-scouting or practice matches.
@@ -314,6 +370,11 @@
       this.updateQrCodeValuePieceSize();
     }
 
+    if (target == 'Init') {
+      this.searchForDuplicateScouting = true;
+      this.findOthersScoutingThisRobot();
+    }
+
     this.section = target;
   }
 
@@ -457,6 +518,7 @@
       this.compType = 'Regular';
       this.matchStartTimestamp = 0;
       this.selectedValue = 0;
+      this.searchForDuplicateScouting = false;
     } else {
       const resBuffer = await res.arrayBuffer();
       const fbBuffer = new ByteBuffer(new Uint8Array(resBuffer));