From 6265d6b7dcf6b6463d462c58cf4c057869778bc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matilda=20Landstr=C3=B6m?= Date: Tue, 8 Oct 2024 12:26:15 +0200 Subject: [PATCH] chore(SW-194): ContentPage Accordion --- .../Blocks/Accordion/accordion.module.css | 7 + components/Blocks/Accordion/index.tsx | 59 ++++++ components/Blocks/UspGrid/renderOptions.tsx | 2 - components/Blocks/index.tsx | 10 + components/ContentType/HotelPage/index.tsx | 3 + .../Fragments/Blocks/Accordion.graphql | 1 + .../Query/ContentPage/ContentPage.graphql | 7 +- lib/graphql/Query/HotelPage/HotelPage.graphql | 56 ++++++ .../contentstack/contentPage/output.ts | 17 ++ .../routers/contentstack/contentPage/query.ts | 7 +- .../routers/contentstack/contentPage/utils.ts | 6 + .../routers/contentstack/hotelPage/output.ts | 8 + .../contentstack/schemas/blocks/accordion.ts | 189 ++++++++++++++++++ server/routers/hotels/query.ts | 4 +- types/components/hotelPage/accordion.ts | 6 + types/components/myPages/header.ts | 2 +- types/enums/blocks.ts | 1 + types/enums/hotelPage.ts | 1 + 18 files changed, 374 insertions(+), 12 deletions(-) create mode 100644 components/Blocks/Accordion/accordion.module.css create mode 100644 components/Blocks/Accordion/index.tsx create mode 100644 server/routers/contentstack/schemas/blocks/accordion.ts create mode 100644 types/components/hotelPage/accordion.ts diff --git a/components/Blocks/Accordion/accordion.module.css b/components/Blocks/Accordion/accordion.module.css new file mode 100644 index 000000000..f3c07125b --- /dev/null +++ b/components/Blocks/Accordion/accordion.module.css @@ -0,0 +1,7 @@ +.hiddenItem { + display: none; +} + +.lastItem { + border: none; +} diff --git a/components/Blocks/Accordion/index.tsx b/components/Blocks/Accordion/index.tsx new file mode 100644 index 000000000..2684fc013 --- /dev/null +++ b/components/Blocks/Accordion/index.tsx @@ -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 ( + + {title && } + + {accordion.map((acc, idx) => ( + + {/**/} + + ))} + + + {accordion.length > 5 ? ( + + ) : null} + + ) +} diff --git a/components/Blocks/UspGrid/renderOptions.tsx b/components/Blocks/UspGrid/renderOptions.tsx index a4033fec5..96a0f7fa1 100644 --- a/components/Blocks/UspGrid/renderOptions.tsx +++ b/components/Blocks/UspGrid/renderOptions.tsx @@ -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 { diff --git a/components/Blocks/index.tsx b/components/Blocks/index.tsx index bd8abb6f7..e90221fcc 100644 --- a/components/Blocks/index.tsx +++ b/components/Blocks/index.tsx @@ -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 + case BlocksEnums.block.Accordion: + console.log("Bub", block.accordion.faq) + return ( + + ) default: return null } diff --git a/components/ContentType/HotelPage/index.tsx b/components/ContentType/HotelPage/index.tsx index 8976ead74..f5ba696d9 100644 --- a/components/ContentType/HotelPage/index.tsx +++ b/components/ContentType/HotelPage/index.tsx @@ -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() { + {/*accordion && */} {googleMapsApiKey ? ( <> diff --git a/lib/graphql/Fragments/Blocks/Accordion.graphql b/lib/graphql/Fragments/Blocks/Accordion.graphql index 6f4ecb0c4..9a253ffa8 100644 --- a/lib/graphql/Fragments/Blocks/Accordion.graphql +++ b/lib/graphql/Fragments/Blocks/Accordion.graphql @@ -73,6 +73,7 @@ fragment SpecificFaq on ContentPageBlocksAccordionBlockFaqSpecificFaq { fragment Accordion_ContentPageRefs on ContentPageBlocksAccordion { accordion { faq { + __typename ...GlobalFaqRefs ...SpecificFaqRefs } diff --git a/lib/graphql/Query/ContentPage/ContentPage.graphql b/lib/graphql/Query/ContentPage/ContentPage.graphql index f73dee9b9..64019f99c 100644 --- a/lib/graphql/Query/ContentPage/ContentPage.graphql +++ b/lib/graphql/Query/ContentPage/ContentPage.graphql @@ -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 { diff --git a/lib/graphql/Query/HotelPage/HotelPage.graphql b/lib/graphql/Query/HotelPage/HotelPage.graphql index 9e90f069c..6d6acabb0 100644 --- a/lib/graphql/Query/HotelPage/HotelPage.graphql +++ b/lib/graphql/Query/HotelPage/HotelPage.graphql @@ -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 { diff --git a/server/routers/contentstack/contentPage/output.ts b/server/routers/contentstack/contentPage/output.ts index 48ebb0f40..f5437052e 100644 --- a/server/routers/contentstack/contentPage/output.ts +++ b/server/routers/contentstack/contentPage/output.ts @@ -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, diff --git a/server/routers/contentstack/contentPage/query.ts b/server/routers/contentstack/contentPage/query.ts index 1e6536ae2..3894a3c6a 100644 --- a/server/routers/contentstack/contentPage/query.ts +++ b/server/routers/contentstack/contentPage/query.ts @@ -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, diff --git a/server/routers/contentstack/contentPage/utils.ts b/server/routers/contentstack/contentPage/utils.ts index 78f5a9d7f..30a947717 100644 --- a/server/routers/contentstack/contentPage/utils.ts +++ b/server/routers/contentstack/contentPage/utils.ts @@ -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) { diff --git a/server/routers/contentstack/hotelPage/output.ts b/server/routers/contentstack/hotelPage/output.ts index b07121934..adafb21b7 100644 --- a/server/routers/contentstack/hotelPage/output.ts +++ b/server/routers/contentstack/hotelPage/output.ts @@ -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(), diff --git a/server/routers/contentstack/schemas/blocks/accordion.ts b/server/routers/contentstack/schemas/blocks/accordion.ts new file mode 100644 index 000000000..f5b5bf5d0 --- /dev/null +++ b/server/routers/contentstack/schemas/blocks/accordion.ts @@ -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 // 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 + ) + ) || [] + ) + } + }) + }), +}) diff --git a/server/routers/hotels/query.ts b/server/routers/hotels/query.ts index 198219e0e..ee9f1f8a4 100644 --- a/server/routers/hotels/query.ts +++ b/server/routers/hotels/query.ts @@ -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) { diff --git a/types/components/hotelPage/accordion.ts b/types/components/hotelPage/accordion.ts new file mode 100644 index 000000000..3c84bde7d --- /dev/null +++ b/types/components/hotelPage/accordion.ts @@ -0,0 +1,6 @@ +import type { FAQtype } from "@/server/routers/contentstack/schemas/blocks/accordion" + +export type AccordionProps = { + accordion: FAQtype["accordion"]["faq"] + title?: string +} diff --git a/types/components/myPages/header.ts b/types/components/myPages/header.ts index 5fa1d1d16..82a662a94 100644 --- a/types/components/myPages/header.ts +++ b/types/components/myPages/header.ts @@ -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 diff --git a/types/enums/blocks.ts b/types/enums/blocks.ts index 81a088bd1..83ee7a13e 100644 --- a/types/enums/blocks.ts +++ b/types/enums/blocks.ts @@ -1,5 +1,6 @@ export namespace BlocksEnums { export const enum block { + Accordion = "Accordion", CardsGrid = "CardsGrid", Content = "Content", DynamicContent = "DynamicContent", diff --git a/types/enums/hotelPage.ts b/types/enums/hotelPage.ts index c7de7b727..64c5d889c 100644 --- a/types/enums/hotelPage.ts +++ b/types/enums/hotelPage.ts @@ -1,6 +1,7 @@ export namespace HotelPageEnum { export namespace ContentStack { export const enum blocks { + Accordion = "HotelPageFaq", ActivitiesCard = "HotelPageContentUpcomingActivitiesCard", } }