Skip to content

Commit 21d17cf

Browse files
authored
Merge pull request #68 from Parvm1102/main
bug: search repo card fix acc to bet 50 for #104 commit
2 parents 107ce5b + 5e93d61 commit 21d17cf

File tree

8 files changed

+269
-43
lines changed

8 files changed

+269
-43
lines changed

backend/api/v1/routes/hub.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@ def get_hub_projects(user: User = Depends(require_auth)) -> List[Project]:
2121
hub_service = HubService(user)
2222
return hub_service.get_projects()
2323

24+
@router.get("/search", response_model=List[Project])
25+
def get_hub_projects(user: User = Depends(require_auth)) -> List[Project]:
26+
"""Get all projects for the user."""
27+
hub_service = HubService(user)
28+
return hub_service.get_projects()
29+
2430
@router.get("/insights", response_model=List[Insight])
2531
def get_hub_insights(user: User = Depends(require_auth)) -> List[Insight]:
2632
"""Get insights for the user."""

backend/app.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ async def lifespan(app: FastAPI):
192192
app.include_router(github_router, prefix="/api/v1/github", tags=["github"])
193193
app.include_router(analytics_router, prefix="/api/v1/analytics", tags=["analytics"])
194194
app.include_router(projects_router, prefix="/api/v1/projects", tags=["projects"])
195+
app.include_router(projects_router, prefix="/api/v1/search", tags=["search"])
195196
app.include_router(webhooks_router, prefix="/api/v1/webhooks", tags=["webhooks"])
196197
app.include_router(aggregated_router, prefix="/api/v1/aggregated", tags=["aggregated"])
197198

ui/app/contribution/page.tsx

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,16 @@ import AnimatedTransition from '@/components/AnimatedTransition';
88
import { useAuth } from '@/contexts/AuthContext';
99
import { toast } from 'sonner';
1010
import ErrorBoundary from '@/components/ErrorBoundary';
11+
import { WithAuthPersistence, useAuthDebug } from '@/utils/authPersistence';
1112
import ContributionRateLimitHandler from '@/components/ContributionRateLimitHandler';
1213

1314
export default function ContributionPage() {
1415
const [authProcessed, setAuthProcessed] = useState(false);
1516
const showContent = useAnimateIn(false, 300);
1617
const router = useRouter();
1718
const searchParams = useSearchParams();
18-
const { setUserFromCallback, isAuthenticated } = useAuth();
19+
const { setUserFromCallback, isAuthenticated, loading } = useAuth();
20+
const { logAuthState } = useAuthDebug();
1921

2022
// Handle authentication parameters from OAuth callback
2123
useEffect(() => {
@@ -72,19 +74,29 @@ export default function ContributionPage() {
7274
const authToken = searchParams.get('auth_token');
7375
const authUser = searchParams.get('auth_user');
7476

75-
// If no auth params and not authenticated, redirect to home
77+
logAuthState('ContributionPage:AuthCheck');
78+
79+
// Wait for auth loading to complete before making redirect decisions
80+
if (loading) {
81+
console.log('Auth still loading, waiting...');
82+
return;
83+
}
84+
85+
// If no auth params and not authenticated after loading, redirect to home
7686
if (!authToken && !authUser && !isAuthenticated) {
77-
console.log('Not authenticated, redirecting to landing page');
87+
console.log('Not authenticated after loading completed, redirecting to landing page');
88+
logAuthState('ContributionPage:BeforeRedirect');
7889
router.push('/');
7990
return;
8091
}
8192

8293
// If auth processing is complete and still not authenticated, redirect
8394
if (authProcessed && !isAuthenticated && !authToken) {
8495
console.log('Authentication processing complete but not authenticated, redirecting to landing page');
96+
logAuthState('ContributionPage:BeforeProcessedRedirect');
8597
router.push('/');
8698
}
87-
}, [isAuthenticated, searchParams, authProcessed, router]);
99+
}, [isAuthenticated, loading, searchParams, authProcessed, router, logAuthState]);
88100

89101
return (
90102
<ContributionRateLimitHandler>

ui/components/hub/projects/ProjectCard.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,12 @@ export const ProjectCard: React.FC<ProjectCardProps> = ({ repo }) => {
4040
<Button variant="outline" size="sm" onClick={() => window.open(repo.html_url, '_blank')} className="bg-black text-white hover:bg-gray-700 border-gray-700">
4141
<ExternalLink className="h-4 w-4" />
4242
</Button>
43-
<Button size="sm" onClick={handleOpenInBeetle} className="bg-orange-500 text-black hover:bg-orange-600">
43+
<Button
44+
size="sm"
45+
onClick={handleOpenInBeetle}
46+
className="bg-orange-500 text-black hover:bg-orange-600"
47+
data-testid="open-in-gitmesh"
48+
>
4449
Open in GitMesh
4550
</Button>
4651
</div>
Lines changed: 37 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,57 @@
1-
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
2-
import { Button } from "@/components/ui/button";
3-
import { GitFork, Star, Users, ExternalLink } from "lucide-react";
4-
import { useRouter } from "next/navigation";
1+
import { Card, CardContent, CardFooter, CardHeader, CardTitle } from '@/components/ui/card';
2+
import { Button } from '@/components/ui/button';
3+
import { Repository } from '@/lib/github-api';
4+
import { Star, GitFork, ExternalLink } from 'lucide-react';
5+
import { useAuthAwareNavigation, useAuthDebug } from '@/utils/authPersistence';
56

6-
export function RepositoryCard({ repo }: { repo: any }) {
7-
const router = useRouter();
7+
interface ProjectCardProps {
8+
repo: Repository;
9+
}
10+
11+
export const RepositoryCard: React.FC<ProjectCardProps> = ({ repo }) => {
12+
const router = useAuthAwareNavigation();
13+
const { logAuthState } = useAuthDebug();
814

915
const handleOpenInBeetle = () => {
16+
logAuthState('RepositoryCard:BeforeNavigation');
1017
const repoData = JSON.stringify(repo);
1118
const encodedRepo = encodeURIComponent(repoData);
1219
router.push(`/contribution?repo=${encodedRepo}`);
1320
};
1421

1522
return (
16-
<Card className="flex flex-col">
23+
<Card className="bg-black shadow-lg rounded-lg flex flex-col h-full hover:shadow-orange-500/20 transition-shadow duration-300">
1724
<CardHeader>
18-
<CardTitle>{repo.name}</CardTitle>
19-
<CardDescription>{repo.description}</CardDescription>
25+
<CardTitle className="text-xl font-bold text-orange-500">{repo.name}</CardTitle>
2026
</CardHeader>
2127
<CardContent className="flex-grow">
22-
<div className="flex items-center space-x-4 text-sm text-muted-foreground">
23-
<div className="flex items-center">
24-
<Star className="mr-1 h-3 w-3" />
25-
{repo.stargazers_count}
26-
</div>
28+
<p className="text-sm text-gray-400">{repo.description}</p>
29+
</CardContent>
30+
<CardFooter className="flex justify-between items-center mt-auto pt-4 border-t border-gray-800">
31+
<div className="flex items-center space-x-4 text-gray-400">
2732
<div className="flex items-center">
28-
<GitFork className="mr-1 h-3 w-3" />
29-
{repo.forks_count}
33+
<Star className="h-4 w-4 mr-1" />
34+
<span>{repo.stargazers_count}</span>
3035
</div>
3136
<div className="flex items-center">
32-
<Users className="mr-1 h-3 w-3" />
33-
{repo.watchers_count}
37+
<GitFork className="h-4 w-4 mr-1" />
38+
<span>{repo.forks_count}</span>
3439
</div>
3540
</div>
36-
</CardContent>
37-
<CardFooter className="flex justify-between items-center space-x-2">
38-
<Button
39-
variant="outline"
40-
size="sm"
41-
onClick={() => window.open(repo.html_url, '_blank')}
42-
className="flex items-center space-x-1"
43-
>
44-
<ExternalLink className="h-3 w-3" />
45-
<span>GitHub</span>
46-
</Button>
47-
<Button
48-
size="sm"
49-
onClick={handleOpenInBeetle}
50-
>
51-
Open in GitMesh
52-
</Button>
41+
<div className="flex items-center space-x-2">
42+
<Button variant="outline" size="sm" onClick={() => window.open(repo.html_url, '_blank')} className="bg-black text-white hover:bg-gray-700 border-gray-700">
43+
<ExternalLink className="h-4 w-4" />
44+
</Button>
45+
<Button
46+
size="sm"
47+
onClick={handleOpenInBeetle}
48+
className="bg-orange-500 text-black hover:bg-orange-600"
49+
data-testid="open-in-gitmesh"
50+
>
51+
Open in GitMesh
52+
</Button>
53+
</div>
5354
</CardFooter>
5455
</Card>
5556
);
56-
}
57+
};

ui/components/hub/search/SearchResults.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { OrganizationCard } from './OrganizationCard';
99

1010
interface SearchResultsProps {
1111
query: string;
12-
}
12+
}RepositoryCard
1313

1414
export function SearchResults({ query }: SearchResultsProps) {
1515
const { token } = useAuth();

ui/contexts/AuthContext.tsx

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,14 +121,29 @@ export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
121121
return false;
122122
}
123123

124+
// First check if token exists in localStorage - if so, assume authenticated during validation
125+
const storedToken = keyManager.getGitmeshToken();
126+
if (storedToken === tokenToUse) {
127+
// Set authenticated state immediately to prevent redirects during validation
128+
setIsAuthenticated(true);
129+
console.log('Token exists in storage, setting authenticated state immediately');
130+
}
131+
124132
console.log('Making validation request to:', `${API_BASE_URL}/auth/validate`);
133+
134+
// Add timeout to prevent hanging requests
135+
const controller = new AbortController();
136+
const timeoutId = setTimeout(() => controller.abort(), 10000); // 10 second timeout
137+
125138
const response = await fetch(`${API_BASE_URL}/auth/validate`, {
126139
headers: {
127140
'Authorization': `Bearer ${tokenToUse}`,
128141
'Content-Type': 'application/json'
129-
}
142+
},
143+
signal: controller.signal
130144
});
131145

146+
clearTimeout(timeoutId);
132147
console.log('Validation response status:', response.status);
133148
console.log('Validation response ok:', response.ok);
134149

@@ -155,6 +170,19 @@ export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
155170
}
156171
} catch (error) {
157172
console.error('Token validation error:', error);
173+
174+
// If it's an abort error (timeout), and we have a stored token,
175+
// don't immediately clear auth state - keep it for offline scenarios
176+
if (error instanceof Error && error.name === 'AbortError') {
177+
const storedToken = keyManager.getGitmeshToken();
178+
if (storedToken && storedToken === (authToken || token)) {
179+
console.log('Token validation timed out, but token exists - maintaining auth state');
180+
setIsAuthenticated(true);
181+
setLoading(false);
182+
return true;
183+
}
184+
}
185+
158186
setIsAuthenticated(false);
159187
setUser(null);
160188
setToken(null);

0 commit comments

Comments
 (0)