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";
});