From aa5d92b9dd508bdad4e6736fcda58998e9853598 Mon Sep 17 00:00:00 2001 From: Ayush Acharjya Date: Sun, 27 Oct 2024 00:07:26 +0100 Subject: [PATCH 1/7] add num tickets --- components/custom/EventDescription.tsx | 9 +++++++-- components/custom/TicketButton.tsx | 25 +++++++++++-------------- lib/buyHandler.ts | 23 ++++++++++++++++------- 3 files changed, 34 insertions(+), 23 deletions(-) diff --git a/components/custom/EventDescription.tsx b/components/custom/EventDescription.tsx index b790ae9..9aaa346 100644 --- a/components/custom/EventDescription.tsx +++ b/components/custom/EventDescription.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useState } from 'react'; import { Card, CardHeader, @@ -32,8 +32,10 @@ const EventDescription: React.FC = ({ 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 = ({
diff --git a/components/custom/TicketButton.tsx b/components/custom/TicketButton.tsx index 0d42a1f..7c330f1 100644 --- a/components/custom/TicketButton.tsx +++ b/components/custom/TicketButton.tsx @@ -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 = ({ max = 10, onChange, }) => { - const [count, setCount] = useState(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); } }; diff --git a/lib/buyHandler.ts b/lib/buyHandler.ts index dfd2808..008fef3 100644 --- a/lib/buyHandler.ts +++ b/lib/buyHandler.ts @@ -17,6 +17,7 @@ type ToastFunction = (options: { export const buyHandler = async ( eventId: number, + numTickets: number, toast: ToastFunction ): Promise => { if (eventId < 0) { @@ -24,6 +25,14 @@ export const buyHandler = async ( return; } + if (numTickets <= 0) { + toast({ + title: 'Please select at least one ticket.', + variant: 'destructive', + }); + return; + } + try { if (typeof window.ethereum === 'undefined') { toast({ @@ -38,11 +47,11 @@ export const buyHandler = async ( 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()); + const singleTicketCost = await contract.getEventPriceFlare(eventId); + const totalTicketCost = singleTicketCost.mul(numTickets).mul(105).div(100); - if (balance.lt(ticketCost)) { + 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', @@ -50,14 +59,14 @@ export const buyHandler = async ( return; } - const tx = await contract.buyTicket(eventId, { value: ticketCost }); + const tx = await contract.buyTicket(eventId, { value: totalTicketCost }); const receipt = await tx.wait(); toast({ - title: `Ticket purchased successfully! Transaction Hash: ${receipt.transactionHash}`, + title: `Tickets purchased successfully! Transaction Hash: ${receipt.transactionHash}`, }); } catch (error) { - console.error('Error buying ticket:', error); + console.error('Error buying tickets:', error); toast({ title: 'Transaction failed. Please try again.', variant: 'destructive', From c5b020d71d53cc7d685cbcef20bad3468b7eb9af Mon Sep 17 00:00:00 2001 From: Ayush Acharjya Date: Sun, 27 Oct 2024 00:11:06 +0100 Subject: [PATCH 2/7] pull form main --- package-lock.json | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0916733..ff74cd1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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", From 99bc489909c66bb02c4674b75f69f6b53f682eb0 Mon Sep 17 00:00:00 2001 From: Ayush Acharjya Date: Sun, 27 Oct 2024 00:50:29 +0100 Subject: [PATCH 3/7] add host --- app/host/page.tsx | 14 ++++++++++++++ components/custom/header.tsx | 10 ++++++++++ lib/createEvent.ts | 3 +++ package-lock.json | 10 ++++++++-- 4 files changed, 35 insertions(+), 2 deletions(-) create mode 100644 app/host/page.tsx create mode 100644 lib/createEvent.ts diff --git a/app/host/page.tsx b/app/host/page.tsx new file mode 100644 index 0000000..89f8c98 --- /dev/null +++ b/app/host/page.tsx @@ -0,0 +1,14 @@ +'use client'; + +import EventForm from '@/components/custom/EventForm'; +import React from 'react'; + +const page = () => { + return ( + <> + {}} /> + + ); +}; + +export default page; diff --git a/components/custom/header.tsx b/components/custom/header.tsx index b044a19..c25cdfd 100644 --- a/components/custom/header.tsx +++ b/components/custom/header.tsx @@ -62,6 +62,16 @@ const Header = () => { +
  • + + + Host Event + + +
  • { + console.log('HELLO'); +}; diff --git a/package-lock.json b/package-lock.json index 0916733..ff74cd1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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", From c5e8aa67f54053da523944b0b22ed54a58aee3f4 Mon Sep 17 00:00:00 2001 From: ashprit Date: Sun, 27 Oct 2024 00:53:22 +0100 Subject: [PATCH 4/7] adding to prev commit --- .eslintrc.json | 4 +++- components/EventPage.tsx | 7 +++++++ components/ProfilePage.tsx | 7 +++++++ components/{ => custom}/Profile.tsx | 0 4 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 components/ProfilePage.tsx rename components/{ => custom}/Profile.tsx (100%) diff --git a/.eslintrc.json b/.eslintrc.json index c9fcf13..4060e80 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -2,6 +2,8 @@ "extends": ["next/core-web-vitals", "next/typescript"], "rules": { "@next/next/no-img-element": "off", - "@typescript-eslint/no-explicit-any": "off" + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-empty-object-type": "off", + "@typescript-eslint/no-unused-vars": "off" } } diff --git a/components/EventPage.tsx b/components/EventPage.tsx index 0c7e0eb..75287e2 100644 --- a/components/EventPage.tsx +++ b/components/EventPage.tsx @@ -16,3 +16,10 @@ const EventPage = () => { }; export default EventPage; + +// profile page + +// EventForm to Register Events +// on submit form +// fix ui to match ticketchain initial ui +// diff --git a/components/ProfilePage.tsx b/components/ProfilePage.tsx new file mode 100644 index 0000000..e7135e3 --- /dev/null +++ b/components/ProfilePage.tsx @@ -0,0 +1,7 @@ +import React from 'react'; + +const ProfilePage = () => { + return
    ProfilePage
    ; +}; + +export default ProfilePage; diff --git a/components/Profile.tsx b/components/custom/Profile.tsx similarity index 100% rename from components/Profile.tsx rename to components/custom/Profile.tsx From 85ad44cc648e77519cfb3f2cfcb9f8b992ecb162 Mon Sep 17 00:00:00 2001 From: Ayush Acharjya Date: Sun, 27 Oct 2024 01:03:00 +0100 Subject: [PATCH 5/7] fix multiple tickers + abi --- contracts/EventManagerABI.json | 504 ++++++++++++++++++++++++++++++++ lib/buyHandler.ts | 78 ++--- lib/ethers.ts | 506 +-------------------------------- 3 files changed, 551 insertions(+), 537 deletions(-) create mode 100644 contracts/EventManagerABI.json diff --git a/contracts/EventManagerABI.json b/contracts/EventManagerABI.json new file mode 100644 index 0000000..4d7c5b0 --- /dev/null +++ b/contracts/EventManagerABI.json @@ -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" + } +] diff --git a/lib/buyHandler.ts b/lib/buyHandler.ts index 172c392..02a28b2 100644 --- a/lib/buyHandler.ts +++ b/lib/buyHandler.ts @@ -33,42 +33,54 @@ export const buyHandler = async ( return; } - try { - if (typeof window.ethereum === 'undefined') { + 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: 'Please install MetaMask or another Ethereum wallet', + 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', }); - 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}`, - }); - } catch (error) { - console.error('Error buying tickets:', error); - toast({ - title: 'Transaction failed. Please try again.', - variant: 'destructive', - }); } }; diff --git a/lib/ethers.ts b/lib/ethers.ts index f16d3ab..09df0fb 100644 --- a/lib/ethers.ts +++ b/lib/ethers.ts @@ -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); } From cce9632b5f82f10a59b10965682ff0649a1c2220 Mon Sep 17 00:00:00 2001 From: ashprit Date: Sun, 27 Oct 2024 01:55:58 +0000 Subject: [PATCH 6/7] adding all changes --- app/host/page.tsx | 105 +++++++++++++++++++++- components/ProfilePage.tsx | 120 ++++++++++++++++++++++++- components/custom/EventDescription.tsx | 2 +- components/custom/EventForm.tsx | 2 +- 4 files changed, 221 insertions(+), 8 deletions(-) diff --git a/app/host/page.tsx b/app/host/page.tsx index 89f8c98..f78c01e 100644 --- a/app/host/page.tsx +++ b/app/host/page.tsx @@ -1,14 +1,111 @@ 'use client'; import EventForm from '@/components/custom/EventForm'; -import React from 'react'; +import FeaturedEvent from '@/components/custom/FeaturedEvent'; +import Footer from '@/components/custom/footer'; +import Header from '@/components/custom/header'; +import { Button } from '@/components/ui/button'; +import { FlipWords } from '@/components/ui/flip-words'; +import { useRouter } from 'next/navigation'; +import React, { useEffect, useRef, useState } from 'react'; +import { motion } from 'framer-motion'; +import { EventFormData } from '@/components/custom/EventForm'; + +const Page = () => { + const router = useRouter(); + const [isClient, setIsClient] = useState(false); + const inputRef = useRef(null); + + useEffect(() => { + setIsClient(true); + }, []); + + function searchForEvents() { + if (inputRef.current && inputRef.current.value === '') return; + + if (inputRef.current) + router.replace('/events?q=' + encodeURIComponent(inputRef.current.value)); + } + + function handleSubmit(data: { + name: string; + description: string; + capacity: number; + ticketPrice: number; + location: string; + eventStartTime: Date; + eventEndTime?: Date | undefined; + images?: string[] | undefined; + }) { + // Logic for handling the form submission + console.log('Event data submitted:', data); + // You can replace the console log with an API call or any other handling logic + router.push('/events'); + } + + const words = [ + 'adventure', + 'concert', + 'outing', + 'journey', + 'hackathon', + 'conference', + ]; -const page = () => { return ( <> - {}} /> +
    +
    + {/* Video Background */} + {isClient && ( + + )} + + {/* Dark Overlay for Enhanced Readability */} +
    + + {/* Page Content Over the Video */} +
    +
    + +
    + + Create your event here! + + + + +
    +
    +
    +
    +
    +
    ); }; -export default page; +export default Page; diff --git a/components/ProfilePage.tsx b/components/ProfilePage.tsx index e7135e3..6bd0bb8 100644 --- a/components/ProfilePage.tsx +++ b/components/ProfilePage.tsx @@ -1,7 +1,123 @@ -import React from 'react'; +import { useRouter } from 'next/router'; +// import { Input } from 'postcss'; // Removed incorrect import +import React, { useEffect, useRef, useState } from 'react'; +import FeaturedEvent from './custom/FeaturedEvent'; +import Footer from './custom/footer'; +import Header from './custom/header'; +import { Button } from './ui/button'; +import { FlipWords } from './ui/flip-words'; const ProfilePage = () => { - return
    ProfilePage
    ; + const router = useRouter(); + const [isClient, setIsClient] = useState(false); + const inputRef: any = useRef(null); + + useEffect(() => { + setIsClient(true); + }, []); + + function searchForEvents() { + if (inputRef.current.value == '') return; + router.replace('/events?q=' + encodeURIComponent(inputRef.current.value)); + } + + const words = [ + 'adventure', + 'concert', + 'outing', + 'journey', + 'hackathon', + 'conference', + ]; + + return ( + <> +
    +
    + {/* Video Background */} + {isClient && ( + + )} + + {/* Dark Overlay for Enhanced Readability */} +
    + + {/* Page Content Over the Video */} +
    +
    +
    +
    + Book your next + + on the Flare blockchain. +
    +
    + +
    + + +
    +
    +
    + + + +
    +
    +
    +
    +
    +
    + + ); }; export default ProfilePage; diff --git a/components/custom/EventDescription.tsx b/components/custom/EventDescription.tsx index b790ae9..c41ad77 100644 --- a/components/custom/EventDescription.tsx +++ b/components/custom/EventDescription.tsx @@ -13,7 +13,7 @@ import { buyHandler } from '@/lib/buyHandler'; import { useToast } from '@/hooks/use-toast'; import NumberPicker from './TicketButton'; -interface EventDescriptionProps { +export interface EventDescriptionProps { eventDetails: { EventID: number; name: string; diff --git a/components/custom/EventForm.tsx b/components/custom/EventForm.tsx index 9273dd0..f6dfe64 100644 --- a/components/custom/EventForm.tsx +++ b/components/custom/EventForm.tsx @@ -58,7 +58,7 @@ const eventSchema = z }); // Define the TypeScript type based on the Zod schema -type EventFormData = z.infer; +export type EventFormData = z.infer; interface EventFormProps { onSubmit: (data: EventFormData) => void; From e9f0e9e75918ebd8288c8a5f88fe837793253512 Mon Sep 17 00:00:00 2001 From: Ayush Acharjya Date: Sun, 27 Oct 2024 02:40:19 +0000 Subject: [PATCH 7/7] interlink create host --- app/host/page.tsx | 17 +++++++-- lib/createEvent.ts | 92 +++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 104 insertions(+), 5 deletions(-) diff --git a/app/host/page.tsx b/app/host/page.tsx index f78c01e..1b63f2b 100644 --- a/app/host/page.tsx +++ b/app/host/page.tsx @@ -10,6 +10,7 @@ import { useRouter } from 'next/navigation'; import React, { useEffect, useRef, useState } from 'react'; import { motion } from 'framer-motion'; import { EventFormData } from '@/components/custom/EventForm'; +import { createEvent } from '@/lib/createEvent'; const Page = () => { const router = useRouter(); @@ -37,9 +38,19 @@ const Page = () => { eventEndTime?: Date | undefined; images?: string[] | undefined; }) { - // Logic for handling the form submission - console.log('Event data submitted:', data); - // You can replace the console log with an API call or any other handling logic + createEvent({ + name: data.name, + description: data.description, + location: data.location, + capacity: data.capacity, + ticketPrice: data.ticketPrice, + startDate: data.eventStartTime, + endDate: data.eventEndTime || new Date(), + images: data.images || [], + toast: ({ title, variant }) => { + alert(title); + }, + }); router.push('/events'); } diff --git a/lib/createEvent.ts b/lib/createEvent.ts index 7e84b9a..31a6f5b 100644 --- a/lib/createEvent.ts +++ b/lib/createEvent.ts @@ -1,3 +1,91 @@ -export const createEvent = async (event: Event) => { - console.log('HELLO'); +import { ethers } from 'ethers'; +import { getContract } from './ethers'; + +interface CreateEventProps { + name: string; + description: string; + location: string; + capacity: number; + ticketPrice: number; + startDate: Date; + endDate: Date; + images: string[]; + toast: ToastFunction; +} + +type ToastFunction = (options: { + title: string; + variant?: 'default' | 'destructive' | null | undefined; +}) => void; + +declare global { + interface Window { + ethereumProvider?: ethers.providers.ExternalProvider & { + isMetaMask?: boolean; + request?: (method: string, params?: unknown[]) => Promise; + }; + } +} + +export const createEvent = async ({ + name, + description, + location, + capacity, + ticketPrice, + startDate, + endDate, + images, + toast, +}: CreateEventProps) => { + try { + console.log('Starting createEvent function'); + if (typeof window.ethereum === 'undefined') { + console.error('Ethereum provider not found'); + toast({ + title: 'Please install MetaMask or another Ethereum wallet', + variant: 'destructive', + }); + return; + } + + console.log('Connecting to Ethereum provider'); + const provider = new ethers.providers.Web3Provider(window.ethereum); + const signer = provider.getSigner(); + const contract = getContract().connect(signer); + + console.log('Preparing transaction data'); + const tx = await contract.createEvent( + name, + description, + capacity, + ethers.utils.parseEther(ticketPrice.toString()), + Math.floor(startDate.getTime() / 1000), + images + ); + + console.log('Transaction sent, waiting for confirmation'); + const receipt = await tx.wait(); + + console.log('Transaction confirmed:', receipt.transactionHash); + toast({ + title: `Event created successfully! Transaction Hash: ${receipt.transactionHash}`, + }); + + return receipt.transactionHash; + } catch (error) { + console.error('Error in createEvent:', error); + if (error instanceof Error) { + toast({ + title: `Transaction failed: ${error.message}`, + variant: 'destructive', + }); + } else { + toast({ + title: 'Transaction failed. Please try again.', + variant: 'destructive', + }); + } + throw error; + } };