From d7bb77b4860fdc56931db63f6f064cac960a8e61 Mon Sep 17 00:00:00 2001 From: sigonasr2 Date: Sat, 13 May 2023 09:23:44 -0500 Subject: [PATCH] Updated app to support fuzzy item searches and fixed bugs --- package-lock.json | 5 ++ package.json | 1 + src/App.js | 176 +++++++++++++++++++++++++++++----------------- 3 files changed, 118 insertions(+), 64 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5198036..27625d4 100755 --- a/package-lock.json +++ b/package-lock.json @@ -6992,6 +6992,11 @@ "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=" }, + "fuzzysort": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/fuzzysort/-/fuzzysort-2.0.4.tgz", + "integrity": "sha512-Api1mJL+Ad7W7vnDZnWq5pGaXJjyencT+iKGia2PlHUcSsSzWwIQ3S1isiMpwpavjYtGd2FzhUIhnnhOULZgDw==" + }, "gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", diff --git a/package.json b/package.json index 1fa332d..7d35a55 100755 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "axios": "^0.21.1", "bootstrap": "^5.0.2", "csv-parse": "^4.16.0", + "fuzzysort": "^2.0.4", "react": "^17.0.2", "react-bootstrap": "^2.0.0-beta.4", "react-dom": "^17.0.2", diff --git a/src/App.js b/src/App.js index 328c074..991482f 100755 --- a/src/App.js +++ b/src/App.js @@ -1,7 +1,7 @@ import './App.css'; import 'bootstrap/dist/css/bootstrap.min.css'; -import { useState,useEffect } from 'react'; +import { useState,useEffect,Fragment } from 'react'; import Container from 'react-bootstrap/Container'; import Row from 'react-bootstrap/Row'; @@ -14,15 +14,18 @@ import ToastContainer from 'react-bootstrap/ToastContainer' import Toast from 'react-bootstrap/Toast' import Nav from 'react-bootstrap/Nav' import Spinner from 'react-bootstrap/Spinner'; +import Form from 'react-bootstrap/Form'; import { FaCheckCircle } from 'react-icons/fa'; import { IoCheckmarkCircleOutline,IoCloseCircleSharp,IoAlertCircleOutline } from 'react-icons/io5'; +const fuzzysort = require('fuzzysort') + const parse = require('csv-parse/lib/sync') const axios = require('axios'); -const dataSplitters = [0,128,225,363] +const dataSplitters = [0,190,475,670] const BACKEND_URL = "https://projectdivar.com:4505" @@ -31,6 +34,43 @@ const NOTIFICATIONTIMEOUT = 300 //In seconds const progress1 = new Audio(process.env.PUBLIC_URL+"/progress1.mp3") const progress2 = new Audio(process.env.PUBLIC_URL+"/progress2.mp3") +function Item(p){ + const {item,setLockout,contributor,lockout} = p + + function updateItem(item,target,contributor) { + var correctedVal=Math.min(item.required,target.value); + if (correctedVal===Number(item.obtained)) {return;} + setLockout(true) + axios.post(BACKEND_URL+"/updateItem",{obtained:correctedVal,id:item.id,last_modified:new Date(),item_name:item.name,username:contributor,required:item.required,operation:correctedVal===Number(item.required)?"FINISH":correctedVal>item.obtained?"INCREASE":"SET",previous_amt:item.obtained}) + .then((data)=>{ + setLockout(false) + }) + .catch((err)=>{ + + }) + } + + return + + {item.name}/ {item.name} + + + { + if (k.key==='Enter') {updateItem(item,document.getElementById("field_"+item.id),contributor)} + }} + onChange={(f)=>{ + if (f.currentTarget.value>=item.required) {f.currentTarget.blur()} + }} onBlur={(f)=>{updateItem(item,f.currentTarget,contributor)}} type="number" min="0" max={item.required}/> / {item.required} {item.required!==item.obtained&&{ + updateItem(item,{value:item.required},contributor) + }}/>} + + + View Item Info + + +} + function ItemGroup(p) { const { data } = p const { contributor } = p @@ -53,42 +93,11 @@ function ItemGroup(p) { } }) },[displayData]) - - function updateItem(item,target,contributor) { - var correctedVal=Math.min(item.required,target.value); - if (correctedVal===Number(item.obtained)) {return;} - setLockout(true) - axios.post(BACKEND_URL+"/updateItem",{obtained:correctedVal,id:item.id,last_modified:new Date(),item_name:item.name,username:contributor,required:item.required,operation:correctedVal===Number(item.required)?"FINISH":correctedVal>item.obtained?"INCREASE":"SET",previous_amt:item.obtained}) - .then((data)=>{ - setLockout(false) - }) - .catch((err)=>{ - - }) - } return {p.name} - {displayData.map((item,i,arr)=> - - {item.name}/ {item.name} - - - { - if (k.key==='Enter') {updateItem(item,document.getElementById("field_"+item.id),contributor)} - }} - onChange={(f)=>{ - if (f.currentTarget.value>=item.required) {f.currentTarget.blur()} - }} onBlur={(f)=>{updateItem(item,f.currentTarget,contributor)}} type="number" min="0" max={item.required}/> / {item.required} {item.required!==item.obtained&&{ - updateItem(item,{value:item.required},contributor) - }}/>} - - - View Item Info - - )} + {displayData.map((item,i,arr)=>)} } @@ -211,6 +220,7 @@ function ListApp(p){ let currentPage=1 let recipeData=[] setChecking(true) + setGroceryList([]) axios.get(encodeURI(filter)) .then(async(resp)=>{ let data=resp.data @@ -293,7 +303,7 @@ function ListApp(p){ function Item(p){ const {it} = p return it.amt>0&& - {it.slot?"["+Math.floor(it.slot/35+1)+"]":""} {it.name} x{it.amt} {it.hq?"(HQ)":""} + {Number.isInteger(it.slot)?"["+Math.floor(it.slot/35+1)+"]":""} {it.name} x{it.amt} {it.hq?"(HQ)":""} } function RetainerDisplay(p){ @@ -326,18 +336,21 @@ function ListApp(p){ + + + A {groceryList.map((list,i)=>{ if (list.length>0){ - return <> + return {(i===9)?

Not Found:

:

From {retainerNames[i]}:

}
    - {list.map((item,j)=>
  • )} + {list.map((item,j)=>
  • )}
- +
} })} Inventories @@ -368,6 +381,7 @@ function App() { const [succeeded,setSucceeded] = useState(0) const [failed,setFailed] = useState(0) const [total,setTotal] = useState(0) + const [completeRatio,setCompleteRatio] = useState(0) const [lastModified,setLastModified] = useState(new Date()) const [contributor,setContributor] = useState("") @@ -377,6 +391,10 @@ function App() { const [transferItems,setTransferItems] = useState([]) + const [matchedItems,setMatchedItems] = useState([]) + + const [lockout,setLockout] = useState(false) + function LZ(digits,numb) { return "0".repeat(digits-String(numb).length)+numb } @@ -395,6 +413,12 @@ function App() { setData2(data.data.slice(dataSplitters[1],dataSplitters[2])) setData3(data.data.slice(dataSplitters[2],dataSplitters[3])) setData4(data.data.slice(dataSplitters[3],data.data.length)) + let items=0,tot=0 + for (var item of data.data){ + items+=item.obtained + tot+=item.required + } + setCompleteRatio(items/tot) }) } }) @@ -410,13 +434,13 @@ function App() { var largestNotificationID = -1 var dataCheck=true const interval = setInterval(()=>{ - if (dataCheck) { + if (dataCheck&&nav==="main") { dataCheck=false notificationLastUpdate = new Date(new Date()-(NOTIFICATIONTIMEOUT*1000)) axios.get(BACKEND_URL+"/getNotifications?date="+encodeURIComponent(LZ(4,notificationLastUpdate.getUTCFullYear())+"-"+LZ(2,notificationLastUpdate.getUTCMonth()+1)+"-"+LZ(2,notificationLastUpdate.getUTCDate())+" "+LZ(2,notificationLastUpdate.getUTCHours())+":"+LZ(2,notificationLastUpdate.getUTCMinutes())+":"+LZ(2,notificationLastUpdate.getUTCSeconds())+"."+LZ(3,notificationLastUpdate.getUTCMilliseconds())+"+00")) .then((data)=>{ if (data.data.length>0) { - console.log("New notification array: "+JSON.stringify(data.data)) + //console.log("New notification array: "+JSON.stringify(data.data)) setNotifications(data.data) var completion=false var largestID = -1 @@ -459,6 +483,12 @@ function App() { setData2(data.data.slice(dataSplitters[1],dataSplitters[2])) setData3(data.data.slice(dataSplitters[2],dataSplitters[3])) setData4(data.data.slice(dataSplitters[3],data.data.length)) + let items=0,tot=0 + for (var item of data.data){ + items+=item.obtained + tot+=item.required + } + setCompleteRatio(items/tot) }) .catch((err)=>{ console.log(err.message) @@ -521,7 +551,29 @@ function App() { console.log(d) downloadData(d,0,d.length) setTotal(d.length) - },[fileData,failed,succeeded]) + },[fileData]) + + function Importer(){ + return + + {total===0?{ + const reader = new FileReader() + reader.onload=(ev)=>{ + setFileData(ev.target.result) + } + reader.readAsText(f.target.files[0]) + }} style={{opacity:0}} id="uploads" type="file" accept=".txt,.csv"/>: + <> + + + + +
{Math.round(((failed+succeeded)/total)*100)+"%"}
+ + } + +
+ } return ( @@ -545,35 +597,31 @@ function App() { nav==="main"? data.length>0? <> + + + + + + +
+ + { + if (f.currentTarget.value.length>2){ + setMatchedItems(fuzzysort.go(f.currentTarget.value.trim().toLowerCase(), [...data,...data2,...data3,...data4], {key:'name'})) + } + }} /> + {matchedItems.map((item)=>)} + +
+
- : - !disabled&& - - - {total===0?{ - const reader = new FileReader() - reader.onload=(ev)=>{ - setFileData(ev.target.result) - } - reader.readAsText(f.target.files[0]) - }} style={{opacity:0}} id="uploads" type="file" accept=".txt,.csv"/>: - <> - - - - -
{Math.round(((failed+succeeded)/total)*100)+"%"}
- - } - -
- : - nav==="list"?: + : + :nav==="list"?: <> }