Skip to content

Commit

Permalink
preperation for big-calendar, a.k.a. CS "plachta" for a better use - …
Browse files Browse the repository at this point in the history
…global calendar overview
  • Loading branch information
filipc30 committed Jan 27, 2024
1 parent 44b2de0 commit 4f54dc8
Show file tree
Hide file tree
Showing 4 changed files with 267 additions and 12 deletions.
14 changes: 13 additions & 1 deletion app/components/calendar-helpers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -131,13 +131,25 @@ export function useCalendarsCommonLogic(monthsInPastAllowed?: boolean) {
<div>Su</div>
</div>
)
const daysTitlesBigCalendar = (
<div className="flex overflow-scroll">
<div className="text-foreground opacity-40 rounded-lg p-2 m-1">Mo</div>
<div className="text-foreground opacity-40 rounded-lg p-2 m-1">Tu</div>
<div className="text-foreground opacity-40 rounded-lg p-2 m-1">We</div>
<div className="text-foreground opacity-40 rounded-lg p-2 m-1">Th</div>
<div className="text-foreground opacity-40 rounded-lg p-2 m-1">Fr</div>
<div className="text-foreground opacity-40 rounded-lg p-2 m-1">Sa</div>
<div className="text-foreground opacity-40 rounded-lg p-2 m-1">Su</div>
</div>
)

return {
currentMonth,
selectedMonth,
selectedYear,
calendarNavigation,
daysTitles,
daysTitlesBigCalendar,
}
}

Expand All @@ -153,4 +165,4 @@ export function getDatesInBetween(startDate: Date, endDate: Date) {
}

return dates
}
}
113 changes: 113 additions & 0 deletions app/components/reservation-handlers-extensions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1212,3 +1212,116 @@ function getMultiNightDiscount(
// No discount found
return null
}

// room's calendar with dates availability preview
export function ReadOnlyReservationsBigCalendar({
roomReservations,
}: {
roomReservations: {
reservationDateFrom: string
reservationDateTo: string
}[]
}) {
const { calendarNavigation, daysTitlesBigCalendar, selectedMonth, selectedYear } =
useCalendarsCommonLogic()

// handling the rendered section of all the dates
const displayedCalendarDate = new Date()
displayedCalendarDate.setMonth(selectedMonth - 1)
displayedCalendarDate.setFullYear(selectedYear)
const selectedMonthDates = generateCalendar(displayedCalendarDate)

// handling existing reservations from db
const reservations = Object.values(roomReservations)
const reservationDatesFrom = reservations.map(reservation =>
format(new Date(reservation.reservationDateFrom), 'yyyy/M/d'),
)
const reservationDatesTo = reservations.map(reservation =>
format(new Date(reservation.reservationDateTo), 'yyyy/M/d'),
)
const reservationDatesBetween = reservations
.map(reservation =>
getDatesInBetween(
new Date(reservation.reservationDateFrom),
new Date(reservation.reservationDateTo),
).map(date => format(date, 'yyyy/M/d')),
)
.flat()

const calendarDates = selectedMonthDates.map(week =>
week.map((date, i) => {
const renderedFullDate =
date !== 0 ? selectedYear + '/' + selectedMonth + '/' + date : ''
let isDateCheckIn
let isDateCheckOut

let classList = daysInReservationCalendarClassList
if (date !== 0) {
if (addDays(new Date(), -1) >= new Date(renderedFullDate)) {
classList = disabledDaysInReservationCalendarClassList
} else {
isDateCheckIn = reservationDatesFrom.includes(renderedFullDate)
isDateCheckOut = reservationDatesTo.includes(renderedFullDate)

const isDateBetweenCheckInAndCheckOut =
reservationDatesBetween.includes(renderedFullDate)

if (isDateCheckIn && isDateCheckOut) {
classList = fullyBookedDaysInReservationCalendarClassList
} else {
if (
isDateCheckIn &&
isSameDay(new Date(), new Date(renderedFullDate))
) {
classList = fullyBookedDaysInReservationCalendarClassList
} else if (isDateCheckIn) {
classList = checkInDaysInReservationCalendarClassList
}
if (isDateCheckOut) {
classList = checkOutDaysInReservationCalendarClassList
}
if (isDateBetweenCheckInAndCheckOut) {
classList = fullyBookedDaysInReservationCalendarClassList
}
}
}
}

const dateButton =
date !== 0 ? (
<button
type="button"
key={i}
className={cn(
classList,
(isDateCheckIn || isDateCheckOut) &&
!(isDateCheckIn && isDateCheckOut) &&
!isSameDay(new Date(), new Date(renderedFullDate))
? highlightHoverClassList
: '',
)}
disabled={true}
>
<div className="flex flex-col">{date}</div>
</button>
) : (
<button type="button" disabled className="opacity-0" key={i}></button>
)

return dateButton
}),
)

return (
<>
{calendarNavigation}

<Spacer size="4xs" />
<div>
{daysTitlesBigCalendar}

<div className="flex overflow-scroll">{calendarDates}</div>
</div>
</>
)
}
93 changes: 93 additions & 0 deletions app/routes/admin+/reservations+/big-calendar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { json } from '@remix-run/node'
import {
Outlet,
useLoaderData,
} from '@remix-run/react'
import { GeneralErrorBoundary } from '#app/components/error-boundary.tsx'
import { ReadOnlyReservationsBigCalendar } from '#app/components/reservation-handlers-extensions.tsx'
import { prisma } from '#app/utils/db.server.ts'
import {
invariantResponse,
} from '#app/utils/misc.tsx'

export async function loader() {
const rooms = await prisma.room.findMany({
select: {
id: true,
url: true,
title: true,
price1: true,
price2: true,
price3: true,
additionalNightPrice1: true,
additionalNightPrice2: true,
additionalNightPrice3: true,
reservations: {
orderBy: {
createdAt: 'desc',
},
take: 50,
select: {
id: true,
status: true,
reservationNumber: true,
numberOfGuests: true,
numberOfNights: true,
name: true,
email: true,
reservationDateFrom: true,
reservationDateTo: true,
totalPrice: true,
message: true,
createdAt: true,
// nightPrice: true,
// additionalGuestNightPrice: true,
},
},
},
})
invariantResponse(rooms, 'Not found', { status: 404 })

return json({
rooms,
})
}

export default function RoomIdRoute() {
const data = useLoaderData<typeof loader>()

return (
<>
<div className="px-2 md:px-6 xl:mx-auto xl:max-w-[1200px] 2xl:max-w-[1300px] w-full">

{data.rooms.map((room, i) => (
<div key={i} className='mb-8'>
<ReadOnlyReservationsBigCalendar
roomReservations={room.reservations}
/>
</div>
))

}
</div>

<Outlet />
</>
)
}

export function ErrorBoundary() {
return (
<GeneralErrorBoundary
statusHandlers={{
404: ({ params }) => (
<div className="container mx-auto flex h-5/6 flex-col justify-center pb-32 pt-20 text-center">
<h3 className="text-h3">
No room with the id "{params.id}" exists
</h3>
</div>
),
}}
/>
)
}
59 changes: 48 additions & 11 deletions app/routes/admin.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ function SidebarMainNavLink({
<div
className={cn(
'group/item p-2 text-center capitalize lg:px-2 lg:py-3',
isActive ? 'rounded-xl lg:rounded-2xl bg-background text-foreground' : '',
isActive
? 'rounded-xl bg-background text-foreground lg:rounded-2xl'
: '',
)}
>
<Icon
Expand Down Expand Up @@ -94,7 +96,9 @@ function SidebarNavLink({
'capitalize',
isActive
? routeName !== 'rooms'
? 'bg-background font-bold text-highlight'
? routeName !== 'reservations'
? 'bg-background font-bold text-highlight'
: 'hover:bg-background hover:text-foreground'
: 'hover:bg-background hover:text-foreground'
: 'hover:bg-background hover:text-foreground',
)}
Expand Down Expand Up @@ -151,7 +155,7 @@ export default function AdminRoute() {
onMouseLeave={handleMouseOut}
>
<div className={cn(sidebarBoxBaseClasslist, 'py-1 lg:py-8')}>
<div className="text-center max-lg:hidden">logo</div>
<div className="text-center max-lg:hidden">Filapps</div>

<div className="custom-admin-sidebar-height flex w-full items-center justify-between gap-1 lg:flex-col 2xl:gap-2">
<SidebarMainNavLink
Expand All @@ -161,11 +165,42 @@ export default function AdminRoute() {
icon="dashboard"
/>

<SidebarMainNavLink
routeName="reservations"
title="bookings"
icon="calendar"
/>
<div className="group/bookings relative w-full">
<SidebarMainNavLink
title="bookings"
routeName="reservations"
icon="calendar"
/>

<div className="pointer-events-none absolute z-3001 group-hover/bookings:pointer-events-auto max-lg:bottom-16 max-lg:right-[-3rem] lg:left-full lg:top-[-50%]">
<div className="ml-4 rounded-2xl bg-foreground px-4 py-2 opacity-0 transition group-hover/bookings:opacity-100 dark:bg-black dark:text-foreground">
<div
className="max-lg:hidden"
style={{
content: "''",
position: 'absolute',
top: '5rem',
left: '-.6rem',
borderWidth: '13px',
borderStyle: 'solid',
borderColor:
'transparent #161414 transparent transparent',
}}
/>

<SidebarNavLink
routeName="reservations/big-calendar"
title="calendar"
icon="calendar"
/>
<SidebarNavLink
title="overview"
routeName="reservations"
icon="calendar"
/>
</div>
</div>
</div>

<div className="group/rooms relative w-full">
<SidebarMainNavLink routeName="rooms" icon="home" />
Expand Down Expand Up @@ -303,7 +338,7 @@ export default function AdminRoute() {
<div className="h-full w-full max-lg:hidden lg:w-[135px] xl:w-[145px] 2xl:w-[152px]" />

<div className="w-full pb-28 lg:pb-12 xl:pb-10">
<div className="relative my-6 max-lg:hidden lg:mx-2 flex items-center justify-between p-2 lg:mb-6">
<div className="relative my-6 flex items-center justify-between p-2 max-lg:hidden lg:mx-2 lg:mb-6">
<div className="flex gap-2 ">
<Icon
name="arrow-left"
Expand All @@ -319,11 +354,13 @@ export default function AdminRoute() {
/>
</div>

<Link to="/admin" className='hover:opacity-80 transition-opacity absolute left-1/2 lg:top-1/2 -translate-x-1/2 lg:-translate-y-1/2 text-h5 capitalize'>
<Link
to="/admin"
className="absolute left-1/2 -translate-x-1/2 text-h5 capitalize transition-opacity hover:opacity-80 lg:top-1/2 lg:-translate-y-1/2"
>
dashboard
</Link>


<UserDropdown />
</div>

Expand Down

0 comments on commit 4f54dc8

Please sign in to comment.