mirror of
https://github.com/joaovitoriasilva/endurain.git
synced 2026-01-10 08:17:59 -05:00
Frontend revamp with Vue
[frontend] Fixed background colors. Footer and navbar are grey and the rest is black. Gives a better contrast between the elements [frontend] Moved search logic to footer. It is now possible to search in every view if the user is logged by user and gear. Activity is missing. [frontend] Changed icon and link color to "link-body-emphasis", meaning in dark theme it will be white and in light theme it will be black. [frontend] Fixed routing on user page when navigating between users. Now user data is updated.
This commit is contained in:
@@ -44,4 +44,4 @@ ENV FRONTEND_HOST="frontend"
|
||||
ENV GEOCODES_MAPS_API="changeme"
|
||||
|
||||
# Run main.py when the container launches
|
||||
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"]
|
||||
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"]
|
||||
@@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html data-bs-theme="dark" lang="en">
|
||||
<html class="bg-body-secondary" data-bs-theme="dark" lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="icon" href="/logo/logo.png">
|
||||
@@ -7,7 +7,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Endurain</title>
|
||||
</head>
|
||||
<body class="bg-body">
|
||||
<body >
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
<script>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
<template>
|
||||
<NavbarComponent />
|
||||
<main class="container mt-4 mb-4">
|
||||
<main class="container py-4 bg-body">
|
||||
<RouterView />
|
||||
</main>
|
||||
<FooterComponent />
|
||||
|
||||
@@ -14,10 +14,10 @@
|
||||
<img src="/src/assets/avatar/female1.png" alt="Default Female Avatar" width="55" height="55" class="rounded-circle" v-else>
|
||||
<div class="ms-3 me-3">
|
||||
<div class="fw-bold">
|
||||
<router-link :to="{ name: 'activity', params: { id: activity.id }}" class="link-underline-opacity-25 link-underline-opacity-100-hover" v-if="sourceProp === 'home'">
|
||||
<router-link :to="{ name: 'activity', params: { id: activity.id }}" class="link-body-emphasis link-underline-opacity-0 link-underline-opacity-100-hover" v-if="sourceProp === 'home'">
|
||||
{{ activity.name}}
|
||||
</router-link>
|
||||
<router-link :to="{ name: 'user', params: { id: userActivity.id }}" class="link-underline-opacity-25 link-underline-opacity-100-hover" v-if="sourceProp === 'activity'">
|
||||
<router-link :to="{ name: 'user', params: { id: userActivity.id }}" class="link-body-emphasis link-underline-opacity-0 link-underline-opacity-100-hover" v-if="sourceProp === 'activity'">
|
||||
{{ userActivity.name}}
|
||||
</router-link>
|
||||
</div>
|
||||
@@ -52,11 +52,11 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="dropdown d-flex">
|
||||
<a class="btn btn-link btn-lg mt-1" :href="`https://www.strava.com/activities/${activity.strava_activity_id}`" role="button" v-if="activity.strava_activity_id">
|
||||
<a class="btn btn-link btn-lg mt-1 link-body-emphasis" :href="`https://www.strava.com/activities/${activity.strava_activity_id}`" role="button" v-if="activity.strava_activity_id">
|
||||
<font-awesome-icon :icon="['fab', 'fa-strava']" />
|
||||
</a>
|
||||
<div v-if="sourceProp === 'activity'">
|
||||
<button class="btn btn-link btn-lg" type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<button class="btn btn-link btn-lg link-body-emphasis" type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
<font-awesome-icon :icon="['fas', 'fa-ellipsis-vertical']" />
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
|
||||
@@ -8,12 +8,12 @@
|
||||
<img src="/src/assets/avatar/female1.png" alt="Default Female Avatar" width="55" height="55" class="rounded-circle" v-else>
|
||||
<div class="ms-3">
|
||||
<div class="fw-bold">
|
||||
<!--<router-link :to="{ name: 'user', params: { id: userFollower.id }}">
|
||||
<router-link :to="{ name: 'user', params: { id: userFollower.id }}" class="link-body-emphasis link-underline-opacity-0 link-underline-opacity-100-hover">
|
||||
{{ userFollower.name }}
|
||||
</router-link>-->
|
||||
<a :href="`/user/${userFollower.id}`">
|
||||
</router-link>
|
||||
<!--<a :href="`/user/${userFollower.id}`" class="link-body-emphasis link-underline-opacity-0 link-underline-opacity-100-hover">
|
||||
{{ userFollower.name }}
|
||||
</a>
|
||||
</a>-->
|
||||
</div>
|
||||
{{ userFollower.username }}
|
||||
</div>
|
||||
@@ -25,7 +25,7 @@
|
||||
<span class="badge bg-danger-subtle border border-danger-subtle text-danger-emphasis rounded-pill align-middle" v-else>{{ $t("followersListComponent.requestPending") }}</span>
|
||||
|
||||
<!-- delete following zone -->
|
||||
<a class="ms-2 btn btn-link btn-lg" href="#" role="button" data-bs-toggle="modal" :data-bs-target="`#deleteFollowingModal${userFollower.id}`" v-if="typeProp == 1 && loggedUserId == idFromParam"><font-awesome-icon :icon="['fas', 'fa-trash']" /></a>
|
||||
<a class="ms-2 btn btn-link btn-lg link-body-emphasis" href="#" role="button" data-bs-toggle="modal" :data-bs-target="`#deleteFollowingModal${userFollower.id}`" v-if="typeProp == 1 && loggedUserId == idFromParam"><font-awesome-icon :icon="['fas', 'fa-trash']" /></a>
|
||||
|
||||
<div class="modal fade" :id="`deleteFollowingModal${userFollower.id}`" tabindex="-1" :aria-labelledby="`deleteFollowingModal${userFollower.id}`" aria-hidden="true" v-if="typeProp == 1 && loggedUserId == idFromParam">
|
||||
<div class="modal-dialog">
|
||||
@@ -54,7 +54,7 @@
|
||||
</div>
|
||||
|
||||
<!-- delete follower zone -->
|
||||
<a class="ms-2 btn btn-link btn-lg" href="#" role="button" data-bs-toggle="modal" :data-bs-target="`#deleteFollowerModal${userFollower.id}`" v-if="typeProp != 1 && loggedUserId == idFromParam && followerProp.is_accepted == 1"><font-awesome-icon :icon="['fas', 'fa-trash']" /></a>
|
||||
<a class="ms-2 btn btn-link btn-lg link-body-emphasis" href="#" role="button" data-bs-toggle="modal" :data-bs-target="`#deleteFollowerModal${userFollower.id}`" v-if="typeProp != 1 && loggedUserId == idFromParam && followerProp.is_accepted == 1"><font-awesome-icon :icon="['fas', 'fa-trash']" /></a>
|
||||
|
||||
<!-- Modal delete follower -->
|
||||
<div class="modal fade" :id="`deleteFollowerModal${userFollower.id}`" tabindex="-1" :aria-labelledby="`deleteFollowerModal${userFollower.id}`" aria-hidden="true" v-if="typeProp != 1 && loggedUserId == idFromParam && followerProp.is_accepted == 1">
|
||||
@@ -84,7 +84,7 @@
|
||||
</div>
|
||||
|
||||
<!-- accept folllower request -->
|
||||
<a class="btn btn-link btn-lg" href="#" role="button" data-bs-toggle="modal" :data-bs-target="`#acceptRequestModal${userFollower.id}`" v-if="typeProp != 1 && loggedUserId == idFromParam && followerProp.is_accepted == 0"><font-awesome-icon :icon="['fas', 'fa-check']" /></a>
|
||||
<a class="btn btn-link btn-lg link-body-emphasis" href="#" role="button" data-bs-toggle="modal" :data-bs-target="`#acceptRequestModal${userFollower.id}`" v-if="typeProp != 1 && loggedUserId == idFromParam && followerProp.is_accepted == 0"><font-awesome-icon :icon="['fas', 'fa-check']" /></a>
|
||||
|
||||
<!-- Modal accept user request -->
|
||||
<div class="modal fade" :id="`acceptRequestModal${userFollower.id}`" tabindex="-1" :aria-labelledby="`acceptRequestModal${userFollower.id}`" aria-hidden="true" v-if="typeProp != 1 && loggedUserId == idFromParam && followerProp.is_accepted == 0">
|
||||
@@ -114,7 +114,7 @@
|
||||
</div>
|
||||
|
||||
<!-- decline user request button -->
|
||||
<a class="ms-2 btn btn-link btn-lg" href="#" role="button" data-bs-toggle="modal" :data-bs-target="`#declineRequestModal${userFollower.id}`" v-if="typeProp != 1 && loggedUserId == idFromParam && followerProp.is_accepted == 0"><font-awesome-icon :icon="['fas', 'fa-x']" /></a>
|
||||
<a class="ms-2 btn btn-link btn-lg link-body-emphasis" href="#" role="button" data-bs-toggle="modal" :data-bs-target="`#declineRequestModal${userFollower.id}`" v-if="typeProp != 1 && loggedUserId == idFromParam && followerProp.is_accepted == 0"><font-awesome-icon :icon="['fas', 'fa-x']" /></a>
|
||||
|
||||
<!-- Modal decline user request -->
|
||||
<div class="modal fade" :id="`declineRequestModal${userFollower.id}`" tabindex="-1" :aria-labelledby="`declineRequestModal${userFollower.id}`" aria-hidden="true" v-if="typeProp != 1 && loggedUserId == idFromParam && followerProp.is_accepted == 0">
|
||||
|
||||
@@ -1,7 +1,136 @@
|
||||
<template>
|
||||
<footer class="pb-3 mt-auto bg-body">
|
||||
<hr>
|
||||
<p class="text-center text-muted">© {{ new Date().getFullYear() === 2023 ? '2023' : '2023 - ' + new Date().getFullYear() }} Endurain • <a href="https://github.com/joaovitoriasilva/endurain" role="button"><font-awesome-icon :icon="['fab', 'fa-github']" /></a> • <a href="https://fosstodon.org/@endurain"><font-awesome-icon :icon="['fab', 'fa-mastodon']" /></a> • v0.1.6</p>
|
||||
<p class="text-center text-muted"><img src="/src/assets/strava/api_logo_cptblWith_strava_horiz_light.png" alt="Compatible with STRAVA image" height="25" /></p>
|
||||
<footer class="py-5 bg-body-secondary">
|
||||
<div class="container">
|
||||
<div class="row align-items-center justify-content-center">
|
||||
<div class="col-md" v-if="isLoggedIn">
|
||||
<form>
|
||||
<label for="inputSelectTypeToSearch" class="form-label">{{ $t("footer.searchSelectLabel") }}</label>
|
||||
<select id="inputSelectTypeToSearch" class="form-select" v-model="searchSelectValue">
|
||||
<option value="1">{{ $t("footer.searchSelectOptionUser") }}</option>
|
||||
<option value="2">{{ $t("footer.searchSelectOptionActivity") }}</option>
|
||||
<option value="3">{{ $t("footer.searchSelectOptionGear") }}</option>
|
||||
</select>
|
||||
<br>
|
||||
<input type="text" class="form-control" id="inputTextFieldToSearch" :placeholder='$t("footer.searchInputPlaceholder")' v-model="inputSearch">
|
||||
<ul v-if="searchResults.length" class="list-group">
|
||||
<li v-for="result in searchResults" :key="result.id" class="list-group-item list-group-item-action" @click="goToResultPage(result)">
|
||||
<!-- user link -->
|
||||
<router-link :to="{ name: 'user', params: { id: result.id }}" class="link-body-emphasis link-underline-opacity-0 link-underline-opacity-100-hover" v-if="searchSelectValue == 1">
|
||||
{{ result.name}}
|
||||
</router-link>
|
||||
<router-link :to="{ name: 'activity', params: { id: result.id }}" class="link-body-emphasis link-underline-opacity-0 link-underline-opacity-100-hover" v-else-if="searchSelectValue == 2">
|
||||
{{ result.name}}
|
||||
</router-link>
|
||||
<router-link :to="{ name: 'gear', params: { id: result.id }}" class="link-body-emphasis link-underline-opacity-0 link-underline-opacity-100-hover" v-else-if="searchSelectValue == 3">
|
||||
{{ result.nickname }}
|
||||
</router-link>
|
||||
</li>
|
||||
</ul>
|
||||
</form>
|
||||
</div>
|
||||
<div class="mt-3 col">
|
||||
<p class="text-center text-muted">© {{ new Date().getFullYear() === 2023 ? '2023' : '2023 - ' + new Date().getFullYear() }} Endurain • <a class="link-body-emphasis" href="https://github.com/joaovitoriasilva/endurain" role="button"><font-awesome-icon :icon="['fab', 'fa-github']" /></a> • <a class="link-body-emphasis" href="https://fosstodon.org/@endurain"><font-awesome-icon :icon="['fab', 'fa-mastodon']" /></a> • v0.1.6</p>
|
||||
<p class="text-center text-muted"><img src="/src/assets/strava/api_logo_cptblWith_strava_horiz_light.png" alt="Compatible with STRAVA image" height="25" /></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { watch, ref } from 'vue';
|
||||
import { auth } from '@/services/auth';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
import { users } from '@/services/user';
|
||||
import { gears } from '@/services/gears';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const route = useRoute();
|
||||
const { t } = useI18n();
|
||||
const path = ref(route.path);
|
||||
const isLoggedIn = ref(auth.isTokenValid(localStorage.getItem('accessToken')))
|
||||
const searchSelectValue = ref(1);
|
||||
const inputSearch = ref('');
|
||||
const searchResults = ref([]);
|
||||
|
||||
const fetchUserResults = async (query) => {
|
||||
if (!query) {
|
||||
searchResults.value = [];
|
||||
return;
|
||||
}
|
||||
try {
|
||||
searchResults.value = await users.getUserByUsername(query);
|
||||
} catch (error) {
|
||||
console.error('Error fetching user results:', error);
|
||||
}
|
||||
};
|
||||
|
||||
/* const fetchActivityResults = async (query) => {
|
||||
if (!query) {
|
||||
searchResults.value = [];
|
||||
return;
|
||||
}
|
||||
try {
|
||||
// Replace with your actual API call for activities
|
||||
searchResults.value = await activities.getActivityByName(query);
|
||||
} catch (error) {
|
||||
console.error('Error fetching activity results:', error);
|
||||
}
|
||||
}; */
|
||||
|
||||
const fetchGearResults = async (query) => {
|
||||
if (!query) {
|
||||
searchResults.value = [];
|
||||
return;
|
||||
}
|
||||
try {
|
||||
// Replace with your actual API call for gear
|
||||
searchResults.value = await gears.getGearByNickname(query);
|
||||
} catch (error) {
|
||||
console.error('Error fetching gear results:', error);
|
||||
}
|
||||
};
|
||||
|
||||
watch(() => route.path, (newPath, oldPath) => {
|
||||
path.value = newPath;
|
||||
/* reset search values */
|
||||
searchSelectValue.value = 1;
|
||||
inputSearch.value = '';
|
||||
searchResults.value = [];
|
||||
// Perform actions based on newPath if needed
|
||||
if (newPath === '/login' && isLoggedIn.value) {
|
||||
isLoggedIn.value = auth.isTokenValid(localStorage.getItem('accessToken'));
|
||||
}
|
||||
if (oldPath === '/login' && !isLoggedIn.value) {
|
||||
isLoggedIn.value = auth.isTokenValid(localStorage.getItem('accessToken'));
|
||||
}
|
||||
});
|
||||
|
||||
watch(searchSelectValue, () => {
|
||||
inputSearch.value = '';
|
||||
searchResults.value = [];
|
||||
});
|
||||
|
||||
watch(inputSearch, async (newQuery) => {
|
||||
if (searchSelectValue.value == 1) {
|
||||
await fetchUserResults(newQuery);
|
||||
} else if (searchSelectValue.value == 2) {
|
||||
// await fetchActivityResults(newQuery);
|
||||
} else {
|
||||
await fetchGearResults(newQuery);
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
isLoggedIn,
|
||||
searchSelectValue,
|
||||
inputSearch,
|
||||
searchResults,
|
||||
t,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
||||
7
frontend_vue/src/i18n/en/components/footerComponent.json
Normal file
7
frontend_vue/src/i18n/en/components/footerComponent.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"searchSelectLabel": "Search",
|
||||
"searchSelectOptionActivity": "Activity",
|
||||
"searchSelectOptionUser": "User",
|
||||
"searchSelectOptionGear": "Gear",
|
||||
"searchInputPlaceholder": "Search text"
|
||||
}
|
||||
@@ -1,8 +1,9 @@
|
||||
import { createI18n } from 'vue-i18n';
|
||||
|
||||
// Importing translations
|
||||
// Navbar component
|
||||
// Navbar and footer components
|
||||
import enNavbarComponent from './en/components/navbarComponent.json';
|
||||
import enFooterComponent from './en/components/footerComponent.json';
|
||||
// Activities component
|
||||
import enUserDistanceStatsComponent from './en/components/activities/userDistanceStatsComponent.json';
|
||||
import enActivitySummaryComponent from './en/components/activities/activitySummaryComponent.json';
|
||||
@@ -25,6 +26,7 @@ import enUserView from './en/userView.json';
|
||||
const messages = {
|
||||
en: {
|
||||
navbar: enNavbarComponent,
|
||||
footer: enFooterComponent,
|
||||
userDistanceStats: enUserDistanceStatsComponent,
|
||||
activitySummary: enActivitySummaryComponent,
|
||||
followersListComponent: enFollowersListComponent,
|
||||
|
||||
@@ -4,4 +4,7 @@ export const users = {
|
||||
getUserById(user_id) {
|
||||
return fetchGetRequest(`users/id/${user_id}`);
|
||||
},
|
||||
getUserByUsername(username){
|
||||
return fetchGetRequest(`users/username/contains/${username}`);
|
||||
}
|
||||
};
|
||||
@@ -46,7 +46,7 @@
|
||||
</p>
|
||||
<div class="justify-content-end">
|
||||
<!-- add gear button -->
|
||||
<a class="btn btn-link btn-lg" href="#" role="button" data-bs-toggle="modal" data-bs-target="#addGearToActivityModal" v-if="!activity.gear_id">
|
||||
<a class="btn btn-link btn-lg link-body-emphasis" href="#" role="button" data-bs-toggle="modal" data-bs-target="#addGearToActivityModal" v-if="!activity.gear_id">
|
||||
<font-awesome-icon :icon="['fas', 'fa-plus']" />
|
||||
</a>
|
||||
|
||||
@@ -86,12 +86,12 @@
|
||||
|
||||
|
||||
<!-- edit gear button -->
|
||||
<a class="btn btn-link btn-lg" href="#" role="button" data-bs-toggle="modal" data-bs-target="#addGearToActivityModal" v-if="activity.gear_id">
|
||||
<a class="btn btn-link btn-lg link-body-emphasis" href="#" role="button" data-bs-toggle="modal" data-bs-target="#addGearToActivityModal" v-if="activity.gear_id">
|
||||
<font-awesome-icon :icon="['far', 'fa-pen-to-square']" />
|
||||
</a>
|
||||
|
||||
<!-- Delete zone -->
|
||||
<a class="btn btn-link btn-lg" href="#" role="button" data-bs-toggle="modal" data-bs-target="#deleteGearActivityModal" v-if="activity.gear_id">
|
||||
<a class="btn btn-link btn-lg link-body-emphasis" href="#" role="button" data-bs-toggle="modal" data-bs-target="#deleteGearActivityModal" v-if="activity.gear_id">
|
||||
<font-awesome-icon :icon="['fas', 'fa-trash']" />
|
||||
</a>
|
||||
|
||||
|
||||
@@ -161,7 +161,7 @@
|
||||
<div v-else>
|
||||
<ul class="list-group list-group-flush" v-for="activity in gearActivities" :key="activity.id" :activity="activity">
|
||||
<li class="vstack list-group-item d-flex justify-content-between">
|
||||
<router-link :to="{ name: 'activity', params: { id: activity.id }}">
|
||||
<router-link :to="{ name: 'activity', params: { id: activity.id }}" class="link-body-emphasis link-underline-opacity-0 link-underline-opacity-100-hover">
|
||||
{{ activity.name}}
|
||||
</router-link>
|
||||
<span><strong>{{ $t("gear.labelDate") }}:</strong> {{ formatDate(activity.start_time) }} @ {{ formatTime(activity.start_time) }}</span>
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
<img src="/src/assets/avatar/wetsuit1.png" alt="Bycicle avatar" width="55" height="55" v-else>
|
||||
<div class="ms-3">
|
||||
<div class="fw-bold">
|
||||
<router-link :to="{ name: 'gear', params: { id: gear.id }}" class="link-underline-opacity-25 link-underline-opacity-100-hover">
|
||||
<router-link :to="{ name: 'gear', params: { id: gear.id }}" class="link-body-emphasis link-underline-opacity-0 link-underline-opacity-100-hover">
|
||||
{{ gear.nickname }}
|
||||
</router-link>
|
||||
</div>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<img src="/src/assets/avatar/female1.png" alt="Default Female Avatar" width="120" height="120" class="rounded-circle" v-else>
|
||||
</div>
|
||||
<div class="text-center mt-3 mb-3 fw-bold">
|
||||
<router-link :to="{ name: 'user', params: { id: userMe.id }}" class="link-underline-opacity-25 link-underline-opacity-100-hover">
|
||||
<router-link :to="{ name: 'user', params: { id: userMe.id }}" class="link-body-emphasis link-underline-opacity-0 link-underline-opacity-100-hover">
|
||||
{{ userMe.name}}
|
||||
</router-link>
|
||||
</div>
|
||||
|
||||
@@ -68,28 +68,28 @@
|
||||
</div>
|
||||
<ul class="nav nav-pills mb-3 justify-content-center" id="pills-tab" role="tablist" v-else>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link active" id="pills-activities-tab" data-bs-toggle="pill"
|
||||
<button class="nav-link active link-body-emphasis" id="pills-activities-tab" data-bs-toggle="pill"
|
||||
data-bs-target="#pills-activities" type="button" role="tab" aria-controls="pills-activities"
|
||||
aria-selected="true">
|
||||
{{ $t("user.navigationActivities") }}
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" id="pills-following-tab" data-bs-toggle="pill"
|
||||
<button class="nav-link link-body-emphasis" id="pills-following-tab" data-bs-toggle="pill"
|
||||
data-bs-target="#pills-following" type="button" role="tab" aria-controls="pills-following"
|
||||
aria-selected="false">
|
||||
{{ $t("user.navigationFollowing") }}
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" id="pills-followers-tab" data-bs-toggle="pill"
|
||||
<button class="nav-link link-body-emphasis" id="pills-followers-tab" data-bs-toggle="pill"
|
||||
data-bs-target="#pills-followers" type="button" role="tab" aria-controls="pills-followers"
|
||||
aria-selected="false">
|
||||
{{ $t("user.navigationFollowers") }}
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation" v-if="userMe.id == loggedUserId">
|
||||
<router-link :to="{ name: 'settings', query: { profileSettings: 1 }}" class="btn nav-link">
|
||||
<router-link :to="{ name: 'settings', query: { profileSettings: 1 }}" class="btn nav-link link-body-emphasis">
|
||||
<font-awesome-icon :icon="['fas', 'fa-gear']" />
|
||||
{{ $t("user.navigationUserSettings") }}
|
||||
</router-link>
|
||||
@@ -117,14 +117,17 @@
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="tab-content" id="pills-tabContent">
|
||||
<div v-if="isLoading">
|
||||
<LoadingComponent />
|
||||
</div>
|
||||
<div class="tab-content" id="pills-tabContent" v-else>
|
||||
<!-- activities tab content -->
|
||||
<div class="tab-pane fade show active" id="pills-activities" role="tabpanel" aria-labelledby="pills-activities-tab" tabindex="0">
|
||||
<!-- pagination -->
|
||||
<nav>
|
||||
<ul class="pagination justify-content-center">
|
||||
<li :class="['page-item', { active: week === 0 }]" >
|
||||
<a href="#" class="page-link" @click="setWeek(0, $event)">
|
||||
<a href="#" class="page-link link-body-emphasis" @click="setWeek(0, $event)">
|
||||
{{ $t("user.activitiesPaginationWeek0") }}
|
||||
</a>
|
||||
</li>
|
||||
@@ -132,7 +135,7 @@
|
||||
<a class="page-link">...</a>
|
||||
</li>
|
||||
<li v-for="i in visibleWeeks" :key="i" :class="['page-item', { active: i === week }]" >
|
||||
<a href="#" class="page-link" @click="setWeek(i, $event)">
|
||||
<a href="#" class="page-link link-body-emphasis" @click="setWeek(i, $event)">
|
||||
{{ formatDateRange(i) }}
|
||||
</a>
|
||||
</li>
|
||||
@@ -140,39 +143,30 @@
|
||||
<a class="page-link">...</a>
|
||||
</li>
|
||||
<li :class="['page-item', { active: week === 51 }]" >
|
||||
<a href="#" class="page-link" @click="setWeek(51, $event)">
|
||||
<a href="#" class="page-link link-body-emphasis" @click="setWeek(51, $event)">
|
||||
{{ $t("user.activitiesPaginationWeek51") }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<!-- activities -->
|
||||
<div v-if="isActivitiesLoading">
|
||||
<LoadingComponent />
|
||||
</div>
|
||||
<div v-else>
|
||||
<!-- Checking if userWeekActivities is loaded and has length -->
|
||||
<div v-if="userWeekActivities && userWeekActivities.length">
|
||||
<!-- Iterating over userWeekActivities to display them -->
|
||||
<div class="card mb-3" v-for="activity in userWeekActivities" :key="activity.id">
|
||||
<div class="card-body">
|
||||
<ActivitySummaryComponent :activity="activity" :source="'home'"/>
|
||||
</div>
|
||||
<ActivityMapComponent class="mx-3 mb-3" :activity="activity" :source="'home'"/>
|
||||
<!-- Checking if userWeekActivities is loaded and has length -->
|
||||
<div v-if="userWeekActivities && userWeekActivities.length">
|
||||
<!-- Iterating over userWeekActivities to display them -->
|
||||
<div class="card mb-3" v-for="activity in userWeekActivities" :key="activity.id">
|
||||
<div class="card-body">
|
||||
<ActivitySummaryComponent :activity="activity" :source="'home'"/>
|
||||
</div>
|
||||
<ActivityMapComponent class="mx-3 mb-3" :activity="activity" :source="'home'"/>
|
||||
</div>
|
||||
<!-- Displaying a message or component when there are no activities -->
|
||||
<NoItemsFoundComponent v-else />
|
||||
</div>
|
||||
<!-- Displaying a message or component when there are no activities -->
|
||||
<NoItemsFoundComponent v-else />
|
||||
</div>
|
||||
|
||||
<!-- following tab content -->
|
||||
<div class="tab-pane fade" id="pills-following" role="tabpanel" aria-labelledby="pills-following-tab" tabindex="0">
|
||||
<div v-if="isLoading">
|
||||
<LoadingComponent />
|
||||
</div>
|
||||
<ul class="list-group list-group-flush align-items-center" v-if="!isLoading && userFollowersAll && userFollowersAll.length">
|
||||
<ul class="list-group list-group-flush align-items-center" v-if="userFollowersAll && userFollowersAll.length">
|
||||
<li class="list-group-item d-flex justify-content-between" v-for="follower in userFollowersAll" :key="follower.following_id">
|
||||
<FollowersListComponent :follower="follower" :type="1"/>
|
||||
</li>
|
||||
@@ -183,10 +177,7 @@
|
||||
|
||||
<!-- followers tab content -->
|
||||
<div class="tab-pane fade" id="pills-followers" role="tabpanel" aria-labelledby="pills-followers-tab" tabindex="0">
|
||||
<div v-if="isLoading">
|
||||
<LoadingComponent />
|
||||
</div>
|
||||
<ul class="list-group list-group-flush align-items-center" v-if="!isLoading && userFollowersAll && userFollowersAll.length">
|
||||
<ul class="list-group list-group-flush align-items-center" v-if="userFollowersAll && userFollowersAll.length">
|
||||
<li class="list-group-item d-flex justify-content-between" v-for="follower in userFollowingAll" :key="follower.following_id">
|
||||
<FollowersListComponent :follower="follower" :type="2"/>
|
||||
</li>
|
||||
@@ -204,7 +195,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref, onMounted, computed } from 'vue';
|
||||
import { ref, onMounted, computed, watch } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import { useUserStore } from '@/stores/user';
|
||||
@@ -258,7 +249,35 @@ export default {
|
||||
const errorMessage = ref('');
|
||||
const userFollowState = ref(null);
|
||||
|
||||
onMounted(async () => {
|
||||
const fetchData = async () => {
|
||||
isLoading.value = true;
|
||||
isActivitiesLoading.value = true;
|
||||
week.value = 0;
|
||||
try {
|
||||
await userStore.fetchUserMe(route.params.id);
|
||||
await userStore.fetchUserStats();
|
||||
await userStore.fetchUserThisMonthActivitiesNumber();
|
||||
await userStore.fetchUserFollowersCountAccepted();
|
||||
await userStore.fetchUserFollowingCountAccepted();
|
||||
await userStore.fetchUserFollowersAll();
|
||||
await userStore.fetchUserFollowingAll();
|
||||
userWeekActivities.value = await activities.getUserWeekActivities(userMe.value.id, week.value);
|
||||
if (userMe.value.id != loggedUserId) {
|
||||
userFollowState.value = await followers.getUserFollowState(loggedUserId, userMe.value.id);
|
||||
}
|
||||
} catch (error) {
|
||||
errorMessage.value = t('generalItens.errorFetchingInfo') + " - " + error.toString();
|
||||
errorAlertStore.setAlertMessage(errorMessage.value);
|
||||
}
|
||||
isLoading.value = false;
|
||||
isActivitiesLoading.value = false;
|
||||
};
|
||||
|
||||
onMounted(fetchData);
|
||||
|
||||
watch(() => route.params.id, fetchData);
|
||||
|
||||
/* onMounted(async () => {
|
||||
try {
|
||||
// Fetch the user stats
|
||||
await userStore.fetchUserMe(route.params.id);
|
||||
@@ -268,7 +287,7 @@ export default {
|
||||
await userStore.fetchUserFollowingCountAccepted();
|
||||
await userStore.fetchUserFollowersAll();
|
||||
await userStore.fetchUserFollowingAll();
|
||||
userWeekActivities.value = activities.getUserWeekActivities(userMe.value.id, week.value);
|
||||
userWeekActivities.value = await activities.getUserWeekActivities(userMe.value.id, week.value);
|
||||
if (userMe.value.id != loggedUserId) {
|
||||
userFollowState.value = await followers.getUserFollowState(loggedUserId, userMe.value.id);
|
||||
}
|
||||
@@ -280,7 +299,7 @@ export default {
|
||||
|
||||
isLoading.value = false;
|
||||
isActivitiesLoading.value = false;
|
||||
});
|
||||
}); */
|
||||
|
||||
function formatDateRange(weekNumber) {
|
||||
const today = new Date();
|
||||
|
||||
Reference in New Issue
Block a user