|
/**************************************************************** |
|
* -------------------------------------------------------------- |
|
* Calculates start and end dates for each course remaining in a |
|
* WGU Degree Plan. Additionally, it calculates the student's |
|
* current pace and estimated completion time at that pace. |
|
* -------------------------------------------------------------- |
|
* Usage: Navigate to the Degree Plan page in your WGU dashboard |
|
* (https://my.wgu.edu/degree-plan) and open the Developer Tools. |
|
* paste this script into the Dev Tools and hit Run. |
|
***************************************************************/ |
|
(() => { |
|
/************************************************************ |
|
* CHANGE THESE VARIABLES *********************************** |
|
***********************************************************/ |
|
|
|
// The date you started - to calculate your current pace. |
|
const START_DATE = '10/01/24'; |
|
|
|
// The date you want to finish - to create a completion plan |
|
const TGT_END_DATE = '3/31/25'; |
|
|
|
/************************************************************ |
|
* END OF VARIABLES ***************************************** |
|
***********************************************************/ |
|
|
|
// Helper function to convert mm/dd/yy string to Date |
|
const toDate = mdy => { |
|
let [m, d, y] = mdy.split('/').map(n => +n); |
|
return new Date(2000 + y, m - 1, d); |
|
}; |
|
|
|
// Helper function to convert Date mm/dd/yy string |
|
const fromDate = date => { |
|
let m = `${date.getMonth() + 1}`.padStart(2, '0'); |
|
let d = `${date.getDate()}`.padStart(2, '0'); |
|
let y = `${date.getFullYear()}`.substring(2); |
|
return `${m}/${d}/${y}`; |
|
}; |
|
|
|
// Helper function to add increment mm/dd/yy string by n days |
|
const addDays = (date, days) => { |
|
date = toDate(date); |
|
date.setDate(date.getDate() + days); |
|
return fromDate(date); |
|
}; |
|
|
|
// Parse the page and read the course data |
|
let courses = [...document.querySelectorAll('.dp__course__content')].map(e => { |
|
let complete = e.querySelectorAll('.portal-badge--complete').length !== 0; |
|
let CUs = +e.querySelector('.portal-badge__value').innerHTML.trim(); |
|
let courseName = e.querySelector('.dp__course__content__center__main__link.box__item').innerText.trim(); |
|
let completedDate = null; |
|
if (complete) { |
|
completedDate = toDate(e.querySelector('.completed-date').innerText.trim()); |
|
} |
|
return { courseName, CUs, complete, completedDate }; |
|
}).filter(c => c.CUs > 0); |
|
|
|
// Array of completed courses |
|
const completed_courses = courses.filter(c => c.complete); |
|
|
|
// Array of to-be-completed courses |
|
const incomplete_courses = courses.filter(c => !c.complete); |
|
|
|
// The total number of CUs earned so far |
|
const total_completed_cus = completed_courses.reduce((a, c) => a + c.CUs, 0); |
|
|
|
// The total number of CUs in the program |
|
const total_program_cus = courses.reduce((a, c) => a + c.CUs, 0); |
|
|
|
// Get the most recently completed course |
|
let last_course_complete = null; |
|
for (let i = 0; i < completed_courses.length; i++) { |
|
if (null === last_course_complete || completed_courses[i].completedDate > last_course_complete.completedDate) { |
|
last_course_complete = completed_courses[i]; |
|
} |
|
} |
|
|
|
// Calcuate how many days worked so far |
|
let total_days_worked = 0; |
|
if (last_course_complete) { |
|
let start_time = toDate(START_DATE).getTime(); |
|
let end_time = last_course_complete.completedDate.getTime(); |
|
total_days_worked = Math.round((end_time - start_time) / (1000 * 3600 * 24)) + 1; |
|
} |
|
|
|
// Calculate the average numebr of CUs completed per day, so far |
|
let avg_cus_per_day = 0; |
|
let projected_completion_date = null; |
|
if (completed_courses.length) { |
|
avg_cus_per_day = total_completed_cus / total_days_worked; |
|
let est_days_left = (total_program_cus - total_completed_cus) * avg_cus_per_day; |
|
let date = new Date(); |
|
date.setDate(date.getDate() + est_days_left); |
|
projected_completion_date = fromDate(date); |
|
} |
|
|
|
// Calculate start and end dates for each remaining course in order to finish by the target date |
|
let curr_date = fromDate(new Date()); |
|
let days_until_tgt = Math.round((toDate(TGT_END_DATE).getTime() - new Date().getTime()) / (1000 * 3600 * 24)) + 1; |
|
let remaining_cus = total_program_cus - total_completed_cus; |
|
let rqd_avg_cus_per_day = remaining_cus / days_until_tgt; // do this many cus per day |
|
let total_days = 0; |
|
for (let i = 0; i < incomplete_courses.length; i++) { |
|
let days = Math.floor(incomplete_courses[i].CUs / rqd_avg_cus_per_day); |
|
total_days += days; |
|
let start_date = curr_date; |
|
let end_date = addDays(start_date, days - 1); |
|
incomplete_courses[i].startDate = start_date; |
|
if (i === incomplete_courses.length - 1) { |
|
incomplete_courses[i].endDate = TGT_END_DATE; |
|
let start_time = toDate(start_date).getTime(); |
|
let end_time = toDate(TGT_END_DATE).getTime(); |
|
let daysToComplete = Math.round((end_time - start_time) / (1000 * 3600 * 24)) + 1; |
|
incomplete_courses[i].daysToComplete = daysToComplete; |
|
} else { |
|
incomplete_courses[i].endDate = end_date; |
|
incomplete_courses[i].daysToComplete = days; |
|
} |
|
curr_date = addDays(end_date, 1); |
|
} |
|
|
|
// Output the results |
|
let output = []; |
|
if (total_days_worked > 0) { |
|
output.push(`At your CURRENT pace, your projected completion date is: ${projected_completion_date}`); |
|
} |
|
output.push(`In order to complete at your goal date of ${TGT_END_DATE}, use this plan:`); |
|
incomplete_courses.forEach(g => { |
|
output.push(`${g.courseName}: ${g.startDate}-${g.endDate} (${g.daysToComplete} days)`); |
|
}); |
|
console.log(output.join("\n")); |
|
})(); |
|
|