Make lock charges calculation functional for happy path

This commit is contained in:
Senad Uka
2019-06-03 18:04:42 +02:00
parent d850aef0b8
commit 8e4eb0cf1f
22 changed files with 820 additions and 61 deletions

View File

@@ -3,6 +3,7 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"axios": "^0.18.0",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-redux": "^7.0.3",

View File

@@ -0,0 +1,59 @@
import React, { Component } from 'react';
import { connect } from 'react-redux';
import {Form} from "semantic-ui-react";
import { uploadDoorLockData } from "../../../store/actions";
class FileUpload extends Component {
constructor(props) {
super(props);
this.state = {
file: null,
};
this.onFileChange = this.onFileChange.bind(this);
this.onUploadClick = this.onUploadClick.bind(this);
}
onFileChange(event) {
const file = event.target.files[0];
this.setState({file});
};
onUploadClick() {
const { uploadDoorLockData } = this.props;
const { file } = this.state;
if (file) {
uploadDoorLockData(file);
}
};
render() {
const { pending } = this.props;
return (
<div>
<Form.Input
fluid
required
label="Select DLock file"
type="file"
accept=".csv"
onChange={this.onFileChange}
/>
<Form.Button onClick={this.onUploadClick} disabled={pending} >Upload</Form.Button>
</div>
);
}
}
const mapStateToProps = (state) => ({
pending: state.doorLockData.pending,
});
const mapDispatchToProps = (dispatch) => ({
uploadDoorLockData: (doorLockDataFile) => uploadDoorLockData(dispatch, doorLockDataFile)
});
export default connect(mapStateToProps, mapDispatchToProps)(FileUpload);

View File

@@ -0,0 +1,86 @@
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Loader, Message, Tab, Label, Menu } from 'semantic-ui-react';
class UploadResults extends Component {
render(){
const {pending, result, error} = this.props;
const parsedEntries = result && result.parsedData ? result.parsedData : [];
const errorEntries = result && result.parserErrors ? result.parserErrors : [];
const unknownMembers = result && result.unknownMembers ? result.unknownMembers : [];
const renderParsedEntriesTab = () => {
return (
<div>
<br/>
<Message positive>
<p>{parsedEntries.length} entries successfully parsed</p>
</Message>
</div>
);
};
const renderErrorTabResults = (results) => {
return (
<div>
<br/>
{
results.map((entry, index) => {
return (
<div key={`error-${entry.error}-${index}`}>
<br/>
<Message negative>
<Message.Header>{entry.error}</Message.Header>
<p>{JSON.stringify(entry.details)}</p>
<p>File : {entry.file}</p>
</Message>
</div>
);
})
}
</div>
);
};
const parsedEntriesTabTitle = (<Menu.Item key="parsed-entries">Parsed Entries<Label>{parsedEntries.length}</Label></Menu.Item>);
const errorEntriesTabTitle = (<Menu.Item key="error-entries">Error Entries<Label>{errorEntries.length}</Label></Menu.Item>);
const unknownMembersTabTitle = (<Menu.Item key="unknown-members">Unknown Members<Label>{unknownMembers.length}</Label></Menu.Item>);
const panes = [
{menuItem: parsedEntriesTabTitle, render: renderParsedEntriesTab},
{menuItem: errorEntriesTabTitle, render: () => renderErrorTabResults(errorEntries)},
{menuItem: unknownMembersTabTitle, render: () => renderErrorTabResults(unknownMembers)}
];
return (
<div>
{
pending && <Loader active />
}
<br/>
{
!pending && !error && result &&
<Tab panes={panes}/>
}
{
!pending && error &&
<Message>
<Message.Header>Upload Failed</Message.Header>
<p>{error.data}</p>
</Message>
}
</div>
)
}
}
const mapStateToProps = (state) => ({
pending: state.doorLockData.pending,
result: state.doorLockData.result,
error: state.doorLockData.error,
});
export default connect(mapStateToProps)(UploadResults);

View File

@@ -1,39 +1,22 @@
import React, { Component } from 'react';
import { connect } from 'react-redux';
import React from 'react';
import { Container, Form } from "semantic-ui-react";
import MainMenu from '../../components/MainMenu';
import { uploadDoorLockData } from "../../store/actions";
import FileUpload from './components/FileUpload';
import UploadResults from './components/UploadResults';
class UploadDLockData extends Component {
render () {
return (
<Container>
<MainMenu/>
<h3>DLock Data</h3>
<hr/>
<Form>
<Form.Input
fluid
required
label="Select DLock file"
type="file"
/>
<Form.Button onClick={this.props.uploadDoorLockData}>Upload</Form.Button>
</Form>
</Container>
);
}
function UploadDLockData() {
return (
<Container>
<MainMenu/>
<h3>DLock Data</h3>
<hr/>
<Form>
<FileUpload/>
</Form>
<UploadResults/>
</Container>
);
}
const mapStateToProps = (state) => ({
});
const mapDispatchToProps = (dispatch) => ({
uploadDoorLockData: () => uploadDoorLockData(dispatch),
});
export default connect(mapStateToProps, mapDispatchToProps)(UploadDLockData);
export default UploadDLockData;

View File

@@ -4,14 +4,21 @@ import {
UPLOAD_DOOR_LOCK_DATA_FAILED
} from "../constants";
export const uploadDoorLockData = (dispatch) => {
import API from '../../utilities/api';
export const uploadDoorLockData = (dispatch, doorLockDataFile) => {
const formData = new FormData();
formData.append('doorLockDataFile', doorLockDataFile);
const additionalConfig = {
headers: {'content-type': 'multipart/form-data'}
};
dispatch({type: UPLOAD_DOOR_LOCK_DATA_PENDING});
fetch('/api/doorLockData')
.then(response => response.json())
.then(data => {
dispatch({type: UPLOAD_DOOR_LOCK_DATA_SUCCESS, payload: data})
})
.catch(err => {
dispatch({type: UPLOAD_DOOR_LOCK_DATA_FAILED, payload: err})
API.post('doorLock/upload', formData, additionalConfig)
.then(response => {
dispatch({type: UPLOAD_DOOR_LOCK_DATA_SUCCESS, payload: response.data})
})
.catch(error => {
dispatch({type: UPLOAD_DOOR_LOCK_DATA_FAILED, payload: error.response})
});
};

View File

@@ -6,8 +6,8 @@ import {
const initialState = {
pending: false,
result: {},
error: '',
result: null,
error: null,
};
export const doorLockData = (state, action) => {
@@ -18,15 +18,18 @@ export const doorLockData = (state, action) => {
case UPLOAD_DOOR_LOCK_DATA_PENDING:
return Object.assign({}, state, {
pending: true,
error: null,
});
case UPLOAD_DOOR_LOCK_DATA_SUCCESS:
return Object.assign({}, state, {
pending: false,
result: action.payload,
error: null,
});
case UPLOAD_DOOR_LOCK_DATA_FAILED:
return Object.assign({}, state, {
pending: false,
result: {},
error: action.payload,
});
default:

View File

@@ -0,0 +1,5 @@
import axios from 'axios';
export default axios.create({
baseURL: '/api/'
});

View File

@@ -1597,6 +1597,13 @@ aws4@^1.8.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f"
axios@^0.18.0:
version "0.18.0"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.18.0.tgz#32d53e4851efdc0a11993b6cd000789d70c05102"
dependencies:
follow-redirects "^1.3.0"
is-buffer "^1.1.5"
axobject-query@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.0.2.tgz#ea187abe5b9002b377f925d8bf7d1c561adf38f9"
@@ -3547,7 +3554,7 @@ flush-write-stream@^1.0.0:
inherits "^2.0.3"
readable-stream "^2.3.6"
follow-redirects@^1.0.0:
follow-redirects@^1.0.0, follow-redirects@^1.3.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.7.0.tgz#489ebc198dc0e7f64167bd23b03c4c19b5784c76"
dependencies: