History.cshtml 16 KB

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