diff --git a/apps/climatemappedafrica/public/images/cms/blocks/how-it-works.png b/apps/climatemappedafrica/public/images/cms/blocks/how-it-works.png
new file mode 100644
index 000000000..c1922e11b
Binary files /dev/null and b/apps/climatemappedafrica/public/images/cms/blocks/how-it-works.png differ
diff --git a/apps/climatemappedafrica/src/components/HowItWorks/Player.js b/apps/climatemappedafrica/src/components/HowItWorks/Player.js
new file mode 100644
index 000000000..e893f04f4
--- /dev/null
+++ b/apps/climatemappedafrica/src/components/HowItWorks/Player.js
@@ -0,0 +1,48 @@
+/* eslint-disable jsx-a11y/media-has-caption */
+import PropTypes from "prop-types";
+import React, { useEffect } from "react";
+import videojs from "video.js";
+import "videojs-youtube";
+import "video.js/dist/video-js.css";
+
+function Player({ url, type }) {
+ const videoRef = React.useRef(null);
+ const playerRef = React.useRef(null);
+
+ useEffect(() => {
+ if (videoRef.current && !playerRef.current) {
+ const options = {
+ autoplay: false,
+ controls: true,
+ preload: "auto",
+ sources: [{ src: url, type }],
+ techOrder: ["youtube"],
+ youtube: { ytControls: 2 },
+ };
+ playerRef.current = videojs(videoRef.current, options);
+ }
+ }, [url, type]);
+
+ // Dispose the Video.js player when the functional component unmounts
+ useEffect(() => {
+ return () => {
+ if (playerRef.current) {
+ playerRef.current.dispose();
+ playerRef.current = null;
+ }
+ };
+ }, []);
+
+ return (
+
+
+
+ );
+}
+
+Player.propTypes = {
+ url: PropTypes.string,
+ type: PropTypes.string,
+};
+
+export default Player;
diff --git a/apps/climatemappedafrica/src/components/HowItWorks/index.js b/apps/climatemappedafrica/src/components/HowItWorks/index.js
new file mode 100644
index 000000000..0133a6093
--- /dev/null
+++ b/apps/climatemappedafrica/src/components/HowItWorks/index.js
@@ -0,0 +1,195 @@
+import { Link } from "@commons-ui/next";
+import { RichText } from "@commons-ui/payload";
+import { Box, Grid, Typography } from "@mui/material";
+import PropTypes from "prop-types";
+import React from "react";
+
+import Player from "@/climatemappedafrica/components/HowItWorks/Player";
+import useStyles from "@/climatemappedafrica/components/HowItWorks/useStyles";
+import Section from "@/climatemappedafrica/components/Section";
+
+function HowItWorks({
+ title,
+ description,
+ link,
+ video,
+ backgroundImage,
+ image: foregroundImage,
+ ...props
+}) {
+ const classes = useStyles(props);
+
+ return (
+
+
+ ({
+ display: {
+ xs: "none",
+ md: "block",
+ lg: "none",
+ },
+ position: "absolute",
+ left: 0,
+ top: theme.typography.pxToRem(42),
+ width: "100%",
+ background: `linear-gradient(to right, #ffffffE6 0%, #ffffffE6 56%, transparent 56%, transparent 100%)`,
+ height: theme.typography.pxToRem(524),
+ })}
+ />
+
+
+ ({
+ position: {
+ md: "relative",
+ },
+ top: {
+ md: 0,
+ },
+ backgroundColor: {
+ lg: theme.palette.background.default,
+ },
+ opacity: {
+ md: 0.9,
+ },
+ height: {
+ md: theme.typography.pxToRem(524),
+ lg: theme.typography.pxToRem(600),
+ },
+ padding: {
+ md: `${theme.typography.pxToRem(66)} ${theme.typography.pxToRem(
+ 77,
+ )} ${theme.typography.pxToRem(69)} 0`,
+ lg: `${theme.typography.pxToRem(81)} ${theme.typography.pxToRem(98)}`,
+ },
+ })}
+ >
+ ({
+ position: "relative",
+ "& .video-js": {
+ width: "100%",
+ height: "100%",
+ },
+ "& .vjs-poster": {
+ backgroundColor: "#ffffffE6",
+ backgroundSize: {
+ xs: "120%",
+ md: "auto",
+ },
+ },
+ "& .video-js .vjs-big-play-button": {
+ display: "none",
+ },
+ height: {
+ xs: theme.typography.pxToRem(227),
+ md: theme.typography.pxToRem(194),
+ lg: theme.typography.pxToRem(244),
+ },
+ width: {
+ xs: "100%",
+ md: theme.typography.pxToRem(299),
+ lg: theme.typography.pxToRem(376),
+ },
+ })}
+ >
+
+
+ ({
+ marginTop: theme.typography.pxToRem(18),
+ })}
+ variant="h4"
+ >
+ {title}
+
+ ({
+ fontFamily: theme.typography.body1.fontFamily,
+ margin: `${theme.typography.pxToRem(16.5)} 0`,
+ color: theme.palette.grey.dark,
+ width: {
+ md: theme.typography.pxToRem(278),
+ },
+ })}
+ />
+
+ {link.label}
+
+
+
+
+ ({
+ position: "relative",
+ height: {
+ xs: theme.typography.pxToRem(265),
+ md: theme.typography.pxToRem(211),
+ lg: theme.typography.pxToRem(441.6),
+ },
+ width: {
+ xs: theme.typography.pxToRem(253.6),
+ md: theme.typography.pxToRem(202),
+ lg: theme.typography.pxToRem(422.5),
+ },
+ backgroundImage: `url(${foregroundImage.src})`,
+ backgroundSize: "contain",
+ backgroundRepeat: "no-repeat",
+ marginBottom: theme.typography.pxToRem(23),
+ })}
+ />
+
+
+
+
+ );
+}
+
+HowItWorks.propTypes = {
+ ctaText: PropTypes.string,
+ description: PropTypes.string,
+ href: PropTypes.string,
+ title: PropTypes.string,
+};
+
+export default HowItWorks;
diff --git a/apps/climatemappedafrica/src/components/HowItWorks/useStyles.js b/apps/climatemappedafrica/src/components/HowItWorks/useStyles.js
new file mode 100644
index 000000000..494337cfb
--- /dev/null
+++ b/apps/climatemappedafrica/src/components/HowItWorks/useStyles.js
@@ -0,0 +1,17 @@
+import makeStyles from "@mui/styles/makeStyles";
+
+const useStyles = makeStyles(({ breakpoints, typography }) => ({
+ section: {
+ zIndex: 1,
+ position: "relative",
+ paddingTop: typography.pxToRem(62),
+ [breakpoints.up("md")]: {
+ padding: `${typography.pxToRem(42)} 0`,
+ },
+ [breakpoints.up("lg")]: {
+ padding: `${typography.pxToRem(64)} 0`,
+ },
+ },
+}));
+
+export default useStyles;
diff --git a/apps/climatemappedafrica/src/pages/[[...slugs]].js b/apps/climatemappedafrica/src/pages/[[...slugs]].js
index 24a6d30f9..b82b526b5 100644
--- a/apps/climatemappedafrica/src/pages/[[...slugs]].js
+++ b/apps/climatemappedafrica/src/pages/[[...slugs]].js
@@ -5,6 +5,7 @@ import { SWRConfig } from "swr";
import AboutTeam from "@/climatemappedafrica/components/AboutTeam";
import Footer from "@/climatemappedafrica/components/Footer";
import Hero from "@/climatemappedafrica/components/Hero";
+import HowItWorks from "@/climatemappedafrica/components/HowItWorks";
import Navigation from "@/climatemappedafrica/components/Navigation";
import PageHero from "@/climatemappedafrica/components/PageHero";
import Summary from "@/climatemappedafrica/components/Summary";
@@ -12,6 +13,7 @@ import { getPageServerSideProps } from "@/climatemappedafrica/lib/data";
const componentsBySlugs = {
hero: Hero,
+ "how-it-works": HowItWorks,
"page-hero": PageHero,
summary: Summary,
team: AboutTeam,
diff --git a/apps/climatemappedafrica/src/payload/blocks/HowItWorks.js b/apps/climatemappedafrica/src/payload/blocks/HowItWorks.js
new file mode 100644
index 000000000..135b67e99
--- /dev/null
+++ b/apps/climatemappedafrica/src/payload/blocks/HowItWorks.js
@@ -0,0 +1,86 @@
+import { slateEditor } from "@payloadcms/richtext-slate";
+
+import image from "../fields/image";
+import linkGroup from "../fields/links/linkGroup";
+import richText from "../fields/richText";
+
+const HowItWorks = {
+ slug: "how-it-works",
+ imageURL: "/images/cms/blocks/how-it-works.png",
+ fields: [
+ {
+ name: "title",
+ type: "text",
+ required: true,
+ localized: true,
+ },
+ richText({
+ name: "description",
+ label: {
+ en: "Description",
+ },
+ editor: slateEditor({
+ admin: {
+ elements: ["link"],
+ leaves: ["bold", "code", "italic", "underline"],
+ },
+ }),
+ required: true,
+ localized: true,
+ }),
+ {
+ name: "video",
+ type: "group",
+ fields: [
+ {
+ name: "url",
+ type: "text",
+ label: {
+ en: "Youtube Video URL",
+ },
+ required: true,
+ localized: true,
+ },
+ {
+ name: "type",
+ type: "text",
+ required: true,
+ defaultValue: "video/youtube",
+ admin: {
+ description: "The type of video. e.g. video/mp4, video/youtube",
+ hidden: true,
+ },
+ },
+ ],
+ localized: true,
+ },
+ linkGroup({
+ overrides: {
+ label: {
+ en: "Find out more",
+ },
+ localized: true,
+ },
+ }),
+ image({
+ overrides: {
+ name: "image",
+ required: true,
+ admin: {
+ description: "Image to display on the right side of the video.",
+ },
+ },
+ }),
+ image({
+ overrides: {
+ name: "backgroundImage",
+ required: true,
+ admin: {
+ description: "Image to display in the background.",
+ },
+ },
+ }),
+ ],
+};
+
+export default HowItWorks;
diff --git a/apps/climatemappedafrica/src/payload/collections/Pages.js b/apps/climatemappedafrica/src/payload/collections/Pages.js
index c98d41908..ac157c44b 100644
--- a/apps/climatemappedafrica/src/payload/collections/Pages.js
+++ b/apps/climatemappedafrica/src/payload/collections/Pages.js
@@ -1,4 +1,5 @@
import Hero from "../blocks/Hero";
+import HowItWorks from "../blocks/HowItWorks";
import PageHero from "../blocks/PageHero";
import Summary from "../blocks/Summary";
import Team from "../blocks/Team";
@@ -31,7 +32,7 @@ const Pages = {
{
name: "blocks",
type: "blocks",
- blocks: [Hero, PageHero, Summary, Team],
+ blocks: [Hero, HowItWorks, PageHero, Summary, Team],
localized: true,
admin: {
initCollapsed: true,