Skip to content

Commit

Permalink
feature(unlock-app): Foundational support for wallet funding feature (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
0xTxbi authored Nov 18, 2024
1 parent 8042839 commit 4b43655
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 1 deletion.
9 changes: 8 additions & 1 deletion unlock-app/src/components/content/SettingsContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ import { ReactNode, useState } from 'react'
import { SettingsContext } from '~/components/interface/locks/Settings'
import { PaymentSettings } from '../interface/user-account/PaymentSettings'
import AccountInfo from '../interface/user-account/AccountInfo'
import { Funding } from '../interface/user-account/Funding'

export const SettingsContent = () => {
const [selectedIndex, setSelectedIndex] = useState(0)

const tabs: {
label: string
description?: string
id: 'account' | 'payments'
id: 'account' | 'payments' | 'funding'
children: ReactNode
}[] = [
{
Expand All @@ -27,6 +28,12 @@ export const SettingsContent = () => {
description: 'Configure your credit card payment settings.',
children: <PaymentSettings />,
},
{
id: 'funding',
label: 'Funding',
description: 'Fund your account with ETH.',
children: <Funding />,
},
]

return (
Expand Down
88 changes: 88 additions & 0 deletions unlock-app/src/components/interface/user-account/Funding.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { LoginModal as FundingModal, useFundWallet } from '@privy-io/react-auth'

import { Badge, Button, Modal, Placeholder } from '@unlock-protocol/ui'
import { useState } from 'react'
import { ToastHelper } from '~/components/helpers/toast.helper'
import { useAuthenticate } from '~/hooks/useAuthenticate'
import { useWeb3Service } from '~/utils/withWeb3Service'
import { useQuery } from '@tanstack/react-query'
import { base } from 'viem/chains'
import { SettingCard } from '../locks/Settings/elements/SettingCard'
import { useEthPrice } from '~/hooks/useEthPrice'

export const Funding = () => {
const { account } = useAuthenticate()
const web3Service = useWeb3Service()
const { fundWallet } = useFundWallet({
onUserExited: () => {
ToastHelper.error('Funding operation cancelled')
},
})
const [showFundingModal, setShowFundingModal] = useState(false)

const { isPending: isLoadingBalance, data: userBalance } = useQuery({
queryKey: ['getBalance', account, 8453],
queryFn: async () => {
return parseFloat(await web3Service.getAddressBalance(account!, 8453))
},
})

const { data: ethPrice } = useEthPrice({
amount: userBalance?.toFixed(4),
network: 8453,
})

const handleFundWallet = async () => {
setShowFundingModal(true)
await fundWallet(account!, {
chain: base,
})
}

return (
<SettingCard
label="Fund Wallet"
description="You can fund your account with ETH. This will enable you to purchase paid memberships or event tickets."
defaultOpen={true}
>
<div className="space-y-5 mt-5">
{isLoadingBalance ? (
<Placeholder.Root>
<Placeholder.Line size="md" />
</Placeholder.Root>
) : (
<div className="flex flex-col gap-2">
<div className="text-gray-700">Your current balance</div>
<div className="flex items-center gap-2">
<Badge
variant={userBalance === 0 ? 'red' : 'default'}
className="text-lg font-bold"
>
{userBalance?.toFixed(4)} ETH
</Badge>
{userBalance && ethPrice && ethPrice > 0 && (
<div className="text-gray-600">
(≈{' '}
<span className="font-semibold">
${new Intl.NumberFormat().format(ethPrice)}
</span>
)
</div>
)}
</div>
</div>
)}

<Button onClick={handleFundWallet}>Fund Account</Button>

<Modal
isOpen={showFundingModal}
setIsOpen={setShowFundingModal}
size="small"
>
<FundingModal open={showFundingModal} />
</Modal>
</div>
</SettingCard>
)
}
24 changes: 24 additions & 0 deletions unlock-app/src/hooks/useEthPrice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { useQuery } from '@tanstack/react-query'
import { locksmith } from '~/config/locksmith'

export const useEthPrice = ({
amount,
network,
}: {
amount: string | undefined
network: number
}) => {
return useQuery({
queryKey: ['getEthPrice', amount, network],
queryFn: async () => {
if (!amount) return null
try {
const response = await locksmith.price(network, parseFloat(amount))
return response.data.result?.priceInAmount
} catch (error) {
return null
}
},
enabled: !!amount,
})
}

0 comments on commit 4b43655

Please sign in to comment.