135 lines
3.3 KiB
JavaScript
135 lines
3.3 KiB
JavaScript
import React, { useEffect, useState } from "react";
|
|
import { connect } from "react-redux";
|
|
import { loadCourses, saveCourse } from "../../redux/actions/courseActions";
|
|
import { loadAuthors } from "../../redux/actions/authorActions";
|
|
import PropTypes from "prop-types";
|
|
import { bindActionCreators } from "redux";
|
|
import CourseForm from "./CourseForm";
|
|
import { newCourse } from "../../../tools/mockData";
|
|
import Spinner from "../common/Spinner";
|
|
import { toast } from "react-toastify";
|
|
|
|
export function ManageCoursePage({
|
|
courses,
|
|
authors,
|
|
actions,
|
|
history,
|
|
...props
|
|
}) {
|
|
const [course, setCourse] = useState({ ...props.course });
|
|
const [errors, setErrors] = useState({});
|
|
const [saving, setSaving] = useState(false);
|
|
|
|
useEffect(() => {
|
|
if (courses.length === 0) {
|
|
actions.loadCourses().catch((error) => {
|
|
alert("Loading courses failed. " + error);
|
|
});
|
|
} else {
|
|
setCourse({ ...props.course });
|
|
}
|
|
|
|
if (authors.length === 0) {
|
|
actions.loadAuthors().catch((error) => {
|
|
alert("Loading authors failed. " + error);
|
|
});
|
|
}
|
|
}, [props.course]);
|
|
|
|
function handleChange(event) {
|
|
const { name, value } = event.target;
|
|
setCourse((prevCourse) => ({
|
|
...prevCourse,
|
|
[name]: name === "authorId" ? parseInt(value, 10) : value
|
|
}));
|
|
}
|
|
|
|
function formIsValid() {
|
|
const { title, authorId, category } = course;
|
|
const errors = {};
|
|
|
|
if (!title) errors.title = "Title is required.";
|
|
if (!authorId) errors.author = "Author is required";
|
|
if (!category) errors.category = "Category is required";
|
|
|
|
setErrors(errors);
|
|
// Form is valid if the errors object still has no properties
|
|
return Object.keys(errors).length === 0;
|
|
}
|
|
|
|
const checkSlug = () => {
|
|
if (course.slug) return;
|
|
course.slug = course.title.replace(/\s+/g, "-").toLowerCase();
|
|
};
|
|
|
|
function handleSave(event) {
|
|
event.preventDefault();
|
|
if (!formIsValid()) return;
|
|
checkSlug();
|
|
setSaving(true);
|
|
actions
|
|
.saveCourse(course)
|
|
.then(() => {
|
|
toast.success("Course saved.");
|
|
history.push("/courses");
|
|
})
|
|
.catch((error) => {
|
|
setSaving(false);
|
|
setErrors({ onSave: error.message });
|
|
});
|
|
}
|
|
|
|
return authors.length === 0 || course.length === 0 ? (
|
|
<Spinner />
|
|
) : (
|
|
<CourseForm
|
|
course={course}
|
|
errors={errors}
|
|
authors={authors}
|
|
onChange={handleChange}
|
|
onSave={handleSave}
|
|
saving={saving}
|
|
/>
|
|
);
|
|
}
|
|
|
|
ManageCoursePage.propTypes = {
|
|
course: PropTypes.object.isRequired,
|
|
courses: PropTypes.array.isRequired,
|
|
authors: PropTypes.array.isRequired,
|
|
actions: PropTypes.object.isRequired,
|
|
history: PropTypes.object.isRequired
|
|
};
|
|
|
|
function mapStateToProps(state, ownProps) {
|
|
const slug = ownProps.match.params.slug;
|
|
const course =
|
|
slug && state.courses.length > 0
|
|
? getCourseBySlug(state.courses, slug)
|
|
: newCourse;
|
|
return {
|
|
course,
|
|
courses: state.courses,
|
|
authors: state.authors
|
|
};
|
|
}
|
|
|
|
function getCourseBySlug(courses, slug) {
|
|
return courses.find((course) => course.slug === slug) || null;
|
|
}
|
|
|
|
function mapDispatchToProps(dispatch) {
|
|
return {
|
|
actions: bindActionCreators(
|
|
{
|
|
loadCourses,
|
|
loadAuthors,
|
|
saveCourse
|
|
},
|
|
dispatch
|
|
)
|
|
};
|
|
}
|
|
|
|
export default connect(mapStateToProps, mapDispatchToProps)(ManageCoursePage);
|