more database work, added search route, starting frontend new location form
This commit is contained in:
37
frontend/package-lock.json
generated
37
frontend/package-lock.json
generated
@@ -2030,11 +2030,11 @@
|
||||
}
|
||||
},
|
||||
"@mantine/core": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@mantine/core/-/core-4.1.0.tgz",
|
||||
"integrity": "sha512-uEHGssKveDgGHhbBrgVqp8o12m0oQGLBKH3D8bkrca1GB905ZHuj8CG+i/ojBhqdalfUwqcYGRpwwALtD+XfJg==",
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@mantine/core/-/core-4.1.1.tgz",
|
||||
"integrity": "sha512-7eTv/vXKX863ri3c6zVbxozsAeA8B0iN31j3/dKs0K3y5Vd9+cgAy59WQk2RBGRlWdln7gtLnELePyQz+WlXLQ==",
|
||||
"requires": {
|
||||
"@mantine/styles": "4.1.0",
|
||||
"@mantine/styles": "4.1.1",
|
||||
"@popperjs/core": "^2.9.3",
|
||||
"@radix-ui/react-scroll-area": "^0.1.1",
|
||||
"clsx": "^1.1.1",
|
||||
@@ -2043,9 +2043,9 @@
|
||||
}
|
||||
},
|
||||
"@mantine/dates": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@mantine/dates/-/dates-4.1.0.tgz",
|
||||
"integrity": "sha512-kdKQ9PRGbYe1YhRlqWVUVGG7IKHjdIWMX3XhSFbWWLkfUxqSG4dhwNeAZIcbHXDZhFT9xIifFlBlDiN7JIOmtA==",
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@mantine/dates/-/dates-4.1.1.tgz",
|
||||
"integrity": "sha512-IUATTmne8sE4CwUngDS11zXk9xrpDuyBZSJ2LmHa0aiIm2GUTloPutLyK7zY2umaJVoRok6ji9Nlud7eEEAyYg==",
|
||||
"requires": {
|
||||
"@popperjs/core": "^2.9.3",
|
||||
"clsx": "^1.1.1",
|
||||
@@ -2060,10 +2060,15 @@
|
||||
"react-dropzone": "^11.4.2"
|
||||
}
|
||||
},
|
||||
"@mantine/form": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@mantine/form/-/form-4.1.1.tgz",
|
||||
"integrity": "sha512-Kh7lJ+JcLynCxpqUDmc5zpj/Jd/ZLpHCKnGM4TnfhV45lRlGhDQQtteKJ99XneYu2s23EhsLXfBIhD4RadHZ8g=="
|
||||
},
|
||||
"@mantine/hooks": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@mantine/hooks/-/hooks-4.1.0.tgz",
|
||||
"integrity": "sha512-bvVvHDDfYqdIxl7n+lBBwSIkcqInv6kK+fxvEfFBOUEzN6KbpJaPdaYXP788x64uFbA7AODQjdtOhk3tMyQA8Q=="
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@mantine/hooks/-/hooks-4.1.1.tgz",
|
||||
"integrity": "sha512-uVLVT1Qc7rt3kXy25efUVc509Uv3HPNPMyJaPEGM+o9RWy0k3Mo5Zp3meVfUL7PmjY179RlHmrGtxprdpiDZaA=="
|
||||
},
|
||||
"@mantine/notifications": {
|
||||
"version": "4.1.0",
|
||||
@@ -2075,9 +2080,9 @@
|
||||
}
|
||||
},
|
||||
"@mantine/styles": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@mantine/styles/-/styles-4.1.0.tgz",
|
||||
"integrity": "sha512-mWFNSE5DqE/5C9TDYIkQVbTef8QyWnW8a8MADHl6S52K0iGU8nqw4jnyozB+6y9JEIxdl+sp0o16L2JnAsq7bA==",
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@mantine/styles/-/styles-4.1.1.tgz",
|
||||
"integrity": "sha512-ZTfjqugTrqAQatgmdA0R+smUCIwPZCHykxKA5HwQzuJZh6/9TwaPozdTP7yOKAVyjBDnnAQda2PPZ1Gz1PrXqg==",
|
||||
"requires": {
|
||||
"@emotion/cache": "^11.7.1",
|
||||
"@emotion/react": "^11.7.1",
|
||||
@@ -13172,9 +13177,9 @@
|
||||
"integrity": "sha512-6+X1FLlIcjvFMAeAD/hcxDT8tmyrWnbSPMU0EnxQuDLIxokuFzWliXBiYZuGIx+mrAMLBw0WFfCkaPw8ebzAhw=="
|
||||
},
|
||||
"use-isomorphic-layout-effect": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.1.tgz",
|
||||
"integrity": "sha512-L7Evj8FGcwo/wpbv/qvSfrkHFtOpCzvM5yl2KVyDJoylVuSvzphiiasmjgQPttIGBAy2WKiBNR98q8w7PiNgKQ=="
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz",
|
||||
"integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA=="
|
||||
},
|
||||
"use-latest": {
|
||||
"version": "1.2.0",
|
||||
|
@@ -3,10 +3,11 @@
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@mantine/core": "^4.1.0",
|
||||
"@mantine/dates": "^4.1.0",
|
||||
"@mantine/core": "^4.1.1",
|
||||
"@mantine/dates": "^4.1.1",
|
||||
"@mantine/dropzone": "^4.1.0",
|
||||
"@mantine/hooks": "^4.1.0",
|
||||
"@mantine/form": "^4.1.1",
|
||||
"@mantine/hooks": "^4.1.1",
|
||||
"@mantine/notifications": "^4.1.0",
|
||||
"@testing-library/jest-dom": "^5.16.3",
|
||||
"@testing-library/react": "^12.1.4",
|
||||
|
61
frontend/src/components/cards/LocationCard.js
Normal file
61
frontend/src/components/cards/LocationCard.js
Normal file
@@ -0,0 +1,61 @@
|
||||
import React from 'react';
|
||||
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';
|
||||
|
||||
|
||||
|
||||
function LocationCard(props) {
|
||||
const {location, idx} = props
|
||||
const [serverConfig] = useAtom(serverConfigAtom)
|
||||
const [, setRoomsFilter] = useAtom(roomFilterAtom)
|
||||
const [, setActivePage] = useAtom(activePageAtom)
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
const setRoomNumber = (rooms) => {
|
||||
if (rooms === null) {
|
||||
return <Text>0 Rooms</Text>
|
||||
} else if (rooms.length > 1) {
|
||||
return <Text>{rooms.length} Rooms</Text>
|
||||
} else {
|
||||
return <Text>1 Room</Text>
|
||||
}
|
||||
}
|
||||
|
||||
const navigateToRooms = (locationID, locationName) => {
|
||||
setActivePage("rooms")
|
||||
setRoomsFilter({"filterType": "location", "locationID": locationID, "commonName": "location", "metadata": locationName})
|
||||
navigate("/rooms")
|
||||
}
|
||||
|
||||
|
||||
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>}
|
||||
<Group position='right' style={{position: 'absolute', top: '5px', right: '5px', backgroundColor: 'grey', borderRadius: '25%'}}>
|
||||
<Menu>
|
||||
<Menu.Label>Edit</Menu.Label>
|
||||
<Menu.Label>Delete</Menu.Label>
|
||||
</Menu>
|
||||
</Group>
|
||||
|
||||
</Card.Section>
|
||||
<Group position="apart">
|
||||
<Text weight={500}>{location.Name}</Text>
|
||||
<Badge variant="light">
|
||||
{ setRoomNumber(location.Rooms) }
|
||||
</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>
|
||||
);
|
||||
}
|
||||
|
||||
export default LocationCard;
|
63
frontend/src/components/cards/RoomCard.js
Normal file
63
frontend/src/components/cards/RoomCard.js
Normal file
@@ -0,0 +1,63 @@
|
||||
import React from 'react';
|
||||
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';
|
||||
|
||||
|
||||
|
||||
function RoomCard(props) {
|
||||
const {room, idx} = props
|
||||
const [serverConfig] = useAtom(serverConfigAtom)
|
||||
const [, setRoomsFilter] = useAtom(roomFilterAtom)
|
||||
const [, setActivePage] = useAtom(activePageAtom)
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
const setItemAndCabinetNumber = (category, name) => {
|
||||
if (category === null) {
|
||||
return <Text>0 {name}s</Text>
|
||||
} else if (category.length > 1) {
|
||||
return <Text>{category.length} {name}s</Text>
|
||||
} else {
|
||||
return <Text>1 {name}</Text>
|
||||
}
|
||||
}
|
||||
|
||||
const navigateToCabinets = (roomID, roomName) => {
|
||||
setActivePage("cabinets")
|
||||
setRoomsFilter({"filterType": "room", "roomID": roomID, "commonName": "room", "metadata": roomName})
|
||||
navigate("/cabinets")
|
||||
}
|
||||
|
||||
|
||||
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>}
|
||||
</Card.Section>
|
||||
<Group position="apart">
|
||||
<Text weight={500}>{room.Name}</Text>
|
||||
<Group>
|
||||
<Badge color="pink" variant="light">
|
||||
{room.LocationName}
|
||||
</Badge>
|
||||
<Badge variant='light'>
|
||||
{setItemAndCabinetNumber(room.Cabinets, "Cabinet")}
|
||||
</Badge>
|
||||
<Badge color='teal' variant='light'>
|
||||
{setItemAndCabinetNumber(room.Items, "Item")}
|
||||
</Badge>
|
||||
</Group>
|
||||
</Group>
|
||||
<Text size="sm">{room.Description}</Text>
|
||||
<Group>
|
||||
<Button onClick={() => console.log("test")}>View Details</Button>
|
||||
<Button onClick={() => navigateToCabinets(room.id, room.Name)}>View Cabinets</Button>
|
||||
<Button onClick={() => console.log("test")}>View Items</Button>
|
||||
</Group>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
export default RoomCard;
|
26
frontend/src/components/forms/LocationForm.js
Normal file
26
frontend/src/components/forms/LocationForm.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import React, {useState, useEffect} from 'react';
|
||||
import { Text, Title, TextInput, Button, NumberInput, } from '@mantine/core'
|
||||
import { DatePicker } from '@mantine/dates';
|
||||
import { useForm } from '@mantine/form';
|
||||
import { useAtom } from 'jotai';
|
||||
import { serverConfigAtom } from '../../state/main'
|
||||
|
||||
|
||||
|
||||
function LocationForm(props) {
|
||||
const {location, modify: bool} = props
|
||||
const [opened, setOpened] = useState(false);
|
||||
const [serverConfig] = useAtom(serverConfigAtom)
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<Title>Location Form</Title>
|
||||
<Text>This is the homepage!</Text>
|
||||
</>
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
export default LocationForm;
|
@@ -1,5 +1,4 @@
|
||||
import React, {useState, useEffect, useContext, createContext} from 'react';
|
||||
import APIContext from '../../App';
|
||||
import { Text } from '@mantine/core'
|
||||
import { useAtom } from 'jotai';
|
||||
import { serverConfigAtom } from '../../state/main'
|
||||
|
@@ -1,25 +1,26 @@
|
||||
import React, {useState, useEffect, useContext, createContext} from 'react';
|
||||
import React, {useState, useEffect } from 'react';
|
||||
import { useAtom } from 'jotai'
|
||||
import { activePageAtom, roomFilterAtom, serverConfigAtom } from '../../state/main';
|
||||
import { Text, Loader, Center, Card, Image, Badge, Button, SimpleGrid, Group, Title } from '@mantine/core'
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { serverConfigAtom } from '../../state/main';
|
||||
import { HiPlus } from 'react-icons/hi'
|
||||
import { Loader, Center, SimpleGrid, Title, Group, Button, Divider } from '@mantine/core'
|
||||
|
||||
import { useNotifications } from '@mantine/notifications';
|
||||
|
||||
|
||||
import { backendAPI } from '../../services/backend-api';
|
||||
import LocationCard from '../cards/LocationCard';
|
||||
|
||||
|
||||
function LocationsPage(props) {
|
||||
function LocationsPage() {
|
||||
// const [opened, setOpened] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [locations, setLocations] = useState([])
|
||||
const [serverConfig] = useAtom(serverConfigAtom)
|
||||
const [, setRoomsFilter] = useAtom(roomFilterAtom)
|
||||
const [, setActivePage] = useAtom(activePageAtom)
|
||||
|
||||
|
||||
|
||||
const notifications = useNotifications();
|
||||
const navigate = useNavigate();
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
console.log("LOADING LOCATIONS PAGE!")
|
||||
@@ -46,27 +47,12 @@ function LocationsPage(props) {
|
||||
|
||||
}, [])
|
||||
|
||||
const navigateToRooms = (locationID, locationName) => {
|
||||
setActivePage("rooms")
|
||||
setRoomsFilter({"filterType": "location", "locationID": locationID, "commonName": "location", "metadata": locationName})
|
||||
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>
|
||||
<Button leftIcon={<HiPlus />}>Add New Location</Button>
|
||||
<Divider />
|
||||
<SimpleGrid
|
||||
spacing="md"
|
||||
cols={4}
|
||||
@@ -77,25 +63,9 @@ function LocationsPage(props) {
|
||||
]}
|
||||
|
||||
>
|
||||
{ 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>
|
||||
)}
|
||||
{ locations.map((location, idx) =>
|
||||
<LocationCard location={location} idx={idx}></LocationCard>
|
||||
)}
|
||||
</SimpleGrid>
|
||||
</>
|
||||
|
||||
|
@@ -6,6 +6,7 @@ import { useLocation } from "react-router-dom";
|
||||
import { useNotifications } from '@mantine/notifications';
|
||||
|
||||
import { backendAPI } from '../../services/backend-api';
|
||||
import RoomCard from '../cards/RoomCard';
|
||||
|
||||
|
||||
function RoomsPage(props) {
|
||||
@@ -27,7 +28,7 @@ function RoomsPage(props) {
|
||||
console.log("CURRENT STATE: ", state)
|
||||
// if we are filtering by location
|
||||
if (roomFilter.locationID) {
|
||||
url = `rooms/${roomFilter.locationID}`
|
||||
url = `locations/${roomFilter.locationID}/rooms`
|
||||
}
|
||||
backendAPI.get(url).then(results => {
|
||||
console.log("ROOMS: ", results)
|
||||
@@ -50,10 +51,10 @@ function RoomsPage(props) {
|
||||
}, [roomFilter])
|
||||
|
||||
// Check if filter changes for this page and refresh results
|
||||
useEffect(() => {
|
||||
console.log("CURRENT ROOM FILTER: ", roomFilter)
|
||||
// useEffect(() => {
|
||||
// console.log("CURRENT ROOM FILTER: ", roomFilter)
|
||||
|
||||
}, [roomFilter, setRoomFilter])
|
||||
// }, [roomFilter, setRoomFilter])
|
||||
|
||||
const removeFilterButton = (
|
||||
<ActionIcon size="xs" color="blue" radius="xl" variant="transparent">
|
||||
@@ -83,30 +84,7 @@ function RoomsPage(props) {
|
||||
]}
|
||||
>
|
||||
{ rooms.map((room, idx) =>
|
||||
<Card key={`${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>}
|
||||
</Card.Section>
|
||||
<Group position="apart">
|
||||
<Text weight={500}>{room.Name}</Text>
|
||||
<Group>
|
||||
<Badge color="pink" variant="light">
|
||||
{room.LocationName}
|
||||
</Badge>
|
||||
<Badge variant='light'>
|
||||
{room.Cabinets === null ? 0 : room.Cabinets.length} Cabinets
|
||||
</Badge>
|
||||
<Badge color='teal' variant='light'>
|
||||
{room.Cabinets === null ? 0 : room.Cabinets.length} Items
|
||||
</Badge>
|
||||
</Group>
|
||||
</Group>
|
||||
<Text size="sm">{room.Description}</Text>
|
||||
<Group>
|
||||
<Button onClick={() => console.log("test")}>View Details</Button>
|
||||
<Button onClick={() => console.log("test")}>View Rooms</Button>
|
||||
</Group>
|
||||
</Card>
|
||||
<RoomCard room={room} idx={idx}></RoomCard>
|
||||
)}
|
||||
</SimpleGrid>
|
||||
</>
|
||||
|
Reference in New Issue
Block a user