Add in node timer features

main
sigonasr2 2 years ago
parent 1d044f986d
commit 3b25783304
  1. 264
      src/App.js

@ -17,7 +17,8 @@ import Spinner from 'react-bootstrap/Spinner';
import Form from 'react-bootstrap/Form'; import Form from 'react-bootstrap/Form';
import { FaCheckCircle } from 'react-icons/fa'; import { FaCheckCircle } from 'react-icons/fa';
import { IoCheckmarkCircleOutline,IoCloseCircleSharp,IoAlertCircleOutline } from 'react-icons/io5'; import { BiAlarmAdd } from 'react-icons/bi';
import { MdAlarmOff } from 'react-icons/md';
const fuzzysort = require('fuzzysort') const fuzzysort = require('fuzzysort')
@ -37,8 +38,36 @@ const progress2 = new Audio(process.env.PUBLIC_URL+"/progress2.mp3")
const retainerNames = ["Ayayayaya","Kittystorage","Morecatz","Finalretainer","Nowitsabun","Butwhy","Kkittyy","Howdoesanyonenameall","Ayayayayay"]; const retainerNames = ["Ayayayaya","Kittystorage","Morecatz","Finalretainer","Nowitsabun","Butwhy","Kkittyy","Howdoesanyonenameall","Ayayayayay"];
function Item(p){ function Item(p){
const {item,setLockout,contributor,lockout,itemCount,totalItemCount,playerInventory} = p const {item,contributor,itemCount,totalItemCount,playerInventory} = p
const [itemLoc,setItemLoc]=useState("") const [itemLoc,setItemLoc]=useState("")
const [itemTimers,setItemTimers]=useState([])
const [lockout,setLockout]=useState(false)
function updateTimer(ts,te,timerIndex) {
var newTimerStart=[];
if (item.timer_start!==null){
newTimerStart=[...item.timer_start.split(",")];
}
var newTimerEnd=[];
if (item.timer_end!==null){
newTimerEnd=[...item.timer_end.split(",")];
}
if (ts==""&&te==""){
newTimerStart=newTimerStart.filter((item,i)=>i!=timerIndex);
newTimerEnd=newTimerEnd.filter((item,i)=>i!=timerIndex);
} else {
newTimerStart[timerIndex]=ts;
newTimerEnd[timerIndex]=te;
}
setLockout(true)
axios.post(BACKEND_URL+"/updateTimer",{timer_start:newTimerStart.join(","),timer_end:newTimerEnd.join(","),id:item.id,last_modified:new Date()})
.then((data)=>{
setLockout(false)
})
.catch((err)=>{
setLockout(false)
})
}
function updateItem(item,target,contributor) { function updateItem(item,target,contributor) {
var correctedVal=Math.min(item.required,target.value); var correctedVal=Math.min(item.required,target.value);
@ -49,7 +78,7 @@ function Item(p){
setLockout(false) setLockout(false)
}) })
.catch((err)=>{ .catch((err)=>{
setLockout(false)
}) })
} }
@ -131,7 +160,7 @@ function Item(p){
tempItem.amt+=it.amt tempItem.amt+=it.amt
} }
tempItem.page=Math.floor(j/35+1) tempItem.page=Math.floor(j/35+1)
locObj[String(retainerNames[i-1])]={...tempItem} locObj[String(retainerNames[i-1])]={...tempItem}
} }
} }
} }
@ -145,6 +174,12 @@ function Item(p){
//locs+="Player Inventory ["+Math.floor((j/35+1))+"] x"+it.amt //locs+="Player Inventory ["+Math.floor((j/35+1))+"] x"+it.amt
} }
setItemLoc(locs) setItemLoc(locs)
if (item.required!==item.obtained&&item.timer_start!==null&&item.timer_start.length>0&&item.timer_start[0]!=""){
var endTimers = item.timer_end.split(",");
setItemTimers(item.timer_start.split(",").map((t,i)=>{return {timer_start:t,timer_end:endTimers[i]}}))
} else {
setItemTimers([])
}
},[item,playerInventory]) },[item,playerInventory])
return <Row className={"pb-1 pt-1 text-light"+(Number(item.obtained)===0?item.finalcraft?" finalProduct":" notStarted":Number(item.obtained)===Number(item.required)?" completed":" inProgress")}> return <Row className={"pb-1 pt-1 text-light"+(Number(item.obtained)===0?item.finalcraft?" finalProduct":" notStarted":Number(item.obtained)===Number(item.required)?" completed":" inProgress")}>
@ -164,12 +199,35 @@ function Item(p){
updateItem(item,{value:item.required},contributor) updateItem(item,{value:item.required},contributor)
}}/>} }}/>}
</Col> </Col>
<Col> {item.required!==item.obtained&&<>
<Col sm={2}>
<a style={{position:"relative",top:"8px"}} className="text-muted" href={"https://garlandtools.org/db/#item/"+item.itemid} target="tools">View Item Info</a> <a style={{position:"relative",top:"8px"}} className="text-muted" href={"https://garlandtools.org/db/#item/"+item.itemid} target="tools">View Item Info</a>
</Col> </Col>
<Col sm={1}>
<BiAlarmAdd style={{cursor:"pointer",borderBottom:"1px dotted",color:"#99FF99"}} onClick={()=>{if (item.timer_start!==null&&item.timer_start.length>0){updateTimer("0:00","3:00",item.timer_start.split(",").length)} else {updateTimer("0:00","3:00",0)}}}/>
</Col>
<Col sm={3}>
{itemTimers.map((timer,i)=><Timer key={i} lockout={lockout} updateTimer={updateTimer} timerIndex={i} timer_start={timer.timer_start} timer_end={timer.timer_end}/>)}
</Col></>}
</Row> </Row>
} }
function Timer(p){
const {timer_start,timer_end,timerIndex,updateTimer,lockout}=p
const [timerStart,setTimerStart] = useState("")
const [timerEnd,setTimerEnd] = useState("")
useEffect(()=>{
setTimerStart(timer_start)
setTimerEnd(timer_end)
},[timer_start,timer_end])
return <Row>
<Col sm={3}><DarkInput style={{width:"100%"}} disabled={lockout} value={timerStart} onChange={(f)=>{setTimerStart(f.currentTarget.value)}} onKeyDown={(k)=>{if (k.key==='Enter') {if (k.currentTarget.value!=timer_start){updateTimer(k.currentTarget.value,timer_end,timerIndex)}}}} onBlur={(f)=>{if (f.currentTarget.value!=timer_start){updateTimer(f.currentTarget.value,timer_end,timerIndex)}}}></DarkInput></Col>
<Col sm={1} className="text-white">-</Col>
<Col sm={3}><DarkInput style={{width:"100%"}} disabled={lockout} value={timerEnd} onChange={(f)=>{setTimerEnd(f.currentTarget.value)}} onKeyDown={(k)=>{if (k.key==='Enter') {if (k.currentTarget.value!=timer_end){updateTimer(timer_start,k.currentTarget.value,timerIndex)}}}} onBlur={(f)=>{if (f.currentTarget.value!=timer_end){updateTimer(timer_start,f.currentTarget.value,timerIndex)}}}></DarkInput></Col>
<Col sm={1}><MdAlarmOff style={{cursor:"pointer",color:"red"}} onClick={(f)=>{updateTimer("","",timerIndex)}}/></Col>
</Row>
}
function ItemGroup(p) { function ItemGroup(p) {
const { data } = p const { data } = p
const { contributor,itemCount,totalItemCount,playerInventory,lockout,setLockout } = p const { contributor,itemCount,totalItemCount,playerInventory,lockout,setLockout } = p
@ -472,6 +530,32 @@ function ListApp(p){
</> </>
} }
function TimeDisplay(duration){
var hrs=Math.floor(duration/3600)
var min=Math.floor(duration/60)%60
return (hrs>0?hrs+" hrs,":"")+min+" min"
}
function TimerDisplay(p){
const {timer,eorzeanTime} = p
var eorzeanSeconds=Number(eorzeanTime.split(":")[0])*3600+Number(eorzeanTime.split(":")[1])*60
return <><Row>
<Col>
<img src={"https://xivapi.com"+timer.icon}/> {timer.name} <sub><i style={{color:"gray"}}>{eorzeanSeconds>timer.actual_seconds&&eorzeanSeconds<timer.end_seconds?"Node Available: "+TimeDisplay(timer.end_seconds-eorzeanSeconds):TimeDisplay((eorzeanSeconds>timer.actual_seconds)?timer.actual_seconds+86400-eorzeanSeconds:timer.actual_seconds-eorzeanSeconds)}</i></sub>
</Col>
<Col>
<span style={{float:"right"}}>{timer.timer_start} - {timer.timer_end}</span>
</Col>
</Row>
<Row>
<Col sm={1}/>
<Col sm={10}>
<ProgressBar variant={eorzeanSeconds>timer.actual_seconds&&eorzeanSeconds<timer.end_seconds?"success":""} animated={eorzeanSeconds>timer.actual_seconds&&eorzeanSeconds<timer.end_seconds} striped={eorzeanSeconds>timer.actual_seconds&&eorzeanSeconds<timer.end_seconds} now={eorzeanSeconds>timer.actual_seconds?eorzeanSeconds<timer.end_seconds?100-((eorzeanSeconds-timer.end_seconds)/(timer.seconds-timer.end_seconds))*100:((eorzeanSeconds-timer.actual_seconds)/864):(100-(timer.actual_seconds-eorzeanSeconds)/864)}></ProgressBar>
</Col>
</Row>
</>
}
function App() { function App() {
const [data,setData] = useState([]) const [data,setData] = useState([])
@ -493,6 +577,10 @@ function App() {
const [lastModified,setLastModified] = useState(new Date()) const [lastModified,setLastModified] = useState(new Date())
const [lastUpdate,setLastUpdate] = useState(0) const [lastUpdate,setLastUpdate] = useState(0)
const [playerInventory,setPlayerInventory] = useState([]) const [playerInventory,setPlayerInventory] = useState([])
const [eorzeanTime,setEorzeanTime] = useState("")
const [timerList,setTimerList] = useState([])
const [timerCutList1,setTimerCutList1] = useState([])
const [timerCutList2,setTimerCutList2] = useState([])
const [contributor,setContributor] = useState("") const [contributor,setContributor] = useState("")
const [notifications,setNotifications] = useState([]) const [notifications,setNotifications] = useState([])
@ -503,11 +591,25 @@ function App() {
const [matchedItems,setMatchedItems] = useState([]) const [matchedItems,setMatchedItems] = useState([])
const [lockout,setLockout] = useState(false) //const [lockout,setLockout] = useState(false)
function LZ(digits,numb) { function LZ(digits,numb) {
return "0".repeat(digits-String(numb).length)+numb return "0".repeat(digits-String(numb).length)+numb
} }
useEffect(()=>{
var eorzeanSeconds=Number(eorzeanTime.split(":")[0])*3600+Number(eorzeanTime.split(":")[1])*60
var timerObjs=timerList.map((item)=>{
var seconds=Number(item.timer_start.split(":")[0])*3600+Number(item.timer_start.split(":")[1])*60
var originalSeconds=seconds
var endSeconds=Number(item.timer_end.split(":")[0])*3600+Number(item.timer_end.split(":")[1])*60
if (endSeconds<seconds&&eorzeanSeconds>=0&&eorzeanSeconds<seconds){
seconds=0
}
return {seconds:seconds,actual_seconds:originalSeconds,end_seconds:endSeconds,...item}}).sort((a,b)=>a.end_seconds-b.end_seconds)
setTimerCutList1(timerObjs.filter((timer)=>timer.end_seconds>=eorzeanSeconds))
setTimerCutList2(timerObjs.filter((timer)=>timer.end_seconds<eorzeanSeconds))
},[timerList,eorzeanTime])
useEffect(()=>{ useEffect(()=>{
const interval = setInterval(()=>{ const interval = setInterval(()=>{
@ -519,6 +621,20 @@ function App() {
return axios.get("https://projectdivar.com:4505/getData") return axios.get("https://projectdivar.com:4505/getData")
.then((data)=>{ .then((data)=>{
//setData(data.data) //setData(data.data)
var timers=[]
var timerItems=data.data.filter((item)=>item.obtained!=item.required&&item.timer_start!=null&&item.timer_start.length>0)
for (item of timerItems){
var splitter=item.timer_start.split(",")
var splitter2=item.timer_end.split(",")
var i=0
for (var t of splitter){
var newItem={...item}
newItem.timer_start=t
newItem.timer_end=splitter2[i++]
timers=[...timers,newItem]
}
}
setTimerList(timers)
setData(data.data.slice(dataSplitters[0],dataSplitters[1])) setData(data.data.slice(dataSplitters[0],dataSplitters[1]))
setData2(data.data.slice(dataSplitters[1],dataSplitters[2])) setData2(data.data.slice(dataSplitters[1],dataSplitters[2]))
setData3(data.data.slice(dataSplitters[2],dataSplitters[3])) setData3(data.data.slice(dataSplitters[2],dataSplitters[3]))
@ -577,6 +693,22 @@ function App() {
return ()=>clearInterval(interval) return ()=>clearInterval(interval)
},[nav,lastUpdate]) },[nav,lastUpdate])
useEffect(()=>{
const interval = setInterval(()=>{
if (nav==="main"){
var date=new Date()
var earthH=date.getHours(),earthM=date.getMinutes(),earthS=date.getSeconds()
var earthTime=earthH*3600+earthM*60+earthS
var eorzeanTime=earthTime*20.571428571428571428571428571429
var eorzeanH=Math.floor(eorzeanTime/3600)%24
var eorzeanM=Math.floor(eorzeanTime/60)%60
var eorzeanS=Math.floor(eorzeanTime)%60
setEorzeanTime((("0")+eorzeanH).slice(-2)+":"+(("0")+eorzeanM).slice(-2))
}
},3000)
return ()=>clearInterval(interval)
},[nav,lastUpdate])
useEffect(()=>{ useEffect(()=>{
var notificationLastUpdate = new Date(new Date()-(NOTIFICATIONTIMEOUT*1000)) var notificationLastUpdate = new Date(new Date()-(NOTIFICATIONTIMEOUT*1000))
var largestNotificationID = -1 var largestNotificationID = -1
@ -627,6 +759,20 @@ function App() {
axios.get("https://projectdivar.com:4505/getData") axios.get("https://projectdivar.com:4505/getData")
.then((data)=>{ .then((data)=>{
//setData(data.data) //setData(data.data)
var timers=[]
var timerItems=data.data.filter((item)=>item.obtained!=item.required&&item.timer_start!=null&&item.timer_start.length>0)
for (item of timerItems){
var splitter=item.timer_start.split(",")
var splitter2=item.timer_end.split(",")
var i=0
for (var t of splitter){
var newItem={...item}
newItem.timer_start=t
newItem.timer_end=splitter2[i++]
timers=[...timers,newItem]
}
}
setTimerList(timers)
setData(data.data.slice(dataSplitters[0],dataSplitters[1])) setData(data.data.slice(dataSplitters[0],dataSplitters[1]))
setData2(data.data.slice(dataSplitters[1],dataSplitters[2])) setData2(data.data.slice(dataSplitters[1],dataSplitters[2]))
setData3(data.data.slice(dataSplitters[2],dataSplitters[3])) setData3(data.data.slice(dataSplitters[2],dataSplitters[3]))
@ -773,7 +919,7 @@ function App() {
return ( return (
<Container className="bg-dark" fluid> <Container className="bg-dark" fluid>
<Navbar bg="dark" variant="dark"> <Navbar bg="dark" variant="dark">
<Container> <Container fluid>
<Navbar.Brand href="#home"> <Navbar.Brand href="#home">
<img src={process.env.PUBLIC_URL+"/favicon.ico"} width="30" height="30" className="d-inline-block align-top" alt="BUN logo"/> BUN Collab App <img src={process.env.PUBLIC_URL+"/favicon.ico"} width="30" height="30" className="d-inline-block align-top" alt="BUN logo"/> BUN Collab App
</Navbar.Brand> </Navbar.Brand>
@ -784,52 +930,64 @@ function App() {
</>} </>}
</Container> </Container>
</Navbar> </Navbar>
<Container> <Container fluid>
{contributor.length===0?<> <Row>
<input placeHolder="e.g. Bun" onKeyDown={(k)=>{if (k.key==='Enter') {setContributor(document.getElementById("username").value)}}} id="username"/> <Col sm={1}></Col>
<button type="Submit" onClick={(f)=>{setContributor(document.getElementById("username").value)}}>Submit</button> <Col sm={8}>
</>: {contributor.length===0?<>
nav==="main"? <input placeHolder="e.g. Bun" onKeyDown={(k)=>{if (k.key==='Enter') {setContributor(document.getElementById("username").value)}}} id="username"/>
data.length>0? <button type="Submit" onClick={(f)=>{setContributor(document.getElementById("username").value)}}>Submit</button>
<> </>:
<Row><Col className="text-white"> nav==="main"?
<span style={{fontSize:"2em",paddingRight:"10px"}}>{Math.floor(Number(completeRatio)+Number(inProgressRatio)+Number(craftsRatio))}% complete</span><sub>({itemCount.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") + " / " + totalItemCount.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")})</sub> data.length>0?
</Col></Row> <>
<Row> <Row><Col className="text-white">
<ProgressBar className="bg-dark text-white"> <span style={{fontSize:"2em",paddingRight:"10px"}}>{Math.floor(Number(completeRatio)+Number(inProgressRatio)+Number(craftsRatio))}% complete</span><sub>({itemCount.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") + " / " + totalItemCount.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")})</sub>
<ProgressBar animated striped variant="success" label={`${completeRatio}%`} now={completeRatio} /> </Col></Row>
<ProgressBar animated striped variant="info" label={`${inProgressRatio}%`} now={inProgressRatio} /> <Row>
<ProgressBar animated striped variant="danger" label={`${craftsRatio}%`} now={craftsRatio} /> <ProgressBar className="bg-dark text-white">
<ProgressBar animated striped variant="dark" now={missingProgressRatio} /> <ProgressBar animated striped variant="success" label={`${completeRatio}%`} now={completeRatio} />
</ProgressBar> <ProgressBar animated striped variant="info" label={`${inProgressRatio}%`} now={inProgressRatio} />
</Row> <ProgressBar animated striped variant="danger" label={`${craftsRatio}%`} now={craftsRatio} />
<Row> <ProgressBar animated striped variant="dark" now={missingProgressRatio} />
<Form> </ProgressBar>
<Form.Group className="mb-3"> </Row>
<Form.Control id="searchBar" className="bg-dark text-white" type="text" placeholder="Search Item" onChange={(f)=>{ <Row>
updateSearch(f.currentTarget.value) <Form>
}} /> <Form.Group className="mb-3">
{matchedItems.map((item)=><Item key={item.obj.id} item={item.obj} setLockout={setLockout} lockout={lockout} contributor={contributor} itemCount={itemCount} totalItemCount={totalItemCount} playerInventory={playerInventory}></Item>)} <Form.Control id="searchBar" className="bg-dark text-white" type="text" placeholder="Search Item" onChange={(f)=>{
</Form.Group> updateSearch(f.currentTarget.value)
</Form> }} />
</Row> {matchedItems.map((item)=><Item key={item.obj.id} item={item.obj} contributor={contributor} itemCount={itemCount} totalItemCount={totalItemCount} playerInventory={playerInventory}></Item>)}
<Accordion className="bg-dark" defaultActiveKey="0"> </Form.Group>
<ItemGroup name="Gathering Items" contributor={contributor} akey="0" data={data} lastModified={lastModified} setLastModified={setLastModified} setData={setData} setData1={setData} setData2={setData2} setData3={setData3} setData4={setData4} itemCount={itemCount} totalItemCount={totalItemCount} playerInventory={playerInventory} lockout={lockout} setLockout={setLockout}/> </Form>
<ItemGroup name="Other Items" contributor={contributor} akey="1" data={data2} lastModified={lastModified} setLastModified={setLastModified} setData={setData2} setData1={setData} setData2={setData2} setData3={setData3} setData4={setData4} itemCount={itemCount} totalItemCount={totalItemCount} playerInventory={playerInventory} lockout={lockout} setLockout={setLockout}/> </Row>
<ItemGroup name="Pre-crafting" contributor={contributor} akey="2" data={data3} lastModified={lastModified} setLastModified={setLastModified} setData={setData3} setData1={setData} setData2={setData2} setData3={setData3} setData4={setData4} itemCount={itemCount} totalItemCount={totalItemCount} playerInventory={playerInventory} lockout={lockout} setLockout={setLockout}/> <Accordion className="bg-dark" defaultActiveKey="0">
<ItemGroup name="Crafting Items" contributor={contributor} akey="3" data={data4} lastModified={lastModified} setLastModified={setLastModified} setData={setData4} setData1={setData} setData2={setData2} setData3={setData3} setData4={setData4} itemCount={itemCount} totalItemCount={totalItemCount} playerInventory={playerInventory} lockout={lockout} setLockout={setLockout}/> <ItemGroup name="Gathering Items" contributor={contributor} akey="0" data={data} lastModified={lastModified} setLastModified={setLastModified} setData={setData} setData1={setData} setData2={setData2} setData3={setData3} setData4={setData4} itemCount={itemCount} totalItemCount={totalItemCount} playerInventory={playerInventory}/>
</Accordion> <ItemGroup name="Other Items" contributor={contributor} akey="1" data={data2} lastModified={lastModified} setLastModified={setLastModified} setData={setData2} setData1={setData} setData2={setData2} setData3={setData3} setData4={setData4} itemCount={itemCount} totalItemCount={totalItemCount} playerInventory={playerInventory}/>
</>:<Importer></Importer> <ItemGroup name="Pre-crafting" contributor={contributor} akey="2" data={data3} lastModified={lastModified} setLastModified={setLastModified} setData={setData3} setData1={setData} setData2={setData2} setData3={setData3} setData4={setData4} itemCount={itemCount} totalItemCount={totalItemCount} playerInventory={playerInventory}/>
:nav==="list"?<ListApp transferItems={transferItems}></ListApp>: <ItemGroup name="Crafting Items" contributor={contributor} akey="3" data={data4} lastModified={lastModified} setLastModified={setLastModified} setData={setData4} setData1={setData} setData2={setData2} setData3={setData3} setData4={setData4} itemCount={itemCount} totalItemCount={totalItemCount} playerInventory={playerInventory}/>
<></> </Accordion>
} </>:<Importer></Importer>
<div style={{pointerEvents:"none",position:"fixed",top:"0px",left:"0px",width:"100%",height:"100%"}}> :nav==="list"?<ListApp transferItems={transferItems}></ListApp>:
<ToastContainer position="bottom-end"> <></>
{notifications.map((not)=>{ }
return <Notification key={not.id} not={not}/> <div style={{pointerEvents:"none",position:"fixed",top:"0px",left:"0px",width:"100%",height:"100%"}}>
})} <ToastContainer position="bottom-end">
</ToastContainer> {notifications.map((not)=>{
</div> return <Notification key={not.id} not={not}/>
})}
</ToastContainer>
</div>
</Col>
{contributor.length>0&&
<Col sm={3} className="text-white">
<span style={{fontSize:24,marginRight:"24px"}}>Timers</span><i>ET: {eorzeanTime}</i>
{timerCutList1.map((timer,i)=><TimerDisplay timer={timer} key={i} eorzeanTime={eorzeanTime}/>)}
{timerCutList2.map((timer,i)=><TimerDisplay timer={timer} key={i} eorzeanTime={eorzeanTime}/>)}
</Col>
}
</Row>
</Container> </Container>
</Container> </Container>
); );

Loading…
Cancel
Save