- Wire garageStore.addVehicle to POST /assets/vehicles (real API call) - Wire authStore.fetchUserProfile to GET /users/me (real API call) - Remove mock data fallback for vehicle creation - Add userProfile state to auth store These changes connect the frontend to verified existing FastAPI endpoints as identified in the backend endpoint audit (#132).
274 lines
8.8 KiB
JavaScript
274 lines
8.8 KiB
JavaScript
import { defineStore } from 'pinia'
|
|
import { ref, computed } from 'vue'
|
|
import { useRouter } from 'vue-router'
|
|
|
|
export const useAuthStore = defineStore('auth', () => {
|
|
const router = useRouter()
|
|
|
|
// State
|
|
const token = ref(localStorage.getItem('token') || '')
|
|
const isAdmin = ref(localStorage.getItem('is_admin') === 'true')
|
|
const userEmail = ref(localStorage.getItem('user_email') || '')
|
|
const userRole = ref(localStorage.getItem('user_role') || '')
|
|
const userProfile = ref(null) // Full user profile from /users/me
|
|
|
|
// Getters
|
|
const isLoggedIn = computed(() => !!token.value)
|
|
const isTester = computed(() => userEmail.value === 'tester_pro@profibot.hu' || userRole.value === 'tester')
|
|
const displayName = computed(() => {
|
|
if (isTester.value) return 'TESTER PRO'
|
|
if (isAdmin.value) return 'ADMIN'
|
|
return 'USER'
|
|
})
|
|
|
|
// Actions
|
|
const login = async (email, password) => {
|
|
console.log('AuthStore: Real API login attempt for', email)
|
|
|
|
try {
|
|
// Prepare URL-encoded form data for OAuth2 password grant
|
|
// FastAPI's OAuth2PasswordRequestForm expects application/x-www-form-urlencoded
|
|
const params = new URLSearchParams()
|
|
params.append('username', email)
|
|
params.append('password', password)
|
|
|
|
// Call real backend API
|
|
const response = await fetch('http://localhost:8000/api/v1/auth/login', {
|
|
method: 'POST',
|
|
body: params,
|
|
headers: {
|
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
'Accept': 'application/json'
|
|
}
|
|
})
|
|
|
|
if (!response.ok) {
|
|
const errorText = await response.text()
|
|
console.error('AuthStore: Login API error', response.status, errorText)
|
|
throw new Error(`Login failed: ${response.status} ${response.statusText}`)
|
|
}
|
|
|
|
const data = await response.json()
|
|
console.log('AuthStore: Login API response', data)
|
|
|
|
// Extract token and user info
|
|
const accessToken = data.access_token
|
|
const refreshToken = data.refresh_token
|
|
const tokenType = data.token_type
|
|
const isActive = data.is_active
|
|
|
|
// We need to decode the JWT token to get user role and info
|
|
// For now, we'll make a separate API call to get user info
|
|
// Or we can parse the JWT token (simple base64 decode)
|
|
let userRole = 'user'
|
|
let isAdmin = false
|
|
|
|
try {
|
|
// Decode JWT token to get payload
|
|
const tokenParts = accessToken.split('.')
|
|
if (tokenParts.length === 3) {
|
|
const payload = JSON.parse(atob(tokenParts[1]))
|
|
userRole = payload.role || 'user'
|
|
isAdmin = userRole === 'admin' || userRole === 'superadmin'
|
|
console.log('AuthStore: Decoded JWT payload', payload)
|
|
}
|
|
} catch (decodeError) {
|
|
console.warn('AuthStore: Could not decode JWT token', decodeError)
|
|
// Fallback: Make API call to get user info
|
|
// For now, we'll use a default role
|
|
}
|
|
|
|
// Save to localStorage
|
|
localStorage.setItem('token', accessToken)
|
|
localStorage.setItem('refresh_token', refreshToken)
|
|
localStorage.setItem('is_admin', isAdmin.toString())
|
|
localStorage.setItem('user_email', email)
|
|
localStorage.setItem('user_role', userRole)
|
|
|
|
// Update store state
|
|
token.value = accessToken
|
|
isAdmin.value = isAdmin
|
|
userEmail.value = email
|
|
userRole.value = userRole
|
|
|
|
console.log('AuthStore: State updated, redirecting to /profile-select')
|
|
|
|
// Redirect to profile-select (as per router logic)
|
|
try {
|
|
await router.push('/profile-select')
|
|
console.log('AuthStore: Redirect successful')
|
|
} catch (error) {
|
|
console.error('AuthStore: Router redirect failed:', error)
|
|
throw error
|
|
}
|
|
|
|
return { success: true, token: accessToken, isAdmin, role: userRole }
|
|
|
|
} catch (error) {
|
|
console.error('AuthStore: Login failed', error)
|
|
|
|
// Fallback to mock login for development if API is not available
|
|
if (error.message.includes('Failed to fetch') || error.message.includes('NetworkError')) {
|
|
console.warn('AuthStore: API unavailable, falling back to mock login for development')
|
|
|
|
// Determine user role based on email
|
|
let mockIsAdmin = false
|
|
let mockRole = 'user'
|
|
|
|
if (email === 'superadmin@profibot.hu') {
|
|
mockIsAdmin = true
|
|
mockRole = 'admin'
|
|
} else if (email === 'tester_pro@profibot.hu') {
|
|
mockIsAdmin = true // Tester has admin privileges for testing
|
|
mockRole = 'tester'
|
|
}
|
|
|
|
// Set mock token
|
|
const mockToken = 'mock_jwt_token_' + Date.now()
|
|
|
|
// Save to localStorage
|
|
localStorage.setItem('token', mockToken)
|
|
localStorage.setItem('is_admin', mockIsAdmin.toString())
|
|
localStorage.setItem('user_email', email)
|
|
localStorage.setItem('user_role', mockRole)
|
|
|
|
// Update store state
|
|
token.value = mockToken
|
|
isAdmin.value = mockIsAdmin
|
|
userEmail.value = email
|
|
userRole.value = mockRole
|
|
|
|
// Redirect
|
|
await router.push('/profile-select')
|
|
|
|
return { success: true, token: mockToken, isAdmin: mockIsAdmin, role: mockRole }
|
|
}
|
|
|
|
throw error
|
|
}
|
|
}
|
|
|
|
const logout = () => {
|
|
// Clear localStorage
|
|
localStorage.removeItem('token')
|
|
localStorage.removeItem('is_admin')
|
|
localStorage.removeItem('user_email')
|
|
localStorage.removeItem('user_role')
|
|
localStorage.removeItem('ui_mode') // Also clear UI mode on logout
|
|
|
|
// Reset store state
|
|
token.value = ''
|
|
isAdmin.value = false
|
|
userEmail.value = ''
|
|
userRole.value = ''
|
|
userProfile.value = null
|
|
|
|
// Redirect to login
|
|
router.push('/login')
|
|
}
|
|
|
|
const fetchUserProfile = async () => {
|
|
if (!token.value) {
|
|
throw new Error('Not authenticated')
|
|
}
|
|
|
|
try {
|
|
const response = await fetch('http://localhost:8000/api/v1/users/me', {
|
|
method: 'GET',
|
|
headers: {
|
|
'Authorization': `Bearer ${token.value}`,
|
|
'Accept': 'application/json'
|
|
}
|
|
})
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Failed to fetch user profile: ${response.status} ${response.statusText}`)
|
|
}
|
|
|
|
const data = await response.json()
|
|
console.log('AuthStore: Fetched user profile', data)
|
|
|
|
// Update user profile state
|
|
userProfile.value = data
|
|
|
|
// Also update email and role from profile if available
|
|
if (data.email && !userEmail.value) {
|
|
userEmail.value = data.email
|
|
localStorage.setItem('user_email', data.email)
|
|
}
|
|
|
|
if (data.role && !userRole.value) {
|
|
userRole.value = data.role
|
|
localStorage.setItem('user_role', data.role)
|
|
isAdmin.value = data.role === 'admin' || data.role === 'superadmin'
|
|
localStorage.setItem('is_admin', isAdmin.value.toString())
|
|
}
|
|
|
|
return data
|
|
} catch (err) {
|
|
console.error('AuthStore: Error fetching user profile', err)
|
|
throw err
|
|
}
|
|
}
|
|
|
|
const checkAuth = () => {
|
|
// Sync with localStorage on page load
|
|
const storedToken = localStorage.getItem('token') || ''
|
|
const storedEmail = localStorage.getItem('user_email') || ''
|
|
const storedRole = localStorage.getItem('user_role') || ''
|
|
|
|
// Try to decode JWT token to get role if not stored
|
|
let decodedRole = storedRole
|
|
let decodedIsAdmin = storedRole === 'admin' || storedRole === 'superadmin'
|
|
|
|
if (storedToken && !storedRole) {
|
|
try {
|
|
// Decode JWT token to get payload
|
|
const tokenParts = storedToken.split('.')
|
|
if (tokenParts.length === 3) {
|
|
const payload = JSON.parse(atob(tokenParts[1]))
|
|
decodedRole = payload.role || 'user'
|
|
decodedIsAdmin = decodedRole === 'admin' || decodedRole === 'superadmin'
|
|
console.log('AuthStore: Decoded JWT on checkAuth', payload)
|
|
|
|
// Update localStorage with decoded role
|
|
localStorage.setItem('user_role', decodedRole)
|
|
localStorage.setItem('is_admin', decodedIsAdmin.toString())
|
|
}
|
|
} catch (decodeError) {
|
|
console.warn('AuthStore: Could not decode JWT token on checkAuth', decodeError)
|
|
}
|
|
} else if (storedToken && storedRole) {
|
|
// Use stored role
|
|
decodedIsAdmin = storedRole === 'admin' || storedRole === 'superadmin'
|
|
}
|
|
|
|
token.value = storedToken
|
|
isAdmin.value = decodedIsAdmin
|
|
userEmail.value = storedEmail
|
|
userRole.value = decodedRole || 'user'
|
|
}
|
|
|
|
// Initialize on store creation
|
|
checkAuth()
|
|
|
|
return {
|
|
// State
|
|
token,
|
|
isAdmin,
|
|
userEmail,
|
|
userRole,
|
|
userProfile,
|
|
|
|
// Getters
|
|
isLoggedIn,
|
|
isTester,
|
|
displayName,
|
|
|
|
// Actions
|
|
login,
|
|
logout,
|
|
checkAuth,
|
|
fetchUserProfile
|
|
}
|
|
}) |