fix: SW-1102 show error on invalid entry
This commit is contained in:
@@ -29,23 +29,17 @@ export default function SearchList({
|
|||||||
}: SearchListProps) {
|
}: SearchListProps) {
|
||||||
const intl = useIntl()
|
const intl = useIntl()
|
||||||
const [hasMounted, setHasMounted] = useState(false)
|
const [hasMounted, setHasMounted] = useState(false)
|
||||||
const [isFormSubmitted, setIsFormSubmitted] = useState(false)
|
|
||||||
const {
|
const {
|
||||||
clearErrors,
|
clearErrors,
|
||||||
formState: { errors, isSubmitted },
|
formState: { errors, isSubmitted },
|
||||||
} = useFormContext()
|
} = useFormContext()
|
||||||
const searchError = errors["search"]
|
const searchError = errors["search"]
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setIsFormSubmitted(isSubmitted)
|
|
||||||
}, [isSubmitted])
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let timeoutID: ReturnType<typeof setTimeout> | null = null
|
let timeoutID: ReturnType<typeof setTimeout> | null = null
|
||||||
if (searchError && searchError.message === "Required") {
|
if (searchError) {
|
||||||
timeoutID = setTimeout(() => {
|
timeoutID = setTimeout(() => {
|
||||||
clearErrors("search")
|
clearErrors("search")
|
||||||
setIsFormSubmitted(false)
|
|
||||||
// magic number originates from animation
|
// magic number originates from animation
|
||||||
// 5000ms delay + 120ms exectuion
|
// 5000ms delay + 120ms exectuion
|
||||||
}, 5120)
|
}, 5120)
|
||||||
@@ -66,7 +60,7 @@ export default function SearchList({
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
if (searchError && isFormSubmitted) {
|
if (searchError && isSubmitted) {
|
||||||
if (typeof searchError.message === "string") {
|
if (typeof searchError.message === "string") {
|
||||||
if (!isOpen) {
|
if (!isOpen) {
|
||||||
if (searchError.message === "Required") {
|
if (searchError.message === "Required") {
|
||||||
@@ -87,6 +81,24 @@ export default function SearchList({
|
|||||||
</Body>
|
</Body>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
)
|
)
|
||||||
|
} else if (searchError.type === "custom") {
|
||||||
|
return (
|
||||||
|
<Dialog
|
||||||
|
className={styles.fadeOut}
|
||||||
|
getMenuProps={getMenuProps}
|
||||||
|
variant="error"
|
||||||
|
>
|
||||||
|
<Caption className={styles.heading} color="red">
|
||||||
|
<ErrorCircleIcon color="red" />
|
||||||
|
{intl.formatMessage({ id: "No results" })}
|
||||||
|
</Caption>
|
||||||
|
<Body>
|
||||||
|
{intl.formatMessage({
|
||||||
|
id: "We couldn't find a matching location for your search.",
|
||||||
|
})}
|
||||||
|
</Body>
|
||||||
|
</Dialog>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ import type { Location } from "@/types/trpc/routers/hotel/locations"
|
|||||||
|
|
||||||
const name = "search"
|
const name = "search"
|
||||||
export default function Search({ locations }: SearchProps) {
|
export default function Search({ locations }: SearchProps) {
|
||||||
const { register, setValue, trigger } = useFormContext<BookingWidgetSchema>()
|
const { register, setValue, trigger, unregister } =
|
||||||
|
useFormContext<BookingWidgetSchema>()
|
||||||
const intl = useIntl()
|
const intl = useIntl()
|
||||||
const value = useWatch({ name })
|
const value = useWatch({ name })
|
||||||
const [state, dispatch] = useReducer(
|
const [state, dispatch] = useReducer(
|
||||||
@@ -135,6 +136,27 @@ export default function Search({ locations }: SearchProps) {
|
|||||||
}
|
}
|
||||||
}, [dispatch])
|
}, [dispatch])
|
||||||
|
|
||||||
|
const stayType = state.searchData?.type === "cities" ? "city" : "hotel"
|
||||||
|
const stayValue =
|
||||||
|
(value === state.searchData?.name &&
|
||||||
|
((state.searchData?.type === "cities" && state.searchData?.name) ||
|
||||||
|
state.searchData?.id)) ||
|
||||||
|
""
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (stayType === "city") {
|
||||||
|
unregister("hotel")
|
||||||
|
setValue(stayType, stayValue, {
|
||||||
|
shouldValidate: true,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
unregister("city")
|
||||||
|
setValue(stayType, Number(stayValue), {
|
||||||
|
shouldValidate: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, [stayType, stayValue, unregister, setValue])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Downshift
|
<Downshift
|
||||||
initialSelectedItem={state.searchData}
|
initialSelectedItem={state.searchData}
|
||||||
@@ -155,6 +177,10 @@ export default function Search({ locations }: SearchProps) {
|
|||||||
openMenu,
|
openMenu,
|
||||||
}) => (
|
}) => (
|
||||||
<div className={styles.container}>
|
<div className={styles.container}>
|
||||||
|
{value ? (
|
||||||
|
// Adding hidden input to define hotel or city based on destination selection for basic form submit.
|
||||||
|
<input type="hidden" {...register(stayType)} />
|
||||||
|
) : null}
|
||||||
<label {...getLabelProps({ htmlFor: name })} className={styles.label}>
|
<label {...getLabelProps({ htmlFor: name })} className={styles.label}>
|
||||||
<Caption
|
<Caption
|
||||||
type="bold"
|
type="bold"
|
||||||
|
|||||||
@@ -35,30 +35,37 @@ export const guestRoomSchema = z
|
|||||||
|
|
||||||
export const guestRoomsSchema = z.array(guestRoomSchema)
|
export const guestRoomsSchema = z.array(guestRoomSchema)
|
||||||
|
|
||||||
export const bookingWidgetSchema = z.object({
|
export const bookingWidgetSchema = z
|
||||||
bookingCode: z.string(), // Update this as required when working with booking codes component
|
.object({
|
||||||
date: z.object({
|
bookingCode: z.string(), // Update this as required when working with booking codes component
|
||||||
// Update this as required once started working with Date picker in Nights component
|
date: z.object({
|
||||||
fromDate: z.string(),
|
// Update this as required once started working with Date picker in Nights component
|
||||||
toDate: z.string(),
|
fromDate: z.string(),
|
||||||
}),
|
toDate: z.string(),
|
||||||
location: z.string().refine(
|
}),
|
||||||
(value) => {
|
location: z.string().refine(
|
||||||
if (value) {
|
(value) => {
|
||||||
const parsedValue: Location = JSON.parse(decodeURIComponent(value))
|
if (value) {
|
||||||
switch (parsedValue?.type) {
|
const parsedValue: Location = JSON.parse(decodeURIComponent(value))
|
||||||
case "cities":
|
switch (parsedValue?.type) {
|
||||||
case "hotels":
|
case "cities":
|
||||||
return true
|
case "hotels":
|
||||||
default:
|
return true
|
||||||
return false
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
},
|
{ message: "Required" }
|
||||||
{ message: "Required" }
|
),
|
||||||
),
|
redemption: z.boolean().default(false),
|
||||||
redemption: z.boolean().default(false),
|
rooms: guestRoomsSchema,
|
||||||
rooms: guestRoomsSchema,
|
search: z.string({ coerce: true }).min(1, "Required"),
|
||||||
search: z.string({ coerce: true }).min(1, "Required"),
|
voucher: z.boolean().default(false),
|
||||||
voucher: z.boolean().default(false),
|
hotel: z.number().optional(),
|
||||||
})
|
city: z.string().optional(),
|
||||||
|
})
|
||||||
|
.refine((value) => value.hotel || value.city, {
|
||||||
|
message: "Destination required",
|
||||||
|
path: ["search"],
|
||||||
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user