diff --git a/frontend/src/layouts/MainLayout.vue b/frontend/src/layouts/MainLayout.vue index 35e4cbe..845fb5d 100644 --- a/frontend/src/layouts/MainLayout.vue +++ b/frontend/src/layouts/MainLayout.vue @@ -5,16 +5,29 @@ - + + + + + + + +
- -
-
- -
- - + +
@@ -29,9 +42,9 @@ GitRec
- Explore - Trending - Favorites + Explore + Trending + Favorites - - @@ -117,47 +122,54 @@ - diff --git a/frontend/src/mixins/authMixin.js b/frontend/src/mixins/authMixin.js new file mode 100644 index 0000000..706f57d --- /dev/null +++ b/frontend/src/mixins/authMixin.js @@ -0,0 +1,79 @@ +import axios from 'axios'; + +const AUTH_CACHE_KEY = 'gitrec_auth_state'; +const AUTH_CACHE_EXPIRY_MS = 5 * 60 * 1000; // 5 minutes + +export default { + data() { + return { + isAuthenticated: false, + authLogin: null, + }; + }, + methods: { + async checkAuth() { + const cached = localStorage.getItem(AUTH_CACHE_KEY); + if (cached) { + try { + const data = JSON.parse(cached); + if (Date.now() - data.timestamp < AUTH_CACHE_EXPIRY_MS) { + this.isAuthenticated = data.is_authenticated; + this.authLogin = data.login; + return; + } + } catch { + localStorage.removeItem(AUTH_CACHE_KEY); + } + } + + try { + const response = await axios.get('/api/me', { withCredentials: true }); + this.isAuthenticated = response.data.is_authenticated; + this.authLogin = response.data.login; + if (this.isAuthenticated) { + localStorage.setItem(AUTH_CACHE_KEY, JSON.stringify({ + is_authenticated: true, + login: response.data.login, + timestamp: Date.now() + })); + this.dispatchAuthChange(true); + } else { + localStorage.removeItem(AUTH_CACHE_KEY); + } + } catch { + this.isAuthenticated = false; + this.authLogin = null; + localStorage.removeItem(AUTH_CACHE_KEY); + } + }, + async logout() { + try { + await axios.get('/api/logout', { withCredentials: true }); + } catch (error) { + console.error('Logout failed:', error); + } + localStorage.removeItem(AUTH_CACHE_KEY); + this.isAuthenticated = false; + this.authLogin = null; + this.dispatchAuthChange(false); + }, + dispatchAuthChange(authenticated) { + window.dispatchEvent(new CustomEvent('gitrec-auth-change', { + detail: { authenticated } + })); + }, + handleAuthChange(event) { + this.isAuthenticated = event.detail.authenticated; + if (!event.detail.authenticated) { + this.authLogin = null; + } + }, + }, + mounted() { + this.checkAuth(); + window.addEventListener('gitrec-auth-change', this.handleAuthChange); + }, + beforeUnmount() { + window.removeEventListener('gitrec-auth-change', this.handleAuthChange); + }, +}; diff --git a/frontend/src/views/Favorites.vue b/frontend/src/views/Favorites.vue index 9839bb1..ebf468c 100644 --- a/frontend/src/views/Favorites.vue +++ b/frontend/src/views/Favorites.vue @@ -1,33 +1,46 @@ diff --git a/frontend/src/views/Home.vue b/frontend/src/views/Home.vue index d9ddf4d..d1f602b 100644 --- a/frontend/src/views/Home.vue +++ b/frontend/src/views/Home.vue @@ -2,7 +2,7 @@ - -
+ +
{{ like_pressed ? "mdi-heart" : "mdi-heart-outline" }} - + mdi-play
@@ -66,100 +80,80 @@ -