Fixed API folder name

This commit is contained in:
Richárd Kunkli
2020-10-25 16:56:44 +01:00
parent c837f592d0
commit 853f05d63c
50 changed files with 1 additions and 1 deletions

View File

@ -0,0 +1,7 @@
{
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 6,
"sourceType": "module"
}
}

21
Birdmap.API/ClientApp/.gitignore vendored Normal file
View File

@ -0,0 +1,21 @@
# See https://help.github.com/ignore-files/ for more about ignoring files.
# dependencies
/node_modules
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*

File diff suppressed because it is too large Load Diff

14426
Birdmap.API/ClientApp/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,61 @@
{
"name": "birdmap",
"version": "0.1.0",
"private": true,
"dependencies": {
"@material-ui/core": "^4.11.0",
"@material-ui/lab": "^4.0.0-alpha.56",
"bootstrap": "^4.3.1",
"connected-react-router": "6.5.2",
"history": "4.10.1",
"jquery": "^3.5.1",
"merge": "1.2.1",
"popper.js": "^1.16.0",
"react": "16.11.0",
"react-dom": "16.11.0",
"react-redux": "7.1.1",
"react-router": "5.1.2",
"react-router-dom": "5.1.2",
"react-scripts": "^3.4.4",
"reactstrap": "8.1.1",
"redux": "4.0.4",
"redux-thunk": "2.3.0",
"svgo": "1.3.0"
},
"devDependencies": {
"@types/history": "4.7.3",
"@types/jest": "24.0.19",
"@types/node": "12.11.6",
"@types/react": "16.9.9",
"@types/react-dom": "16.9.2",
"@types/react-redux": "7.1.5",
"@types/react-router": "5.1.2",
"@types/react-router-dom": "5.1.0",
"@types/reactstrap": "8.0.6",
"@typescript-eslint/parser": "^2.5.0",
"cross-env": "6.0.3",
"eslint": "^6.5.1",
"eslint-plugin-flowtype": "^3.13.0",
"eslint-plugin-import": "2.18.2",
"eslint-plugin-jsx-a11y": "6.2.3",
"eslint-plugin-react": "7.16.0",
"nan": "^2.14.1",
"typescript": "3.6.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "cross-env CI=true react-scripts test --env=jsdom",
"eject": "react-scripts eject",
"lint": "eslint ./src/**/*.ts ./src/**/*.tsx"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": [
">0.2%",
"not dead",
"not ie <= 11",
"not op_mini all"
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

@ -0,0 +1,41 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<base href="%PUBLIC_URL%/" />
<!--
manifest.json provides metadata used when your web app is added to the
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>Birdmap</title>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>

View File

@ -0,0 +1,15 @@
{
"short_name": "Birdmap",
"name": "Birdmap",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
}
],
"start_url": "./index.html",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

View File

@ -0,0 +1,31 @@
"use strict";
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
Object.defineProperty(exports, "__esModule", { value: true });
var React = require("react");
var ReactDOM = require("react-dom");
var react_redux_1 = require("react-redux");
var react_router_dom_1 = require("react-router-dom");
var App_1 = require("./App");
it('renders without crashing', function () {
var storeFake = function (state) { return ({
default: function () { },
subscribe: function () { },
dispatch: function () { },
getState: function () { return (__assign({}, state)); }
}); };
var store = storeFake({});
ReactDOM.render(React.createElement(react_redux_1.Provider, { store: store },
React.createElement(react_router_dom_1.MemoryRouter, null,
React.createElement(App_1.default, null))), document.createElement('div'));
});
//# sourceMappingURL=App.test.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"App.test.js","sourceRoot":"","sources":["App.test.tsx"],"names":[],"mappings":";;;;;;;;;;;;;AAAA,6BAA+B;AAC/B,oCAAsC;AACtC,2CAAuC;AACvC,qDAAgD;AAChD,6BAAwB;AAExB,EAAE,CAAC,0BAA0B,EAAE;IAC3B,IAAM,SAAS,GAAG,UAAC,KAAU,IAAK,OAAA,CAAC;QAC/B,OAAO,EAAE,cAAO,CAAC;QACjB,SAAS,EAAE,cAAO,CAAC;QACnB,QAAQ,EAAE,cAAO,CAAC;QAClB,QAAQ,EAAE,cAAM,OAAA,cAAM,KAAK,EAAG,EAAd,CAAc;KACjC,CAAC,EALgC,CAKhC,CAAC;IACH,IAAM,KAAK,GAAG,SAAS,CAAC,EAAE,CAAQ,CAAC;IAEnC,QAAQ,CAAC,MAAM,CACX,oBAAC,sBAAQ,IAAC,KAAK,EAAE,KAAK;QAClB,oBAAC,+BAAY;YACT,oBAAC,aAAG,OAAE,CACK,CACR,EAAE,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;AACpD,CAAC,CAAC,CAAC"}

View File

@ -0,0 +1,22 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { MemoryRouter } from 'react-router-dom';
import App from './App';
it('renders without crashing', () => {
const storeFake = (state: any) => ({
default: () => {},
subscribe: () => {},
dispatch: () => {},
getState: () => ({ ...state })
});
const store = storeFake({}) as any;
ReactDOM.render(
<Provider store={store}>
<MemoryRouter>
<App/>
</MemoryRouter>
</Provider>, document.createElement('div'));
});

View File

@ -0,0 +1,146 @@
import { Box, Container } from '@material-ui/core';
import AppBar from '@material-ui/core/AppBar';
import blue from '@material-ui/core/colors/blue';
import orange from '@material-ui/core/colors/orange';
import { createMuiTheme, createStyles, makeStyles, Theme } from '@material-ui/core/styles';
import Toolbar from '@material-ui/core/Toolbar';
import Typography from '@material-ui/core/Typography';
import { ThemeProvider } from '@material-ui/styles';
import React, { useState } from 'react';
import { BrowserRouter, NavLink, Redirect, Route, Switch } from 'react-router-dom';
import BirdmapTitle from './common/components/BirdmapTitle';
import Auth from './components/auth/Auth';
import AuthService from './components/auth/AuthService';
const theme = createMuiTheme({
palette: {
primary: {
main: blue[900],
},
secondary: {
main: orange[200],
}
},
});
function App() {
const [authenticated, setAuthenticated] = useState(AuthService.isAuthenticated());
const onAuthenticated = () => {
setAuthenticated(AuthService.isAuthenticated());
};
const AuthComponent = () => {
return (
<Auth onAuthenticated={onAuthenticated} />
);
}
const DashboardComponent = () => {
return <Typography>Dashboard</Typography>;
};
const DevicesComponent = () => {
return <Typography>Devices</Typography>;
};
const HeatmapComponent = () => {
return <Typography>Heatmap</Typography>;
};
return (
<ThemeProvider theme={theme}>
<BrowserRouter>
<Switch>
<PublicRoute path="/login" component={AuthComponent} />
<PrivateRoute path="/" exact authenticated={authenticated} component={DashboardComponent} />
<PrivateRoute path="/devices" exact authenticated={authenticated} component={DevicesComponent} />
<PrivateRoute path="/heatmap" exact authenticated={authenticated} component={HeatmapComponent} />
</Switch>
</BrowserRouter>
</ThemeProvider>
);
}
export default App;
const PublicRoute = ({ component: Component, ...rest }: { [x: string]: any, component: any}) => {
return (
<Route {...rest} render={matchProps => (
<DefaultLayout component={Component} authenticated={false} {...matchProps} />
)} />
);
}
const PrivateRoute = ({ component: Component, authenticated: Authenticated, ...rest }: { [x: string]: any, component: any, authenticated: any }) => {
return (
<Route {...rest} render={matchProps => (
Authenticated
? <DefaultLayout component={Component} authenticated={Authenticated} {...matchProps} />
: <Redirect to='/login' />
)} />
);
};
const DefaultLayout = ({ component: Component, authenticated: Authenticated, ...rest }: { [x: string]: any, component: any, authenticated: any }) => {
const classes = useDefaultLayoutStyles();
const renderNavLinks = () => {
return Authenticated
? <Container className={classes.nav_menu}>
<NavLink exact to="/" className={classes.nav_menu_item} activeClassName={classes.nav_menu_item_active}>Dashboard</NavLink>
<NavLink exact to="/devices" className={classes.nav_menu_item} activeClassName={classes.nav_menu_item_active}>Devices</NavLink>
<NavLink exact to="/heatmap" className={classes.nav_menu_item} activeClassName={classes.nav_menu_item_active}>Heatmap</NavLink>
</Container>
: null;
};
return (
<React.Fragment>
<AppBar position="static">
<Toolbar>
<BirdmapTitle />
<Typography component={'span'} className={classes.typo}>
{renderNavLinks()}
</Typography>
</Toolbar>
</AppBar>
<Box style={{ margin: '32px' }}>
<Component {...rest} />
</Box>
</React.Fragment>
);
};
const useDefaultLayoutStyles = makeStyles((theme: Theme) =>
createStyles({
typo: {
marginLeft: 'auto',
color: 'white',
},
nav_menu: {
display: 'flex',
flexDirection: 'row',
},
nav_menu_item: {
textDecoration: 'none',
fontWeight: 'normal',
color: 'inherit',
marginLeft: '24px',
'&:hover': {
color: 'inherit',
}
},
nav_menu_item_active: {
textDecoration: 'underline',
fontWeight: 'bold',
color: 'inherit',
marginLeft: '24px',
'&:hover': {
color: 'inherit',
}
},
}),
);

View File

@ -0,0 +1,14 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var ErrorDispatcher = {
errorHandlers: [],
registerErrorHandler: function (errorHandlerFn) {
this.errorHandlers.push(errorHandlerFn);
},
raiseError: function (errorMessage) {
for (var i = 0; i < this.errorHandlers.length; i++)
this.errorHandlers[i](errorMessage);
}
};
exports.default = ErrorDispatcher;
//# sourceMappingURL=ErrorDispatcher.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"ErrorDispatcher.js","sourceRoot":"","sources":["ErrorDispatcher.ts"],"names":[],"mappings":";;AAAA,IAAM,eAAe,GAAG;IACtB,aAAa,EAAE,EAAE;IAEjB,oBAAoB,YAAC,cAAc;QACjC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC1C,CAAC;IAED,UAAU,YAAC,YAAY;QACrB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC,EAAE;YAChD,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;IACxC,CAAC;CACF,CAAC;AAEF,kBAAe,eAAe,CAAC"}

View File

@ -0,0 +1,14 @@
const ErrorDispatcher = {
errorHandlers: [],
registerErrorHandler(errorHandlerFn) {
this.errorHandlers.push(errorHandlerFn);
},
raiseError(errorMessage) {
for (let i = 0; i < this.errorHandlers.length; i++)
this.errorHandlers[i](errorMessage);
}
};
export default ErrorDispatcher;

View File

@ -0,0 +1,50 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var ErrorDispatcher_1 = require("./ErrorDispatcher");
function get(url) {
var options = {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': sessionStorage.getItem('user')
}
};
return makeRequest(url, options);
}
function post(url, request) {
var options = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': sessionStorage.getItem('user')
},
body: "",
};
if (request)
options.body = JSON.stringify(request);
return makeRequest(url, options);
}
function makeRequest(url, options) {
return fetch(url, options)
.then(ensureResponseSuccess)
.catch(errorHandler);
}
function ensureResponseSuccess(response) {
if (!response.ok)
return response.json()
.then(function (data) { return errorHandler(data); });
return response.text()
.then(function (text) { return text.length ? JSON.parse(text) : {}; });
}
function errorHandler(response) {
console.log(response);
if (response && response.Error)
ErrorDispatcher_1.default.raiseError(response.Error);
return Promise.reject();
}
exports.default = {
get: get,
post: post,
makeRequest: makeRequest
};
//# sourceMappingURL=ServiceBase.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"ServiceBase.js","sourceRoot":"","sources":["ServiceBase.ts"],"names":[],"mappings":";;AAAA,qDAAgD;AAEhD,SAAS,GAAG,CAAC,GAAW;IACpB,IAAI,OAAO,GAAG;QACV,MAAM,EAAE,KAAK;QACb,OAAO,EAAE;YACL,cAAc,EAAE,kBAAkB;YAClC,eAAe,EAAE,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC;SAClD;KACJ,CAAC;IAEF,OAAO,WAAW,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AACrC,CAAC;AAED,SAAS,IAAI,CAAC,GAAW,EAAE,OAAY;IACnC,IAAI,OAAO,GAAG;QACV,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACL,cAAc,EAAE,kBAAkB;YAClC,eAAe,EAAE,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC;SAClD;QACD,IAAI,EAAE,EAAE;KACX,CAAC;IAEF,IAAI,OAAO;QACP,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IAE3C,OAAO,WAAW,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AACrC,CAAC;AAED,SAAS,WAAW,CAAC,GAAW,EAAE,OAAY;IAC1C,OAAO,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC;SACrB,IAAI,CAAC,qBAAqB,CAAC;SAC3B,KAAK,CAAC,YAAY,CAAC,CAAC;AAC7B,CAAC;AAED,SAAS,qBAAqB,CAAC,QAAa;IACxC,IAAI,CAAC,QAAQ,CAAC,EAAE;QACZ,OAAO,QAAQ,CAAC,IAAI,EAAE;aACjB,IAAI,CAAC,UAAC,IAAS,IAAK,OAAA,YAAY,CAAC,IAAI,CAAC,EAAlB,CAAkB,CAAC,CAAC;IAEjD,OAAO,QAAQ,CAAC,IAAI,EAAE;SACjB,IAAI,CAAC,UAAC,IAAS,IAAK,OAAA,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,EAAnC,CAAmC,CAAC,CAAC;AAClE,CAAC;AAED,SAAS,YAAY,CAAC,QAAa;IAC/B,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAEtB,IAAI,QAAQ,IAAI,QAAQ,CAAC,KAAK;QAC1B,yBAAe,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAE/C,OAAO,OAAO,CAAC,MAAM,EAAE,CAAC;AAC5B,CAAC;AAED,kBAAe;IACX,GAAG,KAAA;IACH,IAAI,MAAA;IACJ,WAAW,aAAA;CACd,CAAC"}

View File

@ -0,0 +1,59 @@
import ErrorDispatcher from './ErrorDispatcher';
function get(url: string) {
let options = {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': sessionStorage.getItem('user')
}
};
return makeRequest(url, options);
}
function post(url: string, request: any) {
let options = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': sessionStorage.getItem('user')
},
body: "",
};
if (request)
options.body = JSON.stringify(request);
return makeRequest(url, options);
}
function makeRequest(url: string, options: any) {
return fetch(url, options)
.then(ensureResponseSuccess)
.catch(errorHandler);
}
function ensureResponseSuccess(response: any) {
if (!response.ok)
return response.json()
.then((data: any) => errorHandler(data));
return response.text()
.then((text: any) => text.length ? JSON.parse(text) : {});
}
function errorHandler(response: any) {
console.log(response);
if (response && response.Error)
ErrorDispatcher.raiseError(response.Error);
return Promise.reject();
}
export default {
get,
post,
makeRequest
};

View File

@ -0,0 +1,59 @@
import { Box, Typography } from '@material-ui/core';
import { BrowserRouter, NavLink, Redirect, Route, Switch } from 'react-router-dom';
import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
import React from 'react';
export default function BirdmapTitle(props: any) {
const classes = useStyles();
return (
<Box component="span" className={classes.root}>
<Typography component="span" className={classes.bird}>
<NavLink exact to="/" className={classes.nav_menu_item} activeClassName={classes.nav_menu_item_active}>
Bird
</NavLink>
</Typography>
<Typography component="span" className={classes.map}>
<NavLink exact to="/heatmap" className={classes.nav_menu_item} activeClassName={classes.nav_menu_item_active}>
map
</NavLink>
</Typography>
</Box>
);
};
const useStyles = makeStyles((theme: Theme) =>
createStyles({
root: {
display: 'inline',
},
bird: {
textAlign: "left",
fontWeight: 1000,
fontSize: 30,
textShadow: '3px 3px 0px rgba(0,0,0,0.2)',
},
map: {
textAlign: "left",
fontWeight: 100,
fontSize: 26,
textShadow: '2px 2px 0px rgba(0,0,0,0.2)',
},
nav_menu_item: {
textDecoration: 'none',
color: 'white',
'&:hover': {
textDecoration: 'underline',
color: 'white',
}
},
nav_menu_item_active: {
textDecoration: 'none',
color: 'white',
'&:hover': {
textDecoration: 'underline',
color: 'white',
}
},
}),
);

View File

@ -0,0 +1,131 @@
import React, { useState } from 'react';
import { useHistory } from 'react-router-dom';
import { Box, Grid, TextField, Button, Typography, Paper, CircularProgress } from '@material-ui/core';
import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
import AuthService from './AuthService';
export default function Auth(props: any) {
const history = useHistory();
const classes = useStyles();
const [username, setUsername] = useState<string>("");
const [password, setPassword] = useState<string>("");
const [showError, setShowError] = useState(false);
const [errorMessage, setErrorMessage] = useState('');
const [isLoggingIn, setIsLoggingIn] = useState(false);
const onUsernameChanged = (event: any) => {
setUsername(event.target.value);
setShowError(false);
setErrorMessage('');
};
const onPasswordChanged = (event: any) => {
setPassword(event.target.value);
setShowError(false);
setErrorMessage('');
};
const onPasswordKeyPress = (event: any) => {
if (event.key === 'Enter') {
onLoginClicked();
}
};
const onLoginClicked = () => {
setIsLoggingIn(true);
if (!username) {
setShowError(true);
setErrorMessage('Username required');
return;
}
if (!password) {
setShowError(true);
setErrorMessage('Password required');
return;
}
AuthService.login(username, password)
.then(() => {
props.onAuthenticated();
history.push('/');
}).catch(() => {
setShowError(true);
setErrorMessage('Invalid credentials');
}).finally(() => {
setIsLoggingIn(false);
});
};
const renderErrorLabel = () => {
return showError
? <Typography>{errorMessage}</Typography>
: <React.Fragment />;
};
const renderLoginButton = () => {
return isLoggingIn
? <CircularProgress className={classes.button} />
: <Button className={classes.button} variant="contained" color="primary" onClick={onLoginClicked}>Sign in</Button>
};
return (
<Box className={classes.root}>
<Paper className={classes.paper} elevation={8}>
<Grid container className={classes.container} spacing={2}>
<Grid item>
<Typography component="h1" variant="h5">
Sign in
</Typography>
</Grid>
<Grid item xs={12} >
<TextField label="Username" type="text" onChange={onUsernameChanged} />
</Grid>
<Grid item xs={12} >
<TextField label="Password" type="password" onChange={onPasswordChanged} onKeyPress={onPasswordKeyPress} />
</Grid>
<Grid item xs={12} className={classes.error}>
{renderErrorLabel()}
</Grid>
<Grid item xs={12} className={classes.button}>
{renderLoginButton()}
</Grid>
</Grid>
</Paper>
</Box>
);
};
const useStyles = makeStyles((theme: Theme) =>
createStyles({
root: {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
minWidth: 400,
minHeight: 600,
},
container: {
padding: 40,
flexDirection: "column",
justifyContent: "space-around",
alignItems: "center",
},
paper: {
borderRadius: 15,
},
button: {
justifyContent: "center",
},
error: {
color: "red",
}
}),
);

View File

@ -0,0 +1,28 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var ServiceBase_1 = require("../../common/ServiceBase");
var login_url = 'api/auth/authenticate';
exports.default = {
isAuthenticated: function () {
return sessionStorage.getItem('user') !== null;
},
login: function (username, password) {
var body = {
username: username,
password: password
};
var options = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
};
return ServiceBase_1.default.makeRequest(login_url, options)
.then(function (response) {
sessionStorage.setItem('user', response.token_type + " " + response.access_token);
return Promise.resolve();
});
}
};
//# sourceMappingURL=AuthService.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"AuthService.js","sourceRoot":"","sources":["AuthService.ts"],"names":[],"mappings":";;AAAA,wDAAmD;AAEnD,IAAM,SAAS,GAAG,uBAAuB,CAAC;AAE1C,kBAAe;IACX,eAAe;QACX,OAAO,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC;IACnD,CAAC;IAED,KAAK,EAAL,UAAM,QAAgB,EAAE,QAAgB;QACpC,IAAI,IAAI,GAAG;YACP,QAAQ,EAAE,QAAQ;YAClB,QAAQ,EAAE,QAAQ;SACrB,CAAC;QACF,IAAI,OAAO,GAAG;YACV,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACL,cAAc,EAAE,kBAAkB;aACrC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;SAC7B,CAAC;QAEF,OAAO,qBAAW,CAAC,WAAW,CAAC,SAAS,EAAE,OAAO,CAAC;aAC7C,IAAI,CAAC,UAAA,QAAQ;YACV,cAAc,CAAC,OAAO,CAAC,MAAM,EAAK,QAAQ,CAAC,UAAU,SAAI,QAAQ,CAAC,YAAc,CAAC,CAAC;YAClF,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;QAC7B,CAAC,CAAC,CAAC;IACX,CAAC;CACJ,CAAA"}

View File

@ -0,0 +1,29 @@
import ServiceBase from '../../common/ServiceBase';
const login_url = 'api/auth/authenticate';
export default {
isAuthenticated() {
return sessionStorage.getItem('user') !== null;
},
login(username: string, password: string) {
let body = {
username: username,
password: password
};
let options = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
};
return ServiceBase.makeRequest(login_url, options)
.then(response => {
sessionStorage.setItem('user', `${response.token_type} ${response.access_token}`);
return Promise.resolve();
});
}
}

View File

@ -0,0 +1,21 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
require("bootstrap/dist/css/bootstrap.css");
var React = require("react");
var ReactDOM = require("react-dom");
var react_redux_1 = require("react-redux");
var connected_react_router_1 = require("connected-react-router");
var history_1 = require("history");
var configureStore_1 = require("./store/configureStore");
var App_1 = require("./App");
var registerServiceWorker_1 = require("./registerServiceWorker");
// Create browser history to use in the Redux store
var baseUrl = document.getElementsByTagName('base')[0].getAttribute('href');
var history = history_1.createBrowserHistory({ basename: baseUrl });
// Get the application-wide store instance, prepopulating with state from the server where available.
var store = configureStore_1.default(history);
ReactDOM.render(React.createElement(react_redux_1.Provider, { store: store },
React.createElement(connected_react_router_1.ConnectedRouter, { history: history },
React.createElement(App_1.default, null))), document.getElementById('root'));
registerServiceWorker_1.default();
//# sourceMappingURL=index.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.tsx"],"names":[],"mappings":";;AAAA,4CAA0C;AAE1C,6BAA+B;AAC/B,oCAAsC;AACtC,2CAAuC;AACvC,iEAAyD;AACzD,mCAA+C;AAC/C,yDAAoD;AACpD,6BAAwB;AACxB,iEAA4D;AAE5D,mDAAmD;AACnD,IAAM,OAAO,GAAG,QAAQ,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,CAAW,CAAC;AACxF,IAAM,OAAO,GAAG,8BAAoB,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;AAE5D,qGAAqG;AACrG,IAAM,KAAK,GAAG,wBAAc,CAAC,OAAO,CAAC,CAAC;AAEtC,QAAQ,CAAC,MAAM,CACX,oBAAC,sBAAQ,IAAC,KAAK,EAAE,KAAK;IAClB,oBAAC,wCAAe,IAAC,OAAO,EAAE,OAAO;QAC7B,oBAAC,aAAG,OAAG,CACO,CACX,EACX,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC;AAErC,+BAAqB,EAAE,CAAC"}

View File

@ -0,0 +1,27 @@
import 'bootstrap/dist/css/bootstrap.css';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { ConnectedRouter } from 'connected-react-router';
import { createBrowserHistory } from 'history';
import configureStore from './store/configureStore';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
// Create browser history to use in the Redux store
const baseUrl = document.getElementsByTagName('base')[0].getAttribute('href') as string;
const history = createBrowserHistory({ basename: baseUrl });
// Get the application-wide store instance, prepopulating with state from the server where available.
const store = configureStore(history);
ReactDOM.render(
<Provider store={store}>
<ConnectedRouter history={history}>
<App />
</ConnectedRouter>
</Provider>,
document.getElementById('root'));
registerServiceWorker();

View File

@ -0,0 +1 @@
/// <reference types="react-scripts" />

View File

@ -0,0 +1,105 @@
// In production, we register a service worker to serve assets from local cache.
// This lets the app load faster on subsequent visits in production, and gives
// it offline capabilities. However, it also means that developers (and users)
// will only see deployed updates on the "N+1" visit to a page, since previously
// cached resources are updated in the background.
// To learn more about the benefits of this model, read https://goo.gl/KwvDNy.
// This link also includes instructions on opting out of this behavior.
const isLocalhost = Boolean(
window.location.hostname === 'localhost' ||
// [::1] is the IPv6 localhost address.
window.location.hostname === '[::1]' ||
// 127.0.0.1/8 is considered localhost for IPv4.
window.location.hostname.match(
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
)
);
export default function register() {
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
// The URL constructor is available in all browsers that support SW.
const url = process.env.PUBLIC_URL as string;
const publicUrl = new URL(url, window.location.toString());
if (publicUrl.origin !== window.location.origin) {
// Our service worker won't work if PUBLIC_URL is on a different origin
// from what our page is served on. This might happen if a CDN is used to
// serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374
return;
}
window.addEventListener('load', () => {
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
if (isLocalhost) {
// This is running on localhost. Lets check if a service worker still exists or not.
checkValidServiceWorker(swUrl);
} else {
// Is not local host. Just register service worker
registerValidSW(swUrl);
}
});
}
}
function registerValidSW(swUrl: string) {
navigator.serviceWorker
.register(swUrl)
.then(registration => {
registration.onupdatefound = () => {
const installingWorker = registration.installing as ServiceWorker;
installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
// At this point, the old content will have been purged and
// the fresh content will have been added to the cache.
// It's the perfect time to display a "New content is
// available; please refresh." message in your web app.
console.log('New content is available; please refresh.');
} else {
// At this point, everything has been precached.
// It's the perfect time to display a
// "Content is cached for offline use." message.
console.log('Content is cached for offline use.');
}
}
};
};
})
.catch(error => {
console.error('Error during service worker registration:', error);
});
}
function checkValidServiceWorker(swUrl: string) {
// Check if the service worker can be found. If it can't reload the page.
fetch(swUrl)
.then(response => {
// Ensure service worker exists, and that we really are getting a JS file.
const contentType = response.headers.get('content-type');
if (response.status === 404 || (contentType && contentType.indexOf('javascript') === -1)) {
// No service worker found. Probably a different app. Reload the page.
navigator.serviceWorker.ready.then(registration => {
registration.unregister().then(() => {
window.location.reload();
});
});
} else {
// Service worker found. Proceed as normal.
registerValidSW(swUrl);
}
})
.catch(() => {
console.log('No internet connection found. App is running in offline mode.');
});
}
export function unregister() {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready.then(registration => {
registration.unregister();
});
}
}

View File

@ -0,0 +1,39 @@
"use strict";
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __spreadArrays = (this && this.__spreadArrays) || function () {
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
for (var r = Array(s), k = 0, i = 0; i < il; i++)
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
r[k] = a[j];
return r;
};
Object.defineProperty(exports, "__esModule", { value: true });
var redux_1 = require("redux");
var redux_thunk_1 = require("redux-thunk");
var connected_react_router_1 = require("connected-react-router");
var _1 = require("./");
function configureStore(history, initialState) {
var middleware = [
redux_thunk_1.default,
connected_react_router_1.routerMiddleware(history)
];
var rootReducer = redux_1.combineReducers(__assign(__assign({}, _1.reducers), { router: connected_react_router_1.connectRouter(history) }));
var enhancers = [];
var windowIfDefined = typeof window === 'undefined' ? null : window;
if (windowIfDefined && windowIfDefined.__REDUX_DEVTOOLS_EXTENSION__) {
enhancers.push(windowIfDefined.__REDUX_DEVTOOLS_EXTENSION__());
}
return redux_1.createStore(rootReducer, initialState, redux_1.compose.apply(void 0, __spreadArrays([redux_1.applyMiddleware.apply(void 0, middleware)], enhancers)));
}
exports.default = configureStore;
//# sourceMappingURL=configureStore.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"configureStore.js","sourceRoot":"","sources":["configureStore.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA,+BAA+E;AAC/E,2CAAgC;AAChC,iEAAyE;AAEzE,uBAAgD;AAEhD,SAAwB,cAAc,CAAC,OAAgB,EAAE,YAA+B;IACpF,IAAM,UAAU,GAAG;QACf,qBAAK;QACL,yCAAgB,CAAC,OAAO,CAAC;KAC5B,CAAC;IAEF,IAAM,WAAW,GAAG,uBAAe,uBAC5B,WAAQ,KACX,MAAM,EAAE,sCAAa,CAAC,OAAO,CAAC,IAChC,CAAC;IAEH,IAAM,SAAS,GAAG,EAAE,CAAC;IACrB,IAAM,eAAe,GAAG,OAAO,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAa,CAAC;IAC7E,IAAI,eAAe,IAAI,eAAe,CAAC,4BAA4B,EAAE;QACjE,SAAS,CAAC,IAAI,CAAC,eAAe,CAAC,4BAA4B,EAAE,CAAC,CAAC;KAClE;IAED,OAAO,mBAAW,CACd,WAAW,EACX,YAAY,EACZ,eAAO,+BAAC,uBAAe,eAAI,UAAU,IAAM,SAAS,GACvD,CAAC;AACN,CAAC;AAtBD,iCAsBC"}

View File

@ -0,0 +1,29 @@
import { applyMiddleware, combineReducers, compose, createStore } from 'redux';
import thunk from 'redux-thunk';
import { connectRouter, routerMiddleware } from 'connected-react-router';
import { History } from 'history';
import { ApplicationState, reducers } from './';
export default function configureStore(history: History, initialState?: ApplicationState) {
const middleware = [
thunk,
routerMiddleware(history)
];
const rootReducer = combineReducers({
...reducers,
router: connectRouter(history)
});
const enhancers = [];
const windowIfDefined = typeof window === 'undefined' ? null : window as any;
if (windowIfDefined && windowIfDefined.__REDUX_DEVTOOLS_EXTENSION__) {
enhancers.push(windowIfDefined.__REDUX_DEVTOOLS_EXTENSION__());
}
return createStore(
rootReducer,
initialState,
compose(applyMiddleware(...middleware), ...enhancers)
);
}

View File

@ -0,0 +1,8 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.reducers = void 0;
// Whenever an action is dispatched, Redux will update each top-level application state property using
// the reducer with the matching name. It's important that the names match exactly, and that the reducer
// acts on the corresponding ApplicationState property type.
exports.reducers = {};
//# sourceMappingURL=index.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;AAMA,sGAAsG;AACtG,wGAAwG;AACxG,4DAA4D;AAC/C,QAAA,QAAQ,GAAG,EACvB,CAAC"}

View File

@ -0,0 +1,17 @@
// The top-level state object
export interface ApplicationState {
}
// Whenever an action is dispatched, Redux will update each top-level application state property using
// the reducer with the matching name. It's important that the names match exactly, and that the reducer
// acts on the corresponding ApplicationState property type.
export const reducers = {
};
// This type can be used as a hint on action creators so that its 'dispatch' and 'getState' params are
// correctly typed to match your store.
export interface AppThunkAction<TAction> {
(dispatch: (action: TAction) => void, getState: () => ApplicationState): void;
}

View File

@ -0,0 +1,24 @@
{
"compilerOptions": {
"target": "es5",
"allowJs": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "preserve",
"lib": [
"es2015",
"dom"
],
"skipLibCheck": false
},
"include": [
"src"
]
}