From 20db3638a1d15a908473e81bc7af191cf96f82cc Mon Sep 17 00:00:00 2001 From: Dmitry Date: Thu, 11 Dec 2025 22:57:55 +0300 Subject: [PATCH] stuff --- mnemo_cards_admin/src/api/auth.ts | 21 ++++++- mnemo_cards_admin/src/pages/LoginPage.tsx | 71 ++++++++++++++++++++--- 2 files changed, 82 insertions(+), 10 deletions(-) diff --git a/mnemo_cards_admin/src/api/auth.ts b/mnemo_cards_admin/src/api/auth.ts index 87b06f7..be39eac 100644 --- a/mnemo_cards_admin/src/api/auth.ts +++ b/mnemo_cards_admin/src/api/auth.ts @@ -10,8 +10,25 @@ export const authApi = { // Get code status getCodeStatus: async (code: string): Promise => { - const response = await adminApiClient.get(`/api/v2/admin/auth/code-status/${code}`) - return response.data + try { + const response = await adminApiClient.get(`/api/v2/admin/auth/code-status/${code}`) + return response.data + } catch (error: any) { + // If 404, return a proper error response + if (error.response?.status === 404) { + return { + success: false, + code: code, + status: 'not_found', + remainingSeconds: 0, + isClaimed: false, + isUsed: false, + error: 'NotFound', + message: 'Code not found', + } + } + throw error + } }, // Verify authentication code and login diff --git a/mnemo_cards_admin/src/pages/LoginPage.tsx b/mnemo_cards_admin/src/pages/LoginPage.tsx index 90440de..9b96253 100644 --- a/mnemo_cards_admin/src/pages/LoginPage.tsx +++ b/mnemo_cards_admin/src/pages/LoginPage.tsx @@ -23,6 +23,7 @@ export default function LoginPage() { const [code, setCode] = useState('') const [codeStatus, setCodeStatus] = useState(null) const [countdown, setCountdown] = useState(0) + const [isVerifying, setIsVerifying] = useState(false) const statusPollIntervalRef = useRef(null) const countdownIntervalRef = useRef(null) @@ -66,32 +67,58 @@ export default function LoginPage() { const verifyCodeMutation = useMutation({ mutationFn: (code: string) => authApi.verifyCode(code), onSuccess: (data) => { + console.log('Verify code response:', data) + // Check if response has success field and it's false if (data.success === false) { - toast.error(data.message || 'Verification failed') + const errorMsg = data.message || 'Verification failed' + console.error('Verification failed:', errorMsg) + toast.error(errorMsg) + setIsVerifying(false) + // Don't restart polling if verification failed - user needs to generate new code return } // Validate response structure if (!data.token || !data.user) { + console.error('Invalid response structure:', data) toast.error('Invalid response from server') + setIsVerifying(false) + // Don't restart polling - this is a server error return } // Stop polling stopStatusPolling() stopCountdown() + setIsVerifying(false) + console.log('Login successful, setting token and user') login(data.token, data.user) toast.success('Welcome back!') navigate('/') }, onError: (error: unknown) => { + console.error('Verify code error:', error) + setIsVerifying(false) + const errorResponse = error as { response?: { data?: { message?: string }; status?: number } } const errorMessage = - (error as { response?: { data?: { message?: string } } })?.response?.data?.message || + errorResponse?.response?.data?.message || (error as { message?: string })?.message || 'Invalid code' - toast.error(errorMessage) + + // If 403, it means code was claimed but user is not admin + if (errorResponse?.response?.status === 403) { + toast.error('Access denied: You are not an admin. Code was claimed but verification failed.') + stopStatusPolling() + stopCountdown() + } else { + toast.error(errorMessage) + // Restart polling in case of other errors + if (code) { + startStatusPolling(code) + } + } }, }) @@ -117,27 +144,45 @@ export default function LoginPage() { const checkCodeStatus = async (codeToCheck: string) => { try { const status = await authApi.getCodeStatus(codeToCheck) + + // Check if response is successful + if (!status.success) { + console.error('Code status check failed:', status.message || status.error) + if (status.error === 'NotFound') { + stopStatusPolling() + stopCountdown() + toast.error('Code not found. Please generate a new one.') + } + return + } + setCodeStatus(status) - if (status.status === 'claimed' && !status.isUsed) { + console.log('Code status:', status.status, 'isClaimed:', status.isClaimed, 'isUsed:', status.isUsed) + + if (status.status === 'claimed' && !status.isUsed && !isVerifying) { // Code is claimed, automatically verify and login + console.log('Code claimed, attempting login...') + setIsVerifying(true) stopStatusPolling() verifyCodeMutation.mutate(codeToCheck) - } else if (status.status === 'expired' || status.remainingSeconds <= 0) { + } else if (status.status === 'expired' || (status.remainingSeconds !== undefined && status.remainingSeconds <= 0)) { stopStatusPolling() stopCountdown() toast.error('Code expired. Please generate a new one.') } else if (status.isUsed) { stopStatusPolling() stopCountdown() + toast.info('Code already used') } else { // Update countdown - if (status.remainingSeconds > 0) { + if (status.remainingSeconds !== undefined && status.remainingSeconds > 0) { setCountdown(status.remainingSeconds) } } } catch (error) { console.error('Failed to check code status:', error) + // Don't stop polling on network errors, just log } } @@ -195,6 +240,7 @@ export default function LoginPage() { const handleBack = () => { stopStatusPolling() stopCountdown() + setIsVerifying(false) setCode('') setCodeStatus(null) setCountdown(0) @@ -283,11 +329,11 @@ export default function LoginPage() {
Status: - {getStatusLabel(codeStatus.status)} + {isVerifying ? 'Verifying and logging in...' : getStatusLabel(codeStatus.status)}
{isCodeActive && ( @@ -298,6 +344,15 @@ export default function LoginPage() { )} + {/* Debug info */} + {process.env.NODE_ENV === 'development' && ( +
+
Status: {codeStatus.status}
+
Claimed: {codeStatus.isClaimed ? 'Yes' : 'No'}
+
Used: {codeStatus.isUsed ? 'Yes' : 'No'}
+
Verifying: {isVerifying ? 'Yes' : 'No'}
+
+ )} )}