Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate move app and document files to root layout, migrate meet the team page and create test of the page #1064

Draft
wants to merge 53 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
14de5c6
Create very basic Root Layout
boodland Jul 19, 2024
9afa500
Move Montserrat and Open Sans font to global css
boodland Jul 19, 2024
33a121d
Add Newrelic app router configuration
boodland Jul 19, 2024
a666c15
Add GoogleTagManager and Rollbar scripts
boodland Jul 19, 2024
a2c7bf2
Move primary main colour to a constant
boodland Jul 19, 2024
1de59c5
Add OpenGraph Metadata to root layout
boodland Jul 19, 2024
9561871
Merge branch 'develop' into Migrate--move-app-and-document-files-to-r…
boodland Jul 23, 2024
a2a6763
Add material ui app router configuration
boodland Jul 23, 2024
ac3c284
Add i18n app router configuration
boodland Jul 24, 2024
204468c
Create store provider for app router
boodland Jul 24, 2024
cd339cf
Create AppLayout for app router and make all imported components clie…
boodland Jul 24, 2024
b1ba75c
Add rest of the _app logic to root layout and make impoted components…
boodland Jul 24, 2024
f4e1afb
Fix formatting
boodland Jul 24, 2024
1b718e9
Make storyblock client components so storyblock can be init in app ro…
boodland Jul 24, 2024
2ac6212
Add app router for testing purpouse until we migrate the first one
boodland Jul 24, 2024
1fba2e8
Add comment to explain new public path
boodland Jul 24, 2024
58c1e5e
Add metadata to root layout
boodland Jul 24, 2024
5cb9b9d
Merge branch 'develop' into Migrate--move-app-and-document-files-to-r…
boodland Jul 24, 2024
73ba3c9
Add type that next is automatically adding due to the new version
boodland Jul 25, 2024
c9abab8
Remove non used router
boodland Jul 25, 2024
9515a71
Only use cookie to save locale
boodland Jul 25, 2024
0806a38
Tidy up i18n logic
boodland Jul 25, 2024
eafe1be
Create locale server service and split language menu for both route m…
boodland Jul 25, 2024
ded7eb8
Hacks to get working locale and solve locale always present in the url
boodland Jul 25, 2024
8eb1f0d
Test client page
boodland Jul 25, 2024
75a44d0
Add new dependency
boodland Jul 25, 2024
b4cc4b1
Migrate meet the team page so we have a real page to test
boodland Jul 26, 2024
18f16a1
Fix hydratation bug due to nested p
boodland Jul 26, 2024
5b4dbeb
Remove temporal testing page
boodland Jul 26, 2024
99fe765
Tidy up i18n logic
boodland Jul 26, 2024
43dd86f
Tidy up locale cookies logic
boodland Jul 26, 2024
56fd29d
Fixes after formatting
boodland Jul 26, 2024
8e7ba0b
Remove testing route from publicPathHeads
boodland Jul 26, 2024
01055b6
Remove delete cookies as it is breaking the i18n
boodland Jul 26, 2024
18c173e
Fix qa id label
boodland Jul 26, 2024
5cfabdf
Add meet the team test and fix hydratation problem found in the test
boodland Jul 26, 2024
3df7cd6
Remove unnecesary comment
boodland Jul 26, 2024
93b6f53
Remove no longer needed comment
boodland Jul 27, 2024
443943f
Merge branch 'develop' into Migrate--move-app-and-document-files-to-r…
boodland Aug 9, 2024
d9118e7
Add app router not found config and page
boodland Aug 12, 2024
21b473c
Fix 404 not being redirected using storyblok as reference
boodland Aug 12, 2024
4dd7e95
Add home redirect to match storyblok config
boodland Aug 12, 2024
cdb95d5
Remove comment added for debugging
boodland Aug 12, 2024
ce173e0
Add comment to clarify not found redirect issue
boodland Aug 12, 2024
ac9e376
Add more fixes to special pages
boodland Aug 12, 2024
66727cc
Yet more fixes
boodland Aug 12, 2024
0912997
Add all routeSegment path
boodland Aug 12, 2024
adfd636
Add valid and invalid routes hardcoded and remove query params
boodland Aug 12, 2024
e0ccaa4
Add return statment to new function
boodland Aug 12, 2024
f9b6aad
Retrieve storyblok data only once
boodland Aug 12, 2024
6c9bff2
If no locale is presnt join with the rest of the url
boodland Aug 12, 2024
b482734
Tidy up meet the team client component
boodland Aug 13, 2024
502faf6
Add all the proof of concept that worked for app router
boodland Aug 14, 2024
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
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,10 @@ Chayn team members usually respond within 3 business days.
Chayn is open to all kinds of contributions, such as:

- additional software tests / test coverage
- dependency updates *check Dependabot pull requests
- dependency updates \*check Dependabot pull requests
- code (requested features, bug fixes, quality enhancements, maintenance help)
- accessibility and language support.
- no-code (documentation, translations) *see spam policy below for accepted documentation changes.
- no-code (documentation, translations) \*see spam policy below for accepted documentation changes.

# Chayn's Spam Contribution Policy 🚫

Expand Down
17 changes: 17 additions & 0 deletions app/ThemeRegistry.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { AppRouterCacheProvider } from '@mui/material-nextjs/v13-appRouter';
import CssBaseline from '@mui/material/CssBaseline';
import { ThemeProvider } from '@mui/material/styles';
import theme from '../styles/theme';

// This implementation is from mui integrations with nextjs app router
// see https://mui.com/material-ui/integrations/nextjs/#app-router
export default function ThemeRegistry({ children }: { children: React.ReactNode }) {
return (
<AppRouterCacheProvider>
<ThemeProvider theme={theme}>
<CssBaseline />
{children}
</ThemeProvider>
</AppRouterCacheProvider>
);
}
41 changes: 10 additions & 31 deletions pages/chat.tsx → app/[locale]/chat/chat.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,18 @@
'use client';

import { Box } from '@mui/material';
import { ISbStoryData, useStoryblokState } from '@storyblok/react';
import { GetStaticPropsContext, NextPage } from 'next';
import { useTranslations } from 'next-intl';
import Head from 'next/head';
import { SignUpBanner } from '../components/banner/SignUpBanner';
import NoDataAvailable from '../components/common/NoDataAvailable';
import CrispButton from '../components/crisp/CrispButton';
import Header, { HeaderProps } from '../components/layout/Header';
import StoryblokPageSection from '../components/storyblok/StoryblokPageSection';
import { useTypedSelector } from '../hooks/store';
import { getStoryblokPageProps } from '../utils/getStoryblokPageProps';
import { getEventUserData } from '../utils/logEvent';

interface Props {
story: ISbStoryData | null;
}
import { SignUpBanner } from '../../../components/banner/SignUpBanner';
import NoDataAvailable from '../../../components/common/NoDataAvailable';
import CrispButton from '../../../components/crisp/CrispButton';
import Header, { HeaderProps } from '../../../components/layout/Header';
import StoryblokPageSection from '../../../components/storyblok/StoryblokPageSection';
import { useTypedSelector } from '../../../hooks/store';
import { getEventUserData } from '../../../utils/logEvent';

const Chat: NextPage<Props> = ({ story }) => {
const Chat = ({ story }: { story: ISbStoryData | null }) => {
story = useStoryblokState(story);

const t = useTranslations('Courses');
Expand Down Expand Up @@ -68,21 +64,4 @@ const Chat: NextPage<Props> = ({ story }) => {
);
};

export async function getStaticProps({ locale, preview = false }: GetStaticPropsContext) {
const storyblokProps = await getStoryblokPageProps('chat', locale, preview);

return {
props: {
...storyblokProps,
messages: {
...require(`../messages/shared/${locale}.json`),
...require(`../messages/navigation/${locale}.json`),
...require(`../messages/courses/${locale}.json`),
...require(`../messages/chat/${locale}.json`),
},
},
revalidate: 3600, // revalidate every hour
};
}

export default Chat;
19 changes: 19 additions & 0 deletions app/[locale]/chat/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { getLocale } from 'next-intl/server';
import { locales } from '../../../i18n/config';
import { getStoryblokPageProps } from '../../../utils/getStoryblokPageProps';
import Chat from './chat';

export const revalidate = 3600;

export default async function Page() {
const preview = false;
const locale = await getLocale();
const storyblokProps = await getStoryblokPageProps('chat', locale, preview);
return <Chat story={storyblokProps?.story}></Chat>;
}

export async function generateStaticParams() {
return locales.map((locale) => {
return { params: { locale } };
});
}
13 changes: 13 additions & 0 deletions app/[locale]/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { locales } from '../../i18n/config';

const Layout = ({ children }: { children: React.ReactNode }) => {
return <>{children}</>;
};

export async function generateStaticParams() {
return locales.map((locale) => {
return { params: { locale } };
});
}

export default Layout;
23 changes: 23 additions & 0 deletions app/[locale]/meet-the-team/meet-the-team.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
'use client';

import { ISbStoryData, useStoryblokState } from '@storyblok/react';
import NoDataAvailable from '../../../components/common/NoDataAvailable';
import StoryblokMeetTheTeamPage, {
StoryblokMeetTheTeamPageProps,
} from '../../../components/storyblok/StoryblokMeetTheTeamPage';

interface MeetTheTeamProps {
story: ISbStoryData | null;
}

const MeetTheTeam = ({ story }: MeetTheTeamProps) => {
const storyData = useStoryblokState(story);

if (!storyData) {
return <NoDataAvailable />;
}

return <StoryblokMeetTheTeamPage {...(storyData.content as StoryblokMeetTheTeamPageProps)} />;
};

export default MeetTheTeam;
11 changes: 11 additions & 0 deletions app/[locale]/meet-the-team/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { getStoryblokPageProps } from '../../../utils/getStoryblokPageProps';
import MeetTheTeam from './meet-the-team';

export const revalidate = 3600;

export default async function Page({ params }: { params: { locale: string } }) {
const preview = false;
const locale = params.locale;
const storyblokProps = await getStoryblokPageProps('meet-the-team', locale, preview);
return <MeetTheTeam story={storyblokProps?.story}></MeetTheTeam>;
}
46 changes: 46 additions & 0 deletions app/[locale]/welcome/[partnerName]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { getStoryblokApi, ISbStoriesParams, ISbStoryData } from '@storyblok/react';
import { locales } from '../../../../i18n/config';
import { getStoryblokPageProps } from '../../../../utils/getStoryblokPageProps';
import Welcome from './welcome';

export const revalidate = 3600;

export default async function Page({
params,
}: {
params: { partnerName: string; locale: string };
}) {
const preview = false;
const locale = params.locale;
const partnerName = params?.partnerName;
const storyblokProps = await getStoryblokPageProps(`welcome/${partnerName}`, locale, preview);
return <Welcome story={storyblokProps?.story}></Welcome>;
}

export async function generateStaticParams() {
let sbParams: ISbStoriesParams = {
published: true,
starts_with: 'partnership/',
};

const storyblokApi = getStoryblokApi();
let data = await storyblokApi.getAll('cdn/links', sbParams);

let paths: any = [];

data.forEach((story: Partial<ISbStoryData>) => {
if (!story.slug) return;

// get array for slug because of catch all
let splittedSlug = story.slug.split('/');

if (locales) {
// create additional languages
for (const locale of locales) {
paths.push({ params: { partnerName: splittedSlug[1] } });
}
}
});

return paths;
}
28 changes: 28 additions & 0 deletions app/[locale]/welcome/[partnerName]/welcome.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
'use client';

import { ISbStoryData, useStoryblokState } from '@storyblok/react';
import NoDataAvailable from '../../../../components/common/NoDataAvailable';
import StoryblokWelcomePage, {
StoryblokWelcomePageProps,
} from '../../../../components/storyblok/StoryblokWelcomePage';

interface WelcomeProps {
story: ISbStoryData | null;
}

const Welcome = ({ story }: WelcomeProps) => {
story = useStoryblokState(story);

if (!story) {
return <NoDataAvailable />;
}

return (
<StoryblokWelcomePage
{...(story.content as StoryblokWelcomePageProps)}
storySlug={story.slug}
/>
);
};

export default Welcome;
61 changes: 61 additions & 0 deletions app/appLayout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
'use client';

import { Analytics } from '@mui/icons-material';
import { usePathname } from 'next/navigation';
import { Hotjar } from 'nextjs-hotjar';
import { useEffect } from 'react';
import { AppBarSpacer } from '../components/layout/AppBarSpacer';
import Consent from '../components/layout/Consent';
import Footer from '../components/layout/Footer';
import LanguageMenuAppRoute from '../components/layout/LanguageMenuAppRoute';
import LeaveSiteButton from '../components/layout/LeaveSiteButton';
import TopBar from '../components/layout/TopBar';
import firebase from '../config/firebase';
import { AuthGuard } from '../guards/AuthGuard';

interface AppLayoutProps {
children?: React.ReactNode;
}

// Init firebase
firebase;

export default function AppLayout({ children }: AppLayoutProps) {
const pathname = usePathname();

// Get top level directory of path e.g pathname /courses/course_name has pathHead courses
const pathHead = pathname?.split('/')[1]; // E.g. courses | therapy | partner-admin

useEffect(() => {
// Check if entry path is from a partner referral and if so, store referring partner in local storage
// This enables us to redirect a user to the correct sign up page later (e.g. in SignUpBanner)
const path = pathname;

if (path?.includes('/welcome/')) {
const referralPartner = path.split('/')[2]; // Gets "bumble" from /welcome/bumble

if (referralPartner) {
window.localStorage.setItem('referralPartner', referralPartner);
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

return (
<>
<TopBar>
<LanguageMenuAppRoute />
</TopBar>
<AppBarSpacer />
{pathHead !== 'partner-admin' && <LeaveSiteButton />}
<AuthGuard>{children as JSX.Element}</AuthGuard>
<Footer />
<Consent />
{!!process.env.NEXT_PUBLIC_HOTJAR_ID && process.env.NEXT_PUBLIC_ENV !== 'local' && (
<Hotjar id={process.env.NEXT_PUBLIC_HOTJAR_ID} sv={6} strategy="lazyOnload" />
)}
{/* Vercel analytics */}
<Analytics />
</>
);
}
91 changes: 91 additions & 0 deletions app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import newrelic from 'newrelic';
import Script from 'next/script';

import { Metadata } from 'next';
import { NextIntlClientProvider } from 'next-intl';
import { getLocale, getMessages } from 'next-intl/server';
import CrispScript from '../components/crisp/CrispScript';
import GoogleTagManagerScript from '../components/head/GoogleTagManagerScript';
import OpenGraphMetadata from '../components/head/OpenGraphMetadata';
import RollbarScript from '../components/head/RollbarScript';
import ErrorBoundary from '../components/layout/ErrorBoundary';
import { storyblok } from '../config/storyblok';
import StoreProvider from '../store/storeProvider';
import '../styles/globals.css';
import AppLayout from './appLayout';
import ThemeRegistry from './ThemeRegistry';

// Init storyblok
storyblok;

export const metadata: Metadata = {
title: 'Bloom',
};

export const dynamicParams = false;

export default async function RootLayout({
// Layouts must accept a children prop.
// This will be populated with nested layouts or pages
children,
}: {
children: React.ReactNode;
}) {
// Configuration according to Newrelic app router example
// See https://github.com/newrelic/newrelic-node-nextjs?tab=readme-ov-file#example-projects
// @ts-ignore
if (newrelic.agent.collector.isConnected() === false) {
await new Promise((resolve) => {
// @ts-ignore
newrelic.agent.on('connected', resolve);
});
}

const browserTimingHeader = newrelic.getBrowserTimingHeader({
hasToRemoveScriptWrapper: true,
// @ts-ignore
allowTransactionlessInjection: true,
});

const locale = await getLocale();

// Providing all messages to the client
// side is the easiest way to get started
const messages = await getMessages();

return (
<html lang={locale}>
<head>
<OpenGraphMetadata />
<GoogleTagManagerScript />
<RollbarScript />
</head>
<body>
<StoreProvider>
<ErrorBoundary>
<NextIntlClientProvider messages={messages}>
<CrispScript />
<ThemeRegistry>
<AppLayout>{children}</AppLayout>
</ThemeRegistry>
</NextIntlClientProvider>
</ErrorBoundary>
</StoreProvider>
<Script
// We have to set an id for inline scripts.
// See https://nextjs.org/docs/app/building-your-application/optimizing/scripts#inline-scripts
id="nr-browser-agent"
// By setting the strategy to "beforeInteractive" we guarantee that
// the script will be added to the document's `head` element.
strategy="beforeInteractive"
// The body of the script element comes from the async evaluation
// of `getInitialProps`. We use the special
// `dangerouslySetInnerHTML` to provide that element body. Since
// it requires an object with an `__html` property, we pass in an
// object literal.
dangerouslySetInnerHTML={{ __html: browserTimingHeader }}
/>
</body>
</html>
);
}
5 changes: 5 additions & 0 deletions app/not-found.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { redirect } from 'next/navigation';

export default function Page() {
redirect('/404');
}
Loading
Loading