done user and role table, and add user

This commit is contained in:
2026-03-18 17:24:15 +08:00
parent f84894b6d7
commit 14884f6b3a
14 changed files with 298 additions and 134 deletions

View File

@@ -0,0 +1,32 @@
import React from "react";
const plus = () => {
return (
<>
<svg
xmlns="http://www.w3.org/2000/svg"
width={24}
height={24}
viewBox="0 0 24 24"
fill="none"
>
<path
d="M12 5.29199V18.7087"
stroke="#333649"
strokeWidth={2}
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M5.29102 12H18.7077"
stroke="#333649"
strokeWidth={2}
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
</>
);
};
export default plus;

View File

@@ -0,0 +1,36 @@
import React from "react";
import styles from "./styles.module.css";
import MobileSearchBar from "@/app/components/mobileSearchBar/MobileSearchBar";
import useIsMobile from "@/app/hooks/useIsMobile";
import PlusIcon from "../icons/plus";
const Toggle = ({ tabs = [], activeTab, onChange }) => {
const isMobile = useIsMobile();
return (
<div className={styles.toggleContainer}>
<div className={styles.buttonToggles}>
{tabs.map((tab) => (
<button
key={tab.value}
className={`${styles.buttonStyle} ${activeTab === tab.value ? styles.active : ""}`}
onClick={() => onChange(tab.value)}
>
{tab.label}
</button>
))}
</div>
{isMobile && activeTab === "permissions" && (
<div className={styles.container}>
<MobileSearchBar />
<button>
<PlusIcon />
</button>
</div>
)}
</div>
);
};
export default Toggle;

View File

@@ -0,0 +1,56 @@
.toggleContainer {
display: none;
}
@media (max-width: 950px) {
.toggleContainer {
display: flex;
flex-direction: column;
align-self: stretch;
gap: 16px;
}
.buttonToggles {
display: flex;
align-items: flex-start;
gap: 16px;
align-self: stretch;
}
.container {
display: flex;
align-items: center;
gap: 16px;
flex: 1 0 0;
}
.container > button {
display: flex;
padding: 8px;
border: none;
justify-content: center;
align-items: center;
gap: 12px;
border-radius: 6px;
background: #27293b;
}
.buttonStyle {
display: flex;
background: none;
border: none;
padding: 24px 4px 16px 4px;
flex-direction: column;
justify-content: center;
align-items: flex-start;
gap: 5px;
color: #85869b;
font-family: Inter;
font-size: 18px;
font-style: normal;
font-weight: 400;
line-height: normal;
letter-spacing: 0.18px;
}
.active {
border-bottom: 1px solid #959aff;
color: #959aff;
}
}

View File

@@ -91,7 +91,7 @@
background: #2d3143;
box-shadow: 0 2px 15px 0 rgba(0, 0, 0, 0.25);
position: absolute;
z-index: 4;
z-index: 30;
top: 100%;
margin-top: 8px;
left: 0;

View File

@@ -16,10 +16,9 @@
gap: 10px;
border-radius: 6px;
}
.profileBadge:hover {
.profileBadgeButton:hover {
border-radius: 6px;
background: #21232f;
background: color(display-p3 0.1294 0.1373 0.1804);
}
.nameRole {
display: flex;
@@ -79,12 +78,10 @@
left: 0;
border-radius: 6px;
background: #2d3144;
background: color(display-p3 0.1787 0.1913 0.2605);
box-shadow: 0 2px 15px 0 rgba(0, 0, 0, 0.25);
box-shadow: 0 2px 15px 0 color(display-p3 0 0 0 / 0.25);
cursor: pointer;
position: absolute;
z-index: 10;
z-index: 30;
top: 100%;
margin-top: 3px;
animation-name: dropDownAnimation;

View File

@@ -3,46 +3,24 @@ import DeleteIcon from "../icons/delete";
import FileIcon from "../icons/file";
import editUserStyle from "./styles.module.css";
import React from "react";
import PlusIcon from "../icons/plus";
const Permissions = ({ sampleData = [] }) => {
return (
<>
{/* Permissions */}
<div className={editUserStyle.userPermissions}>
{/* Add permissions */}
<div className={editUserStyle.imanginaryDiv}></div>
<div className={editUserStyle.permissionsContainer}>
{/* Header */}
<div className={editUserStyle.permissionsHeader}>
<p>Permissions</p>
<div className={editUserStyle.svgContainer}>
<div>
<svg
xmlns="http://www.w3.org/2000/svg"
width={24}
height={24}
viewBox="0 0 24 24"
fill="none"
>
<path
d="M12 5.29199V18.7087"
stroke="#333649"
strokeWidth={2}
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M5.29102 12H18.7077"
stroke="#333649"
strokeWidth={2}
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
</div>
{/* Button ni */}
<button>
<PlusIcon />
</button>
</div>
</div>
<div className={editUserStyle.wrapper}>
{sampleData.length === 0 ? (
// Default Message
<div className={editUserStyle.permissionDefaultState}>

View File

@@ -1,19 +1,3 @@
.imanginaryDiv {
padding: 18px;
}
.userPermissions {
display: flex;
flex-direction: column;
align-items: flex-start;
flex: 1 0 0;
align-self: stretch;
border-radius: 6px;
height: calc(100vh - 175px);
position: relative;
overflow: auto;
scrollbar-width: none;
}
.permissionsContainer {
display: flex;
padding: 24px;
@@ -22,7 +6,6 @@
align-self: stretch;
border-radius: 6px;
background: #1d1e2a;
background: color(display-p3 0.1138 0.1191 0.1616);
}
.permissionsHeader {
display: flex;
@@ -41,7 +24,6 @@
flex: 1 0 0;
color: #d2d3e1;
color: color(display-p3 0.8235 0.8275 0.8784);
font-family: Inter;
font-size: 20px;
font-style: normal;
@@ -58,21 +40,20 @@
gap: 5px;
border-radius: 6px;
background: #27293b;
background: color(display-p3 0.1529 0.1608 0.2275);
}
.svgContainer > div {
.svgContainer > button {
display: flex;
padding: 8px;
border: none;
justify-content: center;
align-items: center;
gap: 12px;
border-radius: 6px;
background: #27293b;
background: color(display-p3 0.1529 0.1608 0.2275);
}
.permissionDefaultState {
.wrapper {
display: flex;
height: 43.813px;
padding: 8px 16px;
@@ -80,6 +61,15 @@
align-items: center;
align-self: stretch;
}
.permissionDefaultState {
display: flex;
justify-content: center;
align-items: center;
gap: 12px;
flex: 1 0 0;
align-self: stretch;
}
.permissionDefaultState p {
display: flex;
justify-content: center;
@@ -88,7 +78,6 @@
flex: 1 0 0;
align-self: stretch;
color: #85869b;
color: color(display-p3 0.5216 0.5255 0.6);
font-family: Inter;
font-size: 16px;
font-style: normal;
@@ -104,13 +93,10 @@
align-items: center;
align-self: stretch;
border-bottom: 0.5px solid #2e3042;
border-bottom: 0.5px solid color(display-p3 0.1831 0.189 0.2535);
}
.permissions:hover {
border-bottom: 1px solid rgba(129, 135, 255, 0.25);
border-bottom: 1px solid color(display-p3 0.5098 0.5294 1 / 0.25);
background: rgba(129, 135, 255, 0.05);
background: color(display-p3 0.5098 0.5294 1 / 0.05);
}
.permissionsItem {
display: flex;
@@ -121,7 +107,6 @@
}
.permissionsItem > p {
color: #d2d3e1;
color: color(display-p3 0.8235 0.8275 0.8784);
font-family: Inter;
font-size: 16px;
font-style: normal;
@@ -151,35 +136,40 @@
stroke: color(display-p3 1 1 1);
border-radius: 100px;
border: 1px solid #959aff;
border: 1px solid color(display-p3 0.5892 0.6031 0.9766);
background: linear-gradient(180deg, #696b95 0%, #20202d 100%);
background: linear-gradient(
180deg,
color(display-p3 0.4118 0.4196 0.5725) 0%,
color(display-p3 0.1241 0.1265 0.1725) 100%
);
}
@media (max-width: 768px) {
.permissionsContainer {
border-radius: 4px;
padding: 0 0 24px 0;
}
.permissionsHeader {
padding: 12px 16px;
}
.permissionsHeader > p {
color: #fff;
font-size: 18px;
align-self: stretch;
}
.svgContainer {
display: none;
}
.wrapper {
display: flex;
padding: 24px 16px 0 16px;
align-items: flex-start;
align-self: stretch;
}
.permissionDefaultState {
display: flex;
height: 43.813px;
padding: 8px 16px;
justify-content: center;
align-items: center;
align-self: stretch;
}
.permissionDefaultState p {
display: flex;
justify-content: center;
align-items: center;
gap: 12px;
flex: 1 0 0;
align-self: stretch;
color: #85869b;
color: color(display-p3 0.5216 0.5255 0.6);
font-family: Inter;
font-size: 16px;
font-style: normal;
font-weight: 400;
line-height: normal;
}
.permissionDefaultState > p {
font-weight: 500;
text-align: center;
}
}

View File

@@ -9,37 +9,34 @@ import ViewIcon from "../components/icons/view";
import DeleteIcon from "../components/icons/delete";
import SuccessToast from "../components/toast/success/successToast";
import ActionButton from "../components/actionButton/ActionButton";
import MobileSearchBar from "../components/mobileSearchBar/MobileSearchBar";
import Card from "./role-card/Card";
const RolesPage = () => {
const router = useRouter();
const sampleData = [
{
id: 1,
name: "organization-owner",
orgId: "67160a5ae69144ff19aafb86",
permissions: "35 Permissions",
},
{
id: 2,
name: "organization-owner",
orgId: "67160a5ae69144ff19aafb86",
permissions: "35 Permissions",
},
{
id: 3,
name: "organization-owner",
orgId: "67160a5ae69144ff19aafb86",
permissions: "35 Permissions",
},
{
id: 4,
name: "organization-owner",
orgId: "67160a5ae69144ff19aafb86",
permissions: "35 Permissions",
},
{
id: 5,
name: "organization-owner",
orgId: "67160a5ae69144ff19aafb86",
permissions: "35 Permissions",
@@ -55,6 +52,21 @@ const RolesPage = () => {
topbarTitle="Roles"
requiredButtons={["title", "add", "search"]}
/>
{/* Mobile View */}
<div className={styles.cardContainer}>
<MobileSearchBar />
{sampleData.map((role, index) => {
return (
<Card
role={role}
key={index}
onClick={() => router.push(`/roles/${index}`)}
/>
);
})}
</div>
{/* Users Table */}
<div className={styles.tableContainer}>
<table className={styles.table}>
@@ -71,8 +83,8 @@ const RolesPage = () => {
//role or user?
return (
<tr
key={role.id}
onClick={() => router.push(`/roles/${role.id}`)}
key={index}
onClick={() => router.push(`/roles/${index}`)}
>
<td>{role.name}</td>
<td>{role.orgId}</td>

View File

@@ -1,5 +1,6 @@
import DeleteIcon from "@/app/components/icons/delete";
import React from "react";
import styles from "./styles.module.css";
const Card = (props) => {
return (
@@ -7,15 +8,15 @@ const Card = (props) => {
<div className={styles.cardDetails}>
<div className={styles.list}>
<p>Name</p>
<p>{props?.user?.email}</p>
<p>{props?.role?.name}</p>
</div>
<div className={styles.list}>
<p>Organization ID</p>
<p>{props?.user?.fullName}</p>
<p>{props?.role?.orgId}</p>
</div>
<div className={styles.list}>
<p>Permissions</p>
<p>{props?.user?.createdAt}</p>
<p>{props?.role?.permissions}</p>
</div>
</div>
<div className={styles.cardAction}>

View File

@@ -23,7 +23,7 @@
text-align: left;
color: #85869b;
font-family: Inter;
font-size: 13px;
font-size: var(--table-font-size);
font-style: normal;
flex: 1 0 0;
font-weight: 500;
@@ -41,7 +41,7 @@
padding: 12px 24px;
color: #eeeffd;
font-family: Inter;
font-size: 13px;
font-size: var(--table-font-size);
font-style: normal;
font-weight: 500;
line-height: normal;
@@ -65,7 +65,11 @@
align-self: stretch;
}
/* Mobile */
.cardContainer {
display: none;
}
@media (max-width: 768px) {
.cardContainer {
display: flex;
padding: 0 16px;
@@ -77,3 +81,7 @@
align-self: stretch;
overflow: auto;
}
.tableContainer {
display: none;
}
}

View File

@@ -1,5 +1,5 @@
"use client";
import React from "react";
import React, { useState } from "react";
import TopHeader from "@/app/components/topHeader/TopHeader";
import globalStyle from "../../globalStyle.module.css";
import addUserStyle from "./styles.module.css";
@@ -8,6 +8,8 @@ import SelectField from "@/app/components/select/SelectField";
import Permissions from "@/app/components/permissions/Permissions";
import useUserForm from "@/app/hooks/useUserForm";
import Alert from "@/app/components/alerts/Alert";
import Toggle from "@/app/components/mobileToggleTab/Toggle";
const AddUserPage = () => {
const {
register,
@@ -18,6 +20,9 @@ const AddUserPage = () => {
setTriggerAlert,
} = useUserForm();
// Mobile
const [activeTab, setActiveTab] = useState("details");
return (
<div className={globalStyle.section}>
{triggerAlert && (
@@ -36,18 +41,29 @@ const AddUserPage = () => {
state="add"
requiredButtons={["title", "save"]}
/>
<div className={addUserStyle.addUserContainer}>
{/* Mobile Toggle */}
<Toggle
activeTab={activeTab}
onChange={setActiveTab}
tabs={[
{ label: "User Details", value: "details" },
{ label: "Permissions", value: "permissions" },
]}
/>
{/* Input fields Container */}
<div className={addUserStyle.inputFieldContainer}>
{/* User Details */}
<div className={addUserStyle.userDetails}>
{/* Header */}
<div
className={`${addUserStyle.userDetails} ${activeTab !== "details" ? addUserStyle.hiddenMobile : ""}`}
>
<div className={addUserStyle.header}>
<div>
<p>User Details</p>
</div>
</div>
{/* Input fields */}
{/* Ibalhin ning form na tag */}
<form
className={addUserStyle.fields}
id="form"
@@ -68,11 +84,9 @@ const AddUserPage = () => {
{/* Email */}
<div className={addUserStyle.inputMainContainer}>
<div className={addUserStyle.inputContainer}>
{/* Label */}
<div className={addUserStyle.label}>
<p>Email</p>
</div>
{/* Input field */}
<div className={addUserStyle.inputField}>
<TextField
placeHolder="Enter email"
@@ -85,11 +99,9 @@ const AddUserPage = () => {
{/* Full Name */}
<div className={addUserStyle.inputMainContainer}>
<div className={addUserStyle.inputContainer}>
{/* Label */}
<div className={addUserStyle.label}>
<p>Full Name</p>
</div>
{/* Input field */}
<div className={addUserStyle.inputField}>
<TextField
placeHolder="Enter full name"
@@ -103,12 +115,17 @@ const AddUserPage = () => {
</div>
{/* Permissions */}
<div
className={`${addUserStyle.userPermissions} ${activeTab !== "permissions" ? addUserStyle.hiddenMobile : ""}`}
>
<div className={addUserStyle.imanginaryDiv}></div>
<Permissions />
</div>
</div>
</div>
</div>
</div>
</div>
);
};

View File

@@ -22,7 +22,22 @@
align-items: flex-start;
border-radius: 6px;
background: #1d1e2a;
background: color(display-p3 0.1137 0.1176 0.1608);
}
.imanginaryDiv {
padding: 18px;
}
.userPermissions {
display: flex;
flex-direction: column;
align-items: flex-start;
flex: 1 0 0;
align-self: stretch;
border-radius: 6px;
height: calc(100vh - 175px);
position: relative;
overflow: auto;
scrollbar-width: none;
}
.header {
display: flex;
@@ -42,7 +57,6 @@
.header > div > p {
width: 163px;
color: #d2d3e1;
color: color(display-p3 0.8235 0.8275 0.8784);
font-family: Inter;
font-size: 20px;
font-style: normal;
@@ -79,7 +93,6 @@
}
.label > p {
color: #d2d3e1;
color: color(display-p3 0.8235 0.8275 0.8784);
font-family: Inter;
font-size: 16px;
font-style: normal;
@@ -100,6 +113,33 @@
gap: 8px;
align-self: stretch;
}
.imanginaryDiv {
padding: 18px;
@media (max-width: 950px) {
.hiddenMobile {
display: none;
}
.addUserContainer {
align-self: stretch;
padding: 0 16px;
flex-direction: column;
gap: 16px;
}
.header {
display: none;
}
.userDetails {
background: none;
padding: 0px 0px 0px 0px;
margin-top: 16px;
}
.imanginaryDiv {
display: none;
}
}
@media (max-width: 768px) {
.userDetails {
background: none;
padding: 0px 0px 0px 0px;
width: 100%;
}
}

View File

@@ -22,7 +22,6 @@
text-align: left;
color: #85869b;
font-family: Inter;
font-size: var(--table-font-size);
font-style: normal;
flex: 1 0 0;
@@ -78,7 +77,6 @@
gap: 12px;
align-self: stretch;
overflow: auto;
background-color: red;
}
.tableContainer {
display: none;

View File

@@ -6,7 +6,6 @@
align-self: stretch;
border-bottom: 1px solid #2c2d3d;
cursor: pointer;
background-color: green;
}
.cardDetails {
display: flex;