more database work, added search route, starting frontend new location form
This commit is contained in:
File diff suppressed because it is too large
Load Diff
113
database.go
113
database.go
@@ -6,71 +6,6 @@ import (
|
||||
"github.com/asdine/storm/v3"
|
||||
)
|
||||
|
||||
// Location is a top level component that starts the containerization process
|
||||
type Location struct {
|
||||
ID int `storm:"id,increment,index"`
|
||||
Name string `storm:"unique"`
|
||||
Description string
|
||||
CoverPhoto string // A "cover photo" for the location
|
||||
Photos []string // A list of additional photos for the location
|
||||
Rooms []Room
|
||||
Notes string
|
||||
Address string
|
||||
SquareFeet int
|
||||
Latitude string
|
||||
Longitude string
|
||||
DatePurchased string
|
||||
PurchasePrice string
|
||||
CurrentValue string
|
||||
}
|
||||
|
||||
// Room is a containerized area at a location
|
||||
type Room struct {
|
||||
ID int `storm:"id,increment,index"`
|
||||
Name string
|
||||
Description string
|
||||
CoverPhoto string // A "cover photo" for the room
|
||||
Photos []string // A list of additional photos for the room
|
||||
Paint string // Details about the paint
|
||||
Notes string
|
||||
Cabinets []Cabinet
|
||||
Items []Item
|
||||
SquareFeet int
|
||||
LocationID int //Which location room is assigned to
|
||||
LocationName string // Location name room belongs to
|
||||
|
||||
}
|
||||
|
||||
// Cabinet is a containerized area in a room
|
||||
type Cabinet struct {
|
||||
ID int `storm:"id, increment"`
|
||||
RoomID int // Room ID that the cabinet is assigned to
|
||||
RoomName string // Room name cabinet belongs to
|
||||
CoverPhoto string // A "Cover photo" for this item
|
||||
Items []Item // List of items in the cabinet
|
||||
Name string
|
||||
Notes string
|
||||
}
|
||||
|
||||
// Item is contained inside a room or cabinet
|
||||
type Item struct {
|
||||
ID int `storm:"id, increment"`
|
||||
LocType string // Can be Room or Cabinet to show where it is stored
|
||||
RoomID int // Room ID that item is assigned to (can also be in a cabinet)
|
||||
RoomName string // Room name that item is assigned to
|
||||
CabinetID int //The cabinet id that an item is assigned to
|
||||
CabinetName string // The name of the cabinet it belongs to
|
||||
CoverPhoto string // A "cover photo" for the item
|
||||
Photos []string // A list of additional photos for the item
|
||||
Count int // If item has duplicates
|
||||
Name string
|
||||
Product string
|
||||
Serial string
|
||||
Warranty string
|
||||
Notes string
|
||||
Files []string //filepath to any files relevant to this item
|
||||
}
|
||||
|
||||
// Location Routes
|
||||
|
||||
//SetupDatabase initializes the storm/bbolt database
|
||||
@@ -301,3 +236,51 @@ func (s *Server) DeleteItem(item Item) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Misc calls
|
||||
|
||||
type SearchResults struct {
|
||||
Locations []Location `json:"locations"`
|
||||
Rooms []Room `json:"rooms"`
|
||||
Cabinets []Cabinet `json:"cabinets"`
|
||||
Items []Item `json:"items"`
|
||||
}
|
||||
|
||||
// SearchAllByField searches the entire database (locs, rooms, cabinets, items) by the field and search term passed in
|
||||
func (s *Server) SearchAllByField(fieldFilter string, searchTerm string) (results SearchResults, err error) {
|
||||
s.Log.Info().Msgf("Searching all items for term: %s", searchTerm)
|
||||
var locs []Location
|
||||
var rooms []Room
|
||||
var cabinets []Cabinet
|
||||
var items []Item
|
||||
results = SearchResults{}
|
||||
|
||||
err = s.Database.Find(fieldFilter, searchTerm, &locs)
|
||||
if err != nil && err != storm.ErrNotFound {
|
||||
s.Log.Error().Msgf("Unable to search locations in database with term: %s :error: %s ", searchTerm, err)
|
||||
return results, err
|
||||
}
|
||||
err = s.Database.Find(fieldFilter, searchTerm, &rooms)
|
||||
if err != nil && err != storm.ErrNotFound {
|
||||
s.Log.Error().Msgf("Unable to search rooms in database with term: %s error: %s ", searchTerm, err)
|
||||
return results, err
|
||||
}
|
||||
err = s.Database.Find(fieldFilter, searchTerm, &cabinets)
|
||||
if err != nil && err != storm.ErrNotFound {
|
||||
s.Log.Error().Msgf("Unable to search cabinets in database with term: %s error: %s ", searchTerm, err)
|
||||
return results, err
|
||||
}
|
||||
err = s.Database.Find(fieldFilter, searchTerm, &items)
|
||||
if err != nil && err != storm.ErrNotFound {
|
||||
s.Log.Error().Msgf("Unable to search items in database with term: %s error: %s ", searchTerm, err)
|
||||
return results, err
|
||||
}
|
||||
|
||||
results.Locations = locs
|
||||
results.Rooms = rooms
|
||||
results.Cabinets = cabinets
|
||||
results.Items = items
|
||||
|
||||
return results, nil
|
||||
|
||||
}
|
||||
|
67
database_structs.go
Normal file
67
database_structs.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package main
|
||||
|
||||
// Location is a top level component that starts the containerization process
|
||||
type Location struct {
|
||||
ID int `storm:"id,increment,index"`
|
||||
Name string `storm:"unique"`
|
||||
Description string
|
||||
CoverPhoto string // A "cover photo" for the location
|
||||
Photos []string // A list of additional photos for the location
|
||||
Rooms []Room
|
||||
Notes string
|
||||
Address string
|
||||
SquareFeet int
|
||||
Latitude string
|
||||
Longitude string
|
||||
DatePurchased string
|
||||
PurchasePrice string
|
||||
CurrentValue string
|
||||
}
|
||||
|
||||
// Room is a containerized area at a location
|
||||
type Room struct {
|
||||
ID int `storm:"id,increment,index"`
|
||||
Name string
|
||||
Description string
|
||||
CoverPhoto string // A "cover photo" for the room
|
||||
Photos []string // A list of additional photos for the room
|
||||
Paint string // Details about the paint
|
||||
Notes string
|
||||
Cabinets []Cabinet
|
||||
Items []Item
|
||||
SquareFeet int
|
||||
LocationID int //Which location room is assigned to
|
||||
LocationName string // Location name room belongs to
|
||||
|
||||
}
|
||||
|
||||
// Cabinet is a containerized area in a room
|
||||
type Cabinet struct {
|
||||
ID int `storm:"id, increment"`
|
||||
RoomID int // Room ID that the cabinet is assigned to
|
||||
RoomName string // Room name cabinet belongs to
|
||||
CoverPhoto string // A "Cover photo" for this item
|
||||
Items []Item // List of items in the cabinet
|
||||
Name string
|
||||
Notes string
|
||||
}
|
||||
|
||||
// Item is contained inside a room or cabinet
|
||||
type Item struct {
|
||||
ID int `storm:"id, increment"`
|
||||
LocType string // Can be Room or Cabinet to show where it is stored
|
||||
RoomID int // Room ID that item is assigned to (can also be in a cabinet)
|
||||
RoomName string // Room name that item is assigned to
|
||||
CabinetID int //The cabinet id that an item is assigned to
|
||||
CabinetName string // The name of the cabinet it belongs to
|
||||
CoverPhoto string // A "cover photo" for the item
|
||||
Photos []string // A list of additional photos for the item
|
||||
Count int // If item has duplicates
|
||||
Name string
|
||||
Product string
|
||||
Serial string
|
||||
Warranty string
|
||||
Notes string
|
||||
DatePurchased string
|
||||
Files []string //filepath to any files relevant to this item
|
||||
}
|
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>
|
||||
</>
|
||||
|
@@ -19,6 +19,20 @@ func (s *Server) GetAllItemsHandler(c *fiber.Ctx) error {
|
||||
return c.Status(fiber.StatusOK).JSON(items)
|
||||
}
|
||||
|
||||
// GetItemHandler returns a single item from an ID
|
||||
func (s *Server) GetItemHandler(c *fiber.Ctx) error {
|
||||
itemID, err := c.ParamsInt("itemID")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
room, err := s.GetItem(itemID)
|
||||
if err != nil {
|
||||
s.Log.Err(err).Msgf("Unable to fetch item with id: %d", itemID)
|
||||
return err
|
||||
}
|
||||
return c.Status(fiber.StatusOK).JSON(room)
|
||||
}
|
||||
|
||||
// GetAllItemsAtRoomHandler gets all items in a room
|
||||
func (s *Server) GetAllItemsAtRoomHandler(c *fiber.Ctx) error {
|
||||
roomID, err := c.ParamsInt("roomID")
|
||||
|
22
handlers_other.go
Normal file
22
handlers_other.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
// SearchAllByField searches all of the DB by specified field
|
||||
func (s *Server) SearchAllHandler(c *fiber.Ctx) error {
|
||||
searchField := c.Query("field", "Name")
|
||||
searchTerm := c.Query("term")
|
||||
|
||||
s.Log.Debug().Msgf("Search by term: %s in all items at field: %s", searchTerm, searchField)
|
||||
results, err := s.SearchAllByField(searchField, searchTerm)
|
||||
if err != nil {
|
||||
s.Log.Error().Msgf("SearchAllByField failed to return results: %s ", err)
|
||||
return c.Status(fiber.StatusInternalServerError).SendString(fmt.Sprintf("Database failure! error: %s", err))
|
||||
}
|
||||
|
||||
return c.Status(fiber.StatusOK).JSON(results)
|
||||
}
|
8
main.go
8
main.go
@@ -110,17 +110,19 @@ func main() {
|
||||
// Cabinet Routes
|
||||
server.WebServer.Get("/api/cabinets", server.GetAllCabinetsHandler)
|
||||
server.WebServer.Get("/api/cabinets/:cabinetID", server.GetCabinetHandler)
|
||||
server.WebServer.Post("/api/cabinets/:roomID/new", server.AddNewCabinetHandler)
|
||||
server.WebServer.Get("/api/cabinets/:cabinetID/items", server.GetAllItemsAtCabinetHandler)
|
||||
server.WebServer.Delete("/api/cabinets/:cabinetID", server.DeleteCabinetHandler)
|
||||
|
||||
// Item Routes
|
||||
server.WebServer.Get("/api/items", server.GetAllItemsHandler)
|
||||
server.WebServer.Get("/api/items/room/:roomID", server.GetAllItemsAtRoomHandler)
|
||||
server.WebServer.Get("/api/items/cabinet/:cabinetID", server.GetAllItemsAtCabinetHandler)
|
||||
server.WebServer.Get("/api/items/:itemID", server.GetItemHandler)
|
||||
server.WebServer.Post("/api/items/cabinet/:cabinetID/new", server.AddNewItemHandler)
|
||||
server.WebServer.Post("/api/items/room/:roomID/new", server.AddNewItemHandler)
|
||||
server.WebServer.Delete("/api/items/:itemID", server.DeleteItemHandler)
|
||||
// Misc Routes
|
||||
server.WebServer.Get("/api/search/all", server.SearchAllHandler)
|
||||
|
||||
// Start Server
|
||||
fmt.Println("Everything ready, starting server! ", fmt.Sprintf(":%s", server.Config.Server.Port))
|
||||
server.WebServer.Listen(fmt.Sprintf(":%s", server.Config.Server.Port))
|
||||
}
|
||||
|
Reference in New Issue
Block a user