Improve team page usability
							parent
							
								
									abc456b7d1
								
							
						
					
					
						commit
						9b2153266a
					
				| 
						 | 
				
			
			@ -52,6 +52,10 @@ button {
 | 
			
		|||
  transition-duration: 200ms;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
button.icon-end {
 | 
			
		||||
  justify-content: space-between;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
button.icon {
 | 
			
		||||
  background-color: transparent;
 | 
			
		||||
  padding: 8px;
 | 
			
		||||
| 
						 | 
				
			
			@ -98,6 +102,10 @@ button.destructive {
 | 
			
		|||
  color: var(--base);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
button.destructive-on-hover:hover {
 | 
			
		||||
  background-color: var(--flamingo);
 | 
			
		||||
  color: var(--base);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
button.accent:hover {
 | 
			
		||||
  background-color: var(--text);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -203,7 +203,7 @@ function getAvailabilityCell(day: number, hour: number) {
 | 
			
		|||
const currentTimezone = computed(() =>
 | 
			
		||||
  Intl.DateTimeFormat().resolvedOptions().timeZone);
 | 
			
		||||
 | 
			
		||||
function getHour(offset, tz) {
 | 
			
		||||
function getHour(offset, tz?) {
 | 
			
		||||
  let time = props.dateStart.clone()
 | 
			
		||||
  if (tz) {
 | 
			
		||||
    time = time.tz(tz);
 | 
			
		||||
| 
						 | 
				
			
			@ -226,9 +226,9 @@ function getHour(offset, tz) {
 | 
			
		|||
      </div>
 | 
			
		||||
      <div class="height-24px hour-marker-container">
 | 
			
		||||
        <span class="hour-marker">
 | 
			
		||||
          {{ getHour(hour + 1).format("HH:mm z") }}
 | 
			
		||||
          {{ getHour(lastHour + 1).format("HH:mm z") }}
 | 
			
		||||
          <span v-if="scheduleStore.team.tzTimezone != currentTimezone">
 | 
			
		||||
            / {{ getHour(hour + 1, scheduleStore.team.tzTimezone).format("HH:mm z") }}
 | 
			
		||||
            / {{ getHour(lastHour + 1, scheduleStore.team.tzTimezone).format("HH:mm z") }}
 | 
			
		||||
          </span>
 | 
			
		||||
        </span>
 | 
			
		||||
      </div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -33,7 +33,7 @@ function scheduleRoster() {
 | 
			
		|||
<template>
 | 
			
		||||
  <div class="schedule-player-list">
 | 
			
		||||
    <h3>{{ scheduleStore.team?.teamName }}</h3>
 | 
			
		||||
    <div>
 | 
			
		||||
    <div class="list">
 | 
			
		||||
      <SchedulePlayerListItem
 | 
			
		||||
        v-for="record in scheduleStore.playerAvailability"
 | 
			
		||||
        :player="record"
 | 
			
		||||
| 
						 | 
				
			
			@ -75,4 +75,9 @@ h4, h4 > div {
 | 
			
		|||
.player:hover {
 | 
			
		||||
  background-color: var(--mantle);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.list {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  flex-direction: column;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,8 +8,8 @@ const scheduleStore = useScheduleStore();
 | 
			
		|||
const hoveredIndex = computed(() => scheduleStore.hoveredIndex);
 | 
			
		||||
 | 
			
		||||
const availabilityAtHoveredIndex = computed(() => {
 | 
			
		||||
  if (hoveredIndex.value) {
 | 
			
		||||
    return props.player?.availability[hoveredIndex.value] ?? 0;
 | 
			
		||||
  if (hoveredIndex.value && props.player?.availability) {
 | 
			
		||||
    return props.player.availability[hoveredIndex.value] ?? 0;
 | 
			
		||||
  }
 | 
			
		||||
  return undefined;
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -19,12 +19,14 @@ const props = defineProps({
 | 
			
		|||
});
 | 
			
		||||
 | 
			
		||||
function onMouseOver() {
 | 
			
		||||
  scheduleStore.overlay = props.player;
 | 
			
		||||
  if (props.player) {
 | 
			
		||||
    scheduleStore.hoveredMember = props.player;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function onMouseLeave() {
 | 
			
		||||
  if (scheduleStore.overlay == props.player) {
 | 
			
		||||
    scheduleStore.overlay = undefined;
 | 
			
		||||
  if (scheduleStore.hoveredMember == props.player) {
 | 
			
		||||
    scheduleStore.hoveredMember = undefined;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
| 
						 | 
				
			
			@ -32,10 +34,21 @@ function onMouseLeave() {
 | 
			
		|||
<template>
 | 
			
		||||
  <div
 | 
			
		||||
    class="player"
 | 
			
		||||
    @mouseover="onMouseOver(player)"
 | 
			
		||||
    v-if="player"
 | 
			
		||||
    @mouseover="onMouseOver"
 | 
			
		||||
    @mouseleave="onMouseLeave"
 | 
			
		||||
  >
 | 
			
		||||
    <span v-if="availabilityAtHoveredIndex > 0">
 | 
			
		||||
    <input
 | 
			
		||||
      class="player-checkbox"
 | 
			
		||||
      type="checkbox"
 | 
			
		||||
      v-model="scheduleStore.selectedMembers[player.steamId]"
 | 
			
		||||
      :value="player"
 | 
			
		||||
      :id="player.steamId"
 | 
			
		||||
    />
 | 
			
		||||
    <label
 | 
			
		||||
      :for="player.steamId"
 | 
			
		||||
    >
 | 
			
		||||
      <span v-if="availabilityAtHoveredIndex ?? 0 > 0">
 | 
			
		||||
        <span v-if="availabilityAtHoveredIndex == 1" class="can-be-available">
 | 
			
		||||
          {{ player.username }}
 | 
			
		||||
        </span>
 | 
			
		||||
| 
						 | 
				
			
			@ -49,11 +62,28 @@ function onMouseLeave() {
 | 
			
		|||
      <span v-else>
 | 
			
		||||
        {{ player.username }}
 | 
			
		||||
      </span>
 | 
			
		||||
    </label>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<style scoped>
 | 
			
		||||
.player:hover {
 | 
			
		||||
input {
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
  width: unset;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.player {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  gap: 4px;
 | 
			
		||||
  padding: 6px 8px;
 | 
			
		||||
  border-radius: 4px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.player label {
 | 
			
		||||
  flex-grow: 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.player label:hover {
 | 
			
		||||
  background-color: var(--mantle);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,8 +19,9 @@ export const useAuthStore = defineStore("auth", () => {
 | 
			
		|||
      getUser.name,
 | 
			
		||||
      () => client.default.getUser(),
 | 
			
		||||
      (response) => {
 | 
			
		||||
        isLoggedIn.value = true;
 | 
			
		||||
        steamId.value = response.steamId;
 | 
			
		||||
        username.value = username.value;
 | 
			
		||||
        username.value = response.username;
 | 
			
		||||
        return response;
 | 
			
		||||
      }
 | 
			
		||||
    );
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -29,9 +29,36 @@ export const useScheduleStore = defineStore("schedule", () => {
 | 
			
		|||
 | 
			
		||||
  const playerAvailability: Ref<AvailabilitySchema[]> = ref([ ]);
 | 
			
		||||
 | 
			
		||||
  const overlay: Ref<AvailabilitySchema[] | undefined> = ref();
 | 
			
		||||
  const overlay = computed<number[] | undefined>(() => {
 | 
			
		||||
    let members = Object.keys(selectedMembers)
 | 
			
		||||
      .filter((x) => selectedMembers[x]);
 | 
			
		||||
    if (members.length > 0) {
 | 
			
		||||
      const min = Array(168).fill(0);
 | 
			
		||||
 | 
			
		||||
  const selectedMembers = ref<AvailabilitySchema[]>();
 | 
			
		||||
      const candidates = playerAvailability.value
 | 
			
		||||
        .filter((x) => members.includes(x.steamId));
 | 
			
		||||
      for (let i = 0; i < 168; i++) {
 | 
			
		||||
        min[i] = Math.min(
 | 
			
		||||
          ...candidates.map((c) => c.availability ? c.availability[i] : 0));
 | 
			
		||||
      }
 | 
			
		||||
      //for (const availability of candidates) {
 | 
			
		||||
      //}
 | 
			
		||||
 | 
			
		||||
      return min;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (hoveredMember.value) {
 | 
			
		||||
      return playerAvailability.value
 | 
			
		||||
        .find((x) => x.steamId == hoveredMember.value?.steamId)
 | 
			
		||||
        ?.availability;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return undefined;
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  const hoveredMember = ref<AvailabilitySchema>();
 | 
			
		||||
 | 
			
		||||
  const selectedMembers = reactive<{ [id: string]: boolean }>({ });
 | 
			
		||||
 | 
			
		||||
  const hoveredIndex: Ref<number | undefined> = ref();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -115,6 +142,7 @@ export const useScheduleStore = defineStore("schedule", () => {
 | 
			
		|||
    availability,
 | 
			
		||||
    playerAvailability,
 | 
			
		||||
    overlay,
 | 
			
		||||
    hoveredMember,
 | 
			
		||||
    selectedMembers,
 | 
			
		||||
    hoveredIndex,
 | 
			
		||||
    fetchSchedule,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -28,7 +28,7 @@ const selectionMode = ref(1);
 | 
			
		|||
 | 
			
		||||
const selectedTime = ref(undefined);
 | 
			
		||||
 | 
			
		||||
const availabilityOverlay = computed(() => schedule.overlay?.availability);
 | 
			
		||||
const availabilityOverlay = computed(() => schedule.overlay);
 | 
			
		||||
 | 
			
		||||
const isEditing = ref(false);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -132,7 +132,8 @@ onMounted(() => {
 | 
			
		|||
              Copy previous week
 | 
			
		||||
            </button>
 | 
			
		||||
            <button class="accent" @click="isEditing = true">
 | 
			
		||||
              <i class="bi bi-pencil-fill"></i>
 | 
			
		||||
              <i class="bi bi-pencil-fill margin"></i>
 | 
			
		||||
              Edit
 | 
			
		||||
            </button>
 | 
			
		||||
          </template>
 | 
			
		||||
        </div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,6 +7,10 @@ const {
 | 
			
		|||
  timezone,
 | 
			
		||||
  minuteOffset,
 | 
			
		||||
} = useTeamSettings();
 | 
			
		||||
 | 
			
		||||
function updateTeamSettings() {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2,15 +2,21 @@
 | 
			
		|||
import { useTeamsStore } from "@/stores/teams";
 | 
			
		||||
import { useTeamDetails } from "@/composables/team-details";
 | 
			
		||||
import { onMounted } from "vue";
 | 
			
		||||
import { RouterLink, RouterView } from "vue-router";
 | 
			
		||||
import { RouterLink, RouterView, useRouter } from "vue-router";
 | 
			
		||||
 | 
			
		||||
const teamsStore = useTeamsStore();
 | 
			
		||||
const router = useRouter();
 | 
			
		||||
 | 
			
		||||
const {
 | 
			
		||||
  team,
 | 
			
		||||
  teamId,
 | 
			
		||||
} = useTeamDetails();
 | 
			
		||||
 | 
			
		||||
function leaveTeam() {
 | 
			
		||||
  teamsStore.leaveTeam(teamId.value)
 | 
			
		||||
    .then(() => router.push("/"));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
onMounted(() => {
 | 
			
		||||
  teamsStore.fetchTeam(teamId.value);
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -37,6 +43,10 @@ onMounted(() => {
 | 
			
		|||
          Invites
 | 
			
		||||
        </RouterLink>
 | 
			
		||||
        <hr>
 | 
			
		||||
        <button class="destructive-on-hover icon-end" @click="leaveTeam">
 | 
			
		||||
          Leave team
 | 
			
		||||
          <i class="bi bi-box-arrow-left" />
 | 
			
		||||
        </button>
 | 
			
		||||
      </div>
 | 
			
		||||
    </nav>
 | 
			
		||||
    <div class="view">
 | 
			
		||||
| 
						 | 
				
			
			@ -96,4 +106,17 @@ nav.sidebar a.tab.router-link-exact-active {
 | 
			
		|||
  background-color: var(--crust);
 | 
			
		||||
  color: var(--text);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nav.sidebar button {
 | 
			
		||||
  font-size: 11pt;
 | 
			
		||||
  font-weight: 500;
 | 
			
		||||
  padding: 6px 10px;
 | 
			
		||||
  background-color: transparent;
 | 
			
		||||
  color: var(--overlay-0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
nav.sidebar button:hover {
 | 
			
		||||
  background-color: var(--crust);
 | 
			
		||||
  color: var(--text);
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue