TransferWinMoney.cshtml 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590
  1. @model LotteryWebApp.Models.HomeIndex_ViewModel
  2. @{
  3. ViewData["Title"] = Lang.v2_transfer;
  4. Layout = "~/Areas/LotteryV2/Views/Shared/_Layout.cshtml";
  5. }
  6. @using LotteryWebApp.Languages;
  7. @functions {
  8. public string FormatMoney(string amount) {
  9. if (string.IsNullOrEmpty(amount)) return "0";
  10. var clean = new string(amount.Where(c => char.IsDigit(c)).ToArray());
  11. if (long.TryParse(clean, out long val)) {
  12. return val.ToString("#,##0", new System.Globalization.CultureInfo("vi-VN")).Replace(",", ".");
  13. }
  14. return amount;
  15. }
  16. }
  17. <style>
  18. @@keyframes float {
  19. 0%, 100% { transform: translateY(0); }
  20. 50% { transform: translateY(-8px); }
  21. }
  22. .animate-float {
  23. animation: float 4s ease-in-out infinite;
  24. }
  25. .btn-premium {
  26. border: 2px solid #ffffff !important;
  27. box-shadow: 0 8px 20px rgba(0, 0, 0, 0.15), inset 0 0 0 1px rgba(255, 255, 255, 0.1);
  28. transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  29. }
  30. .btn-premium:active {
  31. transform: scale(0.95);
  32. box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
  33. }
  34. .btn-premium-red {
  35. background: linear-gradient(135deg, #EE0033 0%, #cc002c 100%);
  36. }
  37. </style>
  38. <div class="main-container animate__animated animate__fadeIn bg-[#EAEAEA] min-h-screen font-bricolage overflow-x-hidden">
  39. <!-- Standardized Header (Matches Profile/Rules) -->
  40. <div class="sticky top-0 w-full bg-[#EE0033] h-[52px] flex items-center justify-between px-4 z-[100] shadow-sm">
  41. <!-- Back Button -->
  42. <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">
  43. <i class="fa-solid fa-arrow-left text-[20px]"></i>
  44. </button>
  45. <!-- Title centered -->
  46. <div class="absolute inset-0 flex items-center justify-center pointer-events-none">
  47. <span class="font-bold text-[24px] text-white tracking-wide uppercase">@Lang.v2_transfer</span>
  48. </div>
  49. </div>
  50. <div class="pt-[20px] px-4 pb-24 max-w-[414px] mx-auto">
  51. <!-- Account Card Section (Matching Figma: Frame 69) -->
  52. <div class="relative w-full bg-[#EE0033] 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;">
  53. <!-- Decorative Elements (positions from Figma: card 383×92) -->
  54. <div class="absolute inset-0 pointer-events-none overflow-hidden rounded-[12px]">
  55. <!-- Golden Ribbon: Figma x:232.58 y:19.11 w:202.23 h:113.29 → right:0, top:20.8%, w:52.8% -->
  56. <img src="/LotteryV2/img/transfer_card_bg_v2.png" alt="" class="absolute z-0" style="right: -10%; top: 20%; width: 53%; height: auto;" />
  57. <!-- Coin 2 (top-right): Figma x:336 y:11 w:27 h:26 → right:5.2%, top:12% -->
  58. <img src="/LotteryV2/img/transfer/coin_2.png" alt="" class="absolute z-10 animate-float" style="right: 5%; top: 12%; width: 7%;" />
  59. <!-- Coin 1 (mid-right): Figma x:309 y:51 w:28 h:25 → right:12%, top:55% -->
  60. <img src="/LotteryV2/img/transfer/coin_1.png" alt="" class="absolute z-10 animate-float" style="right: 12%; top: 55%; width: 7.4%; animation-delay: 0.5s;" />
  61. <!-- Coin 3 (small, left of ribbon): Figma x:272 y:27 w:18 h:12 → right:24.3%, top:29% -->
  62. <img src="/LotteryV2/img/transfer/coin_3.png" alt="" class="absolute z-10 animate-pulse" style="right: 24%; top: 29%; width: 4.7%;" />
  63. <!-- Lights: Figma w:800 h:43, full-bleed glow overlays -->
  64. <img src="/LotteryV2/img/transfer/light_1.png" alt="" class="absolute z-[1]" style="top: -23%; left: -55%; width: 210%; opacity: 0.7;" />
  65. <img src="/LotteryV2/img/transfer/light_2.png" alt="" class="absolute z-[1]" style="bottom: -23%; left: -55%; width: 210%; opacity: 0.7;" />
  66. </div>
  67. <!-- Account Label -->
  68. <p class="relative z-10 text-white font-bold text-[16px] tracking-normal" style="font-family: 'Bricolage Grotesque', sans-serif;">@Lang.v2_account_name</p>
  69. <!-- Balance Row -->
  70. <div class="relative z-10 flex items-end gap-2">
  71. <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>
  72. <span class="text-white font-[800] text-[20px] uppercase pb-[6px]" style="font-family: 'Bricolage Grotesque', sans-serif;">htg</span>
  73. </div>
  74. </div>
  75. <!-- Selection Area (Horizontal Cards) -->
  76. <div class="mb-6">
  77. <h2 class="text-[#534A4A] font-[900] text-[18px] mb-3 pl-1">@Lang.v2_choose_account</h2>
  78. <div class="flex gap-3">
  79. <!-- Basic Account Option -->
  80. <div id="selectBasic" onclick="selectChannel(1)" class="channel-card flex-1 bg-white h-[76px] rounded-[18px] border-2 border-[#EE0033] shadow-md flex items-center px-3 gap-2 cursor-pointer relative">
  81. <!-- Selected Icon -->
  82. <div class="check-icon absolute -top-2 -right-1 bg-white rounded-full">
  83. <i class="fa-solid fa-circle-check text-[#00AF1B] text-[20px]"></i>
  84. </div>
  85. <span class="text-[#EE0033] font-[900] text-[15px] leading-tight flex-1">@Lang.Basic<br />@Lang.Account</span>
  86. <img src="/LotteryV2/img/transfer_basic_icon.png" alt="Basic" class="w-12 h-10 object-contain" />
  87. </div>
  88. <!-- Natcash Card -->
  89. <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">
  90. <!-- Selected Icon (Hidden by default) -->
  91. <div class="check-icon absolute -top-2 -right-1 bg-white rounded-full hidden">
  92. <i class="fa-solid fa-circle-check text-[#00AF1B] text-[20px]"></i>
  93. </div>
  94. <div class="flex-1 overflow-hidden h-full flex items-center">
  95. <img src="/LotteryV2/img/transfer_other_card.png" alt="Natcash" class="w-full h-full object-contain" />
  96. </div>
  97. </div>
  98. </div>
  99. </div>
  100. <!-- Form Fields Area -->
  101. <div class="flex flex-col gap-2">
  102. <!-- Sender Phone -->
  103. <div class="flex flex-col gap-2">
  104. <label class="text-[#534A4A] font-[900] text-[16px] px-1 capitalize">@Lang.v2_sender_phone</label>
  105. <div class="relative w-full group">
  106. <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" />
  107. <div class="absolute right-4 top-1/2 -translate-y-1/2 text-gray-400">
  108. <i class="fa-solid fa-lock text-[20px] opacity-40"></i>
  109. </div>
  110. </div>
  111. </div>
  112. <!-- Receiver Phone (Mandatory same as sender) -->
  113. <div class="flex flex-col gap-2">
  114. <label class="text-[#534A4A] font-[900] text-[16px] px-1 capitalize">@Lang.v2_receiver_phone</label>
  115. <div class="relative w-full">
  116. <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" />
  117. <div class="absolute right-4 top-1/2 -translate-y-1/2 text-gray-400">
  118. <i class="fa-solid fa-lock text-[20px] opacity-40"></i>
  119. </div>
  120. </div>
  121. </div>
  122. <!-- Amount -->
  123. <div class="flex flex-col gap-2">
  124. <label class="text-[#534A4A] font-[900] text-[16px] px-1 capitalize">@Lang.v2_amount_htg</label>
  125. <div class="relative w-full">
  126. <input id="transferAmount" type="number" value="5000" placeholder="5,000" class="w-full bg-white border border-gray-300 focus:border-[#EE0033] focus:ring-2 focus:ring-[#EE0033]/10 text-[#EE0033] text-[17px] font-[800] rounded-[18px] py-[15px] px-5 outline-none transition-all placeholder:text-gray-300" />
  127. <span class="absolute right-5 top-1/2 -translate-y-1/2 text-gray-400 font-black">HTG</span>
  128. </div>
  129. <!-- Shortcut Buttons -->
  130. <div class="flex gap-2 mt-1">
  131. <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">
  132. 10
  133. <i class="fa-solid fa-circle-check text-[#00AF1B] text-[14px] hidden"></i>
  134. </button>
  135. <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">
  136. 1.000
  137. <i class="fa-solid fa-circle-check text-[#00AF1B] text-[14px] hidden"></i>
  138. </button>
  139. <button id="defaultAmt" onclick="setAmount(5000, this)" class="amt-btn flex-1 py-1.5 border-2 border-white bg-[#EE0033] rounded-lg text-[14px] font-black text-white transition-all flex items-center justify-center gap-1 shadow-md">
  140. 5.000
  141. <i class="fa-solid fa-circle-check text-white text-[14px]"></i>
  142. </button>
  143. </div>
  144. <!-- Fee Section (Newly placed on a new line) -->
  145. <div class="mt-6 flex flex-col gap-1 px-1">
  146. <span class="text-gray-500 font-bold text-[14px]">@Lang.v2_fee</span>
  147. <span class="text-black font-black text-[28px] leading-none mt-1">@Lang.v2_free</span>
  148. </div>
  149. </div>
  150. </div>
  151. <!-- Main Action Button -->
  152. <div class="mt-6">
  153. <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">
  154. @Lang.v2_continue
  155. </button>
  156. </div>
  157. </div>
  158. <!-- Success Modal Overlay -->
  159. <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);">
  160. <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">
  161. <!-- Content Container -->
  162. <div class="relative z-10 w-full flex flex-col items-center pt-10 pb-8 px-6">
  163. <!-- Success Icon Group -->
  164. <div class="relative w-full flex justify-center mb-0 mt-2 z-10 px-4">
  165. <img src="/LotteryV2/img/modal/otp_success.png" alt="Success" class="w-full max-w-[200px] h-auto object-contain">
  166. </div>
  167. <h2 class="text-[#0A9800] font-[800] text-[32px] mb-1 tracking-tight">@Lang.success</h2>
  168. <p class="text-[#000000] font-[700] text-[20px] text-center px-4 mb-6 leading-tight">
  169. @Lang.v2_payment_successfully
  170. </p>
  171. <div class="w-full border-t border-dashed border-gray-200 pt-5 flex flex-col gap-3 mb-5">
  172. <!-- Info Rows -->
  173. <div class="flex justify-between items-center text-[15px]">
  174. <span class="text-[#534A4A] font-bold">@Lang.amount_transfered</span>
  175. <span id="successAmount" class="text-black font-black text-right">5.000 HTG</span>
  176. </div>
  177. <div class="flex justify-between items-center text-[15px]">
  178. <span class="text-[#534A4A] font-bold">@Lang.sender</span>
  179. <span id="successSender" class="text-black font-black text-right">50940236545</span>
  180. </div>
  181. <div class="flex justify-between items-center text-[15px]">
  182. <span class="text-[#534A4A] font-bold">@Lang.receiver</span>
  183. <span id="successReceiver" class="text-black font-black text-right">50940236545</span>
  184. </div>
  185. <div class="flex justify-between items-center text-[15px]">
  186. <span class="text-[#534A4A] font-bold">@Lang.fee</span>
  187. <span class="text-black font-black text-right">0 HTG</span>
  188. </div>
  189. </div>
  190. <div class="w-full border-t border-dashed border-gray-200 pt-4 flex justify-between items-center mb-8">
  191. <span class="text-[#534A4A] font-bold text-[15px]">@Lang.time</span>
  192. <span id="successTime" class="text-[#534A4A] font-medium text-[14px] text-right">08/01/2022 - 10:00:20</span>
  193. </div>
  194. <button onclick="window.location.href='/LotteryV2/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">
  195. @Lang.back_to_homepage
  196. </button>
  197. </div>
  198. </div>
  199. </div>
  200. <!-- Failure Modal Overlay -->
  201. <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);">
  202. <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">
  203. <div class="w-full flex flex-col items-center mb-6 mt-4">
  204. <div class="relative w-full flex items-center justify-center">
  205. <img src="/LotteryV2/img/modal/fail_icon.png" class="w-[160px] h-auto object-contain" />
  206. </div>
  207. </div>
  208. <div class="px-2 text-center mb-12 mt-2">
  209. <p id="failErrorMessage" class="text-black font-[700] text-[20px] leading-tight">
  210. @Lang.v2_enter_valid_amount
  211. </p>
  212. </div>
  213. <div class="w-full mt-auto">
  214. <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">
  215. @Lang.try_again
  216. </button>
  217. </div>
  218. </div>
  219. </div>
  220. <!-- OTP Modal Overlay -->
  221. <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);">
  222. <!-- Glitter/Sparkles Overlay -->
  223. <img src="/LotteryV2/img/modal/otp_glitter.png" class="absolute pointer-events-none opacity-60 w-full max-w-[500px]" />
  224. <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);">
  225. <!-- Gold Coins on Top -->
  226. <img src="/LotteryV2/img/modal/otp_coins.png" class="absolute -top-12 -right-2 w-32 z-30 pointer-events-none drop-shadow-lg" />
  227. <!-- Red Header -->
  228. <div class="w-full bg-[#EE0033] pt-5 pb-4 px-6 rounded-t-[32px] flex justify-center border-b-4 border-white/20">
  229. <h3 class="text-white font-[900] text-[22px] tracking-tight text-center">@Lang.v2_confirm_transaction</h3>
  230. </div>
  231. <div class="relative z-10 w-full flex flex-col items-center p-6 py-6 pb-8">
  232. <!-- Shield Icon -->
  233. <div class="flex flex-col items-center gap-1 mb-2">
  234. <img src="/LotteryV2/img/modal/otp_shield.png" class="w-[90px] h-auto object-contain drop-shadow-md" />
  235. <span class="text-[#534A4A] font-bold text-[14px]">@Lang.v2_convert</span>
  236. </div>
  237. <!-- Conversion Display Area -->
  238. <div class="flex items-center justify-center gap-2 mb-4">
  239. <span id="displayAmountCoins" class="text-[#EE0033] font-[900] text-[24px]">100</span>
  240. <span class="text-black font-[900] text-[24px]">@Lang.v2_coins</span>
  241. <i class="fa-solid fa-arrow-right text-gray-800 text-[20px] mx-1"></i>
  242. <span id="displayAmountHTG" class="text-[#EE0033] font-[900] text-[24px]">100</span>
  243. <span class="text-black font-[900] text-[24px]">@Lang.v2_htg</span>
  244. </div>
  245. <p class="text-[#534A4A] font-bold text-[14px] text-center px-4 mb-6 leading-tight">@Lang.v2_enter_otp_proceed</p>
  246. <!-- OTP Inputs Area -->
  247. <div class="flex gap-2 mb-4" id="otpInputs">
  248. <input type="tel" maxlength="1" pattern="[0-9]" inputmode="numeric" oninput="handleOtpInput(this)" onkeydown="handleOtpKeydown(event, this)" placeholder="-"
  249. 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" />
  250. <input type="tel" maxlength="1" pattern="[0-9]" inputmode="numeric" oninput="handleOtpInput(this)" onkeydown="handleOtpKeydown(event, this)" placeholder="-"
  251. 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" />
  252. <input type="tel" maxlength="1" pattern="[0-9]" inputmode="numeric" oninput="handleOtpInput(this)" onkeydown="handleOtpKeydown(event, this)" placeholder="-"
  253. 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" />
  254. <input type="tel" maxlength="1" pattern="[0-9]" inputmode="numeric" oninput="handleOtpInput(this)" onkeydown="handleOtpKeydown(event, this)" placeholder="-"
  255. 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" />
  256. <input type="tel" maxlength="1" pattern="[0-9]" inputmode="numeric" oninput="handleOtpInput(this)" onkeydown="handleOtpKeydown(event, this)" placeholder="-"
  257. 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" />
  258. <input type="tel" maxlength="1" pattern="[0-9]" inputmode="numeric" oninput="handleOtpInput(this)" onkeydown="handleOtpKeydown(event, this)" placeholder="-"
  259. 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" />
  260. </div>
  261. <!-- OTP Error Message -->
  262. <p id="otpError" class="text-[#EE0033] font-bold text-[14px] text-center mb-4 hidden animate__animated animate__shakeX"></p>
  263. <!-- Timer & Resend Display -->
  264. <div class="flex flex-col items-center justify-center mb-6 gap-2">
  265. <span id="otpTimer" class="text-[#EE0033] font-[900] text-[18px]">60s</span>
  266. <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.v2_request_new_otp</button>
  267. </div>
  268. <!-- Action Buttons -->
  269. <div class="w-full flex gap-4">
  270. <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>
  271. <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>
  272. </div>
  273. </div>
  274. </div>
  275. </div>
  276. <!-- Bottom Navbar shared component -->
  277. <partial name="_BottomNavbar" />
  278. </div>
  279. @section Scripts {
  280. <script>
  281. function setAmount(val, el) {
  282. $("#transferAmount").val(val);
  283. // Update active state visuals
  284. $(".amt-btn").removeClass("border-2 border-white bg-[#EE0033] text-white shadow-md").addClass("border-gray-300 bg-white text-[#534A4A] shadow-sm");
  285. $(".amt-btn i").addClass("hidden").removeClass("text-white").addClass("text-[#00AF1B]"); // reset icons
  286. $(el).removeClass("border-gray-300 bg-white text-[#534A4A] shadow-sm").addClass("border-2 border-white bg-[#EE0033] text-white shadow-md");
  287. $(el).find("i").removeClass("hidden").removeClass("text-[#00AF1B]").addClass("text-white"); // show current check icon in white
  288. }
  289. // Logic removed as fields are read-only
  290. let timerInterval;
  291. let isProcessing = false;
  292. let selectedChannel = 1; // 1 = Basic, 2 = Natcash
  293. function selectChannel(id) {
  294. selectedChannel = id;
  295. // Reset both
  296. $(".channel-card").removeClass("border-2 border-[#EE0033] shadow-md").addClass("border border-gray-100 shadow-sm");
  297. $(".channel-card .check-icon").addClass("hidden");
  298. // Activate selected
  299. if (id === 1) {
  300. $("#selectBasic").removeClass("border-gray-100 shadow-sm").addClass("border-2 border-[#EE0033] shadow-md");
  301. $("#selectBasic .check-icon").removeClass("hidden");
  302. } else {
  303. $("#selectNatcash").removeClass("border-gray-100 shadow-sm").addClass("border-2 border-[#EE0033] shadow-md");
  304. $("#selectNatcash .check-icon").removeClass("hidden");
  305. }
  306. }
  307. $("#btnContinue").on("click", function() {
  308. if (isProcessing) return; // Prevent double-click
  309. const amount = parseFloat($("#transferAmount").val()) || 0;
  310. const phone = $("#receiverPhone").val();
  311. const winMoney = parseFloat("@(Model?.userStatus?.bet_coin ?? "0")");
  312. if(amount <= 0) {
  313. showFailureModal("@Html.Raw(Lang.v2_enter_valid_amount)");
  314. return;
  315. }
  316. if(amount > winMoney) {
  317. showFailureModal("@Html.Raw(Lang.v2_insufficient_balance)");
  318. return;
  319. }
  320. // Lock button + show loading
  321. isProcessing = true;
  322. const $btn = $(this);
  323. const originalText = $btn.html();
  324. $btn.prop('disabled', true).html('<i class="fa-solid fa-spinner fa-spin mr-2"></i> ...');
  325. // Call sendotp API
  326. $.ajax({
  327. url: subDomain + "/LotteryV2/Home/SendOTP",
  328. type: "POST",
  329. data: { phone: phone, amount: amount, channelPayment: selectedChannel },
  330. success: function(res) {
  331. $btn.prop('disabled', false).html(originalText);
  332. isProcessing = false;
  333. if(res.responseCode == "0" || res.responseCode == 0) {
  334. openOtpModal();
  335. } else {
  336. showFailureModal(res.message || "Failed to send OTP", res.responseCode);
  337. }
  338. },
  339. error: function() {
  340. $btn.prop('disabled', false).html(originalText);
  341. isProcessing = false;
  342. showFailureModal("Network error while sending OTP");
  343. }
  344. });
  345. });
  346. function openOtpModal() {
  347. // Clear previous OTP values
  348. $(".otp-digit").val("");
  349. $("#btnConfirmTransfer").prop('disabled', true);
  350. // Set display amounts
  351. const amt = $("#transferAmount").val();
  352. const formattedAmt = formatMoneyV2(amt);
  353. $("#displayAmountCoins").text(formattedAmt);
  354. $("#displayAmountHTG").text(formattedAmt);
  355. $("#otpModal").removeClass("hidden").addClass("flex");
  356. resetTimer();
  357. $(".otp-digit").first().focus();
  358. }
  359. function closeOtpModal() {
  360. $("#otpModal").addClass("hidden").removeClass("flex");
  361. clearInterval(timerInterval);
  362. }
  363. // OTP input: enforce single digit, auto-advance
  364. function handleOtpInput(el) {
  365. // Allow only single digit
  366. el.value = el.value.replace(/[^0-9]/g, '').slice(0, 1);
  367. if (el.value.length === 1) {
  368. const next = $(el).next('.otp-digit');
  369. if (next.length) {
  370. next.focus();
  371. }
  372. }
  373. // Check if all 6 digits filled
  374. var filled = 0;
  375. $(".otp-digit").each(function() { if ($(this).val().length >= 1) filled++; });
  376. $("#btnConfirmTransfer").prop('disabled', filled < 6);
  377. // Clear error when typing and reset color to red
  378. $("#otpError").addClass("hidden").text("").removeClass("text-[#0A9800]").addClass("text-[#EE0033] animate__shakeX");
  379. }
  380. // OTP backspace: move to previous input
  381. function handleOtpKeydown(e, el) {
  382. if (e.key === 'Backspace') {
  383. if (el.value.length === 0) {
  384. const prev = $(el).prev('.otp-digit');
  385. if (prev.length) {
  386. prev.focus();
  387. }
  388. }
  389. }
  390. }
  391. function resetTimer() {
  392. let seconds = 60;
  393. clearInterval(timerInterval);
  394. $("#otpTimer").removeClass("hidden").text("60s");
  395. $("#resendOtpBtn").addClass("hidden");
  396. // Keep confirm disabled until OTP is filled — don't re-enable here
  397. timerInterval = setInterval(() => {
  398. seconds--;
  399. $("#otpTimer").text(seconds + "s");
  400. if (seconds <= 0) {
  401. clearInterval(timerInterval);
  402. $("#otpTimer").addClass("hidden");
  403. $("#resendOtpBtn").removeClass("hidden");
  404. // Disable confirm when timer expired
  405. $("#btnConfirmTransfer").prop('disabled', true).addClass('opacity-50');
  406. }
  407. }, 1000);
  408. }
  409. function sendOtpRequest() {
  410. const $btn = $("#resendOtpBtn");
  411. const originalText = $btn.text();
  412. $btn.prop('disabled', true).text("...");
  413. $.ajax({
  414. url: subDomain + "/LotteryV2/Home/SendOTP",
  415. type: 'POST',
  416. success: function(data) {
  417. $btn.prop('disabled', false).text(originalText);
  418. if (data.responseCode === "0" || data.responseCode === 0) {
  419. resetTimer();
  420. $("#otpError").removeClass("text-[#EE0033] animate__shakeX").addClass("text-[#0A9800]").text("@Lang.v2_otp_sent_successfully").removeClass("hidden");
  421. $(".otp-digit").val("").first().focus();
  422. } else {
  423. if (data.responseCode === "-2" || (data.responseMessage && data.responseMessage.includes("System is upgrading"))) {
  424. closeOtpModal();
  425. showFailureModal(data.responseMessage || "System is upgrading", data.responseCode);
  426. } else {
  427. $("#otpError").removeClass("text-[#0A9800]").addClass("text-[#EE0033] animate__shakeX").text(data.responseMessage || "Failed to resend OTP").removeClass("hidden");
  428. }
  429. }
  430. },
  431. error: function() {
  432. $btn.prop('disabled', false).text(originalText);
  433. $("#otpError").text("Network error occurred.").removeClass("hidden");
  434. }
  435. });
  436. }
  437. $("#btnConfirmTransfer").on("click", function() {
  438. if (isProcessing) return; // Prevent double-click
  439. let otp = "";
  440. $(".otp-digit").each(function() { otp += $(this).val(); });
  441. if(otp.length < 6) {
  442. showFailureModal("Please enter 6-digit OTP");
  443. return;
  444. }
  445. // Lock button + show loading
  446. isProcessing = true;
  447. const $btn = $(this);
  448. const originalText = $btn.html();
  449. $btn.prop('disabled', true).html('<i class="fa-solid fa-spinner fa-spin mr-2"></i> ...');
  450. // Call the unified backend action that verifies OTP and then transfers
  451. $.ajax({
  452. url: subDomain + "/LotteryV2/Home/ConfirmTransfer",
  453. type: "POST",
  454. data: {
  455. otp: otp,
  456. phone: $("#receiverPhone").val(),
  457. amount: $("#transferAmount").val(),
  458. channelPayment: selectedChannel
  459. },
  460. success: function(res) {
  461. $btn.prop('disabled', false).html(originalText);
  462. isProcessing = false;
  463. if(res.responseCode == "0" || res.responseCode == 0) {
  464. closeOtpModal();
  465. // Update balance in UI immediately
  466. if(res.userStatus && res.userStatus.bet_coin) {
  467. $("#currentBetCoin").text(formatMoneyV2(res.userStatus.bet_coin));
  468. }
  469. // Populate Success Modal Fields
  470. const transferAmt = $("#transferAmount").val();
  471. $("#successAmount").text(formatMoneyV2(transferAmt) + " HTG");
  472. $("#successSender").text("@(Model?.userStatus?.msisdn ?? "0")");
  473. $("#successReceiver").text($("#receiverPhone").val());
  474. const now = new Date();
  475. const pad = (n) => n.toString().padStart(2, '0');
  476. const formattedTime = `${pad(now.getDate())}/${pad(now.getMonth() + 1)}/${now.getFullYear()} - ${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}`;
  477. $("#successTime").text(formattedTime);
  478. $("#successModal").removeClass("hidden").addClass("flex");
  479. } else {
  480. if (res.responseCode === "-2" || (res.message && res.message.includes("System is upgrading"))) {
  481. closeOtpModal();
  482. showFailureModal(res.message || "System is upgrading", res.responseCode);
  483. } else {
  484. $("#otpError").text(res.message || "Invalid OTP").removeClass("hidden");
  485. $(".otp-digit").val("");
  486. $(".otp-digit").first().focus();
  487. }
  488. }
  489. },
  490. error: function() {
  491. $btn.prop('disabled', false).html(originalText);
  492. isProcessing = false;
  493. showFailureModal("Network error while confirming transfer");
  494. }
  495. });
  496. });
  497. var systemUpgrading = false;
  498. function showFailureModal(message, code) {
  499. $("#failErrorMessage").html(message);
  500. const $btn = $("#failureModal button");
  501. if (code === "-2" || (message && message.includes("System is upgrading"))) {
  502. systemUpgrading = true;
  503. $btn.text("@Lang.login");
  504. } else {
  505. systemUpgrading = false;
  506. $btn.text("@Lang.try_again");
  507. }
  508. $("#failureModal").removeClass("hidden").addClass("flex");
  509. }
  510. function closeFailureModal() {
  511. $("#failureModal").addClass("hidden").removeClass("flex");
  512. if (systemUpgrading) {
  513. window.location.href = subDomain + "/Account/Login";
  514. }
  515. }
  516. </script>
  517. }