Profile.cshtml 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. @model LotteryWebApp.Models.HomeIndex_ViewModel
  2. @{
  3. ViewData["Title"] = "Millions - Profile";
  4. ViewData["ActiveTab"] = "More";
  5. Layout = "~/Areas/Millions/Views/Shared/_Layout.cshtml";
  6. }
  7. @using LotteryWebApp.Languages;
  8. <script src="https://cdn.tailwindcss.com"></script>
  9. <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
  10. <link rel="stylesheet" href="/Millions/css/site.css" />
  11. <!-- Add custom font Bricolage Grotesque to match Figma styling -->
  12. <link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:wght@400;700;800&display=swap" rel="stylesheet">
  13. <!-- Flatpickr for premium calendar -->
  14. <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
  15. <script src="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.js"></script>
  16. <link rel="stylesheet" href="/Millions/css/results.css" />
  17. <style>
  18. .font-bricolage { font-family: 'Bricolage Grotesque', sans-serif; }
  19. </style>
  20. <div class="main-container animate__animated animate__fadeIn min-h-screen relative flex flex-col pb-24 font-bricolage" style="background-color: #EAEAEA !important;">
  21. <!-- Header (Red Background) - Fixed -->
  22. <div class="fixed top-0 left-1/2 -translate-x-1/2 w-full max-w-[414px] bg-[#0062FF] h-[52px] flex items-center justify-between px-4 z-[100] shadow-sm">
  23. <!-- Back Button -->
  24. <button onclick="window.location.href='/Millions/Home/More'" class="w-10 h-10 flex items-center justify-center -ml-2 rounded-full active:bg-white/20 transition-colors z-10 text-white">
  25. <i class="fa-solid fa-arrow-left text-[24px]"></i>
  26. </button>
  27. <!-- Title -->
  28. <div class="absolute inset-0 flex items-center justify-center pointer-events-none">
  29. <span class="font-bold text-[32px] text-white tracking-wide">@Lang.profile</span>
  30. </div>
  31. </div>
  32. <!-- Header Spacer (~52px) -->
  33. <div class="h-[52px]"></div>
  34. <!-- Content Form -->
  35. <div class="w-full flex flex-col items-center px-5 py-6 gap-3 flex-1 overflow-x-hidden">
  36. <!-- Phone Number Field (Disabled State) -->
  37. <div class="w-full flex flex-col gap-2">
  38. <label class="font-bold text-[#534A4A] text-[14px]">@Lang.phone_number</label>
  39. <div class="w-full bg-[#C9C9C9] rounded-[8px] h-[50px] px-3 flex items-center shadow-inner">
  40. <span class="font-[800] text-[20px] text-black w-full tracking-wide">@(Model?.profile?.users ?? "509XXXXXXXX")</span>
  41. </div>
  42. </div>
  43. <!-- Name Field -->
  44. <div class="w-full flex flex-col gap-2 mt-2">
  45. <label class="font-bold text-[#534A4A] text-[14px]">@Lang.name</label>
  46. <div class="w-full bg-transparent border border-[#8F8F8F] rounded-[8px] h-[50px] px-3 flex items-center">
  47. <input type="text" id="txtFullName" class="w-full bg-transparent font-[800] text-[20px] text-black outline-none tracking-wide" value="@(Model?.profile?.fullName ?? "User")" />
  48. </div>
  49. </div>
  50. <div class="w-full flex flex-col gap-2 mt-2">
  51. <label class="font-bold text-[#534A4A] text-[14px]">@Lang.dateOfBirth</label>
  52. @{
  53. string birthdayVal = Model?.profile?.birthday ?? "2000-01-01";
  54. if (birthdayVal.Contains("/")) {
  55. try {
  56. var parts = birthdayVal.Split('/');
  57. if (parts.Length == 3) { birthdayVal = $"{parts[2]}-{parts[1]}-{parts[0]}"; }
  58. } catch { birthdayVal = "2000-01-01"; }
  59. }
  60. }
  61. <div class="w-full bg-transparent rounded-[8px] flex items-center justify-between relative cursor-pointer" onclick="document.getElementById('txtBirthday')._flatpickr.open()">
  62. <input type="text" id="txtBirthday" class="w-full bg-transparent font-[800] text-[20px] text-black outline-none tracking-wide flex-1"
  63. value="@birthdayVal" readonly />
  64. <i class="fa-regular fa-calendar text-[#534A4A] text-[20px] pointer-events-none absolute right-3"></i>
  65. </div>
  66. </div>
  67. <!-- Update Button -->
  68. <div class="w-full flex justify-center mt-8">
  69. <button id="btnUpdateProfile" onclick="updateProfile(this)" class="w-[300px] max-w-full bg-[#0062FF] text-white font-[800] text-[20px] py-[10px] rounded-[12px] shadow-[0px_3px_8px_rgba(0,0,0,0.25)] hover:bg-red-700 active:scale-95 transition-all">
  70. @Lang.update
  71. </button>
  72. </div>
  73. </div>
  74. </div>
  75. <!-- Success Modal Overlay -->
  76. <div id="successModal" class="fixed inset-0 z-[100] flex items-center justify-center hidden px-6 translate-y-0" style="background: linear-gradient(135deg, #1A1A2E 0%, #16213E 100%);">
  77. <div class="w-full max-w-[343px] min-h-[520px] bg-white rounded-[20px] overflow-hidden flex flex-col items-center p-8 animate__animated animate__zoomIn animate__faster">
  78. <div class="w-full flex flex-col items-center mb-5 mt-4">
  79. <div class="relative w-full max-w-[343px] flex items-center justify-center">
  80. <img src="/Millions/img/modal/success_header.png" class="w-[280px] h-auto object-contain" />
  81. </div>
  82. </div>
  83. <div class="px-5 text-center mb-10 mt-5">
  84. <p class="text-black font-[700] text-[20px] font-bricolage leading-tight">
  85. @Lang.update_successful
  86. </p>
  87. </div>
  88. <div class="w-full mt-auto">
  89. <button onclick="closeModalAndReload('/Millions/Home/More')" class="w-full bg-[#0062FF] text-white font-[800] text-[20px] py-[10px] rounded-[12px] shadow-[0px_3px_8px_rgba(0,0,0,0.25)] hover:bg-red-700 active:scale-95 transition-all font-bricolage">
  90. @Lang.back_to_homepage
  91. </button>
  92. </div>
  93. </div>
  94. </div>
  95. <!-- Failure Modal Overlay -->
  96. <div id="failureModal" class="fixed inset-0 z-[100] flex items-center justify-center hidden px-6 translate-y-0" style="background: linear-gradient(135deg, #1A1A2E 0%, #16213E 100%);">
  97. <div class="w-full max-w-[343px] min-h-[520px] bg-white rounded-[20px] overflow-hidden flex flex-col items-center p-8 animate__animated animate__zoomIn animate__faster">
  98. <div class="w-full flex flex-col items-center mb-8 mt-10">
  99. <div class="relative w-full max-w-[343px] flex items-center justify-center">
  100. <img src="/Millions/img/modal/fail_icon.png" class="w-[200px] h-auto object-contain" />
  101. </div>
  102. </div>
  103. <div class="px-5 text-center mb-10 mt-5">
  104. <p id="failErrorMessage" class="text-black font-[700] text-[20px] font-bricolage leading-tight">
  105. @Lang.update_profile_error
  106. </p>
  107. </div>
  108. <div class="w-full mt-auto">
  109. <button onclick="closeFailureModal()" class="w-full bg-[#0062FF] text-white font-[800] text-[20px] py-[10px] rounded-[12px] shadow-[0px_3px_8_rgba(0,0,0,0.25)] hover:bg-red-700 active:scale-95 transition-all font-bricolage">
  110. @Lang.try_again
  111. </button>
  112. </div>
  113. </div>
  114. </div>
  115. <partial name="_BottomNavbar" />
  116. <script>
  117. function initBrandedFlatpickr(selector, yearStart, yearEnd) {
  118. flatpickr(selector, {
  119. dateFormat: "Y-m-d",
  120. altInput: true,
  121. altFormat: "d/m/Y",
  122. altInputClass: "w-full bg-transparent font-[800] text-[20px] text-black outline-none tracking-wide cursor-pointer",
  123. disableMobile: true,
  124. monthSelectorType: "dropdown",
  125. onReady: function (selectedDates, dateStr, instance) {
  126. const yearInput = instance.calendarContainer.querySelector(".numInput.cur-year");
  127. if (yearInput) {
  128. const yearSelect = document.createElement("select");
  129. yearSelect.className = "flatpickr-monthDropdown-months cur-year-select";
  130. yearSelect.style.cssText = "appearance:none; font-weight:800; border:none; background:transparent; color:white; cursor:pointer; margin-left:4px; outline:none; font-family:inherit; font-size:inherit;";
  131. for (let y = yearEnd; y >= yearStart; y--) {
  132. const opt = document.createElement("option");
  133. opt.value = y;
  134. opt.text = y;
  135. opt.style.color = "#333";
  136. if (y === instance.currentYear) opt.selected = true;
  137. yearSelect.appendChild(opt);
  138. }
  139. yearSelect.addEventListener("change", function () {
  140. instance.changeYear(parseInt(this.value));
  141. });
  142. yearInput.style.display = "none";
  143. yearInput.parentNode.appendChild(yearSelect);
  144. instance.set("onChange", function(d, s, i) {
  145. yearSelect.value = i.currentYear;
  146. });
  147. }
  148. }
  149. });
  150. }
  151. document.addEventListener('DOMContentLoaded', function() {
  152. initBrandedFlatpickr("#txtBirthday", 1940, 2026);
  153. });
  154. function updateProfile(btn) {
  155. var fullName = $("#txtFullName").val();
  156. var birthday = $("#txtBirthday").val();
  157. if (fullName == "") {
  158. showFailureModal("@Lang.enter_name");
  159. return;
  160. }
  161. // Prevent double-click
  162. var $btn = $(btn);
  163. var originalText = $btn.html();
  164. $btn.prop('disabled', true).html('<i class="fa-solid fa-spinner fa-spin mr-2"></i> ...');
  165. $.ajax({
  166. url: subDomain + "/Millions/Home/UserUpdateProfile",
  167. type: "POST",
  168. data: {
  169. fullName: fullName,
  170. birthday: birthday
  171. },
  172. success: function (response) {
  173. $btn.prop('disabled', false).html(originalText);
  174. if (response.status == "0") {
  175. showSuccessModal();
  176. } else {
  177. showFailureModal(response.message || "Update failed", response.status);
  178. }
  179. },
  180. error: function (error) {
  181. $btn.prop('disabled', false).html(originalText);
  182. showFailureModal("An error occurred during network request");
  183. }
  184. });
  185. }
  186. function showSuccessModal() {
  187. $("#successModal").removeClass("hidden").addClass("flex");
  188. }
  189. var systemUpgrading = false;
  190. function showFailureModal(message, code) {
  191. $("#failErrorMessage").text(message);
  192. const $btn = $("#failureModal button");
  193. if (code === "-2" || (message && message.includes("System is upgrading"))) {
  194. systemUpgrading = true;
  195. $btn.text("@Lang.login");
  196. } else {
  197. systemUpgrading = false;
  198. $btn.text("@Lang.try_again");
  199. }
  200. $("#failureModal").removeClass("hidden").addClass("flex");
  201. }
  202. function closeModalAndReload(url) {
  203. $("#successModal").addClass("hidden").removeClass("flex");
  204. window.location.href = url;
  205. }
  206. function closeFailureModal() {
  207. $("#failureModal").addClass("hidden").removeClass("flex");
  208. if (systemUpgrading) {
  209. window.location.href = subDomain + "/Account/Login";
  210. }
  211. }
  212. </script>