mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-06-02 03:55:55 +00:00
feat: enhance API key normalization and improve Space OAuth callback handling
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useState, useCallback, Suspense } from 'react';
|
||||
import { useEffect, useState, useCallback, Suspense, useRef } from 'react';
|
||||
import { useNavigate, useSearchParams } from 'react-router-dom';
|
||||
import { httpClient } from '@/app/infra/http/HttpClient';
|
||||
import { toast } from 'sonner';
|
||||
@@ -20,10 +20,39 @@ import { Button } from '@/components/ui/button';
|
||||
import { LoadingSpinner } from '@/components/ui/loading-spinner';
|
||||
import langbotIcon from '@/app/assets/langbot-logo.webp';
|
||||
|
||||
type SpaceOAuthLoginResult = {
|
||||
token: string;
|
||||
user: string;
|
||||
};
|
||||
|
||||
const pendingSpaceOAuthLogins = new Map<
|
||||
string,
|
||||
Promise<SpaceOAuthLoginResult>
|
||||
>();
|
||||
|
||||
function getOrCreateSpaceOAuthLoginPromise(
|
||||
authCode: string,
|
||||
): Promise<SpaceOAuthLoginResult> {
|
||||
const pendingRequest = pendingSpaceOAuthLogins.get(authCode);
|
||||
if (pendingRequest) {
|
||||
return pendingRequest;
|
||||
}
|
||||
|
||||
const requestPromise = httpClient
|
||||
.exchangeSpaceOAuthCode(authCode)
|
||||
.finally(() => {
|
||||
pendingSpaceOAuthLogins.delete(authCode);
|
||||
});
|
||||
|
||||
pendingSpaceOAuthLogins.set(authCode, requestPromise);
|
||||
return requestPromise;
|
||||
}
|
||||
|
||||
function SpaceOAuthCallbackContent() {
|
||||
const navigate = useNavigate();
|
||||
const [searchParams] = useSearchParams();
|
||||
const { t } = useTranslation();
|
||||
const isMountedRef = useRef(true);
|
||||
|
||||
const [status, setStatus] = useState<
|
||||
'loading' | 'confirm' | 'success' | 'error'
|
||||
@@ -37,7 +66,11 @@ function SpaceOAuthCallbackContent() {
|
||||
const handleOAuthCallback = useCallback(
|
||||
async (authCode: string) => {
|
||||
try {
|
||||
const response = await httpClient.exchangeSpaceOAuthCode(authCode);
|
||||
const response = await getOrCreateSpaceOAuthLoginPromise(authCode);
|
||||
if (!isMountedRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
localStorage.setItem('token', response.token);
|
||||
if (response.user) {
|
||||
localStorage.setItem('userEmail', response.user);
|
||||
@@ -52,6 +85,10 @@ function SpaceOAuthCallbackContent() {
|
||||
navigate(redirectTo);
|
||||
}, 1000);
|
||||
} catch (err) {
|
||||
if (!isMountedRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
setStatus('error');
|
||||
const errorObj = err as { msg?: string };
|
||||
const errMsg = (errorObj?.msg || '').toLowerCase();
|
||||
@@ -72,6 +109,10 @@ function SpaceOAuthCallbackContent() {
|
||||
setIsProcessing(true);
|
||||
try {
|
||||
const response = await httpClient.bindSpaceAccount(authCode, state);
|
||||
if (!isMountedRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
localStorage.setItem('token', response.token);
|
||||
if (response.user) {
|
||||
localStorage.setItem('userEmail', response.user);
|
||||
@@ -82,6 +123,10 @@ function SpaceOAuthCallbackContent() {
|
||||
navigate('/home');
|
||||
}, 1000);
|
||||
} catch (err) {
|
||||
if (!isMountedRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
setStatus('error');
|
||||
const errorObj = err as { msg?: string };
|
||||
const errMsg = (errorObj?.msg || '').toLowerCase();
|
||||
@@ -91,13 +136,17 @@ function SpaceOAuthCallbackContent() {
|
||||
setErrorMessage(t('account.bindSpaceFailed'));
|
||||
}
|
||||
} finally {
|
||||
setIsProcessing(false);
|
||||
if (isMountedRef.current) {
|
||||
setIsProcessing(false);
|
||||
}
|
||||
}
|
||||
},
|
||||
[navigate, t],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
isMountedRef.current = true;
|
||||
|
||||
const authCode = searchParams.get('code');
|
||||
const error = searchParams.get('error');
|
||||
const errorDescription = searchParams.get('error_description');
|
||||
@@ -135,6 +184,9 @@ function SpaceOAuthCallbackContent() {
|
||||
// Normal login/register mode
|
||||
handleOAuthCallback(authCode);
|
||||
}
|
||||
return () => {
|
||||
isMountedRef.current = false;
|
||||
};
|
||||
}, [searchParams, handleOAuthCallback, t]);
|
||||
|
||||
const handleConfirmBind = () => {
|
||||
|
||||
Reference in New Issue
Block a user