Skip to content

Commit

Permalink
Merge pull request #493 from bounswe/feature/frontend_integrate_map_b…
Browse files Browse the repository at this point in the history
…ackend

Implement category trees and integrate with backend for map page. Add victim page with quick add need
  • Loading branch information
kubraaksux authored Nov 27, 2023
2 parents 048b39d + b11fee7 commit 898aee3
Show file tree
Hide file tree
Showing 13 changed files with 539 additions and 614 deletions.
1 change: 1 addition & 0 deletions resq/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"@mui/styled-engine": "^5.14.14",
"@mui/x-data-grid": "^6.18.1",
"@mui/x-date-pickers": "^6.18.2",
"@tanstack/react-query": "^5.8.7",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
Expand Down
198 changes: 106 additions & 92 deletions resq/frontend/src/App.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import React, { useEffect, useRef, useState } from 'react';
import { BrowserRouter as Router, Routes, Route, Navigate } from "react-router-dom";
import { Navbar, Container, Nav } from 'react-bootstrap';
import React, {useEffect, useRef, useState} from 'react';
import {BrowserRouter as Router, Routes, Route, Navigate} from "react-router-dom";
import {Navbar, Container, Nav} from 'react-bootstrap';
import UserRoles from "./pages/UserRoles";
import SignIn from "./pages/SignIn";
import SignUp from "./pages/SignUp";
import MapDemo from "./pages/MapDemo";
import MapPage from "./pages/MapPage";
import Account from "./pages/Account";
import RoleRequest from "./pages/RoleRequest";
import LogoutIcon from '@mui/icons-material/Logout';
import Request from "./pages/RequestCreation";
import Resource from "./pages/ResourceCreation";
import { LocalizationProvider } from "@mui/x-date-pickers";
import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs";
import {LocalizationProvider} from "@mui/x-date-pickers";
import {AdapterDayjs} from "@mui/x-date-pickers/AdapterDayjs";
import {QueryClient, QueryClientProvider} from "@tanstack/react-query";
import axios from "axios";
import VictimMapPage from "./pages/VictimMapPage";

const SmallRedCircle = () =>
<svg
Expand All @@ -20,9 +23,11 @@ const SmallRedCircle = () =>
height="20"
viewBox="0 0 20 20"
>
<circle cx="10" cy="10" r="8" fill="red" />
<circle cx="10" cy="10" r="8" fill="red"/>
</svg>

const queryClient = new QueryClient()

function App() {
const [token, _setToken] = useState(localStorage.getItem("token"))
const [role, setRole] = useState("")
Expand All @@ -35,24 +40,28 @@ function App() {
return () => window.removeEventListener("resize", updateDimensions);
}, []);

useEffect(() => {
axios.defaults.headers.common['Authorization'] = `Bearer ${token}`
}, [token])

const setToken = t => {
localStorage.setItem("token", t || "")
_setToken(t)
}

const navLinks = [
{ path: '/map', label: <strong>Map Demo</strong>, component: MapDemo, icon: <SmallRedCircle /> },
{path: '/map', label: <strong>Map Demo</strong>, component: VictimMapPage, icon: <SmallRedCircle/>},
token && {
path: '/userroles',
label: <strong>User Roles</strong>,
component: UserRoles,
icon: <SmallRedCircle />
icon: <SmallRedCircle/>
},
(role === "responder") && {
path: '/responder',
label: <strong>Responder Panel</strong>,
component: <div>Responder Panel</div>,
icon: <SmallRedCircle />
icon: <SmallRedCircle/>
},
].filter(l => !!l);

Expand All @@ -63,90 +72,95 @@ function App() {
const ref = useRef(null)

return (
<LocalizationProvider dateAdapter={AdapterDayjs}>
<Router>
<div>
<Navbar bg="light" variant="light" expand="lg">
<Container ref={ref}>
<Navbar.Brand href="/" style={{ color: 'red', fontWeight: 'bold' }}>
<SmallRedCircle />
ResQ
</Navbar.Brand>
<Navbar.Toggle aria-controls="basic-navbar-nav" />
<Navbar.Collapse id="basic-navbar-nav">
<Nav className="me-auto">
{navLinks.map(({ path, label, icon }) => (
<Nav.Link key={path} href={path}>
{icon}
{label}
</Nav.Link>
))}
</Nav>
<Nav className="ml-auto">
{token ?
<>
<Nav.Link key={"/account"} href={"/account"} style={{ "marginLeft": "auto" }}>
<SmallRedCircle />
<strong>Account</strong>
</Nav.Link>
<Nav.Link key={"/requestcreation"} href={"/requestcreation"}
style={{ "marginLeft": "auto" }}>
<SmallRedCircle />
<strong>Create Request</strong>
</Nav.Link>
<Nav.Link key={"/resourcecreation"} href={"/resourcecreation"}
style={{ "marginLeft": "auto" }}>
<SmallRedCircle />
<strong>Create Resource</strong>
</Nav.Link>
<Nav.Link key={"signout"} href={"#"} onClick={signOut}
style={{ "marginLeft": "auto" }}>
<LogoutIcon />
</Nav.Link>
</> :
<>
<Nav.Link key={'/signin'} href={'/signin'} style={{ "marginLeft": "auto" }}>
<strong>Sign In</strong>
</Nav.Link>
<Nav.Link key={'/signup'} href={'/signup'} style={{ "marginLeft": "auto" }}>
<strong>Sign Up</strong>
<QueryClientProvider client={queryClient}>
<LocalizationProvider dateAdapter={AdapterDayjs}>
<Router>
<div>
<Navbar bg="light" variant="light" expand="lg">
<Container ref={ref}>
<Navbar.Brand href="/" style={{color: 'red', fontWeight: 'bold'}}>
<SmallRedCircle/>
ResQ
</Navbar.Brand>
<Navbar.Toggle aria-controls="basic-navbar-nav"/>
<Navbar.Collapse id="basic-navbar-nav">
<Nav className="me-auto">
{navLinks.map(({path, label, icon}) => (
<Nav.Link key={path} href={path}>
{icon}
{label}
</Nav.Link>
))}
</Nav>
<Nav className="ml-auto">
{token ?
<>
<Nav.Link key={"/account"} href={"/account"}
style={{"marginLeft": "auto"}}>
<SmallRedCircle/>
<strong>Account</strong>
</Nav.Link>
<Nav.Link key={"/requestcreation"} href={"/requestcreation"}
style={{"marginLeft": "auto"}}>
<SmallRedCircle/>
<strong>Create Request</strong>
</Nav.Link>
<Nav.Link key={"/resourcecreation"} href={"/resourcecreation"}
style={{"marginLeft": "auto"}}>
<SmallRedCircle/>
<strong>Create Resource</strong>
</Nav.Link>
<Nav.Link key={"signout"} href={"#"} onClick={signOut}
style={{"marginLeft": "auto"}}>
<LogoutIcon/>
</Nav.Link>
</> :
<>
<Nav.Link key={'/signin'} href={'/signin'}
style={{"marginLeft": "auto"}}>
<strong>Sign In</strong>
</Nav.Link>
<Nav.Link key={'/signup'} href={'/signup'}
style={{"marginLeft": "auto"}}>
<strong>Sign Up</strong>
</Nav.Link>
</>
}
</Nav>
</Navbar.Collapse>
</Container>
</Navbar>
<main style={{height: `${height - 57}px`}}>
<Routes>
{navLinks.map(({path, component}) => (
<Route key={path} path={path}
element={React.createElement(component, {token, setToken, role, setRole})}/>
))}
<Route path="/" element={<Navigate to="/map"/>}/>
<Route path="/rolerequest" state={{token, setToken}}
element={React.createElement(RoleRequest, {token, setToken})}/>
{
token ? <>
<Route path="/account" state={{token, setToken}}
element={React.createElement(Account, {token, setToken})}/>
<Route path="/requestcreation" state={{token, setToken}}
element={React.createElement(Request, {token, setToken})}/>
<Route path="/resourcecreation" state={{token, setToken}}
element={React.createElement(Request, {token, setToken})}/>
</>
: <>
<Route path="/signin" state={{token, setToken}}
element={React.createElement(SignIn, {token, setToken})}/>
<Route path="/signup" state={{token, setToken}}
element={React.createElement(SignUp, {token, setToken})}/>
</>
}
</Nav>
</Navbar.Collapse>
</Container>
</Navbar>
<main style={{ height: `${height - 57}px` }}>
<Routes>
{navLinks.map(({ path, component }) => (
<Route key={path} path={path}
element={React.createElement(component, { token, setToken, role, setRole })} />
))}
<Route path="/" element={<Navigate to="/map" />} />
<Route path="/rolerequest" state={{ token, setToken }}
element={React.createElement(RoleRequest, { token, setToken })} />
{
token ? <>
<Route path="/account" state={{ token, setToken }}
element={React.createElement(Account, { token, setToken })} />
<Route path="/requestcreation" state={{ token, setToken }}
element={React.createElement(Request, { token, setToken })} />
<Route path="/resourcecreation" state={{ token, setToken }}
element={React.createElement(Request, { token, setToken })} />
</>
: <>
<Route path="/signin" state={{ token, setToken }}
element={React.createElement(SignIn, { token, setToken })} />
<Route path="/signup" state={{ token, setToken }}
element={React.createElement(SignUp, { token, setToken })} />
</>
}
</Routes>
</main>
</div>
</Router>
</LocalizationProvider>
}
</Routes>
</main>
</div>
</Router>
</LocalizationProvider>
</QueryClientProvider>
);
}

Expand Down
28 changes: 26 additions & 2 deletions resq/frontend/src/AppService.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import axios from 'axios';
import {RootNode} from "./CategoryTree";

const API_BASE_URL = 'https://api.resq.org.tr'
const USER_API_BASE_URL = API_BASE_URL + '/resq/api/v1/user';
Expand All @@ -19,8 +20,13 @@ export function postRequestRole(userId, role) {
return axios.post(`${USER_API_BASE_URL}/requestRole`, requestBody);
}

export function getUserInfo(userId) {
return axios.get(`${USER_API_BASE_URL}/getUserInfo?userId=${userId}`);
export async function getUserInfo(userId) {
const {data} = await axios.get(`${USER_API_BASE_URL}/getUserInfo?userId=${userId}`, {
headers: {
"X-Selected-Role": "VICTIM"
},
});
return data
}

export function getAllAccess() {
Expand Down Expand Up @@ -123,6 +129,24 @@ export function createResource(createResourceRequest) {
return axios.post(`${RESOURCE_API_BASE_URL}/createResource`, createResourceRequest);
}

export function getAllResources() {
return axios.get(`${RESOURCE_API_BASE_URL}/filterByDistance?latitude=39.5&longitude=34.5&distance=10000`, {
headers: {
"X-Selected-Role": "COORDINATOR"
},
});
}

export async function getCategoryTree() {
const {data} = await axios.get(`${CATEGORY_API_BASE_URL}/getMainCategories`, {
headers: {
"X-Selected-Role": "VICTIM"
},
});

return new RootNode(data)
}

export function createTask(createTaskRequest) {
return axios.post(`${TASK_API_BASE_URL}/createTask`, createTaskRequest);
}
Expand Down
56 changes: 56 additions & 0 deletions resq/frontend/src/CategoryTree.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
export class Node {
id
data
children
parent

constructor(id, data, children, parent) {
this.id = id
this.data = data
this.children = children
this.parent = parent
}

getAllParentCategories() {
if (this.parent.data === "")
return [this]
return [this, ...this.parent.getAllParentCategories()]
}

findCategoryWithId(id) {
if (this.id === id) {
return this
} else {
for(const child of this.children){
let cat = child.findCategoryWithId(id)
if (cat)
return cat
}
return null
}
}

isChildCategory(id) {
if (this.id === id) {
return true
} else {
return !this.children.every(child => !child.isChildCategory(id))
}
}

static createFromArray(json, parent) {
return json.map(item => {
const children = []
const node = new Node(item.id, item.data, children, parent)
children.push(...Node.createFromArray(item.children, node))
return node
})
}
}

export class RootNode extends Node {
constructor(json) {
super("-1", "", [], null);
this.children.push(...Node.createFromArray(json, this))
}
}
Loading

0 comments on commit 898aee3

Please sign in to comment.