forked from Navy.gif/webserver-framework-frontend
Update #2 - Electric Boogaloo #2
@ -1,29 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import '../css/components/Sidebar.css';
|
|
||||||
import NavLink from '../structures/NavLink';
|
|
||||||
|
|
||||||
const Sidebar = ({children}) => {
|
|
||||||
|
|
||||||
return <div className='sidebar'>
|
|
||||||
{children}
|
|
||||||
</div>;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
// Nav menu
|
|
||||||
const SidebarMenu = ({menuItems, children}) => {
|
|
||||||
|
|
||||||
let key = 0;
|
|
||||||
return <div className='sidebar-menu'>
|
|
||||||
{menuItems.map(link => {
|
|
||||||
const { label, ...rest } = link;
|
|
||||||
return <NavLink activeClassName='active' className='sidebar-menu-item' key={key++} {...rest}>{ label}</NavLink>;
|
|
||||||
})}
|
|
||||||
|
|
||||||
{children}
|
|
||||||
</div>;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
export {SidebarMenu, Sidebar};
|
|
||||||
export default Sidebar;
|
|
24
src/components/Table.js
Normal file
24
src/components/Table.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
export const TableListEntry = ({onClick, item, itemKeys}) => {
|
||||||
|
|
||||||
|
return <tr onClick={onClick} style={{cursor: 'pointer'}}>
|
||||||
|
{itemKeys.map(key => <td key={key}>{item[key]}</td>)}
|
||||||
|
</tr>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Table = ({headerItems, children, items, itemKeys, maxWidth = '30em'}) => {
|
||||||
|
|
||||||
|
let i = 0;
|
||||||
|
return <table className="striped" style={{ maxWidth, marginBottom: '10px' }}>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
{headerItems.map(item => <th key={item}>{item}</th>)}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{children ? children : items.map(item => <TableListEntry key={i++} item={item} itemKeys={itemKeys} />)}
|
||||||
|
</tbody>
|
||||||
|
</table>;
|
||||||
|
|
||||||
|
};
|
@ -3,6 +3,7 @@ import { Route, Routes, useNavigate, useParams } from "react-router";
|
|||||||
import ErrorBoundary from "../util/ErrorBoundary";
|
import ErrorBoundary from "../util/ErrorBoundary";
|
||||||
import { get } from '../util/Util';
|
import { get } from '../util/Util';
|
||||||
import '../css/pages/Users.css';
|
import '../css/pages/Users.css';
|
||||||
|
import { Table, TableListEntry } from "../components/Table";
|
||||||
|
|
||||||
const Permission = ({name, value}) => {
|
const Permission = ({name, value}) => {
|
||||||
return <li className="flex is-vertical-align">
|
return <li className="flex is-vertical-align">
|
||||||
@ -59,9 +60,19 @@ const Permissions = ({ perms }) => {
|
|||||||
</div>;
|
</div>;
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: Make generic table list component and use it here and the user list
|
|
||||||
const ApplicationList = ({ apps }) => {
|
const ApplicationList = ({ apps }) => {
|
||||||
|
|
||||||
|
const navigate = useNavigate();
|
||||||
|
return <Table headerItems={['Name', 'ID']}>
|
||||||
|
{apps.map(app => <TableListEntry
|
||||||
|
onClick={() => {
|
||||||
|
navigate(`${window.location.pathname}/applications/${app.id}`);
|
||||||
|
}}
|
||||||
|
key={app.id}
|
||||||
|
item={app}
|
||||||
|
itemKeys={['name', 'id']}
|
||||||
|
/>)}
|
||||||
|
</Table>;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -80,7 +91,14 @@ const User = ({ user }) => {
|
|||||||
const response = await get(`/api/users/${user._id}/applications`);
|
const response = await get(`/api/users/${user._id}/applications`);
|
||||||
if(response.status === 200) updateApps(response.data);
|
if(response.status === 200) updateApps(response.data);
|
||||||
})();
|
})();
|
||||||
}, [user]);
|
}, []);
|
||||||
|
|
||||||
|
const ApplicationWrapper = () => {
|
||||||
|
const { appid } = useParams();
|
||||||
|
const app = apps.find(a => a._id === appid);
|
||||||
|
if (!app) return null;
|
||||||
|
return <Application app={app} />;
|
||||||
|
};
|
||||||
|
|
||||||
return <div className='user-card'>
|
return <div className='user-card'>
|
||||||
|
|
||||||
@ -106,8 +124,9 @@ const User = ({ user }) => {
|
|||||||
<h4>Applications</h4>
|
<h4>Applications</h4>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path='/' element={<ApplicationList apps={apps} />} />
|
<Route path='/' element={<ApplicationList apps={apps} />} />
|
||||||
|
<Route path='/applications/:appid' element={<ApplicationWrapper />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
{apps.map(app => <Application key={app._id} app={app} />)}
|
{/* {apps.map(app => <Application key={app._id} app={app} />)} */}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -123,37 +142,37 @@ const User = ({ user }) => {
|
|||||||
</div>;
|
</div>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const UserListEntry = ({ user }) => {
|
// const UserListEntry = ({ user }) => {
|
||||||
|
|
||||||
const navigate = useNavigate();
|
// const navigate = useNavigate();
|
||||||
|
|
||||||
const onClick = () => {
|
// const onClick = () => {
|
||||||
navigate(`/users/${user._id}`);
|
// navigate(`/users/${user._id}`);
|
||||||
};
|
// };
|
||||||
|
|
||||||
return <tr onClick={onClick} style={{cursor: 'pointer'}}>
|
// return <tr onClick={onClick} style={{cursor: 'pointer'}}>
|
||||||
<td>{user.username}</td>
|
// <td>{user.username}</td>
|
||||||
<td>{user._id}</td>
|
// <td>{user._id}</td>
|
||||||
</tr>;
|
// </tr>;
|
||||||
|
|
||||||
};
|
// };
|
||||||
|
|
||||||
// TODO: Make table list generic component
|
// // TODO: Make table list generic component
|
||||||
const UserList = ({ users }) => {
|
// const UserList = ({ users }) => {
|
||||||
|
|
||||||
return <table className="striped" style={{maxWidth: '30em', marginBottom: '10px'}}>
|
// return <table className="striped" style={{maxWidth: '30em', marginBottom: '10px'}}>
|
||||||
<thead>
|
// <thead>
|
||||||
<tr>
|
// <tr>
|
||||||
<th>Username</th>
|
// <th>Username</th>
|
||||||
<th>ID</th>
|
// <th>ID</th>
|
||||||
</tr>
|
// </tr>
|
||||||
</thead>
|
// </thead>
|
||||||
<tbody>
|
// <tbody>
|
||||||
{users.map(user => <UserListEntry key={user._id} user={user} />)}
|
// {users.map(user => <UserListEntry key={user._id} user={user} />)}
|
||||||
</tbody>
|
// </tbody>
|
||||||
</table>;
|
// </table>;
|
||||||
|
|
||||||
};
|
// };
|
||||||
|
|
||||||
const Users = () => {
|
const Users = () => {
|
||||||
|
|
||||||
@ -178,9 +197,20 @@ const Users = () => {
|
|||||||
return <User user={user} />;
|
return <User user={user} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const navigate = useNavigate();
|
||||||
const UserListWrapper = () => {
|
const UserListWrapper = () => {
|
||||||
return <div className="user-list-wrapper">
|
return <div className="user-list-wrapper">
|
||||||
<UserList users={users} />
|
|
||||||
|
<Table headerItems={['Username', 'ID']}>
|
||||||
|
{users.map(user => <TableListEntry
|
||||||
|
onClick={() => {
|
||||||
|
navigate(`/users/${user._id}`);
|
||||||
|
}}
|
||||||
|
key={user._id}
|
||||||
|
item={user}
|
||||||
|
itemKeys={['username', '_id']} />)}
|
||||||
|
</Table>
|
||||||
|
|
||||||
<div className='flex is-vertical-align page-controls'>
|
<div className='flex is-vertical-align page-controls'>
|
||||||
<button className="col-1 button dark" onClick={() => setPage(page - 1 || 1)}>Previous</button>
|
<button className="col-1 button dark" onClick={() => setPage(page - 1 || 1)}>Previous</button>
|
||||||
<p>Page: {page}</p>
|
<p>Page: {page}</p>
|
||||||
@ -188,6 +218,7 @@ const Users = () => {
|
|||||||
if (users.length === 10) setPage(page + 1);
|
if (users.length === 10) setPage(page + 1);
|
||||||
}}>Next</button>
|
}}>Next</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>;
|
</div>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user