Skip to content
This repository was archived by the owner on Jan 30, 2025. It is now read-only.

Commit fa2dc23

Browse files
committed
add navigation to the chapter page
1 parent 3f4b7ed commit fa2dc23

File tree

4 files changed

+104
-2
lines changed

4 files changed

+104
-2
lines changed

src/components/ChapterDetails.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ const ChapterDetails = ({ completed, data }: ChapterDetailsProps) => {
2727
<ItemActionsMenu />
2828
</div>
2929
<ItemProgress progress={completed} />
30-
<Typography variant="body1">{description}</Typography>
30+
<Typography variant="body1" gutterBottom>
31+
{description}
32+
</Typography>
3133
</CardContent>
3234
</Card>
3335
);

src/components/ChapterNav.tsx

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { useEffect, useState } from 'react';
2+
import NextLink from 'next/link';
3+
import { Button } from '@material-ui/core';
4+
import { ArrowBack, ArrowForward } from '@material-ui/icons';
5+
import { getChapterNavigation } from '@zoonk/services';
6+
import useTranslation from './useTranslation';
7+
8+
interface ChapterNavProps {
9+
chapterId: string;
10+
topicId: string;
11+
}
12+
13+
const ChapterNav = ({ chapterId, topicId }: ChapterNavProps) => {
14+
const translate = useTranslation();
15+
const [previous, setPrevious] = useState<string | null>(null);
16+
const [next, setNext] = useState<string | null>(null);
17+
18+
useEffect(() => {
19+
getChapterNavigation(chapterId, topicId).then((res) => {
20+
setPrevious(res.previous);
21+
setNext(res.next);
22+
});
23+
}, [chapterId, topicId]);
24+
25+
if (!previous && !next) return null;
26+
27+
return (
28+
<nav style={{ display: 'flex', alignItems: 'center' }}>
29+
{previous && (
30+
<NextLink href="/chapters/[id]" as={`/chapters/${previous}`} passHref>
31+
<Button
32+
color="primary"
33+
variant="outlined"
34+
startIcon={<ArrowBack style={{ margin: 0 }} />}
35+
component="a"
36+
>
37+
{translate('previous')}
38+
</Button>
39+
</NextLink>
40+
)}
41+
<div style={{ flexGrow: 1 }} />
42+
{next && (
43+
<NextLink href="/chapters/[id]" as={`/chapters/${next}`} passHref>
44+
<Button
45+
color="primary"
46+
variant="outlined"
47+
endIcon={<ArrowForward style={{ margin: 0 }} />}
48+
component="a"
49+
>
50+
{translate('next')}
51+
</Button>
52+
</NextLink>
53+
)}
54+
</nav>
55+
);
56+
};
57+
58+
export default ChapterNav;

src/pages/chapters/[id]/index.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { NextPage } from 'next';
22
import Error from 'next/error';
33
import { Container, Grid } from '@material-ui/core';
44
import ChapterDetails from '@zoonk/components/ChapterDetails';
5+
import ChapterNav from '@zoonk/components/ChapterNav';
56
import LessonsCard from '@zoonk/components/LessonsCard';
67
import Meta from '@zoonk/components/Meta';
78
import TopicsBreadcrumb from '@zoonk/components/TopicsBreadcrumb';
@@ -64,6 +65,9 @@ const ChapterPage: NextPage<ChapterProps> = ({ data }) => {
6465
progress={progress}
6566
/>
6667
</Grid>
68+
<Grid item xs={12}>
69+
<ChapterNav chapterId={id} topicId={topics[0]} />
70+
</Grid>
6771
</Grid>
6872
</Container>
6973
);

src/services/chapters.ts

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { db, timestamp } from '@zoonk/firebase/db';
22
import { Chapter, Profile } from '@zoonk/models';
33
import { generateRandomSlug, logEdit } from '@zoonk/utils';
4-
import { updateTopic } from './topics';
4+
import { getTopic, updateTopic } from './topics';
55
import { serializeChapter } from '../serializers';
66

77
const chapterConverter: firebase.firestore.FirestoreDataConverter<Chapter.Get> = {
@@ -93,3 +93,41 @@ export const deleteChapter = async (
9393
await updateChapter(update, id);
9494
return db.doc(`chapters/${id}`).delete();
9595
};
96+
97+
export const getNextChapter = async (
98+
current: string,
99+
topicId: string,
100+
): Promise<string | null> => {
101+
const topic = await getTopic(topicId);
102+
if (!topic) return null;
103+
104+
const { chapters } = topic;
105+
const chapterOrder = chapters.findIndex((chapter) => chapter === current);
106+
const nextChapter = chapterOrder + 1;
107+
108+
// If there's another chapter after the current one, then use its ID.
109+
return chapters[nextChapter] || null;
110+
};
111+
112+
interface ChapterNav {
113+
next: string | null;
114+
previous: string | null;
115+
}
116+
117+
export const getChapterNavigation = async (
118+
current: string,
119+
topicId: string,
120+
): Promise<ChapterNav> => {
121+
const topic = await getTopic(topicId);
122+
if (!topic) return { next: null, previous: null };
123+
124+
const { chapters } = topic;
125+
const chapterOrder = chapters.findIndex((chapter) => chapter === current);
126+
const previousChapter = chapterOrder - 1;
127+
const nextChapter = chapterOrder + 1;
128+
129+
return {
130+
next: chapters[nextChapter] || null,
131+
previous: chapters[previousChapter] || null,
132+
};
133+
};

0 commit comments

Comments
 (0)