From 53b9eb317760385bd8e188faf6f480ab0cb0d16d Mon Sep 17 00:00:00 2001 From: Hrusikesh123 Date: Sun, 24 Aug 2025 15:12:15 +0530 Subject: [PATCH 1/2] Changes Updated --- frontend/app/skills/page.tsx | 4 +-- frontend/components/skills/skills-test.tsx | 26 ++++++++++--------- frontend/components/skills/welcome-screen.tsx | 8 +++--- package-lock.json | 6 +++++ 4 files changed, 26 insertions(+), 18 deletions(-) create mode 100644 package-lock.json diff --git a/frontend/app/skills/page.tsx b/frontend/app/skills/page.tsx index b889250..07b4487 100644 --- a/frontend/app/skills/page.tsx +++ b/frontend/app/skills/page.tsx @@ -136,7 +136,7 @@ export default function SkillsPage() { // Loading state - show while checking auth or loading user data if (loading || authLoading) { return ( -
+

Loading...

@@ -146,7 +146,7 @@ export default function SkillsPage() { } return ( -
+
{currentScreen === "welcome" && } {currentScreen === "test" && } diff --git a/frontend/components/skills/skills-test.tsx b/frontend/components/skills/skills-test.tsx index e8556a8..56d1f91 100644 --- a/frontend/components/skills/skills-test.tsx +++ b/frontend/components/skills/skills-test.tsx @@ -164,16 +164,16 @@ export default function SkillsTest({ onComplete }: SkillsTestProps) { const canProceed = selectedOptions[currentQuestionIndex] !== -1 return ( -
+
-
+
Question {currentQuestionIndex + 1} of {questions.length} {Math.round(progress)}% Complete
- -
+ +
@@ -186,7 +186,7 @@ export default function SkillsTest({ onComplete }: SkillsTestProps) { transition={{ duration: 0.3 }} className={`${isTransitioning ? "opacity-0" : "opacity-100"} transition-opacity duration-300`} > -

{currentQuestion.question}

+

{currentQuestion.question}

{currentQuestion.options.map((option, index) => ( @@ -194,22 +194,24 @@ export default function SkillsTest({ onComplete }: SkillsTestProps) { key={index} className={`p-4 rounded-lg border-2 cursor-pointer transition-all duration-200 ${ selectedOptions[currentQuestionIndex] === index - ? "border-purple-500 bg-purple-900/30" - : "border-gray-700 hover:border-purple-400 bg-gray-800/30" + ? "border-blue-500 dark:border-purple-500 bg-blue-50/50 dark:bg-purple-900/30" + : "border-gray-300 dark:border-gray-700 hover:border-blue-400 dark:hover:border-purple-400 bg-white/50 dark:bg-gray-800/30" }`} onClick={() => handleOptionSelect(index)} >
{selectedOptions[currentQuestionIndex] === index && (
)}
- {option.text} + {option.text}
))} @@ -220,7 +222,7 @@ export default function SkillsTest({ onComplete }: SkillsTestProps) { variant="outline" onClick={handleBack} disabled={isFirstQuestion} - className={`${isFirstQuestion ? "opacity-0" : "opacity-100"} border-gray-600 text-white hover:bg-purple-900/30 hover:text-purple-300`} + className={`${isFirstQuestion ? "opacity-0" : "opacity-100"} border-gray-300 dark:border-gray-600 text-gray-700 dark:text-white hover:bg-blue-50 dark:hover:bg-purple-900/30 hover:text-blue-700 dark:hover:text-purple-300`} > Back @@ -230,7 +232,7 @@ export default function SkillsTest({ onComplete }: SkillsTestProps) { + + +
+
+

Keywords

+
+ {allSkills.map(skill => ( +
+ handleSkillToggle(skill)} + /> + +
+ ))} +
+
+ +
+ + +
+
+
+ + ) +} diff --git a/frontend/components/issues-list.tsx b/frontend/components/issues-list.tsx index f783005..7dab26f 100644 --- a/frontend/components/issues-list.tsx +++ b/frontend/components/issues-list.tsx @@ -2,6 +2,8 @@ import { useEffect, useState, useRef, useCallback } from "react" import { IssueCard } from "@/components/issue-card" +import { useAuth } from "@/context/auth-context" +import { getUserByGithubId } from "@/lib/firebase-utils" const MATCH_COLORS = ["#8b5cf6", "#ec4899", "#f97316", "#10b981", "#3b82f6"] @@ -21,14 +23,52 @@ interface IssuesListProps { type: "recommended" | "trending" | "favorite" | "recent" } +import { IssueFilter } from "@/components/issue-filter" + export function IssuesList({ type }: IssuesListProps) { const [issues, setIssues] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) + const [userSkills, setUserSkills] = useState([]) + const [filters, setFilters] = useState<{ keywords: string[] }>({ + keywords: [], + }) const timeoutRef = useRef(null) + const { user, isLoading: authLoading } = useAuth() + + // Fetch user skills from Firebase + const fetchUserSkills = useCallback(async () => { + if (!user) { + setUserSkills([]) + return + } + try { + const result = await getUserByGithubId(user.id) + if (result.success && result.data?.skill_keywords) { + setUserSkills(result.data.skill_keywords) + // Initialize filters.keywords with user skills + setFilters((prev) => ({ ...prev, keywords: result.data.skill_keywords })) + } else { + setUserSkills([]) + } + } catch (error) { + console.error("Error fetching user skills:", error) + setUserSkills([]) + } + }, [user]) // Create a fetchIssues function that can be called both in useEffect and by the retry button const fetchIssues = useCallback(async () => { + if (authLoading) { + return + } + + if (!user) { + setError("Please log in to view issues") + setLoading(false) + return + } + // Clear any existing timeout if (timeoutRef.current) { clearTimeout(timeoutRef.current) @@ -38,7 +78,7 @@ export function IssuesList({ type }: IssuesListProps) { timeoutRef.current = setTimeout(() => { setLoading(false) setError("Request timed out. Please try again later.") - }, 25000) // 15 seconds timeout + }, 25000) // 25 seconds timeout setLoading(true) setError(null) @@ -46,32 +86,45 @@ export function IssuesList({ type }: IssuesListProps) { try { console.log(`Fetching ${type} issues...`) - // Different endpoints based on issue type + // Build endpoint with filters for recommended type let endpoint = "" - switch (type) { - case "recommended": - endpoint = "http://localhost:8000/api/v1/match/match-issue?keywords=machine-learning&keywords=java&max_results=5" - break - case "trending": - endpoint = "http://localhost:8000/api/v1/match/trending-issues" - break - case "favorite": - endpoint = "http://localhost:8000/api/v1/match/favorite-issues" - break - case "recent": - endpoint = "http://localhost:8000/api/v1/match/recent-issues" - break - default: - endpoint = "http://localhost:8000/api/v1/match/match-issue?keywords=machine-learning&keywords=java&max_results=5" + if (type === "recommended") { + const params = new URLSearchParams() + if (filters.keywords.length > 0) { + filters.keywords.forEach((skill) => { + params.append("keywords", skill) + }) + } else { + // fallback keywords if no user skills + params.append("keywords", "machine-learning") + params.append("keywords", "java") + } + + params.append("max_results", "5") + endpoint = `http://localhost:8000/api/v1/match/match-issue?${params.toString()}` + } else { + switch (type) { + case "trending": + endpoint = "http://localhost:8000/api/v1/match/trending-issues" + break + case "favorite": + endpoint = "http://localhost:8000/api/v1/match/favorite-issues" + break + case "recent": + endpoint = "http://localhost:8000/api/v1/match/recent-issues" + break + default: + endpoint = "http://localhost:8000/api/v1/match/match-issue?keywords=machine-learning&keywords=java&max_results=5" + } } const response = await fetch(endpoint, { - method: 'GET', + method: "GET", headers: { - 'Content-Type': 'application/json', - 'Accept': 'application/json', + "Content-Type": "application/json", + Accept: "application/json", }, - credentials: 'include' + credentials: "include", }) // Clear the timeout since we got a response @@ -82,7 +135,7 @@ export function IssuesList({ type }: IssuesListProps) { if (!response.ok) { const errorText = await response.text() - throw new Error(`API error: ${response.status} ${response.statusText}${errorText ? ` - ${errorText}` : ''}`) + throw new Error(`API error: ${response.status} ${response.statusText}${errorText ? ` - ${errorText}` : ""}`) } const data = await response.json() @@ -104,9 +157,14 @@ export function IssuesList({ type }: IssuesListProps) { setLoading(false) setError(err instanceof Error ? err.message : "Failed to fetch issues") } - }, [type]) + }, [type, filters, authLoading, user]) - // Effect to fetch issues when the component mounts or type changes + // Effect to fetch user skills when user changes + useEffect(() => { + fetchUserSkills() + }, [fetchUserSkills]) + + // Effect to fetch issues when the component mounts or type, filters change useEffect(() => { fetchIssues() @@ -116,7 +174,7 @@ export function IssuesList({ type }: IssuesListProps) { clearTimeout(timeoutRef.current) } } - }, [fetchIssues]) // fetchIssues already depends on type + }, [fetchIssues]) // fetchIssues already depends on type, filters, authLoading // Transform API issues to the format expected by IssueCard const transformedIssues = issues.map((issue, index) => ({ @@ -127,44 +185,56 @@ export function IssuesList({ type }: IssuesListProps) { skillMatch: Math.min(Math.round(issue.similarity_score * 100 + 30), 99), // Cap at 99% skills: issue.labels?.slice(0, 5) || ["No labels"], matchColor: MATCH_COLORS[index % MATCH_COLORS.length], - issueUrl: issue.issue_url + issueUrl: issue.issue_url, })) return ( -
- {loading ? ( -
-
-
-
-
-
-
-
+ <> + +
+ {loading ? ( +
+
+
+
+
+
+
+
+
-
- ) : error ? ( -
-
Error loading issues
-
{error}
- -
- ) : transformedIssues.length === 0 ? ( -
-
No issues found
-
Try adjusting your search criteria or check back later
-
- ) : ( - transformedIssues.map((issue) => ( - - )) - )} -
+ ) : error ? ( +
+
Error loading issues
+
{error}
+ {error === "Please log in to view issues" ? ( + + Log In + + ) : ( + + )} +
+ ) : transformedIssues.length === 0 ? ( +
+
No issues found
+
Try adjusting your search criteria or check back later
+
+ ) : ( + transformedIssues.map((issue) => ( + + )) + )} +
+ ) -} \ No newline at end of file +}