|
@@ -49,14 +49,55 @@
|
|
|
<div class="px-5 pt-4 pb-2">
|
|
<div class="px-5 pt-4 pb-2">
|
|
|
<h3 class="text-[17px] font-bold text-black text-center mb-3">Results for the last 5 days</h3>
|
|
<h3 class="text-[17px] font-bold text-black text-center mb-3">Results for the last 5 days</h3>
|
|
|
<div id="last5Results" class="flex justify-between gap-1.5 px-1">
|
|
<div id="last5Results" class="flex justify-between gap-1.5 px-1">
|
|
|
- @* Mock data for results *@
|
|
|
|
|
- @for(int r=0; r<5; r++) {
|
|
|
|
|
- var resTitle = isBigSmall ? (r % 2 == 0 ? "Big" : "Small") : (r % 2 == 0 ? "Odd" : "Even");
|
|
|
|
|
- var resColor = isBigSmall ? (resTitle == "Big" ? "#A2FF00" : "#FF4157") : (resTitle == "Odd" ? "#FFC700" : "#B33BD0");
|
|
|
|
|
- <div class="flex flex-col items-center justify-center min-h-[64px] flex-1 rounded-lg py-1.5 border border-gray-200" style="background: linear-gradient(136deg, #FFFAE6 0%, #FFE588 100%);">
|
|
|
|
|
- <span class="text-[11px] font-bold text-black whitespace-nowrap opacity-70">Mar @(16+r)</span>
|
|
|
|
|
- <span class="text-[22px] font-black leading-tight" style="-webkit-text-stroke: 0.5px #000; color: @resColor;">@resTitle</span>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ @{
|
|
|
|
|
+ var pastTerms = ViewBag.PastTerms as List<LotteryWebApp.Service.Term> ?? new List<LotteryWebApp.Service.Term>();
|
|
|
|
|
+ foreach (var term in pastTerms) {
|
|
|
|
|
+ var rawResult = (term.result ?? "").Trim().ToUpper();
|
|
|
|
|
+ var dateStr = "--";
|
|
|
|
|
+ DateTime dt;
|
|
|
|
|
+ if (DateTime.TryParse(term.date_random, out dt)) {
|
|
|
|
|
+ dateStr = dt.ToString("MMM dd", System.Globalization.CultureInfo.InvariantCulture);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ var resKey = rawResult;
|
|
|
|
|
+ var resTitle = rawResult;
|
|
|
|
|
+ if (isBigSmall) {
|
|
|
|
|
+ if (rawResult == "S") { resKey = "Small"; resTitle = Lang.Small; }
|
|
|
|
|
+ else if (rawResult == "B") { resKey = "Big"; resTitle = Lang.Big; }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ if (rawResult == "O") { resKey = "Odd"; resTitle = Lang.Odd; }
|
|
|
|
|
+ else if (rawResult == "E") { resKey = "Even"; resTitle = Lang.Even; }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ var resColor = "";
|
|
|
|
|
+ var bgStyle = "background: linear-gradient(136deg, #FFFAE6 0%, #FFE588 100%);";
|
|
|
|
|
+ var textStyle = "-webkit-text-stroke: 0.5px #000;";
|
|
|
|
|
+
|
|
|
|
|
+ if (resKey == "NA" || string.IsNullOrEmpty(rawResult)) {
|
|
|
|
|
+ bgStyle = "background: #EAEAEA;";
|
|
|
|
|
+ resTitle = "";
|
|
|
|
|
+ textStyle = "";
|
|
|
|
|
+ } else {
|
|
|
|
|
+ if (isBigSmall) {
|
|
|
|
|
+ resColor = resKey == "Big" ? "#A2FF00" : "#FF4157";
|
|
|
|
|
+ } else {
|
|
|
|
|
+ resColor = resKey == "Odd" ? "#FFC700" : "#B33BD0";
|
|
|
|
|
+ }
|
|
|
|
|
+ textStyle += $" color: {resColor};";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ <div class="flex flex-col items-center justify-center min-h-[64px] flex-1 rounded-lg py-1.5 border border-gray-200" style="@bgStyle">
|
|
|
|
|
+ <span class="text-[11px] font-bold text-black whitespace-nowrap opacity-70">@dateStr</span>
|
|
|
|
|
+ <span class="text-[22px] font-black leading-tight" style="@textStyle">@resTitle</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ for(int r = pastTerms.Count; r < 5; r++) {
|
|
|
|
|
+ <div class="flex flex-col items-center justify-center min-h-[64px] flex-1 rounded-lg py-1.5 border border-gray-200" style="background: #EAEAEA; opacity: 0.7;">
|
|
|
|
|
+ <span class="text-[11px] font-bold text-black whitespace-nowrap opacity-70">--</span>
|
|
|
|
|
+ <span class="text-[22px] font-black leading-tight" style="color: transparent;"></span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
@@ -494,8 +535,10 @@ else
|
|
|
var activeBall = null;
|
|
var activeBall = null;
|
|
|
var activeTicketCard = null;
|
|
var activeTicketCard = null;
|
|
|
var selectedNumbers = []; // For Edit mode, this will be an array of fixed size with nulls
|
|
var selectedNumbers = []; // For Edit mode, this will be an array of fixed size with nulls
|
|
|
|
|
+ var isMultiMode = false;
|
|
|
|
|
|
|
|
function editFullTicket(btn) {
|
|
function editFullTicket(btn) {
|
|
|
|
|
+ isMultiMode = true;
|
|
|
activeTicketCard = $(btn).closest('.ticket-card');
|
|
activeTicketCard = $(btn).closest('.ticket-card');
|
|
|
activeBall = null;
|
|
activeBall = null;
|
|
|
|
|
|
|
@@ -562,7 +605,7 @@ else
|
|
|
var $btn = $(this);
|
|
var $btn = $(this);
|
|
|
var picked = $btn.text().trim();
|
|
var picked = $btn.text().trim();
|
|
|
|
|
|
|
|
- if (isMulti) {
|
|
|
|
|
|
|
+ if (isMultiMode) {
|
|
|
if (selectedNumbers.includes(picked)) {
|
|
if (selectedNumbers.includes(picked)) {
|
|
|
// Remove
|
|
// Remove
|
|
|
let idx = selectedNumbers.indexOf(picked);
|
|
let idx = selectedNumbers.indexOf(picked);
|
|
@@ -579,6 +622,20 @@ else
|
|
|
liveUpdateTicket();
|
|
liveUpdateTicket();
|
|
|
} else {
|
|
} else {
|
|
|
// Single Select mode
|
|
// Single Select mode
|
|
|
|
|
+ var exists = false;
|
|
|
|
|
+ if (activeTicketCard) {
|
|
|
|
|
+ activeTicketCard.find('.ball-filled').each(function() {
|
|
|
|
|
+ if (activeBall && this !== activeBall[0] && $(this).text().trim() === picked) {
|
|
|
|
|
+ exists = true;
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ if (exists) {
|
|
|
|
|
+ if (typeof showNotification === "function") {
|
|
|
|
|
+ showNotification("Number already selected", "warning");
|
|
|
|
|
+ }
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
grid.find('.num-btn').removeClass('bg-[#EE0033] text-white shadow-md scale-105 active-num').addClass('bg-white text-gray-700 border border-gray-100');
|
|
grid.find('.num-btn').removeClass('bg-[#EE0033] text-white shadow-md scale-105 active-num').addClass('bg-white text-gray-700 border border-gray-100');
|
|
|
selectedNumbers = [picked];
|
|
selectedNumbers = [picked];
|
|
|
$btn.addClass('bg-[#EE0033] text-white shadow-md scale-105 active-num').removeClass('bg-white text-gray-700 border border-gray-100');
|
|
$btn.addClass('bg-[#EE0033] text-white shadow-md scale-105 active-num').removeClass('bg-white text-gray-700 border border-gray-100');
|
|
@@ -594,7 +651,7 @@ else
|
|
|
var count = selectedNumbers.filter(n => n !== null && n !== "").length;
|
|
var count = selectedNumbers.filter(n => n !== null && n !== "").length;
|
|
|
$("#selectionCount").text(count);
|
|
$("#selectionCount").text(count);
|
|
|
$("#maxSelectionCount").text(maxBalls);
|
|
$("#maxSelectionCount").text(maxBalls);
|
|
|
- var isValid = activeTicketCard ? (count === maxBalls) : (count === 1);
|
|
|
|
|
|
|
+ var isValid = isMultiMode ? (count === maxBalls) : (count === 1);
|
|
|
if (isValid) {
|
|
if (isValid) {
|
|
|
$("#confirmBtn").prop('disabled', false).removeClass('opacity-50 cursor-not-allowed').addClass('cursor-pointer');
|
|
$("#confirmBtn").prop('disabled', false).removeClass('opacity-50 cursor-not-allowed').addClass('cursor-pointer');
|
|
|
} else {
|
|
} else {
|
|
@@ -605,53 +662,46 @@ else
|
|
|
function liveUpdateTicket() {
|
|
function liveUpdateTicket() {
|
|
|
if (!activeTicketCard) return;
|
|
if (!activeTicketCard) return;
|
|
|
var balls = activeTicketCard.find('.ball-circle');
|
|
var balls = activeTicketCard.find('.ball-circle');
|
|
|
- var modalPreview = $("#modalSelectionPreview");
|
|
|
|
|
-
|
|
|
|
|
- // No more clearing all and sorting in fixed-position mode
|
|
|
|
|
- // Just update based on index
|
|
|
|
|
- modalPreview.empty();
|
|
|
|
|
|
|
|
|
|
- // Update Modal Preview Bar & Ticket Card balls
|
|
|
|
|
- for(var i=0; i < maxBalls; i++){
|
|
|
|
|
- var val = selectedNumbers[i];
|
|
|
|
|
-
|
|
|
|
|
- // Update Ticket Card Ball
|
|
|
|
|
- if (i < balls.length) {
|
|
|
|
|
- var tBall = $(balls[i]);
|
|
|
|
|
- if (val) {
|
|
|
|
|
- tBall.removeClass('ball-empty').addClass('ball-filled').text(val);
|
|
|
|
|
- } else {
|
|
|
|
|
- tBall.removeClass('ball-filled').addClass('ball-empty').text('');
|
|
|
|
|
|
|
+ if (isMultiMode) {
|
|
|
|
|
+ // Update Ticket Card balls
|
|
|
|
|
+ for(var i=0; i < maxBalls; i++){
|
|
|
|
|
+ var val = selectedNumbers[i];
|
|
|
|
|
+ if (i < balls.length) {
|
|
|
|
|
+ var tBall = $(balls[i]);
|
|
|
|
|
+ if (val) {
|
|
|
|
|
+ tBall.removeClass('ball-empty').addClass('ball-filled').text(val);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ tBall.removeClass('ball-filled').addClass('ball-empty').text('');
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ // Toggle Rand/Edit button visibility
|
|
|
|
|
+ if (selectedNumbers.filter(n => n !== null && n !== "").length > 0) {
|
|
|
|
|
+ activeTicketCard.find('.rand-btn').hide();
|
|
|
|
|
+ activeTicketCard.find('.edit-delete-group').removeClass('hidden').show();
|
|
|
|
|
+ } else {
|
|
|
|
|
+ activeTicketCard.find('.rand-btn').show();
|
|
|
|
|
+ activeTicketCard.find('.edit-delete-group').addClass('hidden');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ updateTotalPrice();
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- // Toggle Rand/Edit button visibility
|
|
|
|
|
- if (selectedNumbers.length > 0) {
|
|
|
|
|
- activeTicketCard.find('.rand-btn').hide();
|
|
|
|
|
- activeTicketCard.find('.edit-delete-group').removeClass('hidden').show();
|
|
|
|
|
- } else {
|
|
|
|
|
- activeTicketCard.find('.rand-btn').show();
|
|
|
|
|
- activeTicketCard.find('.edit-delete-group').addClass('hidden');
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- updateTotalPrice();
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// All immediate jQuery event bindings must wait for DOM + jQuery to be ready
|
|
// All immediate jQuery event bindings must wait for DOM + jQuery to be ready
|
|
|
document.addEventListener("DOMContentLoaded", function() {
|
|
document.addEventListener("DOMContentLoaded", function() {
|
|
|
// Click on a ball (filled or empty) to pick numbers
|
|
// Click on a ball (filled or empty) to pick numbers
|
|
|
$(document).on('click', '.ball-filled, .ball-empty', function() {
|
|
$(document).on('click', '.ball-filled, .ball-empty', function() {
|
|
|
- activeTicketCard = $(this).closest('.ticket-card');
|
|
|
|
|
|
|
+ isMultiMode = false;
|
|
|
|
|
+ activeBall = $(this);
|
|
|
|
|
+ activeTicketCard = activeBall.closest('.ticket-card');
|
|
|
|
|
|
|
|
- // Read current numbers from balls into the array
|
|
|
|
|
- selectedNumbers = new Array(maxBalls).fill(null);
|
|
|
|
|
- activeTicketCard.find('.ball-circle').each(function(idx) {
|
|
|
|
|
- var val = $(this).text().trim();
|
|
|
|
|
- if (val && idx < maxBalls) selectedNumbers[idx] = val;
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ var val = activeBall.text().trim();
|
|
|
|
|
+ selectedNumbers = val ? [val] : [];
|
|
|
|
|
|
|
|
- openNumberPicker(true);
|
|
|
|
|
|
|
+ openNumberPicker(false);
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
updateTotalPrice();
|
|
updateTotalPrice();
|
|
@@ -663,7 +713,7 @@ else
|
|
|
var count = selectedNumbers.filter(n => n !== null && n !== "").length;
|
|
var count = selectedNumbers.filter(n => n !== null && n !== "").length;
|
|
|
if (count === 0) return;
|
|
if (count === 0) return;
|
|
|
|
|
|
|
|
- if (activeTicketCard && activeTicketCard.length > 0) {
|
|
|
|
|
|
|
+ if (isMultiMode && activeTicketCard && activeTicketCard.length > 0) {
|
|
|
// Collect and sort for final storage/display (lottery numbers are usually sorted)
|
|
// Collect and sort for final storage/display (lottery numbers are usually sorted)
|
|
|
var finalSorted = selectedNumbers.filter(n => n !== null && n !== "").sort((a, b) => parseInt(a) - parseInt(b));
|
|
var finalSorted = selectedNumbers.filter(n => n !== null && n !== "").sort((a, b) => parseInt(a) - parseInt(b));
|
|
|
|
|
|
|
@@ -682,11 +732,23 @@ else
|
|
|
activeTicketCard.find('.edit-delete-group').removeClass('hidden').show();
|
|
activeTicketCard.find('.edit-delete-group').removeClass('hidden').show();
|
|
|
|
|
|
|
|
updateTotalPrice();
|
|
updateTotalPrice();
|
|
|
- } else if (activeBall && activeBall.length > 0) {
|
|
|
|
|
|
|
+ } else if (!isMultiMode && activeBall && activeBall.length > 0) {
|
|
|
// Single mode: Update only the active ball
|
|
// Single mode: Update only the active ball
|
|
|
activeBall.text(selectedNumbers[0]).removeClass('ball-empty').addClass('ball-filled');
|
|
activeBall.text(selectedNumbers[0]).removeClass('ball-empty').addClass('ball-filled');
|
|
|
activeBall.addClass('animate__animated animate__pulse');
|
|
activeBall.addClass('animate__animated animate__pulse');
|
|
|
setTimeout(() => activeBall.removeClass('animate__animated animate__pulse'), 500);
|
|
setTimeout(() => activeBall.removeClass('animate__animated animate__pulse'), 500);
|
|
|
|
|
+
|
|
|
|
|
+ var card = activeBall.closest('.ticket-card');
|
|
|
|
|
+ var filledBalls = card.find('.ball-filled').length;
|
|
|
|
|
+ if (filledBalls > 0) {
|
|
|
|
|
+ card.find('.rand-btn').hide();
|
|
|
|
|
+ card.find('.edit-delete-group').removeClass('hidden').show();
|
|
|
|
|
+ } else {
|
|
|
|
|
+ card.find('.rand-btn').show();
|
|
|
|
|
+ card.find('.edit-delete-group').addClass('hidden');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ updateTotalPrice();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
closeNumberPicker();
|
|
closeNumberPicker();
|