Booking process - Add and remove rooms from booking.

This commit is contained in:
2024-05-09 21:47:12 +02:00
parent 630d5cb708
commit fe7122b107
5 changed files with 201 additions and 10 deletions
+26 -7
View File
@@ -10,18 +10,37 @@ import { DateRange } from "react-day-picker";
import { FareFilter } from "@/model/RoomSearch";
import { useAPIRoomPrices } from "@/api/api-roomSearch";
import { NumberSelector } from "../ui/number-selector";
import { NewBookingRoom } from "@/model/Bookings";
function RoomBooking({ roomCategoryId, availableAmount }: { roomCategoryId: number, availableAmount: number }) {
const [selectedAmount, setSelectedAmount] = useState<number>(0);
const [selectedAmount, setSelectedAmount] = useState<Map<number, number>>(new Map());
const currentDates: DateRange = useAppStore((state) => (state.searchFilter.dateRange));
const addNewRoom = useAppStore((state) => (state.addNewBookingRoom));
function onSelectedAmountUpdate(guestNumber: number, newCount: number) {
function onSelectedAmountUpdate(guestNumber: number, newCount: number, price: number) {
console.log("Room " + roomCategoryId + " Guestnumber: " + guestNumber + " Count: " + newCount);
setSelectedAmount(newCount);
const newAmountMap = new Map(selectedAmount);
newAmountMap.set(guestNumber, newCount);
setSelectedAmount(newAmountMap)
const newRoom: NewBookingRoom = {
roomCategory: roomCategoryId,
guestNumber: guestNumber,
amount: newCount,
price: price
};
addNewRoom(newRoom);
}
const canAddMore: boolean = availableAmount > selectedAmount;
const totalSelected = () => {
let sum = 0;
selectedAmount.forEach((v) => sum += v)
return sum;
};
const canAddMore: boolean = availableAmount > totalSelected();
//This seems a little bit overkill, but IDK.
const fareFilter: FareFilter | null = useMemo(
@@ -69,11 +88,11 @@ function RoomBooking({ roomCategoryId, availableAmount }: { roomCategoryId: numb
if (hasPrices) {
const tableRows = roomPriceList?.map((el) => {
return (
<TableRow>
<TableRow key={el.guestNumber}>
<TableCell>{el.guestNumber}</TableCell>
<TableCell>{el.price / 100} €</TableCell>
<TableCell>
<NumberSelector updateCount={(count) => onSelectedAmountUpdate(el.guestNumber, count)} addEnabled={canAddMore}></NumberSelector>
<NumberSelector updateCount={(count) => onSelectedAmountUpdate(el.guestNumber, count, el.price)} addEnabled={canAddMore}></NumberSelector>
</TableCell>
</TableRow>
);
@@ -116,7 +135,7 @@ function RoomBooking({ roomCategoryId, availableAmount }: { roomCategoryId: numb
{hasPrices ? priceTable : <Typography variant={"largeText"}>No Prices available</Typography>}
<div>
</div>
<p>Selected: {selectedAmount}</p>
<p>Selected: {totalSelected()}</p>
</CardContent>
</Card>
);
@@ -0,0 +1,79 @@
import { useAppStore } from "@/store"
import { Card, CardContent, CardHeader } from "../ui/card"
import { Typography } from "../ui/typography"
import { differenceInDays } from "date-fns";
import { Separator } from "../ui/separator";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "../ui/table";
import { Button } from "../ui/button";
export function BookingDetails() {
const bookingData = useAppStore((state) => state.newBookingData);
if (!bookingData || bookingData.rooms.length <= 0) {
return (
<Card>
<CardHeader>
<Typography variant={"h2"} as="h2">Your Booking</Typography>
</CardHeader>
<CardContent>
<Typography variant={"h3"}>No rooms added yet</Typography>
</CardContent>
</Card>
);
}
const roomList = bookingData.rooms.map((room) => {
return (
<TableRow key={room.roomCategory + "_" + room.guestNumber}>
<TableCell>{room.roomCategory}</TableCell>
<TableCell>{room.guestNumber}</TableCell>
<TableCell>{room.amount}</TableCell>
<TableCell>{room.price / 100} €</TableCell>
</TableRow>
);
})
const roomTable = (
<Table>
<TableHeader>
<TableRow>
<TableHead>Room</TableHead>
<TableHead>Guests</TableHead>
<TableHead>Quantity</TableHead>
<TableHead>Price</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{roomList}
</TableBody>
</Table>
);
const totalPrice = bookingData.rooms.reduce((acc, room) => (acc + room.price), 0);
return (
<Card>
<CardHeader>
<Typography variant={"h2"} as="h2">Your Booking</Typography>
</CardHeader>
<CardContent>
<Typography variant={"h3"}>Your Dates</Typography>
<Typography variant={"largeText"}>
Arrival: {bookingData.arrivalDate.toLocaleDateString()} -
Departure: {bookingData.departureDate.toLocaleDateString()} <br></br>
Number of nights: {differenceInDays(bookingData.departureDate, bookingData.arrivalDate)}
</Typography>
<Separator className="my-2"></Separator>
<Typography variant={"h3"}>Your Rooms</Typography>
{roomTable}
<Separator className="my-2"></Separator>
<Typography variant={"h3"}>Total Price</Typography>
<Typography variant={"h3"}>{totalPrice / 100} €</Typography>
<Button className="my-2"><Typography variant={"largeText"} className="text-primary-foreground">Book it!</Typography></Button>
</CardContent>
</Card>
)
}
+21
View File
@@ -0,0 +1,21 @@
export type NewBooking = {
arrivalDate: Date,
departureDate: Date,
customerDetails: NewBookingCustomerDetails,
rooms: NewBookingRoom[]
};
export type NewBookingCustomerDetails = {
name: string | null,
surname: string | null,
email: string | null,
phoneNumber: string | null
};
export type NewBookingRoom = {
roomCategory: number,
guestNumber: number,
amount: number,
price: number
};
+9 -1
View File
@@ -2,6 +2,7 @@ import { useAPIRoomAvailability } from "@/api/api-roomSearch"
import RoomBooking from "@/components/Rooms/room-booking"
import { SearchFilterCard } from "@/components/Search/SearchFilterCard"
import BackendConnectionStatus from "@/components/backend-conection-status"
import { BookingDetails } from "@/components/booking/booking-details"
import { Separator } from "@/components/ui/separator"
import { Skeleton } from "@/components/ui/skeleton"
import { Typography } from "@/components/ui/typography"
@@ -15,12 +16,19 @@ function SearchPage() {
//const [availabilityFilter, setAvailabilityFilter] = useState<AvailabilityFilter>();
const searchFilter = useAppStore((state) => (state.searchFilter));
const resetBooking = useAppStore((state) => (state.resetBookingState));
const [isSearched, setIsSearched] = useState<boolean>(false);
const onBtSearchClick = (newFilter: SearchFilter) => {
console.log("onBtSearchClick: ");
console.log(newFilter);
if (newFilter.dateRange && newFilter.dateRange.from && newFilter.dateRange.to) {
setIsSearched(true);
resetBooking(newFilter.dateRange.from, newFilter.dateRange.to);
}
}
//This seems a little bit overkill, but IDK.
@@ -71,7 +79,7 @@ function SearchPage() {
{hasRooms ? roomList : (isSearched && noRoomsAvailable)}
</div>
<Separator className="my-10" />
<RoomBooking key={99} availableAmount={5} roomCategoryId={6} />
<BookingDetails></BookingDetails>
<Separator className="my-10" />
<BackendConnectionStatus isLoading={isLoading} isError={isError} />
</div>
+65 -1
View File
@@ -1,16 +1,80 @@
import { create } from 'zustand'
import { SearchFilter } from './model/SearchFilter'
import { NewBooking, NewBookingRoom } from './model/Bookings'
interface AppState {
searchFilter: SearchFilter
setSearchFilter: (newFilter: SearchFilter) => void
newBookingData: NewBooking | null
setNewBooking: (newBooking: NewBooking) => void
resetBookingState: (arrival: Date, departure: Date) => void
addNewBookingRoom: (newRoom: NewBookingRoom) => void
}
const defaultSearchFilter: SearchFilter = {
dateRange: { from: new Date() }
}
const defaultNewBooking: NewBooking = {
arrivalDate: new Date(),
departureDate: new Date(),
customerDetails: {
name: null,
surname: null,
email: null,
phoneNumber: null
},
rooms: []
}
function getDefaultBookingData(arrivalDate: Date, departureDate: Date) {
return {
...defaultNewBooking,
arrivalDate: arrivalDate,
departureDate: departureDate
}
}
function addNewBookingRoomToCurrentState(newRoom: NewBookingRoom, currentState: NewBooking | null): NewBooking | null {
if (currentState == null) {
return currentState;
}
//Remove rooms with "same key".
const filteredRooms = currentState.rooms.filter((room) => {
const diffRoom = room.roomCategory != newRoom.roomCategory;
const diffAmount = room.guestNumber != newRoom.guestNumber;
if(diffRoom || (!diffRoom && diffAmount)) {
return true;
}
return false;
})
console.log(filteredRooms);
if (newRoom.amount > 0) {
filteredRooms.push(newRoom);
}
const newState: NewBooking = {
...currentState,
rooms: filteredRooms ?? []
}
console.log("AddRoomNewState:");
console.log(newState);
return newState;
}
export const useAppStore = create<AppState>()((set) => ({
searchFilter: defaultSearchFilter,
setSearchFilter: (newFilter) => set(() => ({ searchFilter: newFilter }))
setSearchFilter: (newFilter) => set(() => ({ searchFilter: newFilter })),
newBookingData: null,
setNewBooking: (newBooking) => set(() => ({ newBookingData: newBooking })),
resetBookingState: (arrival, departure) =>
set(() => ({ newBookingData: getDefaultBookingData(arrival, departure) })),
addNewBookingRoom: (newRoom: NewBookingRoom) =>
set((state) => ({ newBookingData: addNewBookingRoomToCurrentState(newRoom, state.newBookingData) }))
}))