Skip to content

Commit

Permalink
updates to get us most of the way to voting
Browse files Browse the repository at this point in the history
  • Loading branch information
Pomax committed Oct 18, 2018
1 parent dec0561 commit 476ab22
Show file tree
Hide file tree
Showing 7 changed files with 166 additions and 77 deletions.
Expand Up @@ -23,7 +23,11 @@ <h2 class="h1-heading">{{product.name}}</h2>
</div>
<div class="body-large mb-5">{{product.blurb}}</div>

<div class="creep-vote-target my-5"></div>
<div class="creep-vote-target my-5">
{% csrf_token %}
<input type="hidden" name="productID" value="{{ product.id }}">
<input type="hidden" name="votes" value="{{ product.votes | safe }}">
</div>

<h3 class="h3-heading h3-heading-small">Can it spy on me?</h3>

Expand Down
18 changes: 17 additions & 1 deletion source/js/buyers-guide/bg-main.js
Expand Up @@ -75,7 +75,23 @@ let main = {
injectReactComponents() {
if (document.querySelectorAll(`.creep-vote-target`)) {
Array.from(document.querySelectorAll(`.creep-vote-target`)).forEach(element => {
ReactDOM.render(<CreepVote />, element);
let csrf = element.querySelector(`input[name=csrfmiddlewaretoken]`);
let productID = element.querySelector(`input[name=productID]`).value;
let votes = element.querySelector(`input[name=votes]`).value;

try {
votes = JSON.parse(votes.replace(/'/g,`"`));
} catch (e) {
votes = {
creepiness: {
average: 50,
'vote_breakdown': {'0': 0, '1': 0, '2': 0, '3': 0, '4': 0}
},
confidence: {'0': 0, '1': 0}
};
}

ReactDOM.render(<CreepVote csrf={csrf.value} productID={parseInt(productID,10)} votes={votes}/>, element);
});
}

Expand Down
105 changes: 90 additions & 15 deletions source/js/buyers-guide/components/creep-vote/creep-vote.jsx
Expand Up @@ -6,34 +6,103 @@ import LikelyhoodChart from '../likelyhood-chart/likelyhood-chart.jsx';
export default class CreepVote extends React.Component {
constructor(props) {
super(props);

this.state = this.getInitialState();

this.submitVote = this.submitVote.bind(this);
console.log(this.props.votes);
}

getInitialState() {
let conf = this.props.votes.confidence;
let totalVotes = conf[0] + conf[1];

return {
totalVotes,
creepiness: 50,
confidence: undefined,
didVote: false
};
}

submitVote(){
this.setState({didVote:true});
showVoteResult() {
if (this.state.creepinessSubmitted && this.state.confidenceSubmitted) {
this.setState({ didVote: true });
}
}

sendVoteFor(payload) {
let attribute = payload.attribute;
let url = "/privacynotincluded/vote";
let method = "POST";
let credentials = 'same-origin';
let headers = {
"X-CSRFToken": this.props.csrf,
"Content-Type": "application/json"
};

fetch(url, {
method,
credentials,
headers,
body: JSON.stringify(payload)
})
.then(response => {
let update = {};
update[`${attribute}Submitted`] = true;
this.setState(update, () => {
this.showVoteResult()
});
})
.catch(e => {
console.warn(e);
this.setState({ disableVoteButton: false });
});
}

submitVote(evt) {
evt.preventDefault();

let confidence = this.state.confidence;

if (confidence === undefined) {
return;
}

this.setState({ disableVoteButton: true });

let productID = this.props.productID;

this.sendVoteFor({
attribute: 'confidence',
productID,
value: confidence,
});

this.sendVoteFor({
attribute: 'creepiness',
productID,
value: this.state.creepiness
});
}

setCreepiness(creepiness) {
this.setState({ creepiness });
}

setConfidence(confidence) {
this.setState({ confidence });
}

/**
* @returns {jsx} What users see when they haven't voted on this product yet.
*/
renderVoteAsk() {
return (<form method="post" id="creep-vote" onSubmit={this.submitVote}>
return (<form method="post" id="creep-vote" onSubmit={evt => this.submitVote(evt)}>
<div className="row mb-5">
<div className="col-12 col-md-6">
<div className="mb-4 text-center">
<h3 className="h5-heading mb-2">How creepy is this product?</h3>
<p>Majority of voters think it is super creepy</p>
</div>
<Creepometer initialValue={50}></Creepometer>
<Creepometer initialValue={this.state.creepiness} onChange={value => this.setCreepiness(value)}></Creepometer>
</div>
<div className="col-12 col-md-6">
<div className="mb-4 text-center">
Expand All @@ -43,19 +112,21 @@ export default class CreepVote extends React.Component {
<div className="text-center">
<div class="btn-group btn-group-toggle" data-toggle="buttons">
<label for="likely">
<input type="radio" name="wouldbuy" id="likely" autocomplete="off" required /><span class="btn">Likely</span>
<input type="radio" name="wouldbuy" id="likely" autocomplete="off" required/>
<span class="btn" onClick={evt => this.setConfidence(true)}>Likely</span>
</label>
<label for="unlikely">
<input type="radio" name="wouldbuy" id="unlikely" autocomplete="off" required /><span class="btn">Not likely</span>
<input type="radio" name="wouldbuy" id="unlikely" autocomplete="off" required/>
<span class="btn" onClick={evt => this.setConfidence(false)}>Not likely</span>
</label>
</div>
</div>
</div>
</div>
<div className="row">
<div className="col-12 text-center">
<button type="submit" className="btn btn-ghost mb-2">Vote & See Results</button>
<p>367 votes</p>
<button type="submit" className="btn btn-ghost mb-2" disabled={this.state.confidence===undefined}>Vote & See Results</button>
<p>{this.state.totalVotes} votes</p>
</div>
</div>
</form>);
Expand All @@ -69,12 +140,16 @@ export default class CreepVote extends React.Component {
<div>
<div className="mb-5">
<div className="col-12 text-center">
<h3 className="h4-heading">Thanks for voting! Here are the results</h3>
<div>367 Votes</div>
<h3 className="h4-heading">Thanks for voting! Here are the results so far:</h3>
<div>{this.state.totalVotes} Votes</div>
</div>
<div className="row">
<div className="col"><CreepChart/></div>
<div className="col likelyhood-chart"><LikelyhoodChart /></div>
<div className="col">
<CreepChart values={this.props.votes.creepiness.vote_breakdown} />
</div>
<div className="col likelyhood-chart">
<LikelyhoodChart values={this.props.votes.confidence} />
</div>
</div>
</div>
</div>
Expand Down
11 changes: 11 additions & 0 deletions source/js/buyers-guide/components/creep-vote/creep-vote.scss
Expand Up @@ -5,13 +5,24 @@ $btn-shadow-width: 3px;
border-bottom: 1px solid #c8c8ca;
border-top: 1px solid #c8c8ca;

button[disabled] {
color: #bbbbbb;

&.btn-ghost:hover {
cursor: auto;
color: inherit;
background: inherit;
}
}

.btn-group {
.btn {
border: 1px solid $medium-gray;
border-bottom-width: $btn-shadow-width;
color: black;
text-transform: initial;
transition: all 0.1s linear;

}

input { display: none; }
Expand Down
Expand Up @@ -3,64 +3,47 @@ import React from 'react';
export default class CreepChart extends React.Component {
constructor(props) {
super(props);

this.state = this.getInitialState();

}

getInitialState() {
let values = this.props.values;
let data = [
{c: 'no-creep', label: 'Not creepy', value: values[0], offset: 0},
{c: 'little-creep', label: 'A little creepy', value: values[1], offset: 225},
{c: 'somewhat-creep', label: 'Somewhat creepy', value: values[2], offset: 475},
{c: 'very-creep', label: 'Very creepy', value: values[3], offset: 725},
{c: 'super-creep', label: 'Super creepy', value: values[4], offset: 975}
];
let sum = data.reduce((tally, v) => tally + v.value, 0);

return {
totalCreepiness: sum,
creepinessData: data
};
}

render(){
render() {
return (
<div>
<table id="creepiness-score">
<tbody>
{/* TODO: Pull in vote% and apply as pixel height, td value.
TODO: Apply "your-vote" class to the level of the user's vote
Height needs to be in px so that the value sits on top of the bar */}
<tr className="your-vote no-creep">
<th>
<div className="bar" style={{height: '100px'}}></div>
<span className="creep-label">Not creepy</span>
<span className="creep-face"></span>
</th>
<td className="creepiness">1%</td>
</tr>
<tr className="your-vote little-creep">
<th>
<div className="bar" style={{height: '20px'}}></div>
<span className="creep-label">A little creepy</span>
<span className="creep-face"></span>
</th>
<td className="creepiness">2%</td>
</tr>
<tr className="your-vote somewhat-creep">
<th>
<div className="bar" style={{height: '40px'}}></div>
<span className="creep-label">Somewhat creepy</span>
<span className="creep-face"></span>
</th>
<td className="creepiness">3%</td>
</tr>
<tr className="your-vote very-creep">
<th>
<div className="bar" style={{height: '25px'}}></div>
<span className="creep-label">Very creepy</span>
<span className="creep-face"></span>
</th>
<td className="creepiness">4%</td>
</tr>
<tr className="your-vote super-creep">
<th>
<div className="bar" style={{height: '65px'}}></div>
<span className="creep-label">Super creepy</span>
<span className="creep-face"></span>
</th>
<td className="creepiness">5%</td>
</tr>
{
this.state.creepinessData.map(data => {
let percent = Math.round(100 * data.value / this.state.totalCreepiness);
console.log(data.value, this.state.totalCreepiness, percent);
return (
<tr key={data.c} className={`your-vote ${data.c}`}>
<th>
<div className="bar" style={{height: `${percent}px`}}></div>
<span className="creep-label">{data.label}</span>
<span className="creep-face" style={{backgroundPositionY: `-${data.offset}px`}}></span>
</th>
<td className="creepiness">{percent}%</td>
</tr>
);
})
}
</tbody>
</table>
<div className="row">
Expand Down
9 changes: 7 additions & 2 deletions source/js/buyers-guide/components/creepometer/creepometer.jsx
Expand Up @@ -44,7 +44,7 @@ export default class Creepometer extends React.Component {

slideMove(e) {
if (this.state.isHandleGrabbed) {
let clientX, sliderLeftEdgeX, offset;
let clientX, sliderLeftEdgeX, offset, value=50;

if (e.nativeEvent.type === `touchmove`){
clientX = e.nativeEvent.touches[0].pageX;
Expand All @@ -53,11 +53,16 @@ export default class Creepometer extends React.Component {
}
sliderLeftEdgeX = this.sliderElement.getBoundingClientRect().left;
offset = Math.floor(clientX - sliderLeftEdgeX);
value = Math.floor(offset / this.sliderElement.scrollWidth * this.encodedStepCount);

this.setState({
handleOffset: offset,
encodedValue: Math.floor(offset / this.sliderElement.scrollWidth * this.encodedStepCount)
encodedValue: value
});

if (this.props.onChange) {
this.props.onChange(value);
}
}
}

Expand Down
Expand Up @@ -5,17 +5,12 @@ import React from 'react';
export default class LikelyhoodChart extends React.Component {
constructor(props) {
super(props);

this.state = this.getInitialState();

}

getInitialState() {
return {
};
}

render(){
let values = this.props.values;
let total = values[0] + values[1];
let perc = Math.round(100 * values[0]/total, 10);
return (
<div>
<table id="likelyhood-score">
Expand All @@ -25,17 +20,17 @@ export default class LikelyhoodChart extends React.Component {
<span className="likely-label">Likely</span>
</th>
<td className="likelyhood">
<span className="bar" style={{width: '95%'}}></span>
<span className="likelyhood-words">95% Likely to buy it</span>
<span className="bar" style={{width: `${100 - perc}%`}}></span>
<span className="likelyhood-words">{100 - perc}% Likely to buy it</span>
</td>
</tr>
<tr className="unlikely">
<th>
<span className="likely-label">Not likely</span>
</th>
<td className="likelyhood">
<span className="bar" style={{width: '5%'}}></span>
<span className="likelyhood-words">5% Not likely to buy it</span>
<span className="bar" style={{width: `${perc}%`}}></span>
<span className="likelyhood-words">{perc}% Not likely to buy it</span>
</td>
</tr>
</tbody>
Expand Down

0 comments on commit 476ab22

Please sign in to comment.