General improvements in booking state management.
This commit is contained in:
@@ -7,7 +7,7 @@ import { IconWithTooltip } from "../ui/icon-number-tooltip";
|
|||||||
import defaultRoomImg from "@/res/SomniaRoomImage.svg";
|
import defaultRoomImg from "@/res/SomniaRoomImage.svg";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { Icon } from "@iconify-icon/react";
|
import { Icon } from "@iconify-icon/react";
|
||||||
import { useConfigVariable } from "@/utils/hooks";
|
import { useConfigVariable } from "@/utils/apiHooks";
|
||||||
import { eConfigVarKeys } from "@/model/ConfigVar";
|
import { eConfigVarKeys } from "@/model/ConfigVar";
|
||||||
|
|
||||||
interface RoomItemCardProps {
|
interface RoomItemCardProps {
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { useConfigVariable } from "@/utils/hooks";
|
|
||||||
import { Separator } from "./ui/separator";
|
import { Separator } from "./ui/separator";
|
||||||
import { Typography } from "./ui/typography";
|
import { Typography } from "./ui/typography";
|
||||||
import { eConfigVarKeys } from "@/model/ConfigVar";
|
import { eConfigVarKeys } from "@/model/ConfigVar";
|
||||||
@@ -9,6 +8,7 @@ import {
|
|||||||
import { Skeleton } from "./ui/skeleton";
|
import { Skeleton } from "./ui/skeleton";
|
||||||
import { Mail, Phone } from "lucide-react";
|
import { Mail, Phone } from "lucide-react";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
import { useConfigVariable } from "@/utils/apiHooks";
|
||||||
|
|
||||||
function AppFooter() {
|
function AppFooter() {
|
||||||
const { value: varCompanyLogo, isLoading: isLogoLoading } = useConfigVariable(
|
const { value: varCompanyLogo, isLoading: isLogoLoading } = useConfigVariable(
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { Link } from "react-router-dom";
|
|||||||
import { Bed, BookAIcon, HomeIcon } from "lucide-react";
|
import { Bed, BookAIcon, HomeIcon } from "lucide-react";
|
||||||
import { eConfigVarKeys } from "@/model/ConfigVar";
|
import { eConfigVarKeys } from "@/model/ConfigVar";
|
||||||
import { Skeleton } from "./ui/skeleton";
|
import { Skeleton } from "./ui/skeleton";
|
||||||
import { useConfigVariable } from "@/utils/hooks";
|
import { useConfigVariable } from "@/utils/apiHooks";
|
||||||
|
|
||||||
function AppHeader() {
|
function AppHeader() {
|
||||||
const { value: varCompanyLogo, isLoading: isLogoLoading } = useConfigVariable(
|
const { value: varCompanyLogo, isLoading: isLogoLoading } = useConfigVariable(
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import { useNavigate } from "react-router-dom";
|
|||||||
import { z } from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { eBookingState } from "@/utils/AppStateManager";
|
import { eBookingState } from "@/utils/AppStateManager";
|
||||||
|
import { useBookingStateDispacher } from "@/utils/hooks";
|
||||||
|
|
||||||
enum PageState {
|
enum PageState {
|
||||||
showForm,
|
showForm,
|
||||||
@@ -31,11 +32,11 @@ function BookPage() {
|
|||||||
const [pageState, setPageState] = useState<PageState>(PageState.showForm);
|
const [pageState, setPageState] = useState<PageState>(PageState.showForm);
|
||||||
const bookingData = useAppStore((state) => state.currentBooking);
|
const bookingData = useAppStore((state) => state.currentBooking);
|
||||||
const appBookingState = useAppStore((state) => state.bookingState);
|
const appBookingState = useAppStore((state) => state.bookingState);
|
||||||
const setAppBookingState = useAppStore((state) => state.setBookingState);
|
|
||||||
const setCustomerData = useAppStore(
|
const setCustomerData = useAppStore(
|
||||||
(state) => state.currentBookingSetCustomer,
|
(state) => state.currentBookingSetCustomer,
|
||||||
);
|
);
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const { setBookingStateBooked } = useBookingStateDispacher();
|
||||||
|
|
||||||
const bookingForm = useForm<z.infer<typeof BookingFormSchema>>({
|
const bookingForm = useForm<z.infer<typeof BookingFormSchema>>({
|
||||||
resolver: zodResolver(BookingFormSchema),
|
resolver: zodResolver(BookingFormSchema),
|
||||||
@@ -70,7 +71,7 @@ function BookPage() {
|
|||||||
if (rs.isError) {
|
if (rs.isError) {
|
||||||
setPageState(PageState.error);
|
setPageState(PageState.error);
|
||||||
} else {
|
} else {
|
||||||
setAppBookingState(eBookingState.Booked);
|
setBookingStateBooked();
|
||||||
navigate("/success", { state: rs.bookingResponse });
|
navigate("/success", { state: rs.bookingResponse });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
+19
-18
@@ -7,38 +7,36 @@ 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/InternalTypes";
|
import { SearchFilter } from "@/model/InternalTypes";
|
||||||
import { eBookingState } from "@/utils/AppStateManager";
|
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { LoaderIcon } from "lucide-react";
|
import { LoaderIcon } from "lucide-react";
|
||||||
import "./home-page.css";
|
import "./home-page.css";
|
||||||
import { useAppStore } from "@/store";
|
import { useAppStore } from "@/store";
|
||||||
import { isValidSearchFilter, makeDayUTCDate } from "@/utils/utils";
|
import { isValidSearchFilter } from "@/utils/utils";
|
||||||
import { useConfigVariable } from "@/utils/hooks";
|
import { useBookingStateDispacher } from "@/utils/hooks";
|
||||||
import { eConfigVarKeys } from "@/model/ConfigVar";
|
import { eConfigVarKeys } from "@/model/ConfigVar";
|
||||||
|
import { useConfigVariable } from "@/utils/apiHooks";
|
||||||
|
|
||||||
function Homepage() {
|
function Homepage() {
|
||||||
|
|
||||||
const appSearchFilter = useAppStore((state) => state.searchFilter);
|
const appSearchFilter = useAppStore((state) => state.searchFilter);
|
||||||
const setAppSearchFilter = useAppStore((state) => state.setSearchFilter);
|
|
||||||
const setAppBookingState = useAppStore((state) => state.setBookingState);
|
|
||||||
const initAppBooking = useAppStore((state) => state.initCurrentBooking);
|
|
||||||
|
|
||||||
const { value: varCompanyName } = useConfigVariable(eConfigVarKeys.varCompanyName, "");
|
|
||||||
const { roomCategoryList, isLoading: isLoadingCategories, isError } = useAPIRoomCategoryList();
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const { setBookingStateSearched } = useBookingStateDispacher();
|
||||||
|
|
||||||
|
const { value: varCompanyName } = useConfigVariable(
|
||||||
|
eConfigVarKeys.varCompanyName,
|
||||||
|
"",
|
||||||
|
);
|
||||||
|
const {
|
||||||
|
roomCategoryList,
|
||||||
|
isLoading: isLoadingCategories,
|
||||||
|
isError,
|
||||||
|
} = useAPIRoomCategoryList();
|
||||||
|
|
||||||
const onBtSearchClick = (filter: SearchFilter) => {
|
const onBtSearchClick = (filter: SearchFilter) => {
|
||||||
if (!isValidSearchFilter(filter)) {
|
if (!isValidSearchFilter(filter)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setAppSearchFilter(filter);
|
setBookingStateSearched(filter);
|
||||||
setAppBookingState(eBookingState.Searched);
|
|
||||||
|
|
||||||
initAppBooking(
|
|
||||||
makeDayUTCDate(filter.dateRange.from),
|
|
||||||
makeDayUTCDate(filter.dateRange.to),
|
|
||||||
);
|
|
||||||
|
|
||||||
navigate("/search", { state: filter });
|
navigate("/search", { state: filter });
|
||||||
};
|
};
|
||||||
@@ -67,7 +65,10 @@ function Homepage() {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<Separator />
|
<Separator />
|
||||||
<BackendConnectionStatus isLoading={isLoadingCategories} isError={isError} />
|
<BackendConnectionStatus
|
||||||
|
isLoading={isLoadingCategories}
|
||||||
|
isError={isError}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,21 +11,21 @@ import { eBookingState } from "@/utils/AppStateManager";
|
|||||||
import { useAppStore } from "@/store";
|
import { useAppStore } from "@/store";
|
||||||
import {
|
import {
|
||||||
isValidSearchFilter,
|
isValidSearchFilter,
|
||||||
makeDayUTCDate,
|
|
||||||
makeSearchPeriodRequestFromSearchFilter,
|
makeSearchPeriodRequestFromSearchFilter,
|
||||||
} from "@/utils/utils";
|
} from "@/utils/utils";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
|
import { useBookingStateDispacher } from "@/utils/hooks";
|
||||||
|
|
||||||
//TODOME: Al pulsar el botón "buscar", si ya existen datos en la reserva (se han añadido habitaciones) mostrar un cuadro de aviso de que si se busca se borrará la selección actual.
|
//TODOME: Al pulsar el botón "buscar", si ya existen datos en la reserva (se han añadido habitaciones) mostrar un cuadro de aviso de que si se busca se borrará la selección actual.
|
||||||
//TODOME: Mediante los estados globales de la reserva, si ya está en estado "booking" añadiendo los datos, mostrar un mensaje y permitir redirigir directamente para que continue donde lo dejó.
|
//TODOME: Mediante los estados globales de la reserva, si ya está en estado "booking" añadiendo los datos, mostrar un mensaje y permitir redirigir directamente para que continue donde lo dejó.
|
||||||
function SearchPage() {
|
function SearchPage() {
|
||||||
const appBookingState = useAppStore((state) => state.bookingState);
|
const appBookingState = useAppStore((state) => state.bookingState);
|
||||||
const setAppBookingState = useAppStore((state) => state.setBookingState);
|
|
||||||
const appSearchFilter = useAppStore((state) => state.searchFilter);
|
const appSearchFilter = useAppStore((state) => state.searchFilter);
|
||||||
const setAppSearchFilter = useAppStore((state) => state.setSearchFilter);
|
|
||||||
const initAppBooking = useAppStore((state) => state.initCurrentBooking);
|
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
const { setBookingStateSearched, setBookingStateBooking } =
|
||||||
|
useBookingStateDispacher();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
roomAvailabilityList,
|
roomAvailabilityList,
|
||||||
isLoading: isLoadingAvailability,
|
isLoading: isLoadingAvailability,
|
||||||
@@ -39,23 +39,16 @@ function SearchPage() {
|
|||||||
const hasRooms =
|
const hasRooms =
|
||||||
roomAvailabilityList?.length && roomAvailabilityList?.length > 0;
|
roomAvailabilityList?.length && roomAvailabilityList?.length > 0;
|
||||||
|
|
||||||
//TODOME: Hay que ver para mover esto a un método común.
|
|
||||||
const onBtSearchClick = (newFilter: SearchFilter) => {
|
const onBtSearchClick = (newFilter: SearchFilter) => {
|
||||||
if (!isValidSearchFilter(newFilter)) {
|
if (!isValidSearchFilter(newFilter)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setAppSearchFilter(newFilter);
|
setBookingStateSearched(newFilter);
|
||||||
setAppBookingState(eBookingState.Searched);
|
|
||||||
|
|
||||||
initAppBooking(
|
|
||||||
makeDayUTCDate(newFilter.dateRange.from),
|
|
||||||
makeDayUTCDate(newFilter.dateRange.to),
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const onBookingContinue = () => {
|
const onBookingContinue = () => {
|
||||||
setAppBookingState(eBookingState.Booking);
|
setBookingStateBooking();
|
||||||
navigate("/book");
|
navigate("/book");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,54 @@
|
|||||||
|
import { useAPIConfigVarList } from "@/api/api-configVars";
|
||||||
|
import { getConfigVarFromList } from "./utils";
|
||||||
|
import { eConfigVarKeys } from "@/model/ConfigVar";
|
||||||
|
|
||||||
import { useAPIRoomCategoryList } from "@/api/api-roomCategories";
|
import { useAPIRoomCategoryList } from "@/api/api-roomCategories";
|
||||||
import { useAPIRoomPrices } from "@/api/api-roomSearch";
|
import { useAPIRoomPrices } from "@/api/api-roomSearch";
|
||||||
import { RoomCategory } from "@/model/RoomCategory";
|
import { RoomCategory } from "@/model/RoomCategory";
|
||||||
import { RoomPrice, SearchPeriodRequest } from "@/model/RoomSearch";
|
import { RoomPrice, SearchPeriodRequest } from "@/model/RoomSearch";
|
||||||
|
|
||||||
|
export function useConfigVariable(
|
||||||
|
key: eConfigVarKeys,
|
||||||
|
defaultValue: string,
|
||||||
|
): {
|
||||||
|
value: string;
|
||||||
|
isLoading: boolean;
|
||||||
|
} {
|
||||||
|
const { configVarList, isLoading } = useAPIConfigVarList();
|
||||||
|
|
||||||
|
if (isLoading) {
|
||||||
|
return {
|
||||||
|
value: defaultValue,
|
||||||
|
isLoading: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const configVar = getConfigVarFromList(configVarList, key);
|
||||||
|
|
||||||
|
return { value: configVar?.value ?? defaultValue, isLoading: isLoading };
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useConfigVariableAsNumber(
|
||||||
|
key: eConfigVarKeys,
|
||||||
|
defaultValue: number,
|
||||||
|
): {
|
||||||
|
value: number;
|
||||||
|
isLoading: boolean;
|
||||||
|
} {
|
||||||
|
const rs = useConfigVariable(key, defaultValue.toString());
|
||||||
|
if (rs.isLoading) {
|
||||||
|
return {
|
||||||
|
value: defaultValue,
|
||||||
|
isLoading: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
value: parseFloat(rs.value),
|
||||||
|
isLoading: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export function useRoomCategory(roomCategoryId: number): {
|
export function useRoomCategory(roomCategoryId: number): {
|
||||||
value: RoomCategory | null;
|
value: RoomCategory | null;
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
|
|||||||
+35
-17
@@ -1,23 +1,41 @@
|
|||||||
import { useAPIConfigVarList } from "@/api/api-configVars";
|
import { SearchFilter } from "@/model/InternalTypes";
|
||||||
import { getConfigVarFromList } from "./utils";
|
import { useAppStore } from "@/store";
|
||||||
import { eConfigVarKeys } from "@/model/ConfigVar";
|
import { makeDayUTCDate } from "./utils";
|
||||||
|
import { useCallback } from "react";
|
||||||
|
import { eBookingState } from "./AppStateManager";
|
||||||
|
|
||||||
export function useConfigVariable(
|
export function useBookingStateDispacher(): {
|
||||||
key: eConfigVarKeys,
|
setBookingStateSearched: (sf: SearchFilter) => void;
|
||||||
defaultValue: string,
|
setBookingStateBooking: () => void;
|
||||||
): {
|
setBookingStateBooked: () => void;
|
||||||
value: string;
|
|
||||||
isLoading: boolean;
|
|
||||||
} {
|
} {
|
||||||
const { configVarList, isLoading } = useAPIConfigVarList();
|
const setAppBookingState = useAppStore((state) => state.setBookingState);
|
||||||
|
const setAppSearchFilter = useAppStore((state) => state.setSearchFilter);
|
||||||
|
const initAppBooking = useAppStore((state) => state.initCurrentBooking);
|
||||||
|
|
||||||
|
const fnSearched = useCallback(
|
||||||
|
(sf: SearchFilter) => {
|
||||||
|
setAppSearchFilter(sf);
|
||||||
|
setAppBookingState(eBookingState.Searched);
|
||||||
|
|
||||||
|
initAppBooking(
|
||||||
|
makeDayUTCDate(sf.dateRange.from),
|
||||||
|
makeDayUTCDate(sf.dateRange.to),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[setAppBookingState, setAppSearchFilter, initAppBooking],
|
||||||
|
);
|
||||||
|
|
||||||
|
const fnBooking = useCallback(() => {
|
||||||
|
setAppBookingState(eBookingState.Booking);
|
||||||
|
}, [setAppBookingState]);
|
||||||
|
const fnBooked = useCallback(() => {
|
||||||
|
setAppBookingState(eBookingState.Booked);
|
||||||
|
}, [setAppBookingState]);
|
||||||
|
|
||||||
if (isLoading) {
|
|
||||||
return {
|
return {
|
||||||
value: defaultValue,
|
setBookingStateSearched: fnSearched,
|
||||||
isLoading: true,
|
setBookingStateBooking: fnBooking,
|
||||||
|
setBookingStateBooked: fnBooked,
|
||||||
};
|
};
|
||||||
}
|
|
||||||
const configVar = getConfigVarFromList(configVarList, key);
|
|
||||||
|
|
||||||
return { value: configVar?.value ?? defaultValue, isLoading: isLoading };
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user