Merged in feat/enter-details-multiroom (pull request #1280)
feat(SW-1259): Enter details multiroom * refactor: remove per-step URLs * WIP: map multiroom data * fix: lint errors in details page * fix: made useEnterDetailsStore tests pass * fix: WIP refactor enter details store * fix: WIP enter details store update * fix: added room index to select correct room * fix: added logic for navigating between steps and rooms * fix: update summary to work with store changes * fix: added room and total price calculation * fix: removed unused code and added test for breakfast included * refactor: move store selectors into helpers * refactor: session storage state for multiroom booking * feat: update enter details accordion navigation * fix: added room index to each form component so they select correct room * fix: added unique id to input to handle case when multiple inputs have same name * fix: update payment step with store changes * fix: rebase issues * fix: now you should only be able to go to a step if previous room is completed * refactor: cleanup * fix: if no availability just skip that room for now * fix: add select-rate Summary and adjust typings Approved-by: Arvid Norlin
This commit is contained in:
committed by
Arvid Norlin
parent
f43ee4a0e6
commit
b394d54c3f
@@ -3,8 +3,14 @@ import { useEffect, useState } from "react"
|
||||
import { useIntl } from "react-intl"
|
||||
|
||||
import { useEnterDetailsStore } from "@/stores/enter-details"
|
||||
import {
|
||||
selectBookingProgress,
|
||||
selectNextStep,
|
||||
selectRoom,
|
||||
selectRoomStatus,
|
||||
} from "@/stores/enter-details/helpers"
|
||||
|
||||
import { CheckIcon, ChevronDownIcon } from "@/components/Icons"
|
||||
import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "@/components/Icons"
|
||||
import Footnote from "@/components/TempDesignSystem/Text/Footnote"
|
||||
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
|
||||
import useScrollToActiveSection from "@/hooks/booking/useScrollToActiveSection"
|
||||
@@ -19,24 +25,31 @@ export default function SectionAccordion({
|
||||
header,
|
||||
label,
|
||||
step,
|
||||
roomIndex,
|
||||
}: React.PropsWithChildren<SectionAccordionProps>) {
|
||||
const intl = useIntl()
|
||||
const currentStep = useEnterDetailsStore((state) => state.currentStep)
|
||||
const steps = useEnterDetailsStore((state) => state.steps)
|
||||
const roomStatus = useEnterDetailsStore((state) =>
|
||||
selectRoomStatus(state, roomIndex)
|
||||
)
|
||||
|
||||
const setStep = useEnterDetailsStore((state) => state.actions.setStep)
|
||||
const { bedType, breakfast } = useEnterDetailsStore((state) =>
|
||||
selectRoom(state, roomIndex)
|
||||
)
|
||||
const { roomStatuses, currentRoomIndex } = useEnterDetailsStore((state) =>
|
||||
selectBookingProgress(state)
|
||||
)
|
||||
|
||||
const [isComplete, setIsComplete] = useState(false)
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
const isValid = useEnterDetailsStore((state) => state.isValid[step])
|
||||
const navigate = useEnterDetailsStore((state) => state.actions.navigate)
|
||||
const { bedType, breakfast } = useEnterDetailsStore((state) => ({
|
||||
bedType: state.bedType,
|
||||
breakfast: state.breakfast,
|
||||
}))
|
||||
const isValid = roomStatus.steps[step]?.isValid ?? false
|
||||
|
||||
const [title, setTitle] = useState(label)
|
||||
|
||||
const noBreakfastTitle = intl.formatMessage({ id: "No breakfast" })
|
||||
const breakfastTitle = intl.formatMessage({ id: "Breakfast buffet" })
|
||||
|
||||
useScrollToActiveSection(step, steps, currentStep === step)
|
||||
// useScrollToActiveSection(step, steps, roomStatus.currentStep === step)
|
||||
|
||||
useEffect(() => {
|
||||
if (step === StepEnum.selectBed && bedType) {
|
||||
@@ -57,11 +70,29 @@ export default function SectionAccordion({
|
||||
}, [isValid, setIsComplete])
|
||||
|
||||
useEffect(() => {
|
||||
setIsOpen(currentStep === step)
|
||||
}, [currentStep, setIsOpen, step])
|
||||
setIsOpen(roomStatus.currentStep === step && currentRoomIndex === roomIndex)
|
||||
}, [currentRoomIndex, roomIndex, roomStatus.currentStep, setIsOpen, step])
|
||||
|
||||
function onModify() {
|
||||
navigate(step)
|
||||
setStep(step, roomIndex)
|
||||
}
|
||||
|
||||
function close() {
|
||||
setIsOpen(false)
|
||||
const isLastStep = step === StepEnum.details
|
||||
const hasNextRoom = roomIndex + 1 <= roomStatuses.length
|
||||
|
||||
if (!isLastStep) {
|
||||
const nextStep = selectNextStep(roomStatus)
|
||||
if (nextStep) {
|
||||
setStep(nextStep, roomIndex)
|
||||
}
|
||||
} else if (isLastStep && hasNextRoom) {
|
||||
setStep(StepEnum.selectBed, roomIndex + 1)
|
||||
} else {
|
||||
// Time for payment, collapse any open step
|
||||
setStep(null)
|
||||
}
|
||||
}
|
||||
|
||||
const textColor =
|
||||
@@ -81,7 +112,7 @@ export default function SectionAccordion({
|
||||
</div>
|
||||
<header className={styles.header}>
|
||||
<button
|
||||
onClick={onModify}
|
||||
onClick={isOpen ? close : onModify}
|
||||
disabled={!isComplete}
|
||||
className={styles.modifyButton}
|
||||
>
|
||||
@@ -97,9 +128,11 @@ export default function SectionAccordion({
|
||||
<Subtitle className={styles.selection} type="two" color={textColor}>
|
||||
{title}
|
||||
</Subtitle>
|
||||
|
||||
{isComplete && !isOpen && (
|
||||
<ChevronDownIcon className={styles.button} color="burgundy" />
|
||||
{isComplete && (
|
||||
<ChevronDownIcon
|
||||
className={`${styles.button} ${isOpen ? styles.buttonOpen : ""}`}
|
||||
color="burgundy"
|
||||
/>
|
||||
)}
|
||||
</button>
|
||||
</header>
|
||||
|
||||
@@ -16,10 +16,6 @@
|
||||
transform-origin: top;
|
||||
}
|
||||
|
||||
.accordion:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.header {
|
||||
grid-area: header;
|
||||
}
|
||||
@@ -46,8 +42,13 @@
|
||||
.button {
|
||||
grid-area: button;
|
||||
justify-self: flex-end;
|
||||
transform-origin: 50% 50%;
|
||||
transition: transform 0.3s;
|
||||
}
|
||||
|
||||
.buttonOpen {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
.selection {
|
||||
grid-area: selection;
|
||||
}
|
||||
@@ -85,22 +86,21 @@
|
||||
}
|
||||
|
||||
.contentWrapper {
|
||||
opacity: 0;
|
||||
padding-bottom: var(--Spacing-x3);
|
||||
}
|
||||
|
||||
.accordion[data-section-open="true"] .contentWrapper {
|
||||
opacity: 1;
|
||||
}
|
||||
.content {
|
||||
overflow: hidden;
|
||||
grid-area: content;
|
||||
opacity: 0;
|
||||
border-bottom: 1px solid var(--Primary-Light-On-Surface-Divider-subtle);
|
||||
transform-origin: top;
|
||||
transition: opacity 0.2s linear;
|
||||
}
|
||||
|
||||
.accordion[data-section-open="true"] .content {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.content:has([data-section-open="true"]) {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user