130 lines
4.1 KiB
TypeScript
130 lines
4.1 KiB
TypeScript
import type {
|
|
ChangePasswordRequest,
|
|
CurrentUserResponse, EmailRequest, NotificationListResponse,
|
|
OkResponse,
|
|
OtpRequestResponse, PasswordLoginRequest, RegisterCitizenRequest,
|
|
RegisterCitizenResponse, RewardsResponse,
|
|
TokenResponse, VerifyOtpRequest, UpdateProfileRequest
|
|
} from "~/types/api";
|
|
|
|
export const useAuth = () => {
|
|
const route = useRoute()
|
|
const nuxtApp = useNuxtApp()
|
|
|
|
const token = useCookie<string | null>('auth_token', {
|
|
maxAge: 60 * 60 * 12,
|
|
sameSite: 'lax',
|
|
path: '/',
|
|
watch: true
|
|
})
|
|
|
|
const tokenState = useState<string | null>('auth_token_state', () => token.value ?? null)
|
|
|
|
type UserContext = CurrentUserResponse['user']
|
|
const user = useState<UserContext | null>('auth_user', () => null)
|
|
const isSyncingUser = useState<boolean>('auth_syncing', () => false)
|
|
const isAuthenticated = computed(() => !!(tokenState.value || token.value))
|
|
const isAuthStatusError = (error: any) => {
|
|
const status = error?.statusCode || error?.status || error?.response?.status
|
|
return status === 401 || status === 403
|
|
}
|
|
|
|
watch(() => token.value, (newVal) => {
|
|
tokenState.value = newVal || null
|
|
})
|
|
|
|
const syncUser = async (redirectOnSuccess = false) => {
|
|
const tokenVal = tokenState.value || token.value
|
|
if (!tokenVal || isSyncingUser.value) return
|
|
|
|
isSyncingUser.value = true
|
|
try {
|
|
const res = await fetchCurrentUser()
|
|
if (res.ok) {
|
|
user.value = res.user
|
|
|
|
if (res.user.must_change_password && route.path !== '/auth/change-password') {
|
|
await nuxtApp.runWithContext(() => navigateTo('/auth/change-password'))
|
|
} else if (redirectOnSuccess && route.path.startsWith('/auth')) {
|
|
await nuxtApp.runWithContext(() => navigateTo('/dashboard'))
|
|
}
|
|
}
|
|
} catch (error) {
|
|
if (isAuthStatusError(error)) {
|
|
console.error('[Auth] Sync failed with authentication error, keeping session state:', error)
|
|
return
|
|
}
|
|
|
|
console.error('[Auth] Sync failed, logging out:', error)
|
|
logout()
|
|
} finally {
|
|
isSyncingUser.value = false
|
|
}
|
|
}
|
|
|
|
const handleLoginSuccess = async (jwtToken: string) => {
|
|
token.value = jwtToken
|
|
tokenState.value = jwtToken
|
|
await syncUser(true)
|
|
}
|
|
|
|
const logout = () => {
|
|
token.value = null
|
|
tokenState.value = null
|
|
user.value = null
|
|
nuxtApp.runWithContext(() => navigateTo('/auth/login'))
|
|
}
|
|
|
|
const register = (body: RegisterCitizenRequest) =>
|
|
useApiFetch<RegisterCitizenResponse>('/api/v1/auth/register', { method: 'POST', body })
|
|
|
|
const requestOtp = (body: EmailRequest) =>
|
|
useApiFetch<OtpRequestResponse>('/api/v1/auth/otp/request', { method: 'POST', body })
|
|
|
|
const verifyOtp = (body: VerifyOtpRequest) =>
|
|
useApiFetch<TokenResponse>('/api/v1/auth/otp/verify', { method: 'POST', body })
|
|
|
|
const loginWithPassword = (body: PasswordLoginRequest) =>
|
|
useApiFetch<TokenResponse>('/api/v1/auth/login/password', { method: 'POST', body })
|
|
|
|
const changePassword = (body: ChangePasswordRequest) =>
|
|
useApiFetch<OkResponse>('/api/v1/auth/change-password', { method: 'POST', body })
|
|
|
|
const updateProfile = (body: UpdateProfileRequest) =>
|
|
useApiFetch<CurrentUserResponse>('/api/v1/me', { method: 'PATCH', body })
|
|
|
|
const fetchCurrentUser = () =>
|
|
useApiFetch<CurrentUserResponse>('/api/v1/me', { method: 'GET' })
|
|
|
|
const fetchRewards = (query?: { page?: number; per_page?: number }) =>
|
|
useApiFetch<RewardsResponse>('/api/v1/me/rewards', { method: 'GET', query })
|
|
|
|
const fetchNotifications = (query?: { page?: number; per_page?: number }) =>
|
|
useApiFetch<NotificationListResponse>('/api/v1/notifications', { method: 'GET', query })
|
|
|
|
const markNotificationRead = (id: number) =>
|
|
useApiFetch<OkResponse>(`/api/v1/notifications/${id}/read`, { method: 'PATCH' })
|
|
|
|
return {
|
|
user,
|
|
token,
|
|
tokenState,
|
|
isSyncingUser,
|
|
isAuthenticated,
|
|
handleLoginSuccess,
|
|
syncUser,
|
|
logout,
|
|
|
|
register,
|
|
requestOtp,
|
|
verifyOtp,
|
|
loginWithPassword,
|
|
changePassword,
|
|
updateProfile,
|
|
fetchCurrentUser,
|
|
fetchRewards,
|
|
fetchNotifications,
|
|
markNotificationRead,
|
|
}
|
|
}
|