Skip to content

Commit 3e2c925

Browse files
Merge pull request #74 from talent-path-pipeline/c58-youtube-api-integration
some lesson pane refactors
2 parents 8cf965d + 2338412 commit 3e2c925

File tree

11 files changed

+145
-70
lines changed

11 files changed

+145
-70
lines changed

package-lock.json

Lines changed: 55 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"@fortawesome/react-fontawesome": "^0.1.4",
99
"@glidejs/glide": "^3.3.0",
1010
"axios": "^0.19.0",
11+
"dotenv": "^8.1.0",
1112
"isotope-layout": "^3.0.6",
1213
"node-sass": "^4.12.0",
1314
"prop-types": "^15.7.2",
@@ -16,7 +17,8 @@
1617
"react-dom": "^16.8.6",
1718
"react-router-dom": "^5.0.1",
1819
"react-scripts": "3.0.1",
19-
"react-vertical-timeline-component": "^2.4.0"
20+
"react-vertical-timeline-component": "^2.4.0",
21+
"react-youtube": "^7.9.0"
2022
},
2123
"scripts": {
2224
"start": "react-scripts start",

src/App.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,15 @@ function App() {
5353
const courseObj = courses.find(
5454
course => course.slug === props.match.params.course,
5555
);
56-
if (!courseObj) return <ErrorPage />;
56+
const order = parseInt(props.match.params.order, 10);
57+
if (!courseObj || order >= courseObj.lessons.length) return <ErrorPage />;
5758
return (
5859
<LessonPage
5960
{...props}
61+
course_title={courseObj.title}
6062
lessons={courseObj.lessons}
61-
curr_lesson_num={parseInt(props.match.params.order, 10)}
62-
base_path={props.match.params.course}
63+
curr_lesson_num={order}
64+
base_path={courseObj.slug}
6365
/>
6466
);
6567
}}

src/DUMMY_DATA.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
// channel page: https://www.youtube.com/channel/UCqJ-Xo29CKyLTjn6z2XwYAw
2+
// api call: https://www.googleapis.com/youtube/v3/videos?part=[PART TYPE]&id=[VIDEO ID]key=[API KEY]
3+
// part type = snippet gets: publishedAt, channelId, title, description, thumbnails, channelTitle, tags, categoryId
4+
// part type = contentDetails gets: duration, dimension, definition, caption, licensedContent, projection
5+
16
const example_session = {
27
order: 0,
38
src: 'https://www.youtube.com/embed/MFCzwiqlnCE',
@@ -65,7 +70,7 @@ const adventure_begins = {
6570
const make_rules = {
6671
order: 0,
6772
src: 'https://www.youtube.com/embed/g5lrIDoEPOw',
68-
length: 3603,
73+
length: 'PT3H9M7S',
6974
title: 'You Make the Rules!',
7075
description: `The published D&D sourcebooks have their fair share of suggested rules... but as the DM, you have the special privilege to bend those to your will! Learn in this video how to set house rules for your campaign and your world, and begin collecting these guidelines in a Player's Guide for your party.`,
7176
};

src/components/lesson/Lesson.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
import React from 'react';
22
import PropTypes from 'prop-types';
3+
// import YouTube from 'react-youtube';
4+
// https://www.npmjs.com/package/react-youtube
35
import { LessonVideo, LessonInfo } from '..';
46
import '../../css/lesson/Lesson.scss';
57

68
const Lesson = ({ title, src, description, order, course_size, base_path }) => (
79
<div className="lesson" key={order}>
10+
{/* <YouTube videoId={} opts={} onEnd={} /> */}
811
<LessonVideo title={title} src={src} />
912
<LessonInfo title={title} order={order} description={description} course_size={course_size} base_path={base_path} />
1013
</div>

src/components/lesson/LessonInfo.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ import { LessonNav } from '..';
33
import PropTypes from 'prop-types';
44
import '../../css/lesson/LessonInfo.scss';
55

6+
// TODO: add content channel link
7+
// TODO: add description about channel and text from actual video
8+
// TODO: add next and previous lesson buttons
69
const LessonInfo = ({ title, description, order, base_path, course_size }) => (
710
<div className="lesson-info">
811
<LessonNav order={order} base_path={base_path} course_size={course_size} />

src/components/lesson/LessonLink.js

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,25 @@
11
import React from 'react';
2-
import { Link } from 'react-router-dom'
2+
import { Link } from 'react-router-dom';
33
import PropTypes from 'prop-types';
44
import '../../css/lesson/LessonLink.scss';
55

6-
const formatTime = seconds => {
7-
const h = Math.floor(seconds / 3600);
8-
const m = Math.floor((seconds % 3600) / 60);
9-
const s = Math.floor((seconds % 3600) % 60);
6+
const formatTime = time => {
7+
let h;
8+
let m;
9+
let s;
10+
11+
if (typeof time === 'number') {
12+
h = Math.floor(time / 3600);
13+
m = Math.floor((time % 3600) / 60);
14+
s = Math.floor((time % 3600) % 60);
15+
} else {
16+
// this is the date format the YouTube API uses: "PT3H9M7S"
17+
const timeStr = time.slice(2, time.length - 1);
18+
let msStr;
19+
// TODO: this breaks if there are no hours
20+
[h, msStr] = timeStr.split('H');
21+
[m, s] = msStr.split('M');
22+
}
1023

1124
const hStr = h > 0 ? `${h}:` : '';
1225
const mStr = `${m < 10 ? '0' : ''}${m}:`;
@@ -15,22 +28,15 @@ const formatTime = seconds => {
1528
return `${hStr}${mStr}${sStr}`;
1629
};
1730

18-
const LessonLink = ({ title, length, order, active, base_path }) => (
19-
<div className="lesson-link">
20-
{/* TODO: this can probably be consolidated */}
21-
{active ? (
22-
<div className="active-video">
23-
<p>{title}
24-
<span className="video-length">{formatTime(length)}</span>
25-
</p>
26-
</div>
27-
) : (
28-
<div className="link">
29-
<Link to={`/courses/${base_path}/${order}`}>{title}<span className="video-length">{formatTime(length)}</span></Link>
30-
</div>
31-
)}
32-
</div>
33-
);
31+
const LessonLink = ({ title, length, order, active, base_path }) => {
32+
const TagType = active ? 'p' : Link;
33+
return (
34+
<TagType to={`/courses/${base_path}/${order}`} className="lesson-link">
35+
{title}
36+
<span className="video-length">{formatTime(length)}</span>
37+
</TagType>
38+
);
39+
};
3440

3541
LessonLink.propTypes = {
3642
title: PropTypes.string.isRequired,

src/components/lesson/LessonsPane.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,16 @@ import PropTypes from 'prop-types';
33
import { LessonLink } from '..';
44
import '../../css/lesson/LessonsPane.scss';
55

6-
const LessonsPane = ({ lessons, curr_lesson_num, base_path }) => (
6+
// TODO: add next and previous course buttons
7+
const LessonsPane = ({ course_title, lessons, curr_lesson_num, base_path }) => (
78
<div className="lessons-pane">
8-
<h2>Lessons</h2>
9-
{lessons.map(({ order, title, src, length }) => (
9+
<h2>{course_title}</h2>
10+
{lessons.map(({ order, title, length }) => (
1011
<LessonLink
12+
key={order}
1113
order={order}
1214
title={title}
13-
src={src}
1415
length={length}
15-
key={order}
1616
base_path={base_path}
1717
active={order === curr_lesson_num}
1818
/>
@@ -21,12 +21,12 @@ const LessonsPane = ({ lessons, curr_lesson_num, base_path }) => (
2121
);
2222

2323
LessonsPane.propTypes = {
24+
course_title: PropTypes.string.isRequired,
2425
curr_lesson_num: PropTypes.number.isRequired,
2526
lessons: PropTypes.arrayOf(
2627
PropTypes.shape({
2728
order: PropTypes.number.isRequired,
2829
title: PropTypes.string.isRequired,
29-
src: PropTypes.string.isRequired,
3030
length: PropTypes.number.isRequired,
3131
}),
3232
).isRequired,

src/components/pages/LessonPage.js

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,33 @@ import { Lesson, LessonsPane } from '..';
44
import '../../css/pages/LessonPage.scss';
55

66
function LessonPage(props) {
7-
const { curr_lesson_num, lessons, base_path } = props;
7+
const { curr_lesson_num, lessons, base_path, course_title } = props;
88
// const { title, src, description, id } = lessons.find(elem => elem.id === activeId);
99
const { title, src, description, order } = lessons[curr_lesson_num];
1010
const total = lessons.length;
1111

1212
return (
1313
<div className="lesson-page">
14-
<Lesson order={order} title={title} src={src} description={description} course_size={total} base_path={base_path}/>
15-
<LessonsPane lessons={lessons} curr_lesson_num={curr_lesson_num} base_path={base_path} />
14+
<Lesson
15+
order={order}
16+
title={title}
17+
src={src}
18+
description={description}
19+
course_size={total}
20+
base_path={base_path}
21+
/>
22+
<LessonsPane
23+
course_title={course_title}
24+
lessons={lessons}
25+
curr_lesson_num={curr_lesson_num}
26+
base_path={base_path}
27+
/>
1628
</div>
1729
);
1830
}
1931

2032
LessonPage.propTypes = {
33+
course_title: PropTypes.string.isRequired,
2134
curr_lesson_num: PropTypes.number.isRequired,
2235
lessons: PropTypes.arrayOf(
2336
PropTypes.shape({

src/css/lesson/LessonLink.scss

Lines changed: 18 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,36 @@
1-
21
@import '../VARIABLES.scss';
32

43
.lesson-link {
54
border: dotted var(--blue) 0.5px;
6-
}
7-
8-
.lesson-link .link {
9-
display: flex;
10-
justify-content: space-between;
11-
// padding: 1rem;
12-
cursor: pointer;
135
font-family: var(--fontfamily-alt);
6+
color: var(--black);
147

15-
p {
16-
color: var(--black);
8+
.video-length {
9+
float: right;
1710
}
18-
1911
}
2012

21-
.lesson-link .link a {
22-
color: var(--black);
23-
text-decoration: none;
13+
a.lesson-link,
14+
p.lesson-link {
15+
display: flex;
16+
justify-content: space-between;
2417
padding: 1rem;
2518
width: 100%;
2619
}
2720

28-
.lesson-link .link:hover a{
29-
background-color: var(--greyblue);
30-
color: var(--white);
31-
border: none;
32-
}
33-
34-
.lesson-link .video-length {
35-
float: right;
21+
a.lesson-link {
22+
cursor: pointer;
23+
color: var(--black);
24+
text-decoration: none;
3625
}
3726

38-
.lesson-link .active-video {
39-
display: flex;
40-
justify-content: space-between;
41-
padding: 1rem;
27+
p.lesson-link {
28+
color: var(--white);
4229
background-color: var(--brown);
43-
font-family: var(--fontfamily-alt);
4430
}
4531

46-
47-
.lesson-link .active-video p{
48-
width: 100%;
49-
}
32+
a.lesson-link:hover {
33+
background-color: var(--greyblue);
34+
color: var(--white);
35+
border: none;
36+
}

0 commit comments

Comments
 (0)