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

Add dynamic loaders for admin panel #110

Merged
merged 4 commits into from
Sep 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 6 additions & 0 deletions src/actions/adminPanelActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
SWITCH_TAB,
SET_TABLE_DATA,
RESET_ADMIN_MENU,
TOGGLE_ADMIN_LOADER,
} from 'constants/action-types';

export const SwitchMainMenu = (data) => ({
Expand All @@ -29,3 +30,8 @@ export const SetTableData = (data) => ({
export const ResetAdminMenu = () => ({
type: RESET_ADMIN_MENU,
});

export const ToggleAdminLoader = (data) => ({
type: TOGGLE_ADMIN_LOADER,
payload: data,
});
2 changes: 2 additions & 0 deletions src/components/adminTable/adminMainContainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import * as constants from 'constants/adminPanelMenu';
import { SwitchTab } from 'actions/adminPanelActions';
import AdminCover from 'components/cover/adminCover';

const Tabs = [
constants.ALL_TAB,
Expand All @@ -18,6 +19,7 @@ const AdminMainContainer = (props) => {

return (
<div className="coursepage">
{store.loading && <AdminCover customText={store.loading} />}
{store.activeMainMenu === constants.USER_REQUEST_MENU && (
<>
<div className="coursepage--head">{store.subMenuData[store.activeSubMenu]?.title}</div>
Expand Down
48 changes: 42 additions & 6 deletions src/components/adminTable/courseRequestsTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,54 @@ import { addCourse, rejectCourseRequest, getCourseRequests } from 'api/courseReq
import { getCookie } from 'utils/handleCookies';
import EmptyTable from 'components/error/adminEmptyTable';
import _ from 'lodash';
import { SetTableData, SwitchMainMenu, SwitchSubMenu } from 'actions/adminPanelActions';
import {
SetTableData,
SwitchMainMenu,
SwitchSubMenu,
ToggleAdminLoader,
} from 'actions/adminPanelActions';
import { COURSE_REQUEST_MENU } from 'constants/adminPanelMenu';
import { toast } from 'react-toastify';
import ShortName from 'utils/short-name';

const CourseRequestsTable = () => {
const [approved, setApproved] = useState([]);
const [rejected, setRejected] = useState([]);
const [loading, setLoading] = useState({ approve: [], reject: [] });

const token = getCookie('token');
const dispatch = useDispatch();
const store = useSelector((state) => state.adminPanel);
const activeData = store.tableData[Object.keys(store.tableData)[store.activeSubMenu]];

const handleApprove = (id) => {
const handleApprove = async (id) => {
if (approved.includes(id) || rejected.includes(id)) return null;
addCourse(id, token).then(() => setApproved((prev) => [...prev, id]));
setLoading((prev) => ({ ...prev, approve: [...prev.approve, id] }));

try {
await addCourse(id, token);
setApproved((prev) => [...prev, id]);
toast.success('Request Approved Successfully');
} catch {
toast.error('Error in Approving Request');
} finally {
setLoading((prev) => ({ ...prev, approve: _.without(prev.approve, id) }));
}
};

const handleReject = (id) => {
const handleReject = async (id) => {
if (approved.includes(id) || rejected.includes(id)) return null;
rejectCourseRequest(id, token).then(() => setRejected((prev) => [...prev, id]));
setLoading((prev) => ({ ...prev, reject: [...prev.reject, id] }));

try {
await rejectCourseRequest(id, token);
setRejected((prev) => [...prev, id]);
toast.warn('Request Rejected Successfully');
} catch {
toast.error('Error in Rejecting Request');
} finally {
setLoading((prev) => ({ ...prev, reject: _.without(prev.reject, id) }));
}
};

const setRequestData = (res) => {
Expand All @@ -37,10 +64,17 @@ const CourseRequestsTable = () => {
);
dispatch(SetTableData(res.requests));
dispatch(SwitchSubMenu(0));
dispatch(ToggleAdminLoader(''));
};

useEffect(() => {
getCourseRequests(token).then(setRequestData);
dispatch(ToggleAdminLoader('Fetching Course Requests'));
getCourseRequests(token)
.then(setRequestData)
.catch(() => {
toast.error('Error in fetching requests');
dispatch(ToggleAdminLoader(''));
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

Expand Down Expand Up @@ -69,12 +103,14 @@ const CourseRequestsTable = () => {
<TableIconButton
type={approved.includes(item.id) ? 'approve_confirmed' : 'approve'}
handleClick={() => handleApprove(item.id)}
loading={loading.approve.includes(item.id)}
/>
</div>
<div className="row-item">
<TableIconButton
type={rejected.includes(item.id) ? 'reject_confirmed' : 'reject'}
handleClick={() => handleReject(item.id)}
loading={loading.reject.includes(item.id)}
/>
</div>
</div>
Expand Down
7 changes: 6 additions & 1 deletion src/components/adminTable/tableIconButtons.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import rejectConfirmed from 'assets/reject_confirmed.svg';
import approveConfirmed from 'assets/approve_confirmed.svg';
import downloadIcon from 'assets/downloadCloud.svg';
import previewIcon from 'assets/previewIcon.svg';
import small_loader from 'assets/small_loader.svg';

/**
* Component to handle all icon ctas in tables
Expand All @@ -23,7 +24,10 @@ const IconDetails = {
reload: { src: reloadIcon, class: 'admin-icon--primary' },
};

const TableIconButton = ({ type, handleClick }) => {
const TableIconButton = ({ type, handleClick, loading }) => {
if (loading)
return <img src={small_loader} alt="loader" className="customfileuploader--button-loader" />;

return (
<div onClick={handleClick} className={`admin-icon-btn ${IconDetails[type].class}`}>
<img src={IconDetails[type].src} alt={type} />
Expand All @@ -34,6 +38,7 @@ const TableIconButton = ({ type, handleClick }) => {
TableIconButton.propTypes = {
handleClick: PropTypes.func,
type: PropTypes.string,
loading: PropTypes.bool,
};

export default TableIconButton;
53 changes: 45 additions & 8 deletions src/components/adminTable/userRequestsTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,58 @@ import { getFileRequests, rejectFileRequest, uploadFile } from 'api/fileRequestA
import { getCookie } from 'utils/handleCookies';
import TableIconButton from 'components/adminTable/tableIconButtons';
import EmptyTable from 'components/error/adminEmptyTable';
import { SetTableData, SwitchMainMenu, SwitchSubMenu, SwitchTab } from 'actions/adminPanelActions';
import {
SetTableData,
SwitchMainMenu,
SwitchSubMenu,
SwitchTab,
ToggleAdminLoader,
} from 'actions/adminPanelActions';
import _ from 'lodash';
import { toast } from 'react-toastify';
import ShortName from 'utils/short-name';

const UserRequestsTable = () => {
const [rows, setRows] = useState([]);
const [uploaded, setUploaded] = useState([]);
const [rejected, setRejected] = useState([]);
const [loading, setLoading] = useState({ uploading: [], reject: [] });

const dispatch = useDispatch();
const store = useSelector((state) => state.adminPanel);
const activeData = store.tableData[Object.keys(store.tableData)[store.activeSubMenu]];
const token = getCookie('token');

const handleSendFile = (key, id, filetype, name) => {
const handleSendFile = async (key, id, filetype, name) => {
if (uploaded.includes(id) || rejected.includes(id)) return null;
let tagId = 'file-input' + key;
let file = document.getElementById(tagId).files[0];
uploadFile(id, file, name, filetype, token).then(() => setUploaded((prev) => [...prev, id]));
setLoading((prev) => ({ ...prev, uploading: [...prev.uploading, id] }));

try {
let tagId = 'file-input' + key;
let file = document.getElementById(tagId).files[0];
await uploadFile(id, file, name, filetype, token);
setUploaded((prev) => [...prev, id]);
toast.success('File Uploaded Successfully');
} catch {
toast.error('Error in Uploading File');
} finally {
setLoading((prev) => ({ ...prev, uploading: _.without(prev.uploading, id) }));
}
};

const handleReject = (id) => {
const handleReject = async (id) => {
if (uploaded.includes(id) || rejected.includes(id)) return null;
rejectFileRequest(id, token).then(() => setRejected((prev) => [...prev, id]));
setLoading((prev) => ({ ...prev, reject: [...prev.reject, id] }));

try {
await rejectFileRequest(id, token);
setRejected((prev) => [...prev, id]);
toast.warn('Request Rejected Successfully');
} catch {
toast.error('Error in Rejecting Request');
} finally {
setLoading((prev) => ({ ...prev, reject: _.without(prev.reject, id) }));
}
};

const setRequestData = (res) => {
Expand All @@ -41,10 +69,17 @@ const UserRequestsTable = () => {
dispatch(SetTableData(res.requests));
dispatch(SwitchTab(constants.ALL_TAB));
dispatch(SwitchSubMenu(0));
dispatch(ToggleAdminLoader(''));
};

useEffect(() => {
getFileRequests(token).then(setRequestData);
dispatch(ToggleAdminLoader('Fetching User Requests'));
getFileRequests(token)
.then(setRequestData)
.catch(() => {
toast.error('Error in fetching requests');
dispatch(ToggleAdminLoader(''));
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

Expand Down Expand Up @@ -103,6 +138,7 @@ const UserRequestsTable = () => {
<label htmlFor={'file-input' + key}>
<TableIconButton
type={uploaded.includes(item.id) ? 'approve_confirmed' : 'upload'}
loading={loading.uploading.includes(item.id)}
/>
</label>
<input
Expand All @@ -116,6 +152,7 @@ const UserRequestsTable = () => {
<TableIconButton
type={rejected.includes(item.id) ? 'reject_confirmed' : 'reject'}
handleClick={() => handleReject(item.id)}
loading={loading.reject.includes(item.id)}
/>
</div>
</div>
Expand Down
48 changes: 42 additions & 6 deletions src/components/adminTable/userUploadsTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,21 @@ import { getCookie } from 'utils/handleCookies';
import file_preview from 'assets/file_preview.svg';
import EmptyTable from 'components/error/adminEmptyTable';
import _ from 'lodash';
import { SetTableData, SwitchMainMenu, SwitchSubMenu } from 'actions/adminPanelActions';
import {
SetTableData,
SwitchMainMenu,
SwitchSubMenu,
ToggleAdminLoader,
} from 'actions/adminPanelActions';
import { USER_UPLOADS_MENU } from 'constants/adminPanelMenu';
import { toast } from 'react-toastify';
import ShortName from 'utils/short-name';

const UserUploadsTable = () => {
const [approved, setApproved] = useState([]);
const [rejected, setRejected] = useState([]);
const [previewLink, setPreviewLink] = useState('');
const [loading, setLoading] = useState({ approve: [], reject: [] });

const token = getCookie('token');
const store = useSelector((state) => state.adminPanel);
Expand All @@ -25,14 +32,34 @@ const UserUploadsTable = () => {
setPreviewLink(link);
};

const handleApprove = (id) => {
const handleApprove = async (id) => {
if (approved.includes(id) || rejected.includes(id)) return null;
addUpload(id, token).then(() => setApproved((prev) => [...prev, id]));
setLoading((prev) => ({ ...prev, approve: [...prev.approve, id] }));

try {
await addUpload(id, token);
setApproved((prev) => [...prev, id]);
toast.success('Request Approved Successfully');
} catch {
toast.error('Error in Approving Request');
} finally {
setLoading((prev) => ({ ...prev, approve: _.without(prev.approve, id) }));
}
};

const handleReject = (id) => {
const handleReject = async (id) => {
if (approved.includes(id) || rejected.includes(id)) return null;
deleteUpload(id, token).then(() => setRejected((prev) => [...prev, id]));
setLoading((prev) => ({ ...prev, reject: [...prev.reject, id] }));

try {
await deleteUpload(id, token);
setRejected((prev) => [...prev, id]);
toast.warn('Request Rejected Successfully');
} catch {
toast.error('Error in Rejecting Request');
} finally {
setLoading((prev) => ({ ...prev, reject: _.without(prev.reject, id) }));
}
};

const downloadFile = (url) => {
Expand All @@ -52,10 +79,17 @@ const UserUploadsTable = () => {
);
dispatch(SetTableData(res.uploads));
dispatch(SwitchSubMenu(0));
dispatch(ToggleAdminLoader(''));
};

useEffect(() => {
getUploads(token).then(setRequestData);
dispatch(ToggleAdminLoader('Fetching Upload Requests'));
getUploads(token)
.then(setRequestData)
.catch(() => {
toast.error('Error in fetching requests');
dispatch(ToggleAdminLoader(''));
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

Expand Down Expand Up @@ -102,12 +136,14 @@ const UserUploadsTable = () => {
<TableIconButton
type={approved.includes(item.id) ? 'approve_confirmed' : 'approve'}
handleClick={() => handleApprove(item.id)}
loading={loading.approve.includes(item.id)}
/>
</div>
<div className="row-item">
<TableIconButton
type={rejected.includes(item.id) ? 'reject_confirmed' : 'reject'}
handleClick={() => handleReject(item.id)}
loading={loading.reject.includes(item.id)}
/>
</div>
</div>
Expand Down
20 changes: 20 additions & 0 deletions src/components/cover/adminCover.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React from 'react';
import loader from 'assets/fileloader.svg';
import 'styles/main.scss';
import PropTypes from 'prop-types';

/**
* Admin Panel Loader component for Studyportal.
*/
const AdminCover = ({ customText }) => (
<div className="admincover--wrapper">
<img className="admincover--loader" src={loader} alt="loader" />
<div className="admincover--subtext">{customText || 'Loading'}</div>
</div>
);

AdminCover.propTypes = {
customText: PropTypes.string,
};

export default AdminCover;
1 change: 1 addition & 0 deletions src/constants/action-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ export const SWITCH_SUB_MENU = 'SWITCH_SUB_MENU';
export const SWITCH_TAB = 'SWITCH_TAB';
export const SET_TABLE_DATA = 'SET_TABLE_DATA';
export const RESET_ADMIN_MENU = 'RESET_ADMIN_MENU';
export const TOGGLE_ADMIN_LOADER = 'TOGGLE_ADMIN_LOADER';
4 changes: 2 additions & 2 deletions src/constants/adminPanelMenu.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export const COURSE_REQUEST_MENU = 'Course Requests';
export const USER_REQUEST_MENU = 'User Requests';
export const USER_UPLOADS_MENU = 'User Uploads';
export const USER_REQUEST_MENU = 'File Requests';
export const USER_UPLOADS_MENU = 'Uploads Requests';

export const ALL_TAB = 'All';
export const TUT_TAB = 'Tutorials';
Expand Down
Loading