Check timing validation with scope in laravel - laravel

I store 2 dates in my products table start_discounted and end_discounted this 2 columns are responsible of my discount price duration. Now when my product discount duration expires except it return back to normal price it stays on discounted price and my timer goes to minus.
Codes
my model scope
public function scopeValidDiscount($query){
return $query->where('start_discounted', '<=', Carbon::now()->toDateTimeString())
->where('end_discounted', '>=', Carbon::now()->toDateTimeString());
}
controller
public function product($slug){
$product = Product::where('slug', $slug)->firstOrFail();
$validdiscount = $product->ValidDiscount()->get();
//...
}
blade
#if($validdiscount)
show timer
#endif
PS: I need to avoid showing timer in 2 conditions, 1 discount dates are expired. 2 Product discount dates are null.
Any idea where is my mistake?
UPDATE
My timer in blade:
#if($validdiscount)
<div class="deals_timer row align-items-center">
<div class="col-md-6 deals_timer_title_container">
<div class="deals_timer_title">{{__('store.hurryup')}}</div>
<div class="deals_timer_subtitle">{{__('store.endsin')}}</div>
</div>
<div class="col-md-6 deals_timer_content ml-auto">
<div class="deals_timer_box clearfix" data-target-time="{{$end}}">
<div class="text-center deals_timer_unit">
<div id="deals_timer3_hr" class="deals_timer_hr"></div>
<span>{{__('store.hours')}}</span>
</div>
<div class="text-center deals_timer_unit">
<div id="deals_timer3_min" class="deals_timer_min"></div>
<span>{{__('store.mins')}}</span>
</div>
<div class="text-center deals_timer_unit">
<div id="deals_timer3_sec" class="deals_timer_sec"></div>
<span>{{__('store.secs')}}</span>
</div>
</div>
</div>
</div>
#endif
Please pay attention to data-target-time="{{$end}}" i think the issue might be here...
my timer script:
<script>
$(document).ready(function(){
if($('.deals_timer_box').length)
{
var timers = $('.deals_timer_box');
timers.each(function()
{
var timer = $(this);
var targetTime;
var target_date;
// Add a date to data-target-time of the .deals_timer_box
// Format: "Feb 17, 2018"
if(timer.data('target-time') !== "")
{
targetTime = timer.data('target-time');
target_date = new Date(targetTime).getTime();
}
else
{
var date = new Date();
date.setDate(date.getDate() + 2);
target_date = date.getTime();
}
// variables for time units
var days, hours, minutes, seconds;
var h = timer.find('.deals_timer_hr');
var m = timer.find('.deals_timer_min');
var s = timer.find('.deals_timer_sec');
setInterval(function ()
{
// find the amount of "seconds" between now and target
var current_date = new Date().getTime();
var seconds_left = (target_date - current_date) / 1000;
console.log(seconds_left);
// do some time calculations
days = parseInt(seconds_left / 86400);
seconds_left = seconds_left % 86400;
hours = parseInt(seconds_left / 3600);
hours = hours + days * 24;
seconds_left = seconds_left % 3600;
minutes = parseInt(seconds_left / 60);
seconds = parseInt(seconds_left % 60);
if(hours.toString().length < 2)
{
hours = "0" + hours;
}
if(minutes.toString().length < 2)
{
minutes = "0" + minutes;
}
if(seconds.toString().length < 2)
{
seconds = "0" + seconds;
}
// display results
h.text(hours);
m.text(minutes);
s.text(seconds);
}, 1000);
});
}
});
</script>
{{$end}}
This is what I have in my controller in order to get my expired date and use if in my JavaScript above:
$mytime = Carbon::now();
if(!empty($product->start_discounted && $product->end_discounted)){
$start = $product->start_discounted->format('M d, Y');
$end = $product->end_discounted->format('M d, Y');
}
then I also have my scope code:
$validdiscount = $product->ValidDiscount()->get();
now what I think is that my issue cause by: I get my expire date from
product directly $product->end_discounted while I try to avoid it while I'm using scope which
it does the same carbon thing in my model, not sure! (maybe i should get my $end by scope as well?

You're not using scopes correctly. Scopes are used on query builder, not on an already retrieved model.
For doing this, you just need a regular method:
public function validDiscount() {
return $this->start_discounted <= now()->toDateTimeString()
&& $this->end_discounted >= now()->toDateTimeString();
}
And then in your view, check it like this:
#if($product->validDiscount())
show timer
#endif
And remove the unneeded $validdiscount = $product->ValidDiscount()->get(); (where you're using a query scope on an instance of a model).

You can use javascript/jquery in front end to do it.
When you populate that page, call that js function to check that value like this $(document).ready(function(){ check_timer() })
Then trigger that method again when you timer has expired to update your view(hide promotional price, hide timer & showing actual price)
check_timer function can be like this
function check_timer(){
if(!{{ $validdiscount }}){
//hide your required div
}
}

Related

EventListener wont recognise new buttons

I have only started js recently, so i hope this makes sense..
I have made a simple dynamic form which starts with a table of 4 rows. After the heading row, the remaining 3 rows have +/- symbols which are to add or delete rows as necessary.
The add row functionality is currently working, however, even after assigning the correct class to the new row, the event listener wont work for the new buttons (even thought i have re-assigned the number of buttons within that class).
After adding the row, i re-assign btnAddRows and when logged to the console it is increasing with each row added. I can't figure out why it wont get captured in the for loop?
Thanks
//select elements on DOM
let btnAddRows = document.querySelectorAll('.btnADD');
let myTable = document.querySelector('#SecProp');
let myTableRows = document.querySelector('.tableRows');
for (let i = 0; i < btnAddRows.length; i++) {
btnAddRows[i].addEventListener('click', function () {
console.log(btnAddRows.length);
btnAddRows = document.querySelectorAll('.btnADD');
const rowNum = Number(btnAddRows[i].id.slice(6));
// console.log(rowNum);
// if (rowNum === myTableRows.length - 1) {
// addTableRow(rowNum);
// } else {
addTableRow(rowNum);
// }
btnAddRows = document.querySelectorAll('.btnADD');
myTable = document.querySelector('#SecProp');
myTableRows = document.querySelector('.tableRows');
});
}
const addTableRow = function (rowNum) {
//insert row into table
const addRw = myTable.insertRow(rowNum + 1);
const newRow = myTable.rows[rowNum + 1];
newRow.className = 'tableRows';
console.log(myTable.rows[rowNum + 1], typeof myTable.rows[rowNum + 1]);
const cell1 = newRow.insertCell(0);
const cell2 = newRow.insertCell(1);
const cell3 = newRow.insertCell(2);
const cell4 = newRow.insertCell(3);
const cell5 = newRow.insertCell(4);
cell1.className = 'column1';
cell2.className = 'coordsColumn';
cell3.className = 'coordsColumn';
cell4.className = 'buttons';
cell5.className = 'buttons';
cell1.innerHTML = `<td> ${rowNum + 1}</td>`;
cell2.innerHTML = '<td ><input type = "text" name="" value = ""/><td>';
cell3.innerHTML = '<td ><input type = "text" name="" value = ""/><td>';
cell4.innerHTML = `<td ><button class="btnADD btn btn-success" id="btnADD${
rowNum + 1
}"> + </button>`;
cell5.innerHTML = `<td ><button id="btnDEL${
rowNum + 1
}" class="btnDEL btn btn-success"> -</button>`;
};

how to make a for loop countdown in time format? and how can I put/ code if the user want a specific time they want?

My question: > how to make a for loop countdown in time format? and how can I put/ code if the user wants a specific time they want?
I don't know what's wrong with my reset button...
I just want somebody to help me in the input part because I really don't know how to start my code there. I just don't get the loops. thank you!
function showingLoop() {
for (let counter = 0; counter <= 60; counter += 1) {
setTimeout((`clockInSeconds(${60 - counter})`), counter * 1_000)
}
}
function clockInSeconds(seconds) {
let timeDiv = document.querySelector('#time')
timeDiv.innerHTML = String(seconds)
}
function showingReset() {
document.getElementById('reset').reset();
}
#time {
font-family: 'Red Hat Mono';
font-size: 56px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://fonts.googleapis.com/css2?family=Krona+One&family=Red+Hat+Mono:wght#600&display=swap" rel="stylesheet">
<title>Countdown</title>
</head>
<body>
<div id=hours>
<input type=number>h
</div>
<div id=minutes>
<input type=number>m
</div>
<div id=seconds>
<input type=number>s
</div>
<button onclick="showingLoop()">Start</button>
<button id="reset" onclick="showingReset()">Reset</button>
<div id="time">
</div>
</body>
</html>
Basically you have to create a target date from the user inputs and then refresh the displayed date while the time delta from now to then is > 0.
// Reference to interval
var intervalVar = null;
function showingLoop() {
// Clear interval if not null
if (intervalVar != null) clearInterval(intervalVar);
// Get user input
var element = document.getElementById('hours').getElementsByTagName('input')
const hours = parseInt(element[0].value == "" ? 0 : element[0].value);
element = document.getElementById('minutes').getElementsByTagName('input')
const minutes = parseInt(element[0].value == "" ? 0 : element[0].value);
element = document.getElementById('seconds').getElementsByTagName('input')
const seconds = parseInt(element[0].value == "" ? 0 : element[0].value);
// Parse user input into target date
var tempDate = new Date();
tempDate.setTime(tempDate.getTime() + (hours * 60 * 60 * 1000));
tempDate.setTime(tempDate.getTime() + (minutes * 60 * 1000));
tempDate.setTime(tempDate.getTime() + (seconds * 1000));
var targetDate = tempDate.getTime();
// Create Interval which calls inteself every 1000ms and updates until it reaches target date
intervalVar = setInterval(() => {
var now = new Date().getTime();
// Find delta time between now and target date
var deltaTime = targetDate - now;
// Parse milliseconds into human reable formats
var days = Math.floor(deltaTime / (1000 * 60 * 60 * 24));
var hours = Math.floor((deltaTime % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
var minutes = Math.floor((deltaTime % (1000 * 60 * 60)) / (1000 * 60));
var seconds = Math.floor((deltaTime % (1000 * 60)) / 1000);
// If the count down is finished, clear Interval and write 0s
if (deltaTime < 0) {
clearInterval(intervalVar);
days = hours = minutes = seconds = 0;
}
clockInSeconds(days, hours, minutes, seconds);
}, 1000);
}
function clockInSeconds(days, hours, minutes, seconds) {
let timeDiv = document.querySelector('#time')
timeDiv.innerHTML = days + "d " + hours + "h " + minutes + "m " + seconds + "s ";
}
function showingReset() {
clearInterval(intervalVar);
showingLoop();
}
Note that I replaced setTimeout(...); with setInterval(...);.
I did this because with setTimeout(...); in a for loop you "instantly" queue up every HTML edit and to my knowledge can't quickly just get rid of them all. With the new function it will wait 1000ms between edits and because we are keeping a reference to it we can easily reset it.
The idea for using setInterval(..); originates from w3school. Check it out if interested!
EDIT:
replaced original code using async and await with setInterval(...);
Forgot to give credits

Apply different DIV in For each loop

I am working on MVC 5. Using WEB API, fetch the data now it is time to apply the HTML PAGE design and CSS.
#foreach (var item in Model)
{
if (Model.First() == item)
{
///APPLY FIRST RECORD CSS:- Works FINE
}
else {
<div class="row">
<div class="col-sm-4">
</div>
</div>
}
}
In the else portion, every time it generates the new ROW for a SINGLE record. But I am interested to display record 2 3 4 in SECOND ROW. 5 6 7 Record in the THIRD ROW and so on.
If it is the first item, open a div and then put the items in it. Close the div when the number of columns is 3 or close the div if the item is at the end of the list.
The following algorithm does this for you
#{
int i = 0;
int columnCounter = 1;
bool newRow = false;
}
#foreach (var item in Model)
{
//add and open div row
if (i == 0 || newRow)
{
newRow = false;
#:<div class="row" style="border:2px solid red;">
}
<div class="col-md-4" style="padding:0;">
<div style="height:40px;background:#f6f6f6;width:100%;text-align:center;">
<span>Column #i</span>
</div>
</div>
//close div row if column count == 3 or reach of end list
if (columnCounter == 3 || i == Model.Count - 1)
{
newRow = true;
columnCounter = 1;
#:</div>
}
else
{
columnCounter = columnCounter + 1;
}
}
result:

Validate an input field in order to be unique and non duplicate in jQuery mobile

In my jQuery mobile app I have an alarm service the user enter number of alarms Per day , once the user enters the number of alarms lets say 3 , app will create 3 input fields for time , when the user clicks save button to save data i need to validate all the created input time fields so the entered time not equal the current time, and be unique there is no alarms at this time , I have solved it by the following code but the problem is that when the user enter a unique time " a non repeated time" I change the exist value from true to false but it didn't enter and execute this condition
else if (exist == false && $(this).attr('value') != currentTime ) directly "once " the exist value is updated ,I need to click the save button again in order to make the code know that the exist value is changed , and continue saving the alarm data in the DB .
How can i solve this problem ? please help me ...
<body>
<div data-role="page" id="Alarm">
<div data-role="header" ></div>
<div data-role="content" >
<form>
<input type="number" id="AlarmTimes"/>
<label for="AlarmTimes" > Number of alarms Per day </lable>
<div id="timeFields" style="display:none;" >
</div>
<div>
<input type="button" id="SaveBtn" value="Save Alarm "/></div>
</form>
</div>
</div>
</body>
javascript
var alarm_TimesNum;
var exist = true;
var ExistAlarmTimesArr = [];
$('#AlarmTimes').on('keyup' , function(){
alarm_TimesNum = $('#AlarmTimes').attr('value');
var timeFields = $('#timeFields');
if(timeFields.children().length != 0 )
{
timeFields.empty();
timeFields.hide();
}
for( var i=1 ; i<= alarm_TimesNum ;i++)
{
timeFields.append($( '<div class="ui-grid-a" ><div class="ui-block-a"> <input type="time" name="alarmTime" class="AlarmTime" /></div>'
+'<div class="ui-block-b" ><label for=" alarmTime" ><font size="5px" style="font- weight: normal;" class="Time_label"> Time:: </font></label></div></div>'));
timeFields.trigger('create');
}
timeFields.show();
});
db.transaction(getExistAlarmsTime,transError,transSuccess);
$('#SaveBtn').on('click',function(){
$('.AlarmTime').each(function(i){
if( $(this).attr('value') == currentTime || $.trim( $(this).attr('value')).length ==0 )
{
$('.Time_label').each(function(j){ if(j==i){ $(this).addClass('missing');} });
if(i==0){ alert('Enter time for alarm 1 '); }
else if(i==1){alert('Enter time for alarm 2 '); }
else if(i==2){alert('Enter time for alarm 3 '); }
}
else if( $(this).attr('value') != currentTime && exist == true )
{
for( var k=0;k<ExistAlarmTimesArr.length;k++)
{
if( $(this).attr('value') == ExistAlarmTimesArr[k])
{
$('.Time_label').each(function(j){ if(j==i){ $(this).addClass('missing');} });
if(i==0){alert( 'Enter Another Time for alarm 1 you have another alarm at this time '); }
else if(i==1){ alert( 'Enter Another Time for alarm 2 you have another alarm at this time '); }
else if(i==2){ alert( 'Enter Another Time for alarm 3 you have another alarm at this time '); }
exist = true;
break;
}
else { exist = false; }
}
}
else if (exist == false && $(this).attr('value') != currentTime )
{
$('.Time_label').each(function(j){ if(j==i){ $(this).removeClass('missed');} });
NotifTime = $(this).attr('value');
TimeArr[j] = NotifTime;
j= j+1 ;
count ++;
}
});
// save data in the DB
});
function getExistAlarmsTime(tx)
{
tx.executeSql("SELECT Time FROM AlarmTBL ",[],AlarmTimeExist,transError);
}
function AlarmTimeExist(tx,result)
{
for(var j=0;j< result.rows.length; j++)
{
var row = result.rows.item(j);
ExistAlarmTimesArr[j] = row['Time'];
}
}
I think the issue could just be the use of .attr('value'), try subbing it for .val() instead. I think that will fix your issues.

Asynchronous progress bar on a loop

Using MVC3, C#, jQuery, Ajax ++
My html
<div>
Start Long Running Process
</div>
<br />
<div id="statusBorder">
<div id="statusFill">
</div>
</div>
The javascript part part of the html
var uniqueId = '<%= Guid.NewGuid().ToString() %>';
$(document).ready(function (event) {
$('#startProcess').click(function () {
$.post("SendToDB/StartLongRunningProcess", { id: uniqueId,
//other parameters to be inserted like textbox
}, function () {
$('#statusBorder').show();
getStatus();
});
event.preventDefault;
});
});
function getStatus() {
var url = 'SendToDB/GetCurrentProgress';
$.get(url, function (data) {
if (data != "100") {
$('#status').html(data);
$('#statusFill').width(data);
window.setTimeout("getStatus()", 100);
}
else {
$('#status').html("Done");
$('#statusBorder').hide();
alert("The Long process has finished");
};
});
}
This is the controller.
//Some global variables. I know it is not "good practice" but it works.
private static int _GlobalSentProgress = 0;
private static int _GlobalUsersSelected = 0;
public void StartLongRunningProcess(string id,
//other parameters
)
{
int percentDone = 0;
int sent = 0;
IEnumerable<BatchListModel> users;
users = new UserService(_userRepository.Session).GetUsers(
//several parameters)
foreach (var c in users)
{
var usr = _userRepository.LoadByID(c.ID);
var message = new DbLog
{
//insert parameters
};
_DbLogRepository.Save(message);
sent++;
double _GlobalSentProgress = (double)sent / (double)_GlobalUsersSelected * 100;
if (percentDone < 100)
{
percentDone = Convert.ToInt32(_GlobalSentProgress);
}
//this is supposed to give the current progress to the "GetStatus" in the javascript
public int GetCurrentProgress()
{
return _GlobalSentProgress;
}
Right now the div with the progress bar never shows up. It is honestly kind of broken. But I hope you understand my logic.
In the loop doing the insertions, I do have this calculation:
double _GlobalSentProgress = (double)sent / (double)_GlobalUsersSelected * 100;
Then I convert the _GlobalSentProgress to a normal int in the
percentDone = Convert.ToInt32(_GlobalSentProgress);
so it no longer has any decimals any longer.
If only I could send this "percentDone" or "_GlobalSentProgress" variable (wich is showing perfectly how many percent I have come in the insertion) asynchronous into the "data" variable in javascript every single time it loops, it would work. Then "data" would do it's "statusFill" all the time and show the bar correctly. This is the logic I use.
I believe the word thrown around in order to accomplish this is "asynchronous". I have looked at 2 very promising guides but I was not able to make it work with my loop.
Anyone have a suggestion on how I can do this?
Edit 2: Outer div is named statusBorder not status.

Resources