Skip to content

Commit

Permalink
🚢 App Router PoC - Products Pages (#2420)
Browse files Browse the repository at this point in the history
* added first iteration of products index

* fixed menuwrapper reference

* fixed broken undefined

* fixed next/router

* added draft mode stuff

* simplified client + server pages

* updated schema

* added cache + analytics scripts

* added next/third-parties for GTM

* added loading fallback

* added page stub code

* added generateStaticParams to dynamic route

* added force-static to layout for megamenu

* added basic notfound page

* added back old way of doing gtm

* added dynamic routing

* made lint fix

* added caching for megamenu

* added icons as metadata

* fixed import

* fixed broken type declarations

* fixed reference to error boundary

* added timestamp to layout

* changed to be string

* added viewport tag

* added gh actions cache

* changed ot be hash of pnpm lock

* removed change to workflow

* removed timestamps, added better typing

* changed data fetching logic

* removed dynamic params, added footer

* added timestamp rerun

* renamed draft api url

* added similar behaviour of pages

* made it force static

* added back cache thing

* Removing i18n from the config

* Adding Tina for the dynamic component

* Adding updated pnpm.lock

* Fixing clientpage path

* adding App router breadcrumb

* Added megamenu styling

* Adding updated pnpm and tina lock

* Adding use client tag for domain query

* Adding metadata for the /product route

* Fixing the default MetaData issue

* Adding metadata for the dynamic products' route

* Removing unused import

* Removed the comments that are completed

* Adding 404 page for App Routing

* Fixing layout for the loading page

* removing metadatabase prop

* Adding breadcrumb for the dynamic routes of /products

* Adding switch for Draft mode

* Cleanup for the edit mode

* Adding updated pnpm lock

* Adding logic of enabling draft on login

* Refactoring the component names as per their route

* Fixing typos with file name

* Fixing the naming conventions for product dynamic routes

* Fixing relative path for the dynamic product routes

* Adding metabase URL for metadata

* Adding hostname to redirect when it gets login

* Adding live banner component for the app routing

* Updating references

* removing false true

* Splitting code for better readability

* Fixing seo route with product review component

* fixing the data issue with global variable

* Removing the redirect

* Adding isPreview variable to improve readability

* removing themeColor as it's not supported by metadata

* Fixing the import for userRouter carousel

* Removing the async function for production collection

* Adding comments for the authentication on enabling draft mode

* Adding some more modular imports

* Adding updated pnpm-lock file

* Adding doc link for dynamic props

* Adding GTM using thirdparty scripts

---------

Co-authored-by: Aman Kumar [SSW] <[email protected]>
  • Loading branch information
Harry-Ross and amankumarrr authored May 8, 2024
1 parent 1ad83e5 commit 1bf2885
Show file tree
Hide file tree
Showing 72 changed files with 1,542 additions and 317 deletions.
8 changes: 8 additions & 0 deletions app/api/disable-draft/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { draftMode } from "next/headers";

export async function GET() {
draftMode().disable();
return new Response("Draft mode disabled", {
status: 200,
});
}
9 changes: 9 additions & 0 deletions app/api/enable-draft/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { draftMode } from "next/headers";

export async function GET() {
//TODO: ADD Tina Authentication
draftMode().enable();
return new Response("Draft mode enabled", {
status: 200,
});
}
50 changes: 50 additions & 0 deletions app/components/breadcrumb.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import NextBreadcrumbs from "@marketsystems/nextjs13-appdir-breadcrumbs";
import React, { FC } from "react";
import { tinaField } from "tinacms/dist/react";

interface BreadcrumbsProps {
path: string;
suffix: string;
title: string;
seoSchema?: {
title?: string;
};
}
export const Breadcrumbs: FC<BreadcrumbsProps> = (props) => {
const listItemStyling =
"breadcrumb_item inline text-xs text-gray-700 no-underline not-first:before:content-bread not-first:before:px-2 before:list-none";

return (
<div
{...(props.seoSchema
? { "data-tina-field": tinaField(props.seoSchema, "title") }
: {})}
>
<NextBreadcrumbs
replaceCharacterList={[
{ from: "consulting", to: "Services" },
{ from: "products", to: "Products" },
{ from: "offices", to: "Offices" },
{ from: "training", to: "Training" },
{ from: "employment", to: "Employment" },
{ from: "video-production", to: "Video Production" },
{ from: "Training-videos", to: "Training Videos" },
{ from: "industry", to: "Industry" },
{ from: "company", to: "Company" },
{ from: "events", to: "Events" },
{ from: "partners", to: "Partners" },
{ from: "netug", to: ".NET User Group" },
{ from: "clients", to: "Clients" },
{ from: "live", to: "Live" },
{ from: "logo", to: "Logo" },
{ from: props.path, to: `${props.title}` },
]}
useDefaultStyle={true}
activeItemClassName={listItemStyling}
inactiveItemClassName={listItemStyling}
listClassName="pl-0"
rootLabel={"Home"}
/>
</div>
);
};
88 changes: 88 additions & 0 deletions app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import "styles.css";

// import { CustomLink } from "@/components/customLink";
// import { Footer } from "@/components/layout/footer";
import classNames from "classnames";
import { Open_Sans } from "next/font/google";
// import Head from "next/head";
// import { Theme } from "../components/layout/theme";
import { Footer } from "@/components/layout/footer/footer";
import { MenuWrapper } from "@/components/server/MenuWrapper";
import ChatBaseBot from "@/components/zendeskButton/chatBaseBot";
import { Metadata, Viewport } from "next";

import { EventInfo } from "@/services/server/events";
import { GoogleTagManager } from "@next/third-parties/google";
import dayjs from "dayjs";
import advancedFormat from "dayjs/plugin/advancedFormat";
import isBetween from "dayjs/plugin/isBetween";
import relativeTime from "dayjs/plugin/relativeTime";
import timezone from "dayjs/plugin/timezone";
import utc from "dayjs/plugin/utc";
import Head from "next/head";
import { LiveSteam } from "./live-steam-banner/live-stream";
import { DEFAULT } from "./meta-data/default";
import { getLiveStreamData } from "./utils/get-live-stream-data";
import { getMegamenu } from "./utils/get-mega-menu";

dayjs.extend(relativeTime);
dayjs.extend(timezone);
dayjs.extend(utc);
dayjs.extend(advancedFormat);
dayjs.extend(isBetween);

const openSans = Open_Sans({
variable: "--open-sans-font",
subsets: ["latin"],
});

export const DEFAULT_METADATA: Metadata = {
...DEFAULT,
};

export const viewport: Viewport = {
themeColor: "#ffffff",
};

export default async function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
const menuData = await getMegamenu();
const liveStreamData: EventInfo = await getLiveStreamData();

return (
<html lang="en" className={openSans.className}>
<Head>
<meta charSet="utf-8" />
<meta name="viewport" content="initial-scale=1.0, width=device-width" />
<link rel="manifest" href="/site.webmanifest" />
<meta name="msapplication-TileColor" content="#cc4141" />
<meta name="theme-color" content="#ffffff" />
</Head>
<body>
{/* <Theme> */}
{/* Ensures next/font CSS variable is accessible for all components */}
<div
className={classNames(
"flex min-h-screen flex-col font-sans",
openSans.className
)}
>
<header className="no-print">
<LiveSteam event={liveStreamData}>
<MenuWrapper menu={menuData.data.megamenu.menuGroups} />
</LiveSteam>
</header>
<main className="grow bg-white">{children}</main>

<Footer />
</div>
{/* </Theme> */}
<GoogleTagManager gtmId={process.env.NEXT_PUBLIC_GOOGLE_GTM_ID} />
<ChatBaseBot />
</body>
</html>
);
}
118 changes: 118 additions & 0 deletions app/live-steam-banner/live-stream.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
"use client";

import dayjs from "dayjs";
import advancedFormat from "dayjs/plugin/advancedFormat";
import isBetween from "dayjs/plugin/isBetween";

import relativeTime from "dayjs/plugin/relativeTime";
import timezone from "dayjs/plugin/timezone";
import utc from "dayjs/plugin/utc";
import dynamic from "next/dynamic";

import { EventInfo } from "@/services/server/events";
import { PropsWithChildren, useEffect, useState } from "react";

dayjs.extend(relativeTime);
dayjs.extend(timezone);
dayjs.extend(utc);
dayjs.extend(advancedFormat);
dayjs.extend(isBetween);

const LiveStreamWidget = dynamic(
() => {
return import("./liveStreamWidget").then((mod) => mod.LiveStreamWidget);
},
{
loading: () => <></>,
ssr: true,
}
);

const LiveStreamBanner = dynamic(
() => {
return import("@/components/liveStream/liveStreamBanner").then(
(mod) => mod.LiveStreamBanner
);
},
{
loading: () => <></>,
ssr: true,
}
);

const INTERVAL_MINUTES = 1;

interface LiveStreamProps extends PropsWithChildren {
event: EventInfo;
}

export function LiveSteam({ event, children }: LiveStreamProps) {
const [countdownMins, setCountdownMins] = useState<number>();
const [liveStreamDelayMinutes, setLiveStreamDelayMinutes] = useState(0);

useEffect(() => {
if (!event?.StartDateTime || !event?.EndDateTime) {
return;
}

const rightnow = dayjs()?.utc();

const liveDelay = event.SSW_LiveStreamDelayMinutes ?? 0;
if (!liveStreamDelayMinutes && event.SSW_DelayedLiveStreamStart) {
setLiveStreamDelayMinutes(liveDelay);
}

const start = dayjs(event.StartDateTime).add(liveDelay, "minute");
const minsToStart = start.diff(rightnow, "minute");
setCountdownMins(minsToStart);

const timer = setInterval(
() => {
setCountdownMins((countdownMins) => {
if (!countdownMins) return minsToStart;
return countdownMins - INTERVAL_MINUTES;
});
},
INTERVAL_MINUTES * 60 * 1000
);

return () => clearInterval(timer);
}, [event, liveStreamDelayMinutes]);

const rightnow = dayjs().utc();

const isLive =
countdownMins &&
countdownMins <= 0 &&
!!event &&
rightnow.isBefore(event?.EndDateTime);

const showBanner =
!!event &&
dayjs().isBetween(
dayjs(event.StartShowBannerDateTime),
dayjs(event.EndShowBannerDateTime),
null,
"[)"
);

return (
<>
{showBanner && (
<LiveStreamBanner
{...{ countdownMins, liveStreamDelayMinutes, isLive, event }}
isLive={!!isLive}
/>
)}
<div className="mx-auto max-w-9xl px-8">
{isLive && (
<LiveStreamWidget
{...{ event, liveStreamDelayMinutes }}
isLive={!!isLive}
/>
)}
{children}
</div>
</>
);
}
Loading

0 comments on commit 1bf2885

Please sign in to comment.