Add frontend stuff
							parent
							
								
									210b590544
								
							
						
					
					
						commit
						67567046b8
					
				| 
						 | 
				
			
			@ -13,7 +13,8 @@
 | 
			
		|||
        "pinia": "^2.2.4",
 | 
			
		||||
        "v-tooltip": "^2.1.3",
 | 
			
		||||
        "vue": "^3.5.12",
 | 
			
		||||
        "vue-router": "^4.4.5"
 | 
			
		||||
        "vue-router": "^4.4.5",
 | 
			
		||||
        "vue-select": "^4.0.0-beta.6"
 | 
			
		||||
      },
 | 
			
		||||
      "devDependencies": {
 | 
			
		||||
        "@tsconfig/node20": "^20.1.4",
 | 
			
		||||
| 
						 | 
				
			
			@ -31,6 +32,7 @@
 | 
			
		|||
        "eslint-plugin-vue": "^9.29.0",
 | 
			
		||||
        "jsdom": "^25.0.1",
 | 
			
		||||
        "npm-run-all2": "^6.2.3",
 | 
			
		||||
        "openapi-typescript-codegen": "^0.29.0",
 | 
			
		||||
        "postcss": "^8.4.47",
 | 
			
		||||
        "prettier": "^3.3.3",
 | 
			
		||||
        "tailwindcss": "^3.4.14",
 | 
			
		||||
| 
						 | 
				
			
			@ -53,6 +55,24 @@
 | 
			
		|||
        "url": "https://github.com/sponsors/sindresorhus"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/@apidevtools/json-schema-ref-parser": {
 | 
			
		||||
      "version": "11.7.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.7.2.tgz",
 | 
			
		||||
      "integrity": "sha512-4gY54eEGEstClvEkGnwVkTkrx0sqwemEFG5OSRRn3tD91XH0+Q8XIkYIfo7IwEWPpJZwILb9GUXeShtplRc/eA==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "@jsdevtools/ono": "^7.1.3",
 | 
			
		||||
        "@types/json-schema": "^7.0.15",
 | 
			
		||||
        "js-yaml": "^4.1.0"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">= 16"
 | 
			
		||||
      },
 | 
			
		||||
      "funding": {
 | 
			
		||||
        "url": "https://github.com/sponsors/philsturgeon"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/@babel/helper-string-parser": {
 | 
			
		||||
      "version": "7.25.9",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz",
 | 
			
		||||
| 
						 | 
				
			
			@ -868,6 +888,13 @@
 | 
			
		|||
        "@jridgewell/sourcemap-codec": "^1.4.14"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/@jsdevtools/ono": {
 | 
			
		||||
      "version": "7.1.3",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz",
 | 
			
		||||
      "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "MIT"
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/@nodelib/fs.scandir": {
 | 
			
		||||
      "version": "2.1.5",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
 | 
			
		||||
| 
						 | 
				
			
			@ -2376,6 +2403,19 @@
 | 
			
		|||
        "node": ">=6"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/camelcase": {
 | 
			
		||||
      "version": "6.3.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz",
 | 
			
		||||
      "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=10"
 | 
			
		||||
      },
 | 
			
		||||
      "funding": {
 | 
			
		||||
        "url": "https://github.com/sponsors/sindresorhus"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/camelcase-css": {
 | 
			
		||||
      "version": "2.0.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
 | 
			
		||||
| 
						 | 
				
			
			@ -4059,6 +4099,28 @@
 | 
			
		|||
      "dev": true,
 | 
			
		||||
      "license": "MIT"
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/handlebars": {
 | 
			
		||||
      "version": "4.7.8",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz",
 | 
			
		||||
      "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "minimist": "^1.2.5",
 | 
			
		||||
        "neo-async": "^2.6.2",
 | 
			
		||||
        "source-map": "^0.6.1",
 | 
			
		||||
        "wordwrap": "^1.0.0"
 | 
			
		||||
      },
 | 
			
		||||
      "bin": {
 | 
			
		||||
        "handlebars": "bin/handlebars"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=0.4.7"
 | 
			
		||||
      },
 | 
			
		||||
      "optionalDependencies": {
 | 
			
		||||
        "uglify-js": "^3.1.4"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/has-flag": {
 | 
			
		||||
      "version": "4.0.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
 | 
			
		||||
| 
						 | 
				
			
			@ -5127,6 +5189,13 @@
 | 
			
		|||
      "dev": true,
 | 
			
		||||
      "license": "MIT"
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/neo-async": {
 | 
			
		||||
      "version": "2.6.2",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
 | 
			
		||||
      "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "MIT"
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/node-releases": {
 | 
			
		||||
      "version": "2.0.18",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz",
 | 
			
		||||
| 
						 | 
				
			
			@ -5328,6 +5397,48 @@
 | 
			
		|||
        "url": "https://github.com/sponsors/sindresorhus"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/openapi-typescript-codegen": {
 | 
			
		||||
      "version": "0.29.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/openapi-typescript-codegen/-/openapi-typescript-codegen-0.29.0.tgz",
 | 
			
		||||
      "integrity": "sha512-/wC42PkD0LGjDTEULa/XiWQbv4E9NwLjwLjsaJ/62yOsoYhwvmBR31kPttn1DzQ2OlGe5stACcF/EIkZk43M6w==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "@apidevtools/json-schema-ref-parser": "^11.5.4",
 | 
			
		||||
        "camelcase": "^6.3.0",
 | 
			
		||||
        "commander": "^12.0.0",
 | 
			
		||||
        "fs-extra": "^11.2.0",
 | 
			
		||||
        "handlebars": "^4.7.8"
 | 
			
		||||
      },
 | 
			
		||||
      "bin": {
 | 
			
		||||
        "openapi": "bin/index.js"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/openapi-typescript-codegen/node_modules/commander": {
 | 
			
		||||
      "version": "12.1.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz",
 | 
			
		||||
      "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=18"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/openapi-typescript-codegen/node_modules/fs-extra": {
 | 
			
		||||
      "version": "11.2.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz",
 | 
			
		||||
      "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "graceful-fs": "^4.2.0",
 | 
			
		||||
        "jsonfile": "^6.0.1",
 | 
			
		||||
        "universalify": "^2.0.0"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=14.14"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/optionator": {
 | 
			
		||||
      "version": "0.9.4",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
 | 
			
		||||
| 
						 | 
				
			
			@ -6308,7 +6419,6 @@
 | 
			
		|||
      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
 | 
			
		||||
      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
 | 
			
		||||
      "license": "BSD-3-Clause",
 | 
			
		||||
      "peer": true,
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=0.10.0"
 | 
			
		||||
      }
 | 
			
		||||
| 
						 | 
				
			
			@ -6881,6 +6991,20 @@
 | 
			
		|||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/uglify-js": {
 | 
			
		||||
      "version": "3.19.3",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz",
 | 
			
		||||
      "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "BSD-2-Clause",
 | 
			
		||||
      "optional": true,
 | 
			
		||||
      "bin": {
 | 
			
		||||
        "uglifyjs": "bin/uglifyjs"
 | 
			
		||||
      },
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": ">=0.8.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/undici-types": {
 | 
			
		||||
      "version": "6.19.8",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
 | 
			
		||||
| 
						 | 
				
			
			@ -7316,6 +7440,15 @@
 | 
			
		|||
        "vue": "^3.2.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/vue-select": {
 | 
			
		||||
      "version": "4.0.0-beta.6",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/vue-select/-/vue-select-4.0.0-beta.6.tgz",
 | 
			
		||||
      "integrity": "sha512-K+zrNBSpwMPhAxYLTCl56gaMrWZGgayoWCLqe5rWwkB8aUbAUh7u6sXjIR7v4ckp2WKC7zEEUY27g6h1MRsIHw==",
 | 
			
		||||
      "license": "MIT",
 | 
			
		||||
      "peerDependencies": {
 | 
			
		||||
        "vue": "3.x"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/vue-tsc": {
 | 
			
		||||
      "version": "2.1.6",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-2.1.6.tgz",
 | 
			
		||||
| 
						 | 
				
			
			@ -7447,6 +7580,13 @@
 | 
			
		|||
        "node": ">=0.10.0"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/wordwrap": {
 | 
			
		||||
      "version": "1.0.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
 | 
			
		||||
      "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "license": "MIT"
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/wrap-ansi": {
 | 
			
		||||
      "version": "8.1.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -11,7 +11,8 @@
 | 
			
		|||
    "build-only": "vite build",
 | 
			
		||||
    "type-check": "vue-tsc --build --force",
 | 
			
		||||
    "lint": "eslint . --fix",
 | 
			
		||||
    "format": "prettier --write src/"
 | 
			
		||||
    "format": "prettier --write src/",
 | 
			
		||||
    "openapi-generate": "openapi --input 'http://localhost:5000/apidoc/openapi.json' --output src/client --name AvailabilitfClient"
 | 
			
		||||
  },
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "axios": "^1.7.7",
 | 
			
		||||
| 
						 | 
				
			
			@ -19,7 +20,8 @@
 | 
			
		|||
    "pinia": "^2.2.4",
 | 
			
		||||
    "v-tooltip": "^2.1.3",
 | 
			
		||||
    "vue": "^3.5.12",
 | 
			
		||||
    "vue-router": "^4.4.5"
 | 
			
		||||
    "vue-router": "^4.4.5",
 | 
			
		||||
    "vue-select": "^4.0.0-beta.6"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "@tsconfig/node20": "^20.1.4",
 | 
			
		||||
| 
						 | 
				
			
			@ -37,6 +39,7 @@
 | 
			
		|||
    "eslint-plugin-vue": "^9.29.0",
 | 
			
		||||
    "jsdom": "^25.0.1",
 | 
			
		||||
    "npm-run-all2": "^6.2.3",
 | 
			
		||||
    "openapi-typescript-codegen": "^0.29.0",
 | 
			
		||||
    "postcss": "^8.4.47",
 | 
			
		||||
    "prettier": "^3.3.3",
 | 
			
		||||
    "tailwindcss": "^3.4.14",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,6 +8,7 @@ const baseUrl = window.location.origin;
 | 
			
		|||
  <header>
 | 
			
		||||
    <div class="wrapper">
 | 
			
		||||
      <nav>
 | 
			
		||||
        <h1>availabili.tf</h1>
 | 
			
		||||
        <RouterLink to="/">Home</RouterLink>
 | 
			
		||||
        <RouterLink to="/schedule">Schedule</RouterLink>
 | 
			
		||||
        <RouterLink to="/schedule/roster">Roster Builder</RouterLink>
 | 
			
		||||
| 
						 | 
				
			
			@ -25,7 +26,9 @@ const baseUrl = window.location.origin;
 | 
			
		|||
    </div>
 | 
			
		||||
  </header>
 | 
			
		||||
 | 
			
		||||
  <RouterView />
 | 
			
		||||
  <div class="content">
 | 
			
		||||
    <RouterView />
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<style scoped>
 | 
			
		||||
| 
						 | 
				
			
			@ -45,7 +48,8 @@ nav {
 | 
			
		|||
  width: 100%;
 | 
			
		||||
  font-size: 12px;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  margin-top: 2rem;
 | 
			
		||||
  margin: 0;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nav a.router-link-exact-active {
 | 
			
		||||
| 
						 | 
				
			
			@ -64,6 +68,11 @@ nav a:hover {
 | 
			
		|||
  background-color: var(--accent-transparent);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nav > h1 {
 | 
			
		||||
  line-height: unset;
 | 
			
		||||
  margin-right: 1rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@media (min-width: 1024px) {
 | 
			
		||||
  header {
 | 
			
		||||
    display: flex;
 | 
			
		||||
| 
						 | 
				
			
			@ -88,7 +97,14 @@ nav a:hover {
 | 
			
		|||
    font-size: 1rem;
 | 
			
		||||
 | 
			
		||||
    padding: 1rem 0;
 | 
			
		||||
    margin-top: 1rem;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#app > div.content {
 | 
			
		||||
  display: flex;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#app > div.content > main {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -37,7 +37,8 @@
 | 
			
		|||
 | 
			
		||||
  --flamingo: #f0c6c6;
 | 
			
		||||
  --flamingo-transparent: #f0c6c655;
 | 
			
		||||
  --green: #a6e3a1;
 | 
			
		||||
  --green: #40a02b;
 | 
			
		||||
  --yellow: #df8e1d;
 | 
			
		||||
  --lavender: #7287fd;
 | 
			
		||||
  --accent: var(--lavender);
 | 
			
		||||
  --accent-transparent-80: color-mix(in srgb, var(--accent), transparent 80%);
 | 
			
		||||
| 
						 | 
				
			
			@ -45,6 +46,10 @@
 | 
			
		|||
  --accent-transparent: var(--accent-transparent-80);
 | 
			
		||||
  --shadow: color-mix(in srgb, var(--text), transparent 50%);
 | 
			
		||||
 | 
			
		||||
  --vs-selected-color: var(--text)!important;
 | 
			
		||||
  --vs-dropdown-option--active-bg: var(--accent)!important;
 | 
			
		||||
  --vs-dropdown-option--active-color: var(--base)!important;
 | 
			
		||||
  --vs-border-color: var(--overlay-0)!important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* semantic color variables for this project */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -4,7 +4,6 @@
 | 
			
		|||
  width: 100%;
 | 
			
		||||
  max-width: 1280px;
 | 
			
		||||
  margin: 0 auto;
 | 
			
		||||
  padding: 2rem;
 | 
			
		||||
  font-weight: normal;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -30,7 +29,7 @@ button {
 | 
			
		|||
  background-color: var(--crust);
 | 
			
		||||
  border: none;
 | 
			
		||||
  padding: 10px 20px;
 | 
			
		||||
  border-radius: 8px;
 | 
			
		||||
  border-radius: 4px;
 | 
			
		||||
  font-family:
 | 
			
		||||
    Inter,
 | 
			
		||||
    -apple-system,
 | 
			
		||||
| 
						 | 
				
			
			@ -63,7 +62,7 @@ button:hover {
 | 
			
		|||
button.accent {
 | 
			
		||||
  background-color: var(--accent);
 | 
			
		||||
  color: var(--base);
 | 
			
		||||
  text-transform: uppercase;
 | 
			
		||||
  /*text-transform: uppercase;*/
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
button.accent.dark {
 | 
			
		||||
| 
						 | 
				
			
			@ -88,6 +87,10 @@ button.transparent:hover {
 | 
			
		|||
  background-color: var(--surface-0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
button.small {
 | 
			
		||||
  padding: 8px 16px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
button[disabled] {
 | 
			
		||||
  color: var(--overlay-0);
 | 
			
		||||
  cursor: initial;
 | 
			
		||||
| 
						 | 
				
			
			@ -119,3 +122,31 @@ select {
 | 
			
		|||
.subtext {
 | 
			
		||||
  color: var(--overlay-0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
main {
 | 
			
		||||
  padding: 2rem;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
input {
 | 
			
		||||
  padding: 6px 9px;
 | 
			
		||||
  border: none;
 | 
			
		||||
  /*outline: 1px solid var(--overlay-0);*/
 | 
			
		||||
  border: 1px solid var(--overlay-0);
 | 
			
		||||
  border-radius: 4px;
 | 
			
		||||
  background-color: transparent;
 | 
			
		||||
  /*font-size: 11pt;*/
 | 
			
		||||
  font-size: 15px;
 | 
			
		||||
  font-family:
 | 
			
		||||
    Inter,
 | 
			
		||||
    -apple-system,
 | 
			
		||||
    BlinkMacSystemFont,
 | 
			
		||||
    'Segoe UI',
 | 
			
		||||
    Roboto,
 | 
			
		||||
    Oxygen,
 | 
			
		||||
    Ubuntu,
 | 
			
		||||
    Cantarell,
 | 
			
		||||
    'Fira Sans',
 | 
			
		||||
    'Droid Sans',
 | 
			
		||||
    'Helvetica Neue',
 | 
			
		||||
    sans-serif;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,315 @@
 | 
			
		|||
[
 | 
			
		||||
    "Africa/Abidjan",
 | 
			
		||||
    "Africa/Algiers",
 | 
			
		||||
    "Africa/Bissau",
 | 
			
		||||
    "Africa/Cairo",
 | 
			
		||||
    "Africa/Casablanca",
 | 
			
		||||
    "Africa/Ceuta",
 | 
			
		||||
    "Africa/El_Aaiun",
 | 
			
		||||
    "Africa/Johannesburg",
 | 
			
		||||
    "Africa/Juba",
 | 
			
		||||
    "Africa/Khartoum",
 | 
			
		||||
    "Africa/Lagos",
 | 
			
		||||
    "Africa/Maputo",
 | 
			
		||||
    "Africa/Monrovia",
 | 
			
		||||
    "Africa/Nairobi",
 | 
			
		||||
    "Africa/Ndjamena",
 | 
			
		||||
    "Africa/Sao_Tome",
 | 
			
		||||
    "Africa/Tripoli",
 | 
			
		||||
    "Africa/Tunis",
 | 
			
		||||
    "Africa/Windhoek",
 | 
			
		||||
    "America/Adak",
 | 
			
		||||
    "America/Anchorage",
 | 
			
		||||
    "America/Araguaina",
 | 
			
		||||
    "America/Argentina/Buenos_Aires",
 | 
			
		||||
    "America/Argentina/Catamarca",
 | 
			
		||||
    "America/Argentina/Cordoba",
 | 
			
		||||
    "America/Argentina/Jujuy",
 | 
			
		||||
    "America/Argentina/La_Rioja",
 | 
			
		||||
    "America/Argentina/Mendoza",
 | 
			
		||||
    "America/Argentina/Rio_Gallegos",
 | 
			
		||||
    "America/Argentina/Salta",
 | 
			
		||||
    "America/Argentina/San_Juan",
 | 
			
		||||
    "America/Argentina/San_Luis",
 | 
			
		||||
    "America/Argentina/Tucuman",
 | 
			
		||||
    "America/Argentina/Ushuaia",
 | 
			
		||||
    "America/Asuncion",
 | 
			
		||||
    "America/Bahia",
 | 
			
		||||
    "America/Bahia_Banderas",
 | 
			
		||||
    "America/Barbados",
 | 
			
		||||
    "America/Belem",
 | 
			
		||||
    "America/Belize",
 | 
			
		||||
    "America/Boa_Vista",
 | 
			
		||||
    "America/Bogota",
 | 
			
		||||
    "America/Boise",
 | 
			
		||||
    "America/Cambridge_Bay",
 | 
			
		||||
    "America/Campo_Grande",
 | 
			
		||||
    "America/Cancun",
 | 
			
		||||
    "America/Caracas",
 | 
			
		||||
    "America/Cayenne",
 | 
			
		||||
    "America/Chicago",
 | 
			
		||||
    "America/Chihuahua",
 | 
			
		||||
    "America/Ciudad_Juarez",
 | 
			
		||||
    "America/Costa_Rica",
 | 
			
		||||
    "America/Cuiaba",
 | 
			
		||||
    "America/Danmarkshavn",
 | 
			
		||||
    "America/Dawson",
 | 
			
		||||
    "America/Dawson_Creek",
 | 
			
		||||
    "America/Denver",
 | 
			
		||||
    "America/Detroit",
 | 
			
		||||
    "America/Edmonton",
 | 
			
		||||
    "America/Eirunepe",
 | 
			
		||||
    "America/El_Salvador",
 | 
			
		||||
    "America/Fort_Nelson",
 | 
			
		||||
    "America/Fortaleza",
 | 
			
		||||
    "America/Glace_Bay",
 | 
			
		||||
    "America/Goose_Bay",
 | 
			
		||||
    "America/Grand_Turk",
 | 
			
		||||
    "America/Guatemala",
 | 
			
		||||
    "America/Guayaquil",
 | 
			
		||||
    "America/Guyana",
 | 
			
		||||
    "America/Halifax",
 | 
			
		||||
    "America/Havana",
 | 
			
		||||
    "America/Hermosillo",
 | 
			
		||||
    "America/Indiana/Indianapolis",
 | 
			
		||||
    "America/Indiana/Knox",
 | 
			
		||||
    "America/Indiana/Marengo",
 | 
			
		||||
    "America/Indiana/Petersburg",
 | 
			
		||||
    "America/Indiana/Tell_City",
 | 
			
		||||
    "America/Indiana/Vevay",
 | 
			
		||||
    "America/Indiana/Vincennes",
 | 
			
		||||
    "America/Indiana/Winamac",
 | 
			
		||||
    "America/Inuvik",
 | 
			
		||||
    "America/Iqaluit",
 | 
			
		||||
    "America/Jamaica",
 | 
			
		||||
    "America/Juneau",
 | 
			
		||||
    "America/Kentucky/Louisville",
 | 
			
		||||
    "America/Kentucky/Monticello",
 | 
			
		||||
    "America/La_Paz",
 | 
			
		||||
    "America/Lima",
 | 
			
		||||
    "America/Los_Angeles",
 | 
			
		||||
    "America/Maceio",
 | 
			
		||||
    "America/Managua",
 | 
			
		||||
    "America/Manaus",
 | 
			
		||||
    "America/Martinique",
 | 
			
		||||
    "America/Matamoros",
 | 
			
		||||
    "America/Mazatlan",
 | 
			
		||||
    "America/Menominee",
 | 
			
		||||
    "America/Merida",
 | 
			
		||||
    "America/Metlakatla",
 | 
			
		||||
    "America/Mexico_City",
 | 
			
		||||
    "America/Miquelon",
 | 
			
		||||
    "America/Moncton",
 | 
			
		||||
    "America/Monterrey",
 | 
			
		||||
    "America/Montevideo",
 | 
			
		||||
    "America/New_York",
 | 
			
		||||
    "America/Nome",
 | 
			
		||||
    "America/Noronha",
 | 
			
		||||
    "America/North_Dakota/Beulah",
 | 
			
		||||
    "America/North_Dakota/Center",
 | 
			
		||||
    "America/North_Dakota/New_Salem",
 | 
			
		||||
    "America/Nuuk",
 | 
			
		||||
    "America/Ojinaga",
 | 
			
		||||
    "America/Panama",
 | 
			
		||||
    "America/Paramaribo",
 | 
			
		||||
    "America/Phoenix",
 | 
			
		||||
    "America/Port-au-Prince",
 | 
			
		||||
    "America/Porto_Velho",
 | 
			
		||||
    "America/Puerto_Rico",
 | 
			
		||||
    "America/Punta_Arenas",
 | 
			
		||||
    "America/Rankin_Inlet",
 | 
			
		||||
    "America/Recife",
 | 
			
		||||
    "America/Regina",
 | 
			
		||||
    "America/Resolute",
 | 
			
		||||
    "America/Rio_Branco",
 | 
			
		||||
    "America/Santarem",
 | 
			
		||||
    "America/Santiago",
 | 
			
		||||
    "America/Santo_Domingo",
 | 
			
		||||
    "America/Sao_Paulo",
 | 
			
		||||
    "America/Scoresbysund",
 | 
			
		||||
    "America/Sitka",
 | 
			
		||||
    "America/St_Johns",
 | 
			
		||||
    "America/Swift_Current",
 | 
			
		||||
    "America/Tegucigalpa",
 | 
			
		||||
    "America/Thule",
 | 
			
		||||
    "America/Tijuana",
 | 
			
		||||
    "America/Toronto",
 | 
			
		||||
    "America/Vancouver",
 | 
			
		||||
    "America/Whitehorse",
 | 
			
		||||
    "America/Winnipeg",
 | 
			
		||||
    "America/Yakutat",
 | 
			
		||||
    "Antarctica/Casey",
 | 
			
		||||
    "Antarctica/Davis",
 | 
			
		||||
    "Antarctica/Macquarie",
 | 
			
		||||
    "Antarctica/Mawson",
 | 
			
		||||
    "Antarctica/Palmer",
 | 
			
		||||
    "Antarctica/Rothera",
 | 
			
		||||
    "Antarctica/Troll",
 | 
			
		||||
    "Antarctica/Vostok",
 | 
			
		||||
    "Asia/Almaty",
 | 
			
		||||
    "Asia/Amman",
 | 
			
		||||
    "Asia/Anadyr",
 | 
			
		||||
    "Asia/Aqtau",
 | 
			
		||||
    "Asia/Aqtobe",
 | 
			
		||||
    "Asia/Ashgabat",
 | 
			
		||||
    "Asia/Atyrau",
 | 
			
		||||
    "Asia/Baghdad",
 | 
			
		||||
    "Asia/Baku",
 | 
			
		||||
    "Asia/Bangkok",
 | 
			
		||||
    "Asia/Barnaul",
 | 
			
		||||
    "Asia/Beirut",
 | 
			
		||||
    "Asia/Bishkek",
 | 
			
		||||
    "Asia/Chita",
 | 
			
		||||
    "Asia/Colombo",
 | 
			
		||||
    "Asia/Damascus",
 | 
			
		||||
    "Asia/Dhaka",
 | 
			
		||||
    "Asia/Dili",
 | 
			
		||||
    "Asia/Dubai",
 | 
			
		||||
    "Asia/Dushanbe",
 | 
			
		||||
    "Asia/Famagusta",
 | 
			
		||||
    "Asia/Gaza",
 | 
			
		||||
    "Asia/Hebron",
 | 
			
		||||
    "Asia/Ho_Chi_Minh",
 | 
			
		||||
    "Asia/Hong_Kong",
 | 
			
		||||
    "Asia/Hovd",
 | 
			
		||||
    "Asia/Irkutsk",
 | 
			
		||||
    "Asia/Jakarta",
 | 
			
		||||
    "Asia/Jayapura",
 | 
			
		||||
    "Asia/Jerusalem",
 | 
			
		||||
    "Asia/Kabul",
 | 
			
		||||
    "Asia/Kamchatka",
 | 
			
		||||
    "Asia/Karachi",
 | 
			
		||||
    "Asia/Kathmandu",
 | 
			
		||||
    "Asia/Khandyga",
 | 
			
		||||
    "Asia/Kolkata",
 | 
			
		||||
    "Asia/Krasnoyarsk",
 | 
			
		||||
    "Asia/Kuching",
 | 
			
		||||
    "Asia/Macau",
 | 
			
		||||
    "Asia/Magadan",
 | 
			
		||||
    "Asia/Makassar",
 | 
			
		||||
    "Asia/Manila",
 | 
			
		||||
    "Asia/Nicosia",
 | 
			
		||||
    "Asia/Novokuznetsk",
 | 
			
		||||
    "Asia/Novosibirsk",
 | 
			
		||||
    "Asia/Omsk",
 | 
			
		||||
    "Asia/Oral",
 | 
			
		||||
    "Asia/Pontianak",
 | 
			
		||||
    "Asia/Pyongyang",
 | 
			
		||||
    "Asia/Qatar",
 | 
			
		||||
    "Asia/Qostanay",
 | 
			
		||||
    "Asia/Qyzylorda",
 | 
			
		||||
    "Asia/Riyadh",
 | 
			
		||||
    "Asia/Sakhalin",
 | 
			
		||||
    "Asia/Samarkand",
 | 
			
		||||
    "Asia/Seoul",
 | 
			
		||||
    "Asia/Shanghai",
 | 
			
		||||
    "Asia/Singapore",
 | 
			
		||||
    "Asia/Srednekolymsk",
 | 
			
		||||
    "Asia/Taipei",
 | 
			
		||||
    "Asia/Tashkent",
 | 
			
		||||
    "Asia/Tbilisi",
 | 
			
		||||
    "Asia/Tehran",
 | 
			
		||||
    "Asia/Thimphu",
 | 
			
		||||
    "Asia/Tokyo",
 | 
			
		||||
    "Asia/Tomsk",
 | 
			
		||||
    "Asia/Ulaanbaatar",
 | 
			
		||||
    "Asia/Urumqi",
 | 
			
		||||
    "Asia/Ust-Nera",
 | 
			
		||||
    "Asia/Vladivostok",
 | 
			
		||||
    "Asia/Yakutsk",
 | 
			
		||||
    "Asia/Yangon",
 | 
			
		||||
    "Asia/Yekaterinburg",
 | 
			
		||||
    "Asia/Yerevan",
 | 
			
		||||
    "Atlantic/Azores",
 | 
			
		||||
    "Atlantic/Bermuda",
 | 
			
		||||
    "Atlantic/Canary",
 | 
			
		||||
    "Atlantic/Cape_Verde",
 | 
			
		||||
    "Atlantic/Faroe",
 | 
			
		||||
    "Atlantic/Madeira",
 | 
			
		||||
    "Atlantic/South_Georgia",
 | 
			
		||||
    "Atlantic/Stanley",
 | 
			
		||||
    "Australia/Adelaide",
 | 
			
		||||
    "Australia/Brisbane",
 | 
			
		||||
    "Australia/Broken_Hill",
 | 
			
		||||
    "Australia/Darwin",
 | 
			
		||||
    "Australia/Eucla",
 | 
			
		||||
    "Australia/Hobart",
 | 
			
		||||
    "Australia/Lindeman",
 | 
			
		||||
    "Australia/Lord_Howe",
 | 
			
		||||
    "Australia/Melbourne",
 | 
			
		||||
    "Australia/Perth",
 | 
			
		||||
    "Australia/Sydney",
 | 
			
		||||
    "Etc/UTC",
 | 
			
		||||
    "Europe/Andorra",
 | 
			
		||||
    "Europe/Astrakhan",
 | 
			
		||||
    "Europe/Athens",
 | 
			
		||||
    "Europe/Belgrade",
 | 
			
		||||
    "Europe/Berlin",
 | 
			
		||||
    "Europe/Brussels",
 | 
			
		||||
    "Europe/Bucharest",
 | 
			
		||||
    "Europe/Budapest",
 | 
			
		||||
    "Europe/Chisinau",
 | 
			
		||||
    "Europe/Dublin",
 | 
			
		||||
    "Europe/Gibraltar",
 | 
			
		||||
    "Europe/Helsinki",
 | 
			
		||||
    "Europe/Istanbul",
 | 
			
		||||
    "Europe/Kaliningrad",
 | 
			
		||||
    "Europe/Kirov",
 | 
			
		||||
    "Europe/Kyiv",
 | 
			
		||||
    "Europe/Lisbon",
 | 
			
		||||
    "Europe/London",
 | 
			
		||||
    "Europe/Madrid",
 | 
			
		||||
    "Europe/Malta",
 | 
			
		||||
    "Europe/Minsk",
 | 
			
		||||
    "Europe/Moscow",
 | 
			
		||||
    "Europe/Paris",
 | 
			
		||||
    "Europe/Prague",
 | 
			
		||||
    "Europe/Riga",
 | 
			
		||||
    "Europe/Rome",
 | 
			
		||||
    "Europe/Samara",
 | 
			
		||||
    "Europe/Saratov",
 | 
			
		||||
    "Europe/Simferopol",
 | 
			
		||||
    "Europe/Sofia",
 | 
			
		||||
    "Europe/Tallinn",
 | 
			
		||||
    "Europe/Tirane",
 | 
			
		||||
    "Europe/Ulyanovsk",
 | 
			
		||||
    "Europe/Vienna",
 | 
			
		||||
    "Europe/Vilnius",
 | 
			
		||||
    "Europe/Volgograd",
 | 
			
		||||
    "Europe/Warsaw",
 | 
			
		||||
    "Europe/Zurich",
 | 
			
		||||
    "Factory",
 | 
			
		||||
    "Indian/Chagos",
 | 
			
		||||
    "Indian/Maldives",
 | 
			
		||||
    "Indian/Mauritius",
 | 
			
		||||
    "Pacific/Apia",
 | 
			
		||||
    "Pacific/Auckland",
 | 
			
		||||
    "Pacific/Bougainville",
 | 
			
		||||
    "Pacific/Chatham",
 | 
			
		||||
    "Pacific/Easter",
 | 
			
		||||
    "Pacific/Efate",
 | 
			
		||||
    "Pacific/Fakaofo",
 | 
			
		||||
    "Pacific/Fiji",
 | 
			
		||||
    "Pacific/Galapagos",
 | 
			
		||||
    "Pacific/Gambier",
 | 
			
		||||
    "Pacific/Guadalcanal",
 | 
			
		||||
    "Pacific/Guam",
 | 
			
		||||
    "Pacific/Honolulu",
 | 
			
		||||
    "Pacific/Kanton",
 | 
			
		||||
    "Pacific/Kiritimati",
 | 
			
		||||
    "Pacific/Kosrae",
 | 
			
		||||
    "Pacific/Kwajalein",
 | 
			
		||||
    "Pacific/Marquesas",
 | 
			
		||||
    "Pacific/Nauru",
 | 
			
		||||
    "Pacific/Niue",
 | 
			
		||||
    "Pacific/Norfolk",
 | 
			
		||||
    "Pacific/Noumea",
 | 
			
		||||
    "Pacific/Pago_Pago",
 | 
			
		||||
    "Pacific/Palau",
 | 
			
		||||
    "Pacific/Pitcairn",
 | 
			
		||||
    "Pacific/Port_Moresby",
 | 
			
		||||
    "Pacific/Rarotonga",
 | 
			
		||||
    "Pacific/Tahiti",
 | 
			
		||||
    "Pacific/Tarawa",
 | 
			
		||||
    "Pacific/Tongatapu"
 | 
			
		||||
]
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,28 @@
 | 
			
		|||
/* generated using openapi-typescript-codegen -- do not edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
import type { BaseHttpRequest } from './core/BaseHttpRequest';
 | 
			
		||||
import type { OpenAPIConfig } from './core/OpenAPI';
 | 
			
		||||
import { FetchHttpRequest } from './core/FetchHttpRequest';
 | 
			
		||||
import { DefaultService } from './services/DefaultService';
 | 
			
		||||
type HttpRequestConstructor = new (config: OpenAPIConfig) => BaseHttpRequest;
 | 
			
		||||
export class AvailabilitfClient {
 | 
			
		||||
    public readonly default: DefaultService;
 | 
			
		||||
    public readonly request: BaseHttpRequest;
 | 
			
		||||
    constructor(config?: Partial<OpenAPIConfig>, HttpRequest: HttpRequestConstructor = FetchHttpRequest) {
 | 
			
		||||
        this.request = new HttpRequest({
 | 
			
		||||
            BASE: config?.BASE ?? '',
 | 
			
		||||
            VERSION: config?.VERSION ?? '0.1.0',
 | 
			
		||||
            WITH_CREDENTIALS: config?.WITH_CREDENTIALS ?? false,
 | 
			
		||||
            CREDENTIALS: config?.CREDENTIALS ?? 'include',
 | 
			
		||||
            TOKEN: config?.TOKEN,
 | 
			
		||||
            USERNAME: config?.USERNAME,
 | 
			
		||||
            PASSWORD: config?.PASSWORD,
 | 
			
		||||
            HEADERS: config?.HEADERS,
 | 
			
		||||
            ENCODE_PATH: config?.ENCODE_PATH,
 | 
			
		||||
        });
 | 
			
		||||
        this.default = new DefaultService(this.request);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,25 @@
 | 
			
		|||
/* generated using openapi-typescript-codegen -- do not edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
import type { ApiRequestOptions } from './ApiRequestOptions';
 | 
			
		||||
import type { ApiResult } from './ApiResult';
 | 
			
		||||
 | 
			
		||||
export class ApiError extends Error {
 | 
			
		||||
    public readonly url: string;
 | 
			
		||||
    public readonly status: number;
 | 
			
		||||
    public readonly statusText: string;
 | 
			
		||||
    public readonly body: any;
 | 
			
		||||
    public readonly request: ApiRequestOptions;
 | 
			
		||||
 | 
			
		||||
    constructor(request: ApiRequestOptions, response: ApiResult, message: string) {
 | 
			
		||||
        super(message);
 | 
			
		||||
 | 
			
		||||
        this.name = 'ApiError';
 | 
			
		||||
        this.url = response.url;
 | 
			
		||||
        this.status = response.status;
 | 
			
		||||
        this.statusText = response.statusText;
 | 
			
		||||
        this.body = response.body;
 | 
			
		||||
        this.request = request;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,17 @@
 | 
			
		|||
/* generated using openapi-typescript-codegen -- do not edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
export type ApiRequestOptions = {
 | 
			
		||||
    readonly method: 'GET' | 'PUT' | 'POST' | 'DELETE' | 'OPTIONS' | 'HEAD' | 'PATCH';
 | 
			
		||||
    readonly url: string;
 | 
			
		||||
    readonly path?: Record<string, any>;
 | 
			
		||||
    readonly cookies?: Record<string, any>;
 | 
			
		||||
    readonly headers?: Record<string, any>;
 | 
			
		||||
    readonly query?: Record<string, any>;
 | 
			
		||||
    readonly formData?: Record<string, any>;
 | 
			
		||||
    readonly body?: any;
 | 
			
		||||
    readonly mediaType?: string;
 | 
			
		||||
    readonly responseHeader?: string;
 | 
			
		||||
    readonly errors?: Record<number, string>;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
/* generated using openapi-typescript-codegen -- do not edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
export type ApiResult = {
 | 
			
		||||
    readonly url: string;
 | 
			
		||||
    readonly ok: boolean;
 | 
			
		||||
    readonly status: number;
 | 
			
		||||
    readonly statusText: string;
 | 
			
		||||
    readonly body: any;
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,14 @@
 | 
			
		|||
/* generated using openapi-typescript-codegen -- do not edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
import type { ApiRequestOptions } from './ApiRequestOptions';
 | 
			
		||||
import type { CancelablePromise } from './CancelablePromise';
 | 
			
		||||
import type { OpenAPIConfig } from './OpenAPI';
 | 
			
		||||
 | 
			
		||||
export abstract class BaseHttpRequest {
 | 
			
		||||
 | 
			
		||||
    constructor(public readonly config: OpenAPIConfig) {}
 | 
			
		||||
 | 
			
		||||
    public abstract request<T>(options: ApiRequestOptions): CancelablePromise<T>;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,131 @@
 | 
			
		|||
/* generated using openapi-typescript-codegen -- do not edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
export class CancelError extends Error {
 | 
			
		||||
 | 
			
		||||
    constructor(message: string) {
 | 
			
		||||
        super(message);
 | 
			
		||||
        this.name = 'CancelError';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public get isCancelled(): boolean {
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface OnCancel {
 | 
			
		||||
    readonly isResolved: boolean;
 | 
			
		||||
    readonly isRejected: boolean;
 | 
			
		||||
    readonly isCancelled: boolean;
 | 
			
		||||
 | 
			
		||||
    (cancelHandler: () => void): void;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class CancelablePromise<T> implements Promise<T> {
 | 
			
		||||
    #isResolved: boolean;
 | 
			
		||||
    #isRejected: boolean;
 | 
			
		||||
    #isCancelled: boolean;
 | 
			
		||||
    readonly #cancelHandlers: (() => void)[];
 | 
			
		||||
    readonly #promise: Promise<T>;
 | 
			
		||||
    #resolve?: (value: T | PromiseLike<T>) => void;
 | 
			
		||||
    #reject?: (reason?: any) => void;
 | 
			
		||||
 | 
			
		||||
    constructor(
 | 
			
		||||
        executor: (
 | 
			
		||||
            resolve: (value: T | PromiseLike<T>) => void,
 | 
			
		||||
            reject: (reason?: any) => void,
 | 
			
		||||
            onCancel: OnCancel
 | 
			
		||||
        ) => void
 | 
			
		||||
    ) {
 | 
			
		||||
        this.#isResolved = false;
 | 
			
		||||
        this.#isRejected = false;
 | 
			
		||||
        this.#isCancelled = false;
 | 
			
		||||
        this.#cancelHandlers = [];
 | 
			
		||||
        this.#promise = new Promise<T>((resolve, reject) => {
 | 
			
		||||
            this.#resolve = resolve;
 | 
			
		||||
            this.#reject = reject;
 | 
			
		||||
 | 
			
		||||
            const onResolve = (value: T | PromiseLike<T>): void => {
 | 
			
		||||
                if (this.#isResolved || this.#isRejected || this.#isCancelled) {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                this.#isResolved = true;
 | 
			
		||||
                if (this.#resolve) this.#resolve(value);
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            const onReject = (reason?: any): void => {
 | 
			
		||||
                if (this.#isResolved || this.#isRejected || this.#isCancelled) {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                this.#isRejected = true;
 | 
			
		||||
                if (this.#reject) this.#reject(reason);
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            const onCancel = (cancelHandler: () => void): void => {
 | 
			
		||||
                if (this.#isResolved || this.#isRejected || this.#isCancelled) {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                this.#cancelHandlers.push(cancelHandler);
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            Object.defineProperty(onCancel, 'isResolved', {
 | 
			
		||||
                get: (): boolean => this.#isResolved,
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            Object.defineProperty(onCancel, 'isRejected', {
 | 
			
		||||
                get: (): boolean => this.#isRejected,
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            Object.defineProperty(onCancel, 'isCancelled', {
 | 
			
		||||
                get: (): boolean => this.#isCancelled,
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            return executor(onResolve, onReject, onCancel as OnCancel);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    get [Symbol.toStringTag]() {
 | 
			
		||||
        return "Cancellable Promise";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public then<TResult1 = T, TResult2 = never>(
 | 
			
		||||
        onFulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | null,
 | 
			
		||||
        onRejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null
 | 
			
		||||
    ): Promise<TResult1 | TResult2> {
 | 
			
		||||
        return this.#promise.then(onFulfilled, onRejected);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public catch<TResult = never>(
 | 
			
		||||
        onRejected?: ((reason: any) => TResult | PromiseLike<TResult>) | null
 | 
			
		||||
    ): Promise<T | TResult> {
 | 
			
		||||
        return this.#promise.catch(onRejected);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public finally(onFinally?: (() => void) | null): Promise<T> {
 | 
			
		||||
        return this.#promise.finally(onFinally);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public cancel(): void {
 | 
			
		||||
        if (this.#isResolved || this.#isRejected || this.#isCancelled) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        this.#isCancelled = true;
 | 
			
		||||
        if (this.#cancelHandlers.length) {
 | 
			
		||||
            try {
 | 
			
		||||
                for (const cancelHandler of this.#cancelHandlers) {
 | 
			
		||||
                    cancelHandler();
 | 
			
		||||
                }
 | 
			
		||||
            } catch (error) {
 | 
			
		||||
                console.warn('Cancellation threw an error', error);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        this.#cancelHandlers.length = 0;
 | 
			
		||||
        if (this.#reject) this.#reject(new CancelError('Request aborted'));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public get isCancelled(): boolean {
 | 
			
		||||
        return this.#isCancelled;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,26 @@
 | 
			
		|||
/* generated using openapi-typescript-codegen -- do not edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
import type { ApiRequestOptions } from './ApiRequestOptions';
 | 
			
		||||
import { BaseHttpRequest } from './BaseHttpRequest';
 | 
			
		||||
import type { CancelablePromise } from './CancelablePromise';
 | 
			
		||||
import type { OpenAPIConfig } from './OpenAPI';
 | 
			
		||||
import { request as __request } from './request';
 | 
			
		||||
 | 
			
		||||
export class FetchHttpRequest extends BaseHttpRequest {
 | 
			
		||||
 | 
			
		||||
    constructor(config: OpenAPIConfig) {
 | 
			
		||||
        super(config);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Request method
 | 
			
		||||
     * @param options The request options from the service
 | 
			
		||||
     * @returns CancelablePromise<T>
 | 
			
		||||
     * @throws ApiError
 | 
			
		||||
     */
 | 
			
		||||
    public override request<T>(options: ApiRequestOptions): CancelablePromise<T> {
 | 
			
		||||
        return __request(this.config, options);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,32 @@
 | 
			
		|||
/* generated using openapi-typescript-codegen -- do not edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
import type { ApiRequestOptions } from './ApiRequestOptions';
 | 
			
		||||
 | 
			
		||||
type Resolver<T> = (options: ApiRequestOptions) => Promise<T>;
 | 
			
		||||
type Headers = Record<string, string>;
 | 
			
		||||
 | 
			
		||||
export type OpenAPIConfig = {
 | 
			
		||||
    BASE: string;
 | 
			
		||||
    VERSION: string;
 | 
			
		||||
    WITH_CREDENTIALS: boolean;
 | 
			
		||||
    CREDENTIALS: 'include' | 'omit' | 'same-origin';
 | 
			
		||||
    TOKEN?: string | Resolver<string> | undefined;
 | 
			
		||||
    USERNAME?: string | Resolver<string> | undefined;
 | 
			
		||||
    PASSWORD?: string | Resolver<string> | undefined;
 | 
			
		||||
    HEADERS?: Headers | Resolver<Headers> | undefined;
 | 
			
		||||
    ENCODE_PATH?: ((path: string) => string) | undefined;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const OpenAPI: OpenAPIConfig = {
 | 
			
		||||
    BASE: '',
 | 
			
		||||
    VERSION: '0.1.0',
 | 
			
		||||
    WITH_CREDENTIALS: false,
 | 
			
		||||
    CREDENTIALS: 'include',
 | 
			
		||||
    TOKEN: undefined,
 | 
			
		||||
    USERNAME: undefined,
 | 
			
		||||
    PASSWORD: undefined,
 | 
			
		||||
    HEADERS: undefined,
 | 
			
		||||
    ENCODE_PATH: undefined,
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,322 @@
 | 
			
		|||
/* generated using openapi-typescript-codegen -- do not edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
import { ApiError } from './ApiError';
 | 
			
		||||
import type { ApiRequestOptions } from './ApiRequestOptions';
 | 
			
		||||
import type { ApiResult } from './ApiResult';
 | 
			
		||||
import { CancelablePromise } from './CancelablePromise';
 | 
			
		||||
import type { OnCancel } from './CancelablePromise';
 | 
			
		||||
import type { OpenAPIConfig } from './OpenAPI';
 | 
			
		||||
 | 
			
		||||
export const isDefined = <T>(value: T | null | undefined): value is Exclude<T, null | undefined> => {
 | 
			
		||||
    return value !== undefined && value !== null;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const isString = (value: any): value is string => {
 | 
			
		||||
    return typeof value === 'string';
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const isStringWithValue = (value: any): value is string => {
 | 
			
		||||
    return isString(value) && value !== '';
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const isBlob = (value: any): value is Blob => {
 | 
			
		||||
    return (
 | 
			
		||||
        typeof value === 'object' &&
 | 
			
		||||
        typeof value.type === 'string' &&
 | 
			
		||||
        typeof value.stream === 'function' &&
 | 
			
		||||
        typeof value.arrayBuffer === 'function' &&
 | 
			
		||||
        typeof value.constructor === 'function' &&
 | 
			
		||||
        typeof value.constructor.name === 'string' &&
 | 
			
		||||
        /^(Blob|File)$/.test(value.constructor.name) &&
 | 
			
		||||
        /^(Blob|File)$/.test(value[Symbol.toStringTag])
 | 
			
		||||
    );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const isFormData = (value: any): value is FormData => {
 | 
			
		||||
    return value instanceof FormData;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const base64 = (str: string): string => {
 | 
			
		||||
    try {
 | 
			
		||||
        return btoa(str);
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
        // @ts-ignore
 | 
			
		||||
        return Buffer.from(str).toString('base64');
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const getQueryString = (params: Record<string, any>): string => {
 | 
			
		||||
    const qs: string[] = [];
 | 
			
		||||
 | 
			
		||||
    const append = (key: string, value: any) => {
 | 
			
		||||
        qs.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const process = (key: string, value: any) => {
 | 
			
		||||
        if (isDefined(value)) {
 | 
			
		||||
            if (Array.isArray(value)) {
 | 
			
		||||
                value.forEach(v => {
 | 
			
		||||
                    process(key, v);
 | 
			
		||||
                });
 | 
			
		||||
            } else if (typeof value === 'object') {
 | 
			
		||||
                Object.entries(value).forEach(([k, v]) => {
 | 
			
		||||
                    process(`${key}[${k}]`, v);
 | 
			
		||||
                });
 | 
			
		||||
            } else {
 | 
			
		||||
                append(key, value);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    Object.entries(params).forEach(([key, value]) => {
 | 
			
		||||
        process(key, value);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    if (qs.length > 0) {
 | 
			
		||||
        return `?${qs.join('&')}`;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return '';
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const getUrl = (config: OpenAPIConfig, options: ApiRequestOptions): string => {
 | 
			
		||||
    const encoder = config.ENCODE_PATH || encodeURI;
 | 
			
		||||
 | 
			
		||||
    const path = options.url
 | 
			
		||||
        .replace('{api-version}', config.VERSION)
 | 
			
		||||
        .replace(/{(.*?)}/g, (substring: string, group: string) => {
 | 
			
		||||
            if (options.path?.hasOwnProperty(group)) {
 | 
			
		||||
                return encoder(String(options.path[group]));
 | 
			
		||||
            }
 | 
			
		||||
            return substring;
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
    const url = `${config.BASE}${path}`;
 | 
			
		||||
    if (options.query) {
 | 
			
		||||
        return `${url}${getQueryString(options.query)}`;
 | 
			
		||||
    }
 | 
			
		||||
    return url;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const getFormData = (options: ApiRequestOptions): FormData | undefined => {
 | 
			
		||||
    if (options.formData) {
 | 
			
		||||
        const formData = new FormData();
 | 
			
		||||
 | 
			
		||||
        const process = (key: string, value: any) => {
 | 
			
		||||
            if (isString(value) || isBlob(value)) {
 | 
			
		||||
                formData.append(key, value);
 | 
			
		||||
            } else {
 | 
			
		||||
                formData.append(key, JSON.stringify(value));
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        Object.entries(options.formData)
 | 
			
		||||
            .filter(([_, value]) => isDefined(value))
 | 
			
		||||
            .forEach(([key, value]) => {
 | 
			
		||||
                if (Array.isArray(value)) {
 | 
			
		||||
                    value.forEach(v => process(key, v));
 | 
			
		||||
                } else {
 | 
			
		||||
                    process(key, value);
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        return formData;
 | 
			
		||||
    }
 | 
			
		||||
    return undefined;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
type Resolver<T> = (options: ApiRequestOptions) => Promise<T>;
 | 
			
		||||
 | 
			
		||||
export const resolve = async <T>(options: ApiRequestOptions, resolver?: T | Resolver<T>): Promise<T | undefined> => {
 | 
			
		||||
    if (typeof resolver === 'function') {
 | 
			
		||||
        return (resolver as Resolver<T>)(options);
 | 
			
		||||
    }
 | 
			
		||||
    return resolver;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const getHeaders = async (config: OpenAPIConfig, options: ApiRequestOptions): Promise<Headers> => {
 | 
			
		||||
    const [token, username, password, additionalHeaders] = await Promise.all([
 | 
			
		||||
        resolve(options, config.TOKEN),
 | 
			
		||||
        resolve(options, config.USERNAME),
 | 
			
		||||
        resolve(options, config.PASSWORD),
 | 
			
		||||
        resolve(options, config.HEADERS),
 | 
			
		||||
    ]);
 | 
			
		||||
 | 
			
		||||
    const headers = Object.entries({
 | 
			
		||||
        Accept: 'application/json',
 | 
			
		||||
        ...additionalHeaders,
 | 
			
		||||
        ...options.headers,
 | 
			
		||||
    })
 | 
			
		||||
        .filter(([_, value]) => isDefined(value))
 | 
			
		||||
        .reduce((headers, [key, value]) => ({
 | 
			
		||||
            ...headers,
 | 
			
		||||
            [key]: String(value),
 | 
			
		||||
        }), {} as Record<string, string>);
 | 
			
		||||
 | 
			
		||||
    if (isStringWithValue(token)) {
 | 
			
		||||
        headers['Authorization'] = `Bearer ${token}`;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (isStringWithValue(username) && isStringWithValue(password)) {
 | 
			
		||||
        const credentials = base64(`${username}:${password}`);
 | 
			
		||||
        headers['Authorization'] = `Basic ${credentials}`;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (options.body !== undefined) {
 | 
			
		||||
        if (options.mediaType) {
 | 
			
		||||
            headers['Content-Type'] = options.mediaType;
 | 
			
		||||
        } else if (isBlob(options.body)) {
 | 
			
		||||
            headers['Content-Type'] = options.body.type || 'application/octet-stream';
 | 
			
		||||
        } else if (isString(options.body)) {
 | 
			
		||||
            headers['Content-Type'] = 'text/plain';
 | 
			
		||||
        } else if (!isFormData(options.body)) {
 | 
			
		||||
            headers['Content-Type'] = 'application/json';
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return new Headers(headers);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const getRequestBody = (options: ApiRequestOptions): any => {
 | 
			
		||||
    if (options.body !== undefined) {
 | 
			
		||||
        if (options.mediaType?.includes('/json')) {
 | 
			
		||||
            return JSON.stringify(options.body)
 | 
			
		||||
        } else if (isString(options.body) || isBlob(options.body) || isFormData(options.body)) {
 | 
			
		||||
            return options.body;
 | 
			
		||||
        } else {
 | 
			
		||||
            return JSON.stringify(options.body);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return undefined;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const sendRequest = async (
 | 
			
		||||
    config: OpenAPIConfig,
 | 
			
		||||
    options: ApiRequestOptions,
 | 
			
		||||
    url: string,
 | 
			
		||||
    body: any,
 | 
			
		||||
    formData: FormData | undefined,
 | 
			
		||||
    headers: Headers,
 | 
			
		||||
    onCancel: OnCancel
 | 
			
		||||
): Promise<Response> => {
 | 
			
		||||
    const controller = new AbortController();
 | 
			
		||||
 | 
			
		||||
    const request: RequestInit = {
 | 
			
		||||
        headers,
 | 
			
		||||
        body: body ?? formData,
 | 
			
		||||
        method: options.method,
 | 
			
		||||
        signal: controller.signal,
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    if (config.WITH_CREDENTIALS) {
 | 
			
		||||
        request.credentials = config.CREDENTIALS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    onCancel(() => controller.abort());
 | 
			
		||||
 | 
			
		||||
    return await fetch(url, request);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const getResponseHeader = (response: Response, responseHeader?: string): string | undefined => {
 | 
			
		||||
    if (responseHeader) {
 | 
			
		||||
        const content = response.headers.get(responseHeader);
 | 
			
		||||
        if (isString(content)) {
 | 
			
		||||
            return content;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return undefined;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const getResponseBody = async (response: Response): Promise<any> => {
 | 
			
		||||
    if (response.status !== 204) {
 | 
			
		||||
        try {
 | 
			
		||||
            const contentType = response.headers.get('Content-Type');
 | 
			
		||||
            if (contentType) {
 | 
			
		||||
                const jsonTypes = ['application/json', 'application/problem+json']
 | 
			
		||||
                const isJSON = jsonTypes.some(type => contentType.toLowerCase().startsWith(type));
 | 
			
		||||
                if (isJSON) {
 | 
			
		||||
                    return await response.json();
 | 
			
		||||
                } else {
 | 
			
		||||
                    return await response.text();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            console.error(error);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return undefined;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const catchErrorCodes = (options: ApiRequestOptions, result: ApiResult): void => {
 | 
			
		||||
    const errors: Record<number, string> = {
 | 
			
		||||
        400: 'Bad Request',
 | 
			
		||||
        401: 'Unauthorized',
 | 
			
		||||
        403: 'Forbidden',
 | 
			
		||||
        404: 'Not Found',
 | 
			
		||||
        500: 'Internal Server Error',
 | 
			
		||||
        502: 'Bad Gateway',
 | 
			
		||||
        503: 'Service Unavailable',
 | 
			
		||||
        ...options.errors,
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const error = errors[result.status];
 | 
			
		||||
    if (error) {
 | 
			
		||||
        throw new ApiError(options, result, error);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!result.ok) {
 | 
			
		||||
        const errorStatus = result.status ?? 'unknown';
 | 
			
		||||
        const errorStatusText = result.statusText ?? 'unknown';
 | 
			
		||||
        const errorBody = (() => {
 | 
			
		||||
            try {
 | 
			
		||||
                return JSON.stringify(result.body, null, 2);
 | 
			
		||||
            } catch (e) {
 | 
			
		||||
                return undefined;
 | 
			
		||||
            }
 | 
			
		||||
        })();
 | 
			
		||||
 | 
			
		||||
        throw new ApiError(options, result,
 | 
			
		||||
            `Generic Error: status: ${errorStatus}; status text: ${errorStatusText}; body: ${errorBody}`
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Request method
 | 
			
		||||
 * @param config The OpenAPI configuration object
 | 
			
		||||
 * @param options The request options from the service
 | 
			
		||||
 * @returns CancelablePromise<T>
 | 
			
		||||
 * @throws ApiError
 | 
			
		||||
 */
 | 
			
		||||
export const request = <T>(config: OpenAPIConfig, options: ApiRequestOptions): CancelablePromise<T> => {
 | 
			
		||||
    return new CancelablePromise(async (resolve, reject, onCancel) => {
 | 
			
		||||
        try {
 | 
			
		||||
            const url = getUrl(config, options);
 | 
			
		||||
            const formData = getFormData(options);
 | 
			
		||||
            const body = getRequestBody(options);
 | 
			
		||||
            const headers = await getHeaders(config, options);
 | 
			
		||||
 | 
			
		||||
            if (!onCancel.isCancelled) {
 | 
			
		||||
                const response = await sendRequest(config, options, url, body, formData, headers, onCancel);
 | 
			
		||||
                const responseBody = await getResponseBody(response);
 | 
			
		||||
                const responseHeader = getResponseHeader(response, options.responseHeader);
 | 
			
		||||
 | 
			
		||||
                const result: ApiResult = {
 | 
			
		||||
                    url,
 | 
			
		||||
                    ok: response.ok,
 | 
			
		||||
                    status: response.status,
 | 
			
		||||
                    statusText: response.statusText,
 | 
			
		||||
                    body: responseHeader ?? responseBody,
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                catchErrorCodes(options, result);
 | 
			
		||||
 | 
			
		||||
                resolve(result.body);
 | 
			
		||||
            }
 | 
			
		||||
        } catch (error) {
 | 
			
		||||
            reject(error);
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,29 @@
 | 
			
		|||
/* generated using openapi-typescript-codegen -- do not edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
export { AvailabilitfClient } from './AvailabilitfClient';
 | 
			
		||||
 | 
			
		||||
export { ApiError } from './core/ApiError';
 | 
			
		||||
export { BaseHttpRequest } from './core/BaseHttpRequest';
 | 
			
		||||
export { CancelablePromise, CancelError } from './core/CancelablePromise';
 | 
			
		||||
export { OpenAPI } from './core/OpenAPI';
 | 
			
		||||
export type { OpenAPIConfig } from './core/OpenAPI';
 | 
			
		||||
 | 
			
		||||
export type { AddPlayerJson } from './models/AddPlayerJson';
 | 
			
		||||
export type { CreateTeamJson } from './models/CreateTeamJson';
 | 
			
		||||
export type { PutScheduleForm } from './models/PutScheduleForm';
 | 
			
		||||
export type { RoleSchema } from './models/RoleSchema';
 | 
			
		||||
export { TeamRole } from './models/TeamRole';
 | 
			
		||||
export type { TeamSchema } from './models/TeamSchema';
 | 
			
		||||
export type { ValidationError } from './models/ValidationError';
 | 
			
		||||
export type { ValidationErrorElement } from './models/ValidationErrorElement';
 | 
			
		||||
export type { ViewAvailablePlayersForm } from './models/ViewAvailablePlayersForm';
 | 
			
		||||
export type { ViewScheduleForm } from './models/ViewScheduleForm';
 | 
			
		||||
export type { ViewScheduleResponse } from './models/ViewScheduleResponse';
 | 
			
		||||
export type { ViewTeamMembersResponse } from './models/ViewTeamMembersResponse';
 | 
			
		||||
export type { ViewTeamMembersResponseList } from './models/ViewTeamMembersResponseList';
 | 
			
		||||
export type { ViewTeamResponse } from './models/ViewTeamResponse';
 | 
			
		||||
export type { ViewTeamsResponse } from './models/ViewTeamsResponse';
 | 
			
		||||
 | 
			
		||||
export { DefaultService } from './services/DefaultService';
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,10 @@
 | 
			
		|||
/* generated using openapi-typescript-codegen -- do not edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
import type { TeamRole } from './TeamRole';
 | 
			
		||||
export type AddPlayerJson = {
 | 
			
		||||
    isTeamLeader?: boolean;
 | 
			
		||||
    teamRole?: TeamRole;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,10 @@
 | 
			
		|||
/* generated using openapi-typescript-codegen -- do not edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
export type CreateTeamJson = {
 | 
			
		||||
    discordWebhookUrl?: string;
 | 
			
		||||
    leagueTimezone: string;
 | 
			
		||||
    teamName: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
/* generated using openapi-typescript-codegen -- do not edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
export type PutScheduleForm = {
 | 
			
		||||
    availability: Array<number>;
 | 
			
		||||
    teamId: number;
 | 
			
		||||
    windowSizeDays?: number;
 | 
			
		||||
    windowStart: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,9 @@
 | 
			
		|||
/* generated using openapi-typescript-codegen -- do not edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
export type RoleSchema = {
 | 
			
		||||
    isMain: boolean;
 | 
			
		||||
    role: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
/* generated using openapi-typescript-codegen -- do not edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
/**
 | 
			
		||||
 * An enumeration.
 | 
			
		||||
 */
 | 
			
		||||
export enum TeamRole {
 | 
			
		||||
    '_0' = 0,
 | 
			
		||||
    '_1' = 1,
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,10 @@
 | 
			
		|||
/* generated using openapi-typescript-codegen -- do not edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
export type TeamSchema = {
 | 
			
		||||
    discordWebhookUrl?: string;
 | 
			
		||||
    id: number;
 | 
			
		||||
    teamName: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,9 @@
 | 
			
		|||
/* generated using openapi-typescript-codegen -- do not edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
import type { ValidationErrorElement } from './ValidationErrorElement';
 | 
			
		||||
/**
 | 
			
		||||
 * Model of a validation error response.
 | 
			
		||||
 */
 | 
			
		||||
export type ValidationError = Array<ValidationErrorElement>;
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,14 @@
 | 
			
		|||
/* generated using openapi-typescript-codegen -- do not edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
/**
 | 
			
		||||
 * Model of a validation error response element.
 | 
			
		||||
 */
 | 
			
		||||
export type ValidationErrorElement = {
 | 
			
		||||
    ctx?: Record<string, any>;
 | 
			
		||||
    loc: Array<string>;
 | 
			
		||||
    msg: string;
 | 
			
		||||
    type: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,9 @@
 | 
			
		|||
/* generated using openapi-typescript-codegen -- do not edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
export type ViewAvailablePlayersForm = {
 | 
			
		||||
    startTime: string;
 | 
			
		||||
    teamId: number;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,10 @@
 | 
			
		|||
/* generated using openapi-typescript-codegen -- do not edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
export type ViewScheduleForm = {
 | 
			
		||||
    teamId: number;
 | 
			
		||||
    windowSizeDays?: number;
 | 
			
		||||
    windowStart: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,8 @@
 | 
			
		|||
/* generated using openapi-typescript-codegen -- do not edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
export type ViewScheduleResponse = {
 | 
			
		||||
    availability: Array<number>;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
/* generated using openapi-typescript-codegen -- do not edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
import type { RoleSchema } from './RoleSchema';
 | 
			
		||||
export type ViewTeamMembersResponse = {
 | 
			
		||||
    roles: Array<RoleSchema>;
 | 
			
		||||
    steamId: string;
 | 
			
		||||
    username: string;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,6 @@
 | 
			
		|||
/* generated using openapi-typescript-codegen -- do not edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
import type { ViewTeamMembersResponse } from './ViewTeamMembersResponse';
 | 
			
		||||
export type ViewTeamMembersResponseList = Array<ViewTeamMembersResponse>;
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,9 @@
 | 
			
		|||
/* generated using openapi-typescript-codegen -- do not edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
import type { TeamSchema } from './TeamSchema';
 | 
			
		||||
export type ViewTeamResponse = {
 | 
			
		||||
    team: TeamSchema;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,9 @@
 | 
			
		|||
/* generated using openapi-typescript-codegen -- do not edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
import type { TeamSchema } from './TeamSchema';
 | 
			
		||||
export type ViewTeamsResponse = {
 | 
			
		||||
    teams: Array<TeamSchema>;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,264 @@
 | 
			
		|||
/* generated using openapi-typescript-codegen -- do not edit */
 | 
			
		||||
/* istanbul ignore file */
 | 
			
		||||
/* tslint:disable */
 | 
			
		||||
/* eslint-disable */
 | 
			
		||||
import type { AddPlayerJson } from '../models/AddPlayerJson';
 | 
			
		||||
import type { CreateTeamJson } from '../models/CreateTeamJson';
 | 
			
		||||
import type { PutScheduleForm } from '../models/PutScheduleForm';
 | 
			
		||||
import type { ViewScheduleResponse } from '../models/ViewScheduleResponse';
 | 
			
		||||
import type { ViewTeamMembersResponseList } from '../models/ViewTeamMembersResponseList';
 | 
			
		||||
import type { ViewTeamResponse } from '../models/ViewTeamResponse';
 | 
			
		||||
import type { ViewTeamsResponse } from '../models/ViewTeamsResponse';
 | 
			
		||||
import type { CancelablePromise } from '../core/CancelablePromise';
 | 
			
		||||
import type { BaseHttpRequest } from '../core/BaseHttpRequest';
 | 
			
		||||
export class DefaultService {
 | 
			
		||||
    constructor(public readonly httpRequest: BaseHttpRequest) {}
 | 
			
		||||
    /**
 | 
			
		||||
     * debug_set_cookie <GET>
 | 
			
		||||
     * @returns void
 | 
			
		||||
     * @throws ApiError
 | 
			
		||||
     */
 | 
			
		||||
    public getApiDebugSetCookie(): CancelablePromise<void> {
 | 
			
		||||
        return this.httpRequest.request({
 | 
			
		||||
            method: 'GET',
 | 
			
		||||
            url: '/api/debug/set-cookie',
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * debug_set_cookie <POST>
 | 
			
		||||
     * @returns void
 | 
			
		||||
     * @throws ApiError
 | 
			
		||||
     */
 | 
			
		||||
    public postApiDebugSetCookie(): CancelablePromise<void> {
 | 
			
		||||
        return this.httpRequest.request({
 | 
			
		||||
            method: 'POST',
 | 
			
		||||
            url: '/api/debug/set-cookie',
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * logout <DELETE>
 | 
			
		||||
     * @returns void
 | 
			
		||||
     * @throws ApiError
 | 
			
		||||
     */
 | 
			
		||||
    public deleteApiLogin(): CancelablePromise<void> {
 | 
			
		||||
        return this.httpRequest.request({
 | 
			
		||||
            method: 'DELETE',
 | 
			
		||||
            url: '/api/login/',
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * index <GET>
 | 
			
		||||
     * @returns void
 | 
			
		||||
     * @throws ApiError
 | 
			
		||||
     */
 | 
			
		||||
    public getApiLogin(): CancelablePromise<void> {
 | 
			
		||||
        return this.httpRequest.request({
 | 
			
		||||
            method: 'GET',
 | 
			
		||||
            url: '/api/login/',
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * steam_authenticate <POST>
 | 
			
		||||
     * @returns void
 | 
			
		||||
     * @throws ApiError
 | 
			
		||||
     */
 | 
			
		||||
    public postApiLoginAuthenticate(): CancelablePromise<void> {
 | 
			
		||||
        return this.httpRequest.request({
 | 
			
		||||
            method: 'POST',
 | 
			
		||||
            url: '/api/login/authenticate',
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * get <GET>
 | 
			
		||||
     * @param windowStart
 | 
			
		||||
     * @param teamId
 | 
			
		||||
     * @param windowSizeDays
 | 
			
		||||
     * @returns ViewScheduleResponse OK
 | 
			
		||||
     * @throws ApiError
 | 
			
		||||
     */
 | 
			
		||||
    public getApiSchedule(
 | 
			
		||||
        windowStart: string,
 | 
			
		||||
        teamId: number,
 | 
			
		||||
        windowSizeDays: number = 7,
 | 
			
		||||
    ): CancelablePromise<ViewScheduleResponse> {
 | 
			
		||||
        return this.httpRequest.request({
 | 
			
		||||
            method: 'GET',
 | 
			
		||||
            url: '/api/schedule/',
 | 
			
		||||
            query: {
 | 
			
		||||
                'windowStart': windowStart,
 | 
			
		||||
                'teamId': teamId,
 | 
			
		||||
                'windowSizeDays': windowSizeDays,
 | 
			
		||||
            },
 | 
			
		||||
            errors: {
 | 
			
		||||
                422: `Unprocessable Entity`,
 | 
			
		||||
            },
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * put <PUT>
 | 
			
		||||
     * @param requestBody
 | 
			
		||||
     * @returns void
 | 
			
		||||
     * @throws ApiError
 | 
			
		||||
     */
 | 
			
		||||
    public putApiSchedule(
 | 
			
		||||
        requestBody?: PutScheduleForm,
 | 
			
		||||
    ): CancelablePromise<void> {
 | 
			
		||||
        return this.httpRequest.request({
 | 
			
		||||
            method: 'PUT',
 | 
			
		||||
            url: '/api/schedule/',
 | 
			
		||||
            body: requestBody,
 | 
			
		||||
            mediaType: 'application/json',
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * view_available <GET>
 | 
			
		||||
     * @param startTime
 | 
			
		||||
     * @param teamId
 | 
			
		||||
     * @returns void
 | 
			
		||||
     * @throws ApiError
 | 
			
		||||
     */
 | 
			
		||||
    public getApiScheduleViewAvailable(
 | 
			
		||||
        startTime: string,
 | 
			
		||||
        teamId: number,
 | 
			
		||||
    ): CancelablePromise<void> {
 | 
			
		||||
        return this.httpRequest.request({
 | 
			
		||||
            method: 'GET',
 | 
			
		||||
            url: '/api/schedule/view-available',
 | 
			
		||||
            query: {
 | 
			
		||||
                'startTime': startTime,
 | 
			
		||||
                'teamId': teamId,
 | 
			
		||||
            },
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * create_team <POST>
 | 
			
		||||
     * @param requestBody
 | 
			
		||||
     * @returns ViewTeamResponse OK
 | 
			
		||||
     * @throws ApiError
 | 
			
		||||
     */
 | 
			
		||||
    public createTeam(
 | 
			
		||||
        requestBody?: CreateTeamJson,
 | 
			
		||||
    ): CancelablePromise<ViewTeamResponse> {
 | 
			
		||||
        return this.httpRequest.request({
 | 
			
		||||
            method: 'POST',
 | 
			
		||||
            url: '/api/team/',
 | 
			
		||||
            body: requestBody,
 | 
			
		||||
            mediaType: 'application/json',
 | 
			
		||||
            errors: {
 | 
			
		||||
                403: `Forbidden`,
 | 
			
		||||
                422: `Unprocessable Entity`,
 | 
			
		||||
            },
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * view_teams <GET>
 | 
			
		||||
     * @returns ViewTeamsResponse OK
 | 
			
		||||
     * @throws ApiError
 | 
			
		||||
     */
 | 
			
		||||
    public getTeams(): CancelablePromise<ViewTeamsResponse> {
 | 
			
		||||
        return this.httpRequest.request({
 | 
			
		||||
            method: 'GET',
 | 
			
		||||
            url: '/api/team/all/',
 | 
			
		||||
            errors: {
 | 
			
		||||
                403: `Forbidden`,
 | 
			
		||||
                404: `Not Found`,
 | 
			
		||||
                422: `Unprocessable Entity`,
 | 
			
		||||
            },
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * delete_team <DELETE>
 | 
			
		||||
     * @param teamId
 | 
			
		||||
     * @returns any OK
 | 
			
		||||
     * @throws ApiError
 | 
			
		||||
     */
 | 
			
		||||
    public deleteTeam(
 | 
			
		||||
        teamId: string,
 | 
			
		||||
    ): CancelablePromise<any> {
 | 
			
		||||
        return this.httpRequest.request({
 | 
			
		||||
            method: 'DELETE',
 | 
			
		||||
            url: '/api/team/id/{team_id}/',
 | 
			
		||||
            path: {
 | 
			
		||||
                'team_id': teamId,
 | 
			
		||||
            },
 | 
			
		||||
            errors: {
 | 
			
		||||
                403: `Forbidden`,
 | 
			
		||||
                404: `Not Found`,
 | 
			
		||||
                422: `Unprocessable Entity`,
 | 
			
		||||
            },
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * view_team <GET>
 | 
			
		||||
     * @param teamId
 | 
			
		||||
     * @returns ViewTeamResponse OK
 | 
			
		||||
     * @throws ApiError
 | 
			
		||||
     */
 | 
			
		||||
    public getTeam(
 | 
			
		||||
        teamId: string,
 | 
			
		||||
    ): CancelablePromise<ViewTeamResponse> {
 | 
			
		||||
        return this.httpRequest.request({
 | 
			
		||||
            method: 'GET',
 | 
			
		||||
            url: '/api/team/id/{team_id}/',
 | 
			
		||||
            path: {
 | 
			
		||||
                'team_id': teamId,
 | 
			
		||||
            },
 | 
			
		||||
            errors: {
 | 
			
		||||
                403: `Forbidden`,
 | 
			
		||||
                404: `Not Found`,
 | 
			
		||||
                422: `Unprocessable Entity`,
 | 
			
		||||
            },
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * add_player <PUT>
 | 
			
		||||
     * @param teamId
 | 
			
		||||
     * @param playerId
 | 
			
		||||
     * @param requestBody
 | 
			
		||||
     * @returns any OK
 | 
			
		||||
     * @throws ApiError
 | 
			
		||||
     */
 | 
			
		||||
    public createOrUpdatePlayer(
 | 
			
		||||
        teamId: string,
 | 
			
		||||
        playerId: string,
 | 
			
		||||
        requestBody?: AddPlayerJson,
 | 
			
		||||
    ): CancelablePromise<any> {
 | 
			
		||||
        return this.httpRequest.request({
 | 
			
		||||
            method: 'PUT',
 | 
			
		||||
            url: '/api/team/id/{team_id}/player/{player_id}/',
 | 
			
		||||
            path: {
 | 
			
		||||
                'team_id': teamId,
 | 
			
		||||
                'player_id': playerId,
 | 
			
		||||
            },
 | 
			
		||||
            body: requestBody,
 | 
			
		||||
            mediaType: 'application/json',
 | 
			
		||||
            errors: {
 | 
			
		||||
                403: `Forbidden`,
 | 
			
		||||
                404: `Not Found`,
 | 
			
		||||
                422: `Unprocessable Entity`,
 | 
			
		||||
            },
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    /**
 | 
			
		||||
     * view_team_members <GET>
 | 
			
		||||
     * @param teamId
 | 
			
		||||
     * @returns ViewTeamMembersResponseList OK
 | 
			
		||||
     * @throws ApiError
 | 
			
		||||
     */
 | 
			
		||||
    public getTeamMembers(
 | 
			
		||||
        teamId: string,
 | 
			
		||||
    ): CancelablePromise<ViewTeamMembersResponseList> {
 | 
			
		||||
        return this.httpRequest.request({
 | 
			
		||||
            method: 'GET',
 | 
			
		||||
            url: '/api/team/id/{team_id}/players',
 | 
			
		||||
            path: {
 | 
			
		||||
                'team_id': teamId,
 | 
			
		||||
            },
 | 
			
		||||
            errors: {
 | 
			
		||||
                403: `Forbidden`,
 | 
			
		||||
                404: `Not Found`,
 | 
			
		||||
                422: `Unprocessable Entity`,
 | 
			
		||||
            },
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -5,6 +5,7 @@ const model = defineModel();
 | 
			
		|||
 | 
			
		||||
const props = defineProps({
 | 
			
		||||
  options: Array<String>,
 | 
			
		||||
  isDisabled: Boolean,
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const isOpen = ref(false);
 | 
			
		||||
| 
						 | 
				
			
			@ -18,15 +19,15 @@ function selectOption(index) {
 | 
			
		|||
 | 
			
		||||
<template>
 | 
			
		||||
  <div :class="{ 'dropdown-container': true, 'is-open': isOpen }">
 | 
			
		||||
    <button @click="isOpen = !isOpen">
 | 
			
		||||
    <button @click="isOpen = !isOpen" :disabled="isDisabled">
 | 
			
		||||
      {{ selectedOption }}
 | 
			
		||||
      <i class="bi bi-caret-down-fill"></i>
 | 
			
		||||
    </button>
 | 
			
		||||
    <ul class="dropdown" v-if="isOpen" @blur="isOpen = false">
 | 
			
		||||
      <li v-for="(option, i) in options" :key="i" @click="selectOption(i)">
 | 
			
		||||
        <button :class="{ 'is-selected': i == model }">
 | 
			
		||||
        <option :class="{ 'is-selected': i == model, 'option': true }">
 | 
			
		||||
          {{ option }}
 | 
			
		||||
        </button>
 | 
			
		||||
        </option>
 | 
			
		||||
      </li>
 | 
			
		||||
    </ul>
 | 
			
		||||
  </div>
 | 
			
		||||
| 
						 | 
				
			
			@ -38,7 +39,7 @@ function selectOption(index) {
 | 
			
		|||
  border-radius: 8px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.dropdown-container button {
 | 
			
		||||
.dropdown-container .option {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: row;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
| 
						 | 
				
			
			@ -53,7 +54,19 @@ function selectOption(index) {
 | 
			
		|||
  cursor: pointer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.dropdown-container button:hover {
 | 
			
		||||
.dropdown-container .option {
 | 
			
		||||
  border-radius: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.dropdown-container .option:first-child {
 | 
			
		||||
  border-radius: 8px 8px 0 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.dropdown-container .option:last-child {
 | 
			
		||||
  border-radius: 0 0 8px 8px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.dropdown-container .option:hover {
 | 
			
		||||
  background-color: var(--crust);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -76,14 +89,14 @@ ul.dropdown > li {
 | 
			
		|||
  list-style-type: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.dropdown li > button {
 | 
			
		||||
.dropdown li > .option {
 | 
			
		||||
  padding: 8px 16px;
 | 
			
		||||
  font-weight: 500;
 | 
			
		||||
  font-size: 14px;
 | 
			
		||||
  border-radius: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.dropdown li > button.is-selected {
 | 
			
		||||
.dropdown li > .option.is-selected {
 | 
			
		||||
  background-color: var(--accent-transparent);
 | 
			
		||||
  color: var(--accent);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -226,7 +226,7 @@ onUnmounted(() => {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
.grid {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  display: inline-flex;
 | 
			
		||||
  user-select: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,91 @@
 | 
			
		|||
<script setup lang="ts">
 | 
			
		||||
import { computed, defineModel, defineProps, ref } from "vue";
 | 
			
		||||
 | 
			
		||||
const model = defineModel();
 | 
			
		||||
 | 
			
		||||
const props = defineProps({
 | 
			
		||||
  options: Array<String>,
 | 
			
		||||
  isDisabled: Boolean,
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const isOpen = ref(false);
 | 
			
		||||
const selectedOption = computed(() => props.options[model.value]);
 | 
			
		||||
 | 
			
		||||
function selectOption(index) {
 | 
			
		||||
  model.value = index;
 | 
			
		||||
  isOpen.value = false;
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div :class="{ 'dropdown-container': true, 'is-open': isOpen }">
 | 
			
		||||
    <button @click="isOpen = !isOpen" :disabled="isDisabled">
 | 
			
		||||
      {{ selectedOption }}
 | 
			
		||||
      <i class="bi bi-caret-down-fill"></i>
 | 
			
		||||
    </button>
 | 
			
		||||
    <ul class="dropdown" v-if="isOpen" @blur="isOpen = false">
 | 
			
		||||
      <li v-for="(option, i) in options" :key="i" @click="selectOption(i)">
 | 
			
		||||
        <button :class="{ 'is-selected': i == model }">
 | 
			
		||||
          {{ option }}
 | 
			
		||||
        </button>
 | 
			
		||||
      </li>
 | 
			
		||||
    </ul>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<style scoped>
 | 
			
		||||
.dropdown-container {
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
  border-radius: 8px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.dropdown-container button {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: row;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  justify-content: space-between;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  text-align: left;
 | 
			
		||||
  font-weight: 700;
 | 
			
		||||
  font-size: 16px;
 | 
			
		||||
  padding: 4px;
 | 
			
		||||
  transition-duration: 200ms;
 | 
			
		||||
  background-color: transparent;
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.dropdown-container button:hover {
 | 
			
		||||
  background-color: var(--crust);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.dropdown-container.is-open ul.dropdown {
 | 
			
		||||
  box-shadow: 1px 1px 8px var(--shadow);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ul.dropdown {
 | 
			
		||||
  display: block;
 | 
			
		||||
  background-color: var(--base);
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  margin-top: 8px;
 | 
			
		||||
  padding: 0;
 | 
			
		||||
  z-index: 2;
 | 
			
		||||
  border-radius: 8px;
 | 
			
		||||
  overflow: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ul.dropdown > li {
 | 
			
		||||
  list-style-type: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.dropdown li > button {
 | 
			
		||||
  padding: 8px 16px;
 | 
			
		||||
  font-weight: 500;
 | 
			
		||||
  font-size: 14px;
 | 
			
		||||
  border-radius: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.dropdown li > button.is-selected {
 | 
			
		||||
  background-color: var(--accent-transparent);
 | 
			
		||||
  color: var(--accent);
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,125 @@
 | 
			
		|||
<script setup lang="ts">
 | 
			
		||||
import type { PlayerTeamRole } from "../player";
 | 
			
		||||
import { computed, type PropType } from "vue";
 | 
			
		||||
import { useRosterStore } from "../stores/roster";
 | 
			
		||||
import { type ViewTeamMembersResponse } from "@/client";
 | 
			
		||||
 | 
			
		||||
const props = defineProps({
 | 
			
		||||
  player: Object as PropType<ViewTeamMembersResponse>,
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const rosterStore = useRosterStore();
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <tr class="player-card">
 | 
			
		||||
    <td>
 | 
			
		||||
      <div class="status flex-middle" :availability="player.availability">
 | 
			
		||||
        <span class="dot"></span>
 | 
			
		||||
        <h3>
 | 
			
		||||
          {{ player.username }}
 | 
			
		||||
        </h3>
 | 
			
		||||
      </div>
 | 
			
		||||
    </td>
 | 
			
		||||
    <td>
 | 
			
		||||
      <div class="role-icons flex-middle">
 | 
			
		||||
        <i
 | 
			
		||||
          v-for="role in player.roles"
 | 
			
		||||
          :class="{
 | 
			
		||||
            [rosterStore.roleIcons[role.role]]: true,
 | 
			
		||||
            main: role.is_main,
 | 
			
		||||
          }"
 | 
			
		||||
        />
 | 
			
		||||
      </div>
 | 
			
		||||
    </td>
 | 
			
		||||
    <td>
 | 
			
		||||
      {{ player.playtime.toFixed(1) }} hours
 | 
			
		||||
    </td>
 | 
			
		||||
    <td>
 | 
			
		||||
      {{ new Date(player.created_at).toLocaleString() }}
 | 
			
		||||
    </td>
 | 
			
		||||
    <td>
 | 
			
		||||
      <div class="edit-group">
 | 
			
		||||
        <button>
 | 
			
		||||
          <i class="bi bi-pencil-fill edit-icon" />
 | 
			
		||||
        </button>
 | 
			
		||||
      </div>
 | 
			
		||||
    </td>
 | 
			
		||||
  </tr>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<style scoped>
 | 
			
		||||
.player-card {
 | 
			
		||||
  border-radius: 8px;
 | 
			
		||||
  user-select: none;
 | 
			
		||||
  gap: 1em;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  border: 2px solid white;
 | 
			
		||||
  box-shadow: 1px 1px 8px var(--surface-0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.player-card > td {
 | 
			
		||||
  padding: 1em 2em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.player-card h3 {
 | 
			
		||||
  font-weight: 600;
 | 
			
		||||
  font-size: 12pt;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.dot {
 | 
			
		||||
  display: block;
 | 
			
		||||
  border-radius: 50%;
 | 
			
		||||
  height: 8px;
 | 
			
		||||
  width: 8px;
 | 
			
		||||
  background-color: var(--overlay-0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.status[availability="0"] h3 {
 | 
			
		||||
  color: var(--overlay-0);
 | 
			
		||||
  font-weight: 400;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.status[availability="1"] .dot {
 | 
			
		||||
  background-color: var(--yellow);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.status[availability="2"] .dot {
 | 
			
		||||
  background-color: var(--green);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.flex-middle {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  gap: 8px;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.role-icons {
 | 
			
		||||
  font-size: 24px;
 | 
			
		||||
  line-height: 0;
 | 
			
		||||
  color: var(--overlay-0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.role-icons i.main {
 | 
			
		||||
  color: var(--text);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.edit-group {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: end;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.edit-group > button {
 | 
			
		||||
  background-color: transparent;
 | 
			
		||||
  opacity: 0;
 | 
			
		||||
  padding: 8px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.edit-group > button:hover {
 | 
			
		||||
  background-color: var(--surface-0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.player-card:hover .edit-group > button {
 | 
			
		||||
  opacity: 1;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,51 @@
 | 
			
		|||
<script setup lang="ts">
 | 
			
		||||
import { onMounted } from "vue";
 | 
			
		||||
import { useTeamsStore } from "../stores/teams";
 | 
			
		||||
import { RouterLink } from "vue-router";
 | 
			
		||||
 | 
			
		||||
const teams = useTeamsStore();
 | 
			
		||||
 | 
			
		||||
onMounted(() => {
 | 
			
		||||
  teams.fetchTeams();
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <aside>
 | 
			
		||||
    <div>
 | 
			
		||||
      <div class="teams-header">
 | 
			
		||||
        <h3>Your Teams</h3>
 | 
			
		||||
        <RouterLink to="/team/register">
 | 
			
		||||
          <button class="small accent">
 | 
			
		||||
            <i class="bi bi-plus-circle-fill margin"></i>
 | 
			
		||||
            New
 | 
			
		||||
          </button>
 | 
			
		||||
        </RouterLink>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div
 | 
			
		||||
        v-if="teams.teams"
 | 
			
		||||
        v-for="team in teams.teams"
 | 
			
		||||
      >
 | 
			
		||||
        <RouterLink :to="'/team/id/' + team.id">
 | 
			
		||||
          {{ team.team_name }}
 | 
			
		||||
        </RouterLink>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </aside>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<style scoped>
 | 
			
		||||
aside {
 | 
			
		||||
  flex-basis: 256px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.teams-header {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: space-between;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.teams-header h3 {
 | 
			
		||||
  font-weight: 600;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
| 
						 | 
				
			
			@ -1,14 +1,17 @@
 | 
			
		|||
import './assets/main.css'
 | 
			
		||||
import "./assets/main.css";
 | 
			
		||||
import "vue-select/dist/vue-select.css";
 | 
			
		||||
 | 
			
		||||
import { createApp } from 'vue'
 | 
			
		||||
import { createPinia } from 'pinia'
 | 
			
		||||
import { createApp } from "vue";
 | 
			
		||||
import { createPinia } from "pinia";
 | 
			
		||||
import VueSelect from "vue-select";
 | 
			
		||||
 | 
			
		||||
import App from './App.vue'
 | 
			
		||||
import router from './router'
 | 
			
		||||
import App from "./App.vue";
 | 
			
		||||
import router from "./router";
 | 
			
		||||
 | 
			
		||||
const app = createApp(App)
 | 
			
		||||
 | 
			
		||||
app.use(createPinia())
 | 
			
		||||
app.use(router)
 | 
			
		||||
app.component("v-select", VueSelect);
 | 
			
		||||
 | 
			
		||||
app.mount('#app')
 | 
			
		||||
app.mount("#app")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3,6 +3,8 @@ import HomeView from "../views/HomeView.vue";
 | 
			
		|||
import ScheduleView from "../views/ScheduleView.vue";
 | 
			
		||||
import RosterBuilderView from "../views/RosterBuilderView.vue";
 | 
			
		||||
import LoginView from "../views/LoginView.vue";
 | 
			
		||||
import TeamRegistrationView from "../views/TeamRegistrationView.vue";
 | 
			
		||||
import TeamDetailsView from "../views/TeamDetailsView.vue";
 | 
			
		||||
 | 
			
		||||
const router = createRouter({
 | 
			
		||||
  history: createWebHistory(import.meta.env.BASE_URL),
 | 
			
		||||
| 
						 | 
				
			
			@ -27,6 +29,16 @@ const router = createRouter({
 | 
			
		|||
      name: "roster-builder",
 | 
			
		||||
      component: RosterBuilderView
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      path: "/team/register",
 | 
			
		||||
      name: "team-registration",
 | 
			
		||||
      component: TeamRegistrationView
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      path: "/team/id/:id",
 | 
			
		||||
      name: "team-details",
 | 
			
		||||
      component: TeamDetailsView
 | 
			
		||||
    },
 | 
			
		||||
  ]
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,39 @@
 | 
			
		|||
import { AvailabilitfClient } from "@/client";
 | 
			
		||||
import { defineStore } from "pinia";
 | 
			
		||||
 | 
			
		||||
export const useClientStore = defineStore("client", () => {
 | 
			
		||||
  const client = new AvailabilitfClient({
 | 
			
		||||
    //BASE: import.meta.env.VITE_API_BASE_URL
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  const calls = new Map<string, Promise<any>>();
 | 
			
		||||
 | 
			
		||||
  function call<T>(
 | 
			
		||||
    key: string,
 | 
			
		||||
    apiCall: () => Promise<T>,
 | 
			
		||||
    thenOnce?: (result: T) => T
 | 
			
		||||
  ): Promise<T> {
 | 
			
		||||
    console.log("Fetching call " + key);
 | 
			
		||||
    if (!calls.has(key)) {
 | 
			
		||||
      const promise = apiCall();
 | 
			
		||||
      calls.set(key, promise);
 | 
			
		||||
 | 
			
		||||
      // remove from calls once completed
 | 
			
		||||
      promise.finally(() => calls.delete(key));
 | 
			
		||||
 | 
			
		||||
      // only execute this "then" once if the call was just freshly made
 | 
			
		||||
      if (thenOnce) {
 | 
			
		||||
        promise.then(thenOnce);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return promise;
 | 
			
		||||
    }
 | 
			
		||||
    return calls.get(key) as Promise<T>;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    client,
 | 
			
		||||
    call,
 | 
			
		||||
    calls,
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -177,6 +177,13 @@ export const useRosterStore = defineStore("roster", () => {
 | 
			
		|||
    "Roamer": "tf2-FlankSoldier",
 | 
			
		||||
    "Demoman": "tf2-Demo",
 | 
			
		||||
    "Medic": "tf2-Medic",
 | 
			
		||||
 | 
			
		||||
    "Role.PocketScout": "tf2-PocketScout",
 | 
			
		||||
    "Role.FlankScout": "tf2-FlankScout",
 | 
			
		||||
    "Role.PocketSoldier": "tf2-PocketSoldier",
 | 
			
		||||
    "Role.Roamer": "tf2-FlankSoldier",
 | 
			
		||||
    "Role.Demoman": "tf2-Demo",
 | 
			
		||||
    "Role.Medic": "tf2-Medic",
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  function selectPlayerForRole(player: PlayerTeamRole, role: string) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,56 +2,79 @@ import { computed } from "@vue/reactivity";
 | 
			
		|||
import { defineStore } from "pinia";
 | 
			
		||||
import { reactive, ref, watch } from "vue";
 | 
			
		||||
import { useRoute, useRouter } from "vue-router";
 | 
			
		||||
import { useClientStore } from "./client";
 | 
			
		||||
 | 
			
		||||
export const useScheduleStore = defineStore("schedule", () => {
 | 
			
		||||
  const client = useClientStore().client;
 | 
			
		||||
 | 
			
		||||
  const dateStart = ref(new Date(2024, 9, 21, 0, 30));
 | 
			
		||||
 | 
			
		||||
  const windowStart = computed(() => Math.floor(dateStart.value.getTime() / 1000));
 | 
			
		||||
 | 
			
		||||
  const availability = reactive(new Array(168));
 | 
			
		||||
 | 
			
		||||
  availability.fill(0);
 | 
			
		||||
 | 
			
		||||
  const route = useRoute();
 | 
			
		||||
  const router = useRouter();
 | 
			
		||||
 | 
			
		||||
  const teamId = computed({
 | 
			
		||||
    get: () => route.query.teamId,
 | 
			
		||||
    get: () => Number(route.query.teamId),
 | 
			
		||||
    set: (value) => router.push({ query: { teamId: value } }),
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  watch(dateStart, () => {
 | 
			
		||||
    availability.fill(0);
 | 
			
		||||
    fetchSchedule();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  watch(teamId, () => {
 | 
			
		||||
    fetchSchedule();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  async function fetchSchedule() {
 | 
			
		||||
    return fetch(import.meta.env.VITE_API_BASE_URL + "/schedule?" + new URLSearchParams({
 | 
			
		||||
      window_start: windowStart.value.toString(),
 | 
			
		||||
      team_id: "1",
 | 
			
		||||
    }).toString(),{
 | 
			
		||||
        credentials: "include",
 | 
			
		||||
      })
 | 
			
		||||
      .then((response) => response.json())
 | 
			
		||||
    return client.default.getApiSchedule(
 | 
			
		||||
      Math.floor(dateStart.value.getTime() / 1000).toString(),
 | 
			
		||||
      teamId.value,
 | 
			
		||||
    )
 | 
			
		||||
      .then((response) => {
 | 
			
		||||
        response.availability.forEach((value: number, i: number) => {
 | 
			
		||||
        response.availability.forEach((value, i) => {
 | 
			
		||||
          availability[i] = value;
 | 
			
		||||
        });
 | 
			
		||||
        return response;
 | 
			
		||||
      });
 | 
			
		||||
    //return fetch(import.meta.env.VITE_API_BASE_URL + "/schedule?" + new URLSearchParams({
 | 
			
		||||
    //  window_start: windowStart.value.toString(),
 | 
			
		||||
    //  team_id: teamId.toString(),
 | 
			
		||||
    //}).toString(),{
 | 
			
		||||
    //    credentials: "include",
 | 
			
		||||
    //  })
 | 
			
		||||
    //  .then((response) => response.json())
 | 
			
		||||
    //  .then((response) => {
 | 
			
		||||
    //    response.availability.forEach((value: number, i: number) => {
 | 
			
		||||
    //      availability[i] = value;
 | 
			
		||||
    //    });
 | 
			
		||||
    //    return response;
 | 
			
		||||
    //  });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async function saveSchedule() {
 | 
			
		||||
    return fetch(import.meta.env.VITE_API_BASE_URL + "/schedule", {
 | 
			
		||||
      method: "PUT",
 | 
			
		||||
      credentials: "include",
 | 
			
		||||
      headers: {
 | 
			
		||||
        "Content-Type": "application/json",
 | 
			
		||||
      },
 | 
			
		||||
      body: JSON.stringify({
 | 
			
		||||
        window_start: Math.floor(dateStart.value.getTime() / 1000),
 | 
			
		||||
        team_id: 1,
 | 
			
		||||
        availability: availability,
 | 
			
		||||
      })
 | 
			
		||||
    return client.default.putApiSchedule({
 | 
			
		||||
      windowStart: Math.floor(dateStart.value.getTime() / 1000).toString(),
 | 
			
		||||
      teamId: teamId.value,
 | 
			
		||||
      availability,
 | 
			
		||||
    });
 | 
			
		||||
    //return fetch(import.meta.env.VITE_API_BASE_URL + "/schedule", {
 | 
			
		||||
    //  method: "PUT",
 | 
			
		||||
    //  credentials: "include",
 | 
			
		||||
    //  headers: {
 | 
			
		||||
    //    "Content-Type": "application/json",
 | 
			
		||||
    //  },
 | 
			
		||||
    //  body: JSON.stringify({
 | 
			
		||||
    //    window_start: Math.floor(dateStart.value.getTime() / 1000),
 | 
			
		||||
    //    team_id: teamId.toString(),
 | 
			
		||||
    //    availability: availability,
 | 
			
		||||
    //  })
 | 
			
		||||
    //});
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
| 
						 | 
				
			
			@ -60,5 +83,6 @@ export const useScheduleStore = defineStore("schedule", () => {
 | 
			
		|||
    availability,
 | 
			
		||||
    fetchSchedule,
 | 
			
		||||
    saveSchedule,
 | 
			
		||||
    teamId,
 | 
			
		||||
  };
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,36 +1,81 @@
 | 
			
		|||
import Cacheable from "@/cacheable";
 | 
			
		||||
import { AvailabilitfClient, type TeamSpec, type ViewTeamMembersResponse, type ViewTeamResponse, type ViewTeamsResponse } from "@/client";
 | 
			
		||||
import { defineStore } from "pinia";
 | 
			
		||||
import { computed, reactive, ref, type Reactive, type Ref } from "vue";
 | 
			
		||||
import { useClientStore } from "./client";
 | 
			
		||||
 | 
			
		||||
interface Team {
 | 
			
		||||
  id: number,
 | 
			
		||||
  teamName: string,
 | 
			
		||||
}
 | 
			
		||||
export type TeamMap = { [id: number]: TeamSpec };
 | 
			
		||||
 | 
			
		||||
export const useTeamsStore = defineStore("teams", () => {
 | 
			
		||||
  //const teams: Reactive<Cacheable<Team[]>> =
 | 
			
		||||
  //  reactive(new Cacheable<Team[]>([], 0));
 | 
			
		||||
  const teams: Ref<{ [id: number]: Team }> = ref({ });
 | 
			
		||||
  const clientStore = useClientStore();
 | 
			
		||||
  const client = clientStore.client;
 | 
			
		||||
 | 
			
		||||
  const teams: Reactive<{ [id: number]: TeamSpec }> = reactive({ });
 | 
			
		||||
  const teamMembers: Reactive<{ [id: number]: ViewTeamMembersResponse[] }> = reactive({ });
 | 
			
		||||
 | 
			
		||||
  const isFetchingTeams = ref(false);
 | 
			
		||||
 | 
			
		||||
  async function fetchTeams() {
 | 
			
		||||
    return new Promise((res, rej) => {
 | 
			
		||||
      fetch(import.meta.env.VITE_API_BASE_URL + "/team/view", {
 | 
			
		||||
        credentials: "include",
 | 
			
		||||
      })
 | 
			
		||||
        .then((response) => response.json())
 | 
			
		||||
        .then((response: Array<any>) => {
 | 
			
		||||
          teams.value = response
 | 
			
		||||
            .reduce((acc, team: Team) => {
 | 
			
		||||
              return { ...acc, [team.id]: team }
 | 
			
		||||
            });
 | 
			
		||||
          res(teams.value);
 | 
			
		||||
        })
 | 
			
		||||
        .catch(() => rej());
 | 
			
		||||
    return clientStore.call(
 | 
			
		||||
      fetchTeams.name,
 | 
			
		||||
      () => client.default.getTeams(),
 | 
			
		||||
      (response) => {
 | 
			
		||||
        response.teams.forEach((team) => {
 | 
			
		||||
          teams[team.id] = team;
 | 
			
		||||
        });
 | 
			
		||||
        return response;
 | 
			
		||||
      }
 | 
			
		||||
    )
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async function fetchTeam(id: number) {
 | 
			
		||||
    return clientStore.call(
 | 
			
		||||
      fetchTeam.name,
 | 
			
		||||
      () => client.default.getTeam(id.toString()),
 | 
			
		||||
      (response) => {
 | 
			
		||||
        teams[response.team.id] = response.team;
 | 
			
		||||
        return response;
 | 
			
		||||
      }
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async function fetchTeamMembers(id: number) {
 | 
			
		||||
    return clientStore.call(
 | 
			
		||||
      fetchTeam.name,
 | 
			
		||||
      () => client.default.getTeamMembers(id.toString()),
 | 
			
		||||
      (response) => {
 | 
			
		||||
        response = response
 | 
			
		||||
          .map((member): ViewTeamMembersResponse => {
 | 
			
		||||
            // TODO: snake_case to camelCase
 | 
			
		||||
            member.roles = member.roles.sort((a, b) => {
 | 
			
		||||
                if (a.is_main == b.is_main) {
 | 
			
		||||
                  return 0;
 | 
			
		||||
                }
 | 
			
		||||
                return a.is_main ? -1 : 1;
 | 
			
		||||
              });
 | 
			
		||||
            return member;
 | 
			
		||||
          });
 | 
			
		||||
        console.log(response);
 | 
			
		||||
        teamMembers[id] = response;
 | 
			
		||||
        return response;
 | 
			
		||||
      }
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async function createTeam(teamName: string, tz: string, webhook?: string) {
 | 
			
		||||
    return await client.default.createTeam({
 | 
			
		||||
      teamName,
 | 
			
		||||
      leagueTimezone: tz,
 | 
			
		||||
      discordWebhookUrl: webhook,
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return {
 | 
			
		||||
    teams,
 | 
			
		||||
    teamMembers,
 | 
			
		||||
    fetchTeams,
 | 
			
		||||
  }
 | 
			
		||||
    fetchTeam,
 | 
			
		||||
    fetchTeamMembers,
 | 
			
		||||
    createTeam,
 | 
			
		||||
  };
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,12 +1,13 @@
 | 
			
		|||
<script setup lang="ts">
 | 
			
		||||
import TeamsListSidebar from "../components/TeamsListSidebar.vue";
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <TeamsListSidebar />
 | 
			
		||||
  <main>
 | 
			
		||||
    <h2>JustGetAHouse</h2>
 | 
			
		||||
    <div>
 | 
			
		||||
      test
 | 
			
		||||
    </div>
 | 
			
		||||
    <h1>Your Teams</h1>
 | 
			
		||||
  </main>
 | 
			
		||||
</template>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,17 +2,17 @@
 | 
			
		|||
import AvailabilityGrid from "../components/AvailabilityGrid.vue";
 | 
			
		||||
import AvailabilityComboBox from "../components/AvailabilityComboBox.vue";
 | 
			
		||||
import WeekSelectionBox from "../components/WeekSelectionBox.vue";
 | 
			
		||||
import { computed, onMounted, reactive, ref } from "vue";
 | 
			
		||||
import { computed, onMounted, reactive, ref, watch } from "vue";
 | 
			
		||||
import { useTeamsStore } from "../stores/teams";
 | 
			
		||||
import { useScheduleStore } from "../stores/schedule";
 | 
			
		||||
import { useRoute, useRouter } from "vue-router";
 | 
			
		||||
 | 
			
		||||
const teams = useTeamsStore();
 | 
			
		||||
const teamsStore = useTeamsStore();
 | 
			
		||||
const schedule = useScheduleStore();
 | 
			
		||||
const router = useRouter();
 | 
			
		||||
const route = useRoute();
 | 
			
		||||
 | 
			
		||||
const options = ref([
 | 
			
		||||
  "TEAM PEPEJA forsenCD",
 | 
			
		||||
  "The Snus Brotherhood",
 | 
			
		||||
]);
 | 
			
		||||
const options = ref([ ]);
 | 
			
		||||
 | 
			
		||||
const firstHour = computed(() => shouldShowAllHours.value ? 0 : 14);
 | 
			
		||||
const lastHour = computed(() => shouldShowAllHours.value ? 23 : 22);
 | 
			
		||||
| 
						 | 
				
			
			@ -20,13 +20,20 @@ const shouldShowAllHours = ref(false);
 | 
			
		|||
 | 
			
		||||
const comboBoxIndex = ref(0);
 | 
			
		||||
 | 
			
		||||
//const availability = reactive(new Array(168));
 | 
			
		||||
const availability = schedule.availability;
 | 
			
		||||
 | 
			
		||||
const selectionMode = ref(1);
 | 
			
		||||
 | 
			
		||||
const isEditing = ref(false);
 | 
			
		||||
 | 
			
		||||
const selectedTeam = ref();
 | 
			
		||||
 | 
			
		||||
watch(selectedTeam, (newTeam) => {
 | 
			
		||||
  if (newTeam) {
 | 
			
		||||
    schedule.teamId = newTeam.id;
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function saveSchedule() {
 | 
			
		||||
  schedule.saveSchedule()
 | 
			
		||||
    .then(() => {
 | 
			
		||||
| 
						 | 
				
			
			@ -35,14 +42,18 @@ function saveSchedule() {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
onMounted(() => {
 | 
			
		||||
  teams.fetchTeams()
 | 
			
		||||
  teamsStore.fetchTeams()
 | 
			
		||||
    .then((teamsList) => {
 | 
			
		||||
      options.value = Object.values(teamsList);
 | 
			
		||||
      schedule.fetchSchedule()
 | 
			
		||||
        .then(() => {
 | 
			
		||||
 | 
			
		||||
        });
 | 
			
		||||
    })
 | 
			
		||||
      options.value = Object.values(teamsList.teams);
 | 
			
		||||
      // select team with id in query parameter if exists
 | 
			
		||||
      const queryTeam = teamsList.teams.find(x => x.id == route.query.teamId);
 | 
			
		||||
      console.log(queryTeam);
 | 
			
		||||
      if (queryTeam) {
 | 
			
		||||
        selectedTeam.value = queryTeam;
 | 
			
		||||
        //schedule.teamId = queryTeam.id;
 | 
			
		||||
        schedule.fetchSchedule(schedule.teamId);
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -52,7 +63,11 @@ onMounted(() => {
 | 
			
		|||
      <div class="top-menu">
 | 
			
		||||
        <div class="subtext">
 | 
			
		||||
          Availability for
 | 
			
		||||
          <AvailabilityComboBox :options="options" v-model="comboBoxIndex" />
 | 
			
		||||
          <v-select
 | 
			
		||||
            :options="options"
 | 
			
		||||
            label="team_name"
 | 
			
		||||
            v-model="selectedTeam"
 | 
			
		||||
          />
 | 
			
		||||
        </div>
 | 
			
		||||
        <div>
 | 
			
		||||
          <WeekSelectionBox
 | 
			
		||||
| 
						 | 
				
			
			@ -60,42 +75,44 @@ onMounted(() => {
 | 
			
		|||
            :is-disabled="isEditing" />
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
      <AvailabilityGrid v-model="availability"
 | 
			
		||||
        :selection-mode="selectionMode"
 | 
			
		||||
        :is-disabled="!isEditing"
 | 
			
		||||
        :date-start="schedule.dateStart"
 | 
			
		||||
        :first-hour="firstHour"
 | 
			
		||||
        :last-hour="lastHour"
 | 
			
		||||
      />
 | 
			
		||||
      <div class="button-group">
 | 
			
		||||
        <button v-if="shouldShowAllHours" @click="shouldShowAllHours = false">
 | 
			
		||||
          Show designated times
 | 
			
		||||
        </button>
 | 
			
		||||
        <button v-else @click="shouldShowAllHours = true">
 | 
			
		||||
          Show all times
 | 
			
		||||
        </button>
 | 
			
		||||
        <template v-if="isEditing">
 | 
			
		||||
          <div class="radio-group">
 | 
			
		||||
            <button
 | 
			
		||||
              :class="{ 'radio': true, 'selected': selectionMode == 1, 'left': true }"
 | 
			
		||||
              @click="selectionMode = 1"
 | 
			
		||||
            >
 | 
			
		||||
              Available if needed
 | 
			
		||||
            </button>
 | 
			
		||||
            <button
 | 
			
		||||
              :class="{ 'radio': true, 'selected': selectionMode == 2, 'right': true }"
 | 
			
		||||
              @click="selectionMode = 2"
 | 
			
		||||
            >
 | 
			
		||||
              Definitely available
 | 
			
		||||
            </button>
 | 
			
		||||
          </div>
 | 
			
		||||
          <button @click="saveSchedule()">
 | 
			
		||||
            <i class="bi bi-check-circle-fill"></i>
 | 
			
		||||
      <div class="grid-container">
 | 
			
		||||
        <AvailabilityGrid v-model="availability"
 | 
			
		||||
          :selection-mode="selectionMode"
 | 
			
		||||
          :is-disabled="!isEditing"
 | 
			
		||||
          :date-start="schedule.dateStart"
 | 
			
		||||
          :first-hour="firstHour"
 | 
			
		||||
          :last-hour="lastHour"
 | 
			
		||||
        />
 | 
			
		||||
        <div class="button-group">
 | 
			
		||||
          <button v-if="shouldShowAllHours" @click="shouldShowAllHours = false">
 | 
			
		||||
            Show designated times
 | 
			
		||||
          </button>
 | 
			
		||||
        </template>
 | 
			
		||||
        <button v-else class="accent" @click="isEditing = true">
 | 
			
		||||
          <i class="bi bi-pencil-fill"></i>
 | 
			
		||||
        </button>
 | 
			
		||||
          <button v-else @click="shouldShowAllHours = true">
 | 
			
		||||
            Show all times
 | 
			
		||||
          </button>
 | 
			
		||||
          <template v-if="isEditing">
 | 
			
		||||
            <div class="radio-group">
 | 
			
		||||
              <button
 | 
			
		||||
                :class="{ 'radio': true, 'selected': selectionMode == 1, 'left': true }"
 | 
			
		||||
                @click="selectionMode = 1"
 | 
			
		||||
              >
 | 
			
		||||
                Available if needed
 | 
			
		||||
              </button>
 | 
			
		||||
              <button
 | 
			
		||||
                :class="{ 'radio': true, 'selected': selectionMode == 2, 'right': true }"
 | 
			
		||||
                @click="selectionMode = 2"
 | 
			
		||||
              >
 | 
			
		||||
                Definitely available
 | 
			
		||||
              </button>
 | 
			
		||||
            </div>
 | 
			
		||||
            <button @click="saveSchedule()">
 | 
			
		||||
              <i class="bi bi-check-circle-fill"></i>
 | 
			
		||||
            </button>
 | 
			
		||||
          </template>
 | 
			
		||||
          <button v-else class="accent" @click="isEditing = true">
 | 
			
		||||
            <i class="bi bi-pencil-fill"></i>
 | 
			
		||||
          </button>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div v-else>
 | 
			
		||||
| 
						 | 
				
			
			@ -106,7 +123,10 @@ onMounted(() => {
 | 
			
		|||
 | 
			
		||||
<style scoped>
 | 
			
		||||
.schedule-view-container {
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.top-menu {
 | 
			
		||||
| 
						 | 
				
			
			@ -115,8 +135,14 @@ onMounted(() => {
 | 
			
		|||
  align-items: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.grid-container {
 | 
			
		||||
  display: inline-flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  align-content: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.button-group {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  display: inline-flex;
 | 
			
		||||
  gap: 8px;
 | 
			
		||||
  justify-content: end;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -140,10 +166,16 @@ button.radio.selected {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
button.left {
 | 
			
		||||
  border-radius: 8px 0 0 8px;
 | 
			
		||||
  border-radius: 4px 0 0 4px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
button.right {
 | 
			
		||||
  border-radius: 0 8px 8px 0;
 | 
			
		||||
  border-radius: 0 4px 4px 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.v-select {
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
  width: auto;
 | 
			
		||||
  min-width: 11em;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,77 @@
 | 
			
		|||
<script setup lang="ts">
 | 
			
		||||
import { useRoute, useRouter } from "vue-router";
 | 
			
		||||
import { useTeamsStore } from "../stores/teams";
 | 
			
		||||
import { computed, onMounted } from "vue";
 | 
			
		||||
import PlayerTeamCard from "../components/PlayerTeamCard.vue";
 | 
			
		||||
 | 
			
		||||
const route = useRoute();
 | 
			
		||||
const router = useRouter();
 | 
			
		||||
const teamsStore = useTeamsStore();
 | 
			
		||||
 | 
			
		||||
const team = computed(() => {
 | 
			
		||||
  return teamsStore.teams[route.params.id];
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
onMounted(() => {
 | 
			
		||||
  teamsStore.fetchTeam(route.params.id)
 | 
			
		||||
    .then(() => teamsStore.fetchTeamMembers(route.params.id));
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <main>
 | 
			
		||||
    <template v-if="team">
 | 
			
		||||
      <h1>
 | 
			
		||||
        {{ team.team_name }}
 | 
			
		||||
      </h1>
 | 
			
		||||
      <table class="member-table">
 | 
			
		||||
        <thead>
 | 
			
		||||
          <tr>
 | 
			
		||||
            <th>
 | 
			
		||||
              Name
 | 
			
		||||
            </th>
 | 
			
		||||
            <th>
 | 
			
		||||
              Roles
 | 
			
		||||
            </th>
 | 
			
		||||
            <th>
 | 
			
		||||
              Playtime on team
 | 
			
		||||
            </th>
 | 
			
		||||
            <th>
 | 
			
		||||
              Joined
 | 
			
		||||
            </th>
 | 
			
		||||
          </tr>
 | 
			
		||||
        </thead>
 | 
			
		||||
        <tbody>
 | 
			
		||||
          <PlayerTeamCard
 | 
			
		||||
            v-for="member in teamsStore.teamMembers[route.params.id]"
 | 
			
		||||
            :player="member"
 | 
			
		||||
          />
 | 
			
		||||
        </tbody>
 | 
			
		||||
      </table>
 | 
			
		||||
    </template>
 | 
			
		||||
  </main>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<style scoped>
 | 
			
		||||
h1 {
 | 
			
		||||
  display: flex;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
table.member-table {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
table.member-table th {
 | 
			
		||||
  text-align: left;
 | 
			
		||||
  padding-left: 2em;
 | 
			
		||||
  font-weight: 700;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
div.member-grid {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  gap: 8px;
 | 
			
		||||
  flex-wrap: wrap;
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
</style>
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,143 @@
 | 
			
		|||
<script lang="ts" setup>
 | 
			
		||||
import { ref, watch } from "vue";
 | 
			
		||||
import { useTeamsStore } from "../stores/teams.ts"
 | 
			
		||||
import timezones from "../assets/timezones.json";
 | 
			
		||||
import { useRouter } from "vue-router";
 | 
			
		||||
 | 
			
		||||
const teams = useTeamsStore();
 | 
			
		||||
 | 
			
		||||
const router = useRouter();
 | 
			
		||||
 | 
			
		||||
const teamName = ref("");
 | 
			
		||||
 | 
			
		||||
const timezone = ref(
 | 
			
		||||
  Intl.DateTimeFormat().resolvedOptions().timeZone ??
 | 
			
		||||
    "Etc/UTC"
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
const minuteOffset = ref(0);
 | 
			
		||||
 | 
			
		||||
watch(minuteOffset, (newValue) => {
 | 
			
		||||
  minuteOffset.value = Math.min(Math.max(0, newValue), 59);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const webhook = ref("");
 | 
			
		||||
 | 
			
		||||
function createTeam() {
 | 
			
		||||
  teams.createTeam(teamName.value, timezone.value, webhook.value)
 | 
			
		||||
    .then(() => {
 | 
			
		||||
      router.push("/");
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <main>
 | 
			
		||||
    <div class="team-registration-container">
 | 
			
		||||
      <h1>Create a new team</h1>
 | 
			
		||||
      <p>
 | 
			
		||||
        Register your team to streamline match scheduling, role assignments,
 | 
			
		||||
        and overall team communication.
 | 
			
		||||
      </p>
 | 
			
		||||
      <div class="form-group margin">
 | 
			
		||||
        <h3>Team Name</h3>
 | 
			
		||||
        <input v-model="teamName" />
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="form-group margin">
 | 
			
		||||
        <div class="form-group row">
 | 
			
		||||
          <div class="form-group">
 | 
			
		||||
            <h3>
 | 
			
		||||
              Timezone
 | 
			
		||||
              <a
 | 
			
		||||
                class="aside"
 | 
			
		||||
                href="https://nodatime.org/TimeZones"
 | 
			
		||||
                target="_blank"
 | 
			
		||||
              >
 | 
			
		||||
                (view all timezones)
 | 
			
		||||
              </a>
 | 
			
		||||
            </h3>
 | 
			
		||||
            <v-select :options="timezones" v-model="timezone" />
 | 
			
		||||
          </div>
 | 
			
		||||
          <div class="form-group" id="minute-offset-group">
 | 
			
		||||
            <h3>Minute Offset</h3>
 | 
			
		||||
            <input type="number" v-model="minuteOffset" min="0" max="59" />
 | 
			
		||||
          </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        <em class="aside">
 | 
			
		||||
          Matches will be scheduled against {{ timezone }} at
 | 
			
		||||
          {{ minuteOffset }}
 | 
			
		||||
          <span v-if="minuteOffset == 1">
 | 
			
		||||
            minute
 | 
			
		||||
          </span>
 | 
			
		||||
          <span v-else>
 | 
			
		||||
            minutes
 | 
			
		||||
          </span>
 | 
			
		||||
          past the hour.
 | 
			
		||||
        </em>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="form-group margin">
 | 
			
		||||
        <h3>
 | 
			
		||||
          Announcements Webhook URL
 | 
			
		||||
          <span class="aside">(optional)</span>
 | 
			
		||||
        </h3>
 | 
			
		||||
        <input v-model="webhook" />
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="form-group margin">
 | 
			
		||||
        <div class="action-buttons">
 | 
			
		||||
          <button class="accent" @click="createTeam">Create team</button>
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </main>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<style scoped>
 | 
			
		||||
.team-registration-container {
 | 
			
		||||
  align-items: center;
 | 
			
		||||
  max-width: 500px;
 | 
			
		||||
  margin: auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.team-registration-container h3 {
 | 
			
		||||
  font-size: 11pt;
 | 
			
		||||
  font-weight: 700;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.team-registration-container .aside {
 | 
			
		||||
  font-size: 9pt;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.form-group {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
  gap: 4px;
 | 
			
		||||
  flex-grow: 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.form-group.margin {
 | 
			
		||||
  margin-top: 16px;
 | 
			
		||||
  margin-bottom: 16px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.form-group.row {
 | 
			
		||||
  flex-direction: row;
 | 
			
		||||
  margin: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#minute-offset-group {
 | 
			
		||||
  flex-grow: unset;
 | 
			
		||||
  flex-shrink: 1;
 | 
			
		||||
  flex-basis: 25%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
input {
 | 
			
		||||
  display: block;
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  color: var(--text);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.action-buttons {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: end;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
| 
						 | 
				
			
			@ -16,7 +16,8 @@ export default defineConfig({
 | 
			
		|||
  server: {
 | 
			
		||||
    proxy: {
 | 
			
		||||
      '/api': {
 | 
			
		||||
        target: 'http://localhost:5000',
 | 
			
		||||
        //target: 'http://localhost:5000',
 | 
			
		||||
        target: 'https://on-indirectly-firefly.ngrok-free.app',
 | 
			
		||||
        changeOrigin: true,
 | 
			
		||||
        secure: false,
 | 
			
		||||
        configure: (proxy) => {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue