// Note: We keep the data and the states in this component class ChoiceSituationWrapper extends React.Component { constructor(props) { super(props); this.state = { // Check whether all nodes are clicked isClicked: [ false, false, false, false, false, false, false, false, false, false, false, false, false, false, false ], // Save continuation decision in percent continuation: [ 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 0, 0, 0, 0, 0, 0, // 1, 1, 1, 1, 1, 1, 1 // 1, 1, 1, 1, 1, 1, 1, 1 ], // Save outcome path drawn: [-1], indArray: [ [0], [1, 2], [3, 4, 5], [6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19, 20] ], path: {}, pdStopDecision : {}, clickCounter: 0, // Keep track of clicks currentNode: -1, // Keep track of currently clicked node nodeChoiceShow: false, // Show Choice Section showHelp: false, // Show help section nonStandardBalls: 0, // Number of non-standard balls (numbered or White-black-gradient) } this.submitPage = this.submitPage.bind(this); this.showHelp = this.showHelp.bind(this); this.skip = this.skip.bind(this); this.pdRadioClick = this.pdRadioClick.bind(this); this.updatePDStop = this.updatePDStop.bind(this); this.updateCostly = this.updateCostly.bind(this); } componentDidMount() { this.allButtonsClicked() } NodeClickHandler = (currentNode) => { this.setState({ nodeChoiceShow: true, currentNode: currentNode, }) this.hidePointer(); } // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // Functions to block tree coloring hidePointer() { var balls = document.getElementsByClassName('ball'); for (var i = 0; i < balls.length; i++) { balls[i].style.cursor = 'not-allowed'; balls[i].disabled = true; } document.getElementById("input-widget").style.cursor = 'not-allowed'; } allowPointer() { var balls = document.getElementsByClassName('ball'); for (var i = 0; i < balls.length; i++) { balls[i].style.cursor = 'pointer'; balls[i].disabled = false; } document.getElementById("input-widget").style.cursor = 'auto'; } showHelp() { const current = this.state.showHelp; if (current) { this.setState({showHelp: false}) document.getElementById("help").classList.add("d-none") } else { this.setState({showHelp: true}) document.getElementById("help").classList.remove("d-none") } } allButtonsClicked = () => { const {isClicked} = this.state; if (!isClicked.includes(false)) { document.getElementById("confirmButton").classList.remove("d-none") document.getElementById("helpBtn").classList.add("d-none") } } // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // Functions to submit choice pop submitNodeChoice = (probContinue) =>{ const { isClicked, continuation, currentNode, clickCounter} = this.state; isClicked[currentNode] = true, continuation[currentNode] = probContinue, this.setState({ nodeChoiceShow: false, isClicked, continuation, clickCounter: clickCounter +1, currentNode: -1, }, () => { this.allowPointer() this.allButtonsClicked() // test if all buttons have been clicked if (this.props.costly) { this.updateCostly(); } }) } pdRadioClick() { const {currentNode} = this.state const allPaths = js_vars.allPaths[currentNode] const clickedRadios = document .getElementById("pdInstructCol") .querySelectorAll('input[type=radio]:checked'); if (allPaths.length == clickedRadios.length) { setTimeout(() => { this.updatePDStop(clickedRadios); }, 200); } } updatePDStop(clickedRadios) { const { isClicked, continuation, currentNode} = this.state; let {pdStopDecision} = this.state let allStop = true let allContinue = true for (let i=0; i< clickedRadios.length; i++){ let thisRadio = clickedRadios[i]; let path = thisRadio.name let decision = thisRadio.value if (decision == "Stop") { allContinue = false } else if (decision == "Continue") { allStop = false } pdStopDecision[path] = decision } let probContinue = -100 if (allStop) { probContinue = 0 } else if (allContinue) { probContinue = 100 } isClicked[currentNode] = true continuation[currentNode] = probContinue this.setState({ isClicked, continuation, clickCounter: this.state.clickCounter +1, currentNode: -1, pdStopDecision:pdStopDecision, nodeChoiceShow: false, currentNode: -1, }, () => { this.allButtonsClicked() this.allowPointer(); if (this.props.costly) { this.updateCostly(); } }) } closeNodeChoice = () => { this.setState({ nodeChoiceShow: false, currentNode: -1, }) this.allowPointer(); } updateCostly() { const numCurrentBalls = this.state.nonStandardBalls; const {isClicked, continuation} = this.state // Determine new number of non-standard balls let newnNonStandardBalls = 0; for (const [index, element] of isClicked.entries()) { if (element && continuation[index] != 0 && continuation[index] != 100) { newnNonStandardBalls = newnNonStandardBalls +1; } } if (newnNonStandardBalls != numCurrentBalls) { this.setState({ nonStandardBalls: newnNonStandardBalls, }) document.getElementById("decoloringCost").classList.add("alert-info") setTimeout( () => { document.getElementById("decoloringCost").classList.remove("alert-info") }, 1000) } } // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // Functions to make buttons work submitPage = () =>{ liveSend(this.state) // Sends state to oTree backend } // Skip to next page skip() { if (this.props.treatment == 2 || this.props.treatment == 4) { this.setState({ isClicked: [ true, true, true, true, true, true, true, true, true, true, true, true, true, true, true ], // Save continuation decision in percent continuation: [ 100, 100, 100, 100, 50, 40, 100, 60, 40, 20, 90, 80, 40, 20, 0, 0, 0, 0, 0, 0, 0, // 1, 1, 1, 1, 1, 1, 1 // 1, 1, 1, 1, 1, 1, 1, 1 ], }, () => {document.getElementById("confirmButton").click()}) } else { this.setState({ isClicked: [ true, true, true, true, true, true, true, true, true, true, true, true, true, true, true ], // Save continuation decision in percent continuation: [ 100, 100, 100, 100, 100, 0, 100, 100, 0, 0, 100, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1, 1, 1, 1, 1, 1, 1 // 1, 1, 1, 1, 1, 1, 1, 1 ], }, () => {document.getElementById("confirmButton").click()}) } document.getElementById("helpBtn").classList.add("d-none") document.getElementById("skipBtn").classList.add("d-none") } voidFunction() { return } // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ render() { let upTickSub = js_vars.upTick let upTick = upTickSub.toFixed(2); let downTick; if (js_vars.downTick) { let downTickSub = js_vars.downTick downTickSub = - downTickSub downTick = (downTickSub.toFixed(2)); } else { upTickSub = -upTickSub downTick = (upTickSub.toFixed(2)); } // Determine costs for non-standard balls in respective treatments let costsPerBall = parseFloat(js_vars.costPerBall.replace('£', '')) const nonStandardCosts = (this.state.nonStandardBalls * costsPerBall).toFixed(2); return ( <>
The winning side | Coin toss outcome |
---|---|
![]() |
![]() |
Win the single risk: | +£{upTick} |
Lose the single risk: | -£{upTick} |
Please be reminded that the single risks work
as follows:
You enter the outcome of your coin toss (or
choose a coin side you like).
We – the experimenters – already chose a winning side,
stated in Verification.pdf.
If your coin toss outcome equals the winning side,
you gain £{upTick}. Otherwise, you lose £{upTick}.
Please be reminded of the following decoloring scheme: