Skip to content

Commit

Permalink
Merge pull request #15 from FevenSeyfu/frontend-crud-components
Browse files Browse the repository at this point in the history
Frontend crud components
  • Loading branch information
FevenSeyfu authored Dec 22, 2023
2 parents e3d4d43 + 7a311eb commit 1123463
Show file tree
Hide file tree
Showing 42 changed files with 2,334 additions and 308 deletions.
51 changes: 28 additions & 23 deletions backend/models/projectModel.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,36 @@
import mongoose from "mongoose";

const projectSchema = new mongoose.Schema({
name: { type: String, required: true },
description: { type: String, required: true },
startDate: { type: Date, required: true },
projectOwner: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
required: true,
},
scrumMaster: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
required: true,
},
teamMembers: [
{
const projectSchema = new mongoose.Schema(
{
name: { type: String, required: true },
description: { type: String, required: true },
startDate: { type: Date, required: true },
projectOwner: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
required: true,
},
scrumMaster: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
required: true,
},
teamMembers: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "User",
},
],
tasks: [{ type: mongoose.Schema.Types.ObjectId, ref: "Task" }],
status: {
type: String,
enum: ["open", "onhold", "completed"],
default: "open",
},
],
tasks: [{ type: mongoose.Schema.Types.ObjectId, ref: "Task" }],
status: {
type: String,
enum: ["open", "onhold", "completed"],
default: "open",
},
});
{
timestamps: true,
}
);

export const Project = mongoose.model("Project", projectSchema);
29 changes: 17 additions & 12 deletions backend/models/taskModels.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
import mongoose from "mongoose";

const taskSchema = new mongoose.Schema({
name: { type: String, required: true },
description: { type: String, required: true },
deadline: { type: Date, required: true,index: true },
status: {
type: String,
enum: ["To Do", "In Progress", "Review", "Done"],
default: "To Do",
const taskSchema = new mongoose.Schema(
{
name: { type: String, required: true },
description: { type: String, required: true },
deadline: { type: Date, required: true, index: true },
status: {
type: String,
enum: ["To Do", "In Progress", "Review", "Done"],
default: "To Do",
},
assignee: { type: mongoose.Schema.Types.ObjectId, ref: "User" },
dependencies: [{ type: mongoose.Schema.Types.ObjectId, ref: "Task" }],
sprint: { type: mongoose.Schema.Types.ObjectId, ref: "Sprint" },
},
assignee: { type: mongoose.Schema.Types.ObjectId, ref: "User" },
dependencies: [{ type: mongoose.Schema.Types.ObjectId, ref: "Task" }],
sprint: { type: mongoose.Schema.Types.ObjectId, ref: "Sprint" },
});
{
timestamps: true,
}
);

export const Task = mongoose.model("Task", taskSchema);
2 changes: 1 addition & 1 deletion frontend/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ node_modules
dist
dist-ssr
*.local

.vite
# Editor directories and files
.vscode/*
!.vscode/extensions.json
Expand Down
10 changes: 10 additions & 0 deletions frontend/package-lock.json

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

2 changes: 2 additions & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
"react-router-dom": "^6.21.0",
"react-select": "^5.8.0",
"react-toastify": "^9.1.3",
"redux-persist": "^6.0.0",
"redux-thunk": "^3.1.0",
"typeface-roboto": "^1.1.13"
},
"devDependencies": {
Expand Down
17 changes: 16 additions & 1 deletion frontend/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ import AdminDashboard from "./components/Admin/AdminDashboard";
import ProductOwnerDashboard from "./components/ProductOwner/ProductOwnerDashboard";
import ScrumMasterDashboard from "./components/ScrumMaster/ScrumMasterDashboard";
import DevelopmentTeamDashboard from "./components/DevelopmentTeam/DevelopmentTeamDashboard";

// project
// import ProjectDetail from './components/ProductOwner/ProjectDetail'
import ProjectDetail from "./components/ScrumMaster/project/ProjectDetail"

const App = () => {
const { user, isLoading, isError, isSuccess, message } = useSelector(
(state) => state.auth
Expand Down Expand Up @@ -44,8 +49,18 @@ const App = () => {
)
}
/>
<Route path="/dashboard/project/:id"
element={user ? (
<>
{user.role === "Scrum Master" && <ProjectDetail />}
</>
) : (
<Navigate to="/dashboard" />
)
}
/>
</Routes>
<ToastContainer className='top-left' />
<ToastContainer/>
</>
);
};
Expand Down
45 changes: 31 additions & 14 deletions frontend/src/app/store.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,31 @@
import { configureStore } from '@reduxjs/toolkit'
import authReducer from '../features/Auth/authSlice'
import userReducer from '../features/users/userSlice'
import projectReducer from '../features/Projects/projectSlice'
import taskReducer from '../features/Tasks/taskSlice'

export const store = configureStore({
reducer:{
auth:authReducer,
users:userReducer,
project:projectReducer,
task:taskReducer
}
})
import { configureStore, combineReducers } from "@reduxjs/toolkit";

import authReducer from "../features/Auth/authSlice";
import userReducer from "../features/users/userSlice";
import projectReducer from "../features/Projects/projectSlice";
import taskReducer from "../features/Tasks/taskSlice";

import storage from "redux-persist/lib/storage";
import { persistReducer, persistStore } from "redux-persist";

const persistConfig = {
key: "root",
storage,
};

const rootReducer = combineReducers({
auth: authReducer,
users: userReducer,
project: projectReducer,
task: taskReducer,
});

const persistedReducer = persistReducer(persistConfig, rootReducer);

const store = configureStore({
reducer: persistedReducer,
});

const persistor = persistStore(store);

export { store, persistor };
9 changes: 5 additions & 4 deletions frontend/src/components/Admin/AdminDashboard.jsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import React from 'react'
import UpdateUserProfile from './UpdateUserProfile'
import UserList from './UserList'
import Layout from '../common/Layout'
import { ToastContainer } from 'react-toastify'

const AdminDashboard = () => {
return (
<Layout>
admin
<UpdateUserProfile />
<UserList />
<ToastContainer />
<div>
<UserList />
</div>
</Layout>
)
}
Expand Down
65 changes: 65 additions & 0 deletions frontend/src/components/Admin/DeleteUser.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import React, { useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { deleteUser, reset } from "../../features/users/userSlice";
import Modal from "react-modal";
import { toast } from "react-toastify";
import { FaSpinner } from "react-icons/fa";
import { MdClose } from "react-icons/md";

Modal.setAppElement("#root");

const DeleteUser = ({ userId, onClose }) => {
const dispatch = useDispatch();
const [isDeleting, setIsDeleting] = useState(false);
const { users,isLoading, isError, isSuccess, message } = useSelector(
(state) => state.users
);
let selectedUser
users.forEach((user) => {
user._id === userId && (selectedUser = user.username)

})
const handleDelete = () => {
setIsDeleting(true);
dispatch(deleteUser(userId));
};

const handleClose = () => {
setIsDeleting(false);
onClose();
};
return (
<Modal
isOpen={true}
contentLabel="Delete User Profile"
className="fixed top-0 left-0 w-full h-full flex justify-center items-center"
overlayClassName="fixed top-0 left-0 w-full h-full bg-black bg-opacity-50 flex justify-center items-center"
onRequestClose={onClose}
shouldCloseOnOverlayClick={true}
>
<div className="bg-white text-black p-8 mx-12 rounded">
<div className="flex justify-end">
<MdClose size={30} onClick={onClose} />
</div>
<h2 className="font-bold text-2xl text-center mb-4">Delete User</h2>
{isLoading && <FaSpinner />}
<p>Are you sure you want to delete <b>{selectedUser}'s</b> Profile?</p>
<div className="flex flex-row justify-evenly mt-4">
<button
className="bg-red text-white p-2 rounded-md"
onClick={handleDelete}
disabled={isDeleting}
>
{isDeleting ? "Deleting..." : "Delete"}
</button>
<button className="bg-gray text-white p-2 rounded-md" onClick={handleClose} disabled={isLoading}>
Cancel
</button>
</div>
{isError && <p>Error: {message}</p>}
</div>
</Modal>
);
};

export default DeleteUser;
Loading

0 comments on commit 1123463

Please sign in to comment.