fixing changes

This commit is contained in:
ashprit
2024-10-27 00:55:00 +01:00
12 changed files with 206 additions and 117 deletions

View File

@@ -1,46 +1,55 @@
'use client'; 'use client';
import React from 'react'; import React, { useEffect, useState } from 'react';
import { useSearchParams } from 'next/navigation'; import { useParams } from 'next/navigation';
import Header from '../../../components/custom/header'; import Header from '../../../components/custom/header';
import Footer from '../../../components/custom/footer'; import Footer from '../../../components/custom/footer';
import EventDescription from '../../../components/custom/EventDescription'; import EventDescription from '../../../components/custom/EventDescription';
// Dummy function to simulate a GET request
const fetchEventDetails = (eventID: number) => {
alert(`Fetching details for event ID: ${eventID}`);
// Simulated JSON response for the event
return {
EventID: eventID,
name: 'Example Event Name',
date: '2023-12-01',
location: 'Example Location',
ticketPrice: 100,
description: 'Detailed description of the event.',
capacity: 300,
ticketsSold: 150,
imageUrl: [
'https://via.placeholder.com/150',
'https://via.placeholder.com/150',
],
host: 'Example Host',
tickets: [1, 2, 3, 4],
};
};
const ListingPage: React.FC = () => { const ListingPage: React.FC = () => {
const searchParams = useSearchParams(); const { eventId } = useParams();
const eventID = searchParams.get('eventID'); const [eventDetails, setEventDetails] = useState<any>(null);
// Simulate fetching data from backend useEffect(() => {
if (eventID) { const fetchEventDetails = async (id: number) => {
const eventDetails = fetchEventDetails(Number(eventID)); alert(`Fetching details for event ID: ${id}`);
console.log('Event Details:', eventDetails); // Dummy Response
} const details = {
EventID: id,
name: 'Example Event Name',
date: '2023-12-01',
location: 'Example Location',
ticketPrice: 100,
description: 'Detailed description of the event.',
capacity: 300,
ticketsSold: 295,
imageUrl: [
'https://via.placeholder.com/150',
'https://via.placeholder.com/150',
],
host: 'Example Host',
tickets: [1, 2, 3, 4],
};
return details;
};
const getEventDetails = async () => {
if (eventId) {
const details = await fetchEventDetails(Number(eventId));
setEventDetails(details);
}
};
getEventDetails();
}, [eventId]);
return ( return (
<> <>
<Header /> <Header />
<EventDescription eventId={eventID!} /> {eventDetails ? (
<EventDescription eventDetails={eventDetails} />
) : (
<p>Loading...</p>
)}
<Footer /> <Footer />
</> </>
); );

View File

@@ -18,7 +18,6 @@ interface Event {
host: string; host: string;
} }
// Dummy function to fetch events
const fetchEvents = (): Event[] => { const fetchEvents = (): Event[] => {
return [ return [
{ {
@@ -161,7 +160,7 @@ const EventsPage: React.FC = () => {
}, []); }, []);
const handleEventClick = (eventID: number) => { const handleEventClick = (eventID: number) => {
router.push(`/events/${eventID}`); // You may replace this with a Link from Next.js router.push(`/events/${eventID}`); // Route to the specific event page
}; };
return ( return (

14
app/host/page.tsx Normal file
View File

@@ -0,0 +1,14 @@
'use client';
import EventForm from '@/components/custom/EventForm';
import React from 'react';
const page = () => {
return (
<>
<EventForm onSubmit={() => {}} />
</>
);
};
export default page;

View File

@@ -20,8 +20,8 @@ const inter = Inter({ subsets: ['latin'] });
// }); // });
export const metadata: Metadata = { export const metadata: Metadata = {
title: 'Ticket Chain', title: 'TicketChain',
description: 'A blockchain-based ticketing system.', description: 'A verifiable and immutable ticketing platform.',
}; };
export default function RootLayout({ export default function RootLayout({

View File

@@ -57,11 +57,11 @@ export default function Home() {
<div className="relative z-20 min-h-screen bg-gradient-to-b from-transparent to-gray-900 pt-20"> <div className="relative z-20 min-h-screen bg-gradient-to-b from-transparent to-gray-900 pt-20">
<div className="container mx-auto p-4"> <div className="container mx-auto p-4">
<div className="container mx-auto justify-center items-center p-4"> <div className="container mx-auto justify-center items-center p-4">
<div className="text-4xl font-bold text-white text-shadow-lg"> <div className="text-6xl font-bold text-white text-center text-shadow-lg">
Book your next Book your next
<FlipWords <FlipWords
words={words} words={words}
className="text-light-purple text-opacity-75" className="text-pink-500 text-opacity-75 pl-3.5"
/> />
on the Flare blockchain. on the Flare blockchain.
</div> </div>

View File

@@ -9,43 +9,63 @@ import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge'; import { Badge } from '@/components/ui/badge';
import { Separator } from '@/components/ui/separator'; import { Separator } from '@/components/ui/separator';
import ImageCarousel from './ImageCarousel'; import ImageCarousel from './ImageCarousel';
import TicketButton from './TicketButton';
import { buyHandler } from '@/lib/buyHandler'; import { buyHandler } from '@/lib/buyHandler';
import { useToast } from '@/hooks/use-toast'; import { useToast } from '@/hooks/use-toast';
import NumberPicker from './TicketButton';
const EventDescription = ({ eventId }: { eventId: string }) => { interface EventDescriptionProps {
eventDetails: {
EventID: number;
name: string;
date: string;
location: string;
ticketPrice: number;
description: string;
capacity: number;
ticketsSold: number;
imageUrl: string[];
host: string;
};
}
const EventDescription: React.FC<EventDescriptionProps> = ({
eventDetails,
}) => {
const { toast } = useToast(); const { toast } = useToast();
const handleBuyNow = () => { const handleBuyNow = () => {
buyHandler(Number(eventId), toast); buyHandler(eventDetails.EventID, toast);
}; };
return ( return (
<Card className="pt-10 pb-16 px-6 bg-gradient-to-r from-blue-50 to-gray-50 rounded-xl shadow-lg max-w-4xl mx-auto"> <Card className="pt-10 pb-16 px-6 bg-gradient-to-r from-blue-50 to-gray-50 rounded-xl shadow-lg max-w-4xl mx-auto">
<CardHeader className="flex flex-col items-start space-y-4"> <CardHeader className="flex flex-col items-start space-y-4">
<h1 className="text-3xl font-semibold text-gray-800">TicketTitle</h1> <h1 className="text-3xl font-semibold text-gray-800">
{eventDetails.name}
</h1>
<Badge <Badge
variant="outline" variant="outline"
className="text-blue-600 bg-blue-100 px-3 py-1 rounded-full" className="text-blue-600 bg-blue-100 px-3 py-1 rounded-full"
> >
Price: $99 Price: ${eventDetails.ticketPrice}
</Badge> </Badge>
</CardHeader> </CardHeader>
<CardContent className="flex flex-col md:flex-row items-start space-y-8 md:space-y-0 md:space-x-10"> <CardContent className="flex flex-col md:flex-row items-start space-y-8 md:space-y-0 md:space-x-10">
<div className="md:w-1/2 flex justify-center"> <div className="md:w-1/2 flex justify-center">
<ImageCarousel /> <ImageCarousel images={eventDetails.imageUrl} />
</div> </div>
<div className="md:w-1/2 text-gray-700"> <div className="md:w-1/2 text-gray-700">
<Separator className="my-4" /> <Separator className="my-4" />
<p className="leading-relaxed"> <p className="leading-relaxed">{eventDetails.description}</p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Lorem
ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Lorem ipsum
dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua.
</p>
<Separator className="my-4" /> <Separator className="my-4" />
<p>Location: {eventDetails.location}</p>
<p>Date: {eventDetails.date}</p>
<p>Host: {eventDetails.host}</p>
{eventDetails.ticketsSold / eventDetails.capacity >= 0.9 && (
<div className="mt-2 p-2 bg-yellow-300 text-black rounded">
Limited Tickets Remaining!
</div>
)}
</div> </div>
</CardContent> </CardContent>
@@ -58,7 +78,9 @@ const EventDescription = ({ eventId }: { eventId: string }) => {
Buy now Using MetaMask Buy now Using MetaMask
</Button> </Button>
<div className="relative md:left-5"> <div className="relative md:left-5">
<TicketButton /> <NumberPicker
max={eventDetails.capacity - eventDetails.ticketsSold}
/>
</div> </div>
</CardFooter> </CardFooter>
</Card> </Card>

View File

@@ -1,5 +1,4 @@
import * as React from 'react'; import * as React from 'react';
import { Card, CardContent } from '@/components/ui/card'; import { Card, CardContent } from '@/components/ui/card';
import { import {
Carousel, Carousel,
@@ -9,17 +8,25 @@ import {
CarouselPrevious, CarouselPrevious,
} from '@/components/ui/carousel'; } from '@/components/ui/carousel';
export default function ImageCarousel() { interface ImageCarouselProps {
images: string[];
}
const ImageCarousel: React.FC<ImageCarouselProps> = ({ images }) => {
return ( return (
<Carousel className="w-full max-w-xs"> <Carousel className="w-full max-w-xs">
<CarouselContent> <CarouselContent>
{/* map your images here from the page */} {/* Map over the images array to create CarouselItems */}
{Array.from({ length: 5 }).map((_, index) => ( {images.map((imageUrl, index) => (
<CarouselItem key={index}> <CarouselItem key={index}>
<div className="p-1"> <div className="p-1">
<Card> <Card>
<CardContent className="flex aspect-square items-center justify-center p-6"> <CardContent className="flex aspect-square items-center justify-center p-6">
<span className="text-4xl font-semibold">{index + 1}</span> <img
src={imageUrl}
alt={`Event image ${index + 1}`}
className="w-full h-full object-cover rounded-lg"
/>
</CardContent> </CardContent>
</Card> </Card>
</div> </div>
@@ -30,4 +37,6 @@ export default function ImageCarousel() {
<CarouselNext /> <CarouselNext />
</Carousel> </Carousel>
); );
} };
export default ImageCarousel;

View File

@@ -62,6 +62,16 @@ const Header = () => {
</a> </a>
</Link> </Link>
</li> </li>
<li>
<Link href="/host" legacyBehavior>
<a
className="text-white hover:text-light-purple hover:text-opacity-75 transition-colors duration-300"
style={{ textShadow: '1px 1px 2px rgba(0, 0, 0, 0.5)' }}
>
Host Event
</a>
</Link>
</li>
<li> <li>
<Link href="/contact" legacyBehavior> <Link href="/contact" legacyBehavior>
<a <a

View File

@@ -1,7 +1,7 @@
'use client'; 'use client';
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { useSDK, MetaMaskProvider } from '@metamask/sdk-react'; import { WalletIcon } from 'lucide-react';
import { Button } from '@/components/ui/button'; import { Button } from '@/components/ui/button';
import { import {
Popover, Popover,
@@ -9,54 +9,87 @@ import {
PopoverTrigger, PopoverTrigger,
} from '@/components/ui/popover'; } from '@/components/ui/popover';
function WalletIcon(props: React.SVGProps<SVGSVGElement>) { declare global {
return ( interface Window {
<svg ethereum?: {
{...props} isMetaMask?: boolean;
xmlns="http://www.w3.org/2000/svg" request: (request: {
width="24" method: string;
height="24" params?: Array<unknown>; // Use `unknown` instead of `any`
viewBox="0 0 24 24" }) => Promise<unknown>; // Specify a more accurate return type if possible
fill="none" };
stroke="currentColor" }
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M21 12V7H5a2 2 0 0 1 0-4h14v4" />
<path d="M3 5v14a2 2 0 0 0 2 2h16v-5" />
<path d="M18 12a2 2 0 0 0 0 4h4v-4Z" />
</svg>
);
}
function formatAddress(address: string | undefined): string {
if (!address) return '';
return `${address.slice(0, 6)}...${address.slice(-4)}`;
} }
function MetaMaskConnect() { function MetaMaskConnect() {
const { sdk, connected, connecting, account } = useSDK(); const [isConnected, setIsConnected] = useState<boolean>(false);
const [isConnected, setIsConnected] = useState(false); const [account, setAccount] = useState<string | null>(null);
// Initial check on load
useEffect(() => { useEffect(() => {
setIsConnected(connected); const checkConnection = async () => {
}, [connected]); if (typeof window !== 'undefined' && window.ethereum) {
try {
// Check if there are any accounts already connected
const accounts = (await window.ethereum.request({
method: 'eth_accounts',
})) as string[];
if (accounts && accounts.length > 0) {
setIsConnected(true);
setAccount(accounts[0]);
localStorage.setItem('isConnected', JSON.stringify(true));
localStorage.setItem('account', accounts[0]);
} else {
// No connected accounts found; check `localStorage`
const storedIsConnected = JSON.parse(
localStorage.getItem('isConnected') || 'false'
);
const storedAccount = localStorage.getItem('account') || null;
setIsConnected(storedIsConnected);
setAccount(storedAccount);
}
} catch (error) {
console.error('Error checking MetaMask connection:', error);
}
}
};
checkConnection();
}, []);
// Update localStorage whenever connection state changes
useEffect(() => {
if (typeof window !== 'undefined') {
localStorage.setItem('isConnected', JSON.stringify(isConnected));
localStorage.setItem('account', account || '');
}
}, [isConnected, account]);
const connect = async () => { const connect = async () => {
try { try {
await sdk?.connect(); const accounts = (await window.ethereum?.request({
setIsConnected(true); method: 'eth_requestAccounts',
} catch (err) { })) as string[];
console.warn(`No accounts found`, err); if (accounts && accounts.length > 0) {
setIsConnected(true);
setAccount(accounts[0]);
localStorage.setItem('isConnected', JSON.stringify(true));
localStorage.setItem('account', accounts[0]);
}
} catch (error) {
console.error('MetaMask connection failed:', error);
} }
}; };
const disconnect = () => { const disconnect = async () => {
if (sdk) { setIsConnected(false);
sdk.terminate(); setAccount(null);
setIsConnected(false); localStorage.setItem('isConnected', JSON.stringify(false));
} localStorage.removeItem('account');
await window.ethereum?.request({
method: 'wallet_revokePermissions',
params: [{ eth_accounts: {} }],
});
}; };
return ( return (
@@ -65,7 +98,7 @@ function MetaMaskConnect() {
<Popover> <Popover>
<PopoverTrigger asChild> <PopoverTrigger asChild>
<Button variant="link" className="text-white"> <Button variant="link" className="text-white">
{formatAddress(account)} {account && `${account.slice(0, 6)}...${account.slice(-4)}`}
</Button> </Button>
</PopoverTrigger> </PopoverTrigger>
<PopoverContent className="w-44"> <PopoverContent className="w-44">
@@ -80,7 +113,6 @@ function MetaMaskConnect() {
</Popover> </Popover>
) : ( ) : (
<Button <Button
disabled={connecting}
onClick={connect} onClick={connect}
className="bg-light-purple bg-opacity-75 hover:bg-purple border-0 hover:border-0" className="bg-light-purple bg-opacity-75 hover:bg-purple border-0 hover:border-0"
> >
@@ -91,18 +123,4 @@ function MetaMaskConnect() {
); );
} }
export default function MetaMaskConnectWrapper() { export default MetaMaskConnect;
return (
<MetaMaskProvider
debug={false}
sdkOptions={{
dappMetadata: {
name: 'My dApp',
url: typeof window !== 'undefined' ? window.location.href : '',
},
}}
>
<MetaMaskConnect />
</MetaMaskProvider>
);
}

View File

@@ -33,7 +33,6 @@ export const buyHandler = async (
return; return;
} }
// @ts-expect-error: window.ethereum might not match ExternalProvider exactly
const provider = new ethers.providers.Web3Provider(window.ethereum); const provider = new ethers.providers.Web3Provider(window.ethereum);
const signer = provider.getSigner(); const signer = provider.getSigner();
const contract = getContract().connect(signer); const contract = getContract().connect(signer);

3
lib/createEvent.ts Normal file
View File

@@ -0,0 +1,3 @@
export const createEvent = async (event: Event) => {
console.log('HELLO');
};

10
package-lock.json generated
View File

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