🎯 7. Check in the user
Finally, everything is ready and you can do a check-in for the user.
Add button for checking in​
-
Go to the
check-in.tsx
file. -
Add states to manage the send transaction flow:
-
txHash
: transaction hash received after successfully sending a transaction to Ronin. -
isWaitTx
: loading indicator when user sends their check-in transaction. -
error
: for unexpected cases.
const [txHash, setTxHash] = useState<string>()
const [isWaitTx, setIsWaitTx] = useState<boolean>(false)
const [error, setError] = useState<string>() -
-
Add a button for users to check in. This button should be turned off when
loading
andisWaitTx
. When the user clicks the button, it should call thehandleCheckIn
function.return (
<div>
{/* ALREADY DONE CODE */}
{walletClient && (
<button
className="bg-sky-600 hover:bg-sky-700 text-white font-bold py-3 px-4 rounded-xl mt-2 disabled:opacity-50 tracking-wider"
disabled={isCheckedIn || loading || isWaitTx}
onClick={handleCheckIn}
>
{isWaitTx ? "Wait for transaction" : "Check In"}
</button>
)}
</div>
)
Send transaction to check in​
-
Go to the
check-in.tsx
file. -
Change the loading status to
true
when the user clicks the button:const handleCheckIn = async () => {
setTxHash(undefined)
setIsWaitTx(true)
} -
Before sending a transaction, you need to simulate it:
-
Are all parameters correct?
-
Does user have enough RON to execute the transaction?
-
Because
eth_estimateGas
only reads state from the blockchain, you should usePublic Client
to do it. You can learn more abouteth_estimateGas
in MetaMask documentation. -
Call the
checkIn
function of the smart contract to do the check-in. The only argument isaccount
. -
Wrap this block in
try catch
to handle errors.
const handleCheckIn = async () => {
setTxHash(undefined)
setIsWaitTx(true)
try {
const { txRequest } = await web3PublicClient.simulateContract({
account,
address: CHECK_IN_ADDRESS,
abi: CHECK_IN_ABI,
functionName: "checkIn",
args: [account],
})
} catch (error) {
console.log(error)
setError("Could NOT send transaction - check your console for future details.")
setTxHash(undefined)
setIsWaitTx(false)
}
} -
-
Send a transaction and get the transaction hash:
- When sending a transaction, because you need the user to sign it in their wallet, you should use
Wallet Client
to do this action. - Use
writeContract
function on the wallet client. - All you need is
txRequest
that you received from thesimulateContract
step. - Remember to use
setTxHash
to display it to the user.
const txHash = await walletClient.writeContract(request)
setTxHash(txHash) - When sending a transaction, because you need the user to sign it in their wallet, you should use
-
Display the transaction hash or error to the user:
return (
<div>
{/* ALREADY DONE CODE */}
<div className="flex flex-col gap-2 mt-8">
<button
className="bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-4 rounded-xl mt-2 disabled:opacity-50"
disabled={isCheckedIn || loading || isWaitTx}
onClick={handleCheckIn}
>
{isWaitTx ? "Wait for transaction" : "Check In"}
</button>
{txHash && (
<>
<p className="font-semibold text-green-600">Send successfully!</p>
<a
className="text-blue-700 hover:text-blue-800"
href={`https://saigon-app.roninchain.com/tx/${txHash}`}
>
Check your transaction here
</a>
</>
)}
{error && <p className="text-red-600">{error}</p>}
</div>
</div>
)
Refresh check-in status​
At the step Send transaction to check in, you successfully sent the transaction but the user still receives the "Please do check in" status. This happens due to the following reasons:
- The user only sends the transaction, but the blockchain hasn't yet processed it.
- The Ronin chain often takes 3-4 seconds to process a transaction.
To handle this case in your app, wait for the transaction to process, and then refresh the check-in status.
-
Go to
check-in.tsx
file. -
After sending the transaction, use the
waitForTransactionReceipt
function fromPublic Client
to get the receipt.const receipt = await web3PublicClient.waitForTransactionReceipt({
hash: txHash,
}) -
If the transaction has a
success
status, refetch the check-in information and finish the check-in flow.if (receipt.status === "success") {
refetchCheckedIn()
setError(undefined)
setIsWaitTx(false)
return
}
throw "Transaction reverted!"