"use client"; import React, { useState, useEffect } from "react"; import { PROJECTS_DATA } from "../lib/projectsData"; import { ProjectItem, ActiveTab } from "../lib/types"; import { ExternalLink, Search, Sparkles, ArrowRight, Star, GitFork, Activity, Flame, RefreshCw } from "lucide-react"; const GithubIcon = () => ( ); interface ProjectsViewProps { onSelectPrompt: (prompt: string) => void; setActiveTab: (tab: ActiveTab) => void; tutorConfig?: any; } function formatRelativeTime(dateString: string): { label: string; isRecent: boolean } { try { const date = new Date(dateString); if (isNaN(date.getTime())) return { label: "Recently updated", isRecent: false }; const now = new Date(); const diffMs = now.getTime() - date.getTime(); const diffHours = Math.floor(diffMs / (1000 * 60 * 60)); const diffDays = Math.floor(diffHours / 24); if (diffHours < 1) return { label: "Pushed < 1h ago", isRecent: true }; if (diffHours < 24) return { label: `Pushed ${diffHours}h ago`, isRecent: true }; if (diffDays === 1) return { label: "Pushed yesterday", isRecent: true }; if (diffDays <= 7) return { label: `Pushed ${diffDays}d ago`, isRecent: true }; if (diffDays < 30) return { label: `Pushed ${diffDays}d ago`, isRecent: false }; const months = Math.floor(diffDays / 30); if (months === 1) return { label: "Pushed 1m ago", isRecent: false }; if (months < 12) return { label: `Pushed ${months}m ago`, isRecent: false }; return { label: `Pushed ${Math.floor(months / 12)}y ago`, isRecent: false }; } catch { return { label: "Recently updated", isRecent: false }; } } export const ProjectsView: React.FC = ({ onSelectPrompt, setActiveTab, tutorConfig, }) => { const [selectedCategory, setSelectedCategory] = useState("All"); const [searchQuery, setSearchQuery] = useState(""); const [sortBy, setSortBy] = useState<"recent" | "stars">("recent"); const [projects, setProjects] = useState(PROJECTS_DATA); const [isSyncing, setIsSyncing] = useState(true); const [lastSyncedTime, setLastSyncedTime] = useState(""); const categories = ["All", "Healthcare", "Education", "RAG & AI", "Agents & Tools", "Automation & Scraping"]; // Live GitHub Repository Sync useEffect(() => { let isMounted = true; async function syncGitHubRepos() { setIsSyncing(true); try { const res = await fetch("https://api.github.com/users/neural-arun/repos?sort=pushed&direction=desc&per_page=100"); if (!res.ok) throw new Error(`GitHub API HTTP ${res.status}`); const githubRepos: any[] = await res.json(); if (!isMounted) return; // Map GitHub repo details onto local projects & discover unlisted repos const repoMap = new Map(); githubRepos.forEach((r) => { repoMap.set(r.name.toLowerCase(), r); }); const updatedList: ProjectItem[] = PROJECTS_DATA.map((proj) => { const matchingRepo = repoMap.get(proj.name.toLowerCase()) || repoMap.get(proj.id.toLowerCase()); if (matchingRepo) { const pushedDate = matchingRepo.pushed_at || matchingRepo.updated_at || proj.updatedAt; const { label, isRecent } = formatRelativeTime(pushedDate); return { ...proj, updatedAt: pushedDate, updatedAtLabel: label, relativeTime: label, isRecentActivity: isRecent, stars: matchingRepo.stargazers_count ?? 0, forks: matchingRepo.forks_count ?? 0, }; } else { const { label, isRecent } = formatRelativeTime(proj.updatedAt); return { ...proj, relativeTime: label, isRecentActivity: isRecent, }; } }); // Check for public repos not in static dataset and add them automatically const knownNames = new Set(PROJECTS_DATA.map((p) => p.name.toLowerCase())); githubRepos.forEach((r) => { if (!knownNames.has(r.name.toLowerCase()) && !r.fork && !r.private) { const { label, isRecent } = formatRelativeTime(r.pushed_at || r.updated_at); updatedList.push({ id: r.name, name: r.name, title: r.name.replace(/[-_]/g, " ").replace(/\b\w/g, (c: string) => c.toUpperCase()), category: "Agents & Tools", description: r.description || "Public software repository by Arun Yadav.", githubUrl: r.html_url, techStack: [r.language || "Python", "GitHub"], highlights: [`Live repository from github.com/neural-arun/${r.name}`], suggestedPrompt: `Tell me about the ${r.name} project on GitHub!`, updatedAt: r.pushed_at || r.updated_at, updatedAtLabel: label, relativeTime: label, isRecentActivity: isRecent, stars: r.stargazers_count ?? 0, forks: r.forks_count ?? 0, }); } }); setProjects(updatedList); setLastSyncedTime(new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })); } catch (err) { console.warn("GitHub live sync fallback to static dataset:", err); // Calculate relative times for static data setProjects( PROJECTS_DATA.map((proj) => { const { label, isRecent } = formatRelativeTime(proj.updatedAt); return { ...proj, relativeTime: label, isRecentActivity: isRecent }; }) ); } finally { if (isMounted) setIsSyncing(false); } } syncGitHubRepos(); return () => { isMounted = false; }; }, []); // Filter and Sort Projects const processedProjects = projects .filter((project) => { const matchesCategory = selectedCategory === "All" || project.category === selectedCategory; const matchesSearch = project.title.toLowerCase().includes(searchQuery.toLowerCase()) || project.description.toLowerCase().includes(searchQuery.toLowerCase()) || project.techStack.some((t) => t.toLowerCase().includes(searchQuery.toLowerCase())); return matchesCategory && matchesSearch; }) .sort((a, b) => { if (sortBy === "stars") { return (b.stars || 0) - (a.stars || 0); } // Default: Sort by latest commit date descending (most recent first!) const dateA = new Date(a.updatedAt).getTime() || 0; const dateB = new Date(b.updatedAt).getTime() || 0; return dateB - dateA; }); const handleCardClick = (githubUrl: string) => { window.open(githubUrl, "_blank", "noopener,noreferrer"); }; const handleAskTwin = (e: React.MouseEvent, title: string, repoName: string) => { e.stopPropagation(); const prompt = `Can you give me a comprehensive summary of the ${title} project (${repoName}) based on its repository README and technical architecture?`; onSelectPrompt(prompt); setActiveTab("chat"); }; const coursesList = tutorConfig?.courses || []; if (tutorConfig && coursesList.length > 0) { const pageTitle = tutorConfig?.frontend_ui_dictionary?.projects_view?.header_title || tutorConfig?.title || "Courses & Masterclasses"; const pageSubtitle = tutorConfig?.frontend_ui_dictionary?.projects_view?.header_subtitle || "Browse flagship curriculum, course outcomes, and enrollment options."; return (
{/* Header */}

{pageTitle}

{pageSubtitle}

{/* Courses Cards Grid */}
{coursesList.map((course: any, idx: number) => (

{course.title}

{course.subtitle}

{course.price && ( {course.price} )}

{course.description}

{course.target_audience && (
🎯 Target Audience: {course.target_audience}
)} {course.outcomes && (
🚀 Key Outcomes: {course.outcomes}
)}
{course.link && ( )}
))}
); } return (
{/* Header with Live Sync Status */}

Projects & Engineering Repositories

Click any project card to view its live GitHub repository, or ask my AI Twin for a summary.

setSearchQuery(e.target.value)} placeholder="Search stack or project..." className="w-full rounded-xl border border-[var(--border-subtle)] bg-[var(--bg-surface)] py-2.5 pl-9 pr-4 text-xs sm:text-sm text-[var(--text-main)] placeholder-[var(--text-dim)] focus:border-[var(--border-accent)] focus:outline-none" />
{/* Sort & Category Controls */}
{/* Category Pills */}
{categories.map((cat) => ( ))}
{/* Sort Selector */}
{/* Project Cards */}
{processedProjects.map((proj) => (
handleCardClick(proj.githubUrl)} className="group cursor-pointer rounded-2xl shiny-border-card bg-[var(--bg-surface)] p-6 transition-all hover:bg-[var(--bg-surface-hover)] hover:shadow-xl" >
{proj.category} {/* Dynamic Commit Activity Badge */} {proj.isRecentActivity ? ( ) : ( )} {proj.relativeTime || proj.updatedAtLabel}
{/* Title */}

{proj.title}

{/* GitHub Specs & External Link */}
{typeof proj.stars === "number" && proj.stars > 0 && ( {proj.stars} )} {typeof proj.forks === "number" && proj.forks > 0 && ( {proj.forks} )}
{proj.name}
{/* Description */}

{proj.description}

{/* Highlights */}
{proj.highlights.map((hl, idx) => (
{hl}
))}
{/* Footer Tech Badges & Ask Twin Button */}
{proj.techStack.map((tech, tIdx) => ( {tech} ))}
{/* Ask Twin Summary Action */}
))}
); };