/**
* @file
*
* Summary.
* <p>A component to display and modify a counter.</p>
*
* Counter raises the events that are handled by the Counters component.
*
* @author {@link https://codewithmosh.com|Mosh Hamedani}
* @author Paulo Roma
* @since 08/10/2021
* @see <a href="../src/components/counter.jsx">source</a>
* @see <a href="../components/counter.js">source Babel</a>
* @see <a href="/cwdc/14-react/counter/counter.html">link</a>
*/
import React, { Component } from "react";
/**
* <p>Creates a row of buttons for a counter.</p>
*
* Also define some life cycle hooks.
* @extends {React.Component}
* @see <img src="../row.png" width="256">
*/
class Counter extends React.Component {
/**
* Class components always need to call the base constructor with props.
* Moreover, ES6 classes need to call super in case they are subclasses.
* Thus, if you wish to use it in the constructor, you need to pass it to super().
*
* In case we omit it, we can always find props available inside render function.
* @param {Object} props component input.
* @param props.key {Number} counter id.
* @param props.onDelete {Function} callback to delete a counter.
* @param props.onIncrement {Function} callback to increment a counter.
* @param props.onDecrement {Function} callback to decrement a counter.
* @param props.counter {Object<id:Number,value:Number>} counter object.
* @extends {React.Component<Props>}
* @see https://reactjs.org/docs/react-component.html
* @see https://www.digitalocean.com/community/tutorials/react-constructors-with-react-components
*/
constructor(props) {
super(props);
console.log("Counter constructor: props", props);
}
/**
* <p>Called when a component is updated. </p>
* Remember that setState is asynchronous.<br>
* Furthermore, there is no state in this class.<br>
* As a consequence, prevState is always null.
*
* @param {Object} prevProps previous props object.
* @param {Object} prevState previous state object.
* @see https://dev.to/cesareferrari/how-to-use-componentdidupdate-in-react-30en
*/
componentDidUpdate(prevProps, prevState) {
if (prevProps.counter.value !== this.props.counter.value) {
// Ajax call and get new data from the server
console.log("componentDidUpdate: Ajax has been called");
console.log(`prevProps: ${prevProps.counter.value}`);
console.log(`Props: ${this.props.counter.value}`);
}
}
/**
* Called when the component is destroyed.
*/
componentWillUnmount() {
console.log("Counter - Unmount");
}
/**
* Use bootstrap's <a href="/cwdc/5-bootstrap/5.3.html">grid system</a>
* to build layouts: one row and two columns.
*
* @return {HTMLDivElement} a badge, plus an increment, a decrement, and a delete button.
* @see https://getbootstrap.com/docs/5.0/layout/grid/
* @see https://getbootstrap.com/docs/5.0/utilities/spacing/
* @see https://www.bitdegree.org/learn/horizontal-grid
* @see https://icons.getbootstrap.com/icons/trash/
* @see https://fontawesome.com/search?o=r&c=mathematics&f=classic%2Cbrands
*/
render() {
console.log("Counter: props", this.props);
const { counter, onIncrement, onDecrement, onDelete } = this.props;
return (
<div className="row">
{/* jump line after counterid: 2) */}
<div className="w-100">{this.props.children}</div>
{/* break point medium (720px) */}
{/* .col-xs-* classes, create a basic grid system that starts out stacked on */}
{/* extra small sizes and becomes horizontal at the small breakpoint (sm). */}
<div className="col-sm-1">
<span className={this.getBadgeClasses()}>
{this.formatCount()}
</span>
</div>
<div className="col">
<button
onClick={() => onIncrement(counter)}
className="btn btn-secondary btn-sm"
>
<span className="fa fa-plus"></span>
</button>
{/* m-3 is the marging */}
<button
onClick={() => onDecrement(counter)}
className="btn btn-secondary btn-sm m-3"
disabled={counter.value === 0 ? "disabled" : ""}
>
<span className="fa fa-minus"></span>
</button>
<button
type="button"
className="btn btn-danger btn-sm "
onClick={() => onDelete(counter.id)}
>
<span className="fa fa-trash"></span>
</button>
</div>
</div>
);
}
/**
* Returns the color for this counter badge: yellow for 'Zero', or blue otherwise.
*
* @returns {String} the class for setting the color of this counter badge.
*/
getBadgeClasses() {
let classes = "badge m-2 badge-";
classes += this.props.counter.value === 0 ? "warning" : "primary";
return classes;
}
/**
* Format the value of this counter as 'Zero' or its numerical value.
*
* @returns {String|Number} the value of this counter.
*/
formatCount() {
const { value } = this.props.counter;
return value === 0 ? "Zero" : value;
}
}
export default Counter;