V1.1.0/add compat functions, script to update, data source select
This commit is contained in:
+179
-3
@@ -45,6 +45,7 @@ const serializeGaId = (_gaid: string): string => {
|
|||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
};
|
};
|
||||||
|
|
||||||
const addResultToStats = async (data : SaveResultRequestData) => {
|
const addResultToStats = async (data : SaveResultRequestData) => {
|
||||||
const cleanData : Record<string, any> =
|
const cleanData : Record<string, any> =
|
||||||
Object.assign({}, data);
|
Object.assign({}, data);
|
||||||
@@ -56,6 +57,15 @@ const addResultToStats = async (data : SaveResultRequestData) => {
|
|||||||
count: admin.firestore.FieldValue.increment(1),
|
count: admin.firestore.FieldValue.increment(1),
|
||||||
};
|
};
|
||||||
if (data.name === VAX_NAMES.PB || data.name === VAX_NAMES.MD) {
|
if (data.name === VAX_NAMES.PB || data.name === VAX_NAMES.MD) {
|
||||||
|
if (data.dose === VAX_DOSES.ONE) {
|
||||||
|
updateDoc[`${VAX_DOSES.ONE}.${data.age}.count`] =
|
||||||
|
admin.firestore.FieldValue.increment(1);
|
||||||
|
} else if (data.dose === VAX_DOSES.TWO) {
|
||||||
|
updateDoc[`${VAX_DOSES.ONE}.${data.age}.count`] =
|
||||||
|
admin.firestore.FieldValue.increment(1);
|
||||||
|
updateDoc[`${VAX_DOSES.TWO}.${data.age}.count`] =
|
||||||
|
admin.firestore.FieldValue.increment(1);
|
||||||
|
}
|
||||||
Object.keys(VAX_DOSES).forEach((doseKey : string) => {
|
Object.keys(VAX_DOSES).forEach((doseKey : string) => {
|
||||||
const dose : string = VAX_DOSES[doseKey];
|
const dose : string = VAX_DOSES[doseKey];
|
||||||
Object.keys(cleanData[dose]).forEach((symptom : string) => {
|
Object.keys(cleanData[dose]).forEach((symptom : string) => {
|
||||||
@@ -70,6 +80,8 @@ const addResultToStats = async (data : SaveResultRequestData) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
updateDoc[`${data.age}.count`] =
|
||||||
|
admin.firestore.FieldValue.increment(1);
|
||||||
Object.keys(cleanData).forEach((symptom : string) => {
|
Object.keys(cleanData).forEach((symptom : string) => {
|
||||||
let updateDocSymptom = symptom.replace("/", "OR");
|
let updateDocSymptom = symptom.replace("/", "OR");
|
||||||
if (symptom === "DIARRHEA") {
|
if (symptom === "DIARRHEA") {
|
||||||
@@ -119,7 +131,10 @@ const removeResultFromStats = async (data : FirebaseFirestore.DocumentData) => {
|
|||||||
admin.firestore().collection("stats").doc(data.name).update(updateDoc);
|
admin.firestore().collection("stats").doc(data.name).update(updateDoc);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getStats = functions.https.onCall(
|
/**
|
||||||
|
* FUNCTIONS FROM V1.1.0 TO CURRENT
|
||||||
|
*/
|
||||||
|
export const getStatsV1 = functions.https.onCall(
|
||||||
async () => {
|
async () => {
|
||||||
const stats = await admin.firestore().collection("stats").get();
|
const stats = await admin.firestore().collection("stats").get();
|
||||||
const docs = stats.docs
|
const docs = stats.docs
|
||||||
@@ -132,7 +147,7 @@ export const getStats = functions.https.onCall(
|
|||||||
return returnData;
|
return returnData;
|
||||||
});
|
});
|
||||||
|
|
||||||
export const saveResult = functions.https.onCall(
|
export const saveResultV1 = functions.https.onCall(
|
||||||
async (data: SaveResultRequestData, context) => {
|
async (data: SaveResultRequestData, context) => {
|
||||||
if (!!data && !!context) {
|
if (!!data && !!context) {
|
||||||
const {gid} = data;
|
const {gid} = data;
|
||||||
@@ -162,7 +177,7 @@ export const saveResult = functions.https.onCall(
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export const getPastResult =
|
export const getPastResultV1 =
|
||||||
functions.https.onCall(async (data : {gid:string}, context) => {
|
functions.https.onCall(async (data : {gid:string}, context) => {
|
||||||
if (!!data && !!context) {
|
if (!!data && !!context) {
|
||||||
const {gid} = data;
|
const {gid} = data;
|
||||||
@@ -227,3 +242,164 @@ export const getPastResult =
|
|||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FUNCTIONS FROM V1.0.0 TO V1.0.1
|
||||||
|
*/
|
||||||
|
export const saveResult = functions.https.onCall(
|
||||||
|
async (data: SaveResultRequestData, context) => {
|
||||||
|
if (!!data && !!context) {
|
||||||
|
const {gid} = data;
|
||||||
|
const docId: string = serializeGaId(gid);
|
||||||
|
const docData: Record<string, string | boolean> =
|
||||||
|
Object.assign({}, data);
|
||||||
|
delete docData.gid;
|
||||||
|
const existingData = await admin
|
||||||
|
.firestore()
|
||||||
|
.collection("results")
|
||||||
|
.doc(docId)
|
||||||
|
.get()
|
||||||
|
.then((doc) => doc.data());
|
||||||
|
if (existingData !== undefined && existingData !== docData &&
|
||||||
|
existingData.name === docData.name) {
|
||||||
|
// DATA EXISTS FOR USER
|
||||||
|
// BUT DIFF DATA SENT FOR UPDATE
|
||||||
|
await admin.firestore().collection("results").doc(docId).set(docData);
|
||||||
|
delete docData.age;
|
||||||
|
delete docData.name;
|
||||||
|
delete docData.dose;
|
||||||
|
const updateDoc : Record<string, admin.firestore.FieldValue> = {};
|
||||||
|
Object.keys(docData).forEach((symptom : string) => {
|
||||||
|
// IF WAS TRUE, NOW FALSE = -1
|
||||||
|
// IF WAS TRUE, NOW TRUE = 0
|
||||||
|
// IF WAS FALSE, NOW TRUE = +1
|
||||||
|
// IF WAS FALSE, NOW FALSE = 0
|
||||||
|
let incrementValue = 0;
|
||||||
|
if (existingData[symptom] === true && docData[symptom] === false) {
|
||||||
|
incrementValue = -1;
|
||||||
|
} else if (existingData[symptom] === false &&
|
||||||
|
docData[symptom] === true) {
|
||||||
|
incrementValue = 1;
|
||||||
|
}
|
||||||
|
if (data.dose) {
|
||||||
|
updateDoc[
|
||||||
|
`${data.dose}.${data.age}.${symptom.replace("/", "OR")}`] =
|
||||||
|
admin.firestore.FieldValue.increment(incrementValue);
|
||||||
|
} else {
|
||||||
|
updateDoc[`${data.age}.${symptom.replace("/", "OR")}`] =
|
||||||
|
admin.firestore.FieldValue.increment(incrementValue);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
admin
|
||||||
|
.firestore()
|
||||||
|
.collection("stats")
|
||||||
|
.doc(data.name)
|
||||||
|
.update(updateDoc);
|
||||||
|
} else if (existingData !== undefined && existingData !== docData &&
|
||||||
|
existingData.name !== docData.name) {
|
||||||
|
// UNDO DATA FOR OLD VAX
|
||||||
|
// DECREMENT VALUES FOR EACH SYMPTOM ON OLD VAX
|
||||||
|
const undoDoc : Record<string, admin.firestore.FieldValue> = {
|
||||||
|
count: admin.firestore.FieldValue.increment(-1),
|
||||||
|
};
|
||||||
|
Object.keys(existingData).forEach((symptom : string) => {
|
||||||
|
if (symptom !== "name" && symptom !== "dose" &&
|
||||||
|
symptom !== "age" ) {
|
||||||
|
if (existingData[symptom] === true) {
|
||||||
|
if (existingData.dose) {
|
||||||
|
undoDoc[
|
||||||
|
`${existingData.dose}.${existingData.age}.${
|
||||||
|
symptom.replace("/", "OR")}`] =
|
||||||
|
admin.firestore.FieldValue.increment(-1);
|
||||||
|
} else {
|
||||||
|
undoDoc[`${existingData.age}.${symptom.replace("/", "OR")}`] =
|
||||||
|
admin.firestore.FieldValue.increment(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
admin
|
||||||
|
.firestore()
|
||||||
|
.collection("stats")
|
||||||
|
.doc(existingData.name)
|
||||||
|
.update(undoDoc);
|
||||||
|
// PROCESS NEW DATA FOR USE
|
||||||
|
// SAVE USER DATA
|
||||||
|
await admin.firestore().collection("results").doc(docId).set(docData);
|
||||||
|
delete docData.age;
|
||||||
|
delete docData.name;
|
||||||
|
delete docData.dose;
|
||||||
|
// INCREMENT TOTAL RESPONSE COUNT
|
||||||
|
const updateDoc : Record<string, admin.firestore.FieldValue> = {
|
||||||
|
count: admin.firestore.FieldValue.increment(1),
|
||||||
|
};
|
||||||
|
// INCREMENT VALUES FOR EACH SYMPTOM
|
||||||
|
Object.keys(docData).forEach((symptom : string) => {
|
||||||
|
if (docData[symptom] === true) {
|
||||||
|
if (data.dose) {
|
||||||
|
updateDoc[
|
||||||
|
`${data.dose}.${data.age}.${symptom.replace("/", "OR")}`] =
|
||||||
|
admin.firestore.FieldValue.increment(1);
|
||||||
|
} else {
|
||||||
|
updateDoc[`${data.age}.${symptom.replace("/", "OR")}`] =
|
||||||
|
admin.firestore.FieldValue.increment(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
admin
|
||||||
|
.firestore()
|
||||||
|
.collection("stats")
|
||||||
|
.doc(data.name)
|
||||||
|
.update(updateDoc);
|
||||||
|
} else if (existingData === undefined) {
|
||||||
|
// DATA DOESN'T EXIST FOR USER
|
||||||
|
// SAVE USER DATA
|
||||||
|
await admin.firestore().collection("results").doc(docId).set(docData);
|
||||||
|
delete docData.age;
|
||||||
|
delete docData.name;
|
||||||
|
delete docData.dose;
|
||||||
|
// INCREMENT TOTAL RESPONSE COUNT
|
||||||
|
const updateDoc : Record<string, admin.firestore.FieldValue> = {
|
||||||
|
count: admin.firestore.FieldValue.increment(1),
|
||||||
|
};
|
||||||
|
// INCREMENT VALUES FOR EACH SYMPTOM
|
||||||
|
Object.keys(docData).forEach((symptom : string) => {
|
||||||
|
if (docData[symptom] === true) {
|
||||||
|
if (data.dose) {
|
||||||
|
updateDoc[
|
||||||
|
`${data.dose}.${data.age}.${symptom.replace("/", "OR")}`] =
|
||||||
|
admin.firestore.FieldValue.increment(1);
|
||||||
|
} else {
|
||||||
|
updateDoc[`${data.age}.${symptom.replace("/", "OR")}`] =
|
||||||
|
admin.firestore.FieldValue.increment(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
admin
|
||||||
|
.firestore()
|
||||||
|
.collection("stats")
|
||||||
|
.doc(data.name)
|
||||||
|
.update(updateDoc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export const getPastResult = functions.https.onCall(async (data, context) => {
|
||||||
|
if (!!data && !!context) {
|
||||||
|
const {gid} = data;
|
||||||
|
const existingData : admin.firestore.DocumentData | undefined = await admin
|
||||||
|
.firestore()
|
||||||
|
.collection("results")
|
||||||
|
.doc(serializeGaId(gid))
|
||||||
|
.get()
|
||||||
|
.then((doc) => doc.data());
|
||||||
|
if (existingData) {
|
||||||
|
if (existingData["NAUSEA / VOMITING"]) {
|
||||||
|
existingData["NAUSEA OR VOMITING"] =
|
||||||
|
existingData["NAUSEA / VOMITING"];
|
||||||
|
}
|
||||||
|
return existingData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
});
|
||||||
|
|||||||
@@ -0,0 +1,186 @@
|
|||||||
|
|
||||||
|
const admin = require("firebase-admin");
|
||||||
|
const firebaseSecret = require("./firebaseSecret.json");
|
||||||
|
|
||||||
|
|
||||||
|
admin.initializeApp({
|
||||||
|
credential: admin.credential.cert(firebaseSecret),
|
||||||
|
});
|
||||||
|
|
||||||
|
const VAX_NAMES = {
|
||||||
|
PB: "Pfizer-BioNTech",
|
||||||
|
MD: "Moderna",
|
||||||
|
JJ: "J&J Janssen",
|
||||||
|
};
|
||||||
|
|
||||||
|
const VAX_DOSES = {
|
||||||
|
ONE: "Dose 1",
|
||||||
|
TWO: "Dose 2",
|
||||||
|
};
|
||||||
|
|
||||||
|
const VAX_AGES = {
|
||||||
|
"Pfizer-BioNTech": {
|
||||||
|
YOUNGER: "18 - 55",
|
||||||
|
OLDER: "56 & Older",
|
||||||
|
},
|
||||||
|
"Moderna": {
|
||||||
|
YOUNGER: "18 - 64",
|
||||||
|
OLDER: "65 & Older",
|
||||||
|
},
|
||||||
|
"J&J Janssen": {
|
||||||
|
YOUNGER: "18 - 59",
|
||||||
|
OLDER: "60 & Older",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// PFIZER COUNTS
|
||||||
|
admin.firestore().collection("results")
|
||||||
|
.where("name", "==", VAX_NAMES.PB)
|
||||||
|
.where("dose", "in", [VAX_DOSES.ONE, VAX_DOSES.TWO])
|
||||||
|
.where("age", "==", VAX_AGES[VAX_NAMES.PB].YOUNGER)
|
||||||
|
.get()
|
||||||
|
.then((docs) => {
|
||||||
|
console.log("PB_ONE_YOUNGER", docs.docs.length);
|
||||||
|
admin.firestore()
|
||||||
|
.collection("stats")
|
||||||
|
.doc(VAX_NAMES.PB)
|
||||||
|
.update({
|
||||||
|
[`${VAX_DOSES.ONE}.${VAX_AGES[VAX_NAMES.PB].YOUNGER}.count`]:
|
||||||
|
docs.docs.length,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
admin.firestore().collection("results")
|
||||||
|
.where("name", "==", VAX_NAMES.PB)
|
||||||
|
.where("dose", "==", VAX_DOSES.TWO)
|
||||||
|
.where("age", "==", VAX_AGES[VAX_NAMES.PB].YOUNGER)
|
||||||
|
.get()
|
||||||
|
.then((docs) => {
|
||||||
|
console.log("PB_TWO_YOUNGER", docs.docs.length);
|
||||||
|
admin.firestore()
|
||||||
|
.collection("stats")
|
||||||
|
.doc(VAX_NAMES.PB)
|
||||||
|
.update({
|
||||||
|
[`${VAX_DOSES.TWO}.${VAX_AGES[VAX_NAMES.PB].YOUNGER}.count`]:
|
||||||
|
docs.docs.length,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
admin.firestore().collection("results")
|
||||||
|
.where("name", "==", VAX_NAMES.PB)
|
||||||
|
.where("dose", "in", [VAX_DOSES.ONE, VAX_DOSES.TWO])
|
||||||
|
.where("age", "==", VAX_AGES[VAX_NAMES.PB].OLDER)
|
||||||
|
.get()
|
||||||
|
.then((docs) => {
|
||||||
|
console.log("PB_ONE_OLDER", docs.docs.length);
|
||||||
|
admin.firestore()
|
||||||
|
.collection("stats")
|
||||||
|
.doc(VAX_NAMES.PB)
|
||||||
|
.update({
|
||||||
|
[`${VAX_DOSES.ONE}.${VAX_AGES[VAX_NAMES.PB].OLDER}.count`]:
|
||||||
|
docs.docs.length,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
admin.firestore().collection("results")
|
||||||
|
.where("name", "==", VAX_NAMES.PB)
|
||||||
|
.where("dose", "==", VAX_DOSES.TWO)
|
||||||
|
.where("age", "==", VAX_AGES[VAX_NAMES.PB].OLDER)
|
||||||
|
.get()
|
||||||
|
.then((docs) => {
|
||||||
|
console.log("PB_TWO_OLDER", docs.docs.length);
|
||||||
|
admin.firestore()
|
||||||
|
.collection("stats")
|
||||||
|
.doc(VAX_NAMES.PB)
|
||||||
|
.update({
|
||||||
|
[`${VAX_DOSES.TWO}.${VAX_AGES[VAX_NAMES.PB].OLDER}.count`]:
|
||||||
|
docs.docs.length,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// MODERNA COUNTS
|
||||||
|
admin.firestore().collection("results")
|
||||||
|
.where("name", "==", VAX_NAMES.MD)
|
||||||
|
.where("dose", "in", [VAX_DOSES.ONE, VAX_DOSES.TWO])
|
||||||
|
.where("age", "==", VAX_AGES[VAX_NAMES.MD].YOUNGER)
|
||||||
|
.get()
|
||||||
|
.then((docs) => {
|
||||||
|
console.log("MD_ONE_YOUNGER", docs.docs.length);
|
||||||
|
admin.firestore()
|
||||||
|
.collection("stats")
|
||||||
|
.doc(VAX_NAMES.MD)
|
||||||
|
.update({
|
||||||
|
[`${VAX_DOSES.ONE}.${VAX_AGES[VAX_NAMES.MD].YOUNGER}.count`]:
|
||||||
|
docs.docs.length,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
admin.firestore().collection("results")
|
||||||
|
.where("name", "==", VAX_NAMES.MD)
|
||||||
|
.where("dose", "==", VAX_DOSES.TWO)
|
||||||
|
.where("age", "==", VAX_AGES[VAX_NAMES.MD].YOUNGER)
|
||||||
|
.get()
|
||||||
|
.then((docs) => {
|
||||||
|
console.log("MD_TWO_YOUNGER", docs.docs.length);
|
||||||
|
admin.firestore()
|
||||||
|
.collection("stats")
|
||||||
|
.doc(VAX_NAMES.MD)
|
||||||
|
.update({
|
||||||
|
[`${VAX_DOSES.TWO}.${VAX_AGES[VAX_NAMES.MD].YOUNGER}.count`]:
|
||||||
|
docs.docs.length,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
admin.firestore().collection("results")
|
||||||
|
.where("name", "==", VAX_NAMES.MD)
|
||||||
|
.where("dose", "in", [VAX_DOSES.ONE, VAX_DOSES.TWO])
|
||||||
|
.where("age", "==", VAX_AGES[VAX_NAMES.MD].OLDER)
|
||||||
|
.get()
|
||||||
|
.then((docs) => {
|
||||||
|
console.log("MD_ONE_OLDER", docs.docs.length);
|
||||||
|
admin.firestore()
|
||||||
|
.collection("stats")
|
||||||
|
.doc(VAX_NAMES.MD)
|
||||||
|
.update({
|
||||||
|
[`${VAX_DOSES.ONE}.${VAX_AGES[VAX_NAMES.MD].OLDER}.count`]:
|
||||||
|
docs.docs.length,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
admin.firestore().collection("results")
|
||||||
|
.where("name", "==", VAX_NAMES.MD)
|
||||||
|
.where("dose", "==", VAX_DOSES.TWO)
|
||||||
|
.where("age", "==", VAX_AGES[VAX_NAMES.MD].OLDER)
|
||||||
|
.get()
|
||||||
|
.then((docs) => {
|
||||||
|
console.log("MD_TWO_OLDER", docs.docs.length);
|
||||||
|
admin.firestore()
|
||||||
|
.collection("stats")
|
||||||
|
.doc(VAX_NAMES.MD)
|
||||||
|
.update({
|
||||||
|
[`${VAX_DOSES.TWO}.${VAX_AGES[VAX_NAMES.MD].OLDER}.count`]:
|
||||||
|
docs.docs.length,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// J&J COUNTS
|
||||||
|
admin.firestore().collection("results")
|
||||||
|
.where("name", "==", VAX_NAMES.JJ)
|
||||||
|
.where("age", "==", VAX_AGES[VAX_NAMES.JJ].YOUNGER)
|
||||||
|
.get()
|
||||||
|
.then((docs) => {
|
||||||
|
console.log("JJ_YOUNGER", docs.docs.length);
|
||||||
|
admin.firestore()
|
||||||
|
.collection("stats")
|
||||||
|
.doc(VAX_NAMES.JJ)
|
||||||
|
.update({
|
||||||
|
[`${VAX_AGES[VAX_NAMES.JJ].YOUNGER}.count`]:
|
||||||
|
docs.docs.length,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
admin.firestore().collection("results")
|
||||||
|
.where("name", "==", VAX_NAMES.JJ)
|
||||||
|
.where("age", "==", VAX_AGES[VAX_NAMES.JJ].OLDER)
|
||||||
|
.get()
|
||||||
|
.then((docs) => {
|
||||||
|
console.log("JJ_OLDER", docs.docs.length);
|
||||||
|
admin.firestore()
|
||||||
|
.collection("stats")
|
||||||
|
.doc(VAX_NAMES.JJ)
|
||||||
|
.update({
|
||||||
|
[`${VAX_AGES[VAX_NAMES.JJ].OLDER}.count`]:
|
||||||
|
docs.docs.length,
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -392,6 +392,37 @@ footer .by {
|
|||||||
animation: 2s ease-out 0s infinite loading;
|
animation: 2s ease-out 0s infinite loading;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.result-header-contianer {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
margin-top: 5rem;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-header-contianer .symptom-container {
|
||||||
|
margin-top: 0;
|
||||||
|
flex: 1;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-header-select {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-header-select .overline {
|
||||||
|
font-size: 1.6rem;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-header-select select {
|
||||||
|
background-color: var(--color-tertiary);
|
||||||
|
border-radius: 1rem;
|
||||||
|
padding: 1rem 2rem;
|
||||||
|
outline: none;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
@media (hover: hover) and (pointer: fine) {
|
@media (hover: hover) and (pointer: fine) {
|
||||||
.answer:hover,
|
.answer:hover,
|
||||||
.answer.unselected:hover {
|
.answer.unselected:hover {
|
||||||
|
|||||||
@@ -107,3 +107,23 @@ footer {
|
|||||||
.tip-container {
|
.tip-container {
|
||||||
width: fit-content;
|
width: fit-content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.result-header-contianer {
|
||||||
|
margin-bottom: 0;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-header-contianer .symptom-container {
|
||||||
|
width: fit-content;
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-header-select {
|
||||||
|
width: fit-content;
|
||||||
|
padding-left: 3rem;
|
||||||
|
border-left: 1px solid var(--color-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.result-header-select select {
|
||||||
|
width: fit-content;
|
||||||
|
}
|
||||||
|
|||||||
+178
-122
@@ -18,9 +18,9 @@ if (window.location.host.startsWith("localhost")) {
|
|||||||
firebase.functions().useEmulator("localhost", 5001);
|
firebase.functions().useEmulator("localhost", 5001);
|
||||||
}
|
}
|
||||||
const fb_functions = firebase.functions();
|
const fb_functions = firebase.functions();
|
||||||
const saveResult = fb_functions.httpsCallable("saveResult");
|
const saveResult = fb_functions.httpsCallable("saveResultV1");
|
||||||
const getPastResult = fb_functions.httpsCallable("getPastResult");
|
const getPastResult = fb_functions.httpsCallable("getPastResultV1");
|
||||||
const getStats = fb_functions.httpsCallable("getStats");
|
const getStats = fb_functions.httpsCallable("getStatsV1");
|
||||||
|
|
||||||
const VAX_NAMES = {
|
const VAX_NAMES = {
|
||||||
PB: "Pfizer-BioNTech",
|
PB: "Pfizer-BioNTech",
|
||||||
@@ -61,7 +61,7 @@ const VAX_EFFICACY = {
|
|||||||
"18 - 59": 66.1,
|
"18 - 59": 66.1,
|
||||||
"60 & Older": 66.2,
|
"60 & Older": 66.2,
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
|
|
||||||
const PB_DOSE1_YOUNGER_RESULT = {
|
const PB_DOSE1_YOUNGER_RESULT = {
|
||||||
"PAIN AT SITE": 1904,
|
"PAIN AT SITE": 1904,
|
||||||
@@ -69,7 +69,7 @@ const PB_DOSE1_YOUNGER_RESULT = {
|
|||||||
"SWELLING AT SITE": 132,
|
"SWELLING AT SITE": 132,
|
||||||
FATIGUE: 1085,
|
FATIGUE: 1085,
|
||||||
HEADACHE: 959,
|
HEADACHE: 959,
|
||||||
"NEED PAIN MED":638,
|
"NEED PAIN MED": 638,
|
||||||
"MUSCLE PAIN": 487,
|
"MUSCLE PAIN": 487,
|
||||||
CHILLS: 321,
|
CHILLS: 321,
|
||||||
DIARRHEA: 255,
|
DIARRHEA: 255,
|
||||||
@@ -120,74 +120,74 @@ const PB_DOSE2_OLDER_RESULT = {
|
|||||||
VOMITING: 11,
|
VOMITING: 11,
|
||||||
};
|
};
|
||||||
const MD_DOSE1_YOUNGER_RESULT = {
|
const MD_DOSE1_YOUNGER_RESULT = {
|
||||||
"PAIN AT SITE": "9",
|
"PAIN AT SITE": 9908,
|
||||||
"RED AT SITE": "<1",
|
"RED AT SITE": 344,
|
||||||
"SWELLING AT SITE": "<1",
|
"SWELLING AT SITE": 2089,
|
||||||
HEADACHE: "4",
|
HEADACHE: 4030,
|
||||||
FATIGUE: "4",
|
FATIGUE: 4384,
|
||||||
"MUSCLE PAIN": "2",
|
"MUSCLE PAIN": 2699,
|
||||||
"JOINT PAIN": "2",
|
"JOINT PAIN": 1893,
|
||||||
"NAUSEA OR VOMITING": "1",
|
"NAUSEA OR VOMITING": 1068,
|
||||||
FEVER: "1",
|
FEVER: 105,
|
||||||
CHILLS: "1",
|
CHILLS: 1051,
|
||||||
};
|
};
|
||||||
const MD_DOSE2_YOUNGER_RESULT = {
|
const MD_DOSE2_YOUNGER_RESULT = {
|
||||||
"PAIN AT SITE": "9",
|
"PAIN AT SITE": 9873,
|
||||||
"RED AT SITE": "1",
|
"RED AT SITE": 982,
|
||||||
"SWELLING AT SITE": "1",
|
"SWELLING AT SITE": 3164,
|
||||||
FATIGUE: "7",
|
FATIGUE: 7430,
|
||||||
HEADACHE: "6",
|
HEADACHE: 6898,
|
||||||
"JOINT PAIN": "5",
|
"JOINT PAIN": 4993,
|
||||||
CHILLS: "5",
|
CHILLS: 5341,
|
||||||
FEVER: "2",
|
FEVER: 1908,
|
||||||
"NAUSEA OR VOMITING": "2",
|
"NAUSEA OR VOMITING": 2348,
|
||||||
"MUSCLE PAIN": "1",
|
"MUSCLE PAIN": 6769,
|
||||||
};
|
};
|
||||||
const MD_DOSE1_OLDER_RESULT = {
|
const MD_DOSE1_OLDER_RESULT = {
|
||||||
"PAIN AT SITE": "7",
|
"PAIN AT SITE": 2782,
|
||||||
"RED AT SITE": "<1",
|
"RED AT SITE": 86,
|
||||||
"SWELLING AT SITE": "<1",
|
"SWELLING AT SITE": 396,
|
||||||
HEADACHE: "3",
|
HEADACHE: 921,
|
||||||
FATIGUE: "3",
|
FATIGUE: 1251,
|
||||||
"MUSCLE PAIN": "2",
|
"MUSCLE PAIN": 742,
|
||||||
"JOINT PAIN": "2",
|
"JOINT PAIN": 618,
|
||||||
"NAUSEA OR VOMITING": "1",
|
"NAUSEA OR VOMITING": 194,
|
||||||
CHILLS: "1",
|
CHILLS: 202,
|
||||||
FEVER: "<1",
|
FEVER: 10,
|
||||||
};
|
};
|
||||||
const MD_DOSE2_OLDER_RESULT = {
|
const MD_DOSE2_OLDER_RESULT = {
|
||||||
"PAIN AT SITE": "8",
|
"PAIN AT SITE": 3070,
|
||||||
"RED AT SITE": "1",
|
"RED AT SITE": 275,
|
||||||
"SWELLING AT SITE": "1",
|
"SWELLING AT SITE": 715,
|
||||||
FATIGUE: "6",
|
FATIGUE: 2152,
|
||||||
HEADACHE: "5",
|
HEADACHE: 1704,
|
||||||
"MUSCLE PAIN": "5",
|
"MUSCLE PAIN": 1739,
|
||||||
"JOINT PAIN": "4",
|
"JOINT PAIN": 1291,
|
||||||
CHILLS: "3",
|
CHILLS: 1141,
|
||||||
"NAUSEA OR VOMITING": "1",
|
"NAUSEA OR VOMITING": 437,
|
||||||
FEVER: "1",
|
FEVER: 370,
|
||||||
};
|
};
|
||||||
const JJ_YOUNGER_RESULT = {
|
const JJ_YOUNGER_RESULT = {
|
||||||
"PAIN AT SITE": "6",
|
"PAIN AT SITE": 1193,
|
||||||
"RED AT SITE": "1",
|
"RED AT SITE": 184,
|
||||||
"SWELLING AT SITE": "1",
|
"SWELLING AT SITE": 142,
|
||||||
HEADACHE: "4",
|
HEADACHE: 905,
|
||||||
FATIGUE: "4",
|
FATIGUE: 891,
|
||||||
"MUSCLE PAIN": "4",
|
"MUSCLE PAIN": 796,
|
||||||
"NEED PAIN MED": "3",
|
"NEED PAIN MED": 538,
|
||||||
"NAUSEA OR VOMITING": "2",
|
"NAUSEA OR VOMITING": 315,
|
||||||
FEVER: "1",
|
FEVER: 261,
|
||||||
};
|
};
|
||||||
const JJ_OLDER_RESULT = {
|
const JJ_OLDER_RESULT = {
|
||||||
"PAIN AT SITE": "3",
|
"PAIN AT SITE": 439,
|
||||||
"RED AT SITE": "<1",
|
"RED AT SITE": 61,
|
||||||
"SWELLING AT SITE": "<1",
|
"SWELLING AT SITE": 36,
|
||||||
HEADACHE: "3",
|
HEADACHE: 401,
|
||||||
FATIGUE: "3",
|
FATIGUE: 392,
|
||||||
"MUSCLE PAIN": "2",
|
"MUSCLE PAIN": 317,
|
||||||
"NAUSEA OR VOMITING": "1",
|
"NAUSEA OR VOMITING": 162,
|
||||||
"NEED PAIN MED": "1",
|
"NEED PAIN MED": 130,
|
||||||
FEVER: "<1",
|
FEVER: 41,
|
||||||
};
|
};
|
||||||
|
|
||||||
const VAX_COUNTS = {
|
const VAX_COUNTS = {
|
||||||
@@ -203,17 +203,17 @@ const VAX_COUNTS = {
|
|||||||
},
|
},
|
||||||
Moderna: {
|
Moderna: {
|
||||||
"Dose 1": {
|
"Dose 1": {
|
||||||
"18 - 64": 1,
|
"18 - 64": 11406,
|
||||||
"65 & Older": 1,
|
"65 & Older": 3762,
|
||||||
},
|
},
|
||||||
"Dose 2": {
|
"Dose 2": {
|
||||||
"18 - 64": 1,
|
"18 - 64": 10985,
|
||||||
"65 & Older": 1,
|
"65 & Older": 3692,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"J&J Janssen": {
|
"J&J Janssen": {
|
||||||
"18 - 59": 1,
|
"18 - 59": 2036,
|
||||||
"60 & Older": 1,
|
"60 & Older": 1320,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -260,6 +260,12 @@ const ICONS = {
|
|||||||
"NAUSEA OR VOMITING": "🤮",
|
"NAUSEA OR VOMITING": "🤮",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const DATA_CHOICES = {
|
||||||
|
VNM: "Vax&Me Only",
|
||||||
|
VNM_FDA: "Vax&Me + FDA",
|
||||||
|
FDA: "FDA Only",
|
||||||
|
};
|
||||||
|
|
||||||
class App extends React.Component {
|
class App extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
@@ -270,9 +276,10 @@ class App extends React.Component {
|
|||||||
gid: "",
|
gid: "",
|
||||||
showInputPopup: false,
|
showInputPopup: false,
|
||||||
answers: {},
|
answers: {},
|
||||||
fetchedResult : {},
|
fetchedResult: {},
|
||||||
stats: {},
|
stats: {},
|
||||||
loading: true,
|
loading: true,
|
||||||
|
dataSource: DATA_CHOICES.FDA,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
@@ -321,7 +328,15 @@ class App extends React.Component {
|
|||||||
const { data } = v;
|
const { data } = v;
|
||||||
if (!!data) {
|
if (!!data) {
|
||||||
const { name, age, dose } = data;
|
const { name, age, dose } = data;
|
||||||
this.setState({ name, age, dose, showInputPopup: true, fetchedResult: data, answers: data, loading: false });
|
this.setState({
|
||||||
|
name,
|
||||||
|
age,
|
||||||
|
dose,
|
||||||
|
showInputPopup: true,
|
||||||
|
fetchedResult: data,
|
||||||
|
answers: data,
|
||||||
|
loading: false,
|
||||||
|
});
|
||||||
const inputPopupSubmit = document.querySelector(
|
const inputPopupSubmit = document.querySelector(
|
||||||
".input-popup-submit"
|
".input-popup-submit"
|
||||||
);
|
);
|
||||||
@@ -344,7 +359,7 @@ class App extends React.Component {
|
|||||||
this.setState({ loading: false });
|
this.setState({ loading: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
getStats().then(v => this.setState({ stats: v.data }));
|
getStats().then((v) => this.setState({ stats: v.data }));
|
||||||
}
|
}
|
||||||
shouldShowDoses = () => {
|
shouldShowDoses = () => {
|
||||||
const { name } = this.state;
|
const { name } = this.state;
|
||||||
@@ -449,7 +464,7 @@ class App extends React.Component {
|
|||||||
delete answers.name;
|
delete answers.name;
|
||||||
delete answers.dose;
|
delete answers.dose;
|
||||||
delete answers.age;
|
delete answers.age;
|
||||||
if(!!dose) {
|
if (!!dose) {
|
||||||
symptoms[VAX_DOSES.ONE] = {};
|
symptoms[VAX_DOSES.ONE] = {};
|
||||||
symptoms[VAX_DOSES.TWO] = {};
|
symptoms[VAX_DOSES.TWO] = {};
|
||||||
Object.keys(VAX_DOSES).forEach((dose) => {
|
Object.keys(VAX_DOSES).forEach((dose) => {
|
||||||
@@ -477,7 +492,7 @@ class App extends React.Component {
|
|||||||
saveResult(submitAnswers)
|
saveResult(submitAnswers)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
delete submitAnswers.gid;
|
delete submitAnswers.gid;
|
||||||
this.setState({ fetchedResult : submitAnswers });
|
this.setState({ fetchedResult: submitAnswers });
|
||||||
const inputPopupSubmit = document.querySelector(".input-popup-submit");
|
const inputPopupSubmit = document.querySelector(".input-popup-submit");
|
||||||
if (inputPopupSubmit.classList.contains("errored")) {
|
if (inputPopupSubmit.classList.contains("errored")) {
|
||||||
inputPopupSubmit.classList.remove("errored");
|
inputPopupSubmit.classList.remove("errored");
|
||||||
@@ -508,39 +523,51 @@ class App extends React.Component {
|
|||||||
getAnswerOptions = (answerDose) => {
|
getAnswerOptions = (answerDose) => {
|
||||||
const { answers, dose } = this.state;
|
const { answers, dose } = this.state;
|
||||||
const result = this.getResults();
|
const result = this.getResults();
|
||||||
return <div className="question-container" key={`answer-dose-${answerDose}`}>
|
return (
|
||||||
{!!answerDose ? (
|
<div className="question-container" key={`answer-dose-${answerDose}`}>
|
||||||
<h6 className="overline" data-font="sans">
|
{!!answerDose ? (
|
||||||
{answerDose}
|
<h6 className="overline" data-font="sans">
|
||||||
</h6>
|
{answerDose}
|
||||||
) : null}
|
</h6>
|
||||||
<p className="question" data-font="sans-italic">
|
) : null}
|
||||||
{ ((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 className="question" data-font="sans-italic">
|
||||||
</p>
|
{dose === VAX_DOSES.ONE && answerDose === VAX_DOSES.TWO
|
||||||
<div className="answers-container">
|
? "(You can comeback later to tell us about Dose 2)"
|
||||||
{Object.keys(result).map((symptom) => (
|
: "(Select all side effects that you experienced)"}
|
||||||
<button
|
</p>
|
||||||
key={`ans-${answerDose}-${symptom}`}
|
<div className="answers-container">
|
||||||
data-font="sans-bold"
|
{Object.keys(result).map((symptom) => (
|
||||||
className={`answer${
|
<button
|
||||||
!!answerDose
|
key={`ans-${answerDose}-${symptom}`}
|
||||||
? (answers[answerDose] && answers[answerDose][symptom])
|
data-font="sans-bold"
|
||||||
|
className={`answer${
|
||||||
|
!!answerDose
|
||||||
|
? answers[answerDose] && answers[answerDose][symptom]
|
||||||
|
? " selected"
|
||||||
|
: ""
|
||||||
|
: answers[symptom]
|
||||||
? " selected"
|
? " selected"
|
||||||
: ""
|
: ""
|
||||||
: answers[symptom]
|
}`}
|
||||||
? " selected"
|
onClick={() => this.updateAnswers(symptom, answerDose)}
|
||||||
: ""
|
>
|
||||||
}`}
|
{symptom}
|
||||||
onClick={() => this.updateAnswers(symptom, answerDose)}
|
</button>
|
||||||
>
|
))}
|
||||||
{symptom}
|
</div>
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
</div>;
|
);
|
||||||
};
|
};
|
||||||
render() {
|
render() {
|
||||||
const { name, dose, age, showInputPopup, loading, fetchedResult } = this.state;
|
const {
|
||||||
|
name,
|
||||||
|
dose,
|
||||||
|
age,
|
||||||
|
showInputPopup,
|
||||||
|
loading,
|
||||||
|
fetchedResult,
|
||||||
|
dataSource,
|
||||||
|
} = this.state;
|
||||||
let result = {};
|
let result = {};
|
||||||
let resultAtSite = {};
|
let resultAtSite = {};
|
||||||
if (this.shouldShowResults()) {
|
if (this.shouldShowResults()) {
|
||||||
@@ -663,20 +690,37 @@ class App extends React.Component {
|
|||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{this.shouldShowResults() ? (
|
{this.shouldShowResults() ? (
|
||||||
<div className="symptom-container subheader">
|
<div className="result-header-contianer">
|
||||||
<h3 data-font="sans-bold">Here's what to expect.</h3>
|
<div className="symptom-container subheader">
|
||||||
<h6
|
<h3 data-font="sans-bold">Here's what to expect.</h3>
|
||||||
id="share-result"
|
<h6
|
||||||
onClick={this.copyShareLink}
|
id="share-result"
|
||||||
className="overline"
|
onClick={this.copyShareLink}
|
||||||
data-font="sans"
|
className="overline"
|
||||||
data-button
|
data-font="sans"
|
||||||
>
|
data-button
|
||||||
Share ↗
|
>
|
||||||
</h6>
|
Share ↗
|
||||||
<h6 className="overline" data-font="sans" data-button>
|
</h6>
|
||||||
<a href="/vaxandme_chart.pdf">Download Chart ↗</a>
|
<h6 className="overline" data-font="sans" data-button>
|
||||||
</h6>
|
<a href="/vaxandme_chart.pdf">Download Chart ↗</a>
|
||||||
|
</h6>
|
||||||
|
</div>
|
||||||
|
<div className="result-header-select">
|
||||||
|
<h6 className="overline" data-font="sans-italic">
|
||||||
|
Use data from:
|
||||||
|
</h6>
|
||||||
|
<select
|
||||||
|
onChange={(e) =>
|
||||||
|
this.setState({ dataSource: e.target.value })
|
||||||
|
}
|
||||||
|
value={dataSource}
|
||||||
|
>
|
||||||
|
{Object.keys(DATA_CHOICES).map((dataKey) => (
|
||||||
|
<option key={dataKey}>{DATA_CHOICES[dataKey]}</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
@@ -684,7 +728,11 @@ class App extends React.Component {
|
|||||||
<div className="tip-container">
|
<div className="tip-container">
|
||||||
<div className="tip-icon">ⓘ</div>
|
<div className="tip-icon">ⓘ</div>
|
||||||
<div className="tip">
|
<div className="tip">
|
||||||
<h6 style={{marginBottom: '1.2rem'}} className="overline" data-font="sans">
|
<h6
|
||||||
|
style={{ marginBottom: "1.2rem" }}
|
||||||
|
className="overline"
|
||||||
|
data-font="sans"
|
||||||
|
>
|
||||||
NET EFFICACY
|
NET EFFICACY
|
||||||
</h6>
|
</h6>
|
||||||
<h6 className="overline" data-font="sans-italic">
|
<h6 className="overline" data-font="sans-italic">
|
||||||
@@ -698,8 +746,7 @@ class App extends React.Component {
|
|||||||
</h6>
|
</h6>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : null
|
) : null}
|
||||||
}
|
|
||||||
|
|
||||||
{this.shouldShowResults() ? (
|
{this.shouldShowResults() ? (
|
||||||
<div className="symptom-container">
|
<div className="symptom-container">
|
||||||
@@ -710,7 +757,12 @@ class App extends React.Component {
|
|||||||
{symptom}
|
{symptom}
|
||||||
</p>
|
</p>
|
||||||
<p data-font="sans-bold" className="symptom-chance">
|
<p data-font="sans-bold" className="symptom-chance">
|
||||||
{resultAtSite[symptom]}/10
|
{Math.ceil(
|
||||||
|
(!!dose
|
||||||
|
? resultAtSite[symptom] / VAX_COUNTS[name][dose][age]
|
||||||
|
: resultAtSite[symptom] / VAX_COUNTS[name][age]) * 10
|
||||||
|
)}
|
||||||
|
/10
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
@@ -721,13 +773,17 @@ class App extends React.Component {
|
|||||||
{symptom}
|
{symptom}
|
||||||
</p>
|
</p>
|
||||||
<p data-font="sans-bold" className="symptom-chance">
|
<p data-font="sans-bold" className="symptom-chance">
|
||||||
{result[symptom]}/10
|
{Math.ceil(
|
||||||
|
(!!dose
|
||||||
|
? result[symptom] / VAX_COUNTS[name][dose][age]
|
||||||
|
: result[symptom] / VAX_COUNTS[name][age]) * 10
|
||||||
|
)}
|
||||||
|
/10
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
{this.shouldShowResults() ? (
|
{this.shouldShowResults() ? (
|
||||||
<div className={`input-popup${showInputPopup ? " expanded" : ""}`}>
|
<div className={`input-popup${showInputPopup ? " expanded" : ""}`}>
|
||||||
|
|||||||
Reference in New Issue
Block a user