2024-02-08 10:28:52 +08:00
|
|
|
|
"use client";
|
|
|
|
|
|
2024-03-09 19:50:08 +08:00
|
|
|
|
import { useCallback, useState, useRef, useEffect } from "react";
|
2024-02-08 10:28:52 +08:00
|
|
|
|
//redux
|
|
|
|
|
import { useAppDispatch, useAppSelector } from "@/app/store";
|
|
|
|
|
import {
|
|
|
|
|
setEditorContent,
|
|
|
|
|
setReferencesRedux,
|
|
|
|
|
} from "@/app/store/slices/authSlice";
|
|
|
|
|
import {
|
|
|
|
|
setPaperNumberRedux,
|
|
|
|
|
setContentUpdatedFromNetwork,
|
2024-02-08 23:06:35 +08:00
|
|
|
|
setIsVip,
|
2024-03-09 19:50:08 +08:00
|
|
|
|
setShowPaperManagement,
|
2024-02-08 10:28:52 +08:00
|
|
|
|
} from "@/app/store/slices/stateSlice";
|
|
|
|
|
//supabase
|
|
|
|
|
import { createClient } from "@/utils/supabase/client";
|
|
|
|
|
import {
|
|
|
|
|
getUser,
|
|
|
|
|
getUserPaperNumbers,
|
|
|
|
|
getUserPaper,
|
|
|
|
|
submitPaper,
|
|
|
|
|
deletePaper,
|
2024-02-08 15:47:25 +08:00
|
|
|
|
fetchUserVipStatus,
|
2024-02-08 10:28:52 +08:00
|
|
|
|
} from "@/utils/supabase/supabaseutils";
|
|
|
|
|
//动画
|
|
|
|
|
import { CSSTransition } from "react-transition-group";
|
2024-02-12 20:55:14 +08:00
|
|
|
|
// import { animated, useSpring } from "@react-spring/web";
|
2024-02-09 18:01:00 +08:00
|
|
|
|
|
2024-02-08 10:28:52 +08:00
|
|
|
|
//删除远程论文按钮
|
|
|
|
|
import ParagraphDeleteButton from "@/components/ParagraphDeleteInterface";
|
2024-02-08 15:47:25 +08:00
|
|
|
|
//vip充值按钮
|
|
|
|
|
import BuyVipButton from "@/components/BuyVipButton"; // 假设这是购买VIP的按钮组件
|
2024-02-12 20:55:14 +08:00
|
|
|
|
//i18n
|
|
|
|
|
import { useTranslation } from "@/app/i18n/client";
|
2024-02-08 10:28:52 +08:00
|
|
|
|
|
2024-02-12 20:55:14 +08:00
|
|
|
|
const PaperManagement = ({ lng }) => {
|
|
|
|
|
//i18n
|
|
|
|
|
const { t } = useTranslation(lng);
|
2024-02-08 10:28:52 +08:00
|
|
|
|
//supabase
|
|
|
|
|
const supabase = createClient();
|
|
|
|
|
//redux
|
|
|
|
|
const dispatch = useAppDispatch();
|
|
|
|
|
const paperNumberRedux = useAppSelector(
|
|
|
|
|
(state) => state.state.paperNumberRedux
|
|
|
|
|
);
|
|
|
|
|
const showPaperManagement = useAppSelector(
|
|
|
|
|
(state) => state.state.showPaperManagement
|
|
|
|
|
);
|
2024-02-18 22:36:31 +08:00
|
|
|
|
const editorContent = useAppSelector((state) => state.auth.editorContent);
|
|
|
|
|
const referencesRedux = useAppSelector((state) => state.auth.referencesRedux);
|
2024-02-08 23:06:35 +08:00
|
|
|
|
//vip状态
|
|
|
|
|
const isVip = useAppSelector((state) => state.state.isVip);
|
2024-02-08 15:47:25 +08:00
|
|
|
|
//获取的论文数量列表状态
|
2024-02-08 10:28:52 +08:00
|
|
|
|
const [paperNumbers, setPaperNumbers] = useState<string[]>([]);
|
|
|
|
|
//user id的状态设置
|
|
|
|
|
const [userId, setUserId] = useState<string>("");
|
|
|
|
|
|
2024-02-08 15:47:25 +08:00
|
|
|
|
//获取用户存储在云端的论文,使用useCallback定义一个记忆化的函数来获取用户论文
|
2024-02-08 10:28:52 +08:00
|
|
|
|
const fetchPapers = useCallback(async () => {
|
2024-02-11 22:19:24 +08:00
|
|
|
|
const user = await getUser();
|
2024-02-08 10:28:52 +08:00
|
|
|
|
if (user && user.id) {
|
2024-02-10 13:25:43 +08:00
|
|
|
|
// console.log("user.id", user.id);
|
2024-02-08 15:47:25 +08:00
|
|
|
|
const numbers = await getUserPaperNumbers(user.id, supabase);
|
2024-02-08 10:28:52 +08:00
|
|
|
|
setPaperNumbers(numbers || []); // 直接在这里更新状态
|
|
|
|
|
setUserId(user.id);
|
|
|
|
|
}
|
|
|
|
|
}, [supabase]); // 依赖项数组中包含supabase,因为它可能会影响到fetchPapers函数的结果
|
|
|
|
|
|
2024-02-08 15:47:25 +08:00
|
|
|
|
//获取用户VIP状态
|
2024-02-09 18:01:00 +08:00
|
|
|
|
const initFetchVipStatue = useCallback(async () => {
|
2024-02-08 15:47:25 +08:00
|
|
|
|
const user = await getUser();
|
|
|
|
|
if (user && user.id) {
|
|
|
|
|
const isVip = await fetchUserVipStatus(user.id);
|
2024-02-09 18:01:00 +08:00
|
|
|
|
return isVip;
|
2024-02-08 15:47:25 +08:00
|
|
|
|
}
|
2024-02-09 18:01:00 +08:00
|
|
|
|
}, [supabase]);
|
2024-02-08 15:47:25 +08:00
|
|
|
|
|
2024-02-08 10:28:52 +08:00
|
|
|
|
// 使用useEffect在组件挂载后立即获取数据
|
|
|
|
|
useEffect(() => {
|
2024-02-09 18:01:00 +08:00
|
|
|
|
const checkAndFetchPapers = async () => {
|
|
|
|
|
const isVip = await initFetchVipStatue();
|
|
|
|
|
dispatch(setIsVip(isVip));
|
|
|
|
|
console.log("isVip in initFetchVipStatue", isVip);
|
|
|
|
|
if (isVip) {
|
|
|
|
|
fetchPapers();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
checkAndFetchPapers();
|
|
|
|
|
}, [supabase]);
|
2024-02-08 10:28:52 +08:00
|
|
|
|
|
|
|
|
|
const handlePaperClick = async (paperNumber: string) => {
|
2024-02-08 15:47:25 +08:00
|
|
|
|
const data = await getUserPaper(userId, paperNumber, supabase); // 假设这个函数异步获取论文内容
|
2024-02-08 10:28:52 +08:00
|
|
|
|
if (!data) {
|
|
|
|
|
throw new Error("查询出错");
|
|
|
|
|
}
|
|
|
|
|
console.log("paperNumber", paperNumber);
|
|
|
|
|
// 更新状态以反映选中的论文内容
|
|
|
|
|
dispatch(setEditorContent(data.paper_content)); // 更新 Redux store
|
|
|
|
|
dispatch(setReferencesRedux(JSON.parse(data.paper_reference))); // 清空引用列表
|
|
|
|
|
dispatch(setPaperNumberRedux(paperNumber)); // 更新当前论文编号
|
|
|
|
|
//从网络请求中更新editorContent时,同时设置contentUpdatedFromNetwork为true
|
|
|
|
|
dispatch(setContentUpdatedFromNetwork(true)); // 更新 Redux store
|
|
|
|
|
};
|
|
|
|
|
|
2024-02-08 15:47:25 +08:00
|
|
|
|
function getNextPaperNumber(paperNumbers: string[]) {
|
|
|
|
|
if (paperNumbers.length === 0) {
|
|
|
|
|
return "1";
|
|
|
|
|
} else {
|
|
|
|
|
return String(Math.max(...paperNumbers.map(Number)) + 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-08 10:28:52 +08:00
|
|
|
|
const handleAddPaperClick = async () => {
|
2024-02-18 22:36:31 +08:00
|
|
|
|
// 先手动保存本地内容到云端
|
|
|
|
|
// await submitPaper(
|
|
|
|
|
// supabase,
|
|
|
|
|
// editorContent,
|
|
|
|
|
// referencesRedux,
|
|
|
|
|
// paperNumberRedux
|
|
|
|
|
// );
|
2024-02-08 10:28:52 +08:00
|
|
|
|
// 添加一个新的空白论文
|
|
|
|
|
await submitPaper(
|
|
|
|
|
supabase,
|
|
|
|
|
"This is a blank page",
|
|
|
|
|
[],
|
2024-02-08 15:47:25 +08:00
|
|
|
|
getNextPaperNumber(paperNumbers)
|
2024-02-08 10:28:52 +08:00
|
|
|
|
);
|
|
|
|
|
// 重新获取论文列表
|
|
|
|
|
await fetchPapers();
|
|
|
|
|
};
|
|
|
|
|
|
2024-02-09 18:01:00 +08:00
|
|
|
|
// const animations = useSpring({
|
|
|
|
|
// opacity: showPaperManagement ? 1 : 0,
|
|
|
|
|
// from: { opacity: 0 },
|
|
|
|
|
// });
|
|
|
|
|
|
2024-03-09 19:50:08 +08:00
|
|
|
|
//用于判断点击有没有落在区域中
|
|
|
|
|
const paperManagementRef = useRef(null); // 用于引用PaperManagement组件的根元素
|
|
|
|
|
const handleClickOutside = (event) => {
|
|
|
|
|
if (
|
|
|
|
|
paperManagementRef.current &&
|
|
|
|
|
!paperManagementRef.current.contains(event.target) &&
|
|
|
|
|
showPaperManagement
|
|
|
|
|
) {
|
|
|
|
|
// 如果点击事件的目标不是PaperManagement组件内的元素
|
|
|
|
|
// 隐藏组件
|
|
|
|
|
console.log("Clicked outside of the PaperManagement component.");
|
|
|
|
|
dispatch(setShowPaperManagement());
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (showPaperManagement) {
|
|
|
|
|
// 只有当组件可见时,才添加事件监听器
|
|
|
|
|
document.addEventListener("mousedown", handleClickOutside);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 组件卸载或状态改变时移除事件监听器
|
|
|
|
|
return () => {
|
|
|
|
|
document.removeEventListener("mousedown", handleClickOutside);
|
|
|
|
|
};
|
|
|
|
|
}, [showPaperManagement]); // 依赖项数组包含showPaperManagement状态
|
|
|
|
|
|
2024-02-08 10:28:52 +08:00
|
|
|
|
return (
|
|
|
|
|
<CSSTransition
|
|
|
|
|
in={showPaperManagement}
|
|
|
|
|
timeout={2000}
|
|
|
|
|
classNames="slide"
|
|
|
|
|
unmountOnExit
|
|
|
|
|
>
|
2024-02-09 18:01:00 +08:00
|
|
|
|
{/* showPaperManagement ? ( */}
|
|
|
|
|
{/* <animated.div style={animations}> */}
|
2024-02-08 10:28:52 +08:00
|
|
|
|
<>
|
2024-03-09 19:50:08 +08:00
|
|
|
|
<div
|
|
|
|
|
ref={paperManagementRef}
|
|
|
|
|
className="paper-management-container flex flex-col items-center space-y-4"
|
|
|
|
|
>
|
2024-02-08 10:28:52 +08:00
|
|
|
|
<div className="max-w-md w-full bg-blue-gray-100 rounded overflow-hidden shadow-lg mx-auto p-5">
|
2024-02-12 20:55:14 +08:00
|
|
|
|
<h1 className="font-bold text-3xl text-center">
|
|
|
|
|
{" "}
|
|
|
|
|
{t("Paper Management")}
|
|
|
|
|
</h1>
|
2024-02-08 10:28:52 +08:00
|
|
|
|
</div>
|
2024-02-08 15:47:25 +08:00
|
|
|
|
{isVip ? (
|
|
|
|
|
<div>
|
|
|
|
|
<button
|
|
|
|
|
onClick={handleAddPaperClick}
|
|
|
|
|
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"
|
|
|
|
|
>
|
2024-02-12 20:55:14 +08:00
|
|
|
|
{t("+ Add Paper")}
|
2024-02-08 15:47:25 +08:00
|
|
|
|
</button>
|
|
|
|
|
<div className="flex flex-col items-center space-y-2">
|
2024-02-12 20:55:14 +08:00
|
|
|
|
<h2 className="text-xl font-semibold">
|
|
|
|
|
{" "}
|
|
|
|
|
{t("Your Cloud Papers")}
|
|
|
|
|
</h2>
|
2024-02-08 15:47:25 +08:00
|
|
|
|
{paperNumbers.length > 0 ? (
|
|
|
|
|
<ul className="list-disc">
|
|
|
|
|
{[...paperNumbers]
|
|
|
|
|
.sort((a, b) => parseInt(a, 10) - parseInt(b, 10))
|
|
|
|
|
.map((number, index) => (
|
|
|
|
|
<li
|
|
|
|
|
key={index}
|
|
|
|
|
className={`bg-white w-full max-w-md mx-auto rounded shadow p-4 cursor-pointer ${
|
|
|
|
|
number === paperNumberRedux ? "bg-yellow-200" : ""
|
|
|
|
|
}`}
|
|
|
|
|
onClick={() => handlePaperClick(number)}
|
|
|
|
|
>
|
|
|
|
|
<span>Paper {number}</span>
|
|
|
|
|
<ParagraphDeleteButton
|
|
|
|
|
index={index}
|
|
|
|
|
removeReferenceUpdateIndex={async () => {
|
|
|
|
|
await deletePaper(supabase, userId, number);
|
|
|
|
|
const numbers = await getUserPaperNumbers(
|
|
|
|
|
userId,
|
|
|
|
|
supabase
|
|
|
|
|
);
|
|
|
|
|
setPaperNumbers(numbers || []); // 直接在这里更新状态
|
|
|
|
|
}}
|
|
|
|
|
isRemovePaper={true}
|
|
|
|
|
title="Do you want to delete this paper?"
|
|
|
|
|
text="This action cannot be undone"
|
|
|
|
|
></ParagraphDeleteButton>
|
|
|
|
|
{/* <input
|
2024-02-08 10:28:52 +08:00
|
|
|
|
type="text"
|
|
|
|
|
value={paper.title}
|
|
|
|
|
onChange={(e) => handleTitleChange(index, e.target.value)}
|
|
|
|
|
placeholder="Enter paper title"
|
|
|
|
|
className="mt-2 p-2 border rounded"
|
|
|
|
|
/> */}
|
2024-02-08 15:47:25 +08:00
|
|
|
|
</li>
|
|
|
|
|
))}
|
|
|
|
|
</ul>
|
|
|
|
|
) : (
|
|
|
|
|
<p>No papers found.</p>
|
|
|
|
|
)}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
) : (
|
2024-02-12 20:55:14 +08:00
|
|
|
|
<BuyVipButton lng={lng} />
|
2024-02-08 15:47:25 +08:00
|
|
|
|
)}
|
2024-02-08 10:28:52 +08:00
|
|
|
|
</div>
|
|
|
|
|
</>
|
2024-02-09 18:01:00 +08:00
|
|
|
|
{/* </animated.div>
|
|
|
|
|
) : null */}
|
2024-02-08 10:28:52 +08:00
|
|
|
|
</CSSTransition>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default PaperManagement;
|