Skip to content

Commit

Permalink
Merge pull request #43 from Keeeyaan/master
Browse files Browse the repository at this point in the history
minor update
  • Loading branch information
Keeeyaan authored Jan 1, 2024
2 parents 4ae327d + 917f2d4 commit ca79384
Show file tree
Hide file tree
Showing 11 changed files with 305 additions and 41 deletions.
4 changes: 1 addition & 3 deletions backend/psits_backend/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,6 @@ cloudinary.config({

let PORT = config.PORT;

const __dirname = dirname(fileURLToPath(import.meta.url));

// middlewares
app.use(
cors({
Expand All @@ -58,7 +56,7 @@ app.use(compression()); // compresses all routes
// routes
app.use("/", homeRouter);
app.use("/api/v2/auth", v2AuthRouter);
app.use("/api/v2/user", authenticateUser, v2UserRouter);
app.use("/api/v2/user", v2UserRouter);
app.use("/api/v2/announcement", v2AnnouncementRouter);
app.use("/api/v2/event", v2EventRouter);
app.use("/api/v2/merch", v2MerchandiseRouter);
Expand Down
38 changes: 37 additions & 1 deletion backend/psits_backend/src/controllers/userController.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,44 @@ export const updateCurrentUser = async (req, res) => {

export const getAllUser = async (req, res) => {
if (!req.user.isAdmin) throw new UnauthorizedError("Unauthorized!");
const page = parseInt(req.query.page) - 1 || 0;
const limit = parseInt(req.query.limit) || 15;
const search = req.query.search || "";

const users = await User.find({}, "-password"); // hide password
const users = await User.find(
{
$or: [
{ firstname: { $regex: search } },
{ lastname: { $regex: search } },
{ email: { $regex: search } },
{ role: { $regex: search } },
],
},
"-password" // hide password
)
.skip(page * limit)
.limit(limit);

const total = await User.countDocuments({
firstname: { $regex: search },
lastname: { $regex: search },
email: { $regex: search },
role: { $regex: search },
});

const response = {
error: false,
total,
page: page + 1,
limit,
users,
};

res.status(StatusCodes.OK).json(response);
};

export const getAllUserPublic = async (req, res) => {
const users = await User.find({ showPublic: true }, "-password"); // hide password

res.status(StatusCodes.OK).json({ users });
};
Expand Down
19 changes: 14 additions & 5 deletions backend/psits_backend/src/routes/userRouter.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@ import {
getCurrentUser,
updateCurrentUser,
getAllUser,
getAllUserPublic,
getUserbyId,
updateUserbyId,
deleteUserbyId,
} from "../controllers/userController.js";

import { authenticateUser } from "../middlewares/authMiddleware.js";
import {
validateUserBodyPatch,
validateUserParam,
Expand All @@ -16,15 +19,21 @@ import upload from "../middlewares/multerMiddleware.js";

router
.route("/current-user")
.get(getCurrentUser)
.get(authenticateUser, getCurrentUser)
.patch(upload.single("avatar"), updateCurrentUser);

router.route("/").get(getAllUser);
router.route("/").get(authenticateUser, getAllUser);
router.route("/public").get(getAllUserPublic);

router
.route("/:userId")
.get(validateUserParam, getUserbyId)
.patch(validateUserParam, validateUserBodyPatch, updateUserbyId)
.delete(validateUserParam, deleteUserbyId);
.get(authenticateUser, validateUserParam, getUserbyId)
.patch(
authenticateUser,
validateUserParam,
validateUserBodyPatch,
updateUserbyId
)
.delete(authenticateUser, validateUserParam, deleteUserbyId);

export default router;
9 changes: 7 additions & 2 deletions frontend/psits_frontend/src/api/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,13 @@ export async function updateCurrentUser(data: any) {
return response.data;
}

export async function getAllUser() {
const response = await axios.get(`user`);
export async function getAllUser(search: string, page: number) {
const response = await axios.get(`user?page=${page}&search=${search}`);
return response.data;
}

export async function getAllUserPublic() {
const response = await axios.get(`user/public`);
return response.data.users;
}

Expand Down
21 changes: 13 additions & 8 deletions frontend/psits_frontend/src/components/ProfileAvatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,19 +49,24 @@ const Profile = ({ className }: { className?: string }) => {
className="rounded-full h-[40px] w-[40px] sm:h-[50px] sm:w-[50px] object-cover hover:border-2 transition"
/>
<AvatarFallback>
<User className="rounded-full text-white"/>
<User className="rounded-full text-white" />
</AvatarFallback>
</Avatar>
</DropdownMenuTrigger>
<DropdownMenuContent className="w-40">
<DropdownMenuLabel>My Account</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuItem>
<Link to="/admin" className="flex items-center">
<ShieldAlert className="mr-4 h-6 w-4" />
<span className="text-red-400">Admin</span>
</Link>
</DropdownMenuItem>
{store.authUser?.role === "admin" ||
(store.authUser?.role === "dev" && (
<>
<DropdownMenuSeparator />
<DropdownMenuItem>
<Link to="/admin" className="flex items-center">
<ShieldAlert className="mr-4 h-6 w-4" />
<span className="text-red-400">Admin</span>
</Link>
</DropdownMenuItem>
</>
))}
<DropdownMenuSeparator />
<DropdownMenuItem>
<Link to="/profile" className="flex items-center">
Expand Down
107 changes: 101 additions & 6 deletions frontend/psits_frontend/src/components/tables/AccountsTable.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,73 @@
import { useQuery } from "@tanstack/react-query";
import { Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow } from "../ui/table";
import { getAllUser } from "@/api/user";
import { useState } from "react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { AlertCircle, Loader2Icon } from "lucide-react";
import { toast } from "react-toastify";

import { Input } from "@/components/ui/input"
import { Table, TableBody, TableCaption, TableCell, TableHead, TableHeader, TableRow } from "../ui/table";
import { getAllUser, updateUserbyId } from "@/api/user";
import useStore from "@/store";

import {
Pagination,
PaginationContent,
PaginationEllipsis,
PaginationItem,
PaginationLink,
PaginationNext,
PaginationPrevious,
} from "@/components/ui/pagination"
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "../ui/select";


const AccountsTable = () => {
const { data, isLoading, isError } = useQuery(["users"], getAllUser, {
const [page, setPage] = useState(1);
const [search, setSearch] = useState("");
const {authUser} = useStore();
const queryClient = useQueryClient();

const { data, isLoading, isError } = useQuery(["users", search, page], () => getAllUser(search, page), {
select(userData) {
return userData;
},
});

let totalPages = Math.ceil(data?.total / data?.limit) || 0;

const searchOnChangeHandler = (e: React.ChangeEvent<HTMLInputElement>) => {
const value = e.target.value;
setSearch(value)
}

const handlePrevPage = () => {
if (page > 1) setPage(page => page - 1);
}

const handleNextPage = () => {
if (page < totalPages) setPage(page => page + 1);
}

const { mutate: updateMutate } = useMutation({
mutationFn: updateUserbyId,
onSuccess: (cart) => {
queryClient.invalidateQueries(["users"]);
},
onError(error: any) {
toast.error(error.response.cart.message || error.message, { position: "bottom-right" });
},
});

const handleRoleSelect = (role: string, userId: string) => {
const data = {
role: role,
};

updateMutate({ userId, data });
};

return (
<>
<Input value={search} className="w-[300px] mb-4" placeholder="Search any user here..." onChange={searchOnChangeHandler}/>
<div className="rounded-md border">
<Table>
<TableCaption>A list of student accounts.</TableCaption>
Expand Down Expand Up @@ -38,7 +95,7 @@ const AccountsTable = () => {
</div>
) : (
<TableBody>
{data?.map((user: any) => {
{data.users?.map((user: any) => {
const role = user.role.charAt(0).toUpperCase() + user.role.slice(1);
return (
<TableRow key={user._id}>
Expand All @@ -52,14 +109,52 @@ const AccountsTable = () => {
<TableCell>{user.email}</TableCell>
<TableCell>{user.course}</TableCell>
<TableCell>{user.year}</TableCell>
<TableCell>{role}</TableCell>
<TableCell>
{authUser?.role == "dev" ? (<Select>
<SelectTrigger className="">
<SelectValue defaultValue={user.role} placeholder={role} />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectLabel>Status</SelectLabel>
<SelectItem onMouseDown={() => handleRoleSelect("dev", user.userId)} value="dev">
Dev
</SelectItem>
<SelectItem onMouseDown={() => handleRoleSelect("admin", user.userId)} value="admin">
Admin
</SelectItem>
<SelectItem onMouseDown={() => handleRoleSelect("user", user.userId)} value="user">
User
</SelectItem>
</SelectGroup>
</SelectContent>
</Select>) : role}
</TableCell>
</TableRow>
);
})}
</TableBody>
)}
</Table>
</div>
<Pagination className="my-5" >
<PaginationContent>
<PaginationItem>
<PaginationPrevious onClick={handlePrevPage} />
</PaginationItem>
{
totalPages > 0 && [...Array(totalPages)].map((val, index) => (
<PaginationItem key={index}>
<PaginationLink onClick={() => setPage(index + 1)} isActive={page === index + 1}>{index + 1}</PaginationLink>
</PaginationItem>
))
}
<PaginationItem>
<PaginationNext onClick={handleNextPage} />
</PaginationItem>
</PaginationContent>
</Pagination>
</>
);
};

Expand Down
Loading

0 comments on commit ca79384

Please sign in to comment.