Skip to content
Draft
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
28 changes: 27 additions & 1 deletion admin.html
Original file line number Diff line number Diff line change
Expand Up @@ -786,7 +786,22 @@ <h1 class="hero-title">DSMNRU content dashboard</h1>
</div>
</div>
<div class="card-body">
<form id="addPyqForm" class="resource-form">
<div class="mb-3">
<label class="form-label d-block">Action Mode</label>
<div class="d-flex gap-3">
<div class="form-check"><input class="form-check-input" type="radio" name="adminMode" id="modeAdd" value="add" checked><label class="form-check-label" for="modeAdd">Add New</label></div>
<div class="form-check"><input class="form-check-input" type="radio" name="adminMode" id="modeEdit" value="edit"><label class="form-check-label" for="modeEdit">Edit Current</label></div>
</div>
</div>
<div class="mb-3" id="entitySelectorWrap">
<label for="adminEntitySelect" class="form-label">Choose section</label>
<select id="adminEntitySelect" class="form-select">
<option value="pyq">PYQ</option>
<option value="contributor">Contributor</option>
<option value="user">User</option>
</select>
</div>
<form id="addPyqForm" class="resource-form admin-form-block">
<div class="mb-3">
<label for="pyqCourse" class="form-label">Course</label>
<select class="form-select" id="pyqCourse" required>
Expand Down Expand Up @@ -837,6 +852,10 @@ <h1 class="hero-title">DSMNRU content dashboard</h1>
<label for="pyqSubject" class="form-label">Subject Name</label>
<input type="text" class="form-control" id="pyqSubject" placeholder="e.g., Effective Tech. Communication" required>
</div>
<div class="mt-3 mb-3">
<label for="pyqBranch" class="form-label">Branch (optional)</label>
<input type="text" class="form-control" id="pyqBranch" placeholder="e.g., CSE">
</div>
<div class="mb-3">
<label for="pyqFile" class="form-label">File URL</label>
<input type="url" class="form-control" id="pyqFile" required>
Expand Down Expand Up @@ -929,6 +948,13 @@ <h1 class="hero-title">DSMNRU content dashboard</h1>
<option value="PYQs + Syllabus Provider">PYQs + Syllabus Provider</option>
</select>
</div>
<div class="mb-3">
<label for="contributorShowOnWebsite" class="form-label">Show on website</label>
<select class="form-select" id="contributorShowOnWebsite" required>
<option value="yes" selected>Yes</option>
<option value="no">No</option>
</select>
</div>
<button type="submit" class="btn btn-primary w-100">
<i class="fas fa-plus me-2"></i> Add Contributor
</button>
Expand Down
69 changes: 58 additions & 11 deletions admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ document.addEventListener('DOMContentLoaded', function() {
const course = document.getElementById('pyqCourse').value.trim();
const semester = document.getElementById('pyqSemester').value.trim();
const subject = document.getElementById('pyqSubject').value.trim();
const branch = document.getElementById('pyqBranch').value.trim();
const session = document.getElementById('pyqSession').value.trim();
const file = document.getElementById('pyqFile').value;

Expand All @@ -96,7 +97,7 @@ document.addEventListener('DOMContentLoaded', function() {
}

let currentSubject = subject;
let title = buildPyqTitle(course, semester, currentSubject, session);
let title = buildPyqTitle(course, branch, semester, currentSubject, session);
let duplicateExists = await pyqTitleExists(title);

if (duplicateExists === null) {
Expand All @@ -123,18 +124,22 @@ document.addEventListener('DOMContentLoaded', function() {
continue;
}

title = buildPyqTitle(course, semester, currentSubject, session);
title = buildPyqTitle(course, branch, semester, currentSubject, session);

duplicateExists = await pyqTitleExists(title);
if (duplicateExists === null) {
return;
}
}

addItem('pyqs', { title, file, course, semester, subject: currentSubject, session });
addItem('pyqs', { title, file, course, branch, semester, subject: currentSubject, session });
this.reset();
});



setupAdminModeSwitcher();

// Edit form
document.getElementById('editForm').addEventListener('submit', function(e) {
e.preventDefault();
Expand All @@ -145,7 +150,9 @@ document.addEventListener('DOMContentLoaded', function() {
const course = document.getElementById('editCourse').value;
const semester = document.getElementById('editSemester').value;
editItem(type, index, { title, file, course, semester });
bootstrap.Modal.getInstance(document.getElementById('editModal')).hide();
const editModalEl = document.getElementById('editModal');
window.bootstrap.Modal.getOrCreateInstance(editModalEl).hide();
cleanupModalArtifacts();
});
});

Expand All @@ -169,6 +176,15 @@ function setupSectionCollapseBehavior() {
});
}


function cleanupModalArtifacts() {
document.body.classList.remove('modal-open');
document.body.style.removeProperty('padding-right');
document.querySelectorAll('.modal-backdrop').forEach(el => el.remove());
}

document.addEventListener('hidden.bs.modal', cleanupModalArtifacts);

function loadData() {
// Auto-load pending uploads and registered users so counts and panels show immediately.
loadPendingOnDemand();
Expand Down Expand Up @@ -463,8 +479,9 @@ function saveData() {
console.warn('saveData() called - this project now uses Firestore. Use addItem/editItem/deleteItem instead.');
}

function buildPyqTitle(course, semester, subject, session) {
return `${normalizePyqText(course)} ${normalizePyqText(semester)} Sem ${normalizePyqText(subject)} {${normalizePyqText(session)}}`;
function buildPyqTitle(course, branch, semester, subject, session) {
const branchPart = normalizePyqText(branch);
return `${normalizePyqText(course)}${branchPart ? ` ${branchPart}` : ''} ${normalizePyqText(semester)} Sem ${normalizePyqText(subject)} {${normalizePyqText(session)}}`;
}

function normalizePyqText(value) {
Expand Down Expand Up @@ -765,7 +782,7 @@ function renderContributors(contributors) {
</div>
</div>
<div class="resource-actions">
<button class="btn btn-sm btn-outline-primary" onclick="editContributor('${contributor.id}', '${contributor.name}', '${contributor.avatar}', '${contributor.role}')">
<button class="btn btn-sm btn-outline-primary" onclick="editContributor('${contributor.id}', '${contributor.name}', '${contributor.avatar}', '${contributor.role}', ${contributor.showOnWebsite !== false})">
<i class="fas fa-edit me-1"></i>Edit
</button>
<button class="btn btn-sm btn-outline-danger" onclick="deleteContributor('${contributor.id}', '${contributor.name}')">
Expand Down Expand Up @@ -816,6 +833,7 @@ document.addEventListener('DOMContentLoaded', function() {
const name = nameInput.value.trim();
const avatar = getContributorInitials(name);
const role = roleInput.value;
const showOnWebsite = document.getElementById('contributorShowOnWebsite').value === 'yes';

if (!name || !avatar || !role) {
alert('Please fill all fields');
Expand All @@ -830,7 +848,8 @@ document.addEventListener('DOMContentLoaded', function() {
db.collection('contributors').add({
name,
avatar,
role
role,
showOnWebsite
})
.then(() => {
addContributorForm.reset();
Expand All @@ -847,7 +866,7 @@ document.addEventListener('DOMContentLoaded', function() {
}
});

window.editContributor = function(id, name, avatar, role) {
window.editContributor = function(id, name, avatar, role, showOnWebsite) {
const newName = prompt('Edit name:', name);
if (newName === null) return;

Expand All @@ -856,6 +875,9 @@ window.editContributor = function(id, name, avatar, role) {

const trimmedName = newName.trim();
const trimmedRole = newRole.trim();
const showAnswer = prompt('Show on website? (yes/no):', showOnWebsite ? 'yes' : 'no');
if (showAnswer === null) return;
const newShowOnWebsite = showAnswer.trim().toLowerCase() === 'yes';
const newAvatar = getContributorInitials(trimmedName);

if (!trimmedName || !newAvatar || !trimmedRole) {
Expand All @@ -871,7 +893,8 @@ window.editContributor = function(id, name, avatar, role) {
db.collection('contributors').doc(id).set({
name: trimmedName,
avatar: newAvatar,
role: trimmedRole
role: trimmedRole,
showOnWebsite: newShowOnWebsite
})
.then(() => {
loadContributors();
Expand All @@ -893,4 +916,28 @@ window.deleteContributor = function(id, name) {
alert('Error deleting contributor: ' + error.message);
});
}
};
};

function setupAdminModeSwitcher() {
const addRadio = document.getElementById('modeAdd');
const editRadio = document.getElementById('modeEdit');
const entity = document.getElementById('adminEntitySelect');
if (!addRadio || !editRadio || !entity) return;

const refresh = () => {
const mode = editRadio.checked ? 'edit' : 'add';
const target = entity.value;
const pyqForm = document.getElementById('addPyqForm');
const contributorForm = document.getElementById('addContributorForm');
const pyqsCollapse = document.getElementById('pyqsCollapse');
const contributorsCollapse = document.getElementById('contributorsCollapse');
const usersCollapse = document.getElementById('usersCollapse');
if (pyqForm) pyqForm.style.display = mode === 'add' && target === 'pyq' ? 'block' : 'none';
if (contributorForm) contributorForm.style.display = mode === 'add' && target === 'contributor' ? 'block' : 'none';
if (mode === 'edit' && target === 'pyq') loadPyqsOnDemand();
if (mode === 'edit' && target === 'contributor') loadContributorsOnDemand();
if (mode === 'edit' && target === 'user') loadUsersOnDemand();
};
[addRadio, editRadio, entity].forEach(el => el.addEventListener('change', refresh));
refresh();
}
13 changes: 2 additions & 11 deletions script.js
Original file line number Diff line number Diff line change
Expand Up @@ -1091,7 +1091,7 @@ document.addEventListener('DOMContentLoaded', function() {

// Load and render contributors from Firestore
function loadContributors() {
const contributorsQuery = db.collection('contributors').orderBy('name').limit(12);
const contributorsQuery = db.collection('contributors').where('showOnWebsite', '==', true).orderBy('name').limit(12);

contributorsQuery.get({ source: 'cache' })
.then(snapshot => {
Expand Down Expand Up @@ -1126,16 +1126,7 @@ document.addEventListener('DOMContentLoaded', function() {
contributorsGrid.appendChild(card);
});

// Add the "Join our team" card at the end
const joinCard = document.createElement('div');
joinCard.className = 'contributor-more';
joinCard.innerHTML = `
<div class="more-avatar">+</div>
<h5>Join our team!</h5>
<p class="contributor-role">Become a contributor</p>
`;
contributorsGrid.appendChild(joinCard);
}
}

async function loadAggregatedStats() {
try {
Expand Down