Profile.cshtml 11 KB

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