profit-planet-frontend/src/app/hooks/useUserStatus.ts
seaznCode 40d626437c + SUSPENDED AUTH CHECK
feat: add suspended account handling with dedicated page and redirect logic
2026-01-30 15:34:43 +01:00

179 lines
5.0 KiB
TypeScript

import { useState, useEffect, useCallback } from 'react'
import { useRouter } from 'next/navigation'
import useAuthStore from '../store/authStore'
export interface UserStatus {
email_verified: boolean
documents_uploaded: boolean
profile_completed: boolean
contract_signed: boolean
is_admin_verified?: boolean
email_verified_at?: string
documents_uploaded_at?: string
profile_completed_at?: string
contract_signed_at?: string
}
export interface UserStatusResponse {
success: boolean
status: UserStatus
message?: string
}
export const useUserStatus = () => {
const router = useRouter()
const [userStatus, setUserStatus] = useState<UserStatus | null>(null)
const [loading, setLoading] = useState(true)
const [error, setError] = useState<string | null>(null)
const [isClient, setIsClient] = useState(false)
const { accessToken, user } = useAuthStore()
// Debug logging
useEffect(() => {
console.log('🔍 useUserStatus debug:', {
isClient,
hasToken: !!accessToken,
tokenPrefix: accessToken ? accessToken.substring(0, 20) + '...' : null,
hasUser: !!user,
userEmail: user?.email || user?.companyName
})
}, [isClient, accessToken, user])
// Handle SSR hydration
useEffect(() => {
setIsClient(true)
}, [])
const fetchUserStatus = useCallback(async () => {
if (!isClient) {
setLoading(false)
return
}
// If no user, clear status and don't show error
if (!user) {
setUserStatus(null)
setLoading(false)
setError(null)
return
}
try {
setLoading(true)
setError(null)
// Get current token - it might be null initially
let currentToken = accessToken
// If no token, try to refresh first
if (!currentToken) {
console.log('No access token, attempting refresh...')
const { refreshAuthToken } = useAuthStore.getState()
const refreshed = await refreshAuthToken()
if (refreshed) {
currentToken = useAuthStore.getState().accessToken
}
}
// If still no token after refresh attempt, this is an auth error
if (!currentToken) {
throw new Error('Not authenticated - please log in again')
}
const response = await fetch(`${process.env.NEXT_PUBLIC_API_BASE_URL}/api/user/status`, {
method: 'GET',
headers: {
'Authorization': `Bearer ${currentToken}`,
'Content-Type': 'application/json'
}
})
if (response.status === 403) {
useAuthStore.getState().clearAuth()
setUserStatus(null)
setError(null)
router.push('/suspended')
return
}
// If 401, try token refresh once
if (response.status === 401) {
console.log('Got 401, attempting token refresh...')
const { refreshAuthToken } = useAuthStore.getState()
const refreshed = await refreshAuthToken()
if (refreshed) {
const newToken = useAuthStore.getState().accessToken
if (newToken) {
// Retry with new token
const retryResponse = await fetch(`${process.env.NEXT_PUBLIC_API_BASE_URL}/api/user/status`, {
method: 'GET',
headers: {
'Authorization': `Bearer ${newToken}`,
'Content-Type': 'application/json'
}
})
if (retryResponse.status === 403) {
useAuthStore.getState().clearAuth()
setUserStatus(null)
setError(null)
router.push('/suspended')
return
}
if (!retryResponse.ok) {
throw new Error(`Failed to fetch user status: ${retryResponse.status}`)
}
const retryData: UserStatusResponse = await retryResponse.json()
if (retryData.success) {
setUserStatus(retryData.status)
return
} else {
throw new Error(retryData.message || 'Failed to fetch user status')
}
}
}
throw new Error('Authentication failed - please log in again')
}
if (!response.ok) {
throw new Error(`Failed to fetch user status: ${response.status}`)
}
const data: UserStatusResponse = await response.json()
if (data.success) {
setUserStatus(data.status)
} else {
throw new Error(data.message || 'Failed to fetch user status')
}
} catch (err) {
console.error('Error fetching user status:', err)
setError(err instanceof Error ? err.message : 'Unknown error occurred')
} finally {
setLoading(false)
}
}, [isClient, accessToken, user, router])
// Fetch status on mount and when auth changes
useEffect(() => {
if (isClient) {
fetchUserStatus()
}
}, [isClient, fetchUserStatus])
// Refresh function for manual updates
const refreshStatus = useCallback(() => {
return fetchUserStatus()
}, [fetchUserStatus])
return {
userStatus,
loading,
error,
refreshStatus
}
}