Files
gitlab-instance-0a899031_cn…/app/[locale]/dating/components/SwipeCard.tsx
2026-06-07 23:57:52 -05:00

144 lines
4.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import { Link } from "@/i18n/navigation";
import { mediaUrl } from "@/app/lib/media";
import type { DatingProfile } from "../types";
interface SwipeCardProps {
profile: DatingProfile;
badgeText: string;
dragX: number;
isDragging: boolean;
isAnimatingOut: "left" | "right" | null;
onLike: () => void;
onDislike: () => void;
onBeginDrag: (clientX: number) => void;
onMoveDrag: (clientX: number) => void;
onEndDrag: () => void;
t: (key: string) => string;
}
export default function SwipeCard({
profile,
badgeText,
dragX,
isDragging,
isAnimatingOut,
onLike,
onDislike,
onBeginDrag,
onMoveDrag,
onEndDrag,
t,
}: SwipeCardProps) {
return (
<div
className={`relative touch-pan-y select-none overflow-hidden rounded-2xl border border-white/20 bg-gradient-to-br ${profile.gradient} p-8 pb-6 shadow-xl ${
isDragging ? "cursor-grabbing" : "cursor-grab"
} transition-transform`}
style={{
transform: `translateX(${isAnimatingOut === "right" ? 420 : isAnimatingOut === "left" ? -420 : dragX}px) rotate(${dragX / 18}deg)`,
opacity: isAnimatingOut ? 0.25 : 1,
transitionDuration: isDragging ? "0ms" : "180ms",
}}
tabIndex={0}
onKeyDown={(e) => {
if (e.key === "ArrowRight") onLike();
if (e.key === "ArrowLeft") onDislike();
}}
onPointerDown={(e) => {
e.currentTarget.setPointerCapture(e.pointerId);
onBeginDrag(e.clientX);
}}
onPointerMove={(e) => onMoveDrag(e.clientX)}
onPointerUp={onEndDrag}
onPointerCancel={onEndDrag}
>
<div
className={`pointer-events-none absolute left-5 top-5 rounded-full border-2 border-white/80 px-4 py-2 text-sm font-bold text-white transition-opacity ${
dragX > 45 ? "opacity-100" : "opacity-0"
}`}
>
{t("likeOverlay")}
</div>
<div
className={`pointer-events-none absolute right-5 top-5 rounded-full border-2 border-white/80 px-4 py-2 text-sm font-bold text-white transition-opacity ${
dragX < -45 ? "opacity-100" : "opacity-0"
}`}
>
{t("passOverlay")}
</div>
<div className="absolute right-4 top-4 flex flex-col items-end gap-1">
<span className="rounded-full bg-white/90 px-3 py-1.5 text-xs font-medium text-gray-800 backdrop-blur-sm">
{badgeText}
</span>
<Link
href={`/feedback?type=report&target=${encodeURIComponent(profile.id)}`}
className="text-sm font-medium text-[#ff4d4f] hover:text-red-600"
>
{t("report")}
</Link>
</div>
<div className="mb-6 mt-12 flex justify-center">
<img
src={mediaUrl(profile.photo)}
alt={profile.name}
className="h-28 w-28 rounded-full border-4 border-white/50 object-cover shadow-lg"
/>
</div>
<div className="mb-4 text-center">
<h3 className="text-xl font-bold text-white drop-shadow-sm">
{profile.name}{profile.age}
</h3>
<p className="mt-1 text-sm text-white/90">📍 {profile.location}</p>
{(profile.gender || profile.single) && (
<p className="mt-1 text-xs text-white/80">
{[profile.gender, profile.single].filter(Boolean).join(" · ")}
</p>
)}
</div>
<div className="mb-4">
<p className="mb-2 text-xs font-medium text-white/90">{t("matchTags")}:</p>
<div className="flex flex-wrap justify-center gap-2">
{profile.tags.map((tag) => (
<span key={tag} className="rounded-full bg-white/80 px-3 py-1 text-xs font-medium text-gray-800">
{tag}
</span>
))}
</div>
</div>
<p className="mb-8 px-2 text-center text-sm leading-relaxed text-white/95">{profile.bio}</p>
<div className="flex items-center justify-center gap-8">
<div className="flex flex-col items-center gap-2">
<button
type="button"
onClick={onDislike}
className="flex h-16 w-16 items-center justify-center rounded-full bg-white text-[#ff4d4f] shadow-lg transition-all hover:scale-105 hover:bg-red-50 active:scale-95"
aria-label={t("dislike")}
>
<span className="text-2xl"></span>
</button>
<span className="text-xs font-medium text-white/80">{t("dislike")}</span>
</div>
<div className="flex flex-col items-center gap-2">
<button
type="button"
onClick={onLike}
className="flex h-16 w-16 items-center justify-center rounded-full bg-[#22c55e] text-white shadow-lg transition-all hover:scale-105 hover:bg-[#16a34a] active:scale-95"
aria-label={t("like")}
>
<span className="text-2xl">💚</span>
</button>
<span className="text-xs font-medium text-white/80">{t("like")}</span>
</div>
</div>
</div>
);
}