History.cshtml 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. @model LotteryWebApp.Models.UserTicketHistoryModel
  2. @using LotteryWebApp.Languages
  3. @using LotteryWebApp.Common
  4. @{
  5. ViewData["Title"] = "Millions - History";
  6. Layout = "~/Areas/Millions/Views/Shared/_Layout.cshtml";
  7. ViewData["ActiveTab"] = "History";
  8. }
  9. @section Styles {
  10. <script src="https://cdn.tailwindcss.com"></script>
  11. <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
  12. <link rel="stylesheet" href="/Millions/css/site.css" />
  13. <link rel="stylesheet" href="/Millions/css/results.css" />
  14. <link rel="stylesheet" href="/Millions/css/history.css" />
  15. }
  16. <div class="main-container results-container animate__animated animate__fadeIn pb-40 relative">
  17. <!-- Header Group: Static at Top -->
  18. <div class="fixed top-0 left-0 md:left-1/2 md:-translate-x-1/2 w-full md:max-w-[430px] z-[100] bg-[#F3F4F6] pb-2 shadow-md">
  19. <!-- Header -->
  20. <div class="results-top-header">
  21. <a href="/Millions/Home/GameHome" class="back-btn">
  22. <i class="fas fa-arrow-left"></i>
  23. </a>
  24. <h1 class="font-bricolage">@Lang.history</h1>
  25. </div>
  26. <!-- Removed game tabs as per request: only Millions_CODE is used -->
  27. <input type="hidden" id="currentTermType" value="@Constants.Millions_CODE" />
  28. <!-- Status Filters -->
  29. <div class="status-filters !mt-1">
  30. <div class="status-filter @(Model.status == Constants.ALL_DATA ? "active" : "")"
  31. onclick="changeStatus('@Constants.ALL_DATA', this)">@Lang.millions_all</div>
  32. <div class="status-filter @(Model.status == Constants.NOT_DRAW_CODE ? "active" : "")"
  33. onclick="changeStatus('@Constants.NOT_DRAW_CODE', this)">@Lang.millions_waiting</div>
  34. <div class="status-filter @(Model.status == Constants.WIN_CODE ? "active" : "")"
  35. onclick="changeStatus('@Constants.WIN_CODE', this)">@Lang.millions_win</div>
  36. <div class="status-filter @(Model.status == Constants.DRAWN_CODE ? "active" : "")"
  37. onclick="changeStatus('@Constants.DRAWN_CODE', this)">@Lang.millions_not_win</div>
  38. </div>
  39. </div>
  40. <!-- Ticket List Container -->
  41. <div id="history-list-container" class="history-items-list px-4 mt-2">
  42. <partial name="_TermUserTicketHistory" model="Model" />
  43. </div>
  44. <!-- Shared Bottom Navbar -->
  45. <partial name="_BottomNavbar" />
  46. <!-- Custom Notification Modal -->
  47. <div id="notificationModal" class="fixed inset-0 z-[300] flex items-center justify-center hidden px-6 font-bricolage" style="background: linear-gradient(135deg, rgba(26, 26, 46, 0.9) 0%, rgba(22, 33, 62, 0.9) 100%);">
  48. <div class="w-full max-w-[343px] min-h-[420px] bg-white rounded-[24px] overflow-hidden flex flex-col items-center p-8 animate__animated animate__zoomIn animate__faster shadow-2xl border border-white/50">
  49. <div class="w-full flex justify-center mb-8 mt-4">
  50. <img src="/Millions/img/modal/fail_icon.png" class="w-[160px] h-auto object-contain" alt="Notificaton icon" />
  51. </div>
  52. <div class="px-2 text-center mb-10 flex-1 flex items-center justify-center">
  53. <p id="notificationMessage" class="text-black font-[800] text-[20px] leading-snug"></p>
  54. </div>
  55. <div class="w-full">
  56. <button onclick="closeNotificationModal()" class="w-full bg-[#0062FF] text-white font-[800] text-[18px] py-[12px] rounded-[16px] shadow-lg active:scale-95 transition-all">
  57. @Lang.login
  58. </button>
  59. </div>
  60. </div>
  61. </div>
  62. </div>
  63. @section Scripts {
  64. <script>
  65. let currentTermType = '@Model.termType';
  66. let currentStatus = '@Model.status';
  67. let currentSeqPage = parseInt('@Model.seqPage');
  68. let totalPages = parseInt('@Model.totalPage' || '1');
  69. function changeGame(type, el) {
  70. if (currentTermType === type) return;
  71. currentTermType = type;
  72. currentSeqPage = 1;
  73. document.querySelectorAll('.game-tab').forEach(t => t.classList.remove('active'));
  74. el.classList.add('active');
  75. loadHistory();
  76. }
  77. function changeStatus(status, el) {
  78. if (currentStatus === status) return;
  79. currentStatus = status;
  80. currentSeqPage = 1;
  81. document.querySelectorAll('.status-filter').forEach(t => t.classList.remove('active'));
  82. el.classList.add('active');
  83. loadHistory();
  84. }
  85. function changePage(page) {
  86. if (page < 1 || page > totalPages) return;
  87. currentSeqPage = page;
  88. loadHistory();
  89. }
  90. var systemUpgrading = false;
  91. function showNotification(message, code) {
  92. $("#notificationMessage").text(message);
  93. const $btn = $("#notificationModal button");
  94. if (code === "-2" || (message && message.includes("System is upgrading"))) {
  95. systemUpgrading = true;
  96. $btn.text("@Lang.login");
  97. } else {
  98. systemUpgrading = false;
  99. $btn.text("OK");
  100. }
  101. $("#notificationModal").removeClass("hidden").addClass("flex");
  102. }
  103. function closeNotificationModal() {
  104. $("#notificationModal").addClass("hidden").removeClass("flex");
  105. if (systemUpgrading) {
  106. window.location.href = subDomain + "/Account/Login";
  107. }
  108. }
  109. function loadHistory() {
  110. const container = document.getElementById("history-list-container");
  111. container.style.opacity = "0.5";
  112. fetch(subDomain + `/Millions/Home/TermUserTicketHistory?termType=${currentTermType}&status=${currentStatus}&seqPage=${currentSeqPage}`)
  113. .then(response => {
  114. if (!response.ok) throw new Error('Network response was not ok');
  115. return response.text();
  116. })
  117. .then(html => {
  118. try {
  119. const json = JSON.parse(html);
  120. if (json.responseCode === "-2" || (json.responseMessage && json.responseMessage.includes("System is upgrading"))) {
  121. showNotification(json.responseMessage || "System is upgrading", "-2");
  122. return;
  123. }
  124. } catch (e) {
  125. // Not JSON, likely HTML partial
  126. }
  127. container.innerHTML = html;
  128. container.style.opacity = "1";
  129. updatePaginationUI();
  130. })
  131. .catch(error => {
  132. console.error("Error loading history:", error);
  133. container.style.opacity = "1";
  134. if (error.message && (error.message.includes("System is upgrading") || error.message.includes("-2"))) {
  135. showNotification(error.message, "-2");
  136. }
  137. });
  138. }
  139. function updatePaginationUI() {
  140. const pageDisplay = document.getElementById("pageDisplay");
  141. const prevBtn = document.getElementById("prevPage");
  142. const nextBtn = document.getElementById("nextPage");
  143. if (pageDisplay) {
  144. pageDisplay.innerText = `${currentSeqPage} / ${totalPages}`;
  145. }
  146. if (prevBtn) prevBtn.disabled = currentSeqPage <= 1;
  147. if (nextBtn) nextBtn.disabled = currentSeqPage >= totalPages;
  148. }
  149. function showTicketDetail(billCode, money, moneyWin, date, channel, payMethod, ticketCode, gameId, drawTime, ticketId) {
  150. document.getElementById('detailBillCode').innerText = '#' + (billCode || '-');
  151. document.getElementById('detailTicketCode').innerText = '#' + (ticketId || '-');
  152. document.getElementById('detailMoney').innerText = formatMoneyV2(money || '0') + ' HTG';
  153. document.getElementById('detailMoneyWin').innerText = formatMoneyV2(moneyWin || '0') + ' HTG';
  154. document.getElementById('detailDate').innerText = date || '-';
  155. document.getElementById('detailDrawTime').innerText = drawTime || '-';
  156. document.getElementById('detailChannel').innerText = channel || 'App';
  157. // Logic for Game Name and Color
  158. let gameName = "@Lang.millions_classic_pick_10";
  159. let gameColor = "#0062FF"; // Red
  160. if (gameId === "31") {
  161. gameName = "@Lang.millions_big_small";
  162. gameColor = "#00A3FF"; // Blue
  163. } else if (gameId === "32") {
  164. gameName = "@Lang.millions_odd_even";
  165. gameColor = "#9333EA"; // Purple
  166. }
  167. const gameEl = document.getElementById('detailGameName');
  168. gameEl.innerText = gameName;
  169. gameEl.style.color = gameColor;
  170. let payMethodText = "Main Account";
  171. if(payMethod == "1") payMethodText = "Wallet";
  172. else if(payMethod == "0") payMethodText = "Main Account";
  173. document.getElementById('detailPaymentMethod').innerText = payMethodText;
  174. // Render Numbers
  175. const container = document.getElementById('detailBallsContainer');
  176. container.innerHTML = '';
  177. if (ticketCode) {
  178. const balls = ticketCode.split(/[;,]/).filter(x => x.trim() !== '');
  179. balls.forEach(val => {
  180. let ballVal = val.trim();
  181. let displayVal = ballVal;
  182. let isLabel = false;
  183. switch(ballVal.toUpperCase()) {
  184. case 'B': displayVal = 'Big'; isLabel = true; break;
  185. case 'S': displayVal = 'Small'; isLabel = true; break;
  186. case 'O': displayVal = 'Odd'; isLabel = true; break;
  187. case 'E': displayVal = 'Even'; isLabel = true; break;
  188. }
  189. const div = document.createElement('div');
  190. if (isLabel) {
  191. div.className = "bg-[#0062FF] text-white px-4 py-1 rounded-full font-black text-[12px] shadow-sm uppercase tracking-wider";
  192. } else {
  193. div.className = "w-8 h-8 rounded-full flex items-center justify-center text-white text-[12px] font-black shadow-md";
  194. div.style.background = "linear-gradient(135deg, #FF3D63 0%, #E3132D 60%, #BA0F21 100%)";
  195. div.style.border = "1px solid rgba(255, 255, 255, 0.3)";
  196. }
  197. div.innerText = displayVal;
  198. container.appendChild(div);
  199. });
  200. }
  201. const modal = document.getElementById('ticketDetailModal');
  202. modal.classList.remove('hidden');
  203. modal.classList.add('flex');
  204. }
  205. function closeDetailModal() {
  206. const modal = document.getElementById('ticketDetailModal');
  207. modal.classList.add('hidden');
  208. modal.classList.remove('flex');
  209. }
  210. </script>
  211. }
  212. <!-- Ticket Detail Modal -->
  213. <div id="ticketDetailModal" class="fixed inset-0 z-[200] bg-black/60 hidden items-center justify-center p-4 font-bricolage backdrop-blur-sm">
  214. <div class="w-full max-w-[380px] bg-white rounded-[28px] overflow-hidden flex flex-col items-center px-6 py-8 shadow-2xl relative animate__animated animate__zoomIn animate__faster">
  215. <button onclick="closeDetailModal()" class="absolute top-4 right-4 text-gray-400 hover:text-gray-600 transition-colors">
  216. <i class="fas fa-times text-xl"></i>
  217. </button>
  218. <div class="w-20 h-20 bg-gray-50 rounded-full flex items-center justify-center mb-4">
  219. <i class="fas fa-receipt text-3xl text-[#0062FF]"></i>
  220. </div>
  221. <h2 class="text-[20px] font-black text-gray-800 mb-2 uppercase tracking-tight">@Lang.millions_ticket_detail</h2>
  222. <!-- Ticket Numbers Display -->
  223. <div id="detailBallsContainer" class="flex flex-wrap justify-center gap-2 mb-6 mt-2 max-w-full">
  224. <!-- Dynamic balls here -->
  225. </div>
  226. <div class="w-full space-y-4">
  227. <div class="flex justify-between items-center text-sm border-b border-gray-50 pb-2">
  228. <span class="text-gray-400 font-bold uppercase text-[11px]">@Lang.millions_game</span>
  229. <span id="detailGameName" class="font-black">Pick 10</span>
  230. </div>
  231. <div class="flex justify-between items-center text-sm border-b border-gray-50 pb-2">
  232. <span class="text-gray-400 font-bold uppercase text-[11px]">@Lang.millions_bill_code</span>
  233. <span id="detailBillCode" class="font-black text-gray-800">#</span>
  234. </div>
  235. <div class="flex justify-between items-center text-sm border-b border-gray-50 pb-2">
  236. <span class="text-gray-400 font-bold uppercase text-[11px]">@Lang.millions_ticket_code</span>
  237. <span id="detailTicketCode" class="font-black text-gray-800">#</span>
  238. </div>
  239. <div class="flex justify-between items-center text-sm border-b border-gray-50 pb-2">
  240. <span class="text-gray-400 font-bold uppercase text-[11px]">@Lang.millions_money_ticket</span>
  241. <span id="detailMoney" class="font-black text-gray-800">0 HTG</span>
  242. </div>
  243. <div class="flex justify-between items-center text-sm border-b border-gray-50 pb-2">
  244. <span class="text-gray-400 font-bold uppercase text-[11px]">@Lang.millions_money_win</span>
  245. <span id="detailMoneyWin" class="font-black text-[#0A9800]">0 HTG</span>
  246. </div>
  247. <div class="flex justify-between items-center text-sm border-b border-gray-50 pb-2">
  248. <span class="text-gray-400 font-bold uppercase text-[11px]">@Lang.millions_purchase_date</span>
  249. <span id="detailDate" class="font-black text-gray-800">-</span>
  250. </div>
  251. <div class="flex justify-between items-center text-sm border-b border-gray-50 pb-2">
  252. <span class="text-gray-400 font-bold uppercase text-[11px]">@Lang.millions_draw_date</span>
  253. <span id="detailDrawTime" class="font-black text-gray-800">-</span>
  254. </div>
  255. <div class="flex justify-between items-center text-sm border-b border-gray-50 pb-2">
  256. <span class="text-gray-400 font-bold uppercase text-[11px]">@Lang.millions_channel</span>
  257. <span id="detailChannel" class="font-black text-gray-800">-</span>
  258. </div>
  259. <div class="flex justify-between items-center text-sm border-b border-gray-50 pb-2">
  260. <span class="text-gray-400 font-bold uppercase text-[11px]">@Lang.millions_payment_method</span>
  261. <span id="detailPaymentMethod" class="font-black text-gray-800">-</span>
  262. </div>
  263. </div>
  264. <button onclick="closeDetailModal()" class="w-full bg-[#0062FF] text-white font-black text-[16px] py-3.5 rounded-2xl shadow-lg mt-8 active:scale-95 transition-all uppercase tracking-widest">
  265. @Lang.millions_close
  266. </button>
  267. </div>
  268. </div>