Created
November 7, 2023 19:02
-
-
Save RichardSlater/3a2a71153f5dfde8f5ba12b2b0836655 to your computer and use it in GitHub Desktop.
Using WharfKit in React /w Typescript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use client" | |
import styles from './page.module.css' | |
import { useCallback, useEffect } from 'react'; | |
import React from 'react' | |
import WalletButton from './components/WalletButton'; | |
import { SessionKit, Session } from "@wharfkit/session" | |
import { WebRenderer } from "@wharfkit/web-renderer" | |
import { WalletPluginAnchor } from "@wharfkit/wallet-plugin-anchor" | |
import { WalletPluginCloudWallet } from "@wharfkit/wallet-plugin-cloudwallet"; | |
import LockedAssetList from './components/LockedAssetList'; | |
import ErrorDialog from './components/ErrorDialog'; | |
export default function Home() { | |
const [sessionKit, setSessionKit] = React.useState<SessionKit | null>(null); | |
const [session, setSession] = React.useState<Session | undefined | null>(null); | |
const [assetData, setAssetData] = React.useState<Asset[] | undefined | null>(null); | |
const [lastError, setLastError] = React.useState<string | undefined | null>(null); | |
const endpoint = "https://api3.hivebp.io"; | |
const atomicEndpoint = "https://wax.api.atomicassets.io"; | |
const getLockedAsets = useCallback((address: string) => { | |
const payload = { | |
"code": "nfthivecraft", | |
"index_position": 1, | |
"json": "true", | |
"key_type": "i64", | |
"limit": 1000, | |
"lower_bound": "", | |
"upper_bound": "", | |
"reverse": "true", | |
"scope": address, | |
"show_payer": "false", | |
"table": "timedlocks", | |
"table_key": "" | |
} | |
fetch(`${endpoint}/v1/chain/get_table_rows`, { | |
method: 'POST', | |
headers: { | |
"Content-Type": "application/json", | |
}, | |
body: JSON.stringify(payload) | |
}) | |
.then(chainResponse => chainResponse.json()) | |
.catch((reason) => setLastError(`Unable to fetch the list of locked assets in the NFT Hive smart contract. Reason: ${reason}`)) | |
.then(chainData => { | |
const assetIds = chainData.rows.map((asset: any) => asset.asset_id).join(',') | |
fetch(`${atomicEndpoint}/atomicassets/v1/assets?asset_id=${assetIds}&page=1&limit=1000&order=desc&sort=asset_id`) | |
.then(assetResponse => assetResponse.json()) | |
.catch(reason => setLastError(`Unable to fetch the list of assets from the Atomic API. Reason: ${reason}.`)) | |
.then(assets => { | |
var lockedAssets = assets.data.map((a: any) => { return { assetName: a.name, id: a.asset_id, unlockTime: getDateFromChainData(chainData, a.asset_id) } }); | |
lockedAssets.sort((a: Asset, b: Asset) => a.unlockTime.getTime() - b.unlockTime.getTime()); | |
setAssetData(lockedAssets); | |
}) | |
.catch(reason => setLastError(`Unable to parse the list of assets from the Atomic API. Reason: ${reason}.`)); | |
}) | |
.catch(reason => setLastError(`Unable to parse the list of locked assets from the NFT Hive API. Reason: ${reason}.`)); | |
}, []); | |
const restoreSession = useCallback(async (sk: any) => { | |
if (sk == null) { | |
throw new Error("sk is null or undefined, blockchain interactions are unavailable.") | |
} | |
var existingSession = await sk.restore(); | |
if (existingSession != null) { | |
setSession(existingSession); | |
getLockedAsets(existingSession.actor.toString()); | |
} | |
}, [setSession, getLockedAsets]); | |
useEffect(() => { | |
const ui = new WebRenderer(); | |
const sk = new SessionKit({ | |
appName: "demo", | |
chains: [ | |
{ | |
id: "1064487b3cd1a897ce03ae5b6a865651747e2e152090f99c1d19d44e01aea5a4", | |
url: "https://api3.hivebp.io", | |
}, | |
], | |
ui: ui, | |
walletPlugins: [ | |
new WalletPluginAnchor(), | |
new WalletPluginCloudWallet(), | |
], | |
}); | |
setSessionKit(sk); | |
restoreSession(sk); | |
ui.appendDialogElement(); | |
}, [restoreSession]); | |
function getDateFromChainData(chainData: any, assetId: string) { | |
var asset = chainData.rows.find((cd: any) => cd.asset_id == assetId); | |
return new Date(asset.unlock_time * 1000); | |
} | |
async function handleLoginLogout() { | |
if (sessionKit == null) { | |
throw new Error("sessionKit is null or undefined, blockchain interactions are unavailable.") | |
} | |
if (session !== null) { | |
await sessionKit.logout(session) | |
setSession(null); | |
setAssetData(null); | |
return; | |
} | |
try { | |
const response = await sessionKit.login(); | |
setSession(response.session); | |
getLockedAsets(response.session.actor.toString()); | |
} catch { | |
// swallow the exception as WharfKit handles it in the UI. | |
} | |
} | |
async function handleClaim() { | |
if (session == null) { | |
return | |
} | |
const data = assetData?.filter((a) => a.unlockTime < new Date()) | |
.map((a) => createAction(session.actor.toString(), session.permission.toString(), a)); | |
try { | |
await session.transact({ actions: data }); | |
} catch { | |
// swallow the exception as the user can just click claim again after resolving issues. | |
} | |
getLockedAsets(session.actor.toString()) | |
} | |
function createAction(actor: string, permission: string, asset: Asset) { | |
return { | |
account: 'nfthivecraft', | |
name: 'unlock', | |
authorization: [ | |
{ | |
"actor": actor, | |
"permission": permission | |
} | |
], | |
data: | |
{ | |
"asset_id": asset.id, | |
"crafter": actor | |
} | |
} | |
} | |
function handleCloseModal() { | |
setLastError(null); | |
} | |
return ( | |
<main className={styles.main}> | |
<WalletButton username={session?.actor.toString()} click={handleLoginLogout} connected={session === null || session === undefined} /> | |
<LockedAssetList click={handleClaim} assets={assetData} /> | |
<ErrorDialog click={handleCloseModal} message={lastError ?? ""} showModal={lastError != null} /> | |
</main> | |
) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment