chore(SW-194): ContentPage Accordion

This commit is contained in:
Matilda Landström
2024-10-08 12:26:15 +02:00
parent 166ddca0e0
commit 6265d6b7dc
18 changed files with 374 additions and 12 deletions

View File

@@ -0,0 +1,7 @@
.hiddenItem {
display: none;
}
.lastItem {
border: none;
}

View File

@@ -0,0 +1,59 @@
"use client"
import { useState } from "react"
import JsonToHtml from "@/components/JsonToHtml"
import SectionContainer from "@/components/Section/Container"
import SectionHeader from "@/components/Section/Header"
import Accordion from "@/components/TempDesignSystem/Accordion"
import AccordionItem from "@/components/TempDesignSystem/Accordion/AccordionItem"
import { ShowMoreButton } from "../../ContentType/HotelPage/ShowMoreButton"
import styles from "./accordion.module.css"
import type { AccordionProps } from "../../../types/components/hotelPage/accordion"
export default function AccordionSection({ accordion, title }: AccordionProps) {
const [allItemsVisible, setAllItemsVisible] = useState(false)
function handleToggleShowMore() {
setAllItemsVisible((previousState) => !previousState)
}
console.log("PUP", accordion)
function getClassName(idx: number): string {
if (!allItemsVisible && idx > 4) {
return styles.hiddenItem
} else if (!allItemsVisible && idx == 4) {
return styles.lastItem
}
return ""
}
return (
<SectionContainer id="faq">
{title && <SectionHeader textTransform="uppercase" title={title} />}
<Accordion theme={"light"} variant={"card"}>
{accordion.map((acc, idx) => (
<AccordionItem
key={acc.question + idx}
title={acc.question}
className={getClassName(idx)}
>
{/*<JsonToHtml
embeds={acc.answer.embedded_itemsConnection.edges}
nodes={acc.answer.json?.children}
/>*/}
</AccordionItem>
))}
</Accordion>
{accordion.length > 5 ? (
<ShowMoreButton
textShowMore="See all FAQ"
textShowLess="See less FAQ"
allItemsVisible={allItemsVisible}
handleToggleShowMore={handleToggleShowMore}
/>
) : null}
</SectionContainer>
)
}

View File

@@ -1,9 +1,7 @@
import Link from "@/components/TempDesignSystem/Link"
import { removeMultipleSlashes } from "@/utils/url"
import styles from "./uspgrid.module.css"
import { EmbedEnum } from "@/types/requests/utils/embeds"
import type { EmbedByUid } from "@/types/transitionTypes/jsontohtml"
import { RTEItemTypeEnum, RTETypeEnum } from "@/types/transitionTypes/rte/enums"
import type {

View File

@@ -6,6 +6,7 @@ import UspGrid from "@/components/Blocks/UspGrid"
import JsonToHtml from "@/components/JsonToHtml"
import Table from "./Table"
import AccordionSection from "./Accordion"
import type { BlocksProps } from "@/types/components/blocks"
import { BlocksEnums } from "@/types/enums/blocks"
@@ -65,6 +66,15 @@ export default function Blocks({ blocks }: BlocksProps) {
)
case BlocksEnums.block.UspGrid:
return <UspGrid usp_grid={block.usp_grid} />
case BlocksEnums.block.Accordion:
console.log("Bub", block.accordion.faq)
return (
<AccordionSection
accordion={block.accordion.faq}
title={block.title}
key={`${block.typename}-${idx}`}
/>
)
default:
return null
}

View File

@@ -2,6 +2,7 @@ import hotelPageParams from "@/constants/routes/hotelPageParams"
import { env } from "@/env/server"
import { serverClient } from "@/lib/trpc/server"
import AccordionSection from "@/components/Blocks/Accordion"
import SidePeekProvider from "@/components/SidePeekProvider"
import SidePeek from "@/components/TempDesignSystem/SidePeek"
import { getIntl } from "@/i18n"
@@ -47,6 +48,7 @@ export default async function HotelPage() {
activitiesCard,
pointsOfInterest,
facilities,
//accordion,
} = hotelData
const topThreePois = pointsOfInterest.slice(0, 3)
@@ -80,6 +82,7 @@ export default async function HotelPage() {
</div>
<Rooms rooms={roomCategories} />
<Facilities facilities={facilities} activitiesCard={activitiesCard} />
{/*accordion && <AccordionSection accordion={accordion} />*/}
</main>
{googleMapsApiKey ? (
<>

View File

@@ -73,6 +73,7 @@ fragment SpecificFaq on ContentPageBlocksAccordionBlockFaqSpecificFaq {
fragment Accordion_ContentPageRefs on ContentPageBlocksAccordion {
accordion {
faq {
__typename
...GlobalFaqRefs
...SpecificFaqRefs
}

View File

@@ -8,7 +8,6 @@
#import "../../Fragments/Blocks/Table.graphql"
#import "../../Fragments/Blocks/TextCols.graphql"
#import "../../Fragments/Blocks/UspGrid.graphql"
#import "../../Fragments/ContentPage/NavigationLinks.graphql"
#import "../../Fragments/Sidebar/Content.graphql"
@@ -26,6 +25,7 @@ query GetContentPage($locale: String!, $uid: String!) {
}
blocks {
__typename
...Accordion_ContentPage
...CardsGrid_ContentPage
...Content_ContentPage
...DynamicContent_ContentPage
@@ -33,7 +33,6 @@ query GetContentPage($locale: String!, $uid: String!) {
...Table_ContentPage
...TextCols_ContentPage
...UspGrid_ContentPage
...Accordion_ContentPage
}
sidebar {
__typename
@@ -84,10 +83,6 @@ query GetContentPageRefs($locale: String!, $uid: String!) {
__typename
...Accordion_ContentPageRefs
...CardsGrid_ContentPageRefs
...Content_ContentPageRefs
...DynamicContent_ContentPageRefs
...Shortcuts_ContentPageRefs
...TextCols_ContentPageRef
...UspGrid_ContentPageRefs
}
sidebar {

View File

@@ -1,10 +1,66 @@
#import "../../Fragments/PageLink/AccountPageLink.graphql"
#import "../../Fragments/PageLink/ContentPageLink.graphql"
#import "../../Fragments/PageLink/HotelPageLink.graphql"
#import "../../Fragments/PageLink/LoyaltyPageLink.graphql"
query GetHotelPage($locale: String!, $uid: String!) {
hotel_page(locale: $locale, uid: $uid) {
hotel_page_id
title
url
faq {
__typename
title
global_hotel_faqConnection {
edges {
node {
... on Accordion {
__typename
title
questions {
question
answer {
json
embedded_itemsConnection {
edges {
node {
__typename
... on ContentPage {
__typename
title
url
system {
...System
}
web {
original_url
}
}
}
}
}
}
}
}
}
}
}
hotel_specific_faq {
questions {
answer {
json
embedded_itemsConnection {
edges {
node {
__typename
}
}
}
}
question
}
}
}
content {
__typename
... on HotelPageContentUpcomingActivitiesCard {

View File

@@ -2,6 +2,10 @@ import { z } from "zod"
import { discriminatedUnionArray } from "@/lib/discriminatedUnion"
import {
accordionRefsSchema,
accordionSchema,
} from "../schemas/blocks/accordion"
import {
cardGridRefsSchema,
cardsGridSchema,
@@ -81,8 +85,14 @@ export const contentPageTable = z
__typename: z.literal(ContentPageEnum.ContentStack.blocks.Table),
})
.merge(tableSchema)
export const contentPageAccordion = z
.object({
__typename: z.literal(ContentPageEnum.ContentStack.blocks.Accordion),
})
.merge(accordionSchema)
export const blocksSchema = z.discriminatedUnion("__typename", [
contentPageAccordion,
contentPageCards,
contentPageContent,
contentPageDynamicContent,
@@ -192,7 +202,14 @@ const contentPageUspGridRefs = z
})
.merge(uspGridRefsSchema)
const contentPageAccordionRefs = z
.object({
__typename: z.literal(ContentPageEnum.ContentStack.blocks.Accordion),
})
.merge(accordionRefsSchema)
const contentPageBlockRefsItem = z.discriminatedUnion("__typename", [
contentPageAccordionRefs,
contentPageBlockContentRefs,
contentPageShortcutsRefs,
contentPageCardsRefs,

View File

@@ -25,6 +25,7 @@ export const contentPageQueryRouter = router({
const { lang, uid } = ctx
const contentPageRefsData = await fetchContentPageRefs(lang, uid)
const contentPageRefs = validateContentPageRefs(
contentPageRefsData,
lang,
@@ -33,8 +34,10 @@ export const contentPageQueryRouter = router({
if (!contentPageRefs) {
return null
}
//console.log("EYY", contentPageRefs.content_page.blocks[1])
//console.log("EYY", contentPageRefs.content_page.blocks[0])
const tags = generatePageTags(contentPageRefs, lang)
//console.log("tags", tags)
getContentPageCounter.add(1, { lang, uid })
console.info(
"contentstack.contentPage start",
@@ -83,7 +86,7 @@ export const contentPageQueryRouter = router({
console.error(contentPage.error?.format())
return null
}
//console.log("HEJ2", contentPage.data.content_page.blocks[0])
const tracking: TrackingSDKPageData = {
pageId: contentPage.data.content_page.system.uid,
lang: contentPage.data.content_page.system.locale as Lang,

View File

@@ -126,6 +126,12 @@ export function getConnections({ content_page }: ContentPageRefs) {
if (content_page.blocks) {
content_page.blocks.forEach((block) => {
switch (block.__typename) {
case ContentPageEnum.ContentStack.blocks.Accordion: {
if (block.accordion.length) {
connections.push(...block.accordion)
}
break
}
case ContentPageEnum.ContentStack.blocks.Content:
{
if (block.content.length) {

View File

@@ -2,6 +2,7 @@ import { z } from "zod"
import { discriminatedUnionArray } from "@/lib/discriminatedUnion"
import { accordionSchema } from "../schemas/blocks/accordion"
import { activitiesCard } from "../schemas/blocks/activitiesCard"
import { HotelPageEnum } from "@/types/enums/hotelPage"
@@ -16,9 +17,16 @@ export const contentBlock = z.discriminatedUnion("__typename", [
contentBlockActivities,
])
export const hotelPageAccordion = z
.object({
__typename: z.literal(HotelPageEnum.ContentStack.blocks.Accordion),
})
.merge(accordionSchema)
export const hotelPageSchema = z.object({
hotel_page: z.object({
content: discriminatedUnionArray(contentBlock.options).nullable(),
faq: hotelPageAccordion,
hotel_page_id: z.string(),
title: z.string(),
url: z.string(),

View File

@@ -0,0 +1,189 @@
import { z } from "zod"
import * as pageLinks from "@/server/routers/contentstack/schemas/pageLinks"
import { BlocksEnums } from "@/types/enums/blocks"
export const faqSchema = z.array(
z.object({
answer: z.object({
json: z.any(),
embedded_itemsConnection: z.object({
edges: z.array(
z.object({
node: z
.discriminatedUnion("__typename", [
pageLinks.contentPageSchema,
pageLinks.hotelPageSchema,
pageLinks.loyaltyPageSchema,
])
.transform((data) => {
const link = pageLinks.transform(data)
if (link) {
return link
}
return data
}),
})
),
}),
}),
question: z.string(),
})
)
export type FAQtype = z.infer<typeof accordionSchema> // MOVE
enum AccordionEnum {
ContentPageBlocksAccordionBlockFaqGlobalFaq = "ContentPageBlocksAccordionBlockFaqGlobalFaq",
ContentPageBlocksAccordionBlockFaqSpecificFaq = "ContentPageBlocksAccordionBlockFaqSpecificFaq",
}
export const accordionSchema = z.object({
typename: z
.literal(BlocksEnums.block.Accordion)
.optional()
.default(BlocksEnums.block.Accordion),
title: z.string().optional().default(""),
accordion: z
.object({
faq: z.array(
z.object({
__typename: z.enum([
AccordionEnum.ContentPageBlocksAccordionBlockFaqGlobalFaq,
AccordionEnum.ContentPageBlocksAccordionBlockFaqSpecificFaq,
]),
global_faq: z
.object({
global_faqConnection: z.object({
edges: z.array(
z.object({
node: z.object({
questions: faqSchema,
}),
})
),
}),
})
.optional(),
specific_faq: z
.object({
questions: faqSchema,
})
.optional(),
})
),
})
.transform((data) => {
return {
...data,
faq: data.faq.flatMap((faq) => {
switch (faq.__typename) {
case AccordionEnum.ContentPageBlocksAccordionBlockFaqGlobalFaq:
return (
faq.global_faq?.global_faqConnection.edges.flatMap(
({ node: faqConnection }) => {
return faqConnection.questions
}
) || []
)
case AccordionEnum.ContentPageBlocksAccordionBlockFaqSpecificFaq:
return faq.specific_faq?.questions || []
}
}),
}
}),
/*hotel_specific_faq: z.object({
questions: faqSchema,
}),*/
})
const actualRefs = z.discriminatedUnion("__typename", [
pageLinks.accountPageRefSchema,
pageLinks.contentPageRefSchema,
pageLinks.hotelPageRefSchema,
pageLinks.loyaltyPageRefSchema,
])
export const accordionRefsSchema = z.object({
accordion: z
.object({
faq: z.array(
z.object({
__typename: z.enum([
AccordionEnum.ContentPageBlocksAccordionBlockFaqGlobalFaq,
AccordionEnum.ContentPageBlocksAccordionBlockFaqSpecificFaq,
]),
global_faq: z
.object({
global_faqConnection: z.object({
edges: z.array(
z.object({
node: z.object({
questions: z.array(
z.object({
answer: z.object({
embedded_itemsConnection: z.object({
edges: z.array(
z.object({
node: actualRefs,
})
),
}),
}),
})
),
}),
})
),
}),
})
.optional(),
specific_faq: z
.object({
questions: z.array(
z.object({
answer: z.object({
embedded_itemsConnection: z.object({
edges: z.array(
z.object({
node: actualRefs,
})
),
}),
}),
})
),
})
.optional(),
})
),
})
.transform((data) => {
return data.faq.flatMap((faq) => {
switch (faq.__typename) {
case AccordionEnum.ContentPageBlocksAccordionBlockFaqGlobalFaq:
return (
faq.global_faq?.global_faqConnection.edges.flatMap(
({ node: faqConnection }) => {
return faqConnection.questions.flatMap((question) =>
question.answer.embedded_itemsConnection.edges.flatMap(
({ node }) => node.system
)
)
}
) || []
)
case AccordionEnum.ContentPageBlocksAccordionBlockFaqSpecificFaq:
return (
faq.specific_faq?.questions.flatMap((question) =>
question.answer.embedded_itemsConnection.edges.flatMap(
({ node }) => node.system
)
) || []
)
}
})
}),
})

View File

@@ -82,7 +82,7 @@ async function getContentstackData(
if (!response.data) {
throw notFound(response)
}
console.log("HEJ", response.data)
const hotelPageData = hotelPageSchema.safeParse(response.data)
if (!hotelPageData.success) {
console.error(
@@ -101,7 +101,9 @@ export const hotelQueryRouter = router({
.query(async ({ ctx, input }) => {
const { lang, uid } = ctx
const { include } = input
console.log("då")
const contentstackData = await getContentstackData(lang, uid)
console.log("då", contentstackData)
const hotelId = contentstackData?.hotel_page_id
if (!hotelId) {

View File

@@ -0,0 +1,6 @@
import type { FAQtype } from "@/server/routers/contentstack/schemas/blocks/accordion"
export type AccordionProps = {
accordion: FAQtype["accordion"]["faq"]
title?: string
}

View File

@@ -5,7 +5,7 @@ export type HeaderProps = {
href: string
text: string
}
preamble: string | null
preamble?: string | null
textTransform?: HeadingProps["textTransform"]
title: string | null
topTitle?: boolean

View File

@@ -1,5 +1,6 @@
export namespace BlocksEnums {
export const enum block {
Accordion = "Accordion",
CardsGrid = "CardsGrid",
Content = "Content",
DynamicContent = "DynamicContent",

View File

@@ -1,6 +1,7 @@
export namespace HotelPageEnum {
export namespace ContentStack {
export const enum blocks {
Accordion = "HotelPageFaq",
ActivitiesCard = "HotelPageContentUpcomingActivitiesCard",
}
}