if (rowError) { throw new Error( "Passport uploaded, but the Passport URL could not be saved: " + rowError.message, ); } if (!rowData || rowData.length === 0) { throw new Error( "Passport uploaded, but no Corps Member record was updated.", ); } /* ===================================================== 5. VERIFY THAT PASSPORT URL WAS ACTUALLY SAVED ===================================================== */ status.textContent = "Verifying passport record..."; const { data: verifyData, error: verifyError } = await window.supabaseClient .from("CorpsMembers") .select("StateCode, PassportURL") .eq("StateCode", stateCode) .single(); console.log("PASSPORT URL VERIFICATION:", verifyData); console.log("PASSPORT URL VERIFICATION ERROR:", verifyError); if (verifyError) { throw new Error( "Passport uploaded, but the saved Passport URL could not be verified.", ); } if (!verifyData || verifyData.PassportURL !== passportURL) { throw new Error( "Passport uploaded, but the Passport URL was not correctly saved to the Corps Member record.", ); } /* ===================================================== 6. EVERYTHING CONFIRMED ===================================================== */ window.passportURL = passportURL; passportUploaded = true; status.style.display = "block"; status.style.color = "green"; status.textContent = "✓ Passport uploaded and saved successfully."; /* ===================================================== 7. LOCK PASSPORT AFTER SUCCESS ===================================================== */ document.getElementById("changePassportHint").style.display = "none"; document.getElementById("passportInfo").style.display = "none"; button.style.display = "none"; console.log("PASSPORT UPLOADED AND DATABASE VERIFIED:", passportURL); } catch (error) { console.error("PASSPORT UPLOAD FAILED:", error); status.style.display = "block"; status.style.color = "red"; status.textContent = error.message; button.disabled = false; } } function loadYears() { const from = document.getElementById("fromYear"); const to = document.getElementById("toYear"); for (let year = 2026; year <= 2040; year++) { from.innerHTML += ``; to.innerHTML += ``; } } window.onload = loadYears; let canvas; let ctx; let drawing = false; let hasSignature = false; let signatureTimer; function initializeSignature() { canvas = document.getElementById("signaturePad"); if (!canvas) { return; } ctx = canvas.getContext("2d"); canvas.width = canvas.offsetWidth; canvas.height = canvas.offsetHeight; ctx.lineWidth = 2; ctx.lineCap = "round"; ctx.lineJoin = "round"; /* ========================= MOUSE ========================= */ canvas.onmousedown = function (e) { startDrawing(e); }; canvas.onmousemove = function (e) { draw(e); }; canvas.onmouseup = function (e) { stopDrawing(e); }; canvas.onmouseleave = function (e) { stopDrawing(e); }; /* ========================= FINGER / TOUCH ========================= */ canvas.addEventListener( "touchstart", function (e) { e.preventDefault(); startDrawing(e); }, { passive: false }, ); canvas.addEventListener( "touchmove", function (e) { e.preventDefault(); draw(e); }, { passive: false }, ); canvas.addEventListener( "touchend", function (e) { e.preventDefault(); stopDrawing(e); }, { passive: false }, ); } function getSignaturePosition(e) { const rect = canvas.getBoundingClientRect(); let clientX; let clientY; if (e.touches && e.touches.length > 0) { clientX = e.touches[0].clientX; clientY = e.touches[0].clientY; } else if (e.changedTouches && e.changedTouches.length > 0) { clientX = e.changedTouches[0].clientX; clientY = e.changedTouches[0].clientY; } else { clientX = e.clientX; clientY = e.clientY; } return { x: clientX - rect.left, y: clientY - rect.top, }; } function startDrawing(e) { drawing = true; hasSignature = true; const position = getSignaturePosition(e); ctx.beginPath(); ctx.moveTo(position.x, position.y); } function draw(e) { if (!drawing) { return; } e.preventDefault(); const position = getSignaturePosition(e); ctx.lineTo(position.x, position.y); ctx.stroke(); } function stopDrawing(e) { if (!drawing) { return; } drawing = false; ctx.beginPath(); clearTimeout(signatureTimer); if (hasSignature) { signatureTimer = setTimeout(function () { checkFormReady(); }, 2000); } } function clearSignature() { ctx.clearRect(0, 0, canvas.width, canvas.height); hasSignature = false; clearTimeout(signatureTimer); checkFormReady(); } async function uploadSignature() { try { const stateCode = document .getElementById("loginStateCode") .value.trim(); const canvas = document.getElementById("signaturePad"); canvas.toBlob(async function (blob) { if (!blob) { console.error("Unable to create signature image."); alert("Unable to create signature image."); return; } const filePath = "signatures/" + stateCode + ".png"; const { error } = await window.supabaseClient.storage .from("form2a") .upload(filePath, blob, { contentType: "image/png", upsert: true, }); if (error) { console.error("Signature upload error:", error); alert("Signature upload failed. Please try again."); return; } const { data: publicURLData } = window.supabaseClient.storage .from("form2a") .getPublicUrl(filePath); signatureURL = publicURLData.publicUrl; console.log("Signature uploaded:", signatureURL); }, "image/png"); } catch (error) { console.error("Signature upload failed:", error); alert("Signature upload failed. Please try again."); } } function showPassport() { document.getElementById("passportSection").style.display = "block"; document.getElementById("passportContinueBtn").style.display = "none"; document.getElementById("passportSection").scrollIntoView({ behavior: "smooth", }); } function checkMemberInformation() { const fields = [ "fullName", "stateCode", "callUpNo", "phoneNo", "gender", "stateOrigin", "deploymentState", ]; let completed = true; fields.forEach(function (field) { const value = document.getElementById(field).value.trim(); if (value === "") { completed = false; } }); if (completed) { document.getElementById("passportSection").style.display = "block"; document.getElementById("passportSection").scrollIntoView({ behavior: "smooth", }); } else { alert( "Please complete all Corps Member Information before continuing.", ); } } function openPassportPicker() { document.getElementById("passportUpload").click(); } function togglePassportInfo() { const content = document.getElementById("passportNoteContent"); const arrow = document.getElementById("passportInfoArrow"); if (content.style.display === "block") { content.style.display = "none"; arrow.className = "fa-solid fa-chevron-down"; } else { content.style.display = "block"; arrow.className = "fa-solid fa-chevron-up"; } } function showSignature() { const comment = document.getElementById("corpsComment").value.trim(); const section = document.getElementById("signatureSection"); if (comment !== "") { section.style.display = "block"; setTimeout(function () { initializeSignature(); }, 500); section.scrollIntoView({ behavior: "smooth", block: "start", }); } else { section.style.display = "none"; } } function testSuccessPage() { document.getElementById("uploadPage").style.display = "none"; document.getElementById("successPage").style.display = "block"; } function getReportDetails() { return { serviceYear: document.getElementById("serviceYear").value.trim(), batchStream: document.getElementById("batchStream").value.trim(), fromYear: document.getElementById("fromYear").value.trim(), toYear: document.getElementById("toYear").value.trim(), comment: document.getElementById("corpsComment").value.trim(), }; } function validateReportDetails() { const fields = [ { id: "serviceYear", label: "Service Year", }, { id: "batchStream", label: "Batch & Stream", }, { id: "fromYear", label: "From Year", }, { id: "toYear", label: "To Year", }, { id: "corpsComment", label: "Corps Member Comment", }, ]; let missingFields = []; fields.forEach(function (field) { const element = document.getElementById(field.id); const value = element.value.trim(); const label = element.closest(".detail-box")?.querySelector("label"); if (value === "") { missingFields.push(field.label); element.classList.add("required-error"); if (label) { label.classList.add("required-error-label"); } } else { element.classList.remove("required-error"); if (label) { label.classList.remove("required-error-label"); } } }); /* ========================= REMOVE OLD ERROR MESSAGE ========================= */ let errorBox = document.getElementById("reportDetailsError"); /* ========================= EVERYTHING COMPLETE ========================= */ if (missingFields.length === 0) { if (errorBox) { errorBox.style.display = "none"; } return true; } /* ========================= CREATE ERROR MESSAGE ========================= */ if (!errorBox) { errorBox = document.createElement("div"); errorBox.id = "reportDetailsError"; errorBox.className = "error-message"; const commentBox = document .getElementById("corpsComment") .closest(".detail-box"); commentBox.parentNode.insertBefore(errorBox, commentBox); } errorBox.innerHTML = ' ' + "Please complete all required fields before you can submit Form 2A."; errorBox.style.display = "block"; /* ========================= SCROLL TO FIRST MISSING FIELD ========================= */ const firstMissing = document.querySelector(".required-error"); if (firstMissing) { firstMissing.scrollIntoView({ behavior: "smooth", block: "center", }); } return false; } function clearFieldError(fieldId) { const field = document.getElementById(fieldId); if (!field) return; if (field.value.trim() !== "") { field.classList.remove("required-error"); const label = field.closest(".detail-box")?.querySelector("label"); if (label) { label.classList.remove("required-error-label"); } } const errorBox = document.getElementById("reportDetailsError"); const remainingErrors = document.querySelectorAll(".required-error"); if (errorBox && remainingErrors.length === 0) { errorBox.style.display = "none"; } } async function submitForm2A() { const stateCode = document.getElementById("stateCode").value.trim(); const submitBtn = document.getElementById("submitBtn"); /* ===================================================== UNIVERSAL IN-APP ERROR MESSAGE ===================================================== */ function showSubmitError(message, targetId = "submitBtn") { let errorBox = document.getElementById("submitValidationError"); if (!errorBox) { errorBox = document.createElement("div"); errorBox.id = "submitValidationError"; errorBox.className = "error-message"; const target = document.getElementById(targetId); if (target && target.parentNode) { target.parentNode.insertBefore(errorBox, target); } else { document.getElementById("uploadPage").appendChild(errorBox); } } errorBox.innerHTML = ' ' + message; errorBox.style.display = "block"; errorBox.scrollIntoView({ behavior: "smooth", block: "center", }); } /* ===================================================== CLEAR PREVIOUS SUBMISSION ERROR ===================================================== */ const oldError = document.getElementById("submitValidationError"); if (oldError) { oldError.style.display = "none"; } /* ===================================================== 1. BASIC VALIDATION ===================================================== */ if (!stateCode) { showSubmitError("State Code is missing.", "stateCode"); return; } /* ===================================================== 2. NAME CHANGE VALIDATION ===================================================== */ const nameChange = document.querySelector( 'input[name="nameChange"]:checked', ); if (!nameChange) { showSubmitError( "Please select whether you have changed or corrected your name.", "nameChangeArea", ); return; } /* ===================================================== 3. VALIDATE REPORT DETAILS ===================================================== */ if (!validateReportDetails()) { return; } /* ===================================================== 4. VALIDATE SIGNATURE ===================================================== */ if (!hasSignature) { const signatureSection = document.getElementById("signatureSection"); let signatureError = document.getElementById("signatureError"); if (!signatureError) { signatureError = document.createElement("div"); signatureError.id = "signatureError"; signatureError.className = "error-message"; signatureSection.appendChild(signatureError); } signatureError.innerHTML = ' ' + "Please provide your signature before submitting Form 2A."; signatureError.style.display = "block"; signatureSection.scrollIntoView({ behavior: "smooth", block: "start", }); return; } /* ===================================================== 5. GET REPORT DETAILS ===================================================== */ const reportDetails = getReportDetails(); /* ===================================================== 6. DISABLE SUBMIT BUTTON ===================================================== */ submitBtn.disabled = true; submitBtn.innerHTML = ' SUBMITTING...'; try { /* =================================================== 7. SAVE FORM DETAILS =================================================== */ const correctedName = document .getElementById("correctedName") .value.trim(); const { data: updateData, error: updateError } = await window.supabaseClient .from("CorpsMembers") .update({ NameChange: correctedName, ServiceYear: reportDetails.serviceYear, BatchStream: reportDetails.batchStream, From: reportDetails.fromYear, To: reportDetails.toYear, Comment: reportDetails.comment, }) .eq("StateCode", stateCode) .select( "StateCode, NameChange, ServiceYear, BatchStream, From, To, Comment", ); console.log("FORM DETAILS UPDATE:", updateData); console.log("FORM DETAILS ERROR:", updateError); if (updateError) { throw new Error( "Unable to save the form details: " + updateError.message, ); } if (!updateData || updateData.length === 0) { throw new Error( "No Corps Member record was updated. Please check the State Code.", ); } /* =================================================== 8. PREPARE SIGNATURE =================================================== */ const canvas = document.getElementById("signaturePad"); if (!canvas) { throw new Error("Signature pad could not be found."); } const signatureBlob = await new Promise(function (resolve) { canvas.toBlob(function (blob) { resolve(blob); }, "image/png"); }); if (!signatureBlob) { throw new Error("Unable to create the signature image."); } /* =================================================== 9. UPLOAD SIGNATURE =================================================== */ const signaturePath = "signatures/" + stateCode.replace(/\//g, "-") + ".png"; console.log("SIGNATURE UPLOAD STARTED"); console.log("SIGNATURE PATH:", signaturePath); const { data: signatureUploadData, error: signatureUploadError } = await window.supabaseClient.storage .from("form2a") .upload(signaturePath, signatureBlob, { contentType: "image/png", upsert: false, }); console.log("SIGNATURE STORAGE DATA:", signatureUploadData); console.log("SIGNATURE STORAGE ERROR:", signatureUploadError); if (signatureUploadError) { throw new Error( "Signature upload failed: " + signatureUploadError.message, ); } /* =================================================== 10. GET SIGNATURE PUBLIC URL =================================================== */ const { data: signatureURLData } = window.supabaseClient.storage .from("form2a") .getPublicUrl(signaturePath); const signatureURL = signatureURLData.publicUrl; console.log("SIGNATURE URL:", signatureURL); if (!signatureURL) { throw new Error("Signature URL could not be generated."); } /* =================================================== 11. SAVE SIGNATURE URL =================================================== */ const { data: signatureRowData, error: signatureRowError } = await window.supabaseClient .from("CorpsMembers") .update({ SignatureURL: signatureURL, }) .eq("StateCode", stateCode) .select("StateCode, SignatureURL"); console.log("SIGNATURE URL ROW:", signatureRowData); console.log("SIGNATURE URL ERROR:", signatureRowError); if (signatureRowError) { throw new Error( "Unable to save SignatureURL: " + signatureRowError.message, ); } if (!signatureRowData || signatureRowData.length === 0) { throw new Error("Signature URL could not be saved."); } /* ========================= 11. MARK FORM AS SUBMITTED ========================= */ const submissionDate = new Date().toISOString().split("T")[0]; const { data: submissionData, error: submissionError } = await window.supabaseClient .from("CorpsMembers") .update({ FormSubmitted: true, FormSubmissionDate: submissionDate, }) .eq("StateCode", stateCode) .select("StateCode, FormSubmitted, FormSubmissionDate"); console.log("FORM SUBMISSION STATUS:", submissionData); console.log("FORM SUBMISSION STATUS ERROR:", submissionError); if (submissionError) { throw new Error( "Unable to record form submission: " + submissionError.message, ); } if (!submissionData || submissionData.length === 0) { throw new Error( "Form was completed, but submission status could not be recorded.", ); } /* =================================================== 12. EVERYTHING SUCCESSFUL =================================================== */ window.signatureURL = signatureURL; console.log("FORM 2A SUBMITTED SUCCESSFULLY"); submitBtn.innerHTML = ' SUBMITTED'; /* =================================================== 13. OPEN SUCCESS PAGE =================================================== */ setTimeout(function () { document.getElementById("uploadPage").style.display = "none"; document.getElementById("successPage").style.display = "block"; window.scrollTo({ top: 0, behavior: "smooth", }); }, 700); } catch (error) { console.error("FORM 2A SUBMISSION FAILED:", error); /* =================================================== SHOW ERROR INSIDE THE APP =================================================== */ showSubmitError(error.message, "submitBtn"); /* =================================================== RESTORE SUBMIT BUTTON =================================================== */ submitBtn.disabled = false; submitBtn.innerHTML = ' SUBMIT FORM 2A'; } } function checkFormReady() { const submitBtn = document.getElementById("submitBtn"); if (!submitBtn) return; submitBtn.disabled = false; } document .getElementById("loginStateCode") .addEventListener("input", function () { document.getElementById("stateCodeError").style.display = "none"; });