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

Week 7 solution #73

Open
wants to merge 41 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
94432d2
Baisc setup
Vikash-thak12 Sep 26, 2024
987be57
Fixed: User Singup Functionality
Vikash-thak12 Sep 26, 2024
fc83ea0
Fixed: User Login Functionality
Vikash-thak12 Sep 26, 2024
0ee9b2c
Created: Course Schema
Vikash-thak12 Sep 27, 2024
ebd9b10
SetUp: Admin signup and login Functionality
Vikash-thak12 Sep 27, 2024
f790564
Implemented: Authorization Functionality
Vikash-thak12 Sep 27, 2024
d0aed44
Implemented: Course creation for Admin
Vikash-thak12 Sep 27, 2024
1a3a49a
Added: Timestamps for specific dates
Vikash-thak12 Sep 27, 2024
ca2d7bd
Fixed: admin posting using middleware
Vikash-thak12 Sep 27, 2024
9a0b30f
Implemented: Updating course functionality
Vikash-thak12 Sep 27, 2024
19e5a99
Implemented: get all courses functionality
Vikash-thak12 Sep 27, 2024
ddbc895
Implemented: User purchasing courses
Vikash-thak12 Sep 27, 2024
11b39c7
Updated: Necessary codes
Vikash-thak12 Sep 27, 2024
b96f6f4
Done: Backend code
Vikash-thak12 Sep 28, 2024
8859cf5
Setup: Basic Frontend
Vikash-thak12 Sep 28, 2024
1b58c63
Fixed: Register Page
Vikash-thak12 Sep 28, 2024
31a3b3a
Implemented: Cors for client-server commnuication
Vikash-thak12 Sep 28, 2024
df61fb3
Fixed: Login-Course functioality
Vikash-thak12 Sep 28, 2024
eedc459
SetUp: Routing using reacr-router-dom
Vikash-thak12 Sep 28, 2024
345965f
Fixed: Admin dashboard
Vikash-thak12 Sep 28, 2024
a3aca69
Added: Get method for a specific course
Vikash-thak12 Sep 28, 2024
0400392
Fixed: Updating and Creating of course for Admin:
Vikash-thak12 Sep 28, 2024
052acda
Updated login page
Vikash-thak12 Sep 28, 2024
74d43bb
Implemented: User's login, signup and Dashboard Functionality
Vikash-thak12 Sep 28, 2024
a024323
Purchased Course funcitonality added
Vikash-thak12 Sep 28, 2024
84c0949
Fixed: Purchased course functionality and other necessary code
Vikash-thak12 Sep 28, 2024
7c70df1
Fixed: Users getting purchased Courses functionality
Vikash-thak12 Sep 28, 2024
0a39212
Fixed Bug: Gave userToken instead of Admin Token
Vikash-thak12 Sep 28, 2024
c74d3e4
SetUp: Tailwind Css
Vikash-thak12 Sep 29, 2024
c7a26f5
Fixed: Home page UI
Vikash-thak12 Sep 29, 2024
eff2ad8
Fixed: Admin UI
Vikash-thak12 Sep 29, 2024
2eca12d
Updated: UI
Vikash-thak12 Sep 29, 2024
aabf74a
Updated: Necessary UI
Vikash-thak12 Sep 29, 2024
c76655d
Implemented: User UI
Vikash-thak12 Sep 29, 2024
3fd7f73
Fixed: User's UI
Vikash-thak12 Sep 29, 2024
abd7bdd
Implementing Toaster
Vikash-thak12 Sep 29, 2024
e48eb02
Fixed: Login bugs
Vikash-thak12 Sep 29, 2024
8f382a1
Fixed: User's Authentication
Vikash-thak12 Sep 29, 2024
c898457
Fixed: Bugs related to purchasing courses
Vikash-thak12 Sep 29, 2024
1eacbba
Fixed: Courses Functionality
Vikash-thak12 Sep 29, 2024
decaccc
Fixed: updating functionality
Vikash-thak12 Sep 29, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,224 changes: 1,222 additions & 2 deletions week-7/client/package-lock.json

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion week-7/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,23 @@
"dependencies": {
"axios": "^1.7.7",
"react": "^18.3.1",
"react-dom": "^18.3.1"
"react-dom": "^18.3.1",
"react-hot-toast": "^2.4.1",
"react-router-dom": "^6.26.2"
},
"devDependencies": {
"@eslint/js": "^9.9.0",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@vitejs/plugin-react": "^4.3.1",
"autoprefixer": "^10.4.20",
"eslint": "^9.9.0",
"eslint-plugin-react": "^7.35.0",
"eslint-plugin-react-hooks": "^5.1.0-rc.0",
"eslint-plugin-react-refresh": "^0.4.9",
"globals": "^15.9.0",
"postcss": "^8.4.47",
"tailwindcss": "^3.4.13",
"vite": "^5.4.1"
}
}
6 changes: 6 additions & 0 deletions week-7/client/postcss.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
Binary file added week-7/client/public/admin1.webp
Binary file not shown.
Binary file added week-7/client/public/user1.avif
Binary file not shown.
31 changes: 29 additions & 2 deletions week-7/client/src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,38 @@
// firstly, Don't get overwhelmed and if you are then go with client-easy.
import { BrowserRouter, Route, Routes} from "react-router-dom"
import Home from "./pages/Home"
import Register from "./components/Register"
import Login from "./components/Login"
import Dashboard from "./components/Dashboard"
import UpdateCourse from "./components/UpdateCourse"

import UserLogin from "./components/UserLogin"
import UserRegister from "./components/UserRegister"
import UserDashBoard from "./components/UserDashboard"
import PurchasedCourses from "./components/PurchasedCourses"

import { Toaster } from 'react-hot-toast';

function App() {

return (
<>
{/* start writing from here */}
<Home/>
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/admin/signup" element={<Register />} />
<Route path="/admin/login" element={<Login />} />
<Route path="/admindashboard" element={<Dashboard />} />
<Route path="/updatecourse/:id" element={<UpdateCourse />} />

<Route path="/user/signup" element={<UserRegister />} />
<Route path="/user/login" element={<UserLogin />} />
<Route path="/userdashboard" element={<UserDashBoard />} />
<Route path="/purchasedcourses" element={<PurchasedCourses />} />

</Routes>
</BrowserRouter>
<Toaster />
</>
)
}
Expand Down
58 changes: 55 additions & 3 deletions week-7/client/src/components/Courses.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,62 @@
// courses code here
import React from 'react'
import axios from "axios";
import { useEffect, useState } from "react"
import { useNavigate } from "react-router-dom";

// use axios here, similar to register and login
const Courses = () => {
const [courses, setCourses] = useState([])
const navigate = useNavigate();

useEffect(() => {
const fetchCourses = async () => {
const response = await axios.get('http://localhost:3000/admin/courses', {
headers: {
Authorization: `Bearer ${localStorage.getItem('adminToken')}`
}
});
setCourses(response.data.courses);
// console.log(courses);
};

fetchCourses();
}, []);
const handleRoute = (id) => {
navigate(`/updatecourse/${id}`)
}
return (
<div>Courses</div>
<div className="px-10 lg:px-52 py-5">
<h1 className="text-3xl font-bold mb-6">All Courses</h1>
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-3 gap-6">
{
courses.map((item, index) => (
<div
key={index}
className="card p-5 rounded-2xl hover:shadow-slate-900 hover:shadow-md transition-all shadow-md cursor-pointer"

>
<figure>
<img
src={item.imageLink}
alt={item.title}
className="h-48 w-full object-cover rounded-2xl"
/>
</figure>
<div className="flex flex-col gap-2">
<h2 className="font-bold mt-2 text-2xl">{item.title}</h2>
<p className="text-gray-500 h-12 line-clamp-2">{item.description}</p>
<p className="font-semibold">Rs. {item.price}</p>
<p className="font-semibold">{item.published ? 'Published' : 'Not Published'}</p>
<div>
<button
onClick={() => handleRoute(item._id)}
className="bg-blue-600 hover:scale-105 transition w-full px-5 py-3 rounded-2xl"><span className="font-bold text-white">Update</span></button>
</div>
</div>
</div>
))
}
</div>
</div>
)
}

Expand Down
76 changes: 76 additions & 0 deletions week-7/client/src/components/Dashboard.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import axios from "axios";
import { useState } from "react";
import Courses from "./Courses"
import toast from "react-hot-toast";
const Dashboard = () => {
const [title, setTitle] = useState("")
const [description, setDescription] = useState("")
const [price, setPrice] = useState("")
const [imageLink, setImageLink] = useState("")
const [published, setPublished] = useState(false)

const handleSubmit = async (e) => {
e.preventDefault();
try {
const response = await axios.post("http://localhost:3000/admin/courses", {
title,
description,
price,
imageLink,
published
}, {
headers: {
Authorization: `Bearer ${localStorage.getItem("adminToken")}`
}
})
console.log(response.data);
toast.success(response.data.message)
setTimeout(() => {
window.location.reload();
}, 2000);
} catch (error) {
console.log("Error in creating Post..", error)
if (error.response && error.response.status === 400) {
toast.error(error.response.data.message || "An error occurred");
} else {
toast.error("An unexpected error occurred");
}
}
}


return (
<main>
<div className="border border-black rounded-3xl flex flex-col max-w-96 md:mx-auto mt-10 px-10 mx-10 text-center">
<h2 className="font-bold text-2xl py-5">Create New Course</h2>
<form onSubmit={handleSubmit} className="flex flex-col gap-2 mb-10">
<input
className="border-2 outline-none font-semibold border-black px-5 py-2 rounded-xl"
type="text" placeholder="Enter Title" value={title} onChange={(e) => setTitle(e.target.value)} required />
<input
className="border-2 outline-none font-semibold border-black px-5 py-2 rounded-xl"
type="text" placeholder="Enter description" value={description} onChange={(e) => setDescription(e.target.value)} required />
<input
className="border-2 outline-none font-semibold border-black px-5 py-2 rounded-xl"
type="number" placeholder="Enter Price" value={price} onChange={(e) => setPrice(e.target.value)} required />
<input
className="border-2 outline-none font-semibold border-black px-5 py-2 rounded-xl"
type="text" placeholder="Enter Image Link" value={imageLink} onChange={(e) => setImageLink(e.target.value)} required />
<label className="flex items-center gap-4">
<span className="text-lg font-semibold">Published:</span>
<input
type="checkbox"
className="h-4 w-4 cursor-pointer"
checked={published}
onChange={(e) => setPublished(e.target.checked)}
/>
</label>
<button className="bg-blue-600 hover:scale-105 transition w-full px-5 py-3 rounded-2xl text-white font-bold" type="submit">Submit</button>
</form>
</div>
<Courses />
</main>
);
};

export default Dashboard;
48 changes: 44 additions & 4 deletions week-7/client/src/components/Login.jsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,54 @@
// login code here
import axios from 'axios';
import React from 'react'
import { useState } from 'react';
import toast from 'react-hot-toast';
import { Link, useNavigate } from 'react-router-dom';

const Login = () => {

const navigate = useNavigate()

const [username, setUsername] = useState("")
const [password, setPassword] = useState("")

// call the functions onClick of button.
async function handleLogin() {
const resposne = await axios.post(); // // if you don't know about axios, give it a read https://axios-http.com/docs/intro
const handleLogin = async () => {

if(!username || !password) {
toast.error("Please fill all the details..")
return;
}
try {
const response = await axios.post("http://localhost:3000/admin/login", { username, password });
localStorage.setItem("adminToken", response.data.token)
toast.success(response.data.message)
navigate("/admindashboard")
} catch (error) {
console.log("While logging", error);
if (error.response && error.response.status === 404) {
toast.error(error.response.data.message || "An error occurred");
} else {
toast.error(error.response.data.message);
}
}
}
return (
<div>Login</div>
<main className='bg-[#030711] h-screen flex items-center justify-center'>
<div className='flex flex-col items-center justify-center border border-white bg-gray-600 px-10 py-10 rounded-3xl gap-8 mx-auto'>
<h1 className='text-3xl font-bold mb-6'><span className='text-white'>Login To Coursifiy</span></h1>
<input
className='px-5 py-3 rounded-2xl outline-none font-semibold w-full'
type="text" placeholder='Enter Username' value={username} onChange={(e) => setUsername(e.target.value)} required />
<input
className='px-5 py-3 rounded-2xl outline-none font-semibold w-full'
type="password" placeholder='Enter Password' value={password} onChange={(e) => setPassword(e.target.value)} required />
<button
className='bg-blue-700 px-5 py-3 rounded-2xl outline-none font-semibold text-white w-full'
onClick={handleLogin}>Submit</button>
<p className='text-white font-semibold'>Didn&apos;t have an Account ? <Link className='text-blue-600 underline' to={"/admin/signup"}>SignUp</Link></p>
</div>
</main>

)
}

Expand Down
55 changes: 55 additions & 0 deletions week-7/client/src/components/PurchasedCourses.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import axios from "axios";
import { useEffect, useState } from "react"
import { Link } from "react-router-dom";

const PurchasedCourses = () => {
const [courses, setCourses] = useState([])

useEffect(() => {
const fetchCourses = async () => {
const response = await axios.get('http://localhost:3000/users/purchasedCourses', {
headers: {
Authorization: `Bearer ${localStorage.getItem('userToken')}`
}
});
setCourses(response.data.purchasedCourses)
};

fetchCourses();
}, []);

return (
<div className="px-10 lg:px-52 py-5">
<div className="flex items-center justify-between">
<h1 className="text-3xl font-bold mb-6">Your Purchased Courses</h1>
<Link to={"/userdashboard"}>
<button className="bg-blue-600 hover:scale-105 transition px-5 py-3 rounded-2xl text-white font-bold">Back to Dashboard</button>
</Link>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-3 gap-6">
{
courses.map((item, index) => (
<div key={index} className="card p-5 rounded-2xl hover:shadow-slate-900 hover:shadow-md transition-all shadow-md cursor-pointer">
<figure>
<img
src={item.imageLink}
alt={item.title}
className="h-48 w-full object-cover rounded-2xl"
/>
</figure>
<div className="flex flex-col gap-2">
<h2 className="font-bold mt-2 text-2xl">{item.title}</h2>
<p className="text-gray-500 h-12 line-clamp-2">{item.description}</p>
<p className="font-semibold">Rs. {item.price}</p>
<p className="font-semibold">{item.published ? 'Published' : 'Not Published'}</p>
</div>
</div>
))
}
</div>
</div>
)
}

export default PurchasedCourses

44 changes: 41 additions & 3 deletions week-7/client/src/components/Register.jsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,53 @@
// register code here
import React from 'react'
import { useState } from 'react'
import axios from "axios"
import { Link, useNavigate } from 'react-router-dom'
import toast from 'react-hot-toast'


const Register = () => {

const [username, setUsername] = useState("")
const [password, setPassword] = useState("")

const navigate = useNavigate();

// call the functions onClick of button.
async function handleRegister() {
const resposne = await axios.post(); // if you don't know about axios, give it a read https://axios-http.com/docs/intro
if(!username || !password) {
toast.error("Please fill all the details..")
return;
}

try {
const response = await axios.post("http://localhost:3000/admin/signup", { username, password});
localStorage.setItem("adminToken", response.data.token)
toast.success(response.data.message)
navigate("/admindashboard")
} catch (error) {
if (error.response && error.response.status === 400) {
toast.error(error.response.data.message || "An error occurred");
} else {
toast.error("An unexpected error occurred");
}
}
}
return (
<div>Register</div>
<main className='bg-[#030711] h-screen flex items-center justify-center'>
<div className='max-w-4xl flex flex-col items-center justify-center border border-white bg-gray-600 px-10 py-10 rounded-3xl gap-8 mx-auto'>
<h1 className='text-3xl font-bold mb-6 text-center'><span className='text-white'>Register To <br /> Coursifiy</span></h1>
<input
className='px-5 py-3 rounded-2xl outline-none font-semibold w-full'
type="text" placeholder='Enter Username' value={username} onChange={(e) => setUsername(e.target.value)} required />
<input
className='px-5 py-3 rounded-2xl outline-none font-semibold w-full'
type="password" placeholder='Enter Password' value={password} onChange={(e) => setPassword(e.target.value)} required />
<button
className='bg-blue-700 px-5 py-3 rounded-2xl outline-none font-semibold text-white w-full'
onClick={handleRegister}>Submit</button>
<p className='text-white font-semibold'>Already have an Account. <Link className='underline text-blue-600' to={"/admin/login"}>Login</Link></p>
</div>
</main>
)
}

Expand Down
Loading