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 { 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')
@ -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"];
function Item(p){
const {item,setLockout,contributor,lockout,itemCount,totalItemCount,playerInventory} = p
const {item,contributor,itemCount,totalItemCount,playerInventory} = p
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) {
var correctedVal=Math.min(item.required,target.value);
@ -49,7 +78,7 @@ function Item(p){
setLockout(false)
})
.catch((err)=>{
setLockout(false)
})
}
@ -131,7 +160,7 @@ function Item(p){
tempItem.amt+=it.amt
}
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
}
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])
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)
}}/>}
</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>
</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>
}
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) {
const { data } = 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() {
const [data,setData] = useState([])
@ -493,6 +577,10 @@ function App() {
const [lastModified,setLastModified] = useState(new Date())
const [lastUpdate,setLastUpdate] = useState(0)
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 [notifications,setNotifications] = useState([])
@ -503,11 +591,25 @@ function App() {
const [matchedItems,setMatchedItems] = useState([])
const [lockout,setLockout] = useState(false)
//const [lockout,setLockout] = useState(false)
function LZ(digits,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(()=>{
const interval = setInterval(()=>{
@ -519,6 +621,20 @@ function App() {
return axios.get("https://projectdivar.com:4505/getData")
.then((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]))
setData2(data.data.slice(dataSplitters[1],dataSplitters[2]))
setData3(data.data.slice(dataSplitters[2],dataSplitters[3]))
@ -577,6 +693,22 @@ function App() {
return ()=>clearInterval(interval)
},[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(()=>{
var notificationLastUpdate = new Date(new Date()-(NOTIFICATIONTIMEOUT*1000))
var largestNotificationID = -1
@ -627,6 +759,20 @@ function App() {
axios.get("https://projectdivar.com:4505/getData")
.then((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]))
setData2(data.data.slice(dataSplitters[1],dataSplitters[2]))
setData3(data.data.slice(dataSplitters[2],dataSplitters[3]))
@ -773,7 +919,7 @@ function App() {
return (
<Container className="bg-dark" fluid>
<Navbar bg="dark" variant="dark">
<Container>
<Container fluid>
<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
</Navbar.Brand>
@ -784,52 +930,64 @@ function App() {
</>}
</Container>
</Navbar>
<Container>
{contributor.length===0?<>
<input placeHolder="e.g. Bun" onKeyDown={(k)=>{if (k.key==='Enter') {setContributor(document.getElementById("username").value)}}} id="username"/>
<button type="Submit" onClick={(f)=>{setContributor(document.getElementById("username").value)}}>Submit</button>
</>:
nav==="main"?
data.length>0?
<>
<Row><Col className="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>
</Col></Row>
<Row>
<ProgressBar className="bg-dark text-white">
<ProgressBar animated striped variant="success" label={`${completeRatio}%`} now={completeRatio} />
<ProgressBar animated striped variant="info" label={`${inProgressRatio}%`} now={inProgressRatio} />
<ProgressBar animated striped variant="danger" label={`${craftsRatio}%`} now={craftsRatio} />
<ProgressBar animated striped variant="dark" now={missingProgressRatio} />
</ProgressBar>
</Row>
<Row>
<Form>
<Form.Group className="mb-3">
<Form.Control id="searchBar" className="bg-dark text-white" type="text" placeholder="Search Item" onChange={(f)=>{
updateSearch(f.currentTarget.value)
}} />
{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.Group>
</Form>
</Row>
<Accordion className="bg-dark" defaultActiveKey="0">
<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}/>
<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}/>
<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}/>
<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}/>
</Accordion>
</>:<Importer></Importer>
:nav==="list"?<ListApp transferItems={transferItems}></ListApp>:
<></>
}
<div style={{pointerEvents:"none",position:"fixed",top:"0px",left:"0px",width:"100%",height:"100%"}}>
<ToastContainer position="bottom-end">
{notifications.map((not)=>{
return <Notification key={not.id} not={not}/>
})}
</ToastContainer>
</div>
<Container fluid>
<Row>
<Col sm={1}></Col>
<Col sm={8}>
{contributor.length===0?<>
<input placeHolder="e.g. Bun" onKeyDown={(k)=>{if (k.key==='Enter') {setContributor(document.getElementById("username").value)}}} id="username"/>
<button type="Submit" onClick={(f)=>{setContributor(document.getElementById("username").value)}}>Submit</button>
</>:
nav==="main"?
data.length>0?
<>
<Row><Col className="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>
</Col></Row>
<Row>
<ProgressBar className="bg-dark text-white">
<ProgressBar animated striped variant="success" label={`${completeRatio}%`} now={completeRatio} />
<ProgressBar animated striped variant="info" label={`${inProgressRatio}%`} now={inProgressRatio} />
<ProgressBar animated striped variant="danger" label={`${craftsRatio}%`} now={craftsRatio} />
<ProgressBar animated striped variant="dark" now={missingProgressRatio} />
</ProgressBar>
</Row>
<Row>
<Form>
<Form.Group className="mb-3">
<Form.Control id="searchBar" className="bg-dark text-white" type="text" placeholder="Search Item" onChange={(f)=>{
updateSearch(f.currentTarget.value)
}} />
{matchedItems.map((item)=><Item key={item.obj.id} item={item.obj} contributor={contributor} itemCount={itemCount} totalItemCount={totalItemCount} playerInventory={playerInventory}></Item>)}
</Form.Group>
</Form>
</Row>
<Accordion className="bg-dark" defaultActiveKey="0">
<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}/>
<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}/>
<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}/>
<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>
:nav==="list"?<ListApp transferItems={transferItems}></ListApp>:
<></>
}
<div style={{pointerEvents:"none",position:"fixed",top:"0px",left:"0px",width:"100%",height:"100%"}}>
<ToastContainer position="bottom-end">
{notifications.map((not)=>{
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>
);

Loading…
Cancel
Save