Skip to content

Commit f518f4d

Browse files
authored
Merge pull request #91 from CrackCode-dev/nadeesha-backup3
Refactor component imports and improve challenge completion logic
2 parents 21b74fc + 16a9728 commit f518f4d

8 files changed

Lines changed: 100 additions & 70 deletions

File tree

crackcode/client/src/components/home/ChallengesThisWeek.jsx

Lines changed: 56 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1-
import { useState, useEffect } from 'react';
1+
/* eslint-disable no-unused-vars */
2+
import { useContext, useState, useEffect } from 'react';
23
import { useTheme } from '../../context/theme/ThemeContext';
3-
import { Calendar, CheckCircle2, Clock, Flame, ArrowRight, ListTodo } from 'lucide-react';
4+
import { Calendar, CheckCircle2, ArrowRight, Lightbulb, Target, BrainCircuit } from 'lucide-react';
45
import Badge from '../ui/Badge';
56
import Button from '../ui/Button';
67
import { useNavigate } from 'react-router-dom'
78
import { fetchWeeklyChallenges, transformProblemData } from '../../services/api/questionService'
9+
import { AppContent } from '../../context/userauth/authenticationContext';
810

911
const PLACEHOLDER = [
1012
{ id: 'wc-1', title: 'The Sorting Showdown', description: 'Solve 5 different sorting challenges this week', difficulty: 'Hard', points: 500, completed: 2, total: 5, icon: '📊', color: '#FF6B6B' },
@@ -26,13 +28,29 @@ const getProgressPercentage = (completed, total) => {
2628
};
2729

2830
export default function ChallengesThisWeek() {
29-
const { theme } = useTheme();
31+
useTheme();
32+
const { userData } = useContext(AppContent);
3033
const [hoveredId, setHoveredId] = useState(null);
3134
const [expandedId, setExpandedId] = useState(null);
3235
const [cards, setCards] = useState(PLACEHOLDER);
3336
const [loading, setLoading] = useState(false);
3437
const [error, setError] = useState(null);
3538
const navigate = useNavigate();
39+
const completedQuestionIds = Array.isArray(userData?.completedQuestionIds) ? userData.completedQuestionIds : [];
40+
41+
const isCompletedQuestion = (challenge) => {
42+
const possibleIds = [
43+
challenge?.id,
44+
challenge?.raw?.problemId,
45+
challenge?.raw?._id,
46+
challenge?.transformed?.problemId,
47+
challenge?.transformed?._id
48+
]
49+
.filter(Boolean)
50+
.map((value) => String(value).trim());
51+
52+
return possibleIds.some((id) => completedQuestionIds.includes(id));
53+
};
3654

3755
useEffect(() => {
3856
let mounted = true;
@@ -62,7 +80,7 @@ export default function ChallengesThisWeek() {
6280
points: t.variant?.points || t.points || 300,
6381
completed: it.completed || 0,
6482
total: it.total || 1,
65-
icon: <ListTodo />,
83+
icon: '📊',
6684
color: '#FF6B6B',
6785
raw: it,
6886
transformed: t,
@@ -96,21 +114,23 @@ export default function ChallengesThisWeek() {
96114
Complete challenges throughout the week to earn bonus points and unlock achievements
97115
</p>
98116
</div>
99-
<div className='text-right'>
117+
{/* <div className='text-right'>
100118
<p className='text-sm' style={{ color: 'var(--textSec)' }}>
101119
5 days remaining
102120
</p>
103121
<p className='text-2xl font-bold' style={{ color: 'var(--brand)' }}>
104122
{cards.reduce((acc, c) => acc + (c.completed || 0), 0)}/{cards.reduce((acc, c) => acc + (c.total || 0), 0)}
105123
</p>
106-
</div>
124+
</div> */}
107125
</div>
108126

109127
<div className='grid grid-cols-1 lg:grid-cols-2 gap-6'>
110128
{loading && <div className='text-sm text-gray-300'>Loading challenges…</div>}
111129
{!loading && cards.map((challenge) => {
112-
const progress = getProgressPercentage(challenge.completed || 0, challenge.total || 1);
113-
const isExpanded = expandedId === challenge.id;
130+
const isCompleted = isCompletedQuestion(challenge);
131+
const progress = isCompleted ? 100 : getProgressPercentage(challenge.completed || 0, challenge.total || 1);
132+
const displayCompleted = isCompleted ? (challenge.total || 1) : (challenge.completed || 0);
133+
const hoverAccent = isCompleted ? '#52C882' : (challenge.color || '#FF6B6B');
114134

115135
return (
116136
<div
@@ -123,9 +143,9 @@ export default function ChallengesThisWeek() {
123143
border: '2px solid var(--border)',
124144
boxShadow:
125145
hoveredId === challenge.id
126-
? `0 12px 32px ${challenge.color || '#FF6B6B'}30`
146+
? `0 12px 32px ${hoverAccent}30`
127147
: 'none',
128-
borderColor: hoveredId === challenge.id ? (challenge.color || '#FF6B6B') : 'var(--border)',
148+
borderColor: hoveredId === challenge.id ? hoverAccent : 'var(--border)',
129149
transform: hoveredId === challenge.id ? 'translateY(-4px)' : 'translateY(0)'
130150
}}
131151
onClick={() => {
@@ -139,20 +159,20 @@ export default function ChallengesThisWeek() {
139159
{/* Header */}
140160
<div className='flex items-start justify-between mb-4'>
141161
<div className='flex items-start gap-3 flex-1'>
142-
<span className='text-3xl mt-1'>{challenge.icon}</span>
162+
<span className='text-3xl'>{challenge.icon || '📊'}</span>
143163
<div className='flex-1 min-w-0'>
144164
<h3 className='text-lg font-bold mb-1'>{challenge.title}</h3>
145165
{/* Only show minimal meta on card. Full problem visible in editor. */}
146166
<p style={{ color: 'var(--textSec)' }} className='text-xs'>
147-
{challenge.completed}/{challenge.total} progress
167+
{isCompleted ? 'Completed' : `${displayCompleted}/${challenge.total} progress`}
148168
</p>
149169
</div>
150170
</div>
151-
{progress === 100 && (
152-
<CheckCircle2
153-
className='w-6 h-6 shrink-0 animate-pulse'
154-
style={{ color: '#52C882' }}
155-
/>
171+
{isCompleted && (
172+
<div className='flex items-center gap-1 rounded-full px-2 py-1 text-xs font-semibold' style={{ background: 'rgba(82, 200, 130, 0.14)', color: '#52C882' }}>
173+
<CheckCircle2 className='w-4 h-4 shrink-0' />
174+
Completed
175+
</div>
156176
)}
157177
</div>
158178

@@ -183,7 +203,7 @@ export default function ChallengesThisWeek() {
183203
Progress
184204
</span>
185205
<span className='text-xs font-bold' style={{ color: getProgressColor(progress) }}>
186-
{challenge.completed}/{challenge.total}
206+
{displayCompleted}/{challenge.total}
187207
</span>
188208
</div>
189209
<div
@@ -194,16 +214,17 @@ export default function ChallengesThisWeek() {
194214
className='h-full rounded-full transition-all duration-500'
195215
style={{
196216
width: `${progress}%`,
197-
background: getProgressColor(progress)
217+
background: isCompleted ? '#52C882' : getProgressColor(progress)
198218
}}
199219
/>
200220
</div>
201221
</div>
202222

203223
<Button variant='primary' size='sm' icon={ArrowRight} iconPosition='right' fullWidth style={{
204-
background: getProgressColor(progress),
205-
borderColor: getProgressColor(progress)}}>
206-
{progress === 100 ? 'Completed!' : 'View Challenge'}
224+
background: isCompleted ? '#52C882' : getProgressColor(progress),
225+
borderColor: isCompleted ? '#52C882' : getProgressColor(progress)
226+
}}>
227+
{isCompleted ? 'Completed!' : 'View Challenge'}
207228
</Button>
208229
</div>
209230
</div>
@@ -220,14 +241,14 @@ export default function ChallengesThisWeek() {
220241
border: '1px solid var(--border)'
221242
}}
222243
>
223-
<p style={{ color: 'var(--textSec)' }} className='text-sm mb-2'>
224-
Total Points Available
244+
<p style={{ color: 'var(--textSec)' }} className='text-sm mb-2 flex items-start justify-center gap-2'>
245+
<span style={{ color: 'var(--brand)' }}><Lightbulb /></span> New Concept Focus
225246
</p>
226247
<p
227-
className='text-3xl font-bold'
248+
className='text-lg font-medium'
228249
style={{ color: 'var(--brand)' }}
229250
>
230-
+{cards.reduce((acc, c) => acc + (c.points || 0), 0)}
251+
Master recursion basics through story-driven challenges
231252
</p>
232253
</div>
233254

@@ -238,14 +259,14 @@ export default function ChallengesThisWeek() {
238259
border: '1px solid var(--border)'
239260
}}
240261
>
241-
<p style={{ color: 'var(--textSec)' }} className='text-sm mb-2'>
242-
Completed Challenges
262+
<p style={{ color: 'var(--textSec)' }} className='text-sm mb-2 flex items-start justify-center gap-2'>
263+
<span style={{ color: '#52C882' }}><Target /></span>Challenge Difficulty
243264
</p>
244265
<p
245-
className='text-3xl font-bold'
266+
className='text-lg font-medium'
246267
style={{ color: '#52C882' }}
247268
>
248-
{cards.filter((c) => (c.completed || 0) === (c.total || 0)).length}/{cards.length}
269+
Balanced mix of easy → medium problems
249270
</p>
250271
</div>
251272

@@ -256,14 +277,15 @@ export default function ChallengesThisWeek() {
256277
border: '1px solid var(--border)'
257278
}}
258279
>
259-
<p style={{ color: 'var(--textSec)' }} className='text-sm mb-2'>
260-
Time Remaining
280+
<p style={{ color: 'var(--textSec)' }} className='text-sm mb-2 flex items-start justify-center gap-2'>
281+
<span style={{ color: '#FF6B6B' }}><BrainCircuit /></span>
282+
Skill Focus
261283
</p>
262284
<p
263-
className='text-3xl font-bold flex items-center justify-center gap-2'
285+
className='text-lg font-medium flex items-center justify-center gap-2'
264286
style={{ color: '#FF6B6B' }}
265287
>
266-
<Flame className='w-6 h-6' />5 days
288+
Problem solving + pattern recognition
267289
</p>
268290
</div>
269291
</div>

crackcode/client/src/components/home/DailyChallenge.jsx

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { useState, useEffect, useContext } from 'react';
22
import { useTheme } from '../../context/theme/ThemeContext';
33
import { useNavigate } from 'react-router-dom';
44
import axios from 'axios';
5-
import { Clock, Target, Flame, AlertCircle } from 'lucide-react';
5+
import { Clock, CircleCheck, Flame, AlertCircle } from 'lucide-react';
66
import { AppContent } from '../../context/userauth/authenticationContext';
77
import Button from '../ui/Button';
88

@@ -15,12 +15,13 @@ const formatTime = (seconds) => {
1515
};
1616

1717
export default function DailyChallenge() {
18-
const { theme } = useTheme();
18+
useTheme();
1919
const navigate = useNavigate();
20-
const { backendUrl } = useContext(AppContent);
20+
const { backendUrl, userData } = useContext(AppContent);
2121
const [timeLeft, setTimeLeft] = useState(23 * 3600 + 45 * 60);
2222
const [isHovered, setIsHovered] = useState(false);
2323
const [challenge, setChallenge] = useState(null);
24+
// eslint-disable-next-line no-unused-vars
2425
const [loading, setLoading] = useState(true);
2526

2627
// Fetch daily challenge on mount
@@ -82,6 +83,11 @@ export default function DailyChallenge() {
8283
topic: 'Algorithms'
8384
};
8485

86+
const completedQuestionIds = Array.isArray(userData?.completedQuestionIds) ? userData.completedQuestionIds : [];
87+
const isCompleted = Boolean(
88+
challenge?.problemId && completedQuestionIds.some((id) => String(id).trim() === String(challenge.problemId).trim())
89+
);
90+
8591
return (
8692
<div
8793
className='rounded-lg p-6 transition-all duration-300 relative overflow-hidden'
@@ -98,9 +104,16 @@ export default function DailyChallenge() {
98104
>
99105
{/* Daily Badge */}
100106
<div className='absolute top-4 right-4'>
101-
<div className='flex items-center gap-1 px-3 py-1 rounded-full text-xs font-bold' style={{ background: 'rgba(255, 107, 107, 0.2)', color: '#FF6B6B' }}>
102-
<Flame className='w-3 h-3' />
103-
Daily Quest
107+
<div
108+
className='flex items-center gap-1 px-3 py-1 rounded-full text-xs font-bold'
109+
style={
110+
isCompleted
111+
? { background: 'rgba(82, 200, 130, 0.2)', color: '#52C882' }
112+
: { background: 'rgba(255, 107, 107, 0.2)', color: '#FF6B6B' }
113+
}
114+
>
115+
{isCompleted ? <CircleCheck className='w-3 h-3' /> : <Flame className='w-3 h-3' />}
116+
{isCompleted ? 'Quest Completed' : 'Daily Quest'}
104117
</div>
105118
</div>
106119

@@ -132,7 +145,7 @@ export default function DailyChallenge() {
132145
border: '1px solid rgba(255, 107, 107, 0.4)'
133146
}}
134147
>
135-
<Clock className='w-5 h-5 animate-spin flex-shrink-0' style={{ color: '#FF6B6B', animationDuration: '2s' }} />
148+
<Clock className='w-5 h-5 animate-spin shrink-0' style={{ color: '#FF6B6B', animationDuration: '2s' }} />
136149
<div className='flex-1'>
137150
<p className='text-xs font-semibold uppercase' style={{ color: 'var(--textSec)' }}>
138151
Quest Reset In
@@ -145,9 +158,15 @@ export default function DailyChallenge() {
145158

146159
{/* Note/Info Tip */}
147160
<div className='flex gap-2 p-3 rounded-lg mb-4' style={{ background: 'rgba(82, 200, 130, 0.1)', borderLeft: '3px solid #52c882' }}>
148-
<AlertCircle className='w-4 h-4 flex-shrink-0 mt-0.5' style={{ color: '#52c882' }} />
161+
{isCompleted ? (
162+
<CircleCheck className='w-4 h-4 shrink-0 mt-0.5' style={{ color: '#52c882' }} />
163+
) : (
164+
<AlertCircle className='w-4 h-4 shrink-0 mt-0.5' style={{ color: '#52c882' }} />
165+
)}
149166
<p className='text-xs' style={{ color: '#52c882' }}>
150-
Solve this daily quest to build your streak and unlock achievements!
167+
{isCompleted
168+
? 'Great work. You completed today\'s quest. Revisit it anytime to refine your solution.'
169+
: 'Solve this daily quest to build your streak and unlock achievements!'}
151170
</p>
152171
</div>
153172

@@ -156,11 +175,11 @@ export default function DailyChallenge() {
156175
<Button
157176
variant='primary'
158177
size='md'
159-
icon={Target}
178+
icon={isCompleted ? CircleCheck : AlertCircle}
160179
fullWidth
161180
onClick={handleStartChallenge}
162181
>
163-
Start Challenge
182+
{isCompleted ? 'Revisit Completed Challenge' : 'Start Challenge'}
164183
</Button>
165184
</div>
166185
</div>

crackcode/client/src/components/home/InviteCard.jsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,10 @@ import { Mail, Link, Link2, Copy, CheckCircle2 } from 'lucide-react';
44
import Button from '../ui/Button';
55

66
function InviteCard() {
7+
// eslint-disable-next-line no-unused-vars
78
const { theme } = useTheme()
89
const [copied, setCopied] = useState(false);
910
const inviteLink = 'https://app.crackcodehq.com';
10-
const friendsInvited = 3;
11-
const bonusPoints = 450;
1211

1312
const handleCopy = () => {
1413
navigator.clipboard.writeText(inviteLink);

crackcode/client/src/components/home/LeaderboardCard.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { getGlobalLeaderboard, getMyRank } from '../../services/api/leaderboardS
88

99
export default function LeaderboardCard() {
1010
const navigate = useNavigate();
11-
const { theme } = useTheme();
11+
useTheme();
1212
const { isLoggedIn, backendUrl } = useContext(AppContent);
1313
const [hoveredRank, setHoveredRank] = useState(null);
1414
const [topPlayers, setTopPlayers] = useState([]);

crackcode/client/src/components/home/ProfileCard.jsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { fetchBadgeProgress } from '../../services/api/badgeService';
99

1010
function ProfileCard() {
1111
const navigate = useNavigate();
12-
const { theme } = useTheme();
12+
useTheme();
1313
const { userData, isLoggedIn } = useContext(AppContent);
1414
const [hoveredBadge, setHoveredBadge] = useState(null);
1515
const [badges, setBadges] = useState([]);
@@ -206,8 +206,6 @@ function ProfileCard() {
206206
// Determine tooltip position based on badge position in grid
207207
const isLeftColumn = index % 4 === 0;
208208
const isRightColumn = index % 4 === 3;
209-
const isCenterColumns = !isLeftColumn && !isRightColumn;
210-
const isTopRow = index < 4;
211209
const isBottomRow = index >= 4;
212210

213211
let tooltipPositioning = {

crackcode/client/src/components/home/RecommendedChallenges.jsx

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@ const PLACEHOLDER = [
1313
];
1414

1515
export default function RecommendedChallenges() {
16-
const { theme } = useTheme();
16+
useTheme();
1717
const [hoveredId, setHoveredId] = useState(null);
18-
const [savedIds, setSavedIds] = useState(new Set());
18+
const [savedIds] = useState(new Set());
1919
const [cards, setCards] = useState(PLACEHOLDER);
2020
const [loading, setLoading] = useState(false);
21-
const [error, setError] = useState(null);
21+
const [setError] = useState(null);
2222
const navigate = useNavigate();
2323

2424
useEffect(() => {
@@ -65,16 +65,6 @@ export default function RecommendedChallenges() {
6565
return () => { mounted = false }
6666
}, [])
6767

68-
const toggleSaved = (id, e) => {
69-
e.stopPropagation();
70-
const newSet = new Set(savedIds);
71-
if (newSet.has(id)) {
72-
newSet.delete(id);
73-
} else {
74-
newSet.add(id);
75-
}
76-
setSavedIds(newSet);
77-
};
7868

7969
return (
8070
<div className='w-full' style={{ color: 'var(--text)' }}>
@@ -97,7 +87,7 @@ export default function RecommendedChallenges() {
9787

9888
<div className='grid grid-cols-1 md:grid-cols-3 gap-6'>
9989
{loading && <div className='text-sm text-gray-300'>Loading recommendations…</div>}
100-
{!loading && cards.map((challenge, index) => (
90+
{!loading && cards.map((challenge) => (
10191
<div
10292
key={challenge.id}
10393
onMouseEnter={() => setHoveredId(challenge.id)}

0 commit comments

Comments
 (0)