From b6aa5a036c2f965e2ca2980813ee63ffd2df97ad Mon Sep 17 00:00:00 2001 From: meskio <meskio@sindominio.net> Date: Wed, 23 Sep 2020 17:00:16 +0200 Subject: [PATCH] Factor out the fetcher --- src/Dashboard.js | 50 ++++++++-------------------------- src/Fetcher.js | 68 ++++++++++++++++++++++++++++++++++++++++++++++ src/ProductList.js | 67 ++++++++++++--------------------------------- src/member.js | 66 ++++++++++++-------------------------------- 4 files changed, 113 insertions(+), 138 deletions(-) create mode 100644 src/Fetcher.js diff --git a/src/Dashboard.js b/src/Dashboard.js index 4273d3f..0752448 100644 --- a/src/Dashboard.js +++ b/src/Dashboard.js @@ -1,6 +1,7 @@ import React from 'react'; +import { Container } from 'react-bootstrap'; import AuthContext from './AuthContext'; -import { Container, Spinner, Alert, Row } from 'react-bootstrap'; +import Fetcher from './Fetcher'; import printMoney from './util'; class Dashboard extends React.Component { @@ -10,49 +11,20 @@ class Dashboard extends React.Component { super(props); this.state = { name: null, - balance: null, - isLoading: false, - error: null + balance: null }; } - componentDidMount() { - this.setState({ isLoading: true }); - - fetch('/api/member/'+this.context.num.toString(), - { headers: { 'x-authentication': this.context.token }}) - .then(response => { - if (!response.ok) { - throw new Error(response.status.toString()+' '+response.statusText); - } - return response.json(); - }) - .then(member => this.setState({ balance: member.balance, name: member.name, isLoading: false })) - .catch(e => this.setState({ error: e.message, isLoading: false })); - } - render() { - if (this.state.isLoading) { - return ( - <Row className="justify-content-md-center"> - <Spinner animation="border" /> - </Row> - ); - } - - if (this.state.error != null) { - return ( - <Alert variant="danger"> - Ha ocurrido un error cargando tu saldo: {this.state.error} - </Alert> - ); - } - return ( - <Container> - <h1>{this.state.name}</h1> - <p>Saldo: {printMoney(this.state.balance)}</p> - </Container> + <Fetcher + url={"/api/member/"+this.context.num.toString()} + onFetch={member => this.setState({ balance: member.balance, name: member.name})} > + <Container> + <h1>{this.state.name}</h1> + <p>Saldo: {printMoney(this.state.balance)}</p> + </Container> + </Fetcher> ); } } diff --git a/src/Fetcher.js b/src/Fetcher.js new file mode 100644 index 0000000..22a563b --- /dev/null +++ b/src/Fetcher.js @@ -0,0 +1,68 @@ +import React from 'react'; +import { Spinner, Alert, Row } from 'react-bootstrap'; +import AuthContext from './AuthContext'; + +class Fetcher extends React.Component { + static contextType = AuthContext; + + constructor(props) { + super(props); + this.state = { + isLoading: false, + error: null + }; + } + + componentDidMount() { + this.setState({ isLoading: true }); + this.fetch(); + this.timerID = setInterval( + () => this.fetch(), + 10000 // every 10 seconds + ); + } + + compomentWillUnmount() { + clearInterval(this.timerID); + } + + fetch() { + fetch(this.props.url, { headers: { 'x-authentication': this.context.token } }) + .then(response => { + if (!response.ok) { + throw new Error(response.status.toString()+' '+response.statusText); + } + return response.json(); + }) + .then(data => { + if (this.state.isLoading) { + this.setState({ isLoading: false }); + } + this.props.onFetch(data); + }) + .catch(e => this.setState({ error: e.message, isLoading: false })); + } + + render() { + if (this.state.isLoading) { + return ( + <Row className="justify-content-md-center"> + <Spinner animation="border" /> + </Row> + ); + } + + if (this.state.error != null) { + console.log(this.state.error); + return ( + <Alert variant="danger"> + Ha ocurrido un error cargando datos: {this.state.error} + </Alert> + ); + } + + return this.props.children; + } +} + +export default Fetcher; diff --git a/src/ProductList.js b/src/ProductList.js index 2eb7f97..5593ab7 100644 --- a/src/ProductList.js +++ b/src/ProductList.js @@ -1,52 +1,17 @@ import React from 'react'; -import { Table, Spinner, Alert, Row } from 'react-bootstrap'; -import AuthContext from './AuthContext'; +import { Table } from 'react-bootstrap'; +import Fetcher from './Fetcher'; import printMoney from './util'; class ProductList extends React.Component { - static contextType = AuthContext; - constructor(props) { super(props); this.state = { products: [], - isLoading: false, - error: null }; } - componentDidMount() { - this.setState({ isLoading: true }); - - fetch('/api/product', { headers: { 'x-authentication': this.context.token }}) - .then(response => { - if (!response.ok) { - throw new Error(response.status.toString()+' '+response.statusText); - } - return response.json(); - }) - .then(products => this.setState({ products, isLoading: false })) - .catch(e => this.setState({ error: e.message, isLoading: false })); - } - render() { - if (this.state.isLoading) { - return ( - <Row className="justify-content-md-center"> - <Spinner animation="border" /> - </Row> - ); - } - - if (this.state.error != null) { - console.log(this.state.error); - return ( - <Alert variant="danger"> - Ha ocurrido un error cargando el listado de productos: {this.state.error} - </Alert> - ); - } - const entries = this.state.products.map((product) => { return ( <tr key={product.code}> @@ -59,19 +24,21 @@ class ProductList extends React.Component { }); return ( - <Table striped bordered hover> - <thead> - <tr> - <th>codigo</th> - <th>Nombre</th> - <th>Precio</th> - <th>Existencias</th> - </tr> - </thead> - <tbody> - {entries} - </tbody> - </Table> + <Fetcher url="/api/product" onFetch={products => this.setState({ products })} > + <Table striped bordered hover> + <thead> + <tr> + <th>codigo</th> + <th>Nombre</th> + <th>Precio</th> + <th>Existencias</th> + </tr> + </thead> + <tbody> + {entries} + </tbody> + </Table> + </Fetcher> ); } } diff --git a/src/member.js b/src/member.js index 6fda8cc..b790c3b 100644 --- a/src/member.js +++ b/src/member.js @@ -1,52 +1,18 @@ import React from 'react'; -import { Table, Spinner, Alert, Row } from 'react-bootstrap'; -import AuthContext from './AuthContext'; +import { Table } from 'react-bootstrap'; +import Fetcher from './Fetcher'; import printMoney from './util'; class MemberList extends React.Component { - static contextType = AuthContext; constructor(props) { super(props); this.state = { members: [], - isLoading: false, - error: null }; } - componentDidMount() { - this.setState({ isLoading: true }); - - fetch('/api/member', { headers: { 'x-authentication': this.context.token }}) - .then(response => { - if (!response.ok) { - throw new Error(response.status.toString()+' '+response.statusText); - } - return response.json(); - }) - .then(members => this.setState({ members, isLoading: false })) - .catch(e => this.setState({ error: e.message, isLoading: false })); - } - render() { - if (this.state.isLoading) { - return ( - <Row className="justify-content-md-center"> - <Spinner animation="border" /> - </Row> - ); - } - - if (this.state.error != null) { - console.log(this.state.error); - return ( - <Alert variant="danger"> - Ha ocurrido un error cargando el listado de socias: {this.state.error} - </Alert> - ); - } - const entries = this.state.members.map((member) => { return ( <tr key={member.num}> @@ -59,19 +25,21 @@ class MemberList extends React.Component { }); return ( - <Table striped bordered hover> - <thead> - <tr> - <th>Numero</th> - <th>Nombre</th> - <th>Email</th> - <th>Saldo</th> - </tr> - </thead> - <tbody> - {entries} - </tbody> - </Table> + <Fetcher url="/api/member" onFetch={members => this.setState({ members })} > + <Table striped bordered hover> + <thead> + <tr> + <th>Numero</th> + <th>Nombre</th> + <th>Email</th> + <th>Saldo</th> + </tr> + </thead> + <tbody> + {entries} + </tbody> + </Table> + </Fetcher> ); } } -- GitLab