working on view location details page

This commit is contained in:
2022-04-11 22:41:14 -04:00
parent c79dc69bb0
commit 55df431241
28 changed files with 549 additions and 346 deletions

View File

@@ -1,7 +1,7 @@
import React, {useState, useEffect } from 'react';
import { useAtom } from 'jotai';
import HomePage from './components/pages/HomePage';
import Locations from './components/pages/Locations';
import LocationsPage from './components/pages/LocationsPage';
import RoomsPage from './components/pages/RoomsPage';
import LocationForm from './components/forms/LocationForm'
import { Routes, Route, useNavigate } from "react-router-dom";
@@ -16,6 +16,7 @@ import { serverConfigAtom } from './state/main'
import SideBar from './components/SideBar';
import AppHeader from './components/AppHeader';
import LocationDetailsPage from './components/pages/LocationDetailsPage';
@@ -70,10 +71,11 @@ function App() {
header={<AppHeader />}
>
<Routes>
<Route path="/" element={<HomePage />} />
<Route path="locations" element={<Locations />} />
<Route path="rooms" element={<RoomsPage />} />
<Route path="locations/new" element={<LocationForm />} />
<Route exact path="/" element={<HomePage />} />
<Route exact path="locations" element={<LocationsPage />} />
<Route exact path="location/:id" element={<LocationDetailsPage />} />
<Route exact path="rooms" element={<RoomsPage />} />
<Route exact path="locations/new" element={<LocationForm />} />
</Routes>
</AppShell>

View File

@@ -49,7 +49,7 @@ const useStyles = createStyles((theme) => ({
const sideBarData = [
{ label: 'Dashboard', icon: GoDashboard },
{ label: 'Dashboard', icon: GoDashboard, link: {label: 'Dashboard', link: '/'}},
{
label: 'Locations',
icon: GoLocation,
@@ -99,10 +99,10 @@ function SideBar(props) {
<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 grow className={classes.links} component={ScrollArea}>
<div className={classes.linksInner}>{links}</div>
</Navbar.Section>
{/* <Navbar.Section className={classes.footer}>
<UserButton
@@ -111,7 +111,7 @@ function SideBar(props) {
email="anullpointer@yahoo.com"
/>
</Navbar.Section> */}
</Navbar>
</Navbar>
</MediaQuery>
</>

View File

@@ -3,6 +3,7 @@ import { Text, Button, Card, Group, Menu, Image, Badge } from '@mantine/core'
import { useAtom } from 'jotai';
import { useNavigate } from "react-router-dom";
import { activePageAtom, roomFilterAtom, serverConfigAtom } from '../../state/main';
import { Link } from 'react-router-dom';
@@ -34,7 +35,7 @@ function LocationCard(props) {
return (
<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>}
{location.CoverPhoto ? <Image src={`${serverConfig.baseURL}/files/locations/${location.Name}/${location.CoverPhoto}`}></Image> : <Text>No Photo</Text>}
<Group position='right' style={{position: 'absolute', top: '5px', right: '5px', backgroundColor: 'grey', borderRadius: '25%'}}>
<Menu>
<Menu.Label>Edit</Menu.Label>
@@ -51,7 +52,7 @@ function LocationCard(props) {
</Group>
<Text size="sm">{location.Description}</Text>
<Group>
<Button onClick={() => navigateToRooms(location.ID, location.Name)}>View Details</Button>
<Button component={Link} to={`/location/${location.ID}`} state={{ location: location }}>View Details</Button>
<Button onClick={() => navigateToRooms(location.ID, location.Name)}>View Rooms</Button>
</Group>
</Card>

View File

@@ -34,7 +34,7 @@ function RoomCard(props) {
return (
<Card key={`${idx} - ${room.ID}`} component="a" onClick={(e) => {}} shadow="sm" padding="md">
<Card.Section>
{room.CoverPhoto ? <Image src={`${serverConfig.baseURL}/photos/locations/${room.CoverPhoto}`}></Image> : <Text>No Photo</Text>}
{room.CoverPhoto ? <Image src={`${serverConfig.baseURL}/files/locations/${room.CoverPhoto}`}></Image> : <Text>No Photo</Text>}
</Card.Section>
<Group position="apart">
<Text weight={500}>{room.Name}</Text>

View File

@@ -1,19 +1,107 @@
import React, {useState, useEffect, useContext, createContext} from 'react';
import { Text } from '@mantine/core'
import { Text, Title, ThemeIcon, Group, Container, Space } from '@mantine/core'
import { useAtom } from 'jotai';
import { serverConfigAtom } from '../../state/main'
import { GoLocation } from 'react-icons/go'
import { BsDoorClosed, BsDiagram2 } from 'react-icons/bs'
import { useNotifications } from '@mantine/notifications';
import { BiCabinet } from 'react-icons/bi'
import { backendAPI } from '../../services/backend-api';
function HomePage() {
const [opened, setOpened] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [serverConfig] = useAtom(serverConfigAtom)
const [overview, setOverview] = useState({})
const notifications = useNotifications();
useEffect(() => {
console.log("LOADING LOCATIONS PAGE!")
setIsLoading(true)
async function fetchSettings() {
backendAPI.get('/overview/all').then(results => {
console.log("CONFIG IN LOCATIONS: ", serverConfig)
console.log("Overview ", results.data)
setOverview(results.data)
setIsLoading(false)
}).catch(err => {
notifications.showNotification({
title: 'Backend Notice',
message: `Failed to fetch statistics from backend! ${err}`,
autoClose: false,
color: "red",
})
setIsLoading(false)
})
}
fetchSettings();
}, [])
return (
<>
<Text>This is the homepage!</Text>
<Title order={2}>Your Instance Statistics</Title>
<Space h="md" />
<Container>
<Group>
<ThemeIcon variant="light" size={30}><GoLocation /></ThemeIcon>
<Text>{overview.NumLocations} Location{overview.NumLocations === 1 ? "": "s"}</Text>
{overview.hasOwnProperty('LastAddedLocation') && overview.LastAddedLocation !== null &&
<>
<Text>Last Added Location: </Text>
<Text>{overview.LastAddedLocation.Name}</Text>
</>
}
</Group>
</Container>
<Space h="md" />
<Container>
<Group>
<ThemeIcon variant="light" size={30}><BsDoorClosed /></ThemeIcon>
<Text>{overview.NumRooms} Room{overview.NumRooms === 1 ? "": "s"}</Text>
{overview.hasOwnProperty('LastAddedRoom') && overview.LastAddedRoom !== null &&
<>
<Text>Last Added Room: </Text>
<Text>{overview.LastAddedRoom.Name}</Text>
</>
}
</Group>
</Container>
<Space h="md" />
<Container>
<Group>
<ThemeIcon variant="light" size={30}><BiCabinet /></ThemeIcon>
<Text>{overview.NumCabinets} Cabinet{overview.NumCabinets === 1 ? "": "s"}</Text>
{overview.hasOwnProperty('LastAddedCabinet') && overview.LastAddedCabinet !== null &&
<>
<Text>Last Added Cabinet: </Text>
<Text>{overview.LastAddedCabinet.Name}</Text>
</>
}
</Group>
</Container>
<Space h="md" />
<Container>
<Group>
<ThemeIcon variant="light" size={30}><BsDiagram2 /></ThemeIcon>
<Text>{overview.NumItems} Item{overview.NumItems === 1 ? "": "s"}</Text>
{overview.hasOwnProperty('LastAddedItem') && overview.LastAddedItem !== null &&
<>
<Text>Last Added Item: </Text>
<Text>{overview.LastAddedItem.Name}</Text>
</>
}
</Group>
</Container>
</>
);

View File

@@ -0,0 +1,148 @@
import React, {useState, useEffect } from 'react';
import { useAtom } from 'jotai'
import { serverConfigAtom } from '../../state/main';
import { Loader, Center, Title, Group, Button, Space, Container, ThemeIcon, Text, Image } from '@mantine/core'
import { useNavigate, useLocation, useParams } from "react-router-dom";
import { useNotifications } from '@mantine/notifications';
import { GoLocation } from 'react-icons/go'
import { backendAPI } from '../../services/backend-api';
function LocationDetailsPage() {
const location = useLocation()
// const [opened, setOpened] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [serverConfig] = useAtom(serverConfigAtom)
const [locationDetails, setLocationDetails] = useState({})
let navigate = useNavigate();
const notifications = useNotifications();
let routeLocationID = useParams()
useEffect(() => {
let locationDetailsProps = {}
if (location.state) {
if (location.state.hasOwnProperty('location')) {
locationDetailsProps = location.state.location
}
}
if (Object.keys(locationDetailsProps).length === 0) {
console.log("manually fetching location details!")
setIsLoading(true)
async function fetchSettings() {
backendAPI.get(`/locations/${routeLocationID.id}`).then(results => {
console.log("CONFIG IN LOCATIONS: ", serverConfig)
console.log("LOCATIONS: ", results.data)
setLocationDetails(results.data)
setIsLoading(false)
}).catch(err => {
notifications.showNotification({
title: 'Backend Notice',
message: `Failed to fetch locations from backend! ${err}`,
autoClose: false,
color: "red",
})
setIsLoading(false)
})
}
fetchSettings();
} else {
console.log("Using passed state!", locationDetailsProps)
setLocationDetails(locationDetailsProps)
}
}, [])
return (
<>
<Center>{ isLoading && <Loader size="xl" variant="bars" />}</Center>
<Center><Title order={1}>{locationDetails.Name}</Title></Center>
<Button>Edit Location</Button>
<Space h="md" />
<Container>
<Group>
<ThemeIcon variant="light" size={30}><GoLocation /></ThemeIcon>
<Text>Description: </Text>
<Text>{locationDetails.Description}</Text>
</Group>
</Container>
<Space h="md" />
<Container>
<Group>
<ThemeIcon variant="light" size={30}><GoLocation /></ThemeIcon>
<Text>Notes: </Text>
<Text>{locationDetails.Notes}</Text>
</Group>
</Container>
<Space h="md" />
<Container>
<Group>
<ThemeIcon variant="light" size={30}><GoLocation /></ThemeIcon>
<Text>Address: </Text>
<Text>{locationDetails.Address}</Text>
</Group>
</Container>
<Space h="md" />
<Container>
<Group>
<ThemeIcon variant="light" size={30}><GoLocation /></ThemeIcon>
<Text>Square Feet: </Text>
<Text>{locationDetails.SquareFeet}</Text>
</Group>
</Container>
<Space h="md" />
<Container>
<Group>
<ThemeIcon variant="light" size={30}><GoLocation /></ThemeIcon>
<Text>Lat/Long: </Text>
<Text>{locationDetails.Latitude}/{locationDetails.Longitude}</Text>
</Group>
</Container>
<Space h="md" />
<Container>
<Group>
<ThemeIcon variant="light" size={30}><GoLocation /></ThemeIcon>
<Text>Date Purchased: </Text>
<Text>{locationDetails.DatePurchased}</Text>
</Group>
</Container>
<Space h="md" />
<Container>
<Group>
<ThemeIcon variant="light" size={30}><GoLocation /></ThemeIcon>
<Text>Purchase Price: </Text>
<Text>{locationDetails.PurchasePrice}</Text>
</Group>
</Container>
<Space h="md" />
<Container>
<Group>
<ThemeIcon variant="light" size={30}><GoLocation /></ThemeIcon>
<Text>Current Value: </Text>
<Text>{locationDetails.CurrentValue}</Text>
</Group>
</Container>
<Space h="md" />
<Container>
<Image src={`${serverConfig.baseURL}/files/locations/${locationDetails.Name}/${locationDetails.CoverPhoto}`} />
</Container>
</>
);
}
export default LocationDetailsPage;

View File

@@ -1,5 +1,5 @@
import React, { useState } from 'react';
import { Group, Box, Collapse, ThemeIcon, Text, UnstyledButton, createStyles } from '@mantine/core';
import { Group, Box, Collapse, ThemeIcon, UnstyledButton, createStyles } from '@mantine/core';
import { useMediaQuery } from '@mantine/hooks';
import { BiChevronLeft, BiChevronRight } from 'react-icons/bi';
import { useAtom } from 'jotai';
@@ -52,10 +52,11 @@ const useStyles = createStyles((theme) => ({
export function LinksGroup(props) {
const { icon: Icon, label, initiallyOpened, links } = 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)
@@ -67,7 +68,7 @@ export function LinksGroup(props) {
const ChevronIcon = theme.dir === 'ltr' ? BiChevronRight : BiChevronLeft;
const navigate = (event, location) => {
const navigate = (location) => {
// event.preventDefault()
if (location === "rooms") {
setRoomFilter({})
@@ -88,36 +89,65 @@ export function LinksGroup(props) {
className={activePage === link.label.toLowerCase() ? cx(classes.link, classes.activeLink) : classes.link}
to={link.link}
key={link.label}
onClick={(e) => {navigate(e, link.label.toLowerCase())}}
onClick={() => {navigate(link.label.toLowerCase())}}
>
{link.label}
</Link>
</>
));
const buttonContents = () => {
return (
<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 (
<>
<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}
style={{
transform: opened ? `rotate(${theme.dir === 'rtl' ? -90 : 90}deg)` : 'none',
}}
/>
)}
</Group>
</UnstyledButton>
{myButton()}
{hasLinks ? <Collapse in={opened}>{items}</Collapse> : null}
</>
);
)
}