fix(SW-2463): scroll to payment error

This commit is contained in:
Christian Andolf
2025-04-30 10:52:53 +02:00
committed by Michael Zetterberg
parent 8b32abbefc
commit 0cd2e9c89f
3 changed files with 31 additions and 10 deletions

View File

@@ -1,13 +1,14 @@
"use client" "use client"
import { usePathname, useSearchParams } from "next/navigation" import { usePathname, useSearchParams } from "next/navigation"
import { useEffect, useState } from "react" import { useEffect, useRef, useState } from "react"
import { useIntl } from "react-intl" import { useIntl } from "react-intl"
import { BookingErrorCodeEnum } from "@/constants/booking" import { BookingErrorCodeEnum } from "@/constants/booking"
import { useEnterDetailsStore } from "@/stores/enter-details" import { useEnterDetailsStore } from "@/stores/enter-details"
import Alert from "@/components/TempDesignSystem/Alert" import Alert from "@/components/TempDesignSystem/Alert"
import useStickyPosition from "@/hooks/useStickyPosition"
import styles from "./paymentAlert.module.css" import styles from "./paymentAlert.module.css"
@@ -64,16 +65,30 @@ export default function PaymentAlert({ isVisible = false }: PaymentAlertProps) {
const { showAlert, errorMessage, severityLevel, discardAlert, setShowAlert } = const { showAlert, errorMessage, severityLevel, discardAlert, setShowAlert } =
useBookingErrorAlert() useBookingErrorAlert()
const ref = useRef<HTMLDivElement>(null)
const { getTopOffset } = useStickyPosition()
useEffect(() => { useEffect(() => {
if (isVisible) { if (isVisible) {
setShowAlert(true) setShowAlert(true)
} }
}, [isVisible, setShowAlert]) }, [isVisible, setShowAlert])
useEffect(() => {
const el = ref.current
if (showAlert && el) {
window.scrollTo({
top: el.offsetTop - getTopOffset(),
behavior: "smooth",
})
}
}, [showAlert, getTopOffset])
if (!showAlert) return null if (!showAlert) return null
return ( return (
<div className={styles.wrapper}> <div className={styles.wrapper} ref={ref}>
<Alert <Alert
type={severityLevel} type={severityLevel}
variant="inline" variant="inline"

View File

@@ -1,5 +1,6 @@
"use client" "use client"
import { useSearchParams } from "next/navigation"
import { type PropsWithChildren, useEffect, useRef } from "react" import { type PropsWithChildren, useEffect, useRef } from "react"
import { useIntl } from "react-intl" import { useIntl } from "react-intl"
@@ -16,6 +17,8 @@ import styles from "./bottomSheet.module.css"
export default function SummaryBottomSheet({ children }: PropsWithChildren) { export default function SummaryBottomSheet({ children }: PropsWithChildren) {
const intl = useIntl() const intl = useIntl()
const scrollY = useRef(0) const scrollY = useRef(0)
const searchParams = useSearchParams()
const errorCode = searchParams.get("errorCode")
const { isSummaryOpen, toggleSummaryOpen, totalPrice, isSubmittingDisabled } = const { isSummaryOpen, toggleSummaryOpen, totalPrice, isSubmittingDisabled } =
useEnterDetailsStore((state) => ({ useEnterDetailsStore((state) => ({
@@ -33,18 +36,21 @@ export default function SummaryBottomSheet({ children }: PropsWithChildren) {
} else { } else {
document.body.style.position = "" document.body.style.position = ""
document.body.style.top = "" document.body.style.top = ""
window.scrollTo({
top: scrollY.current, if (!errorCode) {
left: 0, window.scrollTo({
behavior: "instant", top: scrollY.current,
}) left: 0,
behavior: "instant",
})
}
} }
return () => { return () => {
document.body.style.position = "" document.body.style.position = ""
document.body.style.top = "" document.body.style.top = ""
} }
}, [isSummaryOpen]) }, [isSummaryOpen, errorCode])
return ( return (
<div className={styles.wrapper} data-open={isSummaryOpen}> <div className={styles.wrapper} data-open={isSummaryOpen}>

View File

@@ -24,7 +24,7 @@ let resizeObserver: ResizeObserver | null = null
* This hook registers an element as sticky, calculates its top offset based on * This hook registers an element as sticky, calculates its top offset based on
* other registered sticky elements, and updates the element's position dynamically. * other registered sticky elements, and updates the element's position dynamically.
* *
* @param {UseStickyPositionProps} props - The properties for configuring the hook. * @param {UseStickyPositionProps} [props] - The properties for configuring the hook.
* @param {React.RefObject<HTMLElement>} [props.ref] - A reference to the HTML element that should be sticky. Is optional to allow for other components to only get the height of the sticky elements. * @param {React.RefObject<HTMLElement>} [props.ref] - A reference to the HTML element that should be sticky. Is optional to allow for other components to only get the height of the sticky elements.
* @param {StickyElementNameEnum} [props.name] - A unique name for the sticky element, used for tracking. * @param {StickyElementNameEnum} [props.name] - A unique name for the sticky element, used for tracking.
* @param {string} [props.group] - An optional group identifier to make multiple elements share the same top offset. Defaults to the name if not provided. * @param {string} [props.group] - An optional group identifier to make multiple elements share the same top offset. Defaults to the name if not provided.
@@ -37,7 +37,7 @@ export default function useStickyPosition({
ref, ref,
name, name,
group, group,
}: UseStickyPositionProps) { }: UseStickyPositionProps = {}) {
const { const {
registerSticky, registerSticky,
unregisterSticky, unregisterSticky,