import './App.css'; import 'bootstrap/dist/css/bootstrap.min.css'; import { useState,useEffect } from 'react'; import Container from 'react-bootstrap/Container'; import Row from 'react-bootstrap/Row'; import Col from 'react-bootstrap/Col'; import Navbar from 'react-bootstrap/Navbar'; import Button from 'react-bootstrap/Button'; import ProgressBar from 'react-bootstrap/ProgressBar'; import Accordion from 'react-bootstrap/Accordion'; 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 { FaCheckCircle } from 'react-icons/fa'; import { IoCheckmarkCircleOutline,IoCloseCircleSharp,IoAlertCircleOutline } from 'react-icons/io5'; const parse = require('csv-parse/lib/sync') const axios = require('axios'); const dataSplitters = [0,128,225,363] const BACKEND_URL = "https://projectdivar.com:4505" 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 ItemGroup(p) { const { data } = p const { contributor } = p const [displayData,setDisplayData] = useState([]) const [lockout,setLockout] = useState(false) useEffect(()=>{ setDisplayData([...data].sort((a,b)=>{ if (b.required===b.obtained&&a.required!==a.obtained) {return -1} if (b.required===b.obtained&&a.required===a.obtained) {return a.id-b.id} if (b.required!==b.obtained&&a.required!==a.obtained) {return a.id-b.id} return 0 })) },[data]) useEffect(()=>{ displayData.forEach((item)=>{ if (document.getElementById("field_"+item.id)) { document.getElementById("field_"+item.id).value=item.obtained } }) },[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 )} } function Notification(p) { const [show,setShow] = useState(true) const { not } = p return {setShow(false)}} bg={not.operation==="FINISH"?"success":not.operation==="INCREASE"?"primary":"warning"}> {not.username} {not.operation==="FINISH"?" has finished collecting "+not.required+"/"+not.required+" "+not.item_name+"!": not.operation==="INCREASE"?" has collected "+not.obtained+"/"+not.required+" "+not.item_name+" (+"+(not.obtained-not.previous_amt)+")" :" has set "+not.item_name+" to "+not.obtained+"/"+not.required} } function DarkInput(p){ return } function DarkSelect(p){ return } function ListApp(p){ //https://xivapi.com/search?filters=ClassJob.ID=11,RecipeLevelTable.ClassJobLevel%3E=36,RecipeLevelTable.ClassJobLevel%3C=45&page=1 const {transferItems} = p const [groceryList,setGroceryList] = useState([]) const crafters=["CRP Carpenter","BSM Blacksmith","ARM Armorer","GSM Goldsmith","LTW Leatherworker","WVR Weaver","ALC Alchemist","CUL Culinarian"] const [selectedCrafter,setSelectedCrafter] = useState(0) const [minLevel,setMinLevel] = useState(1) const [maxLevel,setMaxLevel] = useState(10) const [playerInventory,setPlayerInventory] = useState([]) const [saddlebagInventory,setSaddlebagInventory] = useState([]) const [r1Inventory,setR1Inventory] = useState([]) const [r2Inventory,setR2Inventory] = useState([]) const [r3Inventory,setR3Inventory] = useState([]) const [r4Inventory,setR4Inventory] = useState([]) const [r5Inventory,setR5Inventory] = useState([]) const [r6Inventory,setR6Inventory] = useState([]) const [r7Inventory,setR7Inventory] = useState([]) const [r8Inventory,setR8Inventory] = useState([]) const [r9Inventory,setR9Inventory] = useState([]) const [checking,setChecking] = useState(false) const [lastUpdate,setLastUpdate] = useState(0) const retainerNames = ["Ayayayaya","Kittystorage","Morecatz","Finalretainer","Nowitsabun","Butwhy","Kkittyy","Howdoesanyonenameall","Ayayayayay"]; function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } useEffect(()=>{ const interval = setInterval(()=>{ axios.get("http://projectdivar.com/inventoryData?lastUpdate="+lastUpdate) .then((data)=>{ if (data.data.length>0){ setLastUpdate(new Date().getTime()) for (var i=0;i{}) },1000) return ()=>clearInterval(interval) }) function submitForm(){ let classID=Number(selectedCrafter)+8 let filter="https://xivapi.com/search?filters=ClassJob.ID="+classID+",RecipeLevelTable.ClassJobLevel>="+minLevel+",RecipeLevelTable.ClassJobLevel<="+maxLevel let pageCount=0 let currentPage=1 let recipeData=[] setChecking(true) axios.get(encodeURI(filter)) .then(async(resp)=>{ let data=resp.data let pageCount=data.Pagination.PageTotal let results=data.Results while (currentPage<=pageCount){ for (let recipe of results){ axios.get(encodeURI("https://xivapi.com"+recipe.Url)) .then((resp)=>{ let d = resp.data recipeData=[d,...recipeData] }) await sleep(250) } currentPage++; if (currentPage>pageCount){ break; } await axios.get(encodeURI(filter+"&page="+currentPage)) .then((resp)=>{ let d=resp.data results=d.Results }) } }) .finally(async()=>{ //console.log(recipeData) //setChecking(false) let craftedItems={} for(var recipe of recipeData){ for (let i=0;i<=5;i++){ var ingredient=recipe["ItemIngredient"+i] var amount=recipe["AmountIngredient"+i] if (ingredient!==null){ if (ingredient.Name.includes("Component Materials")||ingredient.Name.includes("Skybuilders'")){continue} if (ingredient.Name in craftedItems){ let oldItem=craftedItems[ingredient.Name]; oldItem.amt+=Number(amount) craftedItems[ingredient.Name]=oldItem } else { craftedItems[ingredient.Name]={...ingredient,"amt":Number(amount)} } } } } let retainerItems=[[],[],[],[],[],[],[],[],[],[]] for (var item of Object.keys(craftedItems)){ let found=false let retainerArray=[r1Inventory,r2Inventory,r3Inventory,r4Inventory,r5Inventory,r6Inventory,r7Inventory,r8Inventory,r9Inventory] for (var i=0;ia.slot-b.slot) } setGroceryList(retainerItems) setChecking(false) }) } 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)":""} } function RetainerDisplay(p){ const {id,inventory} = p return <>

{retainerNames[id]}'s Inventory

{inventory.map((item,i)=>)} } return <> {setSelectedCrafter(f.currentTarget.value)}}> {crafters.map((crafter,i)=>)} Level Range: {setMinLevel(f.currentTarget.value)}}> - {setMaxLevel(f.currentTarget.value)}}> A {groceryList.map((list,i)=>{ if (list.length>0){ return <> {(i===9)?

Not Found:

:

From {retainerNames[i]}:

}
    {list.map((item,j)=>
  • )}
} })} Inventories

Player Inventory

{playerInventory.map((item,i)=>)}

Chocobo Saddlebag Inventory

{saddlebagInventory.map((item,i)=>)} } function App() { const [data,setData] = useState([]) const [data2,setData2] = useState([]) const [data3,setData3] = useState([]) const [data4,setData4] = useState([]) const [fileData,setFileData] = useState() const [update,setUpdate] = useState(true) const [succeeded,setSucceeded] = useState(0) const [failed,setFailed] = useState(0) const [total,setTotal] = useState(0) const [lastModified,setLastModified] = useState(new Date()) const [contributor,setContributor] = useState("") const [notifications,setNotifications] = useState([]) const [nav,setNav] = useState("main") const [transferItems,setTransferItems] = useState([]) function LZ(digits,numb) { return "0".repeat(digits-String(numb).length)+numb } useEffect(()=>{ const interval = setInterval(()=>{ axios.get(BACKEND_URL+"/lastUpdate") .then((data)=>{ if (new Date(data.data[0].last_modified)>lastModified) { console.log("Updating entries... "+[lastModified,data.data[0].last_modified]) setLastModified(new Date()) return axios.get("https://projectdivar.com:4505/getData") .then((data)=>{ //setData(data.data) setData(data.data.slice(dataSplitters[0],dataSplitters[1])) 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)) }) } }) .catch((err)=>{ console.log(err.message) }) },1000) return ()=>clearInterval(interval) },[lastModified]) useEffect(()=>{ var notificationLastUpdate = new Date(new Date()-(NOTIFICATIONTIMEOUT*1000)) var largestNotificationID = -1 var dataCheck=true const interval = setInterval(()=>{ if (dataCheck) { 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)) setNotifications(data.data) var completion=false var largestID = -1 for (var dat of data.data) { if (dat.id>largestNotificationID && dat.operation==="FINISH") { completion=true largestID=Math.max(dat.id,largestID) break } else if (dat.id>largestNotificationID) { largestID=Math.max(dat.id,largestID) } } if (largestID!==-1) { largestNotificationID = largestID if (completion) {progress2.play()} else {progress1.play()} } } }) .catch((err)=>{ console.log(err.message) }) .then(()=>{ dataCheck=true }) } },1000) return ()=>clearInterval(interval) },[]) const disabled=true useEffect(()=>{ if (update) { axios.get("https://projectdivar.com:4505/getData") .then((data)=>{ //setData(data.data) setData(data.data.slice(dataSplitters[0],dataSplitters[1])) 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)) }) .catch((err)=>{ console.log(err.message) setData([ {id:1726,itemid:2,name:"Fire Shard",icon:"/i/020000/020001.png",obtained:694,required:4124}, {id:1727,itemid:3,name:"Ice Shard",icon:"/i/020000/020003.png",obtained:0,required:1226}, {id:1728,itemid:4,name:"Wind Shard",icon:"/i/020000/020004.png",obtained:4719,required:4719}, {id:1729,itemid:5,name:"Earth Shard",icon:"/i/020000/020006.png",obtained:15,required:1764}, {id:1730,itemid:6,name:"Lightning Shard",icon:"/i/020000/020005.png",obtained:0,required:2374}, ]) }) setUpdate(false) } },[update]) useEffect(()=>{ if (succeeded+failed===total) { setUpdate(true) } },[succeeded,failed,total]) useEffect(()=>{ const downloadData=(d,val,max)=>{ if (val{ setTimeout(downloadData(d,val+1,max),250) }) .catch((err)=>{ setFailed(failed+1) }) } } var d = parse(fileData,{columns:true,skip_empty_lines:true}) console.log(d) downloadData(d,0,d.length) setTotal(d.length) },[fileData,failed,succeeded]) return ( BUN logo BUN Collab App {contributor.length>0&&<> {setNav("main")}}>Main {setNav("list")}}>Grocery List Signed in as {contributor} } {contributor.length===0?<> {if (k.key==='Enter') {setContributor(document.getElementById("username").value)}}} id="username"/> : nav==="main"? data.length>0? <> : !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"?: <> }
{notifications.map((not)=>{ return })}
); } export default App;