diff --git a/package-lock.json b/package-lock.json index f4dae88d4469d74db10469cb3297e324653b38cd..912d01ee397bb2459335e30e75de107aa6ebfcc0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3758,6 +3758,11 @@ } } }, + "compute-scroll-into-view": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-1.0.16.tgz", + "integrity": "sha512-a85LHKY81oQnikatZYA90pufpZ6sQx++BoCxOEMsjpZx+ZnaKGQnCyCehTRr/1p9GBIAHTjcU9k71kSYWloLiQ==" + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -3955,6 +3960,15 @@ "sha.js": "^2.4.8" } }, + "create-react-context": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/create-react-context/-/create-react-context-0.3.0.tgz", + "integrity": "sha512-dNldIoSuNSvlTJ7slIKC/ZFGKexBMBrrcc+TTe1NdmROnaASuLPvqpwj9v4XS4uXZ8+YPu0sNmShX2rXI5LNsw==", + "requires": { + "gud": "^1.0.0", + "warning": "^4.0.3" + } + }, "cross-spawn": { "version": "6.0.5", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", @@ -6229,6 +6243,11 @@ "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=" }, + "gud": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gud/-/gud-1.0.0.tgz", + "integrity": "sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw==" + }, "gzip-size": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.1.1.tgz", @@ -8001,6 +8020,11 @@ "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=" }, + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" + }, "lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -9217,6 +9241,11 @@ "ts-pnp": "^1.1.6" } }, + "popper.js": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz", + "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==" + }, "portfinder": { "version": "1.0.28", "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", @@ -10484,6 +10513,40 @@ "resolved": "https://registry.npmjs.org/react-bootstrap-table2-editor/-/react-bootstrap-table2-editor-1.4.0.tgz", "integrity": "sha512-18yDCwsVt3b5Fwy0jidNDAbUA6vC7k9JjQVmykazWSw8G115+mmZnhe9/7RO7jAu8X7lhmobwlNwECzwPu1nDg==" }, + "react-bootstrap-typeahead": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/react-bootstrap-typeahead/-/react-bootstrap-typeahead-5.1.1.tgz", + "integrity": "sha512-fjbeF9xenZ7AqH+yQr9ad7PvntA4SSmHMDD56F25B/EmN0NAJsqobXMW8/Y2jllMpcziGG2H4A7GyAdQfyVRFA==", + "requires": { + "@babel/runtime": "^7.3.4", + "@restart/hooks": "^0.3.22", + "classnames": "^2.2.0", + "fast-deep-equal": "^3.1.1", + "invariant": "^2.2.1", + "lodash.debounce": "^4.0.8", + "prop-types": "^15.5.8", + "react-overlays": "^2.0.0", + "react-popper": "^1.0.0", + "scroll-into-view-if-needed": "^2.2.20", + "warning": "^4.0.1" + }, + "dependencies": { + "react-overlays": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/react-overlays/-/react-overlays-2.1.1.tgz", + "integrity": "sha512-gaQJwmb8Ij2IGVt4D1HmLtl4A0mDVYxlsv/8i0dHWK7Mw0kNat6ORelbbEWzaXTK1TqMeQtJw/jraL3WOADz3w==", + "requires": { + "@babel/runtime": "^7.4.5", + "@restart/hooks": "^0.3.12", + "dom-helpers": "^5.1.0", + "popper.js": "^1.15.0", + "prop-types": "^15.7.2", + "uncontrollable": "^7.0.0", + "warning": "^4.0.3" + } + } + } + }, "react-dev-utils": { "version": "10.2.1", "resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-10.2.1.tgz", @@ -10726,6 +10789,20 @@ "warning": "^4.0.3" } }, + "react-popper": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-1.3.7.tgz", + "integrity": "sha512-nmqYTx7QVjCm3WUZLeuOomna138R1luC4EqkW3hxJUrAe+3eNz3oFCLYdnPwILfn0mX1Ew2c3wctrjlUMYYUww==", + "requires": { + "@babel/runtime": "^7.1.2", + "create-react-context": "^0.3.0", + "deep-equal": "^1.1.1", + "popper.js": "^1.14.4", + "prop-types": "^15.6.1", + "typed-styles": "^0.0.7", + "warning": "^4.0.2" + } + }, "react-router": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/react-router/-/react-router-5.2.0.tgz", @@ -11421,6 +11498,14 @@ "ajv-keywords": "^3.5.2" } }, + "scroll-into-view-if-needed": { + "version": "2.2.26", + "resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.26.tgz", + "integrity": "sha512-SQ6AOKfABaSchokAmmaxVnL9IArxEnLEX9j4wAZw+x4iUTb40q7irtHG3z4GtAWz5veVZcCnubXDBRyLVQaohw==", + "requires": { + "compute-scroll-into-view": "^1.0.16" + } + }, "select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", @@ -12755,6 +12840,11 @@ "mime-types": "~2.1.24" } }, + "typed-styles": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/typed-styles/-/typed-styles-0.0.7.tgz", + "integrity": "sha512-pzP0PWoZUhsECYjABgCGQlRGL1n7tOHsgwYv3oIiEpJwGhFTuty/YNeduxQYzXXa3Ge5BdT6sHYIQYpl4uJ+5Q==" + }, "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", diff --git a/package.json b/package.json index d4d957b33692538d67423b25e75ab7ed4b16e63f..e15ea305ab569a4d908e2ed4aee23b421ebc3685 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "react-bootstrap": "^1.3.0", "react-bootstrap-table-next": "^4.0.3", "react-bootstrap-table2-editor": "^1.4.0", + "react-bootstrap-typeahead": "^5.1.1", "react-dom": "^16.13.1", "react-router-dom": "^5.2.0", "react-scripts": "3.4.3" diff --git a/src/index.js b/src/index.js index 17f4c8fbbc0d1fddfe3b96a02fe972bd04be734c..a9db7579f8968bfb049bb7c06b974f1fe1c9452a 100644 --- a/src/index.js +++ b/src/index.js @@ -4,6 +4,7 @@ import App from './App'; import * as serviceWorker from './serviceWorker'; import 'bootstrap/dist/css/bootstrap.min.css'; import 'react-bootstrap-table-next/dist/react-bootstrap-table2.min.css'; +import 'react-bootstrap-typeahead/css/Typeahead.css'; ReactDOM.render( <React.StrictMode> diff --git a/src/purchase/PurchaseForm.js b/src/purchase/PurchaseForm.js index c7338a21cd29cd7cdb92668bb4a95b9b242f30ce..d7cfc6bf50e68207550e96e3f9b9ff83d6580901 100644 --- a/src/purchase/PurchaseForm.js +++ b/src/purchase/PurchaseForm.js @@ -1,5 +1,6 @@ import React from 'react'; -import { Col, Form, Button } from 'react-bootstrap'; +import { Col, Form, Button } from 'react-bootstrap'; +import { Typeahead } from 'react-bootstrap-typeahead'; import printMoney from '../util'; @@ -9,8 +10,7 @@ class PurchaseForm extends React.Component { this.state = { codeInvalid: false, code: "", - name: null, - price: null, + product: null, ammount: 1 }; } @@ -18,33 +18,34 @@ class PurchaseForm extends React.Component { setCode(codeStr) { const code = parseInt(codeStr); const product = this.props.products.find(p => p.code === code); - const name = product === undefined? null: product.name; - const price = product === undefined? null: product.price; - this.setState({ - code: codeStr, name, price, + code: codeStr, + product: product, codeInvalid: product === undefined }); } + setName(product) { + this.setState({ + product, + code: product.code, + codeInvalid: false, + }); + } + submit(e) { e.preventDefault(); - if (this.state.name == null) { + if (!this.state.product) { return } - const product = { - code: this.state.code, - ammount: this.state.ammount, - price: this.state.price, - name: this.state.name - }; - + let product = this.state.product; + product.ammount = this.state.ammount; if (this.props.onSubmit(product)) { this.setState({ code: "", - name: null, - price: null, - ammount: 1 + product: null, + ammount: 1, + codeInvalid: false }); } else { this.setState({ codeInvalid: true }); @@ -52,7 +53,9 @@ class PurchaseForm extends React.Component { } render() { - // TODO: add it by name... + if (this.props.products.length === 0) { + return null; + } return ( <Form onSubmit={e => this.submit(e)}> <Form.Row> @@ -65,10 +68,16 @@ class PurchaseForm extends React.Component { /> </Col> <Col> - {this.state.name} + <Typeahead + id="product-name" + labelKey="name" + options={this.props.products} + onChange={name => this.setName(name[0])} + selected={this.state.product? [this.state.product]:[]} + /> </Col> <Col> - {printMoney(this.state.price)+"€"} + {this.state.product? printMoney(this.state.product.price)+"€":"0.00€"} </Col> <Col> <Form.Control