import React, { useEffect, useState } from 'react';
import { useParams, useNavigate, Link } from 'react-router-dom';
import * as Kubikon3DApi from '../api/Kubikon3DService';
import { KT, KUBIKON_KEYFRAMES, skeletonStyle } from '../utils/kubikonTheme';
import RublocsLogo from '../components/RublocsLogo/RublocsLogo';
import Icon from '../editor/Icon';
/**
* KubikonUserGames — публичный профиль автора со списком его опубликованных игр.
* URL: /user/:userId
*
* Видны опубликованные игры автора (status='published').
* Дизайн в едином wow-стиле Рублокса.
*/
const KubikonUserGames = () => {
const { userId } = useParams();
const navigate = useNavigate();
const [items, setItems] = useState([]);
const [authorName, setAuthorName] = useState('');
const [loading, setLoading] = useState(true);
useEffect(() => {
let active = true;
(async () => {
try {
const res = await Kubikon3DApi.getUserGames(userId);
if (active) {
setItems(res.data?.projects || []);
setAuthorName(res.data?.author_username || '');
setLoading(false);
}
} catch (e) {
if (active) setLoading(false);
}
})();
return () => { active = false; };
}, [userId]);
const totalPlays = items.reduce((s, p) => s + (p.play_count || 0), 0);
const totalLikes = items.reduce((s, p) => s + (p.likes_count || 0), 0);
const initial = (authorName || '?').slice(0, 1).toUpperCase();
return (
{/* Sticky glass header */}
{/* Hero — большая аватарка + имя + статистика */}
{/* Floating shapes */}
{/* Avatar */}
{initial}
Профиль автора
{authorName || `Игрок #${userId}`}
{/* Статистика */}
= 2 && items.length <= 4) ? 'игры' : 'игр'
} />
{/* Список игр — overlap с hero */}
{loading ? (
) : items.length === 0 ? (
Пока нет опубликованных игр
У этого автора скоро здесь что-то появится
) : (
{items.map((p, i) => (
navigate(`/game/${p.id}`)}
animateDelay={Math.min(i * 35, 600)}
/>
))}
)}
);
};
const StatPill = ({ icon, value, label }) => (
{value}
{label}
);
const FloatingShapes = () => (
<>
>
);
const GameCard = ({ project, onClick, animateDelay = 0 }) => {
const [hovered, setHovered] = useState(false);
const p = project;
return (
{ if (e.key === 'Enter') onClick(); }}
onMouseEnter={() => setHovered(true)}
onMouseLeave={() => setHovered(false)}
style={{
background: KT.bgPage,
border: `1px solid ${hovered ? KT.accent : KT.border}`,
borderRadius: KT.radiusLg,
boxShadow: hovered ? KT.shadowLg : KT.shadow,
transform: hovered ? 'translateY(-6px)' : 'translateY(0)',
transition: 'all 280ms cubic-bezier(0.34, 1.56, 0.64, 1)',
cursor: 'pointer',
overflow: 'hidden',
animation: `kubikonFadeIn 460ms cubic-bezier(0.34, 1.56, 0.64, 1) ${animateDelay}ms both`,
}}
>
{p.thumbnail ? (

) : (
)}
{/* Умная лента: бейджа «ранг» больше нет — все опубликованные
игры равны, их позицию определяет алгоритм в ленте. */}
{p.age_rating || 12}+
{p.title}
{(p.play_count || 0).toLocaleString('ru')}
{(p.likes_count || 0).toLocaleString('ru')}
);
};
const SkeletonGrid = () => (
{Array.from({ length: 6 }).map((_, i) => (
))}
);
export default KubikonUserGames;