diff --git a/app/billing/Home.tsx b/app/billing/Home.tsx new file mode 100644 index 0000000..85a3395 --- /dev/null +++ b/app/billing/Home.tsx @@ -0,0 +1,148 @@ +import NavMenu from "@/components/NavMenu"; +import Button from "@/components/ui/Button"; +import { selectOperatorSlice, setIsBillingModalOpen, setIsPayModalOpen } from "@/store/operatorSlice"; +import { useAppDispatch, useAppSelector } from "@/store/store"; + +const planDetails = [ + { + title: "Current plan", + value: "Starter" + }, + { + title: "API calls", + value: "10K" + }, + { + title: "Transactions", + value: "1000" + }, + { + title: "Webhook calls", + value: "10K" + } +] + +const paymentDetails = [ + { + title: "Next invoice issue date", + value: "-" + }, + { + title: "Prepaid months remaining", + value: "-" + } +] + +const invoices = [ + { + date: "Aug 24, 2024", + months: 1, + total: "$100", + status: "Paid" + }, + { + date: "Sep 24, 2024", + months: 3, + total: "$300", + status: "Paid" + } +]; + +const Home = () => { + const dispatch = useAppDispatch(); + const operatorSlice = useAppSelector(selectOperatorSlice); + + return ( +
+
+ + +
+
+

+ Billing & Plan +

+
+
+ {planDetails.map((detail, index) => ( +
+

+ {detail.title} +

+

+ {detail.value} +

+
+ ))} +
+
+ +
+

+ Payment +

+
+
+
+ +
+

+ Invoices +

+ + + + + + + + + + + {invoices.map((invoice, index) => ( + + + + + + + ))} + +
DateMonths +

Invoice Total

+

Total

+
Status
{invoice.date}{invoice.months}{invoice.total} +

{invoice.status}

+

+ View Invoice +

+
+
+
+
+ ); +}; + +export default Home; diff --git a/app/billing/layout.tsx b/app/billing/layout.tsx new file mode 100644 index 0000000..29b1393 --- /dev/null +++ b/app/billing/layout.tsx @@ -0,0 +1,14 @@ +import type { Metadata } from 'next' + +export const metadata: Metadata = { + title: 'Billing & Plan - Fuse Console', + description: 'Upgrade your billing & plan and view your invoices', +} + +export default function BillingLayout({ + children, +}: { + children: React.ReactNode +}) { + return
{children}
+} diff --git a/app/billing/page.tsx b/app/billing/page.tsx new file mode 100644 index 0000000..f4db62e --- /dev/null +++ b/app/billing/page.tsx @@ -0,0 +1,46 @@ +"use client"; + +import { useEffect } from "react"; +import { useRouter } from "next/navigation"; +import Home from "./Home"; + +import { useAppDispatch, useAppSelector } from "@/store/store"; +import { setSelectedNavbar } from "@/store/navbarSlice"; +import Footer from "@/components/Footer"; +import Topbar from "@/components/Topbar"; +import ChainModal from "@/components/ChainModal"; +import PayModal from "@/components/billing/PayModal"; +import BillingModal from "@/components/billing/BillingModal"; +import { selectOperatorSlice } from "@/store/operatorSlice"; +import { path } from "@/lib/helpers"; + +const Billing = () => { + const dispatch = useAppDispatch(); + const operatorSlice = useAppSelector(selectOperatorSlice); + const router = useRouter(); + + useEffect(() => { + dispatch(setSelectedNavbar("billing")); + }, [dispatch]) + + useEffect(() => { + if(!operatorSlice.isAuthenticated && operatorSlice.isHydrated) { + router.push(path.DASHBOARD); + } + }, [dispatch, operatorSlice.isAuthenticated, operatorSlice.isHydrated, router]) + + return ( +
+
+ + + + + +
+
+ ); +}; + +export default Billing; diff --git a/app/build/Home.tsx b/app/build/Home.tsx index e084d73..3036937 100644 --- a/app/build/Home.tsx +++ b/app/build/Home.tsx @@ -10,8 +10,9 @@ import theGraph from "@/public/the-graph.png" import taskOn from "@/public/taskon.png" import { useRouter } from "next/navigation"; import NavMenu from "@/components/NavMenu"; -import { buildSubMenuItems } from "@/lib/helpers"; import * as amplitude from "@amplitude/analytics-browser"; +import { useAppSelector } from "@/store/store"; +import { selectOperatorSlice } from "@/store/operatorSlice"; const apps = [ { @@ -54,6 +55,7 @@ const apps = [ const Home = () => { const router = useRouter(); + const operatorSlice = useAppSelector(selectOperatorSlice); function createAccount(eventInput: string) { amplitude.track(eventInput); @@ -64,7 +66,7 @@ const Home = () => {
- +
diff --git a/app/dashboard/Home.tsx b/app/dashboard/Home.tsx index 692e9ec..9398b3f 100644 --- a/app/dashboard/Home.tsx +++ b/app/dashboard/Home.tsx @@ -1,11 +1,11 @@ import { useEffect, useMemo, useState } from "react"; import Button from "@/components/ui/Button"; -import { buildSubMenuItems, evmDecimals, signDataMessage } from "@/lib/helpers"; +import { evmDecimals, signDataMessage } from "@/lib/helpers"; import { useAppDispatch, useAppSelector } from "@/store/store"; import { BalanceStateType, fetchUsdPrice, selectBalanceSlice } from "@/store/balanceSlice"; import { useAccount, useBalance, useBlockNumber, useSignMessage } from "wagmi"; import { fuse } from "wagmi/chains"; -import { checkIsActivated, fetchSponsorIdBalance, fetchSponsoredTransactions, generateSecretApiKey, selectOperatorSlice, setIsContactDetailsModalOpen, setIsRollSecretKeyModalOpen, setIsTopupAccountModalOpen, setIsWithdrawModalOpen, validateOperator, withRefreshToken } from "@/store/operatorSlice"; +import { OperatorStateType, checkIsActivated, fetchSponsorIdBalance, fetchSponsoredTransactions, fetchTokenBalances, generateSecretApiKey, selectOperatorSlice, setIsContactDetailsModalOpen, setIsRollSecretKeyModalOpen, setIsTopupAccountModalOpen, setIsWithdrawModalOpen, validateOperator, withRefreshToken } from "@/store/operatorSlice"; import TopupAccountModal from "@/components/dashboard/TopupAccountModal"; import Image from "next/image"; import copy from "@/assets/copy-black.svg"; @@ -31,7 +31,7 @@ import hide from "@/assets/hide.svg"; import { formatUnits } from "viem"; import { SignMessageVariables } from "wagmi/query"; import contactSupport from "@/assets/contact-support.svg"; - +import { useRouter } from "next/navigation"; type CreateOperatorWalletProps = { isValidated: boolean; signMessage: (variables: SignMessageVariables) => void; @@ -48,7 +48,7 @@ type OperatorAccountBalanceProps = { chain: any; balanceSlice: BalanceStateType; balance: any; - isActivated: boolean; + operatorSlice: OperatorStateType; dispatch: ThunkDispatch & Dispatch; } @@ -125,12 +125,12 @@ const ConnectEoaWallet = () => { ) } -const OperatorAccountBalance = ({ chain, balanceSlice, balance, isActivated, dispatch }: OperatorAccountBalanceProps) => { +const OperatorAccountBalance = ({ chain, balanceSlice, balance, operatorSlice, dispatch }: OperatorAccountBalanceProps) => { useEffect(() => { const fiveSecondInMillisecond = 5000; const intervalId = setInterval(() => { - if (isActivated) { + if (operatorSlice.isActivated) { dispatch(withRefreshToken(() => dispatch(fetchSponsoredTransactions()))); } else { dispatch(withRefreshToken(() => dispatch(checkIsActivated()))); @@ -140,7 +140,13 @@ const OperatorAccountBalance = ({ chain, balanceSlice, balance, isActivated, dis return () => { clearInterval(intervalId); } - }, [dispatch, isActivated]) + }, [dispatch, operatorSlice.isActivated]) + + useEffect(() => { + if (operatorSlice.operator.user.smartWalletAddress) { + dispatch(fetchTokenBalances({ address: operatorSlice.operator.user.smartWalletAddress })); + } + }, [dispatch, operatorSlice.operator.user.smartWalletAddress]) return (
@@ -160,24 +166,15 @@ const OperatorAccountBalance = ({ chain, balanceSlice, balance, isActivated, dis
-

- {(chain && chain.id === fuse.id) ? - new Intl.NumberFormat().format( - parseFloat(formatUnits(balance?.value ?? BigInt(0), balance?.decimals ?? evmDecimals) ?? "0") - ) : - 0 - } FUSE -

- {balanceSlice.isUsdPriceLoading ? - : -

+ {operatorSlice.isFetchingTokenBalances || balanceSlice.isUsdPriceLoading ? + : +

${(chain && chain.id === fuse.id) ? new Intl.NumberFormat().format( - parseFloat((parseFloat(formatUnits(balance?.value ?? BigInt(0), balance?.decimals ?? evmDecimals) ?? "0.00") * balanceSlice.price).toString()) + (parseFloat(balance?.formatted ?? "0") * balanceSlice.price) + operatorSlice.totalTokenBalance ) : - "0.00" - } -

+ "0.00"} +

}
@@ -209,6 +206,7 @@ const Home = () => { const operatorSlice = useAppSelector(selectOperatorSlice); const [showSecretKey, setShowSecretKey] = useState(false); const controller = useMemo(() => new AbortController(), []); + const router = useRouter(); const { isConnected, address, chain } = useAccount(); const signer = useEthersSigner(); const { data: blockNumber } = useBlockNumber({ watch: true }); @@ -292,7 +290,7 @@ const Home = () => { {operatorSlice.isAccountCreationModalOpen && } {operatorSlice.isCongratulationModalOpen && }
- +

Operator Dashboard @@ -342,7 +340,14 @@ const Home = () => {

}
-
+
+ {operatorSlice.isAuthenticated && ( +