Add Workout Library feature with browse, create, and favorites
This commit is contained in:
269
src/stores/workoutLibrary.js
Normal file
269
src/stores/workoutLibrary.js
Normal file
@@ -0,0 +1,269 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref, computed } from 'vue'
|
||||
import workoutLibraryApi from '@/services/workoutLibraryApi'
|
||||
|
||||
export const useWorkoutLibraryStore = defineStore('workoutLibrary', () => {
|
||||
const workouts = ref([])
|
||||
const userWorkouts = ref([])
|
||||
const favorites = ref([])
|
||||
const currentWorkout = ref(null)
|
||||
const currentIntervals = ref([])
|
||||
const loading = ref(false)
|
||||
const error = ref(null)
|
||||
|
||||
const filters = ref({
|
||||
category: '',
|
||||
duration_min: null,
|
||||
duration_max: null,
|
||||
intensity_min: null,
|
||||
intensity_max: null,
|
||||
search: ''
|
||||
})
|
||||
|
||||
const pagination = ref({
|
||||
page: 1,
|
||||
limit: 20,
|
||||
total: 0
|
||||
})
|
||||
|
||||
const favoriteIds = computed(() => new Set(favorites.value.map(f => f.id)))
|
||||
|
||||
const isFavorited = (workoutId) => favoriteIds.value.has(workoutId)
|
||||
|
||||
async function fetchWorkouts() {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
const params = {
|
||||
page: pagination.value.page,
|
||||
limit: pagination.value.limit,
|
||||
...Object.fromEntries(
|
||||
Object.entries(filters.value).filter(([_, v]) => v !== '' && v !== null)
|
||||
)
|
||||
}
|
||||
const data = await workoutLibraryApi.getWorkouts(params)
|
||||
workouts.value = data.workouts || []
|
||||
pagination.value.total = data.total || 0
|
||||
} catch (err) {
|
||||
error.value = err.response?.data?.error || 'Failed to fetch workouts'
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchWorkout(workoutId) {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
const data = await workoutLibraryApi.getWorkout(workoutId)
|
||||
currentWorkout.value = data.workout || data
|
||||
return currentWorkout.value
|
||||
} catch (err) {
|
||||
error.value = err.response?.data?.error || 'Failed to fetch workout'
|
||||
throw err
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchWorkoutIntervals(workoutId) {
|
||||
try {
|
||||
const data = await workoutLibraryApi.getWorkoutIntervals(workoutId)
|
||||
currentIntervals.value = data.intervals || []
|
||||
return currentIntervals.value
|
||||
} catch (err) {
|
||||
error.value = err.response?.data?.error || 'Failed to fetch intervals'
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchUserWorkouts() {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
const data = await workoutLibraryApi.getUserWorkouts()
|
||||
userWorkouts.value = data.workouts || []
|
||||
} catch (err) {
|
||||
error.value = err.response?.data?.error || 'Failed to fetch your workouts'
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function createWorkout(workout) {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
const data = await workoutLibraryApi.createWorkout(workout)
|
||||
userWorkouts.value.unshift(data.workout || data)
|
||||
return data.workout || data
|
||||
} catch (err) {
|
||||
error.value = err.response?.data?.error || 'Failed to create workout'
|
||||
throw err
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function updateWorkout(workoutId, workout) {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
const data = await workoutLibraryApi.updateWorkout(workoutId, workout)
|
||||
const index = userWorkouts.value.findIndex(w => w.id === workoutId)
|
||||
if (index !== -1) {
|
||||
userWorkouts.value[index] = data.workout || data
|
||||
}
|
||||
return data.workout || data
|
||||
} catch (err) {
|
||||
error.value = err.response?.data?.error || 'Failed to update workout'
|
||||
throw err
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteWorkout(workoutId) {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
await workoutLibraryApi.deleteWorkout(workoutId)
|
||||
userWorkouts.value = userWorkouts.value.filter(w => w.id !== workoutId)
|
||||
} catch (err) {
|
||||
error.value = err.response?.data?.error || 'Failed to delete workout'
|
||||
throw err
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function publishWorkout(workoutId) {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
const data = await workoutLibraryApi.publishWorkout(workoutId)
|
||||
const index = userWorkouts.value.findIndex(w => w.id === workoutId)
|
||||
if (index !== -1) {
|
||||
userWorkouts.value[index].is_public = true
|
||||
}
|
||||
return data
|
||||
} catch (err) {
|
||||
error.value = err.response?.data?.error || 'Failed to publish workout'
|
||||
throw err
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchFavorites() {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
const data = await workoutLibraryApi.getFavorites()
|
||||
favorites.value = data.favorites || data.workouts || []
|
||||
} catch (err) {
|
||||
error.value = err.response?.data?.error || 'Failed to fetch favorites'
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
async function toggleFavorite(workoutId) {
|
||||
try {
|
||||
if (isFavorited(workoutId)) {
|
||||
await workoutLibraryApi.removeFavorite(workoutId)
|
||||
favorites.value = favorites.value.filter(f => f.id !== workoutId)
|
||||
} else {
|
||||
await workoutLibraryApi.addFavorite(workoutId)
|
||||
const workout = workouts.value.find(w => w.id === workoutId) || currentWorkout.value
|
||||
if (workout) {
|
||||
favorites.value.push(workout)
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
error.value = err.response?.data?.error || 'Failed to update favorite'
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
async function recordUsage(workoutId) {
|
||||
try {
|
||||
await workoutLibraryApi.recordUsage(workoutId)
|
||||
} catch (err) {
|
||||
console.error('Failed to record usage:', err)
|
||||
}
|
||||
}
|
||||
|
||||
async function rateWorkout(workoutId, rating) {
|
||||
try {
|
||||
const data = await workoutLibraryApi.rateWorkout(workoutId, rating)
|
||||
if (currentWorkout.value && currentWorkout.value.id === workoutId) {
|
||||
currentWorkout.value.average_rating = data.average_rating
|
||||
currentWorkout.value.rating_count = data.rating_count
|
||||
currentWorkout.value.user_rating = rating
|
||||
}
|
||||
return data
|
||||
} catch (err) {
|
||||
error.value = err.response?.data?.error || 'Failed to rate workout'
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
function setFilters(newFilters) {
|
||||
filters.value = { ...filters.value, ...newFilters }
|
||||
pagination.value.page = 1
|
||||
}
|
||||
|
||||
function clearFilters() {
|
||||
filters.value = {
|
||||
category: '',
|
||||
duration_min: null,
|
||||
duration_max: null,
|
||||
intensity_min: null,
|
||||
intensity_max: null,
|
||||
search: ''
|
||||
}
|
||||
pagination.value.page = 1
|
||||
}
|
||||
|
||||
function setPage(page) {
|
||||
pagination.value.page = page
|
||||
}
|
||||
|
||||
return {
|
||||
workouts,
|
||||
userWorkouts,
|
||||
favorites,
|
||||
currentWorkout,
|
||||
currentIntervals,
|
||||
loading,
|
||||
error,
|
||||
filters,
|
||||
pagination,
|
||||
favoriteIds,
|
||||
isFavorited,
|
||||
fetchWorkouts,
|
||||
fetchWorkout,
|
||||
fetchWorkoutIntervals,
|
||||
fetchUserWorkouts,
|
||||
createWorkout,
|
||||
updateWorkout,
|
||||
deleteWorkout,
|
||||
publishWorkout,
|
||||
fetchFavorites,
|
||||
toggleFavorite,
|
||||
recordUsage,
|
||||
rateWorkout,
|
||||
setFilters,
|
||||
clearFilters,
|
||||
setPage
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user