Files
assetx/webapp/components/points/ReferralCodeCard.tsx

118 lines
4.0 KiB
TypeScript
Raw Normal View History

"use client";
import { useState } from "react";
import { Copy } from "lucide-react";
import { motion, AnimatePresence } from "framer-motion";
import { Button } from "@heroui/react";
import Image from "next/image";
import BorderedButton from "@/components/common/BorderedButton";
import { useApp } from "@/contexts/AppContext";
interface ReferralCodeCardProps {
code: string;
usedCount?: number;
loading?: boolean;
onCopy?: () => void;
onShare?: () => void;
}
export default function ReferralCodeCard({
code = "PR0T0-8821",
usedCount = 0,
loading = false,
onCopy,
onShare,
}: ReferralCodeCardProps) {
const { t } = useApp();
const [copied, setCopied] = useState(false);
const handleCopyClick = () => {
onCopy?.();
setCopied(true);
setTimeout(() => setCopied(false), 1500);
};
return (
<div className="flex-[32] bg-bg-surface dark:bg-gray-800 rounded-3xl border border-border-gray dark:border-gray-700 p-8 flex flex-col gap-6">
{/* Header */}
<div className="flex items-center gap-3 h-6">
<Image src="/components/card/icon0.svg" alt="" width={24} height={24} />
<span className="text-body-default font-bold text-text-primary dark:text-white leading-[150%]">
{t("points.referralCode")}
</span>
</div>
{/* Description */}
<p className="text-caption-tiny font-regular text-text-tertiary dark:text-gray-400 leading-[150%] tracking-[0.01em]">
{t("points.shareYourCodeDescription").replace("{count}", usedCount.toString())}
</p>
{/* Code Display and Buttons */}
<div className="flex flex-col gap-4">
{/* Code Display Row */}
<div className="flex items-center gap-2">
{/* Code Container */}
<div className="flex-1 bg-bg-subtle dark:bg-gray-700 rounded-xl border border-border-gray dark:border-gray-600 px-4 py-3 h-[46px] flex items-center">
{loading ? (
<div className="h-4 bg-gray-300 dark:bg-gray-600 rounded w-24 animate-pulse" />
) : (
<span className="text-body-default font-bold text-text-primary dark:text-white leading-[150%] font-inter">
{code === "Loading..." ? t("points.loading") : code}
</span>
)}
</div>
{/* Copy Button */}
<Button
isIconOnly
onClick={handleCopyClick}
className="rounded-xl w-[46px] h-[46px] min-w-[46px] bg-text-primary dark:bg-white"
>
<AnimatePresence mode="wait" initial={false}>
{copied ? (
<motion.svg
key="check"
width="20" height="20" viewBox="0 0 24 24"
fill="none" stroke="#22c55e" strokeWidth="2.5"
strokeLinecap="round" strokeLinejoin="round"
initial={{ opacity: 0, scale: 0.7 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.7 }}
transition={{ duration: 0.2 }}
>
<motion.path
d="M4 12 L10 18 L20 7"
initial={{ pathLength: 0 }}
animate={{ pathLength: 1 }}
transition={{ duration: 0.3, ease: "easeOut" }}
/>
</motion.svg>
) : (
<motion.span
key="copy"
initial={{ opacity: 0, scale: 0.7 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.7 }}
transition={{ duration: 0.15 }}
>
<Copy size={20} className="text-white dark:text-black" />
</motion.span>
)}
</AnimatePresence>
</Button>
</div>
{/* Share Button */}
<BorderedButton
size="lg"
fullWidth
onClick={onShare}
isTheme
>
{t("points.share")}
</BorderedButton>
</div>
</div>
);
}