General improvements in booking state management.

This commit is contained in:
2026-01-05 20:11:42 +01:00
parent 2b3d1eafd3
commit 5d2eb2e635
8 changed files with 113 additions and 54 deletions
+1 -1
View File
@@ -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 -1
View File
@@ -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(
+1 -1
View File
@@ -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(
+3 -2
View File
@@ -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
View File
@@ -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}
/>
</> </>
); );
} }
+6 -13
View File
@@ -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");
}; };
+46
View File
@@ -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
View File
@@ -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 };
} }