Skip to content

Commit

Permalink
Merge pull request #20 from sliit-foss/feature/addNewRole
Browse files Browse the repository at this point in the history
Feat: Implement new role access
  • Loading branch information
Akalanka47000 authored Sep 15, 2024
2 parents 7179336 + 53268a1 commit 6220cfa
Show file tree
Hide file tree
Showing 10 changed files with 9,657 additions and 75 deletions.
9,519 changes: 9,519 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions src/components/questions/dialog.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ const QuestionDialog = ({ refresh }) => {
}
}, [selectedQuestion]);

const { data: { data: user } = {} } = useAuthUserQuery();
const { data: { data: authUser } = {} } = useAuthUserQuery();

const [addQuestion] = useAddQuestionMutation();
const [updateQuestion] = useUpdateQuestionMutation();
Expand Down Expand Up @@ -159,7 +159,7 @@ const QuestionDialog = ({ refresh }) => {
/>
</div>
<div className="flex flex-col md:flex-row gap-3">
{(!selectedQuestion || selectedQuestion.creator === user._id) && (
{(!selectedQuestion || selectedQuestion.creator === authUser._id) && (
<Dropdown
filterkey="creator_lock"
label="Creator Lock"
Expand Down
21 changes: 13 additions & 8 deletions src/components/questions/question-details/action-buttons.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { useNavigate } from "react-router-dom";
import { twMerge } from "tailwind-merge";
import { store } from "@/store";
import { useAuthUserQuery } from "@/store/api";
import { setSelectedQuestion, toggleAddQuestionDialog } from "@/store/reducers/ui/question";
import { Button } from "@sliit-foss/bashaway-ui/components";

Expand All @@ -11,6 +12,8 @@ const onEditClick = (question) => {

const ActionButtons = ({ question, className, buttonClassName }) => {
const navigate = useNavigate();
const { data: { data: authUser } = {} } = useAuthUserQuery();

return (
<div className={twMerge("flex flex-col md:flex-row gap-3 mt-1", className)}>
<Button
Expand All @@ -20,14 +23,16 @@ const ActionButtons = ({ question, className, buttonClassName }) => {
>
View submissions
</Button>
<Button
variant="secondary"
className={twMerge("bg-transparent", buttonClassName)}
onClick={() => onEditClick(question)}
disabled={!question}
>
Edit
</Button>
{authUser?.role == "ADMIN" && (
<Button
variant="secondary"
className={twMerge("bg-transparent", buttonClassName)}
onClick={() => onEditClick(question)}
disabled={!question}
>
Edit
</Button>
)}
</div>
);
};
Expand Down
66 changes: 37 additions & 29 deletions src/components/submissions/submission/actions.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { ArrowDownToLine, Eye } from "lucide-react";
import { twMerge } from "tailwind-merge";
import { scorekeeperRepositoryLink } from "@/constants";
import { store } from "@/store";
import { useAuthUserQuery } from "@/store/api";
import { setSelectedSubmission, toggleGradeSubmissionDialog } from "@/store/reducers/ui/submission";
import { downloadFile } from "@/utils";
import { Button, IconButton } from "@sliit-foss/bashaway-ui/components";
Expand All @@ -11,35 +12,42 @@ const onGradeClick = (submission) => {
store.dispatch(toggleGradeSubmissionDialog(true));
};

export const Actions = ({ submission, className, buttonClassName }) => (
<div
className={twMerge(
"w-full md:w-auto flex flex-row justify-center md:justify-end items-center gap-3 mt-1",
className
)}
>
<Button
className={twMerge("w-full sm:w-auto self-center py", buttonClassName)}
disabled={!submission}
onClick={() => onGradeClick(submission)}
export const Actions = ({ submission, className, buttonClassName }) => {
const { data: { data: authUser } = {} } = useAuthUserQuery();
return (
<div
className={twMerge(
"w-full md:w-auto flex flex-row justify-center md:justify-end items-center gap-3 mt-1",
className
)}
>
Grade
</Button>
<IconButton
variant="secondary"
icon={<Eye size={18} />}
label="View Results"
disabled={!submission}
onClick={() => window.open(`${scorekeeperRepositoryLink}/actions?query=workflow%3A+${submission?._id}`, "_blank")}
/>
<IconButton
variant="secondary"
icon={<ArrowDownToLine size={18} />}
label="Download"
disabled={!submission}
onClick={() => downloadFile(submission.link)}
/>
</div>
);
{authUser?.role === "ADMIN" && (
<Button
className={twMerge("w-full sm:w-auto self-center py", buttonClassName)}
disabled={!submission}
onClick={() => onGradeClick(submission)}
>
Grade
</Button>
)}
<IconButton
variant="secondary"
icon={<Eye size={18} />}
label="View Results"
disabled={!submission}
onClick={() =>
window.open(`${scorekeeperRepositoryLink}/actions?query=workflow%3A+${submission?._id}`, "_blank")
}
/>
<IconButton
variant="secondary"
icon={<ArrowDownToLine size={18} />}
label="Download"
disabled={!submission}
onClick={() => downloadFile(submission.link)}
/>
</div>
);
};

export default Actions;
15 changes: 13 additions & 2 deletions src/components/users/dialog.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
AlertDialogHeader,
AlertDialogTitle,
Button,
Dropdown,
Input,
toast
} from "@sliit-foss/bashaway-ui/components";
Expand All @@ -24,7 +25,8 @@ const UserDialog = ({ refresh }) => {
e.preventDefault();
await addUser({
name: e.target.name.value,
email: e.target.email.value
email: e.target.email.value,
role: e.target.role.value
})
.unwrap()
.then(() => {
Expand All @@ -44,10 +46,19 @@ const UserDialog = ({ refresh }) => {
<AlertDialogContent overlayClassName="z-[201]" className="z-[201]">
<form onSubmit={handleSubmit} className="flex flex-col gap-3">
<AlertDialogHeader>
<AlertDialogTitle>Add Admin</AlertDialogTitle>
<AlertDialogTitle>Add User</AlertDialogTitle>
</AlertDialogHeader>
<Input placeholder="Name" name="name" required className="sm:h-14" />
<Input placeholder="Email" name="email" type="email" required className="sm:h-14" />
<Dropdown
className="sm:h-14"
label="Select Role"
name="role"
options={[
{ key: "Admin", label: "ADMIN" },
{ key: "Spectator", label: "SPECTATOR" }
]}
/>
<AlertDialogFooter className="mt-4">
<Button type="submit" loading={isLoading}>
Add
Expand Down
28 changes: 16 additions & 12 deletions src/components/users/user/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ import { GraduationCap, Power, Settings } from "lucide-react";
import { twMerge } from "tailwind-merge";
import { store } from "@/store";
import { useUpdateUserMutation, userApi } from "@/store/api";
import { useAuthUserQuery } from "@/store/api";
import { IconButton, Metric, toast } from "@sliit-foss/bashaway-ui/components";
import { Body2, Callout } from "@sliit-foss/bashaway-ui/typography";

export { default as UserGridSkeleton } from "./skeleton";

export const User = ({ user }) => {
const [updateUser, { isLoading }] = useUpdateUserMutation();
const { data: { data: authUser } = {} } = useAuthUserQuery();

const toggleActiveStatus = () => {
updateUser({
Expand Down Expand Up @@ -85,18 +87,20 @@ export const User = ({ user }) => {
</div>
</div>
<div className="ml-auto flex items-center">
<IconButton
className={twMerge(
"ml-auto self-center mt-2 md:mt-0",
user.is_active ? "text-green-400 hover:text-red-500" : "text-red-500 hover:text-green-400"
)}
variant="secondary"
icon={<Power size={16} />}
label={user.is_active ? "Deactivate" : "Activate"}
onClick={toggleActiveStatus}
loading={isLoading}
loaderProps={{ width: 16, height: 16 }}
/>
{authUser?.role == "ADMIN" && (
<IconButton
className={twMerge(
"ml-auto self-center mt-2 md:mt-0",
user.is_active ? "text-green-400 hover:text-red-500" : "text-red-500 hover:text-green-400"
)}
variant="secondary"
icon={<Power size={16} />}
label={user.is_active ? "Deactivate" : "Activate"}
onClick={toggleActiveStatus}
loading={isLoading}
loaderProps={{ width: 16, height: 16 }}
/>
)}
</div>
</div>
</div>
Expand Down
39 changes: 32 additions & 7 deletions src/pages/dashboard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,14 @@ const Dashboard = () => {

const { ghostLegion, toggleGhostLegion } = useGhostLegion();

const { data: { data: registrationInfo } = {}, isFetching: isRegistrationInfoFetching } = useGetRegistrationInfoQuery({ round, ghostLegion });
const { data: { data: questionSubmissionInfo } = {}, isFetching: isQuestionSubmissionsFetching } = useGetQuestionSubmissionsQuery({ round, ghostLegion });
const { data: { data: teamSubmissionInfo } = {}, isFetching: isTeamSubmissionsFetching } = useGetTeamSubmissionsQuery({ round, ghostLegion });
const { data: { data: registrationInfo } = {}, isFetching: isRegistrationInfoFetching } = useGetRegistrationInfoQuery(
{ round, ghostLegion }
);
const { data: { data: questionSubmissionInfo } = {}, isFetching: isQuestionSubmissionsFetching } =
useGetQuestionSubmissionsQuery({ round, ghostLegion });
const { data: { data: teamSubmissionInfo } = {}, isFetching: isTeamSubmissionsFetching } = useGetTeamSubmissionsQuery(
{ round, ghostLegion }
);

useTitle("Dashboard | Bashaway");

Expand All @@ -30,10 +35,30 @@ const Dashboard = () => {
<GhostLegion ghostLegion={ghostLegion} toggleGhostLegion={toggleGhostLegion} round={round} />
</div>
<div className="w-full h-full grid grid-cols-2 md:grid-cols-3 lg:grid-cols-5 justify-start items-start gap-5">
<DashboardCard icon={Building} title="Universities" value={registrationInfo?.university_counts?.length} loading={isRegistrationInfoFetching}/>
<DashboardCard icon={Users} title="Teams" value={registrationInfo?.total_registrations} loading={isRegistrationInfoFetching}/>
<DashboardCard icon={Users2} title="Individuals" value={registrationInfo?.total_members} loading={isRegistrationInfoFetching}/>
<DashboardCard icon={Folder} title="Submissions" value={totalSubmissions} loading={isQuestionSubmissionsFetching}/>
<DashboardCard
icon={Building}
title="Universities"
value={registrationInfo?.university_counts?.length}
loading={isRegistrationInfoFetching}
/>
<DashboardCard
icon={Users}
title="Teams"
value={registrationInfo?.total_registrations}
loading={isRegistrationInfoFetching}
/>
<DashboardCard
icon={Users2}
title="Individuals"
value={registrationInfo?.total_members}
loading={isRegistrationInfoFetching}
/>
<DashboardCard
icon={Folder}
title="Submissions"
value={totalSubmissions}
loading={isQuestionSubmissionsFetching}
/>
<DashboardCard
className="col-span-2 md:col-span-1"
icon={UserGroup}
Expand Down
20 changes: 12 additions & 8 deletions src/pages/questions.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { Question, QuestionDialog, QuestionGridSkeleton } from "@/components/que
import { questionFilters, questionSorts } from "@/filters";
import { useTitle } from "@/hooks";
import { store } from "@/store";
import { useGetQuestionsQuery, useLazyGetQuestionsQuery } from "@/store/api";
import { useAuthUserQuery, useGetQuestionsQuery, useLazyGetQuestionsQuery } from "@/store/api";
import { setSelectedQuestion, toggleAddQuestionDialog } from "@/store/reducers/ui/question";
import { AnimatedSwitcher, Button, Filters, NoRecords, Pagination, Sorts } from "@sliit-foss/bashaway-ui/components";
import { computeFilterQuery, computeSortQuery } from "@sliit-foss/bashaway-ui/utils";
Expand All @@ -23,6 +23,8 @@ const Questions = () => {

const { data: questions, isFetching, isError } = useGetQuestionsQuery({ filters, sorts, page });

const { data: { data: authUser } = {} } = useAuthUserQuery();

const [trigger] = useLazyGetQuestionsQuery();

const refresh = () => trigger({ filters, sorts, page });
Expand All @@ -33,13 +35,15 @@ const Questions = () => {
<>
<div className="w-full flex flex-col justify-center items-center gap-6 mb-8 mt-4">
<div className="w-full flex flex-col md:flex-row gap-6">
<Button
className="w-full md:w-5/12 lg:w-4/12 xl:w-3/12 2xl:w-2/12 py-[13px] sm:py-4 md:py-1.5"
onClick={onAddClick}
>
<Plus strokeWidth="2.5" />
Add Question
</Button>
{authUser?.role === "ADMIN" && (
<Button
className="w-full md:w-5/12 lg:w-4/12 xl:w-3/12 2xl:w-2/12 py-[13px] sm:py-4 md:py-1.5"
onClick={onAddClick}
>
<Plus strokeWidth="2.5" />
Add Question
</Button>
)}
<Filters filters={questionFilters} setFilterQuery={setFilters} />
</div>
<Sorts sorts={questionSorts} setSortQuery={setSorts} />
Expand Down
14 changes: 9 additions & 5 deletions src/pages/users.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { User, UserDialog, UserGridSkeleton } from "@/components/users";
import { userFilters } from "@/filters";
import { useTitle } from "@/hooks";
import { store } from "@/store";
import { useGetAllUsersQuery, useLazyGetAllUsersQuery, userApi } from "@/store/api";
import { useAuthUserQuery, useGetAllUsersQuery, useLazyGetAllUsersQuery, userApi } from "@/store/api";
import { toggleAddUserDialog } from "@/store/reducers/ui/user";
import { AnimatedSwitcher, Button, Filters, NoRecords, Pagination } from "@sliit-foss/bashaway-ui/components";
import { computeFilterQuery } from "@sliit-foss/bashaway-ui/utils";
Expand All @@ -19,6 +19,8 @@ const Users = () => {

const { data: users, isFetching, isError } = useGetAllUsersQuery({ filters, page });

const { data: { data: authUser } = {} } = useAuthUserQuery();

const [trigger] = useLazyGetAllUsersQuery();

const refresh = () => {
Expand All @@ -34,10 +36,12 @@ const Users = () => {
filters={userFilters}
setFilterQuery={setFilters}
action={
<Button className="w-full py-4" onClick={onAddClick}>
<Plus strokeWidth="2.5" />
Add User
</Button>
authUser?.role === "ADMIN" && (
<Button className="w-full py-4" onClick={onAddClick}>
<Plus strokeWidth="2.5" />
Add User
</Button>
)
}
styles={{
root: "md:grid grid-cols-5 self-start mb-8 [&>div:nth-child(2)]:col-span-2 [&>div:nth-child(3)]:col-span-2 [&>div:nth-child(4)]:col-span-2 mt-4",
Expand Down
6 changes: 4 additions & 2 deletions src/store/api/auth.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
import { createApi } from "@reduxjs/toolkit/query/react";
import { toast } from "@sliit-foss/bashaway-ui";
import baseQuery, { mutationHelper } from "./base";
import { default as baseQuery, mutationHelper } from "./base";

const { post } = mutationHelper;

const authorizedRoles = ["ADMIN", "SPECTATOR"];

export const authApi = createApi({
reducerPath: "authApi",
baseQuery,
endpoints: (builder) => ({
login: builder.mutation({
query: (data) => post(`/api/auth/login`, data),
transformResponse: (response) => {
if (response.data.user?.role !== "ADMIN") {
if (!authorizedRoles.includes(response.data.user?.role)) {
toast({
variant: "destructive",
title: "You are not authorized to access this portal"
Expand Down

0 comments on commit 6220cfa

Please sign in to comment.