diff --git a/src/components/courses/CourseList.js b/src/components/courses/CourseList.js
index 40cfe04..7ae652b 100644
--- a/src/components/courses/CourseList.js
+++ b/src/components/courses/CourseList.js
@@ -2,7 +2,7 @@ import React from "react";
import PropTypes from "prop-types";
import { Link } from "react-router-dom";
-const CourseList = ({ courses }) => (
+const CourseList = ({ courses, onDeleteClick }) => (
@@ -10,6 +10,7 @@ const CourseList = ({ courses }) => (
Title |
Author |
Category |
+ |
@@ -29,6 +30,14 @@ const CourseList = ({ courses }) => (
{course.authorName} |
{course.category} |
+
+
+ |
);
})}
@@ -37,7 +46,8 @@ const CourseList = ({ courses }) => (
);
CourseList.propTypes = {
- courses: PropTypes.array.isRequired
+ courses: PropTypes.array.isRequired,
+ onDeleteClick: PropTypes.func.isRequired
};
export default CourseList;
diff --git a/src/components/courses/CoursesPage.js b/src/components/courses/CoursesPage.js
index 0b7cf5c..6e73725 100644
--- a/src/components/courses/CoursesPage.js
+++ b/src/components/courses/CoursesPage.js
@@ -7,6 +7,7 @@ import { bindActionCreators } from "redux";
import CourseList from "./CourseList";
import { Redirect } from "react-router-dom";
import Spinner from "../common/Spinner";
+import { toast } from "react-toastify";
class CoursesPage extends React.Component {
state = {
@@ -29,6 +30,15 @@ class CoursesPage extends React.Component {
}
}
+ handleDeleteCourse = async (course) => {
+ toast.success("Course deleted");
+ try {
+ await this.props.actions.deleteCourse(course);
+ } catch (error) {
+ toast.error("Delete failed. " + error.message, { autoClose: false });
+ }
+ };
+
render() {
return (
<>
@@ -46,7 +56,10 @@ class CoursesPage extends React.Component {
Add Course
-
+
>
)}
>
@@ -83,7 +96,8 @@ function mapDispatchToProps(dispatch) {
actions: bindActionCreators(
{
loadCourses: courseActions.loadCourses,
- loadAuthors: authorActions.loadAuthors
+ loadAuthors: authorActions.loadAuthors,
+ deleteCourse: courseActions.deleteCourse
},
dispatch
)
diff --git a/src/redux/actions/actionTypes.js b/src/redux/actions/actionTypes.js
index 4fe8b31..612614e 100644
--- a/src/redux/actions/actionTypes.js
+++ b/src/redux/actions/actionTypes.js
@@ -5,3 +5,10 @@ export const CREATE_COURSE_SUCCESS = "CREATE_COURSE_SUCCESS";
export const UPDATE_COURSE_SUCCESS = "UPDATE_COURSE_SUCCESS";
export const BEGIN_API_CALL = "BEGIN_API_CALL";
export const API_CALL_ERROR = "API_CALL_ERROR";
+
+// By convention, actions that end in "_SUCCESS" are assumed to have been the result of a completed
+// API call. But since we're doing an optimistic delete, we're hiding loading state.
+// So this action name deliberately omits the "_SUCCESS" suffix.
+// If it had one, our apiCallsInProgress counter would be decremented below zero
+// because we're not incrementing the number of apiCallInProgress when the delete request begins.
+export const DELETE_COURSE_OPTIMISTIC = "DELETE_COURSE_OPTIMISTIC";
diff --git a/src/redux/actions/courseActions.js b/src/redux/actions/courseActions.js
index be5f5a3..b59760c 100644
--- a/src/redux/actions/courseActions.js
+++ b/src/redux/actions/courseActions.js
@@ -14,6 +14,10 @@ export function updateCourseSuccess(course) {
return { type: types.UPDATE_COURSE_SUCCESS, course };
}
+export function deleteCourseOptimistic(course) {
+ return { type: types.DELETE_COURSE_OPTIMISTIC, course };
+}
+
export function loadCourses() {
return function (dispatch) {
dispatch(beginApiCall());
@@ -46,3 +50,12 @@ export function saveCourse(course) {
});
};
}
+
+export function deleteCourse(course) {
+ return function (dispatch) {
+ // Doing optimistic delete, so not dispatching begin/end api call
+ // actions, or apiCallError action since we're not showing the loading status for this.
+ dispatch(deleteCourseOptimistic(course));
+ return courseApi.deleteCourse(course.id);
+ };
+}
diff --git a/src/redux/reducers/courseReducer.js b/src/redux/reducers/courseReducer.js
index c1bf7f9..dcdbae5 100644
--- a/src/redux/reducers/courseReducer.js
+++ b/src/redux/reducers/courseReducer.js
@@ -14,6 +14,9 @@ export default function courseReducer(state = initialState.courses, action) {
course.id === action.course.id ? action.course : course
);
+ case types.DELETE_COURSE_OPTIMISTIC:
+ return state.filter((course) => course.id !== action.course.id);
+
default:
return state;
}