fix: toggle section accordion open

This commit is contained in:
Christel Westerberg
2024-10-03 17:00:04 +02:00
parent 1bb2d3f687
commit 668eedd837
12 changed files with 245 additions and 289 deletions

View File

@@ -1,57 +1,91 @@
import { getHotelDataSchema } from "@/server/routers/hotels/output"
import tempHotelData from "@/server/routers/hotels/tempHotelData.json"
"use client"
import { useEffect, useRef } from "react"
import { useIntl } from "react-intl"
import { CheckCircleIcon, ChevronDownIcon } from "@/components/Icons"
import Button from "@/components/TempDesignSystem/Button"
import { CheckIcon, ChevronDownIcon } from "@/components/Icons"
import Link from "@/components/TempDesignSystem/Link"
import Body from "@/components/TempDesignSystem/Text/Body"
import Caption from "@/components/TempDesignSystem/Text/Caption"
import { getIntl } from "@/i18n"
import HotelSelectionHeader from "../../HotelSelectionHeader"
import Footnote from "@/components/TempDesignSystem/Text/Footnote"
import Subtitle from "@/components/TempDesignSystem/Text/Subtitle"
import styles from "./sectionAccordion.module.css"
import { SectionAccordionProps } from "@/types/components/hotelReservation/selectRate/sectionAccordion"
export default async function SectionAccordion({
export default function SectionAccordion({
header,
selection,
isOpen,
isCompleted,
label,
path,
children,
}: React.PropsWithChildren<SectionAccordionProps>) {
const hotel = getHotelDataSchema.parse(tempHotelData)
const intl = useIntl()
const intl = await getIntl()
const contentRef = useRef<HTMLDivElement>(null)
const circleRef = useRef<HTMLDivElement>(null)
useEffect(() => {
const content = contentRef.current
const circle = circleRef.current
if (content) {
if (isOpen) {
content.style.maxHeight = `${content.scrollHeight}px`
} else {
content.style.maxHeight = "0"
}
}
if (circle) {
if (isOpen) {
circle.style.backgroundColor = `var(--UI-Text-Placeholder);`
} else {
circle.style.backgroundColor = `var(--Base-Surface-Subtle-Hover);`
}
}
}, [isOpen])
return (
<div className={styles.wrapper}>
<HotelSelectionHeader hotel={hotel.data.attributes} />
<div className={styles.top}>
<div>
<CheckCircleIcon color={selection ? "green" : "pale"} />
</div>
<div className={styles.header}>
<Caption color={"burgundy"} asChild>
<h2>{header}</h2>
</Caption>
{(Array.isArray(selection) ? selection : [selection]).map((s) => (
<Body key={s} className={styles.selection} color={"burgundy"}>
{s}
</Body>
))}
</div>
{selection && (
<Button intent="secondary" size="small" asChild>
<Link href={path}>{intl.formatMessage({ id: "Modify" })}</Link>
</Button>
)}
<div>
<ChevronDownIcon />
<section className={styles.wrapper} data-open={isOpen}>
<div className={styles.iconWrapper}>
<div
className={styles.circle}
data-checked={isCompleted}
ref={circleRef}
>
{isCompleted ? (
<CheckIcon color="white" height="16" width="16" />
) : null}
</div>
</div>
{children}
</div>
<main className={styles.main}>
<header className={styles.headerContainer}>
<div>
<Footnote
asChild
textTransform="uppercase"
color="uiTextPlaceholder"
>
<h2>{header}</h2>
</Footnote>
<Subtitle
type="two"
className={styles.selection}
color="highContrast"
>
{label}
</Subtitle>
</div>
{isCompleted && !isOpen && (
<Link href={path} color="burgundy" variant="icon">
{intl.formatMessage({ id: "Modify" })}{" "}
<ChevronDownIcon color="burgundy" />
</Link>
)}
</header>
<div className={styles.content} ref={contentRef}>
{children}
</div>
</main>
</section>
)
}

View File

@@ -1,21 +1,73 @@
.wrapper {
border-bottom: 1px solid var(--Base-Border-Normal);
position: relative;
display: flex;
flex-direction: row;
gap: var(--Spacing-x3);
padding-top: var(--Spacing-x3);
}
.top {
.wrapper:not(:last-child)::after {
position: absolute;
left: 12px;
bottom: 0;
top: var(--Spacing-x5);
height: 100%;
content: "";
border-left: 1px solid var(--Primary-Light-On-Surface-Divider-subtle);
}
.main {
display: flex;
flex-direction: column;
gap: var(--Spacing-x3);
width: 100%;
border-bottom: 1px solid var(--Primary-Light-On-Surface-Divider-subtle);
padding-bottom: var(--Spacing-x3);
padding-top: var(--Spacing-x3);
}
.headerContainer {
display: flex;
justify-content: space-between;
align-items: center;
gap: var(--Spacing-x2);
}
.header {
flex-grow: 1;
}
.selection {
font-weight: 450;
font-size: var(--typography-Title-4-fontSize);
}
.iconWrapper {
position: relative;
top: var(--Spacing-x1);
z-index: 10;
}
.circle {
width: 24px;
height: 24px;
border-radius: 100px;
transition: background-color 0.4s;
border: 2px solid var(--Base-Border-Inverted);
display: flex;
justify-content: center;
align-items: center;
}
.circle[data-checked="true"] {
background-color: var(--UI-Input-Controls-Fill-Selected);
}
.wrapper[data-open="true"] .circle[data-checked="false"] {
background-color: var(--UI-Text-Placeholder);
}
.wrapper[data-open="false"] .circle[data-checked="false"] {
background-color: var(--Base-Surface-Subtle-Hover);
}
.content {
overflow: hidden;
transition: max-height 0.4s ease-out;
max-height: 0;
}