| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592 |
- @model LotteryWebApp.Models.HomeIndex_ViewModel
- @{
- ViewData["Title"] = Lang.millions_transfer;
- Layout = "~/Areas/Millions/Views/Shared/_Layout.cshtml";
- }
- @using LotteryWebApp.Languages;
- @functions {
- public string FormatMoney(string amount) {
- if (string.IsNullOrEmpty(amount)) return "0";
- var clean = new string(amount.Where(c => char.IsDigit(c)).ToArray());
- if (long.TryParse(clean, out long val)) {
- return val.ToString("#,##0", new System.Globalization.CultureInfo("vi-VN")).Replace(",", ".");
- }
- return amount;
- }
- }
- <style>
- @@keyframes float {
- 0%, 100% { transform: translateY(0); }
- 50% { transform: translateY(-8px); }
- }
- .animate-float {
- animation: float 4s ease-in-out infinite;
- }
- .btn-premium {
- border: 2px solid #ffffff !important;
- box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15), inset 0 0 0 1px rgba(255, 255, 255, 0.1);
- transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
- }
- .btn-premium:active {
- transform: scale(0.95);
- box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
- }
- .btn-premium-red {
- background: linear-gradient(135deg, #0062FF 0%, #004ecb 100%);
- }
- </style>
- <div class="main-container animate__animated animate__fadeIn bg-[#EAEAEA] min-h-screen font-bricolage overflow-x-hidden">
- <!-- Standardized Header (Matches Profile/Rules) -->
- <div class="sticky top-0 w-full bg-[#0062FF] h-[52px] flex items-center justify-between px-4 z-[100] shadow-sm">
- <!-- Back Button -->
- <button onclick="history.back()" class="w-10 h-10 flex items-center justify-center -ml-2 rounded-full active:bg-white/20 transition-colors z-10 text-white">
- <i class="fa-solid fa-arrow-left text-[20px]"></i>
- </button>
- <!-- Title centered -->
- <div class="absolute inset-0 flex items-center justify-center pointer-events-none">
- <span class="font-bold text-[24px] text-white tracking-wide uppercase">@Lang.millions_transfer</span>
- </div>
- </div>
- <div class="pt-[20px] px-4 pb-24 max-w-[414px] mx-auto">
- <!-- Account Card Section (Matching Figma: Frame 69) -->
- <div class="relative w-full bg-[#0062FF] rounded-[12px] overflow-hidden shadow-xl mb-6 pl-8 pr-5 py-2 flex flex-col justify-between" style="border: 4px solid transparent; border-image: linear-gradient(175deg, rgba(255,255,255,0.2) 0%, rgba(255,199,0,0.4) 100%) 1; border-radius: 12px; aspect-ratio: 383/92;">
- <!-- Decorative Elements (positions from Figma: card 383×92) -->
- <div class="absolute inset-0 pointer-events-none overflow-hidden rounded-[12px]">
- <!-- Golden Ribbon: Figma x:232.58 y:19.11 w:202.23 h:113.29 → right:0, top:20.8%, w:52.8% -->
- <img src="/Millions/img/transfer_card_bg_v2.png" alt="" class="absolute z-0" style="right: -10%; top: 20%; width: 53%; height: auto;" />
-
- <!-- Coin 2 (top-right): Figma x:336 y:11 w:27 h:26 → right:5.2%, top:12% -->
- <img src="/Millions/img/transfer/coin_2.png" alt="" class="absolute z-10 animate-float" style="right: 5%; top: 12%; width: 7%;" />
- <!-- Coin 1 (mid-right): Figma x:309 y:51 w:28 h:25 → right:12%, top:55% -->
- <img src="/Millions/img/transfer/coin_1.png" alt="" class="absolute z-10 animate-float" style="right: 12%; top: 55%; width: 7.4%; animation-delay: 0.5s;" />
- <!-- Coin 3 (small, left of ribbon): Figma x:272 y:27 w:18 h:12 → right:24.3%, top:29% -->
- <img src="/Millions/img/transfer/coin_3.png" alt="" class="absolute z-10 animate-pulse" style="right: 24%; top: 29%; width: 4.7%;" />
-
- <!-- Lights: Figma w:800 h:43, full-bleed glow overlays -->
- <img src="/Millions/img/transfer/light_1.png" alt="" class="absolute z-[1]" style="top: -23%; left: -55%; width: 210%; opacity: 0.7;" />
- <img src="/Millions/img/transfer/light_2.png" alt="" class="absolute z-[1]" style="bottom: -23%; left: -55%; width: 210%; opacity: 0.7;" />
- </div>
- <!-- Account Label -->
- <p class="relative z-10 text-white font-bold text-[16px] tracking-normal" style="font-family: 'Bricolage Grotesque', sans-serif;">@Lang.millions_account_name</p>
-
- <!-- Balance Row -->
- <div class="relative z-10 flex items-end gap-2">
- <span id="currentBetCoin" class="font-[800] text-[40px] leading-[1.2]" style="background: linear-gradient(179deg, rgba(255,255,255,1) 0%, rgba(240,201,63,1) 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; font-family: 'Bricolage Grotesque', sans-serif;">@FormatMoney(Model?.userStatus?.bet_coin)</span>
- <span class="text-white font-[800] text-[20px] uppercase pb-[6px]" style="font-family: 'Bricolage Grotesque', sans-serif;">htg</span>
- </div>
- </div>
- <!-- Selection Area (Horizontal Cards) -->
- <div class="mb-6">
- <h2 class="text-[#534A4A] font-[900] text-[18px] mb-3 pl-1">@Lang.millions_choose_account</h2>
- <div class="flex gap-3">
- <!-- Basic Account Option -->
- <div id="selectBasic" onclick="selectChannel(1)" class="channel-card flex-1 bg-white h-[76px] rounded-[18px] border-2 border-[#0062FF] shadow-md flex items-center px-3 gap-2 cursor-pointer relative">
- <!-- Selected Icon -->
- <div class="check-icon absolute -top-2 -right-1 bg-white rounded-full">
- <i class="fa-solid fa-circle-check text-[#00AF1B] text-[20px]"></i>
- </div>
- <span class="text-[#0062FF] font-[900] text-[15px] leading-tight flex-1">@Lang.Basic<br />@Lang.Account</span>
- <img src="/Millions/img/transfer_basic_icon.png" alt="Basic" class="w-12 h-10 object-contain" />
- </div>
- <!-- Natcash Card -->
- <div id="selectNatcash" onclick="selectChannel(2)" class="channel-card flex-1 bg-white h-[76px] rounded-[18px] border border-gray-100 shadow-sm flex items-center px-3 gap-2 cursor-pointer relative overflow-visible">
- <!-- Selected Icon (Hidden by default) -->
- <div class="check-icon absolute -top-2 -right-1 bg-white rounded-full hidden">
- <i class="fa-solid fa-circle-check text-[#00AF1B] text-[20px]"></i>
- </div>
- <div class="flex-1 overflow-hidden h-full flex items-center">
- <img src="/Millions/img/transfer_other_card.png" alt="Natcash" class="w-full h-full object-contain" />
- </div>
- </div>
- </div>
- </div>
- <!-- Form Fields Area -->
- <div class="flex flex-col gap-2">
- <!-- Sender Phone -->
- <div class="flex flex-col gap-2">
- <label class="text-[#534A4A] font-[900] text-[16px] px-1 capitalize">@Lang.millions_sender_phone</label>
- <div class="relative w-full group">
- <input type="text" readonly value="@(Model?.userStatus?.msisdn ?? "0")" class="w-full bg-gray-100 border border-gray-300 text-[#534A4A] text-[17px] font-[800] rounded-[18px] py-[15px] px-5 outline-none transition-all cursor-not-allowed" />
- <div class="absolute right-4 top-1/2 -translate-y-1/2 text-gray-400">
- <i class="fa-solid fa-lock text-[20px] opacity-40"></i>
- </div>
- </div>
- </div>
- <!-- Receiver Phone (Mandatory same as sender) -->
- <div class="flex flex-col gap-2">
- <label class="text-[#534A4A] font-[900] text-[16px] px-1 capitalize">@Lang.millions_receiver_phone</label>
- <div class="relative w-full">
- <input id="receiverPhone" type="tel" readonly value="@(Model?.userStatus?.msisdn ?? "0")" class="w-full bg-gray-100 border border-gray-300 text-[#534A4A] text-[17px] font-[800] rounded-[18px] py-[15px] px-5 outline-none transition-all cursor-not-allowed" />
- <div class="absolute right-4 top-1/2 -translate-y-1/2 text-gray-400">
- <i class="fa-solid fa-lock text-[20px] opacity-40"></i>
- </div>
- </div>
- </div>
- <!-- Amount -->
- <div class="flex flex-col gap-2">
- <label class="text-[#534A4A] font-[900] text-[16px] px-1 capitalize">@Lang.millions_amount_htg</label>
- <div class="relative w-full">
- <input id="transferAmount" type="number" value="5000" placeholder="5,000" class="w-full bg-white border border-gray-300 focus:border-[#0062FF] focus:ring-2 focus:ring-[#0062FF]/10 text-[#0062FF] text-[17px] font-[800] rounded-[18px] py-[15px] px-5 outline-none transition-all placeholder:text-gray-300" />
- <span class="absolute right-5 top-1/2 -translate-y-1/2 text-gray-400 font-black">HTG</span>
- </div>
- <!-- Shortcut Buttons -->
- <div class="flex gap-2 mt-1">
- <button onclick="setAmount(10, this)" class="amt-btn flex-1 py-1.5 border border-gray-300 rounded-lg text-[14px] font-black transition-all bg-white text-[#534A4A] flex items-center justify-center gap-1 shadow-sm">
- 10
- <i class="fa-solid fa-circle-check text-[#00AF1B] text-[14px] hidden"></i>
- </button>
- <button onclick="setAmount(1000, this)" class="amt-btn flex-1 py-1.5 border border-gray-300 rounded-lg text-[14px] font-black transition-all bg-white text-[#534A4A] flex items-center justify-center gap-1 shadow-sm">
- 1.000
- <i class="fa-solid fa-circle-check text-[#00AF1B] text-[14px] hidden"></i>
- </button>
- <button id="defaultAmt" onclick="setAmount(5000, this)" class="amt-btn flex-1 py-1.5 border-2 border-white bg-[#0062FF] rounded-lg text-[14px] font-black text-white transition-all flex items-center justify-center gap-1 shadow-md">
- 5.000
- <i class="fa-solid fa-circle-check text-white text-[14px]"></i>
- </button>
- </div>
- <!-- Fee Section (Newly placed on a new line) -->
- <div class="mt-6 flex flex-col gap-1 px-1">
- <span class="text-gray-500 font-bold text-[14px]">@Lang.millions_fee</span>
- <span class="text-black font-black text-[28px] leading-none mt-1">@Lang.millions_free</span>
- </div>
- </div>
- </div>
- <!-- Main Action Button -->
- <div class="mt-6">
- <button id="btnContinue" class="btn-premium btn-premium-red w-full text-white font-[900] text-[18px] py-[18px] rounded-[22px] active:scale-95 transition-all uppercase tracking-wide">
- @Lang.millions_continue
- </button>
- </div>
- </div>
- <!-- Success Modal Overlay -->
- <div id="successModal" class="fixed inset-0 z-[110] flex items-center justify-center hidden px-6" style="background: rgba(0,0,0,0.7);">
- <div class="w-full max-w-[370px] bg-white rounded-[32px] overflow-hidden flex flex-col items-center animate__animated animate__zoomIn animate__faster shadow-2xl relative">
- <!-- Content Container -->
- <div class="relative z-10 w-full flex flex-col items-center pt-10 pb-8 px-6">
-
- <!-- Success Icon Group -->
- <div class="relative w-full flex justify-center mb-0 mt-2 z-10 px-4">
- <img src="/Millions/img/modal/otp_success.png" alt="Success" class="w-full max-w-[200px] h-auto object-contain">
- </div>
- <h2 class="text-[#0A9800] font-[800] text-[32px] mb-1 tracking-tight">@Lang.success</h2>
- <p class="text-[#000000] font-[700] text-[20px] text-center px-4 mb-6 leading-tight">
- @Lang.millions_payment_successfully
- </p>
- <div class="w-full border-t border-dashed border-gray-200 pt-5 flex flex-col gap-3 mb-5">
- <!-- Info Rows -->
- <div class="flex justify-between items-center text-[15px]">
- <span class="text-[#534A4A] font-bold">@Lang.amount_transfered</span>
- <span id="successAmount" class="text-black font-black text-right">5.000 HTG</span>
- </div>
- <div class="flex justify-between items-center text-[15px]">
- <span class="text-[#534A4A] font-bold">@Lang.sender</span>
- <span id="successSender" class="text-black font-black text-right">50940236545</span>
- </div>
- <div class="flex justify-between items-center text-[15px]">
- <span class="text-[#534A4A] font-bold">@Lang.receiver</span>
- <span id="successReceiver" class="text-black font-black text-right">50940236545</span>
- </div>
- <div class="flex justify-between items-center text-[15px]">
- <span class="text-[#534A4A] font-bold">@Lang.fee</span>
- <span class="text-black font-black text-right">0 HTG</span>
- </div>
- </div>
- <div class="w-full border-t border-dashed border-gray-200 pt-4 flex justify-between items-center mb-8">
- <span class="text-[#534A4A] font-bold text-[15px]">@Lang.time</span>
- <span id="successTime" class="text-[#534A4A] font-medium text-[14px] text-right">08/01/2022 - 10:00:20</span>
- </div>
- <button onclick="window.location.href='/Millions/Home/GameHome'" class="btn-premium btn-premium-red w-full text-white font-[800] text-[20px] py-[14px] rounded-[18px] active:scale-95 transition-all">
- @Lang.back_to_homepage
- </button>
- </div>
- </div>
- </div>
- <!-- Failure Modal Overlay -->
- <div id="failureModal" class="fixed inset-0 z-[110] flex items-center justify-center hidden px-6" style="background: rgba(0,0,0,0.5);">
- <div class="w-full max-w-[343px] min-h-[420px] bg-white rounded-[20px] overflow-hidden flex flex-col items-center p-8 animate__animated animate__zoomIn animate__faster shadow-2xl">
- <div class="w-full flex flex-col items-center mb-6 mt-4">
- <div class="relative w-full flex items-center justify-center">
- <img src="/Millions/img/modal/fail_icon.png" class="w-[160px] h-auto object-contain" />
- </div>
- </div>
- <div class="px-2 text-center mb-12 mt-2">
- <p id="failErrorMessage" class="text-black font-[700] text-[20px] leading-tight">
- @Lang.millions_enter_valid_amount
- </p>
- </div>
- <div class="w-full mt-auto">
- <button onclick="closeFailureModal()" class="btn-premium btn-premium-red w-full text-white font-[800] text-[20px] py-[10px] rounded-[14px] active:scale-95 transition-all">
- @Lang.try_again
- </button>
- </div>
- </div>
- </div>
- <!-- OTP Modal Overlay -->
- <div id="otpModal" class="fixed inset-0 z-[120] flex items-center justify-center hidden px-6" style="background: rgba(0,0,0,0.7);">
- <!-- Glitter/Sparkles Overlay -->
- <img src="/Millions/img/modal/otp_glitter.png" class="absolute pointer-events-none opacity-60 w-full max-w-[500px]" />
- <div class="w-full max-w-[360px] bg-white rounded-[32px] overflow-visible flex flex-col items-center animate__animated animate__zoomIn animate__faster relative border-4 border-[#FFCD1D]/10" style="box-shadow: 0 0 25px rgba(229, 107, 35, 0.6);">
-
- <!-- Gold Coins on Top -->
- <img src="/Millions/img/modal/otp_coins.png" class="absolute -top-12 -right-2 w-32 z-30 pointer-events-none drop-shadow-lg" />
- <!-- Red Header -->
- <div class="w-full bg-[#0062FF] pt-5 pb-4 px-6 rounded-t-[32px] flex justify-center border-b-4 border-white/20">
- <h3 class="text-white font-[900] text-[22px] tracking-tight text-center">@Lang.millions_confirm_transaction</h3>
- </div>
- <div class="relative z-10 w-full flex flex-col items-center p-6 py-6 pb-8">
-
- <!-- Shield Icon -->
- <div class="flex flex-col items-center gap-1 mb-2">
- <img src="/Millions/img/modal/otp_shield.png" class="w-[90px] h-auto object-contain drop-shadow-md" />
- <span class="text-[#534A4A] font-bold text-[14px]">@Lang.millions_convert</span>
- </div>
- <!-- Conversion Display Area -->
- <div class="flex items-center justify-center gap-2 mb-4">
- <span id="displayAmountCoins" class="text-[#0062FF] font-[900] text-[24px]">100</span>
- <span class="text-black font-[900] text-[24px]">@Lang.millions_coins</span>
- <i class="fa-solid fa-arrow-right text-gray-800 text-[20px] mx-1"></i>
- <span id="displayAmountHTG" class="text-[#0062FF] font-[900] text-[24px]">100</span>
- <span class="text-black font-[900] text-[24px]">@Lang.millions_htg</span>
- </div>
- <p class="text-[#534A4A] font-bold text-[14px] text-center px-4 mb-6 leading-tight">@Lang.millions_enter_otp_proceed</p>
-
- <!-- OTP Inputs Area -->
- <div class="flex gap-2 mb-4" id="otpInputs">
- <input type="tel" maxlength="1" pattern="[0-9]" inputmode="numeric" oninput="handleOtpInput(this)" onkeydown="handleOtpKeydown(event, this)" placeholder="-"
- class="otp-digit w-[42px] h-[48px] bg-[#757575] text-white rounded-[10px] text-center text-[26px] font-[900] outline-none transition-all placeholder:text-white/60 shadow-inner" />
- <input type="tel" maxlength="1" pattern="[0-9]" inputmode="numeric" oninput="handleOtpInput(this)" onkeydown="handleOtpKeydown(event, this)" placeholder="-"
- class="otp-digit w-[42px] h-[48px] bg-[#757575] text-white rounded-[10px] text-center text-[26px] font-[900] outline-none transition-all placeholder:text-white/60 shadow-inner" />
- <input type="tel" maxlength="1" pattern="[0-9]" inputmode="numeric" oninput="handleOtpInput(this)" onkeydown="handleOtpKeydown(event, this)" placeholder="-"
- class="otp-digit w-[42px] h-[48px] bg-[#757575] text-white rounded-[10px] text-center text-[26px] font-[900] outline-none transition-all placeholder:text-white/60 shadow-inner" />
- <input type="tel" maxlength="1" pattern="[0-9]" inputmode="numeric" oninput="handleOtpInput(this)" onkeydown="handleOtpKeydown(event, this)" placeholder="-"
- class="otp-digit w-[42px] h-[48px] bg-[#757575] text-white rounded-[10px] text-center text-[26px] font-[900] outline-none transition-all placeholder:text-white/60 shadow-inner" />
- <input type="tel" maxlength="1" pattern="[0-9]" inputmode="numeric" oninput="handleOtpInput(this)" onkeydown="handleOtpKeydown(event, this)" placeholder="-"
- class="otp-digit w-[42px] h-[48px] bg-[#757575] text-white rounded-[10px] text-center text-[26px] font-[900] outline-none transition-all placeholder:text-white/60 shadow-inner" />
- <input type="tel" maxlength="1" pattern="[0-9]" inputmode="numeric" oninput="handleOtpInput(this)" onkeydown="handleOtpKeydown(event, this)" placeholder="-"
- class="otp-digit w-[42px] h-[48px] bg-[#757575] text-white rounded-[10px] text-center text-[26px] font-[900] outline-none transition-all placeholder:text-white/60 shadow-inner" />
- </div>
-
- <!-- OTP Error Message -->
- <p id="otpError" class="text-[#0062FF] font-bold text-[14px] text-center mb-4 hidden animate__animated animate__shakeX"></p>
- <!-- Timer & Resend Display -->
- <div class="flex flex-col items-center justify-center mb-6 gap-2">
- <span id="otpTimer" class="text-[#0062FF] font-[900] text-[18px]">60s</span>
- <button id="resendOtpBtn" onclick="sendOtpRequest()" class="hidden text-[15px] font-black text-[#0A9800] underline decoration-solid underline-offset-[4px] hover:text-[#087a00] transition-all font-bricolage">@Lang.millions_request_new_otp</button>
- </div>
-
- <!-- Action Buttons -->
- <div class="w-full flex gap-4">
- <button onclick="closeOtpModal()" class="btn-premium flex-1 bg-[#757575] text-white font-[900] py-2.5 rounded-[16px] active:scale-95 transition-all text-[13px]">@Lang.cancel</button>
- <button id="btnConfirmTransfer" disabled class="btn-premium flex-1 bg-[#0A9800] text-white font-[900] py-2.5 rounded-[16px] active:scale-95 transition-all text-[13px] disabled:opacity-50 disabled:grayscale disabled:cursor-not-allowed">@Lang.confirm</button>
- </div>
- </div>
- </div>
- </div>
- <!-- Bottom Navbar shared component -->
- <partial name="_BottomNavbar" />
- </div>
- @section Scripts {
- <script>
- function setAmount(val, el) {
- $("#transferAmount").val(val);
-
- // Update active state visuals
- $(".amt-btn").removeClass("border-2 border-white bg-[#0062FF] text-white shadow-md").addClass("border-gray-300 bg-white text-[#534A4A] shadow-sm");
- $(".amt-btn i").addClass("hidden").removeClass("text-white").addClass("text-[#00AF1B]"); // reset icons
-
- $(el).removeClass("border-gray-300 bg-white text-[#534A4A] shadow-sm").addClass("border-2 border-white bg-[#0062FF] text-white shadow-md");
- $(el).find("i").removeClass("hidden").removeClass("text-[#00AF1B]").addClass("text-white"); // show current check icon in white
- }
- // Logic removed as fields are read-only
- let timerInterval;
- let isProcessing = false;
- let selectedChannel = 1; // 1 = Basic, 2 = Natcash
- function selectChannel(id) {
- selectedChannel = id;
-
- // Reset both
- $(".channel-card").removeClass("border-2 border-[#0062FF] shadow-md").addClass("border border-gray-100 shadow-sm");
- $(".channel-card .check-icon").addClass("hidden");
-
- // Activate selected
- if (id === 1) {
- $("#selectBasic").removeClass("border-gray-100 shadow-sm").addClass("border-2 border-[#0062FF] shadow-md");
- $("#selectBasic .check-icon").removeClass("hidden");
- } else {
- $("#selectNatcash").removeClass("border-gray-100 shadow-sm").addClass("border-2 border-[#0062FF] shadow-md");
- $("#selectNatcash .check-icon").removeClass("hidden");
- }
- }
- $("#btnContinue").on("click", function() {
- if (isProcessing) return; // Prevent double-click
- const rawAmount = $("#transferAmount").val();
- const amount = parseFloat(unformatMoneyV2(rawAmount)) || 0;
- const phone = $("#receiverPhone").val();
- const winMoney = parseFloat(unformatMoneyV2("@(Model?.userStatus?.bet_coin ?? "0")")) || 0;
-
- if(amount <= 0) {
- showFailureModal("@Html.Raw(Lang.millions_enter_valid_amount)");
- return;
- }
- if(amount > winMoney) {
- showFailureModal("@Html.Raw(Lang.millions_insufficient_balance)");
- return;
- }
- // Lock button + show loading
- isProcessing = true;
- const $btn = $(this);
- const originalText = $btn.html();
- $btn.prop('disabled', true).html('<i class="fa-solid fa-spinner fa-spin mr-2"></i> ...');
- // Call sendotp API
- $.ajax({
- url: subDomain + "/Millions/Home/SendOTP",
- type: "POST",
- data: { phone: phone, amount: unformatMoneyV2(rawAmount), channelPayment: selectedChannel },
- success: function(res) {
- $btn.prop('disabled', false).html(originalText);
- isProcessing = false;
- if(res.responseCode == "0" || res.responseCode == 0) {
- openOtpModal();
- } else {
- showFailureModal(res.message || "Failed to send OTP", res.responseCode);
- }
- },
- error: function() {
- $btn.prop('disabled', false).html(originalText);
- isProcessing = false;
- showFailureModal("Network error while sending OTP");
- }
- });
- });
- function openOtpModal() {
- // Clear previous OTP values
- $(".otp-digit").val("");
- $("#btnConfirmTransfer").prop('disabled', true);
-
- // Set display amounts
- const amt = $("#transferAmount").val();
- const formattedAmt = formatMoneyV2(amt);
- $("#displayAmountCoins").text(formattedAmt);
- $("#displayAmountHTG").text(formattedAmt);
- $("#otpModal").removeClass("hidden").addClass("flex");
- resetTimer();
- $(".otp-digit").first().focus();
- }
- function closeOtpModal() {
- $("#otpModal").addClass("hidden").removeClass("flex");
- clearInterval(timerInterval);
- }
- // OTP input: enforce single digit, auto-advance
- function handleOtpInput(el) {
- // Allow only single digit
- el.value = el.value.replace(/[^0-9]/g, '').slice(0, 1);
-
- if (el.value.length === 1) {
- const next = $(el).next('.otp-digit');
- if (next.length) {
- next.focus();
- }
- }
- // Check if all 6 digits filled
- var filled = 0;
- $(".otp-digit").each(function() { if ($(this).val().length >= 1) filled++; });
- $("#btnConfirmTransfer").prop('disabled', filled < 6);
- // Clear error when typing and reset color to red
- $("#otpError").addClass("hidden").text("").removeClass("text-[#0A9800]").addClass("text-[#0062FF] animate__shakeX");
- }
- // OTP backspace: move to previous input
- function handleOtpKeydown(e, el) {
- if (e.key === 'Backspace') {
- if (el.value.length === 0) {
- const prev = $(el).prev('.otp-digit');
- if (prev.length) {
- prev.focus();
- }
- }
- }
- }
- function resetTimer() {
- let seconds = 60;
- clearInterval(timerInterval);
- $("#otpTimer").removeClass("hidden").text("60s");
- $("#resendOtpBtn").addClass("hidden");
- // Keep confirm disabled until OTP is filled — don't re-enable here
-
- timerInterval = setInterval(() => {
- seconds--;
- $("#otpTimer").text(seconds + "s");
- if (seconds <= 0) {
- clearInterval(timerInterval);
- $("#otpTimer").addClass("hidden");
- $("#resendOtpBtn").removeClass("hidden");
- // Disable confirm when timer expired
- $("#btnConfirmTransfer").prop('disabled', true).addClass('opacity-50');
- }
- }, 1000);
- }
- function sendOtpRequest() {
- const $btn = $("#resendOtpBtn");
- const originalText = $btn.text();
- $btn.prop('disabled', true).text("...");
- $.ajax({
- url: subDomain + "/Millions/Home/SendOTP",
- type: 'POST',
- success: function(data) {
- $btn.prop('disabled', false).text(originalText);
- if (data.responseCode === "0" || data.responseCode === 0) {
- resetTimer();
- $("#otpError").removeClass("text-[#0062FF] animate__shakeX").addClass("text-[#0A9800]").text("@Lang.millions_otp_sent_successfully").removeClass("hidden");
- $(".otp-digit").val("").first().focus();
- } else {
- if (data.responseCode === "-2" || (data.responseMessage && data.responseMessage.includes("System is upgrading"))) {
- closeOtpModal();
- showFailureModal(data.responseMessage || "System is upgrading", data.responseCode);
- } else {
- $("#otpError").removeClass("text-[#0A9800]").addClass("text-[#0062FF] animate__shakeX").text(data.responseMessage || "Failed to resend OTP").removeClass("hidden");
- }
- }
- },
- error: function() {
- $btn.prop('disabled', false).text(originalText);
- $("#otpError").text("Network error occurred.").removeClass("hidden");
- }
- });
- }
- $("#btnConfirmTransfer").on("click", function() {
- if (isProcessing) return; // Prevent double-click
- let otp = "";
- $(".otp-digit").each(function() { otp += $(this).val(); });
-
- if(otp.length < 6) {
- showFailureModal("Please enter 6-digit OTP");
- return;
- }
- // Lock button + show loading
- isProcessing = true;
- const $btn = $(this);
- const originalText = $btn.html();
- $btn.prop('disabled', true).html('<i class="fa-solid fa-spinner fa-spin mr-2"></i> ...');
-
- // Call the unified backend action that verifies OTP and then transfers
- $.ajax({
- url: subDomain + "/Millions/Home/ConfirmTransfer",
- type: "POST",
- data: {
- otp: otp,
- phone: $("#receiverPhone").val(),
- amount: unformatMoneyV2($("#transferAmount").val()),
- channelPayment: selectedChannel
- },
- success: function(res) {
- $btn.prop('disabled', false).html(originalText);
- isProcessing = false;
- if(res.responseCode == "0" || res.responseCode == 0) {
- closeOtpModal();
-
- // Update balance in UI immediately
- if(res.userStatus && res.userStatus.bet_coin) {
- $("#currentBetCoin").text(formatMoneyV2(res.userStatus.bet_coin));
- }
- // Populate Success Modal Fields
- const transferAmt = $("#transferAmount").val();
- $("#successAmount").text(formatMoneyV2(transferAmt) + " HTG");
- $("#successSender").text("@(Model?.userStatus?.msisdn ?? "0")");
- $("#successReceiver").text($("#receiverPhone").val());
-
- const now = new Date();
- const pad = (n) => n.toString().padStart(2, '0');
- const formattedTime = `${pad(now.getDate())}/${pad(now.getMonth() + 1)}/${now.getFullYear()} - ${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}`;
- $("#successTime").text(formattedTime);
- $("#successModal").removeClass("hidden").addClass("flex");
- } else {
- if (res.responseCode === "-2" || (res.message && res.message.includes("System is upgrading"))) {
- closeOtpModal();
- showFailureModal(res.message || "System is upgrading", res.responseCode);
- } else {
- $("#otpError").text(res.message || "Invalid OTP").removeClass("hidden");
- $(".otp-digit").val("");
- $(".otp-digit").first().focus();
- }
- }
- },
- error: function() {
- $btn.prop('disabled', false).html(originalText);
- isProcessing = false;
- showFailureModal("Network error while confirming transfer");
- }
- });
- });
- var systemUpgrading = false;
- function showFailureModal(message, code) {
- $("#failErrorMessage").html(message);
- const $btn = $("#failureModal button");
- if (code === "-2" || (message && message.includes("System is upgrading"))) {
- systemUpgrading = true;
- $btn.text("@Lang.login");
- } else {
- systemUpgrading = false;
- $btn.text("@Lang.try_again");
- }
- $("#failureModal").removeClass("hidden").addClass("flex");
- }
- function closeFailureModal() {
- $("#failureModal").addClass("hidden").removeClass("flex");
- if (systemUpgrading) {
- window.location.href = subDomain + "/Account/Login";
- }
- }
- </script>
- }
|