Improve code quality
							parent
							
								
									cb9e29b402
								
							
						
					
					
						commit
						b4deeddfba
					
				| 
						 | 
					@ -31,6 +31,7 @@
 | 
				
			||||||
        "@vue/eslint-config-typescript": "^14.0.1",
 | 
					        "@vue/eslint-config-typescript": "^14.0.1",
 | 
				
			||||||
        "@vue/test-utils": "^2.4.6",
 | 
					        "@vue/test-utils": "^2.4.6",
 | 
				
			||||||
        "@vue/tsconfig": "^0.5.1",
 | 
					        "@vue/tsconfig": "^0.5.1",
 | 
				
			||||||
 | 
					        "@vue/typescript-plugin": "^2.1.10",
 | 
				
			||||||
        "autoprefixer": "^10.4.20",
 | 
					        "autoprefixer": "^10.4.20",
 | 
				
			||||||
        "cypress": "^13.15.0",
 | 
					        "cypress": "^13.15.0",
 | 
				
			||||||
        "eslint": "^9.12.0",
 | 
					        "eslint": "^9.12.0",
 | 
				
			||||||
| 
						 | 
					@ -1620,30 +1621,30 @@
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/@volar/language-core": {
 | 
					    "node_modules/@volar/language-core": {
 | 
				
			||||||
      "version": "2.4.6",
 | 
					      "version": "2.4.10",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.6.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.10.tgz",
 | 
				
			||||||
      "integrity": "sha512-FxUfxaB8sCqvY46YjyAAV6c3mMIq/NWQMVvJ+uS4yxr1KzOvyg61gAuOnNvgCvO4TZ7HcLExBEsWcDu4+K4E8A==",
 | 
					      "integrity": "sha512-hG3Z13+nJmGaT+fnQzAkS0hjJRa2FCeqZt6Bd+oGNhUkQ+mTFsDETg5rqUTxyzIh5pSOGY7FHCWUS8G82AzLCA==",
 | 
				
			||||||
      "dev": true,
 | 
					      "dev": true,
 | 
				
			||||||
      "license": "MIT",
 | 
					      "license": "MIT",
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
        "@volar/source-map": "2.4.6"
 | 
					        "@volar/source-map": "2.4.10"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/@volar/source-map": {
 | 
					    "node_modules/@volar/source-map": {
 | 
				
			||||||
      "version": "2.4.6",
 | 
					      "version": "2.4.10",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.6.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.10.tgz",
 | 
				
			||||||
      "integrity": "sha512-Nsh7UW2ruK+uURIPzjJgF0YRGP5CX9nQHypA2OMqdM2FKy7rh+uv3XgPnWPw30JADbKvZ5HuBzG4gSbVDYVtiw==",
 | 
					      "integrity": "sha512-OCV+b5ihV0RF3A7vEvNyHPi4G4kFa6ukPmyVocmqm5QzOd8r5yAtiNvaPEjl8dNvgC/lj4JPryeeHLdXd62rWA==",
 | 
				
			||||||
      "dev": true,
 | 
					      "dev": true,
 | 
				
			||||||
      "license": "MIT"
 | 
					      "license": "MIT"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/@volar/typescript": {
 | 
					    "node_modules/@volar/typescript": {
 | 
				
			||||||
      "version": "2.4.6",
 | 
					      "version": "2.4.10",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.6.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.10.tgz",
 | 
				
			||||||
      "integrity": "sha512-NMIrA7y5OOqddL9VtngPWYmdQU03htNKFtAYidbYfWA0TOhyGVd9tfcP4TsLWQ+RBWDZCbBqsr8xzU0ZOxYTCQ==",
 | 
					      "integrity": "sha512-F8ZtBMhSXyYKuBfGpYwqA5rsONnOwAVvjyE7KPYJ7wgZqo2roASqNWUnianOomJX5u1cxeRooHV59N0PhvEOgw==",
 | 
				
			||||||
      "dev": true,
 | 
					      "dev": true,
 | 
				
			||||||
      "license": "MIT",
 | 
					      "license": "MIT",
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
        "@volar/language-core": "2.4.6",
 | 
					        "@volar/language-core": "2.4.10",
 | 
				
			||||||
        "path-browserify": "^1.0.1",
 | 
					        "path-browserify": "^1.0.1",
 | 
				
			||||||
        "vscode-uri": "^3.0.8"
 | 
					        "vscode-uri": "^3.0.8"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
| 
						 | 
					@ -1861,6 +1862,43 @@
 | 
				
			||||||
      "dev": true,
 | 
					      "dev": true,
 | 
				
			||||||
      "license": "MIT"
 | 
					      "license": "MIT"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@vue/typescript-plugin": {
 | 
				
			||||||
 | 
					      "version": "2.1.10",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@vue/typescript-plugin/-/typescript-plugin-2.1.10.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-NrS3BB3l5vuZHU4Vp8l9TbT5pC7VjBfwZKqc24dAXF3Z+dJyGs4mcC3zo59gUggLMQSah8mdXj8xqEfMkrps8w==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
 | 
					      "license": "MIT",
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@volar/typescript": "~2.4.8",
 | 
				
			||||||
 | 
					        "@vue/language-core": "2.1.10",
 | 
				
			||||||
 | 
					        "@vue/shared": "^3.5.0"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/@vue/typescript-plugin/node_modules/@vue/language-core": {
 | 
				
			||||||
 | 
					      "version": "2.1.10",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.1.10.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-DAI289d0K3AB5TUG3xDp9OuQ71CnrujQwJrQnfuZDwo6eGNf0UoRlPuaVNO+Zrn65PC3j0oB2i7mNmVPggeGeQ==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
 | 
					      "license": "MIT",
 | 
				
			||||||
 | 
					      "dependencies": {
 | 
				
			||||||
 | 
					        "@volar/language-core": "~2.4.8",
 | 
				
			||||||
 | 
					        "@vue/compiler-dom": "^3.5.0",
 | 
				
			||||||
 | 
					        "@vue/compiler-vue2": "^2.7.16",
 | 
				
			||||||
 | 
					        "@vue/shared": "^3.5.0",
 | 
				
			||||||
 | 
					        "alien-signals": "^0.2.0",
 | 
				
			||||||
 | 
					        "minimatch": "^9.0.3",
 | 
				
			||||||
 | 
					        "muggle-string": "^0.4.1",
 | 
				
			||||||
 | 
					        "path-browserify": "^1.0.1"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "peerDependencies": {
 | 
				
			||||||
 | 
					        "typescript": "*"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "peerDependenciesMeta": {
 | 
				
			||||||
 | 
					        "typescript": {
 | 
				
			||||||
 | 
					          "optional": true
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/abbrev": {
 | 
					    "node_modules/abbrev": {
 | 
				
			||||||
      "version": "2.0.0",
 | 
					      "version": "2.0.0",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz",
 | 
				
			||||||
| 
						 | 
					@ -1938,6 +1976,13 @@
 | 
				
			||||||
        "url": "https://github.com/sponsors/epoberezkin"
 | 
					        "url": "https://github.com/sponsors/epoberezkin"
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/alien-signals": {
 | 
				
			||||||
 | 
					      "version": "0.2.2",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-0.2.2.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-cZIRkbERILsBOXTQmMrxc9hgpxglstn69zm+F1ARf4aPAzdAFYd6sBq87ErO0Fj3DV94tglcyHG5kQz9nDC/8A==",
 | 
				
			||||||
 | 
					      "dev": true,
 | 
				
			||||||
 | 
					      "license": "MIT"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/ansi-colors": {
 | 
					    "node_modules/ansi-colors": {
 | 
				
			||||||
      "version": "4.1.3",
 | 
					      "version": "4.1.3",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -38,6 +38,7 @@
 | 
				
			||||||
    "@vue/eslint-config-typescript": "^14.0.1",
 | 
					    "@vue/eslint-config-typescript": "^14.0.1",
 | 
				
			||||||
    "@vue/test-utils": "^2.4.6",
 | 
					    "@vue/test-utils": "^2.4.6",
 | 
				
			||||||
    "@vue/tsconfig": "^0.5.1",
 | 
					    "@vue/tsconfig": "^0.5.1",
 | 
				
			||||||
 | 
					    "@vue/typescript-plugin": "^2.1.10",
 | 
				
			||||||
    "autoprefixer": "^10.4.20",
 | 
					    "autoprefixer": "^10.4.20",
 | 
				
			||||||
    "cypress": "^13.15.0",
 | 
					    "cypress": "^13.15.0",
 | 
				
			||||||
    "eslint": "^9.12.0",
 | 
					    "eslint": "^9.12.0",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,12 +1,15 @@
 | 
				
			||||||
<script setup lang="ts">
 | 
					<script setup lang="ts">
 | 
				
			||||||
import { type TeamInviteSchema } from "../client";
 | 
					import { type TeamInviteSchema } from "../client";
 | 
				
			||||||
import { useTeamsStore } from "../stores/teams";
 | 
					import { useTeamsStore } from "../stores/teams";
 | 
				
			||||||
import { computed } from "vue";
 | 
					import { computed, type PropType } from "vue";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const teamsStore = useTeamsStore();
 | 
					const teamsStore = useTeamsStore();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const props = defineProps({
 | 
					const props = defineProps({
 | 
				
			||||||
  invite: Object as PropType<TeamInviteSchema>,
 | 
					  invite: {
 | 
				
			||||||
 | 
					    type: Object as PropType<TeamInviteSchema>,
 | 
				
			||||||
 | 
					    required: true,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const inviteLink = computed(() => {
 | 
					const inviteLink = computed(() => {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,41 @@
 | 
				
			||||||
 | 
					import { useTeamsStore } from "@/stores/teams";
 | 
				
			||||||
 | 
					import { computed } from "vue";
 | 
				
			||||||
 | 
					import { useRoute } from "vue-router";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function useTeamDetails() {
 | 
				
			||||||
 | 
					  const route = useRoute();
 | 
				
			||||||
 | 
					  const teamsStore = useTeamsStore();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const teamId = computed(() => Number(route.params.id));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const team = computed(() => {
 | 
				
			||||||
 | 
					    return teamsStore.teams[teamId.value];
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const invites = computed(() => {
 | 
				
			||||||
 | 
					    return teamsStore.teamInvites[teamId.value];
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const teamMembers = computed(() => {
 | 
				
			||||||
 | 
					    return teamsStore.teamMembers[teamId.value];
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const availableMembers = computed(() => {
 | 
				
			||||||
 | 
					    return teamsStore.teamMembers[teamId.value]
 | 
				
			||||||
 | 
					      .filter((member) => member.availability[0] > 0);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const availableMembersNextHour = computed(() => {
 | 
				
			||||||
 | 
					    return teamsStore.teamMembers[teamId.value]
 | 
				
			||||||
 | 
					      .filter((member) => member.availability[1] > 0);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return {
 | 
				
			||||||
 | 
					    team,
 | 
				
			||||||
 | 
					    teamId,
 | 
				
			||||||
 | 
					    invites,
 | 
				
			||||||
 | 
					    teamMembers,
 | 
				
			||||||
 | 
					    availableMembers,
 | 
				
			||||||
 | 
					    availableMembersNextHour,
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,10 @@
 | 
				
			||||||
 | 
					import { ref } from "vue";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function useTeamSettings() {
 | 
				
			||||||
 | 
					  const teamName = ref("");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const timezone = ref(
 | 
				
			||||||
 | 
					    Intl.DateTimeFormat().resolvedOptions().timeZone ??
 | 
				
			||||||
 | 
					      "Etc/UTC"
 | 
				
			||||||
 | 
					  );
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -6,6 +6,7 @@ import LoginView from "../views/LoginView.vue";
 | 
				
			||||||
import TeamRegistrationView from "../views/TeamRegistrationView.vue";
 | 
					import TeamRegistrationView from "../views/TeamRegistrationView.vue";
 | 
				
			||||||
import TeamDetailsView from "../views/TeamDetailsView.vue";
 | 
					import TeamDetailsView from "../views/TeamDetailsView.vue";
 | 
				
			||||||
import { useAuthStore } from "@/stores/auth";
 | 
					import { useAuthStore } from "@/stores/auth";
 | 
				
			||||||
 | 
					import TeamDetailsMembersListView from "../views/TeamDetailsMembersListView.vue";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const router = createRouter({
 | 
					const router = createRouter({
 | 
				
			||||||
  history: createWebHistory(import.meta.env.BASE_URL),
 | 
					  history: createWebHistory(import.meta.env.BASE_URL),
 | 
				
			||||||
| 
						 | 
					@ -39,10 +40,16 @@ const router = createRouter({
 | 
				
			||||||
      path: "/team/id/:id",
 | 
					      path: "/team/id/:id",
 | 
				
			||||||
      name: "team-details",
 | 
					      name: "team-details",
 | 
				
			||||||
      component: TeamDetailsView,
 | 
					      component: TeamDetailsView,
 | 
				
			||||||
      //children: [
 | 
					      children: [
 | 
				
			||||||
      //  path: "members",
 | 
					        {
 | 
				
			||||||
      //  component:
 | 
					          path: "",
 | 
				
			||||||
      //],
 | 
					          component: TeamDetailsMembersListView,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          path: "",
 | 
				
			||||||
 | 
					          component: TeamDetailsMembersListView,
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					      ],
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
  ]
 | 
					  ]
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,7 @@
 | 
				
			||||||
import { defineStore } from "pinia";
 | 
					import { defineStore } from "pinia";
 | 
				
			||||||
import { ref } from "vue";
 | 
					import { ref } from "vue";
 | 
				
			||||||
import { useClientStore } from "./client";
 | 
					import { useClientStore } from "./client";
 | 
				
			||||||
 | 
					import type { LocationQuery } from "vue-router";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const useAuthStore = defineStore("auth", () => {
 | 
					export const useAuthStore = defineStore("auth", () => {
 | 
				
			||||||
  const clientStore = useClientStore();
 | 
					  const clientStore = useClientStore();
 | 
				
			||||||
| 
						 | 
					@ -25,7 +26,7 @@ export const useAuthStore = defineStore("auth", () => {
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  async function login(queryParams: { [key: string]: string }) {
 | 
					  async function login(queryParams: LocationQuery) {
 | 
				
			||||||
    return fetch(import.meta.env.VITE_API_BASE_URL + "/login/authenticate", {
 | 
					    return fetch(import.meta.env.VITE_API_BASE_URL + "/login/authenticate", {
 | 
				
			||||||
      headers: {
 | 
					      headers: {
 | 
				
			||||||
        "Content-Type": "application/json",
 | 
					        "Content-Type": "application/json",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,13 +12,6 @@ const auth = useAuthStore();
 | 
				
			||||||
const registerUsername = ref("");
 | 
					const registerUsername = ref("");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function register() {
 | 
					function register() {
 | 
				
			||||||
  //const params = {
 | 
					 | 
				
			||||||
  //  ...queryParams.value,
 | 
					 | 
				
			||||||
  //  username: registerUsername.value,
 | 
					 | 
				
			||||||
  //};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  //auth.login(params)
 | 
					 | 
				
			||||||
  //  .then(() => router.push("/"));
 | 
					 | 
				
			||||||
  auth.setUsername(registerUsername.value)
 | 
					  auth.setUsername(registerUsername.value)
 | 
				
			||||||
    .then(() => router.push("/"));
 | 
					    .then(() => router.push("/"));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -39,8 +32,8 @@ onMounted(() => {
 | 
				
			||||||
      <template v-if="auth.isRegistering">
 | 
					      <template v-if="auth.isRegistering">
 | 
				
			||||||
        <h1>New account</h1>
 | 
					        <h1>New account</h1>
 | 
				
			||||||
        <p>
 | 
					        <p>
 | 
				
			||||||
          Your account has been newly created. Select a username to be
 | 
					          Your account has been created with your username set to your Steam ID
 | 
				
			||||||
          associated with this account.
 | 
					          by default. Select a new username to be associated with this account.
 | 
				
			||||||
        </p>
 | 
					        </p>
 | 
				
			||||||
        <div class="form-group margin">
 | 
					        <div class="form-group margin">
 | 
				
			||||||
          <h3>Username</h3>
 | 
					          <h3>Username</h3>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,153 @@
 | 
				
			||||||
 | 
					<script setup lang="ts">
 | 
				
			||||||
 | 
					import { useTeamsStore } from "../stores/teams";
 | 
				
			||||||
 | 
					import { useRoute, useRouter, RouterLink } from "vue-router";
 | 
				
			||||||
 | 
					import { computed } from "vue";
 | 
				
			||||||
 | 
					import { useTeamDetails } from "../composables/team-details";
 | 
				
			||||||
 | 
					import PlayerTeamCard from "../components/PlayerTeamCard.vue";
 | 
				
			||||||
 | 
					import InviteEntry from "../components/InviteEntry.vue";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const route = useRoute();
 | 
				
			||||||
 | 
					const router = useRouter();
 | 
				
			||||||
 | 
					const teamsStore = useTeamsStore();
 | 
				
			||||||
 | 
					const {
 | 
				
			||||||
 | 
					  team,
 | 
				
			||||||
 | 
					  invites,
 | 
				
			||||||
 | 
					  availableMembers,
 | 
				
			||||||
 | 
					  availableMembersNextHour,
 | 
				
			||||||
 | 
					  teamMembers,
 | 
				
			||||||
 | 
					} = useTeamDetails();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function createInvite() {
 | 
				
			||||||
 | 
					  teamsStore.createInvite(team.value.id);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function leaveTeam() {
 | 
				
			||||||
 | 
					  teamsStore.leaveTeam(team.value.id)
 | 
				
			||||||
 | 
					    .then(() => {
 | 
				
			||||||
 | 
					      teamsStore.fetchTeams()
 | 
				
			||||||
 | 
					        .then(() => {
 | 
				
			||||||
 | 
					          router.push("/");
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <div class="member-list-header">
 | 
				
			||||||
 | 
					    <h2>Members</h2>
 | 
				
			||||||
 | 
					    <em class="aside" v-if="teamMembers">
 | 
				
			||||||
 | 
					      {{ teamMembers?.length }} member(s),
 | 
				
			||||||
 | 
					      {{ availableMembers?.length }} currently available,
 | 
				
			||||||
 | 
					      {{ availableMembersNextHour?.length }} available in the next hour
 | 
				
			||||||
 | 
					    </em>
 | 
				
			||||||
 | 
					    <div class="team-details-button-group">
 | 
				
			||||||
 | 
					      <RouterLink class="button" :to="'/schedule?teamId=' + team.id">
 | 
				
			||||||
 | 
					        <button class="accent">
 | 
				
			||||||
 | 
					          <i class="bi bi-calendar-fill margin"></i>
 | 
				
			||||||
 | 
					          View schedule
 | 
				
			||||||
 | 
					        </button>
 | 
				
			||||||
 | 
					      </RouterLink>
 | 
				
			||||||
 | 
					      <button
 | 
				
			||||||
 | 
					        class="destructive"
 | 
				
			||||||
 | 
					        @click="leaveTeam"
 | 
				
			||||||
 | 
					      >
 | 
				
			||||||
 | 
					        Leave
 | 
				
			||||||
 | 
					      </button>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					  <table class="member-table">
 | 
				
			||||||
 | 
					    <tbody>
 | 
				
			||||||
 | 
					      <PlayerTeamCard
 | 
				
			||||||
 | 
					        v-for="member in teamMembers"
 | 
				
			||||||
 | 
					        :player="member"
 | 
				
			||||||
 | 
					        :team="team"
 | 
				
			||||||
 | 
					        :key="member.username"
 | 
				
			||||||
 | 
					      />
 | 
				
			||||||
 | 
					    </tbody>
 | 
				
			||||||
 | 
					  </table>
 | 
				
			||||||
 | 
					  <h2>Active Invites</h2>
 | 
				
			||||||
 | 
					  <div>
 | 
				
			||||||
 | 
					    <details>
 | 
				
			||||||
 | 
					      <summary>View all invites</summary>
 | 
				
			||||||
 | 
					      <span v-if="invites?.length == 0">
 | 
				
			||||||
 | 
					        There are currently no active invites to this team.
 | 
				
			||||||
 | 
					      </span>
 | 
				
			||||||
 | 
					      <table id="invite-table" v-else>
 | 
				
			||||||
 | 
					        <thead>
 | 
				
			||||||
 | 
					          <tr>
 | 
				
			||||||
 | 
					            <th>
 | 
				
			||||||
 | 
					              Key (hover to reveal)
 | 
				
			||||||
 | 
					            </th>
 | 
				
			||||||
 | 
					            <th>
 | 
				
			||||||
 | 
					              Creation time
 | 
				
			||||||
 | 
					            </th>
 | 
				
			||||||
 | 
					          </tr>
 | 
				
			||||||
 | 
					        </thead>
 | 
				
			||||||
 | 
					        <tbody>
 | 
				
			||||||
 | 
					          <InviteEntry
 | 
				
			||||||
 | 
					            v-for="invite in invites"
 | 
				
			||||||
 | 
					            :invite="invite"
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
 | 
					        </tbody>
 | 
				
			||||||
 | 
					      </table>
 | 
				
			||||||
 | 
					      <div class="create-invite-group">
 | 
				
			||||||
 | 
					        <button class="accent" @click="createInvite">
 | 
				
			||||||
 | 
					          <i class="bi bi-person-fill-add margin" />
 | 
				
			||||||
 | 
					          Create Invite
 | 
				
			||||||
 | 
					        </button>
 | 
				
			||||||
 | 
					        <span class="small aside">
 | 
				
			||||||
 | 
					          Invites are usable once and expire after 24 hours.
 | 
				
			||||||
 | 
					        </span>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					    </details>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style scoped>
 | 
				
			||||||
 | 
					.member-list-header {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  gap: 0.5em;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.member-list-header > .aside {
 | 
				
			||||||
 | 
					  font-size: 12pt;
 | 
				
			||||||
 | 
					  font-style: normal;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					table.member-table {
 | 
				
			||||||
 | 
					  width: 100%;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					table.member-table th {
 | 
				
			||||||
 | 
					  text-align: left;
 | 
				
			||||||
 | 
					  padding-left: 2em;
 | 
				
			||||||
 | 
					  font-weight: 700;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					th {
 | 
				
			||||||
 | 
					  text-align: left;
 | 
				
			||||||
 | 
					  font-weight: 600;
 | 
				
			||||||
 | 
					  padding: 8px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#invite-table {
 | 
				
			||||||
 | 
					  width: 100%;
 | 
				
			||||||
 | 
					  border: 1px solid var(--text);
 | 
				
			||||||
 | 
					  margin: 8px 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.team-details-button-group {
 | 
				
			||||||
 | 
					  flex: 1;
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					  justify-content: end;
 | 
				
			||||||
 | 
					  gap: 4px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.create-invite-group {
 | 
				
			||||||
 | 
					  display: flex;
 | 
				
			||||||
 | 
					  gap: 8px;
 | 
				
			||||||
 | 
					  align-items: center;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
| 
						 | 
					@ -1,18 +1,14 @@
 | 
				
			||||||
<script setup lang="ts">
 | 
					<script setup lang="ts">
 | 
				
			||||||
import { useRoute, useRouter, RouterLink } from "vue-router";
 | 
					import { useRoute, useRouter, RouterLink, RouterView } from "vue-router";
 | 
				
			||||||
import { useTeamsStore } from "../stores/teams";
 | 
					import { useTeamsStore } from "../stores/teams";
 | 
				
			||||||
import { computed, onMounted, ref } from "vue";
 | 
					import { computed, onMounted, ref } from "vue";
 | 
				
			||||||
import PlayerTeamCard from "../components/PlayerTeamCard.vue";
 | 
					import { useTeamDetails } from "../composables/team-details";
 | 
				
			||||||
import InviteEntry from "../components/InviteEntry.vue";
 | 
					 | 
				
			||||||
import moment from "moment";
 | 
					import moment from "moment";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const route = useRoute();
 | 
					const route = useRoute();
 | 
				
			||||||
const router = useRouter();
 | 
					const router = useRouter();
 | 
				
			||||||
const teamsStore = useTeamsStore();
 | 
					const teamsStore = useTeamsStore();
 | 
				
			||||||
 | 
					const { team, teamId } = useTeamDetails();
 | 
				
			||||||
const team = computed(() => {
 | 
					 | 
				
			||||||
  return teamsStore.teams[route.params.id];
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const creationDate = computed(() => {
 | 
					const creationDate = computed(() => {
 | 
				
			||||||
  if (team.value) {
 | 
					  if (team.value) {
 | 
				
			||||||
| 
						 | 
					@ -20,55 +16,21 @@ const creationDate = computed(() => {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const invites = computed(() => {
 | 
					const key = computed(() => route.query.key);
 | 
				
			||||||
  return teamsStore.teamInvites[route.params.id];
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const availableMembers = computed(() => {
 | 
					 | 
				
			||||||
  return teamsStore.teamMembers[route.params.id]
 | 
					 | 
				
			||||||
    .filter((member) => member.availability[0] > 0);
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const availableMembersNextHour = computed(() => {
 | 
					 | 
				
			||||||
  return teamsStore.teamMembers[route.params.id]
 | 
					 | 
				
			||||||
    .filter((member) => member.availability[1] > 0);
 | 
					 | 
				
			||||||
});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function createInvite() {
 | 
					 | 
				
			||||||
  teamsStore.createInvite(team.value.id);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function revokeInvite(key) {
 | 
					 | 
				
			||||||
  teamsStore.revokeInvite(team.value.id, key)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
function leaveTeam() {
 | 
					 | 
				
			||||||
  teamsStore.leaveTeam(team.value.id)
 | 
					 | 
				
			||||||
    .then(() => {
 | 
					 | 
				
			||||||
      teamsStore.fetchTeams()
 | 
					 | 
				
			||||||
        .then(() => {
 | 
					 | 
				
			||||||
          router.push("/");
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
    });
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
onMounted(async () => {
 | 
					 | 
				
			||||||
  let key = route.query.key;
 | 
					 | 
				
			||||||
  let teamId = route.params.id;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					onMounted(() => {
 | 
				
			||||||
  let doFetchTeam = () => {
 | 
					  let doFetchTeam = () => {
 | 
				
			||||||
    teamsStore.fetchTeam(teamId)
 | 
					    teamsStore.fetchTeam(teamId.value)
 | 
				
			||||||
      .then(() => teamsStore.fetchTeamMembers(teamId))
 | 
					      .then(() => teamsStore.fetchTeamMembers(teamId.value))
 | 
				
			||||||
      .then(() => teamsStore.getInvites(teamId));
 | 
					      .then(() => teamsStore.getInvites(teamId.value));
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (key) {
 | 
					  if (key.value) {
 | 
				
			||||||
    teamsStore.consumeInvite(teamId, key)
 | 
					    teamsStore.consumeInvite(teamId.value, key.value.toString())
 | 
				
			||||||
      .finally(doFetchTeam);
 | 
					      .finally(doFetchTeam);
 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    doFetchTeam();
 | 
					    doFetchTeam();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -83,90 +45,7 @@ onMounted(async () => {
 | 
				
			||||||
          Formed on {{ creationDate }}
 | 
					          Formed on {{ creationDate }}
 | 
				
			||||||
        </span>
 | 
					        </span>
 | 
				
			||||||
      </center>
 | 
					      </center>
 | 
				
			||||||
      <div class="member-list-header">
 | 
					      <RouterView />
 | 
				
			||||||
        <h2>Members</h2>
 | 
					 | 
				
			||||||
        <em class="aside" v-if="teamsStore.teamMembers[route.params.id]">
 | 
					 | 
				
			||||||
          {{ teamsStore.teamMembers[route.params.id]?.length }} member(s),
 | 
					 | 
				
			||||||
          {{ availableMembers?.length }} currently available,
 | 
					 | 
				
			||||||
          {{ availableMembersNextHour?.length }} available in the next hour
 | 
					 | 
				
			||||||
        </em>
 | 
					 | 
				
			||||||
        <div class="team-details-button-group">
 | 
					 | 
				
			||||||
          <RouterLink class="button" :to="'/schedule?teamId=' + team.id">
 | 
					 | 
				
			||||||
            <button class="accent">
 | 
					 | 
				
			||||||
              <i class="bi bi-calendar-fill margin"></i>
 | 
					 | 
				
			||||||
              View schedule
 | 
					 | 
				
			||||||
            </button>
 | 
					 | 
				
			||||||
          </RouterLink>
 | 
					 | 
				
			||||||
          <button
 | 
					 | 
				
			||||||
            class="destructive"
 | 
					 | 
				
			||||||
            @click="leaveTeam"
 | 
					 | 
				
			||||||
          >
 | 
					 | 
				
			||||||
            Leave
 | 
					 | 
				
			||||||
          </button>
 | 
					 | 
				
			||||||
        </div>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
      <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"
 | 
					 | 
				
			||||||
            :team="team"
 | 
					 | 
				
			||||||
            :key="member.username"
 | 
					 | 
				
			||||||
          />
 | 
					 | 
				
			||||||
        </tbody>
 | 
					 | 
				
			||||||
      </table>
 | 
					 | 
				
			||||||
      <h2>Active Invites</h2>
 | 
					 | 
				
			||||||
      <div>
 | 
					 | 
				
			||||||
        <details>
 | 
					 | 
				
			||||||
          <summary>View all invites</summary>
 | 
					 | 
				
			||||||
          <span v-if="invites?.length == 0">
 | 
					 | 
				
			||||||
            There are currently no active invites to this team.
 | 
					 | 
				
			||||||
          </span>
 | 
					 | 
				
			||||||
          <table id="invite-table" v-else>
 | 
					 | 
				
			||||||
            <thead>
 | 
					 | 
				
			||||||
              <tr>
 | 
					 | 
				
			||||||
                <th>
 | 
					 | 
				
			||||||
                  Key (hover to reveal)
 | 
					 | 
				
			||||||
                </th>
 | 
					 | 
				
			||||||
                <th>
 | 
					 | 
				
			||||||
                  Creation time
 | 
					 | 
				
			||||||
                </th>
 | 
					 | 
				
			||||||
              </tr>
 | 
					 | 
				
			||||||
            </thead>
 | 
					 | 
				
			||||||
            <tbody>
 | 
					 | 
				
			||||||
              <InviteEntry
 | 
					 | 
				
			||||||
                v-for="invite in invites"
 | 
					 | 
				
			||||||
                :invite="invite"
 | 
					 | 
				
			||||||
              />
 | 
					 | 
				
			||||||
            </tbody>
 | 
					 | 
				
			||||||
          </table>
 | 
					 | 
				
			||||||
          <div class="create-invite-group">
 | 
					 | 
				
			||||||
            <button class="accent" @click="createInvite">
 | 
					 | 
				
			||||||
              <i class="bi bi-person-fill-add margin" />
 | 
					 | 
				
			||||||
              Create Invite
 | 
					 | 
				
			||||||
            </button>
 | 
					 | 
				
			||||||
            <span class="small aside">
 | 
					 | 
				
			||||||
              Invites are usable once and expire after 24 hours.
 | 
					 | 
				
			||||||
            </span>
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
        </details>
 | 
					 | 
				
			||||||
      </div>
 | 
					 | 
				
			||||||
    </template>
 | 
					    </template>
 | 
				
			||||||
  </main>
 | 
					  </main>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
| 
						 | 
					@ -175,59 +54,4 @@ onMounted(async () => {
 | 
				
			||||||
.team-info {
 | 
					.team-info {
 | 
				
			||||||
  margin: 4em;
 | 
					  margin: 4em;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
.member-list-header {
 | 
					 | 
				
			||||||
  display: flex;
 | 
					 | 
				
			||||||
  gap: 0.5em;
 | 
					 | 
				
			||||||
  align-items: center;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.member-list-header > .aside {
 | 
					 | 
				
			||||||
  font-size: 12pt;
 | 
					 | 
				
			||||||
  font-style: normal;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
*/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
th {
 | 
					 | 
				
			||||||
  text-align: left;
 | 
					 | 
				
			||||||
  font-weight: 600;
 | 
					 | 
				
			||||||
  padding: 8px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#invite-table {
 | 
					 | 
				
			||||||
  width: 100%;
 | 
					 | 
				
			||||||
  border: 1px solid var(--text);
 | 
					 | 
				
			||||||
  margin: 8px 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.team-details-button-group {
 | 
					 | 
				
			||||||
  flex: 1;
 | 
					 | 
				
			||||||
  display: flex;
 | 
					 | 
				
			||||||
  align-items: center;
 | 
					 | 
				
			||||||
  justify-content: end;
 | 
					 | 
				
			||||||
  gap: 4px;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.create-invite-group {
 | 
					 | 
				
			||||||
  display: flex;
 | 
					 | 
				
			||||||
  gap: 8px;
 | 
					 | 
				
			||||||
  align-items: center;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
</style>
 | 
					</style>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
<script lang="ts" setup>
 | 
					<script lang="ts" setup>
 | 
				
			||||||
import { ref, watch } from "vue";
 | 
					import { ref, watch } from "vue";
 | 
				
			||||||
import { useTeamsStore } from "../stores/teams.ts"
 | 
					import { useTeamsStore } from "../stores/teams";
 | 
				
			||||||
import timezones from "../assets/timezones.json";
 | 
					import timezones from "../assets/timezones.json";
 | 
				
			||||||
import { useRouter } from "vue-router";
 | 
					import { useRouter } from "vue-router";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue