From 025e52e6b1903f762eb02c7b39b5a9b1b3101578 Mon Sep 17 00:00:00 2001 From: HeagBoKaT Date: Fri, 29 May 2026 14:21:40 +0300 Subject: [PATCH] Fix likes display, add avatar system (presets+upload), improve desktop layout, fix profile viewing --- client/src/api/endpoints.ts | 21 +++++ client/src/components/CatCard.tsx | 13 ++- client/src/components/CatModal.tsx | 20 +---- client/src/components/FeedSidebar.tsx | 18 ++-- client/src/components/Navbar.tsx | 12 +-- client/src/components/UserAvatar.tsx | 39 +++++++++ client/src/lib/auth.ts | 1 + client/src/lib/avatars.ts | 16 ++++ client/src/pages/CatPage.tsx | 23 ++---- client/src/pages/FeedPage.tsx | 29 +++++-- client/src/pages/ProfilePage.tsx | 115 ++++++++++++++++++++++---- client/tsconfig.tsbuildinfo | 2 +- server/src/db.ts | 1 + server/src/index.ts | 2 + server/src/routes/admin.ts | 2 +- server/src/routes/auth.ts | 73 ++++++++++++++-- server/src/routes/cats.ts | 8 +- server/src/routes/likes.ts | 19 ++++- server/src/routes/users.ts | 26 ++++++ 19 files changed, 346 insertions(+), 94 deletions(-) create mode 100644 client/src/components/UserAvatar.tsx create mode 100644 client/src/lib/avatars.ts create mode 100644 server/src/routes/users.ts diff --git a/client/src/api/endpoints.ts b/client/src/api/endpoints.ts index 1e8eb46..cdbf6ad 100644 --- a/client/src/api/endpoints.ts +++ b/client/src/api/endpoints.ts @@ -9,6 +9,7 @@ export interface Cat { user_id: number; username: string; user_points: number; + user_avatar_url: string | null; likes_count: number; comments_count: number; } @@ -72,6 +73,10 @@ export function getLikeStatus(catId: number) { return api.get<{ liked: boolean }>(`/likes/${catId}/status`); } +export function getBatchLikeStatus(catIds: number[]) { + return api.post<{ likedIds: number[] }>('/likes/batch/status', { catIds }); +} + // Admin export function getAdminUsers() { return api.get<{ users: User[] }>('/admin/users'); @@ -109,3 +114,19 @@ export function addComment(catId: number, text: string) { export function deleteComment(commentId: number) { return api.delete(`/comments/${commentId}`); } + +// Users +export function getUser(id: number) { + return api.get<{ user: User }>(`/users/${id}`); +} + +// Avatar +export function uploadAvatar(formData: FormData) { + return api.put<{ user: User }>('/auth/avatar', formData, { + headers: { 'Content-Type': 'multipart/form-data' }, + }); +} + +export function setAvatarPreset(preset: string) { + return api.put<{ user: User }>('/auth/avatar/preset', { preset }); +} diff --git a/client/src/components/CatCard.tsx b/client/src/components/CatCard.tsx index db4826d..0934d6e 100644 --- a/client/src/components/CatCard.tsx +++ b/client/src/components/CatCard.tsx @@ -3,17 +3,18 @@ import { Cat } from '@/api/endpoints'; import { useAuth } from '@/hooks/useAuth'; import { useLikeCat, useUnlikeCat } from '@/hooks/useLikes'; import { useToast } from '@/components/Toast'; -import { Avatar, AvatarFallback } from '@/components/ui/avatar'; +import UserAvatar from '@/components/UserAvatar'; import { Heart, MessageCircle, Trophy } from 'lucide-react'; interface CatCardProps { cat: Cat; onOpen: (id: number) => void; + likedIds?: Set; } -export default function CatCard({ cat, onOpen }: CatCardProps) { +export default function CatCard({ cat, onOpen, likedIds }: CatCardProps) { const { user } = useAuth(); - const [liked, setLiked] = useState(false); + const [liked, setLiked] = useState(() => likedIds?.has(cat.id) ?? false); const [likeCount, setLikeCount] = useState(cat.likes_count); const { toast } = useToast(); const likeMutation = useLikeCat(cat.id); @@ -43,11 +44,7 @@ export default function CatCard({ cat, onOpen }: CatCardProps) {
onOpen(cat.id)}>
- - - {cat.username.charAt(0).toUpperCase()} - - +

@{cat.username}

diff --git a/client/src/components/CatModal.tsx b/client/src/components/CatModal.tsx index 8c0f165..0bba412 100644 --- a/client/src/components/CatModal.tsx +++ b/client/src/components/CatModal.tsx @@ -4,7 +4,7 @@ import { useLikeStatus, useLikeCat, useUnlikeCat } from '@/hooks/useLikes'; import { useComments, useAddComment, useDeleteComment } from '@/hooks/useComments'; import { useAuth } from '@/hooks/useAuth'; import { useToast } from '@/components/Toast'; -import { Avatar, AvatarFallback } from '@/components/ui/avatar'; +import UserAvatar from '@/components/UserAvatar'; import { X, Heart, Trash2, Trophy, Send } from 'lucide-react'; interface CatModalProps { @@ -116,11 +116,7 @@ export default function CatModal({ catId, onClose }: CatModalProps) { >
- - - {cat.username.charAt(0).toUpperCase()} - - +
@{cat.username}

{dateStr}

@@ -155,11 +151,7 @@ export default function CatModal({ catId, onClose }: CatModalProps) {
{cat.caption && (
- - - {cat.username.charAt(0).toUpperCase()} - - +

@{cat.username} {cat.caption} @@ -171,11 +163,7 @@ export default function CatModal({ catId, onClose }: CatModalProps) {

{comments.map(c => (
- - - {c.username.charAt(0).toUpperCase()} - - +

@{c.username} diff --git a/client/src/components/FeedSidebar.tsx b/client/src/components/FeedSidebar.tsx index b042b41..e319645 100644 --- a/client/src/components/FeedSidebar.tsx +++ b/client/src/components/FeedSidebar.tsx @@ -1,6 +1,6 @@ import { useAuth } from '@/hooks/useAuth'; import { useCats } from '@/hooks/useCats'; -import { Avatar, AvatarFallback } from '@/components/ui/avatar'; +import UserAvatar from '@/components/UserAvatar'; import { Link } from 'react-router-dom'; import { Trophy, Crown, Medal } from 'lucide-react'; @@ -15,11 +15,11 @@ export default function FeedSidebar() { const { user } = useAuth(); const { data } = useCats(1); - const usersMap = new Map(); + const usersMap = new Map(); if (data?.cats) { for (const cat of data.cats) { if (!usersMap.has(cat.user_id)) - usersMap.set(cat.user_id, { username: cat.username, points: cat.user_points }); + usersMap.set(cat.user_id, { username: cat.username, points: cat.user_points, avatar_url: cat.user_avatar_url }); } } @@ -31,11 +31,7 @@ export default function FeedSidebar() {

{user && ( - - - {user.username.charAt(0).toUpperCase()} - - +

{user.username}

@@ -57,11 +53,7 @@ export default function FeedSidebar() { {topUsers.map(([id, u], i) => ( - - - {u.username.charAt(0).toUpperCase()} - - + {u.username} {u.points} diff --git a/client/src/components/Navbar.tsx b/client/src/components/Navbar.tsx index a7feba1..ccb354a 100644 --- a/client/src/components/Navbar.tsx +++ b/client/src/components/Navbar.tsx @@ -1,7 +1,7 @@ import { Link, useLocation } from 'react-router-dom'; import { useAuth } from '@/hooks/useAuth'; -import { Avatar, AvatarFallback } from '@/components/ui/avatar'; -import { Home, PlusCircle, User, Shield } from 'lucide-react'; +import UserAvatar from '@/components/UserAvatar'; +import { Home, PlusCircle, Shield } from 'lucide-react'; export default function Navbar() { const { user } = useAuth(); @@ -11,7 +11,7 @@ export default function Navbar() { return (