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
25 changes: 19 additions & 6 deletions client/src/components/ui/calendar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -146,12 +146,15 @@ function CalendarDayButton({
locale,
...props
}) {
const defaultClassNames = getDefaultClassNames()
const defaultClassNames = getDefaultClassNames();

const ref = React.useRef(null);

const ref = React.useRef(null)
React.useEffect(() => {
if (modifiers.focused) ref.current?.focus()
}, [modifiers.focused])
if (modifiers.focused) {
ref.current?.focus();
}
}, [modifiers.focused]);

return (
<Button
Expand All @@ -170,10 +173,20 @@ function CalendarDayButton({
data-range-middle={modifiers.range_middle}
className={cn(
"relative isolate z-10 flex aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 border-0 leading-none font-normal group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:border-ring group-data-[focused=true]/day:ring-[3px] group-data-[focused=true]/day:ring-ring/50 data-[range-end=true]:rounded-(--cell-radius) data-[range-end=true]:rounded-r-(--cell-radius) data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground data-[range-middle=true]:rounded-none data-[range-middle=true]:bg-muted data-[range-middle=true]:text-foreground data-[range-start=true]:rounded-(--cell-radius) data-[range-start=true]:rounded-l-(--cell-radius) data-[range-start=true]:bg-primary data-[range-start=true]:text-primary-foreground data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground dark:hover:text-foreground [&>span]:text-xs [&>span]:opacity-70",

defaultClassNames.day,
className
className,

// Partial availability
modifiers.partial &&
"bg-yellow-400 text-black hover:bg-yellow-400 rounded-full",

// Fully booked
modifiers.booked &&
"bg-red-500 text-white hover:bg-red-500 rounded-full"
)}
{...props} />
{...props}
/>
);
}

Expand Down
2 changes: 1 addition & 1 deletion client/src/constants/apiRoutes.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ AUTH:{
GET_BY_ID: (bookingId) => `/user/booking/${bookingId}`,
GET_ALL: "/user/booking",
CANCEL: (bookingId) => `/user/bookings/${bookingId}/cancel`,
AVAILABILITY: (venueId) => `/user/booking/${venueId}/availability`,
AVAILABILITY: (venueId) => `/user/booking/${venueId}/availability`
}
},
ADMIN: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,32 +1,54 @@
import { useState } from "react";
import { useState, useEffect } from "react";
import { Calendar } from "@/components/ui/calendar";
import { useDispatch, useSelector } from "react-redux";
import { fetchAvailability } from "@/redux/slices/UserBookingSlice";

export default function VenueAvailability({
venue,
onAvailabilityChange,
}) {
const [selectedDate, setSelectedDate] =
useState(null);
const dispatch = useDispatch();

const formatDateKey = (date) => {
const year = date.getFullYear();
const [selectedDate, setSelectedDate] = useState(null);
const [currentMonth, setCurrentMonth] = useState(new Date());

const month = String(
date.getMonth() + 1
).padStart(2, "0");
const { availabilityData } = useSelector(
(state) => state.userBooking
);


const day = String(
date.getDate()
).padStart(2, "0");
const formatDateKey = (date) => {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, "0");
const day = String(date.getDate()).padStart(2, "0");

return `${year}-${month}-${day}`;
};

// Fetch availability whenever month changes
useEffect(() => {
const venueId = venue?._id || venue?.id;

if (!venueId) {
console.log("No venue id");
return;
}


dispatch(
fetchAvailability({
venueId,
month: currentMonth.getMonth() + 1,
year: currentMonth.getFullYear(),
})
);

}, [dispatch, venue, currentMonth]);

const handleDateSelect = (date) => {
if (!date) return;

const dateKey =
formatDateKey(date);
const dateKey = formatDateKey(date);

setSelectedDate(date);

Expand All @@ -35,13 +57,30 @@ export default function VenueAvailability({
});
};

return (
<section className="mt-6 rounded-2xl border bg-white p-6">
// Disable fully booked dates
const disabledDays = [
{
before: new Date(),
},
(date) => {
const key = formatDateKey(date);

return (
availabilityData?.[key]?.status === "booked"
);
},
];
const modifiers = {
partial: (date) =>
availabilityData?.[formatDateKey(date)]?.status === "partial",

booked: (date) =>
availabilityData?.[formatDateKey(date)]?.status === "booked",
};

{/* ======================================
HEADER
====================================== */}

return (
<section className="mt-6 rounded-2xl border bg-white p-6">
<h2 className="text-2xl font-bold">
Select Event Date
</h2>
Expand All @@ -53,49 +92,45 @@ export default function VenueAvailability({
</p>

<div className="mt-6">

{/* ======================================
CALENDAR
====================================== */}

<div className="rounded-xl border p-4">

<Calendar
mode="single"
month={currentMonth}
onMonthChange={setCurrentMonth}
selected={selectedDate}
onSelect={handleDateSelect}
disabled={{
before: new Date(),
}}
modifiers={modifiers}
disabled={[{ before: new Date() },modifiers.booked,]}
/>

</div>

{/* ======================================
SELECTED DATE
====================================== */}

{selectedDate && (

<div className="mt-5 rounded-xl border bg-gray-50 p-4">

<p className="text-sm text-gray-500">
Selected Event Date
</p>

<p className="mt-1 font-semibold">
{selectedDate.toLocaleDateString(
"en-GB"
)}
{selectedDate.toLocaleDateString("en-GB")}
</p>

{availabilityData?.[
formatDateKey(selectedDate)
] && (
<p className="mt-2 text-sm">
Status:{" "}
<span className="font-semibold capitalize">
{
availabilityData[
formatDateKey(selectedDate)
].status
}
</span>
</p>
)}
</div>

)}

</div>

</section>
);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,20 @@ const VenueDetailsForm = ({
onRemoveExistingImage,
errors = {},
}) => {
const handleImageChange = (event) => {
const files = Array.from(event.target.files || []);
const handleImageChange = (event) => {
const files = Array.from(event.target.files || []);

setImages(files);
};
setImages((prevImages) => [...prevImages, ...files]);

// Clear image validation error when images are added
setErrors((prev) => ({
...prev,
images: "",
}));

// Allow selecting the same file again if needed
event.target.value = "";
};

const handleLicenseChange = (event) => {
const file = event.target.files?.[0];
Expand Down
23 changes: 22 additions & 1 deletion client/src/presentation/pages/user/VenueDetails.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import VenueGallery from "@/presentation/components/user/venueDetails/VenueGalle
import VenueHeader from "@/presentation/components/user/venueDetails/VenueHeader";
import VenueAbout from "@/presentation/components/user/venueDetails/VenueAbout";
import { getVenueById } from "@/redux/slices/UserVenueSlice";
import { fetchAvailability } from "@/redux/slices/UserBookingSlice";
import BookingCard from "@/presentation/components/user/venueDetails/BookingCard";
import SimilarVenues from "@/presentation/components/user/venueDetails/SimilarVenues";
import VenueAvailability from "@/presentation/components/user/venueDetails/VenueAvailability";
Expand Down Expand Up @@ -40,6 +41,24 @@ export default function VenueDetails() {
}
}, [dispatch, id]);

useEffect(() => {
if (id) {
dispatch(
fetchAvailability({
venueId: id,
month: new Date().getMonth() + 1,
year: new Date().getFullYear(),
})
);
}
}, [dispatch, id]);

const {
availabilityData,
} = useSelector(
(state) => state.userBooking
);

return (
<>
<Header />
Expand Down Expand Up @@ -76,7 +95,9 @@ export default function VenueDetails() {
<div className="lg:col-span-2">
<VenueAbout description={selectedVenue.description} />
<VenueAmenities amenities={selectedVenue.amenities} />
<VenueAvailability venue={selectedVenue} onAvailabilityChange={setAvailability} />
<VenueAvailability venue={selectedVenue}
availability={availabilityData}
onAvailabilityChange={setAvailability} />
<VenueReviews rating={selectedVenue.rating}
reviews={selectedVenue.reviews} />
<HostedBy
Expand Down
Loading