Buy ticket interface works

This commit is contained in:
Adwit Mukherji
2024-10-26 23:32:21 +01:00
parent b54f4d92a5
commit 83156d541f
6 changed files with 98 additions and 56 deletions

View File

@@ -1,6 +1,7 @@
{ {
"extends": ["next/core-web-vitals", "next/typescript"], "extends": ["next/core-web-vitals", "next/typescript"],
"rules": { "rules": {
"@next/next/no-img-element": "off" "@next/next/no-img-element": "off",
"@typescript-eslint/no-explicit-any": "off"
} }
} }

View File

@@ -1,23 +1,27 @@
'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 ListingPage: React.FC = () => {
const fetchEventDetails = (eventID: number) => { const { eventId } = useParams();
alert(`Fetching details for event ID: ${eventID}`); const [eventDetails, setEventDetails] = useState<any>(null);
// Simulated JSON response for the event
return { useEffect(() => {
EventID: eventID, const fetchEventDetails = async (id: number) => {
alert(`Fetching details for event ID: ${id}`);
// Dummy Response
const details = {
EventID: id,
name: 'Example Event Name', name: 'Example Event Name',
date: '2023-12-01', date: '2023-12-01',
location: 'Example Location', location: 'Example Location',
ticketPrice: 100, ticketPrice: 100,
description: 'Detailed description of the event.', description: 'Detailed description of the event.',
capacity: 300, capacity: 300,
ticketsSold: 150, ticketsSold: 295,
imageUrl: [ imageUrl: [
'https://via.placeholder.com/150', 'https://via.placeholder.com/150',
'https://via.placeholder.com/150', 'https://via.placeholder.com/150',
@@ -25,22 +29,27 @@ const fetchEventDetails = (eventID: number) => {
host: 'Example Host', host: 'Example Host',
tickets: [1, 2, 3, 4], tickets: [1, 2, 3, 4],
}; };
}; return details;
};
const ListingPage: React.FC = () => { const getEventDetails = async () => {
const searchParams = useSearchParams(); if (eventId) {
const eventID = searchParams.get('eventID'); const details = await fetchEventDetails(Number(eventId));
setEventDetails(details);
// Simulate fetching data from backend
if (eventID) {
const eventDetails = fetchEventDetails(Number(eventID));
console.log('Event Details:', eventDetails);
} }
};
getEventDetails();
}, [eventId]);
return ( return (
<> <>
<Header /> <Header />
<EventDescription eventId={eventID!} /> {eventDetails ? (
<EventDescription eventDetails={eventDetails} />
) : (
<p>Loading...</p>
)}
<Footer /> <Footer />
</> </>
); );

View File

@@ -17,7 +17,6 @@ interface Event {
host: string; host: string;
} }
// Dummy function to fetch events
const fetchEvents = (): Event[] => { const fetchEvents = (): Event[] => {
return [ return [
{ {
@@ -147,7 +146,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 (

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;

2
package-lock.json generated
View File

@@ -13058,6 +13058,7 @@
"resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.5.tgz", "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.5.tgz",
"integrity": "sha512-HTm14iMQKK2FjFLRTM5lAVcyaUzOnqbPtesFIvREgXpJHdQm8bWS+GkQgIkfaBYRHuCnea7w8UVNfwiAQhlr9A==", "integrity": "sha512-HTm14iMQKK2FjFLRTM5lAVcyaUzOnqbPtesFIvREgXpJHdQm8bWS+GkQgIkfaBYRHuCnea7w8UVNfwiAQhlr9A==",
"dev": true, "dev": true,
"hasInstallScript": true,
"optional": true, "optional": true,
"dependencies": { "dependencies": {
"node-gyp-build": "^4.3.0" "node-gyp-build": "^4.3.0"
@@ -13420,6 +13421,7 @@
"resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.7.tgz", "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.7.tgz",
"integrity": "sha512-vLt1O5Pp+flcArHGIyKEQq883nBt8nN8tVBcoL0qUXj2XT1n7p70yGIq2VK98I5FdZ1YHc0wk/koOnHjnXWk1Q==", "integrity": "sha512-vLt1O5Pp+flcArHGIyKEQq883nBt8nN8tVBcoL0qUXj2XT1n7p70yGIq2VK98I5FdZ1YHc0wk/koOnHjnXWk1Q==",
"dev": true, "dev": true,
"hasInstallScript": true,
"optional": true, "optional": true,
"dependencies": { "dependencies": {
"node-gyp-build": "^4.3.0" "node-gyp-build": "^4.3.0"