/* 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