diff --git a/app/[lang]/programs/index.tsx b/app/[lang]/programs/index.tsx
new file mode 100644
index 0000000..de9c23f
--- /dev/null
+++ b/app/[lang]/programs/index.tsx
@@ -0,0 +1,612 @@
+"use client"
+
+import { useCallback, useEffect, useRef, useState } from "react"
+import Image from "next/image"
+import Link from "next/link"
+import { acceleratorProgramFaq } from "@/data/programs/acceleratorProgramFaq"
+import { coreProgramFaq } from "@/data/programs/coreProgramFaq"
+import { ReactNode } from "react-markdown/lib/ast-to-react"
+import { twMerge } from "tailwind-merge"
+
+import { siteConfig } from "@/config/site"
+import { cn } from "@/lib/utils"
+import { Accordion } from "@/components/ui/accordion"
+import { AppContent } from "@/components/ui/app-content"
+import { Button } from "@/components/ui/button"
+import { Dropdown, DropdownProps } from "@/components/ui/dropdown"
+import { Card } from "@/components/cards/card"
+import { Icons } from "@/components/icons"
+import { PageHeader } from "@/components/page-header"
+import { useTranslation } from "@/app/i18n/client"
+
+type ProgramDetailProps = {
+ region?: string
+ title: ReactNode
+ deadline?: string
+ location?: string
+ date: string
+}
+
+const SectionTitle = ({ label }: { label: string }) => {
+ return (
+
+ {label}
+
+ )
+}
+
+const AccordionLabel = ({
+ label,
+ className,
+}: {
+ label: string
+ className?: string
+}) => {
+ return (
+
+ {label}
+
+ )
+}
+
+const ProgramDetail = ({
+ title,
+ location,
+ date,
+ region,
+ deadline,
+}: ProgramDetailProps) => {
+ return (
+
+
+ {region}
+ {title}
+
+
+ {deadline && (
+
+ Application Deadline: {deadline}
+
+ )}
+
+ {location && (
+
+
+
+ {location}
+
+
+ )}
+
+
+ {date}
+
+
+ )
+}
+
+const ProgramSections = ["coreProgram", "acceleratorProgram"] as const
+
+const ChooseProgramItems: { label: string; value: string; href?: string }[] = [
+ {
+ label: "Core Program",
+ value: "coreProgram",
+ href: siteConfig.links.coreProgram,
+ },
+ {
+ label: "Accelerator Program",
+ value: "acceleratorProgram",
+ href: siteConfig.links.acceleratorProgram,
+ },
+]
+export const ProgramPageContent = ({ lang }: any) => {
+ const { t } = useTranslation(lang, "programs-page")
+ const { t: common } = useTranslation(lang, "common")
+ const [activeId, setActiveId] = useState("")
+ const [isManualScroll, setIsManualScroll] = useState(false)
+ const [selectedProgram, setSelectedProgram] = useState(
+ ChooseProgramItems[0].value
+ )
+ const SCROLL_OFFSET = -400
+ const sectionsRef = useRef | null>(null)
+ const [{ value: defaultProgramValue }] = ChooseProgramItems
+
+ const howToApply: any =
+ t("howToApply", {
+ returnObjects: true,
+ }) || []
+
+ const coreProgramDescription: any[] =
+ t("coreProgram.description", {
+ returnObjects: true,
+ }) || []
+ const acceleratorProgramDescription: any[] =
+ t("acceleratorProgram.description", {
+ returnObjects: true,
+ }) ?? []
+
+ const curriculum: any[] =
+ t("curriculum", {
+ returnObjects: true,
+ }) ?? []
+
+ useEffect(() => {
+ if (sectionsRef.current === null)
+ sectionsRef.current = document.querySelectorAll(`div[data-section]`)
+ if (!activeId) setActiveId(ProgramSections?.[0] ?? "")
+
+ const handleScroll = () => {
+ if (isManualScroll) return
+
+ sectionsRef.current?.forEach((section: any) => {
+ const sectionTop = section.offsetTop - SCROLL_OFFSET
+ if (window.scrollY >= sectionTop && window.scrollY > 0) {
+ setActiveId(section.getAttribute("id"))
+ }
+ })
+ }
+
+ window.addEventListener("scroll", handleScroll)
+ return () => window.removeEventListener("scroll", handleScroll)
+ }, [SCROLL_OFFSET, activeId, isManualScroll])
+
+ const scrollToId = useCallback((id: string) => {
+ const element = document.getElementById(id)
+ const top = element?.offsetTop ?? 0
+
+ if (element) {
+ setActiveId(id) // active clicked id
+ setIsManualScroll(true) // tell the window event listener to ignore this scrolling
+ window?.scrollTo({
+ behavior: "smooth",
+ top: (top ?? 0) - SCROLL_OFFSET,
+ })
+ }
+
+ setTimeout(() => setIsManualScroll(false), 800)
+ }, [])
+
+ const selectedProgramKey: string =
+ ChooseProgramItems?.find((item) => item.value === selectedProgram)?.label ??
+ ""
+ const selectedProgramLabel = t(selectedProgramKey)
+
+ const ApplyButton = () => {
+ return (
+
+ )
+ }
+
+ const selectedProgramUrl = ChooseProgramItems?.find(
+ (item) => item.value === selectedProgram
+ )?.href
+
+ return (
+
+
+ {defaultProgramValue && (
+
+ }
+ actions={
+ defaultProgramValue && (
+
+
+ {common("chooseProgram")}*
+ setSelectedProgram(value)}
+ defaultItem={defaultProgramValue}
+ />
+
+ {!selectedProgram ? (
+
+ ) : (
+
+
+
+ )}
+
+ )
+ }
+ />
+ )}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {coreProgramDescription?.map((description, index) => {
+ return (
+
+ {description}
+
+ )
+ })}
+
+
+
+
+ ),
+ value: "curriculum",
+ children: (
+
+ {curriculum.map(({ title, items }, index) => (
+
+
+
+ {t("common.week", {
+ week: index,
+ })}
+
+ {title}
+
+
+
+
+ {items.map(
+ (label: string, index: number) => {
+ return - {label}
+ }
+ )}
+
+
+
+ ))}
+
+ ),
+ },
+ ]}
+ />
+
,
+ value: "faq",
+ children: (
+
+
{
+ return {
+ label: (
+
+ {question}
+
+ ),
+ value: index.toString(),
+ children: (
+
+ ),
+ }
+ }
+ )}
+ />
+
+ ),
+ },
+ ]}
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Acceleration Program
+ Round 2
+ >
+ }
+ deadline="May 31, 2024"
+ location="Remote Application"
+ date="June 1, 2024 - August 31, 2024"
+ />
+
+
+
+
+
+
+
+
+ {acceleratorProgramDescription?.map((description, index) => {
+ return (
+
+ {description}
+
+ )
+ })}
+
+
+
,
+ value: "howToApply",
+ children: (
+
+
+
+
+
+ {t("howToApply.openTasks.title")}
+
+
+ {howToApply?.openTasks?.description?.map(
+ (task: string, index: number) => {
+ return (
+ -
+
+
+ )
+ }
+ )}
+
+
+
+
+ {t("howToApply.submitIdea.title")}
+
+
+ {howToApply?.submitIdea?.description?.map(
+ (task: string, index: number) => {
+ return (
+ -
+
+
+ )
+ }
+ )}
+
+
+
+ {t("howToApply.description")}
+
+
+
+
+ ),
+ },
+ ]}
+ />
+
+
,
+ value: "faq",
+ children: (
+
+
{
+ return {
+ label: (
+
+ {question}
+
+ ),
+ value: index.toString(),
+ children: (
+
+ {answer}
+
+ ),
+ }
+ }
+ )}
+ />
+
+ ),
+ },
+ ]}
+ />
+
+
+
+
+
+
+
+ )
+}
diff --git a/app/[lang]/programs/page.tsx b/app/[lang]/programs/page.tsx
index e9ac051..9573d77 100644
--- a/app/[lang]/programs/page.tsx
+++ b/app/[lang]/programs/page.tsx
@@ -1,611 +1,21 @@
-"use client"
+import { Metadata } from "next"
-import { ReactNode, useCallback, useEffect, useRef, useState } from "react"
-import Image from "next/image"
-import Link from "next/link"
-import { acceleratorProgramFaq } from "@/data/programs/acceleratorProgramFaq"
-import { coreProgramFaq } from "@/data/programs/coreProgramFaq"
-import { twMerge } from "tailwind-merge"
+import { ProgramPageContent } from "."
-import { siteConfig } from "@/config/site"
-import { cn } from "@/lib/utils"
-import { Accordion } from "@/components/ui/accordion"
-import { AppContent } from "@/components/ui/app-content"
-import { Button } from "@/components/ui/button"
-import { Dropdown, DropdownProps } from "@/components/ui/dropdown"
-import { Card } from "@/components/cards/card"
-import { Icons } from "@/components/icons"
-import { PageHeader } from "@/components/page-header"
-import { useTranslation } from "@/app/i18n/client"
-
-type ProgramDetailProps = {
- region?: string
- title: ReactNode
- deadline?: string
- location?: string
- date: string
-}
-
-const SectionTitle = ({ label }: { label: string }) => {
- return (
-
- {label}
-
- )
-}
-
-const AccordionLabel = ({
- label,
- className,
-}: {
- label: string
- className?: string
-}) => {
- return (
-
- {label}
-
- )
-}
-
-const ProgramDetail = ({
- title,
- location,
- date,
- region,
- deadline,
-}: ProgramDetailProps) => {
- return (
-
-
- {region}
- {title}
-
-
- {deadline && (
-
- Application Deadline: {deadline}
-
- )}
-
- {location && (
-
-
-
- {location}
-
-
- )}
-
-
- {date}
-
-
- )
-}
-
-const ProgramSections = ["coreProgram", "acceleratorProgram"] as const
-
-const ChooseProgramItems: { label: string; value: string; href?: string }[] = [
- {
- label: "Core Program",
- value: "coreProgram",
- href: siteConfig.links.coreProgram,
+export const metadata: Metadata = {
+ title: "Programs page",
+ description: "Join our free programs to start your journey!",
+ openGraph: {
+ images: [
+ {
+ url: "/programs-page-banner.png",
+ width: 1200,
+ height: 630,
+ },
+ ],
},
- {
- label: "Accelerator Program",
- value: "acceleratorProgram",
- href: siteConfig.links.acceleratorProgram,
- },
-]
+}
+
export default function ProgramsPage({ params: { lang } }: any) {
- const { t } = useTranslation(lang, "programs-page")
- const { t: common } = useTranslation(lang, "common")
- const [activeId, setActiveId] = useState("")
- const [isManualScroll, setIsManualScroll] = useState(false)
- const [selectedProgram, setSelectedProgram] = useState(
- ChooseProgramItems[0].value
- )
- const SCROLL_OFFSET = -400
- const sectionsRef = useRef | null>(null)
- const [{ value: defaultProgramValue }] = ChooseProgramItems
-
- const howToApply: any =
- t("howToApply", {
- returnObjects: true,
- }) || []
-
- const coreProgramDescription: any[] =
- t("coreProgram.description", {
- returnObjects: true,
- }) || []
- const acceleratorProgramDescription: any[] =
- t("acceleratorProgram.description", {
- returnObjects: true,
- }) ?? []
-
- const curriculum: any[] =
- t("curriculum", {
- returnObjects: true,
- }) ?? []
-
- useEffect(() => {
- if (sectionsRef.current === null)
- sectionsRef.current = document.querySelectorAll(`div[data-section]`)
- if (!activeId) setActiveId(ProgramSections?.[0] ?? "")
-
- const handleScroll = () => {
- if (isManualScroll) return
-
- sectionsRef.current?.forEach((section: any) => {
- const sectionTop = section.offsetTop - SCROLL_OFFSET
- if (window.scrollY >= sectionTop && window.scrollY > 0) {
- setActiveId(section.getAttribute("id"))
- }
- })
- }
-
- window.addEventListener("scroll", handleScroll)
- return () => window.removeEventListener("scroll", handleScroll)
- }, [SCROLL_OFFSET, activeId, isManualScroll])
-
- const scrollToId = useCallback((id: string) => {
- const element = document.getElementById(id)
- const top = element?.offsetTop ?? 0
-
- if (element) {
- setActiveId(id) // active clicked id
- setIsManualScroll(true) // tell the window event listener to ignore this scrolling
- window?.scrollTo({
- behavior: "smooth",
- top: (top ?? 0) - SCROLL_OFFSET,
- })
- }
-
- setTimeout(() => setIsManualScroll(false), 800)
- }, [])
-
- const selectedProgramKey: string =
- ChooseProgramItems?.find((item) => item.value === selectedProgram)?.label ??
- ""
- const selectedProgramLabel = t(selectedProgramKey)
-
- const ApplyButton = () => {
- return (
-
- )
- }
-
- const selectedProgramUrl = ChooseProgramItems?.find(
- (item) => item.value === selectedProgram
- )?.href
-
- return (
-
-
- {defaultProgramValue && (
-
- }
- actions={
- defaultProgramValue && (
-
-
- {common("chooseProgram")}*
- setSelectedProgram(value)}
- defaultItem={defaultProgramValue}
- />
-
- {!selectedProgram ? (
-
- ) : (
-
-
-
- )}
-
- )
- }
- />
- )}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {coreProgramDescription?.map((description, index) => {
- return (
-
- {description}
-
- )
- })}
-
-
-
-
- ),
- value: "curriculum",
- children: (
-
- {curriculum.map(({ title, items }, index) => (
-
-
-
- {t("common.week", {
- week: index,
- })}
-
- {title}
-
-
-
-
- {items.map(
- (label: string, index: number) => {
- return - {label}
- }
- )}
-
-
-
- ))}
-
- ),
- },
- ]}
- />
-
,
- value: "faq",
- children: (
-
-
{
- return {
- label: (
-
- {question}
-
- ),
- value: index.toString(),
- children: (
-
- ),
- }
- }
- )}
- />
-
- ),
- },
- ]}
- />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Acceleration Program
- Round 2
- >
- }
- deadline="May 31, 2024"
- location="Remote Application"
- date="June 1, 2024 - August 31, 2024"
- />
-
-
-
-
-
-
-
-
- {acceleratorProgramDescription?.map((description, index) => {
- return (
-
- {description}
-
- )
- })}
-
-
-
,
- value: "howToApply",
- children: (
-
-
-
-
-
- {t("howToApply.openTasks.title")}
-
-
- {howToApply?.openTasks?.description?.map(
- (task: string, index: number) => {
- return (
- -
-
-
- )
- }
- )}
-
-
-
-
- {t("howToApply.submitIdea.title")}
-
-
- {howToApply?.submitIdea?.description?.map(
- (task: string, index: number) => {
- return (
- -
-
-
- )
- }
- )}
-
-
-
- {t("howToApply.description")}
-
-
-
-
- ),
- },
- ]}
- />
-
-
,
- value: "faq",
- children: (
-
-
{
- return {
- label: (
-
- {question}
-
- ),
- value: index.toString(),
- children: (
-
- {answer}
-
- ),
- }
- }
- )}
- />
-
- ),
- },
- ]}
- />
-
-
-
-
-
-
-
- )
+ return
}
diff --git a/public/programs-page-banner.png b/public/programs-page-banner.png
new file mode 100644
index 0000000..12a38f1
Binary files /dev/null and b/public/programs-page-banner.png differ