418 lines
12 KiB
JavaScript
418 lines
12 KiB
JavaScript
import React, { useState, useEffect } from 'react';
|
|
import axios from 'axios';
|
|
import Box from './box';
|
|
import api from './api';
|
|
import Modal from './modal';
|
|
import './styles/app.css';
|
|
|
|
function App() {
|
|
|
|
const [data, setData] = useState([]);
|
|
|
|
const [boxID, setBoxID] = useState(undefined);
|
|
const [boxName, setBoxName] = useState('');
|
|
const [boxDescription, setBoxDescription] = useState('');
|
|
|
|
const [showModalBox, setShowModalBox] = useState(false);
|
|
const [showModalItem, setShowModalItem] = useState(false);
|
|
const [showModalItemReadOnly, setShowModalItemReadOnly] = useState(false);
|
|
|
|
const [editBoxBool, setEditBoxBool] = useState(false);
|
|
const [editItemBool, setEditItemBool] = useState(false);
|
|
|
|
const [itemID, setItemID] = useState(undefined);
|
|
const [itemName, setItemName] = useState('');
|
|
const [itemDescription, setItemDescription] = useState('');
|
|
const [itemQuantity, setItemQuantity] = useState(1);
|
|
|
|
const [filter, setFilter] = useState('');
|
|
const [filteredData, setFilteredData] = useState([]);
|
|
|
|
const [dragSource, setDragSource] = useState({});
|
|
const [dragSourceElement, setDragSourceElement] = useState(undefined);
|
|
|
|
const [isMoving, setIsMoving] = useState(false);
|
|
const [moveItemID, setMoveItemID] = useState(null);
|
|
const [moveItemBoxID, setMoveItemBoxID] = useState(null);
|
|
|
|
//fetch all box data
|
|
useEffect(() => {
|
|
const fetchData = async () => {
|
|
await fetchDataAsync();
|
|
}
|
|
fetchData();
|
|
}, []);
|
|
|
|
//set filtered data on filter or original data change
|
|
useEffect(() => {
|
|
const finalFilter = filter.trim().toLowerCase();
|
|
const filtered = data.filter((box) =>
|
|
box.name.toLowerCase().includes(finalFilter) ||
|
|
box.description.toLowerCase().includes(finalFilter) ||
|
|
box.item.some(item =>
|
|
(item.name && item.name.toLowerCase().includes(finalFilter)) ||
|
|
(item.description && item.description.toLowerCase().includes(finalFilter))
|
|
)
|
|
)
|
|
setFilteredData(filtered);
|
|
}, [filter, data]);
|
|
|
|
const fetchDataAsync = async () => {
|
|
try {
|
|
const resp = await axios.get(api.baseApiUrl);
|
|
setData(resp.data);
|
|
setFilteredData(resp.data);
|
|
}
|
|
catch (error) {
|
|
console.log(error);
|
|
}
|
|
}
|
|
|
|
// BOX FUNCTIONS ///////////////////////////////////////////////////////////////
|
|
const createBox = async (boxData) => {
|
|
try {
|
|
const response = await axios.post(api.baseApiUrl, boxData);
|
|
setData(response.data);
|
|
}
|
|
catch (error) {
|
|
console.log(error);
|
|
}
|
|
}
|
|
const editBox = async (boxData) => {
|
|
try {
|
|
const response = await axios.put(`${api.baseApiUrl}/${boxData.id}`, boxData);
|
|
setData(response.data);
|
|
}
|
|
catch (error) {
|
|
console.log(error);
|
|
}
|
|
}
|
|
|
|
const removeBox = async (id) => {
|
|
try {
|
|
const response = await axios.delete(`${api.baseApiUrl}/${id}`);
|
|
const storageData = response.data;
|
|
setData(storageData);
|
|
}
|
|
catch (error) {
|
|
console.log(error);
|
|
}
|
|
}
|
|
|
|
const sortBox = async (target, source) => {
|
|
try {
|
|
const response = await axios.put(`${api.baseApiUrl}/${source._id}/sort`, target);
|
|
setData(response.data);
|
|
}
|
|
catch (error) {
|
|
|
|
}
|
|
}
|
|
const handleNameBox = (e) => {
|
|
setBoxName(e.target.value);
|
|
}
|
|
|
|
const handleBoxDescription = (e) => {
|
|
setBoxDescription(e.target.value);
|
|
}
|
|
|
|
const handleSubmitBox = (event) => {
|
|
event.preventDefault();
|
|
setShowModalBox(false);
|
|
setEditBoxBool(false);
|
|
const boxData = {
|
|
id: boxID,
|
|
name: boxName,
|
|
description: boxDescription
|
|
};
|
|
if (editBoxBool)
|
|
editBox(boxData);
|
|
else
|
|
createBox(boxData);
|
|
|
|
clearFormBox();
|
|
return false;
|
|
}
|
|
|
|
const handleRemoveBox = (id) => {
|
|
removeBox(id);
|
|
}
|
|
const handleAddBox = () => {
|
|
clearFormBox();
|
|
setShowModalBox(true);
|
|
setEditBoxBool(false);
|
|
}
|
|
const handleEditBox = (id) => {
|
|
const box = data.find(box => box._id === id);
|
|
setEditBoxBool(true);
|
|
setBoxName(box.name);
|
|
setBoxDescription(box.description);
|
|
setBoxID(id);
|
|
setShowModalBox(true);
|
|
}
|
|
const clearFormBox = () => {
|
|
setBoxName('');
|
|
setBoxDescription('');
|
|
setBoxID(undefined);
|
|
}
|
|
|
|
const handleDragStartBox = (dragSource, event) => {
|
|
setDragSource(dragSource);
|
|
setDragSourceElement(event.currentTarget);
|
|
event.dataTransfer.dropEffect = "move";
|
|
}
|
|
const handleDragOverBox = (event) => {
|
|
event.preventDefault();
|
|
event.dataTransfer.dropEffect = "move";
|
|
}
|
|
const handleDropBox = async (dragTarget, event) => {
|
|
event.preventDefault();
|
|
|
|
const sourceElement = dragSourceElement;
|
|
const targetElement = event.currentTarget;
|
|
|
|
const elements = [...event.currentTarget.parentElement.children];
|
|
const targetIndex = elements.indexOf(targetElement);
|
|
const sourceIndex = elements.indexOf(sourceElement);
|
|
if (dragTarget._id !== dragSource._id) {
|
|
|
|
const target = Object.assign(dragTarget, { sort: targetIndex });
|
|
const source = Object.assign(dragSource, { sort: sourceIndex });
|
|
await sortBox(target, source);
|
|
}
|
|
return false;
|
|
}
|
|
const handleSelectMoveBox = async (boxData, event) => {
|
|
setMoveItemBoxID(null);
|
|
setMoveItemID(null);
|
|
setIsMoving(false);
|
|
await moveItem(moveItemID,boxData._id);
|
|
|
|
}
|
|
const boxHandler = {
|
|
handleSubmit: handleSubmitBox,
|
|
handleRemove: handleRemoveBox,
|
|
handleName: handleNameBox,
|
|
handleDescription: handleBoxDescription,
|
|
handleEdit: handleEditBox,
|
|
handleDragStart: handleDragStartBox,
|
|
handleDragOver: handleDragOverBox,
|
|
handleDrop: handleDropBox,
|
|
handleSelectMove: handleSelectMoveBox,
|
|
};
|
|
|
|
const handleModalCloseBox = () => {
|
|
setShowModalBox(false);
|
|
}
|
|
// ITEM FUNCTIONS ///////////////////////////////////////////////////////////////
|
|
const moveItem = async (itemID, boxIDTarget) => {
|
|
//post req
|
|
try {
|
|
const response = await axios.post(`${api.baseApiUrl}/item/${itemID}/${boxIDTarget}`);
|
|
setData(response.data);
|
|
}
|
|
catch(error) {
|
|
console.log(error);
|
|
}
|
|
}
|
|
|
|
const createItem = async (boxID, itemData) => {
|
|
try {
|
|
const response = await axios.post(`${api.baseApiUrl}/${boxID}/item`, itemData);
|
|
const boxData = [...data];
|
|
boxData.splice(boxData.findIndex(box => box._id === boxID), 1, response.data);
|
|
setData(boxData);
|
|
}
|
|
catch (error) {
|
|
console.log(error);
|
|
}
|
|
}
|
|
|
|
const editItem = async (boxID, itemID, itemData) => {
|
|
try {
|
|
const response = await axios.put(`${api.baseApiUrl}/${boxID}/item/${itemID}`, itemData);
|
|
const boxData = [...data];
|
|
boxData.splice(boxData.findIndex(box => box._id === boxID), 1, response.data);
|
|
setData(boxData);
|
|
}
|
|
catch (error) {
|
|
console.log(error);
|
|
}
|
|
}
|
|
|
|
const removeItem = async (boxID, itemID) => {
|
|
try {
|
|
const boxData = [...data];
|
|
const response = await axios.delete(`${api.baseApiUrl}/${boxID}/item/${itemID}`);
|
|
boxData.splice(boxData.findIndex(box => box._id === boxID), 1, response.data);
|
|
setData(boxData);
|
|
}
|
|
catch (error) {
|
|
console.log(error);
|
|
}
|
|
}
|
|
|
|
const handleAddItem = (id) => {
|
|
clearFormItem();
|
|
setBoxID(id);
|
|
setEditItemBool(false);
|
|
setShowModalItem(true);
|
|
}
|
|
const setItemInfo = (boxID, itemID) => {
|
|
const box = data.find(box => box._id === boxID);
|
|
const item = box.item.find(item => item._id === itemID);
|
|
setBoxID(boxID);
|
|
setItemID(itemID);
|
|
setItemName(item.name || '');
|
|
setItemDescription(item.description || '');
|
|
setItemQuantity(item.quantity || 1);
|
|
}
|
|
const handleEditItem = (boxID, itemID) => {
|
|
clearFormItem();
|
|
setItemInfo(boxID, itemID);
|
|
setEditItemBool(true);
|
|
setShowModalItem(true);
|
|
}
|
|
const handleMoveItem = (boxID, itemID) => {
|
|
setMoveItemBoxID(boxID);
|
|
setMoveItemID(itemID);
|
|
setIsMoving(true);
|
|
/*highlight which boxes available to move to*/
|
|
/*...*/
|
|
}
|
|
const handleViewItem = (boxID, itemID) => {
|
|
setItemInfo(boxID, itemID);
|
|
setShowModalItemReadOnly(true);
|
|
}
|
|
const handleRemoveItem = (boxID, itemID) => {
|
|
removeItem(boxID, itemID);
|
|
}
|
|
const handleSubmitItem = (event) => {
|
|
event.preventDefault();
|
|
setShowModalItem(false);
|
|
const itemData = {
|
|
id: itemID,
|
|
name: itemName,
|
|
description: itemDescription,
|
|
quantity: itemQuantity
|
|
}
|
|
if (editItemBool)
|
|
editItem(boxID, itemID, itemData);
|
|
|
|
else
|
|
createItem(boxID, itemData);
|
|
|
|
clearFormItem();
|
|
return false;
|
|
}
|
|
|
|
const handleModalCloseItem = () => {
|
|
setShowModalItem(false);
|
|
setShowModalItemReadOnly(false);
|
|
}
|
|
const clearFormItem = () => {
|
|
setItemID(undefined);
|
|
setItemName('');
|
|
setItemDescription('');
|
|
setItemQuantity(1);
|
|
}
|
|
const handleNameItem = (e) => {
|
|
setItemName(e.target.value)
|
|
}
|
|
const handleDescriptionItem = (e) => {
|
|
setItemDescription(e.target.value)
|
|
}
|
|
const handleQuantityItem = (e) => {
|
|
setItemQuantity(parseInt(e.target.value));
|
|
}
|
|
const itemHandler = {
|
|
handleSubmit: handleSubmitItem,
|
|
handleRemove: handleRemoveItem,
|
|
handleAdd: handleAddItem,
|
|
handleEdit: handleEditItem,
|
|
handleMove: handleMoveItem,
|
|
handleView: handleViewItem,
|
|
handleName: handleNameItem,
|
|
handleDescription: handleDescriptionItem,
|
|
handleQuantity: handleQuantityItem
|
|
};
|
|
|
|
const handleFilterChange = (event) => {
|
|
const filterText = event.target.value;
|
|
setFilter(filterText);
|
|
}
|
|
const handleClearFilter = () => {
|
|
setFilter('');
|
|
}
|
|
const boxForm =
|
|
<form onSubmit={boxHandler.handleSubmit}>
|
|
<input id="id" name="id" value={boxID} readOnly hidden></input>
|
|
<legend>New Box</legend>
|
|
<fieldset>
|
|
<label htmlFor="box-name">name
|
|
<input autoFocus onChange={boxHandler.handleName} value={boxName} id="box-name" name="name" type="text" />
|
|
</label>
|
|
<label htmlFor="box-description">description
|
|
<input onChange={boxHandler.handleDescription} value={boxDescription} id="box-description" name="description" type="text" />
|
|
</label>
|
|
</fieldset>
|
|
<button type="submit">submit</button>
|
|
</form>
|
|
|
|
const itemForm = <form onSubmit={itemHandler.handleSubmit}>
|
|
<legend>New Item</legend>
|
|
<fieldset>
|
|
<input id="id" name="id" value={itemID} readOnly hidden></input>
|
|
<label htmlFor="item-name">name
|
|
<input autoFocus onChange={itemHandler.handleName} value={itemName} id="item-name" name="name" type="text"></input>
|
|
</label>
|
|
<label htmlFor="item-description">description
|
|
<input onChange={itemHandler.handleDescription} value={itemDescription} id="item-description" name="description" type="text"></input>
|
|
</label>
|
|
<label htmlFor="item-quantity">quantity
|
|
<input onChange={itemHandler.handleQuantity} value={itemQuantity} id="item-quantity" name="quantity" type="text"></input>
|
|
</label>
|
|
</fieldset>
|
|
<button type="submit">submit</button>
|
|
</form>
|
|
const itemView = <div>
|
|
<h1>{itemName}</h1>
|
|
<h2>{itemDescription}</h2>
|
|
</div>
|
|
|
|
return (
|
|
<>
|
|
{<Modal show={showModalItem} content={itemForm} handleClose={handleModalCloseItem} />}
|
|
{<Modal show={showModalBox} content={boxForm} handleClose={handleModalCloseBox} />}
|
|
{<Modal show={showModalItemReadOnly} content={itemView} handleClose={handleModalCloseItem} />}
|
|
|
|
<div className='header-container'>
|
|
<span className='filter-container'>
|
|
<span className='material-icons icon'>search</span>
|
|
<input spellCheck='false' className='filter' type="search" id="box-filter" name="filter" value={filter} onChange={handleFilterChange} />
|
|
<span className='material-icons icon clear' onClick={handleClearFilter}>clear</span>
|
|
</span>
|
|
{<button className='button' onClick={handleAddBox}>new box</button>}
|
|
</div>
|
|
<div className='body-container scroll-container'>
|
|
<ul className="list-box">
|
|
{filteredData.map((box, index) => {
|
|
return (
|
|
<Box
|
|
isMoving={box._id !== moveItemBoxID && isMoving}
|
|
key={index}
|
|
boxData={box}
|
|
boxHandler={boxHandler}
|
|
itemHandler={itemHandler}
|
|
/>
|
|
);
|
|
})}
|
|
</ul>
|
|
</div>
|
|
|
|
</>
|
|
);
|
|
}
|
|
|
|
export default App;
|