143 lines
3.1 KiB
TypeScript
143 lines
3.1 KiB
TypeScript
'use client';
|
|
|
|
import { useRef } from 'react';
|
|
import { formatPetAge, isBirthdayToday } from '@/app/lib/petAge';
|
|
import { timeAgo } from "@/lib/time";
|
|
|
|
export type PostCardData = {
|
|
id: number;
|
|
petName: string;
|
|
petType: 'Hund' | 'Katze';
|
|
authorName: string;
|
|
createdAt: string;
|
|
text: string;
|
|
likesCount: number;
|
|
commentsCount: number;
|
|
petbirthDate?: string;
|
|
|
|
};
|
|
|
|
type PostCardProps = {
|
|
post: PostCardData;
|
|
isDiscovery?: boolean
|
|
onOpenPreview: (post: PostCardData) => void;
|
|
onCommentClick?: (post: PostCardData) => void;
|
|
|
|
|
|
};
|
|
|
|
export default function PostCard({
|
|
post,
|
|
onOpenPreview,
|
|
onCommentClick,
|
|
isDiscovery,
|
|
}: PostCardProps) {
|
|
const likeRef = useRef<HTMLButtonElement | null>(null);
|
|
const commentRef = useRef<HTMLButtonElement | null>(null);
|
|
const isBirthday = post.petBirthDate && isBirthdayToday(post.petBirthDate);
|
|
|
|
function animate(
|
|
ref: React.RefObject<HTMLButtonElement>,
|
|
animation: string
|
|
) {
|
|
if (!ref.current) return;
|
|
const el = ref.current;
|
|
el.style.animation = animation;
|
|
el.addEventListener(
|
|
'animationend',
|
|
() => {
|
|
el.style.animation = '';
|
|
},
|
|
{ once: true }
|
|
);
|
|
}
|
|
|
|
return (
|
|
<article
|
|
className={`postcard
|
|
${isDiscovery ? 'postcard--discovery' : ''}
|
|
${isBirthday ? 'postcard--birthday' : ''}
|
|
`}
|
|
>
|
|
|
|
|
|
{/* Klickbarer Bereich → Preview */}
|
|
<div
|
|
className="postcard-main"
|
|
onClick={() => onOpenPreview(post)}
|
|
>
|
|
<div className="postcard-media" />
|
|
|
|
<div className="postcard-content">
|
|
<div className="postcard-header">
|
|
{isDiscovery && (
|
|
<div className="post-discovery-wrapper">
|
|
|
|
</div>
|
|
)}
|
|
|
|
<div className="postcard-title-row">
|
|
<strong className="postcard-title">
|
|
{post.petName}
|
|
</strong>
|
|
|
|
<span className="postcard-meta">
|
|
· {post.petType}
|
|
{post.petBirthDate && ` · ${formatPetAge(post.petBirthDate)}`}
|
|
· {post.authorName}
|
|
· {timeAgo(post.createdAt)}
|
|
</span>
|
|
|
|
{isBirthday && (
|
|
<span
|
|
className="birthday-dot"
|
|
title="Heute ist Geburtstag 🎉"
|
|
aria-label="Geburtstag"
|
|
>
|
|
🎂
|
|
</span>
|
|
)}
|
|
</div>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
<p className="postcard-text">{post.text}</p>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Interaktionen */}
|
|
<div className="postcard-actions">
|
|
<button
|
|
ref={likeRef}
|
|
type="button"
|
|
className="postcard-action"
|
|
onClick={(e) => {
|
|
e.stopPropagation();
|
|
animate(likeRef, 'heart-pop 0.3s ease');
|
|
// später: Like-Logik
|
|
}}
|
|
>
|
|
<span aria-hidden>❤️</span>
|
|
<span>{post.likesCount}</span>
|
|
</button>
|
|
|
|
<button
|
|
ref={commentRef}
|
|
type="button"
|
|
className="postcard-action"
|
|
onClick={(e) => {
|
|
e.stopPropagation();
|
|
animate(commentRef, 'comment-wiggle 0.25s ease');
|
|
onCommentClick?.(post);
|
|
}}
|
|
>
|
|
<span aria-hidden>💬</span>
|
|
<span>{post.commentsCount}</span>
|
|
</button>
|
|
</div>
|
|
</article>
|
|
);
|
|
}
|