✨ feat:
This commit is contained in:
parent
c1a8cfd6d6
commit
a58b225544
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* @LastEditors: John
|
||||
* @Date: 2024-06-17 18:25:10
|
||||
* @LastEditTime: 2024-06-19 16:14:06
|
||||
* @LastEditTime: 2024-06-28 17:46:23
|
||||
* @Author: John
|
||||
*/
|
||||
export default {
|
||||
|
@ -11,7 +11,7 @@ export default {
|
|||
rootValue: 37.5,
|
||||
propList: ["*"],
|
||||
exclude: (e) => {
|
||||
if (/.*-m\.css$/.test(e) || /.module\.css$/.test(e)) {
|
||||
if (/.*-m\.css$/.test(e) || /.*-m.module\.css$/.test(e)) {
|
||||
// console.log(e);
|
||||
return false;
|
||||
}
|
||||
|
|
34
src/App.tsx
34
src/App.tsx
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* @LastEditors: John
|
||||
* @Date: 2024-06-17 17:20:03
|
||||
* @LastEditTime: 2024-06-26 16:00:00
|
||||
* @LastEditTime: 2024-06-28 17:44:02
|
||||
* @Author: John
|
||||
*/
|
||||
import { Route, Routes } from "react-router-dom";
|
||||
|
@ -16,7 +16,7 @@ import InvitationList from "./pages/InvitationList";
|
|||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import useUserStore from "./store/User";
|
||||
import { getUrlQueryParam } from "./utils";
|
||||
import { getUrlQueryParam, isMobile } from "./utils";
|
||||
import { UrlQueryParamsKey } from "./constants";
|
||||
import { signAndLogin } from "./utils/wallet";
|
||||
import { useAccount } from "wagmi";
|
||||
|
@ -45,12 +45,30 @@ function App() {
|
|||
return (
|
||||
<>
|
||||
<RouterLogProvider>
|
||||
<Header />
|
||||
<Routes>
|
||||
<Route path="/" element={<Home />} />
|
||||
<Route path="/mint" element={<Mint />} />
|
||||
<Route path="/invitationlist" element={<InvitationList />}></Route>
|
||||
</Routes>
|
||||
{isMobile ? (
|
||||
<>
|
||||
<Header.Mobile />
|
||||
<Routes>
|
||||
<>
|
||||
<Route path="/" element={<Home.Mobile />} />
|
||||
<Route path="/mint" element={<Mint />} />
|
||||
<Route
|
||||
path="/invitationlist"
|
||||
element={<InvitationList />}
|
||||
></Route>
|
||||
</>
|
||||
</Routes>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Header.Desktop />
|
||||
<Routes>
|
||||
<>
|
||||
<Route path="/" element={<Home.Desktop />} />
|
||||
</>
|
||||
</Routes>
|
||||
</>
|
||||
)}
|
||||
</RouterLogProvider>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* @LastEditors: John
|
||||
* @Date: 2024-06-18 15:16:31
|
||||
* @LastEditTime: 2024-06-27 15:29:00
|
||||
* @LastEditTime: 2024-06-28 14:05:29
|
||||
* @Author: John
|
||||
*/
|
||||
import Picker, {
|
||||
|
@ -11,7 +11,7 @@ import Picker, {
|
|||
import { useContext, useEffect, useMemo, useState } from "react";
|
||||
import IconFont from "./iconfont";
|
||||
import logo from "@/assets/logo.svg";
|
||||
import classes from "./Header.module.css";
|
||||
import classes from "./Header-m.module.css";
|
||||
import { useLocation, useNavigate, useNavigation } from "react-router-dom";
|
||||
import { RouterLogContext } from "@/context/RouterContext";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
@ -27,7 +27,7 @@ const langColums: Action[] = [
|
|||
{ text: "日本語", key: Lang.jp },
|
||||
{ text: "DEUTSCH", key: Lang.de },
|
||||
];
|
||||
export default function () {
|
||||
function Mobile() {
|
||||
const { UpdateLang } = useUserStore();
|
||||
|
||||
const route = useContext(RouterLogContext);
|
||||
|
@ -79,3 +79,12 @@ export default function () {
|
|||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function Desktop() {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
export default {
|
||||
Mobile,
|
||||
Desktop,
|
||||
};
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
* @LastEditors: John
|
||||
* @Date: 2024-06-19 10:49:42
|
||||
* @LastEditTime: 2024-06-19 10:52:32
|
||||
* @LastEditTime: 2024-06-28 14:05:45
|
||||
* @Author: John
|
||||
*/
|
||||
import classes from "./RecordsItem.module.css";
|
||||
import classes from "./RecordsItem-m.module.css";
|
||||
export default function RecordsItem({
|
||||
itemList,
|
||||
}: {
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* @LastEditors: John
|
||||
* @Date: 2024-06-28 14:09:55
|
||||
* @LastEditTime: 2024-06-28 14:14:29
|
||||
* @Author: John
|
||||
*/
|
||||
import useUserStore from "@/store/User";
|
||||
import { useWeb3Modal } from "@web3modal/wagmi/react";
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useAccount } from "wagmi";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { Dialog } from "antd-mobile";
|
||||
import {
|
||||
api_get_homepage_user_data,
|
||||
api_query_user_invitation_code,
|
||||
} from "@/server/api";
|
||||
import { UserHomeData } from "@/server/module";
|
||||
import { UrlQueryParamsKey } from "@/constants";
|
||||
import usePollingCheckBuyStatus from "@/hook/usePollingCheckBuyStatus";
|
||||
import { ToastHandler } from "antd-mobile/es/components/toast";
|
||||
import { PullStatus } from "antd-mobile/es/components/pull-to-refresh";
|
||||
export default function () {
|
||||
const { Token, UpdateToken } = useUserStore();
|
||||
const { open } = useWeb3Modal();
|
||||
|
||||
const { t } = useTranslation();
|
||||
const { address } = useAccount();
|
||||
|
||||
const [tabIndex, setTabIndex] = useState(0);
|
||||
const navigate = useNavigate();
|
||||
const [userData, setUserData] = useState<UserHomeData>();
|
||||
const [inviteCode, setInviteCode] = useState("");
|
||||
|
||||
const userInviteLink = useMemo(
|
||||
() =>
|
||||
`${location.origin}/#/?${UrlQueryParamsKey.INVITE_CODE}=${inviteCode}`,
|
||||
[inviteCode]
|
||||
);
|
||||
const receiveLoadingToast = useRef<ToastHandler>();
|
||||
const {
|
||||
transcationStatus,
|
||||
startPollingCheckBuyStatus,
|
||||
stopPollingCheckBuyStatus,
|
||||
} = usePollingCheckBuyStatus("NORMAL");
|
||||
|
||||
const statusRecord: Record<PullStatus, string> = {
|
||||
pulling: "Pull down to refresh",
|
||||
canRelease: "Release to refresh immediately",
|
||||
refreshing: "Loading...",
|
||||
complete: "Refresh complete",
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (Token) {
|
||||
getHomeData();
|
||||
getInviteCode();
|
||||
}
|
||||
return () => {};
|
||||
}, [Token]);
|
||||
|
||||
useEffect(() => {
|
||||
if (transcationStatus == "success") {
|
||||
receiveLoadingToast.current?.close();
|
||||
stopPollingCheckBuyStatus();
|
||||
Dialog.alert({
|
||||
content: `${t("领取成功,前往钱包查看")}`,
|
||||
confirmText: "OK",
|
||||
});
|
||||
}
|
||||
|
||||
return () => {};
|
||||
}, [transcationStatus]);
|
||||
|
||||
async function getHomeData() {
|
||||
const { data } = await api_get_homepage_user_data().send({});
|
||||
setUserData(data?.data);
|
||||
}
|
||||
|
||||
async function getInviteCode() {
|
||||
const { data } = await api_query_user_invitation_code().send({});
|
||||
setInviteCode(data?.data.invitationCode || "");
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
console.log("user token:", Token);
|
||||
|
||||
return () => {};
|
||||
}, [Token]);
|
||||
return {
|
||||
getHomeData,
|
||||
statusRecord,
|
||||
Token,
|
||||
address,
|
||||
setUserData,
|
||||
userData,
|
||||
tabIndex,
|
||||
t,
|
||||
setTabIndex,
|
||||
navigate,
|
||||
userInviteLink,
|
||||
};
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
import usePagination from "@/hook/usePagination";
|
||||
import { api_recommended_list } from "@/server/api";
|
||||
import { RecommendedListItem } from "@/server/module";
|
||||
import { Empty, InfiniteScroll } from "antd-mobile";
|
||||
import DataTable, { TableColumn } from "react-data-table-component";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
export default function () {
|
||||
const { t } = useTranslation();
|
||||
const columns: TableColumn<RecommendedListItem>[] = [
|
||||
{
|
||||
name: t("地址"),
|
||||
selector: (row) => row.walletAddress,
|
||||
grow: 9,
|
||||
},
|
||||
{
|
||||
name: "Node",
|
||||
selector: (row) => row.nodeNumber,
|
||||
grow: 1,
|
||||
// @ts-ignore
|
||||
right: "true",
|
||||
},
|
||||
];
|
||||
|
||||
const { list, hasMore, loadMore } = usePagination<RecommendedListItem>({
|
||||
service({ pageNum, pageSize }) {
|
||||
return new Promise(async (reslove) => {
|
||||
const { data } = await api_recommended_list().send({
|
||||
queryParams: { pageNum, pageSize },
|
||||
});
|
||||
reslove(data?.data.records || []);
|
||||
});
|
||||
},
|
||||
});
|
||||
return {
|
||||
columns,
|
||||
list,
|
||||
loadMore,
|
||||
hasMore,
|
||||
};
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
import { cn, filterAddressBeforeZero, filterAmountBeforeZero } from "@/utils";
|
||||
import classes from "./Mint-m.module.css";
|
||||
import nft_bg from "@/assets/nft_bg.svg";
|
||||
import Button from "antd-mobile/es/components/button";
|
||||
import Space from "antd-mobile/es/components/space";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import {
|
||||
api_get_homepage_user_data,
|
||||
api_get_nft_configuration_data,
|
||||
api_node_order,
|
||||
api_users_cancel_orders,
|
||||
} from "@/server/api";
|
||||
import {
|
||||
NftConfigurationData,
|
||||
NftOrder,
|
||||
NodeOrder,
|
||||
UserHomeData,
|
||||
} from "@/server/module";
|
||||
import {
|
||||
authorizedU,
|
||||
getApproveUsdt,
|
||||
getBalance,
|
||||
payByContract,
|
||||
} from "@/contract/utils";
|
||||
import { Dialog, Modal, Stepper, Toast } from "antd-mobile";
|
||||
import useUserStore from "@/store/User";
|
||||
import usePollingCheckBuyStatus from "@/hook/usePollingCheckBuyStatus";
|
||||
import { ToastHandler } from "antd-mobile/es/components/toast";
|
||||
import { BaseError } from "wagmi";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { toWei } from "web3-utils";
|
||||
|
||||
export default function () {
|
||||
const { t } = useTranslation();
|
||||
const { Token } = useUserStore();
|
||||
const [nodeConfig, setNodeConfig] = useState<UserHomeData>();
|
||||
const [approveUsdt, setApproveUsdt] = useState<bigint>(0n);
|
||||
const [balance, setBalance] = useState<bigint>(0n);
|
||||
const orderInfo = useRef<NodeOrder>();
|
||||
const navigate = useNavigate();
|
||||
const [num, setNum] = useState(1);
|
||||
|
||||
const buyLoadingToast = useRef<ToastHandler>();
|
||||
const approveLoadingToast = useRef<ToastHandler>();
|
||||
const {
|
||||
transcationStatus,
|
||||
startPollingCheckBuyStatus,
|
||||
stopPollingCheckBuyStatus,
|
||||
} = usePollingCheckBuyStatus("NORMAL");
|
||||
|
||||
const costNum = useMemo(
|
||||
() =>
|
||||
BigInt(
|
||||
toWei(`${parseFloat(`${nodeConfig?.nodePrice || "0"}`) * num}`, "ether")
|
||||
),
|
||||
[nodeConfig?.nodePrice, num]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
updateNodeConfig();
|
||||
|
||||
return () => {};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
Toast.show({ icon: "loading", content: t("正在获取已授权金额") });
|
||||
setBalance(await getBalance());
|
||||
setApproveUsdt(await getApproveUsdt());
|
||||
Toast.clear();
|
||||
})();
|
||||
|
||||
return () => {};
|
||||
}, [Token]);
|
||||
|
||||
async function updateNodeConfig() {
|
||||
const { data } = await api_get_homepage_user_data().send({});
|
||||
setNodeConfig(data?.data);
|
||||
}
|
||||
useEffect(() => {
|
||||
if (transcationStatus == "success") {
|
||||
buyLoadingToast.current?.close();
|
||||
stopPollingCheckBuyStatus();
|
||||
Dialog.alert({
|
||||
content: `${t(
|
||||
"Buy successful. Please return to the homepage to view."
|
||||
)}`,
|
||||
confirmText: "OK",
|
||||
onConfirm() {
|
||||
navigate("/");
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return () => {};
|
||||
}, [transcationStatus]);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {};
|
||||
}, []);
|
||||
|
||||
return {
|
||||
nodeConfig,
|
||||
num,
|
||||
setNum,
|
||||
approveUsdt,
|
||||
t,
|
||||
balance,
|
||||
approveLoadingToast,
|
||||
costNum,
|
||||
setApproveUsdt,
|
||||
buyLoadingToast,
|
||||
orderInfo,
|
||||
updateNodeConfig,
|
||||
startPollingCheckBuyStatus,
|
||||
};
|
||||
}
|
|
@ -1,314 +1,287 @@
|
|||
import classes from "./Home.module.css";
|
||||
import useUserStore from "@/store/User";
|
||||
/*
|
||||
* @LastEditors: John
|
||||
* @Date: 2024-06-26 15:04:10
|
||||
* @LastEditTime: 2024-06-28 14:36:37
|
||||
* @Author: John
|
||||
*/
|
||||
import classes from "./Home-m.module.css";
|
||||
import { cn, copyText, getLevelName, shortenString } from "@/utils";
|
||||
import { useWeb3Modal } from "@web3modal/wagmi/react";
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import logo from "@/assets/logo.svg";
|
||||
import nftBg from "@/assets/nft_bg.svg";
|
||||
import usdtBg from "@/assets/usdt_bg.svg";
|
||||
import IconFont from "@/components/iconfont";
|
||||
import { BaseError, useAccount } from "wagmi";
|
||||
import { config } from "@/components/WalletProvider";
|
||||
import { createSearchParams, useNavigate } from "react-router-dom";
|
||||
import { Button, Dialog, Empty, PullToRefresh, Toast } from "antd-mobile";
|
||||
import { PullToRefresh } from "antd-mobile";
|
||||
import { loginOut } from "@/utils/wallet";
|
||||
import {
|
||||
api_claim_income,
|
||||
api_get_homepage_user_data,
|
||||
api_query_user_invitation_code,
|
||||
} from "@/server/api";
|
||||
import { UserHomeData } from "@/server/module";
|
||||
import { UrlQueryParamsKey } from "@/constants";
|
||||
import usePollingCheckBuyStatus from "@/hook/usePollingCheckBuyStatus";
|
||||
import { ToastHandler } from "antd-mobile/es/components/toast";
|
||||
import { disconnect, getAccount } from "@wagmi/core";
|
||||
import { PullStatus } from "antd-mobile/es/components/pull-to-refresh";
|
||||
export default function () {
|
||||
const { Token, UpdateToken } = useUserStore();
|
||||
const { open } = useWeb3Modal();
|
||||
const { t } = useTranslation();
|
||||
const { address } = useAccount();
|
||||
|
||||
const [tabIndex, setTabIndex] = useState(0);
|
||||
const navigate = useNavigate();
|
||||
const [userData, setUserData] = useState<UserHomeData>();
|
||||
const [inviteCode, setInviteCode] = useState("");
|
||||
|
||||
const userInviteLink = useMemo(
|
||||
() =>
|
||||
`${location.origin}/#/?${UrlQueryParamsKey.INVITE_CODE}=${inviteCode}`,
|
||||
[inviteCode]
|
||||
);
|
||||
const receiveLoadingToast = useRef<ToastHandler>();
|
||||
import useHome from "./Feature/useHome";
|
||||
import useMint from "./Feature/useMint";
|
||||
import useInvitationList from "./Feature/useInvitationList";
|
||||
function Mobile() {
|
||||
const {
|
||||
transcationStatus,
|
||||
startPollingCheckBuyStatus,
|
||||
stopPollingCheckBuyStatus,
|
||||
} = usePollingCheckBuyStatus("NORMAL");
|
||||
|
||||
const statusRecord: Record<PullStatus, string> = {
|
||||
pulling: "Pull down to refresh",
|
||||
canRelease: "Release to refresh immediately",
|
||||
refreshing: "Loading...",
|
||||
complete: "Refresh complete",
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (Token) {
|
||||
getHomeData();
|
||||
getInviteCode();
|
||||
}
|
||||
return () => {};
|
||||
}, [Token]);
|
||||
|
||||
useEffect(() => {
|
||||
if (transcationStatus == "success") {
|
||||
receiveLoadingToast.current?.close();
|
||||
stopPollingCheckBuyStatus();
|
||||
Dialog.alert({
|
||||
content: `${t("领取成功,前往钱包查看")}`,
|
||||
confirmText: "OK",
|
||||
});
|
||||
}
|
||||
|
||||
return () => {};
|
||||
}, [transcationStatus]);
|
||||
|
||||
async function getHomeData() {
|
||||
const { data } = await api_get_homepage_user_data().send({});
|
||||
setUserData(data?.data);
|
||||
}
|
||||
|
||||
async function getInviteCode() {
|
||||
const { data } = await api_query_user_invitation_code().send({});
|
||||
setInviteCode(data?.data.invitationCode || "");
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
console.log("user token:", Token);
|
||||
|
||||
return () => {};
|
||||
}, [Token]);
|
||||
getHomeData,
|
||||
statusRecord,
|
||||
Token,
|
||||
address,
|
||||
setUserData,
|
||||
userData,
|
||||
tabIndex,
|
||||
t,
|
||||
setTabIndex,
|
||||
navigate,
|
||||
userInviteLink,
|
||||
} = useHome();
|
||||
|
||||
return (
|
||||
<>
|
||||
<PullToRefresh
|
||||
onRefresh={async () => {
|
||||
await getHomeData();
|
||||
}}
|
||||
renderText={(status) => {
|
||||
return <div>{statusRecord[status]}</div>;
|
||||
}}
|
||||
disabled={!Token}
|
||||
>
|
||||
<div className={cn(classes.Home, classes.container)}>
|
||||
<div className={classes.userinfo}>
|
||||
<div className={classes.userinfo_top}>
|
||||
<img className={classes.userinfo_top_left} src={logo} alt="" />
|
||||
<PullToRefresh
|
||||
onRefresh={async () => {
|
||||
await getHomeData();
|
||||
}}
|
||||
renderText={(status) => {
|
||||
return <div>{statusRecord[status]}</div>;
|
||||
}}
|
||||
disabled={!Token}
|
||||
>
|
||||
<div className={cn(classes.Home, classes.container)}>
|
||||
<div className={classes.userinfo}>
|
||||
<div className={classes.userinfo_top}>
|
||||
<img className={classes.userinfo_top_left} src={logo} alt="" />
|
||||
|
||||
{address ? (
|
||||
<div className={classes.userinfo_top_right}>
|
||||
<div className={classes.userinfo_top_right_wallet}>
|
||||
<span>{shortenString(address, 6, 4)}</span>
|
||||
<IconFont
|
||||
onClick={async () => {
|
||||
loginOut();
|
||||
setUserData(undefined);
|
||||
}}
|
||||
name="tuichu"
|
||||
className={classes.userinfo_top_right_wallet_disconnect}
|
||||
color={"#fff"}
|
||||
/>
|
||||
</div>
|
||||
<div className={classes.userinfo_top_right_btns}>
|
||||
{userData && (
|
||||
<>
|
||||
<div className={classes.userinfo_top_right_btns_item}>
|
||||
<span>{getLevelName(userData.level)}</span>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div
|
||||
className={classes.userinfo_top_right_connect}
|
||||
onClick={() => {
|
||||
open();
|
||||
{address ? (
|
||||
<div className={classes.userinfo_top_right}>
|
||||
<div className={classes.userinfo_top_right_wallet}>
|
||||
<span>{shortenString(address, 6, 4)}</span>
|
||||
<IconFont
|
||||
onClick={async () => {
|
||||
loginOut();
|
||||
setUserData(undefined);
|
||||
}}
|
||||
>
|
||||
<span>{t("链接钱包")}</span>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<ul className={classes.userinfo_data}>
|
||||
<li>
|
||||
<span className={classes.userinfo_data_num}>
|
||||
{userData?.directPushNode || 0}
|
||||
</span>
|
||||
<span className={classes.userinfo_data_des}>
|
||||
{t("Direct Node")}
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<span className={classes.userinfo_data_num}>
|
||||
{userData?.teamNode || 0}
|
||||
</span>
|
||||
<span className={classes.userinfo_data_des}>
|
||||
{t("Team Node")}
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<span className={classes.userinfo_data_num}>
|
||||
{userData?.revenueUsdt || 0}
|
||||
<p>USDT</p>
|
||||
</span>
|
||||
<span className={classes.userinfo_data_des}>
|
||||
{t("Push income")}
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div className={classes.nftToken}>
|
||||
<ul className={classes.nftToken_tab}>
|
||||
<li
|
||||
className={tabIndex == 0 ? classes.nftToken_tab_active : ""}
|
||||
onClick={() => setTabIndex(0)}
|
||||
>
|
||||
NODE
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div className={classes.nftToken_content}>
|
||||
{tabIndex == 0 && (
|
||||
<>
|
||||
{address ? (
|
||||
name="tuichu"
|
||||
className={classes.userinfo_top_right_wallet_disconnect}
|
||||
color={"#fff"}
|
||||
/>
|
||||
</div>
|
||||
<div className={classes.userinfo_top_right_btns}>
|
||||
{userData && (
|
||||
<>
|
||||
{userData?.nodeNumber && userData?.nodeNumber > 0 ? (
|
||||
<div className={classes.nftToken_content_nft}>
|
||||
<div className={classes.nftToken_content_nft_top}>
|
||||
<span>You own {userData.nodeNumber} nodes</span>
|
||||
<span
|
||||
onClick={() => {
|
||||
navigate("/mint");
|
||||
}}
|
||||
>
|
||||
{t("Buy Node")}
|
||||
<IconFont
|
||||
name="chevronsrightshuangyoujiantou"
|
||||
color={"#2DFCFC"}
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<img
|
||||
className={classes.nftToken_content_nft_img}
|
||||
src={nftBg}
|
||||
alt=""
|
||||
/>
|
||||
<span className={classes.nftToken_content_nft_des}>
|
||||
{t("Start mining after node subscription ends.")}
|
||||
</span>
|
||||
</div>
|
||||
) : (
|
||||
<div className={classes.nftToken_content_nft_mint}>
|
||||
<div
|
||||
className={classes.nftToken_content_nft_mint_btn}
|
||||
<div className={classes.userinfo_top_right_btns_item}>
|
||||
<span>{getLevelName(userData.level)}</span>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div
|
||||
className={classes.userinfo_top_right_connect}
|
||||
onClick={() => {
|
||||
open();
|
||||
}}
|
||||
>
|
||||
<span>{t("链接钱包")}</span>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<ul className={classes.userinfo_data}>
|
||||
<li>
|
||||
<span className={classes.userinfo_data_num}>
|
||||
{userData?.directPushNode || 0}
|
||||
</span>
|
||||
<span className={classes.userinfo_data_des}>
|
||||
{t("Direct Node")}
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<span className={classes.userinfo_data_num}>
|
||||
{userData?.teamNode || 0}
|
||||
</span>
|
||||
<span className={classes.userinfo_data_des}>
|
||||
{t("Team Node")}
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<span className={classes.userinfo_data_num}>
|
||||
{userData?.revenueUsdt || 0}
|
||||
<p>USDT</p>
|
||||
</span>
|
||||
<span className={classes.userinfo_data_des}>
|
||||
{t("Push income")}
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div className={classes.nftToken}>
|
||||
<ul className={classes.nftToken_tab}>
|
||||
<li
|
||||
className={tabIndex == 0 ? classes.nftToken_tab_active : ""}
|
||||
onClick={() => setTabIndex(0)}
|
||||
>
|
||||
NODE
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div className={classes.nftToken_content}>
|
||||
{tabIndex == 0 && (
|
||||
<>
|
||||
{address ? (
|
||||
<>
|
||||
{userData?.nodeNumber && userData?.nodeNumber > 0 ? (
|
||||
<div className={classes.nftToken_content_nft}>
|
||||
<div className={classes.nftToken_content_nft_top}>
|
||||
<span>You own {userData.nodeNumber} nodes</span>
|
||||
<span
|
||||
onClick={() => {
|
||||
navigate("/mint");
|
||||
}}
|
||||
>
|
||||
<span>{t("Buy Node")}</span>
|
||||
{t("Buy Node")}
|
||||
<IconFont
|
||||
className={
|
||||
classes.nftToken_content_nft_mint_btn_icon
|
||||
}
|
||||
name="chevronsrightshuangyoujiantou"
|
||||
color={"#101010"}
|
||||
color={"#2DFCFC"}
|
||||
/>
|
||||
</div>
|
||||
<span>{t("Buy Edge AI Node.")}</span>
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<div className={classes.nftToken_content_userDisconnect}>
|
||||
<span>
|
||||
{t(
|
||||
"The wallet is not linked and cannot show you the Node."
|
||||
)}
|
||||
<img
|
||||
className={classes.nftToken_content_nft_img}
|
||||
src={nftBg}
|
||||
alt=""
|
||||
/>
|
||||
<span className={classes.nftToken_content_nft_des}>
|
||||
{t("Start mining after node subscription ends.")}
|
||||
</span>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={classes.invite}>
|
||||
<div className={classes.invite_top}>
|
||||
<span>{t("邀请")}</span>
|
||||
{address && (
|
||||
<span
|
||||
onClick={() => {
|
||||
navigate("/invitationlist");
|
||||
}}
|
||||
>
|
||||
{t("邀请列表")}{" "}
|
||||
<IconFont
|
||||
name="chevronsrightshuangyoujiantou"
|
||||
color={"#2DFCFC"}
|
||||
/>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className={classes.invite_content}>
|
||||
<span>{t("邀请链接")}</span>
|
||||
<div className={classes.invite_content_link}>
|
||||
{address ? (
|
||||
<>
|
||||
{userData?.nodeNumber && userData?.nodeNumber > 0 ? (
|
||||
<>
|
||||
<span>{shortenString(userInviteLink, 15, 15)}</span>
|
||||
<IconFont
|
||||
onClick={() => {
|
||||
copyText(userInviteLink);
|
||||
}}
|
||||
className={classes.invite_content_icon}
|
||||
name="fuzhi"
|
||||
color={"#fff"}
|
||||
/>{" "}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<span>
|
||||
{t("Buy Edge AI Node to get invitation link")}
|
||||
</span>
|
||||
</>
|
||||
<div className={classes.nftToken_content_nft_mint}>
|
||||
<div
|
||||
className={classes.nftToken_content_nft_mint_btn}
|
||||
onClick={() => {
|
||||
navigate("/mint");
|
||||
}}
|
||||
>
|
||||
<span>{t("Buy Node")}</span>
|
||||
<IconFont
|
||||
className={
|
||||
classes.nftToken_content_nft_mint_btn_icon
|
||||
}
|
||||
name="chevronsrightshuangyoujiantou"
|
||||
color={"#101010"}
|
||||
/>
|
||||
</div>
|
||||
<span>{t("Buy Edge AI Node.")}</span>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<span>{t("Link wallet to get invitation link")}</span>
|
||||
<div className={classes.nftToken_content_userDisconnect}>
|
||||
<span>
|
||||
{t(
|
||||
"The wallet is not linked and cannot show you the Node."
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<span>
|
||||
{t(
|
||||
"Invite your friends to become YOTTA nodes and you will get a 20% rebate."
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</PullToRefresh>
|
||||
</>
|
||||
|
||||
<div className={classes.invite}>
|
||||
<div className={classes.invite_top}>
|
||||
<span>{t("邀请")}</span>
|
||||
{address && (
|
||||
<span
|
||||
onClick={() => {
|
||||
navigate("/invitationlist");
|
||||
}}
|
||||
>
|
||||
{t("邀请列表")}{" "}
|
||||
<IconFont
|
||||
name="chevronsrightshuangyoujiantou"
|
||||
color={"#2DFCFC"}
|
||||
/>
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className={classes.invite_content}>
|
||||
<span>{t("邀请链接")}</span>
|
||||
<div className={classes.invite_content_link}>
|
||||
{address ? (
|
||||
<>
|
||||
{userData?.nodeNumber && userData?.nodeNumber > 0 ? (
|
||||
<>
|
||||
<span>{shortenString(userInviteLink, 15, 15)}</span>
|
||||
<IconFont
|
||||
onClick={() => {
|
||||
copyText(userInviteLink);
|
||||
}}
|
||||
className={classes.invite_content_icon}
|
||||
name="fuzhi"
|
||||
color={"#fff"}
|
||||
/>{" "}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<span>
|
||||
{t("Buy Edge AI Node to get invitation link")}
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<span>{t("Link wallet to get invitation link")}</span>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<span>
|
||||
{t(
|
||||
"Invite your friends to become YOTTA nodes and you will get a 20% rebate."
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</PullToRefresh>
|
||||
);
|
||||
}
|
||||
|
||||
function Desktop() {
|
||||
const {
|
||||
getHomeData,
|
||||
statusRecord,
|
||||
Token,
|
||||
address,
|
||||
setUserData,
|
||||
userData,
|
||||
tabIndex,
|
||||
t,
|
||||
setTabIndex,
|
||||
navigate,
|
||||
userInviteLink,
|
||||
} = useHome();
|
||||
const {
|
||||
nodeConfig,
|
||||
num,
|
||||
setNum,
|
||||
approveUsdt,
|
||||
balance,
|
||||
approveLoadingToast,
|
||||
costNum,
|
||||
setApproveUsdt,
|
||||
buyLoadingToast,
|
||||
orderInfo,
|
||||
updateNodeConfig,
|
||||
startPollingCheckBuyStatus,
|
||||
} = useMint();
|
||||
const { columns, list, loadMore, hasMore } = useInvitationList();
|
||||
return <></>;
|
||||
}
|
||||
|
||||
export default {
|
||||
Mobile,
|
||||
Desktop,
|
||||
};
|
||||
|
|
|
@ -4,40 +4,12 @@
|
|||
* @LastEditTime: 2024-06-27 15:33:01
|
||||
* @Author: John
|
||||
*/
|
||||
import usePagination from "@/hook/usePagination";
|
||||
import { api_recommended_list } from "@/server/api";
|
||||
import { RecommendedListItem } from "@/server/module";
|
||||
import { Empty, InfiniteScroll } from "antd-mobile";
|
||||
import DataTable, { TableColumn } from "react-data-table-component";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import DataTable from "react-data-table-component";
|
||||
import useInvitationList from "./Feature/useInvitationList";
|
||||
|
||||
export default function () {
|
||||
const { t } = useTranslation();
|
||||
const columns: TableColumn<RecommendedListItem>[] = [
|
||||
{
|
||||
name: t("地址"),
|
||||
selector: (row) => row.walletAddress,
|
||||
grow: 9,
|
||||
},
|
||||
{
|
||||
name: "Node",
|
||||
selector: (row) => row.nodeNumber,
|
||||
grow: 1,
|
||||
// @ts-ignore
|
||||
right: "true",
|
||||
},
|
||||
];
|
||||
|
||||
const { list, hasMore, loadMore } = usePagination<RecommendedListItem>({
|
||||
service({ pageNum, pageSize }) {
|
||||
return new Promise(async (reslove) => {
|
||||
const { data } = await api_recommended_list().send({
|
||||
queryParams: { pageNum, pageSize },
|
||||
});
|
||||
reslove(data?.data.records || []);
|
||||
});
|
||||
},
|
||||
});
|
||||
const { columns, list, loadMore, hasMore } = useInvitationList();
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
|
@ -1,110 +1,36 @@
|
|||
/*
|
||||
* @LastEditors: John
|
||||
* @Date: 2024-06-18 15:28:03
|
||||
* @LastEditTime: 2024-06-27 17:17:09
|
||||
* @LastEditTime: 2024-06-28 14:33:02
|
||||
* @Author: John
|
||||
*/
|
||||
import { cn, filterAddressBeforeZero, filterAmountBeforeZero } from "@/utils";
|
||||
import classes from "./Mint.module.css";
|
||||
import classes from "./Mint-m.module.css";
|
||||
import nft_bg from "@/assets/nft_bg.svg";
|
||||
import Button from "antd-mobile/es/components/button";
|
||||
import Space from "antd-mobile/es/components/space";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import {
|
||||
api_get_homepage_user_data,
|
||||
api_get_nft_configuration_data,
|
||||
api_node_order,
|
||||
api_users_cancel_orders,
|
||||
} from "@/server/api";
|
||||
import {
|
||||
NftConfigurationData,
|
||||
NftOrder,
|
||||
NodeOrder,
|
||||
UserHomeData,
|
||||
} from "@/server/module";
|
||||
import {
|
||||
authorizedU,
|
||||
getApproveUsdt,
|
||||
getBalance,
|
||||
payByContract,
|
||||
} from "@/contract/utils";
|
||||
import { Dialog, Modal, Stepper, Toast } from "antd-mobile";
|
||||
import useUserStore from "@/store/User";
|
||||
import usePollingCheckBuyStatus from "@/hook/usePollingCheckBuyStatus";
|
||||
import { ToastHandler } from "antd-mobile/es/components/toast";
|
||||
import { api_node_order } from "@/server/api";
|
||||
import { authorizedU, getApproveUsdt, payByContract } from "@/contract/utils";
|
||||
import { Stepper, Toast } from "antd-mobile";
|
||||
import { BaseError } from "wagmi";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { toWei } from "web3-utils";
|
||||
import useMint from "./Feature/useMint";
|
||||
export default function () {
|
||||
const { t } = useTranslation();
|
||||
const { Token } = useUserStore();
|
||||
const [nodeConfig, setNodeConfig] = useState<UserHomeData>();
|
||||
const [approveUsdt, setApproveUsdt] = useState<bigint>(0n);
|
||||
const [balance, setBalance] = useState<bigint>(0n);
|
||||
const orderInfo = useRef<NodeOrder>();
|
||||
const navigate = useNavigate();
|
||||
const [num, setNum] = useState(1);
|
||||
|
||||
const buyLoadingToast = useRef<ToastHandler>();
|
||||
const approveLoadingToast = useRef<ToastHandler>();
|
||||
const {
|
||||
transcationStatus,
|
||||
nodeConfig,
|
||||
num,
|
||||
setNum,
|
||||
approveUsdt,
|
||||
t,
|
||||
balance,
|
||||
approveLoadingToast,
|
||||
costNum,
|
||||
setApproveUsdt,
|
||||
buyLoadingToast,
|
||||
orderInfo,
|
||||
updateNodeConfig,
|
||||
startPollingCheckBuyStatus,
|
||||
stopPollingCheckBuyStatus,
|
||||
} = usePollingCheckBuyStatus("NORMAL");
|
||||
|
||||
const costNum = useMemo(
|
||||
() =>
|
||||
BigInt(
|
||||
toWei(`${parseFloat(`${nodeConfig?.nodePrice || "0"}`) * num}`, "ether")
|
||||
),
|
||||
[nodeConfig?.nodePrice, num]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
updateNodeConfig();
|
||||
|
||||
return () => {};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
Toast.show({ icon: "loading", content: t("正在获取已授权金额") });
|
||||
setBalance(await getBalance());
|
||||
setApproveUsdt(await getApproveUsdt());
|
||||
Toast.clear();
|
||||
})();
|
||||
|
||||
return () => {};
|
||||
}, [Token]);
|
||||
|
||||
async function updateNodeConfig() {
|
||||
const { data } = await api_get_homepage_user_data().send({});
|
||||
setNodeConfig(data?.data);
|
||||
}
|
||||
useEffect(() => {
|
||||
if (transcationStatus == "success") {
|
||||
buyLoadingToast.current?.close();
|
||||
stopPollingCheckBuyStatus();
|
||||
Dialog.alert({
|
||||
content: `${t(
|
||||
"Buy successful. Please return to the homepage to view."
|
||||
)}`,
|
||||
confirmText: "OK",
|
||||
onConfirm() {
|
||||
navigate("/");
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return () => {};
|
||||
}, [transcationStatus]);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {};
|
||||
}, []);
|
||||
|
||||
} = useMint();
|
||||
return (
|
||||
<>
|
||||
<div className={cn(classes.Mint, classes.container)}>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* @LastEditors: John
|
||||
* @Date: 2024-06-17 18:19:27
|
||||
* @LastEditTime: 2024-06-27 11:40:59
|
||||
* @LastEditTime: 2024-06-28 15:32:57
|
||||
* @Author: John
|
||||
*/
|
||||
import { type ClassValue, clsx } from "clsx";
|
||||
|
|
Loading…
Reference in New Issue