feat: vip按钮

This commit is contained in:
liuweiqing 2024-02-08 15:47:25 +08:00
parent 9cb214d67f
commit aeff96032e
4 changed files with 105 additions and 57 deletions

View File

@ -0,0 +1,16 @@
import React from "react";
// BuyVipButton 组件
function BuyVipButton() {
// 这是购买VIP的目标URL
const targetUrl = "https://store.paperai.life";
return (
<a href={targetUrl} target="_blank" className="no-underline">
<button className="bg-gold text-white font-semibold text-lg py-2 px-4 rounded cursor-pointer border-none shadow-md transition duration-300 ease-in-out transform hover:scale-110 ">
Buy VIP TO UNLOCK Cloud Sync and Edit Mutiple Papers Simultaneously
</button>
</a>
);
}
export default BuyVipButton;

View File

@ -1,7 +1,7 @@
"use client"; "use client";
import React from "react"; import React from "react";
import { useAppDispatch } from "@/app/store"; // 确保路径正确 import { useAppDispatch } from "@/app/store";
import { setShowPaperManagement } from "@/app/store/slices/stateSlice"; // 确保路径正确 import { setShowPaperManagement } from "@/app/store/slices/stateSlice";
export default function PaperListButton() { export default function PaperListButton() {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();

View File

@ -19,11 +19,14 @@ import {
getUserPaper, getUserPaper,
submitPaper, submitPaper,
deletePaper, deletePaper,
fetchUserVipStatus,
} from "@/utils/supabase/supabaseutils"; } from "@/utils/supabase/supabaseutils";
//动画 //动画
import { CSSTransition } from "react-transition-group"; import { CSSTransition } from "react-transition-group";
//删除远程论文按钮 //删除远程论文按钮
import ParagraphDeleteButton from "@/components/ParagraphDeleteInterface"; import ParagraphDeleteButton from "@/components/ParagraphDeleteInterface";
//vip充值按钮
import BuyVipButton from "@/components/BuyVipButton"; // 假设这是购买VIP的按钮组件
const PaperManagement = () => { const PaperManagement = () => {
//supabase //supabase
@ -36,29 +39,43 @@ const PaperManagement = () => {
const showPaperManagement = useAppSelector( const showPaperManagement = useAppSelector(
(state) => state.state.showPaperManagement (state) => state.state.showPaperManagement
); );
//状态 //获取的论文数量列表状态
const [paperNumbers, setPaperNumbers] = useState<string[]>([]); const [paperNumbers, setPaperNumbers] = useState<string[]>([]);
//user id的状态设置 //user id的状态设置
const [userId, setUserId] = useState<string>(""); const [userId, setUserId] = useState<string>("");
//vip状态
const [isVip, setIsVip] = useState(false);
//获取用户存储在云端的论文 //获取用户存储在云端的论文使用useCallback定义一个记忆化的函数来获取用户论文
// 使用useCallback定义一个记忆化的函数来获取用户论文
const fetchPapers = useCallback(async () => { const fetchPapers = useCallback(async () => {
const user = await getUser(supabase); const user = await getUser(supabase);
if (user && user.id) { if (user && user.id) {
const numbers = await getUserPaperNumbers(user.id); const numbers = await getUserPaperNumbers(user.id, supabase);
setPaperNumbers(numbers || []); // 直接在这里更新状态 setPaperNumbers(numbers || []); // 直接在这里更新状态
setUserId(user.id); setUserId(user.id);
} }
}, [supabase]); // 依赖项数组中包含supabase因为它可能会影响到fetchPapers函数的结果 }, [supabase]); // 依赖项数组中包含supabase因为它可能会影响到fetchPapers函数的结果
//获取用户VIP状态
const initFetch = async () => {
const user = await getUser();
if (user && user.id) {
const isVip = await fetchUserVipStatus(user.id);
console.log("isVip", isVip);
setIsVip(isVip);
}
};
useEffect(() => {
initFetch();
}, []);
// 使用useEffect在组件挂载后立即获取数据 // 使用useEffect在组件挂载后立即获取数据
useEffect(() => { useEffect(() => {
fetchPapers(); fetchPapers();
}, [fetchPapers]); }, [fetchPapers]);
const handlePaperClick = async (paperNumber: string) => { const handlePaperClick = async (paperNumber: string) => {
const data = await getUserPaper(userId, paperNumber); // 假设这个函数异步获取论文内容 const data = await getUserPaper(userId, paperNumber, supabase); // 假设这个函数异步获取论文内容
if (!data) { if (!data) {
throw new Error("查询出错"); throw new Error("查询出错");
} }
@ -71,20 +88,26 @@ const PaperManagement = () => {
dispatch(setContentUpdatedFromNetwork(true)); // 更新 Redux store dispatch(setContentUpdatedFromNetwork(true)); // 更新 Redux store
}; };
function getNextPaperNumber(paperNumbers: string[]) {
if (paperNumbers.length === 0) {
return "1";
} else {
return String(Math.max(...paperNumbers.map(Number)) + 1);
}
}
const handleAddPaperClick = async () => { const handleAddPaperClick = async () => {
// 添加一个新的空白论文 // 添加一个新的空白论文
await submitPaper( await submitPaper(
supabase, supabase,
"This is a blank page", "This is a blank page",
[], [],
String(Math.max(...paperNumbers.map(Number)) + 1) getNextPaperNumber(paperNumbers)
); );
// 重新获取论文列表 // 重新获取论文列表
await fetchPapers(); await fetchPapers();
}; };
const noop = (...args: any) => {};
return ( return (
<CSSTransition <CSSTransition
in={showPaperManagement} in={showPaperManagement}
@ -97,55 +120,61 @@ const PaperManagement = () => {
<div className="max-w-md w-full bg-blue-gray-100 rounded overflow-hidden shadow-lg mx-auto p-5"> <div className="max-w-md w-full bg-blue-gray-100 rounded overflow-hidden shadow-lg mx-auto p-5">
<h1 className="font-bold text-3xl text-center">Paper Management</h1> <h1 className="font-bold text-3xl text-center">Paper Management</h1>
</div> </div>
<button {isVip ? (
onClick={handleAddPaperClick} <div>
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded" <button
> onClick={handleAddPaperClick}
+ Add Paper className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
</button> >
<div className="flex flex-col items-center space-y-2"> + Add Paper
<h2 className="text-xl font-semibold">Your Papers</h2> </button>
{paperNumbers.length > 0 ? ( <div className="flex flex-col items-center space-y-2">
<ul className="list-disc"> <h2 className="text-xl font-semibold">Your Papers</h2>
{[...paperNumbers] {paperNumbers.length > 0 ? (
.sort((a, b) => parseInt(a, 10) - parseInt(b, 10)) <ul className="list-disc">
.map((number, index) => ( {[...paperNumbers]
<li .sort((a, b) => parseInt(a, 10) - parseInt(b, 10))
key={index} .map((number, index) => (
className={`bg-white w-full max-w-md mx-auto rounded shadow p-4 cursor-pointer ${ <li
number === paperNumberRedux ? "bg-yellow-200" : "" key={index}
}`} className={`bg-white w-full max-w-md mx-auto rounded shadow p-4 cursor-pointer ${
onClick={() => handlePaperClick(number)} number === paperNumberRedux ? "bg-yellow-200" : ""
> }`}
<span>Paper {number}</span> onClick={() => handlePaperClick(number)}
<ParagraphDeleteButton >
index={index} <span>Paper {number}</span>
removeReferenceUpdateIndex={async () => { <ParagraphDeleteButton
await deletePaper(supabase, userId, number); index={index}
const numbers = await getUserPaperNumbers( removeReferenceUpdateIndex={async () => {
userId, await deletePaper(supabase, userId, number);
supabase const numbers = await getUserPaperNumbers(
); userId,
setPaperNumbers(numbers || []); // 直接在这里更新状态 supabase
}} );
isRemovePaper={true} setPaperNumbers(numbers || []); // 直接在这里更新状态
title="Do you want to delete this paper?" }}
text="This action cannot be undone" isRemovePaper={true}
></ParagraphDeleteButton> title="Do you want to delete this paper?"
{/* <input text="This action cannot be undone"
></ParagraphDeleteButton>
{/* <input
type="text" type="text"
value={paper.title} value={paper.title}
onChange={(e) => handleTitleChange(index, e.target.value)} onChange={(e) => handleTitleChange(index, e.target.value)}
placeholder="Enter paper title" placeholder="Enter paper title"
className="mt-2 p-2 border rounded" className="mt-2 p-2 border rounded"
/> */} /> */}
</li> </li>
))} ))}
</ul> </ul>
) : ( ) : (
<p>No papers found.</p> <p>No papers found.</p>
)} )}
</div> </div>
</div>
) : (
<BuyVipButton />
)}
</div> </div>
</> </>
</CSSTransition> </CSSTransition>

View File

@ -147,11 +147,14 @@ export async function fetchUserVipStatus(userId: string) {
.select("is_vip") .select("is_vip")
.eq("user_id", userId) .eq("user_id", userId)
.single(); .single();
if (error) { if (error) {
console.error("Error fetching VIP status:", error); console.error("Error fetching VIP status:", error);
return null; return false;
}
if ("is_vip" in data) {
console.log("VIP status:", data.is_vip);
return data.is_vip;
} else {
return false;
} }
return data?.is_vip;
} }