+ `
+
+ let checkbox = matchElement.querySelector(".match-select")
+ checkbox.addEventListener("input", () => {
+ console.log(checkbox.checked)
+ if (checkbox.checked) { //if its already selected, do nothing
+ //disable editable inputs
+
+ let element = document.getElementsByClassName(`m${i}`);
+ for(team of element)
+ {
+ team.setAttribute("contentEditable", false);
+ }
+ let totalTeams = getTeams("m"+checkbox.id)
+ processTeams(checkbox.id, totalTeams);
+
+
+
+ } else {
+ //enable editable inputs
+ let allianceElement = document.getElementsByClassName(`match-teams qm${i}`);
+ for(element of allianceElement)
+ {
+ let element = document.getElementsByClassName('match-team')
+ for(team of element)
+ {
+ team.setAttribute("contentEditable", true);
+ }
+ }
+ }
+
+ })
+
+ }
+
+}
+
+function getTeams(num) {
+
+ let teamArray = document.getElementsByClassName(num);
+ let processedArray = [];
+ for(value of teamArray)
+ {
+ processedArray.push(value.innerHTML);
+ }
+
+ // returns team data for match selected in an array of 6 strings
+ return processedArray;
+}
+
+var processedManualMatches = [];
+// make an array which will get filled in tba format
+
+function makeMatchSchedule(matchTotalNum){
+ // creates a blank form with the correct number of matches
+ processedManualMatches = [];
+
+ // tba formatted data
+ for (let i=1; i<=matchTotalNum; i++) {
+ processedManualMatches.push({
+ number: i,
+ match_string: `2023temp_q${i}`, // use temp bc we don't need event keys and don't have one
+ robots: {
+ red: [null, null, null], // empty arrays to get filled
+ blue: [null, null, null],
+ }
+ });
+ }
+}
+
+
+async function processTeams(matchNum, teams) {
+ // inserts data into the correct spot
+ let data = await teams;
+ console.log(data);
+ let redTeams = [];
+ let blueTeams = [];
+ for(let i = 0; i < 3; i++)
+ {
+ redTeams.push(data[i]);
+ blueTeams.push(data[i+3]);
+ }
+
+ // acccess the correct match object and then adding to properties
+ processedManualMatches[matchNum-1].robots.red = redTeams;
+ processedManualMatches[matchNum-1].robots.blue = blueTeams;
+
+ // post request to send schedule to admin
+ console.log(processedManualMatches);
+ console.log(JSON.stringify(processedManualMatches))
+ fetch('/schedule/matches',{
+ method:"POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body:JSON.stringify(processedManualMatches)
+ }).catch(e=>console.log(e))
+
+}
+
+async function getManualMatches() {
+ return processedManualMatches;
+
+}
+
+
+
+
diff --git a/src/schedule/public/js/ui-elements.js b/src/schedule/public/js/ui-elements.js
new file mode 100644
index 00000000..231ac169
--- /dev/null
+++ b/src/schedule/public/js/ui-elements.js
@@ -0,0 +1,162 @@
+class Modal {
+ blind; // dimmed background element (closes modal on click)
+ close; // close button element
+ element; // main modal container element
+ modalExit; // function to close and destroy the modal
+ dismissButton; // optional dismiss button element
+ cancel; // cancel function passed in
+
+ constructor(size, closable=true) {
+ this.blind = document.createElement("div")
+ this.blind.classList = "modal-blind"
+ this.element = document.createElement("div")
+ this.element.classList = `modal ${size}`
+
+ this.modalExit = () => {
+ hideFade(this.blind)
+ hideFade(this.element)
+ setTimeout(() => {
+ document.body.removeChild(this.blind)
+ document.body.removeChild(this.element)
+ }, 300)
+ }
+
+ if (closable) {
+ this.close = document.createElement("i")
+ this.close.classList = "fa fa-times modal-close"
+
+ this.blind.addEventListener("click", this.modalExit)
+ this.close.addEventListener("click", this.modalExit)
+ this.element.appendChild(this.close)
+ }
+ document.body.appendChild(this.blind)
+ document.body.appendChild(this.element)
+ this.blind.offsetHeight
+ this.element.offsetHeight
+ showFade(this.blind)
+ showFade(this.element)
+ return this
+ }
+
+ assignCancel(cancelFunction) {
+ this.blind.addEventListener("click", cancelFunction)
+ this.close.addEventListener("click", cancelFunction)
+ this.dismissButton ? this.dismissButton.addEventListener("click", cancelFunction) : null
+ this.cancel = cancelFunction
+ }
+
+ header(text) {
+ const headerElement = document.createElement("div")
+ headerElement.innerHTML = text
+ headerElement.classList.add("header")
+ this.element.appendChild(headerElement)
+ return this
+ }
+
+ text(text) {
+ const textElement = document.createElement("div")
+ textElement.innerHTML = text
+ textElement.classList.add("text")
+ this.element.appendChild(textElement)
+ return this
+ }
+
+ image(src) {
+ const imgElement = document.createElement("img")
+ imgElement.src = src
+ this.element.appendChild(imgElement)
+ return this
+ }
+
+ center(horizontal = true, vertical = false) {
+ if (vertical) {
+ this.element.classList.add("main-center")
+ }
+
+ if (horizontal) {
+ this.element.classList.add("alt-center")
+ }
+
+ return this
+ }
+
+ dismiss(buttonText = "Dismiss") {
+ const buttonElement = document.createElement("button")
+ buttonElement.innerText = buttonText
+ buttonElement.addEventListener("click", this.modalExit)
+ this.cancel ? buttonElement.addEventListener("click", this.cancel) : null
+ this.element.appendChild(buttonElement)
+
+ return this
+ }
+
+ action(buttonText, func) {
+ const buttonElement = document.createElement("button")
+ buttonElement.innerText = buttonText
+ buttonElement.addEventListener("click", func);
+ this.element.appendChild(buttonElement);
+
+ return this
+ }
+}
+
+function showFade(element) {
+ element.classList.add("visible")
+}
+
+function hideFade(element) {
+ element.classList.remove("visible")
+}
+
+class Popup {
+ static types = {
+ "error": {
+ "prefix": "Error: ",
+ "color": "var(--error)"
+ },
+
+ "notice": {
+ "prefix": "",
+ "color": "var(--accent)"
+ },
+
+ "success": {
+ "prefix": "",
+ "color": "var(--green)"
+ },
+ }
+ popupElement;
+
+ constructor(type, text, duration = 5000) {
+ this.popupElement = document.createElement("p")
+ this.popupElement.classList = "popup"
+ this.popupElement.style.backgroundColor = Popup.types[type].color
+ this.popupElement.innerText = Popup.types[type].prefix + text
+ document.body.appendChild(this.popupElement)
+ this.popupElement.offsetHeight
+ this.popupElement.style.top = "55px"
+ setTimeout(() => {
+ this.popupElement.style.top = "0"
+ setTimeout(() => {
+ document.body.removeChild(this.popupElement)
+ }, 600)
+ }, duration)
+ }
+ setText(text) {
+ this.popupElement.innerText = text;
+ return this;
+ }
+ setType(type) {
+ this.popupElement.style.backgroundColor = Popup.types[type].color;
+ return this;
+ }
+}
+
+function createDOMElement(tag, classes, id) {
+ const element = document.createElement(tag)
+ element.classList = classes
+ if (id) {
+ element.id = id
+ }
+ return element
+}
\ No newline at end of file
diff --git a/src/schedule/routes/api.js b/src/schedule/routes/api.js
new file mode 100644
index 00000000..a58b0ac5
--- /dev/null
+++ b/src/schedule/routes/api.js
@@ -0,0 +1,28 @@
+const { Router } = require("express");
+let router = Router();
+const config = require("../../../config/config.json");
+const { TeamMatchPerformance } = require("../../lib/db");
+
+
+router.get("/auth", (req, res) => {
+ if (config.secrets.ACCESS_CODE === "") {
+ res.json({status: 2})
+ } else if (config.secrets.ACCESS_CODE == req.headers.authorization) {
+ res.json({status: 1})
+ } else {
+ res.json({status: 0})
+ }
+})
+
+
+router.get("/data", async (req,res) => {
+ res.json(await TeamMatchPerformance.find());
+})
+
+router.get("/matches", async (req,res) => {
+ res.json({
+ "allMatches": await ScoutingSync.getMatches(),
+ "currentMatch": ScoutingSync.match
+ })
+})
+module.exports = router;
\ No newline at end of file
diff --git a/src/schedule/schedule.js b/src/schedule/schedule.js
new file mode 100644
index 00000000..388ab219
--- /dev/null
+++ b/src/schedule/schedule.js
@@ -0,0 +1,25 @@
+express = require("express");
+
+var schedule = {};
+let router = express.Router();
+
+router.use(express.static(__dirname + "/public"));
+
+router.get("/", (req,res) => {
+ res.render(__dirname + "/views/index.ejs");
+})
+
+router.post('/matches',(req,res)=>{
+
+ console.log("req body on /schedule/matches")
+ console.log(req.body)
+ schedule = req.body;
+ res.send(200)
+})
+router.get('/matches',(req,res)=>{
+ res.send(schedule)
+})
+
+router.use("/api", require("./routes/api.js"));
+
+module.exports = router;
\ No newline at end of file
diff --git a/src/schedule/views/index.ejs b/src/schedule/views/index.ejs
new file mode 100644
index 00000000..5d5a1206
--- /dev/null
+++ b/src/schedule/views/index.ejs
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+ SPOT - Manual Schedule
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
SPOT - Manual Schedule
+
+
+
+
+
+
+
+
+
+
+
+
Matches
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/scouting/scouting-sync.js b/src/scouting/scouting-sync.js
index 0cb7b995..7e714482 100644
--- a/src/scouting/scouting-sync.js
+++ b/src/scouting/scouting-sync.js
@@ -41,6 +41,8 @@ class ScoutingSync {
if (!config.secrets.TBA_API_KEY) {
console.error(chalk.whiteBright.bgRed.bold("TBA_API_KEY not found in config.json file! SPOT will not properly function without this."))
}
+
+
ScoutingSync.match = (await ScoutingSync.getMatches())[0] || {number: 0, match_string: "", robots: {red: [], blue: []}};
io = require("socket.io")(server);