Merge pull request #37 from Ayush272002/add_buy_button_handler

fix num tickets
This commit is contained in:
2024-10-27 01:07:21 +01:00
committed by GitHub
6 changed files with 587 additions and 556 deletions

View File

@@ -1,4 +1,4 @@
import React from 'react';
import React, { useState } from 'react';
import {
Card,
CardHeader,
@@ -32,8 +32,10 @@ const EventDescription: React.FC<EventDescriptionProps> = ({
eventDetails,
}) => {
const { toast } = useToast();
const [numTickets, setNumTickets] = useState(1);
const handleBuyNow = () => {
buyHandler(eventDetails.EventID, toast);
buyHandler(eventDetails.EventID, numTickets, toast);
};
return (
@@ -79,7 +81,10 @@ const EventDescription: React.FC<EventDescriptionProps> = ({
</Button>
<div className="relative md:left-5">
<NumberPicker
initialCount={numTickets}
min={1}
max={eventDetails.capacity - eventDetails.ticketsSold}
onChange={setNumTickets}
/>
</div>
</CardFooter>

View File

@@ -1,6 +1,5 @@
'use client';
import React, { useState } from 'react';
import { Button } from '../ui/button'; // Adjust import path to where your shadcn Button component is located
import React from 'react';
import { Button } from '../ui/button';
interface NumberPickerProps {
initialCount?: number;
@@ -15,25 +14,23 @@ const NumberPicker: React.FC<NumberPickerProps> = ({
max = 10,
onChange,
}) => {
const [count, setCount] = useState<number>(initialCount);
const [count, setCount] = React.useState(initialCount);
React.useEffect(() => {
if (onChange) {
onChange(count);
}
}, [count, onChange]);
const increment = () => {
if (count < max) {
const newCount = count + 1;
setCount(newCount);
if (onChange) {
onChange(newCount);
}
setCount(count + 1);
}
};
const decrement = () => {
if (count > min) {
const newCount = count - 1;
setCount(newCount);
if (onChange) {
onChange(newCount);
}
setCount(count - 1);
}
};

View File

@@ -0,0 +1,504 @@
[
{
"inputs": [
{
"internalType": "uint256",
"name": "_ticketId",
"type": "uint256"
},
{
"internalType": "address",
"name": "_to",
"type": "address"
},
{
"internalType": "bool",
"name": "_allowed",
"type": "bool"
}
],
"name": "approveTicket",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_eventId",
"type": "uint256"
}
],
"name": "buyTicket",
"outputs": [
{
"internalType": "uint256",
"name": "_ticketId",
"type": "uint256"
}
],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "string",
"name": "_name",
"type": "string"
},
{
"internalType": "string",
"name": "_description",
"type": "string"
},
{
"internalType": "uint256",
"name": "_capacity",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "_ticketPrice",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "_eventDate",
"type": "uint256"
},
{
"internalType": "string[]",
"name": "_images",
"type": "string[]"
}
],
"name": "createEvent",
"outputs": [
{
"internalType": "uint256",
"name": "_eventId",
"type": "uint256"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "eventId",
"type": "uint256"
},
{
"indexed": false,
"internalType": "string",
"name": "name",
"type": "string"
},
{
"indexed": false,
"internalType": "uint256",
"name": "eventDate",
"type": "uint256"
}
],
"name": "EventCreated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "ticketId",
"type": "uint256"
},
{
"indexed": false,
"internalType": "uint256",
"name": "eventId",
"type": "uint256"
},
{
"indexed": false,
"internalType": "address",
"name": "buyer",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "price",
"type": "uint256"
}
],
"name": "TicketPurchased",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "ticketId",
"type": "uint256"
},
{
"indexed": false,
"internalType": "address",
"name": "owner",
"type": "address"
},
{
"indexed": false,
"internalType": "address",
"name": "trustee",
"type": "address"
}
],
"name": "TicketTransferApproved",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "uint256",
"name": "ticketId",
"type": "uint256"
},
{
"indexed": false,
"internalType": "address",
"name": "from",
"type": "address"
},
{
"indexed": false,
"internalType": "address",
"name": "to",
"type": "address"
}
],
"name": "TicketTransferred",
"type": "event"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_ticketId",
"type": "uint256"
},
{
"internalType": "address",
"name": "_to",
"type": "address"
}
],
"name": "transferTicket",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_ticketId",
"type": "uint256"
},
{
"internalType": "address",
"name": "_to",
"type": "address"
}
],
"name": "transferTicketFrom",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_cents",
"type": "uint256"
}
],
"name": "centsToFlare",
"outputs": [
{
"internalType": "uint256",
"name": "_flr",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "eventCounter",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "events",
"outputs": [
{
"internalType": "string",
"name": "name",
"type": "string"
},
{
"internalType": "string",
"name": "description",
"type": "string"
},
{
"internalType": "uint256",
"name": "capacity",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "ticketsSold",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "ticketPrice",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "eventDate",
"type": "uint256"
},
{
"internalType": "address payable",
"name": "eventHost",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "feedIds",
"outputs": [
{
"internalType": "bytes21",
"name": "",
"type": "bytes21"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_eventId",
"type": "uint256"
}
],
"name": "getEventImages",
"outputs": [
{
"internalType": "string[]",
"name": "",
"type": "string[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_eventId",
"type": "uint256"
}
],
"name": "getEventPriceFlare",
"outputs": [
{
"internalType": "uint256",
"name": "_flr",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "_eventId",
"type": "uint256"
}
],
"name": "getEventTickets",
"outputs": [
{
"internalType": "uint256[]",
"name": "",
"type": "uint256[]"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getFlareFeed",
"outputs": [
{
"internalType": "uint256",
"name": "_feedValue",
"type": "uint256"
},
{
"internalType": "int8",
"name": "_decimals",
"type": "int8"
},
{
"internalType": "uint64",
"name": "_timestamp",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "getFtsoV2CurrentFeedValues",
"outputs": [
{
"internalType": "uint256[]",
"name": "_feedValues",
"type": "uint256[]"
},
{
"internalType": "int8[]",
"name": "_decimals",
"type": "int8[]"
},
{
"internalType": "uint64",
"name": "_timestamp",
"type": "uint64"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "ticketCounter",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "tickets",
"outputs": [
{
"internalType": "address",
"name": "holder",
"type": "address"
},
{
"internalType": "uint256",
"name": "boughtTime",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "eventId",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "",
"type": "address"
},
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"name": "userTickets",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
}
]

View File

@@ -17,6 +17,7 @@ type ToastFunction = (options: {
export const buyHandler = async (
eventId: number,
numTickets: number,
toast: ToastFunction
): Promise<void> => {
if (eventId < 0) {
@@ -24,42 +25,62 @@ export const buyHandler = async (
return;
}
try {
if (typeof window.ethereum === 'undefined') {
toast({
title: 'Please install MetaMask or another Ethereum wallet',
variant: 'destructive',
});
return;
}
const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner();
const contract = getContract().connect(signer);
let ticketCost = await contract.getEventPriceFlare(eventId);
ticketCost = ticketCost.mul(105).div(100);
const balance = await provider.getBalance(await signer.getAddress());
if (balance.lt(ticketCost)) {
toast({
title: 'Insufficient balance to cover ticket cost and gas fees.',
variant: 'destructive',
});
return;
}
const tx = await contract.buyTicket(eventId, { value: ticketCost });
const receipt = await tx.wait();
if (numTickets <= 0) {
toast({
title: `Ticket purchased successfully! Transaction Hash: ${receipt.transactionHash}`,
});
} catch (error) {
console.error('Error buying ticket:', error);
toast({
title: 'Transaction failed. Please try again.',
title: 'Please select at least one ticket.',
variant: 'destructive',
});
return;
}
toast({
title:
'You might be asked to approve multiple transactions if you buy multiple tickets',
});
while (numTickets > 0) {
try {
if (typeof window.ethereum === 'undefined') {
toast({
title: 'Please install MetaMask or another Ethereum wallet',
variant: 'destructive',
});
return;
}
const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner();
const contract = getContract().connect(signer);
const singleTicketCost = await contract.getEventPriceFlare(eventId);
const totalTicketCost = singleTicketCost
.mul(numTickets)
.mul(105)
.div(100);
const balance = await provider.getBalance(await signer.getAddress());
if (balance.lt(totalTicketCost)) {
toast({
title: 'Insufficient balance to cover ticket cost and gas fees.',
variant: 'destructive',
});
return;
}
const tx = await contract.buyTicket(eventId, { value: totalTicketCost });
const receipt = await tx.wait();
toast({
title: `Tickets purchased successfully! Transaction Hash: ${receipt.transactionHash}`,
});
numTickets -= 1;
} catch (error) {
console.error('Error buying tickets:', error);
toast({
title: 'Transaction failed. Please try again.',
variant: 'destructive',
});
}
}
};

View File

@@ -1,4 +1,5 @@
import { ethers } from 'ethers';
import EventManagerABI from '../contracts/EventManagerABI.json';
const FLARE_TESTNET_RPC_URL = process.env.NEXT_PUBLIC_RPC_URL;
const CONTRACT_ADDRESS = process.env.NEXT_PUBLIC_CONTRACT_ADDRESS;
@@ -12,509 +13,6 @@ export function getFlareProvider() {
export function getContract() {
const provider = getFlareProvider();
const contractAddress = CONTRACT_ADDRESS;
const contractABI = [
{
inputs: [
{
internalType: 'uint256',
name: '_ticketId',
type: 'uint256',
},
{
internalType: 'address',
name: '_to',
type: 'address',
},
{
internalType: 'bool',
name: '_allowed',
type: 'bool',
},
],
name: 'approveTicket',
outputs: [],
stateMutability: 'nonpayable',
type: 'function',
},
{
inputs: [
{
internalType: 'uint256',
name: '_eventId',
type: 'uint256',
},
],
name: 'buyTicket',
outputs: [
{
internalType: 'uint256',
name: '_ticketId',
type: 'uint256',
},
],
stateMutability: 'payable',
type: 'function',
},
{
inputs: [
{
internalType: 'string',
name: '_name',
type: 'string',
},
{
internalType: 'string',
name: '_description',
type: 'string',
},
{
internalType: 'uint256',
name: '_capacity',
type: 'uint256',
},
{
internalType: 'uint256',
name: '_ticketPrice',
type: 'uint256',
},
{
internalType: 'uint256',
name: '_eventDate',
type: 'uint256',
},
{
internalType: 'string[]',
name: '_images',
type: 'string[]',
},
],
name: 'createEvent',
outputs: [
{
internalType: 'uint256',
name: '_eventId',
type: 'uint256',
},
],
stateMutability: 'nonpayable',
type: 'function',
},
{
inputs: [],
stateMutability: 'nonpayable',
type: 'constructor',
},
{
anonymous: false,
inputs: [
{
indexed: false,
internalType: 'uint256',
name: 'eventId',
type: 'uint256',
},
{
indexed: false,
internalType: 'string',
name: 'name',
type: 'string',
},
{
indexed: false,
internalType: 'uint256',
name: 'eventDate',
type: 'uint256',
},
],
name: 'EventCreated',
type: 'event',
},
{
anonymous: false,
inputs: [
{
indexed: false,
internalType: 'uint256',
name: 'ticketId',
type: 'uint256',
},
{
indexed: false,
internalType: 'uint256',
name: 'eventId',
type: 'uint256',
},
{
indexed: false,
internalType: 'address',
name: 'buyer',
type: 'address',
},
{
indexed: false,
internalType: 'uint256',
name: 'price',
type: 'uint256',
},
],
name: 'TicketPurchased',
type: 'event',
},
{
anonymous: false,
inputs: [
{
indexed: false,
internalType: 'uint256',
name: 'ticketId',
type: 'uint256',
},
{
indexed: false,
internalType: 'address',
name: 'owner',
type: 'address',
},
{
indexed: false,
internalType: 'address',
name: 'trustee',
type: 'address',
},
],
name: 'TicketTransferApproved',
type: 'event',
},
{
anonymous: false,
inputs: [
{
indexed: false,
internalType: 'uint256',
name: 'ticketId',
type: 'uint256',
},
{
indexed: false,
internalType: 'address',
name: 'from',
type: 'address',
},
{
indexed: false,
internalType: 'address',
name: 'to',
type: 'address',
},
],
name: 'TicketTransferred',
type: 'event',
},
{
inputs: [
{
internalType: 'uint256',
name: '_ticketId',
type: 'uint256',
},
{
internalType: 'address',
name: '_to',
type: 'address',
},
],
name: 'transferTicket',
outputs: [],
stateMutability: 'nonpayable',
type: 'function',
},
{
inputs: [
{
internalType: 'uint256',
name: '_ticketId',
type: 'uint256',
},
{
internalType: 'address',
name: '_to',
type: 'address',
},
],
name: 'transferTicketFrom',
outputs: [],
stateMutability: 'nonpayable',
type: 'function',
},
{
inputs: [
{
internalType: 'uint256',
name: '_cents',
type: 'uint256',
},
],
name: 'centsToFlare',
outputs: [
{
internalType: 'uint256',
name: '_flr',
type: 'uint256',
},
],
stateMutability: 'view',
type: 'function',
},
{
inputs: [],
name: 'eventCounter',
outputs: [
{
internalType: 'uint256',
name: '',
type: 'uint256',
},
],
stateMutability: 'view',
type: 'function',
},
{
inputs: [
{
internalType: 'uint256',
name: '',
type: 'uint256',
},
],
name: 'events',
outputs: [
{
internalType: 'string',
name: 'name',
type: 'string',
},
{
internalType: 'string',
name: 'description',
type: 'string',
},
{
internalType: 'uint256',
name: 'capacity',
type: 'uint256',
},
{
internalType: 'uint256',
name: 'ticketsSold',
type: 'uint256',
},
{
internalType: 'uint256',
name: 'ticketPrice',
type: 'uint256',
},
{
internalType: 'uint256',
name: 'eventDate',
type: 'uint256',
},
{
internalType: 'address payable',
name: 'eventHost',
type: 'address',
},
],
stateMutability: 'view',
type: 'function',
},
{
inputs: [
{
internalType: 'uint256',
name: '',
type: 'uint256',
},
],
name: 'feedIds',
outputs: [
{
internalType: 'bytes21',
name: '',
type: 'bytes21',
},
],
stateMutability: 'view',
type: 'function',
},
{
inputs: [
{
internalType: 'uint256',
name: '_eventId',
type: 'uint256',
},
],
name: 'getEventImages',
outputs: [
{
internalType: 'string[]',
name: '',
type: 'string[]',
},
],
stateMutability: 'view',
type: 'function',
},
{
inputs: [
{
internalType: 'uint256',
name: '_eventId',
type: 'uint256',
},
],
name: 'getEventPriceFlare',
outputs: [
{
internalType: 'uint256',
name: '_flr',
type: 'uint256',
},
],
stateMutability: 'view',
type: 'function',
},
{
inputs: [
{
internalType: 'uint256',
name: '_eventId',
type: 'uint256',
},
],
name: 'getEventTickets',
outputs: [
{
internalType: 'uint256[]',
name: '',
type: 'uint256[]',
},
],
stateMutability: 'view',
type: 'function',
},
{
inputs: [],
name: 'getFlareFeed',
outputs: [
{
internalType: 'uint256',
name: '_feedValue',
type: 'uint256',
},
{
internalType: 'int8',
name: '_decimals',
type: 'int8',
},
{
internalType: 'uint64',
name: '_timestamp',
type: 'uint64',
},
],
stateMutability: 'view',
type: 'function',
},
{
inputs: [],
name: 'getFtsoV2CurrentFeedValues',
outputs: [
{
internalType: 'uint256[]',
name: '_feedValues',
type: 'uint256[]',
},
{
internalType: 'int8[]',
name: '_decimals',
type: 'int8[]',
},
{
internalType: 'uint64',
name: '_timestamp',
type: 'uint64',
},
],
stateMutability: 'view',
type: 'function',
},
{
inputs: [],
name: 'ticketCounter',
outputs: [
{
internalType: 'uint256',
name: '',
type: 'uint256',
},
],
stateMutability: 'view',
type: 'function',
},
{
inputs: [
{
internalType: 'uint256',
name: '',
type: 'uint256',
},
],
name: 'tickets',
outputs: [
{
internalType: 'address',
name: 'holder',
type: 'address',
},
{
internalType: 'uint256',
name: 'boughtTime',
type: 'uint256',
},
{
internalType: 'uint256',
name: 'eventId',
type: 'uint256',
},
],
stateMutability: 'view',
type: 'function',
},
{
inputs: [
{
internalType: 'address',
name: '',
type: 'address',
},
{
internalType: 'uint256',
name: '',
type: 'uint256',
},
],
name: 'userTickets',
outputs: [
{
internalType: 'uint256',
name: '',
type: 'uint256',
},
],
stateMutability: 'view',
type: 'function',
},
];
const contractABI = EventManagerABI;
return new ethers.Contract(contractAddress!, contractABI, provider);
}

10
package-lock.json generated
View File

@@ -6794,6 +6794,7 @@
"integrity": "sha512-bdM5cEGCOhDSwminryHJbRmXc1x7dPKg6Pqns3qyTwFlxsqUgxE29lsERS3PlIW1HTjoIGMUqsk1zQQwST1Yxw==",
"dev": true,
"hasInstallScript": true,
"optional": true,
"dependencies": {
"node-gyp-build": "4.3.0"
},
@@ -6806,6 +6807,7 @@
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz",
"integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==",
"dev": true,
"optional": true,
"bin": {
"node-gyp-build": "bin.js",
"node-gyp-build-optional": "optional.js",
@@ -19793,6 +19795,7 @@
"resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-5.0.1.tgz",
"integrity": "sha512-lDFs9AAIaWP9UCdtWrotXWWF9t8PWgQDcxqgAnpM9rMqxb3Oaq2J0thzPVSxBwdJgyQtkU/sYtFtbM1RSt/iYA==",
"hasInstallScript": true,
"peer": true,
"dependencies": {
"elliptic": "^6.5.7",
"node-addon-api": "^5.0.0",
@@ -19805,12 +19808,14 @@
"node_modules/secp256k1/node_modules/bn.js": {
"version": "4.12.0",
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz",
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA=="
"integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==",
"peer": true
},
"node_modules/secp256k1/node_modules/elliptic": {
"version": "6.6.0",
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.0.tgz",
"integrity": "sha512-dpwoQcLc/2WLQvJvLRHKZ+f9FgOdjnq11rurqwekGQygGPsYSK29OMMD2WalatiqQ+XGFDglTNixpPfI+lpaAA==",
"peer": true,
"dependencies": {
"bn.js": "^4.11.9",
"brorand": "^1.1.0",
@@ -19824,7 +19829,8 @@
"node_modules/secp256k1/node_modules/node-addon-api": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz",
"integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA=="
"integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==",
"peer": true
},
"node_modules/seedrandom": {
"version": "3.0.5",