mirror of
https://github.com/0xShay/ticketchain.git
synced 2026-01-11 05:03:26 +00:00
Buy ticket interface works
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"extends": ["next/core-web-vitals", "next/typescript"],
|
||||
"rules": {
|
||||
"@next/next/no-img-element": "off"
|
||||
"@next/next/no-img-element": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,46 +1,55 @@
|
||||
'use client';
|
||||
import React from 'react';
|
||||
import { useSearchParams } from 'next/navigation';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useParams } from 'next/navigation';
|
||||
import Header from '../../../components/custom/header';
|
||||
import Footer from '../../../components/custom/footer';
|
||||
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 searchParams = useSearchParams();
|
||||
const eventID = searchParams.get('eventID');
|
||||
const { eventId } = useParams();
|
||||
const [eventDetails, setEventDetails] = useState<any>(null);
|
||||
|
||||
// Simulate fetching data from backend
|
||||
if (eventID) {
|
||||
const eventDetails = fetchEventDetails(Number(eventID));
|
||||
console.log('Event Details:', eventDetails);
|
||||
}
|
||||
useEffect(() => {
|
||||
const fetchEventDetails = async (id: number) => {
|
||||
alert(`Fetching details for event ID: ${id}`);
|
||||
// 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 (
|
||||
<>
|
||||
<Header />
|
||||
<EventDescription eventId={eventID!} />
|
||||
{eventDetails ? (
|
||||
<EventDescription eventDetails={eventDetails} />
|
||||
) : (
|
||||
<p>Loading...</p>
|
||||
)}
|
||||
<Footer />
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -17,7 +17,6 @@ interface Event {
|
||||
host: string;
|
||||
}
|
||||
|
||||
// Dummy function to fetch events
|
||||
const fetchEvents = (): Event[] => {
|
||||
return [
|
||||
{
|
||||
@@ -147,7 +146,7 @@ const EventsPage: React.FC = () => {
|
||||
}, []);
|
||||
|
||||
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 (
|
||||
|
||||
@@ -9,43 +9,63 @@ import { Button } from '@/components/ui/button';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
import ImageCarousel from './ImageCarousel';
|
||||
import TicketButton from './TicketButton';
|
||||
import { buyHandler } from '@/lib/buyHandler';
|
||||
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 handleBuyNow = () => {
|
||||
buyHandler(Number(eventId), toast);
|
||||
buyHandler(eventDetails.EventID, toast);
|
||||
};
|
||||
|
||||
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">
|
||||
<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
|
||||
variant="outline"
|
||||
className="text-blue-600 bg-blue-100 px-3 py-1 rounded-full"
|
||||
>
|
||||
Price: $99
|
||||
Price: ${eventDetails.ticketPrice}
|
||||
</Badge>
|
||||
</CardHeader>
|
||||
|
||||
<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">
|
||||
<ImageCarousel />
|
||||
<ImageCarousel images={eventDetails.imageUrl} />
|
||||
</div>
|
||||
<div className="md:w-1/2 text-gray-700">
|
||||
<Separator className="my-4" />
|
||||
<p className="leading-relaxed">
|
||||
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>
|
||||
<p className="leading-relaxed">{eventDetails.description}</p>
|
||||
<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>
|
||||
</CardContent>
|
||||
|
||||
@@ -58,7 +78,9 @@ const EventDescription = ({ eventId }: { eventId: string }) => {
|
||||
Buy now Using MetaMask
|
||||
</Button>
|
||||
<div className="relative md:left-5">
|
||||
<TicketButton />
|
||||
<NumberPicker
|
||||
max={eventDetails.capacity - eventDetails.ticketsSold}
|
||||
/>
|
||||
</div>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { Card, CardContent } from '@/components/ui/card';
|
||||
import {
|
||||
Carousel,
|
||||
@@ -9,17 +8,25 @@ import {
|
||||
CarouselPrevious,
|
||||
} from '@/components/ui/carousel';
|
||||
|
||||
export default function ImageCarousel() {
|
||||
interface ImageCarouselProps {
|
||||
images: string[];
|
||||
}
|
||||
|
||||
const ImageCarousel: React.FC<ImageCarouselProps> = ({ images }) => {
|
||||
return (
|
||||
<Carousel className="w-full max-w-xs">
|
||||
<CarouselContent>
|
||||
{/* map your images here from the page */}
|
||||
{Array.from({ length: 5 }).map((_, index) => (
|
||||
{/* Map over the images array to create CarouselItems */}
|
||||
{images.map((imageUrl, index) => (
|
||||
<CarouselItem key={index}>
|
||||
<div className="p-1">
|
||||
<Card>
|
||||
<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>
|
||||
</Card>
|
||||
</div>
|
||||
@@ -30,4 +37,6 @@ export default function ImageCarousel() {
|
||||
<CarouselNext />
|
||||
</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",
|
||||
"integrity": "sha512-HTm14iMQKK2FjFLRTM5lAVcyaUzOnqbPtesFIvREgXpJHdQm8bWS+GkQgIkfaBYRHuCnea7w8UVNfwiAQhlr9A==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"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",
|
||||
"integrity": "sha512-vLt1O5Pp+flcArHGIyKEQq883nBt8nN8tVBcoL0qUXj2XT1n7p70yGIq2VK98I5FdZ1YHc0wk/koOnHjnXWk1Q==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"node-gyp-build": "^4.3.0"
|
||||
|
||||
Reference in New Issue
Block a user