Compare commits

..

10 Commits

Author SHA1 Message Date
Tiago Ribeiro
b162770e2d Navbar.tsx edited online with Bitbucket 2025-03-19 10:51:51 +00:00
Tiago Ribeiro
ce44293669 Removed telemetry 2024-05-21 22:42:43 +01:00
Tiago Ribeiro
d6dd879db8 Merge branch 'master' of bitbucket.org:ecropdev/encoach-landing-page 2024-04-22 13:48:21 +01:00
Tiago Ribeiro
f15d01ba2c Updated the Twitter logo to X 2024-04-22 13:47:51 +01:00
João Ramos
7b1df2d74b Merged in missing-dir-country-manager-contact (pull request #12)
Fixed a missing dir on the Country Manager contact page

Approved-by: Tiago Ribeiro
2024-04-19 08:18:51 +00:00
Joao Ramos
df5c49f4f0 Fixed a missing dir on the Country Manager contact page 2024-04-18 19:19:33 +01:00
João Ramos
514cee1487 Merged in advertisement-banner (pull request #11)
Added Advertisement Banner support
2024-04-08 22:50:20 +00:00
Joao Ramos
33199f26ec Added Advertisement Banner support 2024-04-08 18:47:32 +01:00
Tiago Ribeiro
3359c47379 Updated the code to allow for images 2024-04-01 00:50:53 +01:00
Tiago Ribeiro
1c5f16d42b Updated some client pages to externalize the Navbar and Footer 2024-03-21 12:47:03 +00:00
32 changed files with 313 additions and 215 deletions

View File

@@ -21,7 +21,7 @@ COPY . .
# Next.js collects completely anonymous telemetry data about general usage.
# Learn more here: https://nextjs.org/telemetry
# Uncomment the following line in case you want to disable telemetry during the build.
# ENV NEXT_TELEMETRY_DISABLED 1
ENV NEXT_TELEMETRY_DISABLED 1
ARG STRAPI_URL=http://localhost:1337
ARG STRAPI_TOKEN=TOKEN

View File

@@ -23,7 +23,7 @@
"react": "^18",
"react-dom": "^18",
"react-hook-form": "^7.50.1",
"react-icons": "^4.11.0",
"react-icons": "^5.1.0",
"react-string-replace": "^1.1.1",
"react-toastify": "^10.0.4",
"sharp": "^0.32.6"

View File

@@ -3,7 +3,7 @@ import About from "@/templates/About";
import AboutPage from "@/types/cms/about";
export default async function Page() {
const {data} = await getData<AboutPage>("about", "en");
const data = await getData<AboutPage>("about", "en");
return <About data={data.data.attributes} language="en" />;
return <About data={data} language="en" />;
}

View File

@@ -3,7 +3,7 @@ import About from "@/templates/About";
import AboutPage from "@/types/cms/about";
export default async function Page() {
const {data} = await getData<AboutPage>("about", "ar");
const data = await getData<AboutPage>("about", "ar");
return <About data={data.data.attributes} language="ar" />;
return <About data={data} language="ar" />;
}

View File

@@ -1,9 +1,17 @@
import {getData} from "@/cms";
import Footer from "@/components/Footer";
import Navbar from "@/components/Navbar";
import ContactUs from "@/templates/ContactUs";
import ContactPage from "@/types/cms/contact";
export default async function Page() {
const {data} = await getData<ContactPage>("contact", "ar");
const data = await getData<ContactPage>("contact", "ar");
return <ContactUs data={data.data.attributes} page="/contact" language="ar" />;
return (
<main className="text-mti-black flex h-screen w-full flex-col bg-white" dir="rtl">
<Navbar currentPage="/contact" language="ar" />
<ContactUs data={data} />;
<Footer language="ar" />
</main>
);
}

View File

@@ -15,7 +15,7 @@ export async function generateStaticParams() {
}
export default async function Page({params: {country}}: PageProps) {
const {data} = await getData<CountryManagerContactsPage>("country-managers-contact", language);
const data = await getData<CountryManagerContactsPage>("country-managers-contact", language);
return <AgentContacts data={data.data.attributes} country={country} page={`/contacts/${country}`} language={language} />;
return <AgentContacts data={data} country={country} page={`/contacts/${country}`} language={language} />;
}

View File

@@ -3,7 +3,7 @@ import History from "@/templates/History";
import HistoryPage from "@/types/cms/history";
export default async function Page() {
const {data} = await getData<HistoryPage>("history", "ar");
const data = await getData<HistoryPage>("history", "ar");
return <History data={data.data.attributes} language="ar" />;
return <History data={data} language="ar" />;
}

View File

@@ -1,10 +1,16 @@
import {getData} from "@/cms";
import Home from "@/templates/Home";
import HomePage from "@/types/cms/home";
import HomePage, {HomePageData} from "@/types/cms/home";
import {NextPageContext} from "next";
export default async function Page() {
const {data} = await getData<HomePage>("home", "ar");
const data = await getData<HomePageData>("home", "ar");
return <Home data={data.data.attributes} language="ar" />;
const home: HomePage = {
...data,
Banner: data?.Banner?.data?.attributes,
AdvertisementBanner: data?.AdvertisementBanner?.data?.attributes,
};
return <Home data={home} language="ar" />;
}

View File

@@ -1,9 +1,17 @@
import {getData} from "@/cms";
import Footer from "@/components/Footer";
import Navbar from "@/components/Navbar";
import Price from "@/templates/Price";
import PricePage from "@/types/cms/price";
export default async function Page() {
const {data} = await getData<PricePage>("price", "ar");
const data = await getData<PricePage>("price", "ar");
return <Price data={data.data.attributes} language="ar" />;
return (
<main className="h-screen w-full bg-white text-mti-black flex flex-col" dir="rtl">
<Navbar currentPage="/price" language="ar" />
<Price data={data} language="ar" />
<Footer language="ar" />
</main>
);
}

View File

@@ -4,7 +4,7 @@ import Terms from "@/templates/Terms";
import PrivacyPolicyPage from "@/types/cms/privacyPolicy";
export default async function Page() {
const {data} = await getData<PrivacyPolicyPage>("privacy-policy", "ar");
const data = await getData<PrivacyPolicyPage>("privacy-policy", "ar");
return <Privacy data={data.data.attributes} language="ar" />;
return <Privacy data={data} language="ar" />;
}

View File

@@ -3,7 +3,7 @@ import Services from "@/templates/Services";
import ServicesPage from "@/types/cms/services";
export default async function Page() {
const {data} = await getData<ServicesPage>("services", "ar");
const data = await getData<ServicesPage>("services", "ar");
return <Services data={data.data.attributes} language="ar" />;
return <Services data={data} language="ar" />;
}

View File

@@ -3,7 +3,7 @@ import Terms from "@/templates/Terms";
import TermsAndConditionsPage from "@/types/cms/termsConditions";
export default async function Page() {
const {data} = await getData<TermsAndConditionsPage>("terms-and-conditions", "ar");
const data = await getData<TermsAndConditionsPage>("terms-and-conditions", "ar");
return <Terms data={data.data.attributes} language="ar" />;
return <Terms data={data} language="ar" />;
}

View File

@@ -1,9 +1,17 @@
import {getData} from "@/cms";
import Footer from "@/components/Footer";
import Navbar from "@/components/Navbar";
import ContactUs from "@/templates/ContactUs";
import ContactPage from "@/types/cms/contact";
export default async function Page() {
const {data} = await getData<ContactPage>("contact", "en");
const data = await getData<ContactPage>("contact", "en");
return <ContactUs data={data.data.attributes} page="/contact" language="en" />;
return (
<main className="text-mti-black flex h-screen w-full flex-col bg-white" dir="ltr">
<Navbar currentPage="/contact" language="en" />
<ContactUs data={data} />;
<Footer language="en" />
</main>
);
}

View File

@@ -15,7 +15,7 @@ export async function generateStaticParams() {
}
export default async function Page({params: {country}}: PageProps) {
const {data} = await getData<CountryManagerContactsPage>("country-managers-contact", language);
const data = await getData<CountryManagerContactsPage>("country-managers-contact", language);
return <AgentContacts data={data.data.attributes} country={country} page={`/contacts/${country}`} language={language} />;
return <AgentContacts data={data} country={country} page={`/contacts/${country}`} language={language} />;
}

View File

@@ -3,7 +3,7 @@ import History from "@/templates/History";
import HistoryPage from "@/types/cms/history";
export default async function Page() {
const {data} = await getData<HistoryPage>("history", "en");
const data = await getData<HistoryPage>("history", "en");
return <History data={data.data.attributes} language="en" />;
return <History data={data} language="en" />;
}

View File

@@ -1,10 +1,16 @@
import {getData} from "@/cms";
import Home from "@/templates/Home";
import HomePage from "@/types/cms/home";
import HomePage, {HomePageData} from "@/types/cms/home";
import {NextPageContext} from "next";
export default async function Page() {
const {data} = await getData<HomePage>("home", "en");
const data = await getData<HomePageData>("home", "en");
return <Home data={data.data.attributes} language="en" />;
const home: HomePage = {
...data,
Banner: data?.Banner?.data?.attributes,
AdvertisementBanner: data?.AdvertisementBanner?.data?.attributes,
};
return <Home data={home} language="en" />;
}

View File

@@ -1,9 +1,17 @@
import {getData} from "@/cms";
import Footer from "@/components/Footer";
import Navbar from "@/components/Navbar";
import Price from "@/templates/Price";
import PricePage from "@/types/cms/price";
export default async function Page() {
const {data} = await getData<PricePage>("price", "en");
const data = await getData<PricePage>("price", "en");
return <Price data={data.data.attributes} language="en" />;
return (
<main className="h-screen w-full bg-white text-mti-black flex flex-col" dir="ltr">
<Navbar currentPage="/price" language="en" />
<Price data={data} language="en" />
<Footer language="en" />
</main>
);
}

View File

@@ -4,7 +4,7 @@ import Terms from "@/templates/Terms";
import PrivacyPolicyPage from "@/types/cms/privacyPolicy";
export default async function Page() {
const {data} = await getData<PrivacyPolicyPage>("privacy-policy", "en");
const data = await getData<PrivacyPolicyPage>("privacy-policy", "en");
return <Privacy data={data.data.attributes} language="en" />;
return <Privacy data={data} language="en" />;
}

View File

@@ -3,7 +3,7 @@ import Services from "@/templates/Services";
import ServicesPage from "@/types/cms/services";
export default async function Page() {
const {data} = await getData<ServicesPage>("services", "en");
const data = await getData<ServicesPage>("services", "en");
return <Services data={data.data.attributes} language="en" />;
return <Services data={data} language="en" />;
}

View File

@@ -3,7 +3,7 @@ import Terms from "@/templates/Terms";
import TermsAndConditionsPage from "@/types/cms/termsConditions";
export default async function Page() {
const {data} = await getData<TermsAndConditionsPage>("terms-and-conditions", "en");
const data = await getData<TermsAndConditionsPage>("terms-and-conditions", "en");
return <Terms data={data.data.attributes} language="en" />;
return <Terms data={data} language="en" />;
}

View File

@@ -13,11 +13,12 @@ interface StrapiResponse<T> {
meta: object;
}
type Result<T> = {data: StrapiResponse<T>; isError: boolean};
export async function getData<T>(page: string, locale: "ar" | "en"): Promise<Result<T>> {
export async function getData<T>(page: string, locale: "ar" | "en"): Promise<T> {
const request = await axios.get<StrapiResponse<T>>(`${process.env.STRAPI_URL}/api/${page}/?populate=deep&locale=${locale}`, {
headers: {Authorization: `Bearer ${process.env.STRAPI_TOKEN}`},
});
return {data: request.data, isError: request.status !== 200};
console.log('GetDAta', page, JSON.stringify(request.data.data.attributes, null, 2));
return request.data.data.attributes;
}

View File

@@ -1,6 +1,6 @@
import Link from "next/link";
import { BiLogoFacebook } from "react-icons/bi";
import {BsInstagram, BsTwitter} from "react-icons/bs";
import { BsInstagram, BsTwitterX } from "react-icons/bs";
import translation from "@/translation/footer.json";
import clsx from "clsx";
import FooterSection from "@/types/cms/footer";
@@ -17,7 +17,9 @@ interface FooterLinkProps {
}
const FooterLink = ({ language, href, children }: FooterLinkProps) => {
return <Link href={`${language === "ar" ? "/ar" : ""}${href}`}>{children}</Link>;
return (
<Link href={`${language === "ar" ? "/ar" : ""}${href}`}>{children}</Link>
);
};
export default function Footer({ language, data }: Props) {
@@ -28,7 +30,8 @@ export default function Footer({language, data}: Props) {
className={clsx(
"w-full py-10 px-8 md:px-28 flex flex-col md:justify-between gap-8 lg:container lg:mx-auto",
language === "ar" ? "md:flex-row-reverse" : "md:flex-row",
)}>
)}
>
<div className="flex flex-col gap-4">
<span className="font-bold text-xl">{data.Navigation.Text}</span>
<div className="flex flex-col gap-2">
@@ -78,20 +81,28 @@ export default function Footer({language, data}: Props) {
<span className="font-bold text-xl">{data.GetInTouch.Title}</span>
<div className="flex flex-col gap-4">
<span className="max-w-[280px]">{data.GetInTouch.Text}</span>
<div className={clsx("flex gap-6 items-center", language === "ar" && "flex-row-reverse justify-start")}>
<div
className={clsx(
"flex gap-6 items-center",
language === "ar" && "flex-row-reverse justify-start",
)}
>
<Link
href="https://facebook.com"
className="bg-mti-purple-ultralight rounded-full w-10 h-10 flex items-center justify-center hover:bg-mti-purple-dark text-mti-purple-light hover:text-white transition ease-in-out duration-300">
className="bg-mti-purple-ultralight rounded-full w-10 h-10 flex items-center justify-center hover:bg-mti-purple-dark text-mti-purple-light hover:text-white transition ease-in-out duration-300"
>
<BiLogoFacebook className="w-6 h-6" />
</Link>
<Link
href="https://twitter.com"
className="bg-mti-purple-ultralight rounded-full w-10 h-10 flex items-center justify-center hover:bg-mti-purple-dark text-mti-purple-light hover:text-white transition ease-in-out duration-300">
<BsTwitter className="w-5 h-5" />
className="bg-mti-purple-ultralight rounded-full w-10 h-10 flex items-center justify-center hover:bg-mti-purple-dark text-mti-purple-light hover:text-white transition ease-in-out duration-300"
>
<BsTwitterX className="w-5 h-5" />
</Link>
<Link
href="https://instagram.com"
className="bg-mti-purple-ultralight rounded-full w-10 h-10 flex items-center justify-center hover:bg-mti-purple-dark text-mti-purple-light hover:text-white transition ease-in-out duration-300">
className="bg-mti-purple-ultralight rounded-full w-10 h-10 flex items-center justify-center hover:bg-mti-purple-dark text-mti-purple-light hover:text-white transition ease-in-out duration-300"
>
<BsInstagram className="w-5 h-5" />
</Link>
</div>
@@ -100,7 +111,9 @@ export default function Footer({language, data}: Props) {
</div>
</section>
<footer className="w-full py-10 bg-mti-rose-light text-white flex items-center justify-center">© {data.Copyright}</footer>
<footer className="w-full py-10 bg-mti-rose-light text-white flex items-center justify-center">
© {data.Copyright}
</footer>
</>
);
}

View File

@@ -7,7 +7,7 @@ interface Props {
}
export default async function FooterContainer({language}: Props) {
const {data} = await getData<FooterSection>("footer", language);
const data = await getData<FooterSection>("footer", language);
return <Footer data={data.data.attributes} language={language} />;
return <Footer data={data} language={language} />;
}

View File

@@ -117,6 +117,11 @@ export default function Navbar({currentPage, language, data}: Props) {
)}
</div>
<div className="flex w-fit items-center gap-4">
<Link
href="https://platform.encoach.com/official-exam"
className="hover:bg-mti-purple-dark border-mti-purple-dark rounded-xl border px-8 py-2 transition duration-300 ease-in-out hover:text-white">
Official Exam
</Link>
<Link
href="https://platform.encoach.com"
className="hover:bg-mti-purple-dark border-mti-purple-dark rounded-xl border px-8 py-2 transition duration-300 ease-in-out hover:text-white">

View File

@@ -8,7 +8,7 @@ interface Props {
}
export default async function NavbarContainer({currentPage, language}: Props) {
const {data} = await getData<NavBarSection>("nav-bar", language);
const data = await getData<NavBarSection>("nav-bar", language);
return <Navbar data={data.data.attributes} language={language} currentPage={currentPage} />;
return <Navbar data={data} language={language} currentPage={currentPage} />;
}

View File

@@ -33,7 +33,7 @@ export async function AgentContacts({language, page, country, data}: Props) {
const contact = (await getCountryManagers(country, language)) as Contact;
return (
<main className="text-mti-black flex h-screen w-full flex-col bg-white">
<main className="text-mti-black flex h-screen w-full flex-col bg-white" dir={language === "ar" ? "rtl" : "ltr"}>
<Navbar currentPage={page} language={language} />
<section className="bg-mti-purple h-full w-full p-8 text-center text-white md:p-16">

View File

@@ -18,9 +18,7 @@ type FormValues = {
};
interface Props {
language: "en" | "ar";
data: ContactPage;
page: string;
}
const ErrorMessage = ({message}: {message: string}) => (
@@ -28,7 +26,7 @@ const ErrorMessage = ({message}: {message: string}) => (
<span className="text-mti-red">{message}</span>
</div>
);
export default function App({language, data, page}: Props) {
export default function App({data}: Props) {
const selectOptions = [
{
label: data.Feedback,
@@ -92,8 +90,6 @@ export default function App({language, data, page}: Props) {
return (
<>
<ToastContainer />
<main className="text-mti-black flex h-screen w-full flex-col bg-white" dir={language === "ar" ? "rtl" : "ltr"}>
<Navbar currentPage={page} language={language} />
<section className="w-full bg-mti-purple text-white text-center p-8 md:p-16">
<div className="w-full h-full flex flex-col items-center justify-center">
<Title>{data.Title}</Title>
@@ -151,8 +147,6 @@ export default function App({language, data, page}: Props) {
<Image src="/person_laptop_focus.jpg" alt="Contact Us" width={500} height={340} className="rounded-xl" />
</div>
</section>
<Footer language={language} />
</main>
</>
);
}

View File

@@ -20,9 +20,21 @@ export default function Home({language, data}: Props) {
className={clsx("h-screen w-full bg-white text-mti-black flex flex-col", language === "ar" && "text-right")}
dir={language === "ar" ? "rtl" : "ltr"}>
<Navbar currentPage="/" language={language} />
{data.AdvertisementBanner?.url && (
<section className="w-full relative bg-white mb-4">
<img
src={data.AdvertisementBanner.url}
alt={data.AdvertisementBanner.alternativeText || 'Advertisement Banner'}
className="w-full"
/>
</section>
)}
<section className="w-full relative bg-white">
<img src="/banner_encoach_home.png" alt="IELTS Packages - Together we prepare for the future" className="w-full" />
<img
src={data.Banner?.url || "/banner_encoach_home.png"}
alt={data.Banner?.alternativeText ?? "IELTS Packages - Together we prepare for the future"}
className="w-full"
/>
<Link href={language === "ar" ? "/ar/price" : "/price"}>
<button className="absolute bottom-1/12 -lg:hidden left-1/12 bg-mti-purple-light hover:bg-mti-purple text-white rounded-xl px-8 py-4 transition ease-in-out duration-300 shadow">
{data.GetStartedButton}

View File

@@ -67,8 +67,7 @@ export default function Page({language, data}: Props) {
getData();
}, []);
return (
<main className="h-screen w-full bg-white text-mti-black flex flex-col" dir={language === "ar" ? "rtl" : "ltr"}>
<Navbar currentPage="/price" language={language} />
<>
<section className="w-full relative bg-white px-8 flex flex-col items-center text-center gap-4">
<h2 className="text-3xl font-bold">{data.Title}</h2>
<div className="grid grid-cols-2 gap-8">
@@ -103,7 +102,6 @@ export default function Page({language, data}: Props) {
{data.SignUp}
</Link>
</section>
<Footer language={language} />
</main>
</>
);
}

View File

@@ -13,3 +13,24 @@ export type TitleWithTagAndText = TagTitle & TitleWithText;
export interface TitleWithTextAndList extends TitleWithText {
List: string;
}
export interface ImageData {
data: {
id: number;
attributes: Image;
};
}
export interface Image {
name: string;
alternativeText: string | null;
caption: string | null;
width: number;
height: number;
hash: string;
ext: string;
mime: string;
size: number;
url: string;
previewUrl: string | null;
}

View File

@@ -1,6 +1,6 @@
import {TagTitle, TitleWithTagAndText, TitleWithText} from "./common";
import {TagTitle, TitleWithTagAndText, TitleWithText, ImageData, Image} from "./common";
export default interface HomePage {
interface Base {
GetStartedButton: string;
Modules: Modules;
LearnAI: TitleWithTagAndText;
@@ -12,6 +12,16 @@ export default interface HomePage {
Accreditation: string;
}
export default interface HomePage extends Base {
Banner: Image;
AdvertisementBanner: Image;
}
export interface HomePageData extends Base {
Banner: ImageData;
AdvertisementBanner: ImageData;
}
interface Modules {
Reading: TitleWithText;
Listening: TitleWithText;

View File

@@ -2263,10 +2263,10 @@ react-hook-form@^7.50.1:
resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.50.1.tgz#f6aeb17a863327e5a0252de8b35b4fc8990377ed"
integrity sha512-3PCY82oE0WgeOgUtIr3nYNNtNvqtJ7BZjsbxh6TnYNbXButaD5WpjOmTjdxZfheuHKR68qfeFnEDVYoSSFPMTQ==
react-icons@^4.11.0:
version "4.11.0"
resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-4.11.0.tgz#4b0e31c9bfc919608095cc429c4f1846f4d66c65"
integrity sha512-V+4khzYcE5EBk/BvcuYRq6V/osf11ODUM2J8hg2FDSswRrGvqiYUYPRy4OdrWaQOBj4NcpJfmHZLNaD+VH0TyA==
react-icons@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-5.1.0.tgz#9e7533cc256571a610c2a1ec8a7a143fb1222943"
integrity sha512-D3zug1270S4hbSlIRJ0CUS97QE1yNNKDjzQe3HqY0aefp2CBn9VgzgES27sRR2gOvFK+0CNx/BW0ggOESp6fqQ==
react-is@^16.13.1:
version "16.13.1"