Client - use <script setup> in components

This commit is contained in:
Sam
2021-11-10 21:19:27 +01:00
parent 857c0ecd2d
commit 1bede62d80
126 changed files with 2133 additions and 3207 deletions

View File

@ -30,15 +30,8 @@
</div>
</template>
<script lang="ts">
import {
ComputedRef,
PropType,
computed,
defineComponent,
ref,
onBeforeMount,
} from 'vue'
<script setup lang="ts">
import { ComputedRef, computed, ref, onBeforeMount, toRefs } from 'vue'
import WorkoutCard from '@/components/Workout/WorkoutCard.vue'
import NoWorkouts from '@/components/Workouts/NoWorkouts.vue'
@ -49,65 +42,44 @@
import { useStore } from '@/use/useStore'
import { defaultOrder } from '@/utils/workouts'
export default defineComponent({
name: 'Timeline',
components: {
NoWorkouts,
WorkoutCard,
},
props: {
sports: {
type: Object as PropType<ISport[]>,
required: true,
},
user: {
type: Object as PropType<IUserProfile>,
required: true,
},
},
setup(props) {
const store = useStore()
interface Props {
sports: ISport[]
user: IUserProfile
}
const props = defineProps<Props>()
let page = ref(1)
const per_page = 5
const initWorkoutsCount =
props.user.nb_workouts >= per_page ? per_page : props.user.nb_workouts
onBeforeMount(() => loadWorkouts())
const store = useStore()
const workouts: ComputedRef<IWorkout[]> = computed(
() => store.getters[WORKOUTS_STORE.GETTERS.TIMELINE_WORKOUTS]
)
const moreWorkoutsExist: ComputedRef<boolean> = computed(() =>
workouts.value.length > 0
? workouts.value[workouts.value.length - 1].previous_workout !== null
: false
)
const { sports, user } = toRefs(props)
let page = ref(1)
const per_page = 5
const initWorkoutsCount =
props.user.nb_workouts >= per_page ? per_page : props.user.nb_workouts
onBeforeMount(() => loadWorkouts())
const workouts: ComputedRef<IWorkout[]> = computed(
() => store.getters[WORKOUTS_STORE.GETTERS.TIMELINE_WORKOUTS]
)
const moreWorkoutsExist: ComputedRef<boolean> = computed(() =>
workouts.value.length > 0
? workouts.value[workouts.value.length - 1].previous_workout !== null
: false
)
function loadWorkouts() {
store.dispatch(WORKOUTS_STORE.ACTIONS.GET_TIMELINE_WORKOUTS, {
page: page.value,
per_page,
...defaultOrder,
})
}
function loadMoreWorkouts() {
page.value += 1
store.dispatch(WORKOUTS_STORE.ACTIONS.GET_MORE_TIMELINE_WORKOUTS, {
page: page.value,
per_page,
...defaultOrder,
})
}
return {
initWorkoutsCount,
moreWorkoutsExist,
per_page,
workouts,
loadMoreWorkouts,
}
},
})
function loadWorkouts() {
store.dispatch(WORKOUTS_STORE.ACTIONS.GET_TIMELINE_WORKOUTS, {
page: page.value,
per_page,
...defaultOrder,
})
}
function loadMoreWorkouts() {
page.value += 1
store.dispatch(WORKOUTS_STORE.ACTIONS.GET_MORE_TIMELINE_WORKOUTS, {
page: page.value,
per_page,
...defaultOrder,
})
}
</script>
<style lang="scss" scoped>

View File

@ -23,105 +23,71 @@
</div>
</template>
<script lang="ts">
<script setup lang="ts">
import { addDays, format, isSameDay, isSameMonth, isToday } from 'date-fns'
import {
PropType,
Ref,
defineComponent,
ref,
toRefs,
watch,
onMounted,
} from 'vue'
import { Ref, ref, toRefs, watch, onMounted } 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: Ref<Date[][]> = ref([])
let { startDate, endDate, weekStartingMonday } = toRefs(props)
interface Props {
currentDay: Date
endDate: Date
sports: ISport[]
startDate: Date
timezone: string
weekStartingMonday: boolean
workouts: IWorkout[]
}
const props = defineProps<Props>()
onMounted(() => getDays())
const {
currentDay,
endDate,
sports,
startDate,
timezone,
weekStartingMonday,
workouts,
} = toRefs(props)
const rows: Ref<Date[][]> = ref([])
function getDays() {
rows.value = []
let day = startDate.value
while (day <= endDate.value) {
const days: Date[] = []
for (let i = 0; i < 7; i++) {
days.push(day)
day = addDays(day, 1)
}
rows.value.push(days)
}
onMounted(() => getDays())
function getDays() {
rows.value = []
let day = startDate.value
while (day <= endDate.value) {
const days: Date[] = []
for (let i = 0; i < 7; i++) {
days.push(day)
day = addDays(day, 1)
}
rows.value.push(days)
}
}
function isWeekEnd(day: number): boolean {
return weekStartingMonday.value
? [5, 6].includes(day)
: [0, 6].includes(day)
}
function filterWorkouts(day: Date, workouts: IWorkout[]) {
if (workouts) {
return workouts
.filter((workout) =>
isSameDay(getDateWithTZ(workout.workout_date, timezone), day)
)
.reverse()
}
return []
}
function isWeekEnd(day: number): boolean {
return weekStartingMonday.value
? [5, 6].includes(day)
: [0, 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 []
}
watch(
() => props.currentDay,
() => getDays()
)
return { rows, format, isSameMonth, isToday, isWeekEnd, filterWorkouts }
},
})
watch(
() => props.currentDay,
() => getDays()
)
</script>
<style lang="scss">

View File

@ -6,30 +6,19 @@
</div>
</template>
<script lang="ts">
<script setup 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 }
},
})
interface Props {
startDate: Date
localeOptions: string
}
const props = defineProps<Props>()
const days = []
for (let i = 0; i < 7; i++) {
days.push(addDays(props.startDate, i))
}
</script>
<style lang="scss">

View File

@ -20,27 +20,19 @@
</div>
</template>
<script lang="ts">
<script setup lang="ts">
import { format } from 'date-fns'
import { defineComponent } from 'vue'
import { toRefs } from 'vue'
export default defineComponent({
name: 'CalendarHeader',
props: {
day: {
type: Date,
required: true,
},
localeOptions: {
type: String,
required: true,
},
},
emits: ['displayNextMonth', 'displayPreviousMonth'],
setup(props, { emit }) {
return { emit, format }
},
})
interface Props {
day: Date
localeOptions: string
}
const props = defineProps<Props>()
const emit = defineEmits(['displayNextMonth', 'displayPreviousMonth'])
const { day, localeOptions } = toRefs(props)
</script>
<style lang="scss">

View File

@ -13,7 +13,7 @@
aria-hidden="true"
:title="
workout.records.map(
(record) => ` ${t(`workouts.RECORD_${record.record_type}`)}`
(record) => ` ${$t(`workouts.RECORD_${record.record_type}`)}`
)
"
/>
@ -21,29 +21,17 @@
</div>
</template>
<script lang="ts">
import { defineComponent, PropType } from 'vue'
import { useI18n } from 'vue-i18n'
<script setup lang="ts">
import { toRefs } from 'vue'
import { IWorkout } from '@/types/workouts'
interface Props {
workout: IWorkout
sportLabel: string
}
const props = defineProps<Props>()
export default defineComponent({
name: 'CalendarWorkout',
props: {
workout: {
type: Object as PropType<IWorkout>,
required: true,
},
sportLabel: {
type: String,
required: true,
},
},
setup() {
const { t } = useI18n()
return { t }
},
})
const { workout, sportLabel } = toRefs(props)
</script>
<style lang="scss">

View File

@ -34,8 +34,8 @@
</div>
</template>
<script lang="ts">
import { PropType, computed, defineComponent } from 'vue'
<script setup lang="ts">
import { computed, toRefs } from 'vue'
import CalendarWorkout from '@/components/Dashboard/UserCalendar/CalendarWorkout.vue'
import CalendarWorkoutsChart from '@/components/Dashboard/UserCalendar/CalendarWorkoutsChart.vue'
@ -44,31 +44,16 @@
import { getSportLabel, sportIdColors } from '@/utils/sports'
import { getDonutDatasets } from '@/utils/workouts'
export default defineComponent({
name: 'CalendarWorkouts',
components: {
CalendarWorkout,
CalendarWorkoutsChart,
},
props: {
workouts: {
type: Object as PropType<IWorkout[]>,
required: true,
},
sports: {
type: Object as PropType<ISport[]>,
required: true,
},
},
setup(props) {
return {
chartDatasets: computed(() => getDonutDatasets(props.workouts)),
colors: computed(() => sportIdColors(props.sports)),
displayedWorkoutCount: 6,
getSportLabel,
}
},
})
interface Props {
workouts: IWorkout[]
sports: ISport[]
}
const props = defineProps<Props>()
const { workouts, sports } = toRefs(props)
const chartDatasets = computed(() => getDonutDatasets(props.workouts))
const colors = computed(() => sportIdColors(props.sports))
const displayedWorkoutCount = 6
</script>
<style lang="scss">

View File

@ -22,8 +22,8 @@
</div>
</template>
<script lang="ts">
import { PropType, defineComponent, ref } from 'vue'
<script setup lang="ts">
import { ref, toRefs } from 'vue'
import CalendarWorkout from '@/components/Dashboard/UserCalendar/CalendarWorkout.vue'
import DonutChart from '@/components/Dashboard/UserCalendar/DonutChart.vue'
@ -31,39 +31,21 @@
import { IWorkout } from '@/types/workouts'
import { getSportLabel } from '@/utils/sports'
export default defineComponent({
name: 'CalendarWorkoutsChart',
components: {
CalendarWorkout,
DonutChart,
},
props: {
colors: {
type: Object as PropType<Record<number, string>>,
required: true,
},
datasets: {
type: Object as PropType<Record<number, Record<string, number>>>,
required: true,
},
sports: {
type: Object as PropType<ISport[]>,
required: true,
},
workouts: {
type: Object as PropType<IWorkout[]>,
required: true,
},
},
setup() {
const isHidden = ref(true)
function togglePane(event: Event & { target: HTMLElement }) {
event.stopPropagation()
isHidden.value = !isHidden.value
}
return { isHidden, getSportLabel, togglePane }
},
})
interface Props {
colors: Record<number, string>
datasets: Record<number, Record<string, number>>
sports: ISport[]
workouts: IWorkout[]
}
const props = defineProps<Props>()
const { colors, datasets, sports, workouts } = toRefs(props)
const isHidden = ref(true)
function togglePane(event: Event & { target: HTMLElement }) {
event.stopPropagation()
isHidden.value = !isHidden.value
}
</script>
<style lang="scss" scoped>

View File

@ -22,52 +22,34 @@
</div>
</template>
<script lang="ts">
import { PropType, defineComponent } from 'vue'
<script setup lang="ts">
import { toRefs } from 'vue'
export default defineComponent({
name: 'DonutChart',
props: {
colors: {
type: Object as PropType<Record<number, string>>,
required: true,
},
datasets: {
type: Object as PropType<Record<number, Record<string, number>>>,
required: true,
},
},
setup() {
let angleOffset = -90
const cx = 16
const cy = 16
const radius = 14
const circumference = 2 * Math.PI * radius
interface Props {
colors: Record<number, string>
datasets: Record<number, Record<string, number>>
}
const props = defineProps<Props>()
function calculateStrokeDashOffset(
percentage: number,
circumference: number
): number {
return circumference - percentage * circumference
}
function returnCircleTransformValue(
index: number,
percentage: number
): string {
const rotation = `rotate(${angleOffset}, ${cx}, ${cy})`
angleOffset = percentage * 360 + angleOffset
return rotation
}
const { colors, datasets } = toRefs(props)
let angleOffset = -90
const cx = 16
const cy = 16
const radius = 14
const circumference = 2 * Math.PI * radius
return {
angleOffset,
circumference,
cx,
cy,
radius,
calculateStrokeDashOffset,
returnCircleTransformValue,
}
},
})
function calculateStrokeDashOffset(
percentage: number,
circumference: number
): number {
return circumference - percentage * circumference
}
function returnCircleTransformValue(
index: number,
percentage: number
): string {
const rotation = `rotate(${angleOffset}, ${cx}, ${cy})`
angleOffset = percentage * 360 + angleOffset
return rotation
}
</script>

View File

@ -21,16 +21,9 @@
</div>
</template>
<script lang="ts">
<script setup lang="ts">
import { addMonths, format, subMonths } from 'date-fns'
import {
ComputedRef,
PropType,
computed,
defineComponent,
ref,
onBeforeMount,
} from 'vue'
import { ComputedRef, computed, ref, toRefs, onBeforeMount } from 'vue'
import CalendarCells from '@/components/Dashboard/UserCalendar/CalendarCells.vue'
import CalendarDays from '@/components/Dashboard/UserCalendar/CalendarDays.vue'
@ -43,70 +36,43 @@
import { getCalendarStartAndEnd } from '@/utils/dates'
import { defaultOrder } from '@/utils/workouts'
export default defineComponent({
name: 'UserCalendar',
components: {
CalendarCells,
CalendarDays,
CalendarHeader,
},
props: {
sports: {
type: Object as PropType<ISport[]>,
required: true,
},
user: {
type: Object as PropType<IUserProfile>,
required: true,
},
},
setup(props) {
const store = useStore()
interface Props {
sports: ISport[]
user: IUserProfile
}
const props = defineProps<Props>()
onBeforeMount(() => getCalendarWorkouts())
const store = useStore()
const dateFormat = 'yyyy-MM-dd'
let day = ref(new Date())
let calendarDates = ref(
getCalendarStartAndEnd(day.value, props.user.weekm)
)
const calendarWorkouts: ComputedRef<IWorkout[]> = computed(
() => store.getters[WORKOUTS_STORE.GETTERS.CALENDAR_WORKOUTS]
)
const { sports, user } = toRefs(props)
const dateFormat = 'yyyy-MM-dd'
let day = ref(new Date())
let calendarDates = ref(getCalendarStartAndEnd(day.value, props.user.weekm))
const calendarWorkouts: ComputedRef<IWorkout[]> = computed(
() => store.getters[WORKOUTS_STORE.GETTERS.CALENDAR_WORKOUTS]
)
function getCalendarWorkouts() {
calendarDates.value = getCalendarStartAndEnd(
day.value,
props.user.weekm
)
const apiParams: TWorkoutsPayload = {
from: format(calendarDates.value.start, dateFormat),
to: format(calendarDates.value.end, dateFormat),
page: 1,
per_page: 100,
...defaultOrder,
}
store.dispatch(WORKOUTS_STORE.ACTIONS.GET_CALENDAR_WORKOUTS, apiParams)
}
onBeforeMount(() => getCalendarWorkouts())
function displayNextMonth() {
day.value = addMonths(day.value, 1)
getCalendarWorkouts()
}
function displayPreviousMonth() {
day.value = subMonths(day.value, 1)
getCalendarWorkouts()
}
return {
day,
calendarDates,
calendarWorkouts,
displayNextMonth,
displayPreviousMonth,
}
},
})
function getCalendarWorkouts() {
calendarDates.value = getCalendarStartAndEnd(day.value, props.user.weekm)
const apiParams: TWorkoutsPayload = {
from: format(calendarDates.value.start, dateFormat),
to: format(calendarDates.value.end, dateFormat),
page: 1,
per_page: 100,
...defaultOrder,
}
store.dispatch(WORKOUTS_STORE.ACTIONS.GET_CALENDAR_WORKOUTS, apiParams)
}
function displayNextMonth() {
day.value = addMonths(day.value, 1)
getCalendarWorkouts()
}
function displayPreviousMonth() {
day.value = subMonths(day.value, 1)
getCalendarWorkouts()
}
</script>
<style lang="scss">

View File

@ -15,41 +15,28 @@
</div>
</template>
<script lang="ts">
<script setup lang="ts">
import { endOfMonth, startOfMonth } from 'date-fns'
import { PropType, defineComponent } from 'vue'
import { toRefs } from 'vue'
import StatChart from '@/components/Common/StatsChart/index.vue'
import { ISport } from '@/types/sports'
import { IUserProfile } from '@/types/user'
export default defineComponent({
name: 'UserMonthStats',
components: {
StatChart,
},
props: {
sports: {
type: Object as PropType<ISport[]>,
required: true,
},
user: {
type: Object as PropType<IUserProfile>,
required: true,
},
},
setup(props) {
const date = new Date()
return {
chartParams: {
duration: 'week',
start: startOfMonth(date),
end: endOfMonth(date),
},
selectedSportIds: props.sports.map((sport) => sport.id),
}
},
})
interface Props {
sports: ISport[]
user: IUserProfile
}
const props = defineProps<Props>()
const { sports, user } = toRefs(props)
const date = new Date()
const chartParams = {
duration: 'week',
start: startOfMonth(date),
end: endOfMonth(date),
}
const selectedSportIds = props.sports.map((sport) => sport.id)
</script>
<style lang="scss" scoped>

View File

@ -7,9 +7,9 @@
</template>
<template #content>
<div class="record" v-for="record in records.records" :key="record.id">
<span class="record-type">{{
t(`workouts.RECORD_${record.record_type}`)
}}</span>
<span class="record-type">
{{ $t(`workouts.RECORD_${record.record_type}`) }}
</span>
<span class="record-value">{{ record.value }}</span>
<span class="record-date">
<router-link
@ -17,8 +17,9 @@
name: 'Workout',
params: { workoutId: record.workout_id },
}"
>{{ record.workout_date }}</router-link
>
{{ record.workout_date }}
</router-link>
</span>
</div>
</template>
@ -26,29 +27,18 @@
</div>
</template>
<script lang="ts">
import { PropType, defineComponent } from 'vue'
import { useI18n } from 'vue-i18n'
<script setup lang="ts">
import { toRefs } from 'vue'
import { IRecord } from '@/types/workouts'
import { IRecordsBySports } from '@/types/workouts'
export default defineComponent({
name: 'RecordsCard',
props: {
records: {
type: Object as PropType<IRecord[]>,
required: true,
},
sportTranslatedLabel: {
type: String,
required: true,
},
},
setup() {
const { t } = useI18n()
return { t }
},
})
interface Props {
records: IRecordsBySports
sportTranslatedLabel: string
}
const props = defineProps<Props>()
const { records, sportTranslatedLabel } = toRefs(props)
</script>
<style lang="scss" scoped>

View File

@ -18,8 +18,8 @@
</div>
</template>
<script lang="ts">
import { computed, defineComponent, PropType } from 'vue'
<script setup lang="ts">
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
import RecordsCard from '@/components/Dashboard/UserRecords/RecordsCard.vue'
@ -28,33 +28,21 @@
import { getRecordsBySports } from '@/utils/records'
import { translateSports } from '@/utils/sports'
export default defineComponent({
name: 'UserRecords',
components: {
RecordsCard,
},
props: {
sports: {
type: Object as PropType<ISport[]>,
required: true,
},
user: {
type: Object as PropType<IUserProfile>,
required: true,
},
},
setup(props) {
const { t } = useI18n()
const recordsBySport = computed(() =>
getRecordsBySports(
props.user.records,
translateSports(props.sports, t),
props.user.timezone
)
)
return { recordsBySport }
},
})
interface Props {
sports: ISport[]
user: IUserProfile
}
const props = defineProps<Props>()
const { t } = useI18n()
const recordsBySport = computed(() =>
getRecordsBySports(
props.user.records,
translateSports(props.sports, t),
props.user.timezone
)
)
</script>
<style lang="scss" scoped>

View File

@ -12,8 +12,8 @@
/>
<StatCard
icon="clock-o"
:value="total_duration.days"
:text="total_duration.duration"
:value="totalDuration.days"
:text="totalDuration.duration"
/>
<StatCard
icon="tags"
@ -23,49 +23,40 @@
</div>
</template>
<script lang="ts">
import { ComputedRef, PropType, defineComponent, computed } from 'vue'
<script setup lang="ts">
import { ComputedRef, computed, toRefs } from 'vue'
import { useI18n } from 'vue-i18n'
import StatCard from '@/components/Common/StatCard.vue'
import { IUserProfile } from '@/types/user'
interface Props {
user: IUserProfile
}
const props = defineProps<Props>()
export default defineComponent({
name: 'UserStatsCards',
components: {
StatCard,
},
props: {
user: {
type: Object as PropType<IUserProfile>,
required: true,
},
},
setup(props) {
const { t } = useI18n()
const total_duration: ComputedRef<string> = computed(
() => props.user.total_duration
)
const { t } = useI18n()
function get_duration(total_duration: ComputedRef<string>) {
const duration = total_duration.value.match(/day/g)
? total_duration.value.split(', ')[1]
: total_duration.value
return {
days: total_duration.value.match(/day/g)
? `${total_duration.value.split(' ')[0]} ${
total_duration.value.match(/days/g)
? t('common.DAY', 2)
: t('common.DAY', 1)
}`
: `0 ${t('common.DAY', 2)},`,
duration: `${duration.split(':')[0]}h ${duration.split(':')[1]}min`,
}
}
const { user } = toRefs(props)
const userTotalDuration: ComputedRef<string> = computed(
() => props.user.total_duration
)
const totalDuration = computed(() => get_duration(userTotalDuration))
return { total_duration: computed(() => get_duration(total_duration)) }
},
})
function get_duration(total_duration: ComputedRef<string>) {
const duration = total_duration.value.match(/day/g)
? total_duration.value.split(', ')[1]
: total_duration.value
return {
days: total_duration.value.match(/day/g)
? `${total_duration.value.split(' ')[0]} ${
total_duration.value.match(/days/g)
? t('common.DAY', 2)
: t('common.DAY', 1)
}`
: `0 ${t('common.DAY', 2)},`,
duration: `${duration.split(':')[0]}h ${duration.split(':')[1]}min`,
}
}
</script>
<style lang="scss">