Files
storage-manager/client/src/app.js
T

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;