Skip to content

Commit

Permalink
Merge pull request #373 from peanutprotocol/feat/cashout-status
Browse files Browse the repository at this point in the history
Feat/cashout status
  • Loading branch information
borcherd authored Sep 6, 2024
2 parents 10dc198 + 9b1ac95 commit 2536227
Show file tree
Hide file tree
Showing 14 changed files with 360 additions and 9 deletions.
29 changes: 29 additions & 0 deletions src/app/api/peanut/get-cashout-status/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import type { NextRequest } from 'next/server'
import { NextResponse } from 'next/server'
import * as consts from '@/constants'

export async function POST(request: NextRequest) {
try {
const { pubKey } = await request.json()
const apiKey = process.env.PEANUT_API_KEY!

const response = await fetch(`${consts.PEANUT_API_URL}/cashouts/${pubKey}/status`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'api-key': apiKey,
},
})

if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}

const data = await response.json()

return NextResponse.json(data)
} catch (error) {
console.error('Failed to get cashout status:', error)
return new NextResponse('Internal Server Error', { status: 500 })
}
}
46 changes: 46 additions & 0 deletions src/app/api/peanut/submit-cashout-link/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import type { NextRequest } from 'next/server'
import { NextResponse } from 'next/server'
import * as consts from '@/constants'
import { generateKeysFromString } from '@squirrel-labs/peanut-sdk'
import { url } from 'inspector'

export async function POST(request: NextRequest) {
try {
const {
pubKey,
bridgeCustomerId,
liquidationAddressId,
cashoutTransactionHash,
externalAccountId,
chainId,
tokenName,
} = await request.json()

const response = await fetch(`${consts.PEANUT_API_URL}/cashouts`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
bridgeCustomerId: bridgeCustomerId,
liquidationAddressId: liquidationAddressId,
cashoutTransactionHash: cashoutTransactionHash,
externalAccountId: externalAccountId,
chainId: chainId,
tokenName: tokenName,
pubKey: pubKey,
}),
})

if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}

const data = await response.json()

return NextResponse.json(data)
} catch (error) {
console.error('Failed to submit cashout link:', error)
return new NextResponse('Internal Server Error', { status: 500 })
}
}
4 changes: 3 additions & 1 deletion src/app/cashout/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import Layout from '@/components/Global/Layout'

export const dynamic = 'force-dynamic'

export default function ClaimPage() {
// TODO: add metadata

export default function CashoutPage() {
return (
<Layout>
<components.Cashout />
Expand Down
14 changes: 14 additions & 0 deletions src/app/cashout/status/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import * as components from '@/components'
import Layout from '@/components/Global/Layout'

export const dynamic = 'force-dynamic'

// TODO: add metadata

export default function CashoutStatusPage() {
return (
<Layout>
<components.CashoutStatus />
</Layout>
)
}
60 changes: 60 additions & 0 deletions src/components/Cashout/CashoutStatus.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
'use client'
import { useEffect, useState } from 'react'
import * as assets from '@/assets'
import { generateKeysFromString } from '@squirrel-labs/peanut-sdk'
import * as utils from '@/utils'
import Link from 'next/link'
import Icon from '../Global/Icon'

export const CashoutStatus = () => {
const [cashoutStatus, setCashoutStatus] = useState<'FOUND' | 'NOT FOUND' | undefined>(undefined)
const [cashoutStatusData, setCashoutStatusData] = useState<utils.CashoutTransaction | undefined>(undefined)

const getAndSetCashoutStatus = async () => {
try {
const response = await utils.getCashoutStatus(window.location.href)
setCashoutStatusData(response)
setCashoutStatus('FOUND')
} catch (error) {
console.error(error)
setCashoutStatus('NOT FOUND')
}
}

useEffect(() => {
getAndSetCashoutStatus()
}, [])

return (
<div className="card">
{!cashoutStatus ? (
<div className="relative flex w-full items-center justify-center">
<div className="animate-spin">
<img src={assets.PEANUTMAN_LOGO.src} alt="logo" className="h-6 sm:h-10" />
<span className="sr-only">Loading...</span>
</div>
</div>
) : cashoutStatus === 'FOUND' ? (
<div className="mx-auto flex max-w-[96%] flex-col items-center justify-center gap-4 pb-20 text-center">
<label className="text-h2">Cashout status</label>
<div className="flex flex-col justify-center gap-3">
<label className="text-start text-h8 font-light">
{cashoutStatusData && utils.CashoutStatusDescriptions[cashoutStatusData?.status]}{' '}
</label>
</div>
<Link
className="absolute bottom-0 flex h-20 w-[27rem] w-full flex-row items-center justify-start gap-2 border-t-[1px] border-black bg-purple-3 px-4.5 dark:text-black"
href={`/profile`}
>
<div className=" border border-n-1 p-0 px-1">
<Icon name="dashboard" className="-mt-0.5" />
</div>
Go to profile
</Link>
</div>
) : (
cashoutStatus === 'NOT FOUND' && 'Cashout Not Found'
)}
</div>
)
}
19 changes: 14 additions & 5 deletions src/components/Cashout/Components/Confirm.view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ export const ConfirmCashoutView = ({
const chainId = utils.getChainIdFromBridgeChainName(chainName) ?? ''
const tokenAddress = utils.getTokenAddressFromBridgeTokenName(chainId ?? '10', tokenName) ?? ''
let hash

if (xchainNeeded) {
hash = await claimLinkXchain({
address: liquidationAddress.address,
Expand Down Expand Up @@ -188,22 +189,30 @@ export const ConfirmCashoutView = ({
peanutExternalAccountId: peanutAccount.account_id,
},
})

await utils.submitCashoutLink({
link: claimLinkData.link,
bridgeCustomerId: bridgeCustomerId,
liquidationAddressId: liquidationAddress.id,
cashoutTransactionHash: hash,
externalAccountId: bridgeExternalAccountId,
chainId: chainId,
tokenName: tokenName,
})

setTransactionHash(hash)
console.log('Transaction hash:', hash)
setLoadingState('Idle')
onNext()
}
onNext()
setLoadingState('Idle')
} catch (error) {
setErrorState({
showError: true,
errorMessage: 'Please enter a valid amount',
})
return
} finally {
setLoadingState('Idle')
}

onNext()
}

const { setStep: setActiveStep, activeStep } = useSteps({
Expand Down
1 change: 1 addition & 0 deletions src/components/Cashout/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './Cashout'
export * from './CashoutStatus'
22 changes: 20 additions & 2 deletions src/components/Dashboard/useDashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,27 @@ export const useDashboard = () => {
}
})
)
} catch (error) {
console.error('Error fetching link details:', error)
}

const _data3 = visibleData.filter((item) => item.type == 'Offramp Claim')

try {
await Promise.all(
_data3.map(async (item) => {
try {
const offrampStatus = await utils.getCashoutStatus(item.link ?? '')
item.status = offrampStatus.status
} catch (error) {
item.status = 'claimed'
console.error(error)
}
})
)
} catch (error) {}

const _data = [..._data1, ..._data2]
const _data = [..._data1, ..._data2, ..._data3]

return _data
}
Expand Down Expand Up @@ -82,7 +100,7 @@ export const useDashboard = () => {
chain: consts.supportedPeanutChains.find((chain) => chain.chainId === link.chainId)?.name ?? '',
date: link.depositDate.toString(),
address: link.senderAddress,
status: 'claimed',
status: undefined,
message: link.message,
attachmentUrl: link.attachmentUrl,
points: link.points,
Expand Down
17 changes: 17 additions & 0 deletions src/components/Profile/Components/MobileTableComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ export const MobileTableComponent = ({
<div className="border border-teal-3 px-2 py-1 text-center text-teal-3">sent</div>
) : dashboardItem.status === 'paid' ? (
<div className="border border-teal-3 px-2 py-1 text-center text-teal-3">paid</div>
) : dashboardItem.status ? (
<div className="border border-gray-1 px-2 py-1 text-center text-gray-1">
{dashboardItem.status.toLowerCase().replaceAll('_', ' ')}
</div>
) : (
<div className="border border-gray-1 px-2 py-1 text-center text-gray-1">
pending
Expand Down Expand Up @@ -141,6 +145,19 @@ export const MobileTableComponent = ({
Download attachment
</a>
)}
{dashboardItem?.type === 'Offramp Claim' && dashboardItem.status !== 'claimed' && (
<a
href={(() => {
const url = new URL(dashboardItem?.link ?? '')
url.pathname = '/cashout/status'
return url.toString()
})()}
target="_blank"
className="flex h-12 w-full items-center gap-2 px-4 text-h8 text-sm font-bold transition-colors last:mb-0 hover:bg-n-3/10 disabled:cursor-not-allowed disabled:bg-n-4 disabled:hover:bg-n-4/90 dark:hover:bg-white/20"
>
Check Status
</a>
)}
</>
) : (
type === 'contacts' && (
Expand Down
14 changes: 14 additions & 0 deletions src/components/Profile/Components/TableComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,10 @@ export const TableComponent = ({
<div className="border border-teal-3 px-2 py-1 text-center text-teal-3">
paid
</div>
) : data.dashboardItem.status ? (
<div className="border border-gray-1 px-2 py-1 text-center text-gray-1">
{data.dashboardItem.status.toLowerCase().replaceAll('_', ' ')}
</div>
) : (
<div className="border border-gray-1 px-2 py-1 text-center text-gray-1">
pending
Expand Down Expand Up @@ -182,6 +186,16 @@ export const TableComponent = ({
window.open(data.dashboardItem?.link ?? '', '_blank')
},
},
data.dashboardItem?.type === 'Offramp Claim' &&
data.dashboardItem.status !== 'claimed' && {
name: 'Check status',
action: () => {
const url = new URL(data.dashboardItem?.link ?? '')
url.pathname = '/cashout/status'

window.open(url.toString(), '_blank')
},
},
].filter(Boolean) as { name: string; action: () => void }[]
}
/>
Expand Down
2 changes: 2 additions & 0 deletions src/components/Profile/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import IframeWrapper from '../Global/IframeWrapper'
import Link from 'next/link'
import * as context from '@/context'
import Loading from '../Global/Loading'
import peanut, { generateKeysFromString } from '@squirrel-labs/peanut-sdk'
const tabs = [
{
title: 'History',
Expand Down Expand Up @@ -300,6 +301,7 @@ export const Profile = () => {
// UseEffect hook to fetch the link details for the visible data
useEffect(() => {
async function _fetchLinkDetailsAsync(visibleData: interfaces.IDashboardItem[]) {
console.log('visibleData', visibleData)
const data = await fetchLinkDetailsAsync(visibleData)
setDashboardData((prevData) =>
prevData.map((item) => {
Expand Down
Empty file.
21 changes: 20 additions & 1 deletion src/interfaces/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,26 @@ export interface IDashboardItem {
date: string
chain: string
address: string | undefined
status: 'claimed' | 'pending' | 'transfer' | 'paid' | undefined
status:
| 'claimed'
| 'pending'
| 'transfer'
| 'paid'
| 'REFUNDED'
| 'READY'
| 'AWAITING_TX'
| 'FUNDS_IN_BRIDGE'
| 'FUNDS_MOVED_AWAY'
| 'FUNDS_IN_BANK'
| 'AWAITING_FUNDS'
| 'IN_REVIEW'
| 'FUNDS_RECEIVED'
| 'PAYMENT_SUBMITTED'
| 'PAYMENT_PROCESSED'
| 'CANCELED'
| 'ERROR'
| 'RETURNED'
| undefined
message: string | undefined
attachmentUrl: string | undefined
points: number
Expand Down
Loading

0 comments on commit 2536227

Please sign in to comment.