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 ( <Providers> <div className="p-4"> <MenuDropdown /> - <main className="mt-16 px-8 max-w-md mx-auto text-center">{children}</main> + <main className="mt-16 px-8 max-w-md mx-auto text-center"> + <AppContextProvider>{children}</AppContextProvider> + </main> </div> </Providers> ) 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<IBalanceProps> = ({ unit }) => { +const Balance: FC<IBalanceProps> = ({}) => { 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<IBalanceProps> = ({ 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 ( - <div> - <h1 className="text-6xl">{isLoading ? '...' : balanceSat}</h1> + <div + onClick={() => { + setBalanceUnitIdx((prev) => { + return prev + 1 >= unitList.length ? 0 : prev + 1 + }) + }} + > + <h1 className="text-6xl">{isLoading ? '...' : displayBalance}</h1> <p className="mt-2 text-lg">{unit}</p> </div> ) 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<IAppContext>({ + priceTHB: 0, + priceUSD: 0, +}) + +interface IAppContextProviderProps extends PropsWithChildren {} + +export const AppContextProvider: FC<IAppContextProviderProps> = ({ 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 <AppContext.Provider value={value}>{children}</AppContext.Provider> +} + +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<GetPriceResult> { + 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<string, number> +}