making frontend responsive starting item backend routes

This commit is contained in:
2022-03-30 22:57:38 -04:00
parent 1bed72250d
commit a70baddc4b
17 changed files with 909 additions and 242 deletions

View File

@@ -4,7 +4,7 @@ import HomePage from './components/pages/HomePage';
import Locations from './components/pages/Locations';
import RoomsPage from './components/pages/RoomsPage';
import { Routes, Route, useNavigate } from "react-router-dom";
import { Modal, Button, Text, Group, TextInput, Loader, AppShell } from '@mantine/core';
import { Modal, Button, Text, Group, TextInput, Loader, AppShell, MediaQuery } from '@mantine/core';
import { useDebouncedValue, useLocalStorageValue } from '@mantine/hooks';
import { useNotifications } from '@mantine/notifications';
@@ -20,13 +20,12 @@ import AppHeader from './components/AppHeader';
function App() {
// Main nav/sidebar appshell openend
const [shellOpened, setShellOpened] = useState(false)
const [isLoading, setIsLoading] = useState(true)
const [, setServerConfig] = useAtom(serverConfigAtom)
const notifications = useNotifications();
const navigate = useNavigate();
// const navigate = useNavigate();
@@ -61,28 +60,13 @@ function App() {
}, [])
// function showPage() {
// switch (currentPage.path) {
// case "home":
// return <HomePage />
// case "locations":
// console.log("RETURNING LOCATIONS: ", currentPage)
// return <Locations setCurrentPage={setCurrentPage} id={currentPage.id}/>
// case "rooms":
// console.log("RETURNING ROOMS: ", currentPage)
// return <RoomsPage setCurrentPage={setCurrentPage} id={currentPage.id} />
// default:
// break;
// }
// }
return (
<AppShell
navbarOffsetBreakpoint="sm" // navbarOffsetBreakpoint controls when navbar should no longer be offset with padding-left
fixed // fixed prop on AppShell will be automatically added to Header and Navbar
navbar={<SideBar opened={shellOpened} />}
header={<AppHeader opened={shellOpened} setOpened={setShellOpened}/>}
navbar={<SideBar />}
header={<AppHeader />}
>
<Routes>
<Route path="/" element={<HomePage />} />

View File

@@ -1,22 +1,23 @@
import React, {useState, useEffect, useContext } from 'react';
import { Header, MediaQuery, Burger, Text, ThemeIcon, Group, Title } from '@mantine/core';
import { useMantineTheme } from '@mantine/core';
import { useAtom } from 'jotai';
import { Header, MediaQuery, Burger, Text, ThemeIcon, Group, Title, createStyles, useMantineTheme } from '@mantine/core';
import { BsHouseDoor } from 'react-icons/bs'
import { menuOpenedAtom } from '../state/main';
function AppHeader(props) {
const theme = useMantineTheme();
const theme = useMantineTheme()
const [menuOpened, setMenuOpened] = useAtom(menuOpenedAtom)
return (
<Header height={70} padding="md">
{/* You can handle other responsive styles with MediaQuery component or createStyles function */}
<div style={{ display: 'flex', alignItems: 'center', height: '100%' }}>
<MediaQuery smallerThan="sm" styles={{ display: 'none' }}>
<MediaQuery largerThan="sm" styles={{ display: 'none' }}>
<Burger
opened={props.opened}
onClick={() => props.setOpened((o) => !o)}
opened={menuOpened}
onClick={() => setMenuOpened((o) => !o)}
size="sm"
color={theme.colors.gray[6]}
mr="xl"

View File

@@ -1,7 +1,7 @@
import React, {useState } from 'react';
import { useAtom } from 'jotai';
import { activePageAtom, roomFilterAtom } from '../state/main';
import { Navbar, Group, Code, ScrollArea, createStyles } from '@mantine/core';
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';
@@ -80,6 +80,8 @@ const useStyles = createStyles((theme) => ({
function SideBar(props) {
const { classes } = useStyles();
const [menuOpened] = useAtom(menuOpenedAtom)
@@ -88,51 +90,31 @@ function SideBar(props) {
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> */}
<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>
// <Navbar
// padding="md"
// // Breakpoint at which navbar will be hidden if hidden prop is true
// hiddenBreakpoint="sm"
// // Hides navbar when viewport size is less than value specified in hiddenBreakpoint
// hidden={!props.opened}
// width={{ base: 200, breakpoints: { sm: '100%', lg: 300 } }}
// >
// <Button leftIcon={<BsMap />} variant="white" className={activePage === "locations" ? classes.activeButton : classes.button} component={Link} to="/locations" onClick={() => setActivePage("locations")} >
// Locations
// </Button>
// <Button leftIcon={<BsMap />} variant="white" className={activePage === "rooms" ? classes.activeButton : classes.button} component={Link} to="/rooms" onClick={() => setActivePage("rooms")} >
// Rooms
// </Button>
// {/* <UnstyledButton component={Link} to="/rooms" className={activePage === "rooms" ? classes.activeButton : classes.button} onClick={() => changeView("rooms")} >
// <Group>
// <BsMap />
// <Text>Rooms</Text>
// </Group>
// </UnstyledButton> */}
// </Navbar>
<>
<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>
</>
)
}

View File

@@ -52,31 +52,50 @@ function LocationsPage(props) {
navigate("/rooms")
}
const setRoomNumber = (location) => {
if (location.Rooms === null) {
return <Text>0 Rooms</Text>
} else if (location.Rooms.length > 1) {
return <Text>{location.Rooms.length} Rooms</Text>
} else {
return <Text>1 Room</Text>
}
}
return (
<>
<Center>{ isLoading && <Loader size="xl" variant="bars" />}</Center>
<Center><Title order={1}>Locations</Title></Center>
<SimpleGrid cols={4} spacing="xl">
{ locations.map((location, idx) =>
<Card key={`${idx} - ${location.ID}`} shadow="md" padding="md">
<Card.Section>
{location.CoverPhoto ? <Image src={`${serverConfig.baseURL}/photos/locations/${location.Name}/${location.CoverPhoto}`}></Image> : <Text>No Photo</Text>}
</Card.Section>
<Group position="apart">
<Text weight={500}>{location.Name}</Text>
<Badge variant="light">
{ location.Rooms !== null && location.Rooms.length !== 0 && location.Rooms.length > 1 ? <Text>{location.Rooms.length} Rooms</Text> : <Text>{location.Rooms.length} Room</Text>}
</Badge>
</Group>
<Text size="sm">{location.Description}</Text>
<Group>
<Button onClick={() => navigateToRooms(location.ID, location.Name)}>View Details</Button>
<Button onClick={() => navigateToRooms(location.ID, location.Name)}>View Rooms</Button>
</Group>
<SimpleGrid
spacing="md"
cols={4}
breakpoints={[
{ maxWidth: 'sm', cols: 1, spacing: 'md'},
{ maxWidth: 'md', cols: 3, spacing: "sm"},
{ maxWidth: 'lg', cols: 4, spacing: 'md'}
]}
>
{ locations.map((location, idx) =>
<Card key={`${idx} - ${location.ID}`} shadow="md" padding="md">
<Card.Section>
{location.CoverPhoto ? <Image src={`${serverConfig.baseURL}/photos/locations/${location.Name}/${location.CoverPhoto}`}></Image> : <Text>No Photo</Text>}
</Card.Section>
<Group position="apart">
<Text weight={500}>{location.Name}</Text>
<Badge variant="light">
{ setRoomNumber(location) }
</Badge>
</Group>
<Text size="sm">{location.Description}</Text>
<Group>
<Button onClick={() => navigateToRooms(location.ID, location.Name)}>View Details</Button>
<Button onClick={() => navigateToRooms(location.ID, location.Name)}>View Rooms</Button>
</Group>
</Card>
)}
</Card>
)}
</SimpleGrid>
</>

View File

@@ -73,7 +73,15 @@ function RoomsPage(props) {
</Badge>
}
<SimpleGrid cols={4} spacing="xl">
<SimpleGrid
spacing="md"
cols={4}
breakpoints={[
{ maxWidth: 'sm', cols: 1, spacing: 'md'},
{ maxWidth: 'md', cols: 3, spacing: "sm"},
{ maxWidth: 'lg', cols: 4, spacing: 'md'}
]}
>
{ rooms.map((room, idx) =>
<Card key={`${room.ID}`} component="a" onClick={(e) => {}} shadow="sm" padding="md">
<Card.Section>

View File

@@ -1,8 +1,9 @@
import React, { useState } from 'react';
import { Group, Box, Collapse, ThemeIcon, Text, UnstyledButton, createStyles } from '@mantine/core';
import { useMediaQuery } from '@mantine/hooks';
import { BiChevronLeft, BiChevronRight } from 'react-icons/bi';
import { useAtom } from 'jotai';
import { activePageAtom, roomFilterAtom } from '../../state/main';
import { activePageAtom, menuOpenedAtom, roomFilterAtom } from '../../state/main';
import { Link } from 'react-router-dom';
@@ -35,12 +36,13 @@ const useStyles = createStyles((theme) => ({
}`,
'&:hover': {
backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[7] : theme.colors.gray[0],
backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[7] : theme.colors.gray[1],
color: theme.colorScheme === 'dark' ? theme.white : theme.black,
},
'&:active': {
backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[7] : theme.colors.gray[6]
}
},
activeLink: {
backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[7] : theme.colors.gray[3],
},
chevron: {
@@ -51,12 +53,17 @@ const useStyles = createStyles((theme) => ({
export function LinksGroup(props) {
const { icon: Icon, label, initiallyOpened, links } = props
const { classes, theme } = useStyles();
const isMobile = useMediaQuery('(max-width: 768px)')
const hasLinks = Array.isArray(links);
const [opened, setOpened] = useState(initiallyOpened || false);
// Navigation State
const [activePage, setActivePage] = useAtom(activePageAtom)
const [roomFilter, setRoomFilter] = useAtom(roomFilterAtom)
const [menuOpened, setMenuOpened] = useAtom(menuOpenedAtom)
const { classes, theme, cx } = useStyles();
const ChevronIcon = theme.dir === 'ltr' ? BiChevronRight : BiChevronLeft;
@@ -66,6 +73,9 @@ export function LinksGroup(props) {
setRoomFilter({})
}
console.log("navigate to: ", location)
if (isMobile && menuOpened) {
setMenuOpened(false)
}
setActivePage(location)
}
@@ -75,11 +85,10 @@ export function LinksGroup(props) {
<>
<Link
component={Link}
className={activePage === label.toLowerCase() ? classes.link : classes.link}
className={activePage === link.label.toLowerCase() ? cx(classes.link, classes.activeLink) : classes.link}
to={link.link}
// href={link.link}
key={link.label}
onClick={(e) => {navigate(e, label.toLowerCase())}}
onClick={(e) => {navigate(e, link.label.toLowerCase())}}
>
{link.label}
</Link>

View File

@@ -3,6 +3,9 @@ import { atom } from 'jotai'
export const serverConfigAtom = atom({})
// Size and menu handling
export const menuOpenedAtom = atom(false)
// Pages state
export const activePageAtom = atom({})