-
Activity
-
-
+
+
+
+
+ Activity Heatmap
+
+
+
-
-
+
);
-}
+}
\ No newline at end of file
diff --git a/frontend/src/Components/DashBoard/GithubRepoCard.jsx b/frontend/src/Components/DashBoard/GithubRepoCard.jsx
new file mode 100644
index 0000000..f203fd3
--- /dev/null
+++ b/frontend/src/Components/DashBoard/GithubRepoCard.jsx
@@ -0,0 +1,117 @@
+import React from 'react';
+import { Github, Star, GitFork, Clock } from 'lucide-react';
+import CardWrapper from './CardWrapper';
+
+/**
+ * Component to display a list of GitHub repositories
+ */
+export default function GithubRepoCard({ repositories = [], className = '' }) {
+ // Format the update time to a readable string
+ const formatUpdateTime = (dateString) => {
+ if (!dateString) return '';
+
+ const date = new Date(dateString);
+ const now = new Date();
+ const diffMs = now - date;
+ const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
+
+ if (diffDays === 0) {
+ return 'Today';
+ } else if (diffDays === 1) {
+ return 'Yesterday';
+ } else if (diffDays < 7) {
+ return `${diffDays} days ago`;
+ } else if (diffDays < 30) {
+ const weeks = Math.floor(diffDays / 7);
+ return `${weeks} ${weeks === 1 ? 'week' : 'weeks'} ago`;
+ } else {
+ const months = Math.floor(diffDays / 30);
+ return `${months} ${months === 1 ? 'month' : 'months'} ago`;
+ }
+ };
+
+ // Language color mapping
+ const languageColors = {
+ JavaScript: '#f1e05a',
+ TypeScript: '#3178c6',
+ HTML: '#e34c26',
+ CSS: '#563d7c',
+ Python: '#3572A5',
+ Java: '#b07219',
+ 'C#': '#178600',
+ PHP: '#4F5D95',
+ Ruby: '#701516',
+ Go: '#00ADD8',
+ Swift: '#F05138',
+ Kotlin: '#A97BFF',
+ Rust: '#dea584',
+ Dart: '#00B4AB',
+ // Add more languages as needed
+ default: '#cccccc'
+ };
+
+ return (
+
+
+
+
+ Repositories
+
+
+
+ {repositories.length === 0 ? (
+
+ No repositories found. Connect with GitHub to see your repositories.
+
+ ) : (
+
+ {repositories.map((repo) => (
+
+
+ {repo.name}
+
+
+ {repo.description && (
+
+ {repo.description}
+
+ )}
+
+
+ {repo.language && (
+
+
+ {repo.language}
+
+ )}
+
+
+
+ {repo.stargazers_count}
+
+
+
+
+ {repo.forks_count}
+
+
+
+
+ {formatUpdateTime(repo.updated_at)}
+
+
+
+ ))}
+
+ )}
+
+ );
+}
\ No newline at end of file
diff --git a/frontend/src/Components/DashBoard/StreakCard.jsx b/frontend/src/Components/DashBoard/StreakCard.jsx
index 131749e..806cdb5 100644
--- a/frontend/src/Components/DashBoard/StreakCard.jsx
+++ b/frontend/src/Components/DashBoard/StreakCard.jsx
@@ -1,14 +1,44 @@
import { Flame } from "lucide-react";
import CardWrapper from "./CardWrapper";
+import React, { useEffect } from "react";
export default function StreakCard({ streak }) {
const safeStreak = streak ?? 0;
+
+ // Log streak data for debugging
+ useEffect(() => {
+ console.log("StreakCard received streak:", streak);
+ }, [streak]);
+
+ // Create a visual representation of the streak
+ const renderStreakBoxes = () => {
+ const boxes = [];
+ const maxBoxes = 7; // Show up to 7 days
+ const displayCount = Math.min(safeStreak, maxBoxes);
+
+ for (let i = 0; i < maxBoxes; i++) {
+ // Active if current index is less than the streak
+ const isActive = i < displayCount;
+ boxes.push(
+
+ );
+ }
+ return boxes;
+ };
return (
-
-
- {safeStreak} Days
- Current Streak
+
+
+ {safeStreak} Days
+ Current Streak
+
+ {/* Visual streak representation */}
+
+ {renderStreakBoxes()}
+
);
}
diff --git a/frontend/src/Components/Dashboard.jsx b/frontend/src/Components/Dashboard.jsx
index f9cbd91..d6d3ef2 100644
--- a/frontend/src/Components/Dashboard.jsx
+++ b/frontend/src/Components/Dashboard.jsx
@@ -17,17 +17,21 @@ export default function Dashboard() {
const [error, setError] = useState(null);
const [goals, setGoals] = useState([]);
const navigate = useNavigate();
-
+
useEffect(() => {
// Capture token issued by backend OAuth redirect: /dashboard?token=...
const params = new URLSearchParams(window.location.search);
const oauthToken = params.get("token");
+
if (oauthToken) {
try {
localStorage.setItem("token", oauthToken);
+ // Also store in sessionStorage for GitHub API calls (from your branch)
+ sessionStorage.setItem("github_token", oauthToken);
} catch (e) {
console.error("Failed to persist OAuth token:", e);
}
+
// Clean up URL after capturing token (avoid keeping token in address bar)
const cleanUrl = window.location.origin + window.location.pathname;
window.history.replaceState({}, document.title, cleanUrl);
@@ -36,20 +40,28 @@ export default function Dashboard() {
const fetchProfile = async () => {
try {
const token = localStorage.getItem("token");
+
if (!token) {
navigate("/login");
setLoading(false);
return;
}
+ // For session auth, keeping both auth methods (your custom + main branch approach)
const res = await fetch(`${import.meta.env.VITE_API_URL}/api/profile`, {
headers: { "x-auth-token": token },
+ credentials: 'include', // Important for session-based auth (from your branch)
});
const data = await res.json();
if (!res.ok) {
throw new Error(data.errors?.[0]?.msg || "Failed to load profile");
}
+
+ // Use DevSync activity data or initialize empty array
+ if (!data.activity || !Array.isArray(data.activity)) {
+ data.activity = [];
+ }
setProfile(data);
setGoals(data.goals || []);
@@ -116,7 +128,7 @@ export default function Dashboard() {
{/* Row 1 */}
-
+
{/* GitHub Card (conditionally rendered) */}
diff --git a/frontend/src/Components/Features.jsx b/frontend/src/Components/Features.jsx
index 4846db2..62cc785 100644
--- a/frontend/src/Components/Features.jsx
+++ b/frontend/src/Components/Features.jsx
@@ -29,8 +29,8 @@ export function FeaturesSection() {
icon:
,
},
{
- title: "Auto GitHub Sync",
- description: "Sync contributions, commits, and streaks automatically.",
+ title: "GitHub Authentication",
+ description: "Secure login with your GitHub account.",
icon:
,
},
{
diff --git a/frontend/src/Components/GitHubProfile.jsx b/frontend/src/Components/GitHubProfile.jsx
index 8d677e9..2d26974 100644
--- a/frontend/src/Components/GitHubProfile.jsx
+++ b/frontend/src/Components/GitHubProfile.jsx
@@ -1,3 +1,4 @@
+
import React, { useEffect, useState } from "react";
import { useParams, Link } from "react-router-dom";
import { Card, CardHeader, CardTitle, CardContent } from "@/Components/ui/Card";
diff --git a/frontend/src/Components/auth/Login.jsx b/frontend/src/Components/auth/Login.jsx
index 6d1182b..e360cf5 100644
--- a/frontend/src/Components/auth/Login.jsx
+++ b/frontend/src/Components/auth/Login.jsx
@@ -78,6 +78,18 @@ const Login = () => {
window.location.href = `${import.meta.env.VITE_API_URL}/auth/google`;
};
+ const handleGithubLogin = () => {
+ // Clear any existing tokens to avoid conflicts with session-based auth
+ localStorage.removeItem('token');
+
+ // Try the /auth/github path instead as this matches GitHub's configured callback
+ console.log(`Redirecting to: ${import.meta.env.VITE_API_URL}/auth/github?from=login`);
+
+ // Use a timestamp to prevent caching issues
+ const timestamp = new Date().getTime();
+ window.location.href = `${import.meta.env.VITE_API_URL}/auth/github?from=login&t=${timestamp}`;
+ };
+
// Show verification component if user needs to verify email
if (showVerification) {
return (
@@ -242,6 +254,7 @@ const Login = () => {
{/* Social Login */}