student 3 недель назад
Родитель
Сommit
7ffa866dcd

+ 9 - 4
Kitty_Fall/Kitty_Fall/Common/Extension/SessionExtension.cs

@@ -22,7 +22,8 @@ namespace Common.Extension
             session.SetString(key, JsonConvert.SerializeObject(value));
         }
 
-        // Free user = no active RegInfo. Subscriber = at least one RegInfo with active status.
+        // CHARGE la goi mua luot mot lan, khong phai goi subscription.
+        // Subscriber chi la RegInfo active cua goi DAILY/DAYLY.
         public static bool IsSubscriber(this ISession session)
         {
             var role = session.GetComplexData<string>("role");
@@ -39,7 +40,7 @@ namespace Common.Extension
 
                 foreach (var item in arr)
                 {
-                    if (IsActiveRegInfo(item)) return true;
+                    if (IsActiveDailySubscription(item)) return true;
                 }
 
                 return false;
@@ -50,10 +51,14 @@ namespace Common.Extension
             }
         }
 
-        private static bool IsActiveRegInfo(JToken item)
+        private static bool IsActiveDailySubscription(JToken item)
         {
             var status = item["status"] ?? item["Status"];
-            return status != null && ReadTruthy(status);
+            if (status == null || !ReadTruthy(status)) return false;
+
+            var productName = (item["productName"] ?? item["ProductName"])?.ToString() ?? "";
+            return productName.Contains("_DAILY", StringComparison.OrdinalIgnoreCase)
+                || productName.Contains("_DAYLY", StringComparison.OrdinalIgnoreCase);
         }
 
         private static bool ReadTruthy(JToken token)

+ 1 - 0
Kitty_Fall/Kitty_Fall/Common/Http/Apis/Request/UserGameLevelResult.cs

@@ -24,6 +24,7 @@ namespace Common.Http.Apis.Request
         public string rewardType { get; set; } = "";
         public decimal rewardValue { get; set; }
         public string rewardUnit { get; set; } = "";
+        public string reason { get; set; } = "";
     }
 
     public class UserGameLevelResultRes : CommonResponse

+ 6 - 1
Kitty_Fall/Kitty_Fall/Kitty_Fall.Apis/Business/Game/GameBusinessImpl.cs

@@ -658,7 +658,12 @@ namespace Kitty_Fall.Apis.Business.Game
                     var turn = await DeductOneTurnAsync(msisdn, now);
                     if (turn == null)
                     {
-                        return CommonLogic.BuildResponse(url, json, CommonErrorCode.Error, Lang.overTurn, new { });
+                        return CommonLogic.BuildResponse(
+                            url,
+                            json,
+                            CommonErrorCode.Error,
+                            Lang.overTurn,
+                            new UserGameLevelResultData { reason = "TURN_OVER" });
                     }
 
                     session.TurnDeducted = true;

+ 1 - 0
Kitty_Fall/Kitty_Fall/Kitty_Fall.Website/Controllers/GameController.cs

@@ -36,6 +36,7 @@ namespace Kitty_Fall.Website.Controllers
                 return Json(new
                 {
                     success = false,
+                    reason = apiResult.data?.reason ?? "",
                     message = apiResult.message ?? "Start game failed."
                 });
             }

+ 5 - 0
Kitty_Fall/Kitty_Fall/Kitty_Fall.Website/Language/Lang.Designer.cs

@@ -1325,5 +1325,10 @@ namespace Kitty_Fall.Website.Language {
         public static string AccountAvatarAlt => ResourceManager.GetString("AccountAvatarAlt", resourceCulture);
         public static string AccountCancelCatAlt => ResourceManager.GetString("AccountCancelCatAlt", resourceCulture);
         public static string BuyTurnSuccessMessage => ResourceManager.GetString("BuyTurnSuccessMessage", resourceCulture);
+        public static string TurnOverTitle => ResourceManager.GetString("TurnOverTitle", resourceCulture);
+        public static string TurnOverPrimary => ResourceManager.GetString("TurnOverPrimary", resourceCulture);
+        public static string TurnOverSecondary => ResourceManager.GetString("TurnOverSecondary", resourceCulture);
+        public static string BuyMoreTurns => ResourceManager.GetString("BuyMoreTurns", resourceCulture);
+        public static string Close => ResourceManager.GetString("Close", resourceCulture);
     }
 }

+ 15 - 0
Kitty_Fall/Kitty_Fall/Kitty_Fall.Website/Language/Lang.resx

@@ -639,4 +639,19 @@
   <data name="BuyTurnSuccessMessage" xml:space="preserve">
     <value>You have successfully purchased {0} turns!</value>
   </data>
+  <data name="TurnOverTitle" xml:space="preserve">
+    <value>NO TURNS LEFT!</value>
+  </data>
+  <data name="TurnOverPrimary" xml:space="preserve">
+    <value>You don't have any play turns left.</value>
+  </data>
+  <data name="TurnOverSecondary" xml:space="preserve">
+    <value>Get more turns and continue your adventure!</value>
+  </data>
+  <data name="BuyMoreTurns" xml:space="preserve">
+    <value>BUY MORE TURNS</value>
+  </data>
+  <data name="Close" xml:space="preserve">
+    <value>Close</value>
+  </data>
 </root>

+ 15 - 0
Kitty_Fall/Kitty_Fall/Kitty_Fall.Website/Language/Lang.vi.resx

@@ -639,4 +639,19 @@
   <data name="BuyTurnSuccessMessage" xml:space="preserve">
     <value>သင်သည် ကစားခွင့် {0} ကြိမ်ကို အောင်မြင်စွာ ဝယ်ယူပြီးပါပြီ။</value>
   </data>
+  <data name="TurnOverTitle" xml:space="preserve">
+    <value>ကစားခွင့် မကျန်တော့ပါ!</value>
+  </data>
+  <data name="TurnOverPrimary" xml:space="preserve">
+    <value>သင့်တွင် ကစားခွင့် မကျန်တော့ပါ။</value>
+  </data>
+  <data name="TurnOverSecondary" xml:space="preserve">
+    <value>ကစားခွင့်များ ထပ်မံရယူပြီး စွန့်စားခန်းကို ဆက်ကစားပါ!</value>
+  </data>
+  <data name="BuyMoreTurns" xml:space="preserve">
+    <value>ကစားခွင့် ထပ်ဝယ်မည်</value>
+  </data>
+  <data name="Close" xml:space="preserve">
+    <value>ပိတ်ရန်</value>
+  </data>
 </root>

+ 3 - 3
Kitty_Fall/Kitty_Fall/Kitty_Fall.Website/Views/Home/Index.cshtml

@@ -32,6 +32,9 @@
 
     <header class="topbar">
         <div class="profile">
+            <button class="home-back-button" type="button" aria-label="Back" onclick="logoutAndBack()">
+                <span></span>
+            </button>
             <img class="profile-avatar" src="@avatarUrl" alt="Player avatar">
             <div class="profile-copy">
                 <strong>@Lang.Hello</strong>
@@ -39,9 +42,6 @@
             </div>
         </div>
         <div class="topbar-actions">
-            <button class="home-back-button" type="button" aria-label="Back" onclick="logoutAndBack()">
-                <span></span>
-            </button>
             <button class="menu-button" type="button" aria-label="Open menu">
                 <span></span>
                 <span></span>

+ 12 - 6
Kitty_Fall/Kitty_Fall/Kitty_Fall.Website/Views/Play/Index.cshtml

@@ -140,16 +140,22 @@
 
     <section class="game-over-modal" data-turn-over-modal aria-hidden="true">
         <div class="game-over-backdrop" data-turn-over-close></div>
-        <div class="game-over-card" role="dialog" aria-modal="true" aria-labelledby="turn-over-title">
-            <button class="game-over-close" type="button" data-turn-over-close aria-label="Close">×</button>
-            <img class="game-over-cat" src="~/kitty/assets/kitty-fall/cat.png" alt="">
-            <h2 id="turn-over-title">Turn Over</h2>
-            <p>You have no play turns left.</p>
+        <div class="game-over-card turn-over-card" role="dialog" aria-modal="true" aria-labelledby="turn-over-title">
+            <button class="game-over-close" type="button" data-turn-over-close aria-label="@Lang.Close">×</button>
+            <div class="turn-over-hero" aria-hidden="true">
+                <img class="game-over-cat" src="~/kitty/assets/kitty-fall/turn-over-sad-cat.png" alt="">
+                <span class="turn-over-zero">0</span>
+            </div>
+            <h2 id="turn-over-title">@Lang.TurnOverTitle</h2>
+            <p class="turn-over-copy">
+                <strong>@Lang.TurnOverPrimary</strong>
+                <span>@Lang.TurnOverSecondary</span>
+            </p>
             <a class="game-over-play-button" href="@Url.Action("Index", "Home", new { buyturn = true })">
                 <span class="play-icon">
                     <img src="~/kitty/assets/kitty-fall/ticket.png" alt="">
                 </span>
-                <strong>@Lang.BuyTurn</strong>
+                <strong>@Lang.BuyMoreTurns</strong>
             </a>
         </div>
     </section>

+ 14 - 31
Kitty_Fall/Kitty_Fall/Kitty_Fall.Website/Views/Shared/_Layout.cshtml

@@ -27,13 +27,25 @@
         : "bottom-nav-shell scale-floor";
     var currentCulture = System.Globalization.CultureInfo.CurrentUICulture.Name.ToLower().StartsWith("vi") ? "vi" : "en";
     var accountMsisdn = Context.Session.GetComplexData<string>("msisdn") ?? "";
-    var accountAvatar = Url.Content("~/kitty/assets/kitty-fall/account-cat-avatar.png");
+    var accountProfilePicture = Context.Session.GetComplexData<string>("profilePicture") ?? "";
+    var accountAvatar = string.IsNullOrWhiteSpace(accountProfilePicture)
+        ? Url.Content("~/kitty/assets/kitty-fall/avatar.png")
+        : Url.Content("~/kitty/assets/kitty-fall/") + accountProfilePicture;
     var accountScore = Context.Session.GetComplexData<long?>("totalPoint") ?? 0;
     var accountDataMb = Context.Session.GetComplexData<decimal?>("totalDataMb") ?? 0;
     var accountLoyalty = Context.Session.GetComplexData<decimal?>("totalLoyaltyPoints") ?? 0;
     var regInfos = Context.Session.GetComplexData<JArray>("regInfos");
     var activeReg = regInfos?.FirstOrDefault(x =>
-        bool.TryParse((x["status"] ?? x["Status"])?.ToString(), out var active) && active);
+    {
+        var statusText = (x["status"] ?? x["Status"])?.ToString() ?? "";
+        var isActive = bool.TryParse(statusText, out var activeFlag)
+            ? activeFlag
+            : decimal.TryParse(statusText, out var activeNumber) && activeNumber != 0;
+        var product = (x["productName"] ?? x["ProductName"])?.ToString() ?? "";
+        var isDailySubscription = product.Contains("_DAILY", StringComparison.OrdinalIgnoreCase)
+            || product.Contains("_DAYLY", StringComparison.OrdinalIgnoreCase);
+        return isActive && isDailySubscription;
+    });
     var packageNameRaw = (activeReg?["productName"] ?? activeReg?["ProductName"])?.ToString() ?? "";
     var packageName = string.IsNullOrWhiteSpace(packageNameRaw)
         ? Lang.AccountNoActivePackage
@@ -41,13 +53,6 @@
             || packageNameRaw.Contains("DAILY", StringComparison.OrdinalIgnoreCase)
                 ? Lang.AccountDailyPackage
                 : packageNameRaw.Replace("_", " ");
-    var packageTurns = (activeReg?["numberSpin"] ?? activeReg?["NumberSpin"])?.ToString() ?? "0";
-    var packageRegisterText = (activeReg?["registerTime"] ?? activeReg?["RegisterTime"])?.ToString();
-    var packageExpireText = (activeReg?["expireTime"] ?? activeReg?["ExpireTime"])?.ToString();
-    var packageRenewText = (activeReg?["renew"] ?? activeReg?["Renew"])?.ToString();
-    var hasPackageRegisterTime = DateTime.TryParse(packageRegisterText, out var packageRegisterTime);
-    var hasPackageExpireTime = DateTime.TryParse(packageExpireText, out var packageExpireTime);
-    var isPackageRenewing = byte.TryParse(packageRenewText, out var packageRenewValue) && packageRenewValue == 1;
     var cancelKeyword = Configuration["AccountMenu:CancelKeyword"] ?? "OFF";
     var cancelShortCode = Configuration["AccountMenu:CancelShortCode"] ?? "562";
     var monthStart = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1);
@@ -100,28 +105,6 @@
                             @if (activeReg != null) { <b>@Lang.AccountActiveSubscription</b> }
                         </small>
                         <strong>@packageName</strong>
-                        @if (activeReg != null)
-                        {
-                            <p>
-                                @string.Format(Lang.AccountPlaysPerDay, packageTurns)
-                                @if (hasPackageExpireTime)
-                                {
-                                    <span>• @string.Format(Lang.AccountExpires, packageExpireTime.ToString("dd/MM/yyyy"))</span>
-                                }
-                                else if (isPackageRenewing)
-                                {
-                                    <span>• @Lang.AccountAutoRenew</span>
-                                }
-                            </p>
-                            @if (hasPackageRegisterTime)
-                            {
-                                <em>@string.Format(Lang.AccountSubscribedSince, packageRegisterTime.ToString("dd/MM/yyyy"))</em>
-                            }
-                        }
-                        else
-                        {
-                            <p>@Lang.AccountSubscriptionUnavailable</p>
-                        }
                     </div>
                 </section>
 

BIN
Kitty_Fall/Kitty_Fall/Kitty_Fall.Website/wwwroot/kitty/assets/kitty-fall/turn-over-sad-cat.png


+ 120 - 1
Kitty_Fall/Kitty_Fall/Kitty_Fall.Website/wwwroot/kitty/css/all.min.css

@@ -2854,6 +2854,125 @@ button {
     text-shadow: 0 2px 2px rgba(0, 0, 0, 0.25);
 }
 
+[data-turn-over-modal] .game-over-backdrop {
+    background: rgba(24, 12, 40, 0.56);
+    -webkit-backdrop-filter: blur(3px);
+    backdrop-filter: blur(3px);
+}
+
+.turn-over-card {
+    width: min(calc(100% - 12px), 330px);
+    min-height: 0;
+    height: 278px;
+    border: 2px solid #793ce2;
+    border-radius: 16px;
+    padding: 104px 20px 18px;
+    justify-content: flex-start;
+    background:
+        radial-gradient(circle at 15% 30%, rgba(122, 72, 230, 0.08) 0 3px, transparent 4px),
+        radial-gradient(circle at 84% 38%, rgba(122, 72, 230, 0.08) 0 3px, transparent 4px),
+        rgba(255, 253, 255, 0.98);
+    box-shadow: 0 4px 0 rgba(79, 28, 139, 0.2);
+}
+
+.turn-over-card .game-over-close {
+    top: -12px;
+    right: -10px;
+    width: 34px;
+    height: 34px;
+    border: 2px solid #fff;
+    background: linear-gradient(180deg, #ff5978 0%, #ec3158 100%);
+    font-size: 27px;
+    box-shadow: 0 2px 0 rgba(101, 28, 120, 0.25);
+}
+
+.turn-over-hero {
+    position: absolute;
+    top: -34px;
+    left: 50%;
+    width: 166px;
+    height: 140px;
+    transform: translateX(-50%);
+    pointer-events: none;
+}
+
+.turn-over-card .game-over-cat {
+    top: 0;
+    left: 8px;
+    width: 142px;
+    height: 142px;
+}
+
+.turn-over-zero {
+    position: absolute;
+    z-index: 3;
+    top: 27px;
+    right: -2px;
+    width: 48px;
+    height: 46px;
+    border: 3px solid #fff;
+    border-radius: 50% 50% 50% 18%;
+    display: grid;
+    place-items: center;
+    background: linear-gradient(180deg, #ff5177 0%, #ec2f59 100%);
+    color: #fff;
+    font-size: 24px;
+    line-height: 1;
+    font-weight: 900;
+    box-shadow: 0 2px 0 rgba(123, 39, 137, 0.24);
+    transform: rotate(5deg);
+}
+
+.turn-over-card h2 {
+    margin: 0;
+    color: #5720cc;
+    font-size: 25px;
+    line-height: 1;
+    text-shadow: none;
+}
+
+.turn-over-card .turn-over-copy {
+    margin: 8px 0 0;
+    color: #383040;
+    font-size: 11px;
+    line-height: 1.32;
+    font-weight: 500;
+}
+
+.turn-over-copy strong,
+.turn-over-copy span {
+    display: block;
+}
+
+.turn-over-copy strong {
+    color: #4b4050;
+    font-weight: 700;
+}
+
+.turn-over-card .game-over-play-button {
+    width: 224px;
+    height: 43px;
+    margin-top: 14px;
+    background: linear-gradient(180deg, #ec38de 0%, #a916d7 100%);
+    box-shadow: inset 0 3px 0 rgba(255, 255, 255, 0.24), 0 3px 0 rgba(80, 29, 135, 0.22);
+}
+
+.turn-over-card .game-over-play-button strong {
+    font-size: 15px;
+    text-shadow: none;
+}
+
+.turn-over-card .game-over-play-button .play-icon {
+    width: 25px;
+    height: 25px;
+}
+
+.turn-over-card .game-over-play-button .play-icon img {
+    width: 29px;
+    height: 23px;
+    object-fit: contain;
+}
+
 .subscription-modal {
     position: absolute;
     z-index: 20;
@@ -4669,7 +4788,7 @@ body.has-account-menu {
 
 
 .account-package-card {
-    min-height: 92px;
+    min-height: 70px;
 }
 
 .account-package-info small {

+ 120 - 1
Kitty_Fall/Kitty_Fall/Kitty_Fall.Website/wwwroot/kitty/css/input.css

@@ -2854,6 +2854,125 @@ button {
     text-shadow: 0 2px 2px rgba(0, 0, 0, 0.25);
 }
 
+[data-turn-over-modal] .game-over-backdrop {
+    background: rgba(24, 12, 40, 0.56);
+    -webkit-backdrop-filter: blur(3px);
+    backdrop-filter: blur(3px);
+}
+
+.turn-over-card {
+    width: min(calc(100% - 12px), 330px);
+    min-height: 0;
+    height: 278px;
+    border: 2px solid #793ce2;
+    border-radius: 16px;
+    padding: 104px 20px 18px;
+    justify-content: flex-start;
+    background:
+        radial-gradient(circle at 15% 30%, rgba(122, 72, 230, 0.08) 0 3px, transparent 4px),
+        radial-gradient(circle at 84% 38%, rgba(122, 72, 230, 0.08) 0 3px, transparent 4px),
+        rgba(255, 253, 255, 0.98);
+    box-shadow: 0 4px 0 rgba(79, 28, 139, 0.2);
+}
+
+.turn-over-card .game-over-close {
+    top: -12px;
+    right: -10px;
+    width: 34px;
+    height: 34px;
+    border: 2px solid #fff;
+    background: linear-gradient(180deg, #ff5978 0%, #ec3158 100%);
+    font-size: 27px;
+    box-shadow: 0 2px 0 rgba(101, 28, 120, 0.25);
+}
+
+.turn-over-hero {
+    position: absolute;
+    top: -34px;
+    left: 50%;
+    width: 166px;
+    height: 140px;
+    transform: translateX(-50%);
+    pointer-events: none;
+}
+
+.turn-over-card .game-over-cat {
+    top: 0;
+    left: 8px;
+    width: 142px;
+    height: 142px;
+}
+
+.turn-over-zero {
+    position: absolute;
+    z-index: 3;
+    top: 27px;
+    right: -2px;
+    width: 48px;
+    height: 46px;
+    border: 3px solid #fff;
+    border-radius: 50% 50% 50% 18%;
+    display: grid;
+    place-items: center;
+    background: linear-gradient(180deg, #ff5177 0%, #ec2f59 100%);
+    color: #fff;
+    font-size: 24px;
+    line-height: 1;
+    font-weight: 900;
+    box-shadow: 0 2px 0 rgba(123, 39, 137, 0.24);
+    transform: rotate(5deg);
+}
+
+.turn-over-card h2 {
+    margin: 0;
+    color: #5720cc;
+    font-size: 25px;
+    line-height: 1;
+    text-shadow: none;
+}
+
+.turn-over-card .turn-over-copy {
+    margin: 8px 0 0;
+    color: #383040;
+    font-size: 11px;
+    line-height: 1.32;
+    font-weight: 500;
+}
+
+.turn-over-copy strong,
+.turn-over-copy span {
+    display: block;
+}
+
+.turn-over-copy strong {
+    color: #4b4050;
+    font-weight: 700;
+}
+
+.turn-over-card .game-over-play-button {
+    width: 224px;
+    height: 43px;
+    margin-top: 14px;
+    background: linear-gradient(180deg, #ec38de 0%, #a916d7 100%);
+    box-shadow: inset 0 3px 0 rgba(255, 255, 255, 0.24), 0 3px 0 rgba(80, 29, 135, 0.22);
+}
+
+.turn-over-card .game-over-play-button strong {
+    font-size: 15px;
+    text-shadow: none;
+}
+
+.turn-over-card .game-over-play-button .play-icon {
+    width: 25px;
+    height: 25px;
+}
+
+.turn-over-card .game-over-play-button .play-icon img {
+    width: 29px;
+    height: 23px;
+    object-fit: contain;
+}
+
 .subscription-modal {
     position: absolute;
     z-index: 20;
@@ -4669,7 +4788,7 @@ body.has-account-menu {
 
 
 .account-package-card {
-    min-height: 92px;
+    min-height: 70px;
 }
 
 .account-package-info small {

+ 2 - 1
Kitty_Fall/Kitty_Fall/Kitty_Fall.Website/wwwroot/kitty/js/all.min.js

@@ -431,7 +431,8 @@ const initKittyFall = () => {
                 const result = await startSession();
                 if (!result?.success) {
                     const message = String(result?.message || "");
-                    if (message.toLowerCase().includes("turn over")) {
+                    const reason = String(result?.reason || "").toUpperCase();
+                    if (reason === "TURN_OVER" || message.toLowerCase().includes("turn over")) {
                         showTurnOverModal();
                     } else {
                         window.alert(message || "Unable to start game.");

+ 2 - 1
Kitty_Fall/Kitty_Fall/Kitty_Fall.Website/wwwroot/kitty/js/input.js

@@ -431,7 +431,8 @@ const initKittyFall = () => {
                 const result = await startSession();
                 if (!result?.success) {
                     const message = String(result?.message || "");
-                    if (message.toLowerCase().includes("turn over")) {
+                    const reason = String(result?.reason || "").toUpperCase();
+                    if (reason === "TURN_OVER" || message.toLowerCase().includes("turn over")) {
                         showTurnOverModal();
                     } else {
                         window.alert(message || "Unable to start game.");