Skip to content

Commit 7508baa

Browse files
author
Lasim
committed
feat: add dashboard view with user data fetching and error handling
1 parent bcb334f commit 7508baa

File tree

2 files changed

+137
-0
lines changed

2 files changed

+137
-0
lines changed

services/frontend/src/router/index.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,12 @@ const routes = [
3030
component: () => import('../views/Logout.vue'),
3131
meta: { requiresSetup: true }, // Or false, depending on whether logout should be accessible if setup isn't complete
3232
},
33+
{
34+
path: '/dashboard',
35+
name: 'Dashboard',
36+
component: () => import('../views/Dashboard.vue'),
37+
meta: { requiresSetup: true },
38+
},
3339
{
3440
path: '/plugin-demo',
3541
name: 'PluginDemo',
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
<script setup lang="ts">
2+
import { ref, onMounted } from 'vue'
3+
import { useRouter } from 'vue-router'
4+
import { Button } from '@/components/ui/button'
5+
import { getEnv } from '@/utils/env'
6+
7+
const router = useRouter()
8+
const loading = ref(true)
9+
const error = ref('')
10+
const userEmail = ref('')
11+
const userName = ref('')
12+
13+
interface UserData {
14+
id: string
15+
email: string
16+
username: string
17+
firstName?: string
18+
lastName?: string
19+
}
20+
21+
const fetchUserData = async () => {
22+
loading.value = true
23+
error.value = ''
24+
25+
try {
26+
const apiUrl = getEnv('VITE_DEPLOYSTACK_APP_URL')
27+
28+
if (!apiUrl) {
29+
throw new Error('API URL not configured')
30+
}
31+
32+
const response = await fetch(`${apiUrl}/api/users/me`, {
33+
method: 'GET',
34+
headers: {
35+
'Content-Type': 'application/json',
36+
},
37+
credentials: 'include', // Include cookies for session management
38+
})
39+
40+
if (!response.ok) {
41+
if (response.status === 401) {
42+
// User not authenticated, redirect to login
43+
router.push('/login')
44+
return
45+
}
46+
throw new Error(`Failed to fetch user data: ${response.status}`)
47+
}
48+
49+
const data = await response.json()
50+
51+
if (data.success && data.data) {
52+
const userData: UserData = data.data
53+
userEmail.value = userData.email
54+
userName.value = userData.username
55+
} else {
56+
throw new Error('Invalid response format')
57+
}
58+
59+
} catch (e) {
60+
console.error('Error fetching user data:', e)
61+
if (e instanceof Error) {
62+
error.value = e.message
63+
} else {
64+
error.value = 'Failed to load user data'
65+
}
66+
} finally {
67+
loading.value = false
68+
}
69+
}
70+
71+
const logout = () => {
72+
router.push('/logout')
73+
}
74+
75+
onMounted(() => {
76+
fetchUserData()
77+
})
78+
</script>
79+
80+
<template>
81+
<div class="min-h-screen flex items-center justify-center bg-background">
82+
<div class="text-center space-y-6 p-8">
83+
<!-- Loading state -->
84+
<div v-if="loading" class="space-y-4">
85+
<div class="animate-spin h-8 w-8 border-4 border-primary border-t-transparent rounded-full mx-auto"></div>
86+
<p class="text-muted-foreground">Loading dashboard...</p>
87+
</div>
88+
89+
<!-- Error state -->
90+
<div v-else-if="error" class="space-y-4">
91+
<h1 class="text-2xl font-bold text-destructive">Error</h1>
92+
<p class="text-muted-foreground">{{ error }}</p>
93+
<Button @click="fetchUserData" variant="outline">
94+
Try Again
95+
</Button>
96+
</div>
97+
98+
<!-- Success state -->
99+
<div v-else class="space-y-6">
100+
<div class="space-y-2">
101+
<h1 class="text-3xl font-bold">Dashboard</h1>
102+
<p class="text-muted-foreground">Welcome to your dashboard</p>
103+
</div>
104+
105+
<div class="space-y-2">
106+
<p class="text-sm text-muted-foreground">Logged in as:</p>
107+
<p class="text-xl font-medium">{{ userEmail }}</p>
108+
</div>
109+
110+
<Button @click="logout" variant="outline" class="mt-6">
111+
Logout
112+
</Button>
113+
</div>
114+
</div>
115+
</div>
116+
</template>
117+
118+
<style scoped>
119+
.bg-background {
120+
background-color: hsl(var(--background));
121+
}
122+
.text-muted-foreground {
123+
color: hsl(var(--muted-foreground));
124+
}
125+
.text-destructive {
126+
color: hsl(var(--destructive));
127+
}
128+
.border-primary {
129+
border-color: hsl(var(--primary));
130+
}
131+
</style>

0 commit comments

Comments
 (0)