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

feat/HNG-77-Implement member management functionalities on admin dashboard #309

Open
wants to merge 21 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
9c8c882
updated
pauluwaifo Jul 20, 2024
7a9f492
feat: fix member manegement functionality issue
pauluwaifo Jul 20, 2024
3a5e40e
use pnpm in deploy scripts
ickynavigator Jul 20, 2024
c88f5e0
feat: fix member management function-on admin dashboard
pauluwaifo Jul 20, 2024
e8947c0
ran update
pauluwaifo Jul 21, 2024
d258982
Merge branch 'dev' of https://github.com/hngprojects/hng_boilerplate_…
pauluwaifo Jul 21, 2024
204cf1e
Merge branch 'dev' of https://github.com/hngprojects/hng_boilerplate_…
pauluwaifo Jul 21, 2024
626578f
Merge branch 'dev' of https://github.com/hngprojects/hng_boilerplate_…
pauluwaifo Jul 21, 2024
6a405a6
updated
pauluwaifo Jul 21, 2024
e378327
updated my code
pauluwaifo Jul 21, 2024
5458126
updated
pauluwaifo Jul 21, 2024
9662428
feat: fix Member Management Functionalities on Admin Dashboard
pauluwaifo Jul 21, 2024
dec96ed
feat: fix user search filter issue
pauluwaifo Jul 21, 2024
521125f
pulled from upstream and updated
pauluwaifo Jul 22, 2024
96969da
feat: fix pulled from upstream and fix filter issue
pauluwaifo Jul 22, 2024
fa3e2a9
feat: fix package.json issue
pauluwaifo Jul 22, 2024
e14d1cb
Merge branch 'dev' of https://github.com/hngprojects/hng_boilerplate_…
pauluwaifo Jul 22, 2024
ec7e5e1
Merge branch 'dev' into feat/HNG-77-Implement-Member-Management-Funct…
pauluwaifo Jul 22, 2024
9974f74
feat: Removed pnpm package from package.json
lordfrantex Jul 19, 2024
32d2df7
Merge branch 'feat/HNG-77-Implement-Member-Management-Functionalities…
pauluwaifo Jul 22, 2024
c6e7acb
passed lint test
lordfrantex Jul 20, 2024
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
232 changes: 232 additions & 0 deletions app/components/dashboard/MemberManagement.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
import { Link } from "@remix-run/react";
import { ArrowRight, Check, ChevronDown, Ellipsis, Search } from "lucide-react";
import { ChangeEvent, useEffect, useState } from "react";

import DeleteMemberModal from "../ui/DeleteMemberModal";

function MemberManagement() {
const [search, setSearch] = useState<string>("");
const [filter, setFilter] = useState<string>("All");
const [display, setDisplay] = useState<string>("none");
const [isModalVisible, setIsModalVisible] = useState<boolean>(false);
const [selectedUserName, setSelectedUserName] = useState<string>("");

// handle member delete modal
const handleMemberDelete = (userName: string): void => {
setSelectedUserName(userName);
setIsModalVisible(true);
};

// search
const handleSearch = (event: ChangeEvent<HTMLInputElement>) => {
setSearch(event.target.value);
};

// filter buttons
const accountType_button: string[] = [
"All",
"Members",
"Suspended",
"Left workspace",
];

interface User {
id: number;
name: string;
email: string;
isAdmin: boolean;
isUser: boolean;
isGuest: boolean;
role: string;
}

// demo users data
const users: User[] = [
{
id: 1,
name: "john doe",
email: "[email protected]",
isAdmin: true,
isUser: false,
isGuest: false,
role: "members",
},
{
id: 2,
name: "tester",
email: "[email protected]",
isAdmin: false,
isUser: true,
isGuest: false,
role: "suspended",
},
{
id: 3,
name: "rest2",
email: "[email protected]",
isAdmin: false,
isUser: true,
isGuest: false,
role: "left workspace",
},
];

// demo card design for users
const userList = () => {
return (
<>
<p>{users.length} active members</p>
{users
.filter(
(user) =>
user.name.toLowerCase().includes(search.toLowerCase()) ||
user.email.toLowerCase().includes(search.toLowerCase()) ||
user.role.toLowerCase() === filter.toLowerCase(),
)
.map((user, index) => (
<div
className="mt-2 flex flex-row flex-wrap items-center"
key={index}
>
<div className="flex basis-2/3 flex-row items-center justify-between">
<div className="flex flex-row items-center">
<div className="min:w-32 min:h-32 rounded-full border bg-gray-500 p-10"></div>
<div className="mx-2 flex flex-col">
<p>{user.name}</p>
<p>{user.email}</p>
</div>
</div>
<p className="flex flex-row items-center">
{user.isAdmin ? "Admin" : user.isGuest ? "Guest" : "Users"}
<ChevronDown />
</p>
</div>

<div className="relative flex basis-1/3 flex-row justify-end">
<button onClick={() => handleMemberDelete(user.name)}>
<Ellipsis />
</button>

{isModalVisible && selectedUserName === user.name && (
<div className="absolute">
<DeleteMemberModal memberName={selectedUserName} />
</div>
)}
</div>
</div>
))}
</>
);
};

useEffect(() => {
const handleClick = () => {
setDisplay("none");
};

window.addEventListener("click", handleClick);

return () => {
window.removeEventListener("click", handleClick);
};
}, []);

const toggleDropdown = (event: React.MouseEvent) => {
event.stopPropagation();
setDisplay(display === "none" ? "block" : "none");
};

const handleOptionClick = (button: string, event: React.MouseEvent) => {
event.stopPropagation();
setFilter(button);
setDisplay("none");
};

return (
<div className="flex flex-col flex-wrap p-5">
<p className="text-lg font-semibold">Manage members</p>

{/* heading */}
<div className="flex flex-wrap items-center text-sm">
On the Free plan all members in a workspace are administrators. Upgrade
to a paid plan to add the ability to assign or remove administrator
roles.
<Link
className="mx-1 flex flex-row items-center text-[#eb7300]"
to={"/"}
>
Go to Plans
<span className="mx-2 fill-[#eb7300]">
<ArrowRight width={"12px"} />
</span>
</Link>
</div>

<div className="mt-5 flex flex-row flex-wrap items-center">
<div className="flex basis-1/2 flex-row">
<form
className="flex w-72 flex-row items-center rounded-lg border-[1.5px] border-[#cdd5e1] px-2"
action=""
>
<span>
<Search width={"22px"} stroke="#525252" />
</span>
<input
type="text"
name="search"
id="search"
onChange={handleSearch}
placeholder="Search by name or email"
className="basis-full border-none p-2 text-sm placeholder-[#525252] outline-none"
/>
</form>

<div className="relative flex">
<button
onClick={toggleDropdown}
className="mx-2 flex cursor-pointer flex-row items-center overflow-hidden rounded-lg border-[1.5px] border-[#cdd5e1] px-3 py-2"
>
{filter}
<ChevronDown
width={"20px"}
className="ml-2 inline-block stroke-[#525252]"
/>
</button>

<div
className={`absolute ${
display === "block" ? "flex" : "hidden"
} left-2 top-0 w-64 flex-col flex-wrap items-start rounded-sm bg-white p-2 font-semibold text-[#525252] shadow-[2px_1px_10px_2px_rgba(0,0,0,0.1)]`}
onClick={(event) => event.stopPropagation()}
>
{accountType_button.map((button, index) => (
<button
key={index}
onClick={(event) => handleOptionClick(button, event)}
className={`${
filter === button ? "bg-[#cdd5e1]" : ""
} mt-[1px] flex w-full cursor-pointer flex-row justify-between rounded px-2 py-1 transition delay-100 ease-in-out hover:bg-[#cdd5e1]`}
>
{button}
{filter === button && (
<Check className="mr-end inline-block" />
)}
</button>
))}
</div>
</div>
</div>

<div className="flex basis-1/2 flex-row items-center justify-end">
<button className="rounded-sm bg-[#eb7300] px-3 py-2 text-white">
Invite people
</button>
</div>
</div>

{userList()}
</div>
);
}

export default MemberManagement;
11 changes: 11 additions & 0 deletions app/components/ui/arrow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export const Arrow = () => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512"
width={"13px"}
>
<path d="M502.6 278.6c12.5-12.5 12.5-32.8 0-45.3l-128-128c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L402.7 224 32 224c-17.7 0-32 14.3-32 32s14.3 32 32 32l370.7 0-73.4 73.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l128-128z" />
</svg>
);
};
Loading