fix: refactor language switcher

This commit is contained in:
Christel Westerberg
2024-06-03 09:38:17 +02:00
parent 2c102c62e0
commit 095edcce8c
14 changed files with 196 additions and 230 deletions

View File

@@ -5,16 +5,20 @@ import Mobile from "@/components/Current/Header/LanguageSwitcher/Mobile"
import styles from "./page.module.css" import styles from "./page.module.css"
export default async function LanguageSwitcher() { import { LangParams, PageArgs, UriParams } from "@/types/params"
const data = await serverClient().contentstack.accountPage.languageSwitcher()
export default async function LanguageSwitcher({
params,
}: PageArgs<LangParams & UriParams>) {
const { urls } = await serverClient().contentstack.config.languageSwitcher()
return ( return (
<> <>
<section className={styles.desktop}> <section className={styles.desktop}>
<Desktop currentLanguage={data.lang} urls={data.urls} /> <Desktop currentLanguage={params.lang} urls={urls} />
</section> </section>
<section className={styles.mobile}> <section className={styles.mobile}>
<Mobile currentLanguage={data.lang} urls={data.urls} /> <Mobile currentLanguage={params.lang} urls={urls} />
</section> </section>
</> </>
) )

View File

@@ -1,50 +0,0 @@
import { notFound } from "next/navigation"
import { Lang } from "@/constants/languages"
import { serverClient } from "@/lib/trpc/server"
import Desktop from "@/components/Current/Header/LanguageSwitcher/Desktop"
import Mobile from "@/components/Current/Header/LanguageSwitcher/Mobile"
import styles from "./page.module.css"
import {
ContentTypeParams,
LangParams,
PageArgs,
UIDParams,
} from "@/types/params"
import { LanguageSwitcherData } from "@/types/requests/languageSwitcher"
export default async function LanguageSwitcher({
params,
}: PageArgs<LangParams & ContentTypeParams & UIDParams, {}>) {
let urls: LanguageSwitcherData
let lang: Lang
switch (params.contentType) {
case "loyalty-page":
const data =
await serverClient().contentstack.loyaltyPage.languageSwitcher()
urls = data.urls
lang = data.lang
break
case "content-page":
// TODO: Implement this
return null
default:
const type: never = params.contentType
console.error(`Unsupported content type given: ${type}`)
notFound()
}
return (
<>
<section className={styles.desktop}>
<Desktop currentLanguage={params.lang} urls={urls} />
</section>
<section className={styles.mobile}>
<Mobile currentLanguage={params.lang} urls={urls} />
</section>
</>
)
}

View File

@@ -1,17 +0,0 @@
.desktop {
display: none;
}
.mobile {
display: block;
}
@media (min-width: 950px) {
.desktop {
display: block;
}
.mobile {
display: none;
}
}

View File

@@ -1,8 +1,4 @@
import { batchRequest } from "@/lib/graphql/batchRequest" import { serverClient } from "@/lib/trpc/server"
import {
GetDaDeEnUrlsCurrentBlocksPage,
GetFiNoSvUrlsCurrentBlocksPage,
} from "@/lib/graphql/Query/LanguageSwitcherCurrent.graphql"
import Desktop from "@/components/Current/Header/LanguageSwitcher/Desktop" import Desktop from "@/components/Current/Header/LanguageSwitcher/Desktop"
import Mobile from "@/components/Current/Header/LanguageSwitcher/Mobile" import Mobile from "@/components/Current/Header/LanguageSwitcher/Mobile"
@@ -10,7 +6,6 @@ import Mobile from "@/components/Current/Header/LanguageSwitcher/Mobile"
import styles from "./page.module.css" import styles from "./page.module.css"
import { LangParams, PageArgs, UIDParams, UriParams } from "@/types/params" import { LangParams, PageArgs, UIDParams, UriParams } from "@/types/params"
import { LanguageSwitcherData } from "@/types/requests/languageSwitcher"
export default async function LanguageSwitcher({ export default async function LanguageSwitcher({
params, params,
@@ -20,20 +15,7 @@ export default async function LanguageSwitcher({
return null return null
} }
const variables = { const { urls } = await serverClient().contentstack.config.languageSwitcher()
uid: searchParams.uid,
}
const { data: urls } = await batchRequest<LanguageSwitcherData>([
{
document: GetDaDeEnUrlsCurrentBlocksPage,
variables,
},
{
document: GetFiNoSvUrlsCurrentBlocksPage,
variables,
},
])
return ( return (
<> <>

View File

@@ -64,35 +64,29 @@ query GetAccountPageRefs($locale: String!, $uid: String!) {
} }
query GetDaDeEnUrlsAccountPage($uid: String!) { query GetDaDeEnUrlsAccountPage($uid: String!) {
de: all_account_page(where: { uid: $uid }, locale: "de") { de: account_page(uid: $uid, locale: "de") {
items { url
url
}
} }
en: all_account_page(where: { uid: $uid }, locale: "en") { en: account_page(uid: $uid, locale: "en") {
items { url
url
}
} }
da: all_account_page(where: { uid: $uid }, locale: "da") { da: account_page(uid: $uid, locale: "da") {
items { url
url
}
} }
} }
query GetFiNoSvUrlsAccountPage($uid: String!) { query GetFiNoSvUrlsAccountPage($uid: String!) {
fi: all_account_page(where: { uid: $uid }, locale: "fi") { fi: account_page(uid: $uid, locale: "fi") {
items { items {
url url
} }
} }
no: all_account_page(where: { uid: $uid }, locale: "no") { no: account_page(uid: $uid, locale: "no") {
items { items {
url url
} }
} }
sv: all_account_page(where: { uid: $uid }, locale: "sv") { sv: account_page(uid: $uid, locale: "sv") {
items { items {
url url
} }

View File

@@ -3,6 +3,7 @@
#import "../Fragments/Footer/Navigation.graphql" #import "../Fragments/Footer/Navigation.graphql"
#import "../Fragments/Footer/SocialMedia.graphql" #import "../Fragments/Footer/SocialMedia.graphql"
#import "../Fragments/Footer/TripAdvisor.graphql" #import "../Fragments/Footer/TripAdvisor.graphql"
#import "../Fragments/Refs/System.graphql"
query GetCurrentFooter($locale: String!) { query GetCurrentFooter($locale: String!) {
all_current_footer(limit: 1, locale: $locale) { all_current_footer(limit: 1, locale: $locale) {
@@ -24,3 +25,13 @@ query GetCurrentFooter($locale: String!) {
} }
} }
} }
query GetCurrentFooterRef($locale: String!) {
all_current_footer(limit: 1, locale: $locale) {
items {
system {
...System
}
}
}
}

View File

@@ -1,10 +1,6 @@
import { Lang } from "@/constants/languages"
import { batchRequest } from "@/lib/graphql/batchRequest"
import { import {
GetAccountPage, GetAccountPage,
GetAccountPageRefs, GetAccountPageRefs,
GetDaDeEnUrlsAccountPage,
GetFiNoSvUrlsAccountPage,
} from "@/lib/graphql/Query/AccountPage.graphql" } from "@/lib/graphql/Query/AccountPage.graphql"
import { request } from "@/lib/graphql/request" import { request } from "@/lib/graphql/request"
import { internalServerError, notFound } from "@/server/errors/trpc" import { internalServerError, notFound } from "@/server/errors/trpc"
@@ -22,16 +18,11 @@ import {
AccountPageRefsDataRaw, AccountPageRefsDataRaw,
validateAccountPageRefsSchema, validateAccountPageRefsSchema,
validateAccountPageSchema, validateAccountPageSchema,
validateLanguageSwitcherData,
} from "./output" } from "./output"
import { getConnections } from "./utils" import { getConnections } from "./utils"
import { ContentEntries } from "@/types/components/myPages/myPage/enums" import { ContentEntries } from "@/types/components/myPages/myPage/enums"
import { Embeds } from "@/types/requests/embeds" import { Embeds } from "@/types/requests/embeds"
import {
LanguageSwitcherData,
LanguageSwitcherQueryDataRaw,
} from "@/types/requests/languageSwitcher"
import { Edges } from "@/types/requests/utils/edges" import { Edges } from "@/types/requests/utils/edges"
import { RTEDocument } from "@/types/rte/node" import { RTEDocument } from "@/types/rte/node"
@@ -140,38 +131,4 @@ export const accountPageQueryRouter = router({
return accountPage return accountPage
}), }),
languageSwitcher: contentstackProcedure.query(async ({ ctx }) => {
const variables = {
uid: ctx.uid,
}
const res = await batchRequest<LanguageSwitcherQueryDataRaw>([
{
document: GetDaDeEnUrlsAccountPage,
variables,
},
{
document: GetFiNoSvUrlsAccountPage,
variables,
},
])
const urls = Object.keys(res.data).reduce<LanguageSwitcherData>(
(acc, key) => {
const item = res.data[key as Lang]?.items[0]
const url = item ? `/${key}${item.url}` : undefined
return { ...acc, [key]: { url, isExternal: false } }
},
{} as LanguageSwitcherData
)
const validatedLanguageSwitcherData =
validateLanguageSwitcherData.safeParse(urls)
if (!validatedLanguageSwitcherData.success) {
throw internalServerError(validatedLanguageSwitcherData.error)
}
return { lang: ctx.lang, urls }
}),
}) })

View File

@@ -132,6 +132,8 @@ const validateHeaderRefConfigSchema = z.object({
}), }),
}) })
export type HeaderRefDataRaw = z.infer<typeof validateHeaderRefConfigSchema>
const validateAppDownload = z.object({ const validateAppDownload = z.object({
href: z.string(), href: z.string(),
imageConnection: z.object({ imageConnection: z.object({
@@ -155,9 +157,6 @@ const validateAppDownload = z.object({
}), }),
}) })
export type HeaderRefDataRaw = z.infer<typeof validateHeaderRefConfigSchema>
const validateNavigationItem = z.object({ const validateNavigationItem = z.object({
links: z.array(z.object({ href: z.string(), title: z.string() })), links: z.array(z.object({ href: z.string(), title: z.string() })),
title: z.string(), title: z.string(),
@@ -240,3 +239,27 @@ export type FooterData = Omit<
> & { > & {
logo: Image logo: Image
} }
const validateFooterRefConfigSchema = z.object({
all_current_footer: z.object({
items: z.array(
z.object({
system: z.object({
content_type_uid: z.string(),
uid: z.string(),
}),
})
),
}),
})
export type FooterRefDataRaw = z.infer<typeof validateFooterRefConfigSchema>
export const validateLanguageSwitcherData = z.object({
en: z.object({ url: z.string(), isExternal: z.boolean() }).optional(),
da: z.object({ url: z.string(), isExternal: z.boolean() }).optional(),
de: z.object({ url: z.string(), isExternal: z.boolean() }).optional(),
fi: z.object({ url: z.string(), isExternal: z.boolean() }).optional(),
sv: z.object({ url: z.string(), isExternal: z.boolean() }).optional(),
no: z.object({ url: z.string(), isExternal: z.boolean() }).optional(),
})

View File

@@ -1,9 +1,26 @@
import { Lang } from "@/constants/languages"
import { batchRequest } from "@/lib/graphql/batchRequest"
import {
GetDaDeEnUrlsAccountPage,
GetFiNoSvUrlsAccountPage,
} from "@/lib/graphql/Query/AccountPage.graphql"
import { GetContactConfig } from "@/lib/graphql/Query/ContactConfig.graphql" import { GetContactConfig } from "@/lib/graphql/Query/ContactConfig.graphql"
import { GetCurrentFooter } from "@/lib/graphql/Query/CurrentFooter.graphql" import {
GetCurrentFooter,
GetCurrentFooterRef,
} from "@/lib/graphql/Query/CurrentFooter.graphql"
import { import {
GetCurrentHeader, GetCurrentHeader,
GetCurrentHeaderRef, GetCurrentHeaderRef,
} from "@/lib/graphql/Query/CurrentHeader.graphql" } from "@/lib/graphql/Query/CurrentHeader.graphql"
import {
GetDaDeEnUrlsCurrentBlocksPage,
GetFiNoSvUrlsCurrentBlocksPage,
} from "@/lib/graphql/Query/LanguageSwitcherCurrent.graphql"
import {
GetDaDeEnUrlsLoyaltyPage,
GetFiNoSvUrlsLoyaltyPage,
} from "@/lib/graphql/Query/LoyaltyPage.graphql"
import { request } from "@/lib/graphql/request" import { request } from "@/lib/graphql/request"
import { internalServerError, notFound } from "@/server/errors/trpc" import { internalServerError, notFound } from "@/server/errors/trpc"
import { contentstackProcedure, publicProcedure, router } from "@/server/trpc" import { contentstackProcedure, publicProcedure, router } from "@/server/trpc"
@@ -13,14 +30,22 @@ import { generateTag } from "@/utils/generateTag"
import { import {
type ContactConfigData, type ContactConfigData,
FooterDataRaw, FooterDataRaw,
FooterRefDataRaw,
HeaderData, HeaderData,
HeaderDataRaw, HeaderDataRaw,
HeaderRefDataRaw, HeaderRefDataRaw,
validateContactConfigSchema, validateContactConfigSchema,
validateFooterConfigSchema, validateFooterConfigSchema,
validateHeaderConfigSchema, validateHeaderConfigSchema,
validateLanguageSwitcherData,
} from "./output" } from "./output"
import {
LanguageSwitcherData,
LanguageSwitcherQueryDataRaw,
} from "@/types/requests/languageSwitcher"
import { PageTypeEnum } from "@/types/requests/pageType"
export const configQueryRouter = router({ export const configQueryRouter = router({
contact: contentstackProcedure.query(async ({ ctx }) => { contact: contentstackProcedure.query(async ({ ctx }) => {
const { lang } = ctx const { lang } = ctx
@@ -85,13 +110,24 @@ export const configQueryRouter = router({
} as HeaderData } as HeaderData
}), }),
footer: contentstackProcedure.query(async ({ ctx }) => { footer: contentstackProcedure.query(async ({ ctx }) => {
const responseRef = await request<FooterRefDataRaw>(GetCurrentFooterRef, {
locale: ctx.lang,
})
const response = await request<FooterDataRaw>( const response = await request<FooterDataRaw>(
GetCurrentFooter, GetCurrentFooter,
{ {
locale: ctx.lang, locale: ctx.lang,
}, },
{ {
next: { tags: [`footer-${ctx.lang}`] }, next: {
tags: [
generateTag(
ctx.lang,
responseRef.data.all_current_footer.items[0].system.uid
),
],
},
} }
) )
@@ -105,4 +141,99 @@ export const configQueryRouter = router({
return validatedFooterConfig.data.all_current_footer.items[0] return validatedFooterConfig.data.all_current_footer.items[0]
}), }),
languageSwitcher: contentstackProcedure.query(async ({ ctx }) => {
const variables = { uid: ctx.uid, locale: ctx.lang }
let urls: LanguageSwitcherData
switch (ctx.contentType) {
case PageTypeEnum.accountPage:
const accountPageRes = await batchRequest<LanguageSwitcherQueryDataRaw>(
[
{
document: GetDaDeEnUrlsAccountPage,
variables,
},
{
document: GetFiNoSvUrlsAccountPage,
variables,
},
]
)
const accountPageUrls = Object.keys(
accountPageRes.data
).reduce<LanguageSwitcherData>((acc, key) => {
const item = accountPageRes.data[key as Lang]?.items?.[0]
const url = item
? { url: `/${key}${item.url}`, isExternal: false }
: undefined
return { ...acc, [key]: url }
}, {} as LanguageSwitcherData)
const validatedAccountLanguageSwitcherData =
validateLanguageSwitcherData.safeParse(accountPageUrls)
if (!validatedAccountLanguageSwitcherData.success) {
throw internalServerError(validatedAccountLanguageSwitcherData.error)
}
urls = validatedAccountLanguageSwitcherData.data
break
case PageTypeEnum.loyaltyPage:
const loyaltyPageRes = await batchRequest<LanguageSwitcherQueryDataRaw>(
[
{
document: GetDaDeEnUrlsLoyaltyPage,
variables,
},
{
document: GetFiNoSvUrlsLoyaltyPage,
variables,
},
]
)
const loyaltyPageUrls = Object.keys(
loyaltyPageRes.data
).reduce<LanguageSwitcherData>((acc, key) => {
const item = loyaltyPageRes.data[key as Lang]?.items?.[0]
const url = item
? {
url: item.web?.original_url || `/${key}${item.url}`,
isExternal: !!item?.web?.original_url,
}
: undefined
return {
...acc,
[key]: url,
}
}, {} as LanguageSwitcherData)
const validatedLoyaltyLanguageSwitcherData =
validateLanguageSwitcherData.safeParse(loyaltyPageUrls)
if (!validatedLoyaltyLanguageSwitcherData.success) {
throw internalServerError(validatedLoyaltyLanguageSwitcherData.error)
}
urls = validatedLoyaltyLanguageSwitcherData.data
break
case PageTypeEnum.currentBlocksPage:
const { data } = await batchRequest<LanguageSwitcherData>([
{
document: GetDaDeEnUrlsCurrentBlocksPage,
variables,
},
{
document: GetFiNoSvUrlsCurrentBlocksPage,
variables,
},
])
urls = data
break
default:
urls = [] as unknown as LanguageSwitcherData
}
return { urls, lang: ctx.lang }
}),
}) })

View File

@@ -306,24 +306,3 @@ export const validateLoyaltyPageRefsSchema = z.object({
export type LoyaltyPageRefsDataRaw = z.infer< export type LoyaltyPageRefsDataRaw = z.infer<
typeof validateLoyaltyPageRefsSchema typeof validateLoyaltyPageRefsSchema
> >
export const validateLanguageSwitcherData = z.object({
en: z
.object({ url: z.string().optional(), isExternal: z.boolean() })
.nullable(),
da: z
.object({ url: z.string().optional(), isExternal: z.boolean() })
.nullable(),
de: z
.object({ url: z.string().optional(), isExternal: z.boolean() })
.nullable(),
fi: z
.object({ url: z.string().optional(), isExternal: z.boolean() })
.nullable(),
sv: z
.object({ url: z.string().optional(), isExternal: z.boolean() })
.nullable(),
no: z
.object({ url: z.string().optional(), isExternal: z.boolean() })
.nullable(),
})

View File

@@ -1,8 +1,4 @@
import { Lang } from "@/constants/languages"
import { batchRequest } from "@/lib/graphql/batchRequest"
import { import {
GetDaDeEnUrlsLoyaltyPage,
GetFiNoSvUrlsLoyaltyPage,
GetLoyaltyPage, GetLoyaltyPage,
GetLoyaltyPageRefs, GetLoyaltyPageRefs,
} from "@/lib/graphql/Query/LoyaltyPage.graphql" } from "@/lib/graphql/Query/LoyaltyPage.graphql"
@@ -21,17 +17,12 @@ import { removeEmptyObjects } from "../../utils"
import { import {
LoyaltyPage, LoyaltyPage,
type LoyaltyPageRefsDataRaw, type LoyaltyPageRefsDataRaw,
validateLanguageSwitcherData,
validateLoyaltyPageRefsSchema, validateLoyaltyPageRefsSchema,
validateLoyaltyPageSchema, validateLoyaltyPageSchema,
} from "./output" } from "./output"
import { getConnections } from "./utils" import { getConnections } from "./utils"
import { LoyaltyBlocksTypenameEnum } from "@/types/components/loyalty/enums" import { LoyaltyBlocksTypenameEnum } from "@/types/components/loyalty/enums"
import {
LanguageSwitcherData,
LanguageSwitcherQueryDataRaw,
} from "@/types/requests/languageSwitcher"
function makeButtonObject(button: any) { function makeButtonObject(button: any) {
return { return {
@@ -181,44 +172,4 @@ export const loyaltyPageQueryRouter = router({
// Assert LoyaltyPage type to get correct typings for RTE fields // Assert LoyaltyPage type to get correct typings for RTE fields
return validatedLoyaltyPage.data as LoyaltyPage return validatedLoyaltyPage.data as LoyaltyPage
}), }),
languageSwitcher: contentstackProcedure.query(async ({ ctx }) => {
const variables = {
uid: ctx.uid,
}
const res = await batchRequest<LanguageSwitcherQueryDataRaw>([
{
document: GetDaDeEnUrlsLoyaltyPage,
variables,
},
{
document: GetFiNoSvUrlsLoyaltyPage,
variables,
},
])
const urls = Object.keys(res.data).reduce<LanguageSwitcherData>(
(acc, key) => {
const item = res.data[key as Lang]?.items[0]
const url = item
? item.web?.original_url || `/${key}${item.url}`
: undefined
return {
...acc,
[key]: { url, isExternal: !!item?.web?.original_url },
}
},
{} as LanguageSwitcherData
)
const validatedLanguageSwitcherData =
validateLanguageSwitcherData.safeParse(urls)
if (!validatedLanguageSwitcherData.success) {
throw internalServerError(validatedLanguageSwitcherData.error)
}
return { lang: ctx.lang, urls }
}),
}) })

View File

@@ -4,12 +4,12 @@ type CurrentLanguageResult = {
} }
export type LanguageSwitcherData = { export type LanguageSwitcherData = {
da: CurrentLanguageResult | undefined da?: CurrentLanguageResult
de: CurrentLanguageResult | undefined de?: CurrentLanguageResult
en: CurrentLanguageResult | undefined en?: CurrentLanguageResult
fi: CurrentLanguageResult | undefined fi?: CurrentLanguageResult
no: CurrentLanguageResult | undefined no?: CurrentLanguageResult
sv: CurrentLanguageResult | undefined sv?: CurrentLanguageResult
} }
type LanguageResult = { type LanguageResult = {

View File

@@ -1,4 +1,5 @@
export enum PageTypeEnum { export enum PageTypeEnum {
accountPage = "account-page", accountPage = "account-page",
loyaltyPage = "loyalty-page", loyaltyPage = "loyalty-page",
currentBlocksPage = "current-blocks-page",
} }