v1.1.0/number values and efficacy

This commit is contained in:
2021-04-20 20:16:21 -04:00
parent 2eabb6807f
commit 5c39e8a628
10 changed files with 581 additions and 435 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
.input-popup.expanded {
height: 40vh;
height: 50vh;
}
.loading-bar-container {
+37
View File
@@ -331,6 +331,43 @@ footer .by {
.input-popup-submit.submitted {
background-color: #55c16c;
}
.input-popup-submit.errored {
background-color: #c43d34;
}
.input-popup.expanded::-webkit-scrollbar {
width: 1.5rem;
background-color: var(--color-tertiary);
border-radius: 0 4rem 4rem 0;
}
.input-popup.expanded::-webkit-scrollbar-thumb {
width: 1rem;
background-color: var(--color-dim);
border-radius: 0 4rem 4rem 0;
}
.tip-container {
display: flex;
flex-direction: row;
align-items: center;
padding: 2rem 4rem;
padding-left: 2rem;
border-radius: 1rem;
margin-bottom: 2rem;
border: 1px solid var(--color-secondary);
}
.tip-icon {
font-size: 3rem;
}
.tip {
padding-left: 2rem;
}
.tip .overline {
font-size: 1.4rem;
}
.tip .subheader {
font-size: 3.2rem;
}
@keyframes loading {
0% {
+1 -1
View File
@@ -22,7 +22,7 @@ footer {
height: 10rem;
}
.input-popup.expanded {
height: 50vh;
height: 55vh;
}
.loading-bar-container {
+4
View File
@@ -103,3 +103,7 @@ footer {
.loading-bar-container {
max-width: 50%;
}
.tip-container {
width: fit-content;
}
+225 -100
View File
@@ -20,6 +20,7 @@ if (window.location.host.startsWith("localhost")) {
const fb_functions = firebase.functions();
const saveResult = fb_functions.httpsCallable("saveResult");
const getPastResult = fb_functions.httpsCallable("getPastResult");
const getStats = fb_functions.httpsCallable("getStats");
const VAX_NAMES = {
PB: "Pfizer-BioNTech",
@@ -47,61 +48,76 @@ const VAX_AGES = {
},
};
const VAX_EFFICACY = {
"Pfizer-BioNTech": {
"18 - 55": 95.3,
"56 & Older": 93.8,
},
Moderna: {
"18 - 64": 95.6,
"65 & Older": 86.4,
},
"J&J Janssen": {
"18 - 59": 66.1,
"60 & Older": 66.2,
},
}
const PB_DOSE1_YOUNGER_RESULT = {
"PAIN AT SITE": "8",
"RED AT SITE": "1",
"SWELLING AT SITE": "1",
FATIGUE: "5",
HEADACHE: "4",
"NEED PAIN MED": "3",
"MUSCLE PAIN": "2",
CHILLS: "1",
DIRRHEA: "1",
"JOINT PAIN": "1",
FEVER: "<1",
VOMITING: "<1",
"PAIN AT SITE": 1904,
"RED AT SITE": 104,
"SWELLING AT SITE": 132,
FATIGUE: 1085,
HEADACHE: 959,
"NEED PAIN MED":638,
"MUSCLE PAIN": 487,
CHILLS: 321,
DIARRHEA: 255,
"JOINT PAIN": 251,
FEVER: 85,
VOMITING: 28,
};
const PB_DOSE2_YOUNGER_RESULT = {
"PAIN AT SITE": "8",
"RED AT SITE": "1",
"SWELLING AT SITE": "1",
FATIGUE: "6",
HEADACHE: "5",
"NEED PAIN MED": "5",
"MUSCLE PAIN": "4",
CHILLS: "4",
"JOINT PAIN": "2",
FEVER: "2",
DIRRHEA: "1",
VOMITING: "<1",
"PAIN AT SITE": 1632,
"RED AT SITE": 123,
"SWELLING AT SITE": 132,
FATIGUE: 1247,
HEADACHE: 1085,
"NEED PAIN MED": 945,
"MUSCLE PAIN": 783,
CHILLS: 737,
"JOINT PAIN": 459,
FEVER: 331,
DIARRHEA: 219,
VOMITING: 40,
};
const PB_DOSE1_OLDER_RESULT = {
"PAIN AT SITE": "7",
"RED AT SITE": "1",
"SWELLING AT SITE": "1",
FATIGUE: "3",
HEADACHE: "3",
"NEED PAIN MED": "2",
"MUSCLE PAIN": "1",
CHILLS: "1",
DIRRHEA: "1",
"JOINT PAIN": "1",
FEVER: "<1",
VOMITING: "<1",
"PAIN AT SITE": 1282,
"RED AT SITE": 85,
"SWELLING AT SITE": 118,
FATIGUE: 615,
HEADACHE: 454,
"NEED PAIN MED": 358,
"MUSCLE PAIN": 251,
CHILLS: 113,
DIARRHEA: 147,
"JOINT PAIN": 155,
FEVER: 26,
VOMITING: 9,
};
const PB_DOSE2_OLDER_RESULT = {
"PAIN AT SITE": "7",
"RED AT SITE": "1",
"SWELLING AT SITE": "1",
FATIGUE: "5",
HEADACHE: "4",
"NEED PAIN MED": "4",
"MUSCLE PAIN": "3",
CHILLS: "2",
"JOINT PAIN": "2",
DIRRHEA: "1",
FEVER: "1",
VOMITING: "<1",
"PAIN AT SITE": 1098,
"RED AT SITE": 120,
"SWELLING AT SITE": 124,
FATIGUE: 839,
HEADACHE: 647,
"NEED PAIN MED": 625,
"MUSCLE PAIN": 477,
CHILLS: 377,
"JOINT PAIN": 313,
DIARRHEA: 137,
FEVER: 181,
VOMITING: 11,
};
const MD_DOSE1_YOUNGER_RESULT = {
"PAIN AT SITE": "9",
@@ -174,6 +190,33 @@ const JJ_OLDER_RESULT = {
FEVER: "<1",
};
const VAX_COUNTS = {
"Pfizer-BioNTech": {
"Dose 1": {
"18 - 55": 2291,
"56 & Older": 1802,
},
"Dose 2": {
"18 - 55": 2098,
"56 & Older": 1660,
},
},
Moderna: {
"Dose 1": {
"18 - 64": 1,
"65 & Older": 1,
},
"Dose 2": {
"18 - 64": 1,
"65 & Older": 1,
},
},
"J&J Janssen": {
"18 - 59": 1,
"60 & Older": 1,
},
};
const VAX_RESULTS = {
"Pfizer-BioNTech": {
"Dose 1": {
@@ -210,7 +253,7 @@ const ICONS = {
"NEED PAIN MED": "💊",
"MUSCLE PAIN": "😫",
CHILLS: "🥶",
DIRRHEA: "💩",
DIARRHEA: "💩",
"JOINT PAIN": "🦵",
FEVER: "🤒",
VOMITING: "🤮",
@@ -227,6 +270,8 @@ class App extends React.Component {
gid: "",
showInputPopup: false,
answers: {},
fetchedResult : {},
stats: {},
loading: true,
};
}
@@ -276,11 +321,7 @@ class App extends React.Component {
const { data } = v;
if (!!data) {
const { name, age, dose } = data;
this.setState({ name, age, dose, showInputPopup: true });
delete data.name;
delete data.age;
delete data.dose;
this.setState({ answers: data, loading: false });
this.setState({ name, age, dose, showInputPopup: true, fetchedResult: data, answers: data, loading: false });
const inputPopupSubmit = document.querySelector(
".input-popup-submit"
);
@@ -302,7 +343,13 @@ class App extends React.Component {
} else {
this.setState({ loading: false });
}
getStats().then(v => this.setState({ stats: v.data }));
}
shouldShowDoses = () => {
const { name } = this.state;
return name && (name === VAX_NAMES.PB || name === VAX_NAMES.MD);
};
shouldShowAgeGroup = () => {
const { name, dose } = this.state;
switch (name) {
@@ -373,25 +420,55 @@ class App extends React.Component {
document.querySelector("#share-result").innerHTML = "Share ↗";
}, 1500);
};
updateAnswers = (symptom) => {
updateAnswers = (symptom, dose) => {
const { answers } = this.state;
const newAnswers = Object.assign({}, answers);
if (answers[symptom]) {
newAnswers[symptom] = !answers[symptom];
if (!!dose) {
if (!newAnswers[dose]) {
newAnswers[dose] = {};
}
if (newAnswers[dose][symptom]) {
newAnswers[dose][symptom] = !newAnswers[dose][symptom];
} else {
newAnswers[dose][symptom] = true;
}
} else {
newAnswers[symptom] = true;
if (newAnswers[symptom]) {
newAnswers[symptom] = !newAnswers[symptom];
} else {
newAnswers[symptom] = true;
}
}
this.setState({ answers: newAnswers });
};
submitAnswer = () => {
document.querySelector(".input-popup-submit").innerHTML = "SENDING...";
const { name, dose, age, answers, gid } = this.state;
const result = Object.assign({}, this.getResults());
const result = this.getResults();
const symptoms = {};
Object.keys(result).forEach((symptom) => {
symptoms[symptom] = false;
});
const submitAnswers = Object.assign({}, symptoms, answers, {
delete answers.name;
delete answers.dose;
delete answers.age;
if(!!dose) {
symptoms[VAX_DOSES.ONE] = {};
symptoms[VAX_DOSES.TWO] = {};
Object.keys(VAX_DOSES).forEach((dose) => {
Object.keys(result).forEach((symptom) => {
symptoms[VAX_DOSES[dose]][symptom] = false;
if (answers[VAX_DOSES[dose]] && answers[VAX_DOSES[dose]][symptom]) {
symptoms[VAX_DOSES[dose]][symptom] = true;
}
});
});
} else {
Object.keys(result).forEach((symptom) => {
symptoms[symptom] = false;
if (answers[symptom]) {
symptoms[symptom] = true;
}
});
}
const submitAnswers = Object.assign({}, symptoms, {
name,
dose,
age,
@@ -399,7 +476,12 @@ class App extends React.Component {
});
saveResult(submitAnswers)
.then(() => {
delete submitAnswers.gid;
this.setState({ fetchedResult : submitAnswers });
const inputPopupSubmit = document.querySelector(".input-popup-submit");
if (inputPopupSubmit.classList.contains("errored")) {
inputPopupSubmit.classList.remove("errored");
}
if (!inputPopupSubmit.classList.contains("submitted")) {
inputPopupSubmit.classList.add("submitted");
}
@@ -408,10 +490,57 @@ class App extends React.Component {
inputPopupSubmit.innerHTML = "UPDATE ANSWER";
}, 1500);
})
.catch((err) => console.error("ERROR Saving Answer", err));
.catch((err) => {
const inputPopupSubmit = document.querySelector(".input-popup-submit");
if (!inputPopupSubmit.classList.contains("errored")) {
inputPopupSubmit.classList.add("errored");
}
if (inputPopupSubmit.classList.contains("submitted")) {
inputPopupSubmit.classList.remove("submitted");
}
inputPopupSubmit.innerHTML = "UH OH...UNABLE TO SEND";
setTimeout(() => {
inputPopupSubmit.innerHTML = "TRY AGAIN";
}, 1500);
console.error("ERROR Saving Answer", err);
});
};
getAnswerOptions = (answerDose) => {
const { answers, dose } = this.state;
const result = this.getResults();
return <div className="question-container" key={`answer-dose-${answerDose}`}>
{!!answerDose ? (
<h6 className="overline" data-font="sans">
{answerDose}
</h6>
) : null}
<p className="question" data-font="sans-italic">
{ ((dose === VAX_DOSES.ONE) && (answerDose === VAX_DOSES.TWO)) ? "(You can comeback later to tell us about Dose 2)":"(Select all side effects that you experienced)" }
</p>
<div className="answers-container">
{Object.keys(result).map((symptom) => (
<button
key={`ans-${answerDose}-${symptom}`}
data-font="sans-bold"
className={`answer${
!!answerDose
? (answers[answerDose] && answers[answerDose][symptom])
? " selected"
: ""
: answers[symptom]
? " selected"
: ""
}`}
onClick={() => this.updateAnswers(symptom, answerDose)}
>
{symptom}
</button>
))}
</div>
</div>;
};
render() {
const { name, dose, age, showInputPopup, answers, loading } = this.state;
const { name, dose, age, showInputPopup, loading, fetchedResult } = this.state;
let result = {};
let resultAtSite = {};
if (this.shouldShowResults()) {
@@ -463,7 +592,7 @@ class App extends React.Component {
name: v,
dose: "",
age: "",
answers: {},
answers: v === fetchedResult.name ? fetchedResult : {},
showInputPopup: false,
})
}
@@ -478,7 +607,7 @@ class App extends React.Component {
</div>
</div>
) : null}
{name && (name === VAX_NAMES.PB || name === VAX_NAMES.MD) ? (
{this.shouldShowDoses() ? (
<div className="question-container">
<p className="question" data-font="sans-italic">
Select Dose
@@ -491,7 +620,6 @@ class App extends React.Component {
this.setState({
dose: v,
age: "",
answers: {},
showInputPopup: false,
})
}
@@ -519,7 +647,6 @@ class App extends React.Component {
onClick={() =>
this.setState({
age: v,
answers: {},
showInputPopup: false,
})
}
@@ -553,6 +680,27 @@ class App extends React.Component {
</div>
) : null}
{this.shouldShowResults() ? (
<div className="tip-container">
<div className="tip-icon">&#9432;</div>
<div className="tip">
<h6 style={{marginBottom: '1.2rem'}} className="overline" data-font="sans">
NET EFFICACY
</h6>
<h6 className="overline" data-font="sans-italic">
{name} was effective for
</h6>
<h3 className="subheader" data-font="sans-bold">
{VAX_EFFICACY[name][age]}%
</h3>
<h6 className="overline" data-font="sans-italic">
of people who took it, in the {age} age group
</h6>
</div>
</div>
) : null
}
{this.shouldShowResults() ? (
<div className="symptom-container">
{Object.keys(resultAtSite).map((symptom) => (
@@ -579,6 +727,7 @@ class App extends React.Component {
))}
</div>
) : null}
</main>
{this.shouldShowResults() ? (
<div className={`input-popup${showInputPopup ? " expanded" : ""}`}>
@@ -606,41 +755,17 @@ class App extends React.Component {
</div>
<div className="input-popup-body">
<p className="question" data-font="sans">
I am in age group <strong>{age}</strong> and got
<strong>{!!dose ? ` ${dose} ` : ""}</strong>
{!!dose ? `of` : ""} the
I am in age group <strong>{age}</strong> and got the
<strong> {name}</strong> vaccine. I experienced:
</p>
<div className="question-container">
<p className="question" data-font="sans-italic">
(Select all side effects that you experienced)
</p>
<div className="answers-container">
{Object.keys(resultAtSite).map((symptom) => (
<button
key={`ans-${symptom}`}
data-font="sans-bold"
className={`answer${answers[symptom] ? " selected" : ""}`}
onClick={() => this.updateAnswers(symptom)}
>
{symptom}
</button>
))}
{Object.keys(result).map((symptom) => (
<button
key={`ans-${symptom}`}
data-font="sans-bold"
className={`answer${answers[symptom] ? " selected" : ""}`}
onClick={() => this.updateAnswers(symptom)}
>
{symptom}
</button>
))}
</div>
</div>
{this.shouldShowDoses()
? Object.keys(VAX_DOSES).map((dose) =>
this.getAnswerOptions(VAX_DOSES[dose])
)
: this.getAnswerOptions()}
<div className="question-container">
<p className="question" data-font="sans">
You can comeback and update your experience later!
You can comeback and update your experience at any time!
</p>
<p className="question" data-font="sans-italic">
(Just use the same device)