PageSourceSearch

https://shirdisaiparivaar.org/wp-content/plugins/mr-rental-request-manager/assets/erm-frontend.js?ver=3.3.33

js shirdisaiparivaar.org collected 2026-10-06 21:50:41 UTC 12,549 bytes, 496 lines download raw bytes

1(function ($) {
2function initDatePicker() {
3    $(".event-date").each(function () {
4
5        if ($(this).hasClass("hasDatepicker")) {
6            $(this).datepicker("destroy");
7        }
8
9        $(this).datepicker({
10            dateFormat: "mm/dd/yy",
11            changeMonth: true,
12            changeYear: true
13        });
14
15    });
16}
17document.addEventListener("DOMContentLoaded", function () {
18
19    // Disable past dates
20    let today = new Date().toISOString().split('T')[0];
21    document.querySelectorAll(".event-date").forEach(function (input) {
22        input.setAttribute("min", today);
23    });
24
25});
26
27let blockedSlots = [];
28
29function loadBlockedSlots() {
30    $.post(erm_ajax.ajax_url, {
31        action: 'erm_get_blocked_slots'
32    }, function(resp) {
33        if(resp.success){
34            blockedSlots = resp.data;
35        }
36    });
37}
38
39loadBlockedSlots();
40
41
42$(document).ready(function () {
43
44 
45	initDatePicker();
46    /* -------------------------------
47       ADD / REMOVE EVENT ROW
48    ---------------------------------*/
49
50    $('#erm_add_row').on('click', function () {
51
52        if ($('.erm-event-wrapper').length >= 2) {
53            alert('Only one alternate date allowed');
54            return;
55        }
56    
57        var wrapper = $('.erm-event-wrapper:first').clone();
58    
59        // Clear all values
60        wrapper.find('input').val('');
61    
62        // Reset datepicker
63        wrapper.find('.event-date')
64            .removeClass('hasDatepicker')
65            .removeAttr('id');
66    
67        // Change label
68        wrapper.find('.erm-row-label').text('Alternate Date');
69    
70        // Show remove button ONLY on alternate row
71        wrapper.find('.erm-remove-column').show();
72    
73        // Add alternate row
74        $('#erm_event_rows').append(wrapper);
75    
76        // Reinitialize datepicker
77        initDatePicker();
78    });
79    
80   
81
82    $(document).on('click', '.erm-remove-row', function () {
83
84        if ($('.erm-event-wrapper').length > 1) {
85            $(this).closest('.erm-event-wrapper').remove();
86        }
87
88    });
89    
90    /* --------------------------------
91   TIME VALIDATION HELPERS
92--------------------------------- */
93
94function isValidTime(time) {
95
96    if (!/^\d{2}:\d{2}$/.test(time)) {
97        return false;
98    }
99
100    var parts = time.split(':');
101
102    var hours = parseInt(parts[0], 10);
103    var minutes = parseInt(parts[1], 10);
104
105    return (
106        hours >= 0 &&
107        hours <= 23 &&
108        minutes >= 0 &&
109        minutes <= 59
110    );
111}
112
113function timeToMinutes(time) {
114
115    if (!isValidTime(time)) {
116        return null;
117    }
118
119    var parts = time.split(':');
120
121    return (
122        parseInt(parts[0], 10) * 60 +
123        parseInt(parts[1], 10)
124    );
125}
126
127
128/* --------------------------------
129   TIME INPUT
130   HH:MM
131--------------------------------- */
132
133$(document).on('input', '.event-time', function () {
134
135    var input = this;
136
137    // Numbers only
138    var value = input.value.replace(/\D/g, '');
139
140    // Maximum 4 digits
141    value = value.substring(0, 4);
142
143    // Add colon automatically
144    if (value.length >= 3) {
145        value = value.substring(0, 2) + ':' + value.substring(2);
146    }
147
148    input.value = value;
149});
150
151
152/* --------------------------------
153   VALIDATE TIME ON BLUR
154--------------------------------- */
155
156$(document).on('blur', '.event-time', function () {
157
158    var input = this;
159    var value = input.value.trim();
160
161    if (!value) {
162        return;
163    }
164
165    if (!isValidTime(value)) {
166
167        alert('Please enter a valid time between 00:00 and 23:59.');
168
169        input.value = '';
170        input.focus();
171
172        return;
173    }
174
175    var row = $(input).closest('.erm-event-row');
176
177    var start = row
178        .find('input[name="event_start[]"]')
179        .val();
180
181    var end = row
182        .find('input[name="event_end[]"]')
183        .val();
184
185    /*
186     * If both times are valid,
187     * make sure end is after start.
188     */
189    if (isValidTime(start) && isValidTime(end)) {
190
191        if (timeToMinutes(end) <= timeToMinutes(start)) {
192
193            alert('End time must be after start time.');
194
195            row.find('input[name="event_duration[]"]').val('');
196
197            /*
198             * Clear only the end time if the
199             * user has entered an invalid range.
200             */
201            if ($(input).attr('name') === 'event_end[]') {
202                input.value = '';
203                input.focus();
204            }
205
206            return;
207        }
208    }
209});
210
211
212/* --------------------------------
213   AUTO CALCULATE DURATION
214--------------------------------- */
215
216$(document).on(
217    'input change blur',
218    'input[name="event_start[]"], input[name="event_end[]"]',
219    function () {
220
221        var row = $(this).closest('.erm-event-row');
222
223        var start = row
224            .find('input[name="event_start[]"]')
225            .val();
226
227        var end = row
228            .find('input[name="event_end[]"]')
229            .val();
230
231        var startMinutes = timeToMinutes(start);
232        var endMinutes = timeToMinutes(end);
233
234        /*
235         * Don't calculate until both
236         * values are valid.
237         */
238        if (startMinutes === null || endMinutes === null) {
239
240            row.find('input[name="event_duration[]"]').val('');
241
242            return;
243        }
244
245        /*
246         * End must be later than start.
247         */
248        if (endMinutes <= startMinutes) {
249
250            row.find('input[name="event_duration[]"]').val('');
251
252            return;
253        }
254
255        var diff = endMinutes - startMinutes;
256
257        var hours = Math.floor(diff / 60);
258        var minutes = diff % 60;
259
260        var durationText = '';
261
262        if (hours > 0) {
263            durationText += hours + 'h ';
264        }
265
266        if (minutes > 0) {
267            durationText += minutes + 'm';
268        }
269
270        row.find('input[name="event_duration[]"]')
271            .val(durationText.trim());
272});
273
274    
275
276    /* -------------------------------
277       BLOCKED TIME VALIDATION
278    ---------------------------------*/
279
280   // Convert mm/dd/yyyy → Date object safely
281function createDate(dateStr, timeStr) {
282
283    var parts = dateStr.split("/"); // mm/dd/yyyy
284
285    var month = parseInt(parts[0], 10) - 1; // JS month is 0-indexed
286    var day   = parseInt(parts[1], 10);
287    var year  = parseInt(parts[2], 10);
288
289    var timeParts = timeStr.split(":");
290    var hours   = parseInt(timeParts[0], 10);
291    var minutes = parseInt(timeParts[1], 10);
292
293    return new Date(year, month, day, hours, minutes, 0);
294}
295
296        
297
298$(document).on('change', 'input[name="event_date[]"], input[name="event_start[]"], input[name="event_end[]"]', function () {
299
300    var row = $(this).closest('.erm-event-row');
301
302    var selectedDate = row.find('input[name="event_date[]"]').val();
303    var startTime    = row.find('input[name="event_start[]"]').val();
304    var endTime      = row.find('input[name="event_end[]"]').val();
305
306    if (!selectedDate || !startTime || !endTime) return;
307
308    var userStart = createDate(selectedDate, startTime);
309    var userEnd   = createDate(selectedDate, endTime);
310
311    // Handle overnight user booking
312    if (userEnd <= userStart) {
313        userEnd.setDate(userEnd.getDate() + 1);
314    }
315
316    var isBlocked = false;
317    var reason = '';
318
319    for (var i = 0; i < blockedSlots.length; i++) {
320
321        var slot = blockedSlots[i];
322
323        // Convert blocked slot date (yyyy-mm-dd) properly
324        var blockDateParts = slot.date.split("-");
325        var blockYear  = parseInt(blockDateParts[0], 10);
326        var blockMonth = parseInt(blockDateParts[1], 10) - 1;
327        var blockDay   = parseInt(blockDateParts[2], 10);
328
329        var fromParts = slot.from_time.split(":");
330        var toParts   = slot.to_time.split(":");
331
332        var blockStart = new Date(
333            blockYear,
334            blockMonth,
335            blockDay,
336            parseInt(fromParts[0], 10),
337            parseInt(fromParts[1], 10)
338        );
339
340        var blockEnd = new Date(
341            blockYear,
342            blockMonth,
343            blockDay,
344            parseInt(toParts[0], 10),
345            parseInt(toParts[1], 10)
346        );
347
348        // Handle overnight block
349        if (blockEnd <= blockStart) {
350            blockEnd.setDate(blockEnd.getDate() + 1);
351        }
352
353        // Check overlap
354        if (userStart < blockEnd && userEnd > blockStart) {
355            isBlocked = true;
356            reason = slot.reason || "This time slot is unavailable.";
357            break; // stop loop immediately
358        }
359    }
360
361    if (isBlocked) {
362
363        alert("The chosen time conflicts with a blocked schedule. Please select another available time slot to complete your reservation.\nReason: " + reason);
364
365        row.find('input[name="event_start[]"]').val('');
366        row.find('input[name="event_end[]"]').val('');
367        row.find('input[name="event_duration[]"]').val('');
368    }
369
370});
371
372    /* -------------------------------
373       FINAL FORM SUBMIT
374    ---------------------------------*/
375
376    $('#ermForm').on('submit', function (e) {
377
378        e.preventDefault();
379
380        var form = this;
381
382        // Trigger HTML5 validation
383        if (!form.checkValidity()) {
384            form.classList.add('was-validated');
385            return;
386        }
387
388        // Extra custom validation for event rows
389        var isValid = true;
390
391        $('.erm-event-row').each(function () {
392
393            var date  = $(this).find('input[name="event_date[]"]').val();
394            var start = $(this).find('input[name="event_start[]"]').val();
395            var end   = $(this).find('input[name="event_end[]"]').val();
396
397                if (!date || !start || !end) {
398                    isValid = false;
399                    alert('Please fill all event date and time fields.');
400                    return false;
401                }
402                
403                if (!isValidTime(start) || !isValidTime(end)) {
404                    isValid = false;
405                    alert('Please enter time in HH:MM format, for example 09:00 or 17:30.');
406                    return false;
407                }
408
409                if (timeToMinutes(end) <= timeToMinutes(start)) {
410                    isValid = false;
411                    alert('End time must be after start time.');
412                    return false;
413                }
414
415        });
416
417        if (!isValid) return;
418
419        var data = $(this).serializeArray();
420        data.push({ name: 'erm_nonce', value: erm_ajax.nonce });
421        data.push({ name: 'action', value: 'erm_submit' });
422
423        $('#erm_response').html('<div class="alert alert-info">Submitting…</div>');
424
425        $.ajax({
426            type: "POST",
427            url: erm_ajax.ajax_url,
428            data: data,
429            dataType: "json",
430            success: function (resp) {
431
432                if (resp.success) {
433
434                    $('#erm_response').html('<div class="alert alert-success">' + resp.data + '</div>');
435
436                    $('#ermForm')[0].reset();
437                    $('#ermForm').removeClass('was-validated');
438
439                } else {
440
441                    $('#erm_response').html('<div class="alert alert-danger">' + resp.data + '</div>');
442
443                }
444            },
445            error: function () {
446
447                $('#erm_response').html('<div class="alert alert-danger">Something went wrong. Please try again.</div>');
448
449            }
450        });
451
452    });
453
454    if ($('#erm-user-dashboard').length) {
455
456        $.post(erm_ajax.ajax_url, {
457            action: 'erm_user_dashboard',
458            nonce: erm_ajax.nonce
459        }, function(res){
460
461            if(res.success){
462
463                let stats = res.data.stats;
464
465                $('#erm-stats').html(`
466                    <div class="col">Total: ${stats.total}</div>
467                    <div class="col text-success">Approved: ${stats.approved}</div>
468                    <div class="col text-warning">Pending: ${stats.pending}</div>
469                    <div class="col text-danger">Rejected: ${stats.rejected}</div>
470                `);
471
472                let rows = '';
473
474                res.data.list.forEach(item => {
475                    rows += `
476                        <tr>
477                            <td>${item.id}</td>
478                            <td>${item.name}</td>
479                            <td>${item.event}</td>
480                            <td>${item.confirmed}</td>
481                            <td>${item.status}</td>
482                            <td>${item.submitted}</td>
483                        </tr>
484                    `;
485                });
486
487                $('#erm-user-table').html(rows);
488            }
489        });
490
491    }
492
493
494});
495
496})(jQuery);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.