Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 18 additions & 14 deletions app/(main)/events/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { format } from "date-fns";
import Link from "next/link";
import Image from "next/image";
import { EventRegistrationModal } from "@/components/EventRegistrationModal";
import { getEventPriceDisplay } from "@/lib/utils/event-priceUtils";

const EventDetailsPage = ({ params }: { params: { id: string } }) => {
const { id } = params;
Expand Down Expand Up @@ -52,9 +53,12 @@ const EventDetailsPage = ({ params }: { params: { id: string } }) => {
<div className="min-h-screen bg-white flex items-center justify-center p-4">
<div className="max-w-md w-full bg-white rounded-lg shadow-lg p-8 text-center">
<AlertCircle className="h-16 w-16 text-red-500 mx-auto mb-4" />
<h2 className="text-2xl font-bold text-gray-900 mb-2">Event Not Found</h2>
<h2 className="text-2xl font-bold text-gray-900 mb-2">
Event Not Found
</h2>
<p className="text-gray-600 mb-6">
The event you&apos;re looking for doesn&apos;t exist or has been removed.
The event you&apos;re looking for doesn&apos;t exist or has been
removed.
</p>
<Button asChild>
<Link href="/events">
Expand All @@ -74,15 +78,8 @@ const EventDetailsPage = ({ params }: { params: { id: string } }) => {
"hh:mm a"
)} - ${format(eventEndDate, "hh:mm a")}`;

// Determine event price (using first ticket category)
const eventPrice =
event.TicketCategories?.[0]?.price === 0
? "Free"
: event.TicketCategories?.[0]?.price
? `₱${event.TicketCategories[0].price}`
: "Free";
const eventPrice = getEventPriceDisplay(event.TicketCategories);

// Truncate description for preview (first 400 characters)
const descriptionPreview =
event.description?.length > 400 && !showFullDescription
? `${event.description.substring(0, 400)}...`
Expand Down Expand Up @@ -181,14 +178,18 @@ const EventDetailsPage = ({ params }: { params: { id: string } }) => {

{/* Event Price - Right aligned */}
<div className="text-right ml-8">
<p className="text-sm text-gray-900 font-semibold mb-1">Event Price</p>
<p className="text-4xl md:text-5xl font-bold text-gray-900">{eventPrice}</p>
<span className="text-xs text-gray-500 uppercase tracking-wide">
Price
</span>
<p className="text-xl font-bold text-gray-900">{eventPrice}</p>
</div>
</div>

{/* Event Description */}
<div className="mt-8 mb-8">
<h3 className="text-2xl font-bold text-gray-900 mb-4">Event Description</h3>
<h3 className="text-2xl font-bold text-gray-900 mb-4">
Event Description
</h3>
<div className="text-gray-700 leading-relaxed text-base whitespace-pre-line">
{descriptionPreview}
</div>
Expand All @@ -207,7 +208,10 @@ const EventDetailsPage = ({ params }: { params: { id: string } }) => {
<Button
size="lg"
onClick={handleRegisterClick}
disabled={!event.isRegistrationOpen || (event.isRegistrationRequired && !event.TicketCategories?.[0])}
disabled={
!event.isRegistrationOpen ||
(event.isRegistrationRequired && !event.TicketCategories?.[0])
}
className="px-16 py-6 text-lg font-semibold rounded-lg bg-blue-600 hover:bg-blue-700"
>
{event.isRegistrationOpen ? "Register" : "Registration Closed"}
Expand Down
2 changes: 2 additions & 0 deletions app/(main)/events/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { Skeleton } from "@/components/ui/skeleton";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import { useSearchParams } from "next/navigation";
import { getEventPriceDisplay } from "@/lib/utils/event-priceUtils";

const EventsContent = () => {
const searchParams = useSearchParams();
Expand Down Expand Up @@ -258,6 +259,7 @@ const EventsContent = () => {
<EventCard
key={event.id}
id={event.id}
price={getEventPriceDisplay(event.TicketCategories)}
title={event.name}
organization={event.org?.name || ""}
dateRange={`${new Date(event.dateStart).toLocaleDateString(
Expand Down
104 changes: 48 additions & 56 deletions components/EventCard.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
"use client";

import * as React from "react";
import { Calendar, Clock, Users } from "lucide-react";
import { Calendar, Clock } from "lucide-react";
import Image from "next/image";

import { cn } from "@/lib/utils";
import { Card } from "@/components/ui/card";
import { Badge } from "@/components/ui/badge";
import { useRouter } from "next/navigation";

interface EventCardProps extends React.HTMLAttributes<HTMLDivElement> {
id: string;
title?: string;
Expand All @@ -28,6 +26,7 @@ const EventCard = React.forwardRef<HTMLDivElement, EventCardProps>(
organization,
dateRange,
timeRange,
price,
imageUrl,
...props
},
Expand All @@ -37,11 +36,12 @@ const EventCard = React.forwardRef<HTMLDivElement, EventCardProps>(
const handleRedirectToDetails = () => {
router.push(`/events/${id}`);
};

return (
<Card
ref={ref}
className={cn(
"group w-full overflow-hidden rounded-2xl border-0 shadow-md hover:shadow-xl transition-all duration-300 cursor-pointer bg-white",
"group w-full overflow-hidden rounded-2xl border-0 shadow-md hover:shadow-xl transition-all duration-300 cursor-pointer bg-white flex flex-col",
className
)}
{...props}
Expand All @@ -66,70 +66,62 @@ const EventCard = React.forwardRef<HTMLDivElement, EventCardProps>(
)}

<div className="absolute inset-0 bg-gradient-to-t from-black/20 via-transparent to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300" />

{organization && (
<div className="absolute top-4 left-4">
<Badge
variant="secondary"
className="bg-white/90 text-gray-800 backdrop-blur-sm"
>
{organization}
</Badge>
</div>
)}
</div>

<div className="p-6 space-y-4">
<div className="space-y-2">
<h3 className="text-xl font-bold text-gray-900 line-clamp-2 group-hover:text-blue-600 transition-colors duration-200">
{title || "Event Title"}
</h3>
</div>

<div className="space-y-3">
<div className="flex items-start gap-3 text-sm text-gray-600">
<Calendar className="h-4 w-4 text-blue-500 mt-0.5 flex-shrink-0" />
<div className="space-y-1">
<p className="font-medium text-gray-900">
<div className="p-6 flex flex-col flex-grow">
<div className="space-y-3 pb-3">
<div className="flex items-start gap-4 text-sm text-gray-600">
<div className="flex items-start gap-2">
<Calendar className="h-4 w-4 text-blue-500 mt-0.5 flex-shrink-0" />
<p className="font-medium text-gray-900 text-xs">
{dateRange || "DD-MMM-YYYY to DD-MMM-YYYY"}
</p>
</div>
</div>

<div className="flex items-start gap-3 text-sm text-gray-600">
<Clock className="h-4 w-4 text-blue-500 mt-0.5 flex-shrink-0" />
<div className="space-y-1">
<p className="font-medium text-gray-900">
<div className="flex items-start gap-2">
<Clock className="h-4 w-4 text-blue-500 mt-0.5 flex-shrink-0" />
<p className="font-medium text-gray-900 text-xs">
{timeRange || "00:00 AM to 00:00 AM"}
</p>
</div>
</div>
</div>

<div className="pt-2 border-t border-gray-100">
<div
className="flex items-center justify-between"
onClick={() => handleRedirectToDetails()}
>
<div className="flex items-center gap-2 text-sm text-gray-500">
<Users className="h-4 w-4" />
<span>Join Event</span>
</div>
<div className="w-8 h-8 rounded-full bg-blue-100 flex items-center justify-center group-hover:bg-blue-500 group-hover:text-white transition-all duration-200">
<svg
className="w-4 h-4"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M9 5l7 7-7 7"
/>
</svg>
</div>
<div className="pt-2 border-t border-gray-100 flex-grow mb-4">
<h3 className="text-2xl font-bold text-gray-900 line-clamp-2 group-hover:text-blue-600 transition-colors duration-200">
{title || "Event Title"}
</h3>
<p className="text-sm font-medium text-gray-900 line-clamp-2 group-hover:text-blue-600 transition-colors duration-200">
{organization || "Organization Name"}
</p>
</div>

<div
className="flex items-center justify-between mt-auto "
onClick={() => handleRedirectToDetails()}
>
<div className="flex flex-col gap-0.5">
<span className="text-xs text-gray-500 uppercase tracking-wide">
Price
</span>
<span className="text-lg font-bold text-gray-900">
{price || "Free"}
</span>
</div>
<div className="w-10 h-10 rounded-full bg-blue-500 flex items-center justify-center group-hover:bg-blue-600 text-white transition-all duration-200 shadow-sm">
<svg
className="w-5 h-5"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M9 5l7 7-7 7"
/>
</svg>
</div>
</div>
</div>
Expand Down
19 changes: 19 additions & 0 deletions lib/utils/event-priceUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import type { TicketCategory } from "@/client/types/entities";

export const getEventPriceDisplay = (
ticketCategories?: TicketCategory[]
): string => {
if (!ticketCategories || ticketCategories.length === 0) return "Free";

const prices = ticketCategories.map((tc) => tc.price);
const minPrice = Math.min(...prices);
const maxPrice = Math.max(...prices);

if (maxPrice === 0) return "Free";

if (minPrice === maxPrice) return `Php ${minPrice}.00`;

if (minPrice === 0) return `Free - Php ${maxPrice}.00`;

return `Php ${minPrice}.00 - ${maxPrice}.00`;
};