Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/deploy-preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ on:
pull_request:
paths:
- "public/**"
- "package*json"

jobs:
build_and_preview:
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/deploy-prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ on:
- main
paths:
- "public/**"
- "package*json"

jobs:
deploy_live_website:
Expand Down
2,673 changes: 1,479 additions & 1,194 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"cytoscape-fcose": "^2.2.0",
"d3": "^7.8.2",
"d3-sankey": "^0.12.3",
"firebase": "^10.8.0",
"firebase": "^12.1.0",
"jieba-wasm": "^0.0.2"
},
"jshintConfig": {
Expand Down
1 change: 1 addition & 0 deletions public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -452,6 +452,7 @@ <h3>What is the flow diagram?</h3>
</div>
<div class="menu-item active-link" id="exportStudyListButton" style="display:none">Export study
list</div>
<div class="menu-item" id="debug">debug</div>
</main>
</div>
<div id="menu-popover" popover></div>
Expand Down
104 changes: 93 additions & 11 deletions public/js/modules/data-layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -358,26 +358,93 @@ let getResultCount = function (results) {
return (results[studyResult.CORRECT] || 0) + (results[studyResult.INCORRECT] || 0);
}

let authStateUnsubscribe = null;
let studyListUnsubscribe = null;
let hourlyUnsubscribe = null;
let dailyUnsubscribe = null;
let permissionsUnsubscribe = null;
let receivedAuthEventCount = 0;
let receivedStudyListEventCount = 0;
let receivedPermissionsEventCount = 0;
let receivedDailyEventCount = 0;
let receivedHourlyEventCount = 0;
let lastStudyListTimestamp = Date.now();
let lastAuthTimestamp = Date.now();
let debugString = '';
let intervalCount = 0;
let db = null;
let app = null;
let auth = null;
let freezeCount = 0;
let lastFreeze = null;
let resumeCount = 0;
let lastResume = null;
let hiddenCount = 0;
let lastHidden = null;
let visibleCount = 0;
let lastVisible = null;

const debugElement = document.getElementById('debug');
function getDebug() {
return `hidden: ${hiddenCount}; ${lastHidden}<br>vis: ${visibleCount}; ${lastVisible}<br>resume: ${resumeCount}; ${lastResume}<br>freeze: ${freezeCount}; ${lastFreeze}<br>uid: ${authenticatedUser.uid}<br>unsubscribe: ${JSON.stringify(studyListUnsubscribe)}<br>errors: ${debugString}<br>auth events: ${receivedAuthEventCount}<br>study list events: ${receivedStudyListEventCount}<br>perms: ${receivedPermissionsEventCount}<br>daily: ${receivedDailyEventCount}<br>hourly: ${receivedHourlyEventCount}<br>studylist update time: ${lastStudyListTimestamp}<br>authstate update time: ${lastAuthTimestamp}<br>interval fired: ${intervalCount}`;
}//db: ${JSON.stringify(db)}<br>app: ${JSON.stringify(app)}<br>auth:${JSON.stringify(auth)}
setInterval(() => {
intervalCount++;
debugElement.innerHTML = getDebug();
}, 15000);

let initialize = function () {
let auth = getAuth();
const app = getApp();
initializeFirestore(app,
auth = getAuth();
app = getApp();
db = initializeFirestore(app,
{
localCache:
persistentLocalCache(/*settings*/{})
});
setupFirestoreListeners();
document.addEventListener('force-debug', function () {
debugElement.innerHTML = getDebug();
});
document.addEventListener('freeze', function () {
freezeCount++;
lastFreeze = Date.now();
});
document.addEventListener('resume', function () {
resumeCount++;
lastResume = Date.now();
});
document.addEventListener("visibilitychange", () => {
if (document.hidden) {
hiddenCount++;
lastHidden = Date.now();
studyListUnsubscribe();
hourlyUnsubscribe();
dailyUnsubscribe();
permissionsUnsubscribe();
} else {
// Page became visible
visibleCount++;
lastVisible = Date.now();
setupFirestoreListeners();
}
});
};

// TODO cancel callback?
onAuthStateChanged(auth, (user) => {
function setupFirestoreListeners() {
authStateUnsubscribe = onAuthStateChanged(auth, (user) => {
receivedAuthEventCount++;
lastAuthTimestamp = Date.now();
if (user) {
authenticatedUser = user;
//TODO get study results here, too
const db = getFirestore();
// db = getFirestore();

let localStudyList = JSON.parse(localStorage.getItem('studyList'));
let localStudyResults = JSON.parse(localStorage.getItem('studyResults'));
//TODO: these are all horribly repetitive and overengineered
onSnapshot(collection(db, `users/${authenticatedUser.uid}/studyList`), { includeMetadataChanges: true }, (doc) => {
studyListUnsubscribe = onSnapshot(collection(db, `users/${authenticatedUser.uid}/studyList`), { includeMetadataChanges: true }, (doc) => {
receivedStudyListEventCount++;
lastStudyListTimestamp = Date.now();
// if hasPendingWrites is true, we're getting a notification for our own write; ignore
// unless it's fromCache, possibly indicating offline updates
// TODO: is this or clause effectively just making this always get entered?
Expand Down Expand Up @@ -471,9 +538,12 @@ let initialize = function () {
callbacks[dataTypes.studyList].forEach(x => x(studyList));
}
}
}, (error) => {
debugString += JSON.stringify(error);
});
// TODO: combine hourly and daily
onSnapshot(collection(db, `users/${authenticatedUser.uid}/hourly`), { includeMetadataChanges: true }, (doc) => {
hourlyUnsubscribe = onSnapshot(collection(db, `users/${authenticatedUser.uid}/hourly`), { includeMetadataChanges: true }, (doc) => {
receivedHourlyEventCount++;
if (!doc.metadata.hasPendingWrites || doc.metadata.fromCache) {
let serverHourly = {};
for (const item of doc.docChanges()) {
Expand Down Expand Up @@ -512,8 +582,11 @@ let initialize = function () {
}
}
}
}, (error) => {
debugString += JSON.stringify(error);
});
onSnapshot(collection(db, `users/${authenticatedUser.uid}/daily`), { includeMetadataChanges: true }, (doc) => {
dailyUnsubscribe = onSnapshot(collection(db, `users/${authenticatedUser.uid}/daily`), { includeMetadataChanges: true }, (doc) => {
receivedDailyEventCount++;
if (!doc.metadata.hasPendingWrites || doc.metadata.fromCache) {
let serverDaily = {};
for (const item of doc.docChanges()) {
Expand Down Expand Up @@ -550,20 +623,29 @@ let initialize = function () {
}
}
}
}, (error) => {
debugString += JSON.stringify(error);
});

// users have permission to read their own doc in permissions, but not to write it.
onSnapshot(doc(db, `permissions/${authenticatedUser.uid}`), doc => {
permissionsUnsubscribe = onSnapshot(doc(db, `permissions/${authenticatedUser.uid}`), doc => {
receivedPermissionsEventCount++;
aiEligible = (doc && doc.get('ai') === true);
document.dispatchEvent(new CustomEvent('ai-eligibility-changed', { detail: aiEligible }));
}, (error) => {
debugString += JSON.stringify(error);
})
} else {
// no signed in user means no AI features.
aiEligible = false;
document.dispatchEvent(new CustomEvent('ai-eligibility-changed', { detail: aiEligible }));
studyListUnsubscribe();
hourlyUnsubscribe();
dailyUnsubscribe();
permissionsUnsubscribe();
}
});
};
}

let readOptionState = function () {
return JSON.parse(localStorage.getItem('options'));
Expand Down
1 change: 1 addition & 0 deletions public/js/modules/ui-orchestrator.js
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,7 @@ function handleTouchMove(event) {

function initialize() {
leftButtonContainer.addEventListener('click', function () {
document.dispatchEvent(new CustomEvent('force-debug'));
if (states[currentState].leftState) {
switchToState(states[currentState].leftState);
}
Expand Down