/**
* University Document Upload Plugin - JavaScript Handler
* Pre-uploads files immediately on selection (in parallel), then on submit
* only sends the temp_file_ids[] references — so submission is near-instant.
*/
jQuery(document).ready(function ($) {
'use strict';
// Check if form exists on this page before running
const form = $('#udp-upload-form');
if (form.length === 0) {
return; // Exit if form doesn't exist
}
const submitBtn = $('#udpSubmitBtn');
function setupCheckbox(cardId) {
const card = document.getElementById(cardId);
if (!card) {
return;
}
const input = card.querySelector('input[type="checkbox"]');
const sync = function () {
card.classList.toggle('checked', input.checked);
updateSubmitState();
};
card.addEventListener('click', function (e) {
if (e.target.tagName === 'A') {
return;
}
if (e.target === input) {
sync();
return;
}
e.preventDefault();
input.checked = !input.checked;
sync();
});
input.addEventListener('change', sync);
sync();
}
function updateSubmitState() {
const termsChecked = $('#terms_check').is(':checked');
submitBtn.prop('disabled', !termsChecked);
}
setupCheckbox('termsCheck');
setupCheckbox('specialCheck');
const dropZone = $('#dropZone');
const fileInput = $('#fileInput');
const fileListEl = $('#fileList');
const degreeFormTemplate = document.getElementById('degree-form-template');
const hiddenUniversity = $('#university_name');
const hiddenCollege = $('#college_name');
const hiddenCourse = $('#course_name');
const degreeList = $('#degree-list');
const degreesHidden = $('#degrees-hidden');
let selectedFiles = [];
let degreeCounter = 0;
let degreeFilesMap = {}; // Tracks uploaded files per degree ID
// Get universities from PHP localized data
const universityList = udpVars.universities || [];
// --- Pre-upload helpers --------------------------------------------------
/**
* Pre-upload a single File object to the server immediately.
* Returns a Promise that resolves to { file, tempId, fileName } on success
* or rejects with an error message on failure.
*/
function preUploadFile(file, onProgress) {
return new Promise(function (resolve, reject) {
const fd = new FormData();
fd.append('action', 'udp_preupload_file');
fd.append('udp_nonce', udpVars.nonce ? udpVars.nonce : $('[name="udp_nonce"]').val());
fd.append('file', file, file.name);
const xhr = new XMLHttpRequest();
if (onProgress) {
xhr.upload.addEventListener('progress', function (e) {
if (e.lengthComputable) {
onProgress(Math.round((e.loaded / e.total) * 100));
}
});
}
xhr.addEventListener('load', function () {
if (xhr.status === 200) {
try {
const res = JSON.parse(xhr.responseText);
if (res.success) {
resolve({ file: file, tempId: res.data.temp_id, fileName: res.data.file_name });
} else {
reject((res.data && res.data.message) ? res.data.message : 'Upload failed for ' + file.name);
}
} catch (err) {
reject('Invalid server response for ' + file.name);
}
} else {
reject('Server error (' + xhr.status + ') for ' + file.name);
}
});
xhr.addEventListener('error', function () {
reject('Network error uploading ' + file.name);
});
xhr.addEventListener('abort', function () {
reject('Upload cancelled for ' + file.name);
});
xhr.open('POST', udpVars.ajaxUrl, true);
xhr.send(fd);
});
}
/**
* Pre-upload an array of File objects immediately, all in parallel.
* Updates the file-list UI with per-file progress/status.
*
* @param {File[]} files New files to upload
* @param {Object[]} fileStore Array where we push { file, state, tempId, fileName, listEl }
* @param {Function} renderList Function that re-renders the file list UI
*/
function preUploadAll(files, fileStore, renderList) {
const newEntries = [];
files.forEach(function (file) {
// Deduplicate
const isDup = fileStore.some(function (e) {
return e.file.name === file.name &&
e.file.size === file.size &&
e.file.lastModified === file.lastModified;
});
if (isDup) return;
const entry = {
file: file,
state: 'uploading', // 'uploading' | 'done' | 'error'
progress: 0,
tempId: null,
fileName: null,
error: null
};
fileStore.push(entry);
newEntries.push(entry);
});
if (newEntries.length === 0) return;
renderList();
// Start all uploads in parallel
newEntries.forEach(function (entry) {
preUploadFile(entry.file, function (pct) {
entry.progress = pct;
renderList();
}).then(function (result) {
entry.state = 'done';
entry.tempId = result.tempId;
entry.fileName = result.fileName;
entry.progress = 100;
renderList();
}).catch(function (errMsg) {
entry.state = 'error';
entry.error = errMsg;
renderList();
showStatus('Upload error: ' + errMsg, 'error');
});
});
}
// --- Degree form factory -------------------------------------------------
function createDegreeForm(degreeNumber = null, initialFiles = []) {
if (!degreeFormTemplate) {
return null;
}
const templateItem = degreeFormTemplate.querySelector('.degree-form-item');
if (!templateItem) {
return null;
}
const form = templateItem.cloneNode(true);
const currentDegreeNumber = degreeNumber !== null ? degreeNumber : degreeCounter + 1;
form.id = 'degree-form-' + currentDegreeNumber;
form.dataset.dynamicNum = currentDegreeNumber;
form.querySelector('.degree-title').textContent = 'Degree ' + currentDegreeNumber;
// Store file entries for this degree form
// Each entry: { file, state, progress, tempId, fileName, error }
let degreeFormFiles = initialFiles.map(function (e) {
// Re-upload any file that doesn't have a valid tempId yet
return Object.assign({}, e);
});
// University autocomplete dropdown
const universityWrapper = form.querySelector('.university-select-wrapper');
const universityInput = form.querySelector('.degree-university');
const dropdown = form.querySelector('.university-select-dropdown');
const chevronIcon = form.querySelector('.university-chevron-icon');
const customUniversityField = form.querySelector('.degree-university-custom-field');
const customUniversityInput = form.querySelector('.degree-university-custom');
const switchHint = form.querySelector('.university-switch-hint');
const universityNameField = form.querySelector('.university-name-field');
function lockOthersState(initialText = '') {
universityInput.value = 'Others';
universityInput.readOnly = true;
universityWrapper.classList.add('university-others-locked');
if (universityNameField) {
universityNameField.classList.add('is-others-mode');
}
customUniversityField.hidden = false;
customUniversityField.classList.add('is-visible');
customUniversityInput.value = initialText;
customUniversityInput.focus();
dropdown.style.display = 'none';
}
function unlockOthersState() {
universityInput.value = '';
universityInput.readOnly = false;
universityWrapper.classList.remove('university-others-locked');
if (universityNameField) {
universityNameField.classList.remove('is-others-mode');
}
customUniversityField.hidden = true;
customUniversityField.classList.remove('is-visible');
customUniversityInput.value = '';
window.setTimeout(() => universityInput.focus(), 10);
}
if (switchHint) {
switchHint.addEventListener('click', function(e) {
e.stopPropagation();
unlockOthersState();
});
}
universityWrapper.addEventListener('click', function(e) {
if (universityWrapper.classList.contains('university-others-locked')) {
unlockOthersState();
}
});
function showUniversityDropdown(filterText = '') {
const filtered = universityList.filter(uni =>
uni.toLowerCase().includes(filterText.toLowerCase())
);
dropdown.innerHTML = '';
if (filtered.length > 0 || filterText === '') {
filtered.slice(0, 10).forEach(uni => {
const option = document.createElement('div');
option.className = 'university-option';
option.textContent = uni;
option.style.padding = '10px 12px';
option.style.cursor = 'pointer';
option.style.borderBottom = '1px solid #f0f0f0';
option.style.transition = 'background 0.2s';
option.addEventListener('mouseenter', function () {
this.style.background = '#f0f0f0';
});
option.addEventListener('mouseleave', function () {
this.style.background = 'transparent';
});
option.addEventListener('click', function (e) {
e.stopPropagation();
universityInput.value = uni;
customUniversityField.hidden = true;
customUniversityField.classList.remove('is-visible');
customUniversityInput.value = '';
dropdown.style.display = 'none';
});
dropdown.appendChild(option);
});
}
// Always add "Others" option
const othersOption = document.createElement('div');
othersOption.className = 'university-option';
othersOption.textContent = 'Others';
othersOption.style.padding = '10px 12px';
othersOption.style.cursor = 'pointer';
othersOption.style.borderBottom = '1px solid #f0f0f0';
othersOption.style.transition = 'background 0.2s';
othersOption.style.fontWeight = '600';
othersOption.addEventListener('mouseenter', function () {
this.style.background = '#f0f0f0';
});
othersOption.addEventListener('mouseleave', function () {
this.style.background = 'transparent';
});
othersOption.addEventListener('click', function (e) {
e.stopPropagation();
lockOthersState('');
});
dropdown.appendChild(othersOption);
dropdown.style.display = 'block';
}
universityInput.addEventListener('input', function () {
const filterText = this.value;
showUniversityDropdown(filterText);
});
universityInput.addEventListener('focus', function () {
if (!universityWrapper.classList.contains('university-others-locked')) {
showUniversityDropdown(this.value);
}
});
chevronIcon.addEventListener('click', function (e) {
e.stopPropagation();
if (universityWrapper.classList.contains('university-others-locked')) {
unlockOthersState();
return;
}
if (dropdown.style.display === 'block') {
dropdown.style.display = 'none';
} else {
showUniversityDropdown(universityInput.value);
}
});
document.addEventListener('click', function (event) {
if (!form.contains(event.target) || (!universityWrapper.contains(event.target) && !dropdown.contains(event.target))) {
dropdown.style.display = 'none';
}
});
// File upload handling for degree form
const degreeDropZone = form.querySelector('.degree-drop-zone');
const degreeFileInput = form.querySelector('.degree-file-input');
const degreeFileList = form.querySelector('.degree-file-list');
if (degreeDropZone && degreeFileInput) {
degreeDropZone.addEventListener('dragover', function (e) {
e.preventDefault();
degreeDropZone.style.background = 'rgba(234, 240, 255, 0.4)';
});
degreeDropZone.addEventListener('dragleave', function () {
degreeDropZone.style.background = 'rgba(234, 240, 255, 0.2)';
});
degreeDropZone.addEventListener('drop', function (e) {
e.preventDefault();
degreeDropZone.style.background = 'rgba(234, 240, 255, 0.2)';
addDegreeFiles(e.dataTransfer.files);
});
degreeFileInput.addEventListener('change', function () {
addDegreeFiles(this.files);
degreeFileInput.value = '';
});
}
function addDegreeFiles(fileList) {
if (!fileList || !fileList.length) return;
const validFiles = [];
Array.from(fileList).forEach(function (file) {
if (validateFile(file)) {
validFiles.push(file);
}
});
if (validFiles.length === 0) return;
// Pre-upload all valid files immediately & in parallel
preUploadAll(validFiles, degreeFormFiles, renderDegreeFileList);
}
function renderDegreeFileList() {
degreeFileList.innerHTML = '';
degreeFormFiles.forEach(function (entry, idx) {
const li = document.createElement('li');
li.className = 'file-item';
li.style.cssText = 'margin-bottom: 6px; padding: 8px 12px; border-radius: 10px; gap: 8px; border: 1px solid var(--border); background: var(--surface); box-shadow: 0 4px 12px -2px rgba(63, 81, 181, 0.08); display: flex; align-items: center; min-width: 0;';
let statusHtml = '';
if (entry.state === 'uploading') {
statusHtml = `↑ ${entry.progress}%`;
} else if (entry.state === 'done') {
statusHtml = `✓ Ready`;
} else if (entry.state === 'error') {
statusHtml = `✗ Failed`;
}
li.innerHTML = `
${fileIconSvg}
${escapeHtml(entry.file.name)}
${(entry.file.size / 1024).toFixed(1)} KB
${entry.state === 'uploading' ? `
` : ''}
${entry.state === 'error' ? `
${escapeHtml(entry.error || 'Upload failed')}
` : ''}
${statusHtml}
`;
li.querySelector('.btn-remove').addEventListener('mouseenter', function () {
this.style.background = 'rgba(239, 68, 68, 0.1)';
this.style.color = 'var(--destructive)';
});
li.querySelector('.btn-remove').addEventListener('mouseleave', function () {
this.style.background = 'transparent';
this.style.color = 'var(--muted-foreground)';
});
li.querySelector('.btn-remove').addEventListener('click', function (e) {
e.preventDefault();
degreeFormFiles.splice(idx, 1);
renderDegreeFileList();
});
degreeFileList.appendChild(li);
});
// Update Submit Degree button state based on file progress
const submitBtn = form.querySelector('.submit-degree-btn');
if (submitBtn) {
const total = degreeFormFiles.length;
if (total === 0) {
submitBtn.textContent = 'Submit Degree';
submitBtn.disabled = false;
submitBtn.style.opacity = '1';
submitBtn.style.cursor = 'pointer';
} else {
const done = degreeFormFiles.filter(function(e) { return e.state === 'done'; }).length;
const uploading = degreeFormFiles.filter(function(e) { return e.state === 'uploading'; }).length;
if (uploading > 0) {
submitBtn.textContent = 'Uploading... (' + done + '/' + total + ')';
submitBtn.disabled = true;
submitBtn.style.opacity = '0.7';
submitBtn.style.cursor = 'not-allowed';
} else {
submitBtn.textContent = 'Submit Degree';
submitBtn.disabled = false;
submitBtn.style.opacity = '1';
submitBtn.style.cursor = 'pointer';
}
}
}
}
// Render initial files if passed in
if (degreeFormFiles.length > 0) {
renderDegreeFileList();
}
const closeBtn = form.querySelector('.close-degree-form');
if (closeBtn) {
closeBtn.addEventListener('click', function (e) {
e.preventDefault();
e.stopPropagation();
form.remove();
syncDegreeButtons(); // show Add Degree or Add Another based on remaining cards
});
}
const submitDegree = form.querySelector('.submit-degree-btn');
if (submitDegree) {
submitDegree.addEventListener('click', function (e) {
e.preventDefault();
const degreeType = form.querySelector('.degree-type').value.trim();
let uni = universityInput.value.trim();
const customFieldWrap = form.querySelector('.degree-university-custom-field');
if ((uni === 'Others' || !uni) && customFieldWrap && !customFieldWrap.hidden) {
uni = customUniversityInput.value.trim();
}
const college = form.querySelector('.degree-college').value.trim();
if (!degreeType || !uni || !college) {
alert('Please complete all degree fields.');
return;
}
if (degreeFormFiles.length === 0) {
alert('Please upload at least one document for this degree.');
return;
}
// Check if any file is still uploading
const stillUploading = degreeFormFiles.some(function (e) { return e.state === 'uploading'; });
if (stillUploading) {
alert('Please wait — files are still uploading. Try again in a moment.');
return;
}
// Check if any file failed
const hasErrors = degreeFormFiles.some(function (e) { return e.state === 'error'; });
if (hasErrors) {
alert('One or more files failed to upload. Please remove failed files and re-add them.');
return;
}
const currentDegreeNumber = parseInt(form.dataset.dynamicNum, 10);
// Increment degreeCounter if it's a completely new degree form
if (degreeNumber === null && currentDegreeNumber > degreeCounter) {
degreeCounter = currentDegreeNumber;
}
const item = document.createElement('div');
item.className = 'degree-item';
item.setAttribute('data-degree-number', currentDegreeNumber);
// Build files HTML for right column with scrollable container
let filesHtml = '';
if (degreeFormFiles.length > 0) {
filesHtml = '';
degreeFormFiles.forEach(function (entry) {
filesHtml += '
' +
'
' +
'
' +
'' + escapeHtml(entry.file.name) + '' +
'' + (entry.file.size / 1024).toFixed(1) + ' KB' +
'
' +
'
✓ Uploaded' +
'
';
});
filesHtml += '
';
} else {
filesHtml = 'No files uploaded
';
}
item.innerHTML = '' +
'
' +
'
Degree ' + currentDegreeNumber + '
' +
'
' +
'
Degree Type:
' +
'
' + escapeHtml(degreeType) + '
' +
'
' +
'
' +
'
University:
' +
'
' + escapeHtml(uni) + '
' +
'
' +
'
' +
'
College:
' +
'
' + escapeHtml(college) + '
' +
'
' +
'
' +
'' +
'' +
'
' +
'
' +
'
' +
'
Uploaded Documents
' +
filesHtml +
'
' +
'
';
degreeList.append(item);
showAddAnotherBtn(); // reveal after every successful degree submission
const hiddenWrap = document.createElement('div');
hiddenWrap.className = 'degree-hidden-wrap';
hiddenWrap.innerHTML = '' +
'' +
'';
degreesHidden.append(hiddenWrap);
item._hiddenWrap = hiddenWrap;
// Save file entries globally (with tempIds)
degreeFilesMap[currentDegreeNumber] = degreeFormFiles.slice();
if (!hiddenUniversity.val() && !hiddenCollege.val() && !hiddenCourse.val()) {
hiddenUniversity.val(uni);
hiddenCollege.val(college);
hiddenCourse.val(degreeType);
}
item.querySelector('.remove-degree-btn').addEventListener('click', function () {
const removeNum = parseInt(item.getAttribute('data-degree-number'), 10);
if (item._hiddenWrap) item._hiddenWrap.remove();
item.remove();
delete degreeFilesMap[removeNum];
renumberDegrees();
syncDegreeButtons(); // if last degree removed, show Add Degree again
if (!hasDegreeCards()) {
degreeCounter = 0;
}
});
item.querySelector('.edit-degree-btn').addEventListener('click', function () {
const editNum = parseInt(item.getAttribute('data-degree-number'), 10);
const nextSibling = item.nextElementSibling;
if (item._hiddenWrap) item._hiddenWrap.remove();
item.remove();
const existingFiles = degreeFilesMap[editNum] || [];
delete degreeFilesMap[editNum];
const editForm = createDegreeForm(editNum, existingFiles);
editForm.querySelector('.degree-type').value = degreeType;
const editUniInput = editForm.querySelector('.degree-university');
const editCustomInput = editForm.querySelector('.degree-university-custom');
const editCustomField = editForm.querySelector('.degree-university-custom-field');
const editWrapper = editForm.querySelector('.university-select-wrapper');
const editNameField = editForm.querySelector('.university-name-field');
const isKnownUni = universityList.some(u => u.toLowerCase() === uni.toLowerCase());
if (isKnownUni || !uni) {
editUniInput.value = uni;
} else {
editUniInput.value = 'Others';
editUniInput.readOnly = true;
editWrapper.classList.add('university-others-locked');
if (editNameField) {
editNameField.classList.add('is-others-mode');
}
editCustomField.hidden = false;
editCustomField.classList.add('is-visible');
editCustomInput.value = uni;
}
editForm.querySelector('.degree-college').value = college;
editForm.querySelector('.submit-degree-btn').textContent = 'Update Degree';
if (nextSibling) {
$(nextSibling).before(editForm);
} else {
degreeList.append(editForm);
}
window.setTimeout(function () {
editForm.scrollIntoView({ behavior: 'smooth', block: 'start' });
}, 100);
form.remove();
// While edit form is open, hide both buttons
$('#add-degree-btn').hide();
hideAddAnotherBtn();
});
form.remove();
});
}
return form;
}
function renumberDegrees() {
const newDegreeFilesMap = {};
const allNodes = Array.from(document.querySelectorAll('.degree-item, .udp-form-container')).filter(node => {
return node.id !== 'degree-form-template' && (node.classList.contains('degree-item') || node.id.startsWith('degree-form-'));
});
let currentNum = 1;
allNodes.forEach(node => {
const oldNum = parseInt(node.dataset.degreeNumber || node.dataset.dynamicNum, 10);
if (node.classList.contains('degree-item')) {
node.dataset.degreeNumber = currentNum;
const titleDisplay = node.querySelector('.degree-number');
if (titleDisplay) {
titleDisplay.innerHTML = 'Degree ' + currentNum;
}
const hiddenWrap = node._hiddenWrap;
if (hiddenWrap) {
const inputs = hiddenWrap.querySelectorAll('input');
inputs.forEach(input => {
input.name = input.name.replace(/degrees\[\d+\]/, 'degrees[' + currentNum + ']');
});
}
} else {
node.id = 'degree-form-' + currentNum;
node.dataset.dynamicNum = currentNum;
const title = node.querySelector('.degree-title');
if (title) title.textContent = 'Degree ' + currentNum;
}
if (degreeFilesMap[oldNum]) {
newDegreeFilesMap[currentNum] = degreeFilesMap[oldNum];
}
currentNum++;
});
degreeCounter = currentNum - 1;
for (let key in degreeFilesMap) {
delete degreeFilesMap[key];
}
for (let key in newDegreeFilesMap) {
degreeFilesMap[key] = newDegreeFilesMap[key];
}
}
function escapeHtml(value) {
return String(value)
.replace(/&/g, '&')
.replace(//g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
// --- Degree button helpers ------------------------------------------------
function hasDegreeCards() {
return degreeList.find('.degree-item').length > 0;
}
/** Show "Add Another Degree" and ALWAYS hide the primary "Add Degree" button */
function showAddAnotherBtn() {
$('#add-another-degree-wrapper').css('display', 'flex');
$('#add-degree-btn').hide();
}
/** Hide "Add Another Degree" button */
function hideAddAnotherBtn() {
$('#add-another-degree-wrapper').hide();
}
/**
* syncDegreeButtons — call after any degree card is added or removed.
* • Degrees exist ? Show "Add Another Degree", hide "Add Degree"
* • No degrees ? Show "Add Degree", hide "Add Another Degree"
*/
function syncDegreeButtons() {
if (hasDegreeCards()) {
showAddAnotherBtn();
} else {
hideAddAnotherBtn();
$('#add-degree-btn').show();
}
}
// "Add Degree" — only for the very first degree; hides itself once clicked
$('#add-degree-btn').on('click', function (e) {
e.preventDefault();
if (!degreeFormTemplate) return;
$(this).hide(); // hide itself while form is open
hideAddAnotherBtn(); // ensure secondary button is also hidden
const newForm = createDegreeForm();
if (newForm) {
$('#add-another-degree-wrapper').before(newForm);
newForm.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
});
// "Add Another Degree" — visible after first degree submitted; hides while form open
$('#add-another-degree-btn').on('click', function (e) {
e.preventDefault();
if (!degreeFormTemplate) return;
hideAddAnotherBtn(); // hide itself while form is open
const newForm = createDegreeForm();
if (newForm) {
$('#add-another-degree-wrapper').before(newForm);
newForm.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
});
const fileIconSvg = '';
const removeIconSvg = '';
// --- Global file list (non-degree area, if used) -------------------------
function addFiles(fileList) {
if (!fileList || !fileList.length) {
return;
}
Array.from(fileList).forEach(function (file) {
if (!validateFile(file)) {
return;
}
const isDuplicate = selectedFiles.some(function (existing) {
return existing.name === file.name &&
existing.size === file.size &&
existing.lastModified === file.lastModified;
});
if (!isDuplicate) {
selectedFiles.push(file);
}
});
renderFileList();
}
function renderFileList() {
fileListEl.empty();
selectedFiles.forEach(function (file, idx) {
const item = $(
'' +
'' + fileIconSvg + '
' +
'' +
'' +
''
);
item.find('.file-name').text(file.name);
item.find('.file-size').text((file.size / 1024).toFixed(1) + ' KB');
item.find('.btn-remove').on('click', function (e) {
e.preventDefault();
e.stopPropagation();
selectedFiles.splice(idx, 1);
renderFileList();
});
fileListEl.append(item);
});
}
if (dropZone.length) {
dropZone.on('dragover', function (e) {
e.preventDefault();
dropZone.addClass('dragover');
});
dropZone.on('dragleave', function () {
dropZone.removeClass('dragover');
});
dropZone.on('drop', function (e) {
e.preventDefault();
dropZone.removeClass('dragover');
addFiles(e.originalEvent.dataTransfer.files);
});
}
if (fileInput.length) {
fileInput.on('change', function () {
addFiles(this.files);
fileInput.val('');
});
}
function validateFile(file) {
const maxSize = 50 * 1024 * 1024; // 50 MB — matches PHP MAX_FILE_SIZE
const allowedTypes = [
'application/pdf',
'image/jpeg',
'image/png',
'application/msword',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
];
if (file.size > maxSize) {
showStatus('File "' + file.name + '" exceeds maximum size of 50 MB', 'error');
return false;
}
if (!allowedTypes.includes(file.type)) {
showStatus('File type "' + file.type + '" is not allowed', 'error');
return false;
}
return true;
}
function showStatus(message, type) {
const status = $('#udp-upload-status');
status.removeClass('success error info');
status.addClass(type).addClass('show').text(message).show();
setTimeout(() => {
status.fadeOut(function () {
status.removeClass('show');
});
}, 5000);
}
// Handle requirement type change for conditional reference number display
$('#requirement_type').on('change', function () {
const selectedValue = $(this).val();
const defaultRef = $('#defaultRef');
const defaultInput = $('#reference_number');
const defaultTextarea = $('#reference_number_textarea');
const defaultLabel = $('#reference-label');
const requirementsRef = $('#requirementsRef');
const requirementsTextarea = $('#reference_requirements');
const addressRef = $('#addressRef');
const addressTextarea = $('#reference_address');
// Hide all initially and disable their inputs to prevent submission of hidden fields
defaultRef.hide();
defaultInput.prop('disabled', true).hide();
defaultTextarea.prop('disabled', true).hide();
requirementsRef.hide();
requirementsTextarea.prop('disabled', true).hide();
addressRef.hide();
addressTextarea.prop('disabled', true).hide();
const labelMap = {
'ECE': 'ECE Reference Number',
'IEE': 'IEE Order Number',
'SpanTran': 'SpanTran: (TEC) Reference Number',
'WES': 'WES Reference Number'
};
if (labelMap[selectedValue]) {
defaultLabel.html(labelMap[selectedValue]);
defaultRef.show();
defaultInput.prop('disabled', false).prop('required', false).val('').show();
} else if (selectedValue === 'MOI') {
defaultLabel.html('Enter address to deliver *');
defaultRef.show();
defaultTextarea.prop('disabled', false).prop('required', true).val('').show();
defaultTextarea.attr('placeholder', 'Enter your complete address');
} else if (selectedValue === 'Others') {
requirementsRef.show();
requirementsTextarea.prop('disabled', false).prop('required', true).val('').show();
addressRef.show();
addressTextarea.prop('disabled', false).prop('required', true).val('').show();
}
});
// --- Form submit ---------------------------------------------------------
form.on('submit', function (e) {
e.preventDefault();
if (!form[0].checkValidity()) {
showStatus('Please fill in all required fields', 'error');
return false;
}
if (!$('#terms_check').is(':checked')) {
showStatus('Please accept the terms and conditions', 'error');
return false;
}
// Collect all file entries from all submitted degrees
const allFileEntries = [];
Object.keys(degreeFilesMap).forEach(function (degNum) {
(degreeFilesMap[degNum] || []).forEach(function (entry) {
allFileEntries.push(entry);
});
});
if (allFileEntries.length === 0) {
showStatus('Please add at least one degree with uploaded documents.', 'error');
return false;
}
// Check for still-uploading files
const stillUploading = allFileEntries.some(function (e) { return e.state === 'uploading'; });
if (stillUploading) {
showStatus('Files are still uploading. Please wait a moment then try again.', 'error');
return false;
}
// Check for failed uploads
const failedEntries = allFileEntries.filter(function (e) { return e.state === 'error'; });
if (failedEntries.length > 0) {
showStatus('Some files failed to upload: ' + failedEntries.map(function (e) { return e.file.name; }).join(', ') + '. Please remove and re-add them.', 'error');
return false;
}
// Check all have valid temp IDs
const missingTempId = allFileEntries.filter(function (e) { return !e.tempId; });
if (missingTempId.length > 0) {
showStatus('Some files are not ready yet. Please wait for uploads to complete.', 'error');
return false;
}
// Build FormData — send temp_file_ids[], NOT raw file binaries
const formData = new FormData();
formData.append('full_name', $('#full_name').val());
formData.append('user_email', $('#user_email').val());
formData.append('phone', $('#phone').val());
formData.append('alternative_phone', $('#alternative_phone').val());
formData.append('university_name', $('#university_name').val());
formData.append('college_name', $('#college_name').val());
formData.append('course_name', $('#course_name').val());
formData.append('requirement_type', $('#requirement_type').val());
const refValue = $('#reference_number').is(':visible')
? $('#reference_number').val()
: $('#reference_number_textarea').val();
formData.append('reference_number', refValue);
if ($('#reference_requirements').is(':visible')) {
formData.append('reference_requirements', $('#reference_requirements').val());
}
if ($('#reference_address').is(':visible')) {
formData.append('reference_address', $('#reference_address').val());
}
formData.append('action', 'udp_upload_documents');
formData.append('udp_nonce', udpVars.nonce ? udpVars.nonce : $('[name="udp_nonce"]').val());
// Append pre-uploaded temp file IDs
allFileEntries.forEach(function (entry) {
formData.append('temp_file_ids[]', entry.tempId + '::' + entry.file.name);
});
// Append degree hidden fields
degreesHidden.find('input').each(function () {
formData.append(this.name, $(this).val());
});
// -- Button spinner helpers ------------------------------------------
const submitIconEl = document.getElementById('udpSubmitIcon');
const checkmarkIconHtml = submitIconEl ? submitIconEl.innerHTML : '';
const spinnerSvg = '';
function setSubmitSpinner() {
if (submitIconEl) submitIconEl.innerHTML = spinnerSvg;
}
function restoreSubmitIcon() {
if (submitIconEl) submitIconEl.innerHTML = checkmarkIconHtml;
}
submitBtn.prop('disabled', true);
setSubmitSpinner();
// Show progress container
const progressContainer = $('#udp-upload-progress-container');
const progressBar = $('#udp-progress-bar');
const progressPercentage = $('.udp-progress-percentage');
const progressDetails = $('#udp-progress-details');
progressContainer.show();
progressBar.css('width', '5%');
progressPercentage.text('Submitting...');
progressDetails.text('Sending your application...');
// Use XMLHttpRequest
const xhr = new XMLHttpRequest();
xhr.upload.addEventListener('progress', function (e) {
if (e.lengthComputable) {
const pct = Math.round((e.loaded / e.total) * 100);
progressBar.css('width', pct + '%');
progressPercentage.text(pct + '%');
progressDetails.text('Submitting application...');
}
}, false);
xhr.addEventListener('load', function () {
if (xhr.status === 200) {
try {
const response = JSON.parse(xhr.responseText);
if (response.success) {
progressBar.css('width', '100%');
progressPercentage.text('100%');
progressDetails.text('Submitted! Processing...');
progressContainer.hide();
$('#udp-form-card').hide();
$('#udp-form-footer').hide();
const thankYouCard = $('#udp-thankyou-card');
thankYouCard.removeAttr('hidden').removeAttr('aria-hidden');
thankYouCard.addClass('udp-thankyou-visible');
// Reset form state
form[0].reset();
$('#termsCheck, #specialCheck').removeClass('checked');
$('#reference_number').val('').hide();
$('#reference_number_textarea').val('').hide();
$('#defaultRef').hide();
selectedFiles = [];
renderFileList();
degreeList.empty();
degreesHidden.empty();
degreeFilesMap = {};
degreeCounter = 0;
hideAddAnotherBtn(); // hide "Add Another Degree"
$('#add-degree-btn').show(); // restore "Add Degree" for next use
updateSubmitState();
} else {
progressContainer.hide();
showStatus('Error: ' + (response.data && response.data.message ? response.data.message : 'Unknown error'), 'error');
restoreSubmitIcon();
submitBtn.prop('disabled', false);
}
} catch (err) {
progressContainer.hide();
showStatus('Submission failed: Invalid response', 'error');
restoreSubmitIcon();
submitBtn.prop('disabled', false);
console.error('Parse error:', err);
}
} else {
progressContainer.hide();
showStatus('Submission failed with status ' + xhr.status, 'error');
restoreSubmitIcon();
submitBtn.prop('disabled', false);
}
}, false);
xhr.addEventListener('error', function () {
progressContainer.hide();
showStatus('Submission failed: Network error', 'error');
restoreSubmitIcon();
submitBtn.prop('disabled', false);
}, false);
xhr.addEventListener('abort', function () {
progressContainer.hide();
showStatus('Submission cancelled', 'error');
restoreSubmitIcon();
submitBtn.prop('disabled', false);
}, false);
xhr.open('POST', udpVars.ajaxUrl, true);
xhr.send(formData);
});
// --- RE-UPLOAD FORM HANDLER ------------------------------------------------
const reuploadForm = document.getElementById('udp-reupload-form');
if (reuploadForm) {
let reuploadFiles = [];
const reuploadDropZone = reuploadForm.querySelector('#reupload-drop-zone');
const reuploadFileInput = reuploadForm.querySelector('#reupload-file-input');
const reuploadFileList = reuploadForm.querySelector('#reupload-file-list');
const reuploadSubmitBtn = reuploadForm.querySelector('button[type="submit"]');
function renderReuploadFileList() {
reuploadFileList.innerHTML = '';
reuploadFiles.forEach(function (entry, idx) {
const li = document.createElement('li');
let statusHtml = '';
if (entry.state === 'done') {
statusHtml = `? Ready`;
} else if (entry.state === 'uploading') {
statusHtml = `${entry.progress}%`;
} else if (entry.state === 'error') {
statusHtml = `? Failed`;
}
li.innerHTML = `
${escapeHtml(entry.file.name)}
${(entry.file.size / 1024).toFixed(1)} KB
${entry.state === 'uploading' ? `
` : ''}
${entry.state === 'error' ? `
${escapeHtml(entry.error || 'Upload failed')}
` : ''}
${statusHtml}
`;
li.querySelector('.btn-remove-reupload').addEventListener('mouseenter', function () {
this.style.background = 'rgba(239, 68, 68, 0.1)';
this.style.color = '#ef4444';
});
li.querySelector('.btn-remove-reupload').addEventListener('mouseleave', function () {
this.style.background = 'transparent';
this.style.color = '#999';
});
li.querySelector('.btn-remove-reupload').addEventListener('click', function (e) {
e.preventDefault();
reuploadFiles.splice(idx, 1);
renderReuploadFileList();
updateReuploadSubmitState();
});
reuploadFileList.appendChild(li);
});
updateReuploadSubmitState();
}
function updateReuploadSubmitState() {
if (!reuploadSubmitBtn) return;
const total = reuploadFiles.length;
if (total === 0) {
reuploadSubmitBtn.textContent = 'Upload Documents';
reuploadSubmitBtn.disabled = true;
reuploadSubmitBtn.style.opacity = '0.7';
} else {
const done = reuploadFiles.filter(function (e) { return e.state === 'done'; }).length;
const uploading = reuploadFiles.filter(function (e) { return e.state === 'uploading'; }).length;
if (uploading > 0) {
reuploadSubmitBtn.textContent = `Uploading... (${done}/${total})`;
reuploadSubmitBtn.disabled = true;
reuploadSubmitBtn.style.opacity = '0.7';
} else {
reuploadSubmitBtn.textContent = 'Upload Documents';
reuploadSubmitBtn.disabled = false;
reuploadSubmitBtn.style.opacity = '1';
}
}
}
function addReuploadFiles(fileList) {
if (!fileList || !fileList.length) return;
Array.from(fileList).forEach(function (file) {
if (!validateFile(file)) return;
const isDuplicate = reuploadFiles.some(function (existing) {
return existing.file.name === file.name &&
existing.file.size === file.size &&
existing.file.lastModified === file.lastModified;
});
if (!isDuplicate) {
reuploadFiles.push({
file: file,
state: 'pending',
progress: 0,
tempId: null,
error: null
});
}
});
preUploadAllReupload();
}
function preUploadAllReupload() {
const pendingFiles = reuploadFiles.filter(function (e) { return e.state === 'pending'; });
const totalPending = pendingFiles.length;
if (totalPending === 0) return;
let completed = 0;
pendingFiles.forEach(function (entry) {
entry.state = 'uploading';
entry.progress = 5;
renderReuploadFileList();
preUploadFile(entry.file, function (progress) {
entry.progress = Math.min(95, progress);
renderReuploadFileList();
}).then(function (result) {
entry.tempId = result.tempId + '::' + result.fileName;
entry.state = 'done';
entry.progress = 100;
completed++;
renderReuploadFileList();
}).catch(function (error) {
entry.state = 'error';
entry.error = error.message || 'Failed to upload';
completed++;
renderReuploadFileList();
});
});
}
// Drag-drop handlers
if (reuploadDropZone) {
reuploadDropZone.addEventListener('dragover', function (e) {
e.preventDefault();
e.stopPropagation();
reuploadDropZone.style.backgroundColor = 'rgba(79, 110, 247, 0.05)';
reuploadDropZone.style.borderColor = '#4f6ef7';
});
reuploadDropZone.addEventListener('dragleave', function (e) {
if (e.target === reuploadDropZone) {
reuploadDropZone.style.backgroundColor = 'transparent';
reuploadDropZone.style.borderColor = '#e5e7eb';
}
});
reuploadDropZone.addEventListener('drop', function (e) {
e.preventDefault();
e.stopPropagation();
reuploadDropZone.style.backgroundColor = 'transparent';
reuploadDropZone.style.borderColor = '#e5e7eb';
addReuploadFiles(e.dataTransfer.files);
});
reuploadDropZone.addEventListener('click', function (e) {
if (e.target === reuploadDropZone || e.target.closest('#reupload-drop-zone')) {
reuploadFileInput.click();
}
});
}
if (reuploadFileInput) {
reuploadFileInput.addEventListener('change', function (e) {
addReuploadFiles(e.target.files);
reuploadFileInput.value = '';
});
}
// Form submission
reuploadForm.addEventListener('submit', function (e) {
e.preventDefault();
const emailField = reuploadForm.querySelector('input[name="reupload_email"]');
const email = emailField ? emailField.value.trim() : '';
if (!email || !email.includes('@')) {
alert('Please enter a valid email address');
return;
}
if (reuploadFiles.length === 0) {
alert('Please select at least one file to upload');
return;
}
const stillUploading = reuploadFiles.some(function (e) { return e.state === 'uploading'; });
if (stillUploading) {
alert('Files are still uploading. Please wait...');
return;
}
const failedEntries = reuploadFiles.filter(function (e) { return e.state === 'error'; });
if (failedEntries.length > 0) {
alert('Some files failed to pre-upload. Please remove and try again.');
return;
}
const missingTempId = reuploadFiles.filter(function (e) { return !e.tempId; });
if (missingTempId.length > 0) {
alert('Some files are not ready yet. Please wait...');
return;
}
const formData = new FormData();
formData.append('action', 'udp_reupload_documents');
formData.append('udp_reupload_nonce', udpVars.reuploadNonce);
formData.append('reupload_email', email);
reuploadFiles.forEach(function (entry) {
if (entry.tempId) {
formData.append('reupload_file_ids[]', entry.tempId);
}
});
if (reuploadSubmitBtn) {
reuploadSubmitBtn.disabled = true;
reuploadSubmitBtn.style.opacity = '0.7';
}
const xhr = new XMLHttpRequest();
xhr.addEventListener('load', function () {
if (xhr.status === 200) {
try {
const response = JSON.parse(xhr.responseText);
if (response.success) {
const thankyouCard = reuploadForm.querySelector('#udp-reupload-thankyou-card');
if (thankyouCard) {
const formCard = reuploadForm.querySelector('#udp-reupload-form-card') || document.getElementById('udp-reupload-form-card');
if (formCard) formCard.style.display = 'none';
const footer = document.getElementById('udp-reupload-footer');
if (footer) footer.style.display = 'none';
thankyouCard.removeAttribute('hidden');
thankyouCard.removeAttribute('aria-hidden');
thankyouCard.classList.add('udp-thankyou-visible');
}
} else {
alert('Error: ' + (response.data && response.data.message ? response.data.message : 'Upload failed'));
if (reuploadSubmitBtn) {
reuploadSubmitBtn.disabled = false;
reuploadSubmitBtn.style.opacity = '1';
}
}
} catch (err) {
alert('Invalid response from server');
if (reuploadSubmitBtn) {
reuploadSubmitBtn.disabled = false;
reuploadSubmitBtn.style.opacity = '1';
}
}
} else {
alert('Server error: ' + xhr.status);
if (reuploadSubmitBtn) {
reuploadSubmitBtn.disabled = false;
reuploadSubmitBtn.style.opacity = '1';
}
}
}, false);
xhr.addEventListener('error', function () {
alert('Network error');
if (reuploadSubmitBtn) {
reuploadSubmitBtn.disabled = false;
reuploadSubmitBtn.style.opacity = '1';
}
}, false);
xhr.open('POST', udpVars.ajaxUrl, true);
xhr.send(formData);
});
}
});
https://100transcripts.com/page-sitemap.xml
2026-06-25T08:13:49+00:00
https://100transcripts.com/product-sitemap.xml
2026-02-02T10:28:10+00:00
https://100transcripts.com/da_image-sitemap.xml
2022-05-02T08:24:54+00:00
https://100transcripts.com/discussion-topics-sitemap.xml
2025-08-22T04:18:26+00:00
https://100transcripts.com/category-sitemap.xml
2022-02-15T08:52:31+00:00
https://100transcripts.com/author-sitemap.xml
2022-02-15T08:57:52+00:00