<div id="app"></div>
.App{
display:flex;
flex-direction:column;
justify-content:center;
align-items:center;
}
.FlexContainer{
display:flex;
flex-direction:column;
justify-content:center;
align-items:center;
}
.GenericButton{
margin-right:5px;
}
.MinusOne{
margin-right:25px;
}
.PlusOneHundred{
margin-left:30px;
}
.Undo{
margin-right:30px;
}
.FlexContainer__FirstRow{
margin-bottom:20px;
}
.GenericButton{
/* width:30px;
height:30px; */
}
.TopRow{
/* margin:10px; */
justify-content:space-between;
}
.HistoryTable{
border:1px solid black;
width:40vw;
display:flex;
flex-direction:column;
}
.HistoryTable__row{
padding-left:10px;
padding-bottom:10px;
margin-top:10px;
border-bottom:1px solid black;
text-align:center;
}
.HistoryTable__Counters{
margin-left:20px;
}
.HistoryTable__row:last-child{
border:none;
}
/*
* https://frontendeval.com/questions/undoable-counter
*
* Create a simple counter with undo/redo functionality
*/
const HistoryTable=({history})=>{
return(history.length>1 && history.length<50 &&(
<>
<h2>History</h2>
<div className="HistoryTable">
{ history.slice(0,history.length-1).reverse().map((item)=>{
const{action,currentCounter,futureCounter}=item
return(
<div className="HistoryTable__row">
<span className="HistoryTable__Action">{action>0?`+${action}`:action}</span>
<span className="HistoryTable__Counters">({currentCounter} -> {futureCounter})</span>
</div>
)})}
</div>
</> )
)
}
const Counter=()=>{
//Counter buttons:
// //pushes {action,currentCounter,futureCounter}
//adds or subtracts to master counter
const[masterCounter,setMasterCounter]=React.useState(0)
const [historyTable,setHistoryTable]=React.useState([])
const [masterHistory,setMasterHistory]=React.useState([])
const [undoClickedCounter,setUndoClickedCounter]=React.useState(0)
const lastItem=(arr)=>arr[arr.length-1]
React.useEffect(()=>
console.log("undoClickedCounter",undoClickedCounter,masterHistory),[undoClickedCounter])
const counterHandler=(action)=>{
setMasterCounter((prevState)=>prevState+=action)
//keeps all history of actions
setMasterHistory((prevState)=>prevState.concat(action))
//controls what is shown on screen - immediate history
setHistoryTable((prevState)=>prevState.concat({action,currentCounter:masterCounter,futureCounter:masterCounter+action}))}
const undoHandler=()=>{
if(historyTable.length>0){
//track how many times undo clicked
setUndoClickedCounter((prevState)=>prevState+=1)
//get last object in array
const prevHistory=historyTable[historyTable.length-1]
//set counter equal to opposite of prevAction
setMasterCounter((prevState)=>prevState-=prevHistory.action)
//pop out last item in history
let historyTableCopy=[...historyTable]
historyTableCopy.pop()
setHistoryTable(historyTableCopy)
}
}
const redoHandler=()=>{
if(masterHistory.length>0){
//track how many times undo clicked
setUndoClickedCounter((prevState)=>prevState-=1)
//take last item of masterHistory
const redoItem=masterHistory[masterHistory.length-1]
//set history/counter to this item
setMasterCounter((prevState)=>prevState+=redoItem)
setHistoryTable((prevState)=>prevState.concat({action:redoItem,currentCounter:masterCounter,futureCounter:masterCounter+redoItem}))
//set masterHistory using undoClickCounter
}
}
return(
<div className="App">
<h1>Undoable Counter</h1>
<div className="FlexContainer">
<div className="FlexContainer__FirstRow">
<button className="EditButton Undo" onClick={undoHandler}>Undo</button>
<button className="EditButton Redo" disabled={undoClickedCounter<=0} onClick={redoHandler}>Redo</button>
</div>
<div className="FlexContainer__SecondRow">
<button className="GenericButton -100" onClick={()=>counterHandler(-100)}>-100</button>
<button className="GenericButton -10" onClick={()=>counterHandler(-10)}>-10</button>
<button className="GenericButton MinusOne" onClick={()=>counterHandler(-1)}>-1</button>
{masterCounter}
<button className="GenericButton PlusOneHundred" onClick={()=>counterHandler(100)}>+100</button>
<button className="GenericButton +10" onClick={()=>counterHandler(10)}>+10</button>
<button className="GenericButton +1" onClick={()=>counterHandler(1)}>+1</button>
</div>
</div>
<HistoryTable history={historyTable}/>
</div>
)
}
const App = () => {
return( <Counter/>)
}
ReactDOM.render(<App />, document.getElementById('app'));
View Compiled
This Pen doesn't use any external CSS resources.