Skip to content

Commit

Permalink
Refactor and fix next page text logic
Browse files Browse the repository at this point in the history
  • Loading branch information
nygrenh committed Sep 6, 2024
1 parent aa4e9b9 commit 5eff33c
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 136 deletions.
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import { useQuery } from "@tanstack/react-query"
import { differenceInSeconds, formatDuration, parseISO } from "date-fns"
import React, { useEffect } from "react"
import { i18n, TFunction } from "i18next"
import React, { useMemo } from "react"
import { useTranslation } from "react-i18next"

import useTime from "../../../../hooks/useTime"
import { fetchPageNavigationData } from "../../../../services/backend"
import { courseFrontPageRoute, coursePageRoute } from "../../../../utils/routing"

import { PageNavigationInformation } from "@/shared-module/common/bindings"
import ErrorBanner from "@/shared-module/common/components/ErrorBanner"
import NextSectionLink from "@/shared-module/common/components/NextSectionLink"
import NextSectionLink, {
NextSectionLinkProps,
} from "@/shared-module/common/components/NextSectionLink"
import Spinner from "@/shared-module/common/components/Spinner"

export interface NextPageProps {
Expand All @@ -18,6 +22,9 @@ export interface NextPageProps {
organizationSlug: string
}

const NUMERIC = "numeric"
const LONG = "long"

const NextPage: React.FC<React.PropsWithChildren<NextPageProps>> = ({
chapterId,
currentPageId,
Expand All @@ -26,165 +33,141 @@ const NextPage: React.FC<React.PropsWithChildren<NextPageProps>> = ({
}) => {
const { t, i18n } = useTranslation()
const now = useTime()
const [nextPageChapterOpen, setnextPageChapterOpen] = React.useState(false)

const getPageRoutingData = useQuery({
queryKey: [`pages-${chapterId}-page-routing-data`, currentPageId],
queryFn: () => fetchPageNavigationData(currentPageId),
})

useEffect(() => {
const nextPageProps = useMemo(() => {
if (!getPageRoutingData.data) {
return
}
if (!getPageRoutingData.data.next_page) {
return
}
if (getPageRoutingData.data.next_page.chapter_opens_at === null) {
setnextPageChapterOpen(true)
return
return null
}
const diffSeconds = differenceInSeconds(getPageRoutingData.data.next_page.chapter_opens_at, now)
setnextPageChapterOpen(diffSeconds <= 0)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [getPageRoutingData.data])
return deriveNextpageProps(
t,
getPageRoutingData.data,
chapterId,
now,
i18n,
organizationSlug,
courseSlug,
currentPageId,
)
}, [
chapterId,
courseSlug,
currentPageId,
getPageRoutingData.data,
i18n,
now,
organizationSlug,
t,
])

if (getPageRoutingData.isError) {
return <ErrorBanner variant={"readOnly"} error={getPageRoutingData.error} />
}
if (getPageRoutingData.isPending) {
if (getPageRoutingData.isPending || !nextPageProps) {
return <Spinner variant={"medium"} />
}

const { chapter_front_page, next_page, previous_page } = getPageRoutingData.data

if (next_page === null) {
// if data is null we have reached the end of the course material. i.e. no page or chapter found
return (
<NextSectionLink
title={t("title-congratulations")}
subtitle={t("reached-end-of-course-material")}
nextTitle={t("action-back-to-front-page")}
url={courseFrontPageRoute(organizationSlug, courseSlug)}
/>
)
return (
// Chapter exists, but next chapter not open yet.
<NextSectionLink {...nextPageProps} />
)
}

function deriveNextpageProps(
t: TFunction,
info: PageNavigationInformation,
chapterId: string | null,
now: Date,
i18n: i18n,
organizationSlug: string,
courseSlug: string,
currentPageId: string,
): NextSectionLinkProps {
const res: NextSectionLinkProps = {
title: t("reached-end-of-topic"),
subtitle: t("proceed-to-next-topic"),
nextTitle: "",
chapterFrontPageURL: coursePageRoute(
organizationSlug,
courseSlug,
info.chapter_front_page?.url_path ?? "",
),
}

if (previous_page === null) {
// if data is null, we are in the beginning of the course (chapter-1 frontpage precisely)
// eslint-disable-next-line i18next/no-literal-string
return (
<NextSectionLink
title={t("start-studying")}
subtitle={t("proceed-to-the-first-topic")}
nextTitle={next_page.title}
url={coursePageRoute(organizationSlug, courseSlug, next_page.url_path)}
/>
)
const endOfCourse = info.next_page === null
const endOfChapter = info.next_page?.chapter_id !== chapterId
const currentPageIsChapterFrontPage = Boolean(
info.chapter_front_page && info.chapter_front_page.chapter_front_page_id === currentPageId,
)
let nextPageIsNotOpen = false
if (info.next_page && info.next_page.chapter_opens_at !== null) {
const diffSeconds = differenceInSeconds(info.next_page.chapter_opens_at, now)
if (diffSeconds > 0) {
nextPageIsNotOpen = true
}
}

const NUMERIC = "numeric"
const LONG = "long"
const nextPageUrl = coursePageRoute(organizationSlug, courseSlug, next_page.url_path)

const previousPageUrl = coursePageRoute(organizationSlug, courseSlug, previous_page.url_path)

if (chapter_front_page === null) {
// if data is null, we are in the chapter front-page
return (
<NextSectionLink
title={t("start-studying")}
subtitle={t("proceed-to-the-first-topic")}
nextTitle={next_page.title}
url={coursePageRoute(organizationSlug, courseSlug, next_page.url_path)}
/>
)
if (info.previous_page !== null) {
res.previous = coursePageRoute(organizationSlug, courseSlug, info.previous_page.url_path)
}
if (info.next_page !== null) {
res.nextTitle = info.next_page.title
res.url = coursePageRoute(organizationSlug, courseSlug, info.next_page.url_path)
}

// eslint-disable-next-line i18next/no-literal-string
const chapterPageUrl = coursePageRoute(organizationSlug, courseSlug, chapter_front_page.url_path)

// Chapter front page NextSectionLink
if (next_page.chapter_front_page_id === currentPageId) {
return (
<NextSectionLink
title={t("start-studying")}
subtitle={t("proceed-to-the-first-topic")}
nextTitle={next_page.title}
url={nextPageUrl}
previous={previousPageUrl}
/>
)
if (currentPageIsChapterFrontPage) {
res.title = t("start-studying")
res.subtitle = t("proceed-to-the-first-topic")
res.chapterFrontPageURL = undefined
}
if (nextPageChapterOpen) {
if (chapterId !== next_page.chapter_id) {
// End of chapter NextSectionLink
return (
<NextSectionLink
title={t("impressive-reached-end-of-chapter")}
subtitle={t("proceed-to-the-next-chapter")}
nextTitle={next_page.title}
url={nextPageUrl}
previous={previousPageUrl}
chapterFrontPageURL={chapterPageUrl}
/>
)
} else {
// End of page NextSectionLink
return (
<NextSectionLink
title={t("reached-end-of-topic")}
subtitle={t("proceed-to-next-topic")}
nextTitle={next_page.title}
url={nextPageUrl}
previous={previousPageUrl}
chapterFrontPageURL={chapterPageUrl}
/>
)
}
} else {
let closedUntil
if (next_page.chapter_opens_at) {
const diffSeconds = differenceInSeconds(next_page.chapter_opens_at, now)

if (endOfChapter) {
res.title = t("impressive-reached-end-of-chapter")
res.subtitle = t("proceed-to-the-next-chapter")
}

if (endOfCourse) {
res.title = t("title-congratulations")
res.subtitle = t("reached-end-of-course-material")
res.nextTitle = t("action-back-to-front-page")
res.url = courseFrontPageRoute(organizationSlug, courseSlug)
}

if (nextPageIsNotOpen) {
res.nextTitle = t("closed")
res.url = undefined
if (info.next_page?.chapter_opens_at) {
const diffSeconds = differenceInSeconds(info.next_page.chapter_opens_at, now)
if (diffSeconds <= 0) {
// eslint-disable-next-line i18next/no-literal-string
setnextPageChapterOpen(true)
closedUntil = t("opens-now")
// Insert confetti drop here.
res.nextTitle = t("opens-now")
} else if (diffSeconds < 60 * 10) {
const minutes = Math.floor(diffSeconds / 60)
const seconds = diffSeconds % 60
const formatted = formatDuration({
minutes,
seconds,
})
closedUntil = t("opens-in-time", { "relative-time": formatted })
res.nextTitle = t("opens-in-time", { "relative-time": formatted })
} else {
const date = parseISO(next_page.chapter_opens_at).toLocaleString(i18n.language, {
const date = parseISO(info.next_page.chapter_opens_at).toLocaleString(i18n.language, {
year: NUMERIC,
month: LONG,
day: NUMERIC,
})
const time = parseISO(next_page.chapter_opens_at).toLocaleString(i18n.language, {
const time = parseISO(info.next_page.chapter_opens_at).toLocaleString(i18n.language, {
hour: NUMERIC,
minute: NUMERIC,
})
closedUntil = t("available-on-date-at-time", { date: date, time: time })
res.nextTitle = t("available-on-date-at-time", { date: date, time: time })
}
} else {
closedUntil = t("closed")
}
return (
// Chapter exists, but next chapter not open yet.
<NextSectionLink
title={t("impressive-reached-end-of-chapter")}
subtitle={t("please-wait-until-next-chapter-opens")}
nextTitle={closedUntil}
previous={previousPageUrl}
chapterFrontPageURL={chapterPageUrl}
/>
)
}

return res
}

export default NextPage

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 11 additions & 11 deletions services/headless-lms/models/src/pages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2433,7 +2433,7 @@ pub async fn get_page_navigation_data(
.await
.transpose()?;

let chapter_front_page_data = chapter_front_page
let chapter_front_page = chapter_front_page
.map(|front_page| -> ModelResult<_> {
if let Some(chapter_front_page_chapter) = chapter_front_page_chapter {
Ok(PageRoutingData {
Expand All @@ -2455,7 +2455,7 @@ pub async fn get_page_navigation_data(
})
.transpose()?;
Ok(PageNavigationInformation {
chapter_front_page: chapter_front_page_data,
chapter_front_page,
next_page: next_page_data,
previous_page: previous_page_data,
})
Expand Down Expand Up @@ -2534,15 +2534,15 @@ async fn get_previous_page_by_chapter_number(
let previous_page = sqlx::query_as!(
PageRoutingData,
"
SELECT p.url_path as url_path,
p.title as title,
p.id as page_id,
c.chapter_number as chapter_number,
c.id as chapter_id,
c.opens_at as chapter_opens_at,
c.front_page_id as chapter_front_page_id
SELECT p.url_path AS url_path,
p.title AS title,
p.id AS page_id,
c.chapter_number AS chapter_number,
c.id AS chapter_id,
c.opens_at AS chapter_opens_at,
c.front_page_id AS chapter_front_page_id
FROM chapters c
INNER JOIN pages p on c.id = p.chapter_id
INNER JOIN pages p ON c.id = p.chapter_id
WHERE c.chapter_number = (
SELECT MAX(ca.chapter_number)
FROM chapters ca
Expand All @@ -2551,7 +2551,7 @@ WHERE c.chapter_number = (
)
AND c.course_id = $2
AND p.deleted_at IS NULL
ORDER BY p.order_number
ORDER BY p.order_number DESC
LIMIT 1;
",
current_page_metadata.chapter_number,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { respondToOrLarger } from "../styles/respond"
import LinkOrNoLink from "./LinkOrNoLink"
import HideTextInSystemTests from "./system-tests/HideTextInSystemTests"

export interface NextSectionLinkExtraProps {
export interface NextSectionLinkProps {
title: string
subtitle: string
nextTitle: string
Expand Down Expand Up @@ -78,8 +78,6 @@ const StyledLink = styled(Link)`
}
`

export type NextSectionLinkProps = React.HTMLAttributes<HTMLDivElement> & NextSectionLinkExtraProps

const NextSectionLink: React.FC<
React.PropsWithChildren<React.PropsWithChildren<NextSectionLinkProps>>
> = ({ title, subtitle, nextTitle, url, previous, chapterFrontPageURL }) => {
Expand Down

0 comments on commit 5eff33c

Please sign in to comment.