Refactor code structure and remove redundant sections for improved readability and maintainability

This commit is contained in:
2026-05-26 20:21:02 +07:00
parent 8df58d74de
commit c0be5d76d6
31 changed files with 97 additions and 52 deletions
+1 -3
View File
@@ -52,9 +52,7 @@ const authStore = useAuthStore();
const uiStore = useUiStore();
const playerStore = usePlayerStore();
const isAuthPage = computed(() => {
return route.meta?.guest === true || route.path === '/register';
});
const isAuthPage = computed(() => route.meta?.guest === true)
const hasPlayer = computed(() => !!playerStore.currentTrack);
+15 -3
View File
@@ -41,14 +41,14 @@
<path d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"/>
</svg>
</button>
<router-link to="/profile" class="text-black hover:opacity-80">
<button @click="goToProfile" class="text-black hover:opacity-80">
<div class="w-8 h-8 rounded-full bg-noctune-dark overflow-hidden border-2 border-black">
<img v-if="authStore.user?.avatarUrl" :src="formatUrl(authStore.user.avatarUrl)" class="w-full h-full object-cover" />
<div v-else class="w-full h-full flex items-center justify-center">
<svg class="w-5 h-5 text-white" fill="currentColor" viewBox="0 0 24 24"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/></svg>
</div>
</div>
</router-link>
</button>
</div>
</header>
</template>
@@ -61,11 +61,13 @@ import { usePlayerStore } from '../stores/playerStore.js'
import { useQueueStore } from '../stores/queueStore.js'
import api from '../lib/api.js'
import { formatUrl } from '../lib/utils.js'
import { useAuthGate } from '../composables/useAuthGate.js'
const router = useRouter()
const authStore = useAuthStore()
const playerStore = usePlayerStore()
const queueStore = useQueueStore()
const { requireAuth } = useAuthGate()
const query = ref('')
const searchResults = ref(null)
@@ -100,6 +102,16 @@ function playSearchTrack(track) {
}
function toggleLikeRedirect() {
router.push('/library')
requireAuth({
redirectTo: '/login',
onAuthenticated: () => router.push('/library')
})
}
function goToProfile() {
requireAuth({
redirectTo: '/login',
onAuthenticated: () => router.push('/profile')
})
}
</script>
+7 -2
View File
@@ -60,10 +60,12 @@ import { usePlayerStore } from '../stores/playerStore.js'
import { useQueueStore } from '../stores/queueStore.js'
import { useAuthStore } from '../stores/authStore.js'
import { formatUrl } from '../lib/utils.js'
import { useAuthGate } from '../composables/useAuthGate.js'
const playerStore = usePlayerStore()
const queueStore = useQueueStore()
const authStore = useAuthStore()
const { requireAuth } = useAuthGate()
const isLiked = ref(false)
@@ -105,10 +107,13 @@ function playPrev() {
}
}
async function toggleLike() {
function toggleLike() {
if (!playerStore.currentTrack) return
const id = playerStore.currentTrack._id || playerStore.currentTrack.id
await authStore.toggleLike(id)
requireAuth({
redirectTo: '/login',
onAuthenticated: () => authStore.toggleLike(id)
})
}
// Sync isLiked ref reactively from authStore
+16 -8
View File
@@ -70,6 +70,7 @@ import { ref, onMounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { useAuthStore } from '../stores/authStore.js'
import api from '../lib/api.js'
import { useAuthGate } from '../composables/useAuthGate.js'
const route = useRoute()
const router = useRouter()
@@ -77,6 +78,8 @@ const authStore = useAuthStore()
const playlists = ref([])
const { requireAuth } = useAuthGate()
const isActive = (path) => route.path === path
const isActivePrefix = (prefix) => route.path.startsWith(prefix)
@@ -88,15 +91,20 @@ async function fetchPlaylists() {
} catch {}
}
async function openCreatePlaylist() {
const name = prompt('Playlist name:')
if (!name?.trim()) return
try {
const { data } = await api.post('/playlists', { name: name.trim() })
if (data.success) {
playlists.value.push(data.data)
function openCreatePlaylist() {
requireAuth({
redirectTo: '/login',
onAuthenticated: async () => {
const name = prompt('Playlist name:')
if (!name?.trim()) return
try {
const { data } = await api.post('/playlists', { name: name.trim() })
if (data.success) {
playlists.value.push(data.data)
}
} catch {}
}
} catch {}
})
}
onMounted(fetchPlaylists)
+7 -4
View File
@@ -1,16 +1,19 @@
import { useAuthStore } from '../stores/authStore.js'
import router from '../router/index.js'
let pendingAction = null
export function useAuthGate() {
const authStore = useAuthStore()
async function requireAuth({ message, onAuthenticated }) {
async function requireAuth({ message, onAuthenticated, redirectTo }) {
if (authStore.isLoggedIn) {
onAuthenticated()
onAuthenticated?.()
} else {
pendingAction = onAuthenticated
if (message) {
pendingAction = onAuthenticated || null
if (redirectTo) {
router.push(redirectTo)
} else if (message) {
const { useUiStore } = await import('../stores/uiStore.js')
const uiStore = useUiStore()
uiStore.showToast(message, 'info')
+8 -11
View File
@@ -10,14 +10,15 @@ import ProfilePage from '../views/ProfilePage.vue'
import AdminPage from '../views/AdminPage.vue'
const routes = [
{ path: '/', name: 'Login', component: LoginPage, meta: { guest: true } },
{ path: '/', redirect: '/home' },
{ path: '/login', name: 'Login', component: LoginPage, meta: { guest: true } },
{ path: '/register', name: 'Register', component: RegisterPage, meta: { guest: true } },
{ path: '/home', name: 'Home', component: LandingPage, meta: { auth: true } },
{ path: '/library', name: 'Library', component: LibraryPage, meta: { auth: true } },
{ path: '/playlist', name: 'Playlist', component: PlaylistPage, meta: { auth: true } },
{ path: '/playlist/:id', name: 'PlaylistDetail', component: PlaylistPage, meta: { auth: true } },
{ path: '/profile', name: 'Profile', component: ProfilePage, meta: { auth: true } },
{ path: '/admin/tracks', name: 'AdminTracks', component: AdminPage, meta: { auth: true, admin: true } },
{ path: '/home', name: 'Home', component: LandingPage },
{ path: '/library', name: 'Library', component: LibraryPage },
{ path: '/playlist', name: 'Playlist', component: PlaylistPage },
{ path: '/playlist/:id', name: 'PlaylistDetail', component: PlaylistPage },
{ path: '/profile', name: 'Profile', component: ProfilePage },
{ path: '/admin/tracks', name: 'AdminTracks', component: AdminPage, meta: { admin: true } },
]
const router = createRouter({
@@ -32,10 +33,6 @@ router.beforeEach((to, from, next) => {
return next('/home')
}
if (to.meta.auth && !authStore.isLoggedIn) {
return next('/')
}
if (to.meta.guest && authStore.isLoggedIn) {
return next('/home')
}
+7 -2
View File
@@ -62,10 +62,12 @@ import { useQueueStore } from '../stores/queueStore.js'
import { useAuthStore } from '../stores/authStore.js'
import api from '../lib/api.js'
import { formatUrl } from '../lib/utils.js'
import { useAuthGate } from '../composables/useAuthGate.js'
const playerStore = usePlayerStore()
const queueStore = useQueueStore()
const authStore = useAuthStore()
const { requireAuth } = useAuthGate()
const tracks = ref([])
const loading = ref(true)
@@ -93,8 +95,11 @@ function playFirstTrack() {
if (tracks.value.length) playTrack(tracks.value[0])
}
async function toggleLike(track) {
await authStore.toggleLike(track._id)
function toggleLike(track) {
requireAuth({
redirectTo: '/login',
onAuthenticated: () => authStore.toggleLike(track._id)
})
}
onMounted(async () => {
+25 -13
View File
@@ -3,6 +3,10 @@
<section class="mb-12">
<h2 class="text-3xl font-black text-black mb-6">Liked Tracks</h2>
<div v-if="loading" class="text-center py-12 text-gray-500">Loading...</div>
<div v-else-if="!authStore.isLoggedIn" class="text-center py-12">
<p class="text-gray-500 mb-4">Login to see your liked tracks</p>
<router-link to="/login" class="bg-noctune-yellow border-2 border-black px-6 py-3 font-bold inline-block hover:bg-yellow-400 transition-colors rounded-lg">Login</router-link>
</div>
<div v-else-if="likedTracks.length === 0" class="text-center py-12">
<p class="text-gray-500 mb-4">No liked tracks yet</p>
<router-link to="/home" class="bg-noctune-yellow border-2 border-black px-6 py-3 font-bold inline-block hover:bg-yellow-400 transition-colors rounded-lg">Discover Music</router-link>
@@ -75,10 +79,12 @@ import { useQueueStore } from '../stores/queueStore.js'
import { useAuthStore } from '../stores/authStore.js'
import api from '../lib/api.js'
import { formatUrl } from '../lib/utils.js'
import { useAuthGate } from '../composables/useAuthGate.js'
const playerStore = usePlayerStore()
const queueStore = useQueueStore()
const authStore = useAuthStore()
const { requireAuth } = useAuthGate()
const likedTracks = ref([])
const allTracks = ref([])
@@ -105,25 +111,31 @@ function playTrack(track, fromLiked = false, idx) {
playerStore.play()
}
async function toggleLike(track) {
function toggleLike(track) {
const wasLiked = isLiked(track)
await authStore.toggleLike(track._id)
if (wasLiked) {
likedTracks.value = likedTracks.value.filter((t) => t._id !== track._id)
}
requireAuth({
redirectTo: '/login',
onAuthenticated: async () => {
await authStore.toggleLike(track._id)
if (wasLiked) {
likedTracks.value = likedTracks.value.filter((t) => t._id !== track._id)
}
}
})
}
onMounted(async () => {
try {
const { data: liked } = await api.get('/tracks/liked')
if (liked.success) {
likedTracks.value = liked.data || []
if (authStore.isLoggedIn) {
try {
const { data: liked } = await api.get('/tracks/liked')
if (liked.success) {
likedTracks.value = liked.data || []
}
} catch {
// ignore
}
} catch {
// ignore
} finally {
loading.value = false
}
loading.value = false
try {
const { data: all } = await api.get('/tracks')
+6 -1
View File
@@ -77,6 +77,7 @@ import { useRouter } from 'vue-router'
import { useAuthStore } from '../stores/authStore.js'
import api from '../lib/api.js'
import { formatUrl } from '../lib/utils.js'
import { useAuthGate } from '../composables/useAuthGate.js'
const router = useRouter()
const authStore = useAuthStore()
@@ -138,10 +139,14 @@ async function handleUpdate() {
async function handleLogout() {
await authStore.logout()
router.push('/')
router.push('/login')
}
onMounted(async () => {
if (!authStore.isLoggedIn) {
router.push('/login')
return
}
try {
const { data } = await api.get('/tracks/liked')
if (data.success) {
+1 -1
View File
@@ -47,7 +47,7 @@
</button>
<p class="text-center mt-6 text-gray-600">
Already have an account?
<router-link to="/" class="text-noctune-orange font-bold hover:underline">Login</router-link>
<router-link to="/login" class="text-noctune-orange font-bold hover:underline">Login</router-link>
</p>
</div>
</div>