Merged in feat/SW-1276-implement-design (pull request #1348)

Feat/SW-1276 implement design

* feat(SW-1276) UI implementation Desktop part 1 for MyStay

* feat(SW-1276) UI implementation Desktop part 2 for MyStay

* feat(SW-1276) UI implementation Mobile part 1 for MyStay

* refactor: move files from MyStay/MyStay to MyStay

* feat(SW-1276) Sidepeek implementation

* feat(SW-1276): Refactoring

* feat(SW-1276) UI implementation Mobile part 2 for MyStay

* feat(SW-1276): translations

* feat(SW-1276) fixed skeleton

* feat(SW-1276): Added missing translations

* feat(SW-1276): Removed console log

* feat(SW-1276) fixed translations

* feat(SW-1276): Added translations

* feat(SW-1276) fix dynamic ID:s

* feat(SW-1276) removed createElement

* feat(SW-1276): Fixed build errors

* feat(SW-1276): Updated label

* feat(SW-1276): Rewrite SummaryCard


Approved-by: Niclas Edenvin
This commit is contained in:
Pontus Dreij
2025-02-18 14:20:54 +00:00
parent 90fee1b0c4
commit 8616e4ab76
56 changed files with 4163 additions and 227 deletions

View File

@@ -0,0 +1,87 @@
.container {
display: flex;
flex-direction: column;
gap: var(--Spacing-x2);
}
.title {
display: flex;
justify-content: space-between;
}
.modalContent {
width: 100%;
}
.tabs {
display: flex;
gap: var(--Spacing-x1);
padding: var(--Spacing-x3) 0;
flex-wrap: wrap;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(251px, 1fr));
gap: var(--Spacing-x2);
max-height: 417px;
overflow-y: auto;
padding-right: var(--Spacing-x1);
margin-top: var(--Spacing-x2);
}
.chip {
border-radius: 28px;
padding: var(--Spacing-x-one-and-half) var(--Spacing-x2);
border: none;
cursor: pointer;
background: var(--Base-Surface-Subtle-Normal);
}
.chip.selected {
background: var(--Base-Text-High-contrast);
}
.ancillaries {
display: none;
}
.modal {
display: none;
}
.carouselContainer {
display: grid;
grid-auto-flow: column;
grid-auto-columns: 80%;
gap: var(--Spacing-x2);
}
@media screen and (min-width: 768px) {
.modalContent {
width: 600px;
}
.carouselContainer {
grid-auto-columns: calc((100% - var(--Spacing-x3)) / 2);
}
}
@media screen and (min-width: 1052px) {
.mobileAncillaries {
display: none;
}
.modalContent {
width: 833px;
}
.ancillaries {
display: grid;
grid-template-columns: repeat(4, minmax(251px, 1fr));
gap: var(--Spacing-x2);
}
.modal {
display: block;
}
}

View File

@@ -0,0 +1,120 @@
"use client"
import { useState } from "react"
import { useIntl } from "react-intl"
import { Carousel } from "@/components/Carousel"
import { ChevronRightSmallIcon } from "@/components/Icons"
import Modal from "@/components/Modal"
import { AncillaryCard } from "@/components/TempDesignSystem/AncillaryCard"
import Button from "@/components/TempDesignSystem/Button"
import Caption from "@/components/TempDesignSystem/Text/Caption"
import Title from "@/components/TempDesignSystem/Text/Title"
import styles from "./ancillaries.module.css"
import type {
Ancillaries,
AncillariesProps,
Ancillary,
} from "@/types/components/myPages/myStay/ancillaries"
export function Ancillaries({ ancillaries }: AncillariesProps) {
const intl = useIntl()
const [selectedCategory, setSelectedCategory] = useState<string | null>(
() => {
return ancillaries?.[0]?.categoryName ?? null
}
)
if (!ancillaries?.length) {
return null
}
function mergeAncillaries(
ancillaries: Ancillaries
): Ancillary["ancillaryContent"] {
const uniqueAncillaries = new Map(
ancillaries
.flatMap((category) => category.ancillaryContent)
.map((ancillary) => [ancillary.id, ancillary])
)
return [...uniqueAncillaries.values()]
}
const allAncillaries = mergeAncillaries(ancillaries)
return (
<div className={styles.container}>
<div className={styles.title}>
<Title as="h5">{intl.formatMessage({ id: "Upgrade your stay" })}</Title>
<div className={styles.modal}>
<Modal
trigger={
<Button theme="base" variant="icon" intent="text" size="small">
{intl.formatMessage({ id: "View all" })}
<ChevronRightSmallIcon
width={20}
height={20}
color="baseButtonTextOnFillNormal"
/>
</Button>
}
title={intl.formatMessage({ id: "Upgrade your stay" })}
>
<div className={styles.modalContent}>
<div className={styles.tabs}>
{ancillaries.map((category) => (
<button
key={category.categoryName}
className={`${styles.chip} ${category.categoryName === selectedCategory ? styles.selected : ""}`}
onClick={() => setSelectedCategory(category.categoryName)}
>
<Caption
color={
category.categoryName === selectedCategory
? "pale"
: "baseTextHighContrast"
}
>
{category.categoryName}
</Caption>
</button>
))}
</div>
<div className={styles.grid}>
{ancillaries
.find(
(category) => category.categoryName === selectedCategory
)
?.ancillaryContent.map(({ description, ...ancillary }) => (
<AncillaryCard key={ancillary.id} ancillary={ancillary} />
))}
</div>
</div>
</Modal>
</div>
</div>
<div className={styles.ancillaries}>
{allAncillaries.slice(0, 4).map(({ description, ...ancillary }) => (
<AncillaryCard key={ancillary.id} ancillary={ancillary} />
))}
</div>
<div className={styles.mobileAncillaries}>
<Carousel>
<Carousel.Content className={styles.carouselContainer}>
{allAncillaries.map(({ description, ...ancillary }) => (
<Carousel.Item key={ancillary.id}>
<AncillaryCard key={ancillary.id} ancillary={ancillary} />
</Carousel.Item>
))}
</Carousel.Content>
<Carousel.Previous className={styles.navigationButton} />
<Carousel.Next className={styles.navigationButton} />
<Carousel.Dots />
</Carousel>
</div>
</div>
)
}