From aff0f68989352f6a8bacc534d53d89246047200f Mon Sep 17 00:00:00 2001 From: john Date: Tue, 2 Jul 2024 18:41:27 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9E=20fix:?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.development | 3 +- .env.test | 3 +- iconfont.json | 2 +- src/App.tsx | 6 +- src/components/iconfont/IconTransfer.tsx | 33 ++ src/components/iconfont/index.tsx | 6 +- src/contract/abi/receive.json | 173 ++++++ src/contract/utils.ts | 90 +++- src/i18n/translation/cn.json | 4 +- src/i18n/translation/de.json | 3 +- src/i18n/translation/en.json | 3 +- src/i18n/translation/jp.json | 3 +- src/i18n/translation/tw.json | 3 +- src/main.tsx | 6 +- src/pages/AssetRecord.tsx | 17 +- src/pages/Home.module.css | 40 +- src/pages/Home.tsx | 655 ++++++++++++----------- src/server/api.ts | 4 +- src/server/client.ts | 13 +- src/server/module.d.ts | 2 +- src/style/ant-cover-m.css | 18 + src/utils/index.ts | 11 + src/utils/wallet.ts | 14 +- src/vite-env.d.ts | 3 +- 24 files changed, 768 insertions(+), 347 deletions(-) create mode 100644 src/components/iconfont/IconTransfer.tsx create mode 100644 src/contract/abi/receive.json diff --git a/.env.development b/.env.development index fd551ad..32f711c 100644 --- a/.env.development +++ b/.env.development @@ -1,12 +1,13 @@ ### # @LastEditors: John # @Date: 2024-06-18 10:12:21 - # @LastEditTime: 2024-06-27 15:35:23 + # @LastEditTime: 2024-07-02 16:46:51 # @Author: John ### VITE_BASE_URL= VITE_BASE_API_URL=/dev VITE_PARTICIPATE_CHAIN_ID=97 VITE_PURCHASED_CONTRACT_ADDRESS=0x7aAe4f2CA23482B58D6f9e8d1fBb5e413e7013c8 +VITE_RECEIVE_RAMB_CONTRACT_ADDRESS=0x8291A98382d751CdD52460A547eE94ceE8258930 VITE_NETWORK_USDT_ADDRESS=0xf9A18B7FC8Eb118f8Ad59fBD6eb1A181eaCb4E63 VITE_CHECK_TRANSACTION_DETAILS_URL=https://testnet.bscscan.com/ \ No newline at end of file diff --git a/.env.test b/.env.test index 1c1e5f6..24da1f6 100644 --- a/.env.test +++ b/.env.test @@ -1,12 +1,13 @@ ### # @LastEditors: John # @Date: 2024-06-24 18:38:45 - # @LastEditTime: 2024-06-25 14:04:37 + # @LastEditTime: 2024-07-02 16:49:31 # @Author: John ### VITE_BASE_URL=http://wwwtest.exgo.pro VITE_BASE_API_URL=http://wwwtest.exgo.pro VITE_PARTICIPATE_CHAIN_ID=97 VITE_PURCHASED_CONTRACT_ADDRESS=0x7aAe4f2CA23482B58D6f9e8d1fBb5e413e7013c8 +VITE_RECEIVE_RAMB_CONTRACT_ADDRESS=0x8291A98382d751CdD52460A547eE94ceE8258930 VITE_NETWORK_USDT_ADDRESS=0xf9A18B7FC8Eb118f8Ad59fBD6eb1A181eaCb4E63 VITE_CHECK_TRANSACTION_DETAILS_URL=https://testnet.bscscan.com/ \ No newline at end of file diff --git a/iconfont.json b/iconfont.json index 879baf1..126126f 100644 --- a/iconfont.json +++ b/iconfont.json @@ -1,5 +1,5 @@ { - "symbol_url": "//at.alicdn.com/t/c/font_4589567_vzk80gocu8s.js", + "symbol_url": "//at.alicdn.com/t/c/font_4589567_u5yhe33hzt.js", "use_typescript": true, "save_dir": "./src/components/iconfont", "trim_icon_prefix": "icon", diff --git a/src/App.tsx b/src/App.tsx index 74efe28..31eb8f4 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -19,7 +19,7 @@ import InvitationList from "./pages/InvitationList"; import { useEffect } from "react"; import { useTranslation } from "react-i18next"; import useUserStore from "./store/User"; -import { getUrlQueryParam } from "./utils"; +import { getUrlParameterByName } from "./utils"; import { UrlQueryParamsKey } from "./constants"; import { signAndLogin } from "./utils/wallet"; import { useAccount } from "wagmi"; @@ -29,7 +29,9 @@ function App() { const { address } = useAccount(); useEffect(() => { i18n.changeLanguage(currantLang); - UpdateInviteCode(getUrlQueryParam(UrlQueryParamsKey.INVITE_CODE) || ""); + UpdateInviteCode( + getUrlParameterByName(UrlQueryParamsKey.INVITE_CODE) || "" + ); return () => {}; }, []); diff --git a/src/components/iconfont/IconTransfer.tsx b/src/components/iconfont/IconTransfer.tsx new file mode 100644 index 0000000..264f4c0 --- /dev/null +++ b/src/components/iconfont/IconTransfer.tsx @@ -0,0 +1,33 @@ +/* tslint:disable */ +/* eslint-disable */ + +import React, { CSSProperties, SVGAttributes, FunctionComponent } from 'react'; +import { getIconColor } from './helper'; + +interface Props extends Omit, 'color'> { + size?: number; + color?: string | string[]; +} + +const DEFAULT_STYLE: CSSProperties = { + display: 'block', +}; + +const IconTransfer: FunctionComponent = ({ size = 18, color, style: _style, ...rest }) => { + const style = _style ? { ...DEFAULT_STYLE, ..._style } : DEFAULT_STYLE; + + return ( + + + + + ); +}; + +export default IconTransfer; diff --git a/src/components/iconfont/index.tsx b/src/components/iconfont/index.tsx index 26ab637..7c11035 100644 --- a/src/components/iconfont/index.tsx +++ b/src/components/iconfont/index.tsx @@ -2,6 +2,7 @@ /* eslint-disable */ import React, { SVGAttributes, FunctionComponent } from 'react'; +import IconTransfer from './IconTransfer'; import IconDiqiu from './IconDiqiu'; import IconTuichu from './IconTuichu'; import IconChevronsrightshuangyoujiantou from './IconChevronsrightshuangyoujiantou'; @@ -11,6 +12,7 @@ import IconTongdun from './IconTongdun'; import IconJindun from './IconJindun'; import IconXingdun from './IconXingdun'; import IconGuanjun from './IconGuanjun'; +export { default as IconTransfer } from './IconTransfer'; export { default as IconDiqiu } from './IconDiqiu'; export { default as IconTuichu } from './IconTuichu'; export { default as IconChevronsrightshuangyoujiantou } from './IconChevronsrightshuangyoujiantou'; @@ -21,7 +23,7 @@ export { default as IconJindun } from './IconJindun'; export { default as IconXingdun } from './IconXingdun'; export { default as IconGuanjun } from './IconGuanjun'; -export type IconNames = 'diqiu' | 'tuichu' | 'chevronsrightshuangyoujiantou' | 'fuzhi' | 'icon_arrow_left' | 'tongdun' | 'jindun' | 'xingdun' | 'guanjun'; +export type IconNames = 'transfer' | 'diqiu' | 'tuichu' | 'chevronsrightshuangyoujiantou' | 'fuzhi' | 'icon_arrow_left' | 'tongdun' | 'jindun' | 'xingdun' | 'guanjun'; interface Props extends Omit, 'color'> { name: IconNames; @@ -31,6 +33,8 @@ interface Props extends Omit, 'color'> { const IconFont: FunctionComponent = ({ name, ...rest }) => { switch (name) { + case 'transfer': + return ; case 'diqiu': return ; case 'tuichu': diff --git a/src/contract/abi/receive.json b/src/contract/abi/receive.json new file mode 100644 index 0000000..9393446 --- /dev/null +++ b/src/contract/abi/receive.json @@ -0,0 +1,173 @@ +[ + { + "inputs": [ + { + "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": "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": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "paymentTime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "orderId", + "type": "uint256" + }, + { + "internalType": "bytes32", + "name": "hashStr", + "type": "bytes32" + } + ], + "name": "reward", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "buyAddr", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "orderId", + "type": "uint256" + } + ], + "name": "RewardSuccess", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "addr", + "type": "address" + } + ], + "name": "setUSDCAddress", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "usdc", + "outputs": [ + { + "internalType": "contract IERC20", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + } +] diff --git a/src/contract/utils.ts b/src/contract/utils.ts index 8037857..7924ed5 100644 --- a/src/contract/utils.ts +++ b/src/contract/utils.ts @@ -1,7 +1,7 @@ /* * @LastEditors: John * @Date: 2024-06-19 15:48:57 - * @LastEditTime: 2024-06-27 18:00:07 + * @LastEditTime: 2024-07-02 17:40:49 * @Author: John */ import { config } from "@/components/WalletProvider"; @@ -16,8 +16,10 @@ import { encodeFunctionData } from "viem/utils"; import erc20Abi from "@/contract/abi/erc20abi.json"; import usdtAbi from "@/contract/abi/USDT.json"; import RedDevilsAbi from "@/contract/abi/RedDevils.json"; +import receiveAbi from "@/contract/abi/receive.json"; import i18next from "i18next"; import { BaseError } from "wagmi"; +import { UserIncome } from "@/server/module"; /** * @description 获取代币余额 @@ -270,19 +272,76 @@ export async function upGradeByContract(amount: bigint, orderID: string) { } /** - * receiveByContract + * receiveRMABByContract * @param amount + * @param paymentTime * @param orderID + * @param hashStr * @returns */ -export async function receiveByContract( +export async function receiveRMABByContract( + amount: bigint, + paymentTime: number, + orderID: string, + hashStr: string +) { + console.log("pay buy contract params", { amount, orderID }); + + return new Promise(async (reslove, reject) => { + try { + console.log("参数:", amount, paymentTime, orderID, hashStr); + estimateGas(config, { + to: import.meta.env.VITE_RECEIVE_RAMB_CONTRACT_ADDRESS, + data: encodeFunctionData({ + abi: receiveAbi, + functionName: "reward", + args: [amount, paymentTime, orderID, hashStr], + }), + }) + .then((gas) => { + const gasPrice = (gas * 12n) / 10n; + console.log("estimate gas:%d , my gas: %d", gas, gasPrice); + writeContract(config, { + abi: receiveAbi, + address: import.meta.env.VITE_PURCHASED_CONTRACT_ADDRESS, + functionName: "reward", + args: [amount, paymentTime, orderID, hashStr], + gas: gasPrice, + }) + .then((receipt) => { + console.log("write contract success!, receipt:", receipt); + reslove(receipt); + }) + .catch((err: BaseError) => { + console.log("reward rmab Transaction err", err); + reject(err); + }); + }) + .catch((err: BaseError) => { + console.log("reward rmab estimateGas err", err); + reject(err); + }); + } catch (err) { + reject(new BaseError(`${err}`)); + } + }); +} + +/** + * receiveUSDTByContract + * @param amount + * @param paymentTime + * @param orderID + * @param hashStr + * @returns + */ +export async function receiveUSDTByContract( amount: bigint, paymentTime: number, orderID: string, hashStr: string ) { console.log("pay buy contract params", { amount, orderID }); - console.log("NETWORK_USDT:", import.meta.env.VITE_NETWORK_USDT_ADDRESS); return new Promise(async (reslove, reject) => { try { @@ -323,3 +382,26 @@ export async function receiveByContract( } }); } + +/** + * receiveByContract + * @param type + * @param amount + * @param paymentTime + * @param orderID + * @param hashStr + * @returns + */ +export async function receiveByContract( + type: UserIncome["coinId"], + amount: bigint, + paymentTime: number, + orderID: string, + hashStr: string +) { + if (type == 1) { + return receiveUSDTByContract(amount, paymentTime, orderID, hashStr); + } else if (type == 2) { + return receiveRMABByContract(amount, paymentTime, orderID, hashStr); + } +} diff --git a/src/i18n/translation/cn.json b/src/i18n/translation/cn.json index 70f9c78..bf05743 100644 --- a/src/i18n/translation/cn.json +++ b/src/i18n/translation/cn.json @@ -104,5 +104,7 @@ "没有更多数据了": "没有更多数据了", "升级中": "升级中", "无等级": "无等级", - "无效的邀请链接": "无效的邀请链接" + "无效的邀请链接": "无效的邀请链接", + + "交易红魔股权NFT": "交易红魔股权NFT" } diff --git a/src/i18n/translation/de.json b/src/i18n/translation/de.json index f017ac5..187ea3a 100644 --- a/src/i18n/translation/de.json +++ b/src/i18n/translation/de.json @@ -104,5 +104,6 @@ "没有更多数据了": "Keine weiteren Daten", "升级中": "Wird aktualisiert", "无等级": "Keine Bewertung", - "无效的邀请链接": "Ungültiger Einladungslink" + "无效的邀请链接": "Ungültiger Einladungslink", + "交易红魔股权NFT": "Handel mit Red Devil Equity NFT" } diff --git a/src/i18n/translation/en.json b/src/i18n/translation/en.json index c2d82da..ef90064 100644 --- a/src/i18n/translation/en.json +++ b/src/i18n/translation/en.json @@ -104,5 +104,6 @@ "没有更多数据了": "No more data", "升级中": "Upgrading", "无等级": "No Grade", - "无效的邀请链接": "Invalid invitation link" + "无效的邀请链接": "Invalid invitation link", + "交易红魔股权NFT": "Trade Red Devil Equity NFT" } diff --git a/src/i18n/translation/jp.json b/src/i18n/translation/jp.json index 820e40e..4dab8e6 100644 --- a/src/i18n/translation/jp.json +++ b/src/i18n/translation/jp.json @@ -104,5 +104,6 @@ "没有更多数据了": "これ以上のデータはありません", "升级中": "アップグレード中", "无等级": "グレードなし", - "无效的邀请链接": "無効な招待リンクです" + "无效的邀请链接": "無効な招待リンクです", + "交易红魔股权NFT": "レッドデビル株式NFTを取引する" } diff --git a/src/i18n/translation/tw.json b/src/i18n/translation/tw.json index da5503c..6a4c21c 100644 --- a/src/i18n/translation/tw.json +++ b/src/i18n/translation/tw.json @@ -104,5 +104,6 @@ "没有更多数据了": "沒有更多數據了", "升级中": "升級中", "无等级": "無等級", - "无效的邀请链接": "無效的邀請連結" + "无效的邀请链接": "無效的邀請連結", + "交易红魔股权NFT": "交易紅魔股權NFT" } diff --git a/src/main.tsx b/src/main.tsx index c085e6b..f582992 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,7 +1,7 @@ /* * @LastEditors: John * @Date: 2024-06-17 17:20:03 - * @LastEditTime: 2024-06-20 11:43:14 + * @LastEditTime: 2024-07-02 11:38:25 * @Author: John */ import "@/i18n/init.ts"; @@ -15,9 +15,9 @@ import EventBusProvider from "./context/EventBusContext.tsx"; import { WalletProvider } from "./components/WalletProvider.tsx"; import flexible from "./utils/flexible.ts"; import VConsole from "vconsole"; -import { getUrlQueryParam } from "./utils/index.ts"; +import { getUrlParameterByName } from "./utils/index.ts"; -if (getUrlQueryParam("vconsole") === "1") { +if (getUrlParameterByName("vconsole") === "1") { new VConsole(); } flexible(window, document); diff --git a/src/pages/AssetRecord.tsx b/src/pages/AssetRecord.tsx index 86ae499..f211bef 100644 --- a/src/pages/AssetRecord.tsx +++ b/src/pages/AssetRecord.tsx @@ -1,12 +1,12 @@ /* * @LastEditors: John * @Date: 2024-06-18 17:57:13 - * @LastEditTime: 2024-06-25 16:17:20 + * @LastEditTime: 2024-07-02 17:43:52 * @Author: John */ import Tabs from "antd-mobile/es/components/tabs"; import classes from "./AssetRecord.module.css"; -import { cn, getUrlQueryParam } from "@/utils"; +import { cn, getUrlParameterByName } from "@/utils"; import CapsuleTabs from "antd-mobile/es/components/capsule-tabs"; import RecordsItem from "@/components/RecordsItem"; import { useTranslation } from "react-i18next"; @@ -14,12 +14,11 @@ 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 () { const { t } = useTranslation(); - const coinId = useMemo(() => getUrlQueryParam("id"), []); - const coinName = useMemo(() => getUrlQueryParam("name"), []); + const id = useMemo(() => getUrlParameterByName("id"), []); + const coinId = useMemo(() => getUrlParameterByName("coinId"), []); const currentType = useRef<1 | 2>(2); const [issueRecords, setIssueRecords] = useState([]); const [receiveRecord, setReceiveRecord] = useState( @@ -35,7 +34,7 @@ export default function () { async function getRecord() { return new Promise(async (reslove) => { - if (!coinId) return; + if (!id) return; if (!hasMore.current) return; @@ -43,7 +42,7 @@ export default function () { pageNum.current++; const { data } = await api_pagling_query_income_record().send({ queryParams: { - id: coinId, + id, type: currentType.current, pageNum: pageNum.current, pageSize, @@ -91,7 +90,7 @@ export default function () { }} > - {coinName == CoinName.USDT && ( + {coinId == "1" && ( { switch (key) { @@ -117,7 +116,7 @@ export default function () { )} - {coinName == CoinName.RMOB && ( + {coinId == "2" && ( { switch (key) { diff --git a/src/pages/Home.module.css b/src/pages/Home.module.css index 1d9dc48..1b91eb6 100644 --- a/src/pages/Home.module.css +++ b/src/pages/Home.module.css @@ -204,7 +204,7 @@ flex-direction: row; align-items: center; li { - width: 76px; + min-width: 76px; height: 34px; opacity: 1; @@ -220,6 +220,7 @@ color: #4d4d4d; text-align: center; line-height: 34px; + padding: 0 10px; &.nftToken_tab_active { border-radius: 10px; opacity: 1; @@ -585,6 +586,43 @@ } } + .equityNft { + display: flex; + flex-direction: row; + align-items: center; + gap: 16px; + padding: 10px 15px; + + border-radius: 14px; + opacity: 1; + background: #171719; + margin-top: 26px; + + > svg { + width: 26px; + height: 26px; + + &:nth-of-type(2) { + margin-left: auto; + } + } + span { + opacity: 1; + + font-family: DM Sans; + font-size: 14px; + font-weight: 500; + line-height: normal; + letter-spacing: 0em; + + font-variation-settings: "opsz" auto; + font-feature-settings: "kern" on; + color: #ffffff; + + z-index: 1; + } + } + .invite { margin-top: 25px; .invite_top { diff --git a/src/pages/Home.tsx b/src/pages/Home.tsx index ffe531e..a52e4cc 100644 --- a/src/pages/Home.tsx +++ b/src/pages/Home.tsx @@ -10,17 +10,16 @@ import usdtBg from "@/assets/usdt_bg.svg"; import RMOB_logo from "@/assets/RMOB_logo.svg"; import IconFont from "@/components/iconfont"; import { BaseError, useAccount } from "wagmi"; -import { config } from "@/components/WalletProvider"; -import { createSearchParams, useNavigate } from "react-router-dom"; -import { Button, Dialog, Empty, Toast } from "antd-mobile"; +import { useNavigate } from "react-router-dom"; +import { Button, Dialog, Empty, PullToRefresh, Toast } from "antd-mobile"; import { loginOut } from "@/utils/wallet"; import { api_claim_income, api_get_homepage_user_data } from "@/server/api"; -import { UserHomeData } from "@/server/module"; +import { UserHomeData, UserIncome } 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"; -import { disconnect, getAccount } from "@wagmi/core"; +import { PullStatus } from "antd-mobile/es/components/pull-to-refresh"; export default function () { const { Token, UpdateToken } = useUserStore(); const { open } = useWeb3Modal(); @@ -30,7 +29,12 @@ export default function () { const [tabIndex, setTabIndex] = useState(0); const navigate = useNavigate(); const [userData, setUserData] = useState(); - + const statusRecord: Record = { + pulling: "Pull down to refresh", + canRelease: "Release to refresh immediately", + refreshing: "Loading...", + complete: "Refresh complete", + }; const userInviteLink = useMemo( () => `${location.origin}/#/?${UrlQueryParamsKey.INVITE_CODE}=${ @@ -76,334 +80,369 @@ export default function () { return ( <> -
-
-
- + { + await getHomeData(); + }} + renderText={(status) => { + return
{statusRecord[status]}
; + }} + disabled={!Token} + > +
+
+
+ - {address ? ( -
-
- {shortenString(address, 6, 4)} - { - loginOut(); + {address ? ( +
+
+ {shortenString(address, 6, 4)} + { + loginOut(); + }} + name="tuichu" + className={classes.userinfo_top_right_wallet_disconnect} + color={"#fff"} + /> +
+
+ {userData && ( + <> +
+ {userData.level == 0 && ( + <> + + {t("无等级")} + + )} + {userData.level == 1 && ( + <> + + {userData.active === 0 && ( + {t("普通非活跃")} + )} + {userData.active === 1 && ( + {t("普通活跃")} + )} + + )} + {userData.level == 2 && ( + <> + + {t("社长")} + + )} + {userData.level == 3 && ( + <> + + {t("基金会社长")} + + )} +
+ +
{ + navigate("/levelup"); + }} + > + {t("升级")} + +
+ + )} +
+
+ ) : ( + <> +
{ + open(); }} - name="tuichu" - className={classes.userinfo_top_right_wallet_disconnect} - color={"#fff"} - /> -
-
- {userData && ( - <> -
- {userData.level == 0 && ( - <> - - {t("无等级")} - - )} - {userData.level == 1 && ( - <> - - {userData.active === 0 && ( - {t("普通非活跃")} - )} - {userData.active === 1 && ( - {t("普通活跃")} - )} - - )} - {userData.level == 2 && ( - <> - - {t("社长")} - - )} - {userData.level == 3 && ( - <> - - {t("基金会社长")} - - )} -
- -
{ - navigate("/levelup"); - }} - > - {t("升级")} - -
- - )} -
-
- ) : ( - <> -
{ - open(); - }} - > - {t("链接钱包")} -
- - )} + > + {t("链接钱包")} +
+ + )} +
+
    +
  • + + {userData?.mintNumber || 0} + + + {t("邀请铸造")} + +
  • +
  • + + {userData?.presidentNumber || 0} + + + {t("团队社长")} + +
  • +
  • + + {userData?.airdropNumber || 0} + + + {t("邀请空投")} + +
  • +
-
    -
  • - - {userData?.mintNumber || 0} - - {t("邀请铸造")} -
  • -
  • - - {userData?.presidentNumber || 0} - - {t("团队社长")} -
  • -
  • - - {userData?.airdropNumber || 0} - - {t("邀请空投")} -
  • -
-
-
-
    -
  • setTabIndex(0)} - > - NFT -
  • -
  • setTabIndex(1)} - > - {t("收益")} -
  • -
+
+
    +
  • setTabIndex(0)} + > + NFT +
  • +
  • setTabIndex(1)} + > + {t("收益")} +
  • +
-
- {tabIndex == 0 && ( - <> - {address ? ( - <> - {userData?.nftId ? ( -
-
- # {userData?.nftId} - + {tabIndex == 0 && ( + <> + {address ? ( + <> + {userData?.nftId ? ( +
+
+ # {userData?.nftId} + { + navigate("/mint"); + }} + > + {t("铸造 NFT")} + + +
+ + + {t("Min结束后按照规则进行空投。")} + +
+ ) : ( +
+
{ navigate("/mint"); }} > - {t("铸造 NFT")} + {t("铸造 NFT")} - +
+ {t("铸造 NFT 获得代币空投")}
- - - {t("Min结束后按照规则进行空投。")} - + )} + + ) : ( + <> +
+ {t("钱包未链接,无法向您显示 NFT")}
- ) : ( -
-
+ )} + + )} + {tabIndex == 1 && ( +
+
+ {t("总收益= 已领取 + 待领取")} +
+ +
    + {userData?.userIncomes.map((v, i) => ( + { + navigate( + `/assetrecord?id=${v.id}&coinId=${v.coinId}` + ); + }} + onReceive={async () => { + receiveLoadingToast.current = Toast.show({ + icon: "loading", + duration: 0, + 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( + v.coinId, + buyAmount, + orderInfo.time, + orderInfo?.orderNumber, + orderInfo.hash + ) + .then((hash) => { + if (!hash) return; + 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) && } +
+
+ )} +
+
+ +
window.open("https://element.market/account")} + > + + {t("交易红魔股权NFT")} + +
+ +
+
+ {t("邀请")} + {address && ( + { + navigate("/invitationlist"); + }} + > + {t("邀请列表")}{" "} + + + )} +
+ +
+ {t("邀请链接")} +
+ {address ? ( + <> + {userData?.nftId ? ( + <> + {shortenString(userInviteLink, 15, 15)} + { - navigate("/mint"); + copyText(userInviteLink); }} - > - {t("铸造 NFT")} - -
- {t("铸造 NFT 获得代币空投")} -
+ className={classes.invite_content_icon} + name="fuzhi" + color={"#fff"} + />{" "} + + ) : ( + <> + {t("MINT Nft 获取邀请链接")} + )} ) : ( <> -
- {t("钱包未链接,无法向您显示 NFT")} -
+ {t("链接钱包获取邀请链接")} )} - - )} - {tabIndex == 1 && ( -
-
- {t("总收益= 已领取 + 待领取")} -
- -
    - {userData?.userIncomes.map((v, i) => ( - { - navigate(`/assetrecord?id=${v.id}&name=${v.coinName}`); - }} - onReceive={async () => { - receiveLoadingToast.current = Toast.show({ - icon: "loading", - duration: 0, - 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.time, - orderInfo?.orderNumber, - orderInfo.hash - ) - .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) && } -
- )} -
-
-
-
- {t("邀请")} - {address && ( - { - navigate("/invitationlist"); - }} - > - {t("邀请列表")}{" "} - + + {t( + "普通会员每邀请铸造一个NFT可获得一份空投福利;推荐铸造20个NFT的可升级为会长;团队中拥有20位会长可升级为基金会社长;邀请越多级别越高福利越多。" + )} - )} -
- -
- {t("邀请链接")} -
- {address ? ( - <> - {userData?.nftId ? ( - <> - {shortenString(userInviteLink, 15, 15)} - { - copyText(userInviteLink); - }} - className={classes.invite_content_icon} - name="fuzhi" - color={"#fff"} - />{" "} - - ) : ( - <> - {t("MINT Nft 获取邀请链接")} - - )} - - ) : ( - <> - {t("链接钱包获取邀请链接")} - - )}
+
- - {t( - "普通会员每邀请铸造一个NFT可获得一份空投福利;推荐铸造20个NFT的可升级为会长;团队中拥有20位会长可升级为基金会社长;邀请越多级别越高福利越多。" - )} - +
+ {t("数据披露")} +
    +
  • + {t("资金池")} + {userData?.pools || 0} +
  • +
  • + {t("社长席位")} + {userData?.president || 0} +
  • +
  • + {t("基金会社长席位")} + {userData?.foundation || 0} +
  • +
- -
- {t("数据披露")} -
    -
  • - {t("资金池")} - {userData?.pools || 0} -
  • -
  • - {t("社长席位")} - {userData?.president || 0} -
  • -
  • - {t("基金会社长席位")} - {userData?.foundation || 0} -
  • -
-
-
+ ); } @@ -414,18 +453,20 @@ function ReceiveCom({ toReceive, onAssetRec, onReceive, + coinId, }: { tokenName: string; tokenNum: number; toReceive: number; onAssetRec: () => void; onReceive: () => void; + coinId: UserIncome["coinId"]; }) { const { t } = useTranslation(); return (
  • - {tokenName.toUpperCase() == "USDT" && } - {tokenName.toUpperCase() == "RMOB" && } + {coinId == 1 && } + {coinId == 2 && }
    {tokenName} diff --git a/src/server/api.ts b/src/server/api.ts index 76cdfaa..4e13fc3 100644 --- a/src/server/api.ts +++ b/src/server/api.ts @@ -1,7 +1,7 @@ /* * @LastEditors: John * @Date: 2024-06-18 10:28:21 - * @LastEditTime: 2024-06-25 14:47:34 + * @LastEditTime: 2024-07-02 11:36:40 * @Author: John */ import { GET, POST } from "./client"; @@ -52,7 +52,7 @@ export function api_signUp() { chainType: 2; }, any - >({ url: "/api/account/signUp", requiresToken: false }); + >({ url: "/api/account/signUp", requiresToken: false, catchErr: true }); } // 获取钱包签名串 diff --git a/src/server/client.ts b/src/server/client.ts index 739dcee..abafa14 100644 --- a/src/server/client.ts +++ b/src/server/client.ts @@ -1,7 +1,7 @@ /* * @LastEditors: John * @Date: 2024-06-18 10:09:21 - * @LastEditTime: 2024-06-21 14:47:26 + * @LastEditTime: 2024-07-02 11:36:28 * @Author: John */ import { Client } from "@hyper-fetch/core"; @@ -17,9 +17,11 @@ import i18next from "i18next"; function initClient({ requiresToken, requiresAddress, + catchErr, }: { requiresToken: boolean; requiresAddress: boolean; + catchErr: boolean; }) { return new Client({ url: import.meta.env.VITE_BASE_API_URL }) .onAuth(async (req) => { @@ -59,6 +61,7 @@ function initClient({ const resData: BASE_RESPONSE = res.data; if (resData.code !== 200 && resData.code !== 0) { if (resData.msg) Toast.show({ content: resData.msg, icon: "fail" }); + if (catchErr) return res; throw new Error(resData.msg || "client on response error"); } return res; @@ -69,12 +72,14 @@ export const POST =

    ({ url, requiresToken = true, requiresAddress = true, + catchErr = false, }: { url: string; requiresToken?: boolean; requiresAddress?: boolean; + catchErr?: boolean; }) => { - return initClient({ requiresToken, requiresAddress }).createRequest< + return initClient({ requiresToken, requiresAddress, catchErr }).createRequest< BASE_RESPONSE, P, any, @@ -89,12 +94,14 @@ export const GET =

    ({ url, requiresToken = true, requiresAddress = true, + catchErr = false, }: { url: string; requiresToken?: boolean; requiresAddress?: boolean; + catchErr?: boolean; }) => { - return initClient({ requiresToken, requiresAddress }).createRequest< + return initClient({ requiresToken, requiresAddress, catchErr }).createRequest< BASE_RESPONSE, any, any, diff --git a/src/server/module.d.ts b/src/server/module.d.ts index c8184f5..94f6d48 100644 --- a/src/server/module.d.ts +++ b/src/server/module.d.ts @@ -22,7 +22,7 @@ export interface UserHomeData { active: 0 | 1; // "0=非活跃 1=活跃用户" } export interface UserIncome { - coinId: number; + coinId: 1 | 2; // 1 USDT 2 ROMB coinName: string; collection: number; createTime: string; diff --git a/src/style/ant-cover-m.css b/src/style/ant-cover-m.css index 0eeda16..e4a0513 100644 --- a/src/style/ant-cover-m.css +++ b/src/style/ant-cover-m.css @@ -294,3 +294,21 @@ } } } + +/* adm-pull-to-refresh */ +.adm-pull-to-refresh { + .adm-pull-to-refresh-head-content { + /* 自动布局子元素 */ + font-family: Space Grotesk; + font-size: 14px; + font-weight: 500; + line-height: normal; + letter-spacing: 0em; + + font-variation-settings: "opsz" auto; + font-feature-settings: "kern" on; + color: #9e9e9e; + + z-index: 0; + } +} diff --git a/src/utils/index.ts b/src/utils/index.ts index 484180f..cd3cd9b 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -102,3 +102,14 @@ export function getLevelName(level: Level, active?: UserHomeData["active"]) { break; } } + +export function getUrlParameterByName(name: string, url?: string) { + if (!url) url = window.location.href; + name = name.replace(/[\[\]]/g, "\\$&"); + let regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"), + results = regex.exec(url); + if (!results) return null; + if (!results[2]) return ""; + console.log("url params:", results); + return decodeURIComponent(results[2].replace(/\+/g, " ")); +} diff --git a/src/utils/wallet.ts b/src/utils/wallet.ts index 80a8279..495da3c 100644 --- a/src/utils/wallet.ts +++ b/src/utils/wallet.ts @@ -1,7 +1,7 @@ /* * @LastEditors: John * @Date: 2024-06-19 15:55:07 - * @LastEditTime: 2024-06-26 15:18:22 + * @LastEditTime: 2024-07-02 11:38:59 * @Author: John */ import { config } from "@/components/WalletProvider"; @@ -24,7 +24,7 @@ import { } from "@wagmi/core"; import Toast from "antd-mobile/es/components/toast"; import i18next from "i18next"; -import { getUrlQueryParam } from "."; +import { getUrlParameterByName } from "."; import { UrlQueryParamsKey } from "@/constants"; /** @@ -129,13 +129,13 @@ export async function signAndLogin(address?: `0x${string}`): Promise { loadingToast.close(); } } else { - const inviteCode = getUrlQueryParam(UrlQueryParamsKey.INVITE_CODE); + const inviteCode = getUrlParameterByName(UrlQueryParamsKey.INVITE_CODE); if (!inviteCode) { Toast.show({ icon: "fail", content: i18next.t("无效的邀请链接") }); return loginOut(); } // 注册 - await api_signUp().send({ + const { data } = await api_signUp().send({ data: { account: address, publicKey, @@ -143,7 +143,11 @@ export async function signAndLogin(address?: `0x${string}`): Promise { chainType: 2, }, }); - await signAndLogin(address); + if (data?.code === 0) { + await signAndLogin(address); + } else { + return loginOut(); + } reslove(); loadingToast.close(); } diff --git a/src/vite-env.d.ts b/src/vite-env.d.ts index 592dd9f..55b582f 100644 --- a/src/vite-env.d.ts +++ b/src/vite-env.d.ts @@ -1,7 +1,7 @@ /* * @LastEditors: John * @Date: 2024-06-17 17:20:03 - * @LastEditTime: 2024-06-21 13:50:16 + * @LastEditTime: 2024-07-02 16:53:48 * @Author: John */ /// @@ -12,6 +12,7 @@ interface ImportMetaEnv { readonly VITE_PARTICIPATE_CHAIN_ID: number; readonly VITE_NETWORK_USDT_ADDRESS: `0x${string}`; readonly VITE_PURCHASED_CONTRACT_ADDRESS: `0x${string}`; + readonly VITE_RECEIVE_RAMB_CONTRACT_ADDRESS: `0x${string}`; readonly VITE_CHECK_TRANSACTION_DETAILS_URL: string; // 更多环境变量... readonly MODE: "development" | "production" | "test";