Compare commits

..
3 Commits
Author SHA1 Message Date
ayushya 47319c270c Archive 2024-02-27 23:10:08 -05:00
Ayushya Amitabh 365f8bb6e6 wget fetch all sources 2024-02-10 18:37:47 -05:00
Ayushya Amitabh 4705cd6626 archive 2024-02-10 18:26:14 -05:00
43 changed files with 2217 additions and 22622 deletions
Vendored
BIN
View File
Binary file not shown.
-5
View File
@@ -1,5 +0,0 @@
{
"projects": {
"default": "vaxandme"
}
}
-28
View File
@@ -1,28 +0,0 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
*/node_modules
/.pnp
.pnp.js
.firebase
# testing
/coverage
# production
*/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
*.cache
*.log
functions/lib/
functions/src/backup.json
+159 -159
View File
@@ -1,159 +1,159 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Learn about the expected side effects of COVID-19 Vaccines"
/>
<link rel="apple-touch-icon" href="/logo192.png" />
<link rel="manifest" href="/manifest.json" />
<style>
@import "/styles/variables.css";
@import "/styles/variables-dark.css" screen and
(prefers-color-scheme: dark);
@import "/styles/extrasmall.css";
@import "/styles/small.css" only screen and (min-width: 370px) and
(max-width: 767px);
@import "/styles/smallmedium.css" only screen and (min-width: 768px) and
(max-width: 1023px);
@import "/styles/medium.css" only screen and (min-width: 1024px);
@import "/styles/large.css" only screen and (min-width: 1366px);
@import "/styles/extralarge.css" only screen and (min-width: 1921px);
@font-face {
font-family: "GlacialBold";
src: url("/fonts/glacialindifference-bold-webfont.woff2")
format("woff2"),
url("/fonts/glacialindifference-bold-webfont.woff") format("woff");
font-weight: normal;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "GlacialItalic";
src: url("/fonts/glacialindifference-italic-webfont.woff2")
format("woff2"),
url("/fonts/glacialindifference-italic-webfont.woff") format("woff");
font-weight: normal;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "Glacial";
src: url("/fonts/glacialindifference-regular-webfont.woff2")
format("woff2"),
url("/fonts/glacialindifference-regular-webfont.woff") format("woff");
font-weight: normal;
font-style: normal;
font-display: swap;
}
[data-font="sans"] {
font-family: "Glacial", sans-serif;
font-display: swap;
}
[data-font="sans-bold"] {
font-family: "GlacialBold", sans-serif;
font-display: swap;
}
[data-font="sans-italic"] {
font-family: "GlacialItalic", sans-serif;
font-style: italic;
font-display: swap;
}
</style>
<title>Vax & Me | Copyright</title>
</head>
<body>
<div id="root">
<div class="app-container">
<header>
<div class="logo-container">
<div class="logo"></div>
<div class="logo-text-container">
<p data-font="sans-bold">COPYRIGHT</p>
</div>
</div>
</header>
<main>
<div class="intro">
<h3 class="subheader" data-font="sans-bold">© 2021</h3>
<h6 style="display: inline-block;" class="overline" data-font="sans">
Alba Rajanibala
</h6>
<h6 style="display: inline-block;" class="overline" data-font="sans"> &amp; Ayushya Amitabh
</h6>
</div>
<div class="question-container">
<p class="overline" data-font="sans">
Unauthorized copying of this website via any medium is strictly
prohibited. Designed and developed by Alba Rajanibala and Ayushya
Amitabh.
</p>
</div>
<div class="question-container">
<p class="overline" data-font="sans">
All content on this website, unless otherwise cited is the
intellectual property of Alba Rajanibala and Ayushya Amitabh, and
may not be copied, edited, or reproduced without permission.
</p>
</div>
<div class="question-container">
<p class="overline" data-font="sans-italic">
Data shown is based on FDA clinical trials.
</p>
<div class="answers-container">
<a
style="display: block"
class="question"
data-font="sans-italic"
href="https://www.fda.gov/media/144416/download"
>PFizer-BioNTech</a
>
<a
style="display: block"
class="question"
data-font="sans-italic"
href="https://www.fda.gov/media/144637/download"
>Moderna</a
>
<a
style="display: block"
class="question"
data-font="sans-italic"
href="https://www.fda.gov/media/146304/download"
>J&amp;J Janssen</a
>
</div>
</div>
</main>
</div>
</div>
<footer data-font="sans">
<div class="link-container">
<div>
<h6 class="overline" data-font="sans">FDA Data Sources</h6>
<a href="https://www.fda.gov/media/144416/download">PFizer-BioNTech</a>
<a href="https://www.fda.gov/media/144637/download">Moderna</a>
<a href="https://www.fda.gov/media/146304/download">J&J Janssen</a>
</div>
<div>
<h6 class="overline" data-font="sans">Links</h6>
<a href="/vaxandme_chart.pdf">Download Chart</a>
<a href="/">Home</a>
</div>
<div>
<h6 class="overline" data-font="sans">Legal</h6>
<a href="/copyright">Copyright</a>
<a href="/privacy">Privacy</a>
</div>
</div>
<div class="overline by" data-font="sans">
Designed &amp; Developed with ❤ by Alba Rajanibala and Ayushya Amitabh
</div>
</footer>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Learn about the expected side effects of COVID-19 Vaccines"
/>
<link rel="apple-touch-icon" href="logo192.png" />
<link rel="manifest" href="manifest.json" />
<style>
@import "styles/variables.css";
@import "styles/variables-dark.css" screen and
(prefers-color-scheme: dark);
@import "styles/extrasmall.css";
@import "styles/small.css" only screen and (min-width: 370px) and
(max-width: 767px);
@import "styles/smallmedium.css" only screen and (min-width: 768px) and
(max-width: 1023px);
@import "styles/medium.css" only screen and (min-width: 1024px);
@import "styles/large.css" only screen and (min-width: 1366px);
@import "styles/extralarge.css" only screen and (min-width: 1921px);
@font-face {
font-family: "GlacialBold";
src: url("fonts/glacialindifference-bold-webfont.woff2")
format("woff2"),
url("fonts/glacialindifference-bold-webfont.woff") format("woff");
font-weight: normal;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "GlacialItalic";
src: url("fonts/glacialindifference-italic-webfont.woff2")
format("woff2"),
url("fonts/glacialindifference-italic-webfont.woff") format("woff");
font-weight: normal;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "Glacial";
src: url("fonts/glacialindifference-regular-webfont.woff2")
format("woff2"),
url("fonts/glacialindifference-regular-webfont.woff") format("woff");
font-weight: normal;
font-style: normal;
font-display: swap;
}
[data-font="sans"] {
font-family: "Glacial", sans-serif;
font-display: swap;
}
[data-font="sans-bold"] {
font-family: "GlacialBold", sans-serif;
font-display: swap;
}
[data-font="sans-italic"] {
font-family: "GlacialItalic", sans-serif;
font-style: italic;
font-display: swap;
}
</style>
<title>Vax & Me | Copyright</title>
</head>
<body>
<div id="root">
<div class="app-container">
<header>
<div class="logo-container">
<div class="logo"></div>
<div class="logo-text-container">
<p data-font="sans-bold">COPYRIGHT</p>
</div>
</div>
</header>
<main>
<div class="intro">
<h3 class="subheader" data-font="sans-bold">© 2021</h3>
<h6 style="display: inline-block;" class="overline" data-font="sans">
Alba Rajanibala
</h6>
<h6 style="display: inline-block;" class="overline" data-font="sans"> &amp; Ayushya Amitabh
</h6>
</div>
<div class="question-container">
<p class="overline" data-font="sans">
Unauthorized copying of this website via any medium is strictly
prohibited. Designed and developed by Alba Rajanibala and Ayushya
Amitabh.
</p>
</div>
<div class="question-container">
<p class="overline" data-font="sans">
All content on this website, unless otherwise cited is the
intellectual property of Alba Rajanibala and Ayushya Amitabh, and
may not be copied, edited, or reproduced without permission.
</p>
</div>
<div class="question-container">
<p class="overline" data-font="sans-italic">
Data shown is based on FDA clinical trials.
</p>
<div class="answers-container">
<a
style="display: block"
class="question"
data-font="sans-italic"
href="https://www.fda.gov/media/144416/download"
>PFizer-BioNTech</a
>
<a
style="display: block"
class="question"
data-font="sans-italic"
href="https://www.fda.gov/media/144637/download"
>Moderna</a
>
<a
style="display: block"
class="question"
data-font="sans-italic"
href="https://www.fda.gov/media/146304/download"
>J&amp;J Janssen</a
>
</div>
</div>
</main>
</div>
</div>
<footer data-font="sans">
<div class="link-container">
<div>
<h6 class="overline" data-font="sans">FDA Data Sources</h6>
<a href="https://www.fda.gov/media/144416/download">PFizer-BioNTech</a>
<a href="https://www.fda.gov/media/144637/download">Moderna</a>
<a href="https://www.fda.gov/media/146304/download">J&J Janssen</a>
</div>
<div>
<h6 class="overline" data-font="sans">Links</h6>
<a href="vaxandme_chart.pdf">Download Chart</a>
<a href="index.html">Home</a>
</div>
<div>
<h6 class="overline" data-font="sans">Legal</h6>
<a href="copyright.html">Copyright</a>
<a href="privacy.html">Privacy</a>
</div>
</div>
<div class="overline by" data-font="sans">
Designed &amp; Developed with ❤ by Alba Rajanibala and Ayushya Amitabh
</div>
</footer>
</body>
</html>

Before

Width:  |  Height:  |  Size: 4.2 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

-69
View File
@@ -1,69 +0,0 @@
{
"hosting": {
"public": "website/build",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [
{
"source": "/copyright",
"destination": "/copyright.html"
},
{
"source": "/privacy",
"destination": "/privacy.html"
},
{
"source": "/jj",
"destination": "/index.html"
},
{
"source": "/pb",
"destination": "/index.html"
},
{
"source": "/md",
"destination": "/index.html"
},
{
"source": "/jj/**",
"destination": "/index.html"
},
{
"source": "/pb/**",
"destination": "/index.html"
},
{
"source": "/md/**",
"destination": "/index.html"
},
{
"source": "**",
"destination": "/404.html"
}
]
},
"functions": {
"predeploy": [
"npm --prefix \"$RESOURCE_DIR\" run lint",
"npm --prefix \"$RESOURCE_DIR\" run build"
],
"source": "functions"
},
"emulators": {
"functions": {
"port": 5001
},
"firestore": {
"port": 8080
},
"hosting": {
"port": 5000
},
"ui": {
"enabled": true
}
}
}
-28
View File
@@ -1,28 +0,0 @@
module.exports = {
root: true,
env: {
es6: true,
node: true,
},
extends: [
"eslint:recommended",
"plugin:import/errors",
"plugin:import/warnings",
"plugin:import/typescript",
"google",
"plugin:@typescript-eslint/recommended",
],
parser: "@typescript-eslint/parser",
parserOptions: {
project: ["tsconfig.json", "tsconfig.dev.json"],
sourceType: "module",
tsconfigRootDir: __dirname,
},
ignorePatterns: [
"/lib/**/*", // Ignore built files.
],
plugins: ["@typescript-eslint", "import"],
rules: {
quotes: ["error", "double"],
},
};
-12
View File
@@ -1,12 +0,0 @@
{
"type": "service_account",
"project_id": "vaxandme",
"private_key_id": "878a8ed429f84ef5fb42555a34bd71d53ba612b2",
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDnYRdGS8aHi8aY\nDmcIPlPVN0HSDMjg046n1LmR1f1eRS/28m+C94pP6Pn2WvzRJIGK/8XKXARfAiPD\noVfUaXUAPD0DVbgHMn6/1pvCCF0wwlbXZNsIjDg9vLQiGvnsNcgoDXOhfliqw0ca\nTx3oUdgPCzOzkWw4wGMZaJrNK4w0jwuffNgA746jCG3RX9vo/m+aucerYqPPlSfs\nAjJpmpXXCwdHNx0EnEpGQc3bdnbN53hikEJ+J2xCESqaEmTryi1vXDv+i+YCrZn6\nLD+P1etLvtoU0pKMMCcVLk7VmCPMT8F2RB0L21aFmGLuy8fpBDMIYXtjMp+FbKBf\nAne0zKX1AgMBAAECggEAcn4nQ7gsWZdPYp/B2SDqX9fTgKql3iahcSgA2YrPsM3A\nscx+ZIq0TN2GjyKv9pe/aHYvO/azjQXkh6H3cZrrc/3a3SMWCK2ybaA2+9kisAWC\nblwwTHcCP354jmXV5M4qKLObU77PBlTSAtFChdq19J/A6ircJ+r/Pqv16e+SFdD/\n4ie64DR5Uxj9vUN8WFrfDfapwxwnGLgJCOrS7fecC7xDzi5iLR9mZD1ak2a8B+B6\nwNrzGafVz285B0fVtYbXiEGNElbPBd/hvioK0zsHdYxZYmiaZvyWqABejRk6jW6R\n6OTy7fCk6h7LG23+uh9Ruh8jKEE9nX6g/vYaKOqv0wKBgQD6nKvshaCQD4G5s5gK\nwQFYUFJbmMd547BKtzaFXKzUcldZaL9da4AhINoxu70uCl/nDJmTACEcifU/juiO\nM0XsZ0kufoomW2DyxVKBshBoF/OJoEUngDiCDdJFMUsa6zeiZHVi9uFmTY4c4nf8\nozJxxpcbmQRXEdv9kafBEw83DwKBgQDsWpC/t7QCqCytXWqnkVM5QIvrIxXqIHGR\nzHkS6bmUYv2IF6ynzCgAbnRNDh0X2PIvBk6gJDfyC9lN9LvLurn/CVpEK85Q6hRy\nVO4BegYEaFOfDueiAB1RXvGbEvchZp7+DpN2tgi2lRbuEDPWcySFb7YVkyHo/aVO\nfDHjbSmyuwKBgQDB7ORY1Rpm/6jZozB++dTpmtXwDSwmlNsBJf7peco/Zu9Sv2x9\nhMcUW5CcNXNxohON/cEE8G+u3s5JTXOFPgXYpiAJ+185yTIfCjQLKlfpxMbuc3ev\n1ldjxAA3DKrafLODVQtE9ld6y36xuUkx1LMfOZYKhADIw4ghEknmbLI0XwKBgQCJ\njHtI16QPF8hIbGExe8WvP/0trpGGW7M8Yn7jntm9nY5msUBttsZg2ecdIOWVh1AK\nReVkFS/p0TN5xr+z5MtxvQOnQMclF9UmZH7OpTDzR7PCkW4EPYTSYirBUNw5t/s3\nZ0wyfeW8PC/IA+3nE8NhVI3nKGVHrrWRY321GUZ3GQKBgQDzLC96HVGbIQgfGRhW\nu1mcgNKFdQcy8Yu8ffttnuIIPGljwWwLpfbROD+Fe0CtqJ4XXL0Js7XfoPYoxMMH\nc16GysIG9/TYioBhBVfyf94eekylVjdYO0aY7d5Zjw1EuO/LVdPMlSZuosv3q10n\nyB55dJWP6pkR6tLqeNCuJ8+9qQ==\n-----END PRIVATE KEY-----\n",
"client_email": "firebase-adminsdk-meacv@vaxandme.iam.gserviceaccount.com",
"client_id": "110649794888712776390",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-meacv%40vaxandme.iam.gserviceaccount.com"
}
-184
View File
@@ -1,184 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getPastResult = exports.saveResult = void 0;
const functions = require("firebase-functions");
const admin = require("firebase-admin");
const firebaseSecret = require("./firebaseSecret.json");
const params = {
type: firebaseSecret.type,
projectId: firebaseSecret.project_id,
privateKeyId: firebaseSecret.private_key_id,
privateKey: firebaseSecret.private_key,
clientEmail: firebaseSecret.client_email,
clientId: firebaseSecret.client_id,
authUri: firebaseSecret.auth_uri,
tokenUri: firebaseSecret.token_uri,
authProviderX509CertUrl: firebaseSecret.auth_provider_x509_cert_url,
clientC509CertUrl: firebaseSecret.client_x509_cert_url,
};
admin.initializeApp({
credential: admin.credential.cert(params),
});
const serializeGaId = (_gaid) => {
if (_gaid) {
return _gaid.split(".").join("|");
}
return "";
};
exports.saveResult = functions.https.onCall(async (data, context) => {
if (!!data && !!context) {
const { gid } = data;
const docId = serializeGaId(gid);
const docData = 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 = {};
Object.keys(docData).forEach((symptom) => {
// 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 = {
count: admin.firestore.FieldValue.increment(-1),
};
Object.keys(existingData).forEach((symptom) => {
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 = {
count: admin.firestore.FieldValue.increment(1),
};
// INCREMENT VALUES FOR EACH SYMPTOM
Object.keys(docData).forEach((symptom) => {
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 = {
count: admin.firestore.FieldValue.increment(1),
};
// INCREMENT VALUES FOR EACH SYMPTOM
Object.keys(docData).forEach((symptom) => {
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);
}
}
});
exports.getPastResult = functions.https.onCall(async (data, context) => {
if (!!data && !!context) {
const { gid } = data;
const existingData = 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;
});
//# sourceMappingURL=index.js.map
File diff suppressed because one or more lines are too long
-3243
View File
File diff suppressed because it is too large Load Diff
-31
View File
@@ -1,31 +0,0 @@
{
"name": "functions",
"scripts": {
"lint": "eslint --ext .js,.ts .",
"build": "tsc",
"serve": "npm run devenv && npm run build && $env:NODE_ENV=DEV && firebase emulators:start",
"devenv": "SET NODE_ENV=dev",
"shell": "npm run build && firebase functions:shell",
"start": "npm run shell",
"deploy": "firebase deploy --only functions",
"logs": "firebase functions:log"
},
"engines": {
"node": "12"
},
"main": "lib/index.js",
"dependencies": {
"firebase-admin": "^9.2.0",
"firebase-functions": "^3.11.0"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^3.9.1",
"@typescript-eslint/parser": "^3.8.0",
"eslint": "^7.6.0",
"eslint-config-google": "^0.14.0",
"eslint-plugin-import": "^2.22.0",
"firebase-functions-test": "^0.2.0",
"typescript": "^3.8.0"
},
"private": true
}
-12
View File
@@ -1,12 +0,0 @@
{
"type": "service_account",
"project_id": "vaxandme",
"private_key_id": "878a8ed429f84ef5fb42555a34bd71d53ba612b2",
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDnYRdGS8aHi8aY\nDmcIPlPVN0HSDMjg046n1LmR1f1eRS/28m+C94pP6Pn2WvzRJIGK/8XKXARfAiPD\noVfUaXUAPD0DVbgHMn6/1pvCCF0wwlbXZNsIjDg9vLQiGvnsNcgoDXOhfliqw0ca\nTx3oUdgPCzOzkWw4wGMZaJrNK4w0jwuffNgA746jCG3RX9vo/m+aucerYqPPlSfs\nAjJpmpXXCwdHNx0EnEpGQc3bdnbN53hikEJ+J2xCESqaEmTryi1vXDv+i+YCrZn6\nLD+P1etLvtoU0pKMMCcVLk7VmCPMT8F2RB0L21aFmGLuy8fpBDMIYXtjMp+FbKBf\nAne0zKX1AgMBAAECggEAcn4nQ7gsWZdPYp/B2SDqX9fTgKql3iahcSgA2YrPsM3A\nscx+ZIq0TN2GjyKv9pe/aHYvO/azjQXkh6H3cZrrc/3a3SMWCK2ybaA2+9kisAWC\nblwwTHcCP354jmXV5M4qKLObU77PBlTSAtFChdq19J/A6ircJ+r/Pqv16e+SFdD/\n4ie64DR5Uxj9vUN8WFrfDfapwxwnGLgJCOrS7fecC7xDzi5iLR9mZD1ak2a8B+B6\nwNrzGafVz285B0fVtYbXiEGNElbPBd/hvioK0zsHdYxZYmiaZvyWqABejRk6jW6R\n6OTy7fCk6h7LG23+uh9Ruh8jKEE9nX6g/vYaKOqv0wKBgQD6nKvshaCQD4G5s5gK\nwQFYUFJbmMd547BKtzaFXKzUcldZaL9da4AhINoxu70uCl/nDJmTACEcifU/juiO\nM0XsZ0kufoomW2DyxVKBshBoF/OJoEUngDiCDdJFMUsa6zeiZHVi9uFmTY4c4nf8\nozJxxpcbmQRXEdv9kafBEw83DwKBgQDsWpC/t7QCqCytXWqnkVM5QIvrIxXqIHGR\nzHkS6bmUYv2IF6ynzCgAbnRNDh0X2PIvBk6gJDfyC9lN9LvLurn/CVpEK85Q6hRy\nVO4BegYEaFOfDueiAB1RXvGbEvchZp7+DpN2tgi2lRbuEDPWcySFb7YVkyHo/aVO\nfDHjbSmyuwKBgQDB7ORY1Rpm/6jZozB++dTpmtXwDSwmlNsBJf7peco/Zu9Sv2x9\nhMcUW5CcNXNxohON/cEE8G+u3s5JTXOFPgXYpiAJ+185yTIfCjQLKlfpxMbuc3ev\n1ldjxAA3DKrafLODVQtE9ld6y36xuUkx1LMfOZYKhADIw4ghEknmbLI0XwKBgQCJ\njHtI16QPF8hIbGExe8WvP/0trpGGW7M8Yn7jntm9nY5msUBttsZg2ecdIOWVh1AK\nReVkFS/p0TN5xr+z5MtxvQOnQMclF9UmZH7OpTDzR7PCkW4EPYTSYirBUNw5t/s3\nZ0wyfeW8PC/IA+3nE8NhVI3nKGVHrrWRY321GUZ3GQKBgQDzLC96HVGbIQgfGRhW\nu1mcgNKFdQcy8Yu8ffttnuIIPGljwWwLpfbROD+Fe0CtqJ4XXL0Js7XfoPYoxMMH\nc16GysIG9/TYioBhBVfyf94eekylVjdYO0aY7d5Zjw1EuO/LVdPMlSZuosv3q10n\nyB55dJWP6pkR6tLqeNCuJ8+9qQ==\n-----END PRIVATE KEY-----\n",
"client_email": "firebase-adminsdk-meacv@vaxandme.iam.gserviceaccount.com",
"client_id": "110649794888712776390",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-meacv%40vaxandme.iam.gserviceaccount.com"
}
-218
View File
@@ -1,218 +0,0 @@
import * as functions from "firebase-functions";
import * as admin from "firebase-admin";
import * as firebaseSecret from "./firebaseSecret.json";
const params = {
type: firebaseSecret.type,
projectId: firebaseSecret.project_id,
privateKeyId: firebaseSecret.private_key_id,
privateKey: firebaseSecret.private_key,
clientEmail: firebaseSecret.client_email,
clientId: firebaseSecret.client_id,
authUri: firebaseSecret.auth_uri,
tokenUri: firebaseSecret.token_uri,
authProviderX509CertUrl: firebaseSecret.auth_provider_x509_cert_url,
clientC509CertUrl: firebaseSecret.client_x509_cert_url,
};
admin.initializeApp({
credential: admin.credential.cert(params),
});
interface RequestData {
gid: string;
}
interface SaveResultRequestData extends RequestData {
name: string;
age: string;
dose: string;
[x: string]: string;
}
const serializeGaId = (_gaid: string): string => {
if (_gaid) {
return _gaid.split(".").join("|");
}
return "";
};
if (process.env.NODE_ENV && process.env.NODE_ENV === "dev") {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const backup = require("./backup.json");
const BackupResults : Record<string, Record<string,
boolean | Record<string, unknown> | string>> =
backup.results;
const BackupStats : Record<string,
Record<string, unknown> |
Record<string, number> |
Record<string, Record<string, number> |
Record<string, Record<string, Record<string, number>>>>> =
backup.stats;
Object.keys(BackupResults).forEach((key : string) => {
admin.firestore().collection("results").doc(key).set(BackupResults[key]);
});
Object.keys(BackupStats).forEach((key : string) => {
admin.firestore().collection("stats").doc(key).set(BackupStats[key]);
});
}
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;
});
-5
View File
@@ -1,5 +0,0 @@
{
"include": [
".eslintrc.js"
]
}
-16
View File
@@ -1,16 +0,0 @@
{
"compilerOptions": {
"module": "commonjs",
"noImplicitReturns": true,
"noUnusedLocals": true,
"outDir": "lib",
"sourceMap": true,
"strict": true,
"target": "es2017",
"resolveJsonModule": true
},
"compileOnSave": true,
"include": [
"src"
]
}
-1
View File
@@ -1 +0,0 @@
Web / API server started at http://localhost:4000
+124
View File
@@ -0,0 +1,124 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="favicon.ico" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta name="description" content="Learn about the expected side effects of COVID-19 Vaccines" />
<link rel="apple-touch-icon" href="logo192.png" />
<link rel="manifest" href="manifest.json" />
<style>
@import "styles/variables.css";
@import "styles/variables-dark.css" screen and (prefers-color-scheme: dark);
@import "styles/extrasmall.css";
@import "styles/small.css" only screen and (min-width: 370px) and (max-width: 767px);
@import "styles/smallmedium.css" only screen and (min-width: 768px) and (max-width: 1023px);
@import "styles/medium.css" only screen and (min-width: 1024px);
@import "styles/large.css" only screen and (min-width: 1366px);
@import "styles/extralarge.css" only screen and (min-width: 1921px);
@font-face {
font-family: "GlacialBold";
src: url("fonts/glacialindifference-bold-webfont.woff2") format("woff2"),
url("fonts/glacialindifference-bold-webfont.woff") format("woff");
font-weight: normal;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "GlacialItalic";
src: url("fonts/glacialindifference-italic-webfont.woff2") format("woff2"),
url("fonts/glacialindifference-italic-webfont.woff") format("woff");
font-weight: normal;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "Glacial";
src: url("fonts/glacialindifference-regular-webfont.woff2") format("woff2"),
url("fonts/glacialindifference-regular-webfont.woff") format("woff");
font-weight: normal;
font-style: normal;
font-display: swap;
}
[data-font="sans"] {
font-family: "Glacial", sans-serif;
font-display: swap;
}
[data-font="sans-bold"] {
font-family: "GlacialBold", sans-serif;
font-display: swap;
}
[data-font="sans-italic"] {
font-family: "GlacialItalic", sans-serif;
font-style: italic;
font-display: swap;
}
.logo {
background-image: url("logo512.png");
}
header#archived {
background: rgb(149 40 40 / 48%);
border-radius: 2rem;
position: fixed;
padding: 1rem 2rem;
font-size: 1.5rem;
letter-spacing: 1.5px;
text-transform: uppercase;
z-index: 99;
backdrop-filter: blur(7px);
font-family: "GlacialBold";
left: 15rem;
right: 15rem;
top: 3rem;
}
</style>
<script async src="https://www.googletagmanager.com/gtag/js?id=G-7VZCY223NG"></script>
<script>function gtag() { dataLayer.push(arguments) } window.dataLayer = window.dataLayer || [], gtag("js", new Date), gtag("config", "G-7VZCY223NG")</script>
<title>Vax & Me</title>
</head>
<body><noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-K4XHBR6" height="0" width="0"
style="display:none;visibility:hidden"></iframe></noscript>
<header id="archived">
<div>⚠️ Project has been archived.</div>
</header>
<div id="root"></div>
<footer data-font="sans">
<div class="link-container">
<div id="data-sources">
<h6 class="overline" data-font="sans">FDA Data Sources</h6><a id="fda-pfizer"
href="https://www.fda.gov/media/144416/download">PFizer-BioNTech</a> <a id="fda-moderna"
href="https://www.fda.gov/media/144637/download">Moderna</a> <a id="fda-j&j"
href="https://www.fda.gov/media/146304/download">J&J Janssen</a>
</div>
<div>
<h6 class="overline" data-font="sans">Links</h6><a href="vaxandme_chart.pdf">Download Chart</a> <a
href="index.html">Home</a> <a target="_blank"
href="https://www.gavi.org/vaccineswork/what-difference-between-efficacy-and-effectiveness"
rel="noreferrer">What is efficacy? ↗</a>
</div>
<div>
<h6 class="overline" data-font="sans">Legal</h6><a href="copyright.html">Copyright</a> <a
href="privacy.html">Privacy</a>
</div>
</div>
<div class="overline by" data-font="sans">Designed &amp; Developed with ❤ by Alba Rajanibala and Ayushya Amitabh
</div>
</footer>
<script src="https://unpkg.com/react@18/umd/react.production.min.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js" crossorigin></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<script type="text/babel" src="index.js"></script>
</body>
</html>
+989
View File
@@ -0,0 +1,989 @@
'use strict';
//import firebase from "firebase/app";
//import "firebase/functions";
//
//const FIREBASE_CONFIG = {
// apiKey: "AIzaSyDKw8HXWRn3dtkIRETv-BxtwnklZIpIkxU",
// authDomain: "vaxandme.firebaseapp.com",
// projectId: "vaxandme",
// storageBucket: "vaxandme.appspot.com",
// messagingSenderId: "614738281692",
// appId: "1:614738281692:web:7a89e0af76675e4f0ea019",
// measurementId: "G-N016TVJ6JC",
//};
//
//firebase.initializeApp(FIREBASE_CONFIG);
//
//if (window.location.host !== "www.vaxand.me") {
// firebase.functions().useEmulator(window.location.host.split(":")[0], 5001);
//}
//
//const fb_functions = firebase.functions();
//const saveResult = fb_functions.httpsCallable("saveResultV1");
//const getPastResult = fb_functions.httpsCallable("getPastResultV1");
//const getStats = fb_functions.httpsCallable("getStatsV1");
const saveResult = () => new Promise((resolve, reject) => reject());
const getPastResult = () => new Promise((resolve, reject) => reject());
const getStats = () => new Promise((resolve, reject) => reject());
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",
},
};
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": 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": 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": 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": 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": 9908,
"RED AT SITE": 344,
"SWELLING AT SITE": 2089,
HEADACHE: 4030,
FATIGUE: 4384,
"MUSCLE PAIN": 2699,
"JOINT PAIN": 1893,
"NAUSEA OR VOMITING": 1068,
FEVER: 105,
CHILLS: 1051,
};
const MD_DOSE2_YOUNGER_RESULT = {
"PAIN AT SITE": 9873,
"RED AT SITE": 982,
"SWELLING AT SITE": 3164,
FATIGUE: 7430,
HEADACHE: 6898,
"JOINT PAIN": 4993,
CHILLS: 5341,
FEVER: 1908,
"NAUSEA OR VOMITING": 2348,
"MUSCLE PAIN": 6769,
};
const MD_DOSE1_OLDER_RESULT = {
"PAIN AT SITE": 2782,
"RED AT SITE": 86,
"SWELLING AT SITE": 396,
HEADACHE: 921,
FATIGUE: 1251,
"MUSCLE PAIN": 742,
"JOINT PAIN": 618,
"NAUSEA OR VOMITING": 194,
CHILLS: 202,
FEVER: 10,
};
const MD_DOSE2_OLDER_RESULT = {
"PAIN AT SITE": 3070,
"RED AT SITE": 275,
"SWELLING AT SITE": 715,
FATIGUE: 2152,
HEADACHE: 1704,
"MUSCLE PAIN": 1739,
"JOINT PAIN": 1291,
CHILLS: 1141,
"NAUSEA OR VOMITING": 437,
FEVER: 370,
};
const JJ_YOUNGER_RESULT = {
"PAIN AT SITE": 1193,
"RED AT SITE": 184,
"SWELLING AT SITE": 142,
HEADACHE: 905,
FATIGUE: 891,
"MUSCLE PAIN": 796,
"NEED PAIN MED": 538,
"NAUSEA OR VOMITING": 315,
FEVER: 261,
};
const JJ_OLDER_RESULT = {
"PAIN AT SITE": 439,
"RED AT SITE": 61,
"SWELLING AT SITE": 36,
HEADACHE: 401,
FATIGUE: 392,
"MUSCLE PAIN": 317,
"NAUSEA OR VOMITING": 162,
"NEED PAIN MED": 130,
FEVER: 41,
};
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": 11406,
"65 & Older": 3762,
},
"Dose 2": {
"18 - 64": 10985,
"65 & Older": 3692,
},
},
"J&J Janssen": {
"18 - 59": 2036,
"60 & Older": 1320,
},
};
const VAX_RESULTS = {
"Pfizer-BioNTech": {
"Dose 1": {
"18 - 55": PB_DOSE1_YOUNGER_RESULT,
"56 & Older": PB_DOSE1_OLDER_RESULT,
},
"Dose 2": {
"18 - 55": PB_DOSE2_YOUNGER_RESULT,
"56 & Older": PB_DOSE2_OLDER_RESULT,
},
},
Moderna: {
"Dose 1": {
"18 - 64": MD_DOSE1_YOUNGER_RESULT,
"65 & Older": MD_DOSE1_OLDER_RESULT,
},
"Dose 2": {
"18 - 64": MD_DOSE2_YOUNGER_RESULT,
"65 & Older": MD_DOSE2_OLDER_RESULT,
},
},
"J&J Janssen": {
"18 - 59": JJ_YOUNGER_RESULT,
"60 & Older": JJ_OLDER_RESULT,
},
};
const ICONS = {
"PAIN AT SITE": "💪",
"RED AT SITE": "🔴",
"SWELLING AT SITE": "💢",
FATIGUE: "🥱",
HEADACHE: "🤕",
"NEED PAIN MED": "💊",
"MUSCLE PAIN": "😫",
CHILLS: "🥶",
DIARRHEA: "💩",
"JOINT PAIN": "🦵",
FEVER: "🤒",
VOMITING: "🤮",
"NAUSEA OR VOMITING": "🤮",
};
const DATA_CHOICES = {
VNM: "Vax&Me Only",
VNM_FDA: "Vax&Me + FDA",
FDA: "FDA Only",
};
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
name: "",
dose: "",
age: "",
gid: "",
showInputPopup: false,
answers: {},
fetchedResult: {},
stats: {},
loading: true,
dataSource: DATA_CHOICES.FDA,
loadingMessage: "Gettings stats...",
};
}
componentDidMount() {
const params = window.location.pathname
.toUpperCase()
.split("/")
.filter((v) => v.length > 0);
if (params) {
if (params[0] && VAX_NAMES[params[0]]) {
const name = VAX_NAMES[params[0]];
this.setState({ name });
switch (name) {
case VAX_NAMES.PB:
case VAX_NAMES.MD:
if (params[1] && VAX_DOSES[params[1]]) {
const dose = VAX_DOSES[params[1]];
this.setState({ dose });
if (params[2] && VAX_AGES[name][params[2]]) {
const age = VAX_AGES[name][params[2]];
this.setState({ age });
}
}
break;
case VAX_NAMES.JJ:
if (params[1] && VAX_AGES[name][params[1]]) {
const age = VAX_AGES[name][params[1]];
this.setState({ age });
}
break;
default:
break;
}
}
}
getStats()
.then((v) => {
// GET & SET STATS
this.setState({
stats: v.data,
loadingMessage: "Checking for existing answers...",
dataSource: DATA_CHOICES.VNM_FDA,
});
// HAS GID?
if (window.gtag) {
// GET GID
window.gtag("get", "G-7VZCY223NG", "client_id", (client_id) => {
// GOT GID?
if (!!client_id) {
// SAVE GID
this.setState({ gid: client_id });
// GET PAST ANSWER FOR GID
getPastResult({ gid: client_id })
.then((v) => {
const { data } = v;
if (!!data) {
const { name, age, dose } = data;
this.setState({
name,
age,
dose,
showInputPopup: true,
fetchedResult: data,
answers: data,
loading: false,
});
const inputPopupSubmit = document.querySelector(
".input-popup-submit"
);
if (inputPopupSubmit) {
inputPopupSubmit.classList.add("submitted");
inputPopupSubmit.innerHTML = "UPDATE ANSWER";
}
window.localStorage.setItem("hasExistingAnswer", true);
} else {
this.setState({ loading: false });
}
})
.catch((err) => {
console.error("ERROR Getting Past Answer", err);
this.setState({ loading: false });
});
} else {
this.setState({ loading: false });
}
});
} else {
this.setState({ loading: false });
}
})
.catch((err) => {
console.error("ERROR GETTING STATS", err);
this.setState({ loading: false });
});
}
shouldShowDoses = () => {
const { name, loading } = this.state;
if (loading) {
return false;
}
return name && (name === VAX_NAMES.PB || name === VAX_NAMES.MD);
};
shouldShowAgeGroup = () => {
const { name, dose, loading } = this.state;
if (loading) {
return false;
}
switch (name) {
case VAX_NAMES.JJ:
return true;
case VAX_NAMES.MD:
case VAX_NAMES.PB:
return !!dose;
default:
return false;
}
};
shouldShowResults = () => {
const { name, dose, age, loading } = this.state;
if (loading) {
return false;
}
switch (name) {
case VAX_NAMES.JJ:
return !!age;
case VAX_NAMES.MD:
case VAX_NAMES.PB:
return !!dose && !!age;
default:
return false;
}
};
getResults = () => {
const { name, dose, age, loading } = this.state;
if (loading) {
return null;
}
switch (name) {
case VAX_NAMES.JJ:
return VAX_RESULTS[name][age];
case VAX_NAMES.MD:
case VAX_NAMES.PB:
return VAX_RESULTS[name][dose][age];
default:
return null;
}
};
copyShareLink = () => {
const { name, dose, age } = this.state;
let SHARE_URL = window.location.host;
const serialize_name = Object.keys(VAX_NAMES).filter(
(k) => VAX_NAMES[k] === name
)[0];
const serialize_dose = Object.keys(VAX_DOSES).filter(
(k) => VAX_DOSES[k] === dose
)[0];
const serialize_age = Object.keys(VAX_AGES[name]).filter(
(k) => VAX_AGES[name][k] === age
)[0];
if (serialize_name) {
SHARE_URL += `/${serialize_name}`;
}
if (serialize_dose) {
SHARE_URL += `/${serialize_dose}`;
}
if (serialize_age) {
SHARE_URL += `/${serialize_age}`;
}
const copyTextInput = document.createElement("input");
document.body.appendChild(copyTextInput);
copyTextInput.value = SHARE_URL.toLowerCase();
copyTextInput.select();
document.execCommand("copy");
copyTextInput.remove();
document.querySelector("#share-result").innerHTML = "Copied Link";
setTimeout(() => {
document.querySelector("#share-result").innerHTML = "Share ↗";
}, 1500);
};
updateAnswers = (symptom, dose) => {
const { answers } = this.state;
const newAnswers = Object.assign({}, answers);
if (!!dose) {
if (!newAnswers[dose]) {
newAnswers[dose] = {};
}
if (newAnswers[dose][symptom]) {
newAnswers[dose][symptom] = !newAnswers[dose][symptom];
} else {
newAnswers[dose][symptom] = true;
}
} else {
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 = this.getResults();
const symptoms = {};
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,
gid,
});
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");
}
inputPopupSubmit.innerHTML = "THANK YOU!";
setTimeout(() => {
inputPopupSubmit.innerHTML = "UPDATE ANSWER";
}, 1500);
})
.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">
{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>
);
};
getStatForSymptom = (symptom) => {
const { dataSource, name, dose, age, stats } = this.state;
switch (dataSource) {
case DATA_CHOICES.FDA:
if (!!dose) {
return Math.ceil(
(VAX_RESULTS[name][dose][age][symptom] /
VAX_COUNTS[name][dose][age]) *
10
);
} else {
return Math.ceil(
(VAX_RESULTS[name][age][symptom] / VAX_COUNTS[name][age]) * 10
);
}
case DATA_CHOICES.VNM:
if (Object.keys(stats).length > 0) {
if (!!dose) {
return Math.ceil(
(stats[name][dose][age][symptom] / stats[name][dose][age].count) *
10
);
} else {
return Math.ceil(
(stats[name][age][symptom] / stats[name][age].count) * 10
);
}
} else {
return 0;
}
case DATA_CHOICES.VNM_FDA:
let symptomCount = 0;
let totalCount = 0;
if (Object.keys(stats).length > 0) {
if (!!dose) {
symptomCount =
VAX_RESULTS[name][dose][age][symptom] +
stats[name][dose][age][symptom];
totalCount =
VAX_COUNTS[name][dose][age] + stats[name][dose][age].count;
} else {
symptomCount =
VAX_RESULTS[name][age][symptom] + stats[name][age][symptom];
totalCount = VAX_COUNTS[name][age] + stats[name][age].count;
}
} else {
symptomCount = VAX_RESULTS[name][dose][age][symptom];
totalCount = VAX_COUNTS[name][dose][age];
}
return Math.ceil((symptomCount / totalCount) * 10);
default:
return 1;
}
};
getSampleSize = () => {
const { dataSource, name, dose, age, stats } = this.state;
switch (dataSource) {
case DATA_CHOICES.FDA:
if (!!dose) {
return VAX_COUNTS[name][dose][age];
} else {
return VAX_COUNTS[name][age];
}
case DATA_CHOICES.VNM:
if (Object.keys(stats).length > 0) {
if (!!dose) {
return stats[name][dose][age].count;
} else {
return stats[name][age].count;
}
} else {
return 0;
}
case DATA_CHOICES.VNM_FDA:
let totalCount = 0;
if (Object.keys(stats).length > 0) {
if (!!dose) {
totalCount =
VAX_COUNTS[name][dose][age] + stats[name][dose][age].count;
} else {
totalCount = VAX_COUNTS[name][age] + stats[name][age].count;
}
} else {
totalCount = VAX_COUNTS[name][dose][age];
}
return totalCount;
default:
return 0;
}
};
render() {
const {
name,
dose,
age,
showInputPopup,
loading,
fetchedResult,
dataSource,
loadingMessage,
stats,
} = this.state;
let result = {};
let resultAtSite = {};
if (this.shouldShowResults()) {
result = Object.assign({}, this.getResults());
Object.keys(result).forEach((s) => {
if (s.includes("AT SITE")) {
resultAtSite[s] = result[s];
delete result[s];
}
});
}
return (
<div className="app-container">
<header>
<div className="logo-container">
<div className="logo"> </div>
</div>
<div className="intro">
<h6 className="overline" data-font="sans">
Getting vaccinated?
</h6>
<h3 className="subheader" data-font="sans-bold">
Find out what to expect.
</h3>
</div>
</header>
<main>
{loading ? (
<div className="loading-container">
<p className="question" data-font="sans">
{loadingMessage}
</p>
<div className="loading-bar-container">
<div className="loading-bar"></div>
</div>
</div>
) : null}
{!loading ? (
<div className="question-container">
<p className="question" data-font="sans">
Select Vaccine
</p>
<div className="answers-container">
{Object.values(VAX_NAMES).map((v) => (
<button
key={`name-group-${v}`}
onClick={() =>
this.setState({
name: v,
dose: "",
age: "",
answers: v === fetchedResult.name ? fetchedResult : {},
showInputPopup: false,
})
}
data-font="sans-bold"
className={`vaccine answer${name === v ? " selected" : ""}${
name && name !== v ? " unselected" : ""
}`}
>
{v}
</button>
))}
</div>
</div>
) : null}
{this.shouldShowDoses() ? (
<div className="question-container">
<p className="question" data-font="sans">
Select Dose
</p>
<div className="answers-container">
{Object.values(VAX_DOSES).map((v) => (
<button
key={`dose-group-${v}`}
onClick={() =>
this.setState({
dose: v,
age: "",
showInputPopup: false,
})
}
data-font="sans-bold"
className={`dose answer${dose === v ? " selected" : ""}${
dose && dose !== v ? " unselected" : ""
}`}
>
{v}
</button>
))}
</div>
</div>
) : null}
{this.shouldShowAgeGroup() ? (
<div className="question-container">
<p className="question" data-font="sans">
Select Age Group
</p>
<div className="answers-container">
{Object.values(VAX_AGES[name]).map((v) => (
<button
key={`age-group-${v}`}
onClick={() =>
this.setState({
age: v,
showInputPopup: false,
})
}
data-font="sans-bold"
className={`age answer${age === v ? " selected" : ""}${
age && age !== v ? " unselected" : ""
}`}
>
{v}
</button>
))}
</div>
</div>
) : null}
{this.shouldShowResults() ? (
<div className="result-header-container">
<div className="symptom-container subheader">
<h3 data-font="sans-bold">Here's what to expect.</h3>
<h6
id="share-result"
onClick={this.copyShareLink}
className="overline"
data-font="sans"
data-button
>
Share ↗
</h6>
<h6 className="overline" data-font="sans" data-button>
<a href="/vaxandme_chart.pdf">Download Chart ↗</a>
</h6>
</div>
<div className="result-header-select">
<h6 className="overline" data-font="sans">
Use data from:
</h6>
<select
disabled={Object.keys(stats).length < 1}
onChange={(e) =>
this.setState({ dataSource: e.target.value })
}
value={dataSource}
>
{Object.keys(DATA_CHOICES).map((dataKey) => (
<option key={dataKey}>{DATA_CHOICES[dataKey]}</option>
))}
</select>
<h6 className="overline success" data-font="sans">
Based on
{` ${this.getSampleSize()
.toString()
.replace(/\B(?=(\d{3})+(?!\d))/g, ",")} `}
individual experiences
</h6>
{Object.keys(stats).length < 1 ? (
<h6 className="overline errored" data-font="sans">
Failed to get stats from Vax&amp;Me
</h6>
) : null}
</div>
</div>
) : null}
{this.shouldShowResults() ? (
<div className="tip-container">
{/* <div className="tip-icon">&#9432;</div> */}
<div className="tip">
<h6 className="subheader" data-font="sans">
NET EFFICACY
</h6>
<h3 className="header" data-font="sans-bold">
{VAX_EFFICACY[name][age]}%
</h3>
<h6
className="overline"
style={{ wordBreak: "break-word" }}
data-font="sans"
>
of vaccine trial participants who took the <u>{name}</u>{" "}
vaccine (in the <u>{age}</u> age group) did not get COVID-19
</h6>
<h6 className="overline" data-font="sans" data-button>
<a href="#data-sources">See Data Sources ↗</a>
</h6>
<h6 className="overline" data-font="sans" data-button>
<a
target="_blank"
href="https://www.gavi.org/vaccineswork/what-difference-between-efficacy-and-effectiveness"
rel="noreferrer"
>
What is efficacy? ↗
</a>
</h6>
</div>
</div>
) : null}
{this.shouldShowResults() ? (
<div className="symptom-container">
{Object.keys(resultAtSite).map((symptom) => (
<div className="symptom at-site" key={`symptom-${symptom}`}>
<span className="symptom-emoji">{ICONS[symptom]}</span>
<p data-font="sans" className="symptom-name">
{symptom}
</p>
<p data-font="sans-bold" className="symptom-chance">
{this.getStatForSymptom(symptom)}/10
</p>
</div>
))}
{Object.keys(result).map((symptom) => (
<div className="symptom" key={`symptom-${symptom}`}>
<span className="symptom-emoji">{ICONS[symptom]}</span>
<p data-font="sans" className="symptom-name">
{symptom}
</p>
<p data-font="sans-bold" className="symptom-chance">
{this.getStatForSymptom(symptom)}/10
</p>
</div>
))}
</div>
) : null}
</main>
{this.shouldShowResults() ? (
<div className={`input-popup${showInputPopup ? " expanded" : ""}`}>
<div
className="input-popup-header"
onClick={() => this.setState({ showInputPopup: !showInputPopup })}
>
<div className="input-popup-header-text">
<h6 className="overline" data-font="sans">
Already vaxxed?
</h6>
<h3 className="subheader" data-font="sans-bold">
Tell us how it went.
</h3>
</div>
<button
data-font="sans"
className="subheader input-popup-header-icon"
onClick={() =>
this.setState({ showInputPopup: !showInputPopup })
}
>
&#9660;
</button>
</div>
{showInputPopup ? (
<div className="input-popup-body">
<p className="question" data-font="sans">
I am in age group <strong>{age}</strong> and got the
<strong> {name}</strong> vaccine. I experienced:
</p>
{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 at any time!
</p>
<p className="question" data-font="sans">
(Just use the same device)
</p>
</div>
</div>
) : null}
{showInputPopup ? (
<div
onClick={this.submitAnswer}
className="input-popup-submit"
data-font="sans-bold"
>
SUBMIT
</div>
) : null}
</div>
) : null}
</div>
);
}
}
const domContainer = document.querySelector('#root');
const root = ReactDOM.createRoot(domContainer);
root.render(React.createElement(App));

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

+147 -147
View File
@@ -1,147 +1,147 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Learn about the expected side effects of COVID-19 Vaccines"
/>
<link rel="apple-touch-icon" href="/logo192.png" />
<link rel="manifest" href="/manifest.json" />
<style>
@import "/styles/variables.css";
@import "/styles/variables-dark.css" screen and
(prefers-color-scheme: dark);
@import "/styles/extrasmall.css";
@import "/styles/small.css" only screen and (min-width: 370px) and
(max-width: 767px);
@import "/styles/smallmedium.css" only screen and (min-width: 768px) and
(max-width: 1023px);
@import "/styles/medium.css" only screen and (min-width: 1024px);
@import "/styles/large.css" only screen and (min-width: 1366px);
@import "/styles/extralarge.css" only screen and (min-width: 1921px);
@font-face {
font-family: "GlacialBold";
src: url("/fonts/glacialindifference-bold-webfont.woff2")
format("woff2"),
url("/fonts/glacialindifference-bold-webfont.woff") format("woff");
font-weight: normal;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "GlacialItalic";
src: url("/fonts/glacialindifference-italic-webfont.woff2")
format("woff2"),
url("/fonts/glacialindifference-italic-webfont.woff") format("woff");
font-weight: normal;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "Glacial";
src: url("/fonts/glacialindifference-regular-webfont.woff2")
format("woff2"),
url("/fonts/glacialindifference-regular-webfont.woff") format("woff");
font-weight: normal;
font-style: normal;
font-display: swap;
}
[data-font="sans"] {
font-family: "Glacial", sans-serif;
font-display: swap;
}
[data-font="sans-bold"] {
font-family: "GlacialBold", sans-serif;
font-display: swap;
}
[data-font="sans-italic"] {
font-family: "GlacialItalic", sans-serif;
font-style: italic;
font-display: swap;
}
</style>
<title>Vax & Me | Privacy</title>
</head>
<body>
<div id="root">
<div class="app-container">
<header>
<div class="logo-container">
<div class="logo"></div>
<div class="logo-text-container">
<p data-font="sans-bold">PRIVACY</p>
</div>
</div>
</header>
<main>
<div class="intro">
<h6 class="overline" data-font="sans">What's collected</h6>
<h6 class="overline" data-font="sans">&amp; How it's used</h6>
</div>
<div class="question-container">
<h6 class="subheader" data-font="sans-bold">
USER PERSONAL INFORMATION
</h6>
<div class="answers-container">
<p class="overline" data-font="sans">
No personally indentifiable information or user data is
collected. Vax & Me only uses Google Analytics on it's website
to study website performance, and error prevention.
</p>
</div>
</div>
<div class="question-container">
<h6 class="subheader" data-font="sans-bold">USER ACTIVITY</h6>
<div class="answers-container">
<p class="overline" data-font="sans">
Vax & Me monitors some click, and keystrokes on it's website to
detect functionality errors.
</p>
</div>
</div>
<div class="question-container">
<h6 class="subheader" data-font="sans-bold">USER DATA</h6>
<div class="answers-container">
<p class="overline" data-font="sans">
Volunteered data is linked to Google Analytics Client ID - which
is unique to a device and web-browser combination. This is
required to prevent data duplicacy and is core to the
functionality of Vax & Me.
</p>
</div>
</div>
</main>
</div>
</div>
<footer data-font="sans">
<div class="link-container">
<div>
<h6 class="overline" data-font="sans">FDA Data Sources</h6>
<a href="https://www.fda.gov/media/144416/download"
>PFizer-BioNTech</a
>
<a href="https://www.fda.gov/media/144637/download">Moderna</a>
<a href="https://www.fda.gov/media/146304/download">J&J Janssen</a>
</div>
<div>
<h6 class="overline" data-font="sans">Links</h6>
<a href="/vaxandme_chart.pdf">Download Chart</a>
<a href="/">Home</a>
</div>
<div>
<h6 class="overline" data-font="sans">Legal</h6>
<a href="/copyright">Copyright</a>
<a href="/privacy">Privacy</a>
</div>
</div>
<div class="overline by" data-font="sans">
Designed &amp; Developed with ❤ by Alba Rajanibala and Ayushya Amitabh
</div>
</footer>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Learn about the expected side effects of COVID-19 Vaccines"
/>
<link rel="apple-touch-icon" href="logo192.png" />
<link rel="manifest" href="manifest.json" />
<style>
@import "styles/variables.css";
@import "styles/variables-dark.css" screen and
(prefers-color-scheme: dark);
@import "styles/extrasmall.css";
@import "styles/small.css" only screen and (min-width: 370px) and
(max-width: 767px);
@import "styles/smallmedium.css" only screen and (min-width: 768px) and
(max-width: 1023px);
@import "styles/medium.css" only screen and (min-width: 1024px);
@import "styles/large.css" only screen and (min-width: 1366px);
@import "styles/extralarge.css" only screen and (min-width: 1921px);
@font-face {
font-family: "GlacialBold";
src: url("fonts/glacialindifference-bold-webfont.woff2")
format("woff2"),
url("fonts/glacialindifference-bold-webfont.woff") format("woff");
font-weight: normal;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "GlacialItalic";
src: url("fonts/glacialindifference-italic-webfont.woff2")
format("woff2"),
url("fonts/glacialindifference-italic-webfont.woff") format("woff");
font-weight: normal;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "Glacial";
src: url("fonts/glacialindifference-regular-webfont.woff2")
format("woff2"),
url("fonts/glacialindifference-regular-webfont.woff") format("woff");
font-weight: normal;
font-style: normal;
font-display: swap;
}
[data-font="sans"] {
font-family: "Glacial", sans-serif;
font-display: swap;
}
[data-font="sans-bold"] {
font-family: "GlacialBold", sans-serif;
font-display: swap;
}
[data-font="sans-italic"] {
font-family: "GlacialItalic", sans-serif;
font-style: italic;
font-display: swap;
}
</style>
<title>Vax & Me | Privacy</title>
</head>
<body>
<div id="root">
<div class="app-container">
<header>
<div class="logo-container">
<div class="logo"></div>
<div class="logo-text-container">
<p data-font="sans-bold">PRIVACY</p>
</div>
</div>
</header>
<main>
<div class="intro">
<h6 class="overline" data-font="sans">What's collected</h6>
<h6 class="overline" data-font="sans">&amp; How it's used</h6>
</div>
<div class="question-container">
<h6 class="subheader" data-font="sans-bold">
USER PERSONAL INFORMATION
</h6>
<div class="answers-container">
<p class="overline" data-font="sans">
No personally indentifiable information or user data is
collected. Vax & Me only uses Google Analytics on it's website
to study website performance, and error prevention.
</p>
</div>
</div>
<div class="question-container">
<h6 class="subheader" data-font="sans-bold">USER ACTIVITY</h6>
<div class="answers-container">
<p class="overline" data-font="sans">
Vax & Me monitors some click, and keystrokes on it's website to
detect functionality errors.
</p>
</div>
</div>
<div class="question-container">
<h6 class="subheader" data-font="sans-bold">USER DATA</h6>
<div class="answers-container">
<p class="overline" data-font="sans">
Volunteered data is linked to Google Analytics Client ID - which
is unique to a device and web-browser combination. This is
required to prevent data duplicacy and is core to the
functionality of Vax & Me.
</p>
</div>
</div>
</main>
</div>
</div>
<footer data-font="sans">
<div class="link-container">
<div>
<h6 class="overline" data-font="sans">FDA Data Sources</h6>
<a href="https://www.fda.gov/media/144416/download"
>PFizer-BioNTech</a
>
<a href="https://www.fda.gov/media/144637/download">Moderna</a>
<a href="https://www.fda.gov/media/146304/download">J&J Janssen</a>
</div>
<div>
<h6 class="overline" data-font="sans">Links</h6>
<a href="vaxandme_chart.pdf">Download Chart</a>
<a href="index.html">Home</a>
</div>
<div>
<h6 class="overline" data-font="sans">Legal</h6>
<a href="copyright.html">Copyright</a>
<a href="privacy.html">Privacy</a>
</div>
</div>
<div class="overline by" data-font="sans">
Designed &amp; Developed with ❤ by Alba Rajanibala and Ayushya Amitabh
</div>
</footer>
</body>
</html>
+119 -119
View File
@@ -1,119 +1,119 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Learn about the expected side effects of COVID-19 Vaccines"
/>
<link rel="apple-touch-icon" href="/logo192.png" />
<link rel="manifest" href="/manifest.json" />
<style>
@import "/styles/variables.css";
@import "/styles/variables-dark.css" screen and
(prefers-color-scheme: dark);
@import "/styles/extrasmall.css";
@import "/styles/small.css" only screen and (min-width: 370px)
and (max-width: 767px);
@import "/styles/smallmedium.css" only screen and
(min-width: 768px) and (max-width: 1023px);
@import "/styles/medium.css" only screen and
(min-width: 1024px);
@import "/styles/large.css" only screen and
(min-width: 1366px);
@import "/styles/extralarge.css" only screen and
(min-width: 1921px);
@font-face {
font-family: "GlacialBold";
src: url("/fonts/glacialindifference-bold-webfont.woff2")
format("woff2"),
url("/fonts/glacialindifference-bold-webfont.woff") format("woff");
font-weight: normal;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "GlacialItalic";
src: url("/fonts/glacialindifference-italic-webfont.woff2")
format("woff2"),
url("/fonts/glacialindifference-italic-webfont.woff")
format("woff");
font-weight: normal;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "Glacial";
src: url("/fonts/glacialindifference-regular-webfont.woff2")
format("woff2"),
url("/fonts/glacialindifference-regular-webfont.woff")
format("woff");
font-weight: normal;
font-style: normal;
font-display: swap;
}
[data-font="sans"] {
font-family: "Glacial", sans-serif;
font-display: swap;
}
[data-font="sans-bold"] {
font-family: "GlacialBold", sans-serif;
font-display: swap;
}
[data-font="sans-italic"] {
font-family: "GlacialItalic", sans-serif;
font-style: italic;
font-display: swap;
}
</style>
<title>Vax & Me | 404</title>
</head>
<body>
<div id="root">
<div class="app-container">
<header>
<div class="logo-container">
<div class="logo"> </div>
</div>
</header>
<main>
<div class="intro">
<h1 class="header" data-font="sans-bold">
404
</h1>
<h6 class="overline" data-font="sans">
This page doesn't exist.
</h6>
</div>
</main>
</div>
</div>
<footer data-font="sans">
<div class="link-container">
<div>
<h6 class="overline" data-font="sans">FDA Data Sources</h6>
<a href="https://www.fda.gov/media/144416/download">PFizer-BioNTech</a>
<a href="https://www.fda.gov/media/144637/download">Moderna</a>
<a href="https://www.fda.gov/media/146304/download">J&J Janssen</a>
</div>
<div>
<h6 class="overline" data-font="sans">Links</h6>
<a href="/vaxandme_chart.pdf">Download Chart</a>
<a href="/">Home</a>
</div>
<div>
<h6 class="overline" data-font="sans">Legal</h6>
<a href="/copyright">Copyright</a>
<a href="/privacy">Privacy</a>
</div>
</div>
<div class="overline by" data-font="sans">
Designed &amp; Developed with ❤ by Alba Rajanibala and Ayushya Amitabh
</div>
</footer>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Learn about the expected side effects of COVID-19 Vaccines"
/>
<link rel="apple-touch-icon" href="logo192.png" />
<link rel="manifest" href="manifest.json" />
<style>
@import "styles/variables.css";
@import "styles/variables-dark.css" screen and
(prefers-color-scheme: dark);
@import "styles/extrasmall.css";
@import "styles/small.css" only screen and (min-width: 370px)
and (max-width: 767px);
@import "styles/smallmedium.css" only screen and
(min-width: 768px) and (max-width: 1023px);
@import "styles/medium.css" only screen and
(min-width: 1024px);
@import "styles/large.css" only screen and
(min-width: 1366px);
@import "styles/extralarge.css" only screen and
(min-width: 1921px);
@font-face {
font-family: "GlacialBold";
src: url("fonts/glacialindifference-bold-webfont.woff2")
format("woff2"),
url("fonts/glacialindifference-bold-webfont.woff") format("woff");
font-weight: normal;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "GlacialItalic";
src: url("fonts/glacialindifference-italic-webfont.woff2")
format("woff2"),
url("fonts/glacialindifference-italic-webfont.woff")
format("woff");
font-weight: normal;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "Glacial";
src: url("fonts/glacialindifference-regular-webfont.woff2")
format("woff2"),
url("fonts/glacialindifference-regular-webfont.woff")
format("woff");
font-weight: normal;
font-style: normal;
font-display: swap;
}
[data-font="sans"] {
font-family: "Glacial", sans-serif;
font-display: swap;
}
[data-font="sans-bold"] {
font-family: "GlacialBold", sans-serif;
font-display: swap;
}
[data-font="sans-italic"] {
font-family: "GlacialItalic", sans-serif;
font-style: italic;
font-display: swap;
}
</style>
<title>Vax & Me | 404</title>
</head>
<body>
<div id="root">
<div class="app-container">
<header>
<div class="logo-container">
<div class="logo"> </div>
</div>
</header>
<main>
<div class="intro">
<h1 class="header" data-font="sans-bold">
404
</h1>
<h6 class="overline" data-font="sans">
This page doesn't exist.
</h6>
</div>
</main>
</div>
</div>
<footer data-font="sans">
<div class="link-container">
<div>
<h6 class="overline" data-font="sans">FDA Data Sources</h6>
<a href="https://www.fda.gov/media/144416/download">PFizer-BioNTech</a>
<a href="https://www.fda.gov/media/144637/download">Moderna</a>
<a href="https://www.fda.gov/media/146304/download">J&J Janssen</a>
</div>
<div>
<h6 class="overline" data-font="sans">Links</h6>
<a href="vaxandme_chart.pdf">Download Chart</a>
<a href="index.html">Home</a>
</div>
<div>
<h6 class="overline" data-font="sans">Legal</h6>
<a href="copyright.html">Copyright</a>
<a href="privacy.html">Privacy</a>
</div>
</div>
<div class="overline by" data-font="sans">
Designed &amp; Developed with ❤ by Alba Rajanibala and Ayushya Amitabh
</div>
</footer>
</body>
</html>
@@ -1,7 +1,7 @@
.input-popup.expanded {
height: 40vh;
}
.loading-bar-container {
max-width: 25%;
}
.input-popup.expanded {
height: 50vh;
}
.loading-bar-container {
max-width: 25%;
}
@@ -1,384 +1,475 @@
* {
margin: 0;
padding: 0;
transition: all ease-in-out 0.2s;
color: var(--color-secondary);
user-select: none;
}
html {
font-size: 10px;
}
body {
display: flex;
flex-direction: column;
font-size: 10px;
padding: 3.75rem;
padding-bottom: 0 !important;
height: calc(100vh - 3.75rem);
overflow-x: hidden;
max-width: 100vw;
background: var(--color-primary);
}
#root {
flex: 1;
display: flex;
}
.app-container {
flex: 1;
}
header {
display: flex;
justify-content: center;
flex-direction: column;
}
.logo-container {
display: flex;
width: fit-content;
justify-content: center;
flex-direction: column;
}
.logo {
background-size: 100%;
width: 5rem;
height: 5rem;
display: inline-block;
background-image: url("/logo512.png");
}
.logo-text-container {
justify-content: center;
vertical-align: middle;
flex-direction: column;
flex: 1;
margin-top: 3.5rem;
}
.logo-text-container p {
font-size: 2.4rem;
}
.header {
font-size: 10rem;
letter-spacing: 1rem;
}
.subheader {
font-size: 2.5rem;
margin: 0;
}
.overline {
font-size: 2rem;
letter-spacing: 0.1rem;
margin: 0;
}
.overline[data-button] {
border-bottom: 1px solid;
width: fit-content;
cursor: pointer;
}
.overline[data-button] a {
text-decoration: none;
}
.intro {
margin: 4.5rem 0;
display: inline-block;
width: fit-content;
}
.question-container {
margin: 3.5rem 0;
}
.question {
font-size: 2rem;
}
.answers-container {
margin: 1rem 0;
}
.answer {
display: inline-flex;
font-size: 1.8rem;
padding: 1.2rem 1.5rem;
margin-right: 0.75rem;
margin-bottom: 0.75rem;
border-radius: 24rem;
background-color: var(--color-secondary);
color: var(--color-primary);
outline: none !important;
border: none !important;
letter-spacing: 0.2rem;
text-transform: uppercase;
cursor: pointer;
}
.answer.selected {
background-color: var(--color-bright);
}
.answer.unselected {
background-color: var(--color-dim);
}
.symptom-container.subheader {
margin-top: 5rem;
margin-bottom: 2.5rem;
display: block !important;
}
.symptom-container.subheader .overline {
margin: 1rem 0;
}
.symptom-container {
margin-bottom: 5rem;
}
.symptom {
max-width: 100%;
padding: 1.5rem;
flex-direction: column;
justify-content: center;
align-items: center;
border: 1px solid transparent;
border-radius: 1rem;
transition: border-color ease-in-out 0.4s;
transition: box-shadow ease-in-out 0.3s;
}
.symptom.at-site {
background-color: var(--color-dim);
border-radius: 0;
}
.symptom.at-site:first-of-type {
border-top-left-radius: 1rem;
border-top-right-radius: 1rem;
}
.symptom.at-site:nth-of-type(3) {
border-bottom-left-radius: 1rem;
border-bottom-right-radius: 1rem;
}
.symptom-emoji {
text-align: center;
font-size: 3rem;
padding: 0.75rem;
display: block;
}
.symptom-name {
font-size: 2rem;
text-align: center;
display: block;
}
.symptom-chance {
font-size: 1.8rem;
text-align: center;
display: block;
}
.symptom-chance:before {
content: "EXPERIENCED BY";
font-size: 1rem;
display: block;
text-align: center;
letter-spacing: 0.1rem;
}
.symptom-chance:after {
content: "PEOPLE";
font-size: 1rem;
display: block;
text-align: center;
letter-spacing: 0.1rem;
}
footer {
padding: 5rem 3.75rem;
width: calc(100vw - 7.5rem);
margin-left: -3.75rem;
background-color: var(--color-secondary-light);
}
.link-container {
font-size: 1.2rem;
transition: none !important;
display: flex;
flex-direction: column;
}
.link-container > div {
flex: 1;
display: flex;
flex-direction: column;
color: var(--color-primary);
}
.link-container > div > .overline {
color: var(--color-primary);
}
.link-container > div:not(:first-of-type) {
margin-top: 3rem;
}
a {
color: var(--color);
margin-top: 0.75rem;
max-width: fit-content;
}
.link-container a {
font-size: 1.8rem;
}
footer .by {
color: var(--color-primary);
margin-top: 4rem;
}
@keyframes slideUp {
0% {
transform: translateY(300%);
}
100% {
transform: translateY(0);
}
}
.input-popup {
position: sticky;
background-color: var(--color-secondary-light);
bottom: 1rem;
height: 13.5rem;
margin-bottom: 7.5rem;
transition: height ease-in-out 0.3s;
overflow: hidden;
border-radius: 2rem;
max-height: 85vh;
display: flex;
flex-direction: column;
animation: 0.5s ease-out 0s 1 slideUp;
animation-delay: 0.5s;
animation-fill-mode: forwards;
transform: translateY(200%);
}
.input-popup * {
color: var(--color-primary);
}
.input-popup.expanded {
height: 80vh;
overflow-y: auto;
}
.input-popup .input-popup-header-icon {
transform: rotate(180deg);
}
.input-popup.expanded .input-popup-header-icon {
transform: rotate(0deg);
}
.input-popup-header {
padding: 2.5rem;
position: sticky;
top: 0;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
background-color: var(--color-secondary-light);
border-bottom: 1px solid transparent;
}
.input-popup.expanded .input-popup-header {
border-bottom: 1px solid var(--color-tertiary);
}
.input-popup-header-text {
flex: 1;
}
.input-popup-header-icon {
cursor: pointer;
background-color: var(--color-secondary);
outline: none;
color: var(--color-primary);
border: 1px solid transparent;
border-radius: 10rem;
height: 5rem;
width: 5rem;
}
.input-popup-body {
padding: 2.5rem 2.5rem;
flex: 1;
}
.input-popup-body .question-container .answers-container .answer {
background-color: var(--color-tertiary);
}
.input-popup-body .question-container .answers-container .answer.selected {
background-color: var(--color-secondary);
}
.input-popup-submit {
padding: 2.5rem;
text-align: center;
font-size: 2rem;
letter-spacing: 0.3rem;
background-color: var(--color-secondary);
cursor: pointer;
}
.input-popup.expanded .input-popup-submit {
position: sticky;
bottom: 0;
}
.input-popup-submit.submitted {
background-color: #55c16c;
}
@keyframes loading {
0% {
width: 0%;
}
100% {
width: 100%;
}
}
.loading-bar-container {
min-height: 2rem;
background-color: var(--color-secondary-light);
border-radius: 1rem;
margin-top: 1rem;
}
.loading-bar {
position: relative;
width: 1rem;
min-height: 2rem;
background-color: #25d255;
border-radius: 1rem;
animation: 2s ease-out 0s infinite loading;
}
@media (hover: hover) and (pointer: fine) {
.answer:hover,
.answer.unselected:hover {
background-color: var(--color-secondary-light);
}
.symptom:hover {
box-shadow: 0px 0px 100px var(--color-tertiary);
background-color: var(--color-primary);
}
.symptom.at-site:hover {
box-shadow: 0px 0px 100px var(--color-dim);
background-color: var(--color-secondary-light);
color: var(--color-primary);
}
.symptom.at-site:hover p {
color: var(--color-primary);
}
.input-popup-header-icon:hover {
background-color: var(--color-tertiary);
}
.input-popup-body .question-container .answers-container .answer:hover {
background-color: var(--color-bright);
}
.input-popup-submit:hover {
background-color: var(--color-tertiary);
}
}
* {
margin: 0;
padding: 0;
transition: all ease-in-out 0.2s;
color: var(--color-secondary);
user-select: none;
}
html {
font-size: 10px;
scroll-behavior: smooth;
}
body {
display: flex;
flex-direction: column;
font-size: 10px;
padding: 3.75rem;
padding-bottom: 0 !important;
height: calc(100vh - 3.75rem);
overflow-x: hidden;
max-width: 100vw;
background: var(--color-primary);
}
#root {
flex: 1;
display: flex;
}
.app-container {
flex: 1;
}
header {
display: flex;
justify-content: center;
flex-direction: column;
}
.logo-container {
display: flex;
width: fit-content;
justify-content: center;
flex-direction: column;
}
.logo {
background-size: 100%;
width: 5rem;
height: 5rem;
display: inline-block;
background-image: url("../logo512.png");
}
.logo-text-container {
justify-content: center;
vertical-align: middle;
flex-direction: column;
flex: 1;
margin-top: 3.5rem;
}
.logo-text-container p {
font-size: 2.4rem;
}
.header {
font-size: 10rem;
letter-spacing: 1rem;
}
.subheader {
font-size: 2.5rem;
margin: 0;
}
.overline {
font-size: 2rem;
letter-spacing: 0.1rem;
margin: 0;
}
.overline[data-button] {
border-bottom: 1px solid;
width: fit-content;
cursor: pointer;
}
.overline[data-button] a {
text-decoration: none;
}
.intro {
margin: 4.5rem 0;
display: inline-block;
width: fit-content;
}
.question-container {
margin: 3.5rem 0;
}
.question {
font-size: 2rem;
}
.answers-container {
margin: 1rem 0;
}
.answer {
display: inline-flex;
font-size: 1.8rem;
padding: 1.2rem 1.5rem;
margin-right: 0.75rem;
margin-bottom: 0.75rem;
border-radius: 24rem;
background-color: var(--color-secondary);
color: var(--color-primary);
outline: none !important;
border: none !important;
letter-spacing: 0.2rem;
text-transform: uppercase;
cursor: pointer;
}
.answer.selected {
background-color: var(--color-bright);
}
.answer.unselected {
background-color: var(--color-dim);
}
.symptom-container.subheader {
margin-top: 5rem;
margin-bottom: 2.5rem;
display: block !important;
}
.symptom-container.subheader .overline {
margin: 1rem 0;
}
.symptom-container {
margin-bottom: 5rem;
}
.symptom {
max-width: 100%;
padding: 1.5rem;
flex-direction: column;
justify-content: center;
align-items: center;
border: 1px solid transparent;
border-radius: 1rem;
transition: border-color ease-in-out 0.4s;
transition: box-shadow ease-in-out 0.3s;
}
.symptom.at-site {
background-color: var(--color-dim);
border-radius: 0;
}
.symptom.at-site:first-of-type {
border-top-left-radius: 1rem;
border-top-right-radius: 1rem;
}
.symptom.at-site:nth-of-type(3) {
border-bottom-left-radius: 1rem;
border-bottom-right-radius: 1rem;
}
.symptom-emoji {
text-align: center;
font-size: 3rem;
padding: 0.75rem;
display: block;
}
.symptom-name {
font-size: 2rem;
text-align: center;
display: block;
}
.symptom-chance {
font-size: 1.8rem;
text-align: center;
display: block;
}
.symptom-chance:before {
content: "EXPERIENCED BY";
font-size: 1rem;
display: block;
text-align: center;
letter-spacing: 0.1rem;
}
.symptom-chance:after {
content: "PEOPLE";
font-size: 1rem;
display: block;
text-align: center;
letter-spacing: 0.1rem;
}
footer {
padding: 5rem 3.75rem;
width: calc(100vw - 7.5rem);
margin-left: -3.75rem;
background-color: var(--color-secondary-light);
}
.link-container {
font-size: 1.2rem;
transition: none !important;
display: flex;
flex-direction: column;
}
.link-container > div {
flex: 1;
display: flex;
flex-direction: column;
color: var(--color-primary);
}
.link-container > div > .overline {
color: var(--color-primary);
}
.link-container > div:not(:first-of-type) {
margin-top: 3rem;
}
a {
color: var(--color);
margin-top: 0.75rem;
max-width: fit-content;
}
.link-container a {
font-size: 1.8rem;
}
footer .by {
color: var(--color-primary);
margin-top: 4rem;
}
@keyframes slideUp {
0% {
transform: translateY(300%);
}
100% {
transform: translateY(0);
}
}
.input-popup {
position: sticky;
background-color: var(--color-secondary-light);
bottom: 1rem;
height: 13.5rem;
margin-bottom: 7.5rem;
transition: height ease-in-out 0.3s;
overflow: hidden;
border-radius: 2rem;
max-height: 85vh;
display: flex;
flex-direction: column;
animation: 0.5s ease-out 0s 1 slideUp;
animation-delay: 0.5s;
animation-fill-mode: forwards;
transform: translateY(200%);
}
.input-popup * {
color: var(--color-primary);
}
.input-popup.expanded {
height: 80vh;
overflow-y: auto;
}
.input-popup .input-popup-header-icon {
transform: rotate(180deg);
}
.input-popup.expanded .input-popup-header-icon {
transform: rotate(0deg);
}
.input-popup-header {
padding: 2.5rem;
position: sticky;
top: 0;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
background-color: var(--color-secondary-light);
border-bottom: 1px solid transparent;
}
.input-popup.expanded .input-popup-header {
border-bottom: 1px solid var(--color-tertiary);
}
.input-popup-header-text {
flex: 1;
}
.input-popup-header-icon {
cursor: pointer;
background-color: var(--color-primary);
outline: none;
color: var(--color-secondary);
border: 1px solid transparent;
border-radius: 10rem;
height: 5rem;
width: 5rem;
}
.input-popup-body {
padding: 2.5rem 2.5rem;
flex: 1;
}
.input-popup-body .question-container .answers-container .answer {
background-color: var(--color-tertiary);
}
.input-popup-body .question-container .answers-container .answer.selected {
background-color: var(--color-secondary);
}
.input-popup-submit {
padding: 2.5rem;
text-align: center;
font-size: 2rem;
letter-spacing: 0.3rem;
background-color: var(--color-secondary);
cursor: pointer;
}
.input-popup.expanded .input-popup-submit {
position: sticky;
bottom: 0;
}
.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;
padding: 2rem 0;
margin: 2rem 0;
border-radius: 1rem;
margin-bottom: 2rem;
}
.tip-icon {
font-size: 3rem;
}
.tip .overline {
font-size: 1.6rem;
}
.tip .subheader {
font-size: 2rem;
letter-spacing: 0.2rem;
margin-top: 0.4rem;
}
.tip .header {
font-size: 6rem;
letter-spacing: 0.5rem;
}
.tip-container .overline[data-button] {
margin-top: 1rem;
}
.tip-container .overline[data-button]:first-of-type {
margin-top: 2rem;
}
@keyframes loading {
0% {
width: 0%;
}
100% {
width: 100%;
}
}
.loading-bar-container {
min-height: 2rem;
background-color: var(--color-secondary-light);
border-radius: 1rem;
margin-top: 1rem;
}
.loading-bar {
position: relative;
width: 1rem;
min-height: 2rem;
background-color: #25d255;
border-radius: 1rem;
animation: 2s ease-out 0s infinite loading;
}
.result-header-container {
display: flex;
align-items: center;
margin-top: 5rem;
flex-direction: column;
margin-bottom: 2rem;
border: 1px solid var(--color-secondary);
border-radius: 1rem;
padding: 3rem 2rem;
}
.result-header-container .symptom-container {
margin: 0;
flex: 1;
width: 100%;
}
.result-header-select {
width: 100%;
margin-top: 2rem;
}
.result-header-select .overline {
font-size: 1.6rem;
margin-bottom: 0.75rem;
}
.result-header-select .overline.errored {
margin-bottom: 0;
margin-top: 0.75rem;
color: #c43d34;
}
.result-header-select .overline.success {
margin-bottom: 0;
margin-top: 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) {
.answer:hover,
.answer.unselected:hover {
background-color: var(--color-secondary-light);
}
.symptom:hover {
box-shadow: 0px 0px 100px var(--color-tertiary);
background-color: var(--color-primary);
}
.symptom.at-site:hover {
box-shadow: 0px 0px 100px var(--color-dim);
background-color: var(--color-secondary-light);
color: var(--color-primary);
}
.symptom.at-site:hover p {
color: var(--color-primary);
}
.input-popup-header-icon:hover {
background-color: var(--color-tertiary);
}
.input-popup-body .question-container .answers-container .answer:hover {
background-color: var(--color-bright);
}
.input-popup-submit:hover {
background-color: var(--color-tertiary);
}
}
@@ -1,30 +1,30 @@
body {
padding: 15rem;
padding-top: 10rem;
height: calc(100vh - 10rem);
}
.logo {
width: 10rem;
height: 10rem;
}
.symptom {
max-width: 25rem;
height: 25rem;
}
footer {
padding: 5rem 15rem;
width: calc(100vw - 30rem);
margin-left: -15rem;
}
.input-popup {
height: 10rem;
}
.input-popup.expanded {
height: 50vh;
}
.loading-bar-container {
max-width: 35%;
}
body {
padding: 15rem;
padding-top: 10rem;
height: calc(100vh - 10rem);
}
.logo {
width: 10rem;
height: 10rem;
}
.symptom {
max-width: 25rem;
height: 25rem;
}
footer {
padding: 5rem 15rem;
width: calc(100vw - 30rem);
margin-left: -15rem;
}
.input-popup {
height: 10rem;
}
.input-popup.expanded {
height: 55vh;
}
.loading-bar-container {
max-width: 35%;
}
@@ -1,105 +1,135 @@
body {
padding: 7.5rem;
padding-top: 5rem;
height: calc(100vh - 5rem);
}
.logo-container {
flex-direction: row;
align-items: center;
justify-content: flex-start;
}
.logo {
width: 7.5rem;
height: 7.5rem;
}
.logo-text-container {
margin-top: 0;
margin-left: 1.5rem;
border-left: 1px solid var(--color-secondary);
padding-left: 1.5rem;
}
.intro .overline {
font-size: 3rem;
}
.intro .subheader {
font-size: 4rem;
}
.header {
font-size: 15rem;
letter-spacing: 1.5rem;
}
.overline[data-button] {
display: inline-block;
}
.overline[data-button]:not(:first-of-type) {
margin-left: 1.5rem;
}
.symptom {
width: 100%;
max-width: 20rem;
height: 20rem;
display: inline-flex;
margin-bottom: 0.75rem;
}
.symptom-emoji {
font-size: 3.5rem;
padding: 0.75rem;
}
.symptom-name {
font-size: 2.5rem;
text-align: center;
}
.symptom-chance {
font-size: 2.4rem;
text-align: center;
}
.symptom-chance:before {
font-size: 1.5rem;
}
.symptom-chance:after {
font-size: 1.5rem;
}
.symptom.at-site:first-of-type {
border-radius: 0;
border-top-left-radius: 1rem;
border-bottom-left-radius: 1rem;
}
.symptom.at-site:nth-of-type(3) {
border-radius: 0;
border-top-right-radius: 1rem;
border-bottom-right-radius: 1rem;
}
footer {
padding: 5rem 7.5rem;
width: calc(100vw - 15rem);
margin-left: -7.5rem;
}
.link-container {
font-size: 1.7rem;
flex-direction: row;
}
.link-container > div {
flex-direction: column;
flex: 1;
}
.link-container > div:not(:first-of-type) {
margin-left: 3rem;
margin-top: 0;
}
.input-popup {
height: 10rem;
}
.input-popup.expanded {
height: 55vh;
}
.loading-bar-container {
max-width: 50%;
}
body {
padding: 7.5rem;
padding-top: 5rem;
height: calc(100vh - 5rem);
}
.logo-container {
flex-direction: row;
align-items: center;
justify-content: flex-start;
}
.logo {
width: 7.5rem;
height: 7.5rem;
}
.logo-text-container {
margin-top: 0;
margin-left: 1.5rem;
border-left: 1px solid var(--color-secondary);
padding-left: 1.5rem;
}
.intro .overline {
font-size: 3rem;
}
.intro .subheader {
font-size: 4rem;
}
.header {
font-size: 15rem;
letter-spacing: 1.5rem;
}
.overline[data-button] {
display: inline-block;
}
.overline[data-button]:not(:first-of-type) {
margin-left: 1.5rem;
}
.symptom {
width: 100%;
max-width: 20rem;
height: 20rem;
display: inline-flex;
margin-bottom: 0.75rem;
}
.symptom-emoji {
font-size: 3.5rem;
padding: 0.75rem;
}
.symptom-name {
font-size: 2.5rem;
text-align: center;
}
.symptom-chance {
font-size: 2.4rem;
text-align: center;
}
.symptom-chance:before {
font-size: 1.5rem;
}
.symptom-chance:after {
font-size: 1.5rem;
}
.symptom.at-site:first-of-type {
border-radius: 0;
border-top-left-radius: 1rem;
border-bottom-left-radius: 1rem;
}
.symptom.at-site:nth-of-type(3) {
border-radius: 0;
border-top-right-radius: 1rem;
border-bottom-right-radius: 1rem;
}
footer {
padding: 5rem 7.5rem;
width: calc(100vw - 15rem);
margin-left: -7.5rem;
}
.link-container {
font-size: 1.7rem;
flex-direction: row;
}
.link-container > div {
flex-direction: column;
flex: 1;
}
.link-container > div:not(:first-of-type) {
margin-left: 3rem;
margin-top: 0;
}
.input-popup {
height: 10rem;
}
.input-popup.expanded {
height: 55vh;
}
.loading-bar-container {
max-width: 50%;
}
.tip-container .overline[data-button] {
margin-top: 2rem;
margin-left: 0;
}
.tip-container .overline[data-button]:last-of-type {
margin-left: 1.2rem;
}
.tip {
padding-left: 2rem;
}
.result-header-container {
flex-direction: row;
}
.result-header-container .symptom-container {
width: fit-content;
}
.result-header-select {
margin-top: 0rem;
width: fit-content;
padding-left: 3rem;
border-left: 1px solid var(--color-secondary);
}
.result-header-select select {
width: fit-content;
}
@@ -1,7 +1,7 @@
.input-popup {
height: 11.5rem;
}
.input-popup.expanded {
height: 85vh;
}
.input-popup {
height: 11.5rem;
}
.input-popup.expanded {
height: 85vh;
}
@@ -1,7 +1,7 @@
.input-popup {
height: 11rem;
}
.input-popup.expanded {
height: 65vh;
}
.input-popup {
height: 11rem;
}
.input-popup.expanded {
height: 65vh;
}
@@ -1,9 +1,9 @@
:root {
--color-primary: black;
--color-secondary: white;
--color-secondary-light: rgb(185, 185, 185);
--color-tertiary: rgb(105, 105, 105);
--color-bright: #636363;
--color-dim: #352f2f;
font-size: 10px;
}
:root {
--color-primary: black;
--color-secondary: white;
--color-secondary-light: rgb(185, 185, 185);
--color-tertiary: rgb(105, 105, 105);
--color-bright: #636363;
--color-dim: #352f2f;
font-size: 10px;
}
@@ -1,9 +1,9 @@
:root {
--color-primary: white;
--color-secondary: black;
--color-secondary-light: rgb(56, 56, 56);
--color-tertiary: rgba(185, 185, 185, 0.459);
--color-bright: #575757;
--color-dim: #aeadb0;
font-size: 10px;
}
:root {
--color-primary: white;
--color-secondary: black;
--color-secondary-light: rgb(56, 56, 56);
--color-tertiary: rgba(185, 185, 185, 0.459);
--color-bright: #575757;
--color-dim: #aeadb0;
font-size: 10px;
}
-16937
View File
File diff suppressed because it is too large Load Diff
-38
View File
@@ -1,38 +0,0 @@
{
"name": "vaxandme",
"version": "0.1.0",
"private": true,
"dependencies": {
"firebase": "^8.4.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-scripts": "4.0.3",
"web-vitals": "^1.1.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"deploy": "firebase deploy --only hosting",
"serve" : "firebase serve --only hosting"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
-142
View File
@@ -1,142 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Google Tag Manager -->
<script>
(function (w, d, s, l, i) {
w[l] = w[l] || [];
w[l].push({ "gtm.start": new Date().getTime(), event: "gtm.js" });
var f = d.getElementsByTagName(s)[0],
j = d.createElement(s),
dl = l != "dataLayer" ? "&l=" + l : "";
j.async = true;
j.src = "https://www.googletagmanager.com/gtm.js?id=" + i + dl;
f.parentNode.insertBefore(j, f);
})(window, document, "script", "dataLayer", "GTM-K4XHBR6");
</script>
<!-- End Google Tag Manager -->
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Learn about the expected side effects of COVID-19 Vaccines"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<style>
@import "%PUBLIC_URL%/styles/variables.css";
@import "%PUBLIC_URL%/styles/variables-dark.css" screen and
(prefers-color-scheme: dark);
@import "%PUBLIC_URL%/styles/extrasmall.css";
@import "%PUBLIC_URL%/styles/small.css" only screen and (min-width: 370px)
and (max-width: 767px);
@import "%PUBLIC_URL%/styles/smallmedium.css" only screen and
(min-width: 768px) and (max-width: 1023px);
@import "%PUBLIC_URL%/styles/medium.css" only screen and
(min-width: 1024px);
@import "%PUBLIC_URL%/styles/large.css" only screen and
(min-width: 1366px);
@import "%PUBLIC_URL%/styles/extralarge.css" only screen and
(min-width: 1921px);
@font-face {
font-family: "GlacialBold";
src: url("%PUBLIC_URL%/fonts/glacialindifference-bold-webfont.woff2")
format("woff2"),
url("/fonts/glacialindifference-bold-webfont.woff") format("woff");
font-weight: normal;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "GlacialItalic";
src: url("%PUBLIC_URL%/fonts/glacialindifference-italic-webfont.woff2")
format("woff2"),
url("%PUBLIC_URL%/fonts/glacialindifference-italic-webfont.woff")
format("woff");
font-weight: normal;
font-style: normal;
font-display: swap;
}
@font-face {
font-family: "Glacial";
src: url("%PUBLIC_URL%/fonts/glacialindifference-regular-webfont.woff2")
format("woff2"),
url("%PUBLIC_URL%/fonts/glacialindifference-regular-webfont.woff")
format("woff");
font-weight: normal;
font-style: normal;
font-display: swap;
}
[data-font="sans"] {
font-family: "Glacial", sans-serif;
font-display: swap;
}
[data-font="sans-bold"] {
font-family: "GlacialBold", sans-serif;
font-display: swap;
}
[data-font="sans-italic"] {
font-family: "GlacialItalic", sans-serif;
font-style: italic;
font-display: swap;
}
.logo {
background-image: url("%PUBLIC_URL%/logo512.png");
}
</style>
<!-- Google Analytics -->
<script
async
src="https://www.googletagmanager.com/gtag/js?id=G-7VZCY223NG"
></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag("js", new Date());
gtag("config", "G-7VZCY223NG");
</script>
<title>Vax & Me</title>
</head>
<body>
<!-- Google Tag Manager (noscript) -->
<noscript>
<iframe
src="https://www.googletagmanager.com/ns.html?id=GTM-K4XHBR6"
height="0"
width="0"
style="display: none; visibility: hidden"
>
</iframe>
</noscript>
<!-- End Google Tag Manager (noscript) -->
<div id="root"></div>
<footer data-font="sans">
<div class="link-container">
<div>
<h6 class="overline" data-font="sans">FDA Data Sources</h6>
<a href="https://www.fda.gov/media/144416/download">PFizer-BioNTech</a>
<a href="https://www.fda.gov/media/144637/download">Moderna</a>
<a href="https://www.fda.gov/media/146304/download">J&J Janssen</a>
</div>
<div>
<h6 class="overline" data-font="sans">Links</h6>
<a href="%PUBLIC_URL%/vaxandme_chart.pdf">Download Chart</a>
<a href="/">Home</a>
</div>
<div>
<h6 class="overline" data-font="sans">Legal</h6>
<a href="/copyright">Copyright</a>
<a href="/privacy">Privacy</a>
</div>
</div>
<div class="overline by" data-font="sans">
Designed &amp; Developed with ❤ by Alba Rajanibala and Ayushya Amitabh
</div>
</footer>
</body>
</html>
-669
View File
@@ -1,669 +0,0 @@
import React from "react";
import ReactDOM from "react-dom";
import firebase from "firebase/app";
import "firebase/functions";
const FIREBASE_CONFIG = {
apiKey: "AIzaSyDKw8HXWRn3dtkIRETv-BxtwnklZIpIkxU",
authDomain: "vaxandme.firebaseapp.com",
projectId: "vaxandme",
storageBucket: "vaxandme.appspot.com",
messagingSenderId: "614738281692",
appId: "1:614738281692:web:7a89e0af76675e4f0ea019",
measurementId: "G-N016TVJ6JC",
};
firebase.initializeApp(FIREBASE_CONFIG);
if (window.location.host.startsWith("localhost")) {
firebase.functions().useEmulator("localhost", 5001);
}
const fb_functions = firebase.functions();
const saveResult = fb_functions.httpsCallable("saveResult");
const getPastResult = fb_functions.httpsCallable("getPastResult");
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",
},
};
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",
};
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",
};
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",
};
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",
};
const MD_DOSE1_YOUNGER_RESULT = {
"PAIN AT SITE": "9",
"RED AT SITE": "<1",
"SWELLING AT SITE": "<1",
HEADACHE: "4",
FATIGUE: "4",
"MUSCLE PAIN": "2",
"JOINT PAIN": "2",
"NAUSEA OR VOMITING": "1",
FEVER: "1",
CHILLS: "1",
};
const MD_DOSE2_YOUNGER_RESULT = {
"PAIN AT SITE": "9",
"RED AT SITE": "1",
"SWELLING AT SITE": "1",
FATIGUE: "7",
HEADACHE: "6",
"JOINT PAIN": "5",
CHILLS: "5",
FEVER: "2",
"NAUSEA OR VOMITING": "2",
"MUSCLE PAIN": "1",
};
const MD_DOSE1_OLDER_RESULT = {
"PAIN AT SITE": "7",
"RED AT SITE": "<1",
"SWELLING AT SITE": "<1",
HEADACHE: "3",
FATIGUE: "3",
"MUSCLE PAIN": "2",
"JOINT PAIN": "2",
"NAUSEA OR VOMITING": "1",
CHILLS: "1",
FEVER: "<1",
};
const MD_DOSE2_OLDER_RESULT = {
"PAIN AT SITE": "8",
"RED AT SITE": "1",
"SWELLING AT SITE": "1",
FATIGUE: "6",
HEADACHE: "5",
"MUSCLE PAIN": "5",
"JOINT PAIN": "4",
CHILLS: "3",
"NAUSEA OR VOMITING": "1",
FEVER: "1",
};
const JJ_YOUNGER_RESULT = {
"PAIN AT SITE": "6",
"RED AT SITE": "1",
"SWELLING AT SITE": "1",
HEADACHE: "4",
FATIGUE: "4",
"MUSCLE PAIN": "4",
"NEED PAIN MED": "3",
"NAUSEA OR VOMITING": "2",
FEVER: "1",
};
const JJ_OLDER_RESULT = {
"PAIN AT SITE": "3",
"RED AT SITE": "<1",
"SWELLING AT SITE": "<1",
HEADACHE: "3",
FATIGUE: "3",
"MUSCLE PAIN": "2",
"NAUSEA OR VOMITING": "1",
"NEED PAIN MED": "1",
FEVER: "<1",
};
const VAX_RESULTS = {
"Pfizer-BioNTech": {
"Dose 1": {
"18 - 55": PB_DOSE1_YOUNGER_RESULT,
"56 & Older": PB_DOSE1_OLDER_RESULT,
},
"Dose 2": {
"18 - 55": PB_DOSE2_YOUNGER_RESULT,
"56 & Older": PB_DOSE2_OLDER_RESULT,
},
},
Moderna: {
"Dose 1": {
"18 - 64": MD_DOSE1_YOUNGER_RESULT,
"65 & Older": MD_DOSE1_OLDER_RESULT,
},
"Dose 2": {
"18 - 64": MD_DOSE2_YOUNGER_RESULT,
"65 & Older": MD_DOSE2_OLDER_RESULT,
},
},
"J&J Janssen": {
"18 - 59": JJ_YOUNGER_RESULT,
"60 & Older": JJ_OLDER_RESULT,
},
};
const ICONS = {
"PAIN AT SITE": "💪",
"RED AT SITE": "🔴",
"SWELLING AT SITE": "💢",
FATIGUE: "🥱",
HEADACHE: "🤕",
"NEED PAIN MED": "💊",
"MUSCLE PAIN": "😫",
CHILLS: "🥶",
DIRRHEA: "💩",
"JOINT PAIN": "🦵",
FEVER: "🤒",
VOMITING: "🤮",
"NAUSEA OR VOMITING": "🤮",
};
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
name: "",
dose: "",
age: "",
gid: "",
showInputPopup: false,
answers: {},
loading: true,
};
}
componentDidMount() {
const params = window.location.pathname
.toUpperCase()
.split("/")
.filter((v) => v.length > 0);
if (params) {
if (params[0] && VAX_NAMES[params[0]]) {
const name = VAX_NAMES[params[0]];
this.setState({ name });
switch (name) {
case VAX_NAMES.PB:
case VAX_NAMES.MD:
if (params[1] && VAX_DOSES[params[1]]) {
const dose = VAX_DOSES[params[1]];
this.setState({ dose });
if (params[2] && VAX_AGES[name][params[2]]) {
const age = VAX_AGES[name][params[2]];
this.setState({ age });
}
}
break;
case VAX_NAMES.JJ:
if (params[1] && VAX_AGES[name][params[1]]) {
const age = VAX_AGES[name][params[1]];
this.setState({ age });
}
break;
default:
break;
}
}
}
if (!window.localStorage.getItem("hasExistingAnswer")) {
this.setState({ loading: false });
}
if (window.gtag) {
window.gtag("get", "G-7VZCY223NG", "client_id", (client_id) => {
if (!!client_id) {
this.setState({ gid: client_id });
getPastResult({ gid: client_id })
.then((v) => {
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 });
const inputPopupSubmit = document.querySelector(
".input-popup-submit"
);
if (inputPopupSubmit) {
inputPopupSubmit.classList.add("submitted");
inputPopupSubmit.innerHTML = "UPDATE ANSWER";
}
window.localStorage.setItem("hasExistingAnswer", true);
} else {
this.setState({ loading: false });
}
})
.catch((err) => {
console.error("ERROR Getting Past Answer", err);
this.setState({ loading: false });
});
}
});
} else {
this.setState({ loading: false });
}
}
shouldShowAgeGroup = () => {
const { name, dose } = this.state;
switch (name) {
case VAX_NAMES.JJ:
return true;
case VAX_NAMES.MD:
case VAX_NAMES.PB:
return !!dose;
default:
return false;
}
};
shouldShowResults = () => {
const { name, dose, age } = this.state;
switch (name) {
case VAX_NAMES.JJ:
return !!age;
case VAX_NAMES.MD:
case VAX_NAMES.PB:
return !!dose && !!age;
default:
return false;
}
};
getResults = () => {
const { name, dose, age } = this.state;
switch (name) {
case VAX_NAMES.JJ:
return VAX_RESULTS[name][age];
case VAX_NAMES.MD:
case VAX_NAMES.PB:
return VAX_RESULTS[name][dose][age];
default:
return null;
}
};
copyShareLink = () => {
const { name, dose, age } = this.state;
let SHARE_URL = window.location.host;
const serialize_name = Object.keys(VAX_NAMES).filter(
(k) => VAX_NAMES[k] === name
)[0];
const serialize_dose = Object.keys(VAX_DOSES).filter(
(k) => VAX_DOSES[k] === dose
)[0];
const serialize_age = Object.keys(VAX_AGES[name]).filter(
(k) => VAX_AGES[name][k] === age
)[0];
if (serialize_name) {
SHARE_URL += `/${serialize_name}`;
}
if (serialize_dose) {
SHARE_URL += `/${serialize_dose}`;
}
if (serialize_age) {
SHARE_URL += `/${serialize_age}`;
}
const copyTextInput = document.createElement("input");
document.body.appendChild(copyTextInput);
copyTextInput.value = SHARE_URL.toLowerCase();
copyTextInput.select();
document.execCommand("copy");
copyTextInput.remove();
document.querySelector("#share-result").innerHTML = "Copied Link";
setTimeout(() => {
document.querySelector("#share-result").innerHTML = "Share ↗";
}, 1500);
};
updateAnswers = (symptom) => {
const { answers } = this.state;
const newAnswers = Object.assign({}, answers);
if (answers[symptom]) {
newAnswers[symptom] = !answers[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 symptoms = {};
Object.keys(result).forEach((symptom) => {
symptoms[symptom] = false;
});
const submitAnswers = Object.assign({}, symptoms, answers, {
name,
dose,
age,
gid,
});
saveResult(submitAnswers)
.then(() => {
const inputPopupSubmit = document.querySelector(".input-popup-submit");
if (!inputPopupSubmit.classList.contains("submitted")) {
inputPopupSubmit.classList.add("submitted");
}
inputPopupSubmit.innerHTML = "THANK YOU!";
setTimeout(() => {
inputPopupSubmit.innerHTML = "UPDATE ANSWER";
}, 1500);
})
.catch((err) => console.error("ERROR Saving Answer", err));
};
render() {
const { name, dose, age, showInputPopup, answers, loading } = this.state;
let result = {};
let resultAtSite = {};
if (this.shouldShowResults()) {
result = Object.assign({}, this.getResults());
Object.keys(result).forEach((s) => {
if (s.includes("AT SITE")) {
resultAtSite[s] = result[s];
delete result[s];
}
});
}
return (
<div className="app-container">
<header>
<div className="logo-container">
<div className="logo"> </div>
</div>
<div className="intro">
<h6 className="overline" data-font="sans">
Getting vaccinated?
</h6>
<h3 className="subheader" data-font="sans-bold">
Find out what to expect.
</h3>
</div>
</header>
<main>
{loading ? (
<div className="loading-container">
<p className="question" data-font="sans">
Checking for existing answers...
</p>
<div className="loading-bar-container">
<div className="loading-bar"></div>
</div>
</div>
) : null}
{!loading ? (
<div className="question-container">
<p className="question" data-font="sans-italic">
Select Vaccine
</p>
<div className="answers-container">
{Object.values(VAX_NAMES).map((v) => (
<button
key={`name-group-${v}`}
onClick={() =>
this.setState({
name: v,
dose: "",
age: "",
answers: {},
showInputPopup: false,
})
}
data-font="sans-bold"
className={`vaccine answer${name === v ? " selected" : ""}${
name && name !== v ? " unselected" : ""
}`}
>
{v}
</button>
))}
</div>
</div>
) : null}
{name && (name === VAX_NAMES.PB || name === VAX_NAMES.MD) ? (
<div className="question-container">
<p className="question" data-font="sans-italic">
Select Dose
</p>
<div className="answers-container">
{Object.values(VAX_DOSES).map((v) => (
<button
key={`dose-group-${v}`}
onClick={() =>
this.setState({
dose: v,
age: "",
answers: {},
showInputPopup: false,
})
}
data-font="sans-bold"
className={`dose answer${dose === v ? " selected" : ""}${
dose && dose !== v ? " unselected" : ""
}`}
>
{v}
</button>
))}
</div>
</div>
) : null}
{this.shouldShowAgeGroup() ? (
<div className="question-container">
<p className="question" data-font="sans-italic">
Select Age Group
</p>
<div className="answers-container">
{Object.values(VAX_AGES[name]).map((v) => (
<button
key={`age-group-${v}`}
onClick={() =>
this.setState({
age: v,
answers: {},
showInputPopup: false,
})
}
data-font="sans-bold"
className={`age answer${age === v ? " selected" : ""}${
age && age !== v ? " unselected" : ""
}`}
>
{v}
</button>
))}
</div>
</div>
) : null}
{this.shouldShowResults() ? (
<div className="symptom-container subheader">
<h3 data-font="sans-bold">Here's what to expect.</h3>
<h6
id="share-result"
onClick={this.copyShareLink}
className="overline"
data-font="sans"
data-button
>
Share ↗
</h6>
<h6 className="overline" data-font="sans" data-button>
<a href="/vaxandme_chart.pdf">Download Chart ↗</a>
</h6>
</div>
) : null}
{this.shouldShowResults() ? (
<div className="symptom-container">
{Object.keys(resultAtSite).map((symptom) => (
<div className="symptom at-site" key={`symptom-${symptom}`}>
<span className="symptom-emoji">{ICONS[symptom]}</span>
<p data-font="sans" className="symptom-name">
{symptom}
</p>
<p data-font="sans-bold" className="symptom-chance">
{resultAtSite[symptom]}/10
</p>
</div>
))}
{Object.keys(result).map((symptom) => (
<div className="symptom" key={`symptom-${symptom}`}>
<span className="symptom-emoji">{ICONS[symptom]}</span>
<p data-font="sans" className="symptom-name">
{symptom}
</p>
<p data-font="sans-bold" className="symptom-chance">
{result[symptom]}/10
</p>
</div>
))}
</div>
) : null}
</main>
{this.shouldShowResults() ? (
<div className={`input-popup${showInputPopup ? " expanded" : ""}`}>
<div
className="input-popup-header"
onClick={() => this.setState({ showInputPopup: !showInputPopup })}
>
<div className="input-popup-header-text">
<h6 className="overline" data-font="sans">
Already vaxxed?
</h6>
<h3 className="subheader" data-font="sans-bold">
Tell us how it went.
</h3>
</div>
<button
data-font="sans"
className="subheader input-popup-header-icon"
onClick={() =>
this.setState({ showInputPopup: !showInputPopup })
}
>
&#9660;
</button>
</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
<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>
<div className="question-container">
<p className="question" data-font="sans">
You can comeback and update your experience later!
</p>
<p className="question" data-font="sans-italic">
(Just use the same device)
</p>
</div>
</div>
<div
onClick={this.submitAnswer}
className="input-popup-submit"
data-font="sans-bold"
>
SUBMIT
</div>
</div>
) : null}
</div>
);
}
}
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.querySelector("#root")
);