From d9aeeaaab8e8aedff6447d5b27b41860a69521eb Mon Sep 17 00:00:00 2001 From: Nils Pukropp Date: Mon, 16 Feb 2026 16:50:07 +0100 Subject: [PATCH] added tiers to profile pages --- frontend/src/pages/PublicProfile.tsx | 210 ++++++++++++++++----------- 1 file changed, 126 insertions(+), 84 deletions(-) diff --git a/frontend/src/pages/PublicProfile.tsx b/frontend/src/pages/PublicProfile.tsx index 674e3e1..91a0237 100644 --- a/frontend/src/pages/PublicProfile.tsx +++ b/frontend/src/pages/PublicProfile.tsx @@ -5,11 +5,14 @@ import { Box, Card, CardContent, - Avatar, - Chip, - Container, - CircularProgress, - Tooltip + Avatar, + Container, + CircularProgress, + Tooltip, + Tabs, + Tab, + Paper, + Divider } from '@mui/material'; import { Link } from 'react-router-dom'; import api from '../api'; @@ -20,6 +23,7 @@ interface Rating { flavor: number; flavor_name: string; flavor_image: string | null; + category_name: string; score: number; comment: string; created_at: string; @@ -36,6 +40,7 @@ const PublicProfile: React.FC = () => { const { username } = useParams<{ username: string }>(); const [data, setData] = useState(null); const [loading, setLoading] = useState(true); + const [activeTab, setActiveTab] = useState(0); useEffect(() => { const fetchProfile = async () => { @@ -56,99 +61,136 @@ const PublicProfile: React.FC = () => { if (loading) return ; if (!data) return Profile not found.; - const favorites = data.ratings.filter(r => r.score >= 8); - const others = data.ratings.filter(r => r.score < 8); + // Group by category + const categoryGroups = data.ratings.reduce((acc: any, rating) => { + const cat = rating.category_name || 'Other'; + if (!acc[cat]) acc[cat] = []; + acc[cat].push(rating); + return acc; + }, {}); - const RatingGrid = ({ ratings, title, chip }: { ratings: Rating[], title: string, chip?: React.ReactNode }) => ( - - - {title} {chip} - - - {ratings.map(rating => ( - - - - - - - {rating.score}/10 - - - - - {rating.flavor_name} - - - - - - ))} - - - ); + const categories = ['All', ...Object.keys(categoryGroups)]; + const currentRatings = activeTab === 0 ? data.ratings : categoryGroups[categories[activeTab]]; + + // Tier logic + const getTier = (score: number) => { + if (score >= 9) return { label: 'S', color: '#ff7f7f', desc: 'Elite' }; + if (score >= 7) return { label: 'A', color: '#ffbf7f', desc: 'Great' }; + if (score >= 5) return { label: 'B', color: '#ffff7f', desc: 'Good' }; + if (score >= 3) return { label: 'C', color: '#bfff7f', desc: 'Okay' }; + return { label: 'D', color: '#7fff7f', desc: 'Avoid' }; + }; + + const tiers = [ + { key: 'S', title: 'S-Tier', min: 9 }, + { key: 'A', title: 'A-Tier', min: 7 }, + { key: 'B', title: 'B-Tier', min: 5 }, + { key: 'C', title: 'C-Tier', min: 3 }, + { key: 'D', title: 'D-Tier', min: 0 }, + ]; return ( - + {/* Profile Header */} + {!data.avatar && data.username.charAt(0).toUpperCase()} - {data.username} + {data.username} - Taste Profile • {data.ratings.length} Flavors + Taste Profile • {data.ratings.length} Flavors Rated - {favorites.length > 0 && ( - } - /> - )} + {/* Category Tabs */} + + setActiveTab(v)} + variant="scrollable" + scrollButtons="auto" + > + {categories.map((cat) => ( + + ))} + + - {others.length > 0 && ( - - )} + {/* Tiered Content */} + + {tiers.map(tier => { + const items = currentRatings.filter((r: Rating) => { + const s = r.score; + if (tier.key === 'S') return s >= 9; + if (tier.key === 'A') return s >= 7 && s < 9; + if (tier.key === 'B') return s >= 5 && s < 7; + if (tier.key === 'C') return s >= 3 && s < 5; + return s < 3; + }); + + if (items.length === 0) return null; + + return ( + + + + {tier.key} + + {tier.title} + + + + + {items.map((rating: Rating) => ( + + + + + + + {rating.score}/10 + + + + + {rating.flavor_name} + + + + + + ))} + + + ); + })} + ); };