import React, { useState } from "react"; import { useWallet } from "@vechain/dapp-kit-react"; import { ABIContract, Address, Clause, VET } from "@vechain/sdk-core"; import { ThorClient } from "@vechain/sdk-network"; import { Drawer, DrawerBody, DrawerCloseButton, DrawerContent, DrawerHeader, DrawerOverlay, Modal, ModalOverlay, ModalContent, ModalHeader, ModalCloseButton, ModalBody, ModalFooter, Button, Stack, Input, Text, useToast, useDisclosure } from "@chakra-ui/react"; import coffeeLogo from "../assets/buy-coffee.png"; import { COFFEE_CONTRACT_ABI, config } from "@repo/config-contract"; import { THOR_URL } from "../config/constants"; import { VetBalance } from "./vetbalance"; import "./buycoffee.css"; enum TransactionStatus { NotSent = "NOT_SENT", Pending = "PENDING", Success = "SUCCESS", Reverted = "REVERTED", } export function SendCoffee({refetch}) { const { account, signer } = useWallet(); const toast = useToast(); const { isOpen: isDrawerOpen, onOpen: onDrawerOpen, onClose: onDrawerClose, } = useDisclosure(); const { isOpen: isModalOpen, onOpen: onModalOpen, onClose: onModalClose, } = useDisclosure(); // Separate states instead of single formData object const [name, setName] = useState("") const [address, setAddress] = useState(""); const [message, setMessage] = useState(""); const [txId, setTxId] = useState(null); const [txStatus, setTxStatus] = useState( TransactionStatus.NotSent ); const [isLoading, setIsLoading] = useState(false); if (!account) return null; const onSendCoffee = async () => { if (!address.trim() || !message.trim() || !name.trim()) { toast({ title: "Missing Information", description: "Please enter recipient address and a message.", status: "warning", duration: 3000, isClosable: true, }); return; } try { setIsLoading(true); onModalClose(); const contractClause = Clause.callFunction( Address.of(config.CONTRACT_ADDRESS), ABIContract.ofAbi(COFFEE_CONTRACT_ABI).getFunction("sendCoffee"), [address, name, message], VET.of(1), { comment: `${account} sent you a coffee!` } ); const tx = () => signer?.sendTransaction({ clauses: [ { to: contractClause.to, value: contractClause.value.toString(), data: contractClause.data.toString(), }, ], comment: `${account} sent you a coffee!`, }); const result = await tx(); setTxId(result); setTxStatus(TransactionStatus.Pending); onDrawerOpen(); const thorClient = ThorClient.at(THOR_URL); const txReceipt = await thorClient.transactions.waitForTransaction( result ); if (txReceipt?.reverted) { setTxStatus(TransactionStatus.Reverted); toast({ title: "Transaction Failed", description: "The transaction was reverted.", status: "error", duration: 5000, isClosable: true, }); } else { setTxStatus(TransactionStatus.Success); toast({ title: "Success!", description: "Thank you, the coffee was sent! ☕", status: "success", duration: 5000, isClosable: true, }); refetch(txReceipt) } } catch (error) { console.error("Error sending coffee:", error); setTxStatus(TransactionStatus.Reverted); toast({ title: "Error", description: "An error occurred while sending the coffee.", status: "error", duration: 5000, isClosable: true, }); } finally { setIsLoading(false); } }; const handleSendCoffee = () => { setTxId(null); setTxStatus(TransactionStatus.NotSent); setName(""); setAddress(""); setMessage(""); onModalOpen(); }; return (
Send Somebody a Coffee! ☕ Send somebody a coffee for 1 VET! Leave their address and a friendly message: setAddress(e.target.value)} isRequired /> setName(e.target.value)} isRequired /> setMessage(e.target.value)} isRequired /> Coffee Status {txId && Transaction ID: {txId}} {txStatus === TransactionStatus.Pending && ( Transaction is pending... )} {txStatus === TransactionStatus.Success && ( Transaction succeeded! ✅ )} {txStatus === TransactionStatus.Reverted && ( Transaction reverted! ❌ )}
); }