Merged in feat/SW-3002-new-hotel-move-tripadvisor (pull request #2375)

feat: SW-3002 Changed tripadvisor review subpage to Sidepeek

* feat: SW-3002 Changed tripadvisor review subpage to Sidepeek

* feat: SW-3002 Optimised styles


Approved-by: Erik Tiekstra
This commit is contained in:
Hrishikesh Vaipurkar
2025-06-24 07:39:18 +00:00
parent bfaa3d4b65
commit e77ed2407b
8 changed files with 136 additions and 210 deletions

View File

@@ -2,10 +2,10 @@ import TripadvisorIcon from "@scandic-hotels/design-system/Icons/TripadvisorIcon
import Link from "@/components/TempDesignSystem/Link"
import { getIntl } from "@/i18n"
import { appendSlugToPathname } from "@/utils/appendSlugToPathname"
import styles from "./tripAdvisorLink.module.css"
import { SidepeekSlugs } from "@/types/components/hotelPage/hotelPage"
import type { HotelTripAdvisor } from "@/types/hotel"
interface TripAdvisorLinkProps {
@@ -32,7 +32,7 @@ export default async function TripAdvisorLink({
const hasTripAdvisorIframeSrc = !!reviews.widgetScriptEmbedUrlIframe
const tripAdvisorHref = hasTripAdvisorIframeSrc
? await appendSlugToPathname("reviews")
? `?s=${SidepeekSlugs.tripAdvisor}`
: null
if (!tripAdvisorHref) {

View File

@@ -0,0 +1,87 @@
import { notFound } from "next/navigation"
import Image from "@/components/Image"
import SidePeek from "@/components/TempDesignSystem/SidePeek"
import { getIntl } from "@/i18n"
import { getLang } from "@/i18n/serverContext"
import styles from "./tripAdvisor.module.css"
import { SidepeekSlugs } from "@/types/components/hotelPage/hotelPage"
import type { HotelRatings } from "@/types/hotel"
type TripAdvisorSidePeekProps = {
hotelName: string
hotelRatings: HotelRatings
showNordicEcoLabel?: boolean
}
export default async function TripAdvisorSidePeek({
hotelName,
hotelRatings,
showNordicEcoLabel,
}: TripAdvisorSidePeekProps) {
const intl = await getIntl()
const lang = await getLang()
const tripAdvisorData = hotelRatings?.tripAdvisor
if (!tripAdvisorData?.reviews.widgetScriptEmbedUrlIframe) {
notFound()
}
const awardsLogos = tripAdvisorData.awards
.map((award) => ({
imageUrl: award.images.small,
altText: award.displayName,
}))
.filter((award) => !!award.imageUrl)
const hotelHasAwards = showNordicEcoLabel || awardsLogos.length > 0
return (
<SidePeek contentKey={SidepeekSlugs.tripAdvisor} title={hotelName}>
<section className={styles.container}>
{hotelHasAwards ? (
<div className={styles.awards}>
{showNordicEcoLabel ? (
<Image
src={`/_static/img/icons/swan-eco/swan_eco_dark_${lang}.png`}
alt={intl.formatMessage({
defaultMessage: "Nordic Swan Ecolabel",
})}
className={styles.logo}
height={100}
width={100}
/>
) : null}
{awardsLogos?.map((award) => (
<Image
src={award.imageUrl}
alt={award.altText}
className={styles.logo}
width={100}
height={100}
key={award.imageUrl}
/>
))}
</div>
) : null}
<main className={styles.main}>
<iframe
className={styles.iframe}
src={tripAdvisorData.reviews.widgetScriptEmbedUrlIframe}
loading="lazy"
title={intl.formatMessage(
{
defaultMessage: "Ratings and reviews for {hotelName}",
},
{
hotelName: hotelName,
}
)}
/>
</main>
</section>
</SidePeek>
)
}

View File

@@ -0,0 +1,40 @@
.container {
height: 100%;
display: flex;
flex-direction: column;
}
.awards {
border-radius: var(--Corner-radius-lg);
background: var(--Surface-Primary-Default);
display: flex;
flex-wrap: wrap;
padding: var(--Space-x2) var(--Space-x15);
justify-content: space-evenly;
align-items: center;
align-self: stretch;
margin-bottom: var(--Space-x3);
}
.main {
flex: 1;
display: flex;
}
.iframe {
width: 100%;
border-width: 0;
border-radius: var(--Corner-radius-lg);
/* Adjustments for devices with tiny screen height */
min-height: max(50dvh, 300px);
padding-bottom: var(--Space-x4);
margin-bottom: calc(0% - var(--Space-x4));
}
.logo {
width: 100%;
max-width: 120px;
height: 100px;
object-fit: contain;
}

View File

@@ -29,6 +29,7 @@ import AmenitiesSidePeek from "./SidePeeks/Amenities"
import MeetingsAndConferencesSidePeek from "./SidePeeks/MeetingsAndConferences"
import RestaurantBarSidePeek from "./SidePeeks/RestaurantBar"
import RoomSidePeek from "./SidePeeks/Room"
import TripAdvisorSidePeek from "./SidePeeks/Tripadvisor"
import WellnessAndExerciseSidePeek from "./SidePeeks/WellnessAndExercise"
import AmenitiesList from "./AmenitiesList"
import DialogshiftWidget from "./DialogshiftWidget"
@@ -222,6 +223,11 @@ export default async function HotelPage({ hotelId }: HotelPageProps) {
</aside>
<MobileMapToggle />
<SidePeeks hotelId={hotelId}>
<TripAdvisorSidePeek
hotelName={hotel.name}
hotelRatings={hotel.ratings}
showNordicEcoLabel={hotel.hotelFacts?.ecoLabels.nordicEcoLabel}
/>
<AmenitiesSidePeek
amenitiesList={detailedFacilities}
parking={{

View File

@@ -1,121 +0,0 @@
import { notFound } from "next/navigation"
import { Suspense } from "react"
import { Typography } from "@scandic-hotels/design-system/Typography"
import Breadcrumbs from "@/components/Breadcrumbs"
import Image from "@/components/Image"
import BreadcrumbsSkeleton from "@/components/TempDesignSystem/Breadcrumbs/BreadcrumbsSkeleton"
import { getIntl } from "@/i18n"
import { getLang } from "@/i18n/serverContext"
import styles from "./reviewsSubpage.module.css"
import type { Hotel } from "@/types/hotel"
interface ReviewsSubpageProps {
hotel: Hotel
}
export default async function ReviewsSubpage({ hotel }: ReviewsSubpageProps) {
const intl = await getIntl()
const lang = await getLang()
const tripAdvisorData = hotel.ratings?.tripAdvisor
if (!tripAdvisorData?.reviews.widgetScriptEmbedUrlIframe) {
notFound()
}
const awardsLogos = tripAdvisorData.awards
.map((award) => ({
imageUrl: award.images.small,
altText: award.displayName,
}))
.filter((award) => !!award.imageUrl)
const showNordicEcoLabel = !!hotel.hotelFacts?.ecoLabels.nordicEcoLabel
return (
<>
<section className={styles.reviewsSubpage}>
<Suspense
fallback={
<BreadcrumbsSkeleton
size="contentWidth"
color="Surface/Secondary/Default"
/>
}
>
<Breadcrumbs
subpageTitle={intl.formatMessage({
defaultMessage: "Reviews",
})}
size="contentWidth"
color="Surface/Secondary/Default"
/>
</Suspense>
<header className={styles.header}>
<Typography variant="Title/md">
<h1 className={styles.heading}>{hotel.name}</h1>
</Typography>
<Typography variant="Title/Subtitle/md">
<p className={styles.subheading}>
{intl.formatMessage({
defaultMessage: "Ratings and reviews",
})}
</p>
</Typography>
</header>
<div className={styles.contentContainer}>
<aside className={styles.sidebar}>
<Typography variant="Title/xs">
<h2 className={styles.sidebarHeading}>
{intl.formatMessage({
defaultMessage: "Awards and certifications",
})}
</h2>
</Typography>
<div className={styles.sidebarContent}>
{showNordicEcoLabel ? (
<Image
src={`/_static/img/icons/swan-eco/swan_eco_dark_${lang}.png`}
alt={intl.formatMessage({
defaultMessage: "Nordic Swan Ecolabel",
})}
className={styles.logo}
height={100}
width={100}
/>
) : null}
{awardsLogos?.map((award) => (
<Image
src={award.imageUrl}
alt={award.altText}
className={styles.logo}
width={100}
height={100}
key={award.imageUrl}
/>
))}
</div>
</aside>
<main className={styles.mainContent}>
<iframe
className={styles.iframe}
src={tripAdvisorData.reviews.widgetScriptEmbedUrlIframe}
loading="lazy"
title={intl.formatMessage(
{
defaultMessage: "Ratings and reviews for {hotelName}",
},
{
hotelName: hotel.name,
}
)}
/>
</main>
</div>
</section>
</>
)
}

View File

@@ -1,84 +0,0 @@
.reviewsSubpage {
padding-bottom: var(--Space-x9);
color: var(--Text-Default);
}
.header {
width: var(--max-width-content);
margin: 0 auto;
display: grid;
gap: var(--Space-x3);
padding: var(--Space-x4) 0;
}
.heading,
.sidebarHeading {
color: var(--Text-Heading);
}
.contentContainer {
display: grid;
gap: var(--Space-x3);
width: var(--max-width-content);
margin: 0 auto;
}
.sidebar {
display: grid;
gap: var(--Space-x3);
align-content: start;
}
.sidebarContent {
display: flex;
flex-wrap: wrap;
gap: var(--Space-x7);
padding: var(--Space-x5) var(--Space-x15);
background-color: var(--Background-Secondary);
border-radius: var(--Corner-radius-lg);
justify-content: center;
align-items: center;
}
.iframe {
width: 100%;
height: 50dvh;
border-width: 0;
border-radius: var(--Corner-radius-lg);
}
.logo {
width: 100%;
max-width: 120px;
height: 100px;
object-fit: contain;
}
@media screen and (min-width: 768px) {
.iframe {
height: 1150px; /* Maximum(ish) content height on desktop without the need of scrolling */
}
}
@media screen and (max-width: 1366px) {
.subheading,
.sidebarHeading {
display: none;
}
}
@media screen and (min-width: 1367px) {
.contentContainer {
grid-template-columns: var(--max-width-text-block) 1fr;
grid-template-areas: "main sidebar";
gap: var(--Space-x9);
}
.mainContent {
grid-area: main;
}
.sidebar {
grid-area: sidebar;
}
}

View File

@@ -8,7 +8,6 @@ import AccessibilitySubpage from "./AccessibilitySubpage"
import MeetingsSubpage from "./MeetingsSubpage"
import ParkingSubpage from "./ParkingSubpage"
import RestaurantSubpage from "./RestaurantSubpage"
import ReviewsSubpage from "./ReviewsSubpage"
import { verifySubpageShouldExist } from "./utils"
import WellnessSubpage from "./WellnessSubpage"
@@ -71,8 +70,6 @@ export default async function HotelSubpage({
additionalData={additionalData}
/>
)
case "reviews":
return <ReviewsSubpage hotel={hotel} />
default:
notFound()
}

View File

@@ -11,6 +11,7 @@ export enum SidepeekSlugs {
restaurant = "restaurants",
meetings = "meetings",
wellness = "wellness",
tripAdvisor = "tripAdvisor",
}
export type HotelHashValue =