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