Sample Project 1

App.js

import { useState } from 'react';
import classnames from 'classnames';

import shoppingIcon from './assets/shopping-icon.svg'
import plusIcon from './assets/plus-icon.svg'
import minusIcon from './assets/minus-icon.svg'
import './App.css';

function App() {

  const [value, setValue] = useState('');
  const [todos, setTodos] = useState([
    {title: 'Nasi Goreng', count: 1},
    {title: 'Baso', count: 1},
    {title: 'Mie Ayam', count: 1}
  ]);

  const handleSubmit = (e) => {
    e.preventDefault()

    if(!(value)) {
      alert('No blank list!')
      return;
    }

    const addedTodos = [...todos, {
      title: value,
      count: 1
    }]

    setTodos(addedTodos)
    setValue('')
  }

  // console.log(value);
  // console.log(todos);

  const handleAdditionCount = (index) => {
    const newTodos = [...todos]

    newTodos[index].count = newTodos[index].count + 1

    setTodos(newTodos);
  }

  const handleSubstractionCount = (index) => {
    const newTodos = [...todos]

    if(newTodos[index].count > 0) {
      // Selama jumlah count nya masih di atas 0
      // Bisa lakuin pengurangan
      newTodos[index].count = newTodos[index].count - 1
    } else {
      // Kalo udah 0 dan masih dikurangin juga
      // Hapus array value dengan index yang sesuai
      newTodos.splice(index, 1)
    }

    setTodos(newTodos)
  }

  const getTotalCounts = () => {
    const totalCounts = todos.reduce((total, num) => {
      return total + num.count
    }, 0)

    return totalCounts
  }


  return (
    <>
      <nav className='nav'>
        <img className='nav-icon' src={shoppingIcon} alt="shopping-icon" />
        <h1 className='nav-title'>Shopping List</h1>
      </nav>

      <section className='container'>
        <form className='form' onSubmit={handleSubmit}>
          <input 
            onChange={(e) => {setValue(e.target.value)}}
            value={value}
            className='input'
            type='text'
            placeholder="List"
          />
          <button className='add-button' type='submit'>Add</button>
        </form>

        <div className='info'>
          <div className='info-total'>
            <p>
              {`Total List: ${todos.length}`}
            </p>
          </div>
          <div className='info-total'>
            <p>
              {`Total Count: ${getTotalCounts()}`}
            </p>
          </div>
          <button onClick={() => setTodos([])} className='delete-all-button'>
            Delete All List
          </button>
        </div>

        {todos.length > 0 ? (
          <div className="todos">
            {todos.map((todo, index, arr) => {
              return (
                <div key={index} className={`todo ${!(arr.length === index + 1) && 'todo-divider'}`}>
                  {todo.title}

                  <div className='todo-icon-wrapper'>
                    <div className='todo-count'>{todo.count}</div>

                    <button onClick={() => handleSubstractionCount(index)} className='todo-action-button'>
                      <img src={minusIcon} alt="minus icon" />
                    </button>

                    <button onClick={() => handleAdditionCount(index)} className='todo-action-button'>
                      <img src={plusIcon} alt="plus icon" />
                    </button>
                  </div>
                </div>
              )
            })}
          </div>
        ) : (
          <div>Kosong</div>
        )}
      </section>

    </>
  );
}

export default App;

App.css

.nav {
  display: flex;
  justify-content: center;
  align-items: center;
  text-align: center;
  background-color: var(--main-background-color);
  padding: 0 16px;
  height: 55px;
}

.nav-icon{
  height: 24px;
  width: 24px;
}

.nav-title{
  color: var(--secondary-font-color);
  font-size: 24px;
  font-weight: bold;
}

.container {
  display: flex;
  flex-direction: column;

  height: calc(100vh- 55vh);
  max-width: 480px;
  padding: 16px;
  margin: 0 auto;
  background-color: var(--main-container-color);
}

.form{
  display: flex;
}

.input{
  flex: 1;
  margin-right: 8px;

  box-shadow: var(--main-box-shadow);
  border: none;
  border-radius: 6px;
  padding: 10px;

  color: var(--main-font-color);
  font-size: 16px;
  font-weight: 600;
}

.add-button{
  border: none;
  border-radius: 6px;

  color: var(--secondary-font-color);
  font-size: 16px;
  font-weight: bold;
  text-transform: uppercase;

  width: 80px;
  background-color: var(--main-background-color);
  box-shadow: var(--main-box-shadow);
}

.todos {
  box-shadow: var(--main-box-shadow);
  overflow-x: hidden;
  overflow-y: auto;
  border-radius: 8px;
  max-height: 640px;
}

.todo{
  display: flex;
  justify-content: space-between;
  align-items: center;

  height: 60px;
  padding: 12px 16px;
  background-color: var(--main-background-color-light);

  color: var(--main-font-color);
  font-size: 16px;
  font-weight: 600;
}

.todo-count{
  display: flex;
  justify-content: center;
  align-items: center;

  height: 32px;
  padding: 24px;
  border-radius: 4px;

  color: var(--label-font-color);
  background-color: var(--secondary-font-color);
  box-shadow: var(--main-box-shadow-inset);
}

.todo-icon-wrapper{
  display: flex;
  align-items: center;
  justify-content: space-between;

  align-items: center;
  width: 120px;
}

.todo-action-button{
  border: none;
  background-color: unset;
  padding: unset;

  height: 24px;
  width: 24px;
}

.todo-divider{
  border-bottom: 1px solid var(--main-border-color);
}

.info {
  display: flex;
  justify-content: space-between;
  align-items: center;

  width: 100%;
  padding: 16px 0;
}

.info-total{
  display: flex;
  justify-content: center;
  align-items: center;

  color: var(--main-font-color);
  font-size: 12px;
}

.info-total > p {
  font-weight: bold;
}

.delete-all-button {
  background-color: unset;
  border: none;
  padding: unset;
  color: var(--danger-font-color);
  font-size: 12px;
  font-weight: bold;
}

Last updated

Was this helpful?