Add routes & navigation.

This commit is contained in:
2024-05-09 22:45:34 +02:00
parent fe7122b107
commit c753d1e9fa
7 changed files with 103 additions and 16 deletions
+15 -7
View File
@@ -5,25 +5,33 @@ import 'react-day-picker/dist/style.css';
import { DatePickerWithRange } from "../ui/dateRange-picker"; import { DatePickerWithRange } from "../ui/dateRange-picker";
import { Button } from "../ui/button"; import { Button } from "../ui/button";
import { SearchIcon } from "lucide-react"; import { SearchIcon } from "lucide-react";
import { useState } from "react"; import { useEffect, useState } from "react";
import { SearchFilter } from "@/model/SearchFilter"; import { SearchFilter } from "@/model/SearchFilter";
import { DateRange } from "react-day-picker"; import { DateRange } from "react-day-picker";
import { useToast } from "../ui/use-toast"; import { useToast } from "../ui/use-toast";
import { useAppStore } from "@/store"; import { useAppStore } from "@/store";
import { useLocation } from "react-router-dom";
type funOnSearchClick = (newFilter: SearchFilter) => void; type funOnSearchClick = (newFilter: SearchFilter) => void;
export function SearchFilterCard({ onSearchClick }: { onSearchClick?: funOnSearchClick }) { export function SearchFilterCard({ onSearchClick }: { onSearchClick?: funOnSearchClick }) {
const { toast } = useToast(); //App filter. Updated on btSearchClick.
const appSearchFilter = useAppStore((state) => (state.searchFilter));
const setAppSearchFilter = useAppStore((state) => (state.setSearchFilter));
//Local Filter state. //Local Filter state.
const [searchFilter, setSearchFilter] = useState<SearchFilter>({ const [searchFilter, setSearchFilter] = useState<SearchFilter>(appSearchFilter)
dateRange: { from: new Date() }
})
//App filter. Updated on btSearchClick. //On location change, try to load searchFilter from state.
const setAppSearchFilter = useAppStore((state) => (state.setSearchFilter)); //FIXME: Si llegamos sin state, hay que borrar el state global...
const location = useLocation();
useEffect(() => {
setSearchFilter(location.state);
}, [location]);
const { toast } = useToast();
// Validate and call callback on btSearch click. // Validate and call callback on btSearch click.
//TODOME: Add data validations and show messages. //TODOME: Add data validations and show messages.
+11 -5
View File
@@ -1,22 +1,28 @@
import { BookmarkIcon } from "@radix-ui/react-icons"
import { ModeToggle } from "./mode-toggle" import { ModeToggle } from "./mode-toggle"
import { Button } from "./ui/button" import { Button } from "./ui/button"
import { Card, CardContent } from "./ui/card" import { Card, CardContent } from "./ui/card"
import { Typography } from "./ui/typography" import { Typography } from "./ui/typography"
import { Link } from "react-router-dom"
import { BookAIcon, HomeIcon } from "lucide-react"
function AppHeader() { function AppHeader() {
return ( return (
<Card className="flex items-center mx-10 my-4"> <Card className="flex items-center mx-10 my-4">
<CardContent className="w-full"> <CardContent className="w-full">
<div className="flex justify-around"> <div className="flex justify-around items-center">
<div className="flex flex-row items-center gap-2"> <div className="flex flex-row items-center gap-2 relative">
<img src="public/SR2.svg" className="w-[64px]"></img> <img src="public/SR2.svg" className="w-[64px]"></img>
<Typography variant={"largeText"}>Somnia Rooms</Typography> <Typography variant={"largeText"}>Somnia Rooms</Typography>
<a href="https://duck.com" className="absolute w-[100%] h-[100%]"></a>
</div> </div>
<Button variant="ghost"> <Button variant="ghost">
<BookmarkIcon /> <HomeIcon />
<Typography variant={"largeText"}>Reservar</Typography> <Link to={`home`}>Home</Link>
</Button>
<Button variant="ghost">
<BookAIcon />
<Link to={`search`}>Reservar</Link>
</Button> </Button>
<ModeToggle /> <ModeToggle />
</div> </div>
+12 -2
View File
@@ -6,10 +6,18 @@ import { Separator } from "../ui/separator";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "../ui/table"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "../ui/table";
import { Button } from "../ui/button"; import { Button } from "../ui/button";
export function BookingDetails() { type OnBookingClickFunction = () => void;
export function BookingDetails({ onBookingConfirm }: { onBookingConfirm?: OnBookingClickFunction }) {
const bookingData = useAppStore((state) => state.newBookingData); const bookingData = useAppStore((state) => state.newBookingData);
const onBtBookingClick = () => {
if (onBookingConfirm) {
onBookingConfirm();
}
}
if (!bookingData || bookingData.rooms.length <= 0) { if (!bookingData || bookingData.rooms.length <= 0) {
return ( return (
<Card> <Card>
@@ -72,7 +80,9 @@ export function BookingDetails() {
<Separator className="my-2"></Separator> <Separator className="my-2"></Separator>
<Typography variant={"h3"}>Total Price</Typography> <Typography variant={"h3"}>Total Price</Typography>
<Typography variant={"h3"}>{totalPrice / 100} €</Typography> <Typography variant={"h3"}>{totalPrice / 100} €</Typography>
<Button className="my-2"><Typography variant={"largeText"} className="text-primary-foreground">Book it!</Typography></Button> <Button className="my-2" onClick={onBtBookingClick}>
<Typography variant={"largeText"} className="text-primary-foreground">Book it!</Typography>
</Button>
</CardContent> </CardContent>
</Card> </Card>
) )
+11
View File
@@ -6,6 +6,7 @@ import Root from './routes/Root';
import ErrorPage from './error-page'; import ErrorPage from './error-page';
import Homepage from './routes/home-page'; import Homepage from './routes/home-page';
import SearchPage from './routes/search-page'; import SearchPage from './routes/search-page';
import BookPage from './routes/book-page';
const router = createBrowserRouter([ const router = createBrowserRouter([
{ {
@@ -13,6 +14,10 @@ const router = createBrowserRouter([
element: <Root />, element: <Root />,
errorElement: <ErrorPage />, errorElement: <ErrorPage />,
children: [ children: [
{
path: "/",
element: <Homepage />
},
{ {
path: "/home", path: "/home",
element: <Homepage /> element: <Homepage />
@@ -20,11 +25,17 @@ const router = createBrowserRouter([
{ {
path: "/search", path: "/search",
element: <SearchPage /> element: <SearchPage />
},
{
path: "/book",
element: <BookPage />
} }
] ]
}, },
]); ]);
ReactDOM.createRoot(document.getElementById('root')!).render( ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode> <React.StrictMode>
<RouterProvider router={router} /> <RouterProvider router={router} />
+39
View File
@@ -0,0 +1,39 @@
import { BookingDetails } from "@/components/booking/booking-details"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { Separator } from "@/components/ui/separator"
import { Typography } from "@/components/ui/typography"
function BookPage() {
return (
<>
<Typography variant={"h1"}>Booking Details</Typography>
<Separator className="my-10" />
<div>
<Typography variant={"h3"}>Personal Details</Typography>
<div>
<Label>Name</Label>
<Input></Input>
<Label>Surname</Label>
<Input></Input>
<Label>Email</Label>
<Input></Input>
<Label>Phone Number</Label>
<Input></Input>
</div>
</div>
<Separator className="my-10" />
<BookingDetails></BookingDetails>
<Separator className="my-10" />
<Button>
<Typography variant={"h3"} className="text-primary-foreground">Book it now!</Typography>
</Button>
</>
)
}
export default BookPage
+8 -1
View File
@@ -6,10 +6,17 @@ import { Separator } from "@/components/ui/separator"
import { Skeleton } from "@/components/ui/skeleton" import { Skeleton } from "@/components/ui/skeleton"
import { Typography } from "@/components/ui/typography" import { Typography } from "@/components/ui/typography"
import { RoomCategory } from "@/model/RoomCategory" import { RoomCategory } from "@/model/RoomCategory"
import { SearchFilter } from "@/model/SearchFilter"
import { useNavigate } from "react-router-dom"
function Homepage() { function Homepage() {
const { roomCategoryList, isLoading, isError } = useAPIRoomCategories(); const { roomCategoryList, isLoading, isError } = useAPIRoomCategories();
const navigate = useNavigate();
const onBtSearchClick = (filter: SearchFilter) => {
navigate("/search", {state: filter})
}
const roomList = roomCategoryList?.map((element: RoomCategory) => { const roomList = roomCategoryList?.map((element: RoomCategory) => {
return ( return (
@@ -21,7 +28,7 @@ function Homepage() {
<> <>
<Typography variant={"h1"}>Hostal del Val</Typography> <Typography variant={"h1"}>Hostal del Val</Typography>
<Separator className="my-10" /> <Separator className="my-10" />
<SearchFilterCard /> <SearchFilterCard onSearchClick={onBtSearchClick}/>
<Separator className="my-10" /> <Separator className="my-10" />
<div className="grid grid-cols-2 gap-4"> <div className="grid grid-cols-2 gap-4">
{roomList} {roomList}
+7 -1
View File
@@ -10,6 +10,7 @@ import { AvailabilityFilter } from "@/model/RoomSearch"
import { SearchFilter } from "@/model/SearchFilter" import { SearchFilter } from "@/model/SearchFilter"
import { useAppStore } from "@/store" import { useAppStore } from "@/store"
import { useMemo, useState } from "react" import { useMemo, useState } from "react"
import { useNavigate } from "react-router-dom"
//TODOME: Igual podemos crear un StateMachine conjunta para los siguiente estados de la página: Sin Buscar, Sin disponibilidad, error, cargando. //TODOME: Igual podemos crear un StateMachine conjunta para los siguiente estados de la página: Sin Buscar, Sin disponibilidad, error, cargando.
function SearchPage() { function SearchPage() {
@@ -17,6 +18,7 @@ function SearchPage() {
//const [availabilityFilter, setAvailabilityFilter] = useState<AvailabilityFilter>(); //const [availabilityFilter, setAvailabilityFilter] = useState<AvailabilityFilter>();
const searchFilter = useAppStore((state) => (state.searchFilter)); const searchFilter = useAppStore((state) => (state.searchFilter));
const resetBooking = useAppStore((state) => (state.resetBookingState)); const resetBooking = useAppStore((state) => (state.resetBookingState));
const navigate = useNavigate();
const [isSearched, setIsSearched] = useState<boolean>(false); const [isSearched, setIsSearched] = useState<boolean>(false);
@@ -31,6 +33,10 @@ function SearchPage() {
} }
} }
const onBookingContinue = () => {
navigate("/book");
}
//This seems a little bit overkill, but IDK. //This seems a little bit overkill, but IDK.
const availabilityFilter: AvailabilityFilter | null = useMemo( const availabilityFilter: AvailabilityFilter | null = useMemo(
() => { () => {
@@ -79,7 +85,7 @@ function SearchPage() {
{hasRooms ? roomList : (isSearched && noRoomsAvailable)} {hasRooms ? roomList : (isSearched && noRoomsAvailable)}
</div> </div>
<Separator className="my-10" /> <Separator className="my-10" />
<BookingDetails></BookingDetails> <BookingDetails onBookingConfirm={onBookingContinue}></BookingDetails>
<Separator className="my-10" /> <Separator className="my-10" />
<BackendConnectionStatus isLoading={isLoading} isError={isError} /> <BackendConnectionStatus isLoading={isLoading} isError={isError} />
</div> </div>