Skip to content

Instantly share code, notes, and snippets.

@RichardSlater
Created November 7, 2023 19:02
Show Gist options
  • Save RichardSlater/3a2a71153f5dfde8f5ba12b2b0836655 to your computer and use it in GitHub Desktop.
Save RichardSlater/3a2a71153f5dfde8f5ba12b2b0836655 to your computer and use it in GitHub Desktop.
Using WharfKit in React /w Typescript
"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