Skip to content

Commit

Permalink
Add Admin Management Features
Browse files Browse the repository at this point in the history
  • Loading branch information
Harin329 committed Jul 19, 2023
1 parent c89ddee commit 3e14931
Show file tree
Hide file tree
Showing 9 changed files with 145 additions and 14 deletions.
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"C_Cpp.intelliSenseEngineFallback": "enabled"
}
12 changes: 12 additions & 0 deletions backend/src/routes/userRoute.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,18 @@ router.post("/resetpassword", (req, res) => {
}
});

router.post("/adminReset", authorize(true), (req, res) => {
// Reset Password
userController
.updateUserPassword(req, req.body.email)
.then((response) => {
res.status(200).json(response);
})
.catch((err) => {
res.status(404).json(err);
});
});

router.delete("/:userId", authorize(), (req, res) => {
userController
.deleteUser(req.params.userId)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#invoice-template {
color: #000;
margin: 10px auto;
border: 1px solid #ddd;
padding: 10px;
}
#invoice-header {
font-size: 12px;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ const InvoiceTemplate = ({ customer, costcenterMap, invoicNum }) => {
/>
</div>

<div className="signer">
{/* <div className="signer">
<div className="signer-form signer-item">
<label htmlFor="date">Date:</label>
<input
Expand All @@ -127,7 +127,7 @@ const InvoiceTemplate = ({ customer, costcenterMap, invoicNum }) => {
onChange={handleChange}
/>
</div>
</div>
</div> */}
</div>
</div>
</div>
Expand Down Expand Up @@ -175,10 +175,6 @@ function InvoiceDetails({ billingData }) {
<td>Total Due: </td>
<td>${subtotal}</td>
</tr>
<tr className="item total">
<td>Amount Paid:</td>
<td>$0</td>
</tr>
</tbody>
</table>
</div>
Expand Down
24 changes: 20 additions & 4 deletions frontend/src/components/UserManagementTable/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,27 @@
border: none;
}

.userTable .ant-table-footer {
border-bottom-left-radius: 10px;
border-bottom-right-radius: 10px;
background-color: #ECEDF3;
}

.addService {
display: flex;
align-items: center;
gap: 12px;
}

.resetPasswordButton{
text-align: center;
cursor: pointer;
}

.SaveNewPassword{
cursor: pointer;
margin-top: 10px;;
}
.ServiceQuestionSelect {
border: 0;
background-color: #eeeeee;
Expand Down Expand Up @@ -86,10 +102,10 @@ So try and beat it with CSS specificity */
border: 1px solid #d9d9d9;
}
.ant-table-container,
.ant-table-container table > tbody > tr:last-child td:first-child {
border-bottom-left-radius: 10px;
.userTable .ant-table-container table > tbody > tr:last-child td:first-child {
border-bottom-left-radius: 0px;
}
.ant-table-container,
.ant-table-container table > tbody > tr:last-child td:last-child {
border-bottom-right-radius: 10px;
.userTable .ant-table-container table > tbody > tr:last-child td:last-child {
border-bottom-right-radius: 0px;
}
68 changes: 66 additions & 2 deletions frontend/src/components/UserManagementTable/index.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import React, { useState, useRef, useContext, useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Table, Form, Popconfirm, Input, Select } from "antd";
import { Table, Form, Popconfirm, Input, Select, Popover } from "antd";
import "antd/dist/antd.min.css";
import "./index.css";
import { DELETE_USER, GET_ORGANIZATION, LOAD_USERLIST, UPDATE_USER } from "../../redux/actions/userActions";
import Add from "../../assets/AddBlack.png";
import { ADMIN_RESET_PASSWORD, DELETE_USER, GET_ORGANIZATION, LOAD_USERLIST, POST_USER, UPDATE_USER } from "../../redux/actions/userActions";
import RejectUser from "../../assets/RejectUser.png";
import uuid from "react-uuid";

const UserManagementTable = () => {
const columns = [
Expand Down Expand Up @@ -87,6 +89,43 @@ const UserManagementTable = () => {
/>
) : null,
},
{
title: "",
dataIndex: "operation",
render: (_, record) =>
dataSource.length >= 1 ? (
<Popover
content={
<div>
<input className="LoginInput" placeholder="New Password" type={"password"} />
<div className="SaveNewPassword" onClick={() => {
const password = document.getElementsByClassName("LoginInput")[0].value;
if (password && password !== "") {
dispatch({
type: ADMIN_RESET_PASSWORD,
payload: {
email: record.email,
password: password,
},
});
document.getElementsByClassName("LoginInput")[0].value = "";
setResetPasswordRecord(null);
}
}}>Save</div>
</div>
}
title="Change User's Password"
trigger="click"
open={resetPasswordRecord === record.user_id}
onOpenChange={(open) => {
setResetPasswordRecord(open ? record.user_id : null);
}}
>
<div className="resetPasswordButton">Reset Password</div>
</Popover>
) : null,
width: "5%",
},
{
title: "",
dataIndex: "operation",
Expand All @@ -111,6 +150,7 @@ const UserManagementTable = () => {
];

const dispatch = useDispatch();
const [resetPasswordRecord, setResetPasswordRecord] = useState();
const dataSource = useSelector((state) => state.userReducer.userList);
const orgList = useSelector((state) => state.userReducer.organizationList);

Expand All @@ -125,6 +165,22 @@ const UserManagementTable = () => {
const handleSave = (row) => {
dispatch({ type: UPDATE_USER, payload: row });
};
const handleAdd = () => {
const newID = uuid();
const newData = {
user_id: newID,
fk_organization_id: null,
username: "New User",
email: "New User Email",
employee: false,
password: "password",
adminCreated: true,
};
dispatch({
type: POST_USER,
payload: newData
});
};

const EditableContext = React.createContext(null);

Expand Down Expand Up @@ -234,6 +290,14 @@ const UserManagementTable = () => {
rowClassName={(_, index) => index % 2 === 0 ? "editable-row" : "editable-row-dark"}
dataSource={dataSource}
columns={renderedColumns}
footer={() => {
return (
<div className="footerAddButton" onClick={handleAdd}>
<img className="Add" src={Add} alt="Add" />
<div className="ticketSectionTitle">Add</div>
</div>
)
}}
/>
);
};
Expand Down
1 change: 1 addition & 0 deletions frontend/src/redux/actions/userActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export const POST_USER = "POST_USER";
export const UPDATE_USER = "UPDATE_USER";
export const REQUEST_RESET = "REQUEST_RESET";
export const RESET_PASSWORD = "RESET_PASSWORD";
export const ADMIN_RESET_PASSWORD = "ADMIN_RESET_PASSWORD";
export const SIGNUP_USER = "SIGNUP_USER";
export const AUTHENTICATE_USER = "AUTHENTICATE_USER";
export const SET_CURRENT_USER = "SET_CURRENT_USER";
Expand Down
21 changes: 21 additions & 0 deletions frontend/src/redux/api/userApi.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,27 @@ export const resetPasswordApi = async (payload) => {
}
};

export const adminResetPasswordApi = async (payload) => {
try {
const token = JSON.parse(localStorage.getItem("currentUser")).token;
var headers = {
Authorization: `Bearer ${token}`,
};
var data = JSON.stringify({
email: payload.email,
password: payload.password,
});

const user = await axios.post("user/adminReset", data, {
headers: headers,
});

return user;
} catch (err) {
return console.error(err);
}
};

export const updateUserApi = async (payload) => {
try {
const token = JSON.parse(localStorage.getItem("currentUser")).token;
Expand Down
20 changes: 19 additions & 1 deletion frontend/src/redux/saga/userSaga.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
UPDATE_USER,
REQUEST_RESET,
RESET_PASSWORD,
ADMIN_RESET_PASSWORD,
} from "../actions/userActions";
import { getProjectAssignmentApi } from "../api/projectApi";
import {
Expand All @@ -41,6 +42,7 @@ import {
updateUserApi,
requestResetApi,
resetPasswordApi,
adminResetPasswordApi,
} from "../api/userApi";
import { ErrorToast, SuccessToast } from "../../components/Toasts";

Expand Down Expand Up @@ -110,9 +112,24 @@ export function* resetPasswordSaga({ payload }) {
}
}

export function* adminResetPasswordSaga({ payload }) {
const resetRes = yield call(adminResetPasswordApi, payload);
if (resetRes) {
SuccessToast("Password reset successfully!");
} else {
ErrorToast("Password reset failed. Please try again.");
}
}

export function* postUserSaga({ payload }) {
const newUser = yield call(saveUserApi, payload);
if (newUser) {
if (payload.adminCreated) {
SuccessToast("Account created successfully!");
yield call(approveUserList, { users: [payload.user_id]});
yield delay(1000);
yield loadUserlistSaga();
yield loadPendingUserListSaga();
} else if (newUser) {
SuccessToast("Account created successfully! Please login to continue.");
payload.navTo();
} else {
Expand Down Expand Up @@ -182,4 +199,5 @@ export default function* userSaga() {
yield takeLatest(GET_USER, getUserSaga);
yield takeLatest(REQUEST_RESET, requestResetSaga);
yield takeLatest(RESET_PASSWORD, resetPasswordSaga);
yield takeLatest(ADMIN_RESET_PASSWORD, adminResetPasswordSaga);
}

0 comments on commit 3e14931

Please sign in to comment.