226 lines
7.0 KiB
JavaScript
226 lines
7.0 KiB
JavaScript
import { defineStore } from 'pinia'
|
|
import { ref, computed } from 'vue'
|
|
import axios from '@/utils/axios'
|
|
import { uploadFormData } from '@/utils/axios'
|
|
import router from '@/router'
|
|
import { useToast } from 'vue-toastification'
|
|
|
|
export const useAuthStore = defineStore('auth', () => {
|
|
const user = ref(null)
|
|
const token = ref(localStorage.getItem('token'))
|
|
const toast = useToast()
|
|
|
|
const isAuthenticated = computed(() => !!token.value && !!user.value)
|
|
const isAdmin = computed(() => user.value?.is_admin || false)
|
|
|
|
if (token.value) {
|
|
axios.defaults.headers.common['Authorization'] = `Bearer ${token.value}`
|
|
}
|
|
|
|
async function login(email, password) {
|
|
try {
|
|
// Pour OAuth2PasswordRequestForm, on doit envoyer en format x-www-form-urlencoded
|
|
const formData = new URLSearchParams()
|
|
formData.append('username', email) // OAuth2PasswordRequestForm expects username field
|
|
formData.append('password', password)
|
|
|
|
const response = await axios.post('/api/auth/login', formData.toString(), {
|
|
headers: {
|
|
'Content-Type': 'application/x-www-form-urlencoded'
|
|
}
|
|
})
|
|
const { access_token, user: userData } = response.data
|
|
|
|
token.value = access_token
|
|
user.value = userData
|
|
localStorage.setItem('token', access_token)
|
|
axios.defaults.headers.common['Authorization'] = `Bearer ${access_token}`
|
|
|
|
toast.success(`Bienvenue ${userData.full_name} !`)
|
|
router.push('/')
|
|
|
|
return { success: true }
|
|
} catch (error) {
|
|
toast.error(error.response?.data?.detail || 'Erreur de connexion')
|
|
return { success: false, error: error.response?.data?.detail }
|
|
}
|
|
}
|
|
|
|
async function register(userData) {
|
|
try {
|
|
const response = await axios.post('/api/auth/register', userData)
|
|
const { access_token, user: newUser } = response.data
|
|
|
|
token.value = access_token
|
|
user.value = newUser
|
|
localStorage.setItem('token', access_token)
|
|
axios.defaults.headers.common['Authorization'] = `Bearer ${access_token}`
|
|
|
|
toast.success('Inscription réussie !')
|
|
router.push('/')
|
|
|
|
return { success: true }
|
|
} catch (error) {
|
|
toast.error(error.response?.data?.detail || 'Erreur lors de l\'inscription')
|
|
return { success: false, error: error.response?.data?.detail }
|
|
}
|
|
}
|
|
|
|
async function logout() {
|
|
token.value = null
|
|
user.value = null
|
|
notifications.value = []
|
|
unreadCount.value = 0
|
|
localStorage.removeItem('token')
|
|
delete axios.defaults.headers.common['Authorization']
|
|
|
|
// Arrêter le polling des notifications
|
|
const notificationService = (await import('@/services/notificationService')).default
|
|
notificationService.stopPolling()
|
|
|
|
router.push('/login')
|
|
toast.info('Déconnexion réussie')
|
|
}
|
|
|
|
async function fetchCurrentUser() {
|
|
if (!token.value) return
|
|
|
|
try {
|
|
const response = await axios.get('/api/users/me')
|
|
user.value = response.data
|
|
} catch (error) {
|
|
console.error('Error fetching user:', error)
|
|
if (error.response?.status === 401) {
|
|
logout()
|
|
}
|
|
}
|
|
}
|
|
|
|
async function updateProfile(profileData) {
|
|
try {
|
|
const response = await axios.put('/api/users/me', profileData)
|
|
user.value = response.data
|
|
toast.success('Profil mis à jour')
|
|
return { success: true, data: response.data }
|
|
} catch (error) {
|
|
toast.error('Erreur lors de la mise à jour du profil')
|
|
return { success: false, error: error.response?.data?.detail }
|
|
}
|
|
}
|
|
|
|
async function uploadAvatar(file) {
|
|
try {
|
|
const formData = new FormData()
|
|
formData.append('file', file)
|
|
|
|
const data = await uploadFormData('/api/users/me/avatar', formData)
|
|
user.value = data
|
|
toast.success('Avatar mis à jour')
|
|
return { success: true, data }
|
|
} catch (error) {
|
|
toast.error('Erreur lors de l\'upload de l\'avatar')
|
|
return { success: false, error: error.message || 'Erreur inconnue' }
|
|
}
|
|
}
|
|
|
|
// Notifications
|
|
const notifications = ref([])
|
|
const unreadCount = ref(0)
|
|
|
|
async function fetchNotifications() {
|
|
if (!token.value) return
|
|
|
|
try {
|
|
const response = await axios.get('/api/notifications?limit=50')
|
|
const newNotifications = response.data
|
|
|
|
// Détecter les nouvelles notifications non lues
|
|
const previousIds = new Set(notifications.value.map(n => n.id))
|
|
const previousUnreadIds = new Set(
|
|
notifications.value.filter(n => !n.is_read).map(n => n.id)
|
|
)
|
|
|
|
// Nouvelles notifications = celles qui n'existaient pas avant
|
|
const hasNewNotifications = newNotifications.some(n => !previousIds.has(n.id))
|
|
|
|
// Nouvelles notifications non lues = nouvelles ET non lues
|
|
const newUnreadNotifications = newNotifications.filter(
|
|
n => !previousIds.has(n.id) && !n.is_read
|
|
)
|
|
|
|
notifications.value = newNotifications
|
|
const newUnreadCount = notifications.value.filter(n => !n.is_read).length
|
|
const previousUnreadCount = unreadCount.value
|
|
unreadCount.value = newUnreadCount
|
|
|
|
// Retourner si de nouvelles notifications non lues ont été détectées
|
|
return {
|
|
hasNewNotifications: newUnreadNotifications.length > 0,
|
|
newCount: newUnreadCount,
|
|
previousCount: previousUnreadCount
|
|
}
|
|
} catch (error) {
|
|
console.error('Error fetching notifications:', error)
|
|
return { hasNewNotifications: false, newCount: unreadCount.value, previousCount: unreadCount.value }
|
|
}
|
|
}
|
|
|
|
async function markNotificationRead(notificationId) {
|
|
try {
|
|
await axios.put(`/api/notifications/${notificationId}/read`)
|
|
const notification = notifications.value.find(n => n.id === notificationId)
|
|
if (notification && !notification.is_read) {
|
|
notification.is_read = true
|
|
notification.read_at = new Date().toISOString()
|
|
unreadCount.value = Math.max(0, unreadCount.value - 1)
|
|
}
|
|
} catch (error) {
|
|
console.error('Error marking notification read:', error)
|
|
}
|
|
}
|
|
|
|
async function markAllNotificationsRead() {
|
|
try {
|
|
await axios.put('/api/notifications/read-all')
|
|
notifications.value.forEach(n => {
|
|
n.is_read = true
|
|
n.read_at = new Date().toISOString()
|
|
})
|
|
unreadCount.value = 0
|
|
} catch (error) {
|
|
console.error('Error marking all notifications read:', error)
|
|
}
|
|
}
|
|
|
|
async function fetchUnreadCount() {
|
|
if (!token.value) return
|
|
|
|
try {
|
|
const response = await axios.get('/api/notifications/unread-count')
|
|
unreadCount.value = response.data.unread_count
|
|
} catch (error) {
|
|
console.error('Error fetching unread count:', error)
|
|
}
|
|
}
|
|
|
|
return {
|
|
user,
|
|
token,
|
|
isAuthenticated,
|
|
isAdmin,
|
|
login,
|
|
register,
|
|
logout,
|
|
fetchCurrentUser,
|
|
updateProfile,
|
|
uploadAvatar,
|
|
// Notifications
|
|
notifications,
|
|
unreadCount,
|
|
fetchNotifications,
|
|
markNotificationRead,
|
|
markAllNotificationsRead,
|
|
fetchUnreadCount
|
|
}
|
|
})
|