From 1ee2130d88c0a4532e77945f92a490df2ba4a332 Mon Sep 17 00:00:00 2001 From: lethdat Date: Thu, 5 Feb 2026 21:48:22 +0700 Subject: [PATCH] feat: Enhance video management with detailed view and improved routing --- src/components/DashboardNav.vue | 4 +- src/mocks/videos.ts | 9 ++ src/routes/index.ts | 67 +++++---- .../video/{EditVideo.vue => DetailVideo.vue} | 8 +- src/routes/video/Videos.vue | 139 ++++++++---------- src/routes/video/components/VideoFilters.vue | 2 +- src/routes/video/components/VideoTable.vue | 3 +- 7 files changed, 112 insertions(+), 120 deletions(-) rename src/routes/video/{EditVideo.vue => DetailVideo.vue} (95%) diff --git a/src/components/DashboardNav.vue b/src/components/DashboardNav.vue index c124172..6f4bb4b 100644 --- a/src/components/DashboardNav.vue +++ b/src/components/DashboardNav.vue @@ -43,10 +43,10 @@ const links = [ v-bind="i.type === 'a' ? { to: i.href } : {}" v-tooltip="i.label" @click="i.action && i.action($event)" :class="cn( i.className, - ($route.path === i.href || i.isActive?.value) && 'bg-primary/15' + ($route.path === i.href || $route.path.startsWith(i.href+'/') || i.isActive?.value) && 'bg-primary/15' )"> + :filled="$route.path === i.href || $route.path.startsWith(i.href+'/') || i.isActive?.value" /> diff --git a/src/mocks/videos.ts b/src/mocks/videos.ts index fbc0e62..06405c7 100644 --- a/src/mocks/videos.ts +++ b/src/mocks/videos.ts @@ -319,3 +319,12 @@ export const fetchMockVideos = async ({ page, limit, searchQuery, status }: Fetc total }; }; +export const fetchMockVideoById = async (id: string) => { + // Simulate API delay + await new Promise(resolve => setTimeout(resolve, 500)); + const video = mockVideos.find(v => v.id === id); + if (!video) { + throw new Error('Video not found'); + } + return video; +}; \ No newline at end of file diff --git a/src/routes/index.ts b/src/routes/index.ts index 4bba3fd..2b6c725 100644 --- a/src/routes/index.ts +++ b/src/routes/index.ts @@ -102,29 +102,34 @@ const routes: RouteData[] = [ }, { path: "video", - name: "video", - component: () => import("./video/Videos.vue"), - meta: { - head: { - title: "Videos - Holistream", - meta: [ - { - name: "description", - content: "Manage your video content.", + children: [ + { + path: "", + name: "video", + component: () => import("./video/Videos.vue"), + meta: { + head: { + title: "Videos - Holistream", + meta: [ + { + name: "description", + content: "Manage your video content.", + }, + ], }, - ], + }, }, - }, - }, - { - path: "video/:id/edit", - name: "video-edit", - component: () => import("./video/EditVideo.vue"), - meta: { - head: { - title: "Edit Video - Holistream", + { + path: ":id", + name: "video-detail", + component: () => import("./video/DetailVideo.vue"), + meta: { + head: { + title: "Edit Video - Holistream", + }, + }, }, - }, + ], }, { path: "payments-and-plans", @@ -174,17 +179,17 @@ const routes: RouteData[] = [ ]; const createAppRouter = () => { const router = createRouter({ - history: import.meta.env.SSR - ? createMemoryHistory() // server - : createWebHistory(), // client - routes, - scrollBehavior(to, from, savedPosition) { - if (savedPosition) { - return savedPosition - } - return { top: 0 } - } - }); + history: import.meta.env.SSR + ? createMemoryHistory() // server + : createWebHistory(), // client + routes, + scrollBehavior(to, from, savedPosition) { + if (savedPosition) { + return savedPosition; + } + return { top: 0 }; + }, + }); router.beforeEach((to, from, next) => { const auth = useAuthStore(); diff --git a/src/routes/video/EditVideo.vue b/src/routes/video/DetailVideo.vue similarity index 95% rename from src/routes/video/EditVideo.vue rename to src/routes/video/DetailVideo.vue index 353d20d..6c8b8ab 100644 --- a/src/routes/video/EditVideo.vue +++ b/src/routes/video/DetailVideo.vue @@ -8,6 +8,7 @@ import InputText from 'primevue/inputtext'; import Textarea from 'primevue/textarea'; import Button from 'primevue/button'; import Skeleton from 'primevue/skeleton'; +import { fetchMockVideoById } from '@/mocks/videos'; const route = useRoute(); const router = useRouter(); @@ -26,9 +27,9 @@ const form = ref({ const fetchVideo = async () => { loading.value = true; try { - const response = await client.videos.videosDetail(videoId); + const videoData = await fetchMockVideoById(videoId); // response is HttpResponse, response.data is the body, response.data.data is the ModelVideo - const videoData = response.data.data; + // const videoData = response.data.data; if (videoData) { video.value = videoData; form.value.title = videoData.title || ''; @@ -76,7 +77,7 @@ onMounted(() => { { label: 'Videos', to: '/video' }, { label: 'Edit' } ]" /> - +
@@ -122,5 +123,6 @@ onMounted(() => {
+ diff --git a/src/routes/video/Videos.vue b/src/routes/video/Videos.vue index 8020a9b..3347c89 100644 --- a/src/routes/video/Videos.vue +++ b/src/routes/video/Videos.vue @@ -22,7 +22,7 @@ const iconHoist = createStaticVNode(` { { label: 'Dashboard', to: '/' }, { label: 'Videos' } ]" :actions="[ - { - label: 'Upload Video', - icon: iconHoist, - variant: 'primary', - onClick: () => router.push('/upload') - } - ]" /> + { + label: 'Upload Video', + icon: iconHoist, + variant: 'primary', + onClick: () => router.push('/upload') + } + ]" /> - + - -
- -
-
- -
- - -
- - + +
+ +
+
+ +
+ + +
+ + +
+
+
+
+ +
+
+
+ +
+ + +
+ + +
- -
-
-
- -
- - -
- - - -
-
+ + +
+ +

{{ error }}

+
-
- -
- -

{{ error }}

- -
+ + + + - - - - -
- - - - - - - - - - - - - - - - - - - - - - -
- - -
- -
+ + +
diff --git a/src/routes/video/components/VideoFilters.vue b/src/routes/video/components/VideoFilters.vue index 95d1fbe..7c1e1b3 100644 --- a/src/routes/video/components/VideoFilters.vue +++ b/src/routes/video/components/VideoFilters.vue @@ -1,5 +1,4 @@