forked from Somnia/SomniaRoomsApp
Add routes & navigation.
This commit is contained in:
@@ -5,25 +5,33 @@ import 'react-day-picker/dist/style.css';
|
||||
import { DatePickerWithRange } from "../ui/dateRange-picker";
|
||||
import { Button } from "../ui/button";
|
||||
import { SearchIcon } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { SearchFilter } from "@/model/SearchFilter";
|
||||
import { DateRange } from "react-day-picker";
|
||||
import { useToast } from "../ui/use-toast";
|
||||
import { useAppStore } from "@/store";
|
||||
import { useLocation } from "react-router-dom";
|
||||
|
||||
type funOnSearchClick = (newFilter: SearchFilter) => void;
|
||||
|
||||
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.
|
||||
const [searchFilter, setSearchFilter] = useState<SearchFilter>({
|
||||
dateRange: { from: new Date() }
|
||||
})
|
||||
const [searchFilter, setSearchFilter] = useState<SearchFilter>(appSearchFilter)
|
||||
|
||||
//App filter. Updated on btSearchClick.
|
||||
const setAppSearchFilter = useAppStore((state) => (state.setSearchFilter));
|
||||
//On location change, try to load searchFilter from state.
|
||||
//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.
|
||||
//TODOME: Add data validations and show messages.
|
||||
|
||||
@@ -1,22 +1,28 @@
|
||||
import { BookmarkIcon } from "@radix-ui/react-icons"
|
||||
import { ModeToggle } from "./mode-toggle"
|
||||
import { Button } from "./ui/button"
|
||||
import { Card, CardContent } from "./ui/card"
|
||||
import { Typography } from "./ui/typography"
|
||||
import { Link } from "react-router-dom"
|
||||
import { BookAIcon, HomeIcon } from "lucide-react"
|
||||
|
||||
function AppHeader() {
|
||||
|
||||
return (
|
||||
<Card className="flex items-center mx-10 my-4">
|
||||
<CardContent className="w-full">
|
||||
<div className="flex justify-around">
|
||||
<div className="flex flex-row items-center gap-2">
|
||||
<div className="flex justify-around items-center">
|
||||
<div className="flex flex-row items-center gap-2 relative">
|
||||
<img src="public/SR2.svg" className="w-[64px]"></img>
|
||||
<Typography variant={"largeText"}>Somnia Rooms</Typography>
|
||||
<a href="https://duck.com" className="absolute w-[100%] h-[100%]"></a>
|
||||
</div>
|
||||
<Button variant="ghost">
|
||||
<BookmarkIcon />
|
||||
<Typography variant={"largeText"}>Reservar</Typography>
|
||||
<HomeIcon />
|
||||
<Link to={`home`}>Home</Link>
|
||||
</Button>
|
||||
<Button variant="ghost">
|
||||
<BookAIcon />
|
||||
<Link to={`search`}>Reservar</Link>
|
||||
</Button>
|
||||
<ModeToggle />
|
||||
</div>
|
||||
|
||||
@@ -6,10 +6,18 @@ import { Separator } from "../ui/separator";
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "../ui/table";
|
||||
import { Button } from "../ui/button";
|
||||
|
||||
export function BookingDetails() {
|
||||
type OnBookingClickFunction = () => void;
|
||||
|
||||
export function BookingDetails({ onBookingConfirm }: { onBookingConfirm?: OnBookingClickFunction }) {
|
||||
|
||||
const bookingData = useAppStore((state) => state.newBookingData);
|
||||
|
||||
const onBtBookingClick = () => {
|
||||
if (onBookingConfirm) {
|
||||
onBookingConfirm();
|
||||
}
|
||||
}
|
||||
|
||||
if (!bookingData || bookingData.rooms.length <= 0) {
|
||||
return (
|
||||
<Card>
|
||||
@@ -72,7 +80,9 @@ export function BookingDetails() {
|
||||
<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>
|
||||
<Button className="my-2" onClick={onBtBookingClick}>
|
||||
<Typography variant={"largeText"} className="text-primary-foreground">Book it!</Typography>
|
||||
</Button>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
|
||||
@@ -6,6 +6,7 @@ import Root from './routes/Root';
|
||||
import ErrorPage from './error-page';
|
||||
import Homepage from './routes/home-page';
|
||||
import SearchPage from './routes/search-page';
|
||||
import BookPage from './routes/book-page';
|
||||
|
||||
const router = createBrowserRouter([
|
||||
{
|
||||
@@ -13,6 +14,10 @@ const router = createBrowserRouter([
|
||||
element: <Root />,
|
||||
errorElement: <ErrorPage />,
|
||||
children: [
|
||||
{
|
||||
path: "/",
|
||||
element: <Homepage />
|
||||
},
|
||||
{
|
||||
path: "/home",
|
||||
element: <Homepage />
|
||||
@@ -20,11 +25,17 @@ const router = createBrowserRouter([
|
||||
{
|
||||
path: "/search",
|
||||
element: <SearchPage />
|
||||
},
|
||||
{
|
||||
path: "/book",
|
||||
element: <BookPage />
|
||||
}
|
||||
]
|
||||
},
|
||||
]);
|
||||
|
||||
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||
<React.StrictMode>
|
||||
<RouterProvider router={router} />
|
||||
|
||||
@@ -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
|
||||
@@ -6,10 +6,17 @@ import { Separator } from "@/components/ui/separator"
|
||||
import { Skeleton } from "@/components/ui/skeleton"
|
||||
import { Typography } from "@/components/ui/typography"
|
||||
import { RoomCategory } from "@/model/RoomCategory"
|
||||
import { SearchFilter } from "@/model/SearchFilter"
|
||||
import { useNavigate } from "react-router-dom"
|
||||
|
||||
function Homepage() {
|
||||
|
||||
const { roomCategoryList, isLoading, isError } = useAPIRoomCategories();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const onBtSearchClick = (filter: SearchFilter) => {
|
||||
navigate("/search", {state: filter})
|
||||
}
|
||||
|
||||
const roomList = roomCategoryList?.map((element: RoomCategory) => {
|
||||
return (
|
||||
@@ -21,7 +28,7 @@ function Homepage() {
|
||||
<>
|
||||
<Typography variant={"h1"}>Hostal del Val</Typography>
|
||||
<Separator className="my-10" />
|
||||
<SearchFilterCard />
|
||||
<SearchFilterCard onSearchClick={onBtSearchClick}/>
|
||||
<Separator className="my-10" />
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
{roomList}
|
||||
|
||||
@@ -10,6 +10,7 @@ import { AvailabilityFilter } from "@/model/RoomSearch"
|
||||
import { SearchFilter } from "@/model/SearchFilter"
|
||||
import { useAppStore } from "@/store"
|
||||
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.
|
||||
function SearchPage() {
|
||||
@@ -17,6 +18,7 @@ function SearchPage() {
|
||||
//const [availabilityFilter, setAvailabilityFilter] = useState<AvailabilityFilter>();
|
||||
const searchFilter = useAppStore((state) => (state.searchFilter));
|
||||
const resetBooking = useAppStore((state) => (state.resetBookingState));
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [isSearched, setIsSearched] = useState<boolean>(false);
|
||||
|
||||
@@ -31,6 +33,10 @@ function SearchPage() {
|
||||
}
|
||||
}
|
||||
|
||||
const onBookingContinue = () => {
|
||||
navigate("/book");
|
||||
}
|
||||
|
||||
//This seems a little bit overkill, but IDK.
|
||||
const availabilityFilter: AvailabilityFilter | null = useMemo(
|
||||
() => {
|
||||
@@ -79,7 +85,7 @@ function SearchPage() {
|
||||
{hasRooms ? roomList : (isSearched && noRoomsAvailable)}
|
||||
</div>
|
||||
<Separator className="my-10" />
|
||||
<BookingDetails></BookingDetails>
|
||||
<BookingDetails onBookingConfirm={onBookingContinue}></BookingDetails>
|
||||
<Separator className="my-10" />
|
||||
<BackendConnectionStatus isLoading={isLoading} isError={isError} />
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user