205 lines
8.4 KiB
TypeScript
205 lines
8.4 KiB
TypeScript
|
|
"use client";
|
||
|
|
|
||
|
|
import { useState, useEffect } from "react";
|
||
|
|
import Image from "next/image";
|
||
|
|
import { fetchActivities, type ActivitiesData } from "@/lib/api/points";
|
||
|
|
import { useApp } from "@/contexts/AppContext";
|
||
|
|
|
||
|
|
type FilterTab = "all" | "referrals" | "deposits";
|
||
|
|
|
||
|
|
export default function ActivityHistory() {
|
||
|
|
const { t } = useApp();
|
||
|
|
const [activeTab, setActiveTab] = useState<FilterTab>("all");
|
||
|
|
const [currentPage, setCurrentPage] = useState(1);
|
||
|
|
const [data, setData] = useState<ActivitiesData | null>(null);
|
||
|
|
const [loading, setLoading] = useState(true);
|
||
|
|
|
||
|
|
useEffect(() => {
|
||
|
|
loadActivities();
|
||
|
|
}, [activeTab, currentPage]);
|
||
|
|
|
||
|
|
async function loadActivities() {
|
||
|
|
setLoading(true);
|
||
|
|
const result = await fetchActivities(activeTab, currentPage, 5);
|
||
|
|
setData(result);
|
||
|
|
setLoading(false);
|
||
|
|
}
|
||
|
|
|
||
|
|
const totalPages = data?.pagination.totalPage || 1;
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className="w-full bg-bg-surface dark:bg-gray-800 rounded-3xl border border-border-gray dark:border-gray-700 p-8 flex flex-col gap-6 animate-fade-in">
|
||
|
|
{/* Top Section - Title and Filter Tabs */}
|
||
|
|
<div className="flex items-center justify-between">
|
||
|
|
<h3 className="text-heading-h4 font-bold text-text-primary dark:text-white leading-[140%]">
|
||
|
|
{t("points.activityHistory")}
|
||
|
|
</h3>
|
||
|
|
|
||
|
|
{/* Filter Tabs */}
|
||
|
|
<div className="bg-[#f9fafb] dark:bg-gray-700 rounded-xl p-1 flex items-center gap-0 h-9">
|
||
|
|
<button
|
||
|
|
onClick={() => setActiveTab("all")}
|
||
|
|
className={`px-4 h-full rounded-lg text-body-small font-bold transition-all min-w-[60px] ${
|
||
|
|
activeTab === "all"
|
||
|
|
? "bg-white dark:bg-gray-600 text-text-primary dark:text-white shadow-sm"
|
||
|
|
: "text-text-tertiary dark:text-gray-400"
|
||
|
|
}`}
|
||
|
|
>
|
||
|
|
{t("points.all")}
|
||
|
|
</button>
|
||
|
|
<button
|
||
|
|
onClick={() => setActiveTab("referrals")}
|
||
|
|
className={`px-4 h-full rounded-lg text-body-small font-bold transition-all min-w-[90px] ${
|
||
|
|
activeTab === "referrals"
|
||
|
|
? "bg-white dark:bg-gray-600 text-text-primary dark:text-white shadow-sm"
|
||
|
|
: "text-text-tertiary dark:text-gray-400"
|
||
|
|
}`}
|
||
|
|
>
|
||
|
|
{t("points.referrals")}
|
||
|
|
</button>
|
||
|
|
<button
|
||
|
|
onClick={() => setActiveTab("deposits")}
|
||
|
|
className={`px-4 h-full rounded-lg text-body-small font-bold transition-all min-w-[85px] ${
|
||
|
|
activeTab === "deposits"
|
||
|
|
? "bg-white dark:bg-gray-600 text-text-primary dark:text-white shadow-sm"
|
||
|
|
: "text-text-tertiary dark:text-gray-400"
|
||
|
|
}`}
|
||
|
|
>
|
||
|
|
{t("points.deposits")}
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Table Card */}
|
||
|
|
<div className="bg-bg-surface dark:bg-gray-800 rounded-3xl border border-border-gray dark:border-gray-700 overflow-hidden">
|
||
|
|
{/* Table Header Section */}
|
||
|
|
<div className="bg-bg-surface dark:bg-gray-800 border-b border-border-gray dark:border-gray-700 p-6 flex items-center justify-between">
|
||
|
|
<div className="flex flex-col gap-1">
|
||
|
|
<h4 className="text-heading-h4 font-bold text-text-primary dark:text-white leading-[140%]">
|
||
|
|
{t("points.activityHistory")}
|
||
|
|
</h4>
|
||
|
|
<p className="text-caption-tiny font-regular text-text-tertiary dark:text-gray-400 leading-[150%] tracking-[0.01em]">
|
||
|
|
{t("points.trackActivities")}
|
||
|
|
</p>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div className="flex items-center gap-2">
|
||
|
|
<Image src="/icons/actions/icon-refresh.svg" alt="Refresh" width={16} height={16} />
|
||
|
|
<span className="text-caption-tiny font-regular text-text-secondary dark:text-gray-300 leading-[150%] tracking-[0.01em]">
|
||
|
|
{t("points.refreshLastUpdated").replace("{time}", "2")}
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Table */}
|
||
|
|
<div className="overflow-auto">
|
||
|
|
{/* Table Header */}
|
||
|
|
<div className="bg-bg-subtle dark:bg-gray-700/30 border-b border-border-gray dark:border-gray-700 flex">
|
||
|
|
<div className="flex-1 px-6 py-4">
|
||
|
|
<span className="text-caption-tiny font-medium text-text-secondary dark:text-gray-300 leading-[150%] tracking-[0.01em]">
|
||
|
|
{t("points.user")}
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
<div className="flex-1 px-6 py-4">
|
||
|
|
<span className="text-caption-tiny font-medium text-text-secondary dark:text-gray-300 leading-[150%] tracking-[0.01em]">
|
||
|
|
{t("points.friends")}
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
<div className="flex-1 px-6 py-4">
|
||
|
|
<span className="text-caption-tiny font-medium text-text-secondary dark:text-gray-300 leading-[150%] tracking-[0.01em]">
|
||
|
|
{t("points.code")}
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
<div className="flex-1 px-6 py-4">
|
||
|
|
<span className="text-caption-tiny font-medium text-text-secondary dark:text-gray-300 leading-[150%] tracking-[0.01em]">
|
||
|
|
{t("points.points")}
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Table Body */}
|
||
|
|
{loading ? (
|
||
|
|
<div className="p-6 text-center">
|
||
|
|
<div className="h-4 bg-gray-200 dark:bg-gray-700 rounded w-full animate-pulse" />
|
||
|
|
</div>
|
||
|
|
) : data && data.activities && data.activities.length > 0 ? (
|
||
|
|
data.activities.map((row, index) => (
|
||
|
|
<div
|
||
|
|
key={index}
|
||
|
|
className={`flex ${
|
||
|
|
index !== data.activities.length - 1 ? "border-b border-border-gray dark:border-gray-700" : ""
|
||
|
|
}`}
|
||
|
|
>
|
||
|
|
<div className="flex-1 px-6 py-4">
|
||
|
|
<span className="text-body-small font-bold text-text-primary dark:text-white font-inter">
|
||
|
|
{row.userAddress}
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
<div className="flex-1 px-6 py-4">
|
||
|
|
<span className="text-body-small font-bold text-text-primary dark:text-white font-inter">
|
||
|
|
{row.friendAddress || "-"}
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
<div className="flex-1 px-6 py-4">
|
||
|
|
<span className="text-body-small font-bold text-text-primary dark:text-white font-inter">
|
||
|
|
{row.inviteCode || "-"}
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
<div className="flex-1 px-6 py-4">
|
||
|
|
<span className="text-body-small font-bold leading-[150%]" style={{ color: "#10b981" }}>
|
||
|
|
+{row.points}
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
))
|
||
|
|
) : (
|
||
|
|
<div className="p-6 text-center">
|
||
|
|
<span className="text-text-tertiary dark:text-gray-400">{t("points.noActivitiesFound")}</span>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Pagination */}
|
||
|
|
{totalPages > 1 && (
|
||
|
|
<div className="flex items-center justify-center gap-4">
|
||
|
|
{/* Previous Button */}
|
||
|
|
<button
|
||
|
|
onClick={() => setCurrentPage(Math.max(1, currentPage - 1))}
|
||
|
|
disabled={currentPage === 1}
|
||
|
|
className="w-10 h-10 flex items-center justify-center disabled:opacity-50"
|
||
|
|
>
|
||
|
|
<Image src="/icons/ui/icon-chevron-left.svg" alt="Previous" width={10} height={10} />
|
||
|
|
</button>
|
||
|
|
|
||
|
|
{/* Page Numbers */}
|
||
|
|
<div className="flex items-center gap-3">
|
||
|
|
{Array.from({ length: totalPages }, (_, i) => i + 1).map((page) => (
|
||
|
|
<button
|
||
|
|
key={page}
|
||
|
|
onClick={() => setCurrentPage(page)}
|
||
|
|
className={`px-[10px] py-[3px] rounded-lg text-sm leading-[22px] transition-all ${
|
||
|
|
currentPage === page
|
||
|
|
? "bg-bg-subtle dark:bg-gray-700 text-text-primary dark:text-white"
|
||
|
|
: "text-text-tertiary dark:text-gray-400"
|
||
|
|
}`}
|
||
|
|
>
|
||
|
|
{page}
|
||
|
|
</button>
|
||
|
|
))}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Next Button */}
|
||
|
|
<button
|
||
|
|
onClick={() => setCurrentPage(Math.min(totalPages, currentPage + 1))}
|
||
|
|
disabled={currentPage === totalPages}
|
||
|
|
className="w-10 h-10 flex items-center justify-center disabled:opacity-50"
|
||
|
|
>
|
||
|
|
<Image src="/icons/ui/icon-chevron-right.svg" alt="Next" width={10} height={10} />
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|