Client - init calendar on Dashboard
This commit is contained in:
		@@ -14,6 +14,7 @@
 | 
			
		||||
    "chart.js": "^3.5.1",
 | 
			
		||||
    "core-js": "^3.6.5",
 | 
			
		||||
    "date-fns": "^2.23.0",
 | 
			
		||||
    "date-fns-tz": "^1.1.6",
 | 
			
		||||
    "register-service-worker": "^1.7.1",
 | 
			
		||||
    "vue": "^3.0.0",
 | 
			
		||||
    "vue-chart-3": "^0.5.8",
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								fittrackee_client/public/img/sports/cycling-sport.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								fittrackee_client/public/img/sports/cycling-sport.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 5.4 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								fittrackee_client/public/img/sports/cycling-transport.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								fittrackee_client/public/img/sports/cycling-transport.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 5.5 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								fittrackee_client/public/img/sports/hiking.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								fittrackee_client/public/img/sports/hiking.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 3.0 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								fittrackee_client/public/img/sports/mountain-biking.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								fittrackee_client/public/img/sports/mountain-biking.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 4.3 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								fittrackee_client/public/img/sports/running.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								fittrackee_client/public/img/sports/running.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 3.0 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								fittrackee_client/public/img/sports/walking.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								fittrackee_client/public/img/sports/walking.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 3.5 KiB  | 
@@ -1,3 +0,0 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div>Calendar</div>
 | 
			
		||||
</template>
 | 
			
		||||
@@ -0,0 +1,151 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="calendar-cells">
 | 
			
		||||
    <div class="calendar-row" v-for="(row, index) in rows" :key="index">
 | 
			
		||||
      <div
 | 
			
		||||
        class="calendar-cell"
 | 
			
		||||
        :class="{
 | 
			
		||||
          'disabled-cell': !isSameMonth(day, currentDay),
 | 
			
		||||
          'week-end': isWeekEnd(i),
 | 
			
		||||
          today: isToday(day),
 | 
			
		||||
        }"
 | 
			
		||||
        v-for="(day, i) in row"
 | 
			
		||||
        :key="i"
 | 
			
		||||
      >
 | 
			
		||||
        <CalendarWorkouts
 | 
			
		||||
          :workouts="filterWorkouts(day, workouts)"
 | 
			
		||||
          :sports="sports"
 | 
			
		||||
        />
 | 
			
		||||
        <div class="calendar-cell-day">
 | 
			
		||||
          {{ format(day, 'd') }}
 | 
			
		||||
        </div>
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
  import { addDays, format, isSameDay, isSameMonth, isToday } from 'date-fns'
 | 
			
		||||
  import { defineComponent, PropType, toRefs } from 'vue'
 | 
			
		||||
 | 
			
		||||
  import CalendarWorkouts from '@/components/Dashboard/UserCalendar/CalendarWorkouts.vue'
 | 
			
		||||
  import { ISport } from '@/types/sports'
 | 
			
		||||
  import { IWorkout } from '@/types/workouts'
 | 
			
		||||
  import { getDateWithTZ } from '@/utils/dates'
 | 
			
		||||
 | 
			
		||||
  export default defineComponent({
 | 
			
		||||
    name: 'CalendarCells',
 | 
			
		||||
    components: {
 | 
			
		||||
      CalendarWorkouts,
 | 
			
		||||
    },
 | 
			
		||||
    props: {
 | 
			
		||||
      currentDay: {
 | 
			
		||||
        type: Date,
 | 
			
		||||
        required: true,
 | 
			
		||||
      },
 | 
			
		||||
      endDate: {
 | 
			
		||||
        type: Date,
 | 
			
		||||
        required: true,
 | 
			
		||||
      },
 | 
			
		||||
      sports: {
 | 
			
		||||
        type: Object as PropType<ISport[]>,
 | 
			
		||||
        required: true,
 | 
			
		||||
      },
 | 
			
		||||
      startDate: {
 | 
			
		||||
        type: Date,
 | 
			
		||||
        required: true,
 | 
			
		||||
      },
 | 
			
		||||
      timezone: {
 | 
			
		||||
        type: String,
 | 
			
		||||
        required: true,
 | 
			
		||||
      },
 | 
			
		||||
      weekStartingMonday: {
 | 
			
		||||
        type: Boolean,
 | 
			
		||||
        required: true,
 | 
			
		||||
      },
 | 
			
		||||
      workouts: {
 | 
			
		||||
        type: Object as PropType<IWorkout[]>,
 | 
			
		||||
        required: true,
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    setup(props) {
 | 
			
		||||
      const rows = []
 | 
			
		||||
      let { startDate, endDate, weekStartingMonday } = toRefs(props)
 | 
			
		||||
      let day = startDate.value
 | 
			
		||||
      while (day <= endDate.value) {
 | 
			
		||||
        const days = []
 | 
			
		||||
        for (let i = 0; i < 7; i++) {
 | 
			
		||||
          days.push(day)
 | 
			
		||||
          day = addDays(day, 1)
 | 
			
		||||
        }
 | 
			
		||||
        rows.push(days)
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      function isWeekEnd(day: number): boolean {
 | 
			
		||||
        return weekStartingMonday ? [0, 6].includes(day) : [5, 6].includes(day)
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      function filterWorkouts(day: Date, workouts: IWorkout[]) {
 | 
			
		||||
        if (workouts) {
 | 
			
		||||
          return workouts
 | 
			
		||||
            .filter((workout) =>
 | 
			
		||||
              isSameDay(
 | 
			
		||||
                getDateWithTZ(workout.workout_date, props.timezone),
 | 
			
		||||
                day
 | 
			
		||||
              )
 | 
			
		||||
            )
 | 
			
		||||
            .reverse()
 | 
			
		||||
        }
 | 
			
		||||
        return []
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return { rows, format, isSameMonth, isToday, isWeekEnd, filterWorkouts }
 | 
			
		||||
    },
 | 
			
		||||
  })
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss">
 | 
			
		||||
  @import '~@/scss/base';
 | 
			
		||||
  .calendar-cells {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    flex-grow: 1;
 | 
			
		||||
 | 
			
		||||
    .calendar-row {
 | 
			
		||||
      display: flex;
 | 
			
		||||
      flex-wrap: wrap;
 | 
			
		||||
      border-top: solid 1px var(--calendar-border-color);
 | 
			
		||||
 | 
			
		||||
      .calendar-cell {
 | 
			
		||||
        border-right: solid 1px var(--calendar-border-color);
 | 
			
		||||
        height: 3em;
 | 
			
		||||
        flex-grow: 1;
 | 
			
		||||
        flex-basis: 10%;
 | 
			
		||||
        padding: $default-padding * 0.5;
 | 
			
		||||
        width: 10%;
 | 
			
		||||
        position: relative;
 | 
			
		||||
 | 
			
		||||
        .calendar-cell-day {
 | 
			
		||||
          position: absolute;
 | 
			
		||||
          font-size: 0.8em;
 | 
			
		||||
          line-height: 1;
 | 
			
		||||
          top: 0.5em;
 | 
			
		||||
          right: 0.5em;
 | 
			
		||||
          font-weight: bold;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      .calendar-cell:last-child {
 | 
			
		||||
        border-right: 0;
 | 
			
		||||
      }
 | 
			
		||||
      .disabled-cell {
 | 
			
		||||
        color: var(--app-color-light);
 | 
			
		||||
      }
 | 
			
		||||
      .week-end {
 | 
			
		||||
        background: var(--calendar-week-end-color);
 | 
			
		||||
      }
 | 
			
		||||
      .today {
 | 
			
		||||
        background: var(--calendar-today-color);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
@@ -0,0 +1,50 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="calendar-days">
 | 
			
		||||
    <div class="calendar-day" v-for="(day, index) in days" :key="index">
 | 
			
		||||
      {{ format(day, 'EEE', localeOptions) }}
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
  import { format, addDays } from 'date-fns'
 | 
			
		||||
  import { defineComponent } from 'vue'
 | 
			
		||||
 | 
			
		||||
  export default defineComponent({
 | 
			
		||||
    name: 'CalendarDays',
 | 
			
		||||
    props: {
 | 
			
		||||
      startDate: {
 | 
			
		||||
        type: Date,
 | 
			
		||||
        required: true,
 | 
			
		||||
      },
 | 
			
		||||
      localeOptions: {
 | 
			
		||||
        type: String,
 | 
			
		||||
        required: true,
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    setup(props) {
 | 
			
		||||
      const days = []
 | 
			
		||||
      for (let i = 0; i < 7; i++) {
 | 
			
		||||
        days.push(addDays(props.startDate, i))
 | 
			
		||||
      }
 | 
			
		||||
      return { days, addDays, format }
 | 
			
		||||
    },
 | 
			
		||||
  })
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss">
 | 
			
		||||
  @import '~@/scss/base';
 | 
			
		||||
  .calendar-days {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-direction: row;
 | 
			
		||||
    border-top: solid 1px var(--calendar-border-color);
 | 
			
		||||
 | 
			
		||||
    .calendar-day {
 | 
			
		||||
      flex-grow: 1;
 | 
			
		||||
      padding: $default-padding * 0.5;
 | 
			
		||||
      text-align: center;
 | 
			
		||||
      text-transform: uppercase;
 | 
			
		||||
      color: var(--app-color-light);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
@@ -0,0 +1,61 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="calendar-header">
 | 
			
		||||
    <div class="calendar-arrow calendar-arrow-left">
 | 
			
		||||
      <i class="fa fa-chevron-left" aria-hidden="true" />
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="calendar-month">
 | 
			
		||||
      <span>
 | 
			
		||||
        {{ format(day, 'MMM yyyy', localeOptions) }}
 | 
			
		||||
      </span>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="calendar-arrow calendar-arrow-right">
 | 
			
		||||
      <i class="fa fa-chevron-right" aria-hidden="true" />
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
  import { format } from 'date-fns'
 | 
			
		||||
  import { defineComponent } from 'vue'
 | 
			
		||||
  export default defineComponent({
 | 
			
		||||
    name: 'CalendarHeader',
 | 
			
		||||
    props: {
 | 
			
		||||
      day: {
 | 
			
		||||
        type: Date,
 | 
			
		||||
        required: true,
 | 
			
		||||
      },
 | 
			
		||||
      localeOptions: {
 | 
			
		||||
        type: String,
 | 
			
		||||
        required: true,
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    setup() {
 | 
			
		||||
      return { format }
 | 
			
		||||
    },
 | 
			
		||||
  })
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss">
 | 
			
		||||
  @import '~@/scss/base';
 | 
			
		||||
  .calendar-header {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-direction: row;
 | 
			
		||||
 | 
			
		||||
    .calendar-arrow,
 | 
			
		||||
    .calendar-month {
 | 
			
		||||
      flex-grow: 1;
 | 
			
		||||
      padding: $default-padding;
 | 
			
		||||
    }
 | 
			
		||||
    .calendar-arrow-left {
 | 
			
		||||
      text-align: left;
 | 
			
		||||
    }
 | 
			
		||||
    .calendar-arrow-right {
 | 
			
		||||
      text-align: right;
 | 
			
		||||
    }
 | 
			
		||||
    .calendar-month {
 | 
			
		||||
      font-weight: bold;
 | 
			
		||||
      text-align: center;
 | 
			
		||||
      text-transform: uppercase;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
@@ -0,0 +1,34 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="calendar-workout">
 | 
			
		||||
    <img alt="workout sport logo" :src="sportImg" :title="workout.title" />
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
  import { defineComponent, PropType } from 'vue'
 | 
			
		||||
 | 
			
		||||
  import { IWorkout } from '@/types/workouts'
 | 
			
		||||
 | 
			
		||||
  export default defineComponent({
 | 
			
		||||
    name: 'CalendarWorkouts',
 | 
			
		||||
    props: {
 | 
			
		||||
      workout: {
 | 
			
		||||
        type: Object as PropType<IWorkout>,
 | 
			
		||||
        required: true,
 | 
			
		||||
      },
 | 
			
		||||
      sportImg: {
 | 
			
		||||
        type: String,
 | 
			
		||||
        required: true,
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  })
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss">
 | 
			
		||||
  .calendar-workout {
 | 
			
		||||
    img {
 | 
			
		||||
      max-width: 18px;
 | 
			
		||||
      max-height: 18px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
@@ -0,0 +1,45 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="calendar-workouts">
 | 
			
		||||
    <div v-for="(workout, index) in workouts" :key="index">
 | 
			
		||||
      <CalendarWorkout
 | 
			
		||||
        :workout="workout"
 | 
			
		||||
        :sportImg="getSportImg(workout, sports)"
 | 
			
		||||
      />
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
  import { defineComponent, PropType } from 'vue'
 | 
			
		||||
 | 
			
		||||
  import CalendarWorkout from '@/components/Dashboard/UserCalendar/CalendarWorkout.vue'
 | 
			
		||||
  import { ISport } from '@/types/sports'
 | 
			
		||||
  import { IWorkout } from '@/types/workouts'
 | 
			
		||||
 | 
			
		||||
  export default defineComponent({
 | 
			
		||||
    name: 'CalendarWorkouts',
 | 
			
		||||
    components: {
 | 
			
		||||
      CalendarWorkout,
 | 
			
		||||
    },
 | 
			
		||||
    props: {
 | 
			
		||||
      workouts: {
 | 
			
		||||
        type: Object as PropType<IWorkout[]>,
 | 
			
		||||
        required: true,
 | 
			
		||||
      },
 | 
			
		||||
      sports: {
 | 
			
		||||
        type: Object as PropType<ISport[]>,
 | 
			
		||||
        required: true,
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    setup() {
 | 
			
		||||
      function getSportImg(workout: IWorkout, sports: ISport[]): string {
 | 
			
		||||
        return sports
 | 
			
		||||
          .filter((sport) => sport.id === workout.sport_id)
 | 
			
		||||
          .map((sport) => sport.img)[0]
 | 
			
		||||
      }
 | 
			
		||||
      return { getSportImg }
 | 
			
		||||
    },
 | 
			
		||||
  })
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss"></style>
 | 
			
		||||
@@ -0,0 +1,87 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div id="user-calendar">
 | 
			
		||||
    <Card class="calendar-card">
 | 
			
		||||
      <template #content>
 | 
			
		||||
        <CalendarHeader :day="day" locale-options="enGB" />
 | 
			
		||||
        <CalendarDays :start-date="calendarDates.start" locale-options="enGB" />
 | 
			
		||||
        <CalendaCells
 | 
			
		||||
          :currentDay="day"
 | 
			
		||||
          :end-date="calendarDates.end"
 | 
			
		||||
          :sports="sports"
 | 
			
		||||
          :start-date="calendarDates.start"
 | 
			
		||||
          :timezone="user.timezone"
 | 
			
		||||
          :workouts="calendarWorkouts"
 | 
			
		||||
          :weekStartingMonday="user.weekm"
 | 
			
		||||
        />
 | 
			
		||||
      </template>
 | 
			
		||||
    </Card>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
  import { format } from 'date-fns'
 | 
			
		||||
  import {
 | 
			
		||||
    PropType,
 | 
			
		||||
    defineComponent,
 | 
			
		||||
    onBeforeMount,
 | 
			
		||||
    ComputedRef,
 | 
			
		||||
    computed,
 | 
			
		||||
  } from 'vue'
 | 
			
		||||
 | 
			
		||||
  import Card from '@/components/Common/Card.vue'
 | 
			
		||||
  import CalendaCells from '@/components/Dashboard/UserCalendar/CalendarCells.vue'
 | 
			
		||||
  import CalendarDays from '@/components/Dashboard/UserCalendar/CalendarDays.vue'
 | 
			
		||||
  import CalendarHeader from '@/components/Dashboard/UserCalendar/CalendarHeader.vue'
 | 
			
		||||
  import { SPORTS_STORE, WORKOUTS_STORE } from '@/store/constants'
 | 
			
		||||
  import { IAuthUserProfile } from '@/types/user'
 | 
			
		||||
  import { IWorkout, IWorkoutsPayload } from '@/types/workouts'
 | 
			
		||||
  import { useStore } from '@/use/useStore'
 | 
			
		||||
  import { getCalendarStartAndEnd } from '@/utils/dates'
 | 
			
		||||
 | 
			
		||||
  export default defineComponent({
 | 
			
		||||
    name: 'UserCalendar',
 | 
			
		||||
    components: {
 | 
			
		||||
      CalendaCells,
 | 
			
		||||
      CalendarDays,
 | 
			
		||||
      CalendarHeader,
 | 
			
		||||
      Card,
 | 
			
		||||
    },
 | 
			
		||||
    props: {
 | 
			
		||||
      user: {
 | 
			
		||||
        type: Object as PropType<IAuthUserProfile>,
 | 
			
		||||
        required: true,
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    setup(props) {
 | 
			
		||||
      const store = useStore()
 | 
			
		||||
      const dateFormat = 'yyyy-MM-dd'
 | 
			
		||||
      const day = new Date()
 | 
			
		||||
      const calendarDates = getCalendarStartAndEnd(day, props.user.weekm)
 | 
			
		||||
      const apiParams: IWorkoutsPayload = {
 | 
			
		||||
        from: format(calendarDates.start, dateFormat),
 | 
			
		||||
        to: format(calendarDates.end, dateFormat),
 | 
			
		||||
        order: 'desc',
 | 
			
		||||
        per_page: 100,
 | 
			
		||||
      }
 | 
			
		||||
      const calendarWorkouts: ComputedRef<IWorkout[]> = computed(
 | 
			
		||||
        () => store.getters[WORKOUTS_STORE.GETTERS.CALENDAR_WORKOUTS]
 | 
			
		||||
      )
 | 
			
		||||
      const sports = computed(() => store.getters[SPORTS_STORE.GETTERS.SPORTS])
 | 
			
		||||
 | 
			
		||||
      onBeforeMount(() =>
 | 
			
		||||
        store.dispatch(WORKOUTS_STORE.ACTIONS.GET_CALENDAR_WORKOUTS, apiParams)
 | 
			
		||||
      )
 | 
			
		||||
 | 
			
		||||
      return { day, calendarDates, calendarWorkouts, sports }
 | 
			
		||||
    },
 | 
			
		||||
  })
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss">
 | 
			
		||||
  @import '~@/scss/base';
 | 
			
		||||
  #user-calendar {
 | 
			
		||||
    .calendar-card {
 | 
			
		||||
      padding: 0;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
@@ -52,7 +52,7 @@
 | 
			
		||||
    computed,
 | 
			
		||||
    defineComponent,
 | 
			
		||||
    ref,
 | 
			
		||||
    watch,
 | 
			
		||||
    onBeforeMount,
 | 
			
		||||
  } from 'vue'
 | 
			
		||||
  import { useI18n } from 'vue-i18n'
 | 
			
		||||
 | 
			
		||||
@@ -106,18 +106,16 @@
 | 
			
		||||
        displayedData.value = event.target.name
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      watch(
 | 
			
		||||
        () => props.user.username,
 | 
			
		||||
        async (newUsername) => {
 | 
			
		||||
          if (newUsername) {
 | 
			
		||||
            store.dispatch(STATS_STORE.ACTIONS.GET_USER_STATS, {
 | 
			
		||||
              username: newUsername,
 | 
			
		||||
              filterType: 'by_time',
 | 
			
		||||
              params: apiParams,
 | 
			
		||||
            })
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      )
 | 
			
		||||
      function getStatistics() {
 | 
			
		||||
        store.dispatch(STATS_STORE.ACTIONS.GET_USER_STATS, {
 | 
			
		||||
          username: props.user.username,
 | 
			
		||||
          filterType: 'by_time',
 | 
			
		||||
          params: apiParams,
 | 
			
		||||
        })
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      onBeforeMount(() => getStatistics())
 | 
			
		||||
 | 
			
		||||
      return {
 | 
			
		||||
        chartParams,
 | 
			
		||||
        displayedData,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
:root {
 | 
			
		||||
  --app-background-color: #FFFFFF;
 | 
			
		||||
  --app-color: #2c3e50;
 | 
			
		||||
  --app-color-light: #808b96;
 | 
			
		||||
  --app-a-color: #40578a;
 | 
			
		||||
  --app-shadow-color: lightgrey;
 | 
			
		||||
  --app-loading-color:  #f3f3f3;
 | 
			
		||||
@@ -9,6 +10,10 @@
 | 
			
		||||
  --card-border-color: #c4c7cf;
 | 
			
		||||
  --input-border-color: #9da3af;
 | 
			
		||||
 | 
			
		||||
  --calendar-border-color: #c4c7cf;
 | 
			
		||||
  --calendar-week-end-color: #f5f5f5;
 | 
			
		||||
  --calendar-today-color: #eff1f3;
 | 
			
		||||
 | 
			
		||||
  --nav-bar-background-color: #FFFFFF;
 | 
			
		||||
  --nav-bar-link-active: #485b6e;
 | 
			
		||||
  --nav-border-color: #c5ccdb;
 | 
			
		||||
 
 | 
			
		||||
@@ -8,11 +8,13 @@ import { IRootState } from '@/store/modules/root/types'
 | 
			
		||||
import sportsModule from '@/store/modules/sports'
 | 
			
		||||
import statsModule from '@/store/modules/statistics'
 | 
			
		||||
import userModule from '@/store/modules/user'
 | 
			
		||||
import workoutsModule from '@/store/modules/workouts'
 | 
			
		||||
 | 
			
		||||
const modules: ModuleTree<IRootState> = {
 | 
			
		||||
  sportsModule,
 | 
			
		||||
  statsModule,
 | 
			
		||||
  userModule,
 | 
			
		||||
  workoutsModule,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const root: Module<IRootState, IRootState> = {
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,7 @@ export const actions: ActionTree<IWorkoutsState, IRootState> &
 | 
			
		||||
        if (res.data.status === 'success') {
 | 
			
		||||
          context.commit(
 | 
			
		||||
            WORKOUTS_STORE.MUTATIONS.SET_CALENDAR_WORKOUTS,
 | 
			
		||||
            res.data.data.statistics
 | 
			
		||||
            res.data.data.workouts
 | 
			
		||||
          )
 | 
			
		||||
        } else {
 | 
			
		||||
          handleError(context, null)
 | 
			
		||||
 
 | 
			
		||||
@@ -13,3 +13,5 @@ const workouts: Module<IWorkoutsState, IRootState> = {
 | 
			
		||||
  getters,
 | 
			
		||||
  mutations,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default workouts
 | 
			
		||||
 
 | 
			
		||||
@@ -2,10 +2,13 @@ import {
 | 
			
		||||
  addDays,
 | 
			
		||||
  addMonths,
 | 
			
		||||
  addYears,
 | 
			
		||||
  endOfMonth,
 | 
			
		||||
  endOfWeek,
 | 
			
		||||
  startOfMonth,
 | 
			
		||||
  startOfWeek,
 | 
			
		||||
  startOfYear,
 | 
			
		||||
} from 'date-fns'
 | 
			
		||||
import { utcToZonedTime } from 'date-fns-tz'
 | 
			
		||||
 | 
			
		||||
export const startDate = (
 | 
			
		||||
  duration: string,
 | 
			
		||||
@@ -40,3 +43,20 @@ export const incrementDate = (duration: string, day: Date): Date => {
 | 
			
		||||
      )
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const getDateWithTZ = (dateInUTC: string, tz: string): Date => {
 | 
			
		||||
  return utcToZonedTime(new Date(dateInUTC), tz)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const getCalendarStartAndEnd = (
 | 
			
		||||
  date: Date,
 | 
			
		||||
  weekStartingMonday: boolean
 | 
			
		||||
): Record<string, Date> => {
 | 
			
		||||
  const monthStart = startOfMonth(date)
 | 
			
		||||
  const monthEnd = endOfMonth(date)
 | 
			
		||||
  const weekStartsOn = weekStartingMonday ? 1 : 0
 | 
			
		||||
  return {
 | 
			
		||||
    start: startOfWeek(monthStart, { weekStartsOn }),
 | 
			
		||||
    end: endOfWeek(monthEnd),
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div id="dashboard">
 | 
			
		||||
  <div id="dashboard" v-if="authUser.username">
 | 
			
		||||
    <div class="container">
 | 
			
		||||
      <UserStats :user="authUser" v-if="authUser.username" />
 | 
			
		||||
      <UserStats :user="authUser" />
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="container dashboard-container">
 | 
			
		||||
      <div class="left-container dashboard-sub-container">
 | 
			
		||||
@@ -9,7 +9,7 @@
 | 
			
		||||
        <UserRecords />
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="right-container dashboard-sub-container">
 | 
			
		||||
        <UserCalendar />
 | 
			
		||||
        <UserCalendar :user="authUser" />
 | 
			
		||||
        <Timeline />
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
@@ -20,7 +20,7 @@
 | 
			
		||||
  import { computed, ComputedRef, defineComponent } from 'vue'
 | 
			
		||||
 | 
			
		||||
  import Timeline from '@/components/Dashboard/Timeline.vue'
 | 
			
		||||
  import UserCalendar from '@/components/Dashboard/UserCalendar.vue'
 | 
			
		||||
  import UserCalendar from '@/components/Dashboard/UserCalendar/index.vue'
 | 
			
		||||
  import UserMonthStats from '@/components/Dashboard/UserMonthStats.vue'
 | 
			
		||||
  import UserRecords from '@/components/Dashboard/UserRecords.vue'
 | 
			
		||||
  import UserStats from '@/components/Dashboard/UserStats.vue'
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
import { assert, expect } from 'chai'
 | 
			
		||||
 | 
			
		||||
import { incrementDate, startDate } from '@/utils/dates'
 | 
			
		||||
import { getCalendarStartAndEnd, incrementDate, startDate } from '@/utils/dates'
 | 
			
		||||
 | 
			
		||||
describe('startDate (week starting Sunday)', () => {
 | 
			
		||||
  const testsParams = [
 | 
			
		||||
@@ -135,3 +135,23 @@ describe('dateIncrement', () => {
 | 
			
		||||
    )
 | 
			
		||||
  })
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
describe('getCalendarStartAndEnd', () => {
 | 
			
		||||
  const testsParams = [
 | 
			
		||||
    {
 | 
			
		||||
      description: 'returns empty string if no date provided',
 | 
			
		||||
      inputDate: 'September 5, 2021 20:00:00',
 | 
			
		||||
      expectedStartDate: 'August 29, 2021 00:00:00',
 | 
			
		||||
      expectedEndDate: 'October 2, 2021 23:59:59.999',
 | 
			
		||||
    },
 | 
			
		||||
  ]
 | 
			
		||||
 | 
			
		||||
  testsParams.map((testParams) =>
 | 
			
		||||
    it(testParams.description, () => {
 | 
			
		||||
      const date: Date = new Date(testParams.inputDate)
 | 
			
		||||
      const results = getCalendarStartAndEnd(date, false)
 | 
			
		||||
      assert.deepEqual(results.start, new Date(testParams.expectedStartDate))
 | 
			
		||||
      assert.deepEqual(results.end, new Date(testParams.expectedEndDate))
 | 
			
		||||
    })
 | 
			
		||||
  )
 | 
			
		||||
})
 | 
			
		||||
 
 | 
			
		||||
@@ -3581,6 +3581,11 @@ data-urls@^1.1.0:
 | 
			
		||||
    whatwg-mimetype "^2.2.0"
 | 
			
		||||
    whatwg-url "^7.0.0"
 | 
			
		||||
 | 
			
		||||
date-fns-tz@^1.1.6:
 | 
			
		||||
  version "1.1.6"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/date-fns-tz/-/date-fns-tz-1.1.6.tgz#93cbf354e2aeb2cd312ffa32e462c1943cf20a8e"
 | 
			
		||||
  integrity sha512-nyy+URfFI3KUY7udEJozcoftju+KduaqkVfwyTIE0traBiVye09QnyWKLZK7drRr5h9B7sPJITmQnS3U6YOdQg==
 | 
			
		||||
 | 
			
		||||
date-fns@^2.23.0:
 | 
			
		||||
  version "2.23.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.23.0.tgz#4e886c941659af0cf7b30fafdd1eaa37e88788a9"
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user