Merged in monorepo-step-1 (pull request #1080)
Migrate to a monorepo setup - step 1 * Move web to subfolder /apps/scandic-web * Yarn + transitive deps - Move to yarn - design-system package removed for now since yarn doesn't support the parameter for token (ie project currently broken) - Add missing transitive dependencies as Yarn otherwise prevents these imports - VS Code doesn't pick up TS path aliases unless you open /apps/scandic-web instead of root (will be fixed with monorepo) * Pin framer-motion to temporarily fix typing issue https://github.com/adobe/react-spectrum/issues/7494 * Pin zod to avoid typ error There seems to have been a breaking change in the types returned by zod where error is now returned as undefined instead of missing in the type. We should just handle this but to avoid merge conflicts just pin the dependency for now. * Pin react-intl version Pin version of react-intl to avoid tiny type issue where formatMessage does not accept a generic any more. This will be fixed in a future commit, but to avoid merge conflicts just pin for now. * Pin typescript version Temporarily pin version as newer versions as stricter and results in a type error. Will be fixed in future commit after merge. * Setup workspaces * Add design-system as a monorepo package * Remove unused env var DESIGN_SYSTEM_ACCESS_TOKEN * Fix husky for monorepo setup * Update netlify.toml * Add lint script to root package.json * Add stub readme * Fix react-intl formatMessage types * Test netlify.toml in root * Remove root toml * Update netlify.toml publish path * Remove package-lock.json * Update build for branch/preview builds Approved-by: Linus Flood
This commit is contained in:
committed by
Linus Flood
parent
667cab6fb6
commit
80100e7631
@@ -0,0 +1,56 @@
|
||||
import { Lang } from "@/constants/languages"
|
||||
import { profile } from "@/constants/routes/myPages"
|
||||
import { serverClient } from "@/lib/trpc/server"
|
||||
import { getPublicURL } from "@/server/utils"
|
||||
|
||||
import type { NextRequest } from "next/server"
|
||||
|
||||
export async function GET(
|
||||
request: NextRequest,
|
||||
{ params }: { params: { lang: string } }
|
||||
) {
|
||||
const publicURL = getPublicURL(request)
|
||||
|
||||
console.log(`[add-card] callback started`)
|
||||
const lang = params.lang as Lang
|
||||
const returnUrl = new URL(`${publicURL}/${profile[lang ?? Lang.en]}`)
|
||||
|
||||
try {
|
||||
const searchParams = request.nextUrl.searchParams
|
||||
const success = searchParams.get("success")
|
||||
const failure = searchParams.get("failure")
|
||||
const cancel = searchParams.get("cancel")
|
||||
const trxId = searchParams.get("datatransTrxId")
|
||||
|
||||
if (success) {
|
||||
if (trxId) {
|
||||
const saveCardSuccess = await serverClient().user.creditCard.save({
|
||||
transactionId: trxId,
|
||||
})
|
||||
|
||||
if (saveCardSuccess) {
|
||||
console.log(`[add-card] planet success: card saved success`)
|
||||
returnUrl.searchParams.set("success", "true")
|
||||
} else {
|
||||
console.log(`[add-card] planet success: card saved fail`)
|
||||
returnUrl.searchParams.set("failure", "true")
|
||||
}
|
||||
} else {
|
||||
console.log(`[add-card] planet success: missing datatransTrxId`)
|
||||
returnUrl.searchParams.set("error", "true")
|
||||
}
|
||||
} else if (failure) {
|
||||
console.log(`[add-card] planet fail`)
|
||||
returnUrl.searchParams.set("failure", "true")
|
||||
} else if (cancel) {
|
||||
console.log(`[add-card] planet cancel`)
|
||||
returnUrl.searchParams.set("cancel", "true")
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(`[add-card] error saving credit card`, e)
|
||||
returnUrl.searchParams.set("error", "true")
|
||||
}
|
||||
|
||||
console.log(`[add-card] redirecting to: ${returnUrl}`)
|
||||
return Response.redirect(returnUrl)
|
||||
}
|
||||
1
apps/scandic-web/app/api/web/auth/[...nextauth]/route.ts
Normal file
1
apps/scandic-web/app/api/web/auth/[...nextauth]/route.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { GET, POST } from "@/auth"
|
||||
5
apps/scandic-web/app/api/web/check-headers/route.ts
Normal file
5
apps/scandic-web/app/api/web/check-headers/route.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import { type NextRequest, NextResponse } from "next/server"
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
return NextResponse.json(Object.fromEntries(request.headers.entries()))
|
||||
}
|
||||
73
apps/scandic-web/app/api/web/revalidate/hotel/route.ts
Normal file
73
apps/scandic-web/app/api/web/revalidate/hotel/route.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import { revalidateTag } from "next/cache"
|
||||
import { headers } from "next/headers"
|
||||
import { z } from "zod"
|
||||
|
||||
import { Lang } from "@/constants/languages"
|
||||
import { env } from "@/env/server"
|
||||
import { badRequest, internalServerError, notFound } from "@/server/errors/next"
|
||||
|
||||
import { generateHotelUrlTag } from "@/utils/generateTag"
|
||||
|
||||
import type { NextRequest } from "next/server"
|
||||
|
||||
const validateJsonBody = z.object({
|
||||
data: z.object({
|
||||
content_type: z.object({
|
||||
uid: z.literal("hotel_page"),
|
||||
}),
|
||||
entry: z.object({
|
||||
hotel_page_id: z.string(),
|
||||
locale: z.nativeEnum(Lang),
|
||||
publish_details: z.object({ locale: z.nativeEnum(Lang) }).optional(),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const headersList = headers()
|
||||
const secret = headersList.get("x-revalidate-secret")
|
||||
|
||||
if (secret !== env.REVALIDATE_SECRET) {
|
||||
console.error(`Invalid Secret`)
|
||||
console.error({ secret })
|
||||
return badRequest({ revalidated: false, now: Date.now() })
|
||||
}
|
||||
|
||||
const data = await request.json()
|
||||
const validatedData = validateJsonBody.safeParse(data)
|
||||
if (!validatedData.success) {
|
||||
console.error("Bad validation for `validatedData` in hotel revalidation")
|
||||
console.error(validatedData.error)
|
||||
return internalServerError({ revalidated: false, now: Date.now() })
|
||||
}
|
||||
|
||||
const {
|
||||
data: {
|
||||
data: { content_type, entry },
|
||||
},
|
||||
} = validatedData
|
||||
|
||||
// The publish_details.locale is the locale that the entry is published in, regardless if it is "localized" or not
|
||||
const locale = entry.publish_details?.locale ?? entry.locale
|
||||
|
||||
let tag = ""
|
||||
if (content_type.uid === "hotel_page") {
|
||||
tag = generateHotelUrlTag(locale, entry.hotel_page_id)
|
||||
} else {
|
||||
console.error(
|
||||
`Invalid content_type, received ${content_type.uid}, expected "hotel_page"`
|
||||
)
|
||||
return notFound({ revalidated: false, now: Date.now() })
|
||||
}
|
||||
|
||||
console.info(`Revalidating hotel url tag: ${tag}`)
|
||||
revalidateTag(tag)
|
||||
|
||||
return Response.json({ revalidated: true, now: Date.now() })
|
||||
} catch (error) {
|
||||
console.error("Failed to revalidate tag(s) for hotel")
|
||||
console.error(error)
|
||||
return internalServerError({ revalidated: false, now: Date.now() })
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
import { revalidateTag } from "next/cache"
|
||||
import { headers } from "next/headers"
|
||||
import { z } from "zod"
|
||||
|
||||
import { Lang } from "@/constants/languages"
|
||||
import { env } from "@/env/server"
|
||||
import { badRequest, internalServerError, notFound } from "@/server/errors/next"
|
||||
|
||||
import { generateLoyaltyConfigTag } from "@/utils/generateTag"
|
||||
|
||||
import type { NextRequest } from "next/server"
|
||||
|
||||
enum LoyaltyConfigContentTypes {
|
||||
loyalty_level = "loyalty_level",
|
||||
reward = "reward",
|
||||
}
|
||||
|
||||
const validateJsonBody = z.object({
|
||||
data: z.object({
|
||||
content_type: z.object({
|
||||
uid: z.nativeEnum(LoyaltyConfigContentTypes),
|
||||
}),
|
||||
entry: z.object({
|
||||
reward_id: z.string().optional(),
|
||||
level_id: z.string().optional(),
|
||||
locale: z.nativeEnum(Lang),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const headersList = headers()
|
||||
const secret = headersList.get("x-revalidate-secret")
|
||||
|
||||
if (secret !== env.REVALIDATE_SECRET) {
|
||||
console.error(`Invalid Secret`)
|
||||
console.error({ secret })
|
||||
return badRequest({ revalidated: false, now: Date.now() })
|
||||
}
|
||||
|
||||
const data = await request.json()
|
||||
const validatedData = validateJsonBody.safeParse(data)
|
||||
if (!validatedData.success) {
|
||||
console.error(
|
||||
"Bad validation for `validatedData` in loyaltyConfig revalidation"
|
||||
)
|
||||
console.error(validatedData.error)
|
||||
return internalServerError({ revalidated: false, now: Date.now() })
|
||||
}
|
||||
|
||||
const {
|
||||
data: {
|
||||
data: { content_type, entry },
|
||||
},
|
||||
} = validatedData
|
||||
|
||||
let tag = ""
|
||||
if (
|
||||
content_type.uid === LoyaltyConfigContentTypes.loyalty_level &&
|
||||
entry.level_id
|
||||
) {
|
||||
tag = generateLoyaltyConfigTag(
|
||||
entry.locale,
|
||||
content_type.uid,
|
||||
entry.level_id
|
||||
)
|
||||
} else if (
|
||||
content_type.uid === LoyaltyConfigContentTypes.reward &&
|
||||
entry.reward_id
|
||||
) {
|
||||
tag = generateLoyaltyConfigTag(
|
||||
entry.locale,
|
||||
content_type.uid,
|
||||
entry.reward_id
|
||||
)
|
||||
} else {
|
||||
console.error("Invalid content_type")
|
||||
return notFound({ revalidated: false, now: Date.now() })
|
||||
}
|
||||
|
||||
console.info(`Revalidating loyalty config tag: ${tag}`)
|
||||
revalidateTag(tag)
|
||||
|
||||
return Response.json({ revalidated: true, now: Date.now() })
|
||||
} catch (error) {
|
||||
console.error("Failed to revalidate tag(s) for loyalty config")
|
||||
console.error(error)
|
||||
return internalServerError({ revalidated: false, now: Date.now() })
|
||||
}
|
||||
}
|
||||
61
apps/scandic-web/app/api/web/revalidate/manually/route.ts
Normal file
61
apps/scandic-web/app/api/web/revalidate/manually/route.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
import { revalidateTag } from "next/cache"
|
||||
import { headers } from "next/headers"
|
||||
|
||||
import { env } from "@/env/server"
|
||||
import { badRequest, internalServerError } from "@/server/errors/next"
|
||||
|
||||
import { generateTag } from "@/utils/generateTag"
|
||||
|
||||
import type { Lang } from "@/constants/languages"
|
||||
|
||||
// This file is primarily to be used locally to test
|
||||
// purging your cache for new (and old) requests
|
||||
export async function POST() {
|
||||
try {
|
||||
const headersList = headers()
|
||||
const secret = headersList.get("x-revalidate-secret")
|
||||
|
||||
if (secret !== env.REVALIDATE_SECRET) {
|
||||
console.error(`Invalid Secret`)
|
||||
console.error({ secret })
|
||||
return badRequest({
|
||||
now: Date.now(),
|
||||
revalidated: false,
|
||||
})
|
||||
}
|
||||
|
||||
const affix = headersList.get("x-affix")
|
||||
const identifier = headersList.get("x-identifier")
|
||||
const lang = headersList.get("x-lang")
|
||||
if (lang && identifier) {
|
||||
if (affix) {
|
||||
const tag = generateTag(lang as Lang, identifier, affix)
|
||||
console.info(
|
||||
`Revalidated tag for [lang: ${lang}, identifier: ${identifier}, affix: ${affix}]`
|
||||
)
|
||||
console.info(`Tag: ${tag}`)
|
||||
revalidateTag(tag)
|
||||
} else {
|
||||
const tag = generateTag(lang as Lang, identifier)
|
||||
console.info(
|
||||
`Revalidated tag for [lang: ${lang}, identifier: ${identifier}]`
|
||||
)
|
||||
console.info(`Tag: ${tag}`)
|
||||
revalidateTag(tag)
|
||||
}
|
||||
} else {
|
||||
console.info(`Missing lang and/or identifier`)
|
||||
console.info(`lang: ${lang}, identifier: ${identifier}`)
|
||||
return badRequest({
|
||||
now: Date.now(),
|
||||
revalidated: false,
|
||||
})
|
||||
}
|
||||
|
||||
return Response.json({ revalidated: true, now: Date.now() })
|
||||
} catch (error) {
|
||||
console.error("Failed to revalidate tag(s)")
|
||||
console.error(error)
|
||||
return internalServerError({ revalidated: false, now: Date.now() })
|
||||
}
|
||||
}
|
||||
144
apps/scandic-web/app/api/web/revalidate/route.ts
Normal file
144
apps/scandic-web/app/api/web/revalidate/route.ts
Normal file
@@ -0,0 +1,144 @@
|
||||
import { revalidateTag } from "next/cache"
|
||||
import { headers } from "next/headers"
|
||||
import { z } from "zod"
|
||||
|
||||
import { Lang } from "@/constants/languages"
|
||||
import { env } from "@/env/server"
|
||||
import { badRequest, internalServerError } from "@/server/errors/next"
|
||||
import { affix as breadcrumbsAffix } from "@/server/routers/contentstack/breadcrumbs/utils"
|
||||
import { languageSwitcherAffix } from "@/server/routers/contentstack/languageSwitcher/utils"
|
||||
import { affix as metadataAffix } from "@/server/routers/contentstack/metadata/utils"
|
||||
import { affix as pageSettingsAffix } from "@/server/routers/contentstack/pageSettings/utils"
|
||||
|
||||
import {
|
||||
generateRefsResponseTag,
|
||||
generateRefTag,
|
||||
generateTag,
|
||||
} from "@/utils/generateTag"
|
||||
|
||||
import type { NextRequest } from "next/server"
|
||||
|
||||
const validateJsonBody = z.object({
|
||||
data: z.object({
|
||||
content_type: z.object({
|
||||
uid: z.string(),
|
||||
}),
|
||||
entry: z.object({
|
||||
breadcrumbs: z
|
||||
.object({
|
||||
title: z.string(),
|
||||
})
|
||||
.optional(),
|
||||
locale: z.nativeEnum(Lang),
|
||||
publish_details: z.object({ locale: z.nativeEnum(Lang) }).optional(),
|
||||
uid: z.string(),
|
||||
url: z.string().optional(),
|
||||
page_settings: z
|
||||
.object({
|
||||
hide_booking_widget: z.boolean(),
|
||||
})
|
||||
.optional(),
|
||||
}),
|
||||
}),
|
||||
})
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const headersList = headers()
|
||||
const secret = headersList.get("x-revalidate-secret")
|
||||
|
||||
if (secret !== env.REVALIDATE_SECRET) {
|
||||
console.error(`Invalid Secret`)
|
||||
console.error({ secret })
|
||||
return badRequest({
|
||||
now: Date.now(),
|
||||
revalidated: false,
|
||||
})
|
||||
}
|
||||
|
||||
const data = await request.json()
|
||||
const validatedData = validateJsonBody.safeParse(data)
|
||||
if (!validatedData.success) {
|
||||
console.error("Bad validation for `validatedData`")
|
||||
console.error(validatedData.error)
|
||||
return internalServerError({ revalidated: false, now: Date.now() })
|
||||
}
|
||||
|
||||
const {
|
||||
data: {
|
||||
data: { content_type, entry },
|
||||
},
|
||||
} = validatedData
|
||||
|
||||
// The publish_details.locale is the locale that the entry is published in, regardless if it is "localized" or not
|
||||
const entryLocale = entry.publish_details?.locale ?? entry.locale
|
||||
|
||||
const refsTag = generateRefsResponseTag(entryLocale, entry.uid)
|
||||
const contentEntryTag = generateRefsResponseTag(
|
||||
entryLocale,
|
||||
content_type.uid
|
||||
)
|
||||
const refTag = generateRefTag(entryLocale, content_type.uid, entry.uid)
|
||||
const tag = generateTag(entryLocale, entry.uid)
|
||||
const languageSwitcherTag = generateTag(
|
||||
entryLocale,
|
||||
entry.uid,
|
||||
languageSwitcherAffix
|
||||
)
|
||||
const metadataTag = generateTag(entryLocale, entry.uid, metadataAffix)
|
||||
|
||||
console.info(`Revalidating refsTag: ${refsTag}`)
|
||||
revalidateTag(refsTag)
|
||||
|
||||
console.info(`Revalidating refTag: ${refTag}`)
|
||||
revalidateTag(refTag)
|
||||
|
||||
console.info(`Revalidating tag: ${tag}`)
|
||||
revalidateTag(tag)
|
||||
|
||||
console.info(`Revalidating language switcher tag: ${languageSwitcherTag}`)
|
||||
revalidateTag(languageSwitcherTag)
|
||||
|
||||
console.info(`Revalidating metadataTag: ${metadataTag}`)
|
||||
revalidateTag(metadataTag)
|
||||
|
||||
console.info(`Revalidating contentEntryTag: ${contentEntryTag}`)
|
||||
revalidateTag(contentEntryTag)
|
||||
|
||||
if (entry.breadcrumbs) {
|
||||
const breadcrumbsRefsTag = generateRefsResponseTag(
|
||||
entryLocale,
|
||||
entry.uid,
|
||||
breadcrumbsAffix
|
||||
)
|
||||
const breadcrumbsTag = generateTag(
|
||||
entryLocale,
|
||||
entry.uid,
|
||||
breadcrumbsAffix
|
||||
)
|
||||
|
||||
console.info(`Revalidating breadcrumbsRefsTag: ${breadcrumbsRefsTag}`)
|
||||
revalidateTag(breadcrumbsRefsTag)
|
||||
|
||||
console.info(`Revalidating breadcrumbsTag: ${breadcrumbsTag}`)
|
||||
revalidateTag(breadcrumbsTag)
|
||||
}
|
||||
|
||||
if (entry.page_settings) {
|
||||
const pageSettingsTag = generateTag(
|
||||
entryLocale,
|
||||
entry.uid,
|
||||
pageSettingsAffix
|
||||
)
|
||||
|
||||
console.info(`Revalidating pageSettingsTag: ${pageSettingsTag}`)
|
||||
revalidateTag(pageSettingsTag)
|
||||
}
|
||||
|
||||
return Response.json({ revalidated: true, now: Date.now() })
|
||||
} catch (error) {
|
||||
console.error("Failed to revalidate tag(s)")
|
||||
console.error(error)
|
||||
return internalServerError({ revalidated: false, now: Date.now() })
|
||||
}
|
||||
}
|
||||
15
apps/scandic-web/app/api/web/trpc/[trpc]/route.ts
Normal file
15
apps/scandic-web/app/api/web/trpc/[trpc]/route.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { fetchRequestHandler } from "@trpc/server/adapters/fetch"
|
||||
|
||||
import { appRouter } from "@/server"
|
||||
import { createContext } from "@/server/context"
|
||||
|
||||
async function handler(req: Request) {
|
||||
return fetchRequestHandler({
|
||||
createContext,
|
||||
endpoint: "/api/web/trpc",
|
||||
req,
|
||||
router: appRouter,
|
||||
})
|
||||
}
|
||||
|
||||
export { handler as GET, handler as POST }
|
||||
Reference in New Issue
Block a user