frontend to backend communication working, starting on locations page
This commit is contained in:
21
frontend/apis/backend.js
Normal file
21
frontend/apis/backend.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import React, {useState, useEffect, useContext } from 'react';
|
||||
import APIContext from '../../App';
|
||||
import { Text } from '@mantine/core'
|
||||
import useSwr from 'swr';
|
||||
|
||||
|
||||
|
||||
function BackendAPI() {
|
||||
|
||||
const serverConfig = useContext(APIContext);
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<Text>This is the homepage!</Text>
|
||||
</>
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
export default BackendAPI;
|
5
frontend/package-lock.json
generated
5
frontend/package-lock.json
generated
@@ -10672,11 +10672,6 @@
|
||||
"resolved": "https://registry.npmjs.org/klona/-/klona-2.0.4.tgz",
|
||||
"integrity": "sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA=="
|
||||
},
|
||||
"ky": {
|
||||
"version": "0.28.7",
|
||||
"resolved": "https://registry.npmjs.org/ky/-/ky-0.28.7.tgz",
|
||||
"integrity": "sha512-a23i6qSr/ep15vdtw/zyEQIDLoUaKDg9Jf04CYl/0ns/wXNYna26zJpI+MeIFaPeDvkrjLPrKtKOiiI3IE53RQ=="
|
||||
},
|
||||
"language-subtag-registry": {
|
||||
"version": "0.3.21",
|
||||
"resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz",
|
||||
|
@@ -13,7 +13,6 @@
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
"base-64": "^1.0.0",
|
||||
"dayjs": "^1.10.7",
|
||||
"ky": "^0.28.7",
|
||||
"npm-check-updates": "^12.0.2",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
|
@@ -1,112 +1,88 @@
|
||||
import React, {useState, useEffect, useContext, createContext} from 'react';
|
||||
import base64 from 'base-64';
|
||||
import Home from './components/pages/Home';
|
||||
import React, {useState, useEffect, createContext} from 'react';
|
||||
import HomePage from './components/pages/HomePage';
|
||||
import Locations from './components/pages/Locations'
|
||||
import { Modal, Button, Text, Group, TextInput, Loader, AppShell } from '@mantine/core';
|
||||
import { useDebouncedValue, useLocalStorageValue } from '@mantine/hooks';
|
||||
import { useNotifications } from '@mantine/notifications';
|
||||
|
||||
import { backendAPI } from './services/backend-api';
|
||||
|
||||
|
||||
import SideBar from './components/SideBar';
|
||||
import AppHeader from './components/AppHeader';
|
||||
|
||||
|
||||
const defaultSettings = {"serverURL": window.location.href.slice(0, -1), "Timezone": "America/Detroit"}
|
||||
|
||||
|
||||
const APIContext = createContext();
|
||||
|
||||
|
||||
|
||||
|
||||
function App() {
|
||||
// Main nav/sidebar appshell openend
|
||||
const [shellOpened, setShellOpened] = useState(false)
|
||||
const [portModalOpen, setPortModalOpen] = useState(false)
|
||||
const [authModalOpen, setAuthModalOpen] = useState(false)
|
||||
const [isLoading, setIsLoading] = useState(true)
|
||||
const [currentPage, setCurrentPage] = useState("home")
|
||||
|
||||
// json.stringify({"serverURL": window.location.href.slice(0, -1), "Timezone": "America/Detroit"})
|
||||
const [serverConfigLS, setServerConfigLS] = useLocalStorageValue({key: 'serverConfig', defaultValue: JSON.stringify(defaultSettings)})
|
||||
const [serverConfig, setServerConfig] = useState(defaultSettings)
|
||||
const [serverConfig, setServerConfig] = useState({})
|
||||
|
||||
const [fullServerURL] = useDebouncedValue(serverConfig["serverURL"], 800);
|
||||
const notifications = useNotifications();
|
||||
|
||||
//headers.append("Authorization", "Basic " + base64.encode("user:password"));
|
||||
const user = "admin"
|
||||
const password = "password"
|
||||
|
||||
useEffect(() => {
|
||||
console.log("Checking local storage for server settings: ", JSON.parse(serverConfigLS))
|
||||
if(JSON.parse(serverConfigLS)) {
|
||||
setServerConfig(JSON.parse(serverConfigLS))
|
||||
}
|
||||
}, [serverConfigLS, setServerConfig])
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
setPortModalOpen(false)
|
||||
const lastChar = fullServerURL[fullServerURL.length - 1]
|
||||
let newURL = fullServerURL
|
||||
if (lastChar === "/") {
|
||||
newURL = fullServerURL.slice(0, -1)
|
||||
}
|
||||
console.log("Auto-discover URL attempted: ", `${newURL}/config`)
|
||||
fetch(`${newURL}/config`)
|
||||
.then(response => {
|
||||
console.log("RESPONSE: ", response)
|
||||
if (!response.ok) {
|
||||
console.log("Server not responding as expected, this should not happen!")
|
||||
setPortModalOpen(true)
|
||||
} else {
|
||||
response.json().then(data => {
|
||||
console.log("Connected to Server! ", data)
|
||||
setServerConfig({...serverConfig, "Timezone": data["Timezone"], "BasicAuth": data["BasicAuth"]})
|
||||
setServerConfigLS(JSON.stringify({...serverConfig, "Timezone": data["Timezone"], "BasicAuth": data["BasicAuth"]}))
|
||||
setPortModalOpen(false)
|
||||
setIsLoading(false)
|
||||
}).catch(err => {
|
||||
console.log("Server URL is incorrect, please change! ", err)
|
||||
setPortModalOpen(true)
|
||||
})
|
||||
}
|
||||
setIsLoading(true)
|
||||
async function fetchSettings() {
|
||||
backendAPI.get('/config').then(results => {
|
||||
console.log("CONFIG: ", results.data)
|
||||
results.data.baseURL = results.config.baseURL
|
||||
console.log("CONFIG: ", results.data)
|
||||
setServerConfig(results.data)
|
||||
notifications.showNotification({
|
||||
title: 'Backend Notice',
|
||||
message: 'Config fetched from backend!',
|
||||
color: "green"
|
||||
})
|
||||
setIsLoading(false)
|
||||
}).catch(err => {
|
||||
console.log("Server URL is incorrect, please change! ", err)
|
||||
setPortModalOpen(true)
|
||||
notifications.showNotification({
|
||||
title: 'Backend Notice',
|
||||
message: `Failed to connect to backend! ${err}`,
|
||||
autoClose: false,
|
||||
color: "red",
|
||||
})
|
||||
setIsLoading(false)
|
||||
})
|
||||
|
||||
}, [fullServerURL])
|
||||
|
||||
useEffect(() => {
|
||||
console.log("Loading Server Config: ", serverConfig)
|
||||
if (serverConfig["BasicAuth"]) {
|
||||
console.log("Looks like auth is required!")
|
||||
//setAuthModalOpen(true)
|
||||
}
|
||||
}, [serverConfig])
|
||||
fetchSettings();
|
||||
|
||||
|
||||
}, [])
|
||||
|
||||
|
||||
function showPage() {
|
||||
switch (currentPage) {
|
||||
case "home":
|
||||
return <HomePage />
|
||||
case "locations":
|
||||
return <Locations />
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<APIContext.Provider value={{...serverConfig}}>
|
||||
<AppShell
|
||||
navbarOffsetBreakpoint="sm" // navbarOffsetBreakpoint controls when navbar should no longer be offset with padding-left
|
||||
fixed // fixed prop on AppShell will be automatically added to Header and Navbar
|
||||
navbar={<SideBar opened={shellOpened}/>}
|
||||
header={<AppHeader opened={shellOpened} setOpened={setShellOpened}/>}
|
||||
>
|
||||
<Text>Resize app to see responsive navbar in action</Text>
|
||||
</AppShell>
|
||||
<Modal
|
||||
opened={portModalOpen}
|
||||
onClose={() => setPortModalOpen(false)}
|
||||
title="Communication Failed, server URL may not be what was expected!"
|
||||
>
|
||||
<Text>Guessed Server URL: {serverConfig["serverURL"]} does not appear to be correct, please enter correct url.</Text>
|
||||
<TextInput label="Server URL" value={serverConfig["serverURL"]} onChange={(e) => setServerConfig({...serverConfig, "serverURL": e.currentTarget.value})} required></TextInput>
|
||||
</Modal>
|
||||
<Modal opened={authModalOpen} onClose={() => setAuthModalOpen(false)} title="Please Login!">
|
||||
<TextInput label="UserName" value={serverConfig["serverURL"]} onChange={(e) => setServerConfig({"ServerURL": e.currentTarget.value})} required></TextInput>
|
||||
<TextInput label="UserName" type="password" value={serverConfig["serverURL"]} onChange={(e) => setServerConfig({"ServerURL": e.currentTarget.value})} required></TextInput>
|
||||
</Modal>
|
||||
{isLoading ? <Group position="center"><Loader size="xl"></Loader></Group> : <div>Welcome to goInventorize!</div>}
|
||||
|
||||
|
||||
|
||||
<AppShell
|
||||
navbarOffsetBreakpoint="sm" // navbarOffsetBreakpoint controls when navbar should no longer be offset with padding-left
|
||||
fixed // fixed prop on AppShell will be automatically added to Header and Navbar
|
||||
navbar={<SideBar opened={shellOpened} setCurrentPage={setCurrentPage}/>}
|
||||
header={<AppHeader opened={shellOpened} setOpened={setShellOpened}/>}
|
||||
>
|
||||
{showPage()}
|
||||
</AppShell>
|
||||
</APIContext.Provider>
|
||||
|
||||
);
|
||||
|
@@ -21,7 +21,7 @@ function AppHeader(props) {
|
||||
/>
|
||||
</MediaQuery>
|
||||
<Group>
|
||||
<ThemeIcon size="xl"><BsHouseDoor /></ThemeIcon>
|
||||
<BsHouseDoor size={30} />
|
||||
<Title><Text inherit variant="gradient" gradient={{ from: 'indigo', to: 'cyan', deg: 45 }}>goInventorize</Text></Title>
|
||||
</Group>
|
||||
|
||||
|
@@ -1,12 +1,26 @@
|
||||
import React, {useState } from 'react';
|
||||
import { Navbar, Text, Group, ThemeIcon, Button } from '@mantine/core';
|
||||
import { Navbar, Text, Group, ThemeIcon, Button, UnstyledButton } from '@mantine/core';
|
||||
import { createStyles } from '@mantine/styles';
|
||||
import { BsMap } from 'react-icons/bs'
|
||||
import {BrowserRouter as Router, Routes, Route, Link} from 'react-router-dom'
|
||||
|
||||
|
||||
const useStyles = createStyles((theme) => ({
|
||||
button: {
|
||||
display: 'block',
|
||||
width: '100%',
|
||||
padding: theme.spacing.xs,
|
||||
borderRadius: theme.radius.sm,
|
||||
color: theme.colorScheme === 'dark' ? theme.colors.dark[0] : theme.black,
|
||||
backgroundColor: 'transparent',
|
||||
|
||||
'&:hover': {
|
||||
backgroundColor: theme.colorScheme === 'dark' ? theme.colors.dark[6] : theme.colors.gray[0],
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
function SideBar(props) {
|
||||
|
||||
const { classes } = useStyles();
|
||||
|
||||
return (
|
||||
<Navbar
|
||||
@@ -17,14 +31,13 @@ function SideBar(props) {
|
||||
hidden={!props.opened}
|
||||
width={{ base: 200, breakpoints: { sm: '100%', lg: 300 } }}
|
||||
>
|
||||
<Router>
|
||||
<Routes>
|
||||
<Route path="/" element={<Home />} />
|
||||
</Routes>
|
||||
<Button component={Link} to="/locations" leftIcon={<ThemeIcon><BsMap /></ThemeIcon>}>
|
||||
<Text>Locations</Text>
|
||||
</Button>
|
||||
</Router>
|
||||
<UnstyledButton className={classes.button} onClick={() => props.setCurrentPage("locations")} >
|
||||
<Group>
|
||||
<BsMap />
|
||||
<Text>Locations</Text>
|
||||
</Group>
|
||||
|
||||
</UnstyledButton>
|
||||
|
||||
</Navbar>
|
||||
)
|
||||
|
@@ -1,10 +1,10 @@
|
||||
import React, {useState, useEffect, useContext, createContext} from 'react';
|
||||
import APIContext from '../../App';
|
||||
import { Text } from '@mantine/core'
|
||||
|
||||
|
||||
|
||||
|
||||
function App() {
|
||||
function HomePage() {
|
||||
const [opened, setOpened] = useState(false);
|
||||
|
||||
const serverConfig = useContext(APIContext);
|
||||
@@ -12,9 +12,10 @@ function App() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Text>This is the homepage!</Text>
|
||||
</>
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
export default HomePage;
|
@@ -0,0 +1,70 @@
|
||||
import React, {useState, useEffect, useContext, createContext} from 'react';
|
||||
import APIContext from '../../App';
|
||||
import { Text, Loader, Center, Card, Image, Badge, Button, SimpleGrid, Group } from '@mantine/core'
|
||||
import { useNotifications } from '@mantine/notifications';
|
||||
|
||||
import { backendAPI } from '../../services/backend-api';
|
||||
|
||||
|
||||
function LocationsPage() {
|
||||
// const [opened, setOpened] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [locations, setLocations] = useState([])
|
||||
const [baseURL, setBaseURL] = useState("")
|
||||
|
||||
const serverConfig = useContext(APIContext);
|
||||
|
||||
const notifications = useNotifications();
|
||||
|
||||
useEffect(() => {
|
||||
setIsLoading(true)
|
||||
async function fetchSettings() {
|
||||
backendAPI.get('/locations').then(results => {
|
||||
console.log("CONFIG: ", serverConfig)
|
||||
//console.log("baseurl: ", results.config.baseURL)
|
||||
setBaseURL(results.config.baseURL)
|
||||
console.log("URL", `${results.data[0]}`)
|
||||
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 (
|
||||
<>
|
||||
<Center>{ isLoading && <Loader size="xl" variant="bars" />}</Center>
|
||||
<SimpleGrid cols={4} spacing="xl">
|
||||
{ locations.map((location, idx) =>
|
||||
<Card key={idx} shadow="sm" padding="md">
|
||||
<Card.Section>
|
||||
<Image src={`${serverConfig.baseURL}/photos/locations/${location.Name}/${location.CoverPhoto}`}></Image>
|
||||
</Card.Section>
|
||||
<Group position="apart">
|
||||
<Text weight={500}>{location.Name}</Text>
|
||||
<Badge color="pink" variant="light">
|
||||
On Sale
|
||||
</Badge>
|
||||
</Group>
|
||||
<Text size="sm">{location.Description}</Text>
|
||||
</Card>
|
||||
)}
|
||||
</SimpleGrid>
|
||||
</>
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
export default LocationsPage;
|
@@ -2,14 +2,17 @@ import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import App from './App';
|
||||
import reportWebVitals from './reportWebVitals';
|
||||
import { NotificationsProvider } from '@mantine/notifications';
|
||||
|
||||
//setup api
|
||||
const backendPort = process.env.REACT_APP_BACKEND_PORT
|
||||
console.log("BACKEND PORT: ", backendPort)
|
||||
//const backendPort = process.env.REACT_APP_BACKEND_PORT
|
||||
//console.log("BACKEND PORT: ", backendPort)
|
||||
|
||||
ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
<React.StrictMode>
|
||||
<NotificationsProvider>
|
||||
<App />
|
||||
</NotificationsProvider>
|
||||
</React.StrictMode>,
|
||||
document.getElementById('root')
|
||||
);
|
||||
|
@@ -1,12 +1,13 @@
|
||||
import ky from 'ky';
|
||||
import axios from 'axios';
|
||||
|
||||
const url = 'https://sindresorhus.com';
|
||||
const backendPort = 3500
|
||||
|
||||
const backendAPI = ky.create({
|
||||
headers: {
|
||||
rainbow: 'rainbow',
|
||||
unicorn: 'unicorn'
|
||||
}
|
||||
});
|
||||
let baseURL = ""
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
baseURL = 'http://localhost:3500'
|
||||
}
|
||||
|
||||
export const backendAPI = axios.create({
|
||||
baseURL: baseURL
|
||||
})
|
||||
|
||||
|
Reference in New Issue
Block a user