Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/six-buses-sit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@o2s/integrations.contentful-cms': minor
'@o2s/api-harmonization': minor
---

feat: added contentful integration
5 changes: 5 additions & 0 deletions apps/api-harmonization/.env.local
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,8 @@ MEDUSAJS_PUBLISHABLE_API_KEY=
MEDUSAJS_ADMIN_API_KEY=

SEARCH_ARTICLES_INDEX_NAME=mock

CF_TOKEN=
CF_SPACE_ID=
CF_ENV=
CF_MANAGEMENT_TOKEN=
7 changes: 6 additions & 1 deletion apps/api-harmonization/turbo.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,12 @@
"MEDUSAJS_ADMIN_API_KEY",
"SEARCH_ARTICLES_INDEX_NAME",
"TELEMETRY_DISABLED",
"TELEMETRY_BASE_URL"
"TELEMETRY_BASE_URL",
"ALGOLIA_API_KEY",
"CF_TOKEN",
"CF_SPACE_ID",
"CF_ENV",
"CF_MANAGEMENT_TOKEN"
]
}
}
Expand Down
4 changes: 3 additions & 1 deletion apps/frontend/.env.development
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ NEXT_PUBLIC_LOG_FORMAT=text
NEXT_PUBLIC_SUPPORTED_LOCALES=en,de,pl
NEXT_PUBLIC_DEFAULT_LOCALE=en

NEXT_PUBLIC_BASE_URL=http://localhost:3000
NEXT_PUBLIC_BASE_URL=https://localhost:3000

NEXT_PUBLIC_API_URL=http://localhost:3001/api
NEXT_PUBLIC_API_URL_INTERNAL=http://localhost:3001/api
Expand All @@ -25,3 +25,5 @@ AUTH_GITHUB_SECRET={GITHUB_ID}

AUTH_DATABASE_URL=file:./dev.db
AUTH_DEFAULT_USER_ROLE=selfservice_user

CF_PREVIEW_SECRET=q1AuSoM39k3Mymx7mYOvdsrmQBlAPaGA
17 changes: 17 additions & 0 deletions apps/frontend/next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,23 @@ const nextConfig: NextConfig = {

return config;
},
async headers() {
return [
{
source: '/:path*',
headers: [
{
key: 'X-Frame-Options',
value: 'SAMEORIGIN',
},
{
key: 'Content-Security-Policy',
value: `frame-ancestors 'self' https://app.contentful.com`,
},
],
},
];
},
};

export default withPlugins([withBundleAnalyzer, withNextIntl], nextConfig);
55 changes: 28 additions & 27 deletions apps/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
"version": "1.10.0",
"private": true,
"scripts": {
"dev": "next dev --turbopack",
"dev:https": "next dev --turbopack --experimental-https",
"dev1": "next dev --turbopack",
"dev": "next dev --turbopack --experimental-https",
"build": "next build",
"postbuild": "cp -r public .next/standalone/apps/frontend && cp -r .next/static .next/standalone/apps/frontend/.next/",
"start": "node .next/standalone/apps/frontend/server.js",
Expand All @@ -13,10 +13,34 @@
"generate:component": "turbo gen web-component"
},
"dependencies": {
"@contentful/live-preview": "^4.6.52",
"@o2s/api-harmonization": "*",
"@o2s/blocks.article": "*",
"@o2s/blocks.article-list": "*",
"@o2s/blocks.article-search": "*",
"@o2s/blocks.category": "*",
"@o2s/blocks.category-list": "*",
"@o2s/blocks.faq": "*",
"@o2s/blocks.featured-service-list": "*",
"@o2s/blocks.invoice-list": "*",
"@o2s/blocks.notification-details": "*",
"@o2s/blocks.notification-list": "*",
"@o2s/blocks.order-details": "*",
"@o2s/blocks.order-list": "*",
"@o2s/blocks.orders-summary": "*",
"@o2s/blocks.payments-history": "*",
"@o2s/blocks.payments-summary": "*",
"@o2s/blocks.quick-links": "*",
"@o2s/blocks.service-details": "*",
"@o2s/blocks.service-list": "*",
"@o2s/blocks.surveyjs-form": "*",
"@o2s/blocks.ticket-details": "*",
"@o2s/blocks.ticket-list": "*",
"@o2s/blocks.ticket-recent": "*",
"@o2s/blocks.user-account": "*",
"@o2s/framework": "*",
"@o2s/ui": "*",
"@o2s/integrations.mocked": "*",
"@o2s/ui": "*",
"@o2s/utils.api-harmonization": "*",
"@o2s/utils.frontend": "*",
"class-variance-authority": "^0.7.1",
Expand All @@ -34,30 +58,7 @@
"react-string-replace": "^1.1.1",
"string-template": "^1.0.0",
"yup": "^1.7.1",
"zod": "^4.1.12",
"@o2s/blocks.faq": "*",
"@o2s/blocks.invoice-list": "*",
"@o2s/blocks.notification-list": "*",
"@o2s/blocks.quick-links": "*",
"@o2s/blocks.ticket-details": "*",
"@o2s/blocks.ticket-list": "*",
"@o2s/blocks.ticket-recent": "*",
"@o2s/blocks.user-account": "*",
"@o2s/blocks.payments-history": "*",
"@o2s/blocks.payments-summary": "*",
"@o2s/blocks.orders-summary": "*",
"@o2s/blocks.order-details": "*",
"@o2s/blocks.order-list": "*",
"@o2s/blocks.service-details": "*",
"@o2s/blocks.service-list": "*",
"@o2s/blocks.featured-service-list": "*",
"@o2s/blocks.article": "*",
"@o2s/blocks.article-list": "*",
"@o2s/blocks.category-list": "*",
"@o2s/blocks.article-search": "*",
"@o2s/blocks.category": "*",
"@o2s/blocks.notification-details": "*",
"@o2s/blocks.surveyjs-form": "*"
"zod": "^4.1.12"
},
"devDependencies": {
"@next/bundle-analyzer": "^15.5.6",
Expand Down
39 changes: 24 additions & 15 deletions apps/frontend/src/app/[locale]/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { LivePreview } from '@o2s/configs.integrations/live-preview';
import { SessionProvider } from 'next-auth/react';
import { NextIntlClientProvider } from 'next-intl';
import { getMessages, setRequestLocale } from 'next-intl/server';
import { Inter } from 'next/font/google';
import { draftMode } from 'next/headers';
import { notFound } from 'next/navigation';
import React from 'react';

Expand All @@ -28,6 +30,7 @@ interface Props {

export default async function RootLayout({ children, params }: Props) {
const session = await auth();
const { isEnabled: isDraftModeEnabled } = await draftMode();

const { locale } = await params;

Expand All @@ -40,20 +43,26 @@ export default async function RootLayout({ children, params }: Props) {
const messages = await getMessages();

return (
<html lang={locale} className={`${inter.variable} antialiased`}>
<head>
<link rel="icon" type="image/png" href="/favicon/favicon-96x96.png" sizes="96x96" />
<link rel="icon" type="image/svg+xml" href="/favicon/favicon.svg" />
<link rel="shortcut icon" href="/favicon/favicon.ico" />
<link rel="apple-touch-icon" sizes="180x180" href="/favicon/apple-touch-icon.png" />
<meta name="apple-mobile-web-app-title" content="Open Self Service" />
</head>
{/*@see https://github.com/nextauthjs/next-auth/issues/9504#issuecomment-2516665386*/}
<SessionProvider key={session?.user?.id} session={session} refetchOnWindowFocus={false}>
<NextIntlClientProvider messages={messages}>
<TooltipProvider>{children}</TooltipProvider>
</NextIntlClientProvider>
</SessionProvider>
</html>
<LivePreview.Provider
locale={locale}
enableInspectorMode={isDraftModeEnabled}
enableLiveUpdates={isDraftModeEnabled}
>
<html lang={locale} className={`${inter.variable} antialiased`}>
<head>
<link rel="icon" type="image/png" href="/favicon/favicon-96x96.png" sizes="96x96" />
<link rel="icon" type="image/svg+xml" href="/favicon/favicon.svg" />
<link rel="shortcut icon" href="/favicon/favicon.ico" />
<link rel="apple-touch-icon" sizes="180x180" href="/favicon/apple-touch-icon.png" />
<meta name="apple-mobile-web-app-title" content="Open Self Service" />
</head>
{/*@see https://github.com/nextauthjs/next-auth/issues/9504#issuecomment-2516665386*/}
<SessionProvider key={session?.user?.id} session={session} refetchOnWindowFocus={false}>
<NextIntlClientProvider messages={messages}>
<TooltipProvider>{children}</TooltipProvider>
</NextIntlClientProvider>
</SessionProvider>
</html>
</LivePreview.Provider>
);
}
6 changes: 6 additions & 0 deletions apps/frontend/src/app/api/disable-draft/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { draftMode } from 'next/headers';

export async function GET() {
(await draftMode()).disable();
return new Response('Draft mode is disabled');
}
35 changes: 35 additions & 0 deletions apps/frontend/src/app/api/enable-draft/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { draftMode, cookies } from 'next/headers';
import { redirect } from 'next/navigation';
import { NextRequest } from 'next/server';

export async function GET(request: NextRequest) {
const { searchParams } = new URL(request.url);
const secret = searchParams.get('secret');
const slug = searchParams.get('slug');
const locale = searchParams.get('locale');

if (!secret || !slug || !locale) {
return new Response('Missing parameters', { status: 400 });
}

if (secret !== process.env.CF_PREVIEW_SECRET) {
return new Response('Invalid token', { status: 401 });
}

(await draftMode()).enable();

// Override cookie header for draft mode for usage in live-preview
// https://github.com/vercel/next.js/issues/49927
const cookieStore = await cookies();
const cookie = cookieStore.get('__prerender_bypass')!;
cookieStore.set({
name: '__prerender_bypass',
value: cookie?.value,
httpOnly: true,
path: '/',
secure: true,
sameSite: 'none',
});

redirect(`/${locale}/${slug}`);
}
70 changes: 70 additions & 0 deletions apps/frontend/src/auth/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,76 @@ export const nextAuthResult = NextAuth({
// Handle sign out
},
},
cookies: {
sessionToken: {
name: `authjs.session-token`,
options: {
httpOnly: true,
sameSite: 'none',
path: '/',
secure: true,
},
},
callbackUrl: {
name: `authjs.callback-url`,
options: {
httpOnly: true,
sameSite: 'none',
path: '/',
secure: true,
},
},
csrfToken: {
// Default to __Host- for CSRF token for additional protection if using useSecureCookies
// NB: The `__Host-` prefix is stricter than the `__Secure-` prefix.
name: `authjs.csrf-token`,
options: {
httpOnly: true,
sameSite: 'none',
path: '/',
secure: true,
},
},
pkceCodeVerifier: {
name: `authjs.pkce.code_verifier`,
options: {
httpOnly: true,
sameSite: 'none',
path: '/',
secure: true,
maxAge: 60 * 15, // 15 minutes in seconds
},
},
state: {
name: `authjs.state`,
options: {
httpOnly: true,
sameSite: 'none',
path: '/',
secure: true,
maxAge: 60 * 15, // 15 minutes in seconds
},
},
nonce: {
name: `authjs.nonce`,
options: {
httpOnly: true,
sameSite: 'none',
path: '/',
secure: true,
},
},
webauthnChallenge: {
name: `authjs.challenge`,
options: {
httpOnly: true,
sameSite: 'none',
path: '/',
secure: true,
maxAge: 60 * 15, // 15 minutes in seconds
},
},
},
});

export const { handlers, signIn, signOut } = nextAuthResult;
Expand Down
4 changes: 4 additions & 0 deletions apps/frontend/src/blocks/renderBlocks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import * as TicketList from '@o2s/blocks.ticket-list/frontend';
import * as TickeRecent from '@o2s/blocks.ticket-recent/frontend';
import * as UserAccount from '@o2s/blocks.user-account/frontend';
import { getLocale } from 'next-intl/server';
import { draftMode } from 'next/headers';
import React from 'react';

import { CMS } from '@o2s/framework/modules';
Expand All @@ -46,11 +47,13 @@ interface BlockProps {
userId: string | undefined;
routing: typeof routing;
hasPriority?: boolean;
isDraftModeEnabled?: boolean;
}

export const renderBlocks = async (blocks: CMS.Model.Page.SlotBlock[], slug: string[]) => {
const session = await auth();
const locale = await getLocale();
const { isEnabled: isDraftModeEnabled } = await draftMode();

return blocks.map((block, index) => {
// decides whether the block is above the fold,
Expand All @@ -65,6 +68,7 @@ export const renderBlocks = async (blocks: CMS.Model.Page.SlotBlock[], slug: str
userId: session?.user?.id,
routing: routing,
hasPriority,
isDraftModeEnabled: isDraftModeEnabled,
};

return (
Expand Down
Loading
Loading