updated registration, slots

This commit is contained in:
Harini312821
2024-08-12 17:28:25 +08:00
parent dd1d84d22a
commit 2fe13fd724
5 changed files with 296 additions and 167 deletions

View File

@@ -8,6 +8,11 @@ import {
CardBody, CardBody,
Button, Button,
CardFooter, CardFooter,
Modal,
ModalContent,
ModalHeader,
ModalBody,
ModalFooter,
} from "@nextui-org/react"; } from "@nextui-org/react";
import { ArrowUTurnLeftIcon } from "../icons"; // Make sure this path is correct import { ArrowUTurnLeftIcon } from "../icons"; // Make sure this path is correct
@@ -15,153 +20,292 @@ const EventDetailsPage = () => {
const { id } = useParams<{ id: string }>(); // Get the event ID from the URL const { id } = useParams<{ id: string }>(); // Get the event ID from the URL
const [event, setEvent] = useState<any>(null); // State to store event details const [event, setEvent] = useState<any>(null); // State to store event details
const [similarEvents, setSimilarEvents] = useState<any[]>([]); // State to store similar events const [similarEvents, setSimilarEvents] = useState<any[]>([]); // State to store similar events
const [isSuccessModalOpen, setIsSuccessModalOpen] = useState(false);
const [isRegistering, setIsRegistering] = useState(false);
const [isAlreadyRegisteredModalOpen, setIsAlreadyRegisteredModalOpen] = useState(false);
const [hasRegistered, setHasRegistered] = useState(false);
const navigate = useNavigate(); const navigate = useNavigate();
useEffect(() => { let accessToken = localStorage.getItem("accessToken");
const fetchEventDetails = async () => { if (!accessToken) {
try { navigate("/signin");
console.log("Fetching event details for ID:", id); // Debug log }
const res = await instance.get(`${config.serverAddress}/events/${id}`); const fetchEventDetails = () => {
try {
console.log("Fetching event details for ID:", id); // Debug log
instance.get(`${config.serverAddress}/events/${id}`).then((res) => {
console.log("Fetched event details:", res.data); // Log the fetched data console.log("Fetched event details:", res.data); // Log the fetched data
if (res.data.slotsAvailable === 0) {
navigate("/events"); // Redirect if there are no slots available
return;
}
setEvent(res.data); setEvent(res.data);
// Log the image data to debug
console.log("Event image data:", res.data.evtPicture);
// Fetch all events to find similar ones // Fetch all events to find similar ones
const allEventsRes = await instance.get( instance.get(
`${config.serverAddress}/events` `${config.serverAddress}/events`
); ).then((allEventsRes) => {
const allEvents = allEventsRes.data; const allEvents = allEventsRes.data;
// Find similar events based on location and category, excluding the current event // Find similar events based on location and category, excluding the current event
const similar = allEvents.filter( const similar = allEvents.filter(
(e: any) => (e: any) =>
e.id !== Number(id) && // Make sure to exclude the current event e.id !== Number(id) && // Make sure to exclude the current event
(e.location === res.data.location || e.slotsAvailable > 0 && // Ensure similar events have available slots
e.category === res.data.category) (e.location === res.data.location ||
); e.category === res.data.category)
);
setSimilarEvents(similar); console.log("Similar events found:", similar);
} catch (error) {
console.error("Failed to fetch event details:", error);
}
};
setSimilarEvents(similar);
});
// Check if the user has already registered
const registeredStatus = localStorage.getItem(`hasRegistered_${id}`);
if (registeredStatus === 'true') {
setHasRegistered(true);
} else {
setHasRegistered(false);
}
});
} catch (error) {
console.error("Failed to fetch event details:", error);
}
};
useEffect(() => {
fetchEventDetails(); fetchEventDetails();
}, [id]); }, [id]);
if (!event) return <p>Loading...</p>; const handleRegister = async () => {
console.log("Attempting to register...");
console.log("Current hasRegistered value:", hasRegistered);
if (hasRegistered) {
console.log("User has already registered, opening modal...");
setIsAlreadyRegisteredModalOpen(true);
return;
}
setIsRegistering(true);
try {
// Make a request to register for the event
const response = await instance.post(`${config.serverAddress}/events/register/${id}`);
// Check if registration was successful
if (response.status === 200) {
// Fetch updated event details to reflect the new number of available slots
const updatedEventRes = await instance.get(`${config.serverAddress}/events/${id}`);
setEvent(updatedEventRes.data);
console.log("Registration successful");
setHasRegistered(true);
localStorage.setItem(`hasRegistered_${id}`, 'true'); // Save registration status in local storage
setIsSuccessModalOpen(true);
} else if (response.status === 400) {
// Handle case where the user is already registered
setIsAlreadyRegisteredModalOpen(true);
}
} catch (error) {
console.error("Registration failed:", error);
// Handle different types of errors
if (error) {
console.error("Server response error:", error);
} else {
console.error("Network error:", error);
}
} finally {
setIsRegistering(false);
}
console.log("Updated hasRegistered value:", hasRegistered);
};
return ( return (
<div className="w-full h-full p-8"> <>
<Button {event && <div className="w-full h-full p-8">
className="mb-4 bg-gray-200 text-black rounded px-4 py-2 hover:bg-gray-300" <Button
onClick={() => navigate("/events")} // Navigate directly to the events page className="mb-4 bg-gray-200 text-black rounded px-4 py-2 hover:bg-gray-300"
> onClick={() => navigate("/events")} // Navigate directly to the events page
<ArrowUTurnLeftIcon /> >
Back to Events <ArrowUTurnLeftIcon />
</Button> Back to Events
<Card className="bg-white rounded-lg overflow-hidden border"> </Button>
<div className="flex"> <Card className="bg-white rounded-lg overflow-hidden border">
{/* Event Image Section */} <div className="flex">
{event.evtPicture && ( {/* Event Image Section */}
<div className="w-1/3 p-4"> {event.evtPicture && (
<img <div className="w-1/3 p-4">
src={`${config.serverAddress}/events/evtPicture/${event.id}`} <img
alt="Event Picture" src={`${config.serverAddress}/events/evtPicture/${event.id}`}
className="w-full h-auto rounded-lg" alt="Event Picture"
style={{ className="w-full h-auto rounded-lg"
objectFit: 'cover', style={{
}} objectFit: 'cover',
/> }}
/>
</div>
)}
{/* Event Details Section */}
<div className="w-2/3 p-4">
<CardHeader className="pb-0 pt-2">
<h4 className="font-bold text-large">{event.title}</h4>
</CardHeader>
<CardBody className="pb-0 pt-2">
<p className="text-gray-600 mt-4">{event.description}</p>
<p className="text-gray-600 mt-2">
<strong>Date:</strong> {new Date(event.date).toLocaleDateString()}
</p>
<p className="text-gray-600 mt-2">
<strong>Time:</strong> {event.time}
</p>
<p className="text-gray-600 mt-2">
<strong>Location:</strong> {event.location}
</p>
<p className="text-gray-600 mt-2">
<strong>Category:</strong> {event.category}
</p>
<p className="text-gray-600 mt-2">
<strong>Slots Available:</strong> {event.slotsAvailable}
</p>
<Button
className="mt-4 bg-red-500 text-white rounded px-4 py-2 hover:bg-red-600"
onClick={() => handleRegister()}
disabled={isRegistering}
>
Register for Event
</Button>
</CardBody>
</div> </div>
)} </div>
{/* Event Details Section */} </Card>
<div className="w-2/3 p-4">
<CardHeader className="pb-0 pt-2"> {/* Similar Events Section */}
<h4 className="font-bold text-large">{event.title}</h4> <div className="mt-8">
</CardHeader> <h2 className="text-2xl font-semibold mb-4">
<CardBody className="pb-0 pt-2"> Similar Events You Might Be Interested In
<p className="text-gray-600 mt-4">{event.description}</p> </h2>
<p className="text-gray-600 mt-2"> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<strong>Date:</strong> {new Date(event.date).toLocaleDateString()} {similarEvents.length === 0 ? (
</p> <p className="text-gray-600">No similar events available.</p>
<p className="text-gray-600 mt-2"> ) : (
<strong>Time:</strong> {event.time} similarEvents.map((similarEvent: any) => (
</p> <Card
<p className="text-gray-600 mt-2"> key={similarEvent.id}
<strong>Location:</strong> {event.location} className="bg-white rounded-lg overflow-hidden border"
</p> >
<p className="text-gray-600 mt-2"> <CardHeader className="pb-0 pt-2 px-4 flex-col items-start">
<strong>Category:</strong> {event.category} <h4 className="font-bold text-large">{similarEvent.title}</h4>
</p> </CardHeader>
<p className="text-gray-600 mt-2"> <CardBody className="pb-0 pt-2 px-4 flex-col items-start">
<strong>Slots Available:</strong> {event.slotsAvailable} {similarEvent.evtPicture && (
</p> <div style={{
<Button width: '450px',
className="mt-4 bg-red-500 text-white rounded px-4 py-2 hover:bg-red-600" height: '300px',
onClick={() => navigate(`/events/register/${id}`)} overflow: 'hidden',
> borderRadius: '8px',
Register for Event position: 'relative'
</Button> }}>
</CardBody> <img
src={`${config.serverAddress}/events/evtPicture/${similarEvent.id}`}
alt="Event Picture"
style={{
width: '100%',
height: '100%',
objectFit: 'cover',
position: 'absolute',
top: 0,
left: 0
}}
onError={(e) => {
e.currentTarget.src = '/path/to/placeholder-image.png'; // Fallback image if loading fails
}}
/>
</div>
)}
</CardBody>
<CardFooter className="flex flex-col items-start p-4">
<Button
className="bg-primary-600 text-white rounded px-4 py-2 hover:bg-primary-700"
onClick={() => {
console.log(`Navigating to event details for ID: ${similarEvent.id}`);
console.log("Access Token:", localStorage.getItem("accessToken"));
navigate(`/events/view/${similarEvent.id}`);
}}
>
View event details
</Button>
</CardFooter>
</Card>
))
)}
</div> </div>
</div> </div>
</Card> {/* Success Confirmation Modal */}
<Modal
{/* Similar Events Section */} isOpen={isSuccessModalOpen}
<div className="mt-8"> onOpenChange={setIsSuccessModalOpen}
<h2 className="text-2xl font-semibold mb-4"> isDismissable={false}
Similar Events You Might Be Interested In isKeyboardDismissDisabled={true}
</h2> >
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6"> <ModalContent>
{similarEvents.length === 0 ? ( {(onClose) => (
<p className="text-gray-600">No similar events available.</p> <>
) : ( <ModalHeader className="flex flex-col gap-1">
similarEvents.map((similarEvent: any) => ( Success Message
<Card </ModalHeader>
key={similarEvent.id} <ModalBody>
className="bg-white rounded-lg overflow-hidden border" <p>You have successfully registered for this event!!</p>
> </ModalBody>
<CardHeader className="pb-0 pt-2 px-4 flex-col items-start"> <ModalFooter>
<h4 className="font-bold text-large">{similarEvent.title}</h4> <Button onPress={onClose}>Cancel</Button>
</CardHeader>
<CardBody className="pb-0 pt-2 px-4 flex-col items-start">
{similarEvent.evtPicture && (
<div style={{
width: '450px',
height: '300px',
overflow: 'hidden',
borderRadius: '8px',
position: 'relative'
}}>
<img
src={`${config.serverAddress}/events/evtPicture/${similarEvent.id}`}
alt="Event Picture"
style={{
width: '100%',
height: '100%',
objectFit: 'cover',
position: 'absolute',
top: 0,
left: 0
}}
/>
</div>
)}
</CardBody>
<CardFooter className="flex flex-col items-start p-4">
<Button <Button
className="bg-primary-600 text-white rounded px-4 py-2 hover:bg-primary-700" color="danger"
onClick={() => navigate(`/events/view/${similarEvent.id}`)} onPress={() => {
navigate(-1);
}}
> >
View event details Okay
</Button> </Button>
</CardFooter> </ModalFooter>
</Card> </>
)) )}
)} </ModalContent>
</div> </Modal>
</div>
</div> {/* Already Registered Modal */}
<Modal
isOpen={isAlreadyRegisteredModalOpen}
onOpenChange={setIsAlreadyRegisteredModalOpen}
isDismissable={false}
isKeyboardDismissDisabled={true}
>
<ModalContent>
{(onClose) => (
<>
<ModalHeader className="flex flex-col gap-1">
Already Registered
</ModalHeader>
<ModalBody>
<p>You have already registered for this event.</p>
</ModalBody>
<ModalFooter>
<Button onPress={onClose}>Close</Button>
</ModalFooter>
</>
)}
</ModalContent>
</Modal>
</div>}
{!event && <p>Loading...</p>}
</>
); );
}; };

View File

@@ -68,6 +68,14 @@ const EventsPage: React.FC = () => {
fetchTownCouncils(); fetchTownCouncils();
}, []); }, []);
const getTimePeriod = (time: string): string => {
const [hours] = time.split(':').map(Number);
if (hours >= 5 && hours < 12) return 'morning';
if (hours >= 12 && hours < 17) return 'afternoon';
if (hours >= 17 || hours < 5) return 'evening';
return ''; // Default case if none of the above match
};
useEffect(() => { useEffect(() => {
// Filter events based on selected criteria // Filter events based on selected criteria
const filtered = events.filter((event) => { const filtered = events.filter((event) => {
@@ -78,7 +86,7 @@ const EventsPage: React.FC = () => {
? event.location === selectedTownCouncil ? event.location === selectedTownCouncil
: true; : true;
const matchTime = selectedTime const matchTime = selectedTime
? event.time.toLowerCase().trim() === selectedTime.toLowerCase().trim() ? getTimePeriod(event.time) === selectedTime.toLowerCase().trim()
: true; : true;
console.log("Event Time:", event.time); console.log("Event Time:", event.time);

View File

@@ -27,6 +27,7 @@ const ManageEventsPage = () => {
const fetchEvents = async () => { const fetchEvents = async () => {
try { try {
const res = await axios.get(config.serverAddress + "/events"); const res = await axios.get(config.serverAddress + "/events");
console.log(res.data);
setEvents(res.data); setEvents(res.data);
} catch (error) { } catch (error) {
console.error("Failed to fetch events:", error); console.error("Failed to fetch events:", error);

View File

@@ -1,26 +0,0 @@
import React from "react";
import { useParams } from "react-router-dom";
import { Button } from "@nextui-org/react";
const RegisterPage = () => {
const { id } = useParams<{ id: string }>();
const handleRegister = () => {
// Add logic for registration here, if needed
console.log(`Registered for event with ID: ${id}`);
};
return (
<div className="w-full h-full p-8">
<h1 className="text-2xl font-bold mb-4">Register for Event</h1>
<Button
className="bg-red-500 text-white rounded px-4 py-2 hover:bg-red-600"
onClick={handleRegister}
>
Register
</Button>
</div>
);
};
export default RegisterPage;

View File

@@ -12,7 +12,7 @@ const upload = multer({ storage: multer.memoryStorage() });
router.get("/", async (req, res) => { router.get("/", async (req, res) => {
try { try {
const { category, townCouncil, time } = req.query; const { category, townCouncil, time} = req.query;
console.log("Filter Parameters:", { category, townCouncil, time }); console.log("Filter Parameters:", { category, townCouncil, time });
@@ -26,7 +26,9 @@ router.get("/", async (req, res) => {
const timeCategory = timeToCategory(time); const timeCategory = timeToCategory(time);
let filter = {}; let filter = {
slotsAvailable: { [Op.gt]: 0 }
};
if (category) filter.category = category; if (category) filter.category = category;
if (townCouncil) filter.townCouncil = townCouncil; if (townCouncil) filter.townCouncil = townCouncil;
if (timeCategory) filter.timeCategory = timeCategory; if (timeCategory) filter.timeCategory = timeCategory;
@@ -35,13 +37,7 @@ router.get("/", async (req, res) => {
const filteredEvents = await Events.findAll({ const filteredEvents = await Events.findAll({
attributes: { exclude: ["evtPicture"] }, attributes: { exclude: ["evtPicture"] },
where: { where: filter,
[Op.and]: [
category ? { category } : {},
townCouncil ? { townCouncil } : {},
timeCategory ? { timeCategory } : {},
],
},
}); });
res.json(filteredEvents); res.json(filteredEvents);
@@ -241,19 +237,25 @@ router.post("/register/:id", async (req, res) => {
return res.status(404).json({ message: "Event not found" }); return res.status(404).json({ message: "Event not found" });
} }
// Process registration data (e.g., save to a Registration table or similar) // Check if there are available slots
// Here we assume that you might just be updating the event for simplicity if (event.slotsAvailable <= 0) {
// Modify this logic as needed based on your actual requirements return res.status(400).json({ message: "No available slots for this event" });
await Events.update(data, { where: { id: id } }); }
// Decrease the number of available slots
await Events.update(
{ slotsAvailable: event.slotsAvailable - 1 },
{ where: { id: id } }
);
res.json({ message: "Registration successful" }); res.json({ message: "Registration successful" });
} catch (err) { } catch (err) {
console.error("Error during registration:", err); console.error("Error during registration:", err);
res.status(400).json({ errors: err.errors }); res.status(400).json({ errors: err.errors });
res.status(500).json({ message: "Error during registration", error: err.message });
} }
}); });
router.delete("/:id", async (req, res) => { router.delete("/:id", async (req, res) => {
const id = req.params.id; const id = req.params.id;
const event = await Events.findByPk(id); const event = await Events.findByPk(id);