import './reset.css' ; // Generic reset
import './style.css' ; // The new new
import React , { useState , useEffect , useReducer } from 'react' ;
import Toggle from 'react-toggle' //Tooltip props: http://aaronshaf.github.io/react-toggle/
import Helmet from 'react-helmet'
import { XSquareFill , PlusCircle , LifePreserver , Server , CloudUploadFill } from 'react-bootstrap-icons'
import { SkillTreeEditor } from './skilltree/skillTreeEditor'
import {
HashRouter ,
Switch ,
Route ,
useHistory
} from "react-router-dom" ;
import { HashLink as Link } from 'react-router-hash-link' ;
import TestHeader from './TestHeader' ; // Test Header!
import TestPanel from './TestPanel' ; // Dudley's Test Panel
import md5 from 'md5' ;
const axios = require ( 'axios' ) ;
const parse = require ( 'csv-parse/lib/sync' )
/ *
Damage types
const MELEE _DMG = 0
const RANGE _DMG = 1
const TECH _DMG = 2
Art properties
const NORMAL = 0
const PHOTON _ART = 1
const WEAPON _ACTION = 2
const STEP _COUNTER = 3
const PARRY _COUNTER = 4
//NOT USED YET*/
const BACKENDURL = process . env . REACT _APP _GITPOD _WORKSPACE _URL || process . env . REACT _APP _BACKENDURL || 'https://projectdivar.com:4504'
const APP _TITLE = "NGS Planner"
function GetBackendURL ( p ) {
return ( BACKENDURL ) + ( p . TESTMODE ? "/test" : "" )
}
function Box ( p ) {
return < >
< div className = "box" >
< div className = "boxTitleBar" >
< h1 > { p . title } < / h 1 >
< / d i v >
{ p . children }
< / d i v >
< / >
}
function Table ( p ) {
return < p className = { p . classes } >
{ p . children }
< / p >
}
function InputBox ( p ) {
const [ value , setValue ] = useState ( p . value )
const [ failed , setFailed ] = useState ( false )
const [ sending , setSending ] = useState ( false )
function changeFunc ( f ) { setValue ( f . currentTarget . value )
if ( p . callback4 ) {
p . callback4 ( f . currentTarget . value )
} }
function blurFunc ( f ) {
if ( p . callback ) {
setSending ( true )
setFailed ( false )
p . callback ( f . currentTarget . value )
. then ( ( ) => { setFailed ( false ) } )
. catch ( ( ) => { setFailed ( true ) } )
. then ( ( ) => { setSending ( false ) } ) }
else
if ( p . callback3 ) {
p . callback3 ( f . currentTarget . value )
} }
function keydownFunc ( f ) {
if ( p . callback2 ) {
p . callback2 ( f , value )
}
}
return p . data ? < select disabled = { p . lockSubmission } className = { failed ? "failedInput" : sending ? "submitting" : "" } value = { value } onKeyDown = { ( f ) => { keydownFunc ( f ) } } onChange = { ( f ) => { changeFunc ( f ) } } onBlur = { ( f ) => { blurFunc ( f ) } } >
{ p . includeBlankValue && < option / > }
{ p . data . map ( ( item ) => < option value = { item . id } > { item . id } - { item . name || item . username } < / o p t i o n > ) }
< /select>:<input disabled={p.lockSubmission} className={failed?"failedInput":sending?"submitting":""} value={value} onKeyDown={(f)=>{keydownFunc(f)}} onChange={(f)=>{changeFunc(f)}} onBlur={(f)=>{blurFunc(f)}}/ >
}
function TableEditor ( p ) {
const initialVals = { }
function updateVals ( state , update ) {
if ( update === 'Clear' ) {
return initialVals
}
state [ update . field ] = update . value
return state
}
const [ fields , setFields ] = useState ( [ ] )
const [ data , setData ] = useState ( [ ] )
const [ update , setUpdate ] = useState ( false )
const [ submitVals , setSubmitVal ] = useReducer ( updateVals , initialVals )
const [ loading , setLoading ] = useState ( false )
const [ dependencies , setDependencies ] = useState ( [ ] )
const [ importAllowed , setImportAllowed ] = useState ( false )
const [ fileData , setFileData ] = useState ( undefined )
const [ lockSubmission , setLockSubmission ] = useState ( false )
function patchValue ( value , p , col , dat ) {
return axios . patch ( p . BACKENDURL + p . path , {
[ col . name ] : value === "null" ? null : value ,
id : dat . id ,
pass : p . password
} )
}
function SubmitBoxes ( ) {
if ( ! lockSubmission ) {
setLockSubmission ( true )
axios . post ( p . BACKENDURL + p . path , { ... submitVals , pass : p . password } )
. then ( ( ) => {
setSubmitVal ( "Clear" )
setUpdate ( true )
} )
. catch ( ( err ) => {
alert ( JSON . stringify ( err . response . data ) )
} )
. then ( ( ) => {
setLockSubmission ( false )
} )
}
}
useEffect ( ( ) => {
setUpdate ( true )
} , [ p . path ] )
useEffect ( ( ) => {
var promises = [ ]
parse ( fileData , { columns : true , skip _empty _lines : true } ) . forEach ( ( entry ) => {
for ( var col of fields ) {
if ( ( col . dataTypeID === 23 || col . dataTypeID === 701 || col . dataTypeID === 16 ) && entry [ col . name ] === "" ) {
entry [ col . name ] = 0
}
}
promises . push ( axios . post ( p . BACKENDURL + p . path , { ... entry , pass : p . password } ) )
} )
Promise . allSettled ( promises )
. then ( ( ) => {
setUpdate ( true )
} )
} , [ fileData , p . path , p . BACKENDURL , p . password ] )
useEffect ( ( ) => {
for ( var col of fields ) {
if ( col . name === "name" ) {
setImportAllowed ( true )
break ;
}
}
} , [ fields ] )
useEffect ( ( ) => {
if ( update ) {
setLoading ( true )
var dependency _map = { }
axios . get ( p . BACKENDURL + p . path + "?pass=" + p . password )
. then ( ( data ) => {
var cols = data . data . fields
var rows = data . data . rows
setFields ( cols . filter ( ( col , i ) => col . name !== "id" && ! ( i === 0 && col . name === "name" ) ) )
var promise _list = [ ]
cols . filter ( ( col ) => col . name !== "id" && col . name . includes ( "_id" ) ) . forEach ( ( col ) => {
promise _list . push ( axios . get ( p . BACKENDURL + "/" + col . name . replace ( "_id" , "" ) + "?pass=" + p . password )
. then ( ( data ) => {
dependency _map [ col . name ] = data . data . rows . sort ( ( a , b ) => b . id - a . id )
} ) )
} )
setData ( rows )
return Promise . allSettled ( promise _list )
} )
. then ( ( ) => {
setDependencies ( dependency _map )
setLoading ( false )
} )
setUpdate ( false )
}
} , [ update , p . path , p . BACKENDURL , p . password ] )
return < >
{ ! loading ?
< div >
< table >
{ importAllowed && < caption > < label className = "buttonLabel" for = "uploads" > Import CSV < / l a b e l > < i n p u t o n C h a n g e = { ( f ) = > {
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" / > < / c a p t i o n > }
< thead >
< tr >
< th className = "table-padding" > < / t h >
{ fields . map ( ( field , i ) => < React . Fragment key = { i } > < th scope = "col" className = "table-padding" > { field . name } < / t h > < / R e a c t . F r a g m e n t > ) }
< / t r >
< / t h e a d >
< tbody >
{ < tr > < td > < / t d > { f i e l d s . m a p ( ( c o l , i ) = > < t d k e y = { i } > { < I n p u t B o x i n c l u d e B l a n k V a l u e = { t r u e } d a t a = { d e p e n d e n c i e s [ c o l . n a m e ] } c a l l b a c k 4 = {
( f ) => { setSubmitVal ( { field : col . name , value : f } ) ; } } / > } < /td>)}<input style={{display:"none"}}/ > < PlusCircle onClick = { ( ) => { SubmitBoxes ( ) } } className = "submitbutton" / > < / t r > }
{ data . map ( ( dat ) => < tr key = { dat . id } >
< td > < XSquareFill className = "webicon" onClick = { ( ) => { axios . delete ( p . BACKENDURL + p . path , { data : { id : dat . id , pass : p . password } } ) . then ( ( ) => { setUpdate ( true ) } ) . catch ( ( err ) => { alert ( err . response . data ) } ) } } / > < / t d > { f i e l d s . m a p ( ( c o l , i ) = > < t d k e y = { d a t . i d + " _ " + i } c l a s s N a m e = " t a b l e - p a d d i n g t a b l e " >
< InputBox lockSubmission = { lockSubmission } data = { dependencies [ col . name ] } callback = { ( value ) => patchValue ( value , p , col , dat ) } callback2 = { ( f , value ) => { if ( f . key === 'Enter' ) { f . currentTarget . blur ( ) } else { return 'Chill' } } } value = { String ( dat [ col . name ] ) } / > < / t d > ) } < / t r > ) }
< / t b o d y >
< / t a b l e >
< / d i v > : < > < i m g s r c = { p r o c e s s . e n v . P U B L I C _ U R L + " / s p i n n e r . g i f " } a l t = " " / > < i m g s r c = { p r o c e s s . e n v . P U B L I C _ U R L + " / s p i n n e r . g i f " } a l t = " " / > < i m g s r c = { p r o c e s s . e n v . P U B L I C _ U R L + " / s p i n n e r . g i f " } a l t = " " / > < i m g s r c = { p r o c e s s . e n v . P U B L I C _ U R L + " / s p i n n e r . g i f " } a l t = " " / > < i m g s r c = { p r o c e s s . e n v . P U B L I C _ U R L + " / s p i n n e r . g i f " } a l t = " " / > < i m g s r c = { p r o c e s s . e n v . P U B L I C _ U R L + " / s p i n n e r . g i f " } a l t = " " / > < i m g s r c = { p r o c e s s . e n v . P U B L I C _ U R L + " / s p i n n e r . g i f " } a l t = " " / > < i m g s r c = { p r o c e s s . e n v . P U B L I C _ U R L + " / s p i n n e r . g i f " } a l t = " " / > < i m g s r c = { p r o c e s s . e n v . P U B L I C _ U R L + " / s p i n n e r . g i f " } a l t = " " / > < i m g s r c = { p r o c e s s . e n v . P U B L I C _ U R L + " / s p i n n e r . g i f " } a l t = " " / > < i m g s r c = { p r o c e s s . e n v . P U B L I C _ U R L + " / s p i n n e r . g i f " } a l t = " " / > < i m g s r c = { p r o c e s s . e n v . P U B L I C _ U R L + " / s p i n n e r . g i f " } a l t = " " / > < i m g s r c = { p r o c e s s . e n v . P U B L I C _ U R L + " / s p i n n e r . g i f " } a l t = " " / > < i m g s r c = { p r o c e s s . e n v . P U B L I C _ U R L + " / s p i n n e r . g i f " } a l t = " " / > < i m g s r c = { p r o c e s s . e n v . P U B L I C _ U R L + " / s p i n n e r . g i f " } a l t = " " / > < i m g s r c = { p r o c e s s . e n v . P U B L I C _ U R L + " / s p i n n e r . g i f " } a l t = " " / > < i m g s r c = { p r o c e s s . e n v . P U B L I C _ U R L + " / s p i n n e r . g i f " } a l t = " " / > < / > }
< / >
}
function DatabaseEditor ( p ) {
const [ loading , setLoading ] = useState ( true )
const [ message , setMessage ] = useState ( < span style = { { color : "black" } } > < / s p a n > )
const [ databases , setDatabases ] = useState ( [ ] )
const [ update , setUpdate ] = useState ( true )
useEffect ( ( ) => {
if ( update ) {
axios . get ( p . BACKENDURL + "/databases?pass=" + p . password )
. then ( ( data ) => {
setDatabases ( data . data )
} )
. catch ( ( err ) => {
console . log ( err . message )
} )
. then ( ( ) => {
setLoading ( false )
} )
setUpdate ( false )
}
} , [ update , p . BACKENDURL , p . password ] )
return < >
{ ! loading ? < >
< button className = "basichover" style = { { backgroundColor : "navy" } } onClick = { ( ) => {
setLoading ( true )
setMessage ( < span style = { { color : "black" } } > Uploading Test Database to Production ... < / s p a n > )
axios . post ( p . BACKENDURL + "/databases/testtolive" , { pass : p . password } )
. then ( ( ) => {
setMessage ( < span style = { { color : "green" } } > Success ! Test Database is now live ! < / s p a n > )
} )
. catch ( ( err ) => {
setMessage ( < span style = { { color : "red" } } > { err . message } < / s p a n > )
} )
. then ( ( ) => {
setLoading ( false )
} )
} } > Apply TEST Database to LIVE Database < /button><br/ > < br / >
< button className = "basichover" style = { { backgroundColor : "maroon" } } onClick = { ( ) => {
setLoading ( true )
setMessage ( < span style = { { color : "black" } } > Restoring Test Database using Live Database ... < / s p a n > )
axios . post ( p . BACKENDURL + "/databases/livetotest" , { pass : p . password } )
. then ( ( ) => {
setMessage ( < span style = { { color : "green" } } > Success ! Live Database has been applied to the Test Database ! < / s p a n > )
} )
. catch ( ( err ) => {
setMessage ( < span style = { { color : "red" } } > { err . message } < / s p a n > )
} )
. then ( ( ) => {
setLoading ( false )
} )
} } > Reset TEST database using current LIVE Database < /button><br/ > < br / >
< button className = "basichover" style = { { backgroundColor : "darkgreen" } } onClick = { ( ) => {
setLoading ( true )
setMessage ( < span style = { { color : "black" } } > Backing up the Live database ... < / s p a n > )
axios . post ( p . BACKENDURL + "/databases/backup" , { pass : p . password } )
. then ( ( ) => {
setMessage ( < span style = { { color : "green" } } > Success ! Live Database has been saved ! < / s p a n > )
} )
. catch ( ( err ) => {
setMessage ( < span style = { { color : "red" } } > { err . message } < / s p a n > )
} )
. then ( ( ) => {
setUpdate ( true )
} ) } } > Backup current LIVE Database < /button><br/ > < br / >
< / > : < i m g s r c = { p r o c e s s . e n v . P U B L I C _ U R L + " / s p i n n e r . g i f " } a l t = " " / >
}
{ message }
< hr / >
< br / > < br / >
< h2 > < u > Current Databases < / u > < / h 2 >
< br / > < br / >
< span style = { { fontSize : "24px" , top : "-16px" , position : "relative" , height : "64px" , lineHeight : "64px" , textAlign : "center" } } > < LifePreserver className = "databaseIcon" style = { { color : "green" } } / > Live Database < / s p a n >
& nbsp ; & nbsp ; & nbsp ; < span style = { { fontSize : "24px" , top : "-16px" , position : "relative" , height : "64px" , lineHeight : "64px" , textAlign : "center" } } > < LifePreserver className = "databaseIcon" style = { { color : "red" } } / > Test Database < /span><br/ >
{ databases . map ( ( db ) => {
var label = ""
if ( db . datname !== "ngsplanner" && db . datname !== "ngsplanner2" ) {
var dateStr = db . datname . replace ( "ngsplanner" , "" )
var date = new Date ( dateStr . slice ( 0 , 4 ) , dateStr . slice ( 4 , 6 ) , dateStr . slice ( 6 , 8 ) , dateStr . slice ( 8 , 10 ) , dateStr . slice ( 10 , 12 ) , dateStr . slice ( 12 , 14 ) )
label = < > < Server className = "databaseIcon" style = { { color : "blue" } } / > { "Backup from " + date } < / >
return < > < span style = { { fontSize : "24px" , top : "-16px" , position : "relative" , height : "64px" , lineHeight : "64px" , textAlign : "center" } } > { label } < button style = { { background : "blue" } }
onClick = { ( ) => {
setLoading ( true )
axios . post ( p . BACKENDURL + "/databases/restorefrombackup" , {
database : db . datname ,
pass : p . password
} )
. then ( ( data ) => {
setMessage ( < span style = { { color : "green" } } > { "Success! Database has been set to the state from " + date } < / s p a n > )
} )
. catch ( ( err ) => {
setMessage ( < span style = { { color : "red" } } > { err . message } < / s p a n > )
} )
. then ( ( ) => {
setLoading ( false )
} )
} } > < CloudUploadFill / > Restore < / b u t t o n > < / s p a n > < b r / > < / >
} else {
return < > < / >
}
} ) }
< / >
}
function AdminPanel ( p ) {
const [ verified , setVerified ] = useState ( false )
const [ password , setPassword ] = useState ( "" )
const navigationData = [
{ page : "Class" , url : "/admin/class" , table : "/class" } ,
{ page : "Class Data" , url : "/admin/classdata" , table : "/class_level_data" } ,
{ page : "Class-Weapon Compatibility" , url : "/admin/classweaponcompatibility" , table : "/class_weapon_type_data" } ,
{ page : "Class Skills" , url : "/admin/classskills" , table : "/class_skill" } ,
{ page : "Class Skill Data" , url : "/admin/classskilldata" , table : "/class_skill_data" } ,
{ hr : true } ,
{ page : "Weapons" , url : "/admin/weapons" , table : "/weapon" } ,
{ page : "Weapon Existence Data" , url : "/admin/weaponexistencedata" , table : "/weapon_existence_data" } ,
{ page : "Weapon Types" , url : "/admin/weapontypes" , table : "/weapon_type" } ,
{ page : "Class-Weapon Compatibility" , url : "/admin/classweaponcompatibility" , table : "/class_weapon_type_data" , duplicate : true } ,
{ page : "Photon Arts" , url : "/admin/photonarts" , table : "/photon_art" } ,
{ hr : true } ,
{ page : "Armor" , url : "/admin/armor" , table : "/armor" } ,
{ page : "Potentials" , url : "/admin/potentials" , table : "/potential" } ,
{ page : "Potential Data" , url : "/admin/potentialdata" , table : "/potential_data" } ,
{ hr : true } ,
{ page : "Builds" , url : "/admin/builds" , table : "/builds" } ,
{ hr : true } ,
{ page : "Skills" , url : "/admin/skills" , table : "/skill" } ,
{ page : "Skill Types" , url : "/admin/skilltypes" , table : "/skill_type" } ,
{ page : "Skill Data" , url : "/admin/skilldata" , table : "/skill_data" } ,
{ page : < span style = { { color : "gold" } } > Skill Tree Editor < / s p a n > , u r l : " / a d m i n / s k i l l t r e e e d i t o r " , r e n d e r : < S k i l l T r e e E d i t o r s e t U p d a t e = { p . s e t U p d a t e } p a s s w o r d = { p a s s w o r d } B A C K E N D U R L = { G e t B a c k e n d U R L ( p ) } G e t D a t a = { p . D A T A } / > } ,
{ page : "Skill Tree Data" , url : "/admin/skilltreedata" , table : "/skill_tree_data" } ,
{ page : "Photon Arts" , url : "/admin/photonarts" , table : "/photon_art" , duplicate : true } ,
{ page : "Class Skills" , url : "/admin/classskills" , table : "/class_skill" , duplicate : true } ,
{ page : "Class Skill Data" , url : "/admin/classskilldata" , table : "/class_skill_data" , duplicate : true } ,
{ hr : true } ,
{ page : "Augments" , url : "/admin/augments" , table : "/augment" } ,
{ page : "Augment Types" , url : "/admin/augmenttypes" , table : "/augment_type" } ,
{ hr : true } ,
{ page : "Enemy Data" , url : "/admin/enemydata" , table : "/enemy_data" } ,
{ hr : true } ,
{ page : "Food" , url : "/admin/food" , table : "/food" } ,
{ page : "Food Multipliers" , url : "/admin/foodmultipliers" , table : "/food_mult" } ,
{ hr : true } ,
{ page : "Roles" , url : "/admin/roles" , table : "/roles" } ,
{ page : "Users" , url : "/admin/users" , table : "/users" } ,
{ hr : true } ,
{ page : "Misc. Site Data" , url : "/admin/sitedata" , table : "/site_data" } ,
{ page : "Database Audit" , url : "/admin/database_audit" , table : "/database_audit" } ,
]
return < div className = "adminMain" >
{ ! verified ?
< div className = "modalOverlay" >
< div className = "modal" >
< div className = "box boxAdmin" >
< div className = "boxTitleBar" > < h1 > Admin < / h 1 > < / d i v >
< p > < / p >
< input type = "password" value = { password } onChange = { ( f ) => { setPassword ( f . currentTarget . value ) } } onKeyDown = { ( e ) => {
if ( e . key === "Enter" ) {
axios . post ( GetBackendURL ( p ) + "/passwordcheck" , {
pass : password
} )
. then ( ( data ) => {
if ( data . data . verified ) {
setVerified ( data . data . verified )
}
} )
. catch ( ( err ) => {
setVerified ( false )
setPassword ( "" )
} ) } } } > < / i n p u t >
< / d i v >
< / d i v >
< / d i v >
: < >
< div className = "box boxAdminNav" >
< div className = "boxTitleBar" >
< h1 > Navigation < / h 1 >
< / d i v >
< p > Testing Mode < Toggle checked = { p . TESTMODE } onChange = { ( f ) => { p . setTESTMODE ( f . target . checked ) } } / > { p . TESTMODE ? < b > ON < / b > : < b > O F F < / b > } < / p >
< div className = "adminNavContainer customScrollbar" >
< Table classes = "adminNav" >
{ navigationData . map ( ( nav ) => ( nav . hr ) ? < hr / > : < > < Link to = { process . env . PUBLIC _URL + nav . url } > { nav . page } < /Link><br/ > < / > ) }
< Link to = { process . env . PUBLIC _URL + "/admin/database_manager" } > Database Manager < /Link><br/ >
< / T a b l e >
< / d i v >
< / d i v >
{ navigationData . map ( ( nav ) => ( nav . duplicate === undefined && nav . hr === undefined ) && < Route path = { process . env . PUBLIC _URL + nav . url } >
< div className = "box boxAdminContent" >
< div className = "boxTitleBar" >
< h1 > { nav . page } < / h 1 > < / d i v >
< div className = "adminContainer customScrollbar" >
< Helmet >
< title > { APP _TITLE + " - Admin Panel: " + nav . page } < / t i t l e >
< / H e l m e t >
{ nav . render ? ? < TableEditor password = { password } BACKENDURL = { GetBackendURL ( p ) } path = { nav . table } / > }
< / d i v > < / d i v > < / R o u t e > ) }
< Route path = { process . env . PUBLIC _URL + "/admin/database_manager" } >
< div className = "box boxAdminContent" >
< div className = "boxTitleBar" >
< h1 > Database Editor < / h 1 > < / d i v >
< div className = "adminContainer" >
< DatabaseEditor password = { password } BACKENDURL = { GetBackendURL ( p ) } / >
< / d i v >
< / d i v >
< / R o u t e >
< / > }
< / d i v >
}
function EditStatBox ( p ) {
const [ value , setValue ] = useState ( p . value )
useEffect ( ( ) => {
setValue ( p . value )
} , [ p . value ] )
return < > < input value = { value } onChange = { ( f ) => { setValue ( f . currentTarget . value ) ; p . callback ( f . currentTarget . value ) } } / > ( { value } ) < br / > < / >
}
function DamageCalculator ( p ) {
const [ augmentData , setAugmentData ] = useState ( { } )
//const [update,setUpdate] = useState(false)
useEffect ( ( ) => {
axios . get ( p . BACKENDURL + "/augment" )
. then ( ( data ) => {
var augmentData = { }
data . data . rows . forEach ( ( entry ) => { augmentData [ entry . name ] = entry } )
setAugmentData ( augmentData )
} )
} , [ p . BACKENDURL ] )
const character = {
weapon : {
augments : [ "1" , "2" ]
} ,
armor1 : {
augments : [ "2" ]
} ,
armor2 : {
augments : [ ]
} ,
armor3 : {
augments : [ ]
}
}
useEffect ( ( ) => {
if ( Object . keys ( augmentData ) . length > 0 ) {
var searchFields = [ { field : "variance" , variable : 0 } , { field : "mel_dmg" , variable : 0 } ]
for ( var equip of [ character . weapon , character . armor1 , character . armor2 , character . armor3 ] ) {
for ( var field of searchFields ) {
for ( var i = 0 ; i < equip . augments . length ; i ++ ) {
var variance = augmentData [ equip . augments [ i ] ] [ field . field ]
field . variable += variance
}
}
}
setAugDmgVariance ( searchFields [ 0 ] . variable )
}
} , [ augmentData , character . armor1 , character . armor2 , character . armor3 , character . weapon ] )
const [ rawDmg , setRawDmg ] = useState ( 0 )
const [ weaponTotalAtk , setWeaponTotalAtk ] = useState ( 100 )
const [ weaponBaseAtk , setWeaponBaseAtk ] = useState ( 1 )
const [ weaponEnhanceLv , setweaponEnhanceLv ] = useState ( 1 )
useEffect ( ( ) => {
setWeaponTotalAtk ( Number ( weaponBaseAtk ) + Number ( weaponEnhanceLv ) )
} , [ weaponBaseAtk , weaponEnhanceLv ] )
const [ dmgVariance , setDmgVariance ] = useState ( 1 )
const [ weaponDmgVariance , setWeaponDmgVariance ] = useState ( 1 )
const [ augDmgVariance , setAugDmgVariance ] = useState ( 1 )
useEffect ( ( ) => {
setDmgVariance ( Number ( weaponDmgVariance ) + Number ( augDmgVariance ) )
} , [ weaponDmgVariance , augDmgVariance ] )
const [ baseAtk , setBaseAtk ] = useState ( 100 )
const [ enemyDef , setEnemyDef ] = useState ( 5 )
const [ multipliers , setMultipliers ] = useState ( 1 )
useEffect ( ( ) => {
setRawDmg ( ( ( Number ( weaponTotalAtk ) * Number ( dmgVariance ) ) + Number ( baseAtk ) - Number ( enemyDef ) ) * Number ( multipliers ) / 5 )
} , [ weaponTotalAtk , dmgVariance , baseAtk , enemyDef , multipliers ] )
const [ atkmult , setAtkMult ] = useState ( 1 ) ;
const [ partmult , setPartMult ] = useState ( 1 ) ;
const [ elementalWeaknessMult , setElementalWeaknessMult ] = useState ( 1.2 )
const [ mainClassWeaponBoost , setMainClassWeaponBoost ] = useState ( 1.1 )
const [ classSkillMult , setClassSkillMult ] = useState ( 1 )
const [ equipMult , setEquipMult ] = useState ( 1 )
const [ augmentEquipMult , setAugmentEquipMult ] = useState ( 1 )
const [ potencyFloorEquipMult , setPotencyFloorEquipMult ] = useState ( 1 )
const [ elementalWeaponEquipMult , setElementalWeaponEquipMult ] = useState ( 1.1 )
const [ critMult , setCritMult ] = useState ( 1.2 )
const [ appropriateDistance , setAppropriateDistance ] = useState ( 1 )
const [ foodBoost , setFoodBoost ] = useState ( 1 )
const [ fieldEffects , setFieldEffects ] = useState ( 1.05 )
const [ statusAilments , setStatusAilments ] = useState ( 1 )
const [ enemyCorrectionMult , setEnemyCorrectionMult ] = useState ( 1 )
const [ highLevelEnemy , setHighLevelEnemy ] = useState ( 1 )
useEffect ( ( ) => {
setMultipliers ( Number ( atkmult ) * Number ( partmult ) * Number ( elementalWeaknessMult ) * Number ( mainClassWeaponBoost ) * Number ( classSkillMult ) * Number ( equipMult ) * Number ( augmentEquipMult ) * Number ( potencyFloorEquipMult ) * Number ( elementalWeaponEquipMult ) * Number ( critMult ) * Number ( appropriateDistance ) * Number ( foodBoost ) * Number ( fieldEffects ) * Number ( statusAilments ) * Number ( enemyCorrectionMult ) * Number ( highLevelEnemy ) )
} , [ atkmult , partmult , elementalWeaknessMult , mainClassWeaponBoost , classSkillMult , equipMult , augmentEquipMult , potencyFloorEquipMult , elementalWeaponEquipMult , critMult , appropriateDistance , foodBoost , fieldEffects , statusAilments , enemyCorrectionMult , highLevelEnemy ] )
return < >
< div style = { { background : "rgba(200,255,200,1)" } } >
Weapon Total Atk : < EditStatBox value = { weaponTotalAtk } callback = { ( val ) => { setWeaponTotalAtk ( val ) } } / >
< ul >
< li > ● Weapon Base Atk : < EditStatBox value = { weaponBaseAtk } callback = { ( val ) => { setWeaponBaseAtk ( val ) } } / > < / l i >
< li > ● Weapon Enhance Lv : < EditStatBox value = { weaponEnhanceLv } callback = { ( val ) => { setweaponEnhanceLv ( val ) } } / > < / l i >
< / u l >
< br / > < br / > < br / >
Damage Variance : < EditStatBox value = { dmgVariance } callback = { ( val ) => { setDmgVariance ( val ) } } / >
< ul >
< li > ● Weapon Damage Variance : < EditStatBox value = { weaponDmgVariance } callback = { ( val ) => { setWeaponDmgVariance ( val ) } } / > < / l i >
< li > ● Augment Damage Variance : < EditStatBox value = { augDmgVariance } callback = { ( val ) => { setAugDmgVariance ( val ) } } / > < / l i >
< / u l >
< br / > < br / > < br / >
Base Attack : < EditStatBox value = { baseAtk } callback = { ( val ) => { setBaseAtk ( val ) } } / >
Enemy Defense : < EditStatBox value = { enemyDef } callback = { ( val ) => { setEnemyDef ( val ) } } / >
Multipliers : < EditStatBox value = { multipliers } callback = { ( val ) => { setMultipliers ( val ) } } / >
< ul >
< li > ● Atk Mult : < EditStatBox value = { atkmult } callback = { ( val ) => { setAtkMult ( val ) } } / > < / l i >
< li > ● Part Mult : < EditStatBox value = { partmult } callback = { ( val ) => { setPartMult ( val ) } } / > < / l i >
< li > ● Elemental Weakness Mult : < EditStatBox value = { elementalWeaknessMult } callback = { ( val ) => { setElementalWeaknessMult ( val ) } } / > < / l i >
< li > ● Main Class Weapon Boost : < EditStatBox value = { mainClassWeaponBoost } callback = { ( val ) => { setMainClassWeaponBoost ( val ) } } / > < / l i >
< li > ● Class Skill Mult : < EditStatBox value = { classSkillMult } callback = { ( val ) => { setClassSkillMult ( val ) } } / > < / l i >
< li > ● Equip Mult : < EditStatBox value = { equipMult } callback = { ( val ) => { setEquipMult ( val ) } } / > < / l i >
< li >
< ul >
< li > ● Augment Equip Mult : < EditStatBox value = { augmentEquipMult } callback = { ( val ) => { setAugmentEquipMult ( val ) } } / > < / l i >
< li > ● Potency Floor Equip Mult : < EditStatBox value = { potencyFloorEquipMult } callback = { ( val ) => { setPotencyFloorEquipMult ( val ) } } / > < / l i >
< li > ● Elemental Weapon Equip Mult : < EditStatBox value = { elementalWeaponEquipMult } callback = { ( val ) => { setElementalWeaponEquipMult ( val ) } } / > < / l i >
< / u l >
< / l i >
< li > ● Crit Mult : < EditStatBox value = { critMult } callback = { ( val ) => { setCritMult ( val ) } } / > < / l i >
< li > ● Appropriate Distance : < EditStatBox value = { appropriateDistance } callback = { ( val ) => { setAppropriateDistance ( val ) } } / > < / l i >
< li > ● Food Boost : < EditStatBox value = { foodBoost } callback = { ( val ) => { setFoodBoost ( val ) } } / > < / l i >
< li > ● Field Effects : < EditStatBox value = { fieldEffects } callback = { ( val ) => { setFieldEffects ( val ) } } / > < / l i >
< li > ● Status Ailments : < EditStatBox value = { statusAilments } callback = { ( val ) => { setStatusAilments ( val ) } } / > < / l i >
< li > ● Enemy Correction Multiplier : < EditStatBox value = { enemyCorrectionMult } callback = { ( val ) => { setEnemyCorrectionMult ( val ) } } / > < / l i >
< li > ● High Level Enemy : < EditStatBox value = { highLevelEnemy } callback = { ( val ) => { setHighLevelEnemy ( val ) } } / > < / l i >
< / u l >
< br / > < br / > < br / >
Raw Dmg : { rawDmg }
< / d i v >
< / >
}
function FormField ( p ) {
return < > < label className = "formField" for = { p . field } > { p . label } < / l a b e l > {
p . type === "toggle" ? < > < Toggle id = { p . field } checked = { p . checked } onChange = { p . onChange } disabled = { p . loading } / > < label className = "formDescription" for = { p . field } > { p . checked ? < b > YES < / b > : < b > N O < / b > } < / l a b e l > < / > : < i n p u t t y p e = { p . t y p e ? ? " t e x t " } d i s a b l e d = { p . l o a d i n g } i d = { p . f i e l d } m a x l e n g t h = { p . m a x l e n g t h } v a l u e = { p . v a l u e } c h e c k e d = { p . c h e c k e d } o n C h a n g e = { p . o n C h a n g e } p l a c e h o l d e r = { p . p l a c e h o l d e r } / > } < l a b e l c l a s s N a m e = " f o r m D e s c r i p t i o n " f o r = { p . f i e l d } > { p . t o o l t i p } < / l a b e l > < / >
}
function VerifyLogin ( p ) {
axios . post ( GetBackendURL ( p ) + "/validUser" , {
username : p . LOGGEDINUSER ,
password : p . LOGGEDINHASH
} )
. then ( ( data ) => {
if ( data . data . verified ) {
p . history . push ( "/" )
}
} )
. catch ( ( err ) => {
console . log ( err . message )
} )
}
function LoginForm ( p ) {
const [ username , setUsername ] = useState ( "" )
const [ password , setPassword ] = useState ( "" )
const [ rememberMe , setRememberMe ] = useState ( false )
const [ error , setError ] = useState ( "" )
const [ loading , setLoading ] = useState ( false )
const history = useHistory ( )
useEffect ( ( ) => {
VerifyLogin ( { ... p , history : history } )
} , [ history , p ] )
function SubmitLogin ( ) {
setError ( "" )
setLoading ( true )
axios . post ( GetBackendURL ( p ) + "/validUser" , {
username : username ,
password : md5 ( password )
} )
. then ( ( data ) => {
if ( data . data . verified ) {
p . setLOGGEDINUSER ( username )
p . setLOGGEDINHASH ( md5 ( password ) )
setUsername ( "" )
setPassword ( "" )
setRememberMe ( false )
history . push ( "/" )
} else {
setError ( "Could not authenticate!" )
}
} )
. catch ( ( err ) => {
setError ( err ? . message ? ? err ) ;
} )
. then ( ( ) => {
setLoading ( false )
} )
}
return < >
< Box title = "Login Form" >
{ loading ?
< img src = { process . env . PUBLIC _URL + "/spinner.gif" } alt = "" style = { { background : "linear-gradient(white,#bca9f5)" , marginTop : "10px" } } / >
: < > < div onKeyDown = { ( f ) => { if ( f . key === "Enter" ) { SubmitLogin ( ) } } } > < h3 className = "formError" > { error } < / h 3 >
< FormField field = "username" label = "Username: " value = { username } maxlength = { 20 } onChange = { ( p ) => { setUsername ( p . currentTarget . value ) } } placeholder = "Username" / > < br / >
< FormField field = "password" label = "Password: " type = "password" value = { password } onChange = { ( p ) => { setPassword ( p . currentTarget . value ) } } placeholder = "Password" / > < br / >
< FormField field = "rememberMe" label = "Remember Me " type = "toggle" checked = { rememberMe } onChange = { ( p ) => { setRememberMe ( p . currentTarget . checked ) } } / > < br / >
< button type = "submit" onClick = { SubmitLogin } > Login < / b u t t o n > < / d i v > < / >
}
< /Box></ >
}
function RegisterForm ( p ) {
const [ username , setUsername ] = useState ( "" )
const [ password , setPassword ] = useState ( "" )
const [ password2 , setPassword2 ] = useState ( "" )
const [ email , setEmail ] = useState ( "" )
const [ rememberMe , setRememberMe ] = useState ( false )
const [ error , setError ] = useState ( "" )
const [ loading , setLoading ] = useState ( false )
const history = useHistory ( )
useEffect ( ( ) => {
VerifyLogin ( { ... p , history : history } )
} , [ history , p ] )
function SubmitRegister ( ) {
setError ( "" )
setLoading ( true )
try {
if ( username . length < 4 ) { throw new Error ( "Username must be at least 4 characters in length." ) }
if ( username . length > 20 ) { throw new Error ( "Username must be less than 21 characters in length." ) }
if ( password . length < 6 ) { throw new Error ( "Password must contain at least 6 characters." ) }
if ( password !== password2 ) { throw new Error ( "Password fields must match." ) }
if ( ! email . includes ( "@" ) ) { throw new Error ( "Invalid E-mail." ) }
} catch ( err ) {
setError ( err ? . message ? ? err ) ;
setLoading ( false )
return
}
axios . post ( GetBackendURL ( p ) + "/register" , {
username : username ,
password : md5 ( password ) ,
email : email
} )
. then ( ( data ) => {
if ( data . data . verified ) {
p . setLOGGEDINUSER ( username )
p . setLOGGEDINHASH ( md5 ( password ) )
setUsername ( "" )
setPassword ( "" )
setRememberMe ( false )
} else {
setError ( "Could not authenticate!" )
}
} )
. catch ( ( err ) => {
setError ( err ? . message ? ? err ) ;
} )
. then ( ( ) => {
setLoading ( false )
} )
}
return < >
< Box title = "Registration Form" >
{ loading ?
< img src = { process . env . PUBLIC _URL + "/spinner.gif" } alt = "" style = { { background : "linear-gradient(white,#bca9f5)" , marginTop : "10px" } } / >
: < > < h3 className = "formError" > { error } < / h 3 >
< FormField field = "username" label = "Username: " value = { username } maxlength = { 20 } onChange = { ( p ) => { setUsername ( p . currentTarget . value ) } } placeholder = "Username" tooltip = "Enter a username (4-20 characters, a-z and _ only)" / > < br / >
< FormField field = "password" label = "Password: " type = "password" value = { password } onChange = { ( p ) => { setPassword ( p . currentTarget . value ) } } placeholder = "Password" tooltip = "Enter a password (6 or more characters)" / > < br / >
< FormField field = "password2" label = "Verify Password: " type = "password" value = { password2 } onChange = { ( p ) => { setPassword2 ( p . currentTarget . value ) } } placeholder = "Verify Password" tooltip = "Enter password again." / > < br / >
< FormField field = "email" label = "E-mail: " type = "email" value = { email } onChange = { ( p ) => { setEmail ( p . currentTarget . value ) } } placeholder = "email@example.com" tooltip = "This is used to send you password reset emails." / > < br / >
< FormField field = "rememberMe" label = "Remember Me " type = "toggle" checked = { rememberMe } onChange = { ( p ) => { setRememberMe ( p . currentTarget . checked ) } } / > < br / >
< button type = "submit" onClick = { SubmitRegister } > Login < /button></ >
}
< /Box></ >
}
function App ( ) {
const [ author ] = useState ( "Dudley" )
const [ buildName ] = useState ( "Fatimah" )
const [ className ] = useState ( "Ranger" )
const [ secondaryClassName ] = useState ( "Force" )
const [ classLv ] = useState ( 20 )
const [ secondaryClassLv ] = useState ( 15 )
const [ bp ] = useState ( 1330 )
const [ hp ] = useState ( 388 )
const [ pp ] = useState ( 154 )
const [ weaponTotalAtk ] = useState ( 282 )
const [ baseAtk ] = useState ( 650 )
const [ statDisplayAtk , setstatDisplayAtk ] = useState ( 282 )
useEffect ( ( ) => {
setstatDisplayAtk ( Number ( weaponTotalAtk ) + Number ( baseAtk ) )
} , [ weaponTotalAtk , baseAtk ] )
const [ def ] = useState ( 932 )
const [ weaponUp1 ] = useState ( 0.317 )
const [ weaponUp2 ] = useState ( 0.241 )
const [ weaponUp3 ] = useState ( 0.241 )
const [ damageResist ] = useState ( 0.18 )
const [ burnResist ] = useState ( 0 )
const [ shockResist ] = useState ( 0 )
const [ panicResist ] = useState ( 0 )
const [ stunResist ] = useState ( 0 )
const [ freezeResist ] = useState ( 0 )
const [ blindResist ] = useState ( 0 )
const [ poisonResist ] = useState ( 0 )
const [ TESTMODE , setTESTMODE ] = useState ( false )
const [ DATA , setDATA ] = useState ( { GetData : ( ) => { } } )
const [ DATAID , setDATAID ] = useState ( { GetData : ( ) => { } } )
const [ update , setUpdate ] = useState ( false )
const [ LOGGEDINUSER , setLOGGEDINUSER ] = useState ( "" )
const [ LOGGEDINHASH , setLOGGEDINHASH ] = useState ( "" )
function GetData ( table , row , col , id ) {
if ( row === undefined ) { row = '' }
if ( col === undefined ) { col = '' }
var data = id ? DATAID : DATA
return data !== undefined ? data [ table ] !== undefined ? data [ table ] [ row ] !== undefined ? data [ table ] [ row ] [ col ] !== undefined ? data [ table ] [ row ] [ col ] : data [ table ] [ row ] : data [ table ] : data : "no data"
}
useEffect ( ( ) => {
if ( update ) {
setUpdate ( false )
axios . get ( GetBackendURL ( { TESTMODE : TESTMODE } ) + "/data" )
. then ( ( data ) => {
setDATA ( data . data )
} )
axios . get ( GetBackendURL ( { TESTMODE : TESTMODE } ) + "/dataid" )
. then ( ( data ) => {
setDATAID ( data . data )
} )
}
} , [ update , TESTMODE ] )
useEffect ( ( ) => {
axios . get ( GetBackendURL ( { TESTMODE : TESTMODE } ) + "/data" )
. then ( ( data ) => {
setDATA ( data . data )
} )
axios . get ( GetBackendURL ( { TESTMODE : TESTMODE } ) + "/dataid" )
. then ( ( data ) => {
setDATAID ( data . data )
} )
} , [ TESTMODE ] )
return (
< >
< HashRouter >
< Switch >
< Route path = { process . env . PUBLIC _URL + "/admin" } >
< Helmet >
< title > { APP _TITLE + " - Admin Panel" } < / t i t l e >
< / H e l m e t >
< AdminPanel setUpdate = { setUpdate } setTESTMODE = { setTESTMODE } BACKENDURL = { BACKENDURL } TESTMODE = { TESTMODE } DATA = { GetData } / >
< / R o u t e >
< Route path = { process . env . PUBLIC _URL + "/test" } >
< Helmet >
< title > { "Test - " + APP _TITLE } < / t i t l e >
< / H e l m e t >
< TestHeader / >
< TestPanel
author = { author }
buildName = { buildName }
className = { className }
secondaryClassName = { secondaryClassName }
classLv = { classLv }
secondaryClassLv = { secondaryClassLv }
bp = { bp }
hp = { hp }
pp = { pp }
def = { def }
weaponUp1 = { weaponUp1 }
weaponUp2 = { weaponUp2 }
weaponUp3 = { weaponUp3 }
damageResist = { damageResist }
burnResist = { burnResist }
shockResist = { shockResist }
panicResist = { panicResist }
stunResist = { stunResist }
freezeResist = { freezeResist }
blindResist = { blindResist }
poisonResist = { poisonResist }
statDisplayAtk = { statDisplayAtk }
GetData = { GetData }
/ >
< / R o u t e >
< Route path = { process . env . PUBLIC _URL + "/login" } >
< Helmet >
< title > { APP _TITLE + " - Login" } < / t i t l e >
< / H e l m e t >
< TestHeader / >
< LoginForm BACKENDURL = { BACKENDURL } TESTMODE = { TESTMODE } LOGGEDINUSER = { LOGGEDINUSER } LOGGEDINHASH = { LOGGEDINHASH } setLOGGEDINHASH = { setLOGGEDINHASH } setLOGGEDINUSER = { setLOGGEDINUSER } / >
< / R o u t e >
< Route path = { process . env . PUBLIC _URL + "/register" } >
< Helmet >
< title > { APP _TITLE + " - Register" } < / t i t l e >
< / H e l m e t >
< TestHeader / >
< RegisterForm BACKENDURL = { BACKENDURL } TESTMODE = { TESTMODE } LOGGEDINUSER = { LOGGEDINUSER } LOGGEDINHASH = { LOGGEDINHASH } setLOGGEDINHASH = { setLOGGEDINHASH } setLOGGEDINUSER = { setLOGGEDINUSER } / >
< / R o u t e >
< Route path = { process . env . PUBLIC _URL + "/formula" } >
< DamageCalculator / >
< / R o u t e >
< Route path = "/" >
< Helmet >
< title > { APP _TITLE } < / t i t l e >
< / H e l m e t >
< div className = "modalOverlaySplash" >
< div className = "modal" >
< div className = "box boxMisc" >
< div className = "boxTitleBar" > < h1 > { GetData ( "site_data" , "h1" , "data" ) } < / h 1 > < / d i v > < h 2 > { G e t D a t a ( " s i t e _ d a t a " , " h 2 " , " d a t a " ) } < / h 2 > < p > < i m g s r c = { p r o c e s s . e n v . P U B L I C _ U R L + " / s p i n n e r . g i f " } a l t = " " / >
{ GetData ( "site_data" , "UNDER_CONSTRUCTION_TEXT" , "data" ) } < /p><br style={{clear:"both"}} / >
< / d i v >
< / d i v >
< footer > < a href = "https://github.com/sigonasr2/ngsplanner/" > < span className = "github" > & nbsp ; < / s p a n > < / a > < a h r e f = " h t t p s : / / t w i t t e r . c o m / n g s p l a n n e r " > < s p a n c l a s s N a m e = " t w i t t e r " > @ N G S P l a n n e r < / s p a n > < / a > < / f o o t e r >
< / d i v >
< / R o u t e >
< / S w i t c h >
< / H a s h R o u t e r >
< / >
) ;
}
export default App ;