"Fit-Universe" was created to be a demonstration of Vue's composition API
, state management capabilities with Vue version 3 (provide/inject)
, and a way users can chat in
real time while also inputting their workout into the database.
AS a person or influencer who values fitness, growth, and well-being
I WANT a platform that allows me to track my fitness, growth, and well-being
SO THAT I can share this information with like minded individuals across the globe in a social media setting directly within the app
- HTML5
- CSS
- JavaScript
- Vue (Version 3)
- Vue Router
- Naive UI (Vue 3 compatible component library)
- Firebase
- Each workout that comes from the ExerciseDB API doesn't include a standardized formatting to their name. By increasing the number of sets for each movement, I needed to find
a method to create variable names that can be tracked and updated. In order to do this I had to first format every name using the
.replaceAll()
method to eliminate spaces and special characters, the index or current number of sets, and whether the field was for a rep or weight.
addToWorkout(movement) {
state.error = null
state.ongoingWorkout = true
<!-- Format the name -->
const formattedName = movement.replaceAll(' ', '-').replaceAll('/','-').replaceAll('(','').replaceAll(')','')
<!-- Push object into activeWorkout array -->
state.activeWorkout.push({
name: movement,
formattedName: formattedName,
numberSets: 1,
sets: {},
saved: false
})
<!-- Map over each movement in activeWorkout array -->
state.activeWorkout.map(workout => {
<!-- If the current workout's name matches the movement name sent from the front end -->
if(workout.name === movement) {
<!-- Format the rep and weight key's -->
const repName = `${workout.formattedName}-${workout.numberSets}-rep`
const weightName = `${workout.formattedName}-${workout.numberSets}-weight`
<!-- Send formatted names to be added as a set -->
methods.addNewSet(repName, weightName, formattedName)
}
})
},
addNewSet(repName, weightName, formattedName) {
state.error = null
<!-- Find the matching movement in activeWorkout array -->
state.activeWorkout.map(workout => {
if (workout.formattedName === formattedName) {
<!-- Add the formatted keys to the sets object -->
workout.sets = { ...workout.sets, [`${repName}`]: 0}
workout.sets = { ...workout.sets, [`${weightName}`]: 0}
}
})
},
updateReps(value, formattedName, repName) {
state.error = null
state.activeWorkout.map(workout => {
if (workout.formattedName === formattedName) {
workout.sets = {...workout.sets, [`${repName}`]: value}
}
})
},
All components utilize the Vue 3 composition API
which uses thesetup()
function for the components logic.Lifecycle hooks
exposed within the composition API are used to pre-load data prior to mounting the component for the user to see or to compute data for use within the component.- Components utilize the
template ref
method to create references within the template that can be dynamically updated with state changes.
- Workout movements are generated using the ExerciseDB API provided on RapidAPI.
- Clicking on a specific body part fetches data from the API and populates the results as clickable buttons to add a movement to your workout.
- In
/composables
lies functions that can be reused throughout the entire project. Each JavaScript file contains logic to perform either of theCRUD
operations for the Firebase Firestore.
- Main entry point for the application is the App.vue but the first page rended is the
Home
component. Except for the home page, all components are lazy loaded
using a callback function that not only allows webpack to chunk the data for the component but to only load the component when routed to it.Components beyond the login/signup screen require authentication
to be able to be displayed.Authentication is provided by Firebase in firebase.config file.
{
path: '/signup',
name: 'Signup',
component: () => import(/* webpackChunkName: "Signup" */ '../views/Signup.vue'),
beforeEnter: requireNoAuth
},
{
path: '/dashboard',
name: 'Dashboard',
component: () => import(/* webpackChunkName: "Dashboard" */ '../views/Dashboard.vue'),
beforeEnter: requireAuth
},
- State management is handled by using the Vue 3
provide
andinject
methods. - The modules are provided within the
App.vue
setup functions which allows the store modules to be made available throughout the entirety of the project. Components will theninject
the module from the store required for the component. - In
/store
lies anindex.js
file which exports all of the "modules" that contain the local state for their area of the project as well as their own "methods."
provide('store', store)
- Users are able to
upload
their own profile images to Firebase Storage. This data is persistent and will load whenever the user logs into their account.
const uploadImage = async (file) => {
filePath.value = `userImage/${user.value.uid}`
const storageRef = projectStorage.ref(filePath.value)
try {
const response = await storageRef.put(file)
url.value = await response.ref.getDownloadURL()
} catch (err) {
error.value = err.message
}
}
Firebase's firestore
provides the storage required to save the chat comments as well as saving progress and the final workout version.- By using the firestore, users are able to return to their previously left off workout whenever they return to the application.
- Creating dynamic variable names for each set of a given exercise movement. Each time a user adds a new movement to their workout, the application generates a unique variable name to correspond to the input field and allows for
modeling
of data to be possible when updating the fields. - Creating a unique identifier on the back end for each document in a collection prior to storing in the firestore.
- Creating CRUD operation methods for the application within current limitations.
- Limited API calls
- Limited Firebase read/writes
- Unable to return the values for a previously saved workout to the input fields
value
property.Values are retained but not seen on the front end.
- Resizing user avatar so that dimensions are not warped
- Not mobile responsive
- Only one chatroom field