Skip to content

Commit

Permalink
💸 Tech Debt - SharePoint Events Data (#879)
Browse files Browse the repository at this point in the history
* Basic uploading functionality added to newletter form

* Basic implementation of file upload in TinaCMS

* Added image component to schema

* Moved custom file upload component to its own file

* Working file link with TinaCMS

* Removed useless newsletter API routes

* Refactored services to work with constant

* Cleanup of newsletter table

* Updated schema with updated newsletter logic

* Cleaned custom file upload component

* Removed uneeded packages

* Removed uneeded test uploads

* Working OAuth bearer token request

* Working token request system with correct permissions

* Working returning events from Sharepoint

* Removed archived code

* Renamed index service to events

* basic replacement of previous API routes

* Added env variables, simplified API flow

* Removed token endpoint and removed packages

* Undid weird branch changes from newsletter upload branch

* Added sanitisation of speaker ids

* Added sanitisation of input filter values

* Added app insights logging to new API routes

* Separated services into client/server services

* Added bicep config for environment variables

* Fixed broken import

* Refactored custom hook, added dynamic component for lighthouse testing

* Removed commented suspense elements

* Added null coalescing for YouTube

* Removed query string, added conditional useeffect

* Removed validator, replaced with regex

* Changed tooltip on livestream button

* Removed tooltip from livestream widget

* Renamed liveStreamWidget, removed link icon

* 🔊 Log when there are missing env vars

---------

Co-authored-by: Brady Stroud [SSW] <[email protected]>
  • Loading branch information
Harry-Ross and bradystroud authored Jun 28, 2023
1 parent 2759e4f commit 0b7b88a
Show file tree
Hide file tree
Showing 32 changed files with 657 additions and 428 deletions.
10 changes: 10 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,13 @@ GOOGLE_RECAPTCHA_SITE_KEY=***

# New server-side recaptcha key - Previously it was GOOGLE_RECAPTCHA_KEY_v2
GOOGLE_RECAPTCHA_KEY=***

# Microsoft OAuth Keys
MICROSOFT_OAUTH_TENANT_ID=***
MICROSOFT_OAUTH_CLIENT_ID=***
MICROSOFT_OAUTH_CLIENT_SECRET=***

# SharePoint Site and List IDs
SHAREPOINT_SITE_ID=***
SHAREPOINT_EVENTS_LIST_ID=***
SHAREPOINT_EXTERNAL_PRESENTERS_LIST_ID=***
2 changes: 1 addition & 1 deletion .tina/collections/newsletters.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { transformIntToMonth } from "../../services/date.service";
import type { Collection } from "tinacms";
import { transformIntToMonth } from "../../services/client/date.service";

export const newsletterSchema: Collection = {
label: "Newsletters",
Expand Down
10 changes: 5 additions & 5 deletions .tina/config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,18 @@ import {
consultingTagSchema,
} from "./collections/consulting";
import { educationalSchema } from "./collections/educational";
import { employmentSchema } from "./collections/employment";
import { globalSchema } from "./collections/global";
import { marketingSchema } from "./collections/marketing";
import { officeSchema, officeIndexSchema } from "./collections/offices";
import { newsletterSchema } from "./collections/newsletters";
import { officeIndexSchema, officeSchema } from "./collections/offices";
import { opportunitiesSchema } from "./collections/opportunities";
import { pagesSchema } from "./collections/pages";
import { technologiesSchema } from "./collections/technologies";
import { productsIndexSchema } from "./collections/products";
import { technologiesSchema } from "./collections/technologies";
import { testimonialCategoriesSchema } from "./collections/testimonialCategories";
import { testimonialSchema } from "./collections/testimonials";
import { employmentSchema } from "./collections/employment";
import { trainingSchema } from "./collections/training";
import { newsletterSchema } from "./collections/newsletters";
import { opportunitiesSchema } from "./collections/opportunities";

const config = defineStaticConfig({
clientId: process.env.NEXT_PUBLIC_TINA_CLIENT_ID!,
Expand Down
4 changes: 2 additions & 2 deletions components/blocks/newslettersTable.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { useEffect, useState } from "react";
import { FaSpinner } from "react-icons/fa";
import { Template } from "tinacms";
import { transformIntToMonth } from "../../services/date.service";
import client from "../../.tina/__generated__/client";
import { FaSpinner } from "react-icons/fa";
import { transformIntToMonth } from "../../services/client/date.service";

/**
* Render a table of newsletters.
Expand Down
4 changes: 2 additions & 2 deletions components/blocks/upcomingEvents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { useEffect, useState } from "react";
import type { Template } from "tinacms";

import axios from "axios";
import { EventInfo, LiveStreamBannerInfo } from "../../services";
import { EventInfo, LiveStreamBannerInfo } from "../../services/server/events";

dayjs.extend(utc);
dayjs.extend(isBetween);
Expand Down Expand Up @@ -69,7 +69,7 @@ const renderEvent = (e: EventInfo) => {
!e.Url.Url.includes("ssw.com.au") || e.Url.Url.includes("/ssw/redirect");

return (
<article key={e.Id} className="flex">
<article key={e.id} className="flex">
<div className="flex min-w-fit items-center">
<Link href={e.Thumbnail.Url}>
<Image
Expand Down
2 changes: 1 addition & 1 deletion components/bookingForm/bookingFormSubmissionData.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BookingFormSubmissionData } from "../../services";
import { BookingFormSubmissionData } from "../../services/server/events";

export const bookingFormSubmissionData = (
values,
Expand Down
44 changes: 31 additions & 13 deletions components/layout/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
import { Suspense } from "react";
import Head from "next/head";
import { useRouter } from "next/router";
import { MenuBar } from "ssw.megamenu";
import { classNames } from "tinacms";
import { Header } from "./header";
import { useLiveStreamProps } from "../liveStream/useLiveStreamProps";
import { Footer } from "./footer";
import { Header } from "./header";
import { Theme } from "./theme";
import { MenuBar } from "ssw.megamenu";
import { LiveStream } from "../liveStream/liveStream";
import { LiveStreamBanner } from "../liveStream/liveStreamBanner";
import { useLiveStreamProps } from "../liveStream/useLiveStreamProps";

import layoutData from "../../content/global/index.json";
import dynamic from "next/dynamic";
import { Open_Sans } from "next/font/google";
import layoutData from "../../content/global/index.json";

export const openSans = Open_Sans({
variable: "--open-sans-font",
Expand All @@ -27,6 +25,30 @@ const structuredData = {
url: layoutData.header.url,
};

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

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

export const Layout = ({ children, className = "" }) => {
const liveStreamProps = useLiveStreamProps();
const router = useRouter();
Expand Down Expand Up @@ -58,15 +80,11 @@ export const Layout = ({ children, className = "" }) => {
)}
>
<header className="no-print">
<Suspense fallback={<></>}>
<LiveStreamBanner {...liveStreamProps} />
</Suspense>
<DynamicLiveStreamBanner {...liveStreamProps} />
<div className="mx-auto max-w-9xl px-6 sm:px-8">
<Header />
<MenuBar />
<Suspense fallback={<></>}>
<LiveStream {...liveStreamProps} />
</Suspense>
<DynamicLiveStreamWidget {...liveStreamProps} />
</div>
</header>
<main className="grow bg-white">{children}</main>
Expand Down
54 changes: 26 additions & 28 deletions components/liveStream/liveStreamBanner.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import Link from "next/link";
import classNames from "classnames";
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 Link from "next/link";
import { useRouter } from "next/router";
import { FC, useEffect, useState } from "react";
import countdownTextFormat from "../../helpers/countdownTextFormat";
Expand Down Expand Up @@ -54,33 +54,31 @@ export const LiveStreamBanner: FC<LiveStreamProps> = ({
);
}, [countdownMins, event]);

if (!event?.StartDateTime) return <></>;

if (showBanner) {
const liveText = "Streaming live now.";
return (
<div className="w-full bg-gray-900">
<Link className="unstyled" href="/live">
<div
className={classNames(
"mx-auto max-w-9xl bg-gray-900 bg-right-top bg-no-repeat px-6 py-1 uppercase sm:px-8",
isLive ? "md:bg-live-banner-live" : "md:bg-live-banner-wait"
)}
>
<h1 className="m-0 py-0 text-xl font-light text-gray-300">
{event.Title}
</h1>
<p className="py-0 text-xs text-white">
<span className="block text-sswRed">
{isLive ? liveText : countdownText}
</span>
{!isLive && scheduledTimeText(dayjs(event.StartDateTime))}
</p>
</div>
</Link>
</div>
);
} else {
if (!event?.StartDateTime || !showBanner) {
return <></>;
}

const liveText = "Streaming live now.";
return (
<div className="w-full bg-gray-900">
<Link className="unstyled" href="/live">
<div
className={classNames(
"mx-auto max-w-9xl bg-gray-900 bg-right-top bg-no-repeat px-6 py-1 uppercase sm:px-8",
isLive ? "md:bg-live-banner-live" : "md:bg-live-banner-wait"
)}
>
<h1 className="m-0 py-0 text-xl font-light text-gray-300">
{event.Title}
</h1>
<p className="py-0 text-xs text-white">
<span className="block text-sswRed">
{isLive ? liveText : countdownText}
</span>
{!isLive && scheduledTimeText(dayjs(event.StartDateTime))}
</p>
</div>
</Link>
</div>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,15 @@ import { FC, useEffect, useState } from "react";
import { TfiAngleDown, TfiAngleUp } from "react-icons/tfi";
import { Tooltip } from "react-tooltip";
import layoutData from "../../content/global/index.json";
import { LiveStreamWidgetInfo, SpeakerInfo } from "../../services";
import { SpeakerInfo } from "../../services/server/events";
import { SubNewsLetters } from "../blocks/subNewsLetters";
import ReactPlayer from "../reactPlayer/reactPlayer";
import { SocialIcons, SocialTypes } from "../util/socialIcons";
import { LiveStreamProps } from "./useLiveStreamProps";

export const LiveStream: FC<LiveStreamProps> = ({ isLive, event }) => {
export const LiveStreamWidget: FC<LiveStreamProps> = ({ isLive, event }) => {
const eventDescriptionCollapseId = "eventDescription";

const [widgetInfo, setWidgetInfo] = useState<LiveStreamWidgetInfo>();
const [speakersInfo, setSpeakersInfo] = useState<SpeakerInfo[]>([]);
const [youtubeUrls, setYoutubeUrls] = useState<{
videoUrl?: string;
Expand Down Expand Up @@ -53,67 +52,55 @@ export const LiveStream: FC<LiveStreamProps> = ({ isLive, event }) => {
return;
}

const widgetInfoRes = await axios.get<LiveStreamWidgetInfo>(
"/api/get-livestream-widget",
{
params: { eventId: event.Id },
}
);

if (widgetInfoRes.status === 200 && widgetInfoRes.data) {
setWidgetInfo(widgetInfoRes.data);

setYoutubeUrls({
videoUrl: `https://www.youtube.com/embed/${widgetInfoRes.data.YouTubeId}?rel=0&autoplay=1`,
chatUrl: `https://www.youtube.com/live_chat?v=${widgetInfoRes.data.YouTubeId}&embed_domain=${window.location.hostname}`,
liveStreamUrl: `https://www.youtube.com/watch?v=${widgetInfoRes.data.YouTubeId}`,
});
setYoutubeUrls({
videoUrl: `https://www.youtube.com/embed/${event?.YouTubeId}?rel=0&autoplay=1`,
chatUrl: `https://www.youtube.com/live_chat?v=${event?.YouTubeId}&embed_domain=${window.location.hostname}`,
liveStreamUrl: `https://www.youtube.com/watch?v=${event?.YouTubeId}`,
});

const ids: string[] = [];
const emails: string[] = [];
const ids: string[] = [];
const emails: string[] = [];

if (widgetInfoRes.data.ExternalPresentersId?.results?.length) {
ids.push(...widgetInfoRes.data.ExternalPresentersId.results);
}
if (event.ExternalPresenters?.length) {
const presenterIds = event.ExternalPresenters.map((presenter) =>
presenter.LookupId.toString()
);
ids.push(...presenterIds);
}

if (widgetInfoRes.data.InternalPresenters?.results?.length) {
emails.push(
...widgetInfoRes.data.InternalPresenters.results.map((i) => i.EMail)
);
}
if (event.InternalPresenters?.results?.length) {
emails.push(...event.InternalPresenters.results.map((i) => i.EMail));
}

const speakersInfo: SpeakerInfo[] = [];
const speakersInfo: SpeakerInfo[] = [];

if (ids.length || emails.length) {
const idsParam = ids.map((id) => `ids=${id}`).join("&");
const emailsParam = emails
.map((email) => `emails=${email}`)
.join("&");
if (ids.length || emails.length) {
const idsParam = ids.map((id) => `ids=${id}`).join("&");
const emailsParam = emails.map((email) => `emails=${email}`).join("&");

const remoteSpeakersInfoRes = await axios.get<SpeakerInfo[]>(
`/api/get-speakers?${idsParam}&${emailsParam}`
);
const remoteSpeakersInfoRes = await axios.get<SpeakerInfo[]>(
`/api/get-speakers?${idsParam}&${emailsParam}`
);

if (
remoteSpeakersInfoRes.status === 200 &&
remoteSpeakersInfoRes.data.length
) {
speakersInfo.push(...remoteSpeakersInfoRes.data);
}
} else {
speakersInfo.push({
Title: widgetInfoRes.data.Presenter,
PresenterProfileLink: widgetInfoRes.data.PresenterProfileUrl.Url,
});
if (
remoteSpeakersInfoRes.status === 200 &&
remoteSpeakersInfoRes.data.length
) {
speakersInfo.push(...remoteSpeakersInfoRes.data);
}
setSpeakersInfo(speakersInfo);
} else {
speakersInfo.push({
Title: event.Presenter,
PresenterProfileLink: event?.PresenterProfileUrl?.Url,
});
}
setSpeakersInfo(speakersInfo);
};

fetchLiveStreamInfo();
}, [isLive, event]);

if (!widgetInfo) {
if ((!isLive && !router.query.liveStream) || !event) {
return <></>;
}

Expand All @@ -134,7 +121,7 @@ export const LiveStream: FC<LiveStreamProps> = ({ isLive, event }) => {
<span className="hidden pr-2 sm:inline">Subscribe to SSW TV</span>
<div
className="g-ytsubscribe"
data-channelid={widgetInfo.ChannelId}
data-channelid="UCBFgwtV9lIIhvoNh0xoQ7Pg"
data-layout="default"
data-count="default"
></div>
Expand Down Expand Up @@ -275,18 +262,6 @@ export const LiveStream: FC<LiveStreamProps> = ({ isLive, event }) => {
>
Take the Survey
</a>
<div className="pt-3">
<Image
src="/images/icons/external.gif"
alt="You are now leaving SSW"
width="15"
height="11"
data-tooltip-id="external"
data-tooltip-content="You are now leaving SSW"
data-tooltip-place="bottom"
/>
<Tooltip id="external" className="z-tooltip" />
</div>
</div>
</div>
</div>
Expand All @@ -307,8 +282,7 @@ export const LiveStream: FC<LiveStreamProps> = ({ isLive, event }) => {
)}
dangerouslySetInnerHTML={{
__html:
widgetInfo.EventDescription ||
widgetInfo.EventShortDescription,
event?.EventDescription || event?.EventShortDescription,
}}
></div>
{eventDescriptionCollapsable && (
Expand Down
Loading

0 comments on commit 0b7b88a

Please sign in to comment.