Merged in feat/BOOK-591-jotform (pull request #3350)

Feat/BOOK-591 jotform

* feat(BOOK-591): create jotform

* feat(BOOK-591): jotform

* feat(BOOK-591): jotform

* fix(BOOK-591): add embedhandler

* feat(BOOK-591): refactor jotform

* feat(BOOK-591): remove inline styles

* feat(BOOK-591): remove typename

* feat(BOOK-591): add jotformembedhandler


Approved-by: Erik Tiekstra
This commit is contained in:
Bianca Widstam
2025-12-16 14:35:45 +00:00
parent f27ba7ccb6
commit 1dce74c95f
12 changed files with 200 additions and 6 deletions

View File

@@ -0,0 +1,58 @@
"use client"
import Script from "next/script"
import { useEffect, useRef, useState } from "react"
import useLang from "@/hooks/useLang"
import styles from "./jotform.module.css"
type JotformProps = {
formId: string | null | undefined
}
export default function Jotform({ formId }: JotformProps) {
const lang = useLang()
const [scriptInitialized, setScriptInitialized] = useState(
() =>
typeof window !== "undefined" &&
typeof window.jotformEmbedHandler === "function"
)
const componentInitialized = useRef(false)
useEffect(() => {
if (
formId &&
scriptInitialized &&
!componentInitialized.current &&
window.jotformEmbedHandler
) {
window.jotformEmbedHandler(
`iframe[id='JotFormIFrame-${formId}']`,
"https://scandichotels.jotform.com/"
)
componentInitialized.current = true
}
}, [formId, scriptInitialized])
if (!formId) {
return null
}
const src = `https://scandichotels.jotform.com/${formId}?language=${lang}`
return (
<>
<Script
src="https://scandichotels.jotform.com/s/umd/latest/for-form-embed-handler.js"
onLoad={() => setScriptInitialized(true)}
strategy="lazyOnload"
/>
<iframe
id={`JotFormIFrame-${formId}`}
src={src}
className={styles.iframe}
scrolling="no"
/>
</>
)
}

View File

@@ -0,0 +1,5 @@
.iframe {
width: 100%;
border-width: 0;
min-height: max(100dvh, 300px);
}

View File

@@ -14,6 +14,7 @@ import AccordionSection from "./Accordion"
import CardGallery from "./CardGallery"
import Essentials from "./Essentials"
import HotelListing from "./HotelListing"
import Jotform from "./Jotform"
import Table from "./Table"
import type { BlocksProps } from "@/types/components/blocks"
@@ -107,6 +108,8 @@ export default function Blocks({ blocks }: BlocksProps) {
return <UspGrid usp_grid={block.usp_grid} />
case BlocksEnums.block.Essentials:
return <Essentials content={block.essentials} />
case BlocksEnums.block.Jotform:
return <Jotform formId={block.jotform?.form_id} />
case BlocksEnums.block.VideoCard:
return (
<VideoCardBlock

View File

@@ -34,4 +34,5 @@ interface Window {
init?: (args: { micrositeId: string; language: "en" | "sv" }) => void
}
}
jotformEmbedHandler?: (selector: string, url: string) => void
}

View File

@@ -0,0 +1,34 @@
import { gql } from "graphql-tag"
import { Jotform, JotformRef } from "../Jotform.graphql"
export const Jotform_ContentPage = gql`
fragment Jotform_ContentPage on ContentPageBlocksJotform {
__typename
jotform {
formConnection {
edges {
node {
...Jotform
}
}
}
}
}
${Jotform}
`
export const Jotform_ContentPageRefs = gql`
fragment Jotform_ContentPageRefs on ContentPageBlocksJotform {
__typename
jotform {
formConnection {
edges {
node {
...JotformRef
}
}
}
}
}
${JotformRef}
`

View File

@@ -0,0 +1,18 @@
import { gql } from "graphql-tag"
import { System } from "./System.graphql"
export const Jotform = gql`
fragment Jotform on Jotform {
form_id
}
`
export const JotformRef = gql`
fragment JotformRef on Jotform {
system {
...System
}
}
${System}
`

View File

@@ -17,6 +17,10 @@ import {
DynamicContent_ContentPageRefs,
} from "../../Fragments/Blocks/DynamicContent.graphql"
import { HotelListing_ContentPage } from "../../Fragments/Blocks/HotelListing.graphql"
import {
Jotform_ContentPage,
Jotform_ContentPageRefs,
} from "../../Fragments/Blocks/Jotform.graphql"
import {
Shortcuts_ContentPage,
Shortcuts_ContentPageRefs,
@@ -134,6 +138,7 @@ export const GetContentPageBlocksBatch1 = gql`
...CardsGrid_ContentPage
...Content_ContentPage
...DynamicContent_ContentPage
...Jotform_ContentPage
...VideoCard_ContentPage
...Video_ContentPage
}
@@ -143,6 +148,7 @@ export const GetContentPageBlocksBatch1 = gql`
${CardsGrid_ContentPage}
${Content_ContentPage}
${DynamicContent_ContentPage}
${Jotform_ContentPage}
${VideoCard_ContentPage}
${Video_ContentPage}
`
@@ -216,6 +222,7 @@ export const GetContentPageBlocksRefs = gql`
...Shortcuts_ContentPageRefs
...TextCols_ContentPageRef
...UspGrid_ContentPageRefs
...Jotform_ContentPageRefs
...VideoCard_ContentPageRefs
...Video_ContentPageRefs
}
@@ -228,6 +235,7 @@ export const GetContentPageBlocksRefs = gql`
${Shortcuts_ContentPageRefs}
${TextCols_ContentPageRef}
${UspGrid_ContentPageRefs}
${Jotform_ContentPageRefs}
${VideoCard_ContentPageRefs}
${Video_ContentPageRefs}
`

View File

@@ -21,6 +21,7 @@ import {
dynamicContentSchema as blockDynamicContentSchema,
} from "../schemas/blocks/dynamicContent"
import { contentPageHotelListingSchema } from "../schemas/blocks/hotelListing"
import { jotformRefsSchema, jotformSchema } from "../schemas/blocks/jotform"
import {
shortcutsRefsSchema,
shortcutsSchema,
@@ -103,6 +104,12 @@ export const contentPageUspGrid = z
})
.merge(uspGridSchema)
export const contentPageJotform = z
.object({
__typename: z.literal(ContentPageEnum.ContentStack.blocks.Jotform),
})
.merge(jotformSchema)
export const contentPageTable = z
.object({
__typename: z.literal(ContentPageEnum.ContentStack.blocks.Table),
@@ -142,6 +149,7 @@ export const blocksSchema = z.discriminatedUnion("__typename", [
contentPageTable,
contentPageTextCols,
contentPageUspGrid,
contentPageJotform,
contentPageHotelListing,
contentPageVideoCard,
contentPageVideo,
@@ -298,6 +306,12 @@ const contentPageVideoRefs = z
})
.merge(videoBlockRefsSchema)
const contentPageJotformRefs = z
.object({
__typename: z.literal(ContentPageEnum.ContentStack.blocks.Jotform),
})
.merge(jotformRefsSchema)
const contentPageBlockRefsItem = z.discriminatedUnion("__typename", [
contentPageAccordionRefs,
contentPageBlockContentRefs,
@@ -307,6 +321,7 @@ const contentPageBlockRefsItem = z.discriminatedUnion("__typename", [
contentPageTextColsRefs,
contentPageUspGridRefs,
contentPageVideoCardRefs,
contentPageJotformRefs,
contentPageVideoRefs,
])

View File

@@ -172,6 +172,11 @@ export function getConnections({ content_page }: ContentPageRefs) {
break
case ContentPageEnum.ContentStack.blocks.Video:
break
case ContentPageEnum.ContentStack.blocks.Jotform:
if (block.jotform) {
connections.push(block.jotform.system)
}
break
default:
const _exhaustiveCheck: never = typeName
break

View File

@@ -0,0 +1,42 @@
import { z } from "zod"
import { BlocksEnums } from "../../../../types/blocksEnum"
import { systemSchema } from "../system"
export const jotformSchema = z.object({
typename: z
.literal(BlocksEnums.block.Jotform)
.optional()
.default(BlocksEnums.block.Jotform),
jotform: z
.object({
formConnection: z.object({
edges: z.array(
z.object({
node: z.object({
form_id: z.string().nullish(),
}),
})
),
}),
})
.transform((data) => {
return data.formConnection.edges[0]?.node || null
}),
})
export const jotformRefsSchema = z.object({
jotform: z
.object({
formConnection: z.object({
edges: z.array(
z.object({
node: z.object({ system: systemSchema }),
})
),
}),
})
.transform((data) => {
return data.formConnection.edges[0]?.node || null
}),
})

View File

@@ -12,6 +12,7 @@ export namespace BlocksEnums {
CampaignPageHotelListing = "CampaignPageHotelListing",
ContentPageHotelListing = "ContentPageHotelListing",
JoinScandicFriends = "JoinScandicFriends",
Jotform = "Jotform",
Shortcuts = "Shortcuts",
Table = "Table",
TextCols = "TextCols",

View File

@@ -7,14 +7,17 @@ import type {
sidebarSchema,
} from "../routers/contentstack/contentPage/output"
export interface GetContentPageRefsSchema
extends z.input<typeof contentPageRefsSchema> {}
export interface GetContentPageRefsSchema extends z.input<
typeof contentPageRefsSchema
> {}
export interface ContentPageRefs
extends z.output<typeof contentPageRefsSchema> {}
export interface ContentPageRefs extends z.output<
typeof contentPageRefsSchema
> {}
export interface GetContentPageSchema
extends z.input<typeof contentPageSchema> {}
export interface GetContentPageSchema extends z.input<
typeof contentPageSchema
> {}
export interface ContentPage extends z.output<typeof contentPageSchema> {}
@@ -34,6 +37,7 @@ export namespace ContentPageEnum {
Shortcuts = "ContentPageBlocksShortcuts",
TextCols = "ContentPageBlocksTextCols",
UspGrid = "ContentPageBlocksUspGrid",
Jotform = "ContentPageBlocksJotform",
Table = "ContentPageBlocksTable",
HotelListing = "ContentPageBlocksHotelListing",
VideoCard = "ContentPageBlocksVideoCard",