PageSourceSearch

https://samadcottageonline.co.uk/js/fmo_menu.js?1784821479

js samadcottageonline.co.uk collected 2026-09-24 12:41:22 UTC 87,497 bytes, 2,371 lines download raw bytes

1$(document).ready(function () {
2
3    if($('#shopHeaderContainer div.tag--closed').length) {
4        window.modals.TakeawayClosed.show();
5    }
6
7    // See if there is a hash change. This helps to handle the back button on the mobile site when going through the checkout
8    $(window).on('hashchange', function () {
9        // If there is no hash show the menu
10        var currHash = window.location.hash;
11
12        // Remove any # just incase some phone browsers leave them on
13        currHash = currHash.replace('#', '');
14
15        switch (currHash) {
16            case 'options-and-extras':
17                // Hide these
18                $('#yourOrder').addClass('hidden-phone');
19                $('#phoneCartFooter').addClass('hidden-phone');
20
21                // Show these
22                $('#menuHolder').removeClass('hidden-phone');
23                $('#options').show();
24                $('#menu').hide();
25                break;
26
27            case 'checkout':
28                // Hide these
29                $('#menuHolder').addClass('hidden-phone');
30                $('#phoneCartFooter').addClass('hidden-phone');
31
32                // Show these
33                $('#yourOrder').removeClass('hidden-phone');
34                $('#options').hide();
35                $('#menu').hide();
36                break;
37
38            default:
39                // Hide these
40                $('#yourOrder').addClass('hidden-phone');
41
42                // Show these
43                $('#menuHolder').removeClass('hidden-phone');
44                $('#phoneCartFooter').removeClass('hidden-phone');
45                $('#options').hide();
46                $('#menu').show();
47        }
48
49        return false;
50    });
51
52    $(document).on('focus', '.textInput input', function (e) {
53        $(e.target).closest('.textInput').removeClass('iconError');
54    });
55
56    let offerPos = 0;
57    let offerAnimating = false;
58    $(document).on('click', '.offers-ribbon .nav.left', function (e) {
59        if (!offerAnimating) {
60            const scroll = $('.offers-ribbon .scroll');
61            const offers = $('.offers-ribbon .offer');
62            const totalOffers = offers.length;
63            if (offerPos === 0) {
64                offerPos = totalOffers - 4;
65                scroll.scrollLeft(
66                    scroll.scrollLeft() + offers.eq(offerPos).position().left,
67                );
68            }
69            const nextOffer = offerPos - 1;
70            const offerOffset = offers.eq(nextOffer).position();
71
72            offerAnimating = true;
73            scroll.animate({
74                scrollLeft: scroll.scrollLeft() + offerOffset.left,
75            }, 450, function () {
76                offerAnimating = false;
77            });
78
79            offerPos = nextOffer;
80        }
81    });
82
83    $(document).ready(function () {
84        const offers = $('.offers-ribbon .offer');
85        const totalOffers = offers.length;
86        if (totalOffers > 3) {
87            offers.clone().slice(0, 4).map(function () {
88                $(this).addClass('hidden-phone hidden-tablet');
89                return this;
90            }).appendTo($('.offers-ribbon .scroll'));
91            $('.offers-ribbon .nav').css('display', 'flex');
92        }
93    });
94
95    $(document).on('click', '.offers-ribbon .nav.right', function (e) {
96        if (!offerAnimating) {
97            const scroll = $('.offers-ribbon .scroll');
98            const offers = $('.offers-ribbon .offer');
99            const totalOffers = offers.length;
100            const nextOffer = offerPos + 1;
101            const offerOffset = offers.eq(nextOffer).position();
102
103            offerAnimating = true;
104            scroll.animate({
105                scrollLeft: scroll.scrollLeft() + offerOffset.left,
106            }, 450, function () {
107                offerAnimating = false;
108                if (nextOffer === totalOffers - 4) {
109                    scroll.scrollLeft(0);
110                    offerPos = 0;
111                }
112            });
113
114            offerPos = nextOffer;
115        }
116    });
117
118    $(document).on('keypress', '#discount-code', function (e) {
119        if (e.keyCode === 13) {
120            $('#discount-code-apply-button').trigger('click');
121            $(e.target).blur();
122        }
123    })
124
125    $(document).on('click', '#discount-code-apply-button', function (e) {
126        e.preventDefault();
127        const field = $('#discount-code');
128        const fieldValue = field.val().toUpperCase();
129        const textInput = field.closest('.textInput');
130
131        // Make the field uppercase
132        field.val(fieldValue);
133
134        $.ajax({
135            type: 'POST',
136            url: 'checkout/discount_code?ts=' + (new Date().getTime()),
137            data: {
138                'discountCode': fieldValue,
139            },
140            beforeSend: function () {
141                $('#orderSummary .overlay').show();
142                textInput
143                    .removeClass('iconError')
144                    .addClass('iconBusy');
145                disableButtons();
146            },
147            success: function (response) {
148                if (response.error !== undefined) {
149                    textInput.addClass('iconError').find('.textInputError').text(response.error);
150                } else {
151                    updateBasket(response);
152                }
153            },
154            complete: function () {
155                $('#orderSummary .overlay').hide();
156                textInput.removeClass('iconBusy');
157                enableButtons();
158            },
159        })
160    })
161
162    // Handle the clicking of the Update PC button so that they can change their postcode
163    $(document).on('click', '.applied-container #delete', function (e) {
164        e.preventDefault();
165        const discountCode = $(e.target).parent().data('id');
166
167        $.ajax({
168            type: 'DELETE',
169            url: 'checkout/discount_code/' + discountCode + '?ts=' + (new Date().getTime()),
170            beforeSend: function () {
171                $('#orderSummary .overlay').show()
172                disableButtons()
173            },
174            success: function (response) {
175                updateBasket(response)
176            },
177            complete: function () {
178                $('#orderSummary .overlay').hide()
179                enableButtons()
180            },
181        })
182    });
183
184    // Handle the clicking of the Update PC button so that they can change their postcode
185    $(document).on('click', '#changeDeliveryPc', function (e) {
186        e.preventDefault();
187        $('#deliveryPcHolder').hide();
188        $('#updateFullPostcodeHolder').show();
189        $('#validate_pc').focus();
190    });
191
192    // Handle the update of the Postcode
193    $(document).on('click', '#updateFullPostcodeSubmit', function (e) {
194        e.preventDefault();
195
196        const validatePc = $('#validate_pc');
197        validatePc.val(validatePc.val().toUpperCase());
198        const postcode = validatePc.val().replace(/\s/g, '');
199
200        if (!validPostcode(postcode)) {
201            $('#missingPostcodeAlert').html('Please enter a full valid UK post code.').show();
202        } else {
203            $('#missingPostcodeAlert').hide();
204            updateDeliveryPostcode(postcode);
205        }
206    });
207
208    // Hide the reviews
209    $("#reviewsDialog").dialog({
210        autoOpen: false,
211        title: "Reviews",
212        maxHeight: 600,
213        modal: true,
214        buttons: [{
215            text: "Ok", click: function () {
216                $(this).dialog("close");
217            }
218        }]
219    });
220
221    // See if the takeaway is open or closed. If closed show a dialog
222    // if ($('#openClosed').text().toLowerCase() === 'closed') {
223    //     window.scrollTo(0, 0);
224    //     $("#closedDialog").dialog({
225    //         autoOpen: true,
226    //         title: "Closed",
227    //         maxHeight: 600,
228    //         maxWidth: 300,
229    //         modal: true,
230    //         buttons: [{
231    //             text: "Ok", click: function () {
232    //                 $(this).dialog("close");
233    //             }
234    //         }]
235    //     });
236    // }
237
238    // The reviews dialog initialization
239    $('.openReviewsDialog').click(function (e) {
240        e.preventDefault();
241        $("#reviewsDialog").dialog("open");
242    });
243
244    // Bind a resize event so we can update cart total positions if needed
245    $(window).on('resize scroll', function () {
246        updateBasketPosition();
247    });
248
249    $(document).on('click', '#backToTopLink', function (e) {
250        e.preventDefault();
251        $(window).scrollTop(0);
252    });
253
254    // Phone Expanding Category Handler
255    $('.catTitle').click(function () {
256        // Toggle the row
257        var productsRow = $(this).nextAll('.catExpander').first();
258
259        productsRow.toggleClass(
260            'hidden-phone hidden-tablet',
261            !productsRow.hasClass('hidden-phone')
262        )
263    });
264
265    // Phone Checkout Button CLick
266    $(document).on('click', '#phoneViewCartButton', function (e) {
267        e.preventDefault();
268
269        // Add a hash to the url so we can go back in the browser if we are in phone mode
270        window.location.hash = 'checkout';
271
272        $('html, body').animate({scrollTop: 0}, 0);
273    });
274
275    // If the phone back to add items is clicked then hide the cart and show the menu again
276    $(document).on('click', '.phoneHideCartButton', function (e) {
277        e.preventDefault();
278
279        window.history.back();
280
281        // Scroll to top
282        $('html, body').animate({scrollTop: 0}, 0);
283    });
284
285    function changeOrderType(orderType) {
286
287        // Set the global field
288        $('#type').val(orderType);
289
290        // Update the session via ajax call
291        $.ajax({
292            type: 'POST',
293            url: 'update_type?ts=' + (new Date().getTime()),
294            data: {
295                "orderType": orderType
296            },
297            beforeSend: function () {
298                $('#orderSummary .overlay').show();
299                disableButtons();
300            },
301            success: function (response) {
302                updateBasket(response);
303                if (orderType === 'd') {
304                    $('#deliveryTab').show();
305                    $('#collectionTab').hide();
306                    $('.catTitle.type-collection, .menuLink.type-collection').addClass('disabled');
307                    $('.catTitle.type-delivery, .menuLink.type-delivery').removeClass('disabled');
308                } else {
309                    $('#deliveryTab').hide();
310                    $('#collectionTab').show();
311                    $('.catTitle.type-delivery, .menuLink.type-delivery').addClass('disabled');
312                    $('.catTitle.type-collection, .menuLink.type-collection').removeClass('disabled');
313                }
314            },
315            complete: function () {
316                $('#orderSummary .overlay').hide();
317                enableButtons();
318            }
319        });
320    }
321
322    // If URL param is set, change the order type (collection OR delivery)
323    const queryString = window.location.search;
324    const urlParams = new URLSearchParams(queryString);
325    if (urlParams.has('order_method')) {
326        const orderType = urlParams.get('order_method') === 'delivery' ? 'd' : 'c';
327        changeOrderType(orderType);
328    }
329
330    // If order Type changes we need to update the session
331    $(document).on('change', '#basket input[name=orderTypePicker]', function () {
332        changeOrderType($(this).val());
333    });
334
335    // Validate the checkout
336    $(document).on('submit', '#basket #checkoutForm', function () {
337
338        //check basket is valid first (collection only or delivery only items)
339        var orderType = $('#type').val();
340        if (orderType && orderType !== '') {
341            if (invalidBasketMenu(orderType)) {
342                // Scroll back to the top
343                $('html, body').animate({
344                    scrollTop: $("#orderSummary").offset().top
345                }, 500);
346                return false;
347            }
348        }
349
350        if (orderType === '') {
351            $('#validate_post_code').css('border', '4px solid #ED1C24');
352            // Scroll back to the top
353            $('html, body').animate({
354                scrollTop: $("#validate_post_code").offset().top
355            }, 500);
356            return false;
357        }
358
359        // Check that there is a order type selected.
360        if ($('#basket input[name="orderTypePicker"]').val() == '') {
361            alert('Please Select Order Type');
362            return false;
363        }
364
365        var minOrderValue = parseFloat($('#min_delivery').val());
366        var minOrderValueCollection = parseFloat($('#min_collection').val());
367        var cartTotal = parseFloat($('#basket_total').val());
368
369        // Validate if it is delivery
370        if (orderType === 'd') {
371            // If there is a min order value then we need to check that the cart total is higher and there is no minimum order
372            if (cartTotal < minOrderValue) {
373                alert('Your order subtotal does not meet the minimum value of £' + minOrderValue.toFixed(2) + ' for delivery.');
374                return false;
375            }
376        } else {
377            // A new minimum collection order value.
378            if (cartTotal < minOrderValueCollection) {
379                alert('Your order subtotal does not meet the minimum value of £' + minOrderValueCollection.toFixed(2) + ' for collection.');
380                return false;
381            }
382        }
383
384        // If success, we need to show the spinner
385        $('#submit-ajax-load').show();
386        disableButtons();
387        window.location.href = 'checkout/loginform';
388        return false;
389    });
390
391    $(document).on('click', '.editExtras', function (e) {
392        e.preventDefault();
393
394        showOptionsAndExtras({
395            'basket-item-id': $(e.target).data('basket-item-id')
396        });
397    });
398
399    /**
400     * Options and extras screen
401     */
402    // Handle the adding of the options to a product
403    $(document).on('click', '#addProductWithOptions', function (e) {
404        e.preventDefault();
405
406        // Now loop through the options getting selected text
407        var options = $('#selectOptionsAndExtras').find('select');
408        var cont = true; // Used to make the form not submit.
409
410        // Check to see if the option value is not empty ie. they have chosen all options.
411        $.each(options, function (i, option) {
412            if ($(option).find("option:selected").val() === '') {
413                $('#optionsMissing').show();
414                cont = false;
415                return false;
416            }
417        });
418
419        if (cont) {
420            $('#selectOptionsAndExtras').submit();
421        }
422    });
423
424    // Handles the option form submit
425    $(document).on('submit', "#selectOptionsAndExtras", function (ev) {
426        ev.preventDefault();
427        addToCart($(this).serialize());
428    });
429
430    // Click to handle the leaving of the options screen
431    $(document).on('click', '#leaveOptions', function () {
432        window.history.back();
433    });
434
435    $(document).on('click', '#options .quantity .minus', function () {
436        const quantityField = $('#quantity');
437        const quantityHtml = $('#options .quantity .value');
438        let currentValue = parseInt('0' + quantityField.val(), 10);
439
440        if (currentValue > 1) {
441            currentValue--;
442            quantityField.val(currentValue);
443            quantityHtml.html(currentValue);
444        }
445    });
446
447    $(document).on('click', '#options .quantity .plus', function () {
448        const quantityField = $('#quantity');
449        const quantityHtml = $('#options .quantity .value');
450        let currentValue = parseInt('0' + quantityField.val(), 10);
451
452        if (currentValue < 21) {
453            currentValue++;
454            quantityField.val(currentValue);
455            quantityHtml.html(currentValue);
456        }
457    });
458
459
460    // If a menu link is clicked hide options show the menu
461    $('.menuLink').click(function () {
462        $('#options').hide();
463        $('#menu').show();
464    });
465
466    $('.menuAddToBasket').click(function () {
467        updateBasketPosition();
468
469        // Get the data out from the product that add was clicked on
470        var productId = $(this).data("id");
471        var productName = $(this).data("name");
472        var parentId = $(this).data("parentid");
473        var productPrice = $(this).data("price");
474        var productCategory = $(this).data("category");
475        var options = $(this).data("options");
476        var extras = $(this).data("extras");
477
478        if (!(parentId && parentId !== "")) {
479            parentId = ""
480        }
481
482        // If there are options show the options list
483        if (options === 1 || extras === 1) {
484            showOptionsAndExtras($(this).data());
485        } else {
486            // Perform the ajax call to add the product to basket and then update the totals etc.
487            addToCart({
488                "prd_id": productId,
489                "prd_cat": productCategory,
490                "prd_parent": parentId ? parentId : ""
491            });
492        }
493    });
494
495    function addToCart(data) {
496        $.ajax({
497            type: 'POST',
498            url: 'add_to_cart?ts=' + (new Date().getTime()),
499            data: data,
500            beforeSend: function () {
501                $('#orderSummary .overlay').show();
502                disableButtons();
503            },
504            success: function (response) {
505                updateBasket(response);
506                updateBasketPosition();
507
508                if (window.location.hash !== '') {
509                    window.history.back();
510                }
511            },
512            error: function () {
513                alert('Unable to add product please try again');
514            },
515            complete: function () {
516                $('#orderSummary .overlay').hide();
517                enableButtons();
518            }
519        });
520    }
521
522    // Add to cart click
523    function showOptionsAndExtras(data) {
524        const basketItemId = data['basket-item-id'] || '';
525        const productId = data.id || '';
526
527        // Clear any previous options and extras
528        $('#optionsAndExtras').html('');
529
530        // Hide the menu and show options screen
531        window.location.hash = 'options-and-extras';
532
533        // Put user back at top of the screen
534        $('html, body').animate({
535            scrollTop: $('.shop-details-bottom').position().top
536        }, 400);
537
538        // Go get the extras screen
539        $.ajax({
540            type: 'POST',
541            url: 'get_options_and_extras?ts=' + (new Date().getTime()),
542            data: {
543                "prd_id": productId,
544                "basket_item_id": basketItemId
545            },
546            beforeSend: function () {
547                $('#optionsLoader').show();
548                disableButtons();
549            },
550            success: function (response) {
551                if (response.error !== undefined) {
552                    alert('Unable to load product details: ' + response.error);
553                    return;
554                }
555
556                $('#optionsAndExtras').html(response.data);
557            },
558            complete: function () {
559                $('#optionsLoader').hide();
560                enableButtons();
561            }
562        })
563    }
564
565    // The search submit function
566    $('#post_code_search').submit(function (e) {
567        e.preventDefault();
568        searchLocations(); // Call the search function.
569    });
570
571    // Handle the click of the closed view shops
572    $('#viewClosedShopsDesktopContainer').click(function (e) {
573        e.preventDefault();
574        $('#closedShopsDesktopContainer').toggle();
575    });
576
577    // Handle a review link click
578    $('.reviews').click(function (e) {
579        e.preventDefault();
580        var shopId = $(this).data('wid');
581
582        $.ajax({
583            type: "POST",
584            url: '/takeaways/get_reviews?ts=' + (new Date().getTime()),
585            data: {shopId: shopId}
586        })
587            .done(function (msg) {
588                if (msg === false) {
589                    return false;
590                } else {
591                    $('#reviewsHolder').html('');
592
593                    var reviews = $.parseJSON(msg);
594
595                    for (var i = 0; i < reviews.length; i++) {
596                        var average = 0;
597
598                        // Average rating
599                        average = (parseInt(reviews[i].review_food_quality) + parseInt(reviews[i].review_service_quality) + parseInt(reviews[i].review_delivery_quality)) / 3;
600                        average = Math.ceil(average) + 1; // ceil and add 1 to make out of 5
601
602                        // Split timestamp into [ Y, M, D, h, m, s ]
603                        var t = reviews[i].review_date.split(/[- :]/);
604                        var n = reviews[i].review_name.split(' ');
605                        // Apply each element to the Date function
606                        var d = new Date(t[0], t[1] - 1, t[2], t[3], t[4], t[5]);
607                        var reviewDate = d.getDate() + '/' + (d.getMonth() + 1) + '/' + d.getFullYear();
608                        var reviewDiv = '<div class="reviewDiv"><p><strong>Placed: </strong>' + reviewDate + '</p><p><strong>Left By: </strong>' + n[0] + '</p>';
609
610                        // Work out the star rating of the shop
611                        reviewDiv = reviewDiv + '<p><strong>Overall: </strong>';
612                        var count = 0;
613
614                        while (count < average) {
615                            reviewDiv = reviewDiv + '<img src="/imgs/star.png" alt="star" />';
616                            count++;
617                        }
618                        reviewDiv = reviewDiv + '</p>';
619
620                        // If a review description add that to the div
621                        if (reviews[i].review_description.length > 0) {
622                            reviewDiv = reviewDiv + '<p>' + reviews[i].review_description + '</p>';
623                        }
624
625                        reviewDiv = reviewDiv + '<div class="divider_menu"><img src="/imgs/divider_large.png" /></div>';
626
627                        $('#reviewsHolder').append(reviewDiv);
628
629                        // Hide the reviews
630                        $("#reviewsDialog").dialog({
631                            autoOpen: true,
632                            title: "Reviews",
633                            maxHeight: 600,
634                            modal: true,
635                            buttons: [{
636                                text: "Ok", click: function () {
637                                    $(this).dialog("close");
638                                }
639                            }]
640                        });
641                    }
642                }
643            });
644    });
645
646    // Handle the click of a desktop filter
647    $('.sort_types').change(function (e) {
648        e.preventDefault();
649
650        var sort_types = $(this).val();
651
652        $('#shop-details-desktop').html($('.sort-this-desktop').sort(function (a, b) {
653
654            // if there is no filter return
655            var va;
656            var vb;
657            if (sort_types == '') {
658                return false;
659            }
660
661            // If filter by distance make sure that the data type is a float
662            if (sort_types == 'name') {
663                va = $(a).data(sort_types);
664                vb = $(b).data(sort_types);
665
666            } else {
667                va = parseFloat($(a).data(sort_types));
668                vb = parseFloat($(b).data(sort_types));
669            }
670
671            if (sort_types == 'name') {
672                // Sort By Name
673                // DESC
674                return va == vb ? 0 : va < vb ? -1 : 1;
675            } else if (sort_types == 'distance') {
676                // Sort By Distance
677                // DESC
678                return va == vb ? 0 : va < vb ? -1 : 1;
679            } else if (sort_types == 'discount') {
680                //va = va.substring(0, va.length - 1);
681                //vb = vb.substring(0, vb.length - 1);
682                return va == vb ? 0 : va > vb ? -1 : 1;
683            } else {
684                // Sort By Rating And
685                // ASC
686                var ratingTemp = va == vb ? 0 : va > vb ? -1 : 1;
687                return ratingTemp;
688            }
689        }));
690    });
691
692    // The drop down change handle the sort
693    $('#sort_mobile').change(function () {
694        var sort_types = $('#sort_mobile').val();
695
696        $('#shop-details-mobile').html($('.sort-this-mobile').sort(function (a, b) {
697            // if there is no filter return
698            var va;
699            var vb;
700            if (sort_types == '') {
701                return false;
702            }
703
704            // If filter by distance make sure that the data type is a float
705            if (sort_types == 'name') {
706                va = $(a).data(sort_types);
707                vb = $(b).data(sort_types);
708            } else {
709                va = parseFloat($(a).data(sort_types));
710                vb = parseFloat($(b).data(sort_types));
711            }
712
713            if (sort_types == 'name') {
714                // Sort By Name
715                // DESC
716                return va == vb ? 0 : va < vb ? -1 : 1;
717            } else if (sort_types == 'distance') {
718                // Sort By Distance
719                // DESC
720                return va == vb ? 0 : va < vb ? -1 : 1;
721            } else if (sort_types == 'discount') {
722                //va = va.substring(0, va.length - 1);
723                //vb = vb.substring(0, vb.length - 1);
724                return va == vb ? 0 : va > vb ? -1 : 1;
725            } else {
726                // Sort By Rating And
727                // ASC
728                return va == vb ? 0 : va > vb ? -1 : 1;
729            }
730        }));
731    });
732
733    $("#slider-raitings").slider({
734        range: "max",
735        min: 0,
736        max: 3,
737        value: 0,
738        slide: function (event, ui) {
739            var val;
740            if (ui.value == 0) {
741                val = 1;
742            } else if (ui.value == 1) {
743                val = 2;
744            } else if (ui.value == 2) {
745                val = 3;
746            } else {
747                val = 4;
748            }
749
750            $(".shop-details-wrapper").each(function (i) {
751                var rating = parseFloat($(this).data('rating'));
752                // If the value is 1 reset the display
753                if (val == 1) {
754                    // To avoid mobile view been shown when shops reset
755                    if (!$(this).hasClass('closed_shop_list')) {
756                        $(this).css('display', '');
757                    }
758                } else {
759                    // If the raiting is equel or less than the value of the filter
760                    if (parseFloat(val) > rating) {
761                        $(this).css('display', 'none');
762                    } else {
763                        $(this).css('display', '');
764                    }
765                }
766            });
767        }
768    });
769
770    $("#slider-distance").slider({
771        range: "max",
772        min: 0,
773        max: 2,
774        value: 0,
775        slide: function (event, ui) {
776            var val;
777            if (ui.value == 0) {
778                val = 1;
779            } else if (ui.value == 1) {
780                val = 3;
781            } else {
782                val = 6;
783            }
784
785            $(".shop-details-wrapper").each(function (i) {
786                var distance = $(this).data('distance');
787                if (distance > val) {
788                    $(this).css('display', 'none');
789                } else {
790                    $(this).css('display', '');
791                }
792            });
793        }
794    });
795
796    // Show/hide the login/signup
797    $('#newCustomer').click(function (e) {
798        e.preventDefault();
799        $('#loginForm').hide();
800        $('#signUpForm').show();
801        window.scrollTo(0, 0);
802    });
803
804    $('#existingCustomer').click(function (e) {
805        e.preventDefault();
806        $('#signUpForm').hide();
807        $('#loginForm').show();
808        window.scrollTo(0, 0);
809    });
810
811    $('#newCustomerUserArea').click(function (e) {
812        e.preventDefault();
813        $('#loginFormHolder').addClass('hidden-phone');
814        $('#signUpFormHolder').removeClass('hidden-phone');
815        window.scrollTo(0, 0);
816    });
817
818    $('#existingCustomerUserArea').click(function (e) {
819        e.preventDefault();
820        $('#signUpFormHolder').addClass('hidden-phone');
821        $('#loginFormHolder').removeClass('hidden-phone');
822        window.scrollTo(0, 0);
823    });
824
825    // Check to see if there are registration errors if so show the signup form automatically.
826    if ($('#signUpErrors').length > 0) {
827        $('#loginForm').hide();
828        $('#signUpForm').show();
829        window.scrollTo(0, 0);
830    }
831
832    // CLOSES ALL BOXS ON PAGE LOAD
833    $('.category_content').hide();
834
835    // Accordian Button For The Menu
836    $('.category_button').click(function (e) {
837        $('.category_button').removeClass('on');
838        $('.category_content').slideUp('slow');
839
840        if ($(this).next().is(':hidden') == true) {
841            $(this).addClass('on');
842            $(this).next().slideDown('slow');
843        }
844    });
845
846    // GET THE DELIVERY PRICES FOR THIS POSTCODE
847    if ($('#checkout_page').length > 0) {
848        let lastOrderType = $('#checkout_page input[name="order-type"]:checked').val()
849        let lastPaymentType = $('#checkout_page input[name="payment-type"]:checked').val()
850
851        function updatePostcodeWarning() {
852            const payment_type = $('#checkout_page input[name="payment-type"]:checked').val();
853            const ot = $('#checkout_page input[name="order-type"]:checked').val();
854
855            let orderButtonDisplay = payment_type === 'cash' ? 'ORDER NOW' : 'CONTINUE';
856
857            const updateButton = $('#update-button');
858            const continueButton = $('#continue-button');
859            const errorRow = $('#error_row');
860            const validatePc = $('#validate_pc');
861
862            // Post code variables
863            const postCode = $.trim(validatePc.val()).replace(/\s+/, "").toUpperCase();
864            const searched_pc = $.trim($('#delivery_pc').val()).replace(/\s+/, "").toUpperCase();
865
866            // If delivery is selected and the postcodes don't match, take user to the update postcode block
867            if (ot === 'd' && postCode !== searched_pc) {
868                errorRow.html(renderWarning(
869                    'Postcode entered (' +
870                    searched_pc +
871                    ') does not match registered postcode (' +
872                    postCode +
873                    '). Please confirm your delivery address and postcode below.'
874                )).show();
875                updateButton.show();
876                continueButton.hide();
877                validatePc.css('border', '2px solid #AB6503');
878            } else {
879                errorRow.hide();
880                updateButton.hide();
881                continueButton.val(orderButtonDisplay).show();
882                validatePc.css('border', '');
883            }
884        }
885
886        // Handle change of order type at this stage
887        $('#checkout_page input[name="order-type"]').click(function (ev) {
888            ev.preventDefault();
889
890            var orderType = $(this).val();
891            const that = $(this);
892
893            const newCustomerDetailsSectionTitle = orderType === 'c'
894                ? '4. YOUR CUSTOMER COLLECTION DETAILS'
895                : '4. YOUR DELIVERY DETAILS';
896            const newTitle = orderType === 'c'
897                ? 'BASKET FOR COLLECTION'
898                : 'BASKET FOR DELIVERY';
899            const newPotLabel = orderType === 'c'
900                ? 'Collection Time'
901                : 'Delivery Time';
902
903            // Validate
904            if (orderType === lastOrderType) {
905                return;
906            }
907
908            if (invalidBasketMenu(orderType)) {
909                return;
910            }
911
912            if(that.closest('.id_radio').hasClass('radio-disabled')) {
913                return;
914            }
915
916            // Update the session via ajax call
917            $.ajax({
918                type: 'POST',
919                url: 'checkout/update_type?ts=' + (new Date().getTime()),
920                data: {
921                    "orderType": orderType
922                },
923                beforeSend: function () {
924                    $('.information-display .overlay').show();
925                    $('#orderSummary .overlay').show();
926                    disableButtons();
927                },
928                success: function (response) {
929                    if (response.error === undefined) {
930                        that.prop('checked', true);
931                        lastOrderType = orderType;
932                        updateBasket(response);
933                        updatePostcodeWarning();
934                        $('#type_header').html(newTitle);
935                        $('#customerDetailsSectionTitle').html(newCustomerDetailsSectionTitle);
936
937                        const canPreOrder = $('#checkout_page .preOrderTimePicker').length !== 0;
938
939                        if (canPreOrder) {
940                            $('#checkout_page .preOrderTimePicker .pot-label').html(newPotLabel);
941
942                            const currentPaymentType = $('#checkout_page input[name="payment-type"]:checked');
943                            const isCard = (currentPaymentType.val() || 'card').toLowerCase() === 'card';
944                            const isCash = !isCard;
945
946                            // if delivery or collection is not available now
947                            const availableNow = that.data('availableNow');
948                            const availableTime = that.data('firstTime');
949
950                            // If available now, enable all payment options
951                            if (availableNow) {
952                                // Enable cash
953                                $('#checkout_page input[name="payment-type"][value="cash"]')
954                                    .closest('.id_radio')
955                                    .removeClass('radio-disabled');
956
957                                // Hide warning banner
958                                $('#payment-warning').hide();
959
960                                // Set default text to 'As soon as possible'
961                                $('#checkout_page .preOrderTimePicker .pot-value')
962                                    .html('As soon as possible');
963
964                                // Set default value to ''
965                                $('#checkout_page input[name="scheduled_at"]')
966                                    .val('');
967                            } else {
968
969                                // Not available now, disable cash and force selection to card
970                                // Disable cash
971                                $('#checkout_page input[name="payment-type"][value="cash"]')
972                                    .closest('.id_radio')
973                                    .addClass('radio-disabled');
974
975                                // Force selection to card
976                                if (isCash) {
977                                    $('#checkout_page input[name="payment-type"][value="card"]')
978                                        .prop('checked', true)
979                                        .trigger('click')
980                                        .trigger('change');
981
982                                    // Show warning banner if payment method was not already card
983                                    $('#payment-warning')
984                                        .css('display', 'flex')
985                                        .find('.checkout_page__warn-text-title')
986                                        .show();
987                                }
988
989                                // Set default text to hh:mm
990                                $('#checkout_page .preOrderTimePicker .pot-value')
991                                    .html(
992                                        (new Date(availableTime))
993                                            .toLocaleTimeString('en-GB', {
994                                                timeZone: 'Europe/London',
995                                                hour: '2-digit',
996                                                minute: '2-digit',
997                                                hour12: false, // Use 24-hour format
998                                            })
999                                    );
1000
1001                                // Set default value to first available time
1002                                $('#checkout_page input[name="scheduled_at"]')
1003                                    .val(availableTime);
1004                            }
1005
1006                            // Enable/disable the order time picker
1007                            $('#checkout_page .preOrderTimePicker')
1008                                .toggleClass('pot-disabled', availableTime === '')
1009                        }
1010                    }
1011
1012                    if (response.error !== undefined) {
1013                        $('#paymentdeliveryErrors').html(renderError(response.error)).show();
1014                        return;
1015                    }
1016                    $('#paymentdeliveryErrors').hide();
1017                },
1018                complete: function () {
1019                    $('#orderSummary .overlay').hide();
1020                    $('.information-display .overlay').hide();
1021                    enableButtons();
1022                }
1023            });
1024        });
1025
1026        $('#checkout_page .preOrderTimePicker').click(function () {
1027            const orderType = $('#checkout_page input[name="order-type"]:checked');
1028
1029            if($(this).closest('.preOrderTimePicker').hasClass('pot-disabled')) {
1030                return;
1031            }
1032
1033            window.modals.PreOrderTimesModal.show({
1034                availableNow: orderType.data('availableNow'),
1035                orderType: orderType.val(),
1036                value: $('#checkout_page input[name="scheduled_at"]').val(),
1037                onContinue: value => {
1038                    const scheduledAt = $('#checkout_page input[name="scheduled_at"]');
1039                    const originalValue = scheduledAt.val();
1040
1041                    // Update the value
1042                    scheduledAt.val(value);
1043                    let displayText = 'As soon as possible';
1044                    if(value !== '') {
1045                        const date = new Date(value);
1046                        displayText = date.toLocaleTimeString('en-GB', {
1047                            timeZone: 'Europe/London',
1048                            hour: '2-digit',
1049                            minute: '2-digit',
1050                            hour12: false // Use 24-hour format
1051                        })
1052                    }
1053                    $('#checkout_page .preOrderTimePicker .pot-value')
1054                        .html(displayText);
1055
1056                    const paymentType = $('#checkout_page input[name="payment-type"]:checked');
1057                    const isCard = (paymentType.val() || 'card').toLowerCase() === 'card';
1058                    const isCash = !isCard;
1059                    const isPreOrder = value !== '';
1060                    const wasPreOrder = originalValue !== '';
1061
1062                    // Switch payment type to card
1063                    if (isCash && isPreOrder && !wasPreOrder) {
1064                        $('#checkout_page input[name="payment-type"][value="card"]')
1065                            .prop('checked', true)
1066                            .trigger('click')
1067                            .trigger('change');
1068
1069                        $('#payment-warning')
1070                            .css('display', 'flex')
1071                            .find('.checkout_page__warn-text-title')
1072                            .show();
1073                    } else {
1074                        $('#payment-warning').hide();
1075                    }
1076
1077                    // Disable cash option as this is a pre-order
1078                    $('#checkout_page input[name="payment-type"][value="cash"]')
1079                        .closest('.id_radio')
1080                        .toggleClass('radio-disabled', isPreOrder);
1081                }
1082            });
1083        });
1084
1085        $('#payment-warning .checkout_page__warn-close-icon').click(function (ev) {
1086            $('#payment-warning').hide();
1087        });
1088
1089        //Handle change of order type at this stage
1090        $('#checkout_page input[name="payment-type"]').click(function (ev) {
1091            ev.preventDefault();
1092
1093            let paymentType = $(this).val();
1094            const that = $(this);
1095
1096            // Validate
1097            if (paymentType === lastPaymentType) {
1098                return;
1099            }
1100
1101            const radio = that.closest('.id_radio');
1102
1103            if(radio.hasClass('radio-disabled')) {
1104                if(!radio.hasClass('radio-card-only')) {
1105                    $('#payment-warning')
1106                        .css('display', 'flex')
1107                        .find('.checkout_page__warn-text-title')
1108                        .hide();
1109                }
1110                return;
1111            }
1112
1113            // Update the session via ajax call
1114            $.ajax({
1115                type: 'POST',
1116                url: 'checkout/update_payment_type?ts=' + (new Date().getTime()),
1117                data: {
1118                    "paymentType": paymentType
1119                },
1120                beforeSend: function () {
1121                    $('.information-display .overlay').show();
1122                    disableButtons();
1123                },
1124                success: function (response) {
1125                    if (response.error === undefined) {
1126                        that.prop('checked', true);
1127                        lastPaymentType = paymentType;
1128                        updatePostcodeWarning();
1129                    }
1130                    if (response.error !== undefined) {
1131                        $('#paymentdeliveryErrors').html(renderError(response.error)).show();
1132                        return;
1133                    }
1134                    $('#paymentdeliveryErrors').hide();
1135                },
1136                complete: function () {
1137                    $('.information-display .overlay').hide();
1138                    enableButtons();
1139                }
1140            });
1141        });
1142
1143        $("[data-hide]").on("click", function () {
1144            $(this).closest("." + $(this).attr("data-hide")).hide();
1145        });
1146
1147        $('#checkout_page #continue-button, #checkout_page #update-button').click(function () {
1148            const mode = $(this).val().toLowerCase();
1149            const postCode = $.trim($('#validate_pc').val()).replace(/\s+/g, '').toLowerCase();
1150
1151            // Validate
1152            if (!validPostcode(postCode)) {
1153                alert('ALERT: Please Enter A Full Valid UK Post Code');
1154                return;
1155            }
1156
1157            if (postCode === '' || postCode.length <= 4) {
1158                alert('ALERT: Please Enter A Valid Post Code');
1159                return;
1160            }
1161
1162            switch (mode) {
1163                case 'update':
1164                    updateDeliveryAddress(function () {
1165                        updatePostcodeWarning()
1166                    })
1167                    break;
1168
1169                case 'order now':
1170                case 'continue':
1171
1172                    // Validate
1173                    const cashCard = $('input:radio[name=payment-type]:checked').val();
1174                    const cashCardPresent = typeof cashCard !== 'undefined';
1175
1176                    if (!cashCardPresent) {
1177                        $('#paymentOption').css('border', '3px solid #a94442');
1178                        $('#cashCardError').show();
1179                        $('html, body').animate({
1180                            scrollTop: $("#cashCardError").offset().top
1181                        }, 500);
1182                        return false;
1183                    } else {
1184                        $('#paymentOption').css('border', '');
1185                    }
1186
1187                    // Place the order
1188                    order_now();
1189                    break;
1190            }
1191        });
1192
1193        $('#checkout_page #update-address-form input[name="postcode"]').keyup(function () {
1194            updatePostcodeWarning();
1195        });
1196
1197        updatePostcodeWarning();
1198    }
1199
1200    // Show/hide the login/signup
1201    $('#show_closed').click(function (e) {
1202        if ($(".closed_shop_list").is(":hidden")) {
1203            $(".closed_shop_list").slideDown("slow");
1204            $('html, body').animate({
1205                scrollTop: $('#closed_shops').offset().top
1206            }, 500);
1207        } else {
1208            $(".closed_shop_list").slideToggle("slow");
1209        }
1210    });
1211
1212    // $('#takeaway-signup-captcha').click(function(e){
1213    //     e.preventDefault();
1214    //     grecaptcha.ready(function() {
1215    //         grecaptcha.execute('6LfHujcnAAAAANoJ6M_LeOGXwQktW3XCmIIEP0Ha', {action: 'submit'}).then(function(token) {
1216    //             $('form[action="/contact/takeawaySignup"]').submit();
1217    //         });
1218    //     });
1219    // });
1220
1221    // Finally initialise the screen
1222    renderPhoneCartFooter();
1223
1224    // Search results dropdowns
1225    $('#sortDropdown').click(function () {
1226        $('#sortDropdown').children('img').toggleClass('results-filter__dropdown-closed');
1227        $('#sortList').toggle();
1228    })
1229    $('#offerDropdown').click(function () {
1230        $('#offerDropdown').children('img').toggleClass('results-filter__dropdown-closed');
1231        $('#offerList').toggle();
1232    })
1233    $('#cuisineDropdown').click(function () {
1234        $('#cuisineDropdown').children('img').toggleClass('results-filter__dropdown-closed');
1235        $('#cuisineList').toggle();
1236    })
1237    $('#sortList').click(function () {
1238        $('#results-filter__list--start-closed').children('img').toggleClass('results-filter__dropdown-closed');
1239        $('#results-filter__list--start-closed').toggle();
1240    })
1241    // sorting selected state
1242    $('.results-filter__option--sorting, .filter-overlay__option--sorting').click(function () {
1243        if ($(this).find('.filter-overlay__radio-button--active').length === 0) {
1244            $('.results-filter__option--sorting, .filter-overlay__option--sorting').children('.filter-overlay__radio-button').removeClass('filter-overlay__radio-button--active')
1245            $(this).children('.filter-overlay__radio-button').addClass('filter-overlay__radio-button--active')
1246        }
1247
1248        let sortType = $(this).find('span').text().trim();
1249        currentSort = sortType;
1250        sortTakeaways(sortType);
1251    })
1252
1253    // sorting hover state
1254    $('.results-filter__option--sorting, .filter-overlay__option--sorting').hover(function () {
1255        if ($(this).find('.filter-overlay__radio-button--active').length === 0) {
1256            $(this).children('.filter-overlay__radio-button').addClass('filter-overlay__radio-button--hover')
1257        }
1258    }, function () {
1259        if ($(this).find('.filter-overlay__radio-button--active').length === 0) {
1260            $(this).children('.filter-overlay__radio-button').removeClass('filter-overlay__radio-button--hover')
1261        }
1262    })
1263    // filter option hover state
1264    $('.results-filter__option--filter').not('.results-filter__option--disabled').hover(function () {
1265        if ($(this).find('.results-filter__option-icon').attr("src") === "/img/checkbox.svg") {
1266            $(this).find('.results-filter__option-icon').attr("src", "/img/checkbox-hover.svg");
1267        }
1268    }, function () {
1269        if ($(this).find('.results-filter__option-icon').attr("src") === "/img/checkbox-hover.svg") {
1270            $(this).find('.results-filter__option-icon').attr("src", "/img/checkbox.svg");
1271        }
1272    })
1273
1274    // sorting selected state
1275    var currentSort = 'Discount';
1276    var searchTerm = '';
1277    var filterCount = 0;
1278    const tempOffers = new Map();
1279    const tempCuisines = new Map();
1280    const selectedOffers = new Map();
1281    const selectedCuisines = new Map();
1282
1283    // filter option selected state
1284    $('.results-filter__option--filter, .filter-overlay__option--filter')
1285        .not('.results-filter__option--disabled, .filter-overlay__option--disabled')
1286        .click(function () {
1287        let offerType = $(this).find('span').data('offertype');
1288        let foodType = $(this).find('span').data('foodtype');
1289        let checkboxImg = $(this).find('.results-filter__option-icon');
1290
1291        // Toggle checkbox image
1292        if (offerType) {
1293            if ($(this).find('.results-filter__option-icon').attr("src") === "/img/checkbox.svg" || $(this).find('.results-filter__option-icon').attr("src") === "/img/checkbox-hover.svg") {
1294                if (offerType === "All Offers") {
1295                    // Clear all other offers and checkboxes
1296                    selectedOffers.clear();
1297                    $('.results-filter__option--filter span[data-offertype], .filter-overlay__option--filter span[data-offertype]')
1298                        .closest('.filter-overlay__option--filter, .results-filter__option--filter')
1299                        .not('.filter-overlay__option--disabled, .results-filter__option--disabled')
1300                        .find('.results-filter__option-icon')
1301                        .attr("src", "/img/checkbox.svg");
1302                } else {
1303                    // Remove "All Offers" and clear checkbox
1304                    selectedOffers.delete("All Offers");
1305                    $('.results-filter__option--filter span[data-offertype="All Offers"], .filter-overlay__option--filter span[data-offertype="All Offers"]')
1306                        .closest('.filter-overlay__option--filter, .results-filter__option--filter')
1307                        .find('.results-filter__option-icon')
1308                        .attr("src", "/img/checkbox.svg");
1309                }
1310                checkboxImg.attr("src", "/img/checkbox-ticked.svg");
1311                selectedOffers.set(offerType, filterCount++);
1312            } else {
1313                checkboxImg.attr("src", "/img/checkbox.svg");
1314                selectedOffers.delete(offerType);
1315            }
1316        } else {
1317            if ($(this).find('.results-filter__option-icon').attr("src") === "/img/checkbox.svg" || $(this).find('.results-filter__option-icon').attr("src") === "/img/checkbox-hover.svg") {
1318                checkboxImg.attr("src", "/img/checkbox-ticked.svg");
1319                selectedCuisines.set(foodType, filterCount++);
1320            } else {
1321                checkboxImg.attr("src", "/img/checkbox.svg");
1322                selectedCuisines.delete(foodType);
1323            }
1324        }
1325
1326        // Update results and filter tags
1327        filterTakeaways();
1328        updateFilterTags();
1329    });
1330
1331    // Add click event to remove tags
1332    $('.search-results__filter-tag-wrapper').on('click', '.search-results__filter-tag-icon', function () {
1333
1334        let offerToRemove = $(this).data('offer');
1335        let cuisineToRemove = $(this).data('cuisine');
1336
1337        if (offerToRemove) {
1338            // Remove from selected offers
1339            selectedOffers.delete(offerToRemove);
1340
1341            // Find the corresponding filter checkbox and update its state manually
1342            let checkboxWrapper = $('.filter-overlay__option--filter span[data-offertype="' + offerToRemove + '"], .results-filter__option--filter span[data-offertype="' + offerToRemove + '"]')
1343                .closest('.filter-overlay__option--filter, .results-filter__option--filter');
1344
1345            if (checkboxWrapper.length) {
1346                let checkboxImg = checkboxWrapper.find('.results-filter__option-icon');
1347                if (checkboxImg.length) {
1348                    checkboxImg.attr("src", "/img/checkbox.svg");
1349                }
1350            }
1351        } else {
1352            // Remove from selected cuisines
1353            selectedCuisines.delete(cuisineToRemove);
1354
1355            // Find the corresponding filter checkbox and update its state manually
1356            let checkboxWrapper = $('.filter-overlay__option--filter span[data-foodtype="' + cuisineToRemove + '"], .results-filter__option--filter span[data-foodtype="' + cuisineToRemove + '"]')
1357                .closest('.filter-overlay__option--filter, .results-filter__option--filter');
1358
1359            if (checkboxWrapper.length) {
1360                let checkboxImg = checkboxWrapper.find('.results-filter__option-icon');
1361                if (checkboxImg.length) {
1362                    checkboxImg.attr("src", "/img/checkbox.svg");
1363                }
1364            }
1365        }
1366
1367        // Update results and filter tags
1368        filterTakeaways();
1369        updateFilterTags();
1370    });
1371
1372    function updateCheckboxes() {
1373
1374        // Clear checkboxes
1375        $('.results-filter__option--filter span[data-offertype], .filter-overlay__option--filter span[data-offertype]')
1376            .closest('.filter-overlay__option--filter, .results-filter__option--filter')
1377            .find('.results-filter__option-icon')
1378            .attr("src", "/img/checkbox.svg");
1379        $('.results-filter__option--filter span[data-foodtype], .filter-overlay__option--filter span[data-foodtype]')
1380            .closest('.filter-overlay__option--filter, .results-filter__option--filter')
1381            .find('.results-filter__option-icon')
1382            .attr("src", "/img/checkbox.svg");
1383
1384        // Add correct checkboxes
1385        selectedOffers.forEach(function (offer) {
1386            $('.results-filter__option--filter span[data-offertype="' + offer + '"], .filter-overlay__option--filter span[data-offertype="' + offer + '"]')
1387                .closest('.filter-overlay__option--filter, .results-filter__option--filter')
1388                .find('.results-filter__option-icon')
1389                .attr("src", "/img/checkbox-ticked.svg");
1390        });
1391        selectedCuisines.forEach(function (cuisine) {
1392            $('.results-filter__option--filter span[data-foodtype="' + cuisine + '"], .filter-overlay__option--filter span[data-foodtype="' + cuisine + '"]')
1393                .closest('.filter-overlay__option--filter, .results-filter__option--filter')
1394                .find('.results-filter__option-icon')
1395                .attr("src", "/img/checkbox-ticked.svg");
1396        });
1397    }
1398
1399    /**
1400     * Update the filter tags at the top of the page
1401     */
1402    function updateFilterTags() {
1403
1404        let filterTags = [];
1405
1406        // Add selected offers
1407        selectedOffers.forEach((id, label) => {
1408            filterTags.push({ label: label, id: id, type: 'offer' });
1409        });
1410
1411        // Add selected cuisines
1412        selectedCuisines.forEach((id, label) => {
1413            filterTags.push({ label: label, id: id, type: 'cuisine' });
1414        });
1415
1416        // Sort filters by ID
1417        filterTags.sort((a, b) => a.id - b.id);
1418
1419        // Clear existing tags
1420        $('.search-results__filter-tag-wrapper').empty();
1421
1422        // Set filter tags
1423        filterTags.forEach(function (filter) {
1424            let tagHtml = `<div class="search-results__filter-tag" data-id="${filter.id}">
1425            <div>${filter.label}</div>
1426            <img src="/img/close-icon-white.svg"
1427                 class="search-results__filter-tag-icon"
1428                 data-${filter.type}="${filter.label}" />
1429        </div>`;
1430            $('.search-results__filter-tag-wrapper').append(tagHtml);
1431        });
1432
1433        // Update counters for mobile
1434        let totalFilters = filterTags.length;
1435        if (totalFilters > 0) {
1436            $('#filterIcon').hide();
1437            $('.search-results__filter-counter').show();
1438            $('.search-results__filter-counter').text(totalFilters);
1439            $('.filter-overlay__header-tag').text(totalFilters + ' Selected');
1440        } else {
1441            $('#filterIcon').show();
1442            $('.search-results__filter-counter').hide();
1443            $('.filter-overlay__header-tag').text('0 Selected');
1444        }
1445
1446        // Scroll to top of page
1447        window.scrollTo({ top: 0, behavior: "smooth" });
1448    }
1449
1450    function resetSearch() {
1451        // Show/hide clear button
1452      if (searchTerm.length > 0) {
1453          if ($(window).width() < 768) {
1454            $('.empty-results__heading').text('Search Results for "' + searchTerm + '"');
1455          } else {
1456            $('.search-results__title').text('Search Results for "' + searchTerm + '"');
1457          }
1458          $('.results-filter__close-icon').removeClass('hidden');
1459      } else {
1460          $('.search-results__title').text('Search Results');
1461          $('.results-filter__close-icon').addClass('hidden');
1462      }
1463    }
1464
1465    // Handle filtering of takeaway cards based on selected cuisines
1466    function filterTakeaways() {
1467        let totalTakeaways = 0;
1468        let postcode = $('.total-takeaways-count').data('postcode');
1469
1470        $('.shop-card').each(function () {
1471
1472            // Match search filter
1473            let matchesSearch = searchTerm.length === 0
1474                || $(this).data('name').toLowerCase().includes(searchTerm.toLowerCase());
1475
1476            // Match offer filter
1477            let offerTypesRaw = $(this).data('offertypes');
1478            let offerTypes = offerTypesRaw ? offerTypesRaw.split(', ').map(type => type.trim()).filter(type => type !== "") : [];
1479
1480            let matchesOffer;
1481            if (selectedOffers.has("All Offers")) {
1482                matchesOffer = offerTypes.length > 0;
1483            } else {
1484                matchesOffer = selectedOffers.size === 0 || offerTypes.some(type => selectedOffers.has(type));
1485            }
1486
1487            // Match cuisine filter
1488            let foodTypes = $(this).data('foodtypes').split(', ').map(type => type.trim());
1489            let matchesCuisine = selectedCuisines.size === 0 || foodTypes.some(type => selectedCuisines.has(type));
1490
1491            if (matchesSearch && matchesOffer && matchesCuisine) totalTakeaways++;
1492
1493            $(this).toggle(matchesSearch && matchesOffer && matchesCuisine);
1494        });
1495
1496        // Sort shops
1497        sortTakeaways(currentSort);
1498
1499        // Update the total takeaway count
1500        $('.total-takeaways-count').text(totalTakeaways + " takeaway" + (totalTakeaways != 1 ? "s" : "") + " near " + postcode);
1501
1502        // Show empty results state
1503        if (totalTakeaways == 0) {
1504          $('.empty-results').css('display', 'flex');
1505          $(window).width() < 768 && $('.search-results__title-wrapper').hide();
1506        } else {
1507          $('.empty-results').css('display', 'none');
1508          $(window).width() < 768 && $('.search-results__title-wrapper').show();
1509        }
1510    }
1511
1512    $('.results-filter__search-input').on('keyup', function () {
1513        searchTerm = $(this).val().trim();
1514        resetSearch();
1515
1516        // Filter takeaways
1517        filterTakeaways();
1518    });
1519
1520    // Clear search input on no results
1521    $('.empty-results__button--reset-search').on('click', function() {
1522      $('.results-filter__search-input').val('');
1523      clearAll();
1524      resetSearch();
1525      filterTakeaways();
1526    })
1527
1528    // Clear search input and reset list when clicking the "X" button
1529    $('.results-filter__close-icon').on('click', function () {
1530        $('.results-filter__search-input').val('');
1531        searchTerm = $(this).val().trim();
1532        $(this).addClass('hidden');
1533
1534        // Reset header
1535        $('.search-results__title').text('Search Results');
1536
1537        // Filter takeaways
1538        filterTakeaways();
1539    });
1540
1541    $('.filter-overlay__footer-button--apply-filters').click(function () {
1542        filterTakeaways();
1543        $('.filter-overlay').toggle();
1544    })
1545
1546    $('.filter-overlay__footer-button--clear-filters').click(function () {
1547        clearAll();
1548        $('.filter-overlay').toggle();
1549    })
1550
1551    function clearAll() {
1552
1553        // Clear search
1554        searchTerm = '';
1555
1556        // Clear offer and reset checkboxes
1557        selectedOffers.forEach(function (id, offer) {
1558            let checkboxWrapper = $('.filter-overlay__option--filter span[data-offertype="' + offer + '"], .results-filter__option--filter span[data-offertype="' + offer + '"]')
1559                .closest('.filter-overlay__option--filter, .results-filter__option--filter');
1560
1561            if (checkboxWrapper.length) {
1562                let checkboxImg = checkboxWrapper.find('.results-filter__option-icon');
1563                if (checkboxImg.length) {
1564                    checkboxImg.attr("src", "/img/checkbox.svg");
1565                }
1566            }
1567        });
1568        selectedOffers.clear();
1569
1570        // Clear cuisines and reset checkboxes
1571        selectedCuisines.forEach(function (id, cuisine) {
1572            let checkboxWrapper = $('.filter-overlay__option--filter span[data-foodtype="' + cuisine + '"], .results-filter__option--filter span[data-foodtype="' + cuisine + '"]')
1573                .closest('.filter-overlay__option--filter, .results-filter__option--filter');
1574
1575            if (checkboxWrapper.length) {
1576                let checkboxImg = checkboxWrapper.find('.results-filter__option-icon');
1577                if (checkboxImg.length) {
1578                    checkboxImg.attr("src", "/img/checkbox.svg");
1579                }
1580            }
1581        });
1582        selectedCuisines.clear();
1583
1584        // Update results and filter tags
1585        filterTakeaways();
1586        updateFilterTags();
1587    }
1588
1589        // Open filter overlay
1590    $('.search-results__filter-button').click(function () {
1591
1592        // Set temp offers
1593        tempOffers.clear();
1594        selectedOffers.forEach((id, offer) => tempOffers.set(offer, id));
1595
1596        // Set temp cuisines
1597        tempCuisines.clear();
1598        selectedCuisines.forEach((id, cuisine) => tempCuisines.set(cuisine, id));
1599
1600        $('.filter-overlay').toggle();
1601    });
1602
1603    // Toggle search results filter overlay
1604    $('#overlayClose').click(function () {
1605
1606        // Set temp offers
1607        selectedOffers.clear();
1608        tempOffers.forEach((id, offer) => selectedOffers.set(offer, id));
1609        tempOffers.clear();
1610
1611        // Set temp cuisines
1612        selectedCuisines.clear();
1613        tempCuisines.forEach((id, cuisine) => selectedCuisines.set(cuisine, id));
1614        tempCuisines.clear();
1615
1616        // Update results, filter tags and filter checkboxes
1617        filterTakeaways();
1618        updateFilterTags();
1619        updateCheckboxes();
1620
1621        $('.filter-overlay').toggle();
1622    });
1623
1624    // Apply filters and close overlay
1625    $('.apply-filters-btn').click(function () {
1626        filterTakeaways();
1627    });
1628});
1629
1630function reduceQuantity(basketItemId) {
1631    $.ajax({
1632        type: "POST",
1633        url: 'decrease_quantity_in_basket?ts=' + (new Date().getTime()),
1634        data: {
1635            "basket_item_id": basketItemId,
1636        },
1637        beforeSend: function () {
1638            $('#orderSummary .overlay').show();
1639            disableButtons();
1640        },
1641        success: function (response) {
1642            updateBasket(response);
1643            updateBasketPosition();
1644        },
1645        error: function () {
1646            console.log('Error in reduceQuantity() item id ' + basketItemId);
1647        },
1648        complete: function () {
1649            $('#orderSummary .overlay').hide();
1650            enableButtons();
1651        }
1652    });
1653}
1654
1655/**
1656 * Removes an item from the cart
1657 */
1658function removeFromCart(basketItemId) {
1659    $.ajax({
1660        type: "POST",
1661        url: 'delete_product_from_basket?ts=' + (new Date().getTime()),
1662        data: {
1663            "basket_item_id": basketItemId,
1664        },
1665        beforeSend: function () {
1666            $('#orderSummary .overlay').show();
1667            disableButtons();
1668        },
1669        success: function (response) {
1670            updateBasket(response);
1671            updateBasketPosition();
1672        },
1673        complete: function () {
1674            $('#orderSummary .overlay').hide();
1675            enableButtons();
1676        }
1677    });
1678    return false;
1679}
1680
1681/**
1682 * Sort Takeaways
1683 * @param sortType
1684 */
1685function sortTakeaways(sortType = 'discount') {
1686    let items = $('.shop-card').toArray();
1687
1688    items.sort((a, b) => {
1689        let aValue, bValue;
1690
1691        switch (sortType) {
1692            case 'Delivery Cost':
1693                aValue = parseFloat($(a).data('deliveryCost') || 99999);
1694                bValue = parseFloat($(b).data('deliveryCost') || 99999);
1695                if (aValue === bValue) {
1696                    return secondarySort(a, b);
1697                }
1698                return aValue - bValue;
1699            case 'Distance':
1700                aValue = parseFloat($(a).data('distance') || 0);
1701                bValue = parseFloat($(b).data('distance') || 0);
1702                if (aValue === bValue) {
1703                    return secondarySort(a, b);
1704                }
1705                return aValue - bValue;
1706            case 'Name':
1707                aValue = $(a).data('name').toLowerCase();
1708                bValue = $(b).data('name').toLowerCase();
1709                return aValue.localeCompare(bValue);
1710            case 'Rating':
1711                aValue = parseFloat($(a).data('rating') || 0);
1712                bValue = parseFloat($(b).data('rating') || 0);
1713                if (aValue === bValue) {
1714                    return secondarySort(a, b);
1715                }
1716                return bValue - aValue;
1717            case 'Total Reviews':
1718                aValue = parseInt($(a).data('totalReviews') || 0);
1719                bValue = parseInt($(b).data('totalReviews') || 0);
1720                if (aValue === bValue) {
1721                    return secondarySort(a, b);
1722                }
1723                return bValue - aValue;
1724            case 'Discount':
1725            default:
1726                aValue = parseFloat($(a).data('discount') || 0);
1727                bValue = parseFloat($(b).data('discount') || 0);
1728                if (aValue === bValue) {
1729                    return secondarySort(a, b);
1730                }
1731                return bValue - aValue;
1732        }
1733    });
1734
1735    // Final Sort for Shops That Are Open
1736    items.sort((a, b) => {
1737        let aOpen = $(a).data('isOpen') ? 1 : 0;
1738        let bOpen = $(b).data('isOpen') ? 1 : 0;
1739        return bOpen - aOpen;
1740    });
1741
1742    $('.shop-card-wrapper').empty().append(items);
1743}
1744
1745function secondarySort(a, b) {
1746    let aRandom = parseFloat($(a).data('randomSortOrder') || 0);
1747    let bRandom = parseFloat($(b).data('randomSortOrder') || 0);
1748    return aRandom - bRandom;
1749}
1750
1751function renderPhoneCartFooter() {
1752    // Get total product count (this doesn't exist for empty basket, so handle that)
1753    const productCount = parseInt($('#basket_product_count').val() || '0', 10);
1754
1755    // Update the phone footer
1756    const basketSubTotal = $('#basket_sub_total').val();
1757    const basketTotal = $('#basket_total').val();
1758
1759    $('#phoneCartFooterItemText').html(productCount === 1 ? 'item' : 'items');
1760    $('#phoneCartFooterTotalProducts').html(productCount);
1761    $('#phoneCartFooterSubTotalPrice')
1762        .toggle(basketSubTotal !== basketTotal)
1763        .find('span')
1764        .html(basketSubTotal);
1765    $('#phoneCartFooterTotalPrice').html(basketTotal);
1766    $('#phoneCartFooter').toggleClass('hidden-phone', productCount === 0);
1767}
1768
1769function updateBasket(response) {
1770
1771    if (response.error !== undefined) {
1772        alert('A basket error has occurred: ' + response.error);
1773        return;
1774    }
1775
1776    // Update the basket html directly
1777    $('#basket').html(response.data.html);
1778
1779    // Update the basket errors section if available
1780    const basketErrorsField = $('#basket-errors');
1781    if (basketErrorsField.length !== 0) {
1782        const errors = response.data.basketErrors;
1783        if (errors.length === 0) {
1784            basketErrorsField.hide();
1785            $('#continue-button').removeAttr('disabled');
1786        } else {
1787            basketErrorsField.html(renderError(errors[0], "Uh oh, we've found a basket error")).show();
1788            $('#continue-button').attr('disabled', true);
1789        }
1790    }
1791
1792    // Reset counters
1793    $('[id^=product-count-]').html('0').addClass('hide');
1794
1795    // Sync counters with basket
1796    $('#basket .cartItem').each(function (e) {
1797        const id = $(this).data('prd-id');
1798        const quantity = $(this).data('qty');
1799        const countField = $('#product-count-' + id);
1800
1801        countField
1802            .html(parseInt('0' + countField.text(), 10) + quantity)
1803            .removeClass('hide');
1804    });
1805
1806    // Update the phone footer
1807    renderPhoneCartFooter();
1808}
1809
1810// enabling and disabling buttons to prevent button presses during loading times
1811function enableButtons() {
1812    $('#discount-code, #discount-code-apply-button, #basket .applied-codes-container, #order_button input[type=button], #checkout-img-right, .editExtras, #delColRadioHolder, #changeDeliveryPc, #updateFullPostcodeSubmit, #orderTypePickerCollection, #orderTypePickerDelivery, .menuAddToBasket.button-add, .cart_remove_item, #reduce_quantity_button, #addProductWithOptions, .checkout input').removeClass('disabled');
1813}
1814
1815function disableButtons() {
1816    $('#discount-code, #discount-code-apply-button, #basket .applied-codes-container, #order_button input[type=button], #checkout-img-right, .editExtras, #delColRadioHolder, #changeDeliveryPc, #updateFullPostcodeSubmit, #orderTypePickerCollection, #orderTypePickerDelivery, .menuAddToBasket.button-add, .cart_remove_item, #reduce_quantity_button, #addProductWithOptions, .checkout input').addClass('disabled');
1817}
1818
1819/**
1820 * Updates the position of the basket if needs be. Can be called after something has been added to cart or when window scrolls.
1821 */
1822function updateBasketPosition() {
1823
1824    try {
1825        var y = $(this).scrollTop();
1826        var top = $('#totalsSeperator').offset().top;
1827
1828        // Whether that's below the form
1829        if (y >= top) {
1830
1831            // If the window is not wide enough then dont do the scroll.
1832            if ($(window).width() < 768) {
1833                $('#stickyContainer').css({'margin': '', 'max-width': '', 'width': ''});
1834                return false;
1835            }
1836
1837            // check we are past sidebar height so we only do this when we are far down the page
1838            var sidebar = $('#orderSummary');
1839            var bottomOfSidebar = sidebar.position().top + sidebar.outerHeight();
1840
1841            if (y < (bottomOfSidebar / 1.5)) {
1842                // if (y < (bottomOfSidebar)) {
1843                // otherwise remove it
1844                $('#stickyContainer')
1845                    .removeClass('menu-box sticky hidden-phone')
1846                    .css({'margin': '', 'max-width': '', 'width': ''});
1847                $('#backToTopLink')
1848                    .addClass('hide');
1849                return false;
1850            }
1851
1852            // Correct the width
1853            var desiredWidth = $('#basket').outerWidth();
1854
1855            // if so, ad the fixed class
1856            $('#stickyContainer')
1857                .addClass('menu-box sticky hidden-phone')
1858                .css({
1859                    'margin': '-2px',
1860                    'max-width': desiredWidth + 'px',
1861                    'width': desiredWidth + 'px'
1862                });
1863            $('#backToTopLink')
1864                .removeClass('hide');
1865
1866        } else {
1867            // otherwise remove it
1868            $('#stickyContainer')
1869                .removeClass('menu-box sticky hidden-phone')
1870                .css({'margin': '', 'max-width': '', 'width': ''});
1871
1872            $('#backToTopLink')
1873                .addClass('hide');
1874        }
1875    } catch (e) {
1876    }
1877}
1878
1879function renderError(text, title = '') {
1880    const punctuated = text.replace(/\.+$/, '') + '.';
1881    const titleText = title === '' ? '' : '<div class="new-alert-title">' + title + '</div>';
1882    return '<div class="new-alert new-alert-error"><div>' + titleText + punctuated + '</div></div>';
1883}
1884
1885function renderWarning(text, title = '') {
1886    const punctuated = text.replace(/\.+$/, '') + '.';
1887    const titleText = title === '' ? '' : '<div class="new-alert-title">' + title + '</div>';
1888    return '<div class="new-alert new-alert-warning"><div>' + titleText + punctuated + '</div></div>';
1889}
1890
1891function updateDeliveryPostcode(postcode, onComplete = null) {
1892    $.ajax({
1893        type: "POST",
1894        url: 'update_delivery_postcode?ts=' + (new Date().getTime()),
1895        data: {
1896            "postcode": postcode
1897        },
1898        beforeSend: function () {
1899            $('#orderSummary .overlay').show();
1900            disableButtons();
1901        },
1902        success: function (response) {
1903            if (response.error !== undefined) {
1904                $('#missingPostcodeAlert').html(response.error).show();
1905                $('#paymentdeliveryErrors').html(renderError(response.error)).show();
1906                return;
1907            }
1908            $('#missingPostcodeAlert').hide();
1909            $('#paymentdeliveryErrors').hide();
1910            $('#delivery_pc').val(postcode);
1911            $('#deliveryPc').html(postcode);
1912            updateBasket(response);
1913            $('#deliveryPcHolder').show();
1914            $('#updateFullPostcodeHolder').hide();
1915        },
1916        complete: function () {
1917            $('#orderSummary .overlay').hide();
1918            enableButtons();
1919            if (onComplete !== null) {
1920                onComplete();
1921            }
1922        }
1923    })
1924}
1925
1926function updateDeliveryAddress(onComplete = null) {
1927    const postcode = $.trim($('#validate_pc').val()).toUpperCase();
1928    const payload = {
1929        "landline": $('#delivery_landline').val(),
1930        "mobile": $('#delivery_mobile').val(),
1931        "firstname": $('#delivery_firstname').val(),
1932        "lastname": $('#delivery_lastname').val(),
1933        "house_no": $('#delivery_house_number').val(),
1934        "address1": $('#delivery_address1').val(),
1935        "address2": $('#delivery_address2').val(),
1936        "town": $('#delivery_town').val(),
1937        "postcode": postcode,
1938    }
1939
1940    $.ajax({
1941        type: "POST",
1942        url: 'checkout/update_delivery_address?ts=' + (new Date().getTime()),
1943        data: payload,
1944        beforeSend: function () {
1945            $('#orderSummary .overlay').show();
1946            disableButtons();
1947        },
1948        success: function (response) {
1949            if (response.error !== undefined) {
1950                $('#paymentdeliveryErrors')
1951                    .html(renderError(response.error))
1952                    .show();
1953                return;
1954            }
1955            $('#paymentdeliveryErrors').hide();
1956            $('#delivery_pc').val(postcode);
1957            $('#validate_pc').val(postcode);
1958            updateBasket(response, 'checkout');
1959        },
1960        complete: function () {
1961            $('#orderSummary .overlay').hide();
1962            enableButtons();
1963            if (onComplete !== null) {
1964                onComplete();
1965            }
1966        }
1967    })
1968}
1969
1970function invalidBasketMenu(orderType) {
1971    var toCheckAgainst = '';
1972    var errorMessage = '';
1973    var invalidBasket = false;
1974    if (orderType === 'c') {
1975        toCheckAgainst = "Delivery";
1976        errorMessage = "You have chosen an order for Collection but your basket contains delivery-only items. Please check your basket.";
1977    }
1978    if (orderType === 'd') {
1979        toCheckAgainst = "Collection";
1980        errorMessage = "You have chosen an order for Delivery but your basket contains collection-only items. Please check your basket.";
1981    }
1982    $('#myOrder .cartItem').each(function (e) {
1983        if ($(this).data('col-del') === toCheckAgainst) {
1984            invalidBasket = true;
1985            $(this).css('border', '4px solid #ED1C24');
1986        }
1987    });
1988
1989    if (invalidBasket) {
1990        alert(errorMessage);
1991    }
1992
1993    return invalidBasket;
1994}
1995
1996$("#alergyInfo").on('click', function () {
1997    $("#alergyWindow").fadeIn("fast");
1998});
1999
2000$("#alergyCross").on('click', function () {
2001    $("#alergyWindow").fadeOut("fast");
2002});
2003
2004function requestValidPostcode($formContainer, $input) {
2005    if ($formContainer.length) {
2006        var errorToShow = $formContainer.find('#search-form-pc-err');
2007        errorToShow.css('visibility', 'visible');
2008        $input.css({"border-color": "red", "border-style": "dashed"});
2009        setTimeout(function () {
2010            errorToShow.css('visibility', 'hidden');
2011            $input.css({"border-color": "#cccccc", "border-style": "solid"});
2012        }, 1500);
2013    }
2014}
2015
2016function searchLocations() {
2017    var postcode = $("#post_code").val().trim();
2018
2019    if (postcode.length > 4 && postcode.length < 9) {
2020        $("#post_code").val(postcode);
2021        var formattedPostcode = '';
2022        try {
2023            formattedPostcode = postcode.replace(/\s/g, "").replace(/^(.*)(\d)/, "$1 $2").toUpperCase();
2024        } catch (e) {
2025            var formattedPostcode = '';
2026        }
2027        var url = 'https://prd-address-api.actionprompt.com/api/address/maps/' + encodeURIComponent(formattedPostcode);
2028
2029        $.ajax({
2030            type: 'GET',
2031            url: url
2032        })
2033            .done(function (results) {
2034                results = JSON.parse(results);
2035
2036                if (results.status !== 'OK') {
2037                    alert("We have been unable to determine your location, please try again. (1)");
2038                    //callback(null);
2039                    return;
2040                }
2041                window.location.href = "/search/" +
2042                    postcode + "/" +
2043                    results.results[0].geometry.location.lat + "/" +
2044                    results.results[0].geometry.location.lng;
2045            })
2046            .fail(function (results) {
2047                results = JSON.parse(results);
2048                alert("We have been unable to determine your location, please try again. (2)");
2049                return false;
2050            });
2051    } else {
2052        requestValidPostcode($('#search-wrapper'), $('#post_code'));
2053    }
2054}
2055
2056let commentUpdateTimer = null;
2057
2058function addToCommentsToSession() {
2059    clearTimeout(commentUpdateTimer);
2060    commentUpdateTimer = setTimeout(function () {
2061        $.ajax({
2062            type: "POST",
2063            url: 'checkout/add_comments_to_session?ts=' + (new Date().getTime()),
2064            data: {
2065                "comments": $('#orderComments').val()
2066            },
2067        });
2068    }, 1000);
2069}
2070
2071function order_now() {
2072    let scheduled_at = $('input[name="scheduled_at"]').val() ?? null;
2073    var payment_type = $('#checkout_page input[name="payment-type"]:checked').val();
2074    var order_comments = $('#orderComments').val();
2075    var type = $('#checkout_page input[name="order-type"]:checked').val();
2076    var validate = validateAddress();
2077
2078    if (payment_type == '') {
2079        alert('ALERT: Please Select A Payment Method');
2080        return false;
2081    }
2082
2083    if (type == '') {
2084        alert('ALERT: Please Return To the Menu And Select Collection Or Delivery');
2085        return false;
2086    }
2087
2088    // Don't create an order if the address validation fails
2089    if (validate === false) {
2090        return false;
2091    }
2092
2093    $.ajax({
2094        type: "POST",
2095        url: 'checkout/process_order?ts=' + (new Date().getTime()),
2096        data: {
2097            "scheduled_at": scheduled_at,
2098            "payment_type": payment_type,
2099            "type": type,
2100            "order_comments": order_comments,
2101            "customer_info": validate
2102        },
2103        beforeSend: function () {
2104            $('#continue_button_loading').show();
2105            $('.information-display .overlay').show();
2106            disableButtons();
2107        },
2108        success: function (response) {
2109            const error = response.error;
2110            let data = response.data;
2111
2112            if (error !== undefined) {
2113                console.error('error:', error);
2114                data = 'error';
2115            }
2116
2117            switch (data) {
2118                case 'blocked':
2119                    alert('Your order has been blocked automatically, call for further details.');
2120                    break;
2121
2122                case 'cash':
2123                    window.location = 'checkout/order_confirmation?ts=' + new Date().getTime();
2124                    break;
2125
2126                case 'card':
2127                    window.location = 'checkout/payment?ts=' + new Date().getTime();
2128                    break;
2129
2130                case 'complete':
2131                    alert('This order is pending, please wait until your order has been processed. 
2131Click ok to continue.');
2132                    window.location = 'checkout/order_confirmation?ts=' + new Date().getTime();
2133                    break;
2134
2135                default:
2136                    setTimeout(function () {
2137                        alert(error + '\n\nPlease return to the menu and try again.');
2138                    }, 100);
2139                    $('#continue_button_loading').hide();
2140                    $('.information-display .overlay').hide();
2141                    enableButtons();
2142                    break;
2143            }
2144        },
2145        error: function (response) {
2146            console.log(response);
2147        },
2148        complete: function () {
2149        }
2150    });
2151}
2152
2153/**
2154 * Validates Postcode
2155 * @param string postCode The postcode to validate
2156 * @return boolean True if the postcode is valid and false on failure.
2157 */
2158function validPostcode(postcode) {
2159    postcode = postcode.replace(/\s/g, "");
2160    var regex = /^(((^[BEGLMNS][1-9]\d?)|(^W[2-9])|(^(A[BL]|B[ABDHLNRST]|C[ABFHMORTVW]|D[ADEGHLNTY]|E[HNX]|F[KY]|G[LUY]|H[ADGPRSUX]|I[GMPV]|JE|K[ATWY]|L[ADELNSU]|M[EKL]|N[EGNPRW]|O[LX]|P[AEHLOR]|R[GHM]|S[AEGKL-PRSTWY]|T[ADFNQRSW]|UB|W[ADFNRSV]|YO|ZE)\d\d?)|(^W1[A-HJKSTUW0-9])|(((^WC[1-2])|(^EC[1-4])|(^SW1))[ABEHMNPRVWXY]))(\s*)?([0-9][ABD-HJLNP-UW-Z]{2}))$|(^GIR\s?0AA$)/i;
2161    return regex.test(postcode);
2162}
2163
2164function checkOrder(id) {
2165    $.ajax({
2166        type: "POST",
2167        url: 'checkout/order_status/' + id + '?ts=' + (new Date().getTime()),
2168        success: function (response) {
2169            const data = response.data;
2170            const status = data.status || 'unprocessed';
2171
2172            if (status !== 'unprocessed') {
2173                $('#loaderContainer').html(data.html);
2174                clearInterval(timer);
2175            }
2176        }
2177    });
2178}
2179
2180function validateAddress() {
2181    var errors = new Array(); // Stores any errors
2182
2183    // Get all values
2184    var last_name = $('input[name=lastname]').val();
2185    var address2 = $('input[name=address2]').val();
2186    var town = $('input[name=town]').val();
2187    var landline = $('input[name=landline]').val();
2188    var mobile = $('input[name=mobile]').val();
2189
2190    // Check the validation for delivery address
2191    // If both are blank alert the user and return false
2192    if (landline == '' && mobile == '') {
2193        errors.push('You must have at least one contact number');
2194    }
2195
2196    // Build an array of input fields you want to validate
2197    var i,
2198        validate_fields = ['delivery_firstname', 'delivery_house_number', 'delivery_address1', 'validate_pc'], // fields to validate
2199        invalid_fields = [],
2200        valid_array = []; // store of empty fields
2201
2202    // Loop through the fields
2203    for (i in validate_fields) {
2204        // check if field is empty
2205        var field = $('#' + validate_fields[i]).val();
2206        field = field.replace(/\/\W/g, '');
2207
2208        if (field.length < 1) {
2209            invalid_fields.push(validate_fields[i]);
2210        } else {
2211            if (validate_fields[i] === 'delivery_address1') {
2212                valid_array.push($('#' + validate_fields[i]).val());
2213            } else {
2214                valid_array.push(field);
2215            }
2216        }
2217    }
2218
2219    // If the fields are blank alert the user which fields are required
2220    if (invalid_fields.length > 0) {
2221        var errorsTxt = 'The following fields are required: ';
2222
2223        for (i in invalid_fields) {
2224            var field = invalid_fields[i];
2225            field = field.replace('delivery_', '');
2226            field = field.replace('_', ' ');
2227            // Captitalise first letter of each word
2228            field = field.charAt(0).toUpperCase() + field.slice(1);
2229            errorsTxt = errorsTxt + ' ' + field + ',';
2230        }
2231
2232        // Remove the last ,
2233        errorsTxt = errorsTxt.slice(0, errorsTxt.length - 1);
2234        errors.push(errorsTxt);
2235    }
2236
2237    if (errors.length > 0) {
2238        // Reset the error messages
2239        $('#paymentdeliveryErrors').html('').hide();
2240
2241        // Loop through the error messages and display them on the form.
2242        for (var i = 0; i < errors.length; i++) {
2243            $('#paymentdeliveryErrors').append(renderError(errors[i]));
2244        }
2245
2246        $('#paymentdeliveryErrors').show();
2247
2248        // Make the window scroll to the top
2249        window.scrollTo(0, 0);
2250        return false;
2251    } else {
2252        // Return all data back to the order now function
2253        valid = [valid_array, last_name, address2, town, landline, mobile]
2254        return valid;
2255    }
2256}
2257
2258$('.foodTypeFilter').click(function () {
2259    var foodType = $(this).data('foodtype');
2260    var count_total_shops = 0;
2261    var count_total_hidden = 0;
2262
2263    $('.sort-this-desktop').each(function (e) {
2264        var array = $(this).data('foodtypes').split(",");
2265        var is_type = 0;
2266        count_total_shops++
2267
2268        $.each(array, function (i) {
2269            var a = array[i].replace(/\s/g, "");
2270            var b = foodType.replace(/\s/g, "");
2271
2272            if (a == b) {
2273                is_type = 1;
2274                return false;
2275            } else {
2276                is_type = 0;
2277            }
2278        });
2279
2280        if (foodType == 'all') {
2281            $(this).css('display', '');
2282        } else {
2283            if (is_type == 1) {
2284                $(this).css('display', '');
2285            } else {
2286                $(this).css('display', 'none');
2287                count_total_hidden++;
2288            }
2289        }
2290    });
2291
2292    if (count_total_shops == count_total_hidden) {
2293        $(".noFoodTypes").html('We\'re sorry, all ' + foodType + ' takeaways are currently closed').css("padding-top", "2rem");
2294    } else {
2295        $(".noFoodTypes").html('').css("padding-top", "0");
2296    }
2297});
2298
2299$('#food_types').change(function () {
2300    var foodType = $(this).val();
2301    var count_total_shops = 0;
2302    var count_total_hidden = 0;
2303
2304    $('.sort-this-desktop').each(function (e) {
2305        var array = $(this).data('foodtypes').split(",");
2306        var is_type = 0;
2307        count_total_shops++
2308
2309        $.each(array, function (i) {
2310            var a = array[i].replace(/\s/g, "");
2311            var b = foodType.replace(/\s/g, "");
2312
2313            if (a == b) {
2314                is_type = 1;
2315                return false;
2316            } else {
2317                is_type = 0;
2318            }
2319        });
2320
2321        if (foodType == 'Select All') {
2322            $(this).css('display', '');
2323        } else {
2324            if (is_type == 1) {
2325                $(this).css('display', '');
2326            } else {
2327                $(this).css('display', 'none');
2328                count_total_hidden++;
2329            }
2330        }
2331    });
2332
2333    if (count_total_shops == count_total_hidden) {
2334        $(".noFoodTypes").html('We\'re sorry, all ' + foodType + ' takeaways are currently closed').css("padding-top", "2rem");
2335    } else {
2336        $(".noFoodTypes").html('').css("padding-top", "0");
2337    }
2338});
2339
2340// Loop all the faqs
2341$(".faq").each(function (e) {
2342    $(this).click(function () {
2343        // If the element clicked is open close it and perform no other action
2344        if ($(this).find('.faq-answer').is(":visible")) {
2345            $(this).find('.faq-answer').hide('fast');
2346            return false;
2347        }
2348
2349        // If the above is not met loop all other elements and close every one apart from the one thats clicked
2350        $(".faq").each(function (e) {
2351            // when a faq is clicked make sure all the other answers are not displayed
2352            $('.faq-answer').not(this).hide();
2353        });
2354
2355        //show the question for the faq thats clicked if not already visible
2356        if (!$(this).find('.faq-answer').is(":visible")) {
2357            $(this).find('.faq-answer').show('fast');
2358        }
2359    });
2360});
2361
2362// Gets a cookie set in JS
2363function getCookie(cname) {
2364    var name = cname + "=";
2365    var ca = document.cookie.split(';');
2366    for (var i = 0; i < ca.length; i++) {
2367        var c = ca[i].trim();
2368        if (c.indexOf(name) == 0) return c.substring(name.length, c.length);
2369    }
2370    return "";
2371}

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.