|
@@ -294,6 +294,36 @@ else
|
|
|
</div>
|
|
</div>
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+<!-- Payment channel selection -->
|
|
|
|
|
+<div id="paymentChannelModal" class="hidden fixed inset-0 z-[140] bg-black/70 backdrop-blur-[3px] items-center justify-center p-4 font-bricolage">
|
|
|
|
|
+ <div class="relative w-full max-w-[370px] overflow-hidden rounded-[32px] bg-[#F8F9FC] shadow-[0_28px_70px_rgba(0,0,0,0.35)] animate__animated animate__zoomIn animate__faster">
|
|
|
|
|
+ <div class="relative overflow-hidden bg-gradient-to-br from-[#EE0033] to-[#B80028] px-6 pb-7 pt-6 text-white">
|
|
|
|
|
+ <div class="absolute -right-8 -top-10 h-32 w-32 rounded-full bg-white/10"></div>
|
|
|
|
|
+ <div class="absolute -bottom-12 -left-8 h-28 w-28 rounded-full bg-black/10"></div>
|
|
|
|
|
+ <button type="button" onclick="hidePaymentChannelModal()" class="absolute right-4 top-4 z-10 flex h-9 w-9 items-center justify-center rounded-full bg-white/15 text-white transition hover:bg-white/25 active:scale-90" aria-label="Close">
|
|
|
|
|
+ <i class="fa-solid fa-xmark"></i>
|
|
|
|
|
+ </button>
|
|
|
|
|
+ <div class="relative z-[1] flex items-center gap-4">
|
|
|
|
|
+ <div class="flex h-14 w-14 shrink-0 items-center justify-center rounded-2xl bg-white text-[25px] text-[#EE0033] shadow-lg"><i class="fa-solid fa-wallet"></i></div>
|
|
|
|
|
+ <div><h2 class="text-[21px] font-black leading-tight">@Lang.payment_method_title</h2><p class="mt-1 text-[13px] font-semibold text-white/80">@Lang.payment_method_subtitle</p></div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="space-y-3 p-5">
|
|
|
|
|
+ <button type="button" onclick="selectPaymentChannel('@Constants.BASIC_WALLET_TICKET')" class="group flex w-full items-center gap-4 rounded-[20px] border-2 border-transparent bg-white p-4 text-left shadow-[0_5px_18px_rgba(31,41,55,0.07)] transition hover:-translate-y-0.5 hover:border-[#EE0033] active:scale-[0.98]">
|
|
|
|
|
+ <span class="flex h-12 w-12 shrink-0 items-center justify-center rounded-2xl bg-[#FFE8ED] text-[21px] text-[#EE0033]"><i class="fa-solid fa-mobile-screen-button"></i></span>
|
|
|
|
|
+ <span class="min-w-0 flex-1"><span class="block text-[16px] font-black text-[#171A24]">@Lang.payment_main_account</span><span class="mt-0.5 block text-[12px] font-semibold text-gray-500">@Lang.payment_main_account_desc</span></span>
|
|
|
|
|
+ <span class="flex h-8 w-8 items-center justify-center rounded-full bg-gray-100 text-gray-400 transition group-hover:bg-[#EE0033] group-hover:text-white"><i class="fa-solid fa-chevron-right text-[12px]"></i></span>
|
|
|
|
|
+ </button>
|
|
|
|
|
+ <button type="button" onclick="selectPaymentChannel('@Constants.NATCASH_WALLET_TICKET')" class="group flex w-full items-center gap-4 rounded-[20px] border-2 border-transparent bg-white p-4 text-left shadow-[0_5px_18px_rgba(31,41,55,0.07)] transition hover:-translate-y-0.5 hover:border-[#0A9800] active:scale-[0.98]">
|
|
|
|
|
+ <span class="flex h-12 w-12 shrink-0 items-center justify-center rounded-2xl bg-[#E7F8E6] text-[21px] text-[#0A9800]"><i class="fa-solid fa-wallet"></i></span>
|
|
|
|
|
+ <span class="min-w-0 flex-1"><span class="flex items-center gap-2 text-[16px] font-black text-[#171A24]">@Lang.payment_wallet <span class="rounded-full bg-[#E7F8E6] px-2 py-0.5 text-[9px] font-black text-[#0A9800]">PIN</span></span><span class="mt-0.5 block text-[12px] font-semibold text-gray-500">@Lang.payment_wallet_desc</span></span>
|
|
|
|
|
+ <span class="flex h-8 w-8 items-center justify-center rounded-full bg-gray-100 text-gray-400 transition group-hover:bg-[#0A9800] group-hover:text-white"><i class="fa-solid fa-chevron-right text-[12px]"></i></span>
|
|
|
|
|
+ </button>
|
|
|
|
|
+ <p class="pt-1 text-center text-[11px] font-semibold text-gray-400"><i class="fa-solid fa-shield-halved mr-1 text-[#0A9800]"></i>@Lang.payment_security_message</p>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+</div>
|
|
|
|
|
+
|
|
|
<!-- Order Summary Screen (from Figma) -->
|
|
<!-- Order Summary Screen (from Figma) -->
|
|
|
<div id="orderSummaryModal" class="hidden fixed inset-0 z-[150] bg-black/60 flex items-center justify-center p-0 font-bricolage backdrop-blur-[2px]">
|
|
<div id="orderSummaryModal" class="hidden fixed inset-0 z-[150] bg-black/60 flex items-center justify-center p-0 font-bricolage backdrop-blur-[2px]">
|
|
|
<div class="w-full h-full bg-white flex flex-col animate__animated animate__fadeInRight animate__faster shadow-2xl relative lg:max-w-[414px]">
|
|
<div class="w-full h-full bg-white flex flex-col animate__animated animate__fadeInRight animate__faster shadow-2xl relative lg:max-w-[414px]">
|
|
@@ -429,7 +459,7 @@ else
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
- <p class="text-[14px] font-bold text-[#555] text-center px-4 leading-snug mt-0 font-bricolage">@Lang.v2_otp_instruction</p>
|
|
|
|
|
|
|
+ <p id="paymentCodeInstruction" class="text-[14px] font-bold text-[#555] text-center px-4 leading-snug mt-0 font-bricolage">@Lang.v2_otp_instruction</p>
|
|
|
|
|
|
|
|
<!-- 6-Slots OTP Grid (Large Gray Blocks) -->
|
|
<!-- 6-Slots OTP Grid (Large Gray Blocks) -->
|
|
|
<div class="flex items-center justify-center gap-2 w-full mt-1 px-2" id="otpInputs">
|
|
<div class="flex items-center justify-center gap-2 w-full mt-1 px-2" id="otpInputs">
|
|
@@ -824,6 +854,9 @@ else
|
|
|
|
|
|
|
|
// --- Order Summary Modal Logic ---
|
|
// --- Order Summary Modal Logic ---
|
|
|
// --- Payment Preparation & Order Summary Logic ---
|
|
// --- Payment Preparation & Order Summary Logic ---
|
|
|
|
|
+ let pendingTickets = [];
|
|
|
|
|
+ let currentChannelPayment = '@Constants.BASIC_WALLET_TICKET';
|
|
|
|
|
+
|
|
|
function preparePayment(event) {
|
|
function preparePayment(event) {
|
|
|
const isBSMode = @(Model.termType == Constants.PIC10_BIGSMALL_CODE || Model.termType == Constants.PIC10_ODDEVEN_CODE ? "true" : "false");
|
|
const isBSMode = @(Model.termType == Constants.PIC10_BIGSMALL_CODE || Model.termType == Constants.PIC10_ODDEVEN_CODE ? "true" : "false");
|
|
|
const tickets = [];
|
|
const tickets = [];
|
|
@@ -865,19 +898,24 @@ else
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ pendingTickets = tickets;
|
|
|
|
|
+ $("#paymentChannelModal").removeClass("hidden").addClass("flex");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ function hidePaymentChannelModal() {
|
|
|
|
|
+ $("#paymentChannelModal").removeClass("flex").addClass("hidden");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ function selectPaymentChannel(channelPayment) {
|
|
|
|
|
+ currentChannelPayment = channelPayment;
|
|
|
|
|
+ hidePaymentChannelModal();
|
|
|
|
|
+
|
|
|
const requestData = {
|
|
const requestData = {
|
|
|
gameId: "@Model.termType",
|
|
gameId: "@Model.termType",
|
|
|
- ticket: tickets
|
|
|
|
|
|
|
+ ticket: pendingTickets,
|
|
|
|
|
+ channelPayment: channelPayment
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
- const btn = event ? event.currentTarget : null;
|
|
|
|
|
- const originalText = btn ? btn.innerHTML : "@Lang.v2_payment";
|
|
|
|
|
- if (btn) {
|
|
|
|
|
- btn.innerHTML = '<i class="fa-solid fa-circle-notch fa-spin"></i> Loading...';
|
|
|
|
|
- btn.disabled = true;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
$.ajax({
|
|
$.ajax({
|
|
|
url: subDomain + '@Url.Action("ConfirmTicketData", "Home")',
|
|
url: subDomain + '@Url.Action("ConfirmTicketData", "Home")',
|
|
|
type: 'POST',
|
|
type: 'POST',
|
|
@@ -885,23 +923,14 @@ else
|
|
|
data: JSON.stringify(requestData),
|
|
data: JSON.stringify(requestData),
|
|
|
success: function(data) {
|
|
success: function(data) {
|
|
|
|
|
|
|
|
- if (btn) {
|
|
|
|
|
- btn.innerHTML = originalText;
|
|
|
|
|
- btn.disabled = false;
|
|
|
|
|
- }
|
|
|
|
|
- if (data.responseCode === "0") {
|
|
|
|
|
- showOrderSummary(data, tickets);
|
|
|
|
|
|
|
+ if (data.responseCode === "0" || data.responseCode === "0000") {
|
|
|
|
|
+ showOrderSummary(data, pendingTickets);
|
|
|
} else {
|
|
} else {
|
|
|
showNotification(data.responseMessage || "Confirmation failed", data.responseCode);
|
|
showNotification(data.responseMessage || "Confirmation failed", data.responseCode);
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
error: function(err) {
|
|
error: function(err) {
|
|
|
|
|
|
|
|
- if (btn) {
|
|
|
|
|
- btn.innerHTML = originalText;
|
|
|
|
|
- btn.disabled = false;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
showNotification("Network error occurred.", "warning");
|
|
showNotification("Network error occurred.", "warning");
|
|
|
}
|
|
}
|
|
|
});
|
|
});
|
|
@@ -968,6 +997,11 @@ else
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function confirmCheckout(btn) {
|
|
function confirmCheckout(btn) {
|
|
|
|
|
+ if (currentChannelPayment === '@Constants.NATCASH_WALLET_TICKET') {
|
|
|
|
|
+ showOtpModal(true);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
const originalText = $(btn).html();
|
|
const originalText = $(btn).html();
|
|
|
$(btn).prop('disabled', true).html('<i class="fa-solid fa-spinner fa-spin mr-2"></i>Processing...');
|
|
$(btn).prop('disabled', true).html('<i class="fa-solid fa-spinner fa-spin mr-2"></i>Processing...');
|
|
|
|
|
|
|
@@ -979,7 +1013,7 @@ else
|
|
|
$(btn).prop('disabled', false).html(originalText);
|
|
$(btn).prop('disabled', false).html(originalText);
|
|
|
|
|
|
|
|
if (data.responseCode === "0") {
|
|
if (data.responseCode === "0") {
|
|
|
- showOtpModal();
|
|
|
|
|
|
|
+ showOtpModal(false);
|
|
|
} else {
|
|
} else {
|
|
|
showNotification(data.responseMessage || "Failed to send OTP", data.responseCode);
|
|
showNotification(data.responseMessage || "Failed to send OTP", data.responseCode);
|
|
|
}
|
|
}
|
|
@@ -992,7 +1026,7 @@ else
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
let otpInterval;
|
|
let otpInterval;
|
|
|
- function showOtpModal() {
|
|
|
|
|
|
|
+ function showOtpModal(isWalletPin) {
|
|
|
hideOrderSummary();
|
|
hideOrderSummary();
|
|
|
$("#otpModal").removeClass("hidden").addClass("flex");
|
|
$("#otpModal").removeClass("hidden").addClass("flex");
|
|
|
$("#otpInputs input").val("");
|
|
$("#otpInputs input").val("");
|
|
@@ -1034,7 +1068,14 @@ else
|
|
|
$("#otpTicketTypeContainer").append(`<span class='text-[17px] font-[900] ${typeColorClass} italic'>${displayName}</span>`);
|
|
$("#otpTicketTypeContainer").append(`<span class='text-[17px] font-[900] ${typeColorClass} italic'>${displayName}</span>`);
|
|
|
|
|
|
|
|
$("#otpTotalAmount").text($("#summaryTotalAmount").text());
|
|
$("#otpTotalAmount").text($("#summaryTotalAmount").text());
|
|
|
- startOtpTimer(60);
|
|
|
|
|
|
|
+ if (isWalletPin) {
|
|
|
|
|
+ $("#paymentCodeInstruction").text('@Html.Raw(Lang.payment_wallet_pin_instruction.Replace("'", "\\'"))');
|
|
|
|
|
+ $("#otpTimer, #resendOtpBtn").addClass("hidden");
|
|
|
|
|
+ clearInterval(otpInterval);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ $("#paymentCodeInstruction").text('@Html.Raw(Lang.v2_otp_instruction.Replace("'", "\\'"))');
|
|
|
|
|
+ startOtpTimer(60);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Add backspace support for OTP inputs
|
|
// Add backspace support for OTP inputs
|
|
@@ -1140,7 +1181,7 @@ else
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
if (otpCode.length < 6) {
|
|
if (otpCode.length < 6) {
|
|
|
- showNotification("Please enter full 6-digit OTP", "warning");
|
|
|
|
|
|
|
+ showNotification(currentChannelPayment === '@Constants.NATCASH_WALLET_TICKET' ? "Please enter full 6-digit PIN" : "Please enter full 6-digit OTP", "warning");
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -1149,7 +1190,9 @@ else
|
|
|
|
|
|
|
|
const finalData = {
|
|
const finalData = {
|
|
|
transIdByTicket: currentTransId,
|
|
transIdByTicket: currentTransId,
|
|
|
- paymentCode: otpCode
|
|
|
|
|
|
|
+ paymentCode: currentChannelPayment === '@Constants.NATCASH_WALLET_TICKET' ? null : otpCode,
|
|
|
|
|
+ walletPin: currentChannelPayment === '@Constants.NATCASH_WALLET_TICKET' ? otpCode : null,
|
|
|
|
|
+ channelPayment: currentChannelPayment
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
// Call the unified backend action that verifies OTP and then buys the ticket
|
|
// Call the unified backend action that verifies OTP and then buys the ticket
|