<body>
<div>
<button class="btn--alt" onclick="loadDataFromGoogleSheet()" id="refreshBtn">🔄 Refresh Data</button>
<br><strong>Last Updated:</strong> <span id="lastUpdated">Loading...</span>
</div>
<br>
<!-- FILTER LABEL -->
<p id="activeFilters">Selected Filters: Undergraduate & Graduate • All Terms</p>
<div id="filterButtons">
<!-- LEVEL FILTERS -->
<button class="btn--alt" onclick="filterByLevel('Undergraduate', this)">Undergraduate</button>
<button class="btn--alt" onclick="filterByLevel('Graduate', this)">Graduate</button>
<!-- TERM FILTERS -->
<button class="btn--primary" onclick="filterByTerm('all', this)">All Terms</button>
<button class="btn--primary" onclick="filterByTerm('Summer 2026', this)">Summer 2026</button>
<button class="btn--primary" onclick="filterByTerm('Fall 2026', this)">Fall 2026</button>
<button class="btn--primary" onclick="filterByTerm('Winter 2027', this)">Winter 2027</button>
<button class="btn--primary" onclick="filterByTerm('Spring 2027', this)">Spring 2027</button>
</div>
<p>Showing <strong id="resultCount">0</strong> courses</p>
<div id="dataContainer">
<p>Loading course data from Google Sheets, please wait...</p>
</div>
<!-- BLUE OUTLINE FOR ACTIVE BUTTONS -->
<style>
#filterButtons button.is-active {
outline: 3px solid #6FCFEB;
outline-offset: 2px;
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/PapaParse/5.4.1/papaparse.min.js"></script>
<script>
let allData = [];
let currentFilter = 'all';
let currentLevel = 'all';
const UG_SHEET_URL = 'https://docs.google.com/spreadsheets/d/1CbByZcjy3mr5C2yYBWZFmmj-uxThJoc6vNyGXHMfX2A/export?format=csv&gid=0';
const GRAD_SHEET_URL = 'https://docs.google.com/spreadsheets/d/1CbByZcjy3mr5C2yYBWZFmmj-uxThJoc6vNyGXHMfX2A/export?format=csv&gid=1514822965';
const TERM_COLUMNS = [
'Summer 2026',
'Fall 2026',
'Winter 2027',
'Spring 2027'
];
window.addEventListener('load', loadDataFromGoogleSheet);
async function fetchSheet(url, levelLabel) {
const response = await fetch(url, { cache: 'no-cache' });
const csvText = await response.text();
const parsed = Papa.parse(csvText, {
header: true,
skipEmptyLines: true,
transformHeader: h => h && h.trim()
});
return parsed.data.map(row => {
const normalized = {};
for (const k in row) {
normalized[k.trim()] = row[k] ? String(row[k]).trim() : '';
}
normalized["Level"] = levelLabel;
return normalized;
});
}
async function loadDataFromGoogleSheet() {
const refreshBtn = document.getElementById('refreshBtn');
const container = document.getElementById('dataContainer');
refreshBtn.disabled = true;
container.innerHTML = `<p>Loading course data from Google Sheets, please wait...</p>`;
try {
const [ugData, gradData] = await Promise.all([
fetchSheet(UG_SHEET_URL, 'Undergraduate'),
fetchSheet(GRAD_SHEET_URL, 'Graduate')
]);
allData = [...ugData, ...gradData];
updateLastUpdatedTime();
applyFilters();
} catch (error) {
console.error('Error loading data:', error);
container.innerHTML = `<p><strong>⚠️ Unable to load data</strong></p>`;
} finally {
refreshBtn.disabled = false;
}
}
function updateLastUpdatedTime() {
const now = new Date();
document.getElementById('lastUpdated').textContent =
now.toLocaleString('en-US', {
month: 'short',
day: 'numeric',
year: 'numeric',
hour: 'numeric',
minute: '2-digit',
hour12: true
});
}
// UPDATED: separate active states
function setActiveButton(clickedBtn, type) {
let selector;
if (type === 'level') {
selector = '#filterButtons button.btn--alt';
} else {
selector = '#filterButtons button.btn--primary';
}
const buttons = document.querySelectorAll(selector);
buttons.forEach(btn => btn.classList.remove('is-active'));
if (clickedBtn) clickedBtn.classList.add('is-active');
}
function filterByLevel(level, btn) {
currentLevel = level;
setActiveButton(btn, 'level');
applyFilters();
}
function filterByTerm(term, btn) {
currentFilter = term;
setActiveButton(btn, 'term');
applyFilters();
}
function applyFilters() {
let filtered = allData.slice();
if (currentLevel !== 'all') {
filtered = filtered.filter(row => row.Level === currentLevel);
}
if (currentFilter !== 'all') {
filtered = filtered.filter(row => {
const val = row[currentFilter];
return val && val !== '';
});
}
displayData(filtered);
document.getElementById('resultCount').textContent = filtered.length;
updateActiveFiltersText();
}
function updateActiveFiltersText() {
let levelText = currentLevel === 'all' ? 'Undergraduate & Graduate' : currentLevel;
let termText = currentFilter === 'all' ? 'All Terms' : currentFilter;
let text;
if (currentLevel === 'all' && currentFilter === 'all') {
text = 'Selected Filters: Undergraduate & Graduate • All Terms';
} else {
text = `Selected Filters: ${levelText} • ${termText}`;
}
document.getElementById('activeFilters').textContent = text;
}
function displayData(data) {
const container = document.getElementById('dataContainer');
if (!data || data.length === 0) {
container.innerHTML = '<p>No courses found for this selection.</p>';
return;
}
const ug = data.filter(d => d.Level === 'Undergraduate');
const grad = data.filter(d => d.Level === 'Graduate');
if (currentLevel === 'Undergraduate') {
container.innerHTML = `
<h3>Undergraduate Courses</h3>
${buildTable(ug, currentFilter)}
`;
} else if (currentLevel === 'Graduate') {
container.innerHTML = `
<h3>Graduate Courses</h3>
${buildTable(grad, currentFilter)}
`;
} else {
container.innerHTML = `
<h3>Undergraduate Courses</h3>
${buildTable(ug, currentFilter)}
<h3>Graduate Courses</h3>
${buildTable(grad, currentFilter)}
`;
}
}
function buildTable(data, mode) {
if (!data || data.length === 0) return '<p>No courses available.</p>';
const keys = Object.keys(data[0]);
const courseCodeKey = keys.find(k => k.toLowerCase().includes('course code'));
const courseTitleKey = keys.find(k => k.toLowerCase().includes('course title'));
const linkKey = keys.find(k => k.toLowerCase().includes('link'));
let table = '<table><thead><tr>';
table += `<th>${courseCodeKey || 'Course Code'}</th>`;
table += `<th>${courseTitleKey || 'Course Title'}</th>`;
if (mode === 'all') {
TERM_COLUMNS.forEach(t => table += `<th>${t}</th>`);
}
table += '</tr></thead><tbody>';
data.forEach(row => {
table += '<tr>';
const code = row[courseCodeKey] || '';
const title = row[courseTitleKey] || '';
const link = row[linkKey] || '';
if (link) {
table += `<td><a href="${link}" target="_blank">${escapeHtml(code)}</a></td>`;
} else {
table += `<td>${escapeHtml(code)}</td>`;
}
table += `<td>${escapeHtml(title)}</td>`;
if (mode === 'all') {
TERM_COLUMNS.forEach(t => {
table += `<td>${escapeHtml(row[t] || '')}</td>`;
});
}
table += '</tr>';
});
table += '</tbody></table>';
return table;
}
function escapeHtml(str) {
return String(str)
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>');
}
</script>
</body>