feat(marketing): Make marketing page content configurable via CMS data
- Replace hardcoded centerFrames array with CMS data from features.cards - Update hero section to use CMS data for title, description, button text and link - Migrate features section title and description from hardcoded text to CMS - Replace hardcoded challenges section with dynamic CMS data for title, description and cards - Update advantages section to use CMS data for title and cards - Normalize CMS field names from PascalCase to snake_case (Title → title, ButtonLink → button_link, etc.) - Replace Image component with ImageWithFallback for better error handling on dynamic images - Add unoptimized prop to images to support dynamic CMS image URLs - Remove 29 lines of hardcoded content, making the page fully data-driven from CMS
This commit is contained in:
+37
-89
@@ -41,29 +41,7 @@ export default async function Home({ params }: IProps) {
|
|||||||
}
|
}
|
||||||
console.log(cmsData);
|
console.log(cmsData);
|
||||||
|
|
||||||
const centerFrames = [
|
const centerFrames = cmsData?.data.features.cards ?? [];
|
||||||
{
|
|
||||||
src: "/magnifier.svg",
|
|
||||||
title: "1. Discover with AI",
|
|
||||||
alt: "Magnifier",
|
|
||||||
description:
|
|
||||||
"Our intelligent platform scours thousands of sources to find the perfect, most relevant tender opportunities for your specific business and expertise",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: "/clipboard.svg",
|
|
||||||
title: "2. Prepare with Experts",
|
|
||||||
alt: "Clipboard",
|
|
||||||
description:
|
|
||||||
"Gain access to expert support and powerful tools to craft compelling, competitive, and high-quality bids that stand out from the competition.",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
src: "/thumbs-up.svg",
|
|
||||||
title: "3. Win with a Partner",
|
|
||||||
alt: "thumbs-up",
|
|
||||||
description:
|
|
||||||
"We operate on a partnership model. We only succeed when you win. This aligns our goals and makes us a true partner in your growth.",
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -86,7 +64,7 @@ export default async function Home({ params }: IProps) {
|
|||||||
<div className="flex flex-col gap-8">
|
<div className="flex flex-col gap-8">
|
||||||
<h2>
|
<h2>
|
||||||
<span>$</span>
|
<span>$</span>
|
||||||
<span>{cmsData?.data.chart.missedAmount ?? 1672}</span>
|
<span>{cmsData?.data.chart.missed_amount ?? 1672}</span>
|
||||||
</h2>
|
</h2>
|
||||||
<h2 className="capitalize text-2xl font-bold lg:text-3xl">
|
<h2 className="capitalize text-2xl font-bold lg:text-3xl">
|
||||||
total tender amount you missed today
|
total tender amount you missed today
|
||||||
@@ -115,29 +93,27 @@ export default async function Home({ params }: IProps) {
|
|||||||
<section className="text-left flex flex-col gap-6 bg-gradient-to-b from-[#011132] to-[#012B80] text-white rounded-[56px] relative p-6 lg:p-14 -mt-16 z-20 lg:ml-28 ">
|
<section className="text-left flex flex-col gap-6 bg-gradient-to-b from-[#011132] to-[#012B80] text-white rounded-[56px] relative p-6 lg:p-14 -mt-16 z-20 lg:ml-28 ">
|
||||||
<hgroup>
|
<hgroup>
|
||||||
<h1 className="capitalize font-extrabold text-4xl mb-6 md:text-5xl">
|
<h1 className="capitalize font-extrabold text-4xl mb-6 md:text-5xl">
|
||||||
{cmsData?.data.hero.Title}
|
{cmsData?.data.hero.title}
|
||||||
</h1>
|
</h1>
|
||||||
<p className="text-[16px] text-[#dadada]">
|
<p className="text-[16px] text-[#dadada]">
|
||||||
{cmsData?.data.hero.Description}
|
{cmsData?.data.hero.description}
|
||||||
</p>
|
</p>
|
||||||
</hgroup>
|
</hgroup>
|
||||||
<div className="flex justify-end">
|
<div className="flex justify-end">
|
||||||
<Link
|
<Link
|
||||||
className="w-full lg:w-fit capitalize bg-(--primary) rounded-4xl py-4 px-6"
|
className="w-full lg:w-fit capitalize bg-(--primary) rounded-4xl py-4 px-6"
|
||||||
href={cmsData?.data.hero.ButtonLink ?? "#"}>
|
href={cmsData?.data.hero.button_link ?? "#"}>
|
||||||
{cmsData?.data.hero.ButtonText}
|
{cmsData?.data.hero.button_text}
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<article className="mt-40">
|
<article className="mt-40">
|
||||||
<hgroup>
|
<hgroup>
|
||||||
<h4 className="capitalize font-bold text-2xl lg:text-4xl">
|
<h4 className="capitalize font-bold text-2xl lg:text-4xl">
|
||||||
your in-house tender department, powered by
|
{cmsData?.data.features.title}
|
||||||
<span className="uppercase">ai</span>
|
|
||||||
</h4>
|
</h4>
|
||||||
<small className="text-gray-600 mt-3">
|
<small className="text-gray-600 mt-3">
|
||||||
Opplens is the end-to-end solution that gives you the power to
|
{cmsData?.data.features.description}
|
||||||
compete and win.
|
|
||||||
</small>
|
</small>
|
||||||
</hgroup>
|
</hgroup>
|
||||||
</article>
|
</article>
|
||||||
@@ -146,11 +122,12 @@ export default async function Home({ params }: IProps) {
|
|||||||
<article
|
<article
|
||||||
key={frame.description}
|
key={frame.description}
|
||||||
className="bg-[#F7FAFF] border border-(--primary)/30 rounded-3xl my-4 py-10 px-6 flex flex-col gap-5 transition duration-300 transform scale-90 hover:bg-[#0164FF30] hover:scale-110">
|
className="bg-[#F7FAFF] border border-(--primary)/30 rounded-3xl my-4 py-10 px-6 flex flex-col gap-5 transition duration-300 transform scale-90 hover:bg-[#0164FF30] hover:scale-110">
|
||||||
<Image
|
<ImageWithFallback
|
||||||
src={frame.src}
|
src={frame.icon ?? "/magnifier.svg"}
|
||||||
alt={frame.alt}
|
alt={frame.title}
|
||||||
width={36}
|
width={36}
|
||||||
height={36}
|
height={36}
|
||||||
|
unoptimized
|
||||||
/>
|
/>
|
||||||
<h3 className="text-2xl font-bold">{frame.title}</h3>
|
<h3 className="text-2xl font-bold">{frame.title}</h3>
|
||||||
<p className="text-gray-600">{frame.description}</p>
|
<p className="text-gray-600">{frame.description}</p>
|
||||||
@@ -160,82 +137,53 @@ export default async function Home({ params }: IProps) {
|
|||||||
<section className="mt-36 bg-[#F7FAFF] px-4 py-6 rounded-4xl flex flex-col gap-9 lg:p-16">
|
<section className="mt-36 bg-[#F7FAFF] px-4 py-6 rounded-4xl flex flex-col gap-9 lg:p-16">
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
<h2 className=" font-bold text-4xl">
|
<h2 className=" font-bold text-4xl">
|
||||||
Tired of Complex Tenders & Lost Opportunities?
|
{cmsData?.data.challenges.title}
|
||||||
</h2>
|
</h2>
|
||||||
<p className="font-normal text-sm">
|
<p className="font-normal text-sm">
|
||||||
The procurement market is tough for SMEs. We get it. You're facing
|
{cmsData?.data.challenges.description}
|
||||||
an uphill battle.
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<ul className="flex flex-col gap-4 lg:flex-row lg:justify-between">
|
<ul className="flex flex-col gap-4 lg:flex-row lg:justify-between">
|
||||||
<li className="flex flex-col gap-4 lg:w-80">
|
{cmsData?.data.challenges.cards.map((card) => (
|
||||||
<div className="p-4">
|
<li
|
||||||
<Image
|
className="flex flex-col gap-4 lg:w-80"
|
||||||
src={"/clock.svg"}
|
key={card.title}>
|
||||||
alt="clock icon"
|
|
||||||
width={36}
|
|
||||||
height={36}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<h2 className="font-bold">Resource Drain</h2>
|
|
||||||
<p>
|
|
||||||
Lacking the time, dedicated staff, and expertise to constantly
|
|
||||||
monitor the market and prepare high-quality bids.
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
<li className="flex flex-col gap-4 lg:w-80">
|
|
||||||
<div className="p-4">
|
<div className="p-4">
|
||||||
<ImageWithFallback
|
<ImageWithFallback
|
||||||
src={"/file.svg"}
|
src={card.icon ?? "/clock.svg"}
|
||||||
alt="file icon"
|
alt={card.title}
|
||||||
width={36}
|
width={36}
|
||||||
height={36}
|
height={36}
|
||||||
|
unoptimized
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<h2 className="font-bold">Overwhelming Complexity</h2>
|
<h2 className="font-bold">{card.title}</h2>
|
||||||
<p>
|
<p>{card.description}</p>
|
||||||
Navigating complex requirements and processes designed for large
|
|
||||||
corporations with dedicated tender departments.
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
<li className="flex flex-col gap-4 lg:w-80">
|
|
||||||
<div className="p-4">
|
|
||||||
<ImageWithFallback
|
|
||||||
src={"/arrow-up.svg"}
|
|
||||||
alt="arrow-up icon"
|
|
||||||
width={36}
|
|
||||||
height={36}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<h2 className="font-bold">Low Win Rates</h2>
|
|
||||||
<p>
|
|
||||||
Did you know 68% of SMEs in Sweden rarely or never win public
|
|
||||||
tenders? It's time to change that.
|
|
||||||
</p>
|
|
||||||
</li>
|
</li>
|
||||||
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
<section className="flex flex-col mt-36 gap-10 px-2 lg:w-3/4 m-auto">
|
<section className="flex flex-col mt-36 gap-10 px-2 lg:w-3/4 m-auto">
|
||||||
<div>
|
<div>
|
||||||
<h2 className="font-bold text-2xl lg:text-4xl">
|
<h2 className="font-bold text-2xl lg:text-4xl">
|
||||||
{cmsData?.data.advantages.Title}
|
{cmsData?.data.advantages.title}
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<section className="flex flex-col gap-10 lg:flex-row">
|
<section className="flex flex-col gap-10 lg:flex-row">
|
||||||
{cmsData?.data.advantages.Cards.map((card) => (
|
{cmsData?.data.advantages.cards.map((card) => (
|
||||||
<div
|
<div
|
||||||
className="flex flex-col gap-7 bg-[#FFF7EB] p-10 rounded-3xl lg:pb-20"
|
className="flex flex-col gap-7 bg-[#FFF7EB] p-10 rounded-3xl lg:pb-20"
|
||||||
key={card.Title}>
|
key={card.title}>
|
||||||
<ImageWithFallback
|
<ImageWithFallback
|
||||||
src={card.Icon ?? "/people.svg"}
|
src={card.icon ?? "/people.svg"}
|
||||||
width={48}
|
width={48}
|
||||||
height={48}
|
height={48}
|
||||||
alt="people icon"
|
alt="people icon"
|
||||||
unoptimized
|
unoptimized
|
||||||
/>
|
/>
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
<h2 className="font-bold text-xl">{card.Title}</h2>
|
<h2 className="font-bold text-xl">{card.title}</h2>
|
||||||
<p>{card.Description}</p>
|
<p>{card.description}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
@@ -262,10 +210,10 @@ export default async function Home({ params }: IProps) {
|
|||||||
/>
|
/>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-white my-2">
|
<p className="text-white my-2">
|
||||||
{cmsData?.data.footer.Tagline}
|
{cmsData?.data.footer.tagline}
|
||||||
</p>
|
</p>
|
||||||
<small className="text-white my-2">
|
<small className="text-white my-2">
|
||||||
{cmsData?.data.footer.Copyright}
|
{cmsData?.data.footer.copyright}
|
||||||
</small>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -279,8 +227,8 @@ export default async function Home({ params }: IProps) {
|
|||||||
alt=""
|
alt=""
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
/>
|
/>
|
||||||
<a href={`tel:${cmsData?.data.footer.Phone}`}>
|
<a href={`tel:${cmsData?.data.footer.phone}`}>
|
||||||
{cmsData?.data.footer.Phone}
|
{cmsData?.data.footer.phone}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li className="flex gap-3 my-3 text-white">
|
<li className="flex gap-3 my-3 text-white">
|
||||||
@@ -291,8 +239,8 @@ export default async function Home({ params }: IProps) {
|
|||||||
alt=""
|
alt=""
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
/>
|
/>
|
||||||
<a href={`mailto:${cmsData?.data.footer.Email}`}>
|
<a href={`mailto:${cmsData?.data.footer.email}`}>
|
||||||
{cmsData?.data.footer.Email}
|
{cmsData?.data.footer.email}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li className="flex gap-3 my-3 text-white">
|
<li className="flex gap-3 my-3 text-white">
|
||||||
@@ -303,7 +251,7 @@ export default async function Home({ params }: IProps) {
|
|||||||
alt=""
|
alt=""
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
/>
|
/>
|
||||||
<p>{cmsData?.data.footer.Location}</p>
|
<p>{cmsData?.data.footer.location}</p>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</address>
|
</address>
|
||||||
|
|||||||
Reference in New Issue
Block a user