Added login page
This commit is contained in:
		@@ -26,7 +26,10 @@
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
    <None Remove="ClientApp\src\common\ErrorDispatcher.ts" />
 | 
			
		||||
    <None Remove="ClientApp\src\common\ServiceBase.ts" />
 | 
			
		||||
    <None Remove="ClientApp\src\components\auth\Auth.tsx" />
 | 
			
		||||
    <None Remove="ClientApp\src\components\auth\AuthService.ts" />
 | 
			
		||||
  </ItemGroup>
 | 
			
		||||
 | 
			
		||||
  <ItemGroup>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										31
									
								
								Birdmap/ClientApp/src/App.test.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								Birdmap/ClientApp/src/App.test.js
									
									
									
									
									
										Normal 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
 | 
			
		||||
							
								
								
									
										1
									
								
								Birdmap/ClientApp/src/App.test.js.map
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								Birdmap/ClientApp/src/App.test.js.map
									
									
									
									
									
										Normal 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"}
 | 
			
		||||
@@ -1,16 +1,93 @@
 | 
			
		||||
import * as React from 'react';
 | 
			
		||||
import { Route } from 'react-router';
 | 
			
		||||
import Layout from './components/Layout';
 | 
			
		||||
import { Box, Container } from '@material-ui/core';
 | 
			
		||||
import AppBar from '@material-ui/core/AppBar';
 | 
			
		||||
import blue from '@material-ui/core/colors/blue';
 | 
			
		||||
import { createMuiTheme } 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 Auth from './components/auth/Auth';
 | 
			
		||||
import AuthService from './components/auth/AuthService';
 | 
			
		||||
import Home from './components/Home';
 | 
			
		||||
import Counter from './components/Counter';
 | 
			
		||||
import FetchData from './components/FetchData';
 | 
			
		||||
import './custom.css';
 | 
			
		||||
 | 
			
		||||
import './custom.css'
 | 
			
		||||
 | 
			
		||||
export default () => (
 | 
			
		||||
    <Layout>
 | 
			
		||||
        <Route exact path='/' component={Home} />
 | 
			
		||||
        <Route path='/counter' component={Counter} />
 | 
			
		||||
        <Route path='/fetch-data/:startDateIndex?' component={FetchData} />
 | 
			
		||||
    </Layout>
 | 
			
		||||
);
 | 
			
		||||
const theme = createMuiTheme({
 | 
			
		||||
    palette: {
 | 
			
		||||
        primary: {
 | 
			
		||||
            main: blue[800]
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function App() {
 | 
			
		||||
    const [authenticated, setAuthenticated] = useState(AuthService.isAuthenticated());
 | 
			
		||||
 | 
			
		||||
    const onAuthenticated = () => {
 | 
			
		||||
        setAuthenticated(AuthService.isAuthenticated());
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const LoginComponent = () => {
 | 
			
		||||
        return (
 | 
			
		||||
            <Auth onAuthenticated={onAuthenticated} />
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <ThemeProvider theme={theme}>
 | 
			
		||||
                <BrowserRouter>
 | 
			
		||||
                    <Switch>
 | 
			
		||||
                        <PublicRoute path="/login" component={LoginComponent} />
 | 
			
		||||
                        <PrivateRoute path="/" exact authenticated={authenticated} component={Home} />
 | 
			
		||||
                    </Switch>
 | 
			
		||||
                </BrowserRouter>
 | 
			
		||||
        </ThemeProvider>
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default App;
 | 
			
		||||
 | 
			
		||||
const PublicRoute = ({ component: Component, ...rest }: { [x: string]: any, component: any}) => {
 | 
			
		||||
    return (
 | 
			
		||||
        <Route {...rest} render={matchProps => (
 | 
			
		||||
            <NoLayout component={Component} {...matchProps} />
 | 
			
		||||
        )} />
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const PrivateRoute = ({ component: Component, authenticated: Authenticated, ...rest }: { [x: string]: any, component: any, authenticated: any }) => {
 | 
			
		||||
    return (
 | 
			
		||||
        <Route {...rest} render={matchProps => (
 | 
			
		||||
            Authenticated
 | 
			
		||||
                ? <DefaultLayout component={Component} {...matchProps} />
 | 
			
		||||
                : <Redirect to='/login' />
 | 
			
		||||
        )} />
 | 
			
		||||
    );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const NoLayout = ({ component: Component, ...rest }: { [x: string]: any, component: any }) => {
 | 
			
		||||
    return (
 | 
			
		||||
        <Component {...rest} />
 | 
			
		||||
    );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const DefaultLayout = ({ component: Component, ...rest }: { [x: string]: any, component: any }) => {
 | 
			
		||||
    return (
 | 
			
		||||
        <React.Fragment>
 | 
			
		||||
            <AppBar position="static">
 | 
			
		||||
                <Toolbar>
 | 
			
		||||
                    <Typography component={'span'}>
 | 
			
		||||
                        <Container className="nav-menu">
 | 
			
		||||
                            <NavLink exact to="/" className="nav-menu-item" activeStyle={{ color: 'white' }}>Dashboard</NavLink>
 | 
			
		||||
                            <NavLink exact to="/login" className="nav-menu-item" activeStyle={{ color: 'white' }}>Login</NavLink>
 | 
			
		||||
                        </Container>
 | 
			
		||||
                    </Typography>
 | 
			
		||||
                </Toolbar>
 | 
			
		||||
            </AppBar>
 | 
			
		||||
            <Box style={{ margin: '32px' }}>
 | 
			
		||||
                <Component {...rest} />
 | 
			
		||||
            </Box>
 | 
			
		||||
        </React.Fragment>
 | 
			
		||||
    );
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										14
									
								
								Birdmap/ClientApp/src/common/ErrorDispatcher.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								Birdmap/ClientApp/src/common/ErrorDispatcher.js
									
									
									
									
									
										Normal 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
 | 
			
		||||
							
								
								
									
										1
									
								
								Birdmap/ClientApp/src/common/ErrorDispatcher.js.map
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								Birdmap/ClientApp/src/common/ErrorDispatcher.js.map
									
									
									
									
									
										Normal 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"}
 | 
			
		||||
							
								
								
									
										14
									
								
								Birdmap/ClientApp/src/common/ErrorDispatcher.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								Birdmap/ClientApp/src/common/ErrorDispatcher.ts
									
									
									
									
									
										Normal 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;
 | 
			
		||||
							
								
								
									
										50
									
								
								Birdmap/ClientApp/src/common/ServiceBase.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								Birdmap/ClientApp/src/common/ServiceBase.js
									
									
									
									
									
										Normal 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
 | 
			
		||||
							
								
								
									
										1
									
								
								Birdmap/ClientApp/src/common/ServiceBase.js.map
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								Birdmap/ClientApp/src/common/ServiceBase.js.map
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
{"version":3,"file":"ServiceBase.js","sourceRoot":"","sources":["ServiceBase.ts"],"names":[],"mappings":";;AAAA,qDAAgD;AAEhD,SAAS,GAAG,CAAC,GAAG;IACZ,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,GAAG,EAAE,OAAO;IACtB,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,GAAG,EAAE,OAAO;IAC7B,OAAO,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC;SACrB,IAAI,CAAC,qBAAqB,CAAC;SAC3B,KAAK,CAAC,YAAY,CAAC,CAAC;AAC7B,CAAC;AAED,SAAS,qBAAqB,CAAC,QAAQ;IACnC,IAAI,CAAC,QAAQ,CAAC,EAAE;QACZ,OAAO,QAAQ,CAAC,IAAI,EAAE;aACjB,IAAI,CAAC,UAAA,IAAI,IAAI,OAAA,YAAY,CAAC,IAAI,CAAC,EAAlB,CAAkB,CAAC,CAAC;IAE1C,OAAO,QAAQ,CAAC,IAAI,EAAE;SACjB,IAAI,CAAC,UAAA,IAAI,IAAI,OAAA,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,EAAnC,CAAmC,CAAC,CAAC;AAC3D,CAAC;AAED,SAAS,YAAY,CAAC,QAAQ;IAC1B,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"}
 | 
			
		||||
							
								
								
									
										59
									
								
								Birdmap/ClientApp/src/common/ServiceBase.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								Birdmap/ClientApp/src/common/ServiceBase.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,59 @@
 | 
			
		||||
import ErrorDispatcher from './ErrorDispatcher';
 | 
			
		||||
 | 
			
		||||
function get(url) {
 | 
			
		||||
    let options = {
 | 
			
		||||
        method: 'GET',
 | 
			
		||||
        headers: {
 | 
			
		||||
            'Content-Type': 'application/json',
 | 
			
		||||
            'Authorization': sessionStorage.getItem('user')
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return makeRequest(url, options);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function post(url, request) {
 | 
			
		||||
    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, options) {
 | 
			
		||||
    return fetch(url, options)
 | 
			
		||||
        .then(ensureResponseSuccess)
 | 
			
		||||
        .catch(errorHandler);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function ensureResponseSuccess(response) {
 | 
			
		||||
    if (!response.ok)
 | 
			
		||||
        return response.json()
 | 
			
		||||
            .then(data => errorHandler(data));
 | 
			
		||||
 | 
			
		||||
    return response.text()
 | 
			
		||||
        .then(text => text.length ? JSON.parse(text) : {});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function errorHandler(response) {
 | 
			
		||||
    console.log(response);
 | 
			
		||||
 | 
			
		||||
    if (response && response.Error)
 | 
			
		||||
        ErrorDispatcher.raiseError(response.Error);
 | 
			
		||||
 | 
			
		||||
    return Promise.reject();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    get,
 | 
			
		||||
    post,
 | 
			
		||||
    makeRequest
 | 
			
		||||
};
 | 
			
		||||
@@ -1 +1,119 @@
 | 
			
		||||
 | 
			
		||||
import React, { useState } from 'react';
 | 
			
		||||
import { useHistory } from 'react-router-dom';
 | 
			
		||||
import { Box, Grid, TextField, Button, Typography, Paper } from '@material-ui/core';
 | 
			
		||||
import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
 | 
			
		||||
import AuthService from './AuthService';
 | 
			
		||||
 | 
			
		||||
export default function MenuItem(props: any) {
 | 
			
		||||
    const history = useHistory();
 | 
			
		||||
    const classes = useStyles();
 | 
			
		||||
 | 
			
		||||
    const [username, setUsername] = useState(null);
 | 
			
		||||
    const [password, setPassword] = useState(null);
 | 
			
		||||
 | 
			
		||||
    const [showError, setShowError] = useState(false);
 | 
			
		||||
    const [errorMessage, setErrorMessage] = useState('');
 | 
			
		||||
 | 
			
		||||
    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 = () => {
 | 
			
		||||
        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');
 | 
			
		||||
        });
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const renderErrorLabel = () => {
 | 
			
		||||
        return showError
 | 
			
		||||
            ? <Typography>{errorMessage}</Typography>
 | 
			
		||||
            : <React.Fragment />;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return (
 | 
			
		||||
        <Box className={classes.root}>
 | 
			
		||||
            <Paper className={classes.paper}>
 | 
			
		||||
                <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}>
 | 
			
		||||
                        <Button className={classes.button} variant="contained" color="primary" onClick={onLoginClicked}>Login</Button>
 | 
			
		||||
                    </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: {
 | 
			
		||||
        },
 | 
			
		||||
        button: {
 | 
			
		||||
            width: '100%',
 | 
			
		||||
        },
 | 
			
		||||
        error: {
 | 
			
		||||
            color: "red",
 | 
			
		||||
        }
 | 
			
		||||
    }),
 | 
			
		||||
);
 | 
			
		||||
							
								
								
									
										28
									
								
								Birdmap/ClientApp/src/components/auth/AuthService.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								Birdmap/ClientApp/src/components/auth/AuthService.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
			
		||||
"use strict";
 | 
			
		||||
Object.defineProperty(exports, "__esModule", { value: true });
 | 
			
		||||
var ServiceBase_1 = require("../../common/ServiceBase");
 | 
			
		||||
var login_url = '/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
 | 
			
		||||
							
								
								
									
										1
									
								
								Birdmap/ClientApp/src/components/auth/AuthService.js.map
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								Birdmap/ClientApp/src/components/auth/AuthService.js.map
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
{"version":3,"file":"AuthService.js","sourceRoot":"","sources":["AuthService.ts"],"names":[],"mappings":";;AAAA,wDAAmD;AAEnD,IAAM,SAAS,GAAG,oBAAoB,CAAC;AAEvC,kBAAe;IACX,eAAe;QACX,OAAO,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC;IACnD,CAAC;IAED,KAAK,YAAC,QAAQ,EAAE,QAAQ;QACpB,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"}
 | 
			
		||||
							
								
								
									
										29
									
								
								Birdmap/ClientApp/src/components/auth/AuthService.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								Birdmap/ClientApp/src/components/auth/AuthService.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
			
		||||
import ServiceBase from '../../common/ServiceBase';
 | 
			
		||||
 | 
			
		||||
const login_url = '/auth/authenticate';
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    isAuthenticated() {
 | 
			
		||||
        return sessionStorage.getItem('user') !== null;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    login(username, password) {
 | 
			
		||||
        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();
 | 
			
		||||
            });
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										21
									
								
								Birdmap/ClientApp/src/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								Birdmap/ClientApp/src/index.js
									
									
									
									
									
										Normal 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
 | 
			
		||||
							
								
								
									
										1
									
								
								Birdmap/ClientApp/src/index.js.map
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								Birdmap/ClientApp/src/index.js.map
									
									
									
									
									
										Normal 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"}
 | 
			
		||||
@@ -33,7 +33,7 @@ namespace Birdmap.Controllers
 | 
			
		||||
        public async Task<IActionResult> AuthenticateAsync([FromBody] AuthenticateRequest model)
 | 
			
		||||
        {
 | 
			
		||||
            var user = await _service.AuthenticateUserAsync(model.Username, model.Password);
 | 
			
		||||
            var expires = DateTime.UtcNow.AddHours(2);
 | 
			
		||||
            var expiresInSeconds = TimeSpan.FromHours(2).TotalSeconds;
 | 
			
		||||
            var tokenHandler = new JwtSecurityTokenHandler();
 | 
			
		||||
            var key = Encoding.ASCII.GetBytes(_configuration["BasicAuth:Secret"]);
 | 
			
		||||
            var tokenDescriptor = new SecurityTokenDescriptor
 | 
			
		||||
@@ -42,7 +42,7 @@ namespace Birdmap.Controllers
 | 
			
		||||
                    {
 | 
			
		||||
                        new Claim(ClaimTypes.Name, user.Name)
 | 
			
		||||
                    }),
 | 
			
		||||
                Expires = expires,
 | 
			
		||||
                Expires = DateTime.UtcNow.AddHours(expiresInSeconds),
 | 
			
		||||
                SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
 | 
			
		||||
            };
 | 
			
		||||
            var token = tokenHandler.CreateToken(tokenDescriptor);
 | 
			
		||||
@@ -51,9 +51,10 @@ namespace Birdmap.Controllers
 | 
			
		||||
            return Ok(
 | 
			
		||||
                new
 | 
			
		||||
                {
 | 
			
		||||
                    Name = user.Name,
 | 
			
		||||
                    Token = tokenString,
 | 
			
		||||
                    Expires = expires,
 | 
			
		||||
                    user_name = user.Name,
 | 
			
		||||
                    access_token = tokenString,
 | 
			
		||||
                    token_type = "Bearer",
 | 
			
		||||
                    expires_in = expiresInSeconds,
 | 
			
		||||
                });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user