parent
559411a9a6
commit
3b13975d04
|
@ -1,10 +1,12 @@
|
||||||
###
|
###
|
||||||
# @LastEditors: John
|
# @LastEditors: John
|
||||||
# @Date: 2024-06-18 10:12:21
|
# @Date: 2024-06-18 10:12:21
|
||||||
# @LastEditTime: 2024-06-19 15:52:17
|
# @LastEditTime: 2024-06-22 11:22:13
|
||||||
# @Author: John
|
# @Author: John
|
||||||
###
|
###
|
||||||
|
VITE_BASE_URL=http://192.168.10.167:5173/
|
||||||
VITE_BASE_API_URL=/dev
|
VITE_BASE_API_URL=/dev
|
||||||
VITE_PARTICIPATE_CHAIN_ID=97
|
VITE_PARTICIPATE_CHAIN_ID=97
|
||||||
VITE_NETWORK_USDT_ADDRESS=0x204074AD198E7c6e79E195DAf576bc7D53967B45
|
VITE_PURCHASED_CONTRACT_ADDRESS=0x37644e2E1Ac2D0b87f693Ad64A154f3A7fe09b93
|
||||||
|
VITE_NETWORK_USDT_ADDRESS=0xACFE3DF8ACeF83De51d53E22ADE30F18eaB4969A
|
||||||
VITE_CHECK_TRANSACTION_DETAILS_URL=https://testnet.bscscan.com/
|
VITE_CHECK_TRANSACTION_DETAILS_URL=https://testnet.bscscan.com/
|
|
@ -1,3 +1,4 @@
|
||||||
|
VITE_BASE_URL=/
|
||||||
VITE_BASE_API_URL=/dev
|
VITE_BASE_API_URL=/dev
|
||||||
VITE_PARTICIPATE_CHAIN_ID=56
|
VITE_PARTICIPATE_CHAIN_ID=56
|
||||||
VITE_NETWORK_USDT_ADDRESS=0x55d398326f99059ff775485246999027b3197955
|
VITE_NETWORK_USDT_ADDRESS=0x55d398326f99059ff775485246999027b3197955
|
||||||
|
|
Binary file not shown.
|
@ -15,6 +15,7 @@
|
||||||
"@hyper-fetch/react": "^5.7.5",
|
"@hyper-fetch/react": "^5.7.5",
|
||||||
"@tanstack/react-query": "^5.45.1",
|
"@tanstack/react-query": "^5.45.1",
|
||||||
"@web3modal/wagmi": "^5.0.2",
|
"@web3modal/wagmi": "^5.0.2",
|
||||||
|
"ahooks": "^3.8.0",
|
||||||
"antd-mobile": "^5.36.1",
|
"antd-mobile": "^5.36.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"i18next": "^23.11.5",
|
"i18next": "^23.11.5",
|
||||||
|
@ -28,6 +29,7 @@
|
||||||
"vconsole": "^3.15.1",
|
"vconsole": "^3.15.1",
|
||||||
"viem": "^2.14.2",
|
"viem": "^2.14.2",
|
||||||
"wagmi": "^2.10.2",
|
"wagmi": "^2.10.2",
|
||||||
|
"web3-utils": "^4.3.0",
|
||||||
"zustand": "^4.5.2"
|
"zustand": "^4.5.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
24
src/App.tsx
24
src/App.tsx
|
@ -1,10 +1,10 @@
|
||||||
/*
|
/*
|
||||||
* @LastEditors: John
|
* @LastEditors: John
|
||||||
* @Date: 2024-06-17 17:20:03
|
* @Date: 2024-06-17 17:20:03
|
||||||
* @LastEditTime: 2024-06-19 16:59:21
|
* @LastEditTime: 2024-06-21 14:19:52
|
||||||
* @Author: John
|
* @Author: John
|
||||||
*/
|
*/
|
||||||
import { Route, Router, Routes } from "react-router-dom";
|
import { Route, Routes } from "react-router-dom";
|
||||||
import "./style/ant-cover-m.css";
|
import "./style/ant-cover-m.css";
|
||||||
import "./style/react-data-table-component-cover-m.css";
|
import "./style/react-data-table-component-cover-m.css";
|
||||||
import "./App.css";
|
import "./App.css";
|
||||||
|
@ -19,14 +19,32 @@ import InvitationList from "./pages/InvitationList";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import useUserStore from "./store/User";
|
import useUserStore from "./store/User";
|
||||||
|
import { getUrlQueryParam } from "./utils";
|
||||||
|
import { UrlQueryParamsKey } from "./constants";
|
||||||
|
import { signAndLogin } from "./utils/wallet";
|
||||||
|
import { useAccount } from "wagmi";
|
||||||
function App() {
|
function App() {
|
||||||
const { i18n } = useTranslation();
|
const { i18n } = useTranslation();
|
||||||
const { Lang: currantLang } = useUserStore();
|
const { Lang: currantLang, UpdateInviteCode } = useUserStore();
|
||||||
|
const { address } = useAccount();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
i18n.changeLanguage(currantLang);
|
i18n.changeLanguage(currantLang);
|
||||||
|
UpdateInviteCode(getUrlQueryParam(UrlQueryParamsKey.INVITE_CODE) || "");
|
||||||
return () => {};
|
return () => {};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
(async () => {
|
||||||
|
await signAndLogin(address);
|
||||||
|
console.log("login success!");
|
||||||
|
})();
|
||||||
|
return () => {};
|
||||||
|
}, [address]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<RouterLogProvider>
|
<RouterLogProvider>
|
||||||
|
|
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 22 KiB |
|
@ -8,7 +8,7 @@ import classes from "./RecordsItem.module.css";
|
||||||
export default function RecordsItem({
|
export default function RecordsItem({
|
||||||
itemList,
|
itemList,
|
||||||
}: {
|
}: {
|
||||||
itemList: { title: string; value: string; valueColor?: string }[];
|
itemList: { title: string; value?: string; valueColor?: string }[];
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
|
@ -1,13 +1,17 @@
|
||||||
/*
|
/*
|
||||||
* @LastEditors: John
|
* @LastEditors: John
|
||||||
* @Date: 2024-06-17 17:57:13
|
* @Date: 2024-06-17 17:57:13
|
||||||
* @LastEditTime: 2024-06-19 16:26:15
|
* @LastEditTime: 2024-06-21 11:45:40
|
||||||
* @Author: John
|
* @Author: John
|
||||||
*/
|
*/
|
||||||
export enum ASYNC_STORAGE_KEY {
|
export enum ASYNC_STORAGE_KEY {
|
||||||
Store = "user.store",
|
Store = "user.store",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum UrlQueryParamsKey {
|
||||||
|
INVITE_CODE = "inviteCode",
|
||||||
|
}
|
||||||
|
|
||||||
export enum Lang {
|
export enum Lang {
|
||||||
en = "en",
|
en = "en",
|
||||||
cn = "cn",
|
cn = "cn",
|
||||||
|
@ -15,3 +19,8 @@ export enum Lang {
|
||||||
jp = "jp",
|
jp = "jp",
|
||||||
de = "de",
|
de = "de",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum CoinName {
|
||||||
|
USDT = "USDT",
|
||||||
|
RMOB = "RMOB",
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,268 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "amount",
|
||||||
|
"type": "uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "orderId",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "buyHMNFT",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "hongMoAddr",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "payAddr",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "constructor"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "owner",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "OwnableInvalidOwner",
|
||||||
|
"type": "error"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "account",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "OwnableUnauthorizedAccount",
|
||||||
|
"type": "error"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": true,
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "tokenId",
|
||||||
|
"type": "uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": true,
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "amount",
|
||||||
|
"type": "uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": true,
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "buyAddr",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": false,
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "orderId",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "BuySuccess",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": true,
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "previousOwner",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": true,
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "newOwner",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "OwnershipTransferred",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [],
|
||||||
|
"name": "renounceOwnership",
|
||||||
|
"outputs": [],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "tokenIn",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "setTokenIndex",
|
||||||
|
"outputs": [],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "newOwner",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "transferOwnership",
|
||||||
|
"outputs": [],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "amount",
|
||||||
|
"type": "uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "orderId",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "upgradePrivilege",
|
||||||
|
"outputs": [],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anonymous": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"indexed": true,
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "amount",
|
||||||
|
"type": "uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": true,
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "buyAddr",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"indexed": true,
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "orderId",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "UpgradeRange",
|
||||||
|
"type": "event"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [],
|
||||||
|
"name": "hongMoNFT",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "contract HongMoNFT",
|
||||||
|
"name": "",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [],
|
||||||
|
"name": "owner",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [],
|
||||||
|
"name": "price",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [],
|
||||||
|
"name": "tokenIndex",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [],
|
||||||
|
"name": "totalSupply",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [],
|
||||||
|
"name": "usdc",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "contract IERC20",
|
||||||
|
"name": "",
|
||||||
|
"type": "address"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
}
|
||||||
|
]
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* @LastEditors: John
|
* @LastEditors: John
|
||||||
* @Date: 2024-06-19 15:48:57
|
* @Date: 2024-06-19 15:48:57
|
||||||
* @LastEditTime: 2024-06-19 16:13:14
|
* @LastEditTime: 2024-06-24 11:09:12
|
||||||
* @Author: John
|
* @Author: John
|
||||||
*/
|
*/
|
||||||
import { config } from "@/components/WalletProvider";
|
import { config } from "@/components/WalletProvider";
|
||||||
|
@ -10,19 +10,26 @@ import {
|
||||||
estimateGas,
|
estimateGas,
|
||||||
writeContract,
|
writeContract,
|
||||||
waitForTransactionReceipt,
|
waitForTransactionReceipt,
|
||||||
|
getAccount,
|
||||||
} from "@wagmi/core";
|
} from "@wagmi/core";
|
||||||
import { encodeFunctionData } from "viem/utils";
|
import { encodeFunctionData } from "viem/utils";
|
||||||
import erc20Abi from "@/contract/abi/erc20abi.json";
|
import erc20Abi from "@/contract/abi/erc20abi.json";
|
||||||
import usdtAbi from "@/contract/abi/USDT.json";
|
import usdtAbi from "@/contract/abi/USDT.json";
|
||||||
|
import RedDevilsAbi from "@/contract/abi/RedDevils.json";
|
||||||
import Toast from "antd-mobile/es/components/toast";
|
import Toast from "antd-mobile/es/components/toast";
|
||||||
|
import { EstimateGasErrorType, WriteContractErrorType } from "viem";
|
||||||
|
import i18next from "i18next";
|
||||||
|
import { BaseError } from "wagmi";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 获取代币余额
|
* @description 获取代币余额
|
||||||
* @param {string} fromAddress
|
* @param {string} fromAddress
|
||||||
* @return {*}
|
* @return {*}
|
||||||
*/
|
*/
|
||||||
export const getBalance = async (fromAddress: string): Promise<bigint> => {
|
export const getBalance = async (): Promise<bigint> => {
|
||||||
return new Promise((reslove, reject) => {
|
return new Promise((reslove, reject) => {
|
||||||
|
const fromAddress = getAccount(config).address;
|
||||||
|
if (!fromAddress) return reject(new Error("address is emtiy"));
|
||||||
readContract(config, {
|
readContract(config, {
|
||||||
abi: erc20Abi,
|
abi: erc20Abi,
|
||||||
address: import.meta.env.VITE_NETWORK_USDT_ADDRESS,
|
address: import.meta.env.VITE_NETWORK_USDT_ADDRESS,
|
||||||
|
@ -33,15 +40,12 @@ export const getBalance = async (fromAddress: string): Promise<bigint> => {
|
||||||
console.log("U余额:", res);
|
console.log("U余额:", res);
|
||||||
if (typeof res == "undefined") {
|
if (typeof res == "undefined") {
|
||||||
// 获取授权U失败
|
// 获取授权U失败
|
||||||
Toast.show({
|
reject(new BaseError("get balance of usdt error!"));
|
||||||
icon: "fail",
|
|
||||||
content: "get balance of usdt error!",
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
reslove(res);
|
reslove(res);
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err: BaseError) => {
|
||||||
console.log("get balance of usdt err", err);
|
console.log("get balance of usdt err", err);
|
||||||
reject(err);
|
reject(err);
|
||||||
});
|
});
|
||||||
|
@ -53,31 +57,28 @@ export const getBalance = async (fromAddress: string): Promise<bigint> => {
|
||||||
* @param {string} fromAddress
|
* @param {string} fromAddress
|
||||||
* @return {*}
|
* @return {*}
|
||||||
*/
|
*/
|
||||||
export const getApproveUsdt = async (
|
export const getApproveUsdt = async (): Promise<bigint> => {
|
||||||
contractAddress: string,
|
|
||||||
fromAddress: string
|
|
||||||
): Promise<bigint> => {
|
|
||||||
return new Promise((reslove, reject) => {
|
return new Promise((reslove, reject) => {
|
||||||
|
const fromAddress = getAccount(config).address;
|
||||||
|
if (!fromAddress) return reject(new Error("address is emtiy"));
|
||||||
|
|
||||||
readContract(config, {
|
readContract(config, {
|
||||||
abi: erc20Abi,
|
abi: erc20Abi,
|
||||||
address: import.meta.env.VITE_NETWORK_USDT_ADDRESS,
|
address: import.meta.env.VITE_NETWORK_USDT_ADDRESS,
|
||||||
functionName: "allowance",
|
functionName: "allowance",
|
||||||
args: [fromAddress, contractAddress],
|
args: [fromAddress, import.meta.env.VITE_PURCHASED_CONTRACT_ADDRESS],
|
||||||
})
|
})
|
||||||
.then((res: any) => {
|
.then((res: any) => {
|
||||||
console.log("上次授权的U:", res);
|
console.log("上次授权的U:", res);
|
||||||
if (typeof res == "undefined") {
|
if (typeof res == "undefined") {
|
||||||
// 获取授权U失败
|
// 获取授权U失败
|
||||||
Toast.show({
|
reject(new BaseError("get approve usdt error"));
|
||||||
icon: "fail",
|
|
||||||
content: "get approve usdt error!",
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
reslove(res);
|
reslove(res);
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err: BaseError) => {
|
||||||
console.log("get approve usdt err", err);
|
console.log("get approve usdt error", err);
|
||||||
reject(err);
|
reject(err);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -88,15 +89,19 @@ export const getApproveUsdt = async (
|
||||||
* @param {bigint} uNum
|
* @param {bigint} uNum
|
||||||
* @return {*}
|
* @return {*}
|
||||||
*/
|
*/
|
||||||
export const authorizedU = async (uNum: bigint, contractAddress: string) => {
|
export const authorizedU = async (uNum: bigint) => {
|
||||||
console.log("授权金额参数:", contractAddress, uNum);
|
console.log(
|
||||||
|
"授权金额参数:",
|
||||||
|
import.meta.env.VITE_PURCHASED_CONTRACT_ADDRESS,
|
||||||
|
uNum
|
||||||
|
);
|
||||||
return new Promise<void>((reslove, reject) => {
|
return new Promise<void>((reslove, reject) => {
|
||||||
estimateGas(config, {
|
estimateGas(config, {
|
||||||
to: import.meta.env.VITE_NETWORK_USDT_ADDRESS,
|
to: import.meta.env.VITE_NETWORK_USDT_ADDRESS,
|
||||||
data: encodeFunctionData({
|
data: encodeFunctionData({
|
||||||
abi: usdtAbi,
|
abi: usdtAbi,
|
||||||
functionName: "approve",
|
functionName: "approve",
|
||||||
args: [contractAddress, uNum],
|
args: [import.meta.env.VITE_PURCHASED_CONTRACT_ADDRESS, uNum],
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
.then((gas) => {
|
.then((gas) => {
|
||||||
|
@ -111,7 +116,7 @@ export const authorizedU = async (uNum: bigint, contractAddress: string) => {
|
||||||
abi: usdtAbi,
|
abi: usdtAbi,
|
||||||
address: import.meta.env.VITE_NETWORK_USDT_ADDRESS,
|
address: import.meta.env.VITE_NETWORK_USDT_ADDRESS,
|
||||||
functionName: "approve",
|
functionName: "approve",
|
||||||
args: [contractAddress, uNum],
|
args: [import.meta.env.VITE_PURCHASED_CONTRACT_ADDRESS, uNum],
|
||||||
gas: gasPrice,
|
gas: gasPrice,
|
||||||
// gas,
|
// gas,
|
||||||
})
|
})
|
||||||
|
@ -122,14 +127,154 @@ export const authorizedU = async (uNum: bigint, contractAddress: string) => {
|
||||||
});
|
});
|
||||||
if (transactionReceipt.status == "success") reslove();
|
if (transactionReceipt.status == "success") reslove();
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err: BaseError) => {
|
||||||
console.log("approve error", err);
|
console.log("approve error", err);
|
||||||
reject(err);
|
reject(err);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err: BaseError) => {
|
||||||
console.log("estimate approve gas error", err);
|
console.log("estimate approve gas error", err);
|
||||||
reject(err);
|
reject(err);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* payByContract
|
||||||
|
* @param amount
|
||||||
|
* @param orderID
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export async function payByContract(amount: bigint, orderID: string) {
|
||||||
|
console.log("pay buy contract params", { amount, orderID });
|
||||||
|
console.log("NETWORK_USDT:", import.meta.env.VITE_NETWORK_USDT_ADDRESS);
|
||||||
|
|
||||||
|
return new Promise<string>(async (reslove, reject) => {
|
||||||
|
try {
|
||||||
|
const balance = await getBalance();
|
||||||
|
if (balance < amount) {
|
||||||
|
console.log("用户代币余额不足");
|
||||||
|
reject(new BaseError(i18next.t("余额不足")));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("当前要授权的U:", amount);
|
||||||
|
let approvedU = await getApproveUsdt();
|
||||||
|
if (approvedU < amount) {
|
||||||
|
await authorizedU(amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("参数:", amount, orderID);
|
||||||
|
estimateGas(config, {
|
||||||
|
to: import.meta.env.VITE_PURCHASED_CONTRACT_ADDRESS,
|
||||||
|
data: encodeFunctionData({
|
||||||
|
abi: RedDevilsAbi,
|
||||||
|
functionName: "buyHMNFT",
|
||||||
|
args: [amount, orderID],
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.then((gas) => {
|
||||||
|
const gasPrice = (gas * 12n) / 10n;
|
||||||
|
console.log("estimate gas:%d , my gas: %d", gas, gasPrice);
|
||||||
|
writeContract(config, {
|
||||||
|
abi: RedDevilsAbi,
|
||||||
|
address: import.meta.env.VITE_PURCHASED_CONTRACT_ADDRESS,
|
||||||
|
functionName: "buyHMNFT",
|
||||||
|
args: [amount, orderID],
|
||||||
|
gas: gasPrice,
|
||||||
|
})
|
||||||
|
.then((receipt) => {
|
||||||
|
console.log("write contract success!, receipt:", receipt);
|
||||||
|
reslove(receipt);
|
||||||
|
})
|
||||||
|
.catch((err: BaseError) => {
|
||||||
|
console.log("buyHMNFT Transaction err", err.details);
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((err: BaseError) => {
|
||||||
|
console.log("buyHMNFT estimateGas err", err.details);
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.log("pay By Contract catch err", err);
|
||||||
|
reject(new BaseError(`${err}`));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* upGradeByContract
|
||||||
|
* @param amount
|
||||||
|
* @param orderID
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export async function upGradeByContract(amount: bigint, orderID: string) {
|
||||||
|
console.log("pay buy contract params", { amount, orderID });
|
||||||
|
console.log("NETWORK_USDT:", import.meta.env.VITE_NETWORK_USDT_ADDRESS);
|
||||||
|
|
||||||
|
return new Promise<string>(async (reslove, reject) => {
|
||||||
|
try {
|
||||||
|
const balance = await getBalance();
|
||||||
|
if (balance < amount) {
|
||||||
|
console.log("用户代币余额不足");
|
||||||
|
reject(new BaseError(i18next.t("余额不足")));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("当前要授权的U:", amount);
|
||||||
|
let approvedU = await getApproveUsdt();
|
||||||
|
if (approvedU < amount) {
|
||||||
|
await authorizedU(amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("参数:", amount, orderID);
|
||||||
|
estimateGas(config, {
|
||||||
|
to: import.meta.env.VITE_PURCHASED_CONTRACT_ADDRESS,
|
||||||
|
data: encodeFunctionData({
|
||||||
|
abi: RedDevilsAbi,
|
||||||
|
functionName: "upgradePrivilege",
|
||||||
|
args: [amount, orderID],
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
.then((gas) => {
|
||||||
|
const gasPrice = (gas * 12n) / 10n;
|
||||||
|
console.log("estimate gas:%d , my gas: %d", gas, gasPrice);
|
||||||
|
writeContract(config, {
|
||||||
|
abi: RedDevilsAbi,
|
||||||
|
address: import.meta.env.VITE_PURCHASED_CONTRACT_ADDRESS,
|
||||||
|
functionName: "upgradePrivilege",
|
||||||
|
args: [amount, orderID],
|
||||||
|
gas: gasPrice,
|
||||||
|
})
|
||||||
|
.then((receipt) => {
|
||||||
|
console.log("write contract success!, receipt:", receipt);
|
||||||
|
reslove(receipt);
|
||||||
|
})
|
||||||
|
.catch((err: BaseError) => {
|
||||||
|
console.log("upgradePrivilege Transaction err", err.details);
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((err: BaseError) => {
|
||||||
|
console.log("upgradePrivilege estimateGas err", err.details);
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
reject(new BaseError(`${err}`));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* receiveByContract
|
||||||
|
* @param amount
|
||||||
|
* @param orderID
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export async function receiveByContract(amount: bigint, orderID: string) {
|
||||||
|
console.log("pay buy contract params", { amount, orderID });
|
||||||
|
console.log("NETWORK_USDT:", import.meta.env.VITE_NETWORK_USDT_ADDRESS);
|
||||||
|
|
||||||
|
return new Promise<string>(async (reslove, reject) => {});
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
/*
|
||||||
|
* @LastEditors: John
|
||||||
|
* @Date: 2024-06-21 16:08:23
|
||||||
|
* @LastEditTime: 2024-06-21 16:12:31
|
||||||
|
* @Author: John
|
||||||
|
*/
|
||||||
|
import { useRef, useState } from "react";
|
||||||
|
import { waitForTransactionReceipt } from "@wagmi/core";
|
||||||
|
import { config } from "@/components/WalletProvider";
|
||||||
|
/**
|
||||||
|
* @description: 轮询查询交易,获取nft
|
||||||
|
* @return {*}
|
||||||
|
*/
|
||||||
|
export default function (type: "NFT" | "NORMAL") {
|
||||||
|
const [buyNftIds, setBuyNftIds] = useState<string>("");
|
||||||
|
const [transcationStatus, setTranscationStatus] = useState<
|
||||||
|
"success" | undefined
|
||||||
|
>(undefined);
|
||||||
|
const stop = useRef(false);
|
||||||
|
|
||||||
|
function startPollingCheckBuyStatus(hash: string) {
|
||||||
|
setTranscationStatus(undefined);
|
||||||
|
setBuyNftIds("");
|
||||||
|
polling(hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
const checkStatus = async (hash: string) => {
|
||||||
|
return new Promise<void>(async (reslove) => {
|
||||||
|
// let res = await API_GET_ORDER_STATE_BY_HASH(hash);
|
||||||
|
// setBuyNftIds(res.nftIds);
|
||||||
|
// console.log("得到nft ids:", res.nftIds);
|
||||||
|
|
||||||
|
const transactionReceipt = await waitForTransactionReceipt(config, {
|
||||||
|
hash: hash as `0x${string}`,
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("transaction receipt:", transactionReceipt);
|
||||||
|
if (transactionReceipt.status == "success") {
|
||||||
|
if (type == "NFT") {
|
||||||
|
console.log("transaction receipt success:", transactionReceipt);
|
||||||
|
const nftLogs = transactionReceipt.logs.filter(
|
||||||
|
(v) =>
|
||||||
|
v.topics.length === 4 &&
|
||||||
|
v.topics[1] ===
|
||||||
|
"0x0000000000000000000000000000000000000000000000000000000000000000"
|
||||||
|
); // 过滤(挖币的日志)
|
||||||
|
const nftDataArr = nftLogs.map((v) => v.topics[3]);
|
||||||
|
const nftDataStr = nftDataArr.map(
|
||||||
|
(v) => `#${parseInt(v as string, 16)}`
|
||||||
|
);
|
||||||
|
setBuyNftIds(nftDataStr.join(","));
|
||||||
|
} else {
|
||||||
|
setTranscationStatus("success");
|
||||||
|
stopPollingCheckBuyStatus();
|
||||||
|
reslove();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
reslove();
|
||||||
|
}, 2000);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const polling = async (hash: string) => {
|
||||||
|
await checkStatus(hash);
|
||||||
|
if (stop.current) return;
|
||||||
|
polling(hash);
|
||||||
|
};
|
||||||
|
|
||||||
|
function stopPollingCheckBuyStatus() {
|
||||||
|
stop.current = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
transcationStatus,
|
||||||
|
setBuyNftIds,
|
||||||
|
buyNftIds,
|
||||||
|
startPollingCheckBuyStatus,
|
||||||
|
stopPollingCheckBuyStatus,
|
||||||
|
};
|
||||||
|
}
|
|
@ -35,17 +35,17 @@
|
||||||
"MINT余量:": "MINT余量:",
|
"MINT余量:": "MINT余量:",
|
||||||
"当前MINT价格:": "当前MINT价格:",
|
"当前MINT价格:": "当前MINT价格:",
|
||||||
"价格说明:": "价格说明:",
|
"价格说明:": "价格说明:",
|
||||||
"100USDT起,每增加100名普通会员,NFT价格上涨1%,既:前100名价格为100USDT/枚,101-200名价格为100u+100u*1%=101USDT/枚,以此类推。": "100USDT起,每增加100名普通会员,NFT价格上涨1%,既:前100名价格为100USDT/枚,101-200名价格为100u+100u*1%=101USDT/枚,以此类推。",
|
"{{value1}} USDT起,每增加 {{value2}} 名普通会员,NFT价格上涨 {{value3}},既:前 {{value2}} 名价格为 {{value1}} USDT/枚,value4 名价格为{{value1}}u+{{value1}}u*{{value3}}={{value5}} USDT/枚,以此类推。": "{{value1}} USDT起,每增加{{value2}}名普通会员,NFT价格上涨{{value3}},既:前{{value2}}名价格为{{value1}} USDT/枚,{{value4}}名价格为{{value1}}u+{{value1}}u*{{value3}}={{value5}} USDT/枚,以此类推。",
|
||||||
"授权USDT": "授权USDT",
|
"授权USDT": "授权USDT",
|
||||||
"当前级别": "当前级别",
|
"当前级别": "当前级别",
|
||||||
"普通活跃": "普通活跃",
|
"普通活跃": "普通活跃",
|
||||||
"提升级别": "提升级别",
|
"提升级别": "提升级别",
|
||||||
"社长": "社长",
|
"社长": "社长",
|
||||||
"当前升级价格:": "当前升级价格:",
|
"当前升级价格:": "当前升级价格:",
|
||||||
"升级费用100USDT起,其中gas费2USDT,剩余部分50%进入资金池,另外50%平均分给所有升级成功的社长和基金会社长。自第二个社长升级开始,每升级一名社长所需铸造费用增加10%,既第二位社长升级铸造费用为100u+100*10%=110USDT,以此类推。": "升级费用100USDT起,其中gas费2USDT,剩余部分50%进入资金池,另外50%平均分给所有升级成功的社长和基金会社长。自第二个社长升级开始,每升级一名社长所需铸造费用增加10%,既第二位社长升级铸造费用为100u+100*10%=110USDT,以此类推。",
|
"升级费用xxx USDT起,其中gas费2USDT,剩余部分50%进入资金池,另外50%平均分给所有升级成功的社长和基金会社长。自第二个社长升级开始,每升级一名社长所需铸造费用增加xxx,既第二位社长升级铸造费用为xxxu+xxx*xxx=xxx USDT,以此类推。": "升级费用{{value1}} USDT起,其中gas费2USDT,剩余部分50%进入资金池,另外50%平均分给所有升级成功的社长和基金会社长。自第二个社长升级开始,每升级一名社长所需铸造费用增加{{value2}},既第二位社长升级铸造费用为{{value1}}u+{{value1}}*{{value2}}={{value3}} USDT,以此类推。",
|
||||||
"升级条件": "升级条件",
|
"升级条件": "升级条件",
|
||||||
"普通会员": "普通会员",
|
"普通会员": "普通会员",
|
||||||
"(限量20000个)": "(限量20000个)",
|
"(限量xxx个)": "(限量 {{value}} 个)",
|
||||||
"1. MINT一枚NFT成为非活跃普通会员": "1. MINT一枚NFT成为非活跃普通会员",
|
"1. MINT一枚NFT成为非活跃普通会员": "1. MINT一枚NFT成为非活跃普通会员",
|
||||||
"2. MINT NFT并推荐MINT成为活跃普通会员": "2. MINT NFT并推荐MINT成为活跃普通会员",
|
"2. MINT NFT并推荐MINT成为活跃普通会员": "2. MINT NFT并推荐MINT成为活跃普通会员",
|
||||||
"3. 享1%代币空投平分(所有普通会员)": "3. 享1%代币空投平分(所有普通会员)",
|
"3. 享1%代币空投平分(所有普通会员)": "3. 享1%代币空投平分(所有普通会员)",
|
||||||
|
@ -87,5 +87,19 @@
|
||||||
"活跃普通": "活跃普通",
|
"活跃普通": "活跃普通",
|
||||||
|
|
||||||
"复制成功": "复制成功",
|
"复制成功": "复制成功",
|
||||||
"领取成功,前往钱包查看": "领取成功,前往钱包查看"
|
"领取成功,前往钱包查看": "领取成功,前往钱包查看",
|
||||||
|
"链接钱包中...": "链接钱包中...",
|
||||||
|
"无": "无",
|
||||||
|
"服务器错误": "服务器错误",
|
||||||
|
"余额不足": "余额不足",
|
||||||
|
"MINT成功,返回首页查看": "MINT成功,返回首页查看",
|
||||||
|
"正在授权USDT": "正在授权USDT",
|
||||||
|
"购买中": "购买中",
|
||||||
|
"领取中": "领取中",
|
||||||
|
"MINT Nft 获取邀请链接": "MINT Nft 获取邀请链接",
|
||||||
|
"链接钱包获取邀请链接": "链接钱包获取邀请链接",
|
||||||
|
"正在获取已授权金额": "正在获取已授权金额",
|
||||||
|
"升级成功,返回首页查看": "升级成功,返回首页查看",
|
||||||
|
"无级别提升": "无级别提升",
|
||||||
|
"没有更多数据了": "没有更多数据了"
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,17 +35,17 @@
|
||||||
"MINT余量:": "Verbleibende MINT:",
|
"MINT余量:": "Verbleibende MINT:",
|
||||||
"当前MINT价格:": "Aktueller MINT-Preis:",
|
"当前MINT价格:": "Aktueller MINT-Preis:",
|
||||||
"价格说明:": "Preiserklärung:",
|
"价格说明:": "Preiserklärung:",
|
||||||
"100USDT起,每增加100名普通会员,NFT价格上涨1%,既:前100名价格为100USDT/枚,101-200名价格为100u+100u*1%=101USDT/枚,以此类推。": "Beginnend bei 100USDT steigt der NFT-Preis um 1% für jede zusätzlichen 100 Mitglieder: die ersten 100 kosten 100USDT pro Stück, 101-200 kosten 101USDT pro Stück usw.",
|
"{{value1}} USDT起,每增加 {{value2}} 名普通会员,NFT价格上涨 {{value3}},既:前 {{value2}} 名价格为 {{value1}} USDT/枚,value4 名价格为{{value1}}u+{{value1}}u*{{value3}}={{value5}} USDT/枚,以此类推。": "Beginnend bei {{value1}} USDT steigt der NFT-Preis um {{value3}} für jede zusätzlichen {{value2}} Mitglieder: die ersten {{value2}} kosten {{value1}} USDT pro Stück, {{value4}} kosten {{value1}}u+{{value1}}u*{{value3}}={{value5}} USDT pro Stück usw.",
|
||||||
"授权USDT": "USDT autorisieren",
|
"授权USDT": "USDT autorisieren",
|
||||||
"当前级别": "Aktuelles Level",
|
"当前级别": "Aktuelles Level",
|
||||||
"普通活跃": "Aktives Mitglied",
|
"普通活跃": "Aktives Mitglied",
|
||||||
"提升级别": "Levelaufstieg",
|
"提升级别": "Levelaufstieg",
|
||||||
"社长": "Vorsitzender",
|
"社长": "Vorsitzender",
|
||||||
"当前升级价格:": "Aktueller Upgrade-Preis:",
|
"当前升级价格:": "Aktueller Upgrade-Preis:",
|
||||||
"升级费用100USDT起,其中gas费2USDT,剩余部分50%进入资金池,另外50%平均分给所有升级成功的社长和基金会社长。自第二个社长升级开始,每升级一名社长所需铸造费用增加10%,既第二位社长升级铸造费用为100u+100*10%=110USDT,以此类推。": "Upgrade-Kosten ab 100USDT, davon 2USDT Gas-Gebühren, 50% des Restbetrags gehen in den Liquiditätspool und die anderen 50% werden auf alle erfolgreichen Vorsitzenden und Fundmanager aufgeteilt. Ab dem zweiten Vorsitzenden steigen die Prägekosten um 10% pro Aufstieg, also 110USDT für den zweiten, usw.",
|
"升级费用xxx USDT起,其中gas费2USDT,剩余部分50%进入资金池,另外50%平均分给所有升级成功的社长和基金会社长。自第二个社长升级开始,每升级一名社长所需铸造费用增加xxx,既第二位社长升级铸造费用为xxxu+xxx*xxx=xxx USDT,以此类推。": "Upgrade-Kosten ab {{value1}} USDT, davon 2USDT Gas-Gebühren, 50% des Restbetrags gehen in den Liquiditätspool und die anderen 50% werden auf alle erfolgreichen Vorsitzenden und Fundmanager aufgeteilt. Ab dem zweiten Vorsitzenden steigen die Prägekosten um {{value2}} pro Aufstieg, also {{value1}}u+{{value1}}*{{value2}}={{value3}} USDT für den zweiten, usw.",
|
||||||
"升级条件": "Upgrade-Bedingungen",
|
"升级条件": "Upgrade-Bedingungen",
|
||||||
"普通会员": "Normales Mitglied",
|
"普通会员": "Normales Mitglied",
|
||||||
"(限量20000个)": "(Begrenzt auf 20.000 Stück)",
|
"(限量xxx个)": "(Begrenzt auf {{value}} Stück)",
|
||||||
"1. MINT一枚NFT成为非活跃普通会员": "1. Präge ein NFT, um inaktives Mitglied zu werden",
|
"1. MINT一枚NFT成为非活跃普通会员": "1. Präge ein NFT, um inaktives Mitglied zu werden",
|
||||||
"2. MINT NFT并推荐MINT成为活跃普通会员": "2. Präge und empfehle NFTs, um aktives Mitglied zu werden",
|
"2. MINT NFT并推荐MINT成为活跃普通会员": "2. Präge und empfehle NFTs, um aktives Mitglied zu werden",
|
||||||
"3. 享1%代币空投平分(所有普通会员)": "3. Erhalte 1% Token-Airdrop gleichmäßig verteilt (alle normalen Mitglieder)",
|
"3. 享1%代币空投平分(所有普通会员)": "3. Erhalte 1% Token-Airdrop gleichmäßig verteilt (alle normalen Mitglieder)",
|
||||||
|
@ -87,5 +87,19 @@
|
||||||
"活跃普通": "Aktiv allgemein",
|
"活跃普通": "Aktiv allgemein",
|
||||||
|
|
||||||
"复制成功": "Erfolgreich kopiert",
|
"复制成功": "Erfolgreich kopiert",
|
||||||
"领取成功,前往钱包查看": "Erfolgreich abgerufen. Bitte überprüfen Sie Ihre Brieftasche."
|
"领取成功,前往钱包查看": "Erfolgreich abgerufen. Bitte überprüfen Sie Ihre Brieftasche.",
|
||||||
|
"链接钱包中...": "Wallet wird verbunden...",
|
||||||
|
"无": "Keiner",
|
||||||
|
"服务器错误": "Serverfehler",
|
||||||
|
"余额不足": "Unzureichendes Guthaben",
|
||||||
|
"MINT成功,返回首页查看": "MINT erfolgreich, zur Startseite zurückkehren, um nachzusehen.",
|
||||||
|
"正在授权USDT": "USDT wird autorisiert",
|
||||||
|
"购买中": "In Bearbeitung",
|
||||||
|
"领取中": "In Bearbeitung",
|
||||||
|
"MINT Nft 获取邀请链接": "MINT Nft Einladungslink erhalten",
|
||||||
|
"链接钱包获取邀请链接": "Verknüpfen Sie Ihre Brieftasche, um den Einladungslink zu erhalten.",
|
||||||
|
"正在获取已授权金额": "Aktuell wird der autorisierte Betrag abgerufen.",
|
||||||
|
"升级成功,返回首页查看": "Upgrade erfolgreich abgeschlossen, zurück zur Startseite zur Ansicht.",
|
||||||
|
"无级别提升": "Beförderung ohne Rang",
|
||||||
|
"没有更多数据了": "Keine weiteren Daten"
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
"取消": "Cancel",
|
"取消": "Cancel",
|
||||||
"普通非活跃": "Inactive Member",
|
"普通非活跃": "Inactive Member",
|
||||||
"升级": "Upgrade",
|
"升级": "Upgrade",
|
||||||
"链接钱包": "Link Wallet",
|
"链接钱包": "Connect Wallet",
|
||||||
"邀请铸造": "Invite to Mint",
|
"邀请铸造": "Invite to Mint",
|
||||||
"团队社长": "Team Leader",
|
"团队社长": "Team Leader",
|
||||||
"邀请空投": "Invite Airdrop",
|
"邀请空投": "Invite Airdrop",
|
||||||
|
@ -35,17 +35,17 @@
|
||||||
"MINT余量:": "Remaining MINT:",
|
"MINT余量:": "Remaining MINT:",
|
||||||
"当前MINT价格:": "Current MINT Price:",
|
"当前MINT价格:": "Current MINT Price:",
|
||||||
"价格说明:": "Price Explanation:",
|
"价格说明:": "Price Explanation:",
|
||||||
"100USDT起,每增加100名普通会员,NFT价格上涨1%,既:前100名价格为100USDT/枚,101-200名价格为100u+100u*1%=101USDT/枚,以此类推。": "Starting at 100USDT, the NFT price increases by 1% for every 100 new members: first 100 at 100USDT each, 101-200 at 101USDT each, and so on.",
|
"{{value1}} USDT起,每增加 {{value2}} 名普通会员,NFT价格上涨 {{value3}},既:前 {{value2}} 名价格为 {{value1}} USDT/枚,value4 名价格为{{value1}}u+{{value1}}u*{{value3}}={{value5}} USDT/枚,以此类推。": "Starting at {{value1}} USDT, the NFT price increases by {{value3}} for every {{value2}} new members: first {{value2}} at {{value1}} USDT each, {{value4}} at {{value1}}u+{{value1}}u*{{value3}}={{value5}} USDT each, and so on.",
|
||||||
"授权USDT": "Authorize USDT",
|
"授权USDT": "Authorize USDT",
|
||||||
"当前级别": "Current Level",
|
"当前级别": "Current Level",
|
||||||
"普通活跃": "Active Member",
|
"普通活跃": "Active Member",
|
||||||
"提升级别": "Upgrade Level",
|
"提升级别": "Upgrade Level",
|
||||||
"社长": "Leader",
|
"社长": "Leader",
|
||||||
"当前升级价格:": "Current Upgrade Price:",
|
"当前升级价格:": "Current Upgrade Price:",
|
||||||
"升级费用100USDT起,其中gas费2USDT,剩余部分50%进入资金池,另外50%平均分给所有升级成功的社长和基金会社长。自第二个社长升级开始,每升级一名社长所需铸造费用增加10%,既第二位社长升级铸造费用为100u+100*10%=110USDT,以此类推。": "Upgrade cost starts at 100USDT, including 2USDT gas fee; 50% goes to the fund pool, and 50% is distributed among successful Leaders and Foundation Leaders. From the second Leader onwards, each upgrade cost increases by 10%, i.e., second Leader upgrade costs 110USDT, and so on.",
|
"升级费用xxx USDT起,其中gas费2USDT,剩余部分50%进入资金池,另外50%平均分给所有升级成功的社长和基金会社长。自第二个社长升级开始,每升级一名社长所需铸造费用增加xxx,既第二位社长升级铸造费用为xxxu+xxx*xxx=xxx USDT,以此类推。": "Upgrade cost starts at {{value1}} USDT, including 2USDT gas fee; 50% goes to the fund pool, and 50% is distributed among successful Leaders and Foundation Leaders. From the second Leader onwards, each upgrade cost increases by {{value2}}, i.e., second Leader upgrade costs {{value1}}u+{{value1}}*{{value2}}={{value3}} USDT, and so on.",
|
||||||
"升级条件": "Upgrade Conditions",
|
"升级条件": "Upgrade Conditions",
|
||||||
"普通会员": "Regular Member",
|
"普通会员": "Regular Member",
|
||||||
"(限量20000个)": "(Limited to 20000)",
|
"(限量xxx个)": "(Limited to {{value}})",
|
||||||
"1. MINT一枚NFT成为非活跃普通会员": "1. MINT an NFT to become an Inactive Member",
|
"1. MINT一枚NFT成为非活跃普通会员": "1. MINT an NFT to become an Inactive Member",
|
||||||
"2. MINT NFT并推荐MINT成为活跃普通会员": "2. MINT NFT and recommend MINT to become an Active Member",
|
"2. MINT NFT并推荐MINT成为活跃普通会员": "2. MINT NFT and recommend MINT to become an Active Member",
|
||||||
"3. 享1%代币空投平分(所有普通会员)": "3. 1% token airdrop shared among all members",
|
"3. 享1%代币空投平分(所有普通会员)": "3. 1% token airdrop shared among all members",
|
||||||
|
@ -87,5 +87,19 @@
|
||||||
"活跃普通": "Active Member",
|
"活跃普通": "Active Member",
|
||||||
|
|
||||||
"复制成功": "Copy successful",
|
"复制成功": "Copy successful",
|
||||||
"领取成功,前往钱包查看": "Claim successful, please check your wallet."
|
"领取成功,前往钱包查看": "Claim successful, please check your wallet.",
|
||||||
|
"链接钱包中...": "connecting wallet...",
|
||||||
|
"无": "None",
|
||||||
|
"服务器错误": "Server Error",
|
||||||
|
"余额不足": "Insufficient balance",
|
||||||
|
"MINT成功,返回首页查看": "MINT succeeded, return to the homepage to check.",
|
||||||
|
"正在授权USDT": "Authorizing USDT",
|
||||||
|
"购买中": "Purchasing",
|
||||||
|
"领取中": "Processing",
|
||||||
|
"MINT Nft 获取邀请链接": "MINT Nft invite link",
|
||||||
|
"链接钱包获取邀请链接": "Link your wallet to get the invitation link.",
|
||||||
|
"正在获取已授权金额": "Currently retrieving authorized amount.",
|
||||||
|
"升级成功,返回首页查看": "Upgrade successful, return to homepage to view.",
|
||||||
|
"无级别提升": "Promotion without rank",
|
||||||
|
"没有更多数据了": "No more data"
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,17 +35,17 @@
|
||||||
"MINT余量:": "残りのMINT:",
|
"MINT余量:": "残りのMINT:",
|
||||||
"当前MINT价格:": "現在のMINT価格:",
|
"当前MINT价格:": "現在のMINT価格:",
|
||||||
"价格说明:": "価格説明:",
|
"价格说明:": "価格説明:",
|
||||||
"100USDT起,每增加100名普通会员,NFT价格上涨1%,既:前100名价格为100USDT/枚,101-200名价格为100u+100u*1%=101USDT/枚,以此类推。": "100USDTから、100人の会員が増えるごとにNFT価格が1%上昇:最初の100人は100USDT/個、101-200人は101USDT/個、以降も同様。",
|
"{{value1}} USDT起,每增加 {{value2}} 名普通会员,NFT价格上涨 {{value3}},既:前 {{value2}} 名价格为 {{value1}} USDT/枚,value4 名价格为{{value1}}u+{{value1}}u*{{value3}}={{value5}} USDT/枚,以此类推。": "{{value1}} USDTから、{{value2}}人の会員が増えるごとにNFT価格が{{value3}}上昇:最初の{{value2}}人は{{value1}}USDT/個、{{value4}}人は{{value1}}u+{{value1}}u*{{value3}}={{value5}} USDT/個、以降も同様。",
|
||||||
"授权USDT": "USDTの承認",
|
"授权USDT": "USDTの承認",
|
||||||
"当前级别": "現在のレベル",
|
"当前级别": "現在のレベル",
|
||||||
"普通活跃": "活躍メンバー",
|
"普通活跃": "活躍メンバー",
|
||||||
"提升级别": "レベルアップ",
|
"提升级别": "レベルアップ",
|
||||||
"社长": "リーダー",
|
"社长": "リーダー",
|
||||||
"当前升级价格:": "現在のアップグレード価格:",
|
"当前升级价格:": "現在のアップグレード価格:",
|
||||||
"升级费用100USDT起,其中gas费2USDT,剩余部分50%进入资金池,另外50%平均分给所有升级成功的社长和基金会社长。自第二个社长升级开始,每升级一名社长所需铸造费用增加10%,既第二位社长升级铸造费用为100u+100*10%=110USDT,以此类推。": "アップグレード費用は100USDTから、うちガス代2USDT、残りの50%は資金プールに入り、もう50%はアップグレードに成功したリーダーとファンドリーダーに分配。2人目のリーダーからは、アップグレード費用が10%ずつ増加、つまり2人目は110USDT、以降も同様。",
|
"升级费用xxx USDT起,其中gas费2USDT,剩余部分50%进入资金池,另外50%平均分给所有升级成功的社长和基金会社长。自第二个社长升级开始,每升级一名社长所需铸造费用增加xxx,既第二位社长升级铸造费用为xxxu+xxx*xxx=xxx USDT,以此类推。": "アップグレード費用は{{value1}} USDTから、うちガス代2USDT、残りの50%は資金プールに入り、もう50%はアップグレードに成功したリーダーとファンドリーダーに分配。2人目のリーダーからは、アップグレード費用が{{value2}}ずつ増加、つまり2人目は{{value1}}u+{{value1}}*{{value2}}={{value3}} USDT、以降も同様。",
|
||||||
"升级条件": "アップグレード条件",
|
"升级条件": "アップグレード条件",
|
||||||
"普通会员": "一般会員",
|
"普通会员": "一般会員",
|
||||||
"(限量20000个)": "(限定20000個)",
|
"(限量xxx个)": "(限定 {{value}} 個)",
|
||||||
"1. MINT一枚NFT成为非活跃普通会员": "1. NFTを1枚鋳造して非活躍メンバーになる",
|
"1. MINT一枚NFT成为非活跃普通会员": "1. NFTを1枚鋳造して非活躍メンバーになる",
|
||||||
"2. MINT NFT并推荐MINT成为活跃普通会员": "2. NFTを鋳造し、他者に鋳造を推奨して活躍メンバーになる",
|
"2. MINT NFT并推荐MINT成为活跃普通会员": "2. NFTを鋳造し、他者に鋳造を推奨して活躍メンバーになる",
|
||||||
"3. 享1%代币空投平分(所有普通会员)": "3. 一般会員は1%のトークンエアドロップを均等に分配",
|
"3. 享1%代币空投平分(所有普通会员)": "3. 一般会員は1%のトークンエアドロップを均等に分配",
|
||||||
|
@ -87,5 +87,19 @@
|
||||||
"活跃普通": "活躍一般",
|
"活跃普通": "活躍一般",
|
||||||
|
|
||||||
"复制成功": "コピーが成功しました",
|
"复制成功": "コピーが成功しました",
|
||||||
"领取成功,前往钱包查看": "受け取りが成功しました。ウォレットで確認してください。"
|
"领取成功,前往钱包查看": "受け取りが成功しました。ウォレットで確認してください。",
|
||||||
|
"链接钱包中...": "ウォレットをリンク中...",
|
||||||
|
"无": "無",
|
||||||
|
"服务器错误": "サーバーエラー",
|
||||||
|
"余额不足": "ざんだかふそく",
|
||||||
|
"MINT成功,返回首页查看": "MINTが成功しました。ホームページに戻って確認してください",
|
||||||
|
"正在授权USDT": "USDTの認証中",
|
||||||
|
"购买中": "購入中 (こうにゅうちゅう)",
|
||||||
|
"领取中": "しょりちゅう",
|
||||||
|
"MINT Nft 获取邀请链接": "MINT Nft 招待リンクを取得する",
|
||||||
|
"链接钱包获取邀请链接": "ウォレットをリンクして招待リンクを取得します。",
|
||||||
|
"正在获取已授权金额": "承認済み金額を取得中です",
|
||||||
|
"升级成功,返回首页查看": "アップグレードが成功しました。ホームページに戻って確認してください。",
|
||||||
|
"无级别提升": "階級なしの昇進",
|
||||||
|
"没有更多数据了": "これ以上のデータはありません"
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,17 +35,17 @@
|
||||||
"MINT余量:": "MINT餘量:",
|
"MINT余量:": "MINT餘量:",
|
||||||
"当前MINT价格:": "當前MINT價格:",
|
"当前MINT价格:": "當前MINT價格:",
|
||||||
"价格说明:": "價格說明:",
|
"价格说明:": "價格說明:",
|
||||||
"100USDT起,每增加100名普通会员,NFT价格上涨1%,既:前100名价格为100USDT/枚,101-200名价格为100u+100u*1%=101USDT/枚,以此类推。": "100USDT起,每增加100名普通會員,NFT價格上漲1%,即:前100名價格為100USDT/枚,101-200名價格為100u+100u*1%=101USDT/枚,以此類推。",
|
"{{value1}} USDT起,每增加 {{value2}} 名普通会员,NFT价格上涨 {{value3}},既:前 {{value2}} 名价格为 {{value1}} USDT/枚,value4 名价格为{{value1}}u+{{value1}}u*{{value3}}={{value5}} USDT/枚,以此类推。": "{{value1}} USDT起,每增加{{value2}}名普通會員,NFT價格上漲{{value3}},即:前{{value2}}名價格為{{value1}} USDT/枚,{{value4}}名價格為{{value1}}u+{{value1}}u*{{value3}}={{value5}} USDT/枚,以此類推。",
|
||||||
"授权USDT": "授權USDT",
|
"授权USDT": "授權USDT",
|
||||||
"当前级别": "當前級別",
|
"当前级别": "當前級別",
|
||||||
"普通活跃": "普通活躍",
|
"普通活跃": "普通活躍",
|
||||||
"提升级别": "提升級別",
|
"提升级别": "提升級別",
|
||||||
"社长": "社長",
|
"社长": "社長",
|
||||||
"当前升级价格:": "當前升級價格:",
|
"当前升级价格:": "當前升級價格:",
|
||||||
"升级费用100USDT起,其中gas费2USDT,剩余部分50%进入资金池,另外50%平均分给所有升级成功的社长和基金会社长。自第二个社长升级开始,每升级一名社长所需铸造费用增加10%,既第二位社长升级铸造费用为100u+100*10%=110USDT,以此类推。": "升級費用100USDT起,其中gas費2USDT,剩餘部分50%進入資金池,另外50%平均分給所有升級成功的社長和基金會社長。自第二個社長升級開始,每升級一名社長所需鑄造費用增加10%,即第二位社長升級鑄造費用為100u+100*10%=110USDT,以此類推。",
|
"升级费用xxx USDT起,其中gas费2USDT,剩余部分50%进入资金池,另外50%平均分给所有升级成功的社长和基金会社长。自第二个社长升级开始,每升级一名社长所需铸造费用增加xxx,既第二位社长升级铸造费用为xxxu+xxx*xxx=xxx USDT,以此类推。": "升級費用{{value1}} USDT起,其中gas費2USDT,剩餘部分50%進入資金池,另外50%平均分給所有升級成功的社長和基金會社長。自第二個社長升級開始,每升級一名社長所需鑄造費用增加{{value2}},即第二位社長升級鑄造費用為{{value1}}u+{{value1}}*{{value2}}={{value3}} USDT,以此類推。",
|
||||||
"升级条件": "升級條件",
|
"升级条件": "升級條件",
|
||||||
"普通会员": "普通會員",
|
"普通会员": "普通會員",
|
||||||
"(限量20000个)": "(限量20000個)",
|
"(限量xxx个)": "(限量 {{value}} 個)",
|
||||||
"1. MINT一枚NFT成为非活跃普通会员": "1. MINT一枚NFT成為非活躍普通會員",
|
"1. MINT一枚NFT成为非活跃普通会员": "1. MINT一枚NFT成為非活躍普通會員",
|
||||||
"2. MINT NFT并推荐MINT成为活跃普通会员": "2. MINT NFT並推薦MINT成為活躍普通會員",
|
"2. MINT NFT并推荐MINT成为活跃普通会员": "2. MINT NFT並推薦MINT成為活躍普通會員",
|
||||||
"3. 享1%代币空投平分(所有普通会员)": "3. 享1%代幣空投平分(所有普通會員)",
|
"3. 享1%代币空投平分(所有普通会员)": "3. 享1%代幣空投平分(所有普通會員)",
|
||||||
|
@ -87,5 +87,19 @@
|
||||||
"活跃普通": "活躍普通",
|
"活跃普通": "活躍普通",
|
||||||
|
|
||||||
"复制成功": "複製成功",
|
"复制成功": "複製成功",
|
||||||
"领取成功,前往钱包查看": "領取成功,前往錢包查看"
|
"领取成功,前往钱包查看": "領取成功,前往錢包查看",
|
||||||
|
"链接钱包中...": "連結錢包中...",
|
||||||
|
"无": "無",
|
||||||
|
"服务器错误": "伺服器錯誤",
|
||||||
|
"余额不足": "餘額不足",
|
||||||
|
"MINT成功,返回首页查看": "MINT成功,返回首頁查看",
|
||||||
|
"正在授权USDT": "正在授權USDT",
|
||||||
|
"购买中": "購買中",
|
||||||
|
"领取中": "處理中",
|
||||||
|
"MINT Nft 获取邀请链接": "MINT Nft 獲取邀請鏈接",
|
||||||
|
"链接钱包获取邀请链接": "連結錢包以獲取邀請鏈接。",
|
||||||
|
"正在获取已授权金额": "正在取得已授權金額",
|
||||||
|
"升级成功,返回首页查看": "升級成功,返回首頁查看。",
|
||||||
|
"无级别提升": "無級別提升",
|
||||||
|
"没有更多数据了": "沒有更多數據了"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* @LastEditors: John
|
* @LastEditors: John
|
||||||
* @Date: 2024-06-17 17:20:03
|
* @Date: 2024-06-17 17:20:03
|
||||||
* @LastEditTime: 2024-06-19 18:07:46
|
* @LastEditTime: 2024-06-20 11:43:14
|
||||||
* @Author: John
|
* @Author: John
|
||||||
*/
|
*/
|
||||||
import "@/i18n/init.ts";
|
import "@/i18n/init.ts";
|
||||||
|
@ -15,8 +15,9 @@ import EventBusProvider from "./context/EventBusContext.tsx";
|
||||||
import { WalletProvider } from "./components/WalletProvider.tsx";
|
import { WalletProvider } from "./components/WalletProvider.tsx";
|
||||||
import flexible from "./utils/flexible.ts";
|
import flexible from "./utils/flexible.ts";
|
||||||
import VConsole from "vconsole";
|
import VConsole from "vconsole";
|
||||||
|
import { getUrlQueryParam } from "./utils/index.ts";
|
||||||
|
|
||||||
if (import.meta.env.DEV) {
|
if (getUrlQueryParam("vconsole") === "1") {
|
||||||
new VConsole();
|
new VConsole();
|
||||||
}
|
}
|
||||||
flexible(window, document);
|
flexible(window, document);
|
||||||
|
|
|
@ -1,105 +1,209 @@
|
||||||
/*
|
/*
|
||||||
* @LastEditors: John
|
* @LastEditors: John
|
||||||
* @Date: 2024-06-18 17:57:13
|
* @Date: 2024-06-18 17:57:13
|
||||||
* @LastEditTime: 2024-06-19 14:19:55
|
* @LastEditTime: 2024-06-24 10:44:10
|
||||||
* @Author: John
|
* @Author: John
|
||||||
*/
|
*/
|
||||||
import Tabs from "antd-mobile/es/components/tabs";
|
import Tabs from "antd-mobile/es/components/tabs";
|
||||||
import classes from "./AssetRecord.module.css";
|
import classes from "./AssetRecord.module.css";
|
||||||
import { cn } from "@/utils";
|
import { cn, getUrlQueryParam } from "@/utils";
|
||||||
import CapsuleTabs from "antd-mobile/es/components/capsule-tabs";
|
import CapsuleTabs from "antd-mobile/es/components/capsule-tabs";
|
||||||
import RecordsItem from "@/components/RecordsItem";
|
import RecordsItem from "@/components/RecordsItem";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { useEffect, useMemo, useRef, useState } from "react";
|
||||||
|
import { api_pagling_query_income_record } from "@/server/api";
|
||||||
|
import { IncomeRecord, IncomeRecordType } from "@/server/module";
|
||||||
|
import { Empty, InfiniteScroll } from "antd-mobile";
|
||||||
|
import { CoinName } from "@/constants";
|
||||||
|
|
||||||
export default function () {
|
export default function () {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const coinId = useMemo(() => getUrlQueryParam("id"), []);
|
||||||
|
const coinName = useMemo(() => getUrlQueryParam("name"), []);
|
||||||
|
const currentType = useRef<1 | 2>(1);
|
||||||
|
const [issueRecords, setIssueRecords] = useState<IncomeRecord["records"]>([]);
|
||||||
|
const [receiveRecord, setReceiveRecord] = useState<IncomeRecord["records"]>(
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
const conditions = useRef<IncomeRecordType>();
|
||||||
|
|
||||||
|
const pageNum = useRef<number>(0);
|
||||||
|
const hasMore = useRef<boolean>(true);
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {};
|
||||||
|
}, [coinId]);
|
||||||
|
|
||||||
|
async function getRecord() {
|
||||||
|
return new Promise<void>(async (reslove) => {
|
||||||
|
if (!coinId) return;
|
||||||
|
|
||||||
|
if (!hasMore.current) return;
|
||||||
|
|
||||||
|
const pageSize = 20;
|
||||||
|
pageNum.current++;
|
||||||
|
const { data } = await api_pagling_query_income_record().send({
|
||||||
|
queryParams: {
|
||||||
|
id: coinId,
|
||||||
|
type: currentType.current,
|
||||||
|
pageNum: pageNum.current,
|
||||||
|
pageSize,
|
||||||
|
...(conditions.current && currentType.current == 1
|
||||||
|
? { status: conditions.current }
|
||||||
|
: {}),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!data?.data.records) return;
|
||||||
|
|
||||||
|
if (data.data.records.length < pageSize) hasMore.current = false;
|
||||||
|
|
||||||
|
if (currentType.current == 1) {
|
||||||
|
setIssueRecords([...issueRecords, ...data?.data.records]);
|
||||||
|
} else {
|
||||||
|
setReceiveRecord([...receiveRecord, ...data?.data.records]);
|
||||||
|
}
|
||||||
|
reslove();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetPaging() {
|
||||||
|
if (currentType.current == 1) {
|
||||||
|
setIssueRecords([]);
|
||||||
|
} else if (currentType.current == 2) {
|
||||||
|
setReceiveRecord([]);
|
||||||
|
}
|
||||||
|
pageNum.current = 0;
|
||||||
|
hasMore.current = true;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Tabs className={cn(classes.AssetRecord)}>
|
<Tabs
|
||||||
|
className={cn(classes.AssetRecord)}
|
||||||
|
onChange={(key) => {
|
||||||
|
if (parseInt(key) == 1) {
|
||||||
|
currentType.current = 1;
|
||||||
|
resetPaging();
|
||||||
|
} else {
|
||||||
|
currentType.current = 2;
|
||||||
|
resetPaging();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Tabs.Tab className={classes.tab} title={t("发放记录")} key="1">
|
<Tabs.Tab className={classes.tab} title={t("发放记录")} key="1">
|
||||||
<CapsuleTabs>
|
{coinName == CoinName.USDT && (
|
||||||
<CapsuleTabs.Tab title={t("所有")} key="1" />
|
<CapsuleTabs
|
||||||
<CapsuleTabs.Tab title={t("升级费平分")} key="2" />
|
onChange={(key) => {
|
||||||
<CapsuleTabs.Tab title={t("直推>20NFT")} key="3" />
|
switch (key) {
|
||||||
</CapsuleTabs>
|
case "1":
|
||||||
<ul className={classes.recordsList}>
|
conditions.current = undefined;
|
||||||
<li>
|
break;
|
||||||
<RecordsItem
|
case "2":
|
||||||
itemList={[
|
conditions.current = 5;
|
||||||
{
|
break;
|
||||||
title: t("奖励类型"),
|
case "3":
|
||||||
value: t("升级费平分"),
|
conditions.current = 4;
|
||||||
},
|
break;
|
||||||
{ title: t("发放时间"), value: "2024-06-01 12:23:45" },
|
|
||||||
{ title: t("发放数量"), value: "2.00 USDT" },
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<li>
|
default:
|
||||||
<RecordsItem
|
break;
|
||||||
itemList={[
|
}
|
||||||
{
|
resetPaging();
|
||||||
title: t("奖励类型"),
|
}}
|
||||||
value: t("直推>20NFT"),
|
>
|
||||||
},
|
<CapsuleTabs.Tab title={t("所有")} key="1" />
|
||||||
{ title: t("发放时间"), value: "2024-06-01 12:23:45" },
|
<CapsuleTabs.Tab title={t("升级费平分")} key="2" />
|
||||||
{ title: t("发放数量"), value: "2.00 USDT" },
|
<CapsuleTabs.Tab title={t("直推>20NFT")} key="3" />
|
||||||
]}
|
</CapsuleTabs>
|
||||||
/>
|
)}
|
||||||
</li>
|
|
||||||
|
{coinName == CoinName.RMOB && (
|
||||||
|
<CapsuleTabs
|
||||||
|
onChange={(key) => {
|
||||||
|
switch (key) {
|
||||||
|
case "1":
|
||||||
|
conditions.current = undefined;
|
||||||
|
break;
|
||||||
|
case "2":
|
||||||
|
conditions.current = 6;
|
||||||
|
break;
|
||||||
|
case "3":
|
||||||
|
conditions.current = 7;
|
||||||
|
break;
|
||||||
|
case "4":
|
||||||
|
conditions.current = 8;
|
||||||
|
break;
|
||||||
|
case "5":
|
||||||
|
conditions.current = 9;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
resetPaging();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<CapsuleTabs.Tab title={t("所有")} key="1" />
|
||||||
|
<CapsuleTabs.Tab title={t("NFT空投")} key="2" />
|
||||||
|
<CapsuleTabs.Tab title={t("社长空投")} key="3" />
|
||||||
|
<CapsuleTabs.Tab title={t("基金会社长")} key="4" />
|
||||||
|
<CapsuleTabs.Tab title={t("直推空投")} key="5" />
|
||||||
|
</CapsuleTabs>
|
||||||
|
)}
|
||||||
|
<ul className={classes.recordsList}>
|
||||||
|
{issueRecords?.map((v, i) => (
|
||||||
|
<li key={i}>
|
||||||
|
<RecordsItem
|
||||||
|
itemList={[
|
||||||
|
{
|
||||||
|
title: t("奖励类型"),
|
||||||
|
value: v.extRemark,
|
||||||
|
},
|
||||||
|
{ title: t("发放时间"), value: v.createTime },
|
||||||
|
{ title: t("发放数量"), value: `${v.opValue} USDT` },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
{issueRecords?.length == 0 && <Empty />}
|
||||||
|
<InfiniteScroll loadMore={getRecord} hasMore={hasMore.current}>
|
||||||
|
<span>{t("没有更多数据了")}</span>
|
||||||
|
</InfiniteScroll>
|
||||||
</ul>
|
</ul>
|
||||||
</Tabs.Tab>
|
</Tabs.Tab>
|
||||||
<Tabs.Tab className={classes.tab} title={t("领取记录")} key="2">
|
<Tabs.Tab className={classes.tab} title={t("领取记录")} key="2">
|
||||||
<ul className={classes.recordsList}>
|
<ul className={classes.recordsList}>
|
||||||
<li>
|
{receiveRecord?.map((v, i) => (
|
||||||
<RecordsItem
|
<li key={i}>
|
||||||
itemList={[
|
<RecordsItem
|
||||||
{
|
itemList={[
|
||||||
title: t("领取时间"),
|
{
|
||||||
value: "2024-06-01 12:23:45",
|
title: t("领取时间"),
|
||||||
},
|
value: v.createTime,
|
||||||
{ title: t("领取数量"), value: "2.00 USDT" },
|
},
|
||||||
{
|
{ title: t("领取数量"), value: `${v.opValue} USDT` },
|
||||||
title: t("领取状态"),
|
{
|
||||||
value: t("确认中"),
|
title: t("领取状态"),
|
||||||
valueColor: "#FC872B",
|
...(v.type == 1 && {
|
||||||
},
|
value: t("领取成功"),
|
||||||
]}
|
valueColor: "#38C979",
|
||||||
/>
|
}),
|
||||||
</li>
|
...(v.type == 3 && {
|
||||||
<li>
|
value: t("确认中"),
|
||||||
<RecordsItem
|
valueColor: "#FC872B",
|
||||||
itemList={[
|
}),
|
||||||
{
|
...(v.type == 4 && {
|
||||||
title: t("领取时间"),
|
value: t("交易取消"),
|
||||||
value: "2024-06-01 12:23:45",
|
valueColor: "#C94738",
|
||||||
},
|
}),
|
||||||
{ title: t("领取数量"), value: "2.00 USDT" },
|
},
|
||||||
{
|
]}
|
||||||
title: t("领取状态"),
|
/>
|
||||||
value: t("领取成功"),
|
</li>
|
||||||
valueColor: "#38C979",
|
))}
|
||||||
},
|
{receiveRecord?.length == 0 && <Empty />}
|
||||||
]}
|
<InfiniteScroll loadMore={getRecord} hasMore={hasMore.current}>
|
||||||
/>
|
<span>{t("没有更多数据了")}</span>
|
||||||
</li>
|
</InfiniteScroll>
|
||||||
<li>
|
|
||||||
<RecordsItem
|
|
||||||
itemList={[
|
|
||||||
{
|
|
||||||
title: t("领取时间"),
|
|
||||||
value: "2024-06-01 12:23:45",
|
|
||||||
},
|
|
||||||
{ title: t("领取数量"), value: "2.00 USDT" },
|
|
||||||
{
|
|
||||||
title: t("领取状态"),
|
|
||||||
value: t("交易取消"),
|
|
||||||
valueColor: "#C94738",
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</Tabs.Tab>
|
</Tabs.Tab>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
|
@ -235,7 +235,7 @@
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
|
|
||||||
width: 345px;
|
width: 345px;
|
||||||
min-height: 236px;
|
/* min-height: 236px; */
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
|
|
||||||
|
@ -326,6 +326,8 @@
|
||||||
.nftToken_content_token_top {
|
.nftToken_content_token_top {
|
||||||
padding: 14px 15px;
|
padding: 14px 15px;
|
||||||
border-bottom: 1px solid #404040;
|
border-bottom: 1px solid #404040;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
span {
|
span {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
|
|
||||||
|
@ -468,7 +470,7 @@
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|
||||||
> span {
|
span {
|
||||||
/* 自动布局子元素 */
|
/* 自动布局子元素 */
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
|
|
||||||
|
@ -499,6 +501,7 @@
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
|
padding: 0 43px;
|
||||||
.nftToken_content_nft_mint_btn {
|
.nftToken_content_nft_mint_btn {
|
||||||
/* 自动布局子元素 */
|
/* 自动布局子元素 */
|
||||||
width: 169px;
|
width: 169px;
|
||||||
|
@ -643,7 +646,7 @@
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
span {
|
> span {
|
||||||
&:nth-of-type(1) {
|
&:nth-of-type(1) {
|
||||||
/* 自动布局子元素 */
|
/* 自动布局子元素 */
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
|
@ -673,21 +676,18 @@
|
||||||
|
|
||||||
font-variation-settings: "opsz" auto;
|
font-variation-settings: "opsz" auto;
|
||||||
font-feature-settings: "kern" on;
|
font-feature-settings: "kern" on;
|
||||||
color: #ffffff;
|
color: #eaeaea;
|
||||||
|
|
||||||
z-index: 0;
|
z-index: 1;
|
||||||
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 16px;
|
|
||||||
|
|
||||||
.invite_content_icon {
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
.invite_content_link {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
&:nth-of-type(3) {
|
> span {
|
||||||
|
width: 265px;
|
||||||
/* 自动布局子元素 */
|
/* 自动布局子元素 */
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
|
|
||||||
|
@ -699,9 +699,20 @@
|
||||||
|
|
||||||
font-variation-settings: "opsz" auto;
|
font-variation-settings: "opsz" auto;
|
||||||
font-feature-settings: "kern" on;
|
font-feature-settings: "kern" on;
|
||||||
color: #eaeaea;
|
color: #ffffff;
|
||||||
|
|
||||||
z-index: 1;
|
z-index: 0;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
.invite_content_icon {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,17 +2,29 @@ import classes from "./Home.module.css";
|
||||||
import useUserStore from "@/store/User";
|
import useUserStore from "@/store/User";
|
||||||
import { cn, copyText, shortenString } from "@/utils";
|
import { cn, copyText, shortenString } from "@/utils";
|
||||||
import { useWeb3Modal } from "@web3modal/wagmi/react";
|
import { useWeb3Modal } from "@web3modal/wagmi/react";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import logo from "@/assets/logo.svg";
|
import logo from "@/assets/logo.svg";
|
||||||
import nftBg from "@/assets/nft_bg.svg";
|
import nftBg from "@/assets/nft_bg.svg";
|
||||||
import usdtBg from "@/assets/usdt_bg.svg";
|
import usdtBg from "@/assets/usdt_bg.svg";
|
||||||
|
import RMOB_logo from "@/assets/RMOB_logo.svg";
|
||||||
import IconFont from "@/components/iconfont";
|
import IconFont from "@/components/iconfont";
|
||||||
import { useAccount } from "wagmi";
|
import { BaseError, useAccount } from "wagmi";
|
||||||
import { disconnect } from "wagmi/actions";
|
import { disconnect } from "wagmi/actions";
|
||||||
import { config } from "@/components/WalletProvider";
|
import { config } from "@/components/WalletProvider";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { Toast } from "antd-mobile";
|
import { Button, Dialog, Ellipsis, Empty, Toast } from "antd-mobile";
|
||||||
|
import { loginOut, signAndLogin } from "@/utils/wallet";
|
||||||
|
import {
|
||||||
|
api_claim_income,
|
||||||
|
api_get_homepage_user_data,
|
||||||
|
api_users_cancel_orders,
|
||||||
|
} from "@/server/api";
|
||||||
|
import { UserHomeData } from "@/server/module";
|
||||||
|
import { UrlQueryParamsKey } from "@/constants";
|
||||||
|
import { receiveByContract } from "@/contract/utils";
|
||||||
|
import usePollingCheckBuyStatus from "@/hook/usePollingCheckBuyStatus";
|
||||||
|
import { ToastHandler } from "antd-mobile/es/components/toast";
|
||||||
|
|
||||||
export default function () {
|
export default function () {
|
||||||
const { Token, UpdateToken } = useUserStore();
|
const { Token, UpdateToken } = useUserStore();
|
||||||
|
@ -22,10 +34,40 @@ export default function () {
|
||||||
|
|
||||||
const [tabIndex, setTabIndex] = useState(0);
|
const [tabIndex, setTabIndex] = useState(0);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const [userData, setUserData] = useState<UserHomeData>();
|
||||||
|
|
||||||
|
const userInviteLink = useMemo(
|
||||||
|
() =>
|
||||||
|
`${import.meta.env.VITE_BASE_URL}?${UrlQueryParamsKey.INVITE_CODE}=${
|
||||||
|
userData?.invitationCode || ""
|
||||||
|
}`,
|
||||||
|
[userData]
|
||||||
|
);
|
||||||
|
const receiveLoadingToast = useRef<ToastHandler>();
|
||||||
|
const { transcationStatus, startPollingCheckBuyStatus } =
|
||||||
|
usePollingCheckBuyStatus("NORMAL");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
UpdateToken("user token abc");
|
getHomeData();
|
||||||
return () => {};
|
return () => {};
|
||||||
}, []);
|
}, [Token]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (transcationStatus == "success") {
|
||||||
|
receiveLoadingToast.current?.close();
|
||||||
|
Dialog.alert({
|
||||||
|
content: `${t("领取成功,前往钱包查看")}`,
|
||||||
|
confirmText: "OK",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {};
|
||||||
|
}, [transcationStatus]);
|
||||||
|
|
||||||
|
async function getHomeData() {
|
||||||
|
const { data } = await api_get_homepage_user_data().send({});
|
||||||
|
setUserData(data?.data);
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log("user token:", Token);
|
console.log("user token:", Token);
|
||||||
|
@ -47,6 +89,7 @@ export default function () {
|
||||||
<IconFont
|
<IconFont
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
disconnect(config);
|
disconnect(config);
|
||||||
|
loginOut();
|
||||||
}}
|
}}
|
||||||
name="tuichu"
|
name="tuichu"
|
||||||
className={classes.userinfo_top_right_wallet_disconnect}
|
className={classes.userinfo_top_right_wallet_disconnect}
|
||||||
|
@ -54,26 +97,62 @@ export default function () {
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={classes.userinfo_top_right_btns}>
|
<div className={classes.userinfo_top_right_btns}>
|
||||||
<div className={classes.userinfo_top_right_btns_item}>
|
{userData && (
|
||||||
<IconFont
|
<>
|
||||||
name="tongdun"
|
<div className={classes.userinfo_top_right_btns_item}>
|
||||||
className={classes.userinfo_top_right_btns_icon}
|
{userData.level == 0 && (
|
||||||
/>
|
<>
|
||||||
<span>{t("普通非活跃")}</span>
|
<IconFont
|
||||||
</div>
|
name="tongdun"
|
||||||
<div
|
className={classes.userinfo_top_right_btns_icon}
|
||||||
className={classes.userinfo_top_right_btns_item}
|
/>
|
||||||
onClick={() => {
|
<span>{t("普通非活跃")}</span>
|
||||||
navigate("/levelup");
|
</>
|
||||||
}}
|
)}
|
||||||
>
|
{userData.level == 1 && (
|
||||||
<span>{t("升级")}</span>
|
<>
|
||||||
<IconFont
|
<IconFont
|
||||||
name="chevronsrightshuangyoujiantou"
|
name="jindun"
|
||||||
className={classes.userinfo_top_right_btns_icon}
|
className={classes.userinfo_top_right_btns_icon}
|
||||||
color={"#fff"}
|
/>
|
||||||
/>
|
<span>{t("普通活跃")}</span>
|
||||||
</div>
|
</>
|
||||||
|
)}
|
||||||
|
{userData.level == 2 && (
|
||||||
|
<>
|
||||||
|
<IconFont
|
||||||
|
name="xingdun"
|
||||||
|
className={classes.userinfo_top_right_btns_icon}
|
||||||
|
/>
|
||||||
|
<span>{t("社长")}</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{userData.level == 3 && (
|
||||||
|
<>
|
||||||
|
<IconFont
|
||||||
|
name="guanjun"
|
||||||
|
className={classes.userinfo_top_right_btns_icon}
|
||||||
|
/>
|
||||||
|
<span>{t("基金会社长")}</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
className={classes.userinfo_top_right_btns_item}
|
||||||
|
onClick={() => {
|
||||||
|
navigate("/levelup");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span>{t("升级")}</span>
|
||||||
|
<IconFont
|
||||||
|
name="chevronsrightshuangyoujiantou"
|
||||||
|
className={classes.userinfo_top_right_btns_icon}
|
||||||
|
color={"#fff"}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
@ -91,15 +170,21 @@ export default function () {
|
||||||
</div>
|
</div>
|
||||||
<ul className={classes.userinfo_data}>
|
<ul className={classes.userinfo_data}>
|
||||||
<li>
|
<li>
|
||||||
<span className={classes.userinfo_data_num}>20</span>
|
<span className={classes.userinfo_data_num}>
|
||||||
|
{userData?.mintNumber || 0}
|
||||||
|
</span>
|
||||||
<span className={classes.userinfo_data_des}>{t("邀请铸造")}</span>
|
<span className={classes.userinfo_data_des}>{t("邀请铸造")}</span>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<span className={classes.userinfo_data_num}>20</span>
|
<span className={classes.userinfo_data_num}>
|
||||||
|
{userData?.presidentNumber || 0}
|
||||||
|
</span>
|
||||||
<span className={classes.userinfo_data_des}>{t("团队社长")}</span>
|
<span className={classes.userinfo_data_des}>{t("团队社长")}</span>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<span className={classes.userinfo_data_num}>3</span>
|
<span className={classes.userinfo_data_num}>
|
||||||
|
{userData?.airdropNumber || 0}
|
||||||
|
</span>
|
||||||
<span className={classes.userinfo_data_des}>{t("邀请空投")}</span>
|
<span className={classes.userinfo_data_des}>{t("邀请空投")}</span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
@ -126,10 +211,10 @@ export default function () {
|
||||||
<>
|
<>
|
||||||
{address ? (
|
{address ? (
|
||||||
<>
|
<>
|
||||||
{true ? (
|
{userData?.nftId ? (
|
||||||
<div className={classes.nftToken_content_nft}>
|
<div className={classes.nftToken_content_nft}>
|
||||||
<div className={classes.nftToken_content_nft_top}>
|
<div className={classes.nftToken_content_nft_top}>
|
||||||
<span># 737389</span>
|
<span># ${userData?.nftId}</span>
|
||||||
<span
|
<span
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
navigate("/mint");
|
navigate("/mint");
|
||||||
|
@ -188,22 +273,49 @@ export default function () {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul className={classes.nftToken_content_token_list}>
|
<ul className={classes.nftToken_content_token_list}>
|
||||||
<ReceiveCom
|
{userData?.userIncomes.map((v, i) => (
|
||||||
tokenName="USDT"
|
<ReceiveCom
|
||||||
tokenNum={0}
|
key={i}
|
||||||
toReceive={0}
|
tokenName={v.coinName}
|
||||||
onAssetRec={() => {
|
tokenNum={v.receive}
|
||||||
navigate("/assetrecord");
|
toReceive={v.collection}
|
||||||
}}
|
onAssetRec={() => {
|
||||||
/>
|
navigate(`/assetrecord?id=${v.id}&name=${v.coinName}`);
|
||||||
<ReceiveCom
|
}}
|
||||||
tokenName="RMOB"
|
onReceive={async () => {
|
||||||
tokenNum={0}
|
receiveLoadingToast.current = Toast.show({
|
||||||
toReceive={0}
|
icon: "loading",
|
||||||
onAssetRec={() => {
|
duration: 0,
|
||||||
navigate("/airdroprecord");
|
content: t("领取中"),
|
||||||
}}
|
maskClickable: false,
|
||||||
/>
|
});
|
||||||
|
const { data } = await api_claim_income().send({
|
||||||
|
queryParams: { id: v.id },
|
||||||
|
});
|
||||||
|
const orderInfo = data?.data;
|
||||||
|
if (!orderInfo?.orderNumber) return;
|
||||||
|
const buyAmount = BigInt(
|
||||||
|
orderInfo?.claimQuantity || ""
|
||||||
|
);
|
||||||
|
receiveByContract(buyAmount, orderInfo?.orderNumber)
|
||||||
|
.then((hash) => {
|
||||||
|
console.log("领取成功!hash:", hash);
|
||||||
|
getHomeData();
|
||||||
|
startPollingCheckBuyStatus(hash);
|
||||||
|
})
|
||||||
|
.catch(async (err: BaseError) => {
|
||||||
|
receiveLoadingToast.current?.close();
|
||||||
|
Toast.show({
|
||||||
|
content: err.shortMessage,
|
||||||
|
icon: "fail",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
|
||||||
|
{(userData?.userIncomes.length == 0 ||
|
||||||
|
!userData?.userIncomes) && <Empty />}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -213,32 +325,50 @@ export default function () {
|
||||||
<div className={classes.invite}>
|
<div className={classes.invite}>
|
||||||
<div className={classes.invite_top}>
|
<div className={classes.invite_top}>
|
||||||
<span>{t("邀请")}</span>
|
<span>{t("邀请")}</span>
|
||||||
<span
|
{address && (
|
||||||
onClick={() => {
|
<span
|
||||||
navigate("/invitationlist");
|
onClick={() => {
|
||||||
}}
|
navigate("/invitationlist");
|
||||||
>
|
}}
|
||||||
{t("邀请列表")}{" "}
|
>
|
||||||
<IconFont
|
{t("邀请列表")}{" "}
|
||||||
name="chevronsrightshuangyoujiantou"
|
<IconFont
|
||||||
color={"#F3BE3C"}
|
name="chevronsrightshuangyoujiantou"
|
||||||
/>
|
color={"#F3BE3C"}
|
||||||
</span>
|
/>
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={classes.invite_content}>
|
<div className={classes.invite_content}>
|
||||||
<span>{t("邀请链接")}</span>
|
<span>{t("邀请链接")}</span>
|
||||||
<span>
|
<div className={classes.invite_content_link}>
|
||||||
https://www.rmob_nft.com/regster=id?1{" "}
|
{address ? (
|
||||||
<IconFont
|
<>
|
||||||
onClick={() => {
|
{userData?.nftId ? (
|
||||||
copyText("https://www.rmob_nft.com/regster=id?1");
|
<>
|
||||||
}}
|
<span>{shortenString(userInviteLink, 15, 15)}</span>
|
||||||
className={classes.invite_content_icon}
|
<IconFont
|
||||||
name="fuzhi"
|
onClick={() => {
|
||||||
color={"#fff"}
|
copyText(userInviteLink);
|
||||||
/>{" "}
|
}}
|
||||||
</span>
|
className={classes.invite_content_icon}
|
||||||
|
name="fuzhi"
|
||||||
|
color={"#fff"}
|
||||||
|
/>{" "}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<span>{t("MINT Nft 获取邀请链接")}</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<span>{t("链接钱包获取邀请链接")}</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
<span>
|
<span>
|
||||||
{t(
|
{t(
|
||||||
|
@ -253,15 +383,15 @@ export default function () {
|
||||||
<ul className={classes.dataDisclosure_content}>
|
<ul className={classes.dataDisclosure_content}>
|
||||||
<li className={classes.dataDisclosure_content_item}>
|
<li className={classes.dataDisclosure_content_item}>
|
||||||
<span>{t("资金池")}</span>
|
<span>{t("资金池")}</span>
|
||||||
<span>10000</span>
|
<span>{userData?.pools || 0}</span>
|
||||||
</li>
|
</li>
|
||||||
<li className={classes.dataDisclosure_content_item}>
|
<li className={classes.dataDisclosure_content_item}>
|
||||||
<span>{t("社长席位")}</span>
|
<span>{t("社长席位")}</span>
|
||||||
<span>499</span>
|
<span>{userData?.president || 0}</span>
|
||||||
</li>
|
</li>
|
||||||
<li className={classes.dataDisclosure_content_item}>
|
<li className={classes.dataDisclosure_content_item}>
|
||||||
<span>{t("基金会社长席位")}</span>
|
<span>{t("基金会社长席位")}</span>
|
||||||
<span>19</span>
|
<span>{userData?.foundation || 0}</span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
@ -275,16 +405,19 @@ function ReceiveCom({
|
||||||
tokenNum,
|
tokenNum,
|
||||||
toReceive,
|
toReceive,
|
||||||
onAssetRec,
|
onAssetRec,
|
||||||
|
onReceive,
|
||||||
}: {
|
}: {
|
||||||
tokenName: string;
|
tokenName: string;
|
||||||
tokenNum: number;
|
tokenNum: string;
|
||||||
toReceive: number;
|
toReceive: number;
|
||||||
onAssetRec: () => void;
|
onAssetRec: () => void;
|
||||||
|
onReceive: () => void;
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
return (
|
return (
|
||||||
<li className={classes.nftToken_content_token_item}>
|
<li className={classes.nftToken_content_token_item}>
|
||||||
<img src={usdtBg} alt="" />
|
{tokenName.toUpperCase() == "USDT" && <img src={usdtBg} alt="" />}
|
||||||
|
{tokenName.toUpperCase() == "RMOB" && <img src={RMOB_logo} alt="" />}
|
||||||
<div>
|
<div>
|
||||||
<span className={classes.nftToken_content_token_item_tokenName}>
|
<span className={classes.nftToken_content_token_item_tokenName}>
|
||||||
{tokenName}
|
{tokenName}
|
||||||
|
@ -308,17 +441,14 @@ function ReceiveCom({
|
||||||
<span>{t("待领取")}</span>
|
<span>{t("待领取")}</span>
|
||||||
<span>{toReceive}</span>
|
<span>{toReceive}</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<Button
|
||||||
className={classes.nftToken_content_token_item_tokenReceive}
|
className={classes.nftToken_content_token_item_tokenReceive}
|
||||||
onClick={() => {
|
onClick={() => onReceive()}
|
||||||
Toast.show({
|
fill="outline"
|
||||||
content: t("领取成功,前往钱包查看"),
|
disabled={toReceive == 0}
|
||||||
icon: "success",
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<span>{t("领取")}</span>
|
<span>{t("领取")}</span>
|
||||||
</div>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,32 +1,24 @@
|
||||||
/*
|
/*
|
||||||
* @LastEditors: John
|
* @LastEditors: John
|
||||||
* @Date: 2024-06-19 11:03:01
|
* @Date: 2024-06-19 11:03:01
|
||||||
* @LastEditTime: 2024-06-19 17:33:25
|
* @LastEditTime: 2024-06-22 10:27:19
|
||||||
* @Author: John
|
* @Author: John
|
||||||
*/
|
*/
|
||||||
import { shortenString } from "@/utils";
|
import { api_preprelion_list } from "@/server/api";
|
||||||
import Ellipsis from "antd-mobile/es/components/ellipsis";
|
import { PreprelionListItem } from "@/server/module";
|
||||||
|
import { Empty } from "antd-mobile";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
import DataTable, { TableColumn } from "react-data-table-component";
|
import DataTable, { TableColumn } from "react-data-table-component";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useAccount } from "wagmi";
|
|
||||||
|
|
||||||
interface DataRow {
|
|
||||||
id: number;
|
|
||||||
address: string;
|
|
||||||
level: string;
|
|
||||||
nft: number;
|
|
||||||
}
|
|
||||||
export default function () {
|
export default function () {
|
||||||
const { address } = useAccount();
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const columns: TableColumn<DataRow>[] = [
|
const [data, setData] = useState<PreprelionListItem[]>([]);
|
||||||
|
const columns: TableColumn<PreprelionListItem>[] = [
|
||||||
{
|
{
|
||||||
name: t("地址"),
|
name: t("地址"),
|
||||||
selector: (row) => row.address,
|
selector: (row) => row.address,
|
||||||
grow: 4,
|
grow: 4,
|
||||||
// cell(row, rowIndex, column, id) {
|
|
||||||
// return <Ellipsis direction="middle" content={row.address} />;
|
|
||||||
// },
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: t("级别"),
|
name: t("级别"),
|
||||||
|
@ -35,43 +27,25 @@ export default function () {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: t("直推NFT"),
|
name: t("直推NFT"),
|
||||||
selector: (row) => row.nft,
|
selector: (row) => row.mintNumber,
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
right: "true",
|
right: "true",
|
||||||
grow: 2,
|
grow: 2,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const data: DataRow[] = [
|
useEffect(() => {
|
||||||
{
|
(async () => {
|
||||||
id: 1,
|
const { data } = await api_preprelion_list().send({});
|
||||||
address: "0x1000.....2223",
|
setData(data?.data || []);
|
||||||
level: t("非活跃普通"),
|
})();
|
||||||
nft: 0,
|
|
||||||
},
|
return () => {};
|
||||||
{
|
}, []);
|
||||||
id: 2,
|
|
||||||
address: "0x1000.....2223",
|
|
||||||
level: t("活跃普通"),
|
|
||||||
nft: 2,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
address: "0x1000.....2223",
|
|
||||||
level: t("社长"),
|
|
||||||
nft: 23,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 4,
|
|
||||||
address: "0x1000.....2223",
|
|
||||||
level: t("基金会社长"),
|
|
||||||
nft: 50,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<DataTable columns={columns} data={data} />
|
<DataTable columns={columns} data={data} noDataComponent={<Empty />} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
span {
|
span {
|
||||||
|
white-space: nowrap;
|
||||||
&:nth-of-type(1) {
|
&:nth-of-type(1) {
|
||||||
/* 自动布局子元素 */
|
/* 自动布局子元素 */
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
|
|
|
@ -1,12 +1,88 @@
|
||||||
import IconFont from "@/components/iconfont";
|
import IconFont from "@/components/iconfont";
|
||||||
import classes from "./LevelUp.module.css";
|
import classes from "./LevelUp.module.css";
|
||||||
import { cn } from "@/utils";
|
import { cn, getLevelName } from "@/utils";
|
||||||
import Button from "antd-mobile/es/components/button";
|
import Button from "antd-mobile/es/components/button";
|
||||||
import Space from "antd-mobile/es/components/space";
|
import Space from "antd-mobile/es/components/space";
|
||||||
import { PropsWithChildren } from "react";
|
import { PropsWithChildren, useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import {
|
||||||
|
api_get_user_upgrade_information,
|
||||||
|
api_upgrade,
|
||||||
|
api_users_cancel_orders,
|
||||||
|
} from "@/server/api";
|
||||||
|
import { UpgradeOrder, UserUpgradeInformation } from "@/server/module";
|
||||||
|
import Toast, { ToastHandler } from "antd-mobile/es/components/toast";
|
||||||
|
import {
|
||||||
|
authorizedU,
|
||||||
|
getApproveUsdt,
|
||||||
|
getBalance,
|
||||||
|
upGradeByContract,
|
||||||
|
} from "@/contract/utils";
|
||||||
|
import { toWei } from "web3-utils";
|
||||||
|
import usePollingCheckBuyStatus from "@/hook/usePollingCheckBuyStatus";
|
||||||
|
import { BaseError } from "wagmi";
|
||||||
|
import { Dialog } from "antd-mobile";
|
||||||
|
import { useNavigate } from "react-router-dom";
|
||||||
export default function () {
|
export default function () {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const [userUpgradeInfo, setUserUpgradeInfo] =
|
||||||
|
useState<UserUpgradeInformation>();
|
||||||
|
const [approveUsdt, setApproveUsdt] = useState<bigint>(0n);
|
||||||
|
const [balance, setBalance] = useState<bigint>(0n);
|
||||||
|
const approveLoadingToast = useRef<ToastHandler>();
|
||||||
|
const approvePrice = useMemo(
|
||||||
|
() => BigInt(toWei(userUpgradeInfo?.price || "0", "ether")),
|
||||||
|
[userUpgradeInfo?.price]
|
||||||
|
);
|
||||||
|
const upgradeLoadingtoast = useRef<ToastHandler>();
|
||||||
|
const orderInfo = useRef<UpgradeOrder>();
|
||||||
|
|
||||||
|
const { transcationStatus, startPollingCheckBuyStatus } =
|
||||||
|
usePollingCheckBuyStatus("NORMAL");
|
||||||
|
useEffect(() => {
|
||||||
|
updateUserUpgrdeInfo();
|
||||||
|
return () => {};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
(async () => {
|
||||||
|
if (userUpgradeInfo?.status != 1) return;
|
||||||
|
Toast.show({ icon: "loading", content: t("正在获取已授权金额") });
|
||||||
|
setBalance(await getBalance());
|
||||||
|
setApproveUsdt(await getApproveUsdt());
|
||||||
|
Toast.clear();
|
||||||
|
})();
|
||||||
|
|
||||||
|
return () => {};
|
||||||
|
}, [userUpgradeInfo?.status]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
console.log("approvePrice:", approvePrice);
|
||||||
|
|
||||||
|
return () => {};
|
||||||
|
}, [approvePrice]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (transcationStatus == "success") {
|
||||||
|
upgradeLoadingtoast.current?.close();
|
||||||
|
Dialog.alert({
|
||||||
|
content: `${t("升级成功,返回首页查看")}`,
|
||||||
|
confirmText: "OK",
|
||||||
|
onConfirm() {
|
||||||
|
navigate("/");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {};
|
||||||
|
}, [transcationStatus]);
|
||||||
|
|
||||||
|
async function updateUserUpgrdeInfo() {
|
||||||
|
const { data } = await api_get_user_upgrade_information().send({});
|
||||||
|
setUserUpgradeInfo(data?.data);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={cn(classes.LevelUp, classes.container)}>
|
<div className={cn(classes.LevelUp, classes.container)}>
|
||||||
|
@ -14,7 +90,7 @@ export default function () {
|
||||||
<div className={classes.content_box}>
|
<div className={classes.content_box}>
|
||||||
<div className={classes.box_item}>
|
<div className={classes.box_item}>
|
||||||
<span>{t("当前级别")}</span>
|
<span>{t("当前级别")}</span>
|
||||||
<span>{t("普通活跃")}</span>
|
<span>{getLevelName(userUpgradeInfo?.level || 0)}</span>
|
||||||
</div>
|
</div>
|
||||||
<IconFont
|
<IconFont
|
||||||
className={classes.box_arrow}
|
className={classes.box_arrow}
|
||||||
|
@ -23,29 +99,100 @@ export default function () {
|
||||||
/>
|
/>
|
||||||
<div className={classes.box_item}>
|
<div className={classes.box_item}>
|
||||||
<span>{t("提升级别")}</span>
|
<span>{t("提升级别")}</span>
|
||||||
<span>{t("社长")}</span>
|
<span>{userUpgradeInfo?.level == 1 ? t("社长") : t("无")}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={classes.content_price}>
|
<div className={classes.content_price}>
|
||||||
<span>{t("当前升级价格:")}</span>
|
<span>{t("当前升级价格:")}</span>
|
||||||
<span>110 USDT</span>
|
<span>{userUpgradeInfo?.price || 0} USDT</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={classes.content_price_des}>
|
<div className={classes.content_price_des}>
|
||||||
<span>{t("价格说明:")}</span>
|
<span>{t("价格说明:")}</span>
|
||||||
<span>
|
<span>
|
||||||
{t(
|
{t(
|
||||||
"升级费用100USDT起,其中gas费2USDT,剩余部分50%进入资金池,另外50%平均分给所有升级成功的社长和基金会社长。自第二个社长升级开始,每升级一名社长所需铸造费用增加10%,既第二位社长升级铸造费用为100u+100*10%=110USDT,以此类推。"
|
"升级费用xxx USDT起,其中gas费2USDT,剩余部分50%进入资金池,另外50%平均分给所有升级成功的社长和基金会社长。自第二个社长升级开始,每升级一名社长所需铸造费用增加xxx,既第二位社长升级铸造费用为xxxu+xxx*xxx=xxx USDT,以此类推。",
|
||||||
|
{
|
||||||
|
value1: userUpgradeInfo?.upgradeFees || 0,
|
||||||
|
value2: userUpgradeInfo?.proportion || "0%",
|
||||||
|
value3:
|
||||||
|
parseFloat(userUpgradeInfo?.upgradeFees || "0") +
|
||||||
|
(parseFloat(userUpgradeInfo?.upgradeFees || "0") *
|
||||||
|
parseFloat(
|
||||||
|
(userUpgradeInfo?.proportion || "0%").replace("%", "")
|
||||||
|
)) /
|
||||||
|
100,
|
||||||
|
}
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Button className={classes.content_btn} fill="none">
|
<Button
|
||||||
|
className={classes.content_btn}
|
||||||
|
fill="none"
|
||||||
|
disabled={userUpgradeInfo?.status != 1}
|
||||||
|
onClick={async () => {
|
||||||
|
if (balance <= 0n) {
|
||||||
|
Toast.show({ icon: "fail", content: t("余额不足") });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 授权
|
||||||
|
if (approveUsdt === 0n) {
|
||||||
|
approveLoadingToast.current = Toast.show({
|
||||||
|
icon: "loading",
|
||||||
|
duration: 0,
|
||||||
|
content: t("正在授权USDT"),
|
||||||
|
});
|
||||||
|
authorizedU(approvePrice)
|
||||||
|
.then(async () => {
|
||||||
|
setApproveUsdt(await getApproveUsdt());
|
||||||
|
approveLoadingToast.current?.close();
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
Toast.show({ content: err.shortMessage, icon: "fail" });
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 升级
|
||||||
|
upgradeLoadingtoast.current = Toast.show({
|
||||||
|
icon: "loading",
|
||||||
|
duration: 0,
|
||||||
|
content: t("购买中"),
|
||||||
|
maskClickable: false,
|
||||||
|
});
|
||||||
|
const { data: orderRes } = await api_upgrade().send({});
|
||||||
|
orderInfo.current = orderRes?.data;
|
||||||
|
if (!orderInfo.current?.orderNumber) return;
|
||||||
|
const buyAmount = BigInt(orderInfo.current?.buyAmount || "");
|
||||||
|
upGradeByContract(buyAmount, orderInfo.current?.orderNumber)
|
||||||
|
.then((hash) => {
|
||||||
|
console.log("购买成功!hash:", hash);
|
||||||
|
updateUserUpgrdeInfo();
|
||||||
|
startPollingCheckBuyStatus(hash);
|
||||||
|
})
|
||||||
|
.catch(async (err: BaseError) => {
|
||||||
|
upgradeLoadingtoast.current?.close();
|
||||||
|
Toast.show({ content: err.shortMessage, icon: "fail" });
|
||||||
|
// 取消购买
|
||||||
|
await api_users_cancel_orders().send({
|
||||||
|
queryParams: { orderId: orderInfo.current?.id! },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Space>
|
<Space>
|
||||||
{/* <span>MINT</span> */}
|
{userUpgradeInfo?.status == 1 ? (
|
||||||
<span>{t("授权USDT")}</span>
|
<>
|
||||||
{/* <SpinLoading style={{ "--size": "20px" }} color="white" /> */}
|
{approveUsdt > 0n && <span>MINT</span>}
|
||||||
|
{approveUsdt === 0n && <span>{t("授权USDT")}</span>}
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<span>{t("无级别提升")}</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</Space>
|
</Space>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -55,7 +202,9 @@ export default function () {
|
||||||
<ul>
|
<ul>
|
||||||
<ConItem
|
<ConItem
|
||||||
memberName={t("普通会员")}
|
memberName={t("普通会员")}
|
||||||
limitText={t("(限量20000个)")}
|
limitText={t("(限量xxx个)", {
|
||||||
|
value: userUpgradeInfo?.ordinary || 0,
|
||||||
|
})}
|
||||||
conList={[
|
conList={[
|
||||||
t("1. MINT一枚NFT成为非活跃普通会员"),
|
t("1. MINT一枚NFT成为非活跃普通会员"),
|
||||||
t("2. MINT NFT并推荐MINT成为活跃普通会员"),
|
t("2. MINT NFT并推荐MINT成为活跃普通会员"),
|
||||||
|
@ -66,7 +215,9 @@ export default function () {
|
||||||
|
|
||||||
<ConItem
|
<ConItem
|
||||||
memberName={t("社长")}
|
memberName={t("社长")}
|
||||||
limitText={t("(限量500个)")}
|
limitText={t("(限量xxx个)", {
|
||||||
|
value: userUpgradeInfo?.president || 0,
|
||||||
|
})}
|
||||||
conList={[
|
conList={[
|
||||||
t("1. 先成为活跃普通会员,并推荐MINT 20枚NFT"),
|
t("1. 先成为活跃普通会员,并推荐MINT 20枚NFT"),
|
||||||
t("2. 需支付100USDT起升级费用成为社长(第二个起递增10%)"),
|
t("2. 需支付100USDT起升级费用成为社长(第二个起递增10%)"),
|
||||||
|
@ -78,7 +229,9 @@ export default function () {
|
||||||
|
|
||||||
<ConItem
|
<ConItem
|
||||||
memberName={t("基金会社长")}
|
memberName={t("基金会社长")}
|
||||||
limitText={t("(限量20个)")}
|
limitText={t("(限量xxx个)", {
|
||||||
|
value: userUpgradeInfo?.foundation || 0,
|
||||||
|
})}
|
||||||
conList={[
|
conList={[
|
||||||
t("1. 先成为社长,并团队中有20个社长"),
|
t("1. 先成为社长,并团队中有20个社长"),
|
||||||
t("2. 享社长权益+0.5%空投代币平分(所有基金会社长)"),
|
t("2. 享社长权益+0.5%空投代币平分(所有基金会社长)"),
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* @LastEditors: John
|
* @LastEditors: John
|
||||||
* @Date: 2024-06-18 15:28:03
|
* @Date: 2024-06-18 15:28:03
|
||||||
* @LastEditTime: 2024-06-19 14:06:59
|
* @LastEditTime: 2024-06-24 11:08:14
|
||||||
* @Author: John
|
* @Author: John
|
||||||
*/
|
*/
|
||||||
import { cn } from "@/utils";
|
import { cn } from "@/utils";
|
||||||
|
@ -10,8 +10,85 @@ import nft_bg from "@/assets/nft_bg.svg";
|
||||||
import Button from "antd-mobile/es/components/button";
|
import Button from "antd-mobile/es/components/button";
|
||||||
import Space from "antd-mobile/es/components/space";
|
import Space from "antd-mobile/es/components/space";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { useEffect, useMemo, useRef, useState } from "react";
|
||||||
|
import {
|
||||||
|
api_get_nft_configuration_data,
|
||||||
|
api_nft_order,
|
||||||
|
api_users_cancel_orders,
|
||||||
|
} from "@/server/api";
|
||||||
|
import { NftConfigurationData, NftOrder } from "@/server/module";
|
||||||
|
import {
|
||||||
|
authorizedU,
|
||||||
|
getApproveUsdt,
|
||||||
|
getBalance,
|
||||||
|
payByContract,
|
||||||
|
} from "@/contract/utils";
|
||||||
|
import { Dialog, Modal, 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 () {
|
export default function () {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const { Token } = useUserStore();
|
||||||
|
const [nftConfig, setNftConfig] = useState<NftConfigurationData>();
|
||||||
|
const [approveUsdt, setApproveUsdt] = useState<bigint>(0n);
|
||||||
|
const [balance, setBalance] = useState<bigint>(0n);
|
||||||
|
const orderInfo = useRef<NftOrder>();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const buyLoadingToast = useRef<ToastHandler>();
|
||||||
|
const approveLoadingToast = useRef<ToastHandler>();
|
||||||
|
const { buyNftIds, startPollingCheckBuyStatus } =
|
||||||
|
usePollingCheckBuyStatus("NFT");
|
||||||
|
|
||||||
|
const approvePrice = useMemo(
|
||||||
|
() => BigInt(toWei(nftConfig?.nftPrice || "0", "ether")),
|
||||||
|
[nftConfig?.nftPrice]
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
updateNftConfig();
|
||||||
|
|
||||||
|
return () => {};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
(async () => {
|
||||||
|
Toast.show({ icon: "loading", content: t("正在获取已授权金额") });
|
||||||
|
setBalance(await getBalance());
|
||||||
|
setApproveUsdt(await getApproveUsdt());
|
||||||
|
Toast.clear();
|
||||||
|
})();
|
||||||
|
|
||||||
|
return () => {};
|
||||||
|
}, [Token]);
|
||||||
|
|
||||||
|
async function updateNftConfig() {
|
||||||
|
const { data } = await api_get_nft_configuration_data().send({});
|
||||||
|
setNftConfig(data?.data);
|
||||||
|
}
|
||||||
|
useEffect(() => {
|
||||||
|
if (buyNftIds) {
|
||||||
|
buyLoadingToast.current?.close();
|
||||||
|
Dialog.alert({
|
||||||
|
content: `${t("MINT成功,返回首页查看")}`,
|
||||||
|
confirmText: "OK",
|
||||||
|
onConfirm() {
|
||||||
|
navigate("/");
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {};
|
||||||
|
}, [buyNftIds]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {};
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={cn(classes.Mint, classes.container)}>
|
<div className={cn(classes.Mint, classes.container)}>
|
||||||
|
@ -22,17 +99,17 @@ export default function () {
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<span>{t("NFT总量:")}</span>
|
<span>{t("NFT总量:")}</span>
|
||||||
<span>20000</span>
|
<span>{nftConfig?.nftCount || 0}</span>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<span>{t("MINT余量:")}</span>
|
<span>{t("MINT余量:")}</span>
|
||||||
<span>15000</span>
|
<span>{nftConfig?.nftRemainder || 0}</span>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<span>{t("当前MINT价格:")}</span>
|
<span>{t("当前MINT价格:")}</span>
|
||||||
<span>110 USDT</span>
|
<span>{nftConfig?.nftPrice || 0} USDT</span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
@ -40,16 +117,87 @@ export default function () {
|
||||||
<span>{t("价格说明:")}</span>
|
<span>{t("价格说明:")}</span>
|
||||||
<span>
|
<span>
|
||||||
{t(
|
{t(
|
||||||
"100USDT起,每增加100名普通会员,NFT价格上涨1%,既:前100名价格为100USDT/枚,101-200名价格为100u+100u*1%=101USDT/枚,以此类推。"
|
"{{value1}} USDT起,每增加 {{value2}} 名普通会员,NFT价格上涨 {{value3}},既:前 {{value2}} 名价格为 {{value1}} USDT/枚,value4 名价格为{{value1}}u+{{value1}}u*{{value3}}={{value5}} USDT/枚,以此类推。",
|
||||||
|
{
|
||||||
|
value1: nftConfig?.initialPrice || 0,
|
||||||
|
value2: nftConfig?.floatingQuantity || 0,
|
||||||
|
value3: nftConfig?.kamibutsu || "0%",
|
||||||
|
value4: `${
|
||||||
|
parseInt(nftConfig?.floatingQuantity || "0") + 1
|
||||||
|
} - ${parseInt(nftConfig?.floatingQuantity || "0") * 2}`,
|
||||||
|
value5:
|
||||||
|
parseFloat(nftConfig?.initialPrice || "0") +
|
||||||
|
(parseFloat(nftConfig?.initialPrice || "0") *
|
||||||
|
parseFloat(
|
||||||
|
(nftConfig?.kamibutsu || "0%").replace("%", "")
|
||||||
|
)) /
|
||||||
|
100,
|
||||||
|
}
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Button className={classes.btn} fill="none">
|
<Button
|
||||||
|
className={classes.btn}
|
||||||
|
fill="none"
|
||||||
|
onClick={async () => {
|
||||||
|
if (balance <= 0n) {
|
||||||
|
Toast.show({ icon: "fail", content: t("余额不足") });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 授权
|
||||||
|
if (approveUsdt === 0n) {
|
||||||
|
approveLoadingToast.current = Toast.show({
|
||||||
|
icon: "loading",
|
||||||
|
duration: 0,
|
||||||
|
content: t("正在授权USDT"),
|
||||||
|
});
|
||||||
|
authorizedU(approvePrice)
|
||||||
|
.then(async () => {
|
||||||
|
setApproveUsdt(await getApproveUsdt());
|
||||||
|
approveLoadingToast.current?.close();
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
Toast.show({ content: err.shortMessage, icon: "fail" });
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 购买
|
||||||
|
buyLoadingToast.current = Toast.show({
|
||||||
|
icon: "loading",
|
||||||
|
duration: 0,
|
||||||
|
content: t("购买中"),
|
||||||
|
maskClickable: false,
|
||||||
|
});
|
||||||
|
const { data: orderRes } = await api_nft_order().send({});
|
||||||
|
orderInfo.current = orderRes?.data;
|
||||||
|
if (!orderInfo.current?.orderNumber) return;
|
||||||
|
const buyAmount = BigInt(orderInfo.current?.buyAmount || "");
|
||||||
|
payByContract(buyAmount, orderInfo.current?.orderNumber)
|
||||||
|
.then((hash) => {
|
||||||
|
console.log("购买成功!hash:", hash);
|
||||||
|
updateNftConfig();
|
||||||
|
startPollingCheckBuyStatus(hash);
|
||||||
|
})
|
||||||
|
.catch(async (err: BaseError) => {
|
||||||
|
buyLoadingToast.current?.close();
|
||||||
|
Toast.show({
|
||||||
|
content: err.shortMessage,
|
||||||
|
icon: "fail",
|
||||||
|
});
|
||||||
|
// 取消购买
|
||||||
|
await api_users_cancel_orders().send({
|
||||||
|
queryParams: { orderId: orderInfo.current?.id! },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Space>
|
<Space>
|
||||||
{/* <span>MINT</span> */}
|
{approveUsdt > 0n && <span>MINT</span>}
|
||||||
<span>{t("授权USDT")}</span>
|
{approveUsdt === 0n && <span>{t("授权USDT")}</span>}
|
||||||
{/* <SpinLoading style={{ "--size": "20px" }} color="white" /> */}
|
|
||||||
</Space>
|
</Space>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,133 @@
|
||||||
|
/*
|
||||||
|
* @LastEditors: John
|
||||||
|
* @Date: 2024-06-18 10:28:21
|
||||||
|
* @LastEditTime: 2024-06-22 11:43:04
|
||||||
|
* @Author: John
|
||||||
|
*/
|
||||||
|
import { GET, POST } from "./client";
|
||||||
|
import {
|
||||||
|
ClaimIncome,
|
||||||
|
IncomeRecord,
|
||||||
|
IncomeRecordType,
|
||||||
|
NftConfigurationData,
|
||||||
|
NftOrder,
|
||||||
|
PreprelionListItem,
|
||||||
|
UpgradeOrder,
|
||||||
|
UserHomeData,
|
||||||
|
UserIncome,
|
||||||
|
UserUpgradeInformation,
|
||||||
|
} from "./module";
|
||||||
|
|
||||||
|
// 检查账号是否注册
|
||||||
|
export function api_check_account_registration() {
|
||||||
|
return GET<{ account: string }, { exist: boolean }>({
|
||||||
|
url: "/api/account/exist",
|
||||||
|
requiresToken: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 登录
|
||||||
|
export function api_login() {
|
||||||
|
return POST<
|
||||||
|
{
|
||||||
|
account: `0x${string}` | undefined;
|
||||||
|
password: string;
|
||||||
|
publicKey: string;
|
||||||
|
chainType: 2;
|
||||||
|
},
|
||||||
|
{ token: string }
|
||||||
|
>({
|
||||||
|
url: "/api/account/signIn",
|
||||||
|
requiresToken: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 注册
|
||||||
|
export function api_signUp() {
|
||||||
|
return POST<
|
||||||
|
{
|
||||||
|
account: `0x${string}` | undefined;
|
||||||
|
publicKey: string;
|
||||||
|
shareCode: string;
|
||||||
|
chainType: 2;
|
||||||
|
},
|
||||||
|
any
|
||||||
|
>({ url: "/api/account/signUp", requiresToken: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取钱包签名串
|
||||||
|
export function api_get_wallet_signature_string() {
|
||||||
|
return GET<
|
||||||
|
{ account: `0x${string}` | undefined },
|
||||||
|
{ encryptedString: string }
|
||||||
|
>({
|
||||||
|
url: "/api/account/randomCode",
|
||||||
|
requiresToken: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取首页用户数据
|
||||||
|
export function api_get_homepage_user_data() {
|
||||||
|
return GET<any, UserHomeData>({
|
||||||
|
url: "/api/common/getUserData",
|
||||||
|
requiresToken: false,
|
||||||
|
requiresAddress: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取用户升级信息
|
||||||
|
export function api_get_user_upgrade_information() {
|
||||||
|
return GET<any, UserUpgradeInformation>({
|
||||||
|
url: "/api/user/userUpgradeInformation",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取NFT配置数据
|
||||||
|
export function api_get_nft_configuration_data() {
|
||||||
|
return GET<any, NftConfigurationData>({
|
||||||
|
url: "/api/nft/getUserData",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分页查询收益记录
|
||||||
|
export function api_pagling_query_income_record() {
|
||||||
|
return GET<
|
||||||
|
{
|
||||||
|
status?: IncomeRecordType;
|
||||||
|
id: string;
|
||||||
|
type: 1 | 2; // 1=领取记录 2=发放记录
|
||||||
|
pageNum: number;
|
||||||
|
pageSize: number;
|
||||||
|
},
|
||||||
|
IncomeRecord
|
||||||
|
>({
|
||||||
|
url: "/api/common/earningsRecords",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// NFT下单
|
||||||
|
export function api_nft_order() {
|
||||||
|
return POST<any, NftOrder>({ url: "/api/nft/payNft" });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户取消订单告诉我
|
||||||
|
export function api_users_cancel_orders() {
|
||||||
|
return POST<any, any, { orderId: number }>({ url: "/api/nft/cancel" });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 直推列表
|
||||||
|
export function api_preprelion_list() {
|
||||||
|
return GET<any, PreprelionListItem[]>({ url: "/api/user/getDirectPushList" });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 升级
|
||||||
|
export function api_upgrade() {
|
||||||
|
return POST<any, UpgradeOrder>({ url: "/api/user/upgrade" });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 用户领取收益
|
||||||
|
export function api_claim_income() {
|
||||||
|
return POST<any, ClaimIncome, { id: number }>({
|
||||||
|
url: "/api/common/claimYourEarnings",
|
||||||
|
});
|
||||||
|
}
|
|
@ -1,34 +1,132 @@
|
||||||
/*
|
/*
|
||||||
* @LastEditors: John
|
* @LastEditors: John
|
||||||
* @Date: 2024-06-18 10:09:21
|
* @Date: 2024-06-18 10:09:21
|
||||||
* @LastEditTime: 2024-06-18 10:27:04
|
* @LastEditTime: 2024-06-21 14:47:26
|
||||||
* @Author: John
|
* @Author: John
|
||||||
*/
|
*/
|
||||||
import { Client } from "@hyper-fetch/core";
|
import { Client } from "@hyper-fetch/core";
|
||||||
import { BASE_RESPONSE } from "./module";
|
import { BASE_RESPONSE } from "./module";
|
||||||
|
import useUserStore from "@/store/User";
|
||||||
|
import { getAccount, connect } from "@wagmi/core";
|
||||||
|
import { config } from "@/components/WalletProvider";
|
||||||
|
import { Lang } from "@/constants";
|
||||||
|
import { Toast } from "antd-mobile";
|
||||||
|
import { injected } from "wagmi/connectors";
|
||||||
|
import { signAndLogin } from "@/utils/wallet";
|
||||||
|
import i18next from "i18next";
|
||||||
|
function initClient({
|
||||||
|
requiresToken,
|
||||||
|
requiresAddress,
|
||||||
|
}: {
|
||||||
|
requiresToken: boolean;
|
||||||
|
requiresAddress: boolean;
|
||||||
|
}) {
|
||||||
|
return new Client({ url: import.meta.env.VITE_BASE_API_URL })
|
||||||
|
.onAuth(async (req) => {
|
||||||
|
if (requiresToken) {
|
||||||
|
if (!useUserStore.getState().Token) {
|
||||||
|
// TODO 登录获取token
|
||||||
|
// Toast.show({ content: "token is emtiy!", icon: "fail" });
|
||||||
|
if (!getAccount(config).address)
|
||||||
|
await connect(config, { connector: injected() });
|
||||||
|
await signAndLogin(getAccount(config).address!);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const client = new Client({ url: import.meta.env.VITE_BASE_API_URL })
|
if (requiresAddress) {
|
||||||
.onAuth((req) => {
|
if (!getAccount(config).address) {
|
||||||
return req;
|
// TODO 链接钱包
|
||||||
})
|
// Toast.show({ content: "address is emtiy!", icon: "fail" });
|
||||||
.onRequest((req) => {
|
await connect(config, { connector: injected() });
|
||||||
req.setHeaders({});
|
}
|
||||||
return req;
|
}
|
||||||
})
|
|
||||||
.onResponse((res) => {
|
|
||||||
return res;
|
|
||||||
});
|
|
||||||
|
|
||||||
export const POST = <P, R = any>({ url }: { url: string }) => {
|
const headers = {
|
||||||
return client.createRequest<BASE_RESPONSE<R>, P>()({
|
...req.headers,
|
||||||
|
Authorization: useUserStore.getState().Token,
|
||||||
|
"Accept-Language": getAcceptLang(),
|
||||||
|
address: (getAccount(config).address || "") as string,
|
||||||
|
};
|
||||||
|
return req.setHeaders(headers);
|
||||||
|
})
|
||||||
|
.onResponse((res) => {
|
||||||
|
console.log(res);
|
||||||
|
if (!res.success) {
|
||||||
|
Toast.clear();
|
||||||
|
Toast.show({ content: i18next.t("服务器错误"), icon: "fail" });
|
||||||
|
throw new Error(res.error?.message);
|
||||||
|
}
|
||||||
|
const resData: BASE_RESPONSE = res.data;
|
||||||
|
if (resData.code !== 200 && resData.code !== 0) {
|
||||||
|
if (resData.msg) Toast.show({ content: resData.msg, icon: "fail" });
|
||||||
|
throw new Error(resData.msg || "client on response error");
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export const POST = <P = any, R = any, QueryParams = any>({
|
||||||
|
url,
|
||||||
|
requiresToken = true,
|
||||||
|
requiresAddress = true,
|
||||||
|
}: {
|
||||||
|
url: string;
|
||||||
|
requiresToken?: boolean;
|
||||||
|
requiresAddress?: boolean;
|
||||||
|
}) => {
|
||||||
|
return initClient({ requiresToken, requiresAddress }).createRequest<
|
||||||
|
BASE_RESPONSE<R>,
|
||||||
|
P,
|
||||||
|
any,
|
||||||
|
QueryParams
|
||||||
|
>()({
|
||||||
method: "POST",
|
method: "POST",
|
||||||
endpoint: url,
|
endpoint: url,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const GET = <P, R = any>({ url }: { url: string }) => {
|
export const GET = <P = any, R = any>({
|
||||||
return client.createRequest<BASE_RESPONSE<R>, any, any, P>()({
|
url,
|
||||||
|
requiresToken = true,
|
||||||
|
requiresAddress = true,
|
||||||
|
}: {
|
||||||
|
url: string;
|
||||||
|
requiresToken?: boolean;
|
||||||
|
requiresAddress?: boolean;
|
||||||
|
}) => {
|
||||||
|
return initClient({ requiresToken, requiresAddress }).createRequest<
|
||||||
|
BASE_RESPONSE<R>,
|
||||||
|
any,
|
||||||
|
any,
|
||||||
|
P
|
||||||
|
>()({
|
||||||
method: "GET",
|
method: "GET",
|
||||||
endpoint: url,
|
endpoint: url,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function getAcceptLang() {
|
||||||
|
let apiAcceptLang;
|
||||||
|
switch (useUserStore.getState().Lang) {
|
||||||
|
case Lang.cn:
|
||||||
|
apiAcceptLang = "zh-CN";
|
||||||
|
break;
|
||||||
|
case Lang.tw:
|
||||||
|
apiAcceptLang = "zh-TW";
|
||||||
|
break;
|
||||||
|
case Lang.en:
|
||||||
|
apiAcceptLang = "en-US";
|
||||||
|
break;
|
||||||
|
case Lang.de:
|
||||||
|
apiAcceptLang = "de-DE";
|
||||||
|
break;
|
||||||
|
case Lang.jp:
|
||||||
|
apiAcceptLang = "ja-JP";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
apiAcceptLang = "zh-CN";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return apiAcceptLang;
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,137 @@
|
||||||
export type BASE_RESPONSE<T = any> = {
|
export type BASE_RESPONSE<T = any> = {
|
||||||
code: 0 | 200;
|
code: 0 | 200;
|
||||||
data: T | null;
|
data: T;
|
||||||
msg: string;
|
msg: string;
|
||||||
timeMillis: number;
|
timeMillis: number;
|
||||||
}; // What's returned from request
|
}; // What's returned from request
|
||||||
|
|
||||||
|
export type Level = 0 | 1 | 2 | 3; // 0=无等级 1=会员 2=社长 3=基金会
|
||||||
|
export interface UserHomeData {
|
||||||
|
address: string;
|
||||||
|
airdropNumber: number;
|
||||||
|
foundation: number;
|
||||||
|
invitationCode: string;
|
||||||
|
level: Level;
|
||||||
|
mintNumber: number;
|
||||||
|
nftId: number;
|
||||||
|
pools: string;
|
||||||
|
president: number;
|
||||||
|
presidentNumber: number;
|
||||||
|
userImg: string;
|
||||||
|
userIncomes: UserIncome[];
|
||||||
|
}
|
||||||
|
export interface UserIncome {
|
||||||
|
coinId: number;
|
||||||
|
coinName: string;
|
||||||
|
collection: number;
|
||||||
|
createTime: string;
|
||||||
|
flag: number;
|
||||||
|
id: number;
|
||||||
|
receive: string;
|
||||||
|
updateTime: string;
|
||||||
|
userId: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UserUpgradeInformation {
|
||||||
|
foundation: number;
|
||||||
|
level: Level;
|
||||||
|
numberOfPresidents: number;
|
||||||
|
ordinary: number;
|
||||||
|
president: number;
|
||||||
|
price: string;
|
||||||
|
proportion: string;
|
||||||
|
status: 1 | 0; //1=可升级 0=不可升级
|
||||||
|
upgradeFees: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NftConfigurationData {
|
||||||
|
floatingQuantity: string;
|
||||||
|
initialPrice: string;
|
||||||
|
kamibutsu: string;
|
||||||
|
nftCount: number;
|
||||||
|
nftPrice: string;
|
||||||
|
nftRemainder: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IncomeRecord {
|
||||||
|
countId: string;
|
||||||
|
current: number;
|
||||||
|
maxLimit: string;
|
||||||
|
optimizeCountSql: boolean;
|
||||||
|
orders: { asc: boolean; column: string }[];
|
||||||
|
pages: number;
|
||||||
|
records: IncomeRecordsItem[];
|
||||||
|
searchCount: boolean;
|
||||||
|
size: number;
|
||||||
|
total: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IncomeRecordsItem {
|
||||||
|
id: number;
|
||||||
|
createTime: string;
|
||||||
|
updateTime: string;
|
||||||
|
flag: number;
|
||||||
|
userId: number;
|
||||||
|
incomeId: number;
|
||||||
|
type: 1 | 2 | 3 | 4; // 1:领取成功,2发放记录 3,领取中 4:已取消
|
||||||
|
coinId: number;
|
||||||
|
opType: number;
|
||||||
|
opRemark: string;
|
||||||
|
opBefore: number;
|
||||||
|
opValue: number;
|
||||||
|
opAfter: number;
|
||||||
|
extRemark: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type IncomeRecordType = 4 | 5 | 6 | 7 | 8 | 9; //4=直推>20NFT,5=升级费平分,6=NFT空投,7=社长空投,8=基金会社长,9=直推空投
|
||||||
|
|
||||||
|
export interface NftOrder {
|
||||||
|
address: string;
|
||||||
|
buyAmount: string;
|
||||||
|
buyCount: string;
|
||||||
|
createBy: string;
|
||||||
|
createTime: string;
|
||||||
|
hash: string;
|
||||||
|
id: number;
|
||||||
|
illustrate: string;
|
||||||
|
nftId: number;
|
||||||
|
orderNumber: string;
|
||||||
|
payCoin: string;
|
||||||
|
recommendId: number;
|
||||||
|
status: number;
|
||||||
|
updateBy: string;
|
||||||
|
updateTime: string;
|
||||||
|
userId: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PreprelionListItem {
|
||||||
|
address: string;
|
||||||
|
level: number;
|
||||||
|
mintNumber: number;
|
||||||
|
userType: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UpgradeOrder {
|
||||||
|
address: string;
|
||||||
|
buyAmount: string;
|
||||||
|
createBy: string;
|
||||||
|
createTime: string;
|
||||||
|
endLevel: number;
|
||||||
|
hash: string;
|
||||||
|
id: number;
|
||||||
|
illustrate: string;
|
||||||
|
orderNumber: string;
|
||||||
|
payCoin: string;
|
||||||
|
startLevel: number;
|
||||||
|
status: number;
|
||||||
|
updateBy: string;
|
||||||
|
updateTime: string;
|
||||||
|
userId: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ClaimIncome {
|
||||||
|
claimQuantity: string;
|
||||||
|
hash: string;
|
||||||
|
orderNumber: string;
|
||||||
|
time: string;
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* @LastEditors: John
|
* @LastEditors: John
|
||||||
* @Date: 2024-06-17 17:45:43
|
* @Date: 2024-06-17 17:45:43
|
||||||
* @LastEditTime: 2024-06-19 16:26:24
|
* @LastEditTime: 2024-06-20 15:49:09
|
||||||
* @Author: John
|
* @Author: John
|
||||||
*/
|
*/
|
||||||
import { ASYNC_STORAGE_KEY, Lang } from "@/constants";
|
import { ASYNC_STORAGE_KEY, Lang } from "@/constants";
|
||||||
|
@ -9,21 +9,33 @@ import { create } from "zustand";
|
||||||
import { createJSONStorage, persist } from "zustand/middleware";
|
import { createJSONStorage, persist } from "zustand/middleware";
|
||||||
|
|
||||||
interface UserState {
|
interface UserState {
|
||||||
|
Address: string;
|
||||||
|
UpdateAddress: (a: string) => void;
|
||||||
|
|
||||||
Token: string;
|
Token: string;
|
||||||
UpdateToken: (t: string) => void;
|
UpdateToken: (t: string) => void;
|
||||||
|
|
||||||
Lang: Lang;
|
Lang: Lang;
|
||||||
UpdateLang: (l: Lang) => void;
|
UpdateLang: (l: Lang) => void;
|
||||||
|
|
||||||
|
InviteCode: string;
|
||||||
|
UpdateInviteCode: (I: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useUserStore = create<UserState>()(
|
export const useUserStore = create<UserState>()(
|
||||||
persist(
|
persist(
|
||||||
(set, _get) => ({
|
(set, _get) => ({
|
||||||
|
Address: "",
|
||||||
|
UpdateAddress: (a) => set({ Address: a }),
|
||||||
|
|
||||||
Token: "",
|
Token: "",
|
||||||
UpdateToken: (t) => set({ Token: t }),
|
UpdateToken: (t) => set({ Token: t }),
|
||||||
|
|
||||||
Lang: Lang.en,
|
Lang: Lang.en,
|
||||||
UpdateLang: (l) => set({ Lang: l }),
|
UpdateLang: (l) => set({ Lang: l }),
|
||||||
|
|
||||||
|
InviteCode: "",
|
||||||
|
UpdateInviteCode: (i) => set({ InviteCode: i }),
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
name: ASYNC_STORAGE_KEY.Store, // name of item in the storage (must be unique)
|
name: ASYNC_STORAGE_KEY.Store, // name of item in the storage (must be unique)
|
||||||
|
|
|
@ -2,6 +2,9 @@
|
||||||
width: 100vw !important;
|
width: 100vw !important;
|
||||||
background-color: transparent !important;
|
background-color: transparent !important;
|
||||||
padding: 0 14px;
|
padding: 0 14px;
|
||||||
|
> div {
|
||||||
|
background-color: transparent !important;
|
||||||
|
}
|
||||||
|
|
||||||
.rdt_TableHead {
|
.rdt_TableHead {
|
||||||
.rdt_TableHeadRow {
|
.rdt_TableHeadRow {
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
/*
|
/*
|
||||||
* @LastEditors: John
|
* @LastEditors: John
|
||||||
* @Date: 2024-06-17 18:19:27
|
* @Date: 2024-06-17 18:19:27
|
||||||
* @LastEditTime: 2024-06-19 17:07:43
|
* @LastEditTime: 2024-06-22 15:26:37
|
||||||
* @Author: John
|
* @Author: John
|
||||||
*/
|
*/
|
||||||
import { type ClassValue, clsx } from "clsx";
|
import { type ClassValue, clsx } from "clsx";
|
||||||
import { twMerge } from "tailwind-merge";
|
import { twMerge } from "tailwind-merge";
|
||||||
import Toast from "antd-mobile/es/components/toast";
|
import Toast from "antd-mobile/es/components/toast";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
|
import { Level } from "@/server/module";
|
||||||
|
|
||||||
export const ua = navigator.userAgent;
|
export const ua = navigator.userAgent;
|
||||||
export const isIOS = /iphone|ipad|ipod|ios/i.test(ua);
|
export const isIOS = /iphone|ipad|ipod|ios/i.test(ua);
|
||||||
|
@ -83,3 +84,18 @@ export function copyText(text: string) {
|
||||||
export function cn(...inputs: ClassValue[]) {
|
export function cn(...inputs: ClassValue[]) {
|
||||||
return twMerge(clsx(inputs));
|
return twMerge(clsx(inputs));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getLevelName(level: Level) {
|
||||||
|
switch (level) {
|
||||||
|
case 0:
|
||||||
|
return i18next.t("普通非活跃");
|
||||||
|
case 1:
|
||||||
|
return i18next.t("普通活跃");
|
||||||
|
case 2:
|
||||||
|
return i18next.t("社长");
|
||||||
|
case 3:
|
||||||
|
return i18next.t("基金会社长");
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,20 +1,32 @@
|
||||||
/*
|
/*
|
||||||
* @LastEditors: John
|
* @LastEditors: John
|
||||||
* @Date: 2024-06-19 15:55:07
|
* @Date: 2024-06-19 15:55:07
|
||||||
* @LastEditTime: 2024-06-19 15:56:45
|
* @LastEditTime: 2024-06-20 16:30:22
|
||||||
* @Author: John
|
* @Author: John
|
||||||
*/
|
*/
|
||||||
import { config } from "@/components/WalletProvider";
|
import { config } from "@/components/WalletProvider";
|
||||||
|
import {
|
||||||
|
api_check_account_registration,
|
||||||
|
api_get_wallet_signature_string,
|
||||||
|
api_login,
|
||||||
|
api_signUp,
|
||||||
|
} from "@/server/api";
|
||||||
|
import useUserStore from "@/store/User";
|
||||||
import {
|
import {
|
||||||
writeContract,
|
writeContract,
|
||||||
readContract,
|
readContract,
|
||||||
estimateGas,
|
estimateGas,
|
||||||
waitForTransactionReceipt,
|
waitForTransactionReceipt,
|
||||||
getConnectorClient,
|
getConnectorClient,
|
||||||
|
signMessage,
|
||||||
getChains,
|
getChains,
|
||||||
switchChain,
|
switchChain,
|
||||||
getChainId,
|
getChainId,
|
||||||
|
disconnect,
|
||||||
|
getAccount,
|
||||||
} from "@wagmi/core";
|
} from "@wagmi/core";
|
||||||
|
import Toast from "antd-mobile/es/components/toast";
|
||||||
|
import i18next from "i18next";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description: 检测网络并切换
|
* @description: 检测网络并切换
|
||||||
|
@ -55,3 +67,91 @@ export function checkNetWork(): Promise<void> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 签名并且登录
|
||||||
|
export async function signAndLogin(address?: `0x${string}`): Promise<void> {
|
||||||
|
return new Promise(async (reslove) => {
|
||||||
|
if (!address) return loginOut();
|
||||||
|
if (address != useUserStore.getState().Address) {
|
||||||
|
useUserStore.setState((state) => {
|
||||||
|
return { ...state, Address: address, Token: "" };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (useUserStore.getState().Token) return reslove(); // token存在无需登录
|
||||||
|
const publicKey =
|
||||||
|
"0305ef2a74bff2e2d68764c557ce2daecac92caa7a9406e3a90c2cf7c5b444a154";
|
||||||
|
|
||||||
|
const loadingToast = Toast.show({
|
||||||
|
icon: "loading",
|
||||||
|
content: i18next.t("链接钱包中..."),
|
||||||
|
duration: 0,
|
||||||
|
maskClickable: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { data: isExitData } = await api_check_account_registration().send({
|
||||||
|
queryParams: { account: address },
|
||||||
|
});
|
||||||
|
if (isExitData?.data?.exist) {
|
||||||
|
// 登录
|
||||||
|
|
||||||
|
const { data: signatureData } =
|
||||||
|
await api_get_wallet_signature_string().send({
|
||||||
|
queryParams: { account: address },
|
||||||
|
});
|
||||||
|
|
||||||
|
let sign: string;
|
||||||
|
try {
|
||||||
|
sign = await signMessage(config, {
|
||||||
|
message: signatureData?.data?.encryptedString || "",
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
// 用户拒绝签名或者遇到错误,断开链接
|
||||||
|
disconnect(config);
|
||||||
|
loadingToast.close();
|
||||||
|
loginOut();
|
||||||
|
throw new Error("用户拒绝签名或者遇到错误,断开链接");
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO 登录✔
|
||||||
|
const { data: loginInfoData } = await api_login().send({
|
||||||
|
data: {
|
||||||
|
account: address,
|
||||||
|
password: sign,
|
||||||
|
publicKey,
|
||||||
|
chainType: 2,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (loginInfoData) {
|
||||||
|
useUserStore.setState((state) => {
|
||||||
|
return { ...state, Token: loginInfoData.data?.token };
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO 判断用户是否绑定关系✔
|
||||||
|
// await checkUserBind(false);
|
||||||
|
reslove();
|
||||||
|
loadingToast.close();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 注册
|
||||||
|
await api_signUp().send({
|
||||||
|
data: {
|
||||||
|
account: address,
|
||||||
|
publicKey,
|
||||||
|
shareCode: "",
|
||||||
|
chainType: 2,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
await signAndLogin(address);
|
||||||
|
reslove();
|
||||||
|
loadingToast.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function loginOut() {
|
||||||
|
useUserStore.setState((state) => {
|
||||||
|
return { ...state, Address: "", Token: "" };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
|
@ -1,9 +1,17 @@
|
||||||
|
/*
|
||||||
|
* @LastEditors: John
|
||||||
|
* @Date: 2024-06-17 17:20:03
|
||||||
|
* @LastEditTime: 2024-06-21 13:50:16
|
||||||
|
* @Author: John
|
||||||
|
*/
|
||||||
/// <reference types="vite/client" />
|
/// <reference types="vite/client" />
|
||||||
|
|
||||||
interface ImportMetaEnv {
|
interface ImportMetaEnv {
|
||||||
|
readonly VITE_BASE_URL: string;
|
||||||
readonly VITE_BASE_API_URL: string;
|
readonly VITE_BASE_API_URL: string;
|
||||||
readonly VITE_PARTICIPATE_CHAIN_ID: number;
|
readonly VITE_PARTICIPATE_CHAIN_ID: number;
|
||||||
readonly VITE_NETWORK_USDT_ADDRESS: `0x${string}`;
|
readonly VITE_NETWORK_USDT_ADDRESS: `0x${string}`;
|
||||||
|
readonly VITE_PURCHASED_CONTRACT_ADDRESS: `0x${string}`;
|
||||||
readonly VITE_CHECK_TRANSACTION_DETAILS_URL: string;
|
readonly VITE_CHECK_TRANSACTION_DETAILS_URL: string;
|
||||||
// 更多环境变量...
|
// 更多环境变量...
|
||||||
readonly MODE: "development" | "production" | "test";
|
readonly MODE: "development" | "production" | "test";
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* @LastEditors: John
|
* @LastEditors: John
|
||||||
* @Date: 2024-06-17 17:20:03
|
* @Date: 2024-06-17 17:20:03
|
||||||
* @LastEditTime: 2024-06-19 17:41:43
|
* @LastEditTime: 2024-06-24 10:08:56
|
||||||
* @Author: John
|
* @Author: John
|
||||||
*/
|
*/
|
||||||
import { defineConfig } from "vite";
|
import { defineConfig } from "vite";
|
||||||
|
@ -14,6 +14,13 @@ import { nodePolyfills } from "vite-plugin-node-polyfills";
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
server: {
|
server: {
|
||||||
host: "192.168.10.167",
|
host: "192.168.10.167",
|
||||||
|
proxy: {
|
||||||
|
"/dev": {
|
||||||
|
target: "http://192.168.10.106:8100",
|
||||||
|
changeOrigin: true,
|
||||||
|
rewrite: (path) => path.replace(/^\/dev/, ""),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
react(),
|
react(),
|
||||||
|
|
53
yarn.lock
53
yarn.lock
|
@ -2727,7 +2727,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"ahooks@npm:^3.7.6":
|
"ahooks@npm:^3.7.6, ahooks@npm:^3.8.0":
|
||||||
version: 3.8.0
|
version: 3.8.0
|
||||||
resolution: "ahooks@npm:3.8.0"
|
resolution: "ahooks@npm:3.8.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -6957,6 +6957,7 @@ __metadata:
|
||||||
"@typescript-eslint/parser": "npm:^7.2.0"
|
"@typescript-eslint/parser": "npm:^7.2.0"
|
||||||
"@vitejs/plugin-react": "npm:^4.2.1"
|
"@vitejs/plugin-react": "npm:^4.2.1"
|
||||||
"@web3modal/wagmi": "npm:^5.0.2"
|
"@web3modal/wagmi": "npm:^5.0.2"
|
||||||
|
ahooks: "npm:^3.8.0"
|
||||||
antd-mobile: "npm:^5.36.1"
|
antd-mobile: "npm:^5.36.1"
|
||||||
autoprefixer: "npm:^10.4.19"
|
autoprefixer: "npm:^10.4.19"
|
||||||
clsx: "npm:^2.1.1"
|
clsx: "npm:^2.1.1"
|
||||||
|
@ -6982,6 +6983,7 @@ __metadata:
|
||||||
vite-plugin-compression: "npm:^0.5.1"
|
vite-plugin-compression: "npm:^0.5.1"
|
||||||
vite-plugin-node-polyfills: "npm:^0.22.0"
|
vite-plugin-node-polyfills: "npm:^0.22.0"
|
||||||
wagmi: "npm:^2.10.2"
|
wagmi: "npm:^2.10.2"
|
||||||
|
web3-utils: "npm:^4.3.0"
|
||||||
zustand: "npm:^4.5.2"
|
zustand: "npm:^4.5.2"
|
||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
@ -8226,6 +8228,48 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"web3-errors@npm:^1.2.0":
|
||||||
|
version: 1.2.0
|
||||||
|
resolution: "web3-errors@npm:1.2.0"
|
||||||
|
dependencies:
|
||||||
|
web3-types: "npm:^1.6.0"
|
||||||
|
checksum: 10c0/3028ef33ba50f4441e02ff47f56afec226c6946bbb019dbf6260760b7d5980bb42cf9b1ff497ac3442ed498c386e5ca37a7ad20e71b3482e6b3b90b70f1b5249
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"web3-types@npm:^1.6.0":
|
||||||
|
version: 1.7.0
|
||||||
|
resolution: "web3-types@npm:1.7.0"
|
||||||
|
checksum: 10c0/0da724b67911d76139b704406107bde624c524a04bfe749808a3e137e06078ac1c52c305eedb521b84d67363932d214ba54d7851394a8e7b425e17de5ef813e4
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"web3-utils@npm:^4.3.0":
|
||||||
|
version: 4.3.0
|
||||||
|
resolution: "web3-utils@npm:4.3.0"
|
||||||
|
dependencies:
|
||||||
|
ethereum-cryptography: "npm:^2.0.0"
|
||||||
|
eventemitter3: "npm:^5.0.1"
|
||||||
|
web3-errors: "npm:^1.2.0"
|
||||||
|
web3-types: "npm:^1.6.0"
|
||||||
|
web3-validator: "npm:^2.0.6"
|
||||||
|
checksum: 10c0/884e553cacd8009440dcbd1ba80516fadf054b558aa974228f71e20fb2636afab94c3af0d386e88fb662245114ff5d3b251d45bb9b35f1fad8b20f6e1ef49743
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"web3-validator@npm:^2.0.6":
|
||||||
|
version: 2.0.6
|
||||||
|
resolution: "web3-validator@npm:2.0.6"
|
||||||
|
dependencies:
|
||||||
|
ethereum-cryptography: "npm:^2.0.0"
|
||||||
|
util: "npm:^0.12.5"
|
||||||
|
web3-errors: "npm:^1.2.0"
|
||||||
|
web3-types: "npm:^1.6.0"
|
||||||
|
zod: "npm:^3.21.4"
|
||||||
|
checksum: 10c0/28728773b9abad2531f7a4145784db56ec9ecffeb25cc9f6fe67bedeb01a1833b1a5d1a2e0f431ce4a3c8c6f13b111f35202dd8fa0829c6e2fcd68c58d1d5658
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"webextension-polyfill@npm:>=0.10.0 <1.0":
|
"webextension-polyfill@npm:>=0.10.0 <1.0":
|
||||||
version: 0.12.0
|
version: 0.12.0
|
||||||
resolution: "webextension-polyfill@npm:0.12.0"
|
resolution: "webextension-polyfill@npm:0.12.0"
|
||||||
|
@ -8515,6 +8559,13 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"zod@npm:^3.21.4":
|
||||||
|
version: 3.23.8
|
||||||
|
resolution: "zod@npm:3.23.8"
|
||||||
|
checksum: 10c0/8f14c87d6b1b53c944c25ce7a28616896319d95bc46a9660fe441adc0ed0a81253b02b5abdaeffedbeb23bdd25a0bf1c29d2c12dd919aef6447652dd295e3e69
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"zustand@npm:4.4.1":
|
"zustand@npm:4.4.1":
|
||||||
version: 4.4.1
|
version: 4.4.1
|
||||||
resolution: "zustand@npm:4.4.1"
|
resolution: "zustand@npm:4.4.1"
|
||||||
|
|
Loading…
Reference in New Issue