Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 59 additions & 2 deletions src/hooks/useGitHubAuth.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,82 @@
import { useState, useMemo } from 'react';
import { useState, useMemo, useEffect } from 'react';
import { Octokit } from '@octokit/core';

export const useGitHubAuth = () => {
const [username, setUsername] = useState('');
const [token, setToken] = useState('');
const [error, setError] = useState('');

const octokit = useMemo(() => {
if (!username) return null;
if(token){
return new Octokit({ auth: token });
return new Octokit({ auth: token });
}
return new Octokit();
}, [username, token]);
Comment thread
coderabbitai[bot] marked this conversation as resolved.

// Clear error when username or token changes, before validation runs
useEffect(() => {
setError('');
}, [username, token]);

// Validate token format and authentication on mount or change
useEffect(() => {
if (!token || !username) {
return;
}

const controller = new AbortController();

const validateAuth = async () => {
if (!octokit) return;

try {
// Attempt a simple API call to verify the token is valid
await octokit.request('GET /user', { request: { signal: controller.signal } });
// Only update state if request was not aborted
if (!controller.signal.aborted) {
setError('');
}
} catch (err: unknown) {
// Ignore if request was aborted
if (controller.signal.aborted) {
return;
}

const error = err as {
status?: number;
message?: string;
};

if (error.status === 401) {
setError('Invalid personal access token. Please check and try again.');
} else if (error.status === 403) {
setError('Token has insufficient permissions or has expired.');
} else if (error.message?.includes('Bad credentials')) {
setError('Bad credentials. Please verify your personal access token.');
} else {
setError(`Authentication error: ${error.message || 'Unknown error'}`);
}
}
};

// Validate on token change (but with a small delay to avoid excessive API calls during typing)
const timeoutId = setTimeout(validateAuth, 500);
return () => {
clearTimeout(timeoutId);
controller.abort();
};
}, [token, username, octokit]);

const getOctokit = () => octokit;

return {
username,
setUsername,
token,
setToken,
error,
setError,
getOctokit,
};
};
10 changes: 8 additions & 2 deletions src/pages/Tracker/Tracker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -324,9 +324,15 @@ const Home: React.FC = () => {
</FormControl>
</Box>

{(authError || dataError) && (
{authError && (
<Alert severity="error" sx={{ mb: 3 }}>
{authError || dataError}
<strong>Authentication Error:</strong> {authError}
</Alert>
)}

{dataError && !authError && (
<Alert severity="error" sx={{ mb: 3 }}>
<strong>Data Fetch Error:</strong> {dataError}
</Alert>
)}

Expand Down