podzahr/components/AlbumCard.tsx
nfel 9478aa319f
main: added presigned url + favicon
Signed-off-by: nfel <nfilsaraee@gmail.com>
2026-01-01 19:06:11 +03:30

129 lines
4.5 KiB
TypeScript

'use client';
import { motion } from 'framer-motion';
import { useRouter } from 'next/navigation';
import { FaPlay, FaShoppingCart, FaInfoCircle } from 'react-icons/fa';
import { Album } from '@/lib/types';
import { useCart } from '@/lib/CartContext';
import { formatPrice } from '@/lib/utils';
interface AlbumCardProps {
album: Album;
isPurchased: boolean;
onPlay: (album: Album) => void;
onPurchase: (album: Album) => void;
}
export default function AlbumCard({ album, isPurchased, onPlay, onPurchase }: AlbumCardProps) {
const router = useRouter();
const { addToCart, isInCart } = useCart();
const handleAddToCart = (e: React.MouseEvent) => {
e.stopPropagation();
if (!isInCart(album.id) && !isPurchased) {
addToCart(album);
}
};
const handleViewDetails = (e?: React.MouseEvent) => {
if (e) {
e.stopPropagation();
}
router.push(`/album/${album.id}`);
};
const handleCardClick = () => {
router.push(`/album/${album.id}`);
};
return (
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
viewport={{ once: true }}
whileHover={{ y: -4, transition: { duration: 0.2 } }}
onClick={handleCardClick}
className="paper-card-light overflow-hidden group cursor-pointer hover:shadow-paper-lg transition-shadow"
>
{/* Album Cover */}
<div className="relative aspect-square bg-paper-brown overflow-hidden border-b-2 border-paper-gray">
{album.coverImage ? (
<img
src={album.coverImage}
alt={album.title}
className="w-full h-full object-cover"
/>
) : (
<div className="w-full h-full flex items-center justify-center">
<div className="relative z-10 text-6xl font-bold text-paper-dark/20 p-8 text-center">
{album.title}
</div>
</div>
)}
{/* Overlay on hover */}
<div className="absolute inset-0 bg-paper-dark/80 opacity-0 group-hover:opacity-100 transition-all duration-300 flex items-center justify-center gap-3">
<button
onClick={(e) => {
e.stopPropagation();
onPlay(album);
}}
className="p-4 bg-paper-sand hover:bg-paper-gray border-2 border-paper-dark transition-all shadow-paper"
aria-label="Play preview"
>
<FaPlay className="text-2xl text-paper-dark" />
</button>
<button
onClick={(e) => handleViewDetails(e)}
className="p-4 bg-paper-light hover:bg-paper-sand border-2 border-paper-brown transition-all shadow-paper"
aria-label="View details"
>
<FaInfoCircle className="text-2xl text-paper-dark" />
</button>
{!isPurchased && (
<button
onClick={handleAddToCart}
disabled={isInCart(album.id)}
className={`p-4 ${
isInCart(album.id)
? 'bg-paper-gray border-2 border-paper-brown cursor-not-allowed opacity-50'
: 'bg-paper-brown hover:bg-paper-dark border-2 border-paper-dark shadow-paper'
} transition-all`}
aria-label="Add to cart"
>
<FaShoppingCart className="text-2xl text-paper-light" />
</button>
)}
</div>
{/* Purchased Badge */}
{isPurchased && (
<div className="absolute top-4 right-4 bg-paper-dark text-paper-light px-3 py-1 border-2 border-paper-brown text-sm font-semibold">
Owned
</div>
)}
</div>
{/* Album Info */}
<div className="p-6 space-y-3 bg-paper-light cardboard-texture">
<div>
<h3 className="text-xl font-bold text-paper-dark group-hover:border-b-2 group-hover:border-paper-dark transition-all inline-block">
{album.title}
</h3>
<p className="text-sm text-paper-gray font-medium mt-1">{album.year} {album.genre}</p>
</div>
<p className="text-paper-dark text-sm line-clamp-2">{album.description}</p>
<div className="flex items-center justify-between pt-2 border-t-2 border-paper-gray">
<span className="text-sm text-paper-brown font-medium">{album.songs.length} tracks</span>
{!isPurchased && (
<span className="text-lg font-bold text-paper-dark">{formatPrice(album.price)}</span>
)}
</div>
</div>
</motion.div>
);
}