General improvements:

- Search control - Improved error messages.
- Fixed lint errors.
This commit is contained in:
2026-01-13 14:12:58 +01:00
parent 94312de6e2
commit b8ec6f7bdd
6 changed files with 42 additions and 24 deletions
+19 -10
View File
@@ -8,7 +8,6 @@ import { SearchIcon } from "lucide-react";
import { useState } from "react";
import { SearchFilter } from "@/model/InternalTypes";
import { DateRange } from "react-day-picker";
import { useToast } from "../ui/use-toast";
import { isValidSearchFilter } from "@/utils/utils";
import { useNavigate } from "react-router-dom";
import { ConstsNav, ConstsTexts } from "@/utils/Consts";
@@ -28,6 +27,7 @@ export function SearchFilterCard({
const [searchFilter, setSearchFilter] = useState<SearchFilter | null>(
initialsearchFilter ?? null,
);
const [errorMsg, setErrorMsg] = useState<string | null>(null);
const [isContactDialogOpen, setIsContactDialogOpen] =
useState<boolean>(false);
@@ -37,18 +37,12 @@ export function SearchFilterCard({
shouldShowContactDialog: nightCountShowDialog,
} = useCheckForNightCount(searchFilter);
const { toast } = useToast();
const navigate = useNavigate();
// Validate and call callback on btSearch click.
//TODOME: Show validation messages as form instead of toasts.
const btSearchClick = () => {
if (!isValidSearchFilter(searchFilter)) {
toast({
variant: "destructive",
title: "Uh oh! Invalid Search.",
description: "You should select a 'from' and 'to' dates",
});
setErrorMsg("Select a valid 'from' and 'to' dates!");
return;
}
@@ -76,10 +70,16 @@ export function SearchFilterCard({
// Handle internal Searchfilter updates.
const updateDateRange = (newRange: DateRange) => {
setSearchFilter({
const newSearchFilter = {
...searchFilter,
dateRange: newRange,
});
};
setSearchFilter(newSearchFilter);
if (isValidSearchFilter(newSearchFilter)) {
setErrorMsg(null);
}
};
const onContactDialogClose = () => {
@@ -110,6 +110,13 @@ export function SearchFilterCard({
></DatePickerWithRange>
);
const errorMsgLabel = (
<Typography variant={"errorText"} className="mt-2 text-lg">
{errorMsg}
</Typography>
);
const searchHasErrors = errorMsg != null;
return (
<>
<ContactUsDialog
@@ -125,11 +132,13 @@ export function SearchFilterCard({
</CardHeader>
<CardContent>
{datePickerElement}
{searchHasErrors && errorMsgLabel}
<Separator className="my-4" />
<Button
size={"lg"}
onClick={btSearchClick}
disabled={isSearchButtonDisabled}
variant={searchHasErrors ? "destructive" : "default"}
>
<SearchIcon className="me-2 text-primary-foreground" />
<Typography variant={"h3"} className="text-primary-foreground">
+3 -3
View File
@@ -90,7 +90,7 @@ export function DatePickerWithRange({
id="dateFrom"
variant="outline"
data-empty={!dateRange}
className="w-[100%] justify-start text-left font-normal data-[empty=true]:text-muted-foreground"
className="w-full justify-start text-left font-normal data-[empty=true]:text-muted-foreground"
>
<CalendarIcon />
{dateRange?.from ? (
@@ -117,11 +117,11 @@ export function DatePickerWithRange({
id="dateTo"
variant={"outline"}
data-empty={!dateRange}
className="w-[100%] justify-start text-left font-normal data-[empty=true]:text-muted-foreground"
className="w-full justify-start text-left font-normal data-[empty=true]:text-muted-foreground"
>
<CalendarIcon className="mr-2 h-4 w-4" />
{dateRange?.to ? (
format(dateRange.to, "LLL dd, y")
format(dateRange.to, "PPP")
) : (
<span>Pick a date</span>
)}
+4 -1
View File
@@ -24,6 +24,7 @@ const typographyVariants = cva("text-foreground", {
largeText: "text-lg font-semibold",
smallText: "text-sm leading-none font-medium",
mutedText: "text-muted-foreground text-sm",
errorText: "text-destructive text-sm font-normal",
},
},
defaultVariants: {
@@ -51,11 +52,13 @@ const variantElementMap: Record<
smallText: "small",
lead: "p",
mutedText: "p",
errorText: "p",
ul: "ul",
};
export interface TypographyProps
extends React.HTMLAttributes<HTMLElement>,
extends
React.HTMLAttributes<HTMLElement>,
VariantProps<typeof typographyVariants> {
asChild?: boolean;
as?: string;
+11 -8
View File
@@ -22,6 +22,7 @@ import { zodResolver } from "@hookform/resolvers/zod";
import { eBookingState } from "@/utils/AppStateManager";
import { useBookingStateDispacher } from "@/utils/hooks";
import { ConstsNav } from "@/utils/Consts";
import { NewBookingCustomerDetails } from "@/model/Bookings";
enum PageState {
showForm,
@@ -53,12 +54,13 @@ function BookPage() {
if (bookingData == null) {
return;
}
const newCustomerData = bookingData.customerDetails;
newCustomerData.name = values.name;
newCustomerData.surname = values.surname;
newCustomerData.email = values.email;
newCustomerData.phoneNumber = values.phone;
const newCustomerData: NewBookingCustomerDetails = {
...bookingData.customerDetails,
name: values.name,
surname: values.surname,
email: values.email,
phoneNumber: values.phone,
};
setCustomerData(newCustomerData);
setPageState(PageState.sending);
@@ -80,8 +82,9 @@ function BookPage() {
//Redirect to home if no booking is active.
if (
!appBookingState ||
appBookingState.state != eBookingState.Booking ||
!bookingData
!bookingData ||
(appBookingState.state != eBookingState.Booking &&
appBookingState.state != eBookingState.Booked)
) {
navigate(ConstsNav.page_Home);
}
+4 -1
View File
@@ -14,11 +14,14 @@ function SuccessPage() {
const location = useLocation();
const navigate = useNavigate();
if (pageState == null && location.state != null) {
setPageState(location.state);
}
useEffect(() => {
if (location.state == null) {
navigate(ConstsNav.page_Home);
}
setPageState(location.state);
}, [location, navigate]);
const handleBtBackClick = () => {
+1 -1
View File
@@ -13,7 +13,7 @@ export const ConstsNav = {
//TMP - The following texts should be replaced for a proper intl system.
export const ConstsTexts = {
navToContact_maxAllowedNightCount:
"We are sorry, but the selected date range is too large. Search on a smaller range or contact us for a personalized quote.",
"We are sorry, but the selected date range is too large. Search for a smaller range or contact us for a personalized quote.",
navToContact_maxAllowedGuestNumber:
"We are sorry, group bookings are not allowed. Contact us for a personalized quote.",
contactUsAlertDialog_title: "Contact us!",