Skip to content
Merged
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
117 changes: 56 additions & 61 deletions src/pages/CodingOwl.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useState, useEffect, useRef } from "react";
import { Timer, Plus, Check, RotateCcw } from "lucide-react";
import { habitCards, weeklyHeatmap } from "../data/streaks";
import Card from "../components/ui/Card";

Check warning on line 4 in src/pages/CodingOwl.jsx

View workflow job for this annotation

GitHub Actions / Lint Check

'Card' is defined but never used. Allowed unused vars must match /^React$/u
import SectionHeader from "../components/ui/SectionHeader";
import { useAuth } from "../context/AuthContext";

Expand All @@ -10,7 +10,7 @@
const userName = userData?.name || "Developer";
const userStreak = userData?.streak || 0;
const [habits, setHabits] = useState(habitCards);
const [timeLeft, setTimeLeft] = useState(1500); // 25:00 in seconds
const [timeLeft, setTimeLeft] = useState(1500);
const [timerActive, setTimerActive] = useState(false);
const [isResetting, setIsResetting] = useState(false);
const timerRef = useRef(null);
Expand Down Expand Up @@ -40,20 +40,15 @@
};

const resetTimer = () => {
// Add reset animation
setIsResetting(true);

// Clear the active interval if it exists
if (timerRef.current) {
clearInterval(timerRef.current);
timerRef.current = null;
}
// Set timer to inactive state
setTimerActive(false);
// Reset time to 25:00 (1500 seconds)
setTimeLeft(1500);

// Remove animation class after animation completes
setTimeout(() => {
setIsResetting(false);
}, 500);
Expand All @@ -77,7 +72,7 @@
return { ...habit, progress: newProgress, streak: newStreak };
}
return habit;
}),
})
);
};

Expand All @@ -93,71 +88,71 @@

{/* Mascot & Streak Highlight */}
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
{/* Mascot bubble */}
<Card className="lg:col-span-2 p-8 flex flex-col sm:flex-row items-center gap-6 bg-gradient-to-br from-orange-500/10 via-slate-50/0 to-slate-50/0 dark:from-orange-500/5 dark:via-slate-900/0 dark:to-slate-900/0 border-orange-500/15">
{/* Mascot Mascot representation */}
<div className="w-28 h-28 rounded-full bg-gradient-to-tr from-orange-400 to-red-500 flex items-center justify-center text-4xl shadow-lg border border-orange-400/25 flex-shrink-0 animate-bounce">
{/* Mascot bubble - Enhanced visibility */}
<div className="lg:col-span-2 p-8 flex flex-col sm:flex-row items-center gap-6 bg-white dark:bg-slate-800 rounded-2xl shadow-lg border-2 border-orange-200 dark:border-orange-800/50">
{/* Mascot representation */}
<div className="w-28 h-28 rounded-full bg-gradient-to-tr from-orange-400 to-red-500 flex items-center justify-center text-4xl shadow-lg border-2 border-orange-300 dark:border-orange-600 flex-shrink-0 animate-bounce">
🦉
</div>

<div className="space-y-3 flex-1 text-center sm:text-left">
<h3 className="text-xl font-extrabold text-slate-950 dark:text-white my-0">
<h3 className="text-xl font-extrabold text-slate-800 dark:text-white my-0">
Mascot: Oliver the Owl
</h3>

<div className="bg-white/80 dark:bg-slate-950/60 p-4 rounded-xl border border-slate-200/40 dark:border-slate-800/45 text-sm text-slate-600 dark:text-slate-300 leading-relaxed font-semibold italic relative">
<div className="bg-orange-50 dark:bg-slate-700/50 p-4 rounded-xl border-2 border-orange-200 dark:border-orange-800/50 text-sm text-slate-700 dark:text-slate-200 leading-relaxed font-semibold italic relative">
"Whoo-whoo! You've logged code for {userStreak} consecutive days,{" "}
{userName}. Oliver is proud! Maintain your streak today to earn a
1.5x points multiplier."
</div>

<div className="flex justify-center sm:justify-start items-center gap-4 text-xs font-bold text-slate-400">
<div className="flex justify-center sm:justify-start items-center gap-4 text-xs font-bold text-slate-500 dark:text-slate-400">
<span>
Mood: <span className="text-orange-500">Ecstatic! 🔥</span>
</span>
<span>•</span>
<span>Next Check-in: 8 hours remaining</span>
</div>
</div>
</Card>
</div>

{/* Focus Timer Session Card */}
<Card className="p-6 flex flex-col justify-between">
{/* Focus Timer Session Card - Enhanced visibility */}
<div className="p-6 flex flex-col justify-between bg-white dark:bg-slate-800 rounded-2xl shadow-lg border-2 border-orange-200 dark:border-orange-800/50">
<div className="space-y-2">
<span className="text-xs font-bold text-slate-400 uppercase">
<span className="text-xs font-bold text-orange-500 dark:text-orange-400 uppercase">
Focus Arena
</span>
<h3 className="text-lg font-extrabold text-slate-950 dark:text-white my-0">
<h3 className="text-lg font-extrabold text-slate-800 dark:text-white my-0">
Focus Mode Session
</h3>
<p className="text-xs text-slate-500 dark:text-slate-400">
<p className="text-xs text-slate-600 dark:text-slate-400">
Lock out distractions and log heads-down coding time.
</p>
</div>

{/* Timer visualization with reset animation effect */}
{/* Timer visualization */}
<div className="my-6 text-center flex flex-col items-center justify-center">
<span
className={`text-4xl font-black text-slate-900 dark:text-white tracking-widest block font-mono transition-all duration-300 ${
className={`text-4xl font-black text-slate-800 dark:text-white tracking-widest block font-mono transition-all duration-300 ${
isResetting
? "scale-110 text-orange-500 rotate-12"
: "scale-100"
}`}
>
{formatTime(timeLeft)}
</span>
<span className="text-[10px] text-slate-400 uppercase font-bold mt-1.5 block">
<span className="text-[10px] text-slate-500 dark:text-slate-400 uppercase font-bold mt-1.5 block">
Pomodoro Interval
</span>
</div>

<div className="flex items-center gap-2">
<button
onClick={toggleTimer}
className={`flex-1 py-2.5 rounded-xl font-bold border text-sm transition-all duration-300 flex items-center justify-center gap-2 cursor-pointer ${
className={`flex-1 py-2.5 rounded-xl font-bold border-2 text-sm transition-all duration-300 flex items-center justify-center gap-2 cursor-pointer ${
timerActive
? "bg-amber-500 hover:bg-amber-600 text-white border-amber-500"
: "bg-gradient-to-r from-orange-500 to-red-500 hover:opacity-90 text-white border-orange-500"
? "bg-amber-500 hover:bg-amber-600 text-white border-amber-600"
: "bg-gradient-to-r from-orange-500 to-red-500 hover:opacity-90 text-white border-orange-600"
}`}
>
<Timer className="w-4 h-4" />{" "}
Expand All @@ -168,34 +163,34 @@
disabled={isResetting}
className={`px-4 py-2.5 rounded-xl font-bold transition-all duration-300 text-sm cursor-pointer flex items-center justify-center gap-2 ${
isResetting
? "bg-slate-300 dark:bg-slate-700 cursor-not-allowed opacity-60"
: "bg-slate-100 dark:bg-slate-800 hover:bg-slate-200 dark:hover:bg-slate-700 hover:scale-105 active:scale-95"
} border border-slate-200 dark:border-slate-700 text-slate-600 dark:text-slate-350`}
? "bg-slate-200 dark:bg-slate-600 cursor-not-allowed opacity-60"
: "bg-slate-100 dark:bg-slate-700 hover:bg-slate-200 dark:hover:bg-slate-600 hover:scale-105 active:scale-95"
} border-2 border-slate-300 dark:border-slate-600 text-slate-700 dark:text-slate-200`}
>
<RotateCcw
className={`w-4 h-4 transition-transform duration-300 ${isResetting ? "animate-spin" : "group-hover:rotate-180"}`}
/>
Reset
</button>
</div>
</Card>
</div>
</div>

{/* Habits Checklist Grid */}
<div className="space-y-4">
<h3 className="font-extrabold text-lg text-slate-900 dark:text-white my-0">
<h3 className="font-extrabold text-lg text-slate-800 dark:text-white my-0">
Your Habit Dashboard
</h3>

<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
{habits.map((habit) => (
<Card
<div
key={habit.id}
className="p-5 flex flex-col justify-between border-slate-200/50 dark:border-slate-800/50 hover:border-orange-500/25 transition-all"
className="p-5 flex flex-col justify-between bg-white dark:bg-slate-800 rounded-2xl shadow-lg border-2 border-slate-200 dark:border-slate-700 hover:border-orange-300 dark:hover:border-orange-700 transition-all"
>
<div className="space-y-3">
<div className="flex items-center justify-between">
<span className="px-2 py-0.5 rounded-full text-[9px] font-bold bg-orange-500/10 text-orange-500 dark:text-orange-400 border border-orange-500/20">
<span className="px-2 py-0.5 rounded-full text-[9px] font-bold bg-orange-100 dark:bg-orange-900/30 text-orange-600 dark:text-orange-400 border border-orange-200 dark:border-orange-800">
{habit.frequency}
</span>

Expand All @@ -204,24 +199,24 @@
</span>
</div>

<h4 className="font-extrabold text-slate-900 dark:text-white leading-tight my-0">
<h4 className="font-extrabold text-slate-800 dark:text-white leading-tight my-0">
{habit.title}
</h4>

<p className="text-xs text-slate-500 dark:text-slate-400 leading-relaxed font-medium">
<p className="text-xs text-slate-600 dark:text-slate-400 leading-relaxed font-medium">
{habit.description}
</p>
</div>

{/* Progress Slider */}
<div className="mt-6 pt-3 border-t border-slate-100 dark:border-slate-800/80 space-y-2">
<div className="flex justify-between items-center text-[10px] font-bold text-slate-400">
{/* Progress Section */}
<div className="mt-6 pt-3 border-t-2 border-slate-100 dark:border-slate-700 space-y-2">
<div className="flex justify-between items-center text-[10px] font-bold text-slate-500 dark:text-slate-400">
<span>Today's status</span>
<span
className={
habit.progress === 100
? "text-emerald-500"
: "text-slate-400"
: "text-slate-500 dark:text-slate-400"
}
>
{habit.progress === 100 ? "Completed" : "In Progress"}
Expand All @@ -230,10 +225,10 @@

<button
onClick={() => toggleHabitComplete(habit.id)}
className={`w-full py-1.5 rounded-lg text-xs font-bold transition-all flex items-center justify-center gap-1 cursor-pointer ${
className={`w-full py-1.5 rounded-lg text-xs font-bold transition-all flex items-center justify-center gap-1 cursor-pointer border-2 ${
habit.progress === 100
? "bg-emerald-500/10 text-emerald-600 dark:text-emerald-400 border border-emerald-500/20"
: "bg-slate-100 dark:bg-slate-800 hover:bg-slate-200 dark:hover:bg-slate-700 text-slate-700 dark:text-slate-350 border border-slate-200/50 dark:border-slate-750"
? "bg-emerald-50 dark:bg-emerald-900/20 text-emerald-600 dark:text-emerald-400 border-emerald-200 dark:border-emerald-800"
: "bg-slate-50 dark:bg-slate-700 hover:bg-slate-100 dark:hover:bg-slate-600 text-slate-700 dark:text-slate-200 border-slate-200 dark:border-slate-600"
}`}
>
{habit.progress === 100 ? (
Expand All @@ -248,44 +243,44 @@
)}
</button>
</div>
</Card>
</div>
))}
</div>
</div>

{/* 4 Weeks Consistency heatmap representation */}
<Card className="p-6">
<div className="pb-4 border-b border-slate-100 dark:border-slate-800 flex items-center justify-between">
{/* Weekly Consistency heatmap - Enhanced visibility */}
<div className="p-6 bg-white dark:bg-slate-800 rounded-2xl shadow-lg border-2 border-slate-200 dark:border-slate-700">
<div className="pb-4 border-b-2 border-slate-100 dark:border-slate-700 flex items-center justify-between">
<div>
<h3 className="font-extrabold text-lg text-slate-900 dark:text-white my-0">
<h3 className="font-extrabold text-lg text-slate-800 dark:text-white my-0">
Weekly Consistency Grid
</h3>
<p className="text-xs text-slate-400 dark:text-slate-500">
<p className="text-xs text-slate-500 dark:text-slate-400">
A historical log of your daily check-in marks.
</p>
</div>
<span className="text-xs font-bold text-orange-500">
<span className="text-xs font-bold text-orange-500 dark:text-orange-400">
Last 4 Weeks
</span>
</div>

<div className="mt-6 grid grid-cols-4 gap-6">
{weeklyHeatmap.map((week, idx) => (
<div key={idx} className="space-y-3">
<span className="text-xs font-bold text-slate-400 block text-center">
<span className="text-xs font-bold text-slate-500 dark:text-slate-400 block text-center">
Week {week.week}
</span>

<div className="flex justify-between items-center gap-1.5 py-3 px-4 rounded-xl bg-slate-50 dark:bg-slate-950/30 border border-slate-200/40 dark:border-slate-800/40">
<div className="flex justify-between items-center gap-1.5 py-3 px-4 rounded-xl bg-slate-50 dark:bg-slate-700/50 border-2 border-slate-200 dark:border-slate-700">
{week.days.map((day, dayIdx) => (
<div
key={dayIdx}
className={`w-3 h-3 rounded-full ${
day === 2
? "bg-gradient-to-r from-orange-500 to-red-500 shadow-md shadow-orange-500/20"
? "bg-gradient-to-r from-orange-500 to-red-500 shadow-lg shadow-orange-500/30 ring-2 ring-orange-300 dark:ring-orange-700"
: day === 1
? "bg-orange-500/40 dark:bg-orange-500/20"
: "bg-slate-200 dark:bg-slate-800/50"
? "bg-orange-400 dark:bg-orange-500/40 ring-2 ring-orange-200 dark:ring-orange-800"
: "bg-slate-300 dark:bg-slate-600 ring-2 ring-slate-200 dark:ring-slate-700"
}`}
title={`Day status: ${day}`}
/>
Expand All @@ -295,23 +290,23 @@
))}
</div>

<div className="flex justify-center gap-6 mt-6 text-xs text-slate-400 font-bold">
<div className="flex justify-center gap-6 mt-6 text-xs text-slate-600 dark:text-slate-400 font-bold">
<div className="flex items-center gap-1.5">
<div className="w-2.5 h-2.5 rounded-full bg-slate-200 dark:bg-slate-800" />
<div className="w-2.5 h-2.5 rounded-full bg-slate-300 dark:bg-slate-600 ring-2 ring-slate-200 dark:ring-slate-700" />
<span>Missed</span>
</div>
<div className="flex items-center gap-1.5">
<div className="w-2.5 h-2.5 rounded-full bg-orange-500/20" />
<div className="w-2.5 h-2.5 rounded-full bg-orange-400 dark:bg-orange-500/40 ring-2 ring-orange-200 dark:ring-orange-800" />
<span>Logged</span>
</div>
<div className="flex items-center gap-1.5">
<div className="w-2.5 h-2.5 rounded-full bg-gradient-to-r from-orange-500 to-red-500" />
<div className="w-2.5 h-2.5 rounded-full bg-gradient-to-r from-orange-500 to-red-500 ring-2 ring-orange-300 dark:ring-orange-700" />
<span>Bonus Multiplier Achieved</span>
</div>
</div>
</Card>
</div>
</div>
);
};

export default CodingOwl;
export default CodingOwl;
Loading