/* globals */ import React from 'react' import { Link, Redirect } from 'react-router-dom' import { LinkContainer } from 'react-router-bootstrap' import swal from 'sweetalert' /* import moment from 'moment' const formatter = new Intl.NumberFormat('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) */ const handlerOnAddDocEventListener = function (eventObj) { const { error, /* document, foundation, */ data } = eventObj if (error) { // console.error(`Error adding user: ${error}`) return } // console.debug([data, ...this.state.products]) this.setState({ products: [data, ...this.state.products] }) } const handlerOnEditDocEventListener = function (eventObj) { const { data, primaryKey, /* document, foundation, */ error } = eventObj if (error) { // console.error(`Error updating user: ${error}`) return } const newData = this.state.products.map((product) => { if (product.__id === primaryKey) { return data } else { return product } }) // console.debug([...newData]) this.setState({ products: [...newData] }) } const handlerOnDeleteDocEventListener = function (eventObj) { const { error, /* document, foundation, */ data } = eventObj if (error) { // console.error(`Error deleting user: ${error}`) return } const allProducts = [...this.state.products] for (let x = 0; x < allProducts.length; x++) { const product = allProducts[x] if (product.__id === data.__id) { allProducts.splice(x) } } this.setState({ products: allProducts }) } /** * @author Eduardo Perotta de Almeida <web2solucoes@gmail.com> * @Component Products * @description React component consuming a Product Data Entity collection to feed a grid * @extends React.Component */ class Products extends React.Component { constructor (props) { super(props) // console.error('------>', props) /** * Entity name which this component represents to */ this.entity = 'Product' /** * access to foundation instance */ this.foundation = props.foundation /** * default pagination to list data */ this.pagination = { offset: 0, limit: 30 } /** * component state */ this.state = { products: [] } this.onAddDocEventListener = null this.onEditDocEventListener = null this.onDeleteDocEventListener = null this.handleDeleteProduct = this.handleDeleteProduct.bind(this) } /** * @Method Products.componentWillUnmount * @summary Called immediately before a component is destroyed. Perform any necessary cleanup in this method, such as cancelled network requests, or cleaning up any DOM elements created in componentDidMount. * @description lets stop listen to Product Data State Change Events * @example componentWillUnmount() { const { Product } = this.foundation.data Product.stopListenTo(this.onAddDocEventListener) Product.stopListenTo(this.onEditDocEventListener) Product.stopListenTo(this.onDeleteDocEventListener) } */ componentWillUnmount () { const { Product } = this.foundation.data /** * Destroy event listeners of this component which are listening to Product collection * and react to it */ Product.stopListenTo(this.onAddDocEventListener) Product.stopListenTo(this.onEditDocEventListener) Product.stopListenTo(this.onDeleteDocEventListener) this.onAddDocEventListener = null this.onEditDocEventListener = null this.onDeleteDocEventListener = null } /** * @async * @Method Products.componentDidMount * @summary Called immediately after a component is mounted. Setting state here will trigger re-rendering. * @description Once component is monted we are now ready to start listen to changes on Product data entity and get a list of product in database to fill out the state.products * @example componentDidMount() { const { Product } = this.foundation.data this.onAddDocEventListener = Product.on( 'add', handlerOnAddDocEventListener.bind(this) ) this.onEditDocEventListener = Product.on( 'edit', handlerOnEditDocEventListener.bind(this) ) this.onDeleteDocEventListener = Product.on( 'delete', handlerOnDeleteDocEventListener.bind(this) ) const { error, data } = await Product.find({}, { ...this.pagination }) if (!error) { this.setState({ products: products.data }) } } */ async componentDidMount () { const { Product } = this.foundation.data // listen to add, edit and delete events on Product collection // and react to it /** * listen to add Product Data Entity change event on Data API */ this.onAddDocEventListener = Product.on('add', handlerOnAddDocEventListener.bind(this)) /** * listen to edit Product Data Entity change event on Data API */ this.onEditDocEventListener = Product.on('edit', handlerOnEditDocEventListener.bind(this)) /** * listen to delete Product Data Entity change event on Data API */ this.onDeleteDocEventListener = Product.on('delete', handlerOnDeleteDocEventListener.bind(this)) // get Products on database const products = await Product.find({}, { ...this.pagination }) // console.warn(products) if (products.data) { this.setState({ products: products.data }) } } /** * @Method Products.handleDeleteProduct * @summary Event handler that Deletes a product * @description Once component is monted we are now ready to start listen to changes on Product data entity and get a list of product in database to fill out the state.products * @param {event} event - The HTML event triggered on User interation * @param {number} __id - The primaryKey value of the record willing to be deleted * @example handleDeleteProduct(e, ___id) { const { Product } = this.foundation.data e.preventDefault() swal({ title: 'Are you sure?', text: 'Once deleted, you will not be able to recover this!', icon: 'warning', buttons: true, dangerMode: true }).then(async (willDelete) => { if (willDelete) { const r = await Product.delete(___id) if (r.error) { swal('Database error', e.error.message, 'error') return } swal('Poof! The product has been deleted!', { icon: 'success' }) return <Redirect to = '/dashboard' / > } else { swal('The Product is safe!') } }) } // <a color='primary' href='#' onClick={e => this.handleDeleteProduct(e, doc.__id)}>[delete]</a> */ handleDeleteProduct (e, ___id) { const { Product } = this.foundation.data e.preventDefault() // console.error(___id) swal({ title: 'Are you sure?', text: 'Once deleted, you will not be able to recover this!', icon: 'warning', buttons: true, dangerMode: true }).then(async (willDelete) => { if (willDelete) { const r = await Product.delete(___id) // console.error(r) if (r.error) { swal('Database error', e.error.message, 'error') return } swal('Poof! The product has been deleted!', { icon: 'success' }) return <Redirect to='/dashboard' /> } else { swal('The Product is safe!') } }) } /** * @async * @Method Products.render * @summary Component render function. * @description Renders a grid of Products */ render () { return ( <main className='col-md-9 ms-sm-auto col-lg-10 px-md-4 main'> <div className='d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 bproduct-bottom'> <h1 className='h2'>Products</h1> <div className='btn-toolbar mb-2 mb-md-0'> <div className='btn-group me-2'> <LinkContainer to='/ProductsAdd'> <button type='button' className='btn btn-sm btn-outline-secondary'> Add new Product </button> </LinkContainer> </div> </div> </div> <div className='table-responsive'> <table className='table table-striped table-sm'> <thead> <tr> <th>Name</th> <th>Address</th> <th>E-mail</th> <th align='right'>Cards</th> <th>-</th> </tr> </thead> <tbody> {this.state.products.map((doc) => ( <tr key={doc.id}> <td>{doc.name}</td> <td>{doc.address}</td> <td>{doc.email}</td> <td align='right'>{doc.cards}</td> <td> <Link color='primary' to={`/ProductsEdit/${doc.__id}`}>[edit]</Link> | <a color='primary' href='#' onClick={e => this.handleDeleteProduct(e, doc.__id)}>[delete]</a> </td> </tr> ))} </tbody> </table> </div> </main> ) } } export default Products