This repository has been archived on 2026-08-10. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
onlypets/frontend/app/components/PostCard/PostCard.tsx
T
admin aba22e2855 feat(feed): add birthday highlight for pets in feed and explore
- display subtle birthday marker on posts when pet has birthday
- highlight birthday posts with soft accent border
- reuse central petAge utilities for consistent logic
- preserve all existing post meta information (author, time)
- avoid layout shifts by using decorative indicators only
2025-12-25 12:45:14 +01:00

141 lines
3.0 KiB
TypeScript

'use client';
import { useRef } from 'react';
import { formatPetAge, isBirthdayToday } from '@/app/lib/petAge';
export type PostCardData = {
id: number;
petName: string;
petType: 'Hund' | 'Katze';
authorName: string;
createdAt: string;
text: string;
likesCount: number;
commentsCount: number;
};
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}
· {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>
);
}