Client - init calendar on Dashboard
This commit is contained in:
@ -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,
|
||||
|
Reference in New Issue
Block a user