Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Creating the form for adding a new course 🚀 #5

Merged
merged 11 commits into from
Oct 11, 2023
16 changes: 13 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file removed public/course/database.png
Binary file not shown.
Binary file removed public/course/web.png
Binary file not shown.
4 changes: 3 additions & 1 deletion src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ import {
Route,
Navigate,
} from 'react-router-dom';
import MainPage from './components/MainPage';
import MainPage from './components/main_page/MainPage';
import LandingPage from './components/landing_page';
import Login from './components/auth/login';
import Signup from './components/auth/signup';
import CourseList from './components/CourseList';
import CourseDetail from './components/CourseDetail';
import CourseForm from './components/course/courseForm';

function App() {
const status = sessionStorage.getItem('status') || sessionStorage.setItem('status', 'false');
Expand All @@ -24,6 +25,7 @@ function App() {
{status === 'true' ? (
<>
<Route exact path="/" element={<MainPage />} />
<Route path="/course-form" element={<CourseForm />} />
<Route path="/courses/:id" element={<CourseDetail />} />
<Route path="/courses" element={<CourseList />} />
<Route path="*" element={<Navigate to="/" replace />} />
Expand Down
48 changes: 48 additions & 0 deletions src/app/features/courses/courseFormSlice.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// courseSlice.js
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';

const initialState = {
status: 'idle',
error: null,
};

export const createCourse = createAsyncThunk('courseForm/create', async (courseData) => {
const formData = new FormData();
formData.append('course[name]', courseData.name);
formData.append('course[description]', courseData.description);
formData.append('course[fee]', courseData.fee);
formData.append('course[startDate]', courseData.startDate);
formData.append('course[image]', courseData.image);

const response = await fetch('http://localhost:3000/api/courses', {
method: 'POST',
body: formData,
});

if (!response.ok) {
throw new Error('Error creating course');
}

return response.json();
});

const courseFormSlice = createSlice({
name: 'courseForm',
initialState,
reducers: {},
extraReducers: (builder) => {
builder
.addCase(createCourse.pending, (state) => {
state.status = 'loading';
})
.addCase(createCourse.fulfilled, (state) => {
state.status = 'succeeded';
})
.addCase(createCourse.rejected, (state, action) => {
state.status = 'failed';
state.error = action.error.message;
});
},
});

export default courseFormSlice.reducer;
4 changes: 3 additions & 1 deletion src/app/store.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { configureStore } from '@reduxjs/toolkit';
import userReducer from './features/users/userSlice';
import mainPageReducer from './features/mainPageSlice';
import mainPageReducer from './features/main_page/mainPageSlice';
import courseFormReducer from './features/courses/courseFormSlice';
import courseReducer from './features/courseSlice';

const store = configureStore({
reducer: {
user: userReducer,
mainPage: mainPageReducer,
courseForm: courseFormReducer,
course: courseReducer,
},
});
Expand Down
2 changes: 2 additions & 0 deletions src/components/CourseDetail.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ const CourseDetail = () => {
fetch(`http://127.0.0.1:3000/api/courses/${id}`)
.then((response) => response.json())
.then((data) => setCourse(data))
// eslint-disable-next-line
.catch((error) => console.error('Error fetching course:', error));
}, [id]);

const handleReserveClick = () => {
// eslint-disable-next-line
console.log(`Course ${course.name} reserved!`);
// Implement your reservation logic here
};
Expand Down
1 change: 1 addition & 0 deletions src/components/CourseList.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const CourseList = () => {
.then((data) => {
dispatch(setCourses(data));
})
// eslint-disable-next-line
.catch((error) => console.error('Error fetching courses:', error));
}, [dispatch]);

Expand Down
38 changes: 0 additions & 38 deletions src/components/MainPage.css

This file was deleted.

11 changes: 11 additions & 0 deletions src/components/course/CourseForm.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/* CourseForm.css */

* {
margin: 0;
padding: 0;
box-sizing: border-box;
}

.form-container {
min-height: 90vh;
}
132 changes: 132 additions & 0 deletions src/components/course/courseForm.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/* eslint-disable jsx-a11y/label-has-associated-control */

import React, { useState } from 'react';
import { useDispatch } from 'react-redux';
import { useNavigate } from 'react-router-dom';
import { createCourse } from '../../app/features/courses/courseFormSlice';
import './CourseForm.css';

const CourseForm = () => {
const dispatch = useDispatch();
const navigate = useNavigate();

const [courseData, setCourseData] = useState({
name: '',
fee: '',
startDate: '',
image: null,
description: '',
});

const handleInputChange = (e) => {
const { name, value } = e.target;

// Check if the value is a positive number before updating the state
if (name === 'fee' && !Number.isNaN(parseFloat(value)) && parseFloat(value) >= 0) {
setCourseData({ ...courseData, [name]: value });
} else if (name !== 'fee') {
setCourseData({ ...courseData, [name]: value });
}
};

const handleImageChange = (e) => {
const imageFile = e.target.files[0];
setCourseData({ ...courseData, image: imageFile });
};

const handleSubmit = (e) => {
e.preventDefault();

dispatch(createCourse(courseData))
.then(() => {
navigate('/');
})
.catch((error) => {
throw new Error('Error creating course:', error.message);
});
};

return (
<div className="container mt-4">
<div className="row justify-content-center">
<div className="col-md-8">
<div className="card form-container shadow">
<div className="card-header">
<h2 className="card-title text-center mb-1">Create a New Course</h2>
</div>
<div className="card-body">
<form onSubmit={handleSubmit}>
<div className="mb-1">
<label htmlFor="name" className="form-label">Name:</label>
<input
type="text"
className="form-control"
name="name"
id="name"
value={courseData.name}
onChange={handleInputChange}
required
/>
</div>
<div className="mb-1">
<label htmlFor="fee" className="form-label">Fee:</label>
<div className="input-group">
<span className="input-group-text">$</span>
<input
type="number"
className="form-control"
name="fee"
id="fee"
value={courseData.fee}
onChange={handleInputChange}
required
/>
</div>
</div>
<div className="mb-1">
<label htmlFor="startDate" className="form-label">Start Date:</label>
<input
type="date"
className="form-control"
name="startDate"
id="startDate"
value={courseData.startDate}
onChange={handleInputChange}
required
/>
</div>
<div className="mb-1">
<label htmlFor="image" className="form-label">Image:</label>
<input
type="file"
className="form-control"
name="image"
id="image"
accept="image/*"
onChange={handleImageChange}
/>
</div>
<div className="mb-1">
<label htmlFor="description" className="form-label">Description:</label>
<textarea
className="form-control"
name="description"
id="description"
value={courseData.description}
onChange={handleInputChange}
required
/>
</div>
<div className="text-center mb-4">
<button type="submit" className="btn btn-success">Create Course</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
);
};

export default CourseForm;
7 changes: 0 additions & 7 deletions src/components/home.js

This file was deleted.

File renamed without changes.
Loading