Add timezone-aware schedule window
							parent
							
								
									fc6092d282
								
							
						
					
					
						commit
						1bf4cc3125
					
				| 
						 | 
					@ -5,6 +5,8 @@
 | 
				
			||||||
export type TeamSchema = {
 | 
					export type TeamSchema = {
 | 
				
			||||||
    discordWebhookUrl?: string;
 | 
					    discordWebhookUrl?: string;
 | 
				
			||||||
    id: number;
 | 
					    id: number;
 | 
				
			||||||
 | 
					    minuteOffset: number;
 | 
				
			||||||
    teamName: string;
 | 
					    teamName: string;
 | 
				
			||||||
 | 
					    tzTimezone: string;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,31 @@
 | 
				
			||||||
 | 
					import { beforeEach, describe, expect, it } from "vitest";
 | 
				
			||||||
 | 
					import { useScheduleStore } from "./schedule";
 | 
				
			||||||
 | 
					import { createPinia, setActivePinia } from "pinia";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					describe("Schedule store", () => {
 | 
				
			||||||
 | 
					  beforeEach(() => {
 | 
				
			||||||
 | 
					    setActivePinia(createPinia());
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it("should return the proper window start for any timezone", () => {
 | 
				
			||||||
 | 
					    const scheduleStore = useScheduleStore();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let test1 = scheduleStore.getWindowStart({
 | 
				
			||||||
 | 
					      teamName: "",
 | 
				
			||||||
 | 
					      id: 0,
 | 
				
			||||||
 | 
					      tzTimezone: "Asia/Kolkata",
 | 
				
			||||||
 | 
					      minuteOffset: 10,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(test1.get("minutes")).toEqual(40);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let test2 = scheduleStore.getWindowStart({
 | 
				
			||||||
 | 
					      teamName: "",
 | 
				
			||||||
 | 
					      id: 0,
 | 
				
			||||||
 | 
					      tzTimezone: "America/New_York",
 | 
				
			||||||
 | 
					      minuteOffset: 30,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expect(test2.get("minutes")).toEqual(30);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,9 @@ import { defineStore } from "pinia";
 | 
				
			||||||
import { reactive, ref, watch } from "vue";
 | 
					import { reactive, ref, watch } from "vue";
 | 
				
			||||||
import { useRoute, useRouter } from "vue-router";
 | 
					import { useRoute, useRouter } from "vue-router";
 | 
				
			||||||
import { useClientStore } from "./client";
 | 
					import { useClientStore } from "./client";
 | 
				
			||||||
 | 
					import type { TeamSchema } from "@/client";
 | 
				
			||||||
 | 
					import moment from "moment";
 | 
				
			||||||
 | 
					import "moment-timezone";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const useScheduleStore = defineStore("schedule", () => {
 | 
					export const useScheduleStore = defineStore("schedule", () => {
 | 
				
			||||||
  const client = useClientStore().client;
 | 
					  const client = useClientStore().client;
 | 
				
			||||||
| 
						 | 
					@ -18,23 +21,43 @@ export const useScheduleStore = defineStore("schedule", () => {
 | 
				
			||||||
  const route = useRoute();
 | 
					  const route = useRoute();
 | 
				
			||||||
  const router = useRouter();
 | 
					  const router = useRouter();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const teamId = computed({
 | 
					  //const teamId = computed({
 | 
				
			||||||
    get: () => Number(route.query.teamId),
 | 
					  //  get: () => Number(route?.query?.teamId),
 | 
				
			||||||
    set: (value) => router.push({ query: { teamId: value } }),
 | 
					  //  set: (value) => router.push({ query: { teamId: value } }),
 | 
				
			||||||
  });
 | 
					  //});
 | 
				
			||||||
 | 
					  const team = ref();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  function getWindowStart(team: TeamSchema) {
 | 
				
			||||||
 | 
					    // convert local 00:00 to league timezone
 | 
				
			||||||
 | 
					    let localMidnight = moment().startOf("isoWeek");
 | 
				
			||||||
 | 
					    let leagueTime = localMidnight.clone().tz(team.tz_timezone);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let nextMinuteOffsetTime = leagueTime.clone();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (nextMinuteOffsetTime.minute() > team.minute_offset) {
 | 
				
			||||||
 | 
					      nextMinuteOffsetTime.add(1, "hour");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    nextMinuteOffsetTime.minute(team.minute_offset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const deltaMinutes = nextMinuteOffsetTime.diff(leagueTime, "minutes");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return localMidnight.clone().add(deltaMinutes, "minutes");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  watch(dateStart, () => {
 | 
					  watch(dateStart, () => {
 | 
				
			||||||
    fetchSchedule();
 | 
					    fetchSchedule();
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  watch(teamId, () => {
 | 
					  watch(team, () => {
 | 
				
			||||||
    fetchSchedule();
 | 
					    dateStart.value = getWindowStart(team.value).toDate();
 | 
				
			||||||
 | 
					    console.log(dateStart.value);
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  async function fetchSchedule() {
 | 
					  async function fetchSchedule() {
 | 
				
			||||||
    return client.default.getApiSchedule(
 | 
					    return client.default.getApiSchedule(
 | 
				
			||||||
      Math.floor(dateStart.value.getTime() / 1000).toString(),
 | 
					      Math.floor(dateStart.value.getTime() / 1000).toString(),
 | 
				
			||||||
      teamId.value,
 | 
					      team.value.id,
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
      .then((response) => {
 | 
					      .then((response) => {
 | 
				
			||||||
        response.availability.forEach((value, i) => {
 | 
					        response.availability.forEach((value, i) => {
 | 
				
			||||||
| 
						 | 
					@ -60,7 +83,7 @@ export const useScheduleStore = defineStore("schedule", () => {
 | 
				
			||||||
  async function saveSchedule() {
 | 
					  async function saveSchedule() {
 | 
				
			||||||
    return client.default.putApiSchedule({
 | 
					    return client.default.putApiSchedule({
 | 
				
			||||||
      windowStart: Math.floor(dateStart.value.getTime() / 1000).toString(),
 | 
					      windowStart: Math.floor(dateStart.value.getTime() / 1000).toString(),
 | 
				
			||||||
      teamId: teamId.value,
 | 
					      teamId: team.value.id,
 | 
				
			||||||
      availability,
 | 
					      availability,
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
    //return fetch(import.meta.env.VITE_API_BASE_URL + "/schedule", {
 | 
					    //return fetch(import.meta.env.VITE_API_BASE_URL + "/schedule", {
 | 
				
			||||||
| 
						 | 
					@ -83,6 +106,7 @@ export const useScheduleStore = defineStore("schedule", () => {
 | 
				
			||||||
    availability,
 | 
					    availability,
 | 
				
			||||||
    fetchSchedule,
 | 
					    fetchSchedule,
 | 
				
			||||||
    saveSchedule,
 | 
					    saveSchedule,
 | 
				
			||||||
    teamId,
 | 
					    team,
 | 
				
			||||||
 | 
					    getWindowStart,
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,7 +30,7 @@ const selectedTeam = ref();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
watch(selectedTeam, (newTeam) => {
 | 
					watch(selectedTeam, (newTeam) => {
 | 
				
			||||||
  if (newTeam) {
 | 
					  if (newTeam) {
 | 
				
			||||||
    schedule.teamId = newTeam.id;
 | 
					    schedule.team = newTeam;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -47,11 +47,10 @@ onMounted(() => {
 | 
				
			||||||
      options.value = Object.values(teamsList.teams);
 | 
					      options.value = Object.values(teamsList.teams);
 | 
				
			||||||
      // select team with id in query parameter if exists
 | 
					      // select team with id in query parameter if exists
 | 
				
			||||||
      const queryTeam = teamsList.teams.find(x => x.id == route.query.teamId);
 | 
					      const queryTeam = teamsList.teams.find(x => x.id == route.query.teamId);
 | 
				
			||||||
      console.log(queryTeam);
 | 
					 | 
				
			||||||
      if (queryTeam) {
 | 
					      if (queryTeam) {
 | 
				
			||||||
        selectedTeam.value = queryTeam;
 | 
					        selectedTeam.value = queryTeam;
 | 
				
			||||||
        //schedule.teamId = queryTeam.id;
 | 
					        schedule.team = queryTeam;
 | 
				
			||||||
        schedule.fetchSchedule(schedule.teamId);
 | 
					        schedule.fetchSchedule();
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -57,6 +57,8 @@ class TeamSchema(spec.BaseModel):
 | 
				
			||||||
    id: int
 | 
					    id: int
 | 
				
			||||||
    team_name: str
 | 
					    team_name: str
 | 
				
			||||||
    discord_webhook_url: str | None
 | 
					    discord_webhook_url: str | None
 | 
				
			||||||
 | 
					    tz_timezone: str
 | 
				
			||||||
 | 
					    minute_offset: int
 | 
				
			||||||
    #players: list[PlayerTeamSpec] | None
 | 
					    #players: list[PlayerTeamSpec] | None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PlayerTeam(db.Model):
 | 
					class PlayerTeam(db.Model):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,7 +20,9 @@ def map_team_to_schema(team: Team):
 | 
				
			||||||
    return TeamSchema(
 | 
					    return TeamSchema(
 | 
				
			||||||
        id=team.id,
 | 
					        id=team.id,
 | 
				
			||||||
        team_name=team.team_name,
 | 
					        team_name=team.team_name,
 | 
				
			||||||
        discord_webhook_url=None
 | 
					        discord_webhook_url=None,
 | 
				
			||||||
 | 
					        tz_timezone=team.tz_timezone,
 | 
				
			||||||
 | 
					        minute_offset=team.minute_offset
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def map_player_to_schema(player: Player):
 | 
					def map_player_to_schema(player: Player):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue