diff --git a/app/log/goInventorize.log b/app/log/goInventorize.log
index 904f552..5091789 100644
--- a/app/log/goInventorize.log
+++ b/app/log/goInventorize.log
@@ -490,3 +490,90 @@
{"level":"debug","time":"2023-01-09T22:18:51-05:00","message":"Returning Locations: [{ID:1 Name:Location0 Description:This is my test description0 Notes:Notes for my location!0 Address: SquareFeet:2500 Latitude:120N Longitude:120N DatePurchased: PurchasePrice:125000 CurrentValue: CoverPhoto:Location0_cover.png Photos:[] Files:[] Rooms:[]}]"}
{"logtype":"webserver", "pid":"15420", "requestid":"", "status":"200", "method":"GET", "path":"/api/locations"}
{"logtype":"webserver", "pid":"15420", "requestid":"", "status":"200", "method":"GET", "path":"/api/overview/all"}
+{"level":"info","time":"2023-01-10T21:30:33-05:00","message":"Configuration loaded successfully..."}
+{"level":"debug","time":"2023-01-10T21:30:33-05:00","message":"{Timezone:America/New_York Server:{Port:3500 LocationFilesDir:./app/files/} Logger:{Level:debug LoggingFile:./app/log/goInventorize.log} Authentication:{BasicAuth:false UserName:admin Password:password} Development:false}"}
+{"level":"info","time":"2023-01-10T21:30:33-05:00","message":"Database and Config loaded, starting webserver..."}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/config"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/overview/all"}
+{"level":"info","time":"2023-01-10T21:31:52-05:00","message":"Getting all Rooms"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/rooms"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/overview/all"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/overview/all"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/config"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/config"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/overview/all"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/config"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/overview/all"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/config"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/config"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/overview/all"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/config"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/overview/all"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/config"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/overview/all"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/config"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/overview/all"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/config"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/overview/all"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/config"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/overview/all"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/config"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/config"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/overview/all"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/config"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/overview/all"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/config"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/overview/all"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/config"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/overview/all"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/config"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/overview/all"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/config"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/overview/all"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/config"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/config"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/config"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/overview/all"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/config"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/config"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/config"}
+{"level":"debug","time":"2023-01-10T22:30:28-05:00","message":"Returning Locations: [{ID:1 Name:Location0 Description:This is my test description0 Notes:Notes for my location!0 Address: SquareFeet:2500 Latitude:120N Longitude:120N DatePurchased: PurchasePrice:125000 CurrentValue: CoverPhoto:Location0_cover.png Photos:[] Files:[] Rooms:[]}]"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/locations"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/overview/all"}
+{"level":"debug","time":"2023-01-10T22:30:32-05:00","message":"Returning Locations: [{ID:1 Name:Location0 Description:This is my test description0 Notes:Notes for my location!0 Address: SquareFeet:2500 Latitude:120N Longitude:120N DatePurchased: PurchasePrice:125000 CurrentValue: CoverPhoto:Location0_cover.png Photos:[] Files:[] Rooms:[]}]"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/locations"}
+{"level":"info","time":"2023-01-10T22:30:37-05:00","message":"Getting all Rooms"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/rooms"}
+{"level":"debug","time":"2023-01-10T22:30:38-05:00","message":"Returning Locations: [{ID:1 Name:Location0 Description:This is my test description0 Notes:Notes for my location!0 Address: SquareFeet:2500 Latitude:120N Longitude:120N DatePurchased: PurchasePrice:125000 CurrentValue: CoverPhoto:Location0_cover.png Photos:[] Files:[] Rooms:[]}]"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/locations"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/overview/all"}
+{"level":"debug","time":"2023-01-10T22:32:19-05:00","message":"Returning Locations: [{ID:1 Name:Location0 Description:This is my test description0 Notes:Notes for my location!0 Address: SquareFeet:2500 Latitude:120N Longitude:120N DatePurchased: PurchasePrice:125000 CurrentValue: CoverPhoto:Location0_cover.png Photos:[] Files:[] Rooms:[]}]"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/locations"}
+{"level":"info","time":"2023-01-10T22:32:20-05:00","message":"Getting all Rooms"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/rooms"}
+{"level":"info","time":"2023-01-10T22:32:23-05:00","message":"Getting all Rooms"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/rooms"}
+{"level":"debug","time":"2023-01-10T22:32:24-05:00","message":"Returning Locations: [{ID:1 Name:Location0 Description:This is my test description0 Notes:Notes for my location!0 Address: SquareFeet:2500 Latitude:120N Longitude:120N DatePurchased: PurchasePrice:125000 CurrentValue: CoverPhoto:Location0_cover.png Photos:[] Files:[] Rooms:[]}]"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/locations"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/overview/all"}
+{"level":"debug","time":"2023-01-10T22:32:28-05:00","message":"Returning Locations: [{ID:1 Name:Location0 Description:This is my test description0 Notes:Notes for my location!0 Address: SquareFeet:2500 Latitude:120N Longitude:120N DatePurchased: PurchasePrice:125000 CurrentValue: CoverPhoto:Location0_cover.png Photos:[] Files:[] Rooms:[]}]"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/locations"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/config"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/config"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/config"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/config"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/overview/all"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/config"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/overview/all"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/config"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/overview/all"}
+{"level":"debug","time":"2023-01-10T22:38:41-05:00","message":"Returning Locations: [{ID:1 Name:Location0 Description:This is my test description0 Notes:Notes for my location!0 Address: SquareFeet:2500 Latitude:120N Longitude:120N DatePurchased: PurchasePrice:125000 CurrentValue: CoverPhoto:Location0_cover.png Photos:[] Files:[] Rooms:[]}]"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/locations"}
+{"level":"debug","time":"2023-01-10T22:40:26-05:00","message":"Returning Locations: [{ID:1 Name:Location0 Description:This is my test description0 Notes:Notes for my location!0 Address: SquareFeet:2500 Latitude:120N Longitude:120N DatePurchased: PurchasePrice:125000 CurrentValue: CoverPhoto:Location0_cover.png Photos:[] Files:[] Rooms:[]}]"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/locations"}
+{"level":"debug","time":"2023-01-10T22:41:33-05:00","message":"Returning Locations: [{ID:1 Name:Location0 Description:This is my test description0 Notes:Notes for my location!0 Address: SquareFeet:2500 Latitude:120N Longitude:120N DatePurchased: PurchasePrice:125000 CurrentValue: CoverPhoto:Location0_cover.png Photos:[] Files:[] Rooms:[]}]"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/locations"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"404", "method":"GET", "path":"/files/locations/undefined/undefined"}
+{"level":"debug","time":"2023-01-10T22:42:00-05:00","message":"Returning Locations: [{ID:1 Name:Location0 Description:This is my test description0 Notes:Notes for my location!0 Address: SquareFeet:2500 Latitude:120N Longitude:120N DatePurchased: PurchasePrice:125000 CurrentValue: CoverPhoto:Location0_cover.png Photos:[] Files:[] Rooms:[]}]"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"200", "method":"GET", "path":"/api/locations"}
+{"logtype":"webserver", "pid":"14996", "requestid":"", "status":"404", "method":"GET", "path":"/files/locations/undefined/undefined"}
diff --git a/frontend/src/App.js b/frontend/src/App.js
index 44224b0..00eb211 100644
--- a/frontend/src/App.js
+++ b/frontend/src/App.js
@@ -1,23 +1,24 @@
import React, {useState, useEffect } from 'react';
import { useAtom } from 'jotai';
import HomePage from './components/pages/HomePage';
-import LocationsPage from './components/pages/LocationsPage';
+import LocationsPage from './components/pages/Locations/LocationsPage';
import RoomsPage from './components/pages/RoomsPage';
-import LocationForm from './components/forms/LocationForm'
+import LocationForm from './components/pages/Locations/NewLocationForm'
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 { useDebouncedValue, useLocalStorageValue } from '@mantine/hooks';
-import { showNotification } from '@mantine/notifications';
+import { Loader, AppShell, MediaQuery, Header, Center, Title, Burger, useMantineTheme } from '@mantine/core';
+// import { useDebouncedValue, useLocalStorageValue } from '@mantine/hooks';
import { backendAPI, defaultURLS } from './services/backend-api';
-import { serverConfigAtom } from './state/state'
+import { serverConfigAtom, notificationQueueAtom } from './state/state'
+
+import { generateNotification } from './components/Utilities';
import SideBar from './components/SideBar';
-import AppHeader from './components/AppHeader';
-import LocationDetailsPage from './components/pages/LocationDetailsPage';
+// import AppHeader from './components/AppHeader';
+import LocationDetailsPage from './components/pages/Locations/LocationDetailsPage';
@@ -25,52 +26,73 @@ function App() {
// Main nav/sidebar appshell openend
const [isLoading, setIsLoading] = useState(true)
+ const [opened, setOpened] = useState(false);
+
const [, setServerConfig] = useAtom(serverConfigAtom)
+ const [, setNotificationQueue] = useAtom(notificationQueueAtom)
+ const theme = useMantineTheme();
+
// const navigate = useNavigate();
useEffect(() => {
// navigate("/")// Reset to homepage on new load anywhere in the app
- setIsLoading(true)
- async function fetchSettings() {
- backendAPI.get('/config').then(results => {
+
+ const fetchSettings = async () => {
+ setIsLoading(true)
+ try {
+ const results = await backendAPI.get('/config')
// console.log("FULL RESULTS: ", results.config.baseURL)
results.data.baseURL = defaultURLS.baseURL
console.log("CONFIG: ", results.data)
setServerConfig(results.data)
- showNotification({
- title: 'Backend Notice',
- message: 'Config fetched from backend!',
- color: "green"
- })
- setIsLoading(false)
- }).catch(err => {
- showNotification({
- title: 'Backend Notice',
- message: `Failed to connect to backend! ${err}`,
- autoClose: false,
- color: "red",
- })
- setIsLoading(false)
- })
-
+ const notification = generateNotification('success', 'Config Fetched', 'Config fetched from backend')
+ setNotificationQueue((currentQueue) => ([...currentQueue, notification]))
+ } catch(err) {
+ const notification = generateNotification('error', 'Failed to fetch config', `Failed to fetch config: ${err}`)
+ setNotificationQueue((currentQueue) => ([...currentQueue, notification]))
+ }
+ setIsLoading(false)
}
+
fetchSettings();
-
- }, [])
+ }, [setServerConfig, setNotificationQueue])
return (
+ <>
+ {isLoading ?
:
}
- header={}
+ header={
+
+
+ }
>
} />
@@ -86,6 +108,8 @@ function App() {
+ }
+ >
);
}
diff --git a/frontend/src/Notifications.js b/frontend/src/Notifications.js
deleted file mode 100644
index eea2b01..0000000
--- a/frontend/src/Notifications.js
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-function Notifications() {
-
-
- return(
- <>>
- )
-}
-
-export default Notifications;
\ No newline at end of file
diff --git a/frontend/src/components/AppHeader.js b/frontend/src/components/AppHeader.js
deleted file mode 100644
index 6a8b064..0000000
--- a/frontend/src/components/AppHeader.js
+++ /dev/null
@@ -1,38 +0,0 @@
-import React, {useState, useEffect, useContext } from 'react';
-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/state';
-
-
-function AppHeader(props) {
- const theme = useMantineTheme()
- const [menuOpened, setMenuOpened] = useAtom(menuOpenedAtom)
-
-
- return (
-
- )
-}
-
-
-
-export default AppHeader
\ No newline at end of file
diff --git a/frontend/src/components/Notifications.js b/frontend/src/components/Notifications.js
new file mode 100644
index 0000000..bed9726
--- /dev/null
+++ b/frontend/src/components/Notifications.js
@@ -0,0 +1,32 @@
+import { useAtom } from 'jotai';
+import { useResetAtom } from 'jotai/utils'
+import { notificationQueueAtom, notificationHistoryAtom } from '../state/state.js';
+import { showNotification } from '@mantine/notifications';
+import { useEffect } from 'react';
+
+function Notifications() {
+ const [notificationQueue] = useAtom(notificationQueueAtom)
+ const [,setNotificationHistory] = useAtom(notificationHistoryAtom)
+ const resetNotifications = useResetAtom(notificationQueueAtom)
+
+
+ useEffect(() => {
+ if (notificationQueue.length > 0) {
+ notificationQueue.forEach(notification => {
+ // setting the full history so user can view it later
+ setNotificationHistory((history) => [...history, notification])
+ showNotification({
+ title: notification.title,
+ message: notification.message,
+ color: notification.color,
+ icon: notification.icon,
+ disallowClose: notification.disallowClose,
+ })
+ });
+ resetNotifications()
+ }
+ }, [notificationQueue, resetNotifications, setNotificationHistory])
+
+}
+
+export default Notifications
\ No newline at end of file
diff --git a/frontend/src/components/PhotoDisplay.js b/frontend/src/components/PhotoDisplay.js
new file mode 100644
index 0000000..d15a26a
--- /dev/null
+++ b/frontend/src/components/PhotoDisplay.js
@@ -0,0 +1,120 @@
+import {Image, Text, Modal, SimpleGrid, Title, Loader, Center, Card, Group, Badge, Button, Tooltip} from '@mantine/core'
+import { ExternalLink } from 'tabler-icons-react'
+import {useEffect, useState } from 'react'
+// import BackendAPI from '../services/backend'
+
+const urlPrepend = "https://apps.ts.fedex.com/tsrphotos/"
+
+function PhotoDisplay(props) {
+ const { photos } = props
+ //const [photosDisplay, setPhotosDisplay] = useState([])
+ const [photosLoading, setPhotosLoading] = useState(false)
+ const [numPhotos, setNumPhotos] = useState(photos.length)
+ // Modal states
+ const [photoOpened, setPhotoOpened] = useState(false)
+ const [photoDetails, setPhotoDetails] = useState({
+ "name": "",
+ "data": null,
+ "locationName": "",
+ })
+ const [rawPhotoArray, setRawPhotoArray] = useState([])
+
+
+ useEffect(() => {
+ const createPhotos = async () => {
+ setPhotosLoading(true)
+ if (photos.length > 0) {
+ photos.forEach(async (photo) => {
+ console.log("Loading photo: ", photo.photo_path_txt)
+ const fullUrl = `${urlPrepend}${photo.photo_path_txt}`
+ let newPhoto =
+
+
+ displayPhoto(fullUrl, photo)}
+ />
+
+
+ {photo.photo_nm}
+
+ {photo.network_location ? photo.network_location.location_nm : "No Location"}
+
+
+
+ {photo?.photo_notes_txt ? photo.photo_notes_txt : "No Photo Notes!"}
+
+ {photo.latitude_nbr !== 0 && photo.longitude_nbr !== 0 &&
+
+ }>View Photo in Google Maps
+
+ }
+
+ setRawPhotoArray(currArray => [...currArray, newPhoto])
+ // }
+ })
+ }
+ }
+
+ if (photos.length > 0) {
+ console.log("RECEIVED PHOTOS!", photos)
+ setNumPhotos(photos.length)
+ createPhotos()
+ }
+ }, [photos])
+
+ useEffect(() => {
+ if (photos.length === rawPhotoArray.length) {
+ console.log("Done loading! ")
+ setPhotosLoading(false)
+ }
+ }, [rawPhotoArray, photos.length])
+
+
+
+
+ // For displaying photos full screen
+ const displayPhoto = async (photoUrl, photo) => {
+
+ setPhotoDetails({
+ // data: 'data:image/jpeg;base64,' + photoBinary,
+ data: photoUrl,
+ name: photo.photo_nm,
+ locationName: photo.network_location ? photo.network_location.location_nm : ""
+ })
+ setPhotoOpened(true)
+ }
+
+
+
+
+
+ return (
+ <>
+ setPhotoOpened(false)} title={photoDetails.name} size="full">
+ {photoDetails.locationName}{photoDetails.name}>: {photoDetails.name}}
+ withPlaceholder
+ />
+
+ Photos: {numPhotos}
+
+ {rawPhotoArray}
+
+ {photosLoading && }
+
+ >
+ )
+}
+
+export default PhotoDisplay
\ No newline at end of file
diff --git a/frontend/src/components/SideBar.js b/frontend/src/components/SideBar.js
index 73c8017..f67d6e2 100644
--- a/frontend/src/components/SideBar.js
+++ b/frontend/src/components/SideBar.js
@@ -13,8 +13,8 @@ const sideBarData = [
links: [
{ label: 'View Locations', link: '/locations' },
{ label: 'Add New Location', link: '/locations/new' },
- { label: 'Outlook', link: '/' },
- { label: 'Real time', link: '/' },
+ // { label: 'Outlook', link: '/' },
+ // { label: 'Real time', link: '/' },
],
},
{
@@ -24,11 +24,11 @@ const sideBarData = [
links: [
{ label: 'View Rooms', link: '/rooms' },
{ label: 'Add New Room', link: '/rooms/new' },
- { label: 'Releases schedule', link: '/'},
+ // { label: 'Releases schedule', link: '/'},
],
},
- { label: 'Cabinets', icon: BiCabinet, link: "/" },
- { label: 'Items', icon: BsDiagram2, link: "/" },
+ // { label: 'Cabinets', icon: BiCabinet, link: "/" },
+ // { label: 'Items', icon: BsDiagram2, link: "/" },
{ label: 'Settings', icon: GoGear, link: '/settings' },
];
diff --git a/frontend/src/components/Utilities.js b/frontend/src/components/Utilities.js
new file mode 100644
index 0000000..8bec69e
--- /dev/null
+++ b/frontend/src/components/Utilities.js
@@ -0,0 +1,33 @@
+import { IconAlertTriangle, IconAlertCircle, IconCheck } from '@tabler/icons'
+
+
+export const generateNotification = (notificationType, title, message, noClose, id) => {
+ // Generates the notification so you can push it to the queue
+ let baseNotification = {
+ id: id ? id : null,
+ dissallowClose: noClose ? noClose : false,
+ title: title,
+ message: message,
+ color: 'red',
+ icon: null,
+ }
+
+ switch (notificationType) {
+ case "error":
+ baseNotification.color = 'red'
+ baseNotification.icon =
+ break;
+ case "warning":
+ baseNotification.color = 'yellow'
+ baseNotification.icon =
+ break;
+ case "success":
+ baseNotification.color = 'green'
+ baseNotification.icon =
+ break;
+ default:
+ break;
+ }
+ console.log("MY NOTIFICATION: ", baseNotification)
+ return baseNotification
+}
\ No newline at end of file
diff --git a/frontend/src/components/cards/LocationCard.js b/frontend/src/components/cards/LocationCard.js
index 36af880..2a11e6b 100644
--- a/frontend/src/components/cards/LocationCard.js
+++ b/frontend/src/components/cards/LocationCard.js
@@ -1,8 +1,8 @@
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/state';
+// import { useNavigate } from "react-router-dom";
+import { serverConfigAtom } from '../../state/state';
import { Link } from 'react-router-dom';
@@ -10,10 +10,6 @@ import { Link } from 'react-router-dom';
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) {
@@ -25,11 +21,6 @@ function LocationCard(props) {
}
}
- const navigateToRooms = (locationID, locationName) => {
- setActivePage("rooms")
- setRoomsFilter({"filterType": "location", "locationID": locationID, "commonName": "location", "metadata": locationName})
- navigate("/rooms")
- }
return (
@@ -51,9 +42,8 @@ function LocationCard(props) {
{location.Description}
-
-
-
+
+
);
diff --git a/frontend/src/components/pages/LocationDetailsPage.js b/frontend/src/components/pages/Locations/LocationDetailsPage.js
similarity index 82%
rename from frontend/src/components/pages/LocationDetailsPage.js
rename to frontend/src/components/pages/Locations/LocationDetailsPage.js
index d108e0e..5da00e3 100644
--- a/frontend/src/components/pages/LocationDetailsPage.js
+++ b/frontend/src/components/pages/Locations/LocationDetailsPage.js
@@ -1,148 +1,170 @@
-import React, {useState, useEffect } from 'react';
-import { useAtom } from 'jotai'
-import { serverConfigAtom } from '../../state/state';
-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 (
- <>
- { isLoading && }
- {locationDetails.Name}
-
-
-
-
-
- Description:
- {locationDetails.Description}
-
-
-
-
-
-
- Notes:
- {locationDetails.Notes}
-
-
-
-
-
-
- Address:
- {locationDetails.Address}
-
-
-
-
-
-
- Square Feet:
- {locationDetails.SquareFeet}
-
-
-
-
-
-
- Lat/Long:
- {locationDetails.Latitude}/{locationDetails.Longitude}
-
-
-
-
-
-
- Date Purchased:
- {locationDetails.DatePurchased}
-
-
-
-
-
-
- Purchase Price:
- {locationDetails.PurchasePrice}
-
-
-
-
-
-
- Current Value:
- {locationDetails.CurrentValue}
-
-
-
-
-
-
- >
-
- );
-}
-
+import React, {useState, useEffect } from 'react';
+import { useAtom } from 'jotai'
+import { serverConfigAtom } from '../../../state/state';
+import { BsDoorClosed } from 'react-icons/bs';
+import { BiEdit } from 'react-icons/bi';
+import { Loader, Center, Title, Group, Button, Space, Container, ThemeIcon, Text, Image, Accordion, Avatar } 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 (
+ <>
+ { isLoading && }
+ {locationDetails.Name}
+ }>Edit Location
+
+
+
+
+ Description:
+ {locationDetails.Description}
+
+
+
+
+
+
+ Notes:
+ {locationDetails.Notes}
+
+
+
+
+
+
+ Address:
+ {locationDetails.Address}
+
+
+
+
+
+
+ Square Feet:
+ {locationDetails.SquareFeet}
+
+
+
+
+
+
+ Lat/Long:
+ {locationDetails.Latitude}/{locationDetails.Longitude}
+
+
+
+
+
+
+ Date Purchased:
+ {locationDetails.DatePurchased}
+
+
+
+
+
+
+ Purchase Price:
+ {locationDetails.PurchasePrice}
+
+
+
+
+
+
+ Current Value:
+ {locationDetails.CurrentValue}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Rooms
+
+ Rooms in this Location
+
+
+
+
+
+
+
+
+
+ >
+
+ );
+}
+
export default LocationDetailsPage;
\ No newline at end of file
diff --git a/frontend/src/components/pages/LocationsPage.js b/frontend/src/components/pages/Locations/LocationsPage.js
similarity index 90%
rename from frontend/src/components/pages/LocationsPage.js
rename to frontend/src/components/pages/Locations/LocationsPage.js
index 53d89b2..a64f7bf 100644
--- a/frontend/src/components/pages/LocationsPage.js
+++ b/frontend/src/components/pages/Locations/LocationsPage.js
@@ -1,76 +1,76 @@
-import React, {useState, useEffect } from 'react';
-import { useAtom } from 'jotai'
-import { serverConfigAtom } from '../../state/state';
-import { HiPlus } from 'react-icons/hi'
-import { Loader, Center, SimpleGrid, Title, Group, Button } from '@mantine/core'
-import { useNavigate } from "react-router-dom";
-import { useNotifications } from '@mantine/notifications';
-
-
-import { backendAPI } from '../../services/backend-api';
-import LocationCard from '../cards/LocationCard';
-
-
-function LocationsPage() {
- // const [opened, setOpened] = useState(false);
- const [isLoading, setIsLoading] = useState(false);
- const [locations, setLocations] = useState([])
- const [serverConfig] = useAtom(serverConfigAtom)
-
- let navigate = useNavigate();
-
-
-
- const notifications = useNotifications();
-
-
- useEffect(() => {
- console.log("LOADING LOCATIONS PAGE!")
- setIsLoading(true)
- async function fetchSettings() {
- backendAPI.get('/locations').then(results => {
- console.log("CONFIG IN LOCATIONS: ", serverConfig)
- console.log("LOCATIONS: ", results.data)
- setLocations(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();
-
-
- }, [])
-
- return (
- <>
- { isLoading && }
- Locations
- } onClick={(e) => {navigate("/locations/new")}}>Add New Location
-
- { locations.map((location, idx) =>
-
- )}
-
- >
-
- );
-}
-
+import React, {useState, useEffect } from 'react';
+import { useAtom } from 'jotai'
+import { serverConfigAtom } from '../../../state/state';
+import { HiPlus } from 'react-icons/hi'
+import { Loader, Center, SimpleGrid, Title, Group, Button } from '@mantine/core'
+import { useNavigate } from "react-router-dom";
+import { useNotifications } from '@mantine/notifications';
+
+
+import { backendAPI } from '../../../services/backend-api';
+import LocationCard from '../../cards/LocationCard';
+
+
+function LocationsPage() {
+ // const [opened, setOpened] = useState(false);
+ const [isLoading, setIsLoading] = useState(false);
+ const [locations, setLocations] = useState([])
+ const [serverConfig] = useAtom(serverConfigAtom)
+
+ let navigate = useNavigate();
+
+
+
+ const notifications = useNotifications();
+
+
+ useEffect(() => {
+ console.log("LOADING LOCATIONS PAGE!")
+ setIsLoading(true)
+ async function fetchSettings() {
+ backendAPI.get('/locations').then(results => {
+ console.log("CONFIG IN LOCATIONS: ", serverConfig)
+ console.log("LOCATIONS: ", results.data)
+ setLocations(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();
+
+
+ }, [])
+
+ return (
+ <>
+ { isLoading && }
+ Locations
+ } onClick={(e) => {navigate("/locations/new")}}>Add New Location
+
+ { locations.map((location, idx) =>
+
+ )}
+
+ >
+
+ );
+}
+
export default LocationsPage;
\ No newline at end of file
diff --git a/frontend/src/components/forms/LocationForm.js b/frontend/src/components/pages/Locations/NewLocationForm.js
similarity index 94%
rename from frontend/src/components/forms/LocationForm.js
rename to frontend/src/components/pages/Locations/NewLocationForm.js
index 1ce17e6..c7e4403 100644
--- a/frontend/src/components/forms/LocationForm.js
+++ b/frontend/src/components/pages/Locations/NewLocationForm.js
@@ -1,166 +1,166 @@
-import React, {useState, useEffect} from 'react';
-import { Text, Title, TextInput, Button, NumberInput, Textarea, Grid, Group, useMantineTheme, MantineTheme, Image, SimpleGrid } from '@mantine/core'
-import { DatePicker } from '@mantine/dates';
-import dayjs from 'dayjs';
-import { useForm } from '@mantine/form';
-import { useAtom } from 'jotai';
-import { serverConfigAtom } from '../../state/state'
-import { backendAPI } from '../../services/backend-api';
-import { IMAGE_MIME_TYPE } from '@mantine/dropzone';
-import CustomDropZone from '../CustomDropZone';
-
-
-
-function LocationForm(props) {
- const {location, modify: bool} = props
- const [opened, setOpened] = useState(false);
- const [serverConfig] = useAtom(serverConfigAtom)
- // Cover Photo
- const [coverPhoto, setCoverPhoto] = useState(null)
- // Additional Photos
- const [additionalPhotos, setAdditionalPhotos] = useState([])
-
- const theme = useMantineTheme();
-
-
- const form = useForm({
- initialValues: {
- Name: '',
- Description: '',
- Notes: '',
- Address: '',
- SquareFeet: '',
- Latitude: '',
- Longitude: '',
- DatePurchased: '',
- PurchasePrice: '',
- CurrentValue: '',
- CoverPhoto: '',
- AdditionalPhotos: [],
- },
-
- validate: {
- Name: (value) => (/^\S+/.test(value) ? null : 'Invalid Name')
- },
- });
-
-
-
- const submitNewLocation = (values) => {
- console.log("VALUES: ", values)
- // let additionalPhotos = values.AdditionalPhotos
- let formData = new FormData()
- for (const [key, value] of Object.entries(values)) {
- if (key === "AdditionalPhotos" && value.length > 0) {
- value.forEach(photo => {
- console.log("PHOTO VALUE: ", photo)
- formData.append(key, photo)
- });
- }
- formData.append(key, value)
- }
- backendAPI.post("/locations/new", formData).then((result) => {
- console.log("STATUS: ", result.status)
- console.log("result: ", result.data)
- }).catch(err => {
- console.log("Error adding new location!", err)
- })
- }
-
-
- const handleFileAccept = (files) => {
- form.setFieldValue('CoverPhoto', files[0])
- const imageUrl = URL.createObjectURL(files[0]);
- setCoverPhoto(
- URL.revokeObjectURL(imageUrl) }}
- />
- )
- }
-
- const handleAdditionalPhotos = (files) => {
- setAdditionalPhotos(oldPhotos => [...oldPhotos, ...files])
- // setAdditionalPhotos(files)
- console.log("FORM VALUES: ",form.values)
- const oldValues = form.values['AdditionalPhotos']
- form.setFieldValue('AdditionalPhotos', [...oldValues, ...files])
- console.log("NEW FORM VALUES: ", form.values)
-
- }
-
- const previews = additionalPhotos.map((file, index) => {
- console.log("FILE IS: ", file)
- const imageUrl = URL.createObjectURL(file);
- return (
- URL.revokeObjectURL(imageUrl) }}
- />
- )
- })
-
- return (
- <>
- Location Form
-
- >
-
- );
-}
-
-export default LocationForm;
\ No newline at end of file
+import React, {useState, useEffect} from 'react';
+import { Text, Title, TextInput, Button, NumberInput, Textarea, Grid, Group, useMantineTheme, MantineTheme, Image, SimpleGrid } from '@mantine/core'
+import { DatePicker } from '@mantine/dates';
+import dayjs from 'dayjs';
+import { useForm } from '@mantine/form';
+import { useAtom } from 'jotai';
+import { serverConfigAtom } from '../../../state/state'
+import { backendAPI } from '../../../services/backend-api';
+import { IMAGE_MIME_TYPE } from '@mantine/dropzone';
+import CustomDropZone from '../../CustomDropZone';
+
+
+
+function NewLocationForm(props) {
+ const {location, modify: bool} = props
+ const [opened, setOpened] = useState(false);
+ const [serverConfig] = useAtom(serverConfigAtom)
+ // Cover Photo
+ const [coverPhoto, setCoverPhoto] = useState(null)
+ // Additional Photos
+ const [additionalPhotos, setAdditionalPhotos] = useState([])
+
+ const theme = useMantineTheme();
+
+
+ const form = useForm({
+ initialValues: {
+ Name: '',
+ Description: '',
+ Notes: '',
+ Address: '',
+ SquareFeet: '',
+ Latitude: '',
+ Longitude: '',
+ DatePurchased: '',
+ PurchasePrice: '',
+ CurrentValue: '',
+ CoverPhoto: '',
+ AdditionalPhotos: [],
+ },
+
+ validate: {
+ Name: (value) => (/^\S+/.test(value) ? null : 'Invalid Name')
+ },
+ });
+
+
+
+ const submitNewLocation = (values) => {
+ console.log("VALUES: ", values)
+ // let additionalPhotos = values.AdditionalPhotos
+ let formData = new FormData()
+ for (const [key, value] of Object.entries(values)) {
+ if (key === "AdditionalPhotos" && value.length > 0) {
+ value.forEach(photo => {
+ console.log("PHOTO VALUE: ", photo)
+ formData.append(key, photo)
+ });
+ }
+ formData.append(key, value)
+ }
+ backendAPI.post("/locations/new", formData).then((result) => {
+ console.log("STATUS: ", result.status)
+ console.log("result: ", result.data)
+ }).catch(err => {
+ console.log("Error adding new location!", err)
+ })
+ }
+
+
+ const handleFileAccept = (files) => {
+ form.setFieldValue('CoverPhoto', files[0])
+ const imageUrl = URL.createObjectURL(files[0]);
+ setCoverPhoto(
+ URL.revokeObjectURL(imageUrl) }}
+ />
+ )
+ }
+
+ const handleAdditionalPhotos = (files) => {
+ setAdditionalPhotos(oldPhotos => [...oldPhotos, ...files])
+ // setAdditionalPhotos(files)
+ console.log("FORM VALUES: ",form.values)
+ const oldValues = form.values['AdditionalPhotos']
+ form.setFieldValue('AdditionalPhotos', [...oldValues, ...files])
+ console.log("NEW FORM VALUES: ", form.values)
+
+ }
+
+ const previews = additionalPhotos.map((file, index) => {
+ console.log("FILE IS: ", file)
+ const imageUrl = URL.createObjectURL(file);
+ return (
+ URL.revokeObjectURL(imageUrl) }}
+ />
+ )
+ })
+
+ return (
+ <>
+ Location Form
+
+ >
+
+ );
+}
+
+export default NewLocationForm;
\ No newline at end of file
diff --git a/frontend/src/components/sidebar/SidebarLinksGroup.js b/frontend/src/components/sidebar/SidebarLinksGroup.js
index 25ef904..d239152 100644
--- a/frontend/src/components/sidebar/SidebarLinksGroup.js
+++ b/frontend/src/components/sidebar/SidebarLinksGroup.js
@@ -1,8 +1,7 @@
-import { useEffect, useState } from 'react';
-import { Group, Box, Collapse, ThemeIcon, Text, UnstyledButton, createStyles } from '@mantine/core';
+import { useState } from 'react';
+import { Group, Box, Collapse, ThemeIcon, UnstyledButton, createStyles } from '@mantine/core';
import { BiChevronLeft, BiChevronRight } from 'react-icons/bi';
-import { NavLink, useLocation } from 'react-router-dom';
-import { NoEncryption } from '@material-ui/icons';
+import { NavLink } from 'react-router-dom';
const useStyles = createStyles((theme, _params, getRef) => {
const icon = getRef('icon');
@@ -61,7 +60,6 @@ const useStyles = createStyles((theme, _params, getRef) => {
export function LinksGroup({ icon: Icon, label, link, initiallyOpened, links }) {
- const mypath = useLocation()
const { classes, theme, cx } = useStyles();
const hasLinks = Array.isArray(links);
const [opened, setOpened] = useState(initiallyOpened || false);
@@ -78,9 +76,6 @@ export function LinksGroup({ icon: Icon, label, link, initiallyOpened, links })
{link.label}
));
-
- console.log("TOP LINK: ", link)
-
if (link) {
return (
<>
diff --git a/frontend/src/css/custom.css b/frontend/src/css/custom.css
index 3197898..aa18407 100644
--- a/frontend/src/css/custom.css
+++ b/frontend/src/css/custom.css
@@ -1,3 +1,17 @@
-body {
+/* body {
margin: 0px;
+} */
+
+body {
+ margin: 0;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
+ 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
+ sans-serif;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+code {
+font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
+ monospace;
}
\ No newline at end of file
diff --git a/frontend/src/index.js b/frontend/src/index.js
index 4b45b13..127b24b 100644
--- a/frontend/src/index.js
+++ b/frontend/src/index.js
@@ -1,9 +1,11 @@
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
+import './css/custom.css'
import reportWebVitals from './reportWebVitals';
import { NotificationsProvider } from '@mantine/notifications';
-import { Notifications } from './Notifications.js'
+import Notifications from './components/Notifications.js'
+import { MantineProvider } from '@mantine/core';
//setup api
//const backendPort = process.env.REACT_APP_BACKEND_PORT
@@ -11,10 +13,12 @@ import { Notifications } from './Notifications.js'
ReactDOM.render(
-
-
-
-
+
+
+
+
+
+
,
document.getElementById('root')
);
diff --git a/frontend/src/state/state.js b/frontend/src/state/state.js
index c42735e..572abd9 100644
--- a/frontend/src/state/state.js
+++ b/frontend/src/state/state.js
@@ -15,5 +15,5 @@ export const locationFilterAtom = atom({})
export const roomFilterAtom = atom({})
// Notification history and notification stack
-export const notificationHistory = atom([])
-export const notifications = atomWithReset([])
+export const notificationHistoryAtom = atom([])
+export const notificationQueueAtom = atomWithReset([])