it should note in the console all the tracking points we want
Browse filesinstrument the prototype to collect data in the browsers local storage, basically providing it as a fake backend. This directly refers to my revised KPIs for the two workflows.
Data Connection
Total_post_creation_time: the prototype tracks the exact time in seconds from the moment the user enters the dashboard until they've successfully clicked the submit button. This is a great way to measure efficiency.
Form_adherance: I have adjusted from my previous intention of a human observer tracking the users ability to post acceptable content, and instead the prototype now logs an error event if the user submits malformed or empty parts of the post.
Unanswered_filter_interaction_time: Regarding the search workflow, another timer instance measures how long it takes for the user to locate and click a result (fake result at that).
|
@@ -12,12 +12,12 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
| 12 |
const allQuestionsLink = document.getElementById('all-questions-link');
|
| 13 |
const myPostsLink = document.getElementById('my-posts-link');
|
| 14 |
const unansweredLink = document.getElementById('unanswered-link');
|
| 15 |
-
|
| 16 |
// Data collection variables
|
| 17 |
let dashboardEntryTime = Date.now();
|
| 18 |
let postCreationStartTime = null;
|
| 19 |
let unansweredFilterStartTime = null;
|
| 20 |
-
|
|
|
|
| 21 |
const samplePosts = [
|
| 22 |
{
|
| 23 |
id: 1,
|
|
@@ -38,12 +38,13 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
| 38 |
hasNewResponse: false
|
| 39 |
}
|
| 40 |
];
|
| 41 |
-
|
| 42 |
// Initialize data collection
|
| 43 |
initializeDataCollection();
|
| 44 |
let userPosts = [];
|
| 45 |
|
| 46 |
-
//
|
|
|
|
|
|
|
| 47 |
document.getElementById('post-title').addEventListener('focus', function() {
|
| 48 |
if (!postCreationStartTime) {
|
| 49 |
postCreationStartTime = Date.now();
|
|
@@ -61,7 +62,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
| 61 |
postCreationStartTime = Date.now();
|
| 62 |
}
|
| 63 |
});
|
| 64 |
-
// Form submission
|
| 65 |
postForm.addEventListener('submit', function(e) {
|
| 66 |
e.preventDefault();
|
| 67 |
|
|
@@ -74,14 +75,17 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
| 74 |
if (!title.trim()) {
|
| 75 |
logFormError('empty_title');
|
| 76 |
formErrors++;
|
|
|
|
| 77 |
}
|
| 78 |
if (!body.trim()) {
|
| 79 |
logFormError('empty_body');
|
| 80 |
formErrors++;
|
|
|
|
| 81 |
}
|
| 82 |
if (tags.length === 0 || (tags.length === 1 && !tags[0].trim())) {
|
| 83 |
logFormError('empty_tags');
|
| 84 |
formErrors++;
|
|
|
|
| 85 |
}
|
| 86 |
|
| 87 |
// Calculate total post creation time
|
|
@@ -91,6 +95,15 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
| 91 |
storeKPIData('total_post_creation_time', totalPostCreationTime);
|
| 92 |
storeKPIData('form_adherance', formErrors);
|
| 93 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 94 |
// Create new post
|
| 95 |
const newPost = {
|
| 96 |
id: Date.now(),
|
|
@@ -333,7 +346,6 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
| 333 |
setActiveNav(myPostsLink);
|
| 334 |
showPanel3();
|
| 335 |
});
|
| 336 |
-
|
| 337 |
unansweredLink.addEventListener('click', function(e) {
|
| 338 |
e.preventDefault();
|
| 339 |
setActiveNav(unansweredLink);
|
|
@@ -341,6 +353,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
| 341 |
|
| 342 |
// Start unanswered filter interaction timer
|
| 343 |
unansweredFilterStartTime = Date.now();
|
|
|
|
| 344 |
});
|
| 345 |
// Add event listeners for new navigation items
|
| 346 |
document.getElementById('recent-link').addEventListener('click', function(e) {
|
|
@@ -383,7 +396,6 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
| 383 |
});
|
| 384 |
});
|
| 385 |
}
|
| 386 |
-
|
| 387 |
function storeKPIData(kpiName, value) {
|
| 388 |
const kpiData = JSON.parse(localStorage.getItem('piazza_kpi_data') || {};
|
| 389 |
if (!kpiData[kpiName]) {
|
|
@@ -394,8 +406,13 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
| 394 |
timestamp: Date.now()
|
| 395 |
});
|
| 396 |
localStorage.setItem('piazza_kpi_data', JSON.stringify(kpiData));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 397 |
}
|
| 398 |
-
|
| 399 |
function logFormError(errorType) {
|
| 400 |
const errorData = JSON.parse(localStorage.getItem('piazza_form_errors') || {};
|
| 401 |
if (!errorData[errorType]) {
|
|
@@ -403,6 +420,11 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
| 403 |
}
|
| 404 |
errorData[errorType]++;
|
| 405 |
localStorage.setItem('piazza_form_errors', JSON.stringify(errorData));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 406 |
}
|
| 407 |
function showPanel1() {
|
| 408 |
panel1.classList.remove('hidden');
|
|
@@ -414,6 +436,10 @@ function showPanel1() {
|
|
| 414 |
panel2.classList.remove('hidden');
|
| 415 |
panel3.classList.add('hidden');
|
| 416 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 417 |
// Clear existing posts and add unanswered content
|
| 418 |
postsList.innerHTML = '';
|
| 419 |
|
|
@@ -459,7 +485,27 @@ function showPanel1() {
|
|
| 459 |
unansweredCount.textContent = window.placeholderPosts.length;
|
| 460 |
postsList.appendChild(feedContainer);
|
| 461 |
feather.replace();
|
| 462 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 463 |
const sidebar = document.querySelector('custom-sidebar');
|
| 464 |
if (sidebar) {
|
| 465 |
const shadow = sidebar.shadowRoot;
|
|
@@ -472,8 +518,7 @@ postsList.appendChild(feedContainer);
|
|
| 472 |
});
|
| 473 |
}
|
| 474 |
}
|
| 475 |
-
|
| 476 |
-
function showRecentPanel() {
|
| 477 |
panel1.classList.add('hidden');
|
| 478 |
panel2.classList.remove('hidden');
|
| 479 |
panel3.classList.add('hidden');
|
|
|
|
| 12 |
const allQuestionsLink = document.getElementById('all-questions-link');
|
| 13 |
const myPostsLink = document.getElementById('my-posts-link');
|
| 14 |
const unansweredLink = document.getElementById('unanswered-link');
|
|
|
|
| 15 |
// Data collection variables
|
| 16 |
let dashboardEntryTime = Date.now();
|
| 17 |
let postCreationStartTime = null;
|
| 18 |
let unansweredFilterStartTime = null;
|
| 19 |
+
let unansweredFilterInteractionStartTime = null;
|
| 20 |
+
// Sample data
|
| 21 |
const samplePosts = [
|
| 22 |
{
|
| 23 |
id: 1,
|
|
|
|
| 38 |
hasNewResponse: false
|
| 39 |
}
|
| 40 |
];
|
|
|
|
| 41 |
// Initialize data collection
|
| 42 |
initializeDataCollection();
|
| 43 |
let userPosts = [];
|
| 44 |
|
| 45 |
+
// Log dashboard entry
|
| 46 |
+
console.log('π Dashboard entry time recorded:', dashboardEntryTime);
|
| 47 |
+
// Add event listeners for form inputs to start post creation timer
|
| 48 |
document.getElementById('post-title').addEventListener('focus', function() {
|
| 49 |
if (!postCreationStartTime) {
|
| 50 |
postCreationStartTime = Date.now();
|
|
|
|
| 62 |
postCreationStartTime = Date.now();
|
| 63 |
}
|
| 64 |
});
|
| 65 |
+
// Form submission
|
| 66 |
postForm.addEventListener('submit', function(e) {
|
| 67 |
e.preventDefault();
|
| 68 |
|
|
|
|
| 75 |
if (!title.trim()) {
|
| 76 |
logFormError('empty_title');
|
| 77 |
formErrors++;
|
| 78 |
+
console.log('β Form error: Empty title');
|
| 79 |
}
|
| 80 |
if (!body.trim()) {
|
| 81 |
logFormError('empty_body');
|
| 82 |
formErrors++;
|
| 83 |
+
console.log('β Form error: Empty body');
|
| 84 |
}
|
| 85 |
if (tags.length === 0 || (tags.length === 1 && !tags[0].trim())) {
|
| 86 |
logFormError('empty_tags');
|
| 87 |
formErrors++;
|
| 88 |
+
console.log('β Form error: Empty tags');
|
| 89 |
}
|
| 90 |
|
| 91 |
// Calculate total post creation time
|
|
|
|
| 95 |
storeKPIData('total_post_creation_time', totalPostCreationTime);
|
| 96 |
storeKPIData('form_adherance', formErrors);
|
| 97 |
|
| 98 |
+
// Log successful form submission
|
| 99 |
+
console.log('β
Post creation completed:', {
|
| 100 |
+
totalTime: totalPostCreationTime + 's',
|
| 101 |
+
formErrors: formErrors,
|
| 102 |
+
titleLength: title.length,
|
| 103 |
+
bodyLength: body.length,
|
| 104 |
+
tagCount: tags.length
|
| 105 |
+
});
|
| 106 |
+
|
| 107 |
// Create new post
|
| 108 |
const newPost = {
|
| 109 |
id: Date.now(),
|
|
|
|
| 346 |
setActiveNav(myPostsLink);
|
| 347 |
showPanel3();
|
| 348 |
});
|
|
|
|
| 349 |
unansweredLink.addEventListener('click', function(e) {
|
| 350 |
e.preventDefault();
|
| 351 |
setActiveNav(unansweredLink);
|
|
|
|
| 353 |
|
| 354 |
// Start unanswered filter interaction timer
|
| 355 |
unansweredFilterStartTime = Date.now();
|
| 356 |
+
console.log('β±οΈ Unanswered filter interaction timer started');
|
| 357 |
});
|
| 358 |
// Add event listeners for new navigation items
|
| 359 |
document.getElementById('recent-link').addEventListener('click', function(e) {
|
|
|
|
| 396 |
});
|
| 397 |
});
|
| 398 |
}
|
|
|
|
| 399 |
function storeKPIData(kpiName, value) {
|
| 400 |
const kpiData = JSON.parse(localStorage.getItem('piazza_kpi_data') || {};
|
| 401 |
if (!kpiData[kpiName]) {
|
|
|
|
| 406 |
timestamp: Date.now()
|
| 407 |
});
|
| 408 |
localStorage.setItem('piazza_kpi_data', JSON.stringify(kpiData));
|
| 409 |
+
|
| 410 |
+
console.log('π KPI Data Stored:', {
|
| 411 |
+
metric: kpiName,
|
| 412 |
+
value: value,
|
| 413 |
+
timestamp: Date.now()
|
| 414 |
+
});
|
| 415 |
}
|
|
|
|
| 416 |
function logFormError(errorType) {
|
| 417 |
const errorData = JSON.parse(localStorage.getItem('piazza_form_errors') || {};
|
| 418 |
if (!errorData[errorType]) {
|
|
|
|
| 420 |
}
|
| 421 |
errorData[errorType]++;
|
| 422 |
localStorage.setItem('piazza_form_errors', JSON.stringify(errorData));
|
| 423 |
+
|
| 424 |
+
console.log('β Form Error Logged:', {
|
| 425 |
+
type: errorType,
|
| 426 |
+
count: errorData[errorType]
|
| 427 |
+
});
|
| 428 |
}
|
| 429 |
function showPanel1() {
|
| 430 |
panel1.classList.remove('hidden');
|
|
|
|
| 436 |
panel2.classList.remove('hidden');
|
| 437 |
panel3.classList.add('hidden');
|
| 438 |
|
| 439 |
+
// Start unanswered filter result interaction timer
|
| 440 |
+
unansweredFilterInteractionStartTime = Date.now();
|
| 441 |
+
console.log('β±οΈ Unanswered filter result interaction timer started');
|
| 442 |
+
|
| 443 |
// Clear existing posts and add unanswered content
|
| 444 |
postsList.innerHTML = '';
|
| 445 |
|
|
|
|
| 485 |
unansweredCount.textContent = window.placeholderPosts.length;
|
| 486 |
postsList.appendChild(feedContainer);
|
| 487 |
feather.replace();
|
| 488 |
+
|
| 489 |
+
// Add click tracking for unanswered posts
|
| 490 |
+
setTimeout(() => {
|
| 491 |
+
const postCards = document.querySelectorAll('custom-post-card');
|
| 492 |
+
postCards.forEach((card, index) => {
|
| 493 |
+
card.addEventListener('click', function() {
|
| 494 |
+
// Calculate unanswered filter interaction time
|
| 495 |
+
const unansweredFilterInteractionTime = (Date.now() - unansweredFilterInteractionStartTime) / 1000;
|
| 496 |
+
|
| 497 |
+
// Store KPI data
|
| 498 |
+
storeKPIData('unanswered_filter_interaction_time', unansweredFilterInteractionTime);
|
| 499 |
+
|
| 500 |
+
console.log('β
Unanswered filter result clicked:', {
|
| 501 |
+
timeToClick: unansweredFilterInteractionTime + 's',
|
| 502 |
+
postIndex: index,
|
| 503 |
+
postTitle: card.shadowRoot.querySelector('h3').textContent
|
| 504 |
+
});
|
| 505 |
+
});
|
| 506 |
+
}, 100);
|
| 507 |
+
|
| 508 |
+
// Highlight unanswered filter in sidebar
|
| 509 |
const sidebar = document.querySelector('custom-sidebar');
|
| 510 |
if (sidebar) {
|
| 511 |
const shadow = sidebar.shadowRoot;
|
|
|
|
| 518 |
});
|
| 519 |
}
|
| 520 |
}
|
| 521 |
+
function showRecentPanel() {
|
|
|
|
| 522 |
panel1.classList.add('hidden');
|
| 523 |
panel2.classList.remove('hidden');
|
| 524 |
panel3.classList.add('hidden');
|