132 lines
3.4 KiB
React
132 lines
3.4 KiB
React
|
"use client";
|
|||
|
|
|||
|
import { useEffect, useState } from "react";
|
|||
|
import { useRouter } from "next/navigation";
|
|||
|
import toast from "react-hot-toast";
|
|||
|
|
|||
|
export default function CheckIn() {
|
|||
|
const router = useRouter();
|
|||
|
const [checkInData, setCheckInData] = useState(null);
|
|||
|
const [loading, setLoading] = useState(true);
|
|||
|
const [totalPoints, setTotalPoints] = useState(0);
|
|||
|
|
|||
|
useEffect(() => {
|
|||
|
fetchCheckInData();
|
|||
|
const fetchUserPoints = async () => {
|
|||
|
try {
|
|||
|
const token = localStorage.getItem("token");
|
|||
|
if (!token) return;
|
|||
|
|
|||
|
const res = await fetch("/api/user/points", {
|
|||
|
headers: {
|
|||
|
Authorization: `Bearer ${token}`,
|
|||
|
},
|
|||
|
});
|
|||
|
const data = await res.json();
|
|||
|
setTotalPoints(data.points);
|
|||
|
} catch (error) {
|
|||
|
console.error("获取积分失败:", error);
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
fetchUserPoints();
|
|||
|
}, []);
|
|||
|
|
|||
|
const fetchCheckInData = async () => {
|
|||
|
try {
|
|||
|
const token = localStorage.getItem("token");
|
|||
|
if (!token) {
|
|||
|
router.push("/login");
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
const res = await fetch("/api/checkin", {
|
|||
|
headers: {
|
|||
|
Authorization: `Bearer ${token}`,
|
|||
|
},
|
|||
|
});
|
|||
|
const data = await res.json();
|
|||
|
setCheckInData(data);
|
|||
|
} catch (error) {
|
|||
|
console.error("获取签到数据失败:", error);
|
|||
|
} finally {
|
|||
|
setLoading(false);
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
const handleCheckIn = async () => {
|
|||
|
try {
|
|||
|
const token = localStorage.getItem("token");
|
|||
|
if (!token) {
|
|||
|
router.push("/login");
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
const res = await fetch("/api/checkin", {
|
|||
|
method: "POST",
|
|||
|
headers: {
|
|||
|
Authorization: `Bearer ${token}`,
|
|||
|
},
|
|||
|
});
|
|||
|
|
|||
|
const data = await res.json();
|
|||
|
|
|||
|
if (!res.ok) {
|
|||
|
throw new Error(data.error);
|
|||
|
}
|
|||
|
|
|||
|
// 更新本地存储的用户信息
|
|||
|
const user = JSON.parse(localStorage.getItem("user"));
|
|||
|
user.points = data.totalPoints;
|
|||
|
localStorage.setItem("user", JSON.stringify(user));
|
|||
|
|
|||
|
// 更新页面显示的积分
|
|||
|
setTotalPoints(data.totalPoints);
|
|||
|
|
|||
|
toast.success(`签到成功!获得${data.points}积分`);
|
|||
|
fetchCheckInData();
|
|||
|
} catch (error) {
|
|||
|
toast.error(error.message);
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
if (loading) {
|
|||
|
return <div className="p-4">加载中...</div>;
|
|||
|
}
|
|||
|
|
|||
|
return (
|
|||
|
<div className="min-h-screen bg-gray-50 p-4">
|
|||
|
<div className="max-w-md mx-auto">
|
|||
|
<h1 className="text-xl font-bold mb-6">每日签到</h1>
|
|||
|
|
|||
|
{/* 积分展示 */}
|
|||
|
<div className="bg-white rounded-lg p-6 mb-6 text-center">
|
|||
|
<div className="text-3xl font-bold text-yellow-500">
|
|||
|
{totalPoints}
|
|||
|
</div>
|
|||
|
<div className="text-gray-500 mt-2">总积分</div>
|
|||
|
</div>
|
|||
|
|
|||
|
{/* 签到按钮 */}
|
|||
|
<button
|
|||
|
onClick={handleCheckIn}
|
|||
|
className="w-full bg-yellow-400 text-white py-3 rounded-lg mb-6"
|
|||
|
>
|
|||
|
立即签到
|
|||
|
</button>
|
|||
|
|
|||
|
{/* 签到规则 */}
|
|||
|
<div className="bg-white rounded-lg p-4">
|
|||
|
<h2 className="font-bold mb-4">签到规则</h2>
|
|||
|
<ul className="text-sm text-gray-600 space-y-2">
|
|||
|
<li>• 每日签到可获得积分奖励</li>
|
|||
|
<li>• 连续签到积分翻倍(最多7天)</li>
|
|||
|
<li>• 断签后连续签到天数重置</li>
|
|||
|
<li>• 积分可用于商城优惠券兑换</li>
|
|||
|
</ul>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
</div>
|
|||
|
);
|
|||
|
}
|