redoing frontend

This commit is contained in:
2022-07-28 22:56:28 -04:00
parent 55df431241
commit bd6319b6b1
7 changed files with 1003 additions and 802 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -3,26 +3,32 @@
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@mantine/core": "^4.1.2", "@emotion/cache": "^11.9.3",
"@mantine/dates": "^4.1.1", "@emotion/react": "^11.9.3",
"@mantine/dropzone": "^4.1.2", "@emotion/serialize": "^1.0.4",
"@mantine/form": "^4.1.1", "@emotion/utils": "^1.1.0",
"@mantine/hooks": "^4.1.2", "@mantine/core": "^5.0.0",
"@mantine/notifications": "^4.1.0", "@mantine/dates": "^5.0.0",
"@testing-library/jest-dom": "^5.16.3", "@mantine/dropzone": "^5.0.0",
"@testing-library/react": "^12.1.4", "@mantine/form": "^5.0.0",
"@mantine/hooks": "^5.0.0",
"@mantine/notifications": "^5.0.0",
"@tabler/icons": "^1.78.1",
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^12.1.5",
"@testing-library/user-event": "^13.5.0", "@testing-library/user-event": "^13.5.0",
"base-64": "^1.0.0", "base-64": "^1.0.0",
"dayjs": "^1.11.0", "dayjs": "^1.11.4",
"jotai": "^1.6.1", "jotai": "^1.7.6",
"npm-check-updates": "^12.5.4", "npm-check-updates": "^12.5.12",
"react": "^17.0.2", "react": "^17.0.2",
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
"react-icons": "^4.3.1", "react-icons": "^4.4.0",
"react-jss": "^10.9.0", "react-jss": "^10.9.1",
"react-router": "^6.2.2", "react-router": "^6.3.0",
"react-router-dom": "^6.2.2", "react-router-dom": "^6.3.0",
"react-scripts": "5.0.0", "react-scripts": "5.0.0",
"tabler-icons": "^1.35.0",
"web-vitals": "^2.1.4" "web-vitals": "^2.1.4"
}, },
"scripts": { "scripts": {

View File

@@ -4,7 +4,8 @@ import HomePage from './components/pages/HomePage';
import LocationsPage from './components/pages/LocationsPage'; import LocationsPage from './components/pages/LocationsPage';
import RoomsPage from './components/pages/RoomsPage'; import RoomsPage from './components/pages/RoomsPage';
import LocationForm from './components/forms/LocationForm' import LocationForm from './components/forms/LocationForm'
import { Routes, Route, useNavigate } from "react-router-dom"; import NotFound from './components/pages/NotFound';
import { BrowserRouter as Router, Routes, Route} from 'react-router-dom'
import { Modal, Button, Text, Group, TextInput, Loader, AppShell, MediaQuery } from '@mantine/core'; import { Modal, Button, Text, Group, TextInput, Loader, AppShell, MediaQuery } from '@mantine/core';
import { useDebouncedValue, useLocalStorageValue } from '@mantine/hooks'; import { useDebouncedValue, useLocalStorageValue } from '@mantine/hooks';
import { useNotifications } from '@mantine/notifications'; import { useNotifications } from '@mantine/notifications';
@@ -64,21 +65,27 @@ function App() {
return ( return (
<AppShell <Router>
navbarOffsetBreakpoint="sm" // navbarOffsetBreakpoint controls when navbar should no longer be offset with padding-left <AppShell
fixed // fixed prop on AppShell will be automatically added to Header and Navbar navbarOffsetBreakpoint="sm" // navbarOffsetBreakpoint controls when navbar should no longer be offset with padding-left
navbar={<SideBar />} fixed // fixed prop on AppShell will be automatically added to Header and Navbar
header={<AppHeader />} navbar={<SideBar />}
> header={<AppHeader />}
<Routes> >
<Route exact path="/" element={<HomePage />} /> <Routes>
<Route exact path="locations" element={<LocationsPage />} /> <Route path='*' element={<NotFound />} />
<Route exact path="location/:id" element={<LocationDetailsPage />} /> <Route index element={<HomePage />} />
<Route exact path="rooms" element={<RoomsPage />} /> <Route path="locations">
<Route exact path="locations/new" element={<LocationForm />} /> <Route index element={<LocationsPage />} />
<Route path=":id" element={<LocationDetailsPage />} />
</Routes> <Route path="new" element={<LocationForm />} />
</AppShell> </Route>
<Route path="rooms">
<Route index element={<RoomsPage />} />
</Route>
</Routes>
</AppShell>
</Router>
); );
} }

View File

@@ -1,123 +1,99 @@
import React, {useState } from 'react'; import { Navbar, ScrollArea, createStyles } from '@mantine/core';
import { useAtom } from 'jotai';
import { activePageAtom, menuOpenedAtom, roomFilterAtom } from '../state/main';
import { Navbar, Group, ScrollArea, createStyles, MediaQuery } from '@mantine/core';
import { LinksGroup } from './sidebar/SidebarLinksGroup';
// import { UserButton } from './sidebar/UserButton';
import { Link } from 'react-router-dom';
import { GoLocation, GoDashboard, GoGear } from 'react-icons/go' import { GoLocation, GoDashboard, GoGear } from 'react-icons/go'
import { BsDoorClosed, BsDiagram2 } from 'react-icons/bs' import { BsDoorClosed, BsDiagram2 } from 'react-icons/bs'
import { BiCabinet } from 'react-icons/bi' import { BiCabinet } from 'react-icons/bi'
import { LinksGroup } from './sidebar/SidebarLinksGroup';
const sideBarData = [
{ label: 'Dashboard', icon: GoDashboard, link: {label: 'Dashboard', link: '/'}},
{
label: 'Locations',
icon: GoLocation,
initiallyOpened: true,
links: [
{ label: 'View Locations', link: '/locations' },
{ label: 'Add New Location', link: '/locations/new' },
{ label: 'Outlook', link: '/' },
{ label: 'Real time', link: '/' },
],
},
{
label: 'Rooms',
icon: BsDoorClosed,
initiallyOpened: true,
links: [
{ label: 'View Rooms', link: '/rooms' },
{ label: 'Add New Room', link: '/rooms/new' },
{ label: 'Releases schedule', link: '/'},
],
},
{ label: 'Cabinets', icon: BiCabinet, link: "/" },
{ label: 'Items', icon: BsDiagram2, link: "/" },
{ label: 'Settings', icon: GoGear, link: '/' },
];
const useStyles = createStyles((theme) => ({ const useStyles = createStyles((theme) => ({
navbar: { navbar: {
backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[6] : theme.white, backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[6] : theme.white,
paddingBottom: 0, paddingBottom: 0,
}, },
header: { header: {
padding: theme.spacing.md, padding: theme.spacing.md,
paddingTop: 0, paddingTop: 0,
marginLeft: -theme.spacing.md, marginLeft: -theme.spacing.md,
marginRight: -theme.spacing.md, marginRight: -theme.spacing.md,
color: theme.colorScheme === 'dark' ? theme.white : theme.black, color: theme.colorScheme === 'dark' ? theme.white : theme.black,
borderBottom: `1px solid ${ borderBottom: `1px solid ${
theme.colorScheme === 'dark' ? theme.colors.dark[4] : theme.colors.gray[3] theme.colorScheme === 'dark' ? theme.colors.dark[4] : theme.colors.gray[3]
}`, }`,
}, },
links: { links: {
marginLeft: -theme.spacing.md, marginLeft: -theme.spacing.md,
marginRight: -theme.spacing.md, marginRight: -theme.spacing.md,
}, },
linksInner: { linksInner: {
paddingTop: theme.spacing.xl, paddingTop: theme.spacing.xl,
paddingBottom: theme.spacing.xl, paddingBottom: theme.spacing.xl,
}, },
footer: { footer: {
marginLeft: -theme.spacing.md, marginLeft: -theme.spacing.md,
marginRight: -theme.spacing.md, marginRight: -theme.spacing.md,
borderTop: `1px solid ${ borderTop: `1px solid ${
theme.colorScheme === 'dark' ? theme.colors.dark[4] : theme.colors.gray[3] theme.colorScheme === 'dark' ? theme.colors.dark[4] : theme.colors.gray[3]
}`, }`,
}, },
})); }));
export function SideBar() {
const { classes } = useStyles();
const links = sideBarData.map((item) => <LinksGroup {...item} key={item.label} />);
return (
<Navbar height={800} width={{ sm: 300 }} p="md" className={classes.navbar}>
{/* <Navbar.Section className={classes.header}>
<Group position="apart">
<Logo width={120} />
<Code sx={{ fontWeight: 700 }}>v3.1.2</Code>
</Group>
</Navbar.Section> */}
const sideBarData = [ <Navbar.Section grow className={classes.links} component={ScrollArea}>
{ label: 'Dashboard', icon: GoDashboard, link: {label: 'Dashboard', link: '/'}}, <div className={classes.linksInner}>{links}</div>
{ </Navbar.Section>
label: 'Locations',
icon: GoLocation,
initiallyOpened: true,
links: [
{ label: 'View Locations', link: '/locations' },
{ label: 'Add New Location', link: '/locations/new' },
{ label: 'Outlook', link: '/' },
{ label: 'Real time', link: '/' },
],
},
{
label: 'Rooms',
icon: BsDoorClosed,
initiallyOpened: true,
links: [
{ label: 'View Rooms', link: '/rooms' },
{ label: 'Add New Room', link: '/rooms/new' },
{ label: 'Releases schedule', link: '/' },
],
},
{ label: 'Cabinets', icon: BiCabinet },
{ label: 'Items', icon: BsDiagram2 },
{ label: 'Settings', icon: GoGear },
];
{/* <Navbar.Section className={classes.footer}>
function SideBar(props) { <UserButton
const { classes } = useStyles(); image="https://images.unsplash.com/photo-1508214751196-bcfd4ca60f91?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=255&q=80"
name="Ann Nullpointer"
const [menuOpened] = useAtom(menuOpenedAtom) email="anullpointer@yahoo.com"
/>
</Navbar.Section> */}
</Navbar>
);
const links = sideBarData.map((item) => <LinksGroup {...item} key={item.label} />);
return (
<>
<MediaQuery smallerThan="md" styles={!menuOpened && { 'display': 'none'}}>
<Navbar height={800} width={{ sm: 300 }} p="md" className={classes.navbar}>
{/* <Navbar.Section className={classes.header}>
<Group position="apart">
<Logo width={120} />
<Code sx={{ fontWeight: 700 }}>v3.1.2</Code>
</Group>
</Navbar.Section> */}
<Navbar.Section grow className={classes.links} component={ScrollArea}>
<div className={classes.linksInner}>{links}</div>
</Navbar.Section>
{/* <Navbar.Section className={classes.footer}>
<UserButton
image="https://images.unsplash.com/photo-1508214751196-bcfd4ca60f91?ixid=MXwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=255&q=80"
name="Ann Nullpointer"
email="anullpointer@yahoo.com"
/>
</Navbar.Section> */}
</Navbar>
</MediaQuery>
</>
)
} }
export default SideBar
export default SideBar

View File

@@ -0,0 +1,20 @@
import { Title, Text, Center } from '@mantine/core';
function NotFound() {
return (
<>
<Center>
<Title>Page Not Found!</Title>
</Center>
<Text>The page you are looking for does not exist!</Text>
</>
);
}
export default NotFound

View File

@@ -1,153 +1,124 @@
import React, { useState } from 'react'; import { useEffect, useState } from 'react';
import { Group, Box, Collapse, ThemeIcon, UnstyledButton, createStyles } from '@mantine/core'; import { Group, Box, Collapse, ThemeIcon, Text, UnstyledButton, createStyles } from '@mantine/core';
import { useMediaQuery } from '@mantine/hooks';
import { BiChevronLeft, BiChevronRight } from 'react-icons/bi'; import { BiChevronLeft, BiChevronRight } from 'react-icons/bi';
import { useAtom } from 'jotai'; import { NavLink, useLocation } from 'react-router-dom';
import { activePageAtom, menuOpenedAtom, roomFilterAtom } from '../../state/main';
import { Link } from 'react-router-dom';
const useStyles = createStyles((theme, _params, getRef) => {
const icon = getRef('icon');
return {
control: {
fontWeight: 500,
display: 'block',
width: '100%',
padding: `${theme.spacing.xs}px ${theme.spacing.md}px`,
color: theme.colorScheme === 'dark' ? theme.colors.dark[0] : theme.black,
fontSize: theme.fontSizes.sm,
const useStyles = createStyles((theme) => ({ '&:hover': {
control: { backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[7] : theme.colors.gray[0],
fontWeight: 500, color: theme.colorScheme === 'dark' ? theme.white : theme.black,
display: 'block', },
width: '100%',
padding: `${theme.spacing.xs}px ${theme.spacing.md}px`,
color: theme.colorScheme === 'dark' ? theme.colors.dark[0] : theme.black,
fontSize: theme.fontSizes.sm,
'&:hover': {
backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[7] : theme.colors.gray[0],
color: theme.colorScheme === 'dark' ? theme.white : theme.black,
}, },
},
link: { link: {
fontWeight: 500, fontWeight: 500,
display: 'block', display: 'block',
textDecoration: 'none', textDecoration: 'none',
padding: `${theme.spacing.xs}px ${theme.spacing.md}px`, padding: `${theme.spacing.xs}px ${theme.spacing.md}px`,
paddingLeft: 31, paddingLeft: 31,
marginLeft: 30, marginLeft: 30,
fontSize: theme.fontSizes.sm, fontSize: theme.fontSizes.sm,
color: theme.colorScheme === 'dark' ? theme.colors.dark[0] : theme.colors.gray[7], color: theme.colorScheme === 'dark' ? theme.colors.dark[0] : theme.colors.gray[7],
borderLeft: `1px solid ${ borderLeft: `1px solid ${
theme.colorScheme === 'dark' ? theme.colors.dark[4] : theme.colors.gray[3] theme.colorScheme === 'dark' ? theme.colors.dark[4] : theme.colors.gray[3]
}`, }`,
'&:hover': { '&:hover': {
backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[7] : theme.colors.gray[1], backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[7] : theme.colors.gray[0],
color: theme.colorScheme === 'dark' ? theme.white : theme.black, color: theme.colorScheme === 'dark' ? theme.white : theme.black,
},
}, },
},
activeLink: { linkActive: {
backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[7] : theme.colors.gray[3], '&, &:hover': {
}, backgroundColor:
theme.colorScheme === 'dark'
? theme.fn.rgba(theme.colors[theme.primaryColor][8], 0.25)
: theme.colors[theme.primaryColor][0],
color: theme.colorScheme === 'dark' ? theme.white : theme.colors[theme.primaryColor][7],
[`& .${icon}`]: {
color: theme.colors[theme.primaryColor][theme.colorScheme === 'dark' ? 5 : 7],
},
},
},
chevron: { chevron: {
transition: 'transform 200ms ease', transition: 'transform 200ms ease',
}, },
})); }});
export function LinksGroup(props) {
const { icon: Icon, label, initiallyOpened, links, link } = props
const isMobile = useMediaQuery('(max-width: 768px)')
const hasLinks = Array.isArray(links);
const hasLink = (typeof link === "object")
const [opened, setOpened] = useState(initiallyOpened || false);
// Navigation State
const [activePage, setActivePage] = useAtom(activePageAtom)
const [roomFilter, setRoomFilter] = useAtom(roomFilterAtom)
const [menuOpened, setMenuOpened] = useAtom(menuOpenedAtom)
export function LinksGroup({ icon: Icon, label, initiallyOpened, links }) {
const mypath = useLocation()
const { classes, theme, cx } = useStyles(); const { classes, theme, cx } = useStyles();
const hasLinks = Array.isArray(links);
const [opened, setOpened] = useState(initiallyOpened || false);
const ChevronIcon = theme.dir === 'ltr' ? BiChevronRight : BiChevronLeft; const ChevronIcon = theme.dir === 'ltr' ? BiChevronRight : BiChevronLeft;
const navigate = (location) => {
// event.preventDefault()
if (location === "rooms") {
setRoomFilter({})
}
console.log("navigate to: ", location)
if (isMobile && menuOpened) {
setMenuOpened(false)
}
setActivePage(location)
}
const items = (hasLinks ? links : []).map((link) => ( const items = (hasLinks ? links : []).map((link) => (
<> // <Text>{link.link}</Text>
<Link
component={Link} <NavLink
className={activePage === link.label.toLowerCase() ? cx(classes.link, classes.activeLink) : classes.link} className={({ isActive}) => (cx(classes.link, {[classes.linkActive]: isActive === true}))}
to={link.link} key={link.label}
key={link.label} to={link.link}
onClick={() => {navigate(link.label.toLowerCase())}} >
> {link.label}
{link.label} </NavLink>
</Link>
</>
)); ));
const buttonContents = () => { useEffect(() => {
return ( console.log("MYPATH: ", mypath)
<Group position="apart" spacing={0}> }, [])
<Box sx={{ display: 'flex', alignItems: 'center' }}>
<ThemeIcon variant="light" size={30}>
<Icon size={18} />
</ThemeIcon>
<Box ml="md">{label}</Box>
</Box>
{hasLinks && (
<ChevronIcon
className={classes.chevron}
size={14}
style={{
transform: opened ? `rotate(${theme.dir === 'rtl' ? -90 : 90}deg)` : 'none',
}}
/>
)}
</Group>
)
}
const myButton = () => {
if (hasLink) {
return (
<UnstyledButton
onClick={hasLinks ? () => setOpened((o) => !o) : () => navigate(link.label.toLowerCase())}
className={activePage === link.label.toLowerCase() ? cx(classes.control, classes.activeLink) : classes.control}
component={Link}
to={link.link}
key={link.label}
>
{buttonContents()}
</UnstyledButton>
)
} else {
return (
<UnstyledButton
onClick={() => setOpened((o) => !o)}
className={classes.control}
>
{buttonContents()}
</UnstyledButton>
)
}
}
return ( return (
<> <>
{myButton()} <UnstyledButton onClick={() => setOpened((o) => !o)} className={classes.control}>
<Group position="apart" spacing={0}>
<Box sx={{ display: 'flex', alignItems: 'center' }}>
<ThemeIcon variant="light" size={30}>
<Icon size={18} />
</ThemeIcon>
<Box ml="md">{label}</Box>
</Box>
{hasLinks && (
<ChevronIcon
className={classes.chevron}
size={14}
stroke={1.5}
style={{
transform: opened ? `rotate(${theme.dir === 'rtl' ? -90 : 90}deg)` : 'none',
}}
/>
)}
</Group>
</UnstyledButton>
{hasLinks ? <Collapse in={opened}>{items}</Collapse> : null} {hasLinks ? <Collapse in={opened}>{items}</Collapse> : null}
</> </>
);
}
)
export function NavbarLinksGroup(data) {
return (
<Box
sx={(theme) => ({
minHeight: 220,
padding: theme.spacing.md,
backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[6] : theme.white,
})}
>
<LinksGroup {...data} />
</Box>
);
} }

View File

@@ -3,7 +3,6 @@ import ReactDOM from 'react-dom';
import App from './App'; import App from './App';
import reportWebVitals from './reportWebVitals'; import reportWebVitals from './reportWebVitals';
import { NotificationsProvider } from '@mantine/notifications'; import { NotificationsProvider } from '@mantine/notifications';
import { BrowserRouter } from 'react-router-dom';
//setup api //setup api
//const backendPort = process.env.REACT_APP_BACKEND_PORT //const backendPort = process.env.REACT_APP_BACKEND_PORT
@@ -11,10 +10,8 @@ import { BrowserRouter } from 'react-router-dom';
ReactDOM.render( ReactDOM.render(
<React.StrictMode> <React.StrictMode>
<NotificationsProvider> <NotificationsProvider>
<BrowserRouter>
<App /> <App />
</BrowserRouter>
</NotificationsProvider> </NotificationsProvider>
</React.StrictMode>, </React.StrictMode>,
document.getElementById('root') document.getElementById('root')