/** * 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