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