fix: handle submit from summary bottom sheet
This commit is contained in:
@@ -11,7 +11,7 @@
|
|||||||
.enter-details-layout__content {
|
.enter-details-layout__content {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: var(--Spacing-x3) var(--Spacing-x9);
|
gap: var(--Spacing-x3) var(--Spacing-x9);
|
||||||
margin: var(--Spacing-x5) auto 0;
|
margin: var(--Spacing-x3) var(--Spacing-x2) 0;
|
||||||
/* simulates padding on viewport smaller than --max-width-navigation */
|
/* simulates padding on viewport smaller than --max-width-navigation */
|
||||||
width: min(
|
width: min(
|
||||||
calc(100dvw - (var(--Spacing-x2) * 2)),
|
calc(100dvw - (var(--Spacing-x2) * 2)),
|
||||||
@@ -31,6 +31,7 @@
|
|||||||
.enter-details-layout__content {
|
.enter-details-layout__content {
|
||||||
grid-template-columns: 1fr 340px;
|
grid-template-columns: 1fr 340px;
|
||||||
grid-template-rows: auto 1fr;
|
grid-template-rows: auto 1fr;
|
||||||
|
margin: var(--Spacing-x5) auto 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.enter-details-layout__summaryContainer {
|
.enter-details-layout__summaryContainer {
|
||||||
|
|||||||
@@ -45,6 +45,8 @@ import { BreakfastPackageEnum } from "@/types/enums/breakfast"
|
|||||||
const maxRetries = 40
|
const maxRetries = 40
|
||||||
const retryInterval = 2000
|
const retryInterval = 2000
|
||||||
|
|
||||||
|
export const formId = "submit-booking"
|
||||||
|
|
||||||
function isPaymentMethodEnum(value: string): value is PaymentMethodEnum {
|
function isPaymentMethodEnum(value: string): value is PaymentMethodEnum {
|
||||||
return Object.values(PaymentMethodEnum).includes(value as PaymentMethodEnum)
|
return Object.values(PaymentMethodEnum).includes(value as PaymentMethodEnum)
|
||||||
}
|
}
|
||||||
@@ -59,10 +61,13 @@ export default function Payment({
|
|||||||
const lang = useLang()
|
const lang = useLang()
|
||||||
const intl = useIntl()
|
const intl = useIntl()
|
||||||
const queryParams = useSearchParams()
|
const queryParams = useSearchParams()
|
||||||
const { userData, roomData } = useEnterDetailsStore((state) => ({
|
const { userData, roomData, setIsSubmittingDisabled } = useEnterDetailsStore(
|
||||||
|
(state) => ({
|
||||||
userData: state.userData,
|
userData: state.userData,
|
||||||
roomData: state.roomData,
|
roomData: state.roomData,
|
||||||
}))
|
setIsSubmittingDisabled: state.setIsSubmittingDisabled,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
const {
|
const {
|
||||||
firstName,
|
firstName,
|
||||||
@@ -119,6 +124,16 @@ export default function Payment({
|
|||||||
}
|
}
|
||||||
}, [bookingStatus, router])
|
}, [bookingStatus, router])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setIsSubmittingDisabled(
|
||||||
|
!methods.formState.isValid || methods.formState.isSubmitting
|
||||||
|
)
|
||||||
|
}, [
|
||||||
|
methods.formState.isValid,
|
||||||
|
methods.formState.isSubmitting,
|
||||||
|
setIsSubmittingDisabled,
|
||||||
|
])
|
||||||
|
|
||||||
function handleSubmit(data: PaymentFormData) {
|
function handleSubmit(data: PaymentFormData) {
|
||||||
const allQueryParams =
|
const allQueryParams =
|
||||||
queryParams.size > 0 ? `?${queryParams.toString()}` : ""
|
queryParams.size > 0 ? `?${queryParams.toString()}` : ""
|
||||||
@@ -209,6 +224,7 @@ export default function Payment({
|
|||||||
<form
|
<form
|
||||||
className={styles.paymentContainer}
|
className={styles.paymentContainer}
|
||||||
onSubmit={methods.handleSubmit(handleSubmit)}
|
onSubmit={methods.handleSubmit(handleSubmit)}
|
||||||
|
id={formId}
|
||||||
>
|
>
|
||||||
{mustBeGuaranteed ? (
|
{mustBeGuaranteed ? (
|
||||||
<section className={styles.section}>
|
<section className={styles.section}>
|
||||||
@@ -309,15 +325,16 @@ export default function Payment({
|
|||||||
</Caption>
|
</Caption>
|
||||||
</AriaLabel>
|
</AriaLabel>
|
||||||
</section>
|
</section>
|
||||||
|
<div className={styles.submitButton}>
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
className={styles.submitButton}
|
|
||||||
disabled={
|
disabled={
|
||||||
!methods.formState.isValid || methods.formState.isSubmitting
|
!methods.formState.isValid || methods.formState.isSubmitting
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{intl.formatMessage({ id: "Complete booking & go to payment" })}
|
{intl.formatMessage({ id: "Complete booking" })}
|
||||||
</Button>
|
</Button>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</FormProvider>
|
</FormProvider>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.submitButton {
|
.submitButton {
|
||||||
align-self: flex-start;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.paymentContainer .link {
|
.paymentContainer .link {
|
||||||
@@ -31,3 +31,10 @@
|
|||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
gap: var(--Spacing-x-one-and-half);
|
gap: var(--Spacing-x-one-and-half);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 1367px) {
|
||||||
|
.submitButton {
|
||||||
|
display: flex;
|
||||||
|
align-self: flex-start;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
gap: var(--Spacing-x-one-and-half);
|
gap: var(--Spacing-x-one-and-half);
|
||||||
padding-top: var(--Spacing-x3);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.main {
|
.main {
|
||||||
@@ -67,6 +66,7 @@
|
|||||||
@media screen and (min-width: 1367px) {
|
@media screen and (min-width: 1367px) {
|
||||||
.wrapper {
|
.wrapper {
|
||||||
gap: var(--Spacing-x3);
|
gap: var(--Spacing-x3);
|
||||||
|
padding-top: var(--Spacing-x3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.iconWrapper {
|
.iconWrapper {
|
||||||
|
|||||||
@@ -13,8 +13,6 @@
|
|||||||
grid-template-columns: 1fr auto;
|
grid-template-columns: 1fr auto;
|
||||||
padding: var(--Spacing-x2) var(--Spacing-x3) var(--Spacing-x5)
|
padding: var(--Spacing-x2) var(--Spacing-x3) var(--Spacing-x5)
|
||||||
var(--Spacing-x3);
|
var(--Spacing-x3);
|
||||||
justify-content: space-between;
|
|
||||||
width: auto;
|
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
transition: 0.5s ease-in-out;
|
transition: 0.5s ease-in-out;
|
||||||
}
|
}
|
||||||
@@ -24,11 +22,9 @@
|
|||||||
border: none;
|
border: none;
|
||||||
background: none;
|
background: none;
|
||||||
text-align: start;
|
text-align: start;
|
||||||
opacity: 1;
|
transition: padding 0.5s ease-in-out;
|
||||||
transition:
|
|
||||||
opacity 0.5s ease-in-out,
|
|
||||||
padding 0.5s ease-in-out;
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wrapper[data-open="true"] {
|
.wrapper[data-open="true"] {
|
||||||
@@ -36,15 +32,39 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.wrapper[data-open="true"] .bottomSheet {
|
.wrapper[data-open="true"] .bottomSheet {
|
||||||
grid-template-columns: 0fr 1fr;
|
grid-template-columns: 0fr auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wrapper[data-open="true"] .priceDetailsButton {
|
.wrapper[data-open="true"] .priceDetailsButton {
|
||||||
|
animation: fadeOut 0.3s ease-out;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.wrapper[data-open="false"] .priceDetailsButton {
|
||||||
|
animation: fadeIn 0.8s ease-in;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.content,
|
.content,
|
||||||
.priceDetailsButton {
|
.priceDetailsButton {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes fadeIn {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeOut {
|
||||||
|
from {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
import { PropsWithChildren, useState } from "react"
|
import { PropsWithChildren } from "react"
|
||||||
import { useIntl } from "react-intl"
|
import { useIntl } from "react-intl"
|
||||||
|
|
||||||
import { useEnterDetailsStore } from "@/stores/enter-details"
|
import { useEnterDetailsStore } from "@/stores/enter-details"
|
||||||
@@ -9,18 +9,20 @@ import Button from "@/components/TempDesignSystem/Button"
|
|||||||
import Caption from "@/components/TempDesignSystem/Text/Caption"
|
import Caption from "@/components/TempDesignSystem/Text/Caption"
|
||||||
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
|
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
|
||||||
|
|
||||||
|
import { formId } from "../../Payment"
|
||||||
|
|
||||||
import styles from "./bottomSheet.module.css"
|
import styles from "./bottomSheet.module.css"
|
||||||
|
|
||||||
export function SummaryBottomSheet({ children }: PropsWithChildren) {
|
export function SummaryBottomSheet({ children }: PropsWithChildren) {
|
||||||
const intl = useIntl()
|
const intl = useIntl()
|
||||||
|
|
||||||
const { isSummaryOpen, toggleSummaryOpen, totalPrice } = useEnterDetailsStore(
|
const { isSummaryOpen, toggleSummaryOpen, totalPrice, isSubmittingDisabled } =
|
||||||
(state) => ({
|
useEnterDetailsStore((state) => ({
|
||||||
isSummaryOpen: state.isSummaryOpen,
|
isSummaryOpen: state.isSummaryOpen,
|
||||||
toggleSummaryOpen: state.toggleSummaryOpen,
|
toggleSummaryOpen: state.toggleSummaryOpen,
|
||||||
totalPrice: state.totalPrice,
|
totalPrice: state.totalPrice,
|
||||||
})
|
isSubmittingDisabled: state.isSubmittingDisabled,
|
||||||
)
|
}))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.wrapper} data-open={isSummaryOpen}>
|
<div className={styles.wrapper} data-open={isSummaryOpen}>
|
||||||
@@ -45,7 +47,13 @@ export function SummaryBottomSheet({ children }: PropsWithChildren) {
|
|||||||
{intl.formatMessage({ id: "See details" })}
|
{intl.formatMessage({ id: "See details" })}
|
||||||
</Caption>
|
</Caption>
|
||||||
</button>
|
</button>
|
||||||
<Button intent="primary" size="large" type="submit">
|
<Button
|
||||||
|
intent="primary"
|
||||||
|
size="large"
|
||||||
|
type="submit"
|
||||||
|
disabled={isSubmittingDisabled}
|
||||||
|
form={formId}
|
||||||
|
>
|
||||||
{intl.formatMessage({ id: "Complete booking" })}
|
{intl.formatMessage({ id: "Complete booking" })}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ interface EnterDetailsState {
|
|||||||
selectRateUrl: string
|
selectRateUrl: string
|
||||||
currentStep: StepEnum
|
currentStep: StepEnum
|
||||||
totalPrice: TotalPrice
|
totalPrice: TotalPrice
|
||||||
|
isSubmittingDisabled: boolean
|
||||||
isSummaryOpen: boolean
|
isSummaryOpen: boolean
|
||||||
isValid: Record<StepEnum, boolean>
|
isValid: Record<StepEnum, boolean>
|
||||||
completeStep: (updatedData: Partial<EnterDetailsState["userData"]>) => void
|
completeStep: (updatedData: Partial<EnterDetailsState["userData"]>) => void
|
||||||
@@ -51,6 +52,7 @@ interface EnterDetailsState {
|
|||||||
setCurrentStep: (step: StepEnum) => void
|
setCurrentStep: (step: StepEnum) => void
|
||||||
toggleSummaryOpen: () => void
|
toggleSummaryOpen: () => void
|
||||||
setTotalPrice: (totalPrice: TotalPrice) => void
|
setTotalPrice: (totalPrice: TotalPrice) => void
|
||||||
|
setIsSubmittingDisabled: (isSubmittingDisabled: boolean) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export function initEditDetailsState(
|
export function initEditDetailsState(
|
||||||
@@ -143,6 +145,7 @@ export function initEditDetailsState(
|
|||||||
euro: { price: 0, currency: "" },
|
euro: { price: 0, currency: "" },
|
||||||
},
|
},
|
||||||
isSummaryOpen: false,
|
isSummaryOpen: false,
|
||||||
|
isSubmittingDisabled: false,
|
||||||
setCurrentStep: (step) => set({ currentStep: step }),
|
setCurrentStep: (step) => set({ currentStep: step }),
|
||||||
navigate: (step, updatedData) =>
|
navigate: (step, updatedData) =>
|
||||||
set(
|
set(
|
||||||
@@ -182,6 +185,8 @@ export function initEditDetailsState(
|
|||||||
),
|
),
|
||||||
toggleSummaryOpen: () => set({ isSummaryOpen: !get().isSummaryOpen }),
|
toggleSummaryOpen: () => set({ isSummaryOpen: !get().isSummaryOpen }),
|
||||||
setTotalPrice: (totalPrice) => set({ totalPrice: totalPrice }),
|
setTotalPrice: (totalPrice) => set({ totalPrice: totalPrice }),
|
||||||
|
setIsSubmittingDisabled: (isSubmittingDisabled) =>
|
||||||
|
set({ isSubmittingDisabled }),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user