initial commit - LeDiscord plateforme des copains

This commit is contained in:
EvanChal
2025-08-21 00:28:21 +02:00
commit b7a84a53aa
93 changed files with 16247 additions and 0 deletions

197
frontend/src/stores/auth.js Normal file
View File

@@ -0,0 +1,197 @@
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import axios 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)
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
localStorage.removeItem('token')
delete axios.defaults.headers.common['Authorization']
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 response = await axios.post('/api/users/me/avatar', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
user.value = response.data
toast.success('Avatar mis à jour')
return { success: true, data: response.data }
} catch (error) {
console.error('Error uploading avatar:', error)
toast.error('Erreur lors de l\'upload de l\'avatar')
return { success: false, error: error.response?.data?.detail || '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')
notifications.value = response.data
unreadCount.value = notifications.value.filter(n => !n.is_read).length
} catch (error) {
console.error('Error fetching notifications:', error)
}
}
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
}
})