<repo_name>VituBR19/react-drag-and-drop<file_sep>/README.md
# react-drag-and-drop
This project is a study, React Todo List using Drag and Drop feature.

# How to install
Just run into your terminal npm install, to install all modules.

# How to use
All you have to do is create a new card clicking at the '+' button, so you can write you todo item and click 'Create'. 
- You can sort your list by drag and drop
- You can delete a card if you want or if you finished your item
- If you double click on card's text you can edit that text, press `Enter` to apply

# Storage 
The storage was made using just Local Storage from Javascript
<file_sep>/src/components/Board/index.js
import React, { useState, useEffect } from 'react';
import './index.css';

import { DragDropContext, Droppable } from 'react-beautiful-dnd';
import { getListStyle } from '../../styles';
import { getLocalData, setLocalData } from '../../LocalData';

import Card from '../Card';

function Board(props) {
    
    const { boardName } = props;

    const [itens, setItens] = useState(getLocalData() ? getLocalData() : []);
    const [activeAdd, setActiveAdd] = useState('hidden');
    const [textContent, setTextContent] = useState('');

    function dragEnd(result, itens, setItens) {
        if(!result.destination) return;
        
        const { source, destination } = result;
        const copiedItems = itens;
        const [removed] = copiedItems.splice(source.index, 1);
        copiedItems.splice(destination.index, 0, removed);
    
        setItens(copiedItems);
        setLocalData(itens);
    }

    function addTask() {
      setActiveAdd( 'show' );
    }

    function handleCloseModal(e) {
      if(e.keyCode === 27) {
        setActiveAdd('hidden');
        setTextContent('');
        return;
      }

      if(e.target.className.startsWith('text')) {
        setActiveAdd('hidden');
        setTextContent('');
        return;
      }
    }

    function handleTaskcontent(e) {
      setTextContent( e.target.value );
    }

    function handleNewTask() {
      setActiveAdd( 'hidden' );

      if(textContent) {
        const newItem = [...itens, {
          id:`${Date.now()}`,
          content: `${textContent}`
        }];
        
        setLocalData(newItem);
        
        const savedNewItem = getLocalData();

        setItens(savedNewItem);
      }

      setTextContent('');
    }

    return (
        <div className="board">
          <DragDropContext onDragEnd={result => dragEnd(result, itens, setItens)}>
            <span className="board-title" >{`${boardName}`}</span>
            <button className="add" onClick={addTask}>+</button>
            
            {/* area to add some text to a card */}
            <div onClick={handleCloseModal} className={`text-card ${activeAdd}`}>
              <div className="text-area-container">
                <textarea onChange={handleTaskcontent} onKeyDown={handleCloseModal} value={textContent} className="add-text"></textarea>
                <button onClick={handleNewTask} className="apply-text">Criar</button>
              </div>
            </div>

            <Droppable droppableId='droppable'>

              {(provided, snapshot) => (
                <div 
                  {...provided.droppableProps}
                  ref={provided.innerRef}
                  style={getListStyle(snapshot.isDraggingOver)} 
                >
                  
                  { itens.map((item, index) => (
                    <Card 
                      item={item}
                      setItens={setItens}
                      key={index}
                      index={index}
                       />
                  )) }
                  {provided.placeholder}
                </div>
              )}
            </Droppable>
          </DragDropContext>
        </div>
    )
}

export default Board;
<file_sep>/src/components/Card/index.js
import React, { useState } from 'react';
import './index.css';

import { Draggable } from 'react-beautiful-dnd';
import { getItemStyle } from '../../styles';
import { getLocalData, setLocalData } from '../../LocalData';

function Card(props) {

    const {item, index, setItens} = props;

    const [activeInput, setActiveInput] = useState('hidden');
    const [activeText, setActiveText] = useState('show');

    const [ contentText, setContentText] = useState('');

    function handleDelete(e) {
        const allItems = getLocalData();
        const itemIndexToRemove = e.target.id;
        
        allItems.splice(itemIndexToRemove, 1);

        setLocalData(allItems);

        setItens(allItems);
    }

    function handleDoubleClick() {
        setContentText(item.content);

        setActiveInput('show');
        setActiveText('hidden');
    }

    function handleChange(e) {
        setContentText( e.target.value );
    }

    function handleKeyDown(e) {
        if(e.keyCode === 27) {
            setActiveInput('hidden');
            setActiveText('show');
            return;
        }

        if(e.keyCode !== 13) return;

        const allItems = getLocalData();
        
        const foundIndex = allItems.findIndex(i => i.id === item.id);
        allItems[foundIndex].content = contentText;
        setItens(allItems);
        setLocalData(allItems);

        setActiveInput('hidden');
        setActiveText('show');
    } 

    return (
        <>
        <Draggable className='card' key={item.id} draggableId={item.id} index={index}>
            { (provided, snapshot) => (
            <div 
                ref={provided.innerRef}
                {...provided.draggableProps}
                {...provided.dragHandleProps} 
                style={getItemStyle(snapshot.isDragging, provided.draggableProps.style)}
            >
                <div className='content-container'>
                    <textarea type="text" 
                    col="25"
                    onKeyDown={handleKeyDown}
                    onChange={handleChange}
                    className="edit-text"
                    value={contentText}
                    id={activeInput}
                    autoFocus/>

                    <span onDoubleClick={handleDoubleClick} 
                    id={item.id}
                    className={`item-text ${activeText}`}>
                        {item.content}
                    </span>
                    
                    <div className="actions">
                        {/* delete */}
                        <a id={index} onClick={handleDelete}>
                            x
                        </a>
                    </div>
                </div>
            </div>
            ) }
        </Draggable>
        </>
    )
}

export default Card;
<file_sep>/src/LocalData.js
const getLocalData = () => {
    return JSON.parse(localStorage.getItem('items'));
};

const setLocalData = (item) => {
    localStorage.setItem('items', JSON.stringify(item));
};

module.exports = { getLocalData, setLocalData };
