Booking process - Add and remove rooms from booking.
This commit is contained in:
@@ -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>
|
||||
)
|
||||
}
|
||||
@@ -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
|
||||
};
|
||||
@@ -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
@@ -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) }))
|
||||
}))
|
||||
|
||||
Reference in New Issue
Block a user