Fix mobile scroll jump, add comments, rename to Котограм
This commit is contained in:
@@ -1,13 +1,14 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useState, useEffect, useRef } from 'react';
|
||||
import { useParams, useNavigate, Link } from 'react-router-dom';
|
||||
import { useCat, useDeleteCat } from '@/hooks/useCats';
|
||||
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 { Button } from '@/components/ui/button';
|
||||
import { Avatar, AvatarFallback } from '@/components/ui/avatar';
|
||||
import { Skeleton } from '@/components/ui/skeleton';
|
||||
import { ArrowLeft, Heart, Trash2, Trophy, Image } from 'lucide-react';
|
||||
import { ArrowLeft, Heart, Trash2, Trophy, Image, Send, X } from 'lucide-react';
|
||||
|
||||
export default function CatPage() {
|
||||
const { id } = useParams<{ id: string }>();
|
||||
@@ -21,10 +22,16 @@ export default function CatPage() {
|
||||
const likeMutation = useLikeCat(catId);
|
||||
const unlikeMutation = useUnlikeCat(catId);
|
||||
const deleteMutation = useDeleteCat();
|
||||
const { data: commentsData } = useComments(catId);
|
||||
const addCommentMutation = useAddComment(catId);
|
||||
const deleteCommentMutation = useDeleteComment(catId);
|
||||
|
||||
const [liked, setLiked] = useState(false);
|
||||
const [imageLoaded, setImageLoaded] = useState(false);
|
||||
const [commentText, setCommentText] = useState('');
|
||||
const commentsEndRef = useRef<HTMLDivElement>(null);
|
||||
const cat = data?.cat;
|
||||
const comments = commentsData?.comments ?? [];
|
||||
const isOwner = cat && user && cat.user_id === user.id;
|
||||
const isLiked = likeData?.liked ?? false;
|
||||
|
||||
@@ -50,6 +57,21 @@ export default function CatPage() {
|
||||
catch { toast('Ошибка удаления', 'error'); }
|
||||
};
|
||||
|
||||
const handleComment = async () => {
|
||||
const text = commentText.trim();
|
||||
if (!text || !user) return;
|
||||
try {
|
||||
await addCommentMutation.mutateAsync(text);
|
||||
setCommentText('');
|
||||
setTimeout(() => commentsEndRef.current?.scrollIntoView({ behavior: 'smooth' }), 100);
|
||||
} catch { toast('Ошибка', 'error'); }
|
||||
};
|
||||
|
||||
const handleDeleteComment = async (commentId: number) => {
|
||||
try { await deleteCommentMutation.mutateAsync(commentId); }
|
||||
catch { toast('Ошибка', 'error'); }
|
||||
};
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
<div className="mx-auto max-w-[520px] px-5 py-8">
|
||||
@@ -141,6 +163,61 @@ export default function CatPage() {
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{comments.length > 0 && (
|
||||
<div className="space-y-3">
|
||||
<p className="text-[11px] font-bold text-[var(--fg-tertiary)] uppercase tracking-widest">
|
||||
Комментарии · {comments.length}
|
||||
</p>
|
||||
{comments.map(c => (
|
||||
<div key={c.id} className="flex items-start gap-2.5 group">
|
||||
<Avatar className="h-7 w-7 shrink-0 mt-0.5">
|
||||
<AvatarFallback className="text-[9px] avatar-colored bg-[var(--fg-tertiary)]">
|
||||
{c.username.charAt(0).toUpperCase()}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
<div className="flex-1 min-w-0">
|
||||
<p className="text-sm leading-[1.5]">
|
||||
<span className="font-semibold mr-1">@{c.username}</span>
|
||||
{c.text}
|
||||
</p>
|
||||
<p className="text-[10px] text-[var(--fg-tertiary)] mt-0.5">
|
||||
{new Date(c.created_at).toLocaleDateString('ru-RU', { day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit' })}
|
||||
</p>
|
||||
</div>
|
||||
{(user && (c.user_id === user.id || user.is_admin)) && (
|
||||
<button
|
||||
onClick={() => handleDeleteComment(c.id)}
|
||||
className="btn-ghost h-6 w-6 text-[var(--fg-tertiary)] hover:text-red-500 opacity-0 group-hover:opacity-100 transition-opacity shrink-0"
|
||||
>
|
||||
<X className="h-3 w-3" strokeWidth={2} />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
<div ref={commentsEndRef} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{user && (
|
||||
<form onSubmit={e => { e.preventDefault(); handleComment(); }} className="flex items-center gap-2">
|
||||
<input
|
||||
type="text"
|
||||
value={commentText}
|
||||
onChange={e => setCommentText(e.target.value)}
|
||||
placeholder="Написать комментарий..."
|
||||
maxLength={500}
|
||||
className="flex-1 h-9 px-3 text-sm rounded-xl border border-[var(--border)] bg-white placeholder:text-[var(--fg-tertiary)] focus-ring"
|
||||
/>
|
||||
<button
|
||||
type="submit"
|
||||
disabled={!commentText.trim() || addCommentMutation.isPending}
|
||||
className="btn-ghost h-9 w-9 text-[var(--accent)] hover:bg-[var(--accent-light)] disabled:opacity-30 disabled:cursor-not-allowed"
|
||||
>
|
||||
<Send className="h-4 w-4" strokeWidth={1.5} />
|
||||
</button>
|
||||
</form>
|
||||
)}
|
||||
|
||||
<Button variant="outline" size="sm" onClick={() => navigate('/feed')} className="rounded-xl text-xs h-8 px-4 gap-1">
|
||||
<ArrowLeft className="h-3.5 w-3.5" strokeWidth={1.5} /> В ленту
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user