2026-01-07 09:31:02 +00:00
|
|
|
import React, { useState, useEffect } from 'react';
|
|
|
|
|
import { Card } from '../ui/card';
|
|
|
|
|
import { Button } from '../ui/button';
|
|
|
|
|
import { XPBar } from './XPBar';
|
|
|
|
|
import { AchievementCard } from './AchievementCard';
|
|
|
|
|
import { TrendingUp, Target, Crown, Zap, Loader2 } from 'lucide-react';
|
|
|
|
|
import { Achievement } from '../../types';
|
|
|
|
|
import { gamificationService } from '../../services/gamificationService';
|
|
|
|
|
import { logger } from '@/utils/logger';
|
|
|
|
|
|
|
|
|
|
interface ProfileXPViewProps {
|
2026-01-13 18:47:57 +00:00
|
|
|
username: string;
|
2026-01-07 09:31:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const ProfileXPView: React.FC<ProfileXPViewProps> = ({ username }) => {
|
|
|
|
|
const [xpData, setXpData] = useState<any>(null);
|
2026-01-13 18:47:57 +00:00
|
|
|
const [recentAchievements, setRecentAchievements] = useState<Achievement[]>(
|
|
|
|
|
[],
|
|
|
|
|
);
|
2026-01-07 09:31:02 +00:00
|
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
2026-01-13 18:47:57 +00:00
|
|
|
const fetchData = async () => {
|
|
|
|
|
setLoading(true);
|
|
|
|
|
try {
|
|
|
|
|
const [xp, achievements] = await Promise.all([
|
|
|
|
|
gamificationService.getUserXP('me'),
|
|
|
|
|
gamificationService.getAchievements('me'),
|
|
|
|
|
]);
|
|
|
|
|
setXpData(xp);
|
|
|
|
|
setRecentAchievements(achievements.slice(0, 3));
|
|
|
|
|
} catch (e) {
|
|
|
|
|
logger.error('Error loading profile XP data', {
|
|
|
|
|
error: e instanceof Error ? e.message : String(e),
|
|
|
|
|
stack: e instanceof Error ? e.stack : undefined,
|
|
|
|
|
username,
|
|
|
|
|
});
|
|
|
|
|
} finally {
|
|
|
|
|
setLoading(false);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
fetchData();
|
2026-01-07 09:31:02 +00:00
|
|
|
}, []);
|
|
|
|
|
|
2026-01-13 18:47:57 +00:00
|
|
|
if (loading)
|
|
|
|
|
return (
|
aesthetic-improvements: align spacing to 8px grid (Action 11.2.1.3)
- Created automated script (scripts/align-8px-grid.py) to align all spacing to 8px grid
- Replaced non-8px-aligned spacing: gap-3/p-3/m-3 (12px) → gap-4/p-4/m-4 (16px), gap-5/p-5/m-5 (20px) → gap-6/p-6/m-6 (24px), gap-10/p-10/m-10 (40px) → gap-12/p-12/m-12 (48px), gap-20/p-20/m-20 (80px) → gap-24/p-24/m-24 (96px)
- Preserved: 4px values (gap-1, p-1, m-1) as they may be intentional fine-tuning, responsive breakpoints (sm:, md:, lg:), test files, documentation
- Modified files across all components to ensure consistent 8px grid alignment
- Action 11.2.1.3: Align all elements to 8px grid - COMPLETE
2026-01-16 10:50:46 +00:00
|
|
|
<div className="flex justify-center py-24">
|
aesthetic-improvements: reduce decorative cyan in marketplace, gamification, commerce, and education (80/20 rule, batch 10)
- Marketplace: LicenceDetailsModal decorative icon and price text, ProductDetailView decorative author text, ReviewProductModal decorative icon, LicenceCard decorative price text (4 instances)
- Gamification: AchievementCard decorative XP reward text, LeaderboardView loading spinner and decorative XP text, ProfileXPView loading spinner and decorative icons, AchievementsView loading spinner (5 instances)
- Commerce: WishlistView decorative price text, PromoCodeModal decorative icon, CartItem decorative license tag icon, OrderSummary decorative total price text (4 instances)
- Education: MyCoursesView decorative icon (1 instance)
- Total: ~14 files, ~14 instances replaced
- Preserved: Functional links (LicenceDetailsModal legal contract link), active/selected states (CourseLearningView active lesson, QuizModal selected answer - already preserved), primary actions, design system variants
- Action 11.3.1.3 in progress (tenth batch: marketplace, gamification, commerce, and education components)
2026-01-16 10:23:25 +00:00
|
|
|
<Loader2 className="w-10 h-10 text-kodo-steel animate-spin" />
|
2026-01-13 18:47:57 +00:00
|
|
|
</div>
|
|
|
|
|
);
|
2026-01-07 09:31:02 +00:00
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className="space-y-8 animate-fadeIn pb-20">
|
2026-01-15 22:54:05 +00:00
|
|
|
<h2 className="text-2xl font-display font-bold text-white mb-6">
|
2026-01-13 18:47:57 +00:00
|
|
|
LEVEL & PROGRESS
|
|
|
|
|
</h2>
|
2026-01-07 09:31:02 +00:00
|
|
|
|
2026-01-13 18:47:57 +00:00
|
|
|
{/* Main XP Card */}
|
|
|
|
|
<Card
|
2026-01-26 13:12:17 +00:00
|
|
|
variant="glass"
|
2026-01-13 18:47:57 +00:00
|
|
|
className="p-8 relative overflow-hidden border-kodo-gold/30"
|
|
|
|
|
>
|
|
|
|
|
<div className="relative z-10 flex flex-col md:flex-row items-center gap-8">
|
|
|
|
|
{/* Level Badge */}
|
|
|
|
|
<div className="flex flex-col items-center justify-center">
|
|
|
|
|
<div className="w-24 h-24 bg-gradient-to-b from-kodo-gold to-orange-600 rounded-full flex items-center justify-center shadow-[0_0_30px_rgba(234,179,8,0.4)] border-4 border-black">
|
|
|
|
|
<div className="text-4xl font-black text-black">
|
|
|
|
|
{xpData.level}
|
|
|
|
|
</div>
|
2026-01-07 09:31:02 +00:00
|
|
|
</div>
|
2026-01-13 18:47:57 +00:00
|
|
|
<div className="mt-2 text-kodo-gold font-bold uppercase tracking-widest text-sm">
|
|
|
|
|
Level
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
2026-01-07 09:31:02 +00:00
|
|
|
|
2026-01-13 18:47:57 +00:00
|
|
|
{/* Progress */}
|
|
|
|
|
<div className="flex-1 w-full space-y-4">
|
|
|
|
|
<div className="flex justify-between items-end">
|
|
|
|
|
<div>
|
|
|
|
|
<h3 className="text-2xl font-bold text-white">{username}</h3>
|
2026-01-16 00:59:31 +00:00
|
|
|
<p className="text-kodo-content-dim text-sm">
|
2026-01-13 18:47:57 +00:00
|
|
|
Producer • Rank #{xpData.rank}
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="text-right">
|
|
|
|
|
<div className="text-2xl font-mono font-bold text-kodo-gold">
|
|
|
|
|
{xpData.current} XP
|
2026-01-07 09:31:02 +00:00
|
|
|
</div>
|
2026-01-16 00:59:31 +00:00
|
|
|
<div className="text-xs text-kodo-content-dim">
|
2026-01-13 18:47:57 +00:00
|
|
|
Next Level: {xpData.next} XP
|
2026-01-07 09:31:02 +00:00
|
|
|
</div>
|
2026-01-13 18:47:57 +00:00
|
|
|
</div>
|
2026-01-07 09:31:02 +00:00
|
|
|
</div>
|
2026-01-13 18:47:57 +00:00
|
|
|
|
|
|
|
|
<XPBar
|
|
|
|
|
currentXP={xpData.current}
|
|
|
|
|
nextLevelXP={xpData.next}
|
|
|
|
|
level={xpData.level}
|
|
|
|
|
size="lg"
|
|
|
|
|
showLabels={false}
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
<div className="flex gap-4 pt-2">
|
aesthetic-improvements: align spacing to 8px grid (Action 11.2.1.3)
- Created automated script (scripts/align-8px-grid.py) to align all spacing to 8px grid
- Replaced non-8px-aligned spacing: gap-3/p-3/m-3 (12px) → gap-4/p-4/m-4 (16px), gap-5/p-5/m-5 (20px) → gap-6/p-6/m-6 (24px), gap-10/p-10/m-10 (40px) → gap-12/p-12/m-12 (48px), gap-20/p-20/m-20 (80px) → gap-24/p-24/m-24 (96px)
- Preserved: 4px values (gap-1, p-1, m-1) as they may be intentional fine-tuning, responsive breakpoints (sm:, md:, lg:), test files, documentation
- Modified files across all components to ensure consistent 8px grid alignment
- Action 11.2.1.3: Align all elements to 8px grid - COMPLETE
2026-01-16 10:50:46 +00:00
|
|
|
<div className="bg-black/30 px-4 py-1 rounded text-xs text-kodo-content-dim">
|
2026-01-13 18:47:57 +00:00
|
|
|
<span className="text-white font-bold">
|
|
|
|
|
{xpData.totalEarned.toLocaleString()}
|
|
|
|
|
</span>{' '}
|
|
|
|
|
Total Lifetime XP
|
|
|
|
|
</div>
|
aesthetic-improvements: align spacing to 8px grid (Action 11.2.1.3)
- Created automated script (scripts/align-8px-grid.py) to align all spacing to 8px grid
- Replaced non-8px-aligned spacing: gap-3/p-3/m-3 (12px) → gap-4/p-4/m-4 (16px), gap-5/p-5/m-5 (20px) → gap-6/p-6/m-6 (24px), gap-10/p-10/m-10 (40px) → gap-12/p-12/m-12 (48px), gap-20/p-20/m-20 (80px) → gap-24/p-24/m-24 (96px)
- Preserved: 4px values (gap-1, p-1, m-1) as they may be intentional fine-tuning, responsive breakpoints (sm:, md:, lg:), test files, documentation
- Modified files across all components to ensure consistent 8px grid alignment
- Action 11.2.1.3: Align all elements to 8px grid - COMPLETE
2026-01-16 10:50:46 +00:00
|
|
|
<div className="bg-black/30 px-4 py-1 rounded text-xs text-kodo-content-dim">
|
2026-01-13 18:47:57 +00:00
|
|
|
<span className="text-kodo-lime font-bold">+12%</span> vs Last
|
|
|
|
|
Week
|
|
|
|
|
</div>
|
2026-01-07 09:31:02 +00:00
|
|
|
</div>
|
2026-01-13 18:47:57 +00:00
|
|
|
</div>
|
2026-01-07 09:31:02 +00:00
|
|
|
</div>
|
2026-01-13 18:47:57 +00:00
|
|
|
</Card>
|
2026-01-07 09:31:02 +00:00
|
|
|
|
2026-01-13 18:47:57 +00:00
|
|
|
{/* Stats Grid */}
|
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
|
|
|
|
<Card variant="default" className="flex items-center gap-4 p-4">
|
|
|
|
|
<div className="w-12 h-12 bg-kodo-ink rounded-lg flex items-center justify-center text-kodo-gold">
|
|
|
|
|
<Crown className="w-6 h-6" />
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
2026-01-16 00:59:31 +00:00
|
|
|
<div className="text-xs text-kodo-content-dim uppercase font-bold">
|
2026-01-13 18:47:57 +00:00
|
|
|
Global Rank
|
|
|
|
|
</div>
|
|
|
|
|
<div className="text-xl font-bold text-white">#{xpData.rank}</div>
|
|
|
|
|
</div>
|
|
|
|
|
</Card>
|
|
|
|
|
<Card variant="default" className="flex items-center gap-4 p-4">
|
aesthetic-improvements: reduce decorative cyan in marketplace, gamification, commerce, and education (80/20 rule, batch 10)
- Marketplace: LicenceDetailsModal decorative icon and price text, ProductDetailView decorative author text, ReviewProductModal decorative icon, LicenceCard decorative price text (4 instances)
- Gamification: AchievementCard decorative XP reward text, LeaderboardView loading spinner and decorative XP text, ProfileXPView loading spinner and decorative icons, AchievementsView loading spinner (5 instances)
- Commerce: WishlistView decorative price text, PromoCodeModal decorative icon, CartItem decorative license tag icon, OrderSummary decorative total price text (4 instances)
- Education: MyCoursesView decorative icon (1 instance)
- Total: ~14 files, ~14 instances replaced
- Preserved: Functional links (LicenceDetailsModal legal contract link), active/selected states (CourseLearningView active lesson, QuizModal selected answer - already preserved), primary actions, design system variants
- Action 11.3.1.3 in progress (tenth batch: marketplace, gamification, commerce, and education components)
2026-01-16 10:23:25 +00:00
|
|
|
<div className="w-12 h-12 bg-kodo-ink rounded-lg flex items-center justify-center text-kodo-steel">
|
2026-01-13 18:47:57 +00:00
|
|
|
<Zap className="w-6 h-6" />
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
2026-01-16 00:59:31 +00:00
|
|
|
<div className="text-xs text-kodo-content-dim uppercase font-bold">
|
2026-01-13 18:47:57 +00:00
|
|
|
Daily Streak
|
2026-01-07 09:31:02 +00:00
|
|
|
</div>
|
2026-01-13 18:47:57 +00:00
|
|
|
<div className="text-xl font-bold text-white">12 Days</div>
|
|
|
|
|
</div>
|
|
|
|
|
</Card>
|
|
|
|
|
<Card variant="default" className="flex items-center gap-4 p-4">
|
|
|
|
|
<div className="w-12 h-12 bg-kodo-ink rounded-lg flex items-center justify-center text-kodo-magenta">
|
|
|
|
|
<Target className="w-6 h-6" />
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
2026-01-16 00:59:31 +00:00
|
|
|
<div className="text-xs text-kodo-content-dim uppercase font-bold">
|
2026-01-13 18:47:57 +00:00
|
|
|
Quests Complete
|
2026-01-07 09:31:02 +00:00
|
|
|
</div>
|
2026-01-13 18:47:57 +00:00
|
|
|
<div className="text-xl font-bold text-white">8/10</div>
|
|
|
|
|
</div>
|
2026-01-07 09:31:02 +00:00
|
|
|
</Card>
|
2026-01-13 18:47:57 +00:00
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* Recent Achievements */}
|
|
|
|
|
<div>
|
|
|
|
|
<div className="flex justify-between items-center mb-4">
|
|
|
|
|
<h3 className="font-bold text-white">Recent Achievements</h3>
|
|
|
|
|
<Button variant="ghost" size="sm">
|
|
|
|
|
View All
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
|
|
|
|
{recentAchievements.map((ach) => (
|
|
|
|
|
<AchievementCard key={ach.id} achievement={ach} />
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* XP History Graph (Mock) */}
|
|
|
|
|
<Card variant="default">
|
|
|
|
|
<h3 className="font-bold text-white mb-6 flex items-center gap-2">
|
aesthetic-improvements: reduce decorative cyan in marketplace, gamification, commerce, and education (80/20 rule, batch 10)
- Marketplace: LicenceDetailsModal decorative icon and price text, ProductDetailView decorative author text, ReviewProductModal decorative icon, LicenceCard decorative price text (4 instances)
- Gamification: AchievementCard decorative XP reward text, LeaderboardView loading spinner and decorative XP text, ProfileXPView loading spinner and decorative icons, AchievementsView loading spinner (5 instances)
- Commerce: WishlistView decorative price text, PromoCodeModal decorative icon, CartItem decorative license tag icon, OrderSummary decorative total price text (4 instances)
- Education: MyCoursesView decorative icon (1 instance)
- Total: ~14 files, ~14 instances replaced
- Preserved: Functional links (LicenceDetailsModal legal contract link), active/selected states (CourseLearningView active lesson, QuizModal selected answer - already preserved), primary actions, design system variants
- Action 11.3.1.3 in progress (tenth batch: marketplace, gamification, commerce, and education components)
2026-01-16 10:23:25 +00:00
|
|
|
<TrendingUp className="w-5 h-5 text-kodo-steel" /> XP History
|
2026-01-13 18:47:57 +00:00
|
|
|
</h3>
|
|
|
|
|
<div className="h-48 flex items-end gap-2 px-2">
|
|
|
|
|
{Array.from({ length: 14 }).map((_, i) => (
|
|
|
|
|
<div
|
|
|
|
|
key={i}
|
|
|
|
|
className="flex-1 flex flex-col justify-end gap-1 h-full group relative cursor-pointer"
|
|
|
|
|
>
|
|
|
|
|
<div
|
|
|
|
|
className="w-full bg-kodo-gold rounded-t opacity-50 group-hover:opacity-100 transition-opacity"
|
|
|
|
|
style={{ height: `${Math.random() * 60 + 10}%` }}
|
|
|
|
|
></div>
|
|
|
|
|
<div className="absolute -top-8 left-1/2 -translate-x-1/2 bg-black text-white text-xs px-2 py-1 rounded opacity-0 group-hover:opacity-100 pointer-events-none whitespace-nowrap">
|
|
|
|
|
+{Math.floor(Math.random() * 500)} XP
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
2026-01-16 00:59:31 +00:00
|
|
|
<div className="flex justify-between text-xs text-kodo-content-dim mt-2">
|
2026-01-13 18:47:57 +00:00
|
|
|
<span>14 Days Ago</span>
|
|
|
|
|
<span>Today</span>
|
|
|
|
|
</div>
|
|
|
|
|
</Card>
|
2026-01-07 09:31:02 +00:00
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
};
|