course list
parent
04d8e062d4
commit
49fbd7be66
|
@ -0,0 +1,43 @@
|
||||||
|
import React from "react";
|
||||||
|
import PropTypes from "prop-types";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
|
const CourseList = ({ courses }) => (
|
||||||
|
<table className="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th />
|
||||||
|
<th>Title</th>
|
||||||
|
<th>Author</th>
|
||||||
|
<th>Category</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{courses.map((course) => {
|
||||||
|
return (
|
||||||
|
<tr key={course.id}>
|
||||||
|
<td>
|
||||||
|
<a
|
||||||
|
className="btn btn-light"
|
||||||
|
href={"http://pluralsight.com/courses/" + course.slug}
|
||||||
|
>
|
||||||
|
Watch
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<Link to={"/course/" + course.slug}>{course.title}</Link>
|
||||||
|
</td>
|
||||||
|
<td>{course.authorName}</td>
|
||||||
|
<td>{course.category}</td>
|
||||||
|
</tr>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
);
|
||||||
|
|
||||||
|
CourseList.propTypes = {
|
||||||
|
courses: PropTypes.array.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CourseList;
|
|
@ -1,17 +1,33 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import * as courseActions from "../../redux/actions/courseActions";
|
import * as courseActions from "../../redux/actions/courseActions";
|
||||||
|
import * as authorActions from "../../redux/actions/authorActions";
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import { bindActionCreators } from "redux";
|
import { bindActionCreators } from "redux";
|
||||||
|
import CourseList from "./CourseList";
|
||||||
|
|
||||||
class CoursesPage extends React.Component {
|
class CoursesPage extends React.Component {
|
||||||
|
componentDidMount() {
|
||||||
|
const { courses, authors, actions } = this.props;
|
||||||
|
|
||||||
|
if (courses.length === 0) {
|
||||||
|
actions.loadCourses().catch((error) => {
|
||||||
|
alert("Loading courses failed. " + error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (authors.length === 0) {
|
||||||
|
actions.loadAuthors().catch((error) => {
|
||||||
|
alert("Loading authors failed. " + error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<h2>Courses</h2>
|
<h2>Courses</h2>
|
||||||
{this.props.courses.map((course) => (
|
<CourseList courses={this.props.courses} />
|
||||||
<div key={course.title}>{course.title}</div>
|
|
||||||
))}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -19,18 +35,35 @@ class CoursesPage extends React.Component {
|
||||||
|
|
||||||
CoursesPage.propTypes = {
|
CoursesPage.propTypes = {
|
||||||
courses: PropTypes.array.isRequired,
|
courses: PropTypes.array.isRequired,
|
||||||
|
authors: PropTypes.array.isRequired,
|
||||||
actions: PropTypes.object.isRequired
|
actions: PropTypes.object.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
function mapStateToProps(state) {
|
function mapStateToProps(state) {
|
||||||
return {
|
return {
|
||||||
courses: state.courses
|
courses:
|
||||||
|
state.authors.length === 0
|
||||||
|
? []
|
||||||
|
: state.courses.map((course) => {
|
||||||
|
const author = state.authors.find((a) => a.id === course.authorId);
|
||||||
|
return {
|
||||||
|
...course,
|
||||||
|
authorName: author.name
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
authors: state.authors
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapDispatchToProps(dispatch) {
|
function mapDispatchToProps(dispatch) {
|
||||||
return {
|
return {
|
||||||
actions: bindActionCreators(courseActions, dispatch)
|
actions: bindActionCreators(
|
||||||
|
{
|
||||||
|
loadCourses: courseActions.loadCourses,
|
||||||
|
loadAuthors: authorActions.loadAuthors
|
||||||
|
},
|
||||||
|
dispatch
|
||||||
|
)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
export const CREATE_COURSE = "CREATE_COURSE";
|
export const CREATE_COURSE = "CREATE_COURSE";
|
||||||
export const LOAD_COURSES_SUCCESS = "LOAD_COURSES_SUCCESS";
|
export const LOAD_COURSES_SUCCESS = "LOAD_COURSES_SUCCESS";
|
||||||
|
export const LOAD_AUTHORS_SUCCESS = "LOAD_AUTHORS_SUCCESS";
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
import * as types from "./actionTypes";
|
||||||
|
import * as authorApi from "../../api/authorApi";
|
||||||
|
|
||||||
|
function loadAuthorsSuccess(authors) {
|
||||||
|
return { type: types.LOAD_AUTHORS_SUCCESS, authors };
|
||||||
|
}
|
||||||
|
|
||||||
|
export function loadAuthors() {
|
||||||
|
return function (dispatch) {
|
||||||
|
return authorApi
|
||||||
|
.getAuthors()
|
||||||
|
.then((authors) => {
|
||||||
|
dispatch(loadAuthorsSuccess(authors));
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
throw error;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
import * as types from "../actions/actionTypes";
|
||||||
|
|
||||||
|
export default function authorReducer(state = [], action) {
|
||||||
|
switch (action.type) {
|
||||||
|
case types.LOAD_AUTHORS_SUCCESS:
|
||||||
|
return action.authors;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,9 @@ export default function courseReducer(state = [], action) {
|
||||||
case types.CREATE_COURSE:
|
case types.CREATE_COURSE:
|
||||||
return [...state, { ...action.course }];
|
return [...state, { ...action.course }];
|
||||||
|
|
||||||
|
case types.LOAD_COURSES_SUCCESS:
|
||||||
|
return action.courses;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
import { combineReducers } from "redux";
|
import { combineReducers } from "redux";
|
||||||
import courseReducer from "./courseReducer";
|
import courseReducer from "./courseReducer";
|
||||||
|
import authorReducer from "./authorReducer";
|
||||||
|
|
||||||
const rootReducer = combineReducers({
|
const rootReducer = combineReducers({
|
||||||
courses: courseReducer
|
courses: courseReducer,
|
||||||
|
authors: authorReducer
|
||||||
});
|
});
|
||||||
|
|
||||||
export default rootReducer;
|
export default rootReducer;
|
||||||
|
|
Loading…
Reference in New Issue