mirror of
https://github.com/0xShay/ticketchain.git
synced 2026-01-11 21:23:24 +00:00
Merge pull request #33 from Ayush272002/ticket-buy-page
Ticket buy page Done
This commit is contained in:
@@ -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 />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ interface Event {
|
|||||||
host: string;
|
host: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dummy function to fetch events
|
|
||||||
const fetchEvents = (): Event[] => {
|
const fetchEvents = (): Event[] => {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
@@ -159,7 +158,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 (
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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
2
package-lock.json
generated
@@ -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"
|
||||||
|
|||||||
Reference in New Issue
Block a user