140 lines
4.2 KiB
TypeScript
140 lines
4.2 KiB
TypeScript
import type {
|
|
CieSessionResponse,
|
|
CieStartResponse,
|
|
CurrentUserResponse,
|
|
EmailRequest,
|
|
NotificationListResponse,
|
|
OkResponse,
|
|
OtpRequestResponse,
|
|
RegisterCitizenRequest,
|
|
RegisterCitizenResponse,
|
|
RewardsResponse,
|
|
TokenResponse,
|
|
UpdateProfileRequest,
|
|
VerifyOtpRequest
|
|
} from "~/types/api";
|
|
|
|
export const useAuth = () => {
|
|
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 (options: { redirectOnSuccess?: boolean; currentPath?: string } = {}) => {
|
|
const { redirectOnSuccess = false, currentPath } = options
|
|
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
|
|
const path = currentPath ?? useNuxtApp().$router.currentRoute.value.path
|
|
|
|
if (redirectOnSuccess && 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({ redirectOnSuccess: true })
|
|
window.location.reload();
|
|
}
|
|
|
|
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 startCieLogin = (frontendRedirectUri: string) =>
|
|
useApiFetch<CieStartResponse>('/api/v1/auth/cie/start', {
|
|
method: 'POST',
|
|
body: { frontend_redirect_uri: frontendRedirectUri }
|
|
})
|
|
|
|
const fetchCieSession = (id: string) =>
|
|
useApiFetch<CieSessionResponse>(`/api/v1/auth/cie/session/${id}`, { method: 'GET' })
|
|
|
|
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,
|
|
startCieLogin,
|
|
fetchCieSession,
|
|
updateProfile,
|
|
fetchCurrentUser,
|
|
fetchRewards,
|
|
fetchNotifications,
|
|
markNotificationRead,
|
|
}
|
|
}
|