From f0e2fcacdfbaef4c30892ce34f25833688a6757d Mon Sep 17 00:00:00 2001 From: Kittisak Phormraksa Date: Tue, 30 Apr 2024 10:19:39 +0700 Subject: [PATCH] [web] Display balance in `THB` and `USD` --- web/src/app/(auth)/layout.tsx | 7 +++-- web/src/components/Balance.tsx | 42 +++++++++++++++++++++++++----- web/src/contexts/AppContext.tsx | 46 +++++++++++++++++++++++++++++++++ web/src/services/price.ts | 9 +++++++ web/src/types/price.ts | 3 +++ 5 files changed, 98 insertions(+), 9 deletions(-) create mode 100644 web/src/contexts/AppContext.tsx create mode 100644 web/src/services/price.ts create mode 100644 web/src/types/price.ts diff --git a/web/src/app/(auth)/layout.tsx b/web/src/app/(auth)/layout.tsx index e6d3b1f..ed72ecf 100644 --- a/web/src/app/(auth)/layout.tsx +++ b/web/src/app/(auth)/layout.tsx @@ -1,12 +1,15 @@ -import Providers from './providers' import MenuDropdown from '@/components/MenuDropdown' +import { AppContextProvider } from '@/contexts/AppContext' +import Providers from './providers' const Layout = ({ children }: Readonly<{ children: React.ReactNode }>) => { return (
-
{children}
+
+ {children} +
) diff --git a/web/src/components/Balance.tsx b/web/src/components/Balance.tsx index 31da8b0..563ad93 100644 --- a/web/src/components/Balance.tsx +++ b/web/src/components/Balance.tsx @@ -1,19 +1,24 @@ 'use client' -import { FC, useEffect, useState } from 'react' +import { FC, useEffect, useMemo, useState } from 'react' import { BalanceUnit } from '@/enums' import useIsMounted from '@/hooks/useIsMounted' import { LnFService } from '@/services/lnf' +import { useAppContext } from '@/contexts/AppContext' -interface IBalanceProps { - unit: BalanceUnit -} +interface IBalanceProps {} + +const unitList = [BalanceUnit.SATS, BalanceUnit.THB, BalanceUnit.USD] + +const HundredMillion = 100000000 -const Balance: FC = ({ unit }) => { +const Balance: FC = ({}) => { const isMounted = useIsMounted() + const { priceTHB, priceUSD } = useAppContext() const [isLoading, setIsLoading] = useState(true) const [balanceSat, setBalanceSat] = useState(0) + const [balanceUnitIdx, setBalanceUnitIdx] = useState(0) const fetchBalance = async () => { try { @@ -34,9 +39,32 @@ const Balance: FC = ({ unit }) => { return () => {} }, [isMounted]) + const unit = useMemo(() => unitList[balanceUnitIdx], [balanceUnitIdx]) + + const displayBalance = useMemo(() => { + switch (unit) { + case BalanceUnit.SATS: + return balanceSat + case BalanceUnit.THB: + const blTHB = (balanceSat * priceTHB) / HundredMillion + return balanceSat > 0 && blTHB <= 0 ? '...' : blTHB.toFixed(2) + case BalanceUnit.USD: + const blUSD = (balanceSat * priceUSD) / HundredMillion + return balanceSat > 0 && blUSD <= 0 ? '...' : blUSD.toFixed(2) + default: + return balanceSat + } + }, [balanceSat, unit]) + return ( -
-

{isLoading ? '...' : balanceSat}

+
{ + setBalanceUnitIdx((prev) => { + return prev + 1 >= unitList.length ? 0 : prev + 1 + }) + }} + > +

{isLoading ? '...' : displayBalance}

{unit}

) diff --git a/web/src/contexts/AppContext.tsx b/web/src/contexts/AppContext.tsx new file mode 100644 index 0000000..1fd329d --- /dev/null +++ b/web/src/contexts/AppContext.tsx @@ -0,0 +1,46 @@ +'use client' + +import { FC, PropsWithChildren, createContext, useContext, useEffect, useMemo, useState } from 'react' + +import { PriceService } from '@/services/price' +import useIsMounted from '@/hooks/useIsMounted' + +interface IAppContext { + priceTHB: number + priceUSD: number +} + +export const AppContext = createContext({ + priceTHB: 0, + priceUSD: 0, +}) + +interface IAppContextProviderProps extends PropsWithChildren {} + +export const AppContextProvider: FC = ({ children }) => { + const isMounted = useIsMounted() + const [priceTHB, setPriceTHB] = useState(0) + const [priceUSD, setPriceUSD] = useState(0) + + const fetchPrice = async () => { + try { + const res = await PriceService.getPrice() + setPriceTHB(res?.bitcoin['thb'] ?? 0) + setPriceUSD(res?.bitcoin['usd'] ?? 0) + } catch (e) { + console.error('error:', e) + } + } + + useEffect(() => { + if (!isMounted) return + + fetchPrice() + }, [isMounted]) + + const value: IAppContext = useMemo(() => ({ priceTHB, priceUSD }), [priceTHB, priceUSD]) + + return {children} +} + +export const useAppContext = () => useContext(AppContext) diff --git a/web/src/services/price.ts b/web/src/services/price.ts new file mode 100644 index 0000000..e4af441 --- /dev/null +++ b/web/src/services/price.ts @@ -0,0 +1,9 @@ +import { AxiosRequestConfig } from 'axios' + +import BaseService from './base' + +export class PriceService extends BaseService { + static getPrice(config: AxiosRequestConfig = {}): Promise { + return this._post('/price.get', {}, config) + } +} diff --git a/web/src/types/price.ts b/web/src/types/price.ts new file mode 100644 index 0000000..8356e58 --- /dev/null +++ b/web/src/types/price.ts @@ -0,0 +1,3 @@ +interface GetPriceResult { + bitcoin: Record +}