refactor: move provider auth status management to custom hook

This commit is contained in:
Haileyesus
2026-04-11 13:39:25 +03:00
parent d529cfe8fa
commit c981212257
13 changed files with 191 additions and 239 deletions

View File

@@ -1,14 +1,13 @@
import { Check, ChevronLeft, ChevronRight, Loader2 } from 'lucide-react';
import { useCallback, useEffect, useRef, useState } from 'react';
import { authenticatedFetch } from '../../../utils/api';
import { useProviderAuthStatus } from '../../provider-auth/hooks/useProviderAuthStatus';
import type { CliProvider } from '../../provider-auth/types';
import ProviderLoginModal from '../../provider-auth/view/ProviderLoginModal';
import AgentConnectionsStep from './subcomponents/AgentConnectionsStep';
import GitConfigurationStep from './subcomponents/GitConfigurationStep';
import OnboardingStepProgress from './subcomponents/OnboardingStepProgress';
import type { CliProvider, ProviderStatusMap } from './types';
import {
cliProviders,
createInitialProviderStatuses,
gitEmailPattern,
readErrorMessageFromResponse,
} from './utils';
@@ -24,59 +23,14 @@ export default function Onboarding({ onComplete }: OnboardingProps) {
const [isSubmitting, setIsSubmitting] = useState(false);
const [errorMessage, setErrorMessage] = useState('');
const [activeLoginProvider, setActiveLoginProvider] = useState<CliProvider | null>(null);
const [providerStatuses, setProviderStatuses] = useState<ProviderStatusMap>(createInitialProviderStatuses);
const {
providerAuthStatus,
checkProviderAuthStatus,
refreshProviderAuthStatuses,
} = useProviderAuthStatus();
const previousActiveLoginProviderRef = useRef<CliProvider | null | undefined>(undefined);
const checkProviderAuthStatus = useCallback(async (provider: CliProvider) => {
try {
const response = await authenticatedFetch(`/api/cli/${provider}/status`);
if (!response.ok) {
setProviderStatuses((previous) => ({
...previous,
[provider]: {
authenticated: false,
email: null,
loading: false,
error: 'Failed to check authentication status',
},
}));
return;
}
const payload = (await response.json()) as {
authenticated?: boolean;
email?: string | null;
error?: string | null;
};
setProviderStatuses((previous) => ({
...previous,
[provider]: {
authenticated: Boolean(payload.authenticated),
email: payload.email ?? null,
loading: false,
error: payload.error ?? null,
},
}));
} catch (caughtError) {
console.error(`Error checking ${provider} auth status:`, caughtError);
setProviderStatuses((previous) => ({
...previous,
[provider]: {
authenticated: false,
email: null,
loading: false,
error: caughtError instanceof Error ? caughtError.message : 'Unknown error',
},
}));
}
}, []);
const refreshAllProviderStatuses = useCallback(async () => {
await Promise.all(cliProviders.map((provider) => checkProviderAuthStatus(provider)));
}, [checkProviderAuthStatus]);
const loadGitConfig = useCallback(async () => {
try {
const response = await authenticatedFetch('/api/user/git-config');
@@ -98,21 +52,22 @@ export default function Onboarding({ onComplete }: OnboardingProps) {
useEffect(() => {
void loadGitConfig();
void refreshAllProviderStatuses();
}, [loadGitConfig, refreshAllProviderStatuses]);
void refreshProviderAuthStatuses();
}, [loadGitConfig, refreshProviderAuthStatuses]);
useEffect(() => {
const previousProvider = previousActiveLoginProviderRef.current;
previousActiveLoginProviderRef.current = activeLoginProvider;
const isInitialMount = previousProvider === undefined;
const didCloseModal = previousProvider !== null && activeLoginProvider === null;
const didCloseModal = previousProvider !== undefined
&& previousProvider !== null
&& activeLoginProvider === null;
// Refresh statuses once on mount and again after the login modal is closed.
if (isInitialMount || didCloseModal) {
void refreshAllProviderStatuses();
// Refresh statuses after the login modal is closed.
if (didCloseModal) {
void refreshProviderAuthStatuses();
}
}, [activeLoginProvider, refreshAllProviderStatuses]);
}, [activeLoginProvider, refreshProviderAuthStatuses]);
const handleProviderLoginOpen = (provider: CliProvider) => {
setActiveLoginProvider(provider);
@@ -208,7 +163,7 @@ export default function Onboarding({ onComplete }: OnboardingProps) {
/>
) : (
<AgentConnectionsStep
providerStatuses={providerStatuses}
providerStatuses={providerAuthStatus}
onOpenProviderLogin={handleProviderLoginOpen}
/>
)}

View File

@@ -1,6 +1,6 @@
import { Check } from 'lucide-react';
import SessionProviderLogo from '../../../llm-logo-provider/SessionProviderLogo';
import type { CliProvider, ProviderAuthStatus } from '../types';
import type { CliProvider, ProviderAuthStatus } from '../../../provider-auth/types';
type AgentConnectionCardProps = {
provider: CliProvider;

View File

@@ -1,8 +1,8 @@
import type { CliProvider, ProviderStatusMap } from '../types';
import type { CliProvider, ProviderAuthStatusMap } from '../../../provider-auth/types';
import AgentConnectionCard from './AgentConnectionCard';
type AgentConnectionsStepProps = {
providerStatuses: ProviderStatusMap;
providerStatuses: ProviderAuthStatusMap;
onOpenProviderLogin: (provider: CliProvider) => void;
};

View File

@@ -1,12 +0,0 @@
import type { CliProvider } from '../../provider-auth/types';
export type { CliProvider };
export type ProviderAuthStatus = {
authenticated: boolean;
email: string | null;
loading: boolean;
error: string | null;
};
export type ProviderStatusMap = Record<CliProvider, ProviderAuthStatus>;

View File

@@ -1,16 +1,5 @@
import type { CliProvider, ProviderStatusMap } from './types';
export const cliProviders: CliProvider[] = ['claude', 'cursor', 'codex', 'gemini'];
export const gitEmailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
export const createInitialProviderStatuses = (): ProviderStatusMap => ({
claude: { authenticated: false, email: null, loading: true, error: null },
cursor: { authenticated: false, email: null, loading: true, error: null },
codex: { authenticated: false, email: null, loading: true, error: null },
gemini: { authenticated: false, email: null, loading: true, error: null },
});
export const readErrorMessageFromResponse = async (response: Response, fallback: string) => {
try {
const payload = (await response.json()) as { error?: string };