refactor(ui): address PR review feedback for device code auth

- Extract INITIAL_STATE constant to reduce code repetition (DRY)
- Remove duplicate success toast for device code flow
  (useDeviceCode already shows toast via deviceCodeCompleted WebSocket event)
- Replace 7 inline state reset objects with INITIAL_STATE reference
This commit is contained in:
kaitranntt
2026-02-05 15:37:18 -05:00
parent 13f6c3f14b
commit a08d0cfece
+20 -61
View File
@@ -32,16 +32,19 @@ const POLL_INTERVAL = 3000;
/** Maximum polling duration (5 minutes) */ /** Maximum polling duration (5 minutes) */
const MAX_POLL_DURATION = 5 * 60 * 1000; const MAX_POLL_DURATION = 5 * 60 * 1000;
/** Initial state for auth flow - extracted for DRY */
const INITIAL_STATE: AuthFlowState = {
provider: null,
isAuthenticating: false,
error: null,
authUrl: null,
oauthState: null,
isSubmittingCallback: false,
isDeviceCodeFlow: false,
};
export function useCliproxyAuthFlow() { export function useCliproxyAuthFlow() {
const [state, setState] = useState<AuthFlowState>({ const [state, setState] = useState<AuthFlowState>(INITIAL_STATE);
provider: null,
isAuthenticating: false,
error: null,
authUrl: null,
oauthState: null,
isSubmittingCallback: false,
isDeviceCodeFlow: false,
});
const abortControllerRef = useRef<AbortController | null>(null); const abortControllerRef = useRef<AbortController | null>(null);
const pollIntervalRef = useRef<ReturnType<typeof setInterval> | null>(null); const pollIntervalRef = useRef<ReturnType<typeof setInterval> | null>(null);
@@ -89,15 +92,7 @@ export function useCliproxyAuthFlow() {
queryClient.invalidateQueries({ queryKey: ['cliproxy-auth'] }); queryClient.invalidateQueries({ queryKey: ['cliproxy-auth'] });
queryClient.invalidateQueries({ queryKey: ['account-quota'] }); queryClient.invalidateQueries({ queryKey: ['account-quota'] });
toast.success(`${provider} authentication successful`); toast.success(`${provider} authentication successful`);
setState({ setState(INITIAL_STATE);
provider: null,
isAuthenticating: false,
error: null,
authUrl: null,
oauthState: null,
isSubmittingCallback: false,
isDeviceCodeFlow: false,
});
} else if (data.status === 'error') { } else if (data.status === 'error') {
stopPolling(); stopPolling();
const errorMsg = data.error || 'Authentication failed'; const errorMsg = data.error || 'Authentication failed';
@@ -120,13 +115,8 @@ export function useCliproxyAuthFlow() {
async (provider: string, options?: StartAuthOptions) => { async (provider: string, options?: StartAuthOptions) => {
if (!isValidProvider(provider)) { if (!isValidProvider(provider)) {
setState({ setState({
provider: null, ...INITIAL_STATE,
isAuthenticating: false,
error: `Unknown provider: ${provider}`, error: `Unknown provider: ${provider}`,
authUrl: null,
oauthState: null,
isSubmittingCallback: false,
isDeviceCodeFlow: false,
}); });
return; return;
} }
@@ -167,16 +157,9 @@ export function useCliproxyAuthFlow() {
if (response.ok && data.success) { if (response.ok && data.success) {
queryClient.invalidateQueries({ queryKey: ['cliproxy-auth'] }); queryClient.invalidateQueries({ queryKey: ['cliproxy-auth'] });
queryClient.invalidateQueries({ queryKey: ['account-quota'] }); queryClient.invalidateQueries({ queryKey: ['account-quota'] });
toast.success(`${provider} authentication successful`); // Note: No toast here - DeviceCodeDialog's useDeviceCode hook handles success toast
setState({ // via deviceCodeCompleted WebSocket event to avoid duplicate toasts
provider: null, setState(INITIAL_STATE);
isAuthenticating: false,
error: null,
authUrl: null,
oauthState: null,
isSubmittingCallback: false,
isDeviceCodeFlow: false,
});
} else { } else {
const errorMsg = data.error || 'Authentication failed'; const errorMsg = data.error || 'Authentication failed';
toast.error(errorMsg); toast.error(errorMsg);
@@ -238,15 +221,7 @@ export function useCliproxyAuthFlow() {
} }
} catch (error) { } catch (error) {
if (error instanceof Error && error.name === 'AbortError') { if (error instanceof Error && error.name === 'AbortError') {
setState({ setState(INITIAL_STATE);
provider: null,
isAuthenticating: false,
error: null,
authUrl: null,
oauthState: null,
isSubmittingCallback: false,
isDeviceCodeFlow: false,
});
return; return;
} }
const message = error instanceof Error ? error.message : 'Authentication failed'; const message = error instanceof Error ? error.message : 'Authentication failed';
@@ -265,15 +240,7 @@ export function useCliproxyAuthFlow() {
const currentProvider = state.provider; const currentProvider = state.provider;
abortControllerRef.current?.abort(); abortControllerRef.current?.abort();
stopPolling(); stopPolling();
setState({ setState(INITIAL_STATE);
provider: null,
isAuthenticating: false,
error: null,
authUrl: null,
oauthState: null,
isSubmittingCallback: false,
isDeviceCodeFlow: false,
});
// Also cancel on backend // Also cancel on backend
if (currentProvider) { if (currentProvider) {
api.cliproxy.auth.cancel(currentProvider).catch(() => { api.cliproxy.auth.cancel(currentProvider).catch(() => {
@@ -302,15 +269,7 @@ export function useCliproxyAuthFlow() {
queryClient.invalidateQueries({ queryKey: ['cliproxy-auth'] }); queryClient.invalidateQueries({ queryKey: ['cliproxy-auth'] });
queryClient.invalidateQueries({ queryKey: ['account-quota'] }); queryClient.invalidateQueries({ queryKey: ['account-quota'] });
toast.success(`${state.provider} authentication successful`); toast.success(`${state.provider} authentication successful`);
setState({ setState(INITIAL_STATE);
provider: null,
isAuthenticating: false,
error: null,
authUrl: null,
oauthState: null,
isSubmittingCallback: false,
isDeviceCodeFlow: false,
});
} else { } else {
throw new Error(data.error || 'Callback submission failed'); throw new Error(data.error || 'Callback submission failed');
} }