PageSourceSearch

https://willowauctionhouse.com/wp-content/plugins/auctionforge/assets/js/app.js?ver=1791283862

js willowauctionhouse.com collected 2026-10-06 11:23:36 UTC 337,489 bytes, 7,838 lines download raw bytes

1var bidspiritApi;
2
3// Suppress PayTrace env_includes errors
4(function() {
5    var originalOnError = window.onerror;
6    window.onerror = function(message, source, lineno, colno, error) {
7        if (source && source.indexOf('env_includes') !== -1 && source.indexOf('paytrace.com') !== -1) {
8            console.warn('[PayTrace] Suppressed broken dependency error:', message);
9            return true; // Suppress error
10        }
11        if (originalOnError) {
12            return originalOnError.apply(this, arguments);
13        }
14        return false;
15    };
16})();
17
18(function ($) {
19    var BIDSPIRIT_SERVER = window.bidSpiritServer,
20        BIDSPIRIT_API_BASE = BIDSPIRIT_SERVER + "api/thirdparty/v1/",
21        REST_API_BASE = "/wp-json/bidspirit/v1/",
22        LANG = window.bidSpiritLang,
23        currencySymbol = window.bidSpiritCurrency !== "" ? window.bidSpiritCurrency : "$",
24        bidspiritSessionId,
25        bidspiritAuthToken,
26        bidspiritUser,
27        currentAuctionNumber,
28        currentLotIndex,
29        allIncrementsPrices = null,
30        currentItemInfoResponse = null,
31        currentItemInfo = null,
32        auctionApprovalState = null,
33        countriesList = null,
34        auctionHouseData = {
35            disclaimer: null,
36            email: null,
37            info: null,
38            name: null,
39            noVatByDefault: null,
40            phone: null,
41            noVatOnCommission: null,
42
43            /**
44             * Depricated:
45             * enablePrebidsUnderStartPrice: null,
46             * houseCommissionVatRule: null,
47             * requireIdPhoto: null,
48             * idPhotoUploadRequired: null,
49             * vat: null
50             **/
51        },
52        auctionInfo = {
53            approvalRequired: null,
54            paymentMethodRequired: null,
55            absenteeBidsEnabled: null,
56            address: null,
57            automaticAuction: null,
58            commission: null,
59            commissionInfo: null,
60            currency: null,
61            days: null,
62            displayStartPriceInCatalog: null,
63            id: null,
64            info: null,
65            lastCatalogUpdate: null,
66            name: null,
67            number: null,
68            showEstimatedPriceInItemsList: null,
69            state: null,
70        },
71        auctionItemInfo = {},
72        paymentMethods = [],
73        auctionSettingsData = {
74            requireUserId: null,
75            requireTaxNumber: null,
76            documentUrlBase: null,
77            stripePublicKey: null,
78            bidspiritPortal: null,
79            creditCardProvider: null,
80            alertsEnabled: null,
81            minimumForUsersCallRequests: null,
82            enableUsersCallRequests: null,
83            proxyDomain: null,
84            houseInfo: null,
85            autoPaymentDays: null,
86            enablePrebidsUnderStartPrice: null,
87            houseCommissionVatRule: null,
88            requireIdPhoto: null,
89            idPhotoUploadRequired: null,
90            vat: null,
91            hideSoldPrice: true,
92        },
93        imageBlank = (typeof AuctionForgePlugin !== "undefined" && AuctionForgePlugin.imageBlank) ? AuctionForgePlugin.imageBlank : "/wp-content/plugins/uco-auctions/img/not_found.jpg",
94        triggerClass = "is-load-earlier";
95    bidspiritApi = {
96        lang: LANG,
97        getBidspiritSessionId: function () {
98            return bidspiritSessionId;
99        },
100        setBidspiritSessionId: function (sessionId) {
101            if (sessionId === undefined) {
102                try {
103                    sessionId = localStorage.getItem("bidspiritSessionId") || "";
104                } catch (e) {
105                    console.error("Local storage disabled");
106                }
107            }
108
109            bidspiritSessionId = sessionId;
110        },
111        getAuthToken: function (apiAction) {
112            if (apiAction !== undefined && apiAction === "users/initSession" && bpGetQueryParams("authToken") !== null) {
113                return bpGetQueryParams("authToken");
114            }
115
116            try {
117                bidspiritAuthToken = localStorage.getItem("bidspiritAuthToken");
118            } catch (e) {
119                console.error("Local storage disabled");
120                bidspiritAuthToken = "";
121            }
122
123            return bidspiritAuthToken;
124        },
125        setAuthToken: function (authToken) {
126            try {
127                localStorage.setItem("bidspiritAuthToken", authToken);
128            } catch (e) {
129                console.error("Local storage disabled");
130            }
131
132            bidspiritAuthToken = authToken;
133        },
134        getBidspiritUser: function () {
135            return bidspiritUser;
136        },
137        setBidspiritUser: function (user) {
138            bidspiritUser = user;
139            let successMessage = "";
140
141            if (bidspiritUser !== undefined) {
142                if (bidspiritUser.honorific === undefined) {
143                    bidspiritUser.honorific = "";
144                }
145
146                if (bidspiritUser.firstName === undefined) {
147                    bidspiritUser.firstName = "";
148                }
149
150                if (bidspiritUser.lastName === undefined) {
151                    bidspiritUser.lastName = "";
152                }
153
154                successMessage = window.bs_lang.login_success_hello + ", " + bidspiritUser.firstName;
155
156                if (bidspiritUser.honorific !== "") {
157                    successMessage = window.bs_lang.login_success_full_hello.replace(/%s1/, bidspiritUser.honorific).replace(/%s2/, bidspiritUser.firstName).replace(/%s3/, bidspiritUser.lastName);
158                }
159
160                if (window.bs_lang.login_success_hello_custom !== "" && bidspiritUser.honorific !== "") {
161                    successMessage = window.bs_lang.login_success_hello_custom.replace(/%s1/, bidspiritUser.honorific).replace(/%s2/, bidspiritUser.firstName).replace(/%s3/, bidspiritUser.lastName);
162                } else if (window.bs_lang.login_success_hello_custom_default !== "" && bidspiritUser.honorific === "") {
163                    successMessage = window.bs_lang.login_success_hello_custom_default.replace(/%s1/, bidspiritUser.firstName).replace(/%s2/, bidspiritUser.lastName);
164                }
165
166                bidspiritUser.successMessage = successMessage;
167            }
168        },
169        getAuctionApprovalState: function () {
170            return auctionApprovalState;
171        },
172        setAuctionApprovalState: function (value) {
173            auctionApprovalState = value;
174        },
175        getCountriesList: function () {
176            return countriesList;
177        },
178        setCountriesList: function (value) {
179            countriesList = value;
180        },
181        getAuctionHouseData: function () {
182            return auctionHouseData;
183        },
184        setAuctionHouseData: function (value) {
185            auctionHouseData = value;
186        },
187        getAuctionSettingsData: function () {
188            return auctionSettingsData;
189        },
190        setAuctionSettingsData: function (value) {
191            auctionSettingsData = value;
192        },
193        getAuctionInfo: function () {
194            return auctionInfo;
195        },
196        setAuctionInfo: function (value) {
197            if (value.currency !== undefined) {
198                currencySymbol = value.currency;
199            }
200            auctionInfo = value;
201        },
202        getAuctionItemInfo: function () {
203            return auctionItemInfo;
204        },
205        setAuctionItemInfo: function (value) {
206            auctionItemInfo = value;
207        },
208        setIncrementsPrices: function (callback) {
209            if (allIncrementsPrices === null) {
210                allIncrementsPrices = bidspiritApi.getAuctionInfo().increments;
211            } else {
212                callback(allIncrementsPrices);
213            }
214        },
215        getIncrementsPrices: function () {
216            return allIncrementsPrices;
217        },
218        stripeLoad: function (callback) {
219            var classTrigger = "stripe-load";
220
221            if (document.body.classList.contains(classTrigger)) {
222                callback();
223            } else {
224                $.getScript("https://js.stripe.com/v3/").done(function (script, textStatus) {
225                    callback();
226                    console.info(textStatus + " Stripe load");
227                    document.body.classList.add(classTrigger);
228                }).fail(function (jqxhr, settings, exception) {
229                    console.error("Error Stripe load", jqxhr, settings, exception);
230                });
231            }
232        },
233        getLinkOnLive() {
234            let lat = "";
235
236            if (bidspiritUser !== undefined && bidspiritUser.liveAuctionToken !== undefined) {
237                lat = "?lat=" + bidspiritUser.liveAuctionToken;
238            }
239
240            return BIDSPIRIT_SERVER + lat;
241        },
242        auctionSettingsDataInit: function () {
243            if (auctionSettingsData.requireUserId === null) {
244                bidspiritQuery("settings/getSettings", {
245                    sessionId: bidspiritSessionId,
246                    language: LANG
247                }, function (data) {
248                    auctionSettingsData = data.response;
249                    bidspiritApi.setAuctionSettingsData(auctionSettingsData);
250                });
251            }
252        },
253        bidspiritQuery: bidspiritQuery,
254        bidspiritPostQuery: bidspiritPostQuery,
255        init: init,
256        doLogout: doLogout,
257        checkError: checkError,
258        initIncrementSteps: initIncrementSteps,
259        checkErrorForm: checkErrorForm,
260        auctionInfoInit: auctionInfoInit,
261        hangUpEvent: hangUpEvent,
262        saveFirebaseUser: saveFirebaseUser,
263        updateUserDisplay: updateUserDisplay,
264        updateDisplay: updateDisplay,
265        loginLink: loginLink,
266        submitRegister: submitRegister,
267        getDataForm: getDataForm
268    };
269
270    function ajaxQuery(params, apiAction, data, callback, errorCallback, alwaysCallback) {
271        $.ajax(params).done(function (response) {
272            if (callback !== undefined) {
273                callback(response);
274            }
275        }).fail(function () {
276            if (errorCallback !== undefined) {
277                errorCallback();
278            }
279        }).always(function () {
280            if (alwaysCallback !== undefined) {
281                alwaysCallback();
282            }
283        });
284    }
285
286    function restQuery(apiCall, method, data, callback) {
287        var xhttp = new XMLHttpRequest();
288
289        xhttp.onreadystatechange = function () {
290            if (this.readyState == 4 && this.status == 200) {
291                if (callback !== undefined) {
292                    callback(this.responseText);
293                }
294            }
295        };
296
297        apiCall = REST_API_BASE + apiCall + "?" + new URLSearchParams(data).toString();
298        xhttp.open(method, apiCall, true);
299        xhttp.setRequestHeader("Content-type", "application/json");
300        xhttp.send();
301    }
302
303    // A BidSpirit Shop term carries a synthetic auction id (Shop::AUCTION_ID_BASE
304    // on the PHP side) purely because AuctionForge keys every lot on one. No
305    // auction-scoped endpoint can succeed for it: BidSpirit answers
306    // BAD_PARAM_VALUE "Auction <id> not found", and checkError() puts that in
307    // front of the customer as an error modal. Rather than chase every call site
308    // (the catalogue bid loader, the 10s poller, approvals, ...), drop these at
309    // the transport and unwind the caller cleanly.
310    var BS_SHOP_AUCTION_ID_BASE = 990000000;
311
312    function bsShopIsSyntheticAuctionId(value) {
313        var n = parseInt(value, 10);
314        return !isNaN(n) && n >= BS_SHOP_AUCTION_ID_BASE;
315    }
316
317    function bsShopSkipAuctionCall(data, callback, alwaysCallback) {
318        if (!data || (!bsShopIsSyntheticAuctionId(data.auctionId)
319                && !bsShopIsSyntheticAuctionId(data.auctionNumber))) {
320            return false;
321        }
322
323        // Hand back an empty but well-formed response so callers that walk
324        // itemsInfo/notFoundLots do not throw, and run the always handler so no
325        // poller is left stuck marked busy.
326        if (callback !== undefined) {
327            callback({
328                response: {
329                    success: true,
330                    itemsInfo: {},
331                    notFoundLots: [],
332                    auctionIsLive: false
333                }
334            });
335        }
336
337        if (alwaysCallback !== undefined) {
338            alwaysCallback();
339        }
340
341        return true;
342    }
343
344    function bidspiritQuery(apiAction, data, callback, errorCallback, alwaysCallback) {
345        if (bsShopSkipAuctionCall(data, callback, alwaysCallback)) {
346            return;
347        }
348
349        if (bpGetQueryParams("sessionId") !== null) {
350            data.sessionId = bpGetQueryParams("sessionId");
351        }
352
353        ajaxQuery({
354            url: BIDSPIRIT_API_BASE + apiAction + ".api",
355            data: data,
356            timeout: 0,
357            beforeSend: function (request) {
358                request.setRequestHeader("BIDSPIRIT-AUTH-TOKEN", bidspiritApi.getAuthToken(apiAction));
359            },
360            xhrFields: {
361                withCredentials: true
362            }
363        }, apiAction, data, callback, errorCallback, alwaysCallback);
364    }
365
366    function bidspiritPostQuery(apiAction, data, callback, errorCallback, alwaysCallback) {
367        if (bsShopSkipAuctionCall(data, callback, alwaysCallback)) {
368            return;
369        }
370
371        if (bpGetQueryParams("sessionId") !== null) {
372            data.sessionId = bpGetQueryParams("sessionId");
373        }
374
375        ajaxQuery({
376            url: BIDSPIRIT_API_BASE + apiAction + ".api",
377            data: data,
378            type: "POST",
379            timeout: 0,
380            beforeSend: function (request) {
381                request.setRequestHeader("BIDSPIRIT-AUTH-TOKEN", bidspiritApi.getAuthToken(apiAction));
382            },
383            xhrFields: {
384                withCredentials: true
385            }
386        }, apiAction, data, callback, errorCallback, alwaysCallback);
387    }
388
389    function hangUpEvent(name, data, target) {
390        var event = jQuery.Event(name);
391        event.response = data;
392
393        if (target === undefined) {
394            $("body").trigger(event);
395        } else {
396            target.trigger(event);
397        }
398    }
399
400    function compareItemIndex(itemIndex, firstLotIndex, lastLotIndex) {
401        return parseInt(itemIndex) >= parseInt(firstLotIndex) && itemIndex <= parseInt(lastLotIndex);
402    }
403
404    function initialPostAuctionSaleOpenedUntil(auctionData, lotIndex) {
405        let currentAuctionDayIndex = 0,
406            postAuctionSaleOpenedUntil = 0;
407        if (auctionData.days !== undefined && auctionData.days.length > 1) {
408            let indexDetect = false;
409            auctionData.days.forEach((elem, index) => {
410                if (compareItemIndex(lotIndex, elem.firstLotIndex, elem.lastLotIndex) && !indexDetect) {
411                    currentAuctionDayIndex = elem.index - 1;
412                    indexDetect = true;
413                }
414            });
415
416            if (auctionData.days[currentAuctionDayIndex] !== undefined && auctionData.days[currentAuctionDayIndex].postAuctionSaleOpenedUntil !== undefined) {
417                postAuctionSaleOpenedUntil = auctionData.days[currentAuctionDayIndex].postAuctionSaleOpenedUntil;
418                //console.log("testX2.0");
419            } else {
420                postAuctionSaleOpenedUntil = 0;
421                //console.log("testX2.1");
422            }
423        } else {
424            if (auctionData.days[0] !== undefined && auctionData.days[0].postAuctionSaleOpenedUntil !== undefined) {
425                postAuctionSaleOpenedUntil = auctionData.days[0].postAuctionSaleOpenedUntil;
426                //console.log("testX3.0");
427            } else {
428                postAuctionSaleOpenedUntil = 0;
429                //console.log("testX3.1");
430            }
431        }
432
433        return [currentAuctionDayIndex, postAuctionSaleOpenedUntil];
434    }
435
436    function urldecode(url) {
437        return decodeURIComponent(url.replace(/\+/g, " "));
438    }
439
440    function passwordShowAction() {
441        let profilePasswordIcons = $(".bp_show_password-action");
442
443        if (profilePasswordIcons.length > 0) {
444            profilePasswordIcons.each(function (index, elem) {
445                $(elem).off("click", ".bp_show_password").on("click", ".bp_show_password", function (event) {
446                    let profilePasswordIcon = event.target,
447                        fieldPassword = $(elem).find(".bp-form-control_eye");
448
449                    if (fieldPassword[0].type === "password") {
450                        fieldPassword[0].type = "text";
451                        profilePasswordIcon.classList.remove("svg-eye");
452                        profilePasswordIcon.classList.add("svg-eye-slash");
453                    } else {
454                        fieldPassword[0].type = "password";
455                        profilePasswordIcon.classList.remove("svg-eye-slash");
456                        profilePasswordIcon.classList.add("svg-eye");
457                    }
458                });
459            });
460        }
461    }
462
463    function checkPoint(name, clear) {
464        if (clear !== undefined) {
465            document.body.classList.remove(name);
466            setCookie(name, false, -1);
467        } else {
468            document.body.classList.add(name);
469            setCookie(name, true, 1);
470        }
471    }
472
473    function setCookie(cname, cvalue, exdays) {
474        var d = new Date();
475
476        if (exdays === -1) {
477            d.setTime(d.getTime() + exdays);
478        } else {
479            d.setTime(d.getTime() + exdays * 24 * 60 * 60 * 1000);
480        }
481
482        var expires = "expires=" + d.toUTCString();
483        document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/;SameSite=Lax";
484    }
485
486    function getCookie(cname) {
487        var name = cname + "=",
488            data = document.cookie.split(";");
489
490        for (var i = 0; i < data.length; i++) {
491            var item = data[i];
492
493            while (item.charAt(0) === " ") {
494                item = item.substring(1);
495            }
496
497            if (item.indexOf(name) === 0) {
498                return item.substring(name.length, item.length);
499            }
500        }
501
502        return "";
503    }
504
505    function addBodyClass(className) {
506        // $("body").addClass(className);
507        document.body.classList.add(className);
508    }
509
510    function searchGetParam(param) {
511        var name = param.replace(/[\[\]]/g, "\\$&"),
512            regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
513            results = regex.exec(window.location.href);
514
515        if (!results) {
516            return null;
517        }
518
519        if (!results[2]) {
520            return "";
521        }
522
523        return decodeURIComponent(results[2].replace(/\+/g, " "));
524    }
525
526    function fireSwall(message, confirmCallback, deniedCallback) {
527        Swal.fire({
528            html: message,
529            showDenyButton: true,
530            showCancelButton: true,
531            confirmButtonText: "Ok",
532            denyButtonText: "Cancel"
533        }).then(result => {
534            if (result.isConfirmed) {
535                if (confirmCallback !== undefined) {
536                    confirmCallback();
537                }
538            } else if (result.isDenied) {
539                if (deniedCallback !== undefined) {
540                    deniedCallback();
541                }
542            }
543        });
544    }
545
546    function loadTemplate(elem, idTemplate, data, visible, callback, append, prepend) {
547        var jElem = $(elem);
548
549        if (typeof elem === "string" && elem.match(/\#/)) {
550            elem = elem.replace(/\#/, "");
551            jElem = $(document.getElementById(elem));
552        }
553
554        var html = _.template(document.getElementById(idTemplate).innerHTML),
555            hiddenClass = window.bs_data.hidden_class;
556
557        if (visible) {
558            jElem.removeClass(hiddenClass);
559        }
560
561        if (append !== undefined) {
562            if (prepend !== undefined) {
563                jElem.prepend(html(data));
564            } else {
565                jElem.append(html(data));
566            }
567        } else {
568            jElem.html(html(data));
569        }
570
571        if (callback !== undefined) {
572            callback();
573        }
574    }
575
576    function loadTemplateInsert(elem, idTemplate, data, append, prepend, callback) {
577        var jElem = $(elem),
578            html = _.template(document.getElementById(idTemplate).innerHTML);
579
580        if (append !== undefined) {
581            if (prepend !== undefined) {
582                jElem.prepend(html(data));
583            } else {
584                jElem.append(html(data));
585            }
586        } else {
587            jElem.html(html(data));
588        }
589
590        if (callback !== undefined) {
591            callback();
592        }
593    }
594
595    function bPcheckError(responseData) {
596        if (!responseData || responseData.response == null) {
597            noticeSwall(modal, window.bs_lang.error, window.bs_lang.empty_response);
598            return true;
599        }
600
601        if (responseData.response.errorCode) {
602            noticeSwall(window.bs_lang.error, responseData.response.errorCode, responseData.response.errorMessage);
603
604            if (responseData.response.errorCode == "SESSION_ENDED") {
605                bidspiritUser = null;
606                updateDisplay();
607            }
608
609            return true;
610        }
611
612        return false;
613    }
614
615    function checkError(responseData, modal) {
616        if (!responseData || responseData.response.success) {
617            return false;
618        }
619
620        if (!responseData) {
621            noticeSwall(modal, "error", "empty response");
622            return true;
623        }
624
625        hangUpEvent("bp:check-error", responseData.response);
626
627        if (responseData.response.errorCode) {
628            noticeSwall("error", "error", responseData.response.errorMessage);
629
630            if (responseData.response.errorCode === "SESSION_ENDED") {
631                bidspiritUser = null;
632            }
633
634            console.error(responseData.response.errorMessage);
635            return true;
636        }
637
638        return false;
639    }
640
641    function checkErrorForm(form, responseData) {
642        var groupContainerSelector = ".errors-group",
643            submitButton = $(form).find("[type=submit]"),
644            status = false;
645        $(form).find(groupContainerSelector).addClass(window.bs_data.hidden_class);
646
647        if (!!submitButton) {
648            submitButton[0].disabled = true;
649        }
650
651        function printError(form, message) {
652            var groupContainer = $(form).find(groupContainerSelector);
653
654            if (groupContainer.hasClass(window.bs_data.hidden_class)) {
655                groupContainer.removeClass(window.bs_data.hidden_class);
656            }
657
658            groupContainer.empty().append("<p>" + bp_t(message) + "</p>");
659
660            if (!!submitButton) {
661                submitButton[0].disabled = false;
662            }
663        }
664
665        if (!responseData || responseData.response == null) {
666            printError(form, "empty response");
667            status = true;
668        }
669
670        if (responseData.response.errorCode == "USER_EXIST" && window.bs_lang.user_exist !== undefined) {
671            printError(form, window.bs_lang.user_exist);
672            status = true;
673        } else if (responseData.response.errorCode) {
674            printError(form, responseData.response.errorMessage);
675            status = true;
676        }
677
678        hangUpEvent("bp:checkErrorForm", responseData);
679        return status;
680    }
681
682    /**
683     * @param price
684     * @param auctionCommission
685     * @param isFull
686     * @returns {string}
687     * @deprecated Depricated. Used getFullPriceInfo
688     */
689    function calculateCommission(price, auctionCommission, isFull) {
690        var secondPercent = auctionSettingsData.vat,
691            pricePercent = parseFloat(price) * parseFloat(auctionCommission / 100),
692            varPercent = 0,
693            vatRule = auctionSettingsData.houseCommissionVatRule;
694
695        switch (vatRule) {
696            case "EXEMPTED_FROM_VAT":
697                varPercent = pricePercent;
698                break;
699            case "VAT_INCLUDED":
700                varPercent = pricePercent + ((parseFloat(price) + pricePercent) * (secondPercent / 100));
701                break;
702            case "SHOULD_ADD_VAT":
703                varPercent = pricePercent;
704                //varPercent = pricePercent + (secondPercent / 100);
705                // varPercent = pricePercent + (pricePercent * (secondPercent / 100));
706                break;
707            default:
708                varPercent = pricePercent + (pricePercent * (secondPercent / 100));
709        }
710
711        if (isFull) {
712            price = parseFloat(price) + (price * (secondPercent / 100));
713            return (parseFloat(price) + varPercent).toFixed(2);
714        } else {
715            return (parseFloat(price) + varPercent).toFixed(2);
716        }
717    }
718
719    function roundToCents(sum){
720        return Math.round(sum*100)/100;
721    }
722
723    function getCommissonInfoForPrice(lot, auction, price) {
724        var commission = price * (auction.commission) / 100;
725        var commissionLabel = auction.commission+"%";
726        if (auction.minimumItemCommission) {
727            commissionLabel+=". Minimum commission: " + auction.currency+auction.minimumItemCommission;
728            if (auction.itemPriceForMinimumCommission) {
729                commissionLabel+=". Item price for minimum commission:"+auction.itemPriceForMinimumCommission;
730                if (price <= auction.itemPriceForMinimumCommission) {
731                    commission = auction.minimumItemCommission;
732                }
733            } else if (commission < auction.minimumItemCommission) {
734                commission = auction.minimumItemCommission;
735            }
736        }
737        return {
738            commission:roundToCents(commission),
739            commissionLabel:commissionLabel
740        }
741    }
742
743    /**
744     * currentItemInfo, auctionInfo, price
745     * @param lot
746     * @param auction
747     * @param price
748     * @returns {{hammerPrice, commissionInfo: {commission: *, commissionLabel: string}, vatInfo: {vat: *, vatLabel: string}, totalPriceInfo: {price: *, label: string}}}
749     */
750    function getFullPriceInfo(lot, auction, price) {
751        let settings = bidspiritApi.getAuctionSettingsData(),
752            vatPercent = settings.vat,
753            shouldAddVat =  vatPercent  && (!bidspiritUser || !bidspiritUser.exemptedFromTax),
754            commissionInfo = getCommissonInfoForPrice(lot, auction, price),
755            priceWithCommission = roundToCents(price * 1+ commissionInfo.commission),
756            totalPriceLabel,
757            fullPriceVat = lot.fullPriceVat,
758            vatLabel,
759            vat;
760
761        if (shouldAddVat) {
762            vatLabel = vatPercent + "% " + bp_t("vat");
763            if (commissionInfo.commission) {
764                totalPriceLabel = bp_t("price_including_buyers_premium_and_vat");
765                if (fullPriceVat) {
766                    vatLabel += " " + bp_t("on_the_full_lots_price_and_commission");
767                    if (settings.houseCommissionVatRule == 'SHOULD_ADD_VAT') {
768                        vat = vatPercent * priceWithCommission / 100;
769                    } else {
770                        vat = vatPercent * price / 100;
771                    }
772                } else {
773                    vatLabel += " " + bp_t("on commission only");
774                    vat = vatPercent * commissionInfo.commission / 100;
775                }
776            } else {
777                if (fullPriceVat) {
778                    vatLabel = bp_t("on_item_price");
779                    totalPriceLabel = bp_t("price_including_vat");
780                    vat = vatPercent * price / 100;
781                } else {
782                    vatLabel = bp_t("exempted");
783                    totalPriceLabel = bp_t("full_price_no_vat_or_buyers_permium");
784                    vat = 0;
785                }
786            }
787        } else {
788            vatLabel = bp_t("exempted");
789            totalPriceLabel = bp_t("total_with_commission");
790            vat = 0;
791        }
792        vat = roundToCents(vat);
793        return {
794            hammerPrice: parseFloat(price),
795            commissionInfo: commissionInfo,
796            vatInfo:{
797                vat:vat,
798                vatLabel:vatLabel
799            },
800            totalPriceInfo:{
801                price:roundToCents(priceWithCommission + vat),
802                label:totalPriceLabel
803            }
804
805        }
806    }
807
808    function getCommissionPrice(price, fullPriceVat, auctionCommission) {
809        if (fullPriceVat === undefined) {
810            var singleLot = $("#single-lot");
811        }
812
813        if (fullPriceVat === undefined) {
814            fullPriceVat = Boolean(parseInt(singleLot.attr("data-full-price-vat")));
815        }
816
817        if (auctionCommission === undefined) {
818            auctionCommission = bidspiritApi.getAuctionInfo().commission;
819        }
820
821        return calculateCommission(price, auctionCommission, fullPriceVat);
822    }
823
824    function renderCommissionPrice(price) {
825        let fullPriceInfo = getFullPriceInfo(currentItemInfo, auctionInfo, price),
826            auctionHouseData = bidspiritApi.getAuctionSettingsData(),
827            fullVatPrice = Boolean(parseInt($("#single-lot").attr("data-full-price-vat"))),
828            secondaryFullPrice = 0,
829            text = "";
830
831        console.log(fullPriceInfo);
832
833        if (auctionInfo.secondCurrencyRate !== undefined) {
834            secondaryFullPrice = (fullPriceInfo.totalPriceInfo.price * (auctionInfo.secondCurrencyRate).toFixed(4)).toFixed(2);
835            text = " (" + formattedPrice(secondaryFullPrice,auctionInfo.secondCurrency) + ")";
836        }
837
838        loadTemplate("#bp-fullPrice", "full-price-template", {
839            text: text,
840            fullPriceVat: fullVatPrice,
841            fullPriceInfo: getFullPriceInfo(currentItemInfo, auctionInfo, price),
842            auctionHouseData: auctionHouseData,
843            currencySymbol: currencySymbol
844        });
845    }
846
847    function galleryInitial() {
848        function featureGallery(galleryMainSlider, galleryThumbs) {
849            var bidspiritUser = bidspiritApi.getBidspiritUser(),
850                galleryInfo = $("#gallery-info");
851
852            if (window.bs_data.only_for_user_auth && bidspiritUser !== undefined) {
853                var imageWrapper = $("#wrpLotImages");
854                galleryInfo.remove();
855
856                if (imageWrapper.length) {
857                    var imageList = imageWrapper.attr("data-image-list"),
858                        imageTemplate = imageWrapper.attr("data-image-template"),
859                        imgTemplate = "",
860                        isCloned = Boolean(parseInt(imageWrapper.attr("data-image-cloned")));
861
862                    try {
863                        imageTemplate = JSON.parse(imageTemplate);
864                        imageList = imageList.split(/\,/);
865                        imgTemplate = imageTemplate.uncloned.custom;
866
867                        if (Array.isArray(imageList)) {
868                            imageList.splice(0, 1);
869                        }
870
871                        if (isCloned) {
872                            imgTemplate = imageTemplate.cloned.custom;
873                        }
874
875                        var mainSlide = [],
876                            thumbSlide = [];
877                        imageList.forEach(function (elem, index) {
878                            var imgSrc = "";
879                            imgSrc = imgTemplate.replace(/\$1/g, elem);
880                            imgSrc = imgSrc.replace(/\$2/g, elem.replace(/\D+/, ""));
881                            var thumbsTemplate = `<div data-slide="${index + 1}" class='grid-slide swiper-slide' style='background-image:url("${imgSrc}")'></div>`,
882                                slideTemplate = `<a href="${imgSrc}" data-fancybox-bp="gallery" class="swiper-slide" style="background-image:url('${imgSrc}')"></a>`;
883                            mainSlide.push(slideTemplate);
884                            thumbSlide.push(thumbsTemplate);
885                        });
886
887                        if (mainSlide.length > 0) {
888                            galleryMainSlider.appendSlide(mainSlide);
889
890                            if (typeof galleryThumbs.appendSlide === "function") {
891                                galleryThumbs.appendSlide(thumbSlide);
892                            } else {
893                                galleryThumbs.append(thumbSlide);
894                            }
895                        }
896                    } catch (e) {
897                        console.error(e);
898                    }
899                }
900            } else {
901                galleryInfo.removeClass(window.bs_data.hidden_class);
902            }
903        }
904
905        var gallerySelector = ".bp-gallery-thumbs",
906            topGallerySelector = ".bp-gallery-top",
907            topGalleryConfig = {
908                spaceBetween: 10,
909                navigation: {
910                    nextEl: ".swiper-button-next",
911                    prevEl: ".swiper-button-prev"
912                }
913            },
914            gridGalleryThumbs = ".bp-gallery-thumbs-grid",
915            galleryMainSlider = null,
916            galleryThumbs = null;
917
918        if ($(gallerySelector).length) {
919            galleryThumbs = new SwiperBP(".bp-gallery-thumbs", {
920                spaceBetween: 10,
921                slidesPerView: 4,
922                freeMode: true,
923                centeredSlidesBounds: true,
924                slideToClickedSlide: true,
925                watchSlidesVisibility: true,
926                watchSlidesProgress: true
927            });
928
929            if ($(topGallerySelector).length) {
930                topGalleryConfig.thumbs = {
931                    swiper: galleryThumbs
932                };
933                galleryMainSlider = new SwiperBP(topGallerySelector, topGalleryConfig);
934            }
935        } else {
936            if ($(topGallerySelector).length) {
937                galleryMainSlider = new SwiperBP(topGallerySelector, topGalleryConfig), galleryThumbs = $(".bp-gallery-thumbs-grid .swiper-wrapper");
938
939                if (gridGalleryThumbs.length) {
940                    $(gridGalleryThumbs).on("click", ".swiper-slide", function (item) {
941                        var slide = $(this).attr("data-slide");
942                        galleryMainSlider.slideTo(slide);
943                    });
944                }
945            }
946        }
947
948        $(window).on("bp:after-init", function (data) {
949            featureGallery(galleryMainSlider, galleryThumbs);
950        });
951        $(window).on("bp:after-login", function (data) {
952            featureGallery(galleryMainSlider, galleryThumbs);
953        });
954    }
955
956    function initIncrementSteps(incrementsStepPrices, minPrice, enablePrebidsUnderStartPrice) {
957        if (minPrice === undefined) {
958            return;
959        }
960
961        allIncrementsPrices = [];
962        var startStep = null,
963            price = 0,
964            bidLength = 200,
965            bidCount = 0;
966
967        if (enablePrebidsUnderStartPrice !== undefined && enablePrebidsUnderStartPrice === true) {
968            allIncrementsPrices.push(1);
969        }
970
971        for (var j = 0; j < incrementsStepPrices.length; j++) {
972            if (incrementsStepPrices[j][0] >= price) {
973                if (incrementsStepPrices[j - 1] !== undefined) {
974                    startStep = incrementsStepPrices[j - 1][0];
975                    break;
976                } else {
977                    startStep = incrementsStepPrices[j][0];
978                    break;
979                }
980            }
981        }
982
983        for (var i = 0; i < incrementsStepPrices.length; i++) {
984            var increment = incrementsStepPrices[i],
985                step = increment[1],
986                nextPart = null;
987
988            if (incrementsStepPrices[i + 1] !== undefined) {
989                nextPart = incrementsStepPrices[i + 1][0];
990
991                while (nextPart > price) {
992                    price += step;
993
994                    if (price > minPrice) {
995                        allIncrementsPrices.push(price);
996                        bidCount++;
997                    }
998
999                    if (bidLength === bidCount) {
1000                        return;
1001                    }
1002                }
1003            } else {
1004                while (bidLength >= bidCount) {
1005                    price += step;
1006
1007                    if (price > minPrice) {
1008                        allIncrementsPrices.push(price);
1009                        bidCount++;
1010                    }
1011                }
1012            }
1013        }
1014    }
1015
1016    /*function listIncrementSteps(incrementsStepPrices, minPrice) {
1017        if (incrementsStepPrices === null) {
1018            return [];
1019        }
1020
1021        let incrementsPrices = [],
1022            price = 0,
1023            bidCount = 0;
1024
1025        for (var i = 0; i < incrementsStepPrices.length; i++) {
1026            var increment = incrementsStepPrices[i],
1027                step = increment[1],
1028                nextPart = null;
1029
1030            if (incrementsStepPrices[i + 1] !== undefined) {
1031                nextPart = incrementsStepPrices[i + 1][0];
1032
1033                while (nextPart > price) {
1034                    price += step;
1035                    incrementsPrices.push(price);
1036                    bidCount++;
1037                }
1038            }
1039        }
1040
1041        return incrementsPrices;
1042    }*/
1043
1044    function select2ToolsInit() {
1045        function toolsInit(formTools) {
1046            var formSearch = $("#bp-from-tools .bp-btn-search"),
1047                inputSearch = formTools.find("[name=phrase_by]"),
1048                inputPerPage = formTools.find("[name=per_page]"),
1049                inputFilter = $(".bp-form_category"),
1050                soldFilter = $(".bp-form_sold-unsold"),
1051                btnClear = formTools.find(".bp-btn-close");
1052            var settingsSelect2 = {
1053                width: "resolve",
1054                theme: "default bp-custom-select",
1055                minimumResultsForSearch: -1,
1056                dropdownParent: $(".bp-form_sorter .bp-form-group__inner")
1057            };
1058            var settingsSelect2PerPage = {
1059                width: "resolve",
1060                theme: "default bp-custom-select",
1061                minimumResultsForSearch: -1,
1062                dropdownParent: $(".bp-form_per_page .bp-form-group__inner")
1063            };
1064            var settingsSelect2Category = {
1065                width: "resolve",
1066                theme: "default bp-custom-select",
1067                // minimumResultsForSearch: -1,
1068                dropdownParent: $(".bp-form_category .bp-form-group__inner"),
1069                placeholder: window.bs_lang.select_value,
1070                allowClear: true
1071            };
1072
1073            if (formTools.length) {
1074                formSearch.on("click", ".bp-btn-search", function (event) {
1075                    event.preventDefault();
1076                    formTools.submit();
1077                });
1078                inputSearch.on("input, change", function (event) {
1079                    btnClear.removeClass(window.bs_data.hidden_class);
1080                });
1081                btnClear.on("click", function (event) {
1082                    event.preventDefault();
1083                    inputSearch.val("");
1084                    $(this).addClass(window.bs_data.hidden_class);
1085                    formTools.submit();
1086                });
1087                formSearch.on("submit", function (event) {
1088                    event.preventDefault();
1089                });
1090                var currentValue = inputSearch.val();
1091
1092                if (currentValue !== "") {
1093                    inputSearch.trigger("change");
1094                }
1095            }
1096
1097            var selectField = $(".bp-form_sorter .bp-filter-select2");
1098
1099            if (formTools.length && selectField.length) {
1100                selectField.select2(settingsSelect2);
1101                selectField.on("select2:select", function (event) {
1102                    formTools.submit();
1103                });
1104            }
1105
1106            if (inputFilter.length) {
1107                var selectFieldCategory = $(".bp-form_category .bp-filter-select2");
1108                selectFieldCategory.select2(settingsSelect2Category);
1109                selectFieldCategory.on("select2:clear", function (event) {
1110                    formTools.submit();
1111                });
1112                selectFieldCategory.on("select2:select", function (event) {
1113                    formTools.submit();
1114                });
1115            }
1116
1117            if (formTools.length && inputPerPage.length) {
1118                var selectFieldPerPage = $(".bp-form_per_page .bp-per-page-select2");
1119                selectFieldPerPage.select2(settingsSelect2PerPage);
1120                selectFieldPerPage.on("select2:select", function (event) {
1121                    // Changing items-per-page returns to page 1. Done client-side because the
1122                    // server can't rely on the PHP session for this on cached/CDN auction pages.
1123                    try {
1124                        formTools.attr("action", window.location.pathname.replace(/\/page\/\d+\/?/, "/"));
1125                    } catch (e) {}
1126                    formTools.submit();
1127                });
1128            }
1129
1130            if ($(".bp-day-switcher").length) {
1131                var daysSwitcher = $(".bp-day-switcher");
1132                daysSwitcher.select2({
1133                    width: "resolve",
1134                    theme: "default bp-custom-select",
1135                    minimumResultsForSearch: -1
1136                });
1137                daysSwitcher.on("select2:select", function (event) {
1138                    let data = event.params.data,
1139                        value = data.element.getAttribute("value");
1140
1141                    if (value !== undefined) {
1142                        window.location = value;
1143                    }
1144                });
1145            }
1146
1147            if (soldFilter.length) {
1148                soldFilter.find('.bp-select2').select2(settingsSelect2);
1149                soldFilter.on("select2:select", function (event) {
1150                    formTools.submit();
1151                });
1152            }
1153        }
1154
1155        function toolsInitOutdated() {
1156            var formFilter = $("#bp-from-filter"),
1157                formSearch = $("#bp-from-search"),
1158                inputSearch = formSearch.find("[name=bp_auction_search]"),
1159                inputSearchHidden = $("#bp_auction_search"),
1160                inputFilter = $(".bp-form_category"),
1161                btnClear = formSearch.find(".bp-btn-close"),
1162                soldFilter = $(".bp-form_sold-unsold"),
1163                inputSorter = $(".bp-form_sorter");
1164            var settingsSelect2 = {
1165                width: "resolve",
1166                theme: "default bp-custom-select",
1167                minimumResultsForSearch: -1,
1168                dropdownParent: $(".bp-form_sorter .bp-form-group__inner")
1169            };
1170            var settingsSelect2Category = {
1171                width: "resolve",
1172                theme: "default bp-custom-select",
1173                minimumResultsForSearch: -1,
1174                dropdownParent: $(".bp-form_category .bp-form-group__inner"),
1175                placeholder: window.bs_lang.select_value,
1176                allowClear: true
1177            };
1178
1179            if (formSearch.length) {
1180                formSearch.on("click", ".bp-btn-search", function (event) {
1181                    event.preventDefault();
1182                    formFilter.submit();
1183                });
1184                inputSearch.on("input, change", function (event) {
1185                    btnClear.removeClass(window.bs_data.hidden_class);
1186                });
1187                btnClear.on("click", function (event) {
1188                    event.preventDefault();
1189                    inputSearch.val("");
1190                    inputSearchHidden.val("");
1191                    $(this).addClass(window.bs_data.hidden_class);
1192                    formFilter.submit();
1193                });
1194                formSearch.on("submit", function (event) {
1195                    event.preventDefault();
1196                });
1197                inputSearch.on("keypress", function (event) {
1198                    if (event.keyCode === 13) {
1199                        inputSearchHidden.val(inputSearch.val());
1200                    }
1201                });
1202                var currentValue = inputSearch.val();
1203
1204                if (currentValue !== "") {
1205                    inputSearch.trigger("change");
1206                }
1207            }
1208
1209            if (inputSorter.length) {
1210                var selectField = $(".bp-form_sorter .bp-filter-select2"),
1211                    filterParam = searchGetParam("sort_by");
1212                selectField.select2(settingsSelect2);
1213
1214                if (filterParam !== null) {
1215                    var select = selectField.find('option[value="' + filterParam + '"]');
1216
1217                    if (select.length) {
1218                        selectField.val(filterParam);
1219                        selectField.trigger("change");
1220                    }
1221                }
1222
1223                selectField.on("select2:select", function (event) {
1224                    formFilter.submit();
1225                });
1226            }
1227
1228            if (inputSearch.length) {
1229                inputSearch.on("input, change", function (event) {
1230                    inputSearchHidden.val($(this).val());
1231                });
1232            }
1233
1234            if (inputFilter.length) {
1235                var selectFieldCategory = $(".bp-form_category .bp-filter-select2"),
1236                    filterParamCategory = searchGetParam("category_by");
1237                selectFieldCategory.select2(settingsSelect2Category);
1238
1239                if (filterParamCategory !== null) {
1240                    var selectCategory = selectFieldCategory.find('option[value="' + filterParamCategory + '"]');
1241
1242                    if (selectCategory.length) {
1243                        selectFieldCategory.val(filterParamCategory);
1244                        selectFieldCategory.trigger("change");
1245                    }
1246                }
1247
1248                selectFieldCategory.on("select2:clear", function (event) {
1249                    formFilter.submit();
1250                });
1251                selectFieldCategory.on("select2:select", function (event) {
1252                    formFilter.submit();
1253                });
1254            }
1255        }
1256
1257        var formTools = $("#bp-from-tools");
1258
1259        if (formTools.length > 0) {
1260            toolsInit(formTools);
1261        } else {
1262            toolsInitOutdated();
1263        }
1264    }
1265
1266    function select2init() {
1267        function loadStepSelect() {
1268            (function (auctionInfo) {
1269                var select = $("#bidFormPrice"),
1270                    minBidPrice = 1,
1271                    enablePrebidsUnderStartPrice = false;
1272
1273                if (auctionInfo.increments !== undefined) {
1274                    hangUpEvent("bp:get-increment-steps", auctionInfo.increments);
1275                }
1276
1277                if (currentItemInfo !== null) {
1278                    var itemInfo = currentItemInfo,
1279                        settings = bidspiritApi.getAuctionSettingsData();
1280                    select.empty();
1281
1282
1283                    if (itemInfo.leadingBid !== undefined && itemInfo.leadingBid.isSelf && itemInfo.selfAbsenteeBid !== undefined && !isNaN(itemInfo.selfAbsenteeBid.price) && itemInfo.selfAbsenteeBid.price > 0) {
1284                        minBidPrice = itemInfo.selfAbsenteeBid.price - 1;
1285                    } else if (itemInfo.leadingBid !== undefined) {
1286                        minBidPrice = itemInfo.leadingBid.price;
1287                    } else if (settings.enablePrebidsUnderStartPrice !== undefined && settings.enablePrebidsUnderStartPrice === true) {
1288                        enablePrebidsUnderStartPrice = true;
1289
1290                        if (auctionInfo.increments[0][0] !== undefined && auctionInfo.increments[0][0] > 0) {
1291                            minBidPrice = auctionInfo.increments[0][0] - 1;
1292                        } else {
1293                            minBidPrice = 0;
1294                        }
1295                    } else if (itemInfo.startPrice !== undefined) {
1296                        minBidPrice = itemInfo.startPrice;
1297                        select.append('<option value="' + minBidPrice + '">' + formattedPrice(minBidPrice, currencySymbol) + "</option>");
1298                    } else {
1299                        select.append('<option value="0">' + formattedPrice(0, currencySymbol) + "</option>");
1300                    }
1301
1302                    if (isNaN(minBidPrice) || minBidPrice === undefined || minBidPrice === null) {
1303                        if (itemInfo.leadingBid !== undefined && !isNaN(itemInfo.leadingBid.price)) {
1304                            minBidPrice = itemInfo.leadingBid.price;
1305                        } else if (itemInfo.startPrice !== undefined && !isNaN(itemInfo.startPrice)) {
1306                            minBidPrice = itemInfo.startPrice;
1307                        } else {
1308                            minBidPrice = 0;
1309                        }
1310                    }
1311
1312                    initIncrementSteps(bidspiritApi.getAuctionInfo().increments, minBidPrice);
1313
1314                    for (var i = 0; i < allIncrementsPrices.length; i++) {
1315                        var stepPrice = allIncrementsPrices[i];
1316
1317                        if (stepPrice !== undefined) {
1318                            select.append('<option value="' + stepPrice + '">' + formattedPrice(stepPrice, currencySymbol) + "</option>");
1319                        }
1320                    }
1321                }
1322            })(bidspiritApi.getAuctionInfo());
1323        }
1324
1325        loadStepSelect();
1326        var settingsSelect2 = {
1327            width: "resolve",
1328            theme: "default bp-custom-select",
1329            minimumResultsForSearch: -1,
1330            templateSelection: function (data, container) {
1331                renderCommissionPrice(data.id);
1332                return data.text;
1333            }
1334        };
1335        $(".bp-select2").each(function (index, elem) {
1336            $(elem).select2(settingsSelect2).trigger("change");
1337        });
1338    }
1339
1340    function select2build(elemId, items) {
1341        return $(elemId).select2({
1342            data: items,
1343            minimumResultsForSearch: -1,
1344            width: "resolve"
1345        });
1346    }
1347
1348    function setInvitationsEnabled(value) {
1349        bidspiritQuery("users/setInvitationsEnabled", {
1350            sessionId: bidspiritSessionId,
1351            isEnabled: value
1352        });
1353    }
1354
1355    // Consolidated notification preferences (users/updateAlertsPreferences) — saves
1356    // invitations + bid/overbid email prefs together in one call, replacing the separate
1357    // setInvitationsEnabled call. leadingBidAlertsEnabled is passed through unchanged
1358    // (it is auto-managed via Firebase push in saveFirebaseUser, so it has no UI toggle).
1359    function saveAlertsPreferences() {
1360        var user = bidspiritApi.getBidspiritUser() || {};
1361        var allowInvitations = $("#invitationsEnabled input").prop("checked");
1362        var sendBidEmails = $("#af-pref-bid-emails").length ? $("#af-pref-bid-emails").prop("checked") : !!user.sendBidEmails;
1363        var sendOverBidEmails = $("#af-pref-overbid-emails").length ? $("#af-pref-overbid-emails").prop("checked") : !!user.sendOverBidEmails;
1364
1365        bidspiritQuery("users/updateAlertsPreferences", {
1366            sessionId: bidspiritSessionId,
1367            allowInvitations: allowInvitations,
1368            leadingBidAlertsEnabled: !!user.leadingBidAlertsEnabled,
1369            sendBidEmails: sendBidEmails,
1370            sendOverBidEmails: sendOverBidEmails
1371        }, function (data) {
1372            if (!checkError(data)) {
1373                user.allowInvitations = allowInvitations;
1374                user.sendBidEmails = sendBidEmails;
1375                user.sendOverBidEmails = sendOverBidEmails;
1376                bidspiritApi.setBidspiritUser(user);
1377            }
1378        });
1379    }
1380
1381    // === Live bid auto-refresh for the profile Wish List / My Bids "Future" sections ===
1382    // Polls items/getItemsInfo every 10s and patches current bid amounts in place (no reload),
1383    // flashing any price that changed. Only touches non-ended lots in a visible "*-future" section.
1384    var afBidWatch = { intervalId: null, busy: false };
1385    var AF_BIDWATCH_MS = 10000;
1386    var AF_BIDWATCH_KEY = "af_bidwatch_enabled";
1387    var AF_FUTURE_SEL = "[id^='bp-paginated-'][id$='-future']:visible";
1388
1389    function afBidWatchEnabled() {
1390        try { return localStorage.getItem(AF_BIDWATCH_KEY) === "1"; } catch (e) { return false; }
1391    }
1392
1393    function afSetBidWatchEnabled(on) {
1394        try { localStorage.setItem(AF_BIDWATCH_KEY, on ? "1" : "0"); } catch (e) {}
1395        $(".af-bidwatch-checkbox").prop("checked", !!on);
1396    }
1397
1398    function afStopBidWatch() {
1399        if (afBidWatch.intervalId) {
1400            clearInterval(afBidWatch.intervalId);
1401            afBidWatch.intervalId = null;
1402        }
1403        afBidWatch.busy = false;
1404    }
1405
1406    function afStartBidWatch() {
1407        afStopBidWatch();
1408        if (!afBidWatchEnabled()) {
1409            return;
1410        }
1411        afBidWatchTick();
1412        afBidWatch.intervalId = setInterval(afBidWatchTick, AF_BIDWATCH_MS);
1413    }
1414
1415    function afFlashPrice($node) {
1416        if (!$node || !$node.length) {
1417            return;
1418        }
1419        $node.removeClass("af-bid-flash");
1420        void $node[0].offsetWidth; // restart the CSS animation
1421        $node.addClass("af-bid-flash");
1422        setTimeout(function () { $node.removeClass("af-bid-flash"); }, 1500);
1423    }
1424
1425    function afBidWatchTick() {
1426        if (!afBidWatchEnabled()) { afStopBidWatch(); return; }
1427        if (document.hidden || afBidWatch.busy) {
1428            return;
1429        }
1430
1431        var $lots = $(AF_FUTURE_SEL + " .bp-lot").filter(function () {
1432            return $(this).attr("data-ended") !== "1" &&
1433                $(this).attr("data-lot-index") !== undefined &&
1434                !!$(this).attr("data-auction-number");
1435        });
1436        if (!$lots.length) {
1437            return;
1438        }
1439
1440        var groups = {};
1441        $lots.each(function () {
1442            var a = $(this).attr("data-auction-number");
1443            var li = $(this).attr("data-lot-index");
1444            if (!a || li === undefined) { return; }
1445            (groups[a] = groups[a] || []).push(li);
1446        });
1447
1448        var auctionIds = Object.keys(groups);
1449        if (!auctionIds.length) {
1450            return;
1451        }
1452
1453        afBidWatch.busy = true;
1454        var pending = auctionIds.length;
1455        function done() { pending--; if (pending <= 0) { afBidWatch.busy = false; } }
1456
1457        auctionIds.forEach(function (auctionId) {
1458            bidspiritQuery("items/getItemsInfo", {
1459                sessionId: bidspiritSessionId,
1460                auctionId: auctionId,
1461                lotIndexes: groups[auctionId].join(",")
1462            }, function (data) {
1463                if (!data || !data.response || !data.response.itemsInfo) { return; }
1464                var resp = data.response;
1465                var live = resp.auctionIsLive === true;
1466                groups[auctionId].forEach(function (li) {
1467                    var info = resp.itemsInfo[li];
1468                    if (!info) { return; }
1469                    var $lot = $(AF_FUTURE_SEL + " .bp-lot[data-auction-number='" + auctionId + "'][data-lot-index='" + li + "']");
1470                    if ($lot.length) { afPatchWatchedLot($lot.first(), info, live); }
1471                });
1472            }, function () {}, done);
1473        });
1474    }
1475
1476    // Is this rendered lot part of a shop? Profile rows carry the auction id in
1477    // data-auction-number, and bs_data.shop_auction_ids lists every shop on the
1478    // site (legacy "Auctions as shop" plus any BidSpirit Shop).
1479    function afIsShopLot($lot) {
1480        var ids = (window.bs_data && bs_data.shop_auction_ids) ? bs_data.shop_auction_ids : [];
1481        if (!ids.length) {
1482            return false;
1483        }
1484        return ids.indexOf(String($lot.attr("data-auction-number"))) !== -1;
1485    }
1486
1487    function afPatchWatchedLot($lot, info, auctionIsLive) {
1488        var L = window.afBidWatchLang || {};
1489        var current = (auctionIsLive && info.liveBid && info.liveBid.price !== undefined && info.liveBid.price !== null)
1490            ? info.liveBid : info.leadingBid;
1491        var hasSelfAbsentee = info.selfAbsenteeBid && info.selfAbsenteeBid.price !== undefined && info.selfAbsenteeBid.price !== null;
1492        var sold = (info.soldBid && info.soldBid.isSold === true) || (current && current.isSold === true);
1493
1494        var $tool = $lot.find(".bp-lot__tool").first();
1495        var $price = $tool.find(".bp-price").first();
1496        var $subtitle = $tool.find(".bp-subtitle").first();
1497        var $message = $lot.find(".bp-lot__message").first();
1498        if (!$tool.length || !$price.length) {
1499            return;
1500        }
1501
1502        var oldPriceText = $.trim($price.text());
1503        var newPriceVal, subtitle, bgClass = "", withLead = false, messageHtml = "";
1504
1505        if (sold) {
1506            var sb = (info.soldBid && info.soldBid.price !== undefined) ? info.soldBid : current;
1507            newPriceVal = sb.price;
1508            subtitle = sb.isSelf ? (L.sold_to_you_for || "Sold to you for") : (L.sold_for || "Sold for");
1509            bgClass = sb.isSelf ? "bp-bg-green" : "bp-bg-blue";
1510            withLead = true;
1511            $lot.attr("data-ended", "1"); // ended during watch — drop from future ticks
1512        } else if (current && current.price !== undefined && current.price !== null) {
1513            newPriceVal = current.price;
1514            subtitle = current.isSelf ? (L.your_leading_bid || "Your leading bid") : (L.leading_bid || "Leading bid");
1515            withLead = true;
1516            if (current.isSelf) {
1517                bgClass = "bp-bg-green";
1518            } else if (hasSelfAbsentee) {
1519                bgClass = "bp-bg-red";
1520            }
1521
1522            if (!current.isSelf && hasSelfAbsentee) {
1523                messageHtml = '<p class="bp-lot__message-inner bp-text-red bp-lot__message-you_bid">' +
1524                    (L.your_bid_of || "Your bid of") + " " + formattedPrice(info.selfAbsenteeBid.price, currencySymbol) + " " +
1525                    (L.outbid_by_higher || "has been outbid by a higher bid") + "</p>";
1526            } else if (current.isSelf && hasSelfAbsentee) {
1527                messageHtml = '<p class="bp-lot__message-inner bp-text-green bp-lot__message-you_bid">' +
1528                    (L.your_max_absentee_bid || "Your max absentee bid") + ": " + formattedPrice(info.selfAbsenteeBid.price, currencySymbol) + "</p>";
1529            }
1530        } else if (afIsShopLot($lot)) {
1531            // A shop item is bought at a fixed price and has no start price
1532            // (the API reports 0). Without this branch every 10s tick overwrote
1533            // the rendered "Purchase price" with "Start price: $0".
1534            var buyout = (info.buyoutPrice !== undefined && info.buyoutPrice !== null) ? info.buyoutPrice : 0;
1535            if (buyout <= 0) {
1536                // Nothing meaningful to patch — leave what was rendered rather
1537                // than replacing a correct price with a wrong one.
1538                return;
1539            }
1540            newPriceVal = buyout;
1541            subtitle = L.purchase_price || "Purchase Price";
1542        } else {
1543            newPriceVal = info.startPrice;
1544            subtitle = L.start_price || "Start price";
1545        }
1546
1547        if ($subtitle.length) {
1548            $subtitle.text(subtitle + ":");
1549        }
1550        $tool.removeClass("bp-bg-green bp-bg-red bp-bg-blue");
1551        if (bgClass) {
1552            $tool.addClass(bgClass);
1553        }
1554        if (withLead) {
1555            $tool.addClass("bp-lead");
1556        } else {
1557            $tool.removeClass("bp-lead");
1558        }
1559        if ($message.length) {
1560            $message.html(messageHtml);
1561        }
1562
1563        var newPriceText = formattedPrice(newPriceVal, currencySymbol);
1564        if (newPriceText !== oldPriceText) {
1565            $price.text(newPriceText);
1566            afFlashPrice($price);
1567        }
1568    }
1569
1570    // Instant refresh when the user returns to the tab (registered once).
1571    if (!window.afBidWatchVisBound) {
1572        window.afBidWatchVisBound = true;
1573        document.addEventListener("visibilitychange", function () {
1574            if (!document.hidden && afBidWatchEnabled()) {
1575                if (!afBidWatch.intervalId) { afStartBidWatch(); } else { afBidWatchTick(); }
1576            }
1577        });
1578    }
1579
1580    function updateUserDisplay() {
1581        (function () {
1582            var userFront = $("#userFront");
1583
1584            if (bidspiritUser && userFront.length) {
1585                loadTemplate("#modal-profile-content", "user-profile-form", bidspiritUser);
1586            }
1587        })();
1588    }
1589
1590    function someCode() {
1591        var singleLogin = $(".bp-single-login-btn");
1592
1593        if (singleLogin.length && bidspiritUser !== undefined) {
1594            singleLogin.addClass(window.bs_data.hidden_class);
1595        }
1596
1597        if (bidspiritUser !== undefined) {
1598            $(".bp-register-api, .bp-login-api").each(function (index, elem) {
1599                if (elem.name === "bp_short_login_form" || elem.name === "bp_short_register_form") {
1600                    elem.innerHTML = '<div class="bs-loader-small"></div>';
1601                    window.location = window.bs_data.link_profile;
1602                } else {
1603                    elem.innerHTML = "<p class='bp-notice'>" + window.bs_lang.login_success_hello + ", " + bidspiritUser.firstName + "!</p>";
1604                }
1605            });
1606        }
1607    }
1608
1609    function noticeUser(bidspiritUser) {
1610        var mainContentContainer = $(".bp-main-container");
1611
1612        if (bidspiritUser !== undefined && bidspiritUser.approvalState !== null && bidspiritUser.approvalState !== "APPROVED" && mainContentContainer.length) {
1613            mainContentContainer.empty();
1614            loadTemplateInsert(mainContentContainer, "main-notice-template", {
1615                type: bidspiritUser.approvalState,
1616                emailConfirmed: bidspiritUser.emailConfirmed
1617            }, true, true, function () {
1618                resendEmailAction();
1619                changeEmailAction();
1620            });
1621        }
1622    }
1623
1624    function renderVatField(auctionHouseData) {
1625        var fullVatPrice = Boolean(parseInt($("#single-lot").attr("data-full-price-vat")));
1626
1627        if (auctionHouseData.noVatOnCommission && !fullVatPrice) {
1628            $(".vat-field").remove();
1629        } else if (auctionHouseData.noVatOnCommission && fullVatPrice) {
1630            $(".vat-field span").html(window.bs_lang.vat_lot_price_commission);
1631        }
1632    }
1633
1634    /**
1635     * Checks for unpaid invoices and shows a site-wide banner.
1636     * Uses server-side WordPress transients to avoid API calls on every page load.
1637     * Called once from initCore() when a user is logged in.
1638     *
1639     * Session logic:
1640     *  - First page load of a browser session (or after login): always fetches fresh from BidSpirit API.
1641     *  - Subsequent page loads in the same session: uses the server-side cache.
1642     *  - If the user clicked "Pay Now" (banner or individual bill): banner is suppressed for this session.
1643     */
1644    function checkUnpaidBillsBanner() {
1645        // Site has the My Invoices tab disabled — the banner's "Pay Now" would
1646        // link to a profile tab that doesn't exist, so skip the check entirely.
1647        if (window.afBillingTabEnabled === false) return;
1648        if (!bidspiritUser || !bidspiritUser.email) return;
1649        var userKey = bidspiritUser.email;
1650
1651        try {
1652            // First page load of a session (or right after login): bypass cache, fetch fresh
1653            if (!sessionStorage.getItem("af_bills_session_checked")) {
1654                fetchAndCacheUnpaidBills(userKey);
1655                return;
1656            }
1657        } catch(e) {}
1658
1659        // Subsequent page loads: check server-side cache first
1660        $.ajax({
1661            type: "post",
1662            dataType: "json",
1663            url: window.wp_data.ajax_url,
1664            data: {
1665                action: "af_get_unpaid_status",
1666                security: window.wp_nonce,
1667                user_key: userKey
1668            }
1669        }).done(function(res) {
1670            if (res.success && res.data.cached) {
1671                // Cache hit — use stored status, no BidSpirit API call
1672                if (res.data.has_unpaid) {
1673                    renderUnpaidBanner(res.data.count);
1674                }
1675                return;
1676            }
1677            // Cache miss — fetch from BidSpirit API
1678            fetchAndCacheUnpaidBills(userKey);
1679        }).fail(function() {
1680            // WP AJAX failed — try BidSpirit directly as fallback
1681            fetchAndCacheUnpaidBills(userKey);
1682        });
1683    }
1684
1685    /**
1686     * Fetches unpaid bills from BidSpirit and stores result in server-side cache.
1687     * Sets a sessionStorage flag so subsequent page loads in the same session use the cache.
1688     */
1689    function fetchAndCacheUnpaidBills(userKey) {
1690        bidspiritQuery("bills/getUnpaidBills", {
1691            sessionId: bidspiritSessionId,
1692            language: LANG
1693        }, function (data) {
1694            var bills = data && data.response ? data.response : [];
1695            if (!Array.isArray(bills)) bills = [];
1696            var count = bills.length;
1697
1698            // Mark this session as checked so subsequent page loads use the cache
1699            try { sessionStorage.setItem("af_bills_session_checked", "1"); } catch(e) {}
1700
1701            // Store in server-side cache
1702            $.ajax({
1703                type: "post",
1704                url: window.wp_data.ajax_url,
1705                data: {
1706                    action: "af_set_unpaid_status",
1707                    security: window.wp_nonce,
1708                    user_key: userKey,
1709                    count: count
1710                }
1711            });
1712
1713            if (count > 0) {
1714                renderUnpaidBanner(count);
1715            }
1716        }, function () {
1717            // BidSpirit API failed — don't show banner
1718        });
1719    }
1720
1721    /**
1722     * Clears the server-side unpaid bills cache for the current user.
1723     */
1724    function clearUnpaidBillsCache() {
1725        if (!bidspiritUser || !bidspiritUser.email) return;
1726        $.ajax({
1727            type: "post",
1728            url: window.wp_data.ajax_url,
1729            data: {
1730                action: "af_set_unpaid_status",
1731                security: window.wp_nonce,
1732                user_key: bidspiritUser.email,
1733                clear: "1"
1734            }
1735        });
1736    }
1737
1738    /**
1739     * Renders (or removes) the unpaid invoice alert banner.
1740     */
1741    function renderUnpaidBanner(count) {
1742        // Remove any existing banner first
1743        $(".bp-unpaid-invoice-banner").remove();
1744
1745        if (!count || count <= 0) return;
1746
1747        var profileUrl = (window.bs_data && window.bs_data.link_profile)
1748            ? window.bs_data.link_profile + "#bp-bills"
1749            : "#bp-bills";
1750
1751        var bannerHtml = '<div class="bp-unpaid-invoice-banner" style="' +
1752            'width: 100%; z-index: 999; ' +
1753            'background: #cc0000; ' +
1754            'color: #fff; text-align: center; padding: 10px 20px; ' +
1755            'font-size: 14px; font-family: -apple-system, BlinkMacSystemFont, sans-serif; ' +
1756            'display: flex; align-items: center; justify-content: center; gap: 15px;">' +
1757            '<span style="font-weight: 700;">⚠ This account has open invoices</span>' +
1758            '<a href="' + profileUrl + '" class="bp-unpaid-pay-btn" style="' +
1759            'display: inline-block; background: #fff; color: #000; ' +
1760            'padding: 5px 20px; border-radius: 50px; text-decoration: none; ' +
1761            'font-weight: 700; font-size: 13px; ' +
1762            'transition: background 0.2s ease; border: none; cursor: pointer;"' +
1763            ' onmouseover="this.style.background=\'#e6e6e6\'" onmouseout="this.style.background=\'#fff\'"' +
1764            '>Pay Now</a>' +
1765            '</div>';
1766
1767        // Insert after the site header
1768        var $header = $("header.elementor-location-header, #masthead, header").first();
1769        if ($header.length) {
1770            $header.after(bannerHtml);
1771        } else {
1772            $("body").prepend(bannerHtml);
1773        }
1774
1775        // Clear cache and remove banner; next page load will do a fresh check
1776        $(".bp-unpaid-pay-btn").on("click", function(e) {
1777            clearUnpaidBillsCache();
1778            try { sessionStorage.removeItem("af_bills_session_checked"); } catch(e2) {}
1779
1780            // If we're already on the profile page, activate the tab directly
1781            var billsTab = $('.bp-tabs-block a[href="#bp-bills"]');
1782            if (billsTab.length) {
1783                e.preventDefault();
1784                // Set hash — the hashchange listener will handle the tab switch + scroll
1785                window.location.hash = "#bp-bills";
1786                // Remove the banner
1787                $(".bp-unpaid-invoice-banner").remove();
1788            }
1789        });
1790    }
1791
1792    /**
1793     * Watches for clicks on individual invoice "Pay Now" / "Resume" buttons
1794     * in the My Invoices tab. Clears the server-side unpaid cache so the
1795     * banner re-evaluates on the next page load.
1796     */
1797    $(document).on("click", "#profile-bills-section a.bp-btn", function() {
1798        var href = $(this).attr("href") || "";
1799        // Only act on payment links (Pay Now / Resume), not View or Download PDF
1800        if (href.indexOf("standaloneScene=payment") !== -1 || href.indexOf("paymentUrl") !== -1) {
1801            clearUnpaidBillsCache();
1802            try { sessionStorage.removeItem("af_bills_session_checked"); } catch(e) {}
1803            // Remove the banner immediately since user is taking action
1804            $(".bp-unpaid-invoice-banner").remove();
1805        }
1806    });
1807
1808    function initApp() {
1809        var firebaseTokenFCM = getCookie("FCM_TOKEN");
1810
1811        if (firebaseTokenFCM !== "") {
1812            try {
1813                localStorage.setItem("token_firebase_push_id", firebaseTokenFCM);
1814            } catch (e) {
1815                console.error("Local storage disabled");
1816            }
1817        }
1818    }
1819    
1820    function init() {
1821        $("#bsLoader").removeClass(window.bs_data.hidden_class);
1822        bidspiritApi.setBidspiritSessionId();
1823        bidspiritQuery("users/initSession", {
1824            sessionId: bidspiritApi.getBidspiritSessionId(),
1825            language: LANG
1826        }, function (data) {
1827            let coreData = data;
1828            if (data.response !== undefined) {
1829                function initCore(data) {
1830                    updateUserDisplay();
1831                    updateDisplay();
1832                    loginLink();
1833                    someCode();
1834
1835                    galleryInitial();
1836                    updateLotsWidget();
1837                    updateWidgetLots();
1838                    widgetSliders();
1839
1840                    hangUpEvent("bp:after-init", data.response);
1841                    checkPoint("bp-init");
1842
1843                    if (bidspiritUser !== undefined) {
1844                        checkPoint("bp-login");
1845
1846                        if (bidspiritUser.approvalState !== undefined && bidspiritUser.approvalState === "APPROVED") {
1847                            checkPoint("bp-approved-user");
1848                        }
1849
1850                        // Check for unpaid invoices (uses server-side cache)
1851                        checkUnpaidBillsBanner();
1852                    }
1853                }
1854
1855                if (data.response.user !== undefined) {
1856                    bidspiritApi.setAuthToken(data.response.user.authToken);
1857                }
1858
1859                try {
1860                    bidspiritSessionId = localStorage.bidspiritSessionId = data.response.sessionId;
1861                } catch (e) {
1862                    console.error("Local storage disabled");
1863                    bidspiritSessionId = "";
1864                }
1865
1866                bidspiritQuery("settings/getHouseInfo", {
1867                    sessionId: bidspiritSessionId,
1868                    language: LANG
1869                }, function (data) {
1870                    auctionHouseData = data.response;
1871                    bidspiritApi.setAuctionHouseData(auctionHouseData);
1872                });
1873
1874                bidspiritApi.setBidspiritUser(data.response.user);
1875
1876                bidspiritQuery("settings/getSettings", {
1877                    sessionId: bidspiritSessionId,
1878                    language: LANG
1879                }, function (data) {
1880                    auctionSettingsData = data.response;
1881                    bidspiritApi.setAuctionSettingsData(auctionSettingsData);
1882
1883                    initCore(coreData);
1884                });
1885            }
1886
1887            bidspiritQuery("settings/getCountriesList", {
1888                sessionId: bidspiritSessionId,
1889                language: LANG
1890            }, function (data) {
1891                countriesList = data.response;
1892                bidspiritApi.setCountriesList(countriesList);
1893
1894                (function () {
1895                    let codeSelect = jQuery('.countryCodeField'),
1896                        countriesList = bidspiritApi.getCountriesList(),
1897                        codeItems = jQuery.map(countriesList, function (obj) {
1898                            if (obj.phoneCode !== undefined) {
1899                                return {
1900                                    id: obj.phoneCode,
1901                                    text: obj.phoneCode + " (" + obj.name + ")"
1902                                };
1903                            }
1904                        });
1905                    codeSelect.each(function (index, elem) {
1906                        if (elem.classList.contains(window.bs_data.hidden_class)) {
1907                            elem.classList.remove(window.bs_data.hidden_class);
1908                        }
1909
1910                        if (!!jQuery(elem).select2) {
1911                            jQuery(elem).select2({
1912                                theme: "default bp-custom-select",
1913                                width: "resolve",
1914                                data: codeItems,
1915                                placeholder: window.bs_lang.country_code
1916                            });
1917                        }
1918                    })
1919                })();
1920            });
1921
1922            passwordShowAction();
1923        }, function (data) {
1924            disableLoader();
1925        });
1926    }
1927
1928    function loadBid(lotIndex, currentAuctionNumber) {
1929        // A BidSpirit Shop lot belongs to no auction, so items/getAuctionItem
1930        // and items/getItemsInfo have nothing to return for it — calling them
1931        // would just log the lot as not found. Drive the buy-now UI from the
1932        // server-rendered price instead.
1933        if (bsShopIsActive()) {
1934            bsShopRenderBuy(lotIndex, currentAuctionNumber);
1935            return;
1936        }
1937
1938        function vatAndCommission() {
1939            if (!!document.getElementById('vat-and-commission')) {
1940                let itemInfo = bidspiritApi.getAuctionItemInfo(),
1941                    auctionInfo = bidspiritApi.getAuctionInfo();
1942                if (itemInfo.item !== undefined) {
1943                    loadTemplate('#vat-and-commission', 'vat-and-commission-template', {
1944                        itemInfo: itemInfo,
1945                        fullPriceInfo: getFullPriceInfo(itemInfo, auctionInfo, 1),
1946                        auctionHouseData: bidspiritApi.getAuctionSettingsData(),//bidspiritApi.getAuctionHouseData() - some fields depricated
1947                        settings: bidspiritApi.getAuctionSettingsData(),
1948                        bidspiritUser: bidspiritUser,
1949                    })
1950                }
1951            }
1952        }
1953
1954        if (currentAuctionNumber === "") {
1955            return;
1956        }
1957
1958        bidspiritQuery("items/getAuctionItem", {
1959            sessionId: bidspiritSessionId,
1960            auctionId: currentAuctionNumber,
1961            itemIndex: lotIndex,
1962            language: LANG
1963        }, function (data) {
1964            String.prototype.allReplace = function (obj) {
1965                var retStr = this;
1966
1967                for (var x in obj) {
1968                    retStr = retStr.replace(new RegExp("\\" + x, "g"), obj[x]);
1969                }
1970
1971                return retStr;
1972            }; //oversea
1973
1974            bidspiritApi.setAuctionItemInfo(data.response);
1975
1976            if (data.response !== undefined) {
1977                hangUpEvent("bp:get-auction-item", data.response);
1978            }
1979
1980            vatAndCommission();
1981
1982            if ($('#startPriceSingleLot').length > 0) {
1983                if (data.response.item.startPrice !== undefined && data.response.item.currency !== undefined) {
1984                    $('#startPriceSingleLot').html(formattedPrice(data.response.item.startPrice, data.response.item.currency, true));
1985                }
1986            }
1987
1988            bidspiritQuery("items/getItemsInfo", {
1989                sessionId: bidspiritSessionId,
1990                auctionId: currentAuctionNumber,
1991                lotIndexes: lotIndex
1992            }, function (data) {
1993                if (!checkError(data)) {
1994                    if (data.response !== undefined) {
1995                        hangUpEvent("bp:get-items-info", data.response);
1996                    }
1997
1998                    // Live auction: pop the "Auction is live" modal on single-lot pages
1999                    // (catalogue pages get this via updateBidsInfoDisplay)
2000                    if (data.response !== undefined && data.response.auctionIsLive === true) {
2001                        loadTemplate("#modal-islive-content", "modal-islive-template", {
2002                            bidsInfoData: data.response,
2003                            linkLive: bidspiritApi.getLinkOnLive()
2004                        });
2005                        MicroModal.init(microModalInitConfig());
2006                        MicroModal.show("modal-islive", microModalInitConfig());
2007                    }
2008
2009                    if (data.response.notFoundLots[0] === lotIndex) {
2010                        console.error("error", "Lot " + lotIndex, window.bs_lang.not_found);
2011                        disableLoader();
2012                    } else {
2013                        currentItemInfoResponse = data.response;
2014                        currentItemInfo = data.response.itemsInfo[lotIndex];
2015
2016                        if (bpIsset(currentItemInfo)) {
2017                            if (bpIsset(currentItemInfo.isFavorite) && currentItemInfo.isFavorite) {
2018                                $("#single-lot").find(".bp__wishlist").addClass("bp__wishlist-active");
2019                            }
2020
2021                            displayBidFormData(currentItemInfo);
2022                            buyoutAction(currentItemInfoResponse, lotIndex, currentAuctionNumber);
2023                            postSaleAction(currentItemInfoResponse, lotIndex, currentAuctionNumber);
2024                            renderVatField(auctionHouseData);
2025                            hangUpEvent("bp:after-getItemsInfo-content-item", currentItemInfo, $("#single-lot"));
2026                        } else {
2027                            noticeSwall("info", window.bs_lang.not_found);
2028                            disableLoader();
2029                        }
2030                    }
2031                } else {
2032                    disableLoader();
2033                }
2034            });
2035        });
2036    }
2037
2038    // ── BidSpirit Shop ────────────────────────────────────────────────────
2039    // A Shop lot is a fixed-price item that lives outside the auction system:
2040    // shop/getShopItems reports auctionId 0 and no itemIndex, so none of the
2041    // auction endpoints can describe it. AuctionForge imports it as an ordinary
2042    // lot (inc/import/ShopList.php) and the template stamps its price onto
2043    // #preSale-section, which is all the buy flow actually needs.
2044
2045    function bsShopSection() {
2046        return $("#preSale-section[data-bs-shop='1']");
2047    }
2048
2049    // True on any shop surface — the lot page (#preSale-section) and the shop
2050    // catalogue page (the lots container), which both stamp data-bs-shop.
2051    function bsShopIsActive() {
2052        return $("[data-bs-shop='1']").length > 0;
2053    }
2054
2055    // Minimal auctionInfo for a shop. There is no auction to fetch, so anything
2056    // reading bidspiritApi.getAuctionInfo() gets a sane object rather than
2057    // undefined. Commission is 0 deliberately: shop/purchaseShopItem requires
2058    // price to equal shopPrice exactly, so a premium must not be displayed.
2059    function bsShopAuctionInfo() {
2060        return {
2061            id: 0,
2062            state: "READY",
2063            commission: 0,
2064            approvalRequired: false,
2065            paymentMethodRequired: false,
2066            auctionIsLive: false,
2067            days: [],
2068            increments: []
2069        };
2070    }
2071
2072    // Rebuild the shape items/getItemsInfo would have returned, from what the
2073    // server already rendered. Keeps the whole downstream buy flow unchanged.
2074    function bsShopItemInfoResponse(lotIndex) {
2075        var $section = bsShopSection(),
2076            price = parseInt($section.attr("data-shop-price"), 10) || 0,
2077            sold = parseInt($section.attr("data-shop-sold"), 10) || 0,
2078            itemInfo = {
2079                lotIndex: lotIndex,
2080                lotId: parseInt($section.attr("data-shop-lot-id"), 10) || parseInt(lotIndex, 10),
2081                startPrice: 0,
2082                buyoutPrice: price
2083            };
2084
2085        // A sold shop item keeps its page but must not offer a buy button —
2086        // buyoutAction() already bails when soldBid carries a price.
2087        if (sold > 0) {
2088            itemInfo.soldBid = {price: sold, isSold: true, isSelf: false};
2089        }
2090
2091        var itemsInfo = {};
2092        itemsInfo[lotIndex] = itemInfo;
2093
2094        return {
2095            state: "READY",
2096            auctionIsLive: false,
2097            notFoundLots: [],
2098            itemsInfo: itemsInfo
2099        };
2100    }
2101
2102    function bsShopRenderBuy(lotIndex, auctionNumber) {
2103        var response = bsShopItemInfoResponse(lotIndex);
2104
2105        currentItemInfoResponse = response;
2106        currentItemInfo = response.itemsInfo[lotIndex];
2107
2108        buyoutAction(response, lotIndex, auctionNumber);
2109        hangUpEvent("bp:after-getItemsInfo-content-item", currentItemInfo, $("#single-lot"));
2110
2111        // #bsLoader ships visible and is only ever hidden by disableLoader() in
2112        // the getAuctionItem/getItemsInfo callbacks — which this path skips. Without
2113        // this the page renders correctly but sits behind a full-screen 90%-white
2114        // overlay at z-index 999 that also swallows every click.
2115        disableLoader();
2116    }
2117
2118    function buyoutAction(currentItemInfoResponse, lotIndex, auctionNumber) {
2119        var currentItemInfo = currentItemInfoResponse.itemsInfo[lotIndex],
2120            preSaleSectionSelector = "#preSale-section",
2121            auctionInfo = bidspiritApi.getAuctionInfo(),
2122            // Shop lots have no auction behind them, so these two lookups come
2123            // back empty. Defaulting keeps the shared path working for both.
2124            auctionCommission = (auctionInfo && auctionInfo.commission) ? auctionInfo.commission : 0,
2125            modalPreSaleForm = "#modal-pre-sale-content",
2126            auctionItemInfo = bidspiritApi.getAuctionItemInfo(),
2127            fullPriceVat = (auctionItemInfo && auctionItemInfo.item) ? auctionItemInfo.item.fullPriceVat : false,
2128            isShop = Boolean(parseInt($(preSaleSectionSelector).attr("data-is-shop"))),
2129            isBsShop = $(preSaleSectionSelector).attr("data-bs-shop") === "1";
2130
2131        if (currentItemInfoResponse.state === "ENDED" || currentItemInfoResponse.state === "ARCHIVED") {
2132            return;
2133        }
2134
2135        if (currentItemInfoResponse.auctionIsLive === true || currentItemInfo.buyoutPrice === undefined) {
2136            return;
2137        }
2138
2139        if (currentItemInfo.leadingBid !== undefined && currentItemInfo.leadingBid.price !== undefined && currentItemInfo.leadingBid.price >= currentItemInfo.buyoutPrice) {
2140            return;
2141        }
2142
2143        if (currentItemInfo.soldBid !== undefined && currentItemInfo.soldBid.price !== undefined) {
2144            return;
2145        }
2146
2147        $(modalPreSaleForm).off("click", "#agreeSaleBid").on("click", "#agreeSaleBid", function (event) {
2148            event.preventDefault();
2149            let $this = $(this);
2150            $this.prop("disabled", true);
2151            $this.addClass("bp-disabled");
2152            // A BidSpirit Shop item is bought through the shop endpoint, which
2153            // is keyed on the item's own lotId rather than an auction + index,
2154            // and requires price to equal shopPrice exactly.
2155            var purchaseAction = isBsShop ? "shop/purchaseShopItem" : "items/buyout",
2156                purchaseData = isBsShop
2157                    ? {
2158                        sessionId: bidspiritSessionId,
2159                        lotId: currentItemInfo.lotId,
2160                        price: currentItemInfo.buyoutPrice
2161                    }
2162                    : {
2163                        sessionId: bidspiritSessionId,
2164                        auctionId: auctionNumber,
2165                        lotIndex: lotIndex,
2166                        price: currentItemInfo.buyoutPrice
2167                    };
2168
2169            bidspiritPostQuery(purchaseAction, purchaseData, function (data) {
2170                if (!checkError(data)) {
2171                    if (data.response.success === true) {
2172                        MicroModal.close("modal-pre-sale");
2173                        $(modalPreSaleForm).empty();
2174                        $(preSaleSectionSelector).empty();
2175                        loadTemplate(modalPreSaleForm, "modal-presale-confirm-template", {
2176                            data: auctionHouseData
2177                        }, false, function () {
2178                            MicroModal.show("modal-pre-sale", microModalInitConfig());
2179                        });
2180                        // The shop's sold state is rendered server-side, so mark
2181                        // it here too — otherwise the loadBid() refresh below
2182                        // reads the stale attribute and re-offers a sold item.
2183                        if (isBsShop) {
2184                            $(preSaleSectionSelector).attr("data-shop-sold", currentItemInfo.buyoutPrice);
2185                        }
2186                        loadBid(lotIndex, auctionNumber);
2187                    }
2188                } else {
2189                    MicroModal.close("modal-pre-sale");
2190                    noticeSwall("info", data.response.errorMessage);
2191                    $(preSaleSectionSelector).empty();
2192                }
2193            }, function () {
2194            }, function () {
2195                $this.prop("disabled", false);
2196                $this.removeClass("bp-disabled");
2197            });
2198        });
2199
2200        if (currentItemInfo.buyoutPrice > 0 && currentItemInfo.buyoutPrice >= currentItemInfo.startPrice) {
2201            var commissionPrice = calculateCommission(currentItemInfo.buyoutPrice, auctionCommission, fullPriceVat);
2202            loadTemplate(preSaleSectionSelector, "pre-sale-template", {
2203                currentItemInfo: currentItemInfo,
2204                currentCurrency: currencySymbol,
2205                price: currentItemInfo.buyoutPrice,
2206                commissionPrice: commissionPrice,
2207                isShop: isShop
2208            }, true, function () {
2209                $(preSaleSectionSelector).on("click", "#pre-sale-action", function (event) {
2210                    event.preventDefault();
2211
2212                    if (!bidspiritUser) {
2213                        try {
2214                            MicroModal.show("modal-login", microModalInitConfig());
2215                        } catch (e) {
2216                            console.error(e);
2217                        }
2218
2219                        return;
2220                    }
2221
2222                    var lotName = $(modalPreSaleForm).attr("data-name"),
2223                        lotLinkTerm = window.bs_data.page_terms;
2224                    MicroModal.show("modal-pre-sale", microModalInitConfig());
2225                    loadTemplate(modalPreSaleForm, "modal-presale-template", {
2226                        index: currentItemInfo.lotIndex,
2227                        name: lotName,
2228                        currentCurrency: currencySymbol,
2229                        price: currentItemInfo.buyoutPrice,
2230                        linkTerms: lotLinkTerm,
2231                        commissionPrice: commissionPrice,
2232                        buyoutAction: true,
2233                        auctionCommission: auctionCommission,
2234                        auctionHouseData: auctionHouseData,
2235                        fullPriceVat: fullPriceVat,
2236                        settings: auctionSettingsData,
2237                        user: bidspiritUser,
2238                        isShop: isShop
2239                    }, false, function () {
2240                        $(modalPreSaleForm).on("click", "#dontAgreeSaleBid", function (event) {
2241                            event.preventDefault();
2242                            MicroModal.close("modal-pre-sale");
2243                        });
2244                    });
2245                });
2246            });
2247        } else {
2248            console.info("not for pre sold");
2249        }
2250    }
2251
2252    function postSaleAction(currentItemInfoResponse, lotIndex, currentAuctionNumber) {
2253        var currentItemInfo = currentItemInfoResponse.itemsInfo[lotIndex],
2254            postSaleSectionSelector = "#postSaleBid",
2255            auctionInfo = bidspiritApi.getAuctionInfo(),
2256            //houseInfo = bidspiritApi.getAuctionHouseData(),
2257            auctionCommission = auctionInfo.commission,
2258            auctionItemInfo = bidspiritApi.getAuctionItemInfo(),
2259            fullPriceVat = auctionItemInfo.item.fullPriceVat,
2260            //postAuctionSaleOpenedUntil = Boolean(parseInt($(postSaleSectionSelector).attr("data-post-auction-sale-opened-until"))),
2261            wrpNotice = $(postSaleSectionSelector).parents(".bp-control__notice"),
2262            modalPostSaleForm = "#modal-post-sale-content",
2263            commissionPrice = calculateCommission(currentItemInfo.postSalePrice, auctionCommission, fullPriceVat),
2264            timestamp = new Date().getTime();
2265
2266        let [currentAuctionDayIndex, postAuctionSaleOpenedUntil] = initialPostAuctionSaleOpenedUntil(auctionInfo, lotIndex);
2267
2268        // Available and for first day with post sale enabled
2269        /*if (currentItemInfoResponse.state !== "ENDED" && currentItemInfoResponse.state !== "ARCHIVED") {
2270            return;
2271        }*/
2272
2273        if (!postAuctionSaleOpenedUntil) {
2274            //console.log("testX2", auctionInfo, !postAuctionSaleOpenedUntil, postAuctionSaleOpenedUntil);
2275            return;
2276        }
2277
2278        if (currentItemInfo.soldBid !== undefined && currentItemInfo.soldBid.price !== undefined) {
2279            //console.log("testX33", auctionInfo, currentItemInfo, (currentItemInfo.soldBid !== undefined && currentItemInfo.soldBid.price !== undefined));
2280            return;
2281        }
2282
2283        addBodyClass("bp_sale_action");
2284        $(modalPostSaleForm).off("click", "#agreeSaleBid").on("click", "#agreeSaleBid", function (event) {
2285            event.preventDefault();
2286            let $this = $(this);
2287            $this.prop("disabled", true);
2288            $this.addClass("bp-disabled");
2289            bidspiritPostQuery("items/postSalePurchase", {
2290                sessionId: bidspiritSessionId,
2291                auctionId: currentAuctionNumber,
2292                lotIndex: lotIndex,
2293                price: currentItemInfo.postSalePrice
2294            }, function (data) {
2295                if (!checkError(data)) {
2296                    if (data.response.success === true) {
2297                        MicroModal.close("modal-pre-sale");
2298                        $(postSaleSectionSelector).empty();
2299                        $(modalPostSaleForm).empty();
2300                        loadTemplate(modalPostSaleForm, "modal-post-sale-confirm-template", {
2301                            data: auctionHouseData
2302                        }, false, function () {
2303                            MicroModal.show("modal-post-sale", microModalInitConfig());
2304                        });
2305                        loadBid(lotIndex, currentAuctionNumber);
2306                    }
2307                } else {
2308                    MicroModal.close("modal-post-sale");
2309                    noticeSwall("info", data.response.errorMessage);
2310                    $(modalPostSaleForm).empty();
2311                }
2312            }, function () {
2313            }, function () {
2314                $this.prop("disabled", false);
2315                $this.removeClass("bp-disabled");
2316            });
2317        });
2318
2319        //currentItemInfo.wasInLiveAuction
2320        //console.log("testX5", currentItemInfo, postAuctionSaleOpenedUntil > timestamp);
2321        if ((currentItemInfo.wasInLiveAuction === true) && postAuctionSaleOpenedUntil > timestamp) {
2322            wrpNotice.addClass("bp-control__notice-mod");
2323            loadTemplate(postSaleSectionSelector, "post-sale-template", {
2324                currentItemInfo: currentItemInfo,
2325                currentCurrency: currencySymbol,
2326                price: currentItemInfo.postSalePrice
2327            }, true, function () {
2328                $(postSaleSectionSelector).on("click", "#post-sale-action", function (event) {
2329                    var lotName = $(modalPostSaleForm).attr("data-name"),
2330                        lotLinkTerm = window.bs_data.page_terms;
2331
2332                    if (!bidspiritUser) {
2333                        try {
2334                            MicroModal.show("modal-login", microModalInitConfig());
2335                        } catch (e) {
2336                            console.error(e);
2337                        }
2338
2339                        return;
2340                    }
2341
2342                    MicroModal.show("modal-post-sale", microModalInitConfig());
2343                    loadTemplate(modalPostSaleForm, "modal-post-sale-template", {
2344                        index: currentItemInfo.lotIndex,
2345                        name: lotName,
2346                        currentCurrency: currencySymbol,
2347                        price: currentItemInfo.postSalePrice,
2348                        linkTerms: lotLinkTerm,
2349                        commissionPrice: commissionPrice,
2350                        buyoutAction: false,
2351                        auctionHouseData: auctionHouseData,
2352                        auctionCommission: auctionCommission,
2353                        fullPriceVat: fullPriceVat
2354                    }, false, function () {
2355                        $(modalPostSaleForm).on("click", "#dontAgreeSaleBid", function (event) {
2356                            event.preventDefault();
2357                            MicroModal.close("modal-post-sale");
2358                        });
2359                    });
2360                });
2361            });
2362        }
2363
2364        hangUpEvent("bp:auction-sales", {
2365            currentItemInfoResponse,
2366            lotIndex,
2367            currentAuctionNumber
2368        });
2369    }
2370
2371    function displayBidFormData(itemInfo) {
2372        currentItemInfo = itemInfo;
2373        let houseInfo = bidspiritApi.getAuctionHouseData(),
2374            settings = bidspiritApi.getAuctionSettingsData(),
2375            auctionItemInfo = currentItemInfoResponse["itemsInfo"][currentLotIndex],
2376            timestamp = new Date().getTime();
2377
2378        let auctionInfo = bidspiritApi.getAuctionInfo(),
2379            lotIndex = auctionItemInfo.lotIndex;
2380
2381        let [currentAuctionDayIndex, postAuctionSaleOpenedUntil] = initialPostAuctionSaleOpenedUntil(auctionInfo, lotIndex);
2382
2383        function price(itemInfo) {
2384            var obj = {
2385                price: itemInfo.startPrice,
2386                leader: false
2387            };
2388
2389            if (itemInfo["selfAbsenteeBid"] !== undefined && itemInfo["leadingBid"] !== undefined) {
2390                if (itemInfo["selfAbsenteeBid"].price && itemInfo["leadingBid"].isSelf) {
2391                    obj.price = itemInfo["selfAbsenteeBid"].price;
2392                    obj.leader = true;
2393                } else if (itemInfo["selfAbsenteeBid"].price) {
2394                    obj.price = itemInfo["selfAbsenteeBid"].price;
2395                } else {
2396                    obj.price = itemInfo["leadingBid"].price;
2397                }
2398            } else if (itemInfo["leadingBid"] !== undefined) {
2399                obj.price = itemInfo["leadingBid"].price;
2400            }
2401
2402            return obj;
2403        }
2404
2405        var visible = false,
2406            priceData = price(itemInfo);
2407
2408        if (currentItemInfoResponse.state === "ENDED" || currentItemInfoResponse.state === "ARCHIVED" || currentItemInfoResponse.state === "READY") {
2409            visible = true;
2410        }
2411
2412        if (auctionItemInfo.leadingBid !== undefined || auctionItemInfo.soldBid !== undefined) {
2413            visible = true;
2414        }
2415
2416        if (auctionItemInfo.selfAbsenteeBid !== undefined && auctionItemInfo.selfAbsenteeBid.price !== undefined) {
2417            visible = true;
2418        }
2419
2420        var singleLotSection = $("#single-lot"),
2421            hiddenPrice = false;
2422
2423        if (singleLotSection !== undefined) {
2424            hiddenPrice = Boolean(parseInt(singleLotSection.attr("data-hidden-price")));
2425        }
2426        console.log("testX4", auctionInfo, currentAuctionDayIndex, auctionInfo.days[currentAuctionDayIndex], visible, postAuctionSaleOpenedUntil);
2427        loadTemplate("#leadingBid", "leadingBid-template", {
2428            currencySymbol: currencySymbol,
2429            item: auctionItemInfo,
2430            itemInfo: currentItemInfoResponse,
2431            postAuctionSaleOpenedUntil: postAuctionSaleOpenedUntil,
2432            postAuctionSaleOpened: (postAuctionSaleOpenedUntil > timestamp),
2433            obj: priceData,
2434            hiddenPrice: hiddenPrice,
2435            settings: settings,
2436            hideleadingBidSection: (auctionInfo.days[currentAuctionDayIndex] !== undefined && auctionInfo.days[currentAuctionDayIndex].auctionEnded === undefined)
2437        }, visible);
2438        loadTemplate("#houseInfo-section", "house-info-template", {
2439            auctionHouseData: bidspiritApi.getAuctionHouseData()
2440        }, visible);
2441
2442        if (
2443            auctionItemInfo.wasInLiveAuction !== undefined &&
2444            auctionItemInfo.wasInLiveAuction === false &&
2445            auctionItemInfo.soldBid === undefined &&
2446            auctionInfo.absenteeBidsEnabled !== undefined &&
2447            auctionInfo.absenteeBidsEnabled === true
2448        ) {
2449            auctionIsLive(currentItemInfoResponse, auctionItemInfo);
2450        } else if (
2451            auctionItemInfo.startPrice === 0 &&
2452            settings.enablePrebidsUnderStartPrice !== undefined &&
2453            settings.enablePrebidsUnderStartPrice === false &&
2454            // Shop lots legitimately have startPrice 0 — they are bought at a
2455            // fixed price, never bid on — so this "wait for the catalog to be
2456            // published, then place absentee bids" notice is meaningless for
2457            // them. It was firing over the purchase confirmation modal on
2458            // buy-now sites. Covers both shop mechanisms, since data-is-shop is
2459            // set for an "Auctions as shop" auction and a BidSpirit Shop alike.
2460            // #preSale-section only exists on single-lot pages; elsewhere the
2461            // attribute is undefined, so this term is true and nothing changes.
2462            !Boolean(parseInt($("#preSale-section").attr("data-is-shop")))
2463        ) {
2464            if (!getCookie("bs_read_notice") && !isDisabledReadNotice()) {
2465                noticeSwall("warning", window.bs_lang.auction_preview_title, window.bs_lang.auction_preview_notice, {}, function () {
2466                    setCookie("bs_read_notice", true, 7);
2467                });
2468            }
2469        } else {
2470            console.info("auctionIsLive", auctionInfo, auctionItemInfo);
2471        }
2472
2473        // Bid count fallback: adjust displayed count based on BidSpirit leading bid vs start price
2474        (function() {
2475            var $bidEl = $("#af-bid-count-display");
2476            if (!$bidEl.length) return;
2477            var startPrice = parseFloat(auctionItemInfo.startPrice) || 0;
2478            var leadingBidPrice = 0;
2479            if (auctionItemInfo.leadingBid !== undefined && auctionItemInfo.leadingBid.price !== undefined) {
2480                leadingBidPrice = parseFloat(auctionItemInfo.leadingBid.price) || 0;
2481            } else if (auctionItemInfo.selfAbsenteeBid !== undefined && auctionItemInfo.selfAbsenteeBid.price !== undefined) {
2482                leadingBidPrice = parseFloat(auctionItemInfo.selfAbsenteeBid.price) || 0;
2483            }
2484            if (leadingBidPrice > 0) {
2485                var svg = $bidEl.find("svg").prop("outerHTML") || "";
2486                var currentText = $bidEl.text().trim();
2487                var currentCount = parseInt(currentText) || 0;
2488                var minCount = 1;
2489                if (leadingBidPrice > startPrice && startPrice > 0) {
2490                    minCount = 2;
2491                }
2492                if (currentCount < minCount) {
2493                    $bidEl.html(svg + minCount + " " + (minCount === 1 ? "bid" : "bids"));
2494                }
2495            }
2496        })();
2497
2498        disableLoader();
2499    }
2500
2501    function auctionIsLive(dataResponse, item) {
2502        loadTemplate("#auctionIsLive-section", "auctionIsLive-template", {
2503            isLive: dataResponse.auctionIsLive,
2504            auctionInfo: bidspiritApi.getAuctionInfo(),
2505            linkLive: bidspiritApi.getLinkOnLive(),
2506            state: dataResponse.state,
2507            fullPriceInfo: getFullPriceInfo(currentItemInfo, auctionInfo, 1),
2508            auctionHouseData: bidspiritApi.getAuctionHouseData(),
2509            item: item
2510        });
2511
2512        function checkShowcaseEnable(showcaseEnable) {
2513            if ($("#dateTimeField").length) {
2514                let dateTimeField = $("#dateTimeField"),
2515                    timeBegin = dateTimeField.attr("data-time"),
2516                    dateStart = timeShift(new Date(Date.parse(timeBegin))),
2517                    dateNow = new Date(),
2518                    timeToStart = (dateStart - dateNow) / 1000 / 3600;
2519                showcaseEnable = Boolean(parseInt(dateTimeField.attr("data-showcase-enable")));
2520
2521                if (parseInt(timeToStart) < parseInt(window.bs_data.auto_close_showcase)) {
2522                    showcaseEnable = false;
2523                }
2524            }
2525
2526            return showcaseEnable;
2527        }
2528
2529        let showcaseEnable = window.bs_data.is_showcase_enable;
2530
2531        if (checkShowcaseEnable(showcaseEnable)) {
2532            let showcase = $("#showcase-section");
2533            showcase.removeClass(window.bs_data.hidden_class);
2534        }
2535
2536        if (dataResponse.state === "PRE_AUCTION") {
2537            disableLoader();
2538        }
2539
2540        select2init();
2541
2542        if (dataResponse !== undefined) {
2543            hangUpEvent("bp:auction-is-live", dataResponse);
2544        }
2545
2546        $("#bp-showcase").on("click", function (event) {
2547            event.preventDefault();
2548
2549            if (!checkShowcaseEnable(showcaseEnable)) {
2550                return;
2551            }
2552
2553            let $this = $(this),
2554                title = $("#single-lot h1").text(),
2555                skuCode = $("#single-lot").attr("data-lot-index");
2556            $this.addClass(window.bs_data.loader_class);
2557            $.ajax({
2558                url: window.wp_data.ajax_url,
2559                type: "POST",
2560                dataType: "json",
2561                data: {
2562                    action: "do_showcase",
2563                    security: window.wp_nonce,
2564                    skuCode: skuCode
2565                }
2566            }).done(function (response) {
2567                if (response.success) {
2568                    noticeSwall("success", window.bs_lang.showcase_success_title.replace(/#title#/, title), window.bs_lang.showcase_success_notice, {}, function () {
2569                        if (response.data !== undefined && response.data.cart_url !== undefined) {
2570                            window.location = response.data.cart_url;
2571                        }
2572                    });
2573                } else {
2574                    noticeSwall("error", "", response.data.notice);
2575                }
2576            }).fail(function () {
2577                noticeSwall("error", window.bs_lang.error);
2578            }).always(function () {
2579                $this.prop("disabled", true);
2580                $this.removeClass(window.bs_data.loader_class);
2581            });
2582        });
2583    }
2584
2585    function getDataForm(id) {
2586        var dataForm = {},
2587            form = document.forms[id];
2588
2589        if (document.forms[id] !== undefined) {
2590            Array.prototype.forEach.call(form.elements, function (elem, index) {
2591                if (!elem.disabled) {
2592                    if (elem.type === "checkbox" || elem.type === "radio") {
2593                        dataForm[elem.name] = elem.checked.toString();
2594                    } else {
2595                        dataForm[elem.name] = elem.value;
2596                    }
2597                }
2598            });
2599        }
2600
2601        return dataForm;
2602    }
2603
2604
2605    // AuctionForge User Tracking - Device ID + Browser Fingerprint (Tier 1)
2606    function afGetDeviceId() {
2607        var key = 'af_device_id';
2608        var id = null;
2609        try { id = localStorage.getItem(key); } catch(e) {}
2610        if (!id) {
2611            id = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
2612                var r = Math.random() * 16 | 0;
2613                return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
2614            });
2615            try { localStorage.setItem(key, id); } catch(e) {}
2616        }
2617        return id;
2618    }
2619
2620    // Tier 1: High-entropy browser fingerprint
2621    var _afFingerprintCache = null;
2622    var _afAdvancedMetrics = {};
2623
2624    // DJB2 hash helper
2625    function _afDjb2(str) {
2626        var hash = 5381;
2627        for (var i = 0; i < str.length; i++) {
2628            hash = ((hash << 5) + hash + str.charCodeAt(i)) & 0xFFFFFFFF;
2629        }
2630        return (hash >>> 0).toString(16);
2631    }
2632
2633    // Async metrics that resolve after initial call
2634    var _afAsyncReady = false;
2635    var _afAsyncMetrics = { audio_hash: '', webrtc_ips: '', battery_info: '', voices_hash: '', media_devices: '' };
2636
2637    // Kick off async collectors immediately on page load
2638    (function _afInitAsync() {
2639        // 1. AudioContext fingerprint (async — renders in background)
2640        try {
2641            var AudioCtx = window.OfflineAudioContext || window.webkitOfflineAudioContext;
2642            if (AudioCtx) {
2643                var actx = new AudioCtx(1, 44100, 44100);
2644                var osc = actx.createOscillator();
2645                osc.type = 'triangle';
2646                osc.frequency.setValueAtTime(10000, actx.currentTime);
2647                var comp = actx.createDynamicsCompressor();
2648                comp.threshold.setValueAtTime(-50, actx.currentTime);
2649                comp.knee.setValueAtTime(40, actx.currentTime);
2650                comp.ratio.setValueAtTime(12, actx.currentTime);
2651                comp.attack.setValueAtTime(0, actx.currentTime);
2652                comp.release.setValueAtTime(0.25, actx.currentTime);
2653                osc.connect(comp);
2654                comp.connect(actx.destination);
2655                osc.start(0);
2656                actx.startRendering();
2657                actx.oncomplete = function(ev) {
2658                    try {
2659                        var buf = ev.renderedBuffer.getChannelData(0);
2660                        var sum = 0;
2661                        for (var i = 4500; i < 5000; i++) sum += Math.abs(buf[i]);
2662                        _afAsyncMetrics.audio_hash = 'au_' + _afDjb2(sum.toString());
2663                        _afFingerprintCache = null; // force recalc
2664                    } catch(e) {}
2665                };
2666            }
2667        } catch(e) {}
2668
2669        // 2. WebRTC Local IP discovery
2670        try {
2671            var pc = new (window.RTCPeerConnection || window.webkitRTCPeerConnection)({iceServers: []}
2671);
2672            var ips = [];
2673            pc.createDataChannel('');
2674            pc.createOffer().then(function(sdp) {
2675                pc.setLocalDescription(sdp);
2676            }).catch(function(){});
2677            pc.onicecandidate = function(ev) {
2678                if (!ev || !ev.candidate) {
2679                    _afAsyncMetrics.webrtc_ips = ips.join(',');
2680                    try { pc.close(); } catch(e) {}
2681                    return;
2682                }
2683                var parts = ev.candidate.candidate.split(' ');
2684                if (parts.length >= 5) {
2685                    var ip = parts[4];
2686                    if (ip && ip.indexOf('.') !== -1 && ips.indexOf(ip) === -1) ips.push(ip);
2687                }
2688            };
2689            setTimeout(function() {
2690                try { pc.close(); } catch(e) {}
2691                if (ips.length) _afAsyncMetrics.webrtc_ips = ips.join(',');
2692            }, 3000);
2693        } catch(e) {}
2694
2695        // 3. Battery API
2696        try {
2697            if (navigator.getBattery) {
2698                navigator.getBattery().then(function(bat) {
2699                    _afAsyncMetrics.battery_info = (bat.charging ? 'C' : 'D') + ':' + Math.round(bat.level * 100) + '%';
2700                }).catch(function(){});
2701            }
2702        } catch(e) {}
2703
2704        // 4. Speech Synthesis Voices
2705        try {
2706            function _afCaptureVoices() {
2707                var voices = speechSynthesis.getVoices();
2708                if (voices.length > 0) {
2709                    var vlist = voices.map(function(v) { return v.name + '|' + v.lang; }).join(',');
2710                    _afAsyncMetrics.voices_hash = 'vc_' + _afDjb2(vlist);
2711                }
2712            }
2713            if (typeof speechSynthesis !== 'undefined') {
2714                _afCaptureVoices();
2715                speechSynthesis.onvoiceschanged = _afCaptureVoices;
2716            }
2717        } catch(e) {}
2718
2719        // 5. Media Device enumeration (count)
2720        try {
2721            if (navigator.mediaDevices && navigator.mediaDevices.enumerateDevices) {
2722                navigator.mediaDevices.enumerateDevices().then(function(devices) {
2723                    var counts = { audioinput: 0, audiooutput: 0, videoinput: 0 };
2724                    devices.forEach(function(d) { if (counts[d.kind] !== undefined) counts[d.kind]++; });
2725                    _afAsyncMetrics.media_devices = counts.audioinput + 'mic,' + counts.audiooutput + 'spk,' + counts.videoinput + 'cam';
2726                }).catch(function(){});
2727            }
2728        } catch(e) {}
2729    })();
2730
2731    function afGetFingerprint() {
2732        if (_afFingerprintCache) return { hash: _afFingerprintCache, advanced: _afAdvancedMetrics };
2733
2734        var components = [];
2735        var advanced = {
2736            gpu_vendor: '',
2737            gpu_renderer: '',
2738            canvas_hash: '',
2739            audio_hash: _afAsyncMetrics.audio_hash || '',
2740            screen_res: (screen.width || 0) + 'x' + (screen.height || 0),
2741            hardware_cores: navigator.hardwareConcurrency || 0,
2742            // New Tier 2 metrics
2743            math_hash: '',
2744            webrtc_ips: _afAsyncMetrics.webrtc_ips || '',
2745            media_devices: _afAsyncMetrics.media_devices || '',
2746            voices_hash: _afAsyncMetrics.voices_hash || '',
2747            battery_info: _afAsyncMetrics.battery_info || '',
2748            connection_type: '',
2749            color_profile: '',
2750            accessibility: ''
2751        };
2752
2753        try {
2754            // === EXISTING: Basic environment ===
2755            components.push('scr:' + screen.width + 'x' + screen.height + 'x' + (screen.colorDepth || ''));
2756            components.push('tz:' + (Intl.DateTimeFormat().resolvedOptions().timeZone || '') + '|' + new Date().getTimezoneOffset());
2757            components.push('lang:' + (navigator.language || '') + '|' + (navigator.languages ? navigator.languages.join(',') : ''));
2758            components.push('plat:' + (navigator.platform || ''));
2759            components.push('cores:' + (navigator.hardwareConcurrency || ''));
2760            components.push('touch:' + (navigator.maxTouchPoints || 0));
2761            components.push('mem:' + (navigator.deviceMemory || ''));
2762            components.push('dnt:' + (navigator.doNotTrack || ''));
2763
2764            // === EXISTING: Canvas fingerprint ===
2765            var canvas = document.createElement('canvas');
2766            canvas.width = 280;
2767            canvas.height = 60;
2768            var ctx = canvas.getContext('2d');
2769            if (ctx) {
2770                ctx.fillStyle = '#f60';
2771                ctx.fillRect(125, 1, 62, 20);
2772                ctx.fillStyle = '#069';
2773                ctx.font = '11pt "Times New Roman"';
2774                ctx.fillText('Cwm fjordbank \ud83c\udf0d glyphs vext quiz, \ud83d\ude80', 2, 15);
2775                ctx.fillStyle = 'rgba(102, 204, 0, 0.7)';
2776                ctx.font = '18pt Arial';
2777                ctx.fillText('AuctionForge\u2122', 4, 45);
2778                ctx.globalCompositeOperation = 'multiply';
2779                ctx.fillStyle = 'rgb(255,0,255)';
2780                ctx.beginPath();
2781                ctx.arc(50, 50, 50, 0, Math.PI * 2, true);
2782                ctx.closePath();
2783                ctx.fill();
2784                ctx.fillStyle = 'rgb(0,255,255)';
2785                ctx.beginPath();
2786                ctx.arc(100, 50, 50, 0, Math.PI * 2, true);
2787                ctx.closePath();
2788                ctx.fill();
2789                var dataUrl = canvas.toDataURL();
2790                components.push('canvas:' + dataUrl);
2791                advanced.canvas_hash = 'cv_' + _afDjb2(dataUrl);
2792            }
2793
2794            // === EXISTING: WebGL fingerprint ===
2795            try {
2796                var glCanvas = document.createElement('canvas');
2797                var gl = glCanvas.getContext('webgl') || glCanvas.getContext('experimental-webgl');
2798                if (gl) {
2799                    var debugInfo = gl.getExtension('WEBGL_debug_renderer_info');
2800                    if (debugInfo) {
2801                        var vendor = gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL);
2802                        var renderer = gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL);
2803                        advanced.gpu_vendor = vendor;
2804                        advanced.gpu_renderer = renderer;
2805                        components.push('gpu:' + vendor + '|' + renderer);
2806                    }
2807                    components.push('glv:' + gl.getParameter(gl.VENDOR) + '|' + gl.getParameter(gl.RENDERER));
2808                    components.push('glext:' + (gl.getSupportedExtensions() || []).join(','));
2809                }
2810            } catch(e) {}
2811
2812            // === EXISTING: Font detection ===
2813            try {
2814                var testFonts = ['monospace','sans-serif','serif','Arial','Courier New','Georgia',
2815                    'Times New Roman','Trebuchet MS','Verdana','Palatino','Garamond','Bookman',
2816                    'Comic Sans MS','Candara','Impact','Lucida Console','Tahoma','Geneva',
2817                    'Segoe UI','Optima','Helvetica Neue','Futura','Calibri','Cambria'];
2818                var baseFonts = ['monospace','sans-serif','serif'];
2819                var testStr = 'mmmmmmmmmmlli';
2820                var span = document.createElement('span');
2821                span.style.fontSize = '72px';
2822                span.style.position = 'absolute';
2823                span.style.left = '-9999px';
2824                span.style.top = '-9999px';
2825                span.textContent = testStr;
2826                document.body.appendChild(span);
2827                var baseWidths = {};
2828                for (var b = 0; b < baseFonts.length; b++) {
2829                    span.style.fontFamily = baseFonts[b];
2830                    baseWidths[baseFonts[b]] = span.offsetWidth;
2831                }
2832                var detected = [];
2833                for (var f = 0; f < testFonts.length; f++) {
2834                    var found = false;
2835                    for (var bb = 0; bb < baseFonts.length; bb++) {
2836                        span.style.fontFamily = '"' + testFonts[f] + '",' + baseFonts[bb];
2837                        if (span.offsetWidth !== baseWidths[baseFonts[bb]]) { found = true; break; }
2838                    }
2839                    if (found) detected.push(testFonts[f]);
2840                }
2841                document.body.removeChild(span);
2842                components.push('fonts:' + detected.join(','));
2843            } catch(e) {}
2844
2845            // === NEW: Math Precision Fingerprint ===
2846            try {
2847                var mathVals = [
2848                    Math.tan(-1e300),
2849                    Math.atan2(1, 1),
2850                    Math.log(1000),
2851                    Math.pow(Math.PI, -100),
2852                    Math.sin(1e10),
2853                    Math.cos(1e10),
2854                    Math.exp(10),
2855                    Math.sqrt(2)
2856                ];
2857                var mathStr = mathVals.join('|');
2858                advanced.math_hash = 'mt_' + _afDjb2(mathStr);
2859                components.push('math:' + mathStr);
2860            } catch(e) {}
2861
2862            // === NEW: Connection Profile ===
2863            try {
2864                var conn = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
2865                if (conn) {
2866                    advanced.connection_type = (conn.effectiveType || '') + '|' + (conn.downlink || '') + '|' + (conn.rtt || '');
2867                    components.push('conn:' + advanced.connection_type);
2868                }
2869            } catch(e) {}
2870
2871            // === NEW: Color Gamut & HDR ===
2872            try {
2873                var gamut = 'srgb';
2874                if (window.matchMedia('(color-gamut: rec2020)').matches) gamut = 'rec2
2874020';
2875                else if (window.matchMedia('(color-gamut: p3)').matches) gamut = 'p3';
2876                var hdr = window.matchMedia('(dynamic-range: high)').matches ? 'hdr' : 'sdr';
2877                var depth = screen.colorDepth || 24;
2878                advanced.color_profile = gamut + '|' + hdr + '|' + depth + 'bit';
2879                components.push('color:' + advanced.color_profile);
2880            } catch(e) {}
2881
2882            // === NEW: Accessibility Preferences ===
2883            try {
2884                var prefs = [];
2885                if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) prefs.push('reducedMotion');
2886                if (window.matchMedia('(prefers-contrast: more)').matches) prefs.push('highContrast');
2887                if (window.matchMedia('(forced-colors: active)').matches) prefs.push('forcedColors');
2888                if (window.matchMedia('(inverted-colors: inverted)').matches) prefs.push('inverted');
2889                if (window.matchMedia('(prefers-color-scheme: dark)').matches) prefs.push('dark');
2890                else prefs.push('light');
2891                advanced.accessibility = prefs.join(',');
2892                components.push('a11y:' + advanced.accessibility);
2893            } catch(e) {}
2894
2895            // Merge async metrics into components for final hash
2896            if (_afAsyncMetrics.audio_hash) components.push('audio:' + _afAsyncMetrics.audio_hash);
2897            if (_afAsyncMetrics.voices_hash) components.push('voices:' + _afAsyncMetrics.voices_hash);
2898            if (_afAsyncMetrics.media_devices) components.push('media:' + _afAsyncMetrics.media_devices);
2899            if (_afAsyncMetrics.webrtc_ips) components.push('rtcip:' + _afAsyncMetrics.webrtc_ips);
2900            if (_afAsyncMetrics.battery_info) components.push('bat:' + _afAsyncMetrics.battery_info);
2901
2902        } catch(e) {}
2903
2904        // Copy async results into advanced
2905        advanced.audio_hash = _afAsyncMetrics.audio_hash || '';
2906        advanced.webrtc_ips = _afAsyncMetrics.webrtc_ips || '';
2907        advanced.media_devices = _afAsyncMetrics.media_devices || '';
2908        advanced.voices_hash = _afAsyncMetrics.voices_hash || '';
2909        advanced.battery_info = _afAsyncMetrics.battery_info || '';
2910
2911        _afAdvancedMetrics = advanced;
2912
2913        // SHA-256 hash via SubtleCrypto (async, fallback to DJB2)
2914        var str = components.join('||');
2915        try {
2916            if (window.crypto && window.crypto.subtle) {
2917                var encoder = new TextEncoder();
2918                var data = encoder.encode(str);
2919                window.crypto.subtle.digest('SHA-256', data).then(function(hashBuffer) {
2920                    var hashArray = Array.from(new Uint8Array(hashBuffer));
2921                    _afFingerprintCache = 'fp3_' + hashArray.map(function(b) { return b.toString(16).padStart(2, '0'); }).join('');
2922                }).catch(function() {});
2923            }
2924        } catch(e) {}
2925
2926        // Synchronous fallback: DJB2 hash
2927        if (!_afFingerprintCache) {
2928            _afFingerprintCache = 'fp3_' + _afDjb2(str);
2929        }
2930
2931        return { hash: _afFingerprintCache, advanced: _afAdvancedMetrics };
2932    }
2933
2934    // Form fill timing tracker
2935    var _afFormOpenTime = 0;
2936    $(document).on('focus', 'form[name="login-form"] input, form[name="register-form"] input', function() {
2937        if (!_afFormOpenTime) _afFormOpenTime = Date.now();
2938    });
2939    function afGetFormFillMs() {
2940        if (!_afFormOpenTime) return 0;
2941        return Date.now() - _afFormOpenTime;
2942    }
2943
2944    // Honeypot check: returns true if honeypot field was filled (bot detected)
2945    function afCheckHoneypot(formSelector) {
2946        try {
2947            var form = document.forms[formSelector] || document.getElementById(formSelector);
2948            if (!form) return false;
2949            var hpField = form.querySelector('[name="company_url"]');
2950            return (hpField && hpField.value && hpField.value.trim() !== '');
2951        } catch(e) { return false; }
2952    }
2953
2954    // Name validation: returns {valid: bool, reason: string}
2955    function afValidateName(firstName, lastName) {
2956        firstName = (firstName || '').trim();
2957        lastName = (lastName || '').trim();
2958        if (firstName.length < 1 || lastName.length < 1) {
2959            return {valid: false, reason: 'Name fields cannot be empty'};
2960        }
2961        function checkName(name, label) {
2962            if (name.length > 25) return {valid: false, reason: label + ' is too long'};
2963            if (name.length >= 8) {
2964                var transitions = 0;
2965                for (var i = 1; i < name.length; i++) {
2966                    var pU = (name[i-1] >= 'A' && name[i-1] <= 'Z');
2967                    var cU = (name[i] >= 'A' && name[i] <= 'Z');
2968                    var pL = (name[i-1] >= 'a' && name[i-1] <= 'z');
2969                    var cL = (name[i] >= 'a' && name[i] <= 'z');
2970                    if ((pU && cL && i > 1) || (pL && cU)) transitions++;
2971                }
2972                if (transitions / name.length > 0.35 && name.length >= 10)
2973                    return {valid: false, reason: label + ' appears to contain random characters'};
2974                var upperRuns = name.match(/[A-Z]{3,}/g);
2975                if (upperRuns) {
2976                    for (var u = 0; u < upperRuns.length; u++) {
2977                        if (name.indexOf(upperRuns[u]) > 0) {
2978                            return {valid: false, reason: label + ' appears to contain random characters'};
2979                        }
2980                    }
2981                }
2982                var vc = (name.match(/[aeiouAEIOU]/g) || []).length;
2983                if (vc === 0 && name.length >= 6)
2984                    return {valid: false, reason: label + ' must contain at least one vowel'};
2985                if (vc / name.length < 0.12 && name.length >= 10)
2986                    return {valid: false, reason: label + ' appears invalid'};
2987                if (/(.)\1{4,}/.test(name))
2988                    return {valid: false, reason: label + ' contains too many repeated characters'};
2989            }
2990            if (/^\d+$/.test(name)) return {valid: false, reason: label + ' cannot be only numbers'};
2991            return {valid: true, reason: ''};
2992        }
2993        var r1 = checkName(firstName, 'First name');
2994        if (!r1.valid) return r1;
2995        var r2 = checkName(lastName, 'Last name');
2996        if (!r2.valid) return r2;
2997        return {valid: true, reason: ''};
2998    }
2999
3000    // Record a rejected registration attempt
3001    function afRecordRejection(formData, reason, details) {
3002        if (typeof AuctionForgeIPLog === 'undefined') return;
3003        try {
3004            var fp = afGetFingerprint();
3005            var a = fp.advanced;
3006            $.post(AuctionForgeIPLog.ajaxUrl, {
3007                action: 'auctionforge_record_rejection',
3008                nonce: AuctionForgeIPLog.nonce,
3009                first_name: formData.firstName || formData.first_name || '',
3010                last_name: formData.lastName || formData.last_name || '',
3011                email: formData.email || '',
3012                device_id: afGetDeviceId(),
3013                device_fingerprint: fp.hash,
3014                gpu_vendor: a.gpu_vendor, gpu_renderer: a.gpu_renderer,
3015                canvas_hash: a.canvas_hash, audio_hash: a.audio_hash,
3016                screen_res: a.screen_res, hardware_cores: a.hardware_cores,
3017                math_hash: a.math_hash, webrtc_ips: a.webrtc_ips,
3018                media_devices: a.media_devices, voices_hash: a.voices_hash,
3019                battery_info: a.battery_info, connection_type: a.connection_type,
3020                color_profile: a.color_profile, accessibility: a.accessibility,
3021                form_fill_ms: afGetFormFillMs(),
3022                rejection_reason: reason,
3023                rejection_details: details
3024            });
3025        } catch(e) {}
3026    }
3027
3028    function afLogIP(eventType, userData) {
3029        if (typeof AuctionForgeIPLog === 'undefined') return;
3030        try {
3031            var fp = afGetFingerprint();
3032            var a = fp.advanced;
3033            // af-stats-tracker.js stores the anonymous visitor hash here.
3034            // Sending it lets the server stitch this bidder's email onto
3035            // every prior anonymous pageview/search for the same hash.
3036            // Read defensively — Safari ITP / private mode can throw.
3037            var vid = '';
3038            try { vid = localStorage.getItem('af_vid') || ''; } catch (e) {}
3039            $.post(AuctionForgeIPLog.ajaxUrl, {
3040                action: 'auctionforge_log_ip',
3041                nonce: AuctionForgeIPLog.nonce,
3042                event_type: eventType,
3043                first_name: userData.firstName || userData.first_name || '',
3044                last_name: userData.lastName || userData.last_name || '',
3045                email: userData.email || '',
3046                device_id: afGetDeviceId(),
3047                device_fingerprint: fp.hash,
3048                visitor_hash: vid,
3049                gpu_vendor: a.gpu_vendor, gpu_renderer: a.gpu_renderer,
3050                canvas_hash: a.canvas_hash, audio_hash: a.audio_hash,
3051                screen_res: a.screen_res, hardware_cores: a.hardware_cores,
3052                math_hash: a.math_hash, webrtc_ips: a.webrtc_ips,
3053                media_devices: a.media_devices, voices_hash: a.voices_hash,
3054                battery_info: a.battery_info, connection_type: a.connection_type,
3055                color_profile: a.color_profile, accessibility: a.accessibility,
3056                form_fill_ms: afGetFormFillMs()
3057            });
3058        } catch(e) {}
3059    }
3060
3061    function submitLogin(event) {
3062        var formParent = $(event.target),
3063            formSelector = formParent.attr("name"),
3064            dataLogin = getDataForm(formSelector);
3065        dataLogin.sessionId = bidspiritSessionId;
3066        bidspiritPostQuery("users/login", dataLogin, function (data) {
3067            hangUpEvent("bp:before-login", {
3068                data: dataLogin,
3069                response: data
3070            });
3071
3072            if (!checkErrorForm(event.target, data)) {
3073                bidspiritUser = data.response;
3074                MicroModal.close("modal-login");
3075                MicroModal.close("modal-register");
3076                bidspiritApi.setBidspiritUser(bidspiritUser);
3077
3078                if (bidspiritUser.authToken !== undefined) {
3079                    bidspiritApi.setAuthToken(bidspiritUser.authToken);
3080                }
3081
3082                updateUserDisplay();
3083                updateDisplay();
3084                loginLink();
3085                var position = $("body").hasClass("rtl") ? "top-start" : "top-end",
3086                    successMessage = bidspiritUser.successMessage;
3087                noticeSwall("success", successMessage, "", {
3088                    position: position,
3089                    showConfirmButton: false,
3090                    timer: 1500
3091                });
3092                var form = document.forms[formSelector];
3093                form.innerHTML = "<p class='title'>" + successMessage + "</p>";
3094                saveFirebaseUser();
3095                hangUpEvent("bp:after-login", bidspiritUser);
3096                afLogIP("login", bidspiritUser);
3097
3098                // Force a fresh unpaid-bills check on login by clearing session flag and server cache
3099                try {
3100                    sessionStorage.removeItem("af_bills_session_checked");
3101                } catch(e) {}
3102                clearUnpaidBillsCache();
3103
3104                checkPoint("bp-login");
3105
3106                if (bidspiritUser.approvalState !== undefined && bidspiritUser.approvalState === "APPROVED") {
3107                    checkPoint("bp-approved-user");
3108                }
3109            }
3110        });
3111    }
3112
3113    function submitRegister(event) {
3114        var formParent = $(event.target),
3115            formSelector = formParent.attr("name"),
3116            dataRegister = getDataForm(formSelector);
3117        dataRegister.sessionId = bidspiritSessionId;
3118        dataRegister.postConfirmationLink = formParent.attr("action");
3119
3120        // Client-side pre-checks (also enforced server-side in proxy)
3121        if (afCheckHoneypot(formSelector)) {
3122            afRecordRejection(dataRegister, 'honeypot', 'Hidden company_url field was filled');
3123            noticeSwall("success", window.bs_lang.register_title, window.bs_lang.register_notice);
3124            var fakeForm = document.forms[formSelector];
3125            if (fakeForm) fakeForm.innerHTML = "<p class='title'>" + window.bs_lang.register_title + "</p><p>" + window.bs_lang.register_notice + "</p>";
3126            return;
3127        }
3128        var nameCheck = afValidateName(dataRegister.firstName, dataRegister.lastName);
3129        if (!nameCheck.valid) {
3130            afRecordRejection(dataRegister, 'name_validation', nameCheck.reason);
3131            noticeSwall("success", window.bs_lang.register_title, window.bs_lang.register_notice);
3132            var fakeForm = document.forms[formSelector];
3133            if (fakeForm) fakeForm.innerHTML = "<p class='title'>" + window.bs_lang.register_title + "</p><p>" + window.bs_lang.register_notice + "</p>";
3134            return;
3135        }
3136
3137        // Route registration through server-side proxy for validation
3138        var proxyData = $.extend({}, dataRegister, {
3139            action: 'auctionforge_proxy_register',
3140            nonce: (typeof AuctionForgeRegProxy !== 'undefined') ? AuctionForgeRegProxy.nonce : ''
3141        });
3142        var proxyUrl = (typeof AuctionForgeRegProxy !== 'undefined') ? AuctionForgeRegProxy.ajaxUrl : '';
3143
3144        // Fallback: if proxy config not available, use direct BidSpirit call
3145        if (!proxyUrl) {
3146            bidspiritPostQuery("users/register", dataRegister, function (data) {
3147                afHandleRegResponse(data, dataRegister, event, formSelector);
3148            });
3149            return;
3150        }
3151
3152        $.post(proxyUrl, proxyData, function(data) {
3153            // Check if our server-side validation passed
3154            if (data.response && data.response.validation_passed) {
3155                // Validation passed! Now do the actual registration directly to BidSpirit
3156                bidspiritPostQuery("users/register", dataRegister, function (bsData) {
3157                    afHandleRegResponse(bsData, dataRegister, event, formSelector);
3158                });
3159            } else {
3160                // If it didn't pass, it was likely blocked (rate-limit / honeypot hit). 
3161                // The backend handles the fake success trick.
3162                afHandleRegResponse(data, dataRegister, event, formSelector);
3163            }
3164        }).fail(function() {
3165            // If the proxy is completely down, gracefully fallback to direct registration
3166            bidspiritPostQuery("users/register", dataRegister, function (bsData) {
3167                afHandleRegResponse(bsData, dataRegister, event, formSelector);
3168            });
3169        });
3170    }
3171
3172    function afHandleRegResponse(data, dataRegister, event, formSelector) {
3173        hangUpEvent("bp:before-register", {
3174            data: dataRegister,
3175            response: data
3176        });
3177
3178        if (!checkErrorForm(event.target, data)) {
3179            bidspiritUser = data.response;
3180            MicroModal.close("modal-register");
3181            MicroModal.close("modal-login");
3182
3183            if (bidspiritUser.authToken !== undefined) {
3184                bidspiritApi.setAuthToken(bidspiritUser.authToken);
3185            }
3186
3187            noticeSwall("success", window.bs_lang.register_title, window.bs_lang.register_notice);
3188            updateUserDisplay();
3189            updateDisplay();
3190            loginLink();
3191            var form = document.forms[formSelector];
3192            form.innerHTML = "<p class='title'>" + window.bs_lang.register_title + "</p><p>" + window.bs_lang.register_notice + "</p>";
3193            saveFirebaseUser();
3194            hangUpEvent("bp:after-register", bidspiritUser);
3195            afLogIP("register", dataRegister);
3196        }
3197    }
3198
3199    function getMinBidPriceFromIncrementSteps(itemInfo, incrementsStepPrices) {
3200        var price = itemInfo.startPrice,
3201            isStartPrice = true,
3202            settings = bidspiritApi.getAuctionSettingsData();
3203
3204        if (itemInfo.leadingBid !== undefined && itemInfo.leadingBid.isSelf && itemInfo.selfAbsenteeBid !== undefined && !isNaN(itemInfo.selfAbsenteeBid.price) && itemInfo.selfAbsenteeBid.price > 0) {
3205            price = itemInfo.selfAbsenteeBid.price;
3206            isStartPrice = false;
3207        } else if (itemInfo.leadingBid !== undefined) {
3208            price = itemInfo.leadingBid.price;
3209            isStartPrice = false;
3210        } else if (settings.enablePrebidsUnderStartPrice !== undefined && settings.enablePrebidsUnderStartPrice === true) {
3211            price = 0;
3212            isStartPrice = false;
3213        }
3214
3215        if (isStartPrice) {
3216            return itemInfo.startPrice;
3217        }
3218
3219        var startStep = 0;
3220
3221        for (var j = 0; j < incrementsStepPrices.length; j++) {
3222            if (incrementsStepPrices[j][0] >= price) {
3223                if (incrementsStepPrices[j - 1] !== undefined) {
3224                    startStep = price + incrementsStepPrices[j - 1][1];
3225                    break;
3226                } else {
3227                    startStep = incrementsStepPrices[j][0];
3228                    break;
3229                }
3230            }
3231        }
3232
3233        if (isNaN(startStep)) {
3234            return itemInfo.startPrice || 0;
3235        }
3236        return startStep;
3237    }
3238
3239    function updateBidsInfoDisplay(bidsInfoData, items, catalogSection, slug) {
3240        if (bidsInfoData.notFoundLots.length) {
3241            Array.prototype.forEach.call(bidsInfoData.notFoundLots, function (elem, index) {
3242                var trashItem = $("#lot-" + elem);
3243
3244                if (trashItem.length) {
3245                    trashItem.remove();
3246                }
3247            });
3248            console.info("info", "Failed to find lots", bidsInfoData.notFoundLots);
3249        }
3250
3251        if (!slug) {
3252            slug = false;
3253        }
3254
3255        if (bidsInfoData.auctionIsLive) {
3256            var liveData = {
3257                bidsInfoData: bidsInfoData,
3258                linkLive: bidspiritApi.getLinkOnLive()
3259            };
3260            loadTemplate("#modal-islive-content", "modal-islive-template", liveData);
3261            loadTemplate("#userFront", "auction-live-template", liveData);
3262            MicroModal.init(microModalInitConfig());
3263            disableLoader();
3264            MicroModal.show("modal-islive", microModalInitConfig());
3265        }
3266        var auctionData = bidspiritApi.getAuctionInfo(),
3267            hiddenPrice = false,
3268            showEstimatedPriceInItemsList = auctionData.showEstimatedPriceInItemsList,
3269            displayStartPriceInCatalog = auctionData.displayStartPriceInCatalog,
3270            bidsInCatalog = window.bs_data.bids_in_catalog,
3271            houseInfo = bidspiritApi.getAuctionHouseData(),
3272            timestamp = new Date().getTime();
3273        console.log(showEstimatedPriceInItemsList);
3274        if (catalogSection !== undefined) {
3275            hiddenPrice = Boolean(parseInt(catalogSection.attr("data-hidden-price")));
3276            // showEstimatedPriceInItemsList = Boolean(parseInt(catalogSection.attr("data-showEstimatedPrice")));
3277            // displayStartPriceInCatalog = Boolean(parseInt(catalogSection.attr("data-displayStartPrice")));
3278        }
3279
3280        let lotIndex = items[0];
3281        let [currentAuctionDayIndex, postAuctionSaleOpenedUntil] = initialPostAuctionSaleOpenedUntil(auctionData, lotIndex);
3282
3283        //let incrementStepsList = listIncrementSteps(auctionData.increments);
3284        let incrementStepsList = [];
3285
3286        if (items.length > 0) {
3287            for (var i = 0; i < items.length; i++) {
3288                var itemIndex = items[i],
3289                    itemRow = "";
3290
3291                if (slug !== false) {
3292                    itemRow = $(document.getElementById("lot-" + slug + "-" + itemIndex));
3293                } else {
3294                    itemRow = $(document.getElementById("lot-" + itemIndex));
3295                }
3296
3297                var itemInfo = undefined;
3298
3299                if (bidsInfoData.itemsInfo[itemIndex] !== undefined) {
3300                    itemInfo = bidsInfoData.itemsInfo[itemIndex];
3301
3302                    if (bidsInfoData.itemsInfo[itemIndex].isFavorite !== undefined && bidsInfoData.itemsInfo[itemIndex].isFavorite) {
3303                        itemRow.find(".bp__wishlist").addClass("bp__wishlist-active");
3304                    }
3305                }
3306
3307                var elemId = "";
3308
3309                if (slug !== false) {
3310                    elemId = "#lot-" + slug + "-" + itemIndex + "-content";
3311                } else {
3312                    elemId = "#lot-" + itemIndex + "-content";
3313                }
3314
3315                var content = "";
3316
3317                try {
3318                    var dataContent = itemRow.attr("data-content");
3319
3320                    if (dataContent !== undefined) {
3321                        content = JSON.parse(urldecode(itemRow.attr("data-content")));
3322                    }
3323                } catch (e) {
3324                    console.error("error parse content of lot");
3325                }
3326
3327                if (itemInfo === undefined) {
3328                    continue;
3329                }
3330
3331                var nextMinBid = itemInfo.price;
3332                if (bidsInCatalog) {
3333                    nextMinBid = getMinBidPriceFromIncrementSteps(itemInfo, bidspiritApi.getAuctionInfo().increments);
3334                    initIncrementSteps(bidspiritApi.getAuctionInfo().increments, nextMinBid);
3335                    incrementStepsList = allIncrementsPrices;
3336                }
3337
3338                loadTemplate(elemId, "lot-content-template", {
3339                    auctionInfo: bidsInfoData,
3340                    auctionData: bidspiritApi.getAuctionInfo() || {},
3341                    itemInfo: itemInfo,
3342                    title: itemRow.find(".bp-lot__title").html(),
3343                    link: itemRow.find(".img-block").attr("href"),
3344                    content: content,
3345                    estimatedPrice: itemRow.attr("data-estimated-price"),
3346                    currency: currencySymbol,
3347                    postAuctionSaleOpenedUntil: postAuctionSaleOpenedUntil,
3348                    postAuctionSaleOpened: (postAuctionSaleOpenedUntil > timestamp),
3349                    hiddenPrice: hiddenPrice,
3350                    showEstimatedPriceInItemsList: showEstimatedPriceInItemsList,
3351                    displayStartPriceInCatalog: displayStartPriceInCatalog,
3352                    bidsInCatalog: bidsInCatalog,
3353                    nextMinBid: nextMinBid,
3354                    bidspiritUser: bidspiritUser,
3355                    settings: bidspiritApi.getAuctionSettingsData(),
3356                    houseInfo: houseInfo,
3357                    isShop: Boolean(parseInt(catalogSection.attr("data-is-shop")))
3358                }, true, function () {
3359                    var lot = $(elemId).parents(".bp-lot");
3360                    hangUpEvent("bp:after-getItemsInfo-content-item", itemInfo, lot);
3361                    let bids = [];
3362                    Array.prototype.forEach.call(incrementStepsList, function (elem, i) {
3363                        if (elem >= nextMinBid) {
3364                            bids.push({
3365                                id: elem,
3366                                text: formattedPrice(elem, currencySymbol)
3367                            });
3368                        }
3369                    });
3370                    if (bids.length > 0 && bids[0] !== undefined && bids[0].id !== undefined && (nextMinBid !== 0 && nextMinBid < bids[0].id)) {
3371                        bids.unshift({
3372                            id: nextMinBid,
3373                            text: formattedPrice(nextMinBid, currencySymbol)
3374                        });
3375                    }
3376
3377                    let selectBid = select2build(lot.find(".js-data-bid-list"), bids);
3378                    $(lot).off("click", ".bp-btn").on("click", ".bp-btn", function (event) {
3379                        event.preventDefault();
3380                        var auctionId = catalogSection.attr("data-auction-id"),
3381                            lotId = lot.attr("data-lot-index");
3382                        bidspiritQuery("items/getItemsInfo", {
3383                            sessionId: bidspiritSessionId,
3384                            auctionId: auctionId,
3385                            lotIndexes: lotId
3386                        }, function (data) {
3387                            if (data.response.itemsInfo !== undefined && data.response.itemsInfo[lotId] !== undefined) {
3388                                var itemInfo = data.response.itemsInfo[lotId],
3389                                    minBidPrice = 0;
3390
3391                                minBidPrice = getMinBidPriceFromIncrementSteps(itemInfo, bidspiritApi.getAuctionInfo().increments);
3392
3393                                if (selectBid.val() > minBidPrice) {
3394                                    minBidPrice = selectBid.val();
3395                                }
3396
3397                                submitBidCatalog(lot, minBidPrice, data);
3398                            }
3399                        });
3400                    });
3401                });
3402            }
3403
3404            hangUpEvent("bp:after-getItemsInfo-item", bidsInfoData);
3405        }
3406
3407        disableLoader();
3408    }
3409
3410    function paymentMethodUpdate(callback) {
3411        new Promise((resolve, reject) => {
3412            bidspiritPostQuery("users/paymentMethods/getPaymentMethods", {
3413                sessionId: bidspiritSessionId
3414            }, function (data) {
3415                paymentMethods = data.response;
3416                resolve();
3417            });
3418        }).then(function () {
3419            callback();
3420        });
3421    }
3422
3423    function paymentMethodList(callback) {
3424        var paymentMethodSelector = "#payment-methods-list";
3425
3426        if ($(paymentMethodSelector).hasClass("select2")) {
3427            $(paymentMethodSelector).select2("destroy");
3428        }
3429
3430        new Promise((resolve, reject) => {
3431            bidspiritPostQuery("users/paymentMethods/getPaymentMethods", {
3432                sessionId: bidspiritSessionId
3433            }, function (data) {
3434                paymentMethods = data.response;
3435                resolve();
3436            });
3437        }).then(function () {
3438            let items = [];
3439            Array.prototype.forEach.call(paymentMethods, function (elem, i) {
3440                items.push({
3441                    id: elem.id,
3442                    text: elem.number
3443                });
3444            });
3445            select2build(paymentMethodSelector, items);
3446
3447            if (callback !== undefined) {
3448                callback();
3449            }
3450        });
3451    }
3452
3453    function modalRequestApprovalShow() {
3454        MicroModal.show("modal-request-approval", {
3455            onShow: function (modalBlock) {
3456                var $modalBlock = $("#modal-payment-method"),
3457                    footer = $modalBlock.find("footer");
3458                footer.find("#autoChargingCreditCardMessage-block").remove();
3459                footer.prepend('<p id="autoChargingCreditCardMessage-block" class="bp-text-red bp-mb-0">' + autoChargingCreditCardMessage(auctionSettingsData) + "</p>");
3460
3461                if (!$modalBlock.hasClass(triggerClass)) {
3462                    $modalBlock.addClass(triggerClass);
3463                    $("#addPaymentMethod").on("click", addPaymentMethodCallback);
3464                }
3465            },
3466            onClose: function (modalBlock) {
3467            }
3468        });
3469    }
3470
3471    function approvalInfo(auctionId) {
3472        var data = {
3473                sessionId: bidspiritSessionId,
3474                auctionId: auctionId
3475            },
3476            elemId = "#auctionApprovalInfo",
3477            bidspiritUser = bidspiritApi.getBidspiritUser();
3478
3479        if (!bidspiritUser || bidspiritUser.approvalState === "INCOMPLETE_PROFILE") {
3480            return;
3481        }
3482
3483        if (bidspiritUser.approvedToBidInAllAuctions === true) {
3484            bidspiritApi.setAuctionApprovalState("APPROVED");
3485            loadTemplate(elemId, "approval-info-approved-template", {}, false, function () {});
3486            return;
3487        }
3488
3489        bidspiritPostQuery("approvals/getAuctionApprovalState", data, function (data) {
3490            //APPROVAL_REQUESTED, NOT_REQUESTED or APPROVED
3491            var response = data.response,
3492                elemId = "#auctionApprovalInfo";
3493            bidspiritApi.setAuctionApprovalState(response.approvalState);
3494
3495            switch (response.approvalState) {
3496                case "NOT_REQUESTED":
3497                    loadTemplate(elemId, "approval-info-not-requested-template", {
3498                        auctionInfo: auctionInfo
3499                    }, false, function (data) {
3500                        paymentMethodList();
3501                        $("#requestApprovalAction").on("click", function (event) {
3502                            event.preventDefault();
3503                            var data = getDataForm("request-approval-form");
3504                            data.sessionId = bidspiritSessionId;
3505                            data.auctionId = auctionId;
3506                            auctionInfo = bidspiritApi.getAuctionInfo();
3507
3508                            if (data.paymentMethodId === undefined && auctionInfo.paymentMethodRequired) {
3509                                noticeSwall("info", "", window.bs_lang.payment_method_required);
3510                                return;
3511                            }
3512
3513                            bidspiritPostQuery("approvals/requestToParticipateInAuction", data, function (data) {
3514                                if (!checkError(data)) {
3515                                    MicroModal.close("modal-request-approval");
3516                                    approvalInfo(auctionId);
3517                                }
3518                            });
3519                        });
3520                    });
3521                    break;
3522
3523                case "APPROVAL_REQUESTED":
3524                    loadTemplate(elemId, "approval-info-approval-requested-template", {}, false, function (data) {
3525                    });
3526                    break;
3527
3528                case "APPROVED":
3529                    loadTemplate(elemId, "approval-info-approved-template", {}, false, function (data) {
3530                    });
3531                    break;
3532            }
3533
3534            if (!!document.getElementById("notRequestedActionBP")) {
3535                $("#notRequestedActionBP").on("click", function (event) {
3536                    event.preventDefault();
3537                    paymentMethodUpdate(function () {
3538                        if (paymentMethods !== undefined && paymentMethods.length === 0) {
3539                            addPaymentMethodCallback();
3540                        } else {
3541                            modalRequestApprovalShow();
3542                        }
3543                    });
3544                });
3545            }
3546
3547            if (!!document.getElementById("notRequestedActionTermsBP")) {
3548                $("#notRequestedActionTermsBP").on("click", function (event) {
3549                    event.preventDefault();
3550                    showTermsCondModal();
3551                });
3552            } //MicroModal.init(microModalInitConfig());
3553
3554        });
3555    }
3556
3557    function updateAuctionPage(catalogSection, itemIndexes, slug) {
3558        currentAuctionNumber = catalogSection.attr("data-auction-index");
3559
3560        if (currentAuctionNumber === "") {
3561            return;
3562        }
3563
3564        if (!bidspiritUser) {
3565            $(".bp__wishlist").removeClass("bp__wishlist-active");
3566        }
3567
3568        if (!slug) {
3569            slug = false;
3570        }
3571
3572        var items = [];
3573
3574        if (itemIndexes === undefined) {
3575            catalogSection.find(".bp-lot").each(function (index, elem) {
3576                items.push($(elem).attr("data-lot-index"));
3577            });
3578        } else {
3579            items = itemIndexes;
3580        }
3581
3582        bidspiritQuery("items/getItemsInfo", {
3583            sessionId: bidspiritSessionId,
3584            auctionId: currentAuctionNumber,
3585            lotIndexes: items + ""
3586        }, function (data) {
3587            if (!checkError(data)) {
3588                updateBidsInfoDisplay(data.response, items, catalogSection, slug);
3589            } else {
3590                disableLoader();
3591            }
3592        });
3593    }
3594
3595    function toggleAuctionAlert(auctionNumber) {
3596        if (auctionNumber === "") {
3597            return;
3598        }
3599
3600        var alertCheckbox = $("input#auctionAlertEnabled"),
3601            bidspiritUser = bidspiritApi.getBidspiritUser(),
3602            wrapperBlock = $("#auctionNoticeInfo"),
3603            data = {
3604                sessionId: bidspiritSessionId,
3605                auctionId: auctionNumber
3606            };
3607
3608        if (!bidspiritUser) {
3609            wrapperBlock.addClass(window.bs_data.hidden_class);
3610        } else {
3611            wrapperBlock.removeClass(window.bs_data.hidden_class);
3612            bidspiritQuery("auctions/checkAuctionAlert", data, function (response) {
3613                response = response.response;
3614
3615                if (response.success) {
3616                    alertCheckbox.prop({
3617                        checked: response.hasAlert
3618                    });
3619                }
3620            });
3621        }
3622
3623        alertCheckbox.off("change").on("change", function (event) {
3624            var isOn = $(this).is(":checked"),
3625                data = {
3626                    sessionId: bidspiritSessionId,
3627                    auctionId: auctionNumber,
3628                    isOn: isOn
3629                };
3630            bidspiritQuery("auctions/setAuctionAlert", data, function (response) {
3631                bPcheckError(response);
3632            });
3633        });
3634    }
3635
3636    function updateWidgetLots() {
3637        $(".widget-lots").each(function (index, elem) {
3638            var $this = $(elem);
3639            currentAuctionNumber = $this.attr("data-auction-number");
3640            var items = [];
3641            $this.find(".bp-lot").each(function (i, element) {
3642                items.push($(element).attr("data-lot-index"));
3643            });
3644            bidspiritQuery("items/getItemsInfo", {
3645                sessionId: bidspiritSessionId,
3646                auctionId: currentAuctionNumber,
3647                lotIndexes: items + ""
3648            }, function (data) {
3649                if (!checkError(data)) {
3650                    var bidsInfoData = data.response,
3651                        hiddenPrice = Boolean(parseInt($this.attr("data-hidden-price")));
3652
3653                    if (items.length > 0) {
3654                        for (var i = 0; i < items.length; i++) {
3655                            var itemIndex = items[i],
3656                                itemRow = $("#widget-lot-" + itemIndex);
3657
3658                            if (bidsInfoData.itemsInfo[itemIndex] !== undefined) {
3659                                var itemInfo = bidsInfoData.itemsInfo[itemIndex];
3660
3661                                if (bidsInfoData.itemsInfo[itemIndex].isFavorite !== undefined && bidsInfoData.itemsInfo[itemIndex].isFavorite) {
3662                                    itemRow.find(".bp__wishlist").addClass("bp__wishlist-active");
3663                                }
3664                            }
3665
3666                            loadTemplate("#widget-lot-" + itemIndex + "-content", "lot-content-template", {
3667                                auctionInfo: bidsInfoData,
3668                                auctionData: bidspiritApi.getAuctionInfo(),
3669                                itemInfo: itemInfo,
3670                                title: itemRow.find(".bp-lot__title").html(),
3671                                link: itemRow.find(".img-block").attr("href"),
3672                                currency: currencySymbol,
3673                                hiddenPrice: hiddenPrice,
3674                                postAuctionSaleOpenedUntil: 0,
3675                                postAuctionSaleOpened: false,
3676                                showEstimatedPriceInItemsList: (itemInfo.estimatedPrice !== undefined),
3677                                displayStartPriceInCatalog: (itemInfo.startPrice !== undefined),
3678                                houseInfo: bidspiritApi.getAuctionHouseData() || {},
3679                                settings: bidspiritApi.getAuctionSettingsData() || {},//#B141 task
3680                                content: "",
3681
3682                                /*estimatedPrice: itemRow.attr("data-e
3682stimated-price"),
3683                                bidsInCatalog: bidsInCatalog,
3684                                nextMinBid: nextMinBid,
3685                                bidspiritUser: bidspiritUser,
3686                                postAuctionSaleOpenedUntil: Boolean(parseInt(catalogSection.attr("data-post-auction-sale-opened-until"))),*/
3687                            }, true, function () {
3688                                if (itemInfo !== undefined) {
3689                                    hangUpEvent("bp:after-getItemsInfo-content-item", itemInfo, itemRow);
3690                                }
3691                            });
3692                        }
3693
3694                        hangUpEvent("bp:after-getItemsInfo-item", bidsInfoData);
3695                    }
3696                }
3697            });
3698        });
3699    }
3700
3701    function savePaymentMethod(bidspiritSessionId, stripePaymentMethodId, callback) {
3702        bidspiritPostQuery("users/paymentMethods/checkPaymentMethodSaved", {
3703            sessionId: bidspiritSessionId,
3704            stripePaymentMethodId: stripePaymentMethodId
3705        }, function (data) {
3706            function reload() {
3707                showPaymentMethodsList();
3708                MicroModal.close("modal-payment-method");
3709            }
3710
3711            var response = data.response;
3712
3713            if (response.errorCode) {
3714                noticeSwall("error", response.errorCode, "error while trying to save payment method");
3715                reload();
3716            } else if (response.success) {
3717                reload();
3718            } else if (response.pending) {
3719                setTimeout(function () {
3720                    savePaymentMethod(bidspiritSessionId, stripePaymentMethodId, callback);
3721                }, 1000);
3722            }
3723
3724            if (callback !== undefined) {
3725                callback();
3726            }
3727        });
3728    }
3729
3730    function showPaymentMethodsList() {
3731        bidspiritPostQuery("users/paymentMethods/getPaymentMethods", {
3732            sessionId: bidspiritSessionId
3733        }, function (data) {
3734            var methodsList = "#section-payment-method-list";
3735            $(methodsList).empty();
3736            loadTemplate(methodsList, "payment-methods-list-template", {
3737                data: data.response
3738            }, true, function () {
3739                $(methodsList).find(".bp-method-row").each(function (index, elem) {
3740                    var row = $(elem),
3741                        deleteBtn = row.find(".bp-method-delete");
3742                    deleteBtn.on("click", function (event) {
3743                        event.preventDefault();
3744                        fireSwall(window.bs_lang.remove_payment_method, function () {
3745                            bidspiritPostQuery("users/paymentMethods/removePaymentMethod", {
3746                                sessionId: bidspiritSessionId,
3747                                paymentMethodId: row.attr("data-id")
3748                            }, function (data) {
3749                                if (data.response === "ok") {
3750                                    row.remove();
3751                                    showPaymentMethodsList();
3752                                } else {
3753                                    noticeSwall("error", data.response.errorCode, data.response.errorMessage);
3754                                }
3755                            });
3756                        });
3757                    });
3758                });
3759            });
3760        });
3761    }
3762
3763    function btnActionPaymentMethods(stripe, stripeElements) {
3764        $("#addPaymentMethodAction").on("click", function () {
3765            var $this = $(this),
3766                modalContainer = $this.parents(".modal__container");
3767            modalContainer.append('<div class="bs-loader-fill"></div>');
3768            stripe.confirmSetup({
3769                elements: stripeElements,
3770                confirmParams: {
3771                    return_url: window.location.href
3772                },
3773                redirect: "if_required"
3774            }).then(function (response) {
3775                try {
3776                    savePaymentMethod(bidspiritSessionId, response.setupIntent.payment_method, function () {
3777                        modalContainer.find(".bs-loader-fill").remove();
3778                        clearStripeForm();
3779                        paymentMethodList(function () {
3780                            if (!!paymentMethods[0]) {
3781                                let auction = document.querySelector("[data-auction-id]");
3782                                let data = {
3783                                    sessionId: bidspiritSessionId,
3784                                    paymentMethodId: paymentMethods[0].id
3785                                };
3786
3787                                if (!!auction) {
3788                                    data.auctionId = auction.getAttribute("data-auction-id");
3789                                }
3790
3791                                bidspiritPostQuery("approvals/requestToParticipateInAuction", data, function (response) {
3792                                    updateDisplay();
3793                                });
3794                            }
3795                        });
3796                        MicroModal.init(microModalInitConfig());
3797                    });
3798                } catch (e) {
3799                    modalContainer.find(".bs-loader-fill").remove();
3800                    console.error(e);
3801                    noticeSwall("error", "error", response.error.message);
3802                }
3803            });
3804        });
3805    }
3806
3807    function clearStripeForm() {
3808        var stripePaymentElement = $("#stripePaymentElement");
3809
3810        if (stripePaymentElement.length) {
3811            stripePaymentElement.empty().append('<div class="bs-loader-small"></div>');
3812        }
3813    }
3814
3815    function loadStripeForm(apiAction, nodeContainer) {
3816        bidspiritPostQuery(apiAction, {
3817            sessionId: bidspiritSessionId
3818        }, function (data) {
3819            if (data.response.clientSecret !== undefined) {
3820                var options = {
3821                    clientSecret: data.response.clientSecret,
3822                    locale: LANG,
3823                    appearance: {
3824                        theme: "stripe"
3825                    }
3826                };
3827                bidspiritApi.stripeLoad(function () {
3828                    var stripeNode = "#stripePaymentElement",
3829                        stripe = Stripe(auctionSettingsData.stripePublicKey),
3830                        stripeElements = stripe.elements(options),
3831                        paymentElement = stripeElements.create("payment");
3832                    paymentElement.mount(stripeNode);
3833                    paymentElement.on("ready", function () {
3834                        $(nodeContainer).find("footer").removeClass(window.bs_data.hidden_class);
3835                    });
3836                    btnActionPaymentMethods(stripe, stripeElements);
3837                });
3838            } else {
3839                noticeSwall("error", "Unknown error", response.errorMessage);
3840                clearStripeForm();
3841            }
3842        }, function () {
3843        }, function () {
3844        });
3845    }
3846
3847    /**
3848     * Detect Safari Private browsing mode
3849     * Returns a Promise that resolves to true if in private mode
3850     */
3851    function detectSafariPrivateMode() {
3852        return new Promise(function(resolve) {
3853            // Test localStorage access (throws in Safari Private)
3854            var testKey = 'paytrace_test';
3855            try {
3856                localStorage.setItem(testKey, testKey);
3857                localStorage.removeItem(testKey);
3858                // If we get here, not in private mode
3859                resolve(false);
3860            } catch(e) {
3861                // localStorage blocked = Safari Private
3862                resolve(true);
3863            }
3864        });
3865    }
3866
3867    function loadPayTraceForm(apiAction, nodeContainer) {
3868        console.log('[PayTrace] === STARTING PAYMENT FORM LOAD ===');
3869        console.log('[PayTrace] Checking browser compatibility...');
3870        
3871        // Detect Safari Private mode first
3872        detectSafariPrivateMode().then(function(isPrivate) {
3873            if (isPrivate) {
3874                console.error('[PayTrace] Safari Private mode detected - PayTrace not supported');
3875                $(nodeContainer).find(".bs-loader-small").remove();
3876                noticeSwall(
3877                    "error",
3878                    "Browser Compatibility Issue",
3879                    "Safari Private browsing mode is not compatible with PayTrace. " +
3880                    "Please disable Private browsing mode or use Chrome/Firefox to add a payment method."
3881                );
3882                return; // Exit early
3883            }
3884            
3885            // Not in private mode, proceed normally
3886            console.log('[PayTrace] Browser compatible - proceeding');
3887            loadPayTraceFormInternal(apiAction, nodeContainer);
3888        });
3889    }
3890
3891    function loadPayTraceFormInternal(apiAction, nodeContainer) {
3892        // BidSpirit call works directly from browser (has cookies)
3893        console.log('[PayTrace] Step 1: Calling BidSpirit API for clientSecret');
3894        console.log('[PayTrace] SessionId:', bidspiritSessionId);
3895        console.log('[PayTrace] API Action:', apiAction);
3896        
3897        // State tracking to prevent multiple error handlers
3898        var formLoadCompleted = false;
3899        var formLoadFailed = false;
3900        
3901        // Timeout fallback in case things hang
3902        var loadTimeout = setTimeout(function() {
3903            if (!formLoadCompleted && !formLoadFailed) {
3904                formLoadFailed = true;
3905                console.error('[PayTrace] TIMEOUT: Form load took too long (30s)');
3906                $(nodeContainer).find(".bs-loader-small").remove();
3907                noticeSwall("error", "Timeout", "Payment form failed to load. Please try again.");
3908            } else {
3909                console.log('[PayTrace] 30s timeout ignored - form already completed/failed');
3910            }
3911        }, 30000);
3912        
3913        bidspiritPostQuery(apiAction, {
3914            sessionId: bidspiritSessionId
3915        }, function (data) {
3916            console.log('[PayTrace] Step 2: BidSpirit API SUCCESS');
3917            console.log('[PayTrace] Response data:', data);
3918            $(nodeContainer).find('#payTracePaymentElement').append("<div id=\"pt_hpf_form\"></div>");
3919            if (data.response.clientSecret !== undefined) {
3920                console.log('[PayTrace] Step 3: Got clientSecret (length: ' + data.response.clientSecret.length + ')');
3921                console.log('[PayTrace] Step 4: Loading PayTrace SDK...');
3922                loadPayTraceSDK(function() {
3923                    console.log('[PayTrace] Step 5: SDK loaded successfully');
3924                    console.log('[PayTrace] Step 6: Calling PTPayment.setup (no interception - letting it run naturally)...');
3925                    
3926                    // Call PTPayment.setup without any interception
3927                    PTPayment.setup({
3928                        styles: getPayTraceStyles(),
3929                        authorization: {
3930                            clientKey: data.response.clientSecret 
3931                        }
3932                    }).then(function(instance) {
3933                        if (!formLoadCompleted && !formLoadFailed) {
3934                            formLoadCompleted = true;
3935                            clearTimeout(loadTimeout);
3936                            console.log('[PayTrace] Step 7: PTPayment.setup SUCCESS');
3937                            console.log('[PayTrace] Instance:', instance);
3938                            window.payTraceInstance = instance;
3939                            $(nodeContainer).find("footer").removeClass(window.bs_data.hidden_class);
3940                            $(nodeContainer).find(".bs-loader-small").remove();
3941                            console.log('[PayTrace] === FORM LOAD COMPLETE ===');
3942                            btnActionPayTracePaymentMethods();
3943                        }
3944                    }).catch(function(error) {
3945                        if (!formLoadCompleted && !formLoadFailed) {
3946                            formLoadFailed = true;
3947                            clearTimeout(loadTimeout);
3948                            console.error('[PayTrace] Step 7 FAILED: PTPayment.setup error');
3949                            console.error('[PayTrace] Error details:', error);
3950                            console.error('[PayTrace] Error stack:', error ? error.stack : 'no stack');
3951                            
3952                            // Restore original fetch/XHR
3953                            window.fetch = originalFetch;
3954                            XMLHttpRequest.prototype.open = originalOpen;
3955                            
3956                            $(nodeContainer).find(".bs-loader-small").remove();
3957                            
3958                            // Check if it's a timeout
3959                            if (error.message && error.message.indexOf('timed out') !== -1) {
3960                                noticeSwall("error", "Timeout", "PayTrace is incompatible with Safari Private browsing mode. Please use normal browsing or a different browser.");
3961                            } else {
3962                                noticeSwall("error", "Error", "Failed to initialize PayTrace form: " + error.message);
3963                            }
3964                        }
3965                    });
3966                });
3967            } else {
3968                if (!formLoadCompleted && !formLoadFailed) {
3969                    formLoadFailed = true;
3970                    clearTimeout(loadTimeout);
3971                    console.error('[PayTrace] Step 3 FAILED: No clientSecret in response');
3972                    console.error('[PayTrace] Response:', data);
3973                    $(nodeContainer).find(".bs-loader-small").remove();
3974                    noticeSwall("error", "Unknown error", data.response.errorMessage);
3975                }
3976            }
3977        }, function(error) {
3978            if (!formLoadCompleted && !formLoadFailed) {
3979                formLoadFailed = true;
3980                clearTimeout(loadTimeout);
3981                console.error('[PayTrace] Step 2 FAILED: BidSpirit API error callback');
3982                console.error('[PayTrace] Error:', error);
3983                $(nodeContainer).find(".bs-loader-small").remove();
3984                noticeSwall("error", "API Error", "Failed to connect to BidSpirit API");
3985            }
3986        });
3987    }
3988
3989    function loadPayTraceSDK(callback) {
3990        var classTrigger = "paytrace-load";
3991        if (document.body.classList.contains(classTrigger)) {
3992            callback();
3993        } else {
3994            if (window.wp_data.sandbox === true) {
3995                console.info("We use sandbox envirement");
3996            }
3997            const sdkUrl = window.wp_data.sandbox === true
3998                ? "https://protect.sandbox.paytrace.com/js/protect.min.js"
3999                : "https://protect.paytrace.com/js/protect.min.js";
4000
4001            console.log('[PayTrace] Fetching SDK from:', sdkUrl);
4002            $.getScript(sdkUrl)
4003                .done(function(script, textStatus) {
4004                    console.log('[PayTrace] SDK fetch done, status:', textStatus);
4005                    console.log('[PayTrace] PTPayment available:', typeof PTPayment !== 'undefined');
4006                    callback();
4007                    console.info(textStatus + " PayTrace SDK load");
4008                    document.body.classList.add(classTrigger);
4009                })
4010                .fail(function(jqxhr, settings, exception) {
4011                    console.error('[PayTrace] SDK LOAD FAILED');
4012                    console.error('[PayTrace] jqXHR:', jqxhr);
4013                    console.error('[PayTrace] Settings:', settings);
4014                    console.error('[PayTrace] Exception:', exception);
4015                    console.error('[PayTrace] Response text:', jqxhr.responseText);
4016                    $(nodeContainer).find(".bs-loader-small").remove();
4017                    noticeSwall("error", "Error", "Failed to load PayTrace SDK: " + exception);
4018                });
4019        }
4020    }
4021
4022    function getPayTraceStyles() {
4023        var styles = {
4024            'cc': {
4025                'font_size': '16px',
4026                'input_border_radius': '2px',
4027                'input_border_width': '1px',
4028                'input_margin': '5px 0px 5px 0px',
4029                'input_padding': '3px 5px 3px 5px',
4030                'label_size': '14px',
4031                'label_width': '150px',
4032                'label_font_weight': 'bold',
4033                'label_margin': '5px 0px 0px 0px',
4034                'label_padding': '0px 5px 0px 5px',
4035                'background_color': 'white',
4036                'height': '25px',
4037                'width': '327px',
4038                'padding_bottom': '0px'
4039            },
4040            'code': {
4041                'border_color': '#333',
4042                'font_size': '13pt',
4043                'input_border_radius': '2px',
4044                'input_border_width': '1px',
4045                'input_margin': '5px 0px 5px 20px',
4046                'input_padding': '3px 5px 3px 5px',
4047                'background_color': 'white',
4048                'label_size': '14px',
4049                'label_width': '150px',
4050                'label_font_weight': 'bold',
4051                'label_margin': '5px 0px 0px 20px',
4052                'label_padding': '2px 5px 2px 5px',
4053                'height': '25px',
4054                'width': '110px',
4055                'padding_bottom': '2px'
4056            },
4057            'body': {
4058                'background_color': 'white'
4059            }
4060        }
4061        return styles;
4062    }
4063
4064    function clearPayTraceForm() {
4065        var payTraceElement = $("#payTracePaymentElement");
4066        if (payTraceElement.length) {
4067            payTraceElement.empty().append('<div class="bs-loader-small"></div>');
4068        }
4069    }
4070
4071    function btnActionPayTracePaymentMethods() {
4072        $("#addPaymentMethodAction").off("click").on("click", function () {
4073            var $this = $(this),
4074                modalContainer = $this.parents(".modal__container");
4075            modalContainer.append('<div class="bs-loader-fill"></div>');
4076
4077            if (!window.payTraceInstance) {
4078                modalContainer.find(".bs-loader-fill").remove();
4079                noticeSwall("error", "Error", "PayTrace form not initialized");
4080                return;
4081            }
4082
4083            window.payTraceInstance.process()
4084                .then(handlePayTraceCardSubmissionSuccess)
4085                .catch(handlePayTraceCardSubmissionError)
4086                .finally(function() {
4087                    modalContainer.find(".bs-loader-fill").remove();
4088                });
4089        });
4090    }
4091
4092    function handlePayTraceCardSubmissionSuccess(encryptedCardInfo) {
4093        clearPayTraceForm();
4094        bidspiritQuery("users/paymentMethods/saveCardFromPayTrace", {
4095            sessionId: bidspiritSessionId,
4096            hpfToken: encryptedCardInfo.message.hpf_token,
4097            encKey: encryptedCardInfo.message.enc_key
4098        }, function (response) {
4099            clearPayTraceForm();
4100            if (!checkError(response)) {
4101                if (document.body.classList.contains('bp_profile_page')) {
4102                    showPaymentMethodsList();
4103                }
4104
4105                paymentMethodList(function () {
4106                    if (!!paymentMethods[0]) {
4107                        let auction = document.querySelector("[data-auction-id]");
4108                        let data = {
4109                            sessionId: bidspiritSessionId,
4110                            paymentMethodId: paymentMethods[0].id
4111                        };
4112
4113                        if (!!auction) {
4114                            data.auctionId = auction.getAttribute("data-auction-id");
4115                        }
4116
4117                        bidspiritPostQuery("approvals/requestToParticipateInAuction", data, function (response) {
4118                            updateDisplay();
4119                        });
4120                    }
4121                });
4122
4123                MicroModal.close("modal-payment-method");
4124                MicroModal.close("modal-request-approval");
4125            } else {
4126                console.log("handlePayTraceCardSubmissionError 1");
4127                handlePayTraceCardSubmissionError(response.error);
4128            }
4129        });
4130    }
4131
4132    function handlePayTraceCardSubmissionError(error) {
4133        if (error !== undefined) {
4134            console.error("PayTrace submission error:", error);
4135        }
4136        clearPayTraceForm();
4137        loadPayTraceForm("users/paymentMethods/getPayTraceSetupSecret", $("#modal-payment-method").find(".modal__container"));
4138    }
4139
4140    function togglePaymentForms(provider) {
4141        const stripForm = $("#stripePaymentElement");
4142        const payTraceForm = $("#payTracePaymentElement");
4143        
4144        if (provider === "PAY_TRACE") {
4145            stripForm.removeClass("active").addClass(window.bs_data.hidden_class);
4146            payTraceForm.addClass("active").removeClass(window.bs_data.hidden_class);
4147        } else {
4148            stripForm.addClass("active").removeClass(window.bs_data.hidden_class);
4149            payTraceForm.removeClass("active").addClass(window.bs_data.hidden_class);
4150        }
4151    }
4152
4153    function addPaymentMethodCallback() {
4154        MicroModal.show("modal-payment-method", {
4155            onShow: function (modalBlock) {
4156                var $modalBlock = $("#modal-payment-method"),
4157                    footer = $modalBlock.find("footer");
4158                footer.find("#autoChargingCreditCardMessage-block").remove();
4159                footer.prepend('<p id="autoChargingCreditCardMessage-block" class="bp-text-red bp-mb-0">' + autoChargingCreditCardMessage(auctionSettingsData) + "</p>");
4160                
4161                togglePaymentForms(auctionSettingsData.creditCardProvider);
4162                
4163                if (auctionSettingsData.creditCardProvider === "PAY_TRACE") {
4164                    loadPayTraceForm("users/paymentMethods/getPayTraceSetupSecret", $modalBlock.find(".modal__container"));
4165                } else {
4166                    loadStripeForm("users/paymentMethods/getStripeSetupSecret", $modalBlock.find(".modal__container"));
4167                }
4168                
4169                $modalBlock.addClass(triggerClass);
4170            },
4171            onClose: function (modalBlock) {
4172                var $modalBlock = $(modalBlock);
4173                // $modalBlock.find(".modal__container").append('<div class="bs-loader-small"></div>');
4174                
4175                if (auctionSettingsData.creditCardProvider === "PAY_TRACE") {
4176                    clearPayTraceForm();
4177                } else {
4178                    clearStripeForm();
4179                }
4180                
4181                $modalBlock.find("footer").addClass(window.bs_data.hidden_class);
4182                $modalBlock.removeClass(triggerClass);
4183            }
4184        });
4185    }
4186
4187    function paymentMethodAction(apiAction, container, bidspiritUser) {
4188        if (bidspiritUser !== undefined && bidspiritUser.approvalState === "INCOMPLETE_PROFILE") {
4189            loadTemplate(container, "account-empty-template", {
4190                message: window.bs_lang.access_denied
4191            });
4192        } else {
4193            loadTemplate(container, "payment-methods-template", {}, true, function () {
4194                $("#addPaymentMethod").on("click", addPaymentMethodCallback);
4195                showPaymentMethodsList();
4196            });
4197        }
4198    }
4199
4200    function auctionInfoInit(bidspiritSessionId, currentAuctionNumber, callback) {
4201        // A BidSpirit Shop has no auction behind it, so auctions/getAuctionInfo
4202        // answers "Auction <synthetic id> not found" — and checkError() puts
4203        // that straight in front of the customer as an error modal. Seed a
4204        // minimal auctionInfo instead and skip the call.
4205        if (bsShopIsActive()) {
4206            bidspiritApi.setAuctionInfo(bsShopAuctionInfo());
4207            if (callback !== undefined) {
4208                callback();
4209            }
4210            return true;
4211        }
4212
4213        if (currentAuctionNumber === "") {
4214            return false;
4215        } else {
4216            bidspiritQuery("auctions/getAuctionInfo", {
4217                sessionId: bidspiritSessionId,
4218                auctionId: currentAuctionNumber
4219            }, function (data) {
4220                if (!checkError(data)) {
4221                    bidspiritApi.setAuctionInfo(data.response);
4222                    var response = data.response;
4223
4224                    if (response.approvalRequired !== undefined && response.approvalRequired) {
4225                        approvalInfo(currentAuctionNumber);
4226                    }
4227
4228                    if (!!document.getElementById('auction-commission-field')) {
4229                        document.getElementById('auction-commission-field').textContent = data.response.commission + "%";
4230                    }
4231                }
4232
4233                if (callback !== undefined) {
4234                    callback();
4235                }
4236            });
4237        }
4238    }
4239
4240    function autoChargingCreditCardMessage(auctionSettingsData) {
4241        var additionalMessage = "";
4242
4243        if (auctionSettingsData.autoPaymentDays !== undefined) {
4244            additionalMessage = window.bs_lang.auto_charge_x_days_after.replace(/#days#/, auctionSettingsData.autoPaymentDays);
4245        }
4246
4247        return additionalMessage;
4248    }
4249
4250    (function () {
4251        function loadMoreLots() {
4252            var triggerEvent = true,
4253                totalLots = catalogSection.attr("data-lot-count");
4254            $(window, ".st-content").scroll(function (event) {
4255                var st = $(this).scrollTop(),
4256                    wHeight = $(window).height(),
4257                    catalogSection = $("#catalog-section"),
4258                    catalogBlockHeight = catalogSection.height(),
4259                    catalogOffset = catalogSection.offset(),
4260                    endCatalog = catalogBlockHeight + catalogOffset.top,
4261                    midTriggerHeight = st + wHeight + 1000,
4262                    bgColor = catalogSection.attr("data-bg-color"),
4263                    count = catalogSection.find(".bp-lot").length,
4264                    part = catalogSection.attr("data-auction-part"),
4265                    loaderTemplate = $("#loadMore-template").html(),
4266                    lang = window.bs_data.lang;
4267
4268                var sortBy = function () {
4269                    return searchGetParam("sort_by");
4270                };
4271
4272                var categoryBy = function () {
4273                    return searchGetParam("category_by");
4274                };
4275
4276                var phraseBy = function () {
4277                    return searchGetParam("phrase_by");
4278                };
4279
4280                var perPage = function () {
4281                    return searchGetParam("per_page");
4282                };
4283
4284                if (midTriggerHeight > endCatalog && triggerEvent && count < totalLots) {
4285                    catalogSection.append(loaderTemplate);
4286                    triggerEvent = false;
4287                    let currentAuctionNumber = catalogSection.attr("data-auction-index");
4288                    $.ajax({
4289                        type: "post",
4290                        dataType: "json",
4291                        url: window.wp_data.ajax_url,
4292                        data: {
4293                            action: "do_load_more",
4294                            security: window.wp_nonce,
4295                            auctionId: currentAuctionNumber,
4296                            termId: catalogSection.attr("data-term-id"),
4297                            count: count,
4298                            part: part,
4299                            lang: lang,
4300                            sort_by: sortBy(),
4301                            category_by: categoryBy(),
4302                            phrase_by: phraseBy(),
4303                            per_page: perPage()
4304                        }
4305                    }).done(function (response) {
4306                        var indexes = [];
4307                        $.each(response.data.lots, function (index, elem) {
4308                            indexes.push(elem.itemIndex);
4309                        });
4310                        loadTemplate(catalogSection, "lotsLoadMore-template", {
4311                            lots: response.data.lots,
4312                            currency: currencySymbol,
4313                            bgColor: bgColor,
4314                            showEstimatedPriceInItemsList: Boolean(parseInt(response.data.showEstimatedPriceInItemsList)),
4315                            displayStartPriceInCatalog: Boolean(parseInt(response.data.displayStartPriceInCatalog))
4316                        }, false, function () {
4317                        }, true);
4318                        count = catalogSection.find(".bp-lot").length;
4319                        totalLots = response.data.total;
4320
4321                        new Promise((resolve, reject) => {
4322                            auctionInfoInit(bidspiritSessionId, currentAuctionNumber, resolve);
4323                            // resolve();
4324                        }).then(function (response) {
4325                            updateAuctionPage(catalogSection, indexes);
4326                        });
4327
4328                        triggerEvent = true;
4329                    }).fail(function () {
4330                        console.error("Fatal error");
4331                    }).always(function () {
4332                        $("#bsLoaderCatalog").remove();
4333                    });
4334                }
4335            });
4336        }
4337
4338        var catalogSection = $("#catalog-section"),
4339            pagination = window.bs_data.use_pagination;
4340
4341        if (catalogSection.length && pagination === "off") {
4342            loadMoreLots();
4343        }
4344    })();
4345
4346    function updateDisplay() {
4347        var singleLot = $("#single-lot"),
4348            catalogSection = $("#catalog-section"),
4349            profile = $("#profile-page");
4350
4351        (function () {
4352            if (catalogSection.length) {
4353                var currentAuctionNumber = catalogSection.attr("data-auction-id");
4354
4355                new Promise((resolve, reject) => {
4356                    auctionInfoInit(bidspiritSessionId, currentAuctionNumber, resolve);
4357                }).then(function (response) {
4358                    updateAuctionPage(catalogSection);
4359                    toggleAuctionAlert(currentAuctionNumber);
4360                });
4361            }
4362        })();
4363
4364        (function () {
4365            if (singleLot.length) {
4366                var lot = $("#single-lot"),
4367                    dateTime = $("#dateTimeField"),
4368                    fullPriceNode = $("#bp-fullPrice");
4369                currentLotIndex = lot.attr("data-lot-index");
4370                currentAuctionNumber = lot.attr("data-auction-index");
4371
4372                new Promise((resolve, reject) => {
4373                    auctionInfoInit(bidspiritSessionId, currentAuctionNumber, resolve);
4374                }).then(function (response) {
4375                    loadBid(currentLotIndex, currentAuctionNumber);
4376                });
4377
4378                if (dateTime.length) {
4379                    getLeftDate(dateTime.attr("data-time"));
4380                }
4381            }
4382        })();
4383
4384        (function () {
4385            function profileQuery(apiAction, lotList) {
4386                // Use the paginated function with future/past toggle for all profile tabs
4387                if (apiAction === "account/getAbsenteeBids" ||
4388                    apiAction === "account/getFavorites" ||
4389                    apiAction === "account/getPurchases") {
4390                    profilePaginatedQuery(apiAction, lotList);
4391                    return;
4392                }
4393                bidspiritQuery(apiAction, {
4394                    sessionId: bidspiritSessionId,
4395                    language: LANG
4396                }, function (data) {
4397                    if (data.response.count > 0) {
4398                        loadTemplate(lotList, "account-items-template", {
4399                            items: data.response.items,
4400                            currency: currencySymbol,
4401                            imageBlank: imageBlank,
4402                            bgColor: $("#profile-page").attr("data-bg-color")
4403                        }, false, function () {
4404                            $(lotList + " .bp-lots .bp-lot").each(function (index, elem) {
4405                                var $this = $(elem),
4406                                    wishBtn = $this.find(".bp__wishlist");
4407                                $this.find("a").on("click", function (event) {
4408                                    event.preventDefault();
4409                                    event.stopPropagation();
4410                                    $.ajax({
4411                                        type: "post",
4412                                        dataType: "json",
4413                                        url: window.wp_data.ajax_url,
4414                                        data: {
4415                                            action: "do_link",
4416                                            security: window.wp_nonce,
4417                                            bidSpirit: {
4418                                                lot_id: $this.attr("data-lot-id")
4419                                            }
4420                                        }
4421                                    }).done(function (response) {
4422                                        if (response.data !== undefined && response.success === true) {
4423                                            window.location = response.data.link;
4424                                        } else {
4425                                            noticeSwall("error", window.bs_lang.not_found);
4426                                        }
4427                                    }).fail(function (response) {
4428                                        noticeSwall("error", window.bs_lang.not_found);
4429                                    });
4430                                });
4431                                wishBtn.on("click", function (event) {
4432                                    event.preventDefault();
4433                                    event.stopPropagation();
4434                                    toggleFavorite($this, wishBtn, $this.attr("data-auction-number"), true);
4435                                });
4436                            });
4437
4438                            data.response.items.forEach(function (lot) {
4439                                if (lot.item.id !== undefined) {
4440                                    let elem = $("[data-lot-id=\"" + lot.item.id + "\"]");
4441                                    if (elem.length > 0) {
4442                                        let $this = $(elem);
4443
4444                                        var nextMinBid = 0;
4445                                        nextMinBid = getMinBidPriceFromIncrementSteps(lot, lot.auction.increments);
4446                                        initIncrementSteps(lot.auction.increments, nextMinBid);
4447                                        let incrementStepsList = allIncrementsPrices;
4448
4449                                        let bids = [];
4450                                        Array.prototype.forEach.call(incrementStepsList, function (elem, i) {
4451                                            if (elem >= nextMinBid) {
4452                                                bids.push({
4453                                                    id: elem,
4454                                                    text: formattedPrice(elem, currencySymbol)
4455                                                });
4456                                            }
4457                                        });
4458
4459                                        if (bids.length > 0 && bids[0] !== undefined && bids[0].id !== undefined && (nextMinBid !== 0 && nextMinBid < bids[0].id)) {
4460                                            bids.unshift({
4461                                                id: nextMinBid,
4462                                                text: formattedPrice(nextMinBid, currencySymbol)
4463                                            });
4464                                        }
4465
4466                                        console.log($this);
4467                                        let selectBid = select2build($this.find(".js-data-bid-list"), bids);
4468                                    }
4469                                }
4470                            });
4471                        });
4472                    } else {
4473                        loadTemplate(lotList, "account-empty-template", {
4474                            message: "Lot list empty"
4475                        });
4476                    }
4477                }, function (data) {
4478                    noticeSwall("error", "The request failed", "Your account may have been logged in earlier.");
4479                });
4480            }
4481
4482            /**
4483             * Generic paginated profile query with Future / Ended auction toggle.
4484             * Handles BidSpirit's 1000-item API limit by fetching additional pages.
4485             * Works for: getAbsenteeBids, getFavorites, getPurchases
4486             */
4487            function profilePaginatedQuery(apiAction, lotList) {
4488                var API_PAGE_SIZE = 1000;
4489                var allCollectedItems = [];
4490                var sectionPrefix = "bp-paginated-" + apiAction.replace(/\//g, "-");
4491                var futureId = sectionPrefix + "-future";
4492                var endedId = sectionPrefix + "-ended";
4493
4494                $(lotList).html('<div class="bp-row bp-fix-width-lot"><div class="bp-d-flex bp-f-wrap bp-f-center bp-mb-30"><p>Loading...</p></div></div>');
4495
4496                function fetchPage(offset) {
4497                    var params = {
4498                        sessionId: bidspiritSessionId,
4499                        language: LANG
4500                    };
4501                    if (offset > 0) {
4502                        params.offset = offset;
4503                    }
4504
4505                    console.log("[Profile:" + apiAction + "] Fetching page, offset=" + offset);
4506
4507                    bidspiritQuery(apiAction, params, function (data) {
4508                        console.log("[Profile:" + apiAction + "] Page response (offset=" + offset + "):", "count=" + data.response.count, "items=" + (data.response.items ? data.response.items.length : 0));
4509
4510                        if (data.response.items && data.response.items.length > 0) {
4511                            allCollectedItems = allCollectedItems.concat(data.response.items);
4512                            console.log("[Profile:" + apiAction + "] Total collected so far:", allCollectedItems.length);
4513
4514                            if (data.response.items.length >= API_PAGE_SIZE) {
4515                                $(lotList).html('<div class="bp-row bp-fix-width-lot"><div class="bp-d-flex bp-f-wrap bp-f-center bp-mb-30"><p>Loading... (' + allCollectedItems.length + ' loaded)</p></div></div>');
4516                                fetchPage(offset + API_PAGE_SIZE);
4517                                return;
4518                            }
4519                        }
4520
4521                        if (allCollectedItems.length > 0) {
4522                            renderAllItems(allCollectedItems);
4523                        } else {
4524                            loadTemplate(lotList, "account-empty-template", {
4525                                message: "Lots not found"
4526                            });
4527                        }
4528                    }, function (data) {
4529                        if (allCollectedItems.length > 0) {
4530                            console.warn("[Profile:" + apiAction + "] Page fetch failed at offset=" + offset + ", rendering " + allCollectedItems.length + " items collected so far");
4531                            renderAllItems(allCollectedItems);
4532                        } else {
4533                            console.error("[Profile:" + apiAction + "] API request failed:", data);
4534                            noticeSwall("error", "The request failed", "Your account may have been logged in earlier.");
4535                        }
4536                    });
4537                }
4538
4539                function renderAllItems(allItems) {
4540                    console.log("[Profile:" + apiAction + "] Rendering all items, total:", allItems.length);
4541
4542                    var auctionDates = {};
4543                    allItems.forEach(function(lot) {
4544                        var key = lot.auction.date || 'unknown';
4545                        if (!auctionDates[key]) auctionDates[key] = 0;
4546                        auctionDates[key]++;
4547                    });
4548                    console.log("[Profile:" + apiAction + "] Auction dates breakdown:", auctionDates);
4549
4550                    var futureItems = [];
4551                    var endedItems = [];
4552
4553                    allItems.forEach(function(lot) {
4554                        var isEnded = false;
4555                        if (lot.item.wasInLiveAuction === true) {
4556                            isEnded = true;
4557                        } else if (lot.soldBid !== undefined && lot.soldBid.isSold === true) {
4558                            isEnded = true;
4559                        } else if (lot.leadingBid !== undefined && lot.leadingBid.isSold === true) {
4560                            isEnded = true;
4561                        }
4562
4563                        if (isEnded) {
4564                            endedItems.push(lot);
4565                        } else {
4566                            futureItems.push(lot);
4567                        }
4568                    });
4569
4570                    console.log("[Profile:" + apiAction + "] Future items:", futureItems.length, "Ended items:", endedItems.length);
4571
4572                    var toggleHtml = '<div class="bp-bids-toggle-wrapper" style="text-align: center; padding: 15px 0 5px;">';
4573                    toggleHtml += '<button type="button" class="bp-bids-toggle-btn bp-bids-toggle-active" data-target="future">Future Auctions (' + futureItems.length + ')</button>';
4574                    toggleHtml += '<button type="button" class="bp-bids-toggle-btn" data-target="ended">Ended Auctions (' + endedItems.length + ')</button>';
4575                    toggleHtml += '</div>';
4576                    if (futureItems.length > 0) {
4577                        // The checkbox stays as the real control — it keeps the
4578                        // keyboard/tab behaviour and every existing binding on
4579                        // .af-bidwatch-checkbox — and the slider span is purely
4580                        // its visual skin. aria-hidden so screen readers announce
4581                        // the checkbox once, not twice.
4582                        toggleHtml += '<div class="af-bidwatch-wrap"><label class="af-bidwatch-toggle">' +
4583                            '<input type="checkbox" class="af-bidwatch-checkbox">' +
4584                            '<span class="af-bidwatch-slider" aria-hidden="true"></span>' +
4585                            '<span class="af-bidwatch-text">' +
4586                            ((window.afBidWatchLang && window.afBidWatchLang.auto_refresh_label) || 'Auto-refresh bids (every 10s)') +
4587                            '</span></label></div>';
4588                    }
4589                    toggleHtml += '<div id="' + futureId + '"></div>';
4590                    toggleHtml += '<div id="' + endedId + '" style="display:none;"></div>';
4591
4592                    $(lotList).html(toggleHtml);
4593
4594                    function renderSectionItems(targetSelector, items) {
4595                        if (items.length === 0) {
4596                            $(targetSelector).html('<div class="bp-row bp-fix-width-lot"><div class="bp-d-flex bp-f-wrap bp-f-center bp-mb-30"><p>Lots not found</p></div></div>');
4597                            return;
4598                        }
4599                        loadTemplate(targetSelector, "account-items-template", {
4600                            items: items,
4601                            currency: currencySymbol,
4602                            imageBlank: imageBlank,
4603                            bgColor: $("#profile-page").attr("data-bg-color")
4604                        }, false, function () {
4605                            $(targetSelector + " .bp-lots .bp-lot").each(function (index, elem) {
4606                                var $this = $(elem),
4607                                    wishBtn = $this.find(".bp__wishlist");
4608                                $this.find("a").on("click", function (event) {
4609                                    event.preventDefault();
4610                                    event.stopPropagation();
4611                                    $.ajax({
4612                                        type: "post",
4613                                        dataType: "json",
4614                                        url: window.wp_data.ajax_url,
4615                                        data: {
4616                                            action: "do_link",
4617                                            security: window.wp_nonce,
4618                                            bidSpirit: {
4619                                                lot_id: $this.attr("data-lot-id")
4620                                            }
4621                                        }
4622                                    }).done(function (response) {
4623                                        if (response.data !== undefined && response.success === true) {
4624                                            window.location = response.data.link;
4625                                        } else {
4626                                            noticeSwall("error", window.bs_lang.not_found);
4627                                        }
4628                                    }).fail(function (response) {
4629                                        noticeSwall("error", window.bs_lang.not_found);
4630                                    });
4631                                });
4632                                wishBtn.on("click", function (event) {
4633                                    event.preventDefault();
4634                                    event.stopPropagation();
4635                                    toggleFavorite($this, wishBtn, $this.attr("data-auction-number"), true);
4636                                });
4637                            });
4638
4639                            items.forEach(function (lot) {
4640                                if (lot.item.id !== undefined) {
4641                                    var elem = $(targetSelector + " [data-lot-id=\"" + lot.item.id + "\"]");
4642                                    if (elem.length > 0) {
4643                                        var $this = $(elem);
4644                                        var nextMinBid = 0;
4645                                        nextMinBid = getMinBidPriceFromIncrementSteps(lot, lot.auction.increments);
4646                                        initIncrementSteps(lot.auction.increments, nextMinBid);
4647                                        var incrementStepsList = allIncrementsPrices;
4648
4649                                        var bids = [];
4650                                        Array.prototype.forEach.call(incrementStepsList, function (elem, i) {
4651                                            if (elem >= nextMinBid) {
4652                                                bids.push({
4653                                                    id: elem,
4654                                                    text: formattedPrice(elem, currencySymbol)
4655                                                });
4656                                            }
4657                                        });
4658
4659                                        if (bids.length > 0 && bids[0] !== undefined && bids[0].id !== undefined && (nextMinBid !== 0 && nextMinBid < bids[0].id)) {
4660                                            bids.unshift({
4661                                                id: nextMinBid,
4662                                                text: formattedPrice(nextMinBid, currencySymbol)
4663                                            });
4664                                        }
4665
4666                                        select2build($this.find(".js-data-bid-l
4666ist"), bids);
4667                                    }
4668                                }
4669                            });
4670                        });
4671                    }
4672
4673                    renderSectionItems("#" + futureId, futureItems);
4674                    renderSectionItems("#" + endedId, endedItems);
4675
4676                    // Auto-refresh (live bid watch) toggle — only present when there are future lots.
4677                    afStopBidWatch();
4678                    if (futureItems.length > 0) {
4679                        var $afBw = $(lotList).find(".af-bidwatch-checkbox");
4680                        $afBw.prop("checked", afBidWatchEnabled());
4681                        $afBw.off("change.afbw").on("change.afbw", function () {
4682                            afSetBidWatchEnabled(this.checked);
4683                            if (this.checked) { afStartBidWatch(); } else { afStopBidWatch(); }
4684                        });
4685                        if (afBidWatchEnabled()) { afStartBidWatch(); }
4686                    }
4687
4688                    $(lotList).on("click", ".bp-bids-toggle-btn", function () {
4689                        var target = $(this).attr("data-target");
4690                        $(lotList).find(".bp-bids-toggle-btn").removeClass("bp-bids-toggle-active");
4691                        $(this).addClass("bp-bids-toggle-active");
4692                        if (target === "future") {
4693                            $("#" + futureId).show();
4694                            $("#" + endedId).hide();
4695                        } else {
4696                            $("#" + futureId).hide();
4697                            $("#" + endedId).show();
4698                        }
4699                    });
4700                }
4701
4702                // Start fetching from offset 0
4703                fetchPage(0);
4704            }
4705
4706            function buildFields(user) {
4707                function checkField(field) {
4708                    return field !== undefined ? field : "";
4709                }
4710
4711                let settings = bidspiritApi.getAuctionSettingsData();
4712
4713                var fields = {
4714                    honorific: {
4715                        value: checkField(user.honorific),
4716                        label: "Honorific",
4717                        required: false,
4718                        type: "text"
4719                    },
4720                    firstName: {
4721                        value: checkField(user.firstName),
4722                        label: "First Name",
4723                        required: true,
4724                        type: "text"
4725                    },
4726                    lastName: {
4727                        value: checkField(user.lastName),
4728                        label: "Last Name",
4729                        required: true,
4730                        type: "text"
4731                    },
4732                    email: {
4733                        value: checkField(user.email),
4734                        label: "Email",
4735                        required: true,
4736                        type: "email"
4737                    },
4738                    password: {
4739                        value: "",
4740                        label: "Password",
4741                        required: false,
4742                        type: "password"
4743                    },
4744                    phone: {
4745                        value: checkField(user.phone),
4746                        label: "Phone",
4747                        required: true,
4748                        type: "phone"
4749                    },
4750                    secondPhone: {
4751                        value: checkField(user.secondPhone),
4752                        label: "Second phone",
4753                        required: false,
4754                        type: "phone"
4755                    },
4756                    id: {
4757                        value: checkField(user.id),
4758                        label: "ID",
4759                        required: false,
4760                        type: "text",
4761                        idPhotoUploadRequired: settings.idPhotoUploadRequired,
4762                        requireIdPhoto: settings.requireIdPhoto,
4763                        missingIdPhoto: bidspiritUser.missingIdPhoto,
4764                        hasIdPhoto: bidspiritUser.hasIdPhoto
4765                    },
4766                    taxNumber: {
4767                        value: checkField(user.taxNumber),
4768                        label: "Tax number",
4769                        required: false,
4770                        type: "text"
4771                    }
4772                },
4773                fieldsAddress = {
4774                    countryCode: {
4775                        value: "",
4776                        label: "Country",
4777                        required: true,
4778                        type: "select"
4779                    },
4780                    state: {
4781                        value: "",
4782                        label: "State",
4783                        required: false,
4784                        type: "select",
4785                        hidden: true
4786                    },
4787                    province: {
4788                        value: "",
4789                        label: "State",
4790                        required: false,
4791                        type: "text",
4792                        hidden: true
4793                    },
4794                    city: {
4795                        value: "",
4796                        label: "City",
4797                        required: true,
4798                        type: "text"
4799                    },
4800                    address: {
4801                        value: "",
4802                        label: "Address",
4803                        required: true,
4804                        type: "text"
4805                    },
4806                    zipCode: {
4807                        value: "",
4808                        label: "Zip Code",
4809                        required: true,
4810                        type: "text"
4811                    }
4812                };
4813
4814                if (user.address !== undefined) {
4815                    fieldsAddress = {
4816                        countryCode: {
4817                            value: checkField(user.address.countryCode),
4818                            label: "Country",
4819                            required: true,
4820                            type: "select"
4821                        },
4822                        state: {
4823                            value: checkField(user.address.state),
4824                            label: "State",
4825                            required: false,
4826                            type: "select",
4827                            hidden: true
4828                        },
4829                        province: {
4830                            value: checkField(user.address.state),
4831                            label: "State",
4832                            required: false,
4833                            type: "text",
4834                            hidden: true
4835                        },
4836                        city: {
4837                            value: checkField(user.address.city),
4838                            label: "City",
4839                            required: true,
4840                            type: "text"
4841                        },
4842                        address: {
4843                            value: checkField(user.address.address),
4844                            label: "Address",
4845                            required: true,
4846                            type: "text"
4847                        },
4848                        zipCode: {
4849                            value: checkField(user.address.zipCode),
4850                            label: "Zip Code",
4851                            required: true,
4852                            type: "text"
4853                        }
4854                    };
4855                }
4856
4857                return $.extend(fields, fieldsAddress);
4858            }
4859
4860            function buildShippingFields(user) {
4861                function checkField(field) {
4862                    return field !== undefined ? field : "";
4863                }
4864
4865                var shippingFields = {
4866                    recipientName: {
4867                        value: "",
4868                        label: "Recipient name",
4869                        required: false,
4870                        type: "text"
4871                    },
4872                    countryCode: {
4873                        value: "",
4874                        label: "Country",
4875                        required: true,
4876                        type: "select"
4877                    },
4878                    state: {
4879                        value: "",
4880                        label: "State",
4881                        required: false,
4882                        type: "select",
4883                        hidden: true
4884                    },
4885                    province: {
4886                        value: "",
4887                        label: "State",
4888                        required: false,
4889                        type: "text",
4890                        hidden: true
4891                    },
4892                    city: {
4893                        value: "",
4894                        label: "City",
4895                        required: true,
4896                        type: "text"
4897                    },
4898                    address: {
4899                        value: "",
4900                        label: "Address",
4901                        required: true,
4902                        type: "text"
4903                    },
4904                    zipCode: {
4905                        value: "",
4906                        label: "Zip Code",
4907                        required: true,
4908                        type: "text"
4909                    }
4910                };
4911
4912                if (user.shipping !== undefined) {
4913                    shippingFields = {
4914                        recipientName: {
4915                            value: checkField(user.shipping.recipientName),
4916                            label: "Recipient name",
4917                            required: false,
4918                            type: "text"
4919                        },
4920                        countryCode: {
4921                            value: checkField(user.shipping.countryCode),
4922                            label: "Country",
4923                            required: true,
4924                            type: "select"
4925                        },
4926                        state: {
4927                            value: checkField(user.shipping.state),
4928                            label: "State",
4929                            required: false,
4930                            type: "select",
4931                            hidden: true
4932                        },
4933                        province: {
4934                            value: checkField(user.shipping.state),
4935                            label: "State",
4936                            required: false,
4937                            type: "text",
4938                            hidden: true
4939                        },
4940                        city: {
4941                            value: checkField(user.shipping.city),
4942                            label: "City",
4943                            required: true,
4944                            type: "text"
4945                        },
4946                        address: {
4947                            value: checkField(user.shipping.address),
4948                            label: "Address",
4949                            required: true,
4950                            type: "text"
4951                        },
4952                        zipCode: {
4953                            value: checkField(user.shipping.zipCode),
4954                            label: "Zip Code",
4955                            required: true,
4956                            type: "text"
4957                        }
4958                    };
4959                }
4960
4961                return shippingFields;
4962            }
4963
4964            function profileFormAction() {
4965                var profileSection = "#profile-account-section";
4966
4967                function uploadIdPhotoAction() {
4968                    $('#uploadPhotoIdAction').off('click').on('click', function (event) {
4969                        if (!$("#uploadIdPhotoInput").val()){
4970                            noticeSwall("error", window.bs_lang.select_file_to_upload);
4971                            return;
4972                        }
4973                        let $this = $(this);
4974                        $this.prop("disabled", true);
4975                        var formData = new FormData();
4976                        formData.append("file", $("#uploadIdPhotoInput")[0].files[0])
4977
4978                        $.ajax({
4979                            url: BIDSPIRIT_API_BASE + "users/idphoto/setUserIdPhoto.api?sessionId="+bidspiritSessionId,
4980                            headers: {
4981                                'BIDSPIRIT-AUTH-TOKEN': bidspiritApi.getAuthToken('users/idphoto/setUserIdPhoto'),
4982                            },
4983                            type: 'POST',
4984                            data: formData,
4985                            cache: false,
4986                            contentType: false,
4987                            processData: false,
4988                        })
4989                        .done(function(data) {
4990                            if (!checkError(data)) {
4991                                $("#uploadIdPhotoButton").prop({disabled:false});
4992                                bidspiritUser.hasIdPhoto = true;
4993                                noticeSwall("info", window.bs_lang.photo_id_uploaded_successfully);
4994                                updateIdPhotoUploadDisplay();
4995                            }
4996                        })
4997                        .fail(function() {
4998                            console.error("error");
4999                        })
5000                        .always(function() {
5001                            $this.prop("disabled", false);
5002                        });
5003                    })
5004                }
5005
5006                function displayIdPhoto(button){
5007                    MicroModal.init(microModalInitConfig());
5008                    $.ajax({
5009                        url: BIDSPIRIT_API_BASE + "users/idphoto/getUserIdPhoto.api?sessionId=" + bidspiritSessionId,
5010                        headers: {
5011                            'BIDSPIRIT-AUTH-TOKEN': bidspiritApi.getAuthToken('users/idphoto/getUserIdPhoto'),
5012                        },
5013                        xhrFields: {
5014                            responseType: 'blob'
5015                        }
5016                    })
5017                    .done(function(data) {
5018                        var url = URL.createObjectURL(data);
5019                        $('#idPhotoImage').attr('src', url);
5020                        MicroModal.show("modal-photoId", microModalInitConfig());
5021                    })
5022                    .fail(function() {
5023                        console.error("error displayIdPhoto");
5024                    })
5025                    .always(function() {
5026                        $(button).prop("disabled", false);
5027                    });
5028                }
5029
5030                function updateIdPhotoUploadDisplay(){
5031                    if (bidspiritUser && (!bidspiritUser.hasIdPhoto)) {
5032                        $("#uploadIdPhotoSection").show();
5033                        $("#deleteIdPhotoSection").hide();
5034
5035                        if (auctionSettingsData.idPhotoUploadRequired) {
5036                            $('#uploadIdPhotoInput').prop("required", true);
5037                        }
5038                    } else {
5039                        $("#uploadIdPhotoSection").hide();
5040                        $("#deleteIdPhotoSection").show();
5041                    }
5042                }
5043
5044                function deleteIdPhoto(button){
5045                    Swal.fire({
5046                        title: window.bs_lang.you_want_to_remove_your_id_photo,
5047                        showDenyButton: true,
5048                        showCancelButton: true,
5049                        confirmButtonText: window.bs_lang.yes,
5050                        denyButtonText: window.bs_lang.cancel
5051                    }).then((result) => {
5052                        if (result.isConfirmed) {
5053                            bidspiritPostQuery("users/idphoto/removeUserIdPhoto", {
5054                                sessionId: bidspiritSessionId
5055                            }, (data) => {
5056                                if (!checkError(data)) {
5057                                    bidspiritUser.hasIdPhoto = false;
5058                                    noticeSwall("info", window.bs_lang.id_photo_deleted);
5059                                }
5060
5061                                updateIdPhotoUploadDisplay();
5062                            }, () => {}, () => {
5063                                $(button).prop("disabled", false);
5064                            });
5065                        } else if (result.isDenied) {
5066
5067                        }
5068                    });
5069                }
5070
5071                function codeFieldList(bidspiritUser) {
5072                    bidspiritQuery("settings/getCountriesList", {
5073                        sessionId: bidspiritSessionId,
5074                        language: LANG
5075                    }, function (data) {
5076                        var countrySelect = $("#profilecountryCode"),
5077                            countryShippingSelect = $("#shippingcountryCode"),
5078                            stateSelect = $("#profilestate"),
5079                            stateShippingSelect = $("#shippingFieldstate"),
5080                            provinceShippingSelect = $("#shippingFieldprovince"),
5081                            codeSelect = $(".phoneCodeSelect"),
5082                            codeFirstSelect = $("#detailsphoneCountryCode"),
5083                            codeSecondSelect = $("#detailssecondPhoneCountryCode"),
5084                            items = [],
5085                            codeItems = [];
5086
5087                        if (data.response !== undefined) {
5088                            items = $.map(data.response, function (obj) {
5089                                return {
5090                                    id: obj.code,
5091                                    phoneCode: obj.phoneCode,
5092                                    text: obj.name
5093                                };
5094                            });
5095                            codeItems = $.map(data.response, function (obj) {
5096                                if (obj.phoneCode !== undefined) {
5097                                    return {
5098                                        id: obj.phoneCode,
5099                                        text: obj.phoneCode + " (" + obj.name + ")"
5100                                    };
5101                                }
5102                            });
5103                        }
5104
5105                        countrySelect.select2({
5106                            theme: "default bp-custom-select",
5107                            width: "resolve",
5108                            data: items
5109                        });
5110                        countryShippingSelect.select2({
5111                            theme: "default bp-custom-select",
5112                            width: "resolve",
5113                            data: items
5114                        });
5115
5116                        if (bidspiritUser.address !== undefined && bidspiritUser.address.countryCode !== undefined) {
5117                            countrySelect.val(bidspiritUser.address.countryCode).trigger("change.select2");
5118
5119                            if (bidspiritUser.address.countryCode !== "US") {
5120                                stateSelect.val("").trigger("change.select2");
5121                            }
5122                        }
5123                        if (bidspiritUser.shipping !== undefined && bidspiritUser.shipping.countryCode !== undefined) {
5124                            countryShippingSelect.val(bidspiritUser.shipping.countryCode).trigger("change.select2");
5125
5126                            if (bidspiritUser.shipping.countryCode !== "US") {
5127                                countryShippingSelect.val("").trigger("change.select2");
5128                            }
5129                        }
5130
5131                        countrySelect.on("select2:select", function (event) {
5132                            var data = event.params.data;
5133                            fieldState(data.id, "");
5134                            fieldTaxNumber();
5135                        });
5136                        countryShippingSelect.on("select2:select", function (event) {
5137                            var data = event.params.data;
5138                            fieldShippingFields(data.id, "");
5139                        });
5140                        codeSelect.select2({
5141                            theme: "default bp-custom-select",
5142                            width: "resolve",
5143                            data: codeItems,
5144                            placeholder: window.bs_lang.country_code
5145                        });
5146
5147                        if (bidspiritUser.phoneCountryCode !== undefined) {
5148                            codeFirstSelect.val(bidspiritUser.phoneCountryCode).trigger("change.select2");
5149                        }
5150
5151                        if (bidspiritUser.secondPhoneCountryCode !== undefined) {
5152                            codeSecondSelect.val(bidspiritUser.secondPhoneCountryCode).trigger("change.select2");
5153                        }
5154
5155                        stateList(bidspiritUser);
5156
5157                        if (countrySelect.val() === "US") {
5158                            stateSelect.parents(".bp-form-group").removeClass(window.bs_data.hidden_class);
5159                        }
5160                        if (countryShippingSelect.val() === "US") {
5161                            stateShippingSelect.parents(".bp-form-group").removeClass(window.bs_data.hidden_class);
5162                        }
5163                        if (countryShippingSelect.val() !== "US" && countryShippingSelect.val() !== "IL") {
5164                            provinceShippingSelect.removeClass(window.bs_data.hidden_class);
5165                        }
5166                    });
5167                }
5168
5169                function fieldState(stateCode, value) {
5170                    var stateSelect = $("#profilestate"),
5171                        provinceField = $("#profileprovince"),
5172                        stateCodeUS = "US",
5173                        stateCodeIL = "IL";
5174
5175                    if (stateCode === stateCodeUS) {
5176                        provinceField.parents(".bp-form-group").addClass(window.bs_data.hidden_class);
5177                        provinceField.attr("name", "province");
5178                        stateSelect.parents(".bp-form-group").removeClass(window.bs_data.hidden_class);
5179
5180                        if (bidspiritUser.address !== undefined && bidspiritUser.address.stateCode !== undefined && value !== "") {
5181                            stateSelect.val(bidspiritUser.address.stateCode).trigger("change.select2");
5182                        }
5183                    } else if (stateCode === stateCodeIL) {
5184                        stateSelect.parents(".bp-form-group").addClass(window.bs_data.hidden_class);
5185                        provinceField.parents(".bp-form-group").addClass(window.bs_data.hidden_class);
5186                        provinceField.attr({
5187                            name: "state",
5188                            value: ""
5189                        });
5190                    } else {
5191                        provinceField.parents(".bp-form-group").removeClass(window.bs_data.hidden_class);
5192                        provinceField.attr({
5193                            name: "state",
5194                            value: value
5195                        });
5196                        stateSelect.parents(".bp-form-group").addClass(window.bs_data.hidden_class);
5197                    }
5198                }
5199
5200                function fieldShippingFields(stateCode, value) {
5201                    var stateSelect = $("#shippingstate"),
5202                        countryField = $("#shippingcountryCode"),
5203                        provinceField = $("#shippingprovince"),
5204                        stateCodeUS = "US",
5205                        stateCodeIL = "IL";
5206
5207                    if (bidspiritUser.shipping !== undefined && bidspiritUser.shipping.countryCode !== undefined && stateCode !== "") {
5208                        countryField.val(stateCode).trigger("change.select2");
5209                    }
5210
5211                    if (stateCode === stateCodeUS) {
5212                        provinceField.parents(".bp-form-group").addClass(window.bs_data.hidden_class);
5213                        provinceField.attr("name", "shipping.province");
5214                        stateSelect.parents(".bp-form-group").removeClass(window.bs_data.hidden_class);
5215
5216                        if (bidspiritUser.shipping !== undefined && bidspiritUser.shipping.state !== undefined && value !== "") {
5217                            stateSelect.val(bidspiritUser.shipping.state).trigger("change.select2");
5218                        }
5219                    } else if (stateCode === stateCodeIL) {
5220                        stateSelect.parents(".bp-form-group").addClass(window.bs_data.hidden_class);
5221                        provinceField.parents(".bp-form-group").addClass(window.bs_data.hidden_class);
5222                        provinceField.attr({
5223                            name: "shipping.state",
5224                            value: ""
5225                        });
5226                    } else {
5227                        provinceField.parents(".bp-form-group").removeClass(window.bs_data.hidden_class);
5228                        provinceField.attr({
5229                            name: "shipping.state",
5230                            value: value
5231                        });
5232                        stateSelect.parents(".bp-form-group").addClass(window.bs_data.hidden_class);
5233
5234                        if (bidspiritUser.shipping !== undefined && bidspiritUser.shipping.countryCode !== undefined && value !== "") {
5235                            countryField.val(bidspiritUser.shipping.countryCode).trigger("change.select2");
5236                        }
5237                    }
5238                }
5239
5240                function fieldTaxNumber() {
5241                    var taxNumberField = $("#profiletaxNumber"),
5242                        bsOptions = window.bs_data;
5243
5244                    if (bsOptions.tax_number_required !== undefined && bsOptions.tax_number_required === "on") {
5245                        taxNumberField.parents(".bp-form-group").removeClass(window.bs_data.hidden_class);
5246                        taxNumberField.attr("required", "true").attr("placeholder", taxNumberField.attr("placeholder") + " *");
5247                    } else {
5248                        taxNumberField.parents(".bp-form-group").addClass(window.bs_data.hidden_class);
5249                        taxNumberField.val("").removeAttr("required");
5250                    }
5251                }
5252
5253                function stateList(bidspiritUser) {
5254                    var stateCodeUS = "US";
5255                    bidspiritQuery("settings/getCountryStates", {
5256                        sessionId: bidspiritSessionId,
5257                        countryCode: stateCodeUS
5258                    }, function (data) {
5259                        var countrySelect = $("#profilecountryCode"),
5260                            stateSelect = $("#profilestate"),
5261                            stateShippingSelect = $("#shippingstate"),
5262                            items = [];
5263
5264                        if (data.response !== undefined) {
5265                            data.response.unshift({
5266                                code: "",
5267                                name: ""
5268                            });
5269                            items = $.map(data.response, function (obj) {
5270                                return {
5271                                    id: obj.code,
5272                                    text: obj.name
5273                                };
5274                            });
5275                        }
5276
5277                        stateSelect.select2({
5278                            theme: "default bp-custom-select",
5279                            width: "resolve",
5280                            data: items,
5281                            placeholder: "State"
5282                        });
5283                        stateShippingSelect.select2({
5284                            theme: "default bp-custom-select",
5285                            width: "resolve",
5286                            data: items,
5287                            placeholder: "State"
5288                        });
5289
5290                        var stateVal = "";
5291
5292                        if (bidspiritUser.address !== undefined && (bidspiritUser.address.state !== undefined || bidspiritUser.address.stateCode !== undefined)) {
5293                            stateVal = bidspiritUser.address.state;
5294
5295                       
5295     if (bidspiritUser.address.countryCode === "US") {
5296                                stateVal = bpIsset(bidspiritUser.address.stateCode) ? bidspiritUser.address.stateCode : bidspiritUser.address.state;
5297                            }
5298
5299                            fieldState(countrySelect.val(), stateVal);
5300                        }
5301
5302                        if (bidspiritUser.shipping !== undefined && (bidspiritUser.shipping.state !== undefined || bidspiritUser.shipping.stateCode !== undefined)) {
5303                            stateVal = bidspiritUser.shipping.state;
5304
5305                            /*if (bidspiritUser.shipping.countryCode === "US") {
5306                                stateVal = bpIsset(bidspiritUser.shipping.stateCode) ? bidspiritUser.shipping.stateCode : bidspiritUser.shipping.state;
5307                            }*/
5308
5309                            fieldShippingFields(bidspiritUser.shipping.countryCode, stateVal);
5310                        }
5311
5312                        fieldTaxNumber();
5313                    });
5314                }
5315
5316                if (!$(profileSection + " > *").length) {
5317                    let profileJsTemplate = "profile-account-template";
5318                    if (!!document.getElementById("profile-account-v2-template")) {
5319                        profileJsTemplate = "profile-account-v2-template";
5320                    }
5321
5322                    loadTemplate(profileSection, profileJsTemplate, {
5323                        user: bidspiritUser,
5324                        fields: buildFields(bidspiritUser),
5325                        shippingFields: buildShippingFields(bidspiritUser),
5326                        stateInfo: getApprovalStateInfo(bidspiritUser)
5327                    }, true, function () {
5328                        if (bidspiritUser.allowInvitations !== undefined) {
5329                            $(subscribeCheckbox).prop("checked", bidspiritUser.allowInvitations);
5330                        }
5331                        $("#af-pref-bid-emails").prop("checked", !!bidspiritUser.sendBidEmails);
5332                        $("#af-pref-overbid-emails").prop("checked", !!bidspiritUser.sendOverBidEmails);
5333
5334                        $(subscribeCheckbox + ", #af-pref-bid-emails, #af-pref-overbid-emails").on("change", function () {
5335                            saveAlertsPreferences();
5336                        });
5337
5338                        updateIdPhotoUploadDisplay();
5339                        initPhoneVerificationSection();
5340
5341                        if (!!document.getElementById('uploadPhotoIdAction') && !!document.getElementById('uploadIdPhotoInput')) {
5342                            uploadIdPhotoAction();
5343                        }
5344
5345                        if (!!document.getElementById('showIdPhoto') && !!document.getElementById('deleteIdPhoto')) {
5346                            $('#showIdPhoto').off('click').on('click', function (event) {
5347                                event.preventDefault();
5348                                $(event.target).prop("disabled", true);
5349                                displayIdPhoto(event.target);
5350                            });
5351                            $('#deleteIdPhoto').off('click').on('click', function (event) {
5352                                event.preventDefault();
5353                                $(event.target).prop("disabled", true);
5354                                deleteIdPhoto(event.target);
5355                            });
5356                        }
5357                    });
5358
5359                    codeFieldList(bidspiritUser);
5360
5361                }
5362
5363                let profileEmailEditSelector = "#profileemail + svg.icon";
5364
5365                if ($(profileEmailEditSelector).length !== 0) {
5366                    $(profileEmailEditSelector).off('click').on("click", function (event) {
5367                        document.getElementById("profileemail").disabled = false;
5368                    });
5369                }
5370
5371                passwordShowAction();
5372            }
5373
5374            if (profile.length) {
5375                var wishList = "#bp-wish-list",
5376                    wishListSection = "#profile-wishlist-section",
5377                    bidsList = "#bp-my-bids",
5378                    bidsListSection = "#profile-bids-section",
5379                    winningsList = "#bp-winnings",
5380                    winningsListSection = "#profile-winnings-section",
5381                    billsList = "#bp-bills",
5382                    billsListSection = "#profile-bills-section",
5383                    paymentMethods = "#bp-payment-methods",
5384                    paymentMethodsSection = "#profile-payment-methods-section",
5385                    subscribeCheckbox = "#invitationsEnabled input";
5386
5387                if (bidspiritUser && bidspiritUser.emailConfirmed === true) {
5388                    loadTemplate("#profile-page", "profile-page-template", bidspiritUser, false, function () {
5389                        activeTabs();
5390
5391                        switch (window.location.hash) {
5392                            case wishList:
5393                                profileQuery("account/getFavorites", wishListSection);
5394                                break;
5395
5396                            case bidsList:
5397                                profileQuery("account/getAbsenteeBids", bidsListSection);
5398                                break;
5399
5400                            case winningsList:
5401                                profileQuery("account/getPurchases", winningsListSection);
5402                                break;
5403
5404                            case billsList:
5405                                billsAction(billsListSection);
5406                                break;
5407
5408                            case paymentMethods:
5409                                paymentMethodAction("users/paymentMethods/getStripeSetupSecret", paymentMethodsSection, bidspiritUser);
5410                                break;
5411
5412                            default:
5413                                profileFormAction();
5414                        }
5415                    });
5416                } else if (bidspiritUser && bidspiritUser.emailConfirmed === false) {
5417                    loadTemplate("#profile-page", "profile-page-empty-template", bidspiritUser);
5418                } else {
5419                    loadTemplate("#profile-page", "profile-page-gate-template", bidspiritUser);
5420                    MicroModal.init(microModalInitConfig());
5421                }
5422
5423                var updateDetailsForm = $("#updateDetailsSection"),
5424                    logoutAction = $(".logoutLink"),
5425                    shippingAction = $("#profileShippingCheckbox"),
5426                    shippingWrapper = $("#wrpShippingField"),
5427                    profileLink = $("#bp-profile-link, #bp-account .bp-spoiler-trigger"),
5428                    wishListLink = $("#bp-wish-list-link, #bp-wish-list .bp-spoiler-trigger"),
5429                    bidsListLink = $("#bp-bids-list-link, #bp-my-bids .bp-spoiler-trigger"),
5430                    paymentMethodsLink = $("#bp-payment-methods-link, #bp-payment-methods .bp-spoiler-trigger"),
5431                    winningsListLink = $("#bp-winnings-list-link, #bp-winnings .bp-spoiler-trigger"),
5432                    billsListLink = $("#bp-bills-link, #bp-bills .bp-spoiler-trigger");
5433
5434                if (updateDetailsForm.length) {
5435                    updateDetailsForm.on("submit", function (event) {
5436                        event.preventDefault();
5437                        submitUpdateDetails();
5438                    });
5439
5440                    if (shippingAction.length > 0) {
5441                        let shippingFields = updateDetailsForm.find('.bp-shippingField');
5442                        shippingAction.on('change', function (event) {
5443                            let $this = $(this),
5444                                isChecked = $this.prop('checked');
5445
5446                            if (isChecked) {
5447                                shippingWrapper.addClass('hidden');
5448                                shippingFields.each(function (index, field) {
5449                                    $(field).prop("disabled", true);
5450                                });
5451                            } else {
5452                                shippingWrapper.removeClass('hidden');
5453                                shippingFields.each(function (index, field) {
5454                                    $(field).prop("disabled", false);
5455                                });
5456                            }
5457                        });
5458
5459                        if (bidspiritUser.shipping !== undefined && bidspiritUser.shipping.countryCode !== "") {
5460                            shippingAction.prop("checked", false);
5461                            shippingAction.trigger("change");
5462                        }
5463                    }
5464                }
5465
5466                resendEmailAction();
5467                changeEmailAction();
5468
5469                if (profileLink.length) {
5470                    profileLink.on("click", function (event) {
5471                        event.preventDefault();
5472                        profileFormAction();
5473                    });
5474                }
5475
5476                if (wishListLink.length) {
5477                    wishListLink.on("click", function (event) {
5478                        event.preventDefault();
5479
5480                        if ($(wishListSection).is(":empty")) {
5481                            profileQuery("account/getFavorites", wishListSection);
5482                        }
5483                    });
5484                }
5485
5486                if (bidsListLink.length) {
5487                    bidsListLink.on("click", function (event) {
5488                        event.preventDefault();
5489
5490                        if ($(bidsListSection).is(":empty")) {
5491                            profileQuery("account/getAbsenteeBids", bidsListSection);
5492                        }
5493                    });
5494                }
5495
5496                if (paymentMethodsLink.length) {
5497                    paymentMethodsLink.on("click", function (event) {
5498                        event.preventDefault();
5499
5500                        if ($(paymentMethodsSection).is(":empty")) {
5501                            paymentMethodAction("users/paymentMethods/getStripeSetupSecret", paymentMethodsSection, bidspiritUser);
5502                        }
5503                    });
5504                }
5505
5506                if (winningsListLink.length) {
5507                    winningsListLink.on("click", function (event) {
5508                        event.preventDefault();
5509
5510                        if ($(winningsListSection).is(":empty")) {
5511                            profileQuery("account/getPurchases", winningsListSection);
5512                        }
5513                    });
5514                }
5515
5516                if (billsListLink.length) {
5517                    billsListLink.on("click", function (event) {
5518                        event.preventDefault();
5519
5520                        if ($(billsListSection).is(":empty")) {
5521                            billsAction(billsListSection);
5522                        }
5523                    });
5524                }
5525
5526                function billsAction(container) {
5527                    // Clear the cached unpaid bills so the banner re-checks on next page load
5528                    clearUnpaidBillsCache();
5529                    $(container).html('<div class="bp-loading-bills bp-text-center"><p>'+ (window.bs_lang.loading || 'Loading...') +'</p></div>');
5530                    var unpaidReq = $.Deferred();
5531                    bidspiritQuery("bills/getUnpaidBills", {
5532                        sessionId: bidspiritSessionId,
5533                        language: LANG
5534                    }, function (data) {
5535                        var bills = data && data.response ? data.response : [];
5536                        if (!Array.isArray(bills)) bills = [];
5537                        unpaidReq.resolve(bills);
5538                    }, function () {
5539                        unpaidReq.resolve([]);
5540                    });
5541
5542                    var paidReq = $.Deferred();
5543                    bidspiritQuery("bills/getPaidBills", {
5544                        sessionId: bidspiritSessionId,
5545                        language: LANG
5546                    }, function (data) {
5547                        var bills = data && data.response ? data.response : [];
5548                        if (!Array.isArray(bills)) bills = [];
5549                        paidReq.resolve(bills);
5550                    }, function () {
5551                        paidReq.resolve([]);
5552                    });
5553
5554                    $.when(unpaidReq, paidReq).done(function(unpaidBills, paidBills) {
5555                        unpaidBills = unpaidBills || [];
5556                        paidBills = paidBills || [];
5557                        var allBills = unpaidBills.concat(paidBills);
5558                        
5559                        // Extract codes and dates for mapping
5560                        allBills.forEach(function(b) {
5561                            if (b.description) {
5562                                // Only match "for auction [code]" to avoid false positives like "Auction House"
5563                                var m = b.description.match(/for auction\s+#?([a-zA-Z0-9-]+)/i);
5564                                if (m) {
5565                                    b.auctionCode = m[1];
5566                                }
5567                                // Extract date from end of description (e.g., "Mar 29, 2026")
5568                                var mDate = b.description.match(/,\s*([A-Z][a-z]{2}\s+\d{1,2},\s*\d{4})\s*$/i);
5569                                if (mDate) b.auctionDateStr = mDate[1].trim();
5570                            }
5571                            // Also try billTime epoch for date
5572                            if (!b.auctionDateStr && b.billTime) {
5573                                var d = new Date(b.billTime);
5574                                var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
5575                                b.auctionDateStr = months[d.getMonth()] + ' ' + d.getDate() + ', ' + d.getFullYear();
5576                            }
5577                            b.isPaid = (b.status && b.status.toUpperCase() === "PAID") || b.isPaid === true;
5578                        });
5579
5580                        // Build lookups for ALL bills — pass code if available, otherwise pass date for server-side auction matching
5581                        var lookups = {};
5582                        var hasLookups = false;
5583                        allBills.forEach(function(b, idx) {
5584                            var entry = {};
5585                            if (b.auctionCode) {
5586                                entry.code = b.auctionCode;
5587                            }
5588                            if (b.auctionDateStr) {
5589                                entry.date = b.auctionDateStr;
5590                            }
5591                            if (entry.code || entry.date) {
5592                                lookups["bill_" + idx] = entry;
5593                                hasLookups = true;
5594                            }
5595                        });
5596
5597                        if (hasLookups) {
5598                            $.ajax({
5599                                type: "post",
5600                                url: window.wp_data.ajax_url,
5601                                data: {
5602                                    action: "af_resolve_bill_titles",
5603                                    security: window.wp_nonce,
5604                                    lookups: lookups
5605                                }
5606                            }).done(function(res) {
5607                                var mapping = res.success ? res.data : {};
5608                                allBills.forEach(function(b, idx) {
5609                                    var resolvedName = mapping["bill_" + idx];
5610                                    if (b.description) {
5611                                        if (resolvedName) {
5612                                            var datePart = b.auctionDateStr ? " - " + b.auctionDateStr : "";
5613                                            b.description = "Auction: " + resolvedName + datePart;
5614                                        } else {
5615                                            // Fallback cleaning
5616                                            b.description = b.description.replace(/^Bill for auction\s+#?[a-zA-Z0-9-]+\s+/i, "Auction: ");
5617                                            b.description = b.description.replace(/\sthat took place on\s+/i, " - ");
5618                                            b.description = b.description.replace(/\s+-\s+[a-zA-Z0-9-]+\s+-\s+/i, " - ");
5619                                            b.description = b.description.replace(/\s*-\s*-\s*/, " - ");
5620                                        }
5621                                        b.invoiceNumber = b.description;
5622                                    }
5623                                });
5624                                renderInvoices();
5625                            }).fail(function() {
5626                                renderInvoices();
5627                            });
5628                        } else {
5629                            renderInvoices();
5630                        }
5631
5632                        function renderInvoices() {
5633                            loadTemplate(container, "account-bills-template", {
5634                                items: allBills,
5635                                currency: currencySymbol,
5636                                isPaidTab: false,
5637                                formattedPrice: formattedPrice,
5638                                bidspiritServer: BIDSPIRIT_SERVER,
5639                                ajaxUrl: window.wp_data.ajax_url,
5640                                nonce: window.wp_nonce
5641                            }, false);
5642                        }
5643                    });
5644                }
5645
5646                if (bidspiritUser !== undefined && bidspiritUser.number !== undefined && window.bs_data.show_bidder_number !== undefined && window.bs_data.show_bidder_number === 'on') {
5647                    let h1Profile = document.querySelector('.bp_profile_page .bp-header h1');
5648                    if (!!h1Profile) {
5649                        h1Profile.innerText = window.bs_lang.bidder_number.replace(/\%s/, bidspiritUser.number);
5650                    }
5651                }
5652
5653                doLogout(logoutAction);
5654                optOut();
5655            }
5656        })();
5657
5658        (function () {
5659            var dateTimeField = $("#dateTimeField, .bp-auction-start-date");
5660
5661            if (dateTimeField.length) {
5662                dateTimeField.each(function (index, elem) {
5663                    printTime($(elem), $(elem).attr("data-time"));
5664                });
5665            }
5666        })();
5667
5668        if (bidspiritUser !== null) {
5669            noticeUser(bidspiritUser);
5670        }
5671
5672        (function () {
5673            let profileCustomLink = $('[href="#bp-profile"]');
5674            if (profileCustomLink.length) {
5675                let profileLink = window.bs_data.link_profile,
5676                    bidspiritUser = bidspiritApi.getBidspiritUser();
5677
5678                profileCustomLink.each(function (index, elem) {
5679                    $(elem).off('click').on('click', function (event) {
5680                        event.preventDefault();
5681                        if (bidspiritUser) {
5682                            window.location.href = profileLink;
5683                        } else {
5684                            MicroModal.show('modal-login');
5685                        }
5686                    });
5687                });
5688            }
5689        })();
5690    }
5691
5692    function userDestroy(bidspiritUser) {
5693        bidspiritUser = null;
5694
5695        if ($("#modal-profile").length) {
5696            MicroModal.close("modal-profile");
5697            MicroModal.init(microModalInitConfig());
5698        }
5699
5700        try {
5701            localStorage.removeItem("bidspiritSessionId");
5702            localStorage.removeItem("bidspiritAuthToken");
5703        } catch (e) {
5704            console.error("Local storage disabled");
5705        }
5706
5707        window.location.reload();
5708    }
5709
5710    function doLogout(logoutAction) {
5711        checkPoint("bp-login", true);
5712        logoutAction.on("click", function (event) {
5713            event.preventDefault();
5714            bidspiritQuery("users/logout", {
5715                sessionId: bidspiritSessionId
5716            }, function (data) {
5717                if (!checkError(data)) {
5718                    userDestroy(bidspiritUser);
5719                }
5720            });
5721        });
5722    }
5723
5724    function optOut() {
5725        let optOutUserTrigger = $('#optOutUser');
5726        if (optOutUserTrigger.length) {
5727            optOutUserTrigger.off('click').on('click', function (event) {
5728                event.preventDefault();
5729
5730                Swal.fire({
5731                    title: window.bs_lang.want_to_delete_user,
5732                    showCancelButton: true,
5733                    confirmButtonColor: "#DD3333",
5734                    cancelButtonColor: "#3085D6",
5735                    confirmButtonText: window.bs_lang.yes_delete_user,
5736                }).then((result) => {
5737                    if (result.isConfirmed) {
5738                        bidspiritQuery("users/optOut", {
5739                            sessionId: bidspiritSessionId
5740                        }, function (data) {
5741                            if (!checkError(data)) {
5742                                userDestroy(bidspiritUser);
5743                            }
5744                        });
5745                    }
5746                });
5747            });
5748        }
5749    }
5750
5751    function printTime(elem, dateTime) {
5752        function getLocalTime(time) {
5753            var str = time;
5754            var re = /\(.+\)/gm;
5755            var found = str.match(re);
5756
5757            if (found !== null) {
5758                return found[0];
5759            } else {
5760                return "";
5761            }
5762        }
5763
5764        function addZero(i) {
5765            if (i < 10) {
5766                i = "0" + i;
5767            }
5768
5769            return i;
5770        }
5771
5772        if (bpIsset(window.timeZoneName) && bpIsset(window.timeZoneName) !== "") {
5773            var getAuctionDate = new Date(dateTime),
5774                polylangTimeUse = window.polylang_time,
5775                getAuctionDateDiff = timeShift(dateTime);
5776        } else {
5777            var getAuctionDate = new Date(dateTime),
5778                getAuctionDateDiff = getAuctionDate;
5779        }
5780
5781        if (!(bpIsset(window.timeZoneName) && bpIsset(window.timeZoneName) !== "") && window.browser_time === "off") {
5782            getAuctionDateDiff = new Date(getAuctionDate.getTime());
5783        }
5784
5785        if (window.format_display_time === "2" || polylangTimeUse === "on") {
5786            var getAuctionDateDay = addZero(getAuctionDateDiff.getDate()),
5787                getAuctionMonth = addZero(getAuctionDateDiff.getMonth() + 1),
5788                getAuctionFullYear = getAuctionDateDiff.getFullYear(),
5789                getAuctionHours = addZero(getAuctionDateDiff.getHours()),
5790                getAuctionMinutes = addZero(getAuctionDateDiff.getMinutes()),
5791                nameDaysArray = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"][getAuctionDate.getDay()],
5792                nameMonthArray = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "
5792November", "December"][getAuctionDate.getMonth()];
5793        }
5794
5795        var customDateForm = elem.attr("data-custom-format"),
5796            customDateFormTime = elem.attr("data-custom-format-time"),
5797            unknownExactDate = Boolean(parseInt(elem.attr("data-unknown-exact-date"))),
5798            unknownDate = elem.attr("data-unknown-date"),
5799            localTime = getLocalTime(getAuctionDateDiff.toString()),
5800            polyLanguage = getCookie("pll_language");
5801
5802        if (window.browser_time === "off") {
5803            localTime = window.timeZoneLabel !== "" ? "(" + window.timeZoneLabel + ")" : "";
5804        }
5805
5806        var userLang = polyLanguage !== "" ? polyLanguage : navigator.language || navigator.userLanguage;
5807        var options = {
5808            timeZone: getTimeZoneFromUser(),
5809            formatMatcher: "basic",
5810            weekday: "long",
5811            year: "numeric",
5812            month: "long",
5813            day: "numeric",
5814            hour: "numeric",
5815            minute: "numeric",
5816            timeZoneName: "short"
5817        };
5818
5819        if (elem.length) {
5820            if (unknownExactDate) {
5821                elem.html(unknownDate);
5822                return;
5823            }
5824
5825            if (window.browser_time === "on" || customDateForm === "") {
5826                if (window.format_display_time === "2") {
5827                    elem.html(nameMonthArray + " " + getAuctionDateDay + ", " + getAuctionFullYear + ", " + getAuctionHours + ":" + getAuctionMinutes + " " + localTime);
5828                } else if (polylangTimeUse === "on") {
5829                    elem.html(getAuctionDateDiff.toLocaleTimeString(userLang, options));
5830                } else {
5831                    elem.html(getAuctionDateDiff.toLocaleTimeString(getLocaleFromUser(), options));
5832                }
5833            } else {
5834                elem.html(customDateFormTime);
5835            }
5836        }
5837    }
5838
5839    // === Phone verification (BidSpirit users/phone/* APIs) ===
5840    // A verified phone is required to place absentee bids / join live auctions.
5841    var lastVerifyPhoneMethod = "sms";
5842
5843    function populateVerifyPhoneCountries(defaultPhoneCode) {
5844        function fill(list) {
5845            var $select = $("#verifyPhoneCountry");
5846            $select.empty();
5847            $.each(list, function (i, country) {
5848                if (country.phoneCode) {
5849                    $select.append($("<option>").val(country.phoneCode).text(country.phoneCode + " (" + country.name + ")"));
5850                }
5851            });
5852            if (defaultPhoneCode) {
5853                $select.val(defaultPhoneCode);
5854            }
5855        }
5856
5857        var cached = bidspiritApi.getCountriesList();
5858        if (cached) {
5859            fill(cached);
5860        } else {
5861            bidspiritQuery("settings/getCountriesList", {
5862                sessionId: bidspiritSessionId,
5863                language: LANG
5864            }, function (data) {
5865                if (data.response) {
5866                    bidspiritApi.setCountriesList(data.response);
5867                    fill(data.response);
5868                }
5869            });
5870        }
5871    }
5872
5873    function verifyPhoneStatus(message, isError) {
5874        var $status = $("#verifyPhoneStatus");
5875        $status.text(message).removeClass("hidden");
5876        if (isError) {
5877            $status.addClass("bp-text-red");
5878        } else {
5879            $status.removeClass("bp-text-red");
5880        }
5881    }
5882
5883    function phoneVerificationErrorMessage(errorCode) {
5884        switch (errorCode) {
5885            case "SMS_TO_LANDLINE":
5886                return window.bs_lang.verify_phone_sms_to_landline || "This looks like a landline. Please use \"Send code via call\" instead.";
5887            case "INVALID_PHONE_NUMBER":
5888                return window.bs_lang.verify_phone_invalid || "The phone number is invalid. Please check it and try again.";
5889            case "PHONE_EXISTS":
5890            case "SHOULD_SWITCH_USER":
5891                return window.bs_lang.verify_phone_exists || "This phone number is already verified by another account. Please log in with that account, or contact the auction house for support.";
5892            case "FAILED_TO_SENT_CODE":
5893            default:
5894                return window.bs_lang.verify_phone_failed_send || "Failed to send the verification code, please try again.";
5895        }
5896    }
5897
5898    function sendPhoneVerificationCode(method) {
5899        var countryCode = $("#verifyPhoneCountry").val(),
5900            phone = $.trim($("#verifyPhoneNumber").val());
5901
5902        if (!phone) {
5903            verifyPhoneStatus(window.bs_lang.verify_phone_enter_number || "Please enter a phone number.", true);
5904            return;
5905        }
5906
5907        lastVerifyPhoneMethod = method;
5908        $("#verifyPhoneSms, #verifyPhoneCall, #verifyPhoneResend").prop("disabled", true);
5909
5910        bidspiritPostQuery("users/phone/sendPhoneVerificationCode", {
5911            sessionId: bidspiritSessionId,
5912            countryCode: countryCode,
5913            phone: phone,
5914            method: method,
5915            language: LANG
5916        }, function (data) {
5917            var res = data.response || {};
5918            if (res.success) {
5919                $("#verifyPhoneSendStep").addClass("hidden");
5920                $("#verifyPhoneCodeStep").removeClass("hidden");
5921                verifyPhoneStatus((window.bs_lang.verify_phone_code_sent || "A verification code was sent to") + " +" + countryCode + phone, false);
5922                $("#verifyPhoneCode").val("").trigger("focus");
5923            } else {
5924                console.error("[verify phone] sendPhoneVerificationCode failed", {
5925                    errorCode: res.errorCode,
5926                    errorMessage: res.errorMessage,
5927                    sessionIdLen: (bidspiritSessionId || "").length,
5928                    hasAuthToken: !!bidspiritApi.getAuthToken()
5929                });
5930                var msg = phoneVerificationErrorMessage(res.errorCode);
5931                var mappedCodes = ["SMS_TO_LANDLINE", "INVALID_PHONE_NUMBER", "PHONE_EXISTS", "SHOULD_SWITCH_USER", "FAILED_TO_SENT_CODE"];
5932                if (res.errorCode && mappedCodes.indexOf(res.errorCode) === -1) {
5933                    // surface any not-yet-mapped code so it can be handled explicitly
5934                    msg += " [" + res.errorCode + "]";
5935                }
5936                verifyPhoneStatus(msg, true);
5937            }
5938        }, function () {
5939            console.error("[verify phone] sendPhoneVerificationCode AJAX request failed (network/CORS)");
5940            verifyPhoneStatus((window.bs_lang.verify_phone_failed_send || "Failed to send the verification code, please try again.") + " [network]", true);
5941        }, function () {
5942            $("#verifyPhoneSms, #verifyPhoneCall, #verifyPhoneResend").prop("disabled", false);
5943        });
5944    }
5945
5946    function checkPhoneVerificationCode() {
5947        var countryCode = $("#verifyPhoneCountry").val(),
5948            phone = $.trim($("#verifyPhoneNumber").val()),
5949            code = $.trim($("#verifyPhoneCode").val());
5950
5951        if (!code) {
5952            verifyPhoneStatus(window.bs_lang.verify_phone_enter_code || "Please enter the code you received.", true);
5953            return;
5954        }
5955
5956        $("#verifyPhoneCheck").prop("disabled", true);
5957
5958        bidspiritPostQuery("users/phone/checkPhoneVerificationCode", {
5959            sessionId: bidspiritSessionId,
5960            countryCode: countryCode,
5961            phone: phone,
5962            verificationCode: code
5963        }, function (data) {
5964            if (!checkError(data)) {
5965                if (data.response && data.response.verified) {
5966                    var user = bidspiritApi.getBidspiritUser();
5967                    if (user) {
5968                        user.phoneVerified = true;
5969                        user.phoneCountryCode = countryCode;
5970                        user.phone = phone;
5971                        bidspiritApi.setBidspiritUser(user);
5972                    }
5973                    try {
5974                        MicroModal.close("modal-verify-phone");
5975                    } catch (e) {
5976                    }
5977                    initPhoneVerificationSection();
5978                    noticeSwall("success", window.bs_lang.verify_phone_verified || "Your phone has been verified.");
5979                } else {
5980                    verifyPhoneStatus(window.bs_lang.verify_phone_wrong_code || "The code is incorrect. Please try again.", true);
5981                }
5982            }
5983        }, function () {
5984            verifyPhoneStatus(window.bs_lang.verify_phone_failed_send || "Something went wrong, please try again.", true);
5985        }, function () {
5986            $("#verifyPhoneCheck").prop("disabled", false);
5987        });
5988    }
5989
5990    function bindVerifyPhoneModal() {
5991        $("#verifyPhoneSms").off("click.bpVerify").on("click.bpVerify", function () {
5992            sendPhoneVerificationCode("sms");
5993        });
5994        $("#verifyPhoneCall").off("click.bpVerify").on("click.bpVerify", function () {
5995            sendPhoneVerificationCode("call");
5996        });
5997        $("#verifyPhoneResend").off("click.bpVerify").on("click.bpVerify", function () {
5998            sendPhoneVerificationCode(lastVerifyPhoneMethod);
5999        });
6000        $("#verifyPhoneCheck").off("click.bpVerify").on("click.bpVerify", function () {
6001            checkPhoneVerificationCode();
6002        });
6003    }
6004
6005    function showVerifyPhoneModal() {
6006        if (!$("#modal-verify-phone").length) {
6007            return;
6008        }
6009        var user = bidspiritApi.getBidspiritUser() || {};
6010        // reset to the "send code" step
6011        $("#verifyPhoneCodeStep").addClass("hidden");
6012        $("#verifyPhoneSendStep").removeClass("hidden");
6013        $("#verifyPhoneCode").val("");
6014        $("#verifyPhoneStatus").addClass("hidden").text("");
6015        $("#verifyPhoneNumber").val(user.phone || "");
6016        populateVerifyPhoneCountries(user.phoneCountryCode);
6017        bindVerifyPhoneModal();
6018
6019        try {
6020            MicroModal.show("modal-verify-phone", microModalInitConfig());
6021        } catch (e) {
6022            console.error("verify phone modal", e);
6023        }
6024    }
6025
6026    function initPhoneVerificationSection() {
6027        var $section = $("#phoneVerificationSection");
6028        if (!$section.length) {
6029            return;
6030        }
6031        var user = bidspiritApi.getBidspiritUser() || {};
6032        $section.empty();
6033        if (window.afRequirePhoneVerification === false) { return; }
6034
6035        if (user.phoneVerified) {
6036            $section.append($("<span>
6036").addClass("bp-verify-phone__ok").html(
6037                '<svg class="bp-icon bp-icon-green"><use xlink:href="#check"></use></svg> ' +
6038                (window.bs_lang.verify_phone_verified_label || "Phone verified")
6039            ));
6040        } else {
6041            $("<button>")
6042                .attr("type", "button")
6043                .addClass("bp-verify-phone__cta")
6044                .text(window.bs_lang.verify_phone_cta || "Verify phone")
6045                .on("click", function (event) {
6046                    event.preventDefault();
6047                    showVerifyPhoneModal();
6048                })
6049                .appendTo($section);
6050        }
6051    }
6052
6053    function submitBid() {
6054        var singleLot = $("#single-lot"),
6055            notApproveStateNotice = window.bs_lang.not_approved_user,
6056            pendingStateNotice = window.bs_lang.pending_user_state;
6057
6058        if (!bidspiritUser) {
6059            try {
6060                MicroModal.show("modal-login", microModalInitConfig());
6061            } catch (e) {
6062                console.error(e);
6063            }
6064        } else if (bidspiritUser.approvalState === "PENDING") {
6065            noticeSwall("error", window.bs_lang.oops, pendingStateNotice);
6066        } else if (bidspiritUser.approvalState === "INCOMPLETE_PROFILE") {
6067            noticeSwall("error", window.bs_lang.oops, notApproveStateNotice);
6068        } else if (window.afRequirePhoneVerification !== false && !bidspiritUser.phoneVerified) {
6069            showVerifyPhoneModal();
6070        } else {
6071            var data = getDataForm("bidFormSection"),
6072                modalBidForm = "#modal-bid-content",
6073                lotName = $(modalBidForm).attr("data-name"),
6074                houseInfo = bidspiritApi.getAuctionHouseData(),
6075                auctionInfo = bidspiritApi.getAuctionInfo(),
6076                lotLinkTerm = window.bs_data.page_terms,
6077                additionalNotice = false,
6078                additionalNoticeText = "",
6079                auctionItemInfo = bidspiritApi.getAuctionItemInfo(),
6080                fullPriceVat = auctionItemInfo.item.fullPriceVat,
6081                auctionCommission = auctionInfo.commission;
6082
6083            data.sessionId = bidspiritSessionId;
6084            data.auctionId = currentAuctionNumber;
6085            data.lotIndex = currentItemInfo.lotIndex;
6086            data.bidFormUrl = window.location.href;
6087            data.sendBidEmails = false;
6088            data.sendOverBidEmails = false;
6089
6090            if (parseInt(data.price) >= currentItemInfo.buyoutPrice) {
6091                additionalNotice = true;
6092                additionalNoticeText = window.bs_lang.buyout_notice.replace(/#price#/, formattedPrice(currentItemInfo.buyoutPrice, currencySymbol));
6093            }
6094
6095            MicroModal.show("modal-bid", microModalInitConfig());
6096            loadTemplate(modalBidForm, "modal-bid-template", {
6097                index: data.lotIndex,
6098                name: lotName,
6099                currentCurrency: currencySymbol,
6100                price: data.price,
6101                fullPrice: getCommissionPrice(data.price),
6102                fullPriceInfo: getFullPriceInfo(currentItemInfo, auctionInfo, data.price),
6103                linkTerms: lotLinkTerm,
6104                additionalNotice: additionalNotice,
6105                additionalNoticeText: additionalNoticeText,
6106                auctionHouseData: auctionHouseData,
6107                fullPriceVat: fullPriceVat,
6108                auctionCommission: auctionCommission,
6109                user: bidspiritUser,
6110                auctionItemInfo: auctionItemInfo,
6111                itemInfo: currentItemInfo,
6112                settings: auctionSettingsData,
6113                additionalMessage: autoChargingCreditCardMessage(auctionSettingsData)
6114            }, false, function () {
6115                $(modalBidForm).off("click", "#agreeBid").on("click", "#agreeBid", function (event) {
6116                    event.preventDefault();
6117                    var bsOptions = window.bs_data,
6118                        taxNumberNotRequired = bsOptions.tax_number_required !== undefined && bsOptions.tax_number_required === "off";
6119
6120                    function userGate(bidspiritUser) {
6121                        if (bidspiritUser.taxNumber !== undefined && bidspiritUser.taxNumber !== "") {
6122                            return true;
6123                        }
6124
6125                        return false;
6126                    }
6127
6128                    var subData = getDataForm("subBidFormSection");
6129
6130                    if (subData) {
6131                        data.sendBidEmails = subData.sendBidEmails !== undefined && subData.sendBidEmails === "true";
6132                        data.sendOverBidEmails = subData.sendOverBidEmails !== undefined && subData.sendOverBidEmails === "true";
6133                        data.callUserWhenItemIsLive = subData.callUserWhenItemIsLive !== undefined && subData.callUserWhenItemIsLive === "true";
6134                        bidspiritUser.sendBidEmails = data.sendBidEmails;
6135                        bidspiritUser.sendOverBidEmails = data.sendOverBidEmails;
6136                    }
6137
6138                    if (taxNumberNotRequired || userGate(bidspiritUser)) {
6139                        var dataAlert = {
6140                            sessionId: data.sessionId,
6141                            auctionId: data.auctionId,
6142                            lotIndex: data.lotIndex,
6143                            isOn: true
6144                        };
6145                        bidspiritQuery("items/placeBid", data, function (data) {
6146                            if (!checkError(data)) {
6147                                console.log("test1", data);
6148                                handleSubmitResponse(data.response);
6149                                bidspiritQuery("items/setItemAlert", dataAlert, function () {});
6150                                data.response.data = {
6151                                    auctionId: dataAlert.auctionId,
6152                                    lotIndex: dataAlert.lotIndex,
6153                                    user: bidspiritUser.email
6154                                };
6155                                hangUpEvent("bp:after-items-place-bid", data.response);
6156
6157                                // Record bid count
6158                                if (typeof AuctionForgeBidCount !== "undefined") {
6159                                    var bidPostId = $("#af-bid-count-display").attr("data-post-id") || "";
6160                                    if (bidPostId) {
6161                                        $.post(AuctionForgeBidCount.ajaxUrl, {
6162                                            action: "auctionforge_record_bid",
6163                                            nonce: AuctionForgeBidCount.nonce,
6164                                            post_id: bidPostId
6165                                        }, function(resp) {
6166                                            if (resp.success && resp.data && resp.data.bid_count !== undefined) {
6167                                                var $el = $("#af-bid-count-display");
6168                                                if ($el.length) {
6169                                                    var svg = $el.find("svg").prop("outerHTML") || "";
6170                                                    var cnt = resp.data.bid_count;
6171                                                    $el.html(svg + cnt + " " + (cnt === 1 ? "bid" : "bids"));
6172                                                }
6173                                            }
6174                                        });
6175                                    }
6176                                }
6177                            }
6178                        });
6179                        MicroModal.close("modal-bid");
6180                    } else {
6181                        MicroModal.close("modal-bid");
6182                        noticeSwall("error", window.bs_lang.tax_number_required, window.bs_lang.tax_number_required_label, {}, function () {
6183                            var linkProfile = window.bs_data.link_profile;
6184
6185                            if (linkProfile !== undefined && linkProfile !== "link") {
6186                                window.location = linkProfile;
6187                            }
6188                        });
6189                    }
6190                });
6191                $(modalBidForm).off("click", "#dontAgreeBid").on("click", "#dontAgreeBid", function (event) {
6192                    event.preventDefault();
6193                    MicroModal.close("modal-bid");
6194                });
6195            });
6196        }
6197    }
6198
6199    function showTermsCondModal() {
6200        bidspiritQuery("docs/getTerms", {
6201            language: LANG
6202        }, function (data) {
6203            let modalBody = document.getElementById("modal-requestApprovalTerms-content");
6204
6205            if (!!modalBody) {
6206                modalBody.innerHTML = data;
6207                $("#requestApprovalTermsAction").on("click", function (event) {
6208                    event.preventDefault();
6209                    let $this = $(this),
6210                        auctionInfo = bidspiritApi.getAuctionInfo(),
6211                        data = {};
6212                    data.sessionId = bidspiritSessionId;
6213                    data.auctionId = auctionInfo.id;
6214                    $this.prop("disabled", true);
6215                    bidspiritPostQuery("approvals/requestToParticipateInAuction", data, function (data) {
6216                        if (!checkError(data)) {
6217                            MicroModal.close("modal-request-approval-terms");
6218                            approvalInfo(auctionInfo.id);
6219                        }
6220                    }, function () {
6221                    }, function () {
6222                        $this.prop("disabled", false);
6223                    });
6224                });
6225                MicroModal.show("modal-request-approval-terms", microModalInitConfig());
6226            }
6227        });
6228    }
6229
6230    function bidProcessAction(modalBidForm, params, data, dataAlert) {
6231        MicroModal.show("modal-bid", microModalInitConfig());
6232        loadTemplate(modalBidForm, "modal-bid-template", params, false, function () {
6233            $(modalBidForm).off("click", "#agreeBid").on("click", "#agreeBid", function (event) {
6234                event.preventDefault();
6235                var subData = getDataForm("subBidFormSection");
6236
6237                if (subData) {
6238                    data.sendBidEmails = subData.sendBidEmails !== undefined && subData.sendBidEmails === "true";
6239                    data.sendOverBidEmails = subData.sendOverBidEmails !== undefined && subData.sendOverBidEmails === "true";
6240                    data.callUserWhenItemIsLive = subData.callUserWhenItemIsLive !== undefined && subData.callUserWhenItemIsLive === "true";
6241                    bidspiritUser.sendBidEmails = data.sendBidEmails;
6242                    bidspiritUser.sendOverBidEmails = data.sendOverBidEmails;
6243                }
6244
6245                bidspiritQuery("items/placeBid", data, function (data) {
6246                    if (!checkError(data)) {
6247                        var response = data.response;
6248
6249                        let type = "info";
6250                        if (response.leadingBidCode === "ANOTHER_BID_HIGHER" || response.leadingBidCode === "ANOTHER_BID_EARLIER") {
6251                            type = "error";
6252                        }
6253                        noticeSwall(type, getLeadingBidMessage(response.leadingBidCode));
6254
6255                        bidspiritQuery("items/setItemAlert", dataAlert, function () {
6256                        });
6257                        updateDisplay();
6258                        data.response.data = {
6259                            auctionId: dataAlert.auctionId,
6260                            lotIndex: dataAlert.lotIndex,
6261                            user: bidspiritUser.email
6262                        };
6263                        hangUpEvent("bp:after-items-place-bid", data.response);
6264
6265                                // Record bid count
6266                                if (typeof AuctionForgeBidCount !== "undefined") {
6267                                    var bidPostId = $("#af-bid-count-display").attr("data-post-id") || "";
6268                                    if (bidPostId) {
6269                                        $.post(AuctionForgeBidCount.ajaxUrl, {
6270                                            action: "auctionforge_record_bid",
6271                                            nonce: AuctionForgeBidCount.nonce,
6272                                            post_id: bidPostId
6273                                        }, function(resp) {
6274                                            if (resp.success && resp.data && resp.data.bid_count !== undefined) {
6275                                                var $el = $("#af-bid-count-display");
6276                                                if ($el.length) {
6277                                                    var svg = $el.find("svg").prop("outerHTML") || "";
6278                                                    var cnt = resp.data.bid_count;
6279                                                    $el.html(svg + cnt + " " + (cnt === 1 ? "bid" : "bids"));
6280                                                }
6281                                            }
6282                                        });
6283                                    }
6284                                }
6285                    }
6286
6287                    MicroModal.close("modal-bid");
6288                });
6289            });
6290            $(modalBidForm).off("click", "#dontAgreeBid").on("click", "#dontAgreeBid", function (event) {
6291                event.preventDefault();
6292                MicroModal.close("modal-bid");
6293            });
6294        });
6295    }
6296
6297    function submitBidCatalog(lot, minBidPrice, itemInfoData) {
6298        var singleLot = lot,
6299            notApproveStateNotice = window.bs_lang.not_approved_user,
6300            pendingStateNotice = window.bs_lang.pending_user_state;
6301        currentItemInfo = itemInfoData.response.itemsInfo[singleLot.attr("data-lot-index")];
6302        currentItemInfo.buyoutPrice = minBidPrice;
6303        MicroModal.init(microModalInitConfig());
6304
6305        if (!bidspiritUser) {
6306            try {
6307                MicroModal.show("modal-login", microModalInitConfig());
6308            } catch (e) {
6309                console.error(e);
6310            }
6311        } else if (bidspiritUser.approvalState === "PENDING") {
6312            noticeSwall("error", window.bs_lang.oops, pendingStateNotice);
6313        } else if (bidspiritUser.approvalState === "INCOMPLETE_PROFILE") {
6314            noticeSwall("error", window.bs_lang.oops, notApproveStateNotice);
6315        } else if (window.afRequirePhoneVerification !== false && !bidspiritUser.phoneVerified) {
6316            showVerifyPhoneModal();
6317        } else {
6318            var data = getDataForm("bidFormSection"),
6319                modalBidForm = "#modal-bid-content",
6320                lotName = lot.find(".bp-lot__title a").text().replace(/Lot\s\d+\:/, ""),
6321                lotLinkTerm = window.bs_data.page_terms,
6322                additionalNotice = false,
6323                additionalNoticeText = "",
6324                auctionInfo = bidspiritApi.getAuctionInfo(),
6325                fullPriceVat = Boolean(parseInt(lot.attr("data-full-price-vat"))),
6326                auctionCommission = auctionInfo.commission;
6327            data.sessionId = bidspiritSessionId;
6328            data.auctionId = currentAuctionNumber;
6329            data.lotIndex = currentItemInfo.lotIndex;
6330            data.bidFormUrl = lot.find("a").attr("href");
6331            data.sendBidEmails = false;
6332            data.sendOverBidEmails = false;
6333
6334            if (parseInt(data.price) >= currentItemInfo.buyoutPrice) {
6335                additionalNotice = true;
6336                additionalNoticeText = window.bs_lang.buyout_notice.replace(/#price#/, formattedPrice(currentItemInfo.buyoutPrice, currencySymbol));
6337            }
6338
6339            if (data.price === undefined) {
6340                data.price = minBidPrice;
6341            }
6342
6343            var params = {
6344                index: data.lotIndex,
6345                name: lotName,
6346                currentCurrency: currencySymbol,
6347                price: data.price,
6348                fullPrice: getCommissionPrice(data.price, fullPriceVat, auctionCommission),
6349                fullPriceInfo: getFullPriceInfo(currentItemInfo, auctionInfo, data.price),
6350                linkTerms: lotLinkTerm,
6351                additionalNotice: additionalNotice,
6352                additionalNoticeText: additionalNoticeText,
6353                auctionHouseData: auctionHouseData,
6354                fullPriceVat: fullPriceVat,
6355                auctionCommission: auctionCommission,
6356                user: bidspiritUser,
6357                itemInfo: currentItemInfo,
6358                settings: auctionSettingsData,
6359                additionalMessage: autoChargingCreditCardMessage(auctionSettingsData)
6360            };
6361
6362            function userGate(bidspiritUser) {
6363                if (bidspiritUser.taxNumber !== undefined && bidspiritUser.taxNumber !== "") {
6364                    return true;
6365                }
6366
6367                return false;
6368            }
6369
6370            var bsOptions = window.bs_data,
6371                taxNumberNotRequired = bsOptions.tax_number_required !== undefined && bsOptions.tax_number_required === "off";
6372
6373            if (taxNumberNotRequired || userGate(bidspiritUser)) {
6374                var auctionApprovalState = bidspiritApi.getAuctionApprovalState();
6375                var dataAlert = {
6376                    sessionId: data.sessionId,
6377                    auctionId: data.auctionId,
6378                    lotIndex: data.lotIndex,
6379                    isOn: true
6380                };
6381
6382                if (auctionInfo.approvalRequired !== undefined && auctionInfo.approvalRequired) {
6383                    if (auctionInfo.paymentMethodRequired !== undefined && auctionInfo.paymentMethodRequired === true) {
6384                        if (bidspiritApi.getAuctionApprovalState() === "APPROVED") {
6385                            bidProcessAction(modalBidForm, params, data, dataAlert);
6386                        } else if (bidspiritApi.getAuctionApprovalState() === "NOT_REQUESTED") {
6387                            if (paymentMethods.length > 0) {
6388                                modalRequestApprovalShow();
6389                                MicroModal.init(microModalInitConfig());
6390                            } else {
6391                                addPaymentMethodCallback();
6392                            }
6393                        } else if (bidspiritApi.getAuctionApprovalState() === "APPROVAL_REQUESTED") {
6394                            noticeSwall("info", "", window.bs_lang.approval_info_approval_requested);
6395                        } else {
6396                            if (bidspiritApi.getAuctionApprovalState() === "PENDING") {
6397                                noticeSwall("error", window.bs_lang.oops, window.bs_lang.pending_user_state);
6398                            } else if (bidspiritApi.getAuctionApprovalState() === "INCOMPLETE_PROFILE") {
6399                                noticeSwall("error", window.bs_lang.oops, window.bs_lang.not_approved_user);
6400                            }
6401                        }
6402                    } else if (auctionInfo.paymentMethodRequired !== undefined && auctionInfo.paymentMethodRequired === false) {
6403                        if (bidspiritApi.getAuctionApprovalState() === "APPROVED") {
6404                            bidProcessAction(modalBidForm, params, data, dataAlert);
6405                        } else if (bidspiritApi.getAuctionApprovalState() === "NOT_REQUESTED") {
6406                            showTermsCondModal();
6407                        } else if (bidspiritApi.getAuctionApprovalState() === "APPROVAL_REQUESTED") {
6408                            noticeSwall("info", "", window.bs_lang.approval_info_approval_requested);
6409                        } else {
6410                            if (bidspiritApi.getAuctionApprovalState() === "PENDING") {
6411                                noticeSwall("error", window.bs_lang.oops, window.bs_lang.pending_user_state);
6412                            } else if (bidspiritApi.getAuctionApprovalState() === "INCOMPLETE_PROFILE") {
6413                                noticeSwall("error", window.bs_lang.oops, window.bs_lang.not_approved_user);
6414                            }
6415                        }
6416                    } else {
6417                        bidProcessAction(modalBidForm, params, data, dataAlert);
6418                    }
6419
6420                    MicroModal.init(microModalInitConfig());
6421                } else {
6422                    bidProcessAction(modalBidForm, params, data, dataAlert);
6423                }
6424            } else {
6425                MicroModal.close("modal-bid");
6426                noticeSwall("error", window.bs_lang.tax_number_required, window.bs_lang.tax_number_required_label, {}, function () {
6427                    var linkProfile = window.bs_data.link_profile;
6428
6429                    if (linkProfile !== undefined && linkProfile !== "link") {
6430                        window.location = linkProfile;
6431                    }
6432                });
6433            }
6434        }
6435    }
6436
6437    function getApprovalStateInfo(user) {
6438        var userState = $("#profile-account-section");
6439
6440        if (!user.emailConfirmed) {
6441            return userState.attr("data-confirm-email");
6442        }
6443
6444        switch (user.approvalState) {
6445            case "INCOMPLETE_PROFILE":
6446                return userState.attr("data-incomplete-profile");
6447
6448            case "PENDING":
6449                return userState.attr("data-pending");
6450        }
6451
6452        return "";
6453    }
6454
6455    function submitUpdateDetails() {
6456        function filterData(data) {
6457            let updatedData = {
6458                data: {},
6459                errors: {}
6460            };
6461
6462            if (data.countryCode !== undefined && data.countryCode === "US") {
6463                data.stateCode = data.state;
6464                data.state = "";
6465                data.province = "";
6466            } else {
6467                data.stateCode = "";
6468            }
6469
6470            for (const [key, value] of Object.entries(data)) {
6471                if (key === "") {
6472                    continue;
6473                }
6474
6475                if (key === "firstName" || key === "lastName") {
6476                    if (value.match(/\@/)) {
6477                        updatedData["errors"][key] = window.bs_lang.profile_field_error.replace(/\%s/, key);
6478                    }
6479                }
6480
6481                updatedData["data"][key] = value;
6482            }
6483
6484            return updatedData;
6485        }
6486
6487        var data = getDataForm("updateDetailsSection"),
6488            formParent = $("#updateDetailsSection"),
6489            shippingAction = $("#profileShippingCheckbox"),
6490            approvalState = bidspiritUser.approvalState,
6491            postConfirmationLink = formParent.attr("action");
6492        data.sessionId = bidspiritSessionId;
6493        data.postConfirmationLink = postConfirmationLink;
6494        let tmpData = filterData(data);
6495        data = tmpData["data"];
6496
6497        if (Object.keys(tmpData["errors"]).length > 0) {
6498            let keys = Object.keys(tmpData["errors"]),
6499                message = window.bs_lang.profile_error;
6500
6501            if (keys[0] !== undefined) {
6502                message = tmpData["errors"][keys[0]];
6503            }
6504
6505            noticeSwall("error", "Error", message);
6506        } else {
6507            if (approvalState === "PENDING") {
6508                var info = bidspiritApi.getAuctionHouseData(),
6509                    title = window.bs_lang.you_are_still_pending_approval.replace(/\%1s/, info.name),
6510                    message = window.bs_lang.you_are_still_pending_approval_body.replace(/\%1s/, info.phone).replace(/\%2s/, info.email);
6511                noticeSwall("info", title, message);
6512            } else {
6513                bidspiritPostQuery("users/updateDetails", data, function (response) {
6514                    if (response.response.success === false) {
6515                        noticeSwall("error", "Error", data.response.errorMessage);
6516                    } else {
6517                        let userData = response.response,
6518                            shippingData = {};
6519                        Promise.all([
6520                            new Promise(function (resolve) {
6521                                if (shippingAction[0] !== undefined && !shippingAction.prop('checked')) {
6522                                    let shippingFields = Object.keys(data)
6523                                        .filter((key) => key.includes("shipping"))
6524                                        .reduce((object, key) => {
6525                                            return Object.assign(object, {
6526                                                [key.replace(/shipping\./, "")]: data[key]
6527                                            });
6528                                        }, {});
6529
6530                                    bidspiritPostQuery("users/updateShippingAddress",
6531                                        Object.assign({sessionId: bidspiritSessionId}, shippingFields),
6532                                        function (response) {
6533                                            if (response.response.success === false) {
6534                                                shippingData = response.response;
6535                                                noticeSwall("error", "Error", response.response.errorMessage);
6536                                            } else {
6537                                                userData.shipping = response.response;
6538                                                resolve();
6539                                            }
6540                                        });
6541                                } else {
6542                                    let user = bidspiritApi.getBidspiritUser();
6543                                    if (user.shipping !== undefined) {
6544                                        bidspiritPostQuery("users/updateShippingAddress",
6545                                            Object.assign({sessionId: bidspiritSessionId}, {
6546                                                countryCode: "",
6547                                                stateCode: "",
6548                                                state: "",
6549                                                city: "",
6550                                                address: "",
6551                                                zipCode: ""
6552                                            }),
6553                                            function () {
6554                                                shippingData = response.response;
6555                                                userData.shipping = undefined;
6556                                                resolve();
6557                                            });
6558                                    } else {
6559                                        resolve();
6560                                    }
6561                                }
6562                            }),
6563                        ]).then(function (response) {
6564                            bidspiritApi.setBidspiritUser(userData);
6565                            updateDisplay();
6566                            noticeSwall("info", window.bs_lang.profile_changes_saved, window.bs_lang.profile_changes_saved_body, {}, function () {
6567                                if (approvalState !== bidspiritUser.approvalState) {
6568                                    window.location = postConfirmationLink;
6569                                }
6570                            });
6571                        });
6572                    }
6573                });
6574
6575            }
6576        }
6577    }
6578
6579    function handleSubmitResponse(data) {
6580        currentItemInfo.selfAbsenteeBid = data.selfAbsenteeBid;
6581        currentItemInfo.leadingBid = data.leadingBid;
6582        displayBidFormData(currentItemInfo);
6583
6584        let type = "info";
6585        if (data.leadingBidCode === "ANOTHER_BID_HIGHER" || data.leadingBidCode === "ANOTHER_BID_EARLIER") {
6586            type = "error";
6587        }
6588        noticeSwall(type, getLeadingBidMessage(data.leadingBidCode));
6589    }
6590
6591    function disableLoader() {
6592        $("#bsLoader").addClass(window.bs_data.hidden_class);
6593    }
6594
6595    function toggleFavorite(lot, elem, auctionNumber, delLot) {
6596        var lotIndex = lot.attr("data-lot-index"),
6597            wishListClass = "bp__wishlist-active",
6598            isFavorite = !$(elem).hasClass(wishListClass);
6599
6600        if (!bidspiritUser) {
6601            try {
6602                MicroModal.show("modal-login", microModalInitConfig());
6603            } catch (e) {
6604                console.error(e);
6605            }
6606        } else {
6607            bidspiritQuery("items/setFavorite", {
6608                sessionId: bidspiritSessionId,
6609                auctionId: auctionNumber,
6610                lotIndex: lotIndex,
6611                isFavorite: isFavorite
6612            }, function (data) {
6613                if (!checkError(data)) {
6614                    if (data.response.success) {
6615                        if (isFavorite) {
6616                            $(elem).addClass(wishListClass);
6617                        } else {
6618                            $(elem).removeClass(wishListClass);
6619
6620                            if (delLot) {
6621                                lot.remove();
6622                            }
6623                        }
6624                    }
6625                }
6626            });
6627        }
6628    }
6629
6630    function getLeadingBidMessage(leadingBidCode) {
6631        var response = "";
6632
6633        switch (leadingBidCode) {
6634            case "YOU_ARE_THE_HIGH_BIDDER":
6635                response = window.bs_lang.success_high_bidder;
6636                break;
6637
6638            case "ANOTHER_BID_HIGHER":
6639                response = window.bs_lang.higher_your_bid_has_been_outbid;
6640                break;
6641
6642            case "ANOTHER_BID_EARLIER":
6643                response = window.bs_lang.earlier_your_bid_has_been_outbid;
6644                break;
6645
6646            case "SYNC_ERROR":
6647                response = window.bs_lang.sync_error;
6648                break;
6649        }
6650
6651        return response;
6652    }
6653
6654    function tabs() {
6655        $(".tools-wrapper").on("click", ".bp-tabs-link a", function (event) {
6656            event.preventDefault();
6657            var $this = $(this),
6658                parent = $this.parents(".bp-tabs-block"),
6659                idTab = parent.attr("data-tab-id"),
6660                href = $this.attr("href");
6661            window.location.href = window.location.origin + window.location.pathname + href;
6662
6663            if ($(href).length) {
6664                parent.find(".nav-link").removeClass("active");
6665                $("#" + idTab + " > *").removeClass("active");
6666                $this.addClass("active");
6667                $(href).addClass("active");
6668            }
6669        });
6670    }
6671
6672    function activeTabs() {
6673        var activeTab = $('.bp-tabs-block a[href="' + window.location.hash + '"]');
6674
6675        if (activeTab.length) {
6676            activeTab.trigger("click");
6677        }
6678    }
6679
6680    /**
6681     * Global hashchange listener — allows menu links, external links, and
6682     * in-page links to switch profile tabs even when already on the page.
6683     * e.g. a header menu link to /profile/#bp-bills will work from any tab.
6684     */
6685    $(window).on("hashchange", function() {
6686        var hash = window.location.hash;
6687        if (!hash) return;
6688
6689        var tab = $('.bp-tabs-block a[href="' + hash + '"]');
6690        if (tab.length) {
6691            tab.trigger("click");
6692
6693            // Also open the spoiler/accordion on mobile if it's collapsed
6694            var spoilerTrigger = $(hash + " .bp-spoiler-trigger");
6695            if (spoilerTrigger.length && !spoilerTrigger.hasClass("active")) {
6696                spoilerTrigger.trigger("click");
6697            }
6698
6699            // Smooth scroll to the tab section
6700            var section = $(hash);
6701            if (section.length) {
6702                $("html, body").animate({ scrollTop: section.offset().top - 100 }, 300);
6703            }
6704        }
6705    });
6706
6707    function spoiler() {
6708        $(document).on("click", ".bp-spoiler-trigger", function (e) {
6709            e.preventDefault();
6710            $(this).toggleClass("active");
6711            $(this).parent().toggleClass("active-spoiler").find(".bp-spoiler-block").first().toggleClass("active");
6712        });
6713    }
6714
6715    function loginLink() {
6716        function loadLoginLink(login) {
6717            loadTemplate(".wrpLoginLink", "account-link-profile", {
6718                login: login
6719            }, false, function () {
6720                MicroModal.init(microModalInitConfig());
6721            });
6722
6723            if ($(".wrpRegisterLink").length) {
6724                loadTemplate(".wrpRegisterLink", "account-link-register", {
6725                    login: login
6726                }, false, function () {
6727                    MicroModal.init(microModalInitConfig());
6728                });
6729            }
6730        }
6731
6732        var loginLink = $(".bp-login-link"),
6733            menu = loginLink.parents(".menu");
6734
6735        if (loginLink.length && bidspiritUser) {
6736            loadLoginLink(true);
6737
6738            if (menu !== undefined) {
6739                menu.addClass("user-is-authorize");
6740                menu.removeClass("user-is-not-authorize");
6741            }
6742        } else if (!bidspiritUser) {
6743            loadLoginLink(false);
6744
6745            if (menu !== undefined) {
6746                menu.removeClass("user-is-authorize");
6747                menu.addClass("user-is-not-authorize");
6748            }
6749        }
6750    }
6751
6752    function resendEmailAction() {
6753        var resendEmailSection = $("#resendEmailSection");
6754
6755        if (resendEmailSection.length) {
6756            resendEmailSection.on("click", function (event) {
6757                event.preventDefault();
6758                bidspiritQuery("users/resendConfirmationMail", {
6759                    sessionId: bidspiritSessionId,
6760                    postConfirmationLink: window.location.href
6761                }, function (data) {
6762                    if (!bPcheckError(data)) {
6763                        if (data.response.success) {
6764                            noticeSwall("success", "Email confirmation sent");
6765                        } else {
6766                            noticeSwall("error", "Unknown error");
6767                        }
6768                    }
6769                });
6770            });
6771        }
6772    }
6773
6774    // Change email before confirmation (users/updateEmail) — lets a user fix an email typo
6775    // during registration. Sits next to the "Resend email" link (#changeEmailSection).
6776    function changeEmailAction() {
6777        var changeEmailSection = $("#changeEmailSection");
6778
6779        if (!changeEmailSection.length) {
6780            return;
6781        }
6782
6783        changeEmailSection.off("click.bpChangeEmail").on("click.bpChangeEmail", function (event) {
6784            event.preventDefault();
6785            var user = bidspiritApi.getBidspiritUser() || {};
6786
6787            Swal.fire({
6788                title: window.bs_lang.change_email_title || "Change your email",
6789                input: "email",
6790                inputValue: user.email || "",
6791                inputLabel: window.bs_lang.change_email_label || "Enter your correct email address",
6792                showCancelButton: true,
6793                confirmButtonText: window.bs_lang.change_email_confirm || "Send confirmation",
6794                cancelButtonText: window.bs_lang.cancel || "Cancel",
6795                inputValidator: function (value) {
6796                    if (!value) {
6797                        return window.bs_lang.change_email_required || "Please enter an email address";
6798                    }
6799                }
6800            }).then(function (result) {
6801                if (result.isConfirmed && result.value) {
6802                    submitChangeEmail(result.value);
6803                }
6804            });
6805        });
6806    }
6807
6808    function submitChangeEmail(newEmail) {
6809        bidspiritPostQuery("users/updateEmail", {
6810            sessionId: bidspiritSessionId,
6811            email: newEmail,
6812            postConfirmationLink: window.location.href
6813        }, function (data) {
6814            var res = (data && data.response) || {};
6815
6816            if (res.success) {
6817                var user = bidspiritApi.getBidspiritUser();
6818                if (user) {
6819                    user.email = newEmail;
6820                    bidspiritApi.setBidspiritUser(user);
6821                }
6822                noticeSwall("success",
6823                    window.bs_lang.change_email_sent_title || "Confirmation email sent",
6824                    (window.bs_lang.change_email_sent_body || "A new confirmation email was sent to") + " " + newEmail);
6825                updateDisplay();
6826            } else if (res.errorCode === "USER_EXIST") {
6827                noticeSwall("error",
6828                    window.bs_lang.oops || "Oops",
6829                    window.bs_lang.change_email_exists || "That email address is already in use. Please use a different one.");
6830            } else {
6831                noticeSwall("error",
6832                    window.bs_lang.oops || "Oops",
6833                    res.errorMessage || window.bs_lang.change_email_failed || "Could not update your email, please try again.");
6834            }
6835        }, function () {
6836            noticeSwall("error",
6837                window.bs_lang.oops || "Oops",
6838                window.bs_lang.change_email_failed || "Could not update your email, please try again.");
6839        });
6840    }
6841
6842    function saveFirebaseUser() {
6843        try {
6844            var firebaseTokenFCM = localStorage.getItem("token_firebase_push_id");
6845        } catch (e) {
6846            firebaseTokenFCM = null;
6847        }
6848
6849        if (firebaseTokenFCM !== null) {
6850            if (bidspiritUser.leadingBidAlertsEnabled !== undefined && bidspiritUser.leadingBidAlertsEnabled !== true) {
6851                bidspiritQuery("users/setLeadingBidAlertsEnabled", {
6852                    sessionId: bidspiritSessionId,
6853                    isEnabled: true
6854                }, function (data) {
6855                    if (!checkError(data)) {
6856                    }
6857                });
6858            }
6859
6860            restQuery("user/login", "POST", {
6861                bidspirit_user_email: bidspiritUser.email,
6862                firebase_id: firebaseTokenFCM
6863            }, function (response) {
6864                console.info(response);
6865            });
6866        }
6867    }
6868
6869    function widgetSliders() {
6870        new SwiperBP(".widget-lots", {
6871            speed: 400,
6872            slidesPerView: 1,
6873            spaceBetween: 10,
6874            centeredSlides: true,
6875            freeMode: false,
6876            autoplay: {
6877                delay: 4000
6878            },
6879            breakpoints: {
6880                977: {
6881                    slidesPerView: 3,
6882                    spaceBetween: 15
6883                },
6884                1200: {
6885                    slidesPerView: 5,
6886                    spaceBetween: 30,
6887                    centeredSlides: false
6888                }
6889            }
6890        });
6891    }
6892
6893    function updateLotsWidget() {
6894        if ($(".bt-wi-lots_wrp").length) {
6895            var widgets = $(".bt-wi-lots");
6896            widgets.each(function (index, widget) {
6897                var lots = $(widget).find(".bp-lot"),
6898                    hash = $(widget).attr("data-hash"),
6899                    auctions = {};
6900
6901                if (hash === undefined) {
6902                    hash = "";
6903                }
6904
6905                lots.each(function (index, elem) {
6906                    var $this = $(elem),
6907                        auctionId = $this.attr("data-auction-id"),
6908                        lotId = $this.attr("data-lot-index");
6909
6910                    if (auctions[auctionId] === undefined && auctionId !== "") {
6911                        auctions[auctionId] = [];
6912                    }
6913
6914                    if (lotId !== "") {
6915                        auctions[auctionId].push(lotId);
6916                    }
6917                });
6918                $.each(auctions, function (index, items) {
6919                    if (items.length > 0 && index !== "undefined") {
6920                        bidspiritQuery("items/getItemsInfo", {
6921                            sessionId: bidspiritSessionId,
6922                            auctionId: index,
6923                            lotIndexes: items.join(",")
6924                        }, function (data) {
6925                            if (!checkError(data)) {
6926                                var bidsInfoData = data.response;
6927
6928                                if (bidsInfoData.itemsInfo !== undefined && items.length > 0) {
6929                                    for (var i = 0; i < items.length; i++) {
6930                                        var itemIndex = items[i],
6931                                            itemRow = $("#single-lot-" + index + "-" + itemIndex + hash);
6932
6933                                        if (bidsInfoData.itemsInfo[itemIndex] !== undefined) {
6934                                            var itemInfo = bidsInfoData.itemsInfo[itemIndex];
6935                                        } else {
6936                                            console.log(itemIndex);
6937                                            continue;
6938                                        }
6939
6940                                        var content = "";
6941
6942                                        try {
6943                                            var dataContent = itemRow.attr("data-content");
6944
6945                                            if (dataContent !== undefined) {
6946                                                content = JSON.parse(urldecode(itemRow.attr("data-content")));
6947                                            }
6948                                        } catch (e) {
6949                                            console.error("error parse content of lot");
6950                                        }
6951
6952                                        loadTemplate("#single-lot-" + index + "-" + itemIndex + hash + "-content", "lot-content-template", {
6953                                            auctionInfo: bidsInfoData,
6954                                            auctionData: bidspiritApi.getAuctionInfo() || {},
6955                                            itemInfo: itemInfo,
6956                                            title: itemRow.find(".bp-lot__title").html(),
6957                                            link: itemRow.find(".img-block").attr("href"),
6958                                            content: content,
6959                                            currency: currencySymbol,
6960                                            hiddenPrice: false,
6961                                            postAuctionSaleOpenedUntil: 0,
6962                                            postAuctionSaleOpened: false,
6963                                            showEstimatedPriceInItemsList: (itemInfo.estimatedPrice !== undefined),
6964                                            displayStartPriceInCatalog: (itemInfo.startPrice !== undefined),
6965                                            bidspiritUser: bidspiritUser,
6966                                            bidsInCatalog: false,
6967                                            isShop: Boolean(parseInt($("#catalog-section").attr("data-is-shop"))),
6968                                            houseInfo: bidspiritApi.getAuctionHouseData() || {},
6969                                            settings: bidspiritApi.getAuctionSettingsData() || {},//#B141 task
6970                                            estimatedPrice: itemRow.attr("data-e
6970stimated-price"),
6971                                            // nextMinBid: nextMinBid,
6972                                        }, true, function () {
6973                                            if (itemInfo !== undefined) {
6974                                                hangUpEvent("bp:after-getItemsInfo-content-item", itemInfo, itemRow);
6975                                            }
6976                                        });
6977                                    }
6978
6979                                    hangUpEvent("bp:after-getItemsInfo-item", bidsInfoData);
6980                                }
6981                            }
6982                        });
6983                    }
6984                });
6985            });
6986        }
6987    }
6988
6989    function onPageAction() {
6990        function auctionAlertAction() {
6991            $("body").on("click", ".auction-follow-action", function (event) {
6992                event.preventDefault();
6993                var $this = $(event.target),
6994                    auctionId = $this.attr("data-auction-id");
6995                bidspiritQuery("auctions/setAuctionAlert", {
6996                    sessionId: bidspiritSessionId,
6997                    auctionId: auctionId,
6998                    isOn: true
6999                }, function (data) {
7000                    if (data.response.success) {
7001                        noticeSwall("success", "Success", "");
7002                    } else {
7003                        noticeSwall("error", window.bs_lang.oops);
7004                    }
7005                });
7006            });
7007        }
7008
7009        auctionAlertAction();
7010    }
7011
7012    function singleLotAction() {
7013        if (!!document.querySelector('#catalog-section')) {
7014            let catalogHref = window.location.href.replace(/\#.+/, '');
7015            localStorage.setItem('catalog', catalogHref);
7016            console.log("update catalog:", catalogHref);
7017        }
7018
7019        if (!!document.querySelector('.goback')) {
7020            $(".goback").each(function (index, elem) {
7021                $(elem).on("click", function (event) {
7022                    event.preventDefault();
7023                    let catalog = localStorage.getItem('catalog'),
7024                        lotId = $(this).attr('data-id'),
7025                        elemHref = $(this).attr('href');
7026
7027                    if (catalog) {
7028                        catalog = catalog.replace(/#$/, '');
7029                    }
7030
7031                    // If localStorage catalog doesn't match this lot's auction, use the href instead
7032                    if (!catalog || (elemHref && catalog.replace(/\/$/, '') !== elemHref.replace(/\/$/, '').replace(/#.*$/, ''))) {
7033                        window.location = elemHref + (lotId || '');
7034                    } else {
7035                        window.location = catalog + lotId;
7036                    }
7037                });
7038            });
7039        }
7040    }
7041
7042    document.addEventListener("DOMContentLoaded", function (event) {
7043        try {
7044            if (!bpIsset(window.localStorage)) {
7045                noticeSwall("error", window.bs_lang.storage_not_working);
7046            }
7047        } catch (e) {
7048            noticeSwall("error", window.bs_lang.storage_not_working);
7049        }
7050
7051        initApp();
7052        init();
7053        var loginForm = $(".bp-login-api"),
7054            bidForm = $("#bidFormSection"),
7055            loginModal = $("#modal-login"),
7056            registerModal = $("#modal-register"),
7057            registerForm = $(".bp-register-api"),
7058            logoutAction = $("#doLogout"),
7059            forgottenAction = $(".doForgotten"),
7060            wishListButtons = $(".bp-lot .bp__wishlist"),
7061            errorBlockSelector = ".errors-group";
7062
7063        if (loginForm.length) {
7064            loginForm.on("submit", function (event) {
7065                event.preventDefault();
7066                submitLogin(event);
7067            });
7068        }
7069
7070        if (forgottenAction.length) {
7071            forgottenAction.each(function (index, elem) {
7072                var $this = $(elem),
7073                    formParent = $(".bp-login-api");
7074                $this.on("click", function (event) {
7075                    event.preventDefault();
7076                    bidspiritPostQuery("users/sendPasswordReset", {
7077                        sessionId: bidspiritSessionId,
7078                        email: formParent.find("[name='email']").val(),
7079                        language: LANG,
7080                        postResetPage: window.location.href
7081                    }, function (data) {
7082                        if (!checkError(data)) {
7083                            if (data.response.success) {
7084                                noticeSwall("info", window.bs_lang.profile_password_reset);
7085                            } else {
7086                                noticeSwall("error", window.bs_lang.profile_email_not_found);
7087                            }
7088                        }
7089                    });
7090                });
7091            });
7092        }
7093
7094        if (registerForm.length) {
7095            registerForm.each(function (index, elem) {
7096                $(elem).on("submit", function (event) {
7097                    var $this = $(event.target),
7098                        acceptPrivacy = $this.attr("data-accept-privacy");
7099                    event.preventDefault();
7100                    var errorBlock = $this.find(errorBlockSelector),
7101                        checkboxPersonalData = $(event.target).find('[name="personal-data"]');
7102
7103                    if (errorBlock === undefined) {
7104                        errorBlock = registerModal.find(errorBlockSelector);
7105                    }
7106
7107                    errorBlock.empty();
7108
7109                    if (acceptPrivacy === "on") {
7110                        if (checkboxPersonalData.length && checkboxPersonalData.is(":checked")) {
7111                            submitRegister(event);
7112                        } else {
7113                            var error = window.bs_lang["notice_personal_data"];
7114                            errorBlock.empty().append("<p>" + error + "</p>").removeClass(window.bs_data.hidden_class);
7115                        }
7116                    } else {
7117                        submitRegister(event);
7118                    }
7119                });
7120            });
7121        }
7122
7123        if (bidForm.length) {
7124            bidForm.unbind("submit");
7125            bidForm.on("submit", function (event) {
7126                event.preventDefault();
7127
7128                if (!bidspiritUser) {
7129                    try {
7130                        MicroModal.show("modal-login", microModalInitConfig());
7131                    } catch (e) {
7132                        console.error(e);
7133                    }
7134
7135                    return;
7136                }
7137
7138                var auctionInfo = bidspiritApi.getAuctionInfo();
7139
7140                if (auctionInfo.state !== "ENDED") {
7141                    if (auctionInfo.approvalRequired !== undefined && auctionInfo.approvalRequired) {
7142                        if (auctionInfo.paymentMethodRequired !== undefined && auctionInfo.paymentMethodRequired === true) {
7143                            if (bidspiritApi.getAuctionApprovalState() === "APPROVED") {
7144                                submitBid();
7145                            } else if (bidspiritApi.getAuctionApprovalState() === "NOT_REQUESTED") {
7146                                if (paymentMethods.length > 0) {
7147                                    modalRequestApprovalShow();
7148                                    MicroModal.init(microModalInitConfig());
7149                                } else {
7150                                    addPaymentMethodCallback();
7151                                }
7152                            } else if (bidspiritApi.getAuctionApprovalState() === "APPROVAL_REQUESTED") {
7153                                noticeSwall("info", "", window.bs_lang.approval_info_approval_requested);
7154                            } else {
7155                                if (bidspiritApi.getAuctionApprovalState() === "PENDING") {
7156                                    noticeSwall("error", window.bs_lang.oops, window.bs_lang.pending_user_state);
7157                                } else if (bidspiritApi.getAuctionApprovalState() === "INCOMPLETE_PROFILE") {
7158                                    noticeSwall("error", window.bs_lang.oops, window.bs_lang.not_approved_user);
7159                                }
7160                            }
7161                        } else if (auctionInfo.paymentMethodRequired !== undefined && auctionInfo.paymentMethodRequired === false) {
7162                            if (bidspiritApi.getAuctionApprovalState() === "APPROVED") {
7163                                submitBid();
7164                            } else if (bidspiritApi.getAuctionApprovalState() === "NOT_REQUESTED") {
7165                                showTermsCondModal();
7166                            } else if (bidspiritApi.getAuctionApprovalState() === "APPROVAL_REQUESTED") {
7167                                noticeSwall("info", "", window.bs_lang.approval_info_approval_requested);
7168                            } else {
7169                                if (bidspiritApi.getAuctionApprovalState() === "PENDING") {
7170                                    noticeSwall("error", window.bs_lang.oops, window.bs_lang.pending_user_state);
7171                                } else if (bidspiritApi.getAuctionApprovalState() === "INCOMPLETE_PROFILE") {
7172                                    noticeSwall("error", window.bs_lang.oops, window.bs_lang.not_approved_user);
7173                                }
7174                            }
7175                        } else {
7176                            submitBid();
7177                        }
7178
7179                        MicroModal.init(microModalInitConfig());
7180                    } else {
7181                        submitBid();
7182                    }
7183                }
7184            });
7185        }
7186
7187        if (logoutAction.length) {
7188            doLogout(logoutAction);
7189        }
7190
7191        if (loginModal.length) {
7192            loginModal.on("click", "#doRegister", function (event) {
7193                event.preventDefault();
7194                MicroModal.close("modal-login");
7195                MicroModal.init(microModalInitConfig());
7196                MicroModal.show("modal-register");
7197            });
7198        }
7199
7200        if (registerModal.length) {
7201            registerModal.on("click", "#doLogin", function (event) {
7202                event.preventDefault();
7203                MicroModal.close("modal-register");
7204                MicroModal.init(microModalInitConfig());
7205                MicroModal.show("modal-login", microModalInitConfig());
7206            });
7207        }
7208
7209        $("#single-lot, #catalog-section").on("click", wishListButtons, function (event) {
7210            var elem = event.target,
7211                lot = $(elem).parents(".bp-lot");
7212
7213            if ($(elem).hasClass("bp__wishlist")) {
7214                event.stopPropagation();
7215                event.preventDefault();
7216                toggleFavorite(lot, elem, currentAuctionNumber);
7217            }
7218        });
7219        $("body").on("click", ".modal-open", function (event) {
7220            var $this = $(this),
7221                target = $this.attr("data-micromodal-trigger"),
7222                parentModal = $this.parents(".bp-modal");
7223
7224            if (parentModal.length) {
7225                MicroModal.close(parentModal.attr("id"));
7226            }
7227
7228            MicroModal.show(target, microModalInitConfig());
7229        });
7230        $("body").on("click", ".click-action", function (event) {
7231            var $this = $(this),
7232                target = $this.attr("data-trigger"),
7233                parentModal = $this.parents(".bp-modal");
7234
7235            if (parentModal.length) {
7236                MicroModal.close(parentModal.attr("id"));
7237            }
7238
7239            $("#" + target).trigger("click");
7240        });
7241
7242        function loadMore() {
7243            var loadMoreButton = $(".bt-wi-lots_more .btn"),
7244                bgColor = $(".bt-wi-lots_wrp").attr("data-bg-color");
7245
7246            if (loadMoreButton.length) {
7247                loadMoreButton.on("click", function (event) {
7248                    event.preventDefault();
7249                    var $this = $(this),
7250                        parent = $this.parents(".bt-wi-lots_wrp"),
7251                        count = parent.find(".bp-lots .bp-lot").length;
7252                    $.ajax({
7253                        type: "post",
7254                        dataType: "json",
7255                        url: window.wp_data.ajax_url,
7256                        data: {
7257                            action: "do_lot_list",
7258                            security: window.wp_nonce,
7259                            count: count
7260                        }
7261                    }).done(function (response) {
7262                        loadTemplate(parent.find(".bp-lots"), "shortcode-lot", {
7263                            lots: response.data.lots,
7264                            currency: currencySymbol,
7265                            bgColor: bgColor
7266                        }, false, function () {
7267                        }, true);
7268                        count = parent.find(".bp-lots .bp-lot").length;
7269
7270                        if (count >= response.data.total) {
7271                            parent.find(".bt-wi-lots_more").addClass(window.bs_data.hidden_class);
7272                        }
7273                    }).fail(function () {
7274                        console.error("Fatal error");
7275                    });
7276                });
7277            }
7278        }
7279
7280        function printNoticeBanner() {
7281            var htmlTemplate = document.getElementById("oldest-browser-template").innerHTML,
7282                data = {
7283                    message: window.bs_lang.oldest_browser_text,
7284                    linkMessage: window.bs_lang.oldest_browser_link_text,
7285                    link: window.bs_data.link_on_not_supported_browsers
7286                };
7287            htmlTemplate = _.template(htmlTemplate);
7288            $("body").append(htmlTemplate(data));
7289        }
7290
7291        function ie11supportDisabled() {
7292            if (auctionforgeDetectIE()) {
7293                printNoticeBanner();
7294            }
7295        }
7296
7297        function incrementTable() {
7298            $("#incrementTable, [href='#incrementTable']").on("click", function (event) {
7299                MicroModal.show("modal-steps", microModalInitConfig());
7300                loadTemplate("#modal-steps-content", "increment-tables-template", {
7301                    data: bidspiritApi.getAuctionInfo().increments,
7302                    currency: currencySymbol
7303                }, true);
7304            });
7305        }
7306
7307        tabs();
7308        spoiler();
7309        select2ToolsInit();
7310        loadMore();
7311        singleLotAction();
7312        onPageAction();
7313        incrementTable();
7314        ie11supportDisabled();
7315    });
7316})(jQuery);
7317
7318function noticeSwall(type, title, message, params, callback) {
7319    if (params === undefined) {
7320        params = {};
7321    }
7322
7323    var conf = {
7324        icon: type,
7325        title: title,
7326        text: message
7327    };
7328    conf = jQuery.extend({}, conf, params);
7329    Swal.fire(conf).then(function (result) {
7330        if (result.isConfirmed && callback !== undefined) {
7331            callback();
7332        }
7333    });
7334}
7335
7336function getLeftDate(eventDate) {
7337    var timer = jQuery("#auctionStartTimer"),
7338        target = timer.find(".bp-start-countdown"),
7339        archiveDate = timeShift(new Date(eventDate));
7340
7341    function pluralize(value, unit) {
7342        return value + " " + unit + (value === 1 ? "" : "s");
7343    }
7344
7345    function renderLeftDate() {
7346        var result = archiveDate.getTime() - new Date().getTime() + 1000;
7347
7348        if (result < 0) {
7349            timer.hide();
7350            if (getLeftDate._interval) {
7351                clearInterval(getLeftDate._interval);
7352                getLeftDate._interval = null;
7353            }
7354            return;
7355        }
7356
7357        var days = Math.floor(result / 1000 / 60 / 60 / 24),
7358            hours = Math.floor(result / 1000 / 60 / 60 % 24),
7359            minutes = Math.floor(result / 1000 / 60 % 60),
7360            seconds = Math.floor(result / 1000 % 60),
7361            parts = [];
7362
7363        if (days === 0 && hours === 0 && minutes === 0) {
7364            // final minute: count down the seconds so it never sits on "0"
7365            parts.push(pluralize(seconds, "second"));
7366        } else {
7367            if (days > 0) {
7368                parts.push(pluralize(days, "day"));
7369            }
7370            if (days > 0 || hours > 0) {
7371                parts.push(pluralize(hours, "hour"));
7372            }
7373            parts.push(pluralize(minutes, "minute"));
7374        }
7375
7376        var text = parts.length > 1
7377            ? parts.slice(0, -1).join(", ") + " and " + parts[parts.length - 1]
7378            : parts[0];
7379
7380        if (target.length) {
7381            target.text(text);
7382        } else {
7383            // wrapper missing (e.g. stale cached markup): keep original behaviour
7384            timer.find(".outputDays").text(days);
7385            timer.find(".outputHours").text(hours);
7386        }
7387    }
7388
7389    renderLeftDate();
7390    if (getLeftDate._interval) {
7391        clearInterval(getLeftDate._interval);
7392    }
7393    getLeftDate._interval = setInterval(renderLeftDate, 1000);
7394}
7395
7396function smartCut(text, limit) {
7397    if (text === undefined) {
7398        return "";
7399    }
7400
7401    text = text.replace(/<\/?[^>]+(>|$)/g, "");
7402    var array = text.split(" ").slice(0, limit);
7403    return array.join(" ");
7404}
7405
7406function microModalInitConfig() {
7407    return {
7408        onShow: modal => {
7409            console.info(modal);
7410        },
7411        onClose: modal => {
7412            console.info(modal);
7413        },
7414        debugMode: false
7415    };
7416}
7417
7418function formattedPrice(price, currencySymbol, secondPrice, showDecimals) {
7419    if (currencySymbol === undefined) {
7420        currencySymbol = window.bidSpiritCurrency;
7421    }
7422
7423    if (secondPrice !== undefined && secondPrice === true) {
7424        let auctionInfo = bidspiritApi.getAuctionInfo();
7425        if (auctionInfo.secondCurrency !== undefined && auctionInfo.secondCurrencyRate !== undefined) {
7426            secondPrice = " (" + formattedPrice((Number(price) * auctionInfo.secondCurrencyRate).toFixed(2), auctionInfo.secondCurrency) + ")";
7427        } else {
7428            secondPrice = "";
7429        }
7430    } else {
7431        secondPrice = "";
7432    }
7433    try {
7434        if (price === undefined || price === null || (typeof price === 'number' && isNaN(price)) || price === 'NaN') {
7435            price = 0;
7436        }
7437        var _fd = (showDecimals === true) ? 2 : 0;
7438        price = Number(String(price).replace(/[^0-9.-]/g, '')).toLocaleString('en-US', {minimumFractionDigits: _fd, maximumFractionDigits: _fd});
7439
7440        switch (window.bidSpiritLang) {
7441            case "ru":
7442                return price.replace(/(\,)/, " ") + " " + currencySymbol + secondPrice;
7443
7444            default:
7445                return currencySymbol + price + secondPrice;
7446        }
7447    } catch (e) {
7448        return currencySymbol + price + secondPrice;
7449    }
7450}
7451
7452function auctionforgeDetectIE() {
7453    var ua = window.navigator.userAgent;
7454    var msie = ua.indexOf("MSIE ");
7455
7456    if (msie > 0) {
7457        // IE 10 or older => return version number
7458        return true;
7459    }
7460
7461    var trident = ua.indexOf("Trident/");
7462
7463    if (trident > 0) {
7464        // IE 11 => return version number
7465        return true;
7466    }
7467
7468    var edge = ua.indexOf("Edge/");
7469
7470    if (edge > 0) {
7471        // Edge (IE 12+) => return version number
7472        return false;
7473    }
7474
7475    return false;
7476}
7477
7478function bp_t(phrase) {
7479    var key = phrase.toLowerCase().replace(/(\s)+/gm, "_");
7480    if (window.bs_lang[key] !== undefined) {
7481        return window.bs_lang[key];
7482    } else {
7483        return phrase;
7484    }
7485}
7486
7487function bpGetQueryParams(qs) {
7488    var searchParams = new URLSearchParams(window.location.search);
7489    return searchParams.get(qs);
7490}
7491
7492function bpIsset(variable) {
7493    return typeof variable != "undefined" && variable !== null;
7494}
7495
7496function bpYoutubeIDParser(url) {
7497    var regExp = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(?:shorts\/)|(watch\?))\??v?=?([^#&?]*).*/;
7498    var match = url.match(regExp);
7499    return match && match[7].length == 11 ? match[7] : false;
7500}
7501
7502function getTimeZoneFromUser() {
7503    return Intl.DateTimeFormat().resolvedOptions().timeZone;
7504}
7505
7506function convertTZ(date, tzString) {
7507    return new Date((typeof date === "string" ? new Date(date) : date).toLocaleString("en-US", {
7508        timeZone: tzString
7509    }));
7510}
7511
7512function getLocaleFromUser() {
7513    return Intl.DateTimeFormat().resolvedOptions().locale;
7514}
7515
7516function timeShift(deadline, isDTS) {
7517    function createDateAsUTC(date) {
7518        return new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds()));
7519    }
7520
7521    Date.prototype.addHours = function (hours) {
7522        var date = new Date(this.valueOf());
7523        date.setHours(date.getHours() + hours);
7524        return date;
7525    };
7526
7527    var baseTimeZone = parseInt(window.timeZone),
7528        baseTimeZoneName = window.timeZoneName;
7529
7530    if (bpIsset(baseTimeZoneName) && bpIsset(window.timeZoneName) !== "") {
7531        deadline = createDateAsUTC(new Date(new Date(deadline).toLocaleString("en-US", {
7532            timeZone: "UTC"
7533        })));
7534        return deadline;
7535    } else {
7536        var timeZone = deadline.getTimezoneOffset() / 60 * -1 - baseTimeZone;
7537        return new Date(deadline.getTime()).addHours(timeZone);
7538    }
7539}
7540
7541function isDisabledReadNotice() {
7542    return false;
7543}
7544
7545(function ($) {
7546    function metaSlider() {
7547        if ($(".bt-wi-slider .swiper-container").length) {
7548            new SwiperBP(".bt-wi-slider .swiper-container", {
7549                slidesPerView: 1,
7550                breakpoints: {
7551                    320: {
7552                        slidesPerView: 2
7553                    },
7554                    640: {
7555                        slidesPerView: 3,
7556                        spaceBetween: 10
7557                    },
7558                    990: {
7559                        slidesPerView: 4,
7560                        spaceBetween: 15
7561                    },
7562                    1200: {
7563                        slidesPerView: 5,
7564                        spaceBetween: 20
7565                    }
7566                },
7567                autoplay: {
7568                    delay: 4000
7569                }
7570            });
7571        }
7572    }
7573
7574    function inquiryLot() {
7575        function decodeHtmlEntities(html) {
7576            const entities = {
7577                '&lt;': '<',
7578                '&gt;': '>',
7579                '&amp;': '&',
7580                '&quot;': '"',
7581                '&#39;': "'",
7582            };
7583            return html.replace(/&lt;|&gt;|&amp;|&quot;|&#39;/g, match => entities[match]);
7584        }
7585
7586        function fillFiled(inquiryField) {
7587            inquiryField.each(function (index, elem) {
7588                var qParam = "";
7589
7590                try {
7591                    qParam = decodeHtmlEntities(bpGetQueryParams("bp-inquiry"));
7592                } catch (e) {
7593                    console.info(e);
7594                    qParam = bpGetQueryParams("bp-inquiry");
7595                }
7596                $(elem).val(qParam);
7597            });
7598        }
7599
7600        var inquiryField = $(".inquiry-target-field"),
7601            defaultFields = $(".elementor-form .elementor-field-type-textarea textarea, .wpcf7-form .wpcf7-textarea");
7602
7603        if (inquiryField.length) {
7604            fillFiled(inquiryField);
7605        } else if (defaultFields.length) {
7606            fillFiled(defaultFields);
7607        }
7608    }
7609
7610    function fallbackCopyTextToClipboard(text) {
7611        var textArea = document.createElement("textarea");
7612        textArea.value = text;
7613        textArea.style.top = "0";
7614        textArea.style.left = "0";
7615        textArea.style.position = "fixed";
7616        document.body.appendChild(textArea);
7617        textArea.focus();
7618        textArea.select();
7619
7620        try {
7621            var successful = document.execCommand("copy");
7622            var msg = successful ? "successful" : "unsuccessful";
7623            console.info("Fallback: Copying text command was " + msg);
7624        } catch (err) {
7625            console.error("Fallback: Oops, unable to copy", err);
7626        }
7627
7628        document.body.removeChild(textArea);
7629    }
7630
7631    function copyTextToClipboard(text) {
7632        if (!navigator.clipboard) {
7633            fallbackCopyTextToClipboard(text);
7634            return;
7635        }
7636
7637        navigator.clipboard.writeText(text);
7638    }
7639
7640    function shareLink() {
7641        var shaleLinkBtn = $(".share-btn__link[data-id=link]");
7642
7643        if (shaleLinkBtn !== undefined) {
7644            shaleLinkBtn.on("click", function (event) {
7645                event.preventDefault();
7646                var $this = $(this);
7647
7648                if ($this.hasClass("share-btn__link-active")) {
7649                    return;
7650                }
7651
7652                copyTextToClipboard(window.location);
7653                $this.html(window.bs_lang.copied).addClass("share-btn__link-active");
7654                return;
7655            });
7656        }
7657    }
7658
7659    function countDown() {
7660        function getTimeRemaining(endtime) {
7661            var t = Date.parse(endtime) - Date.parse(new Date()),
7662                index = t <= 0 ? 0 : 1,
7663                seconds = Math.floor(t / 1000 % 60) * index,
7664                minutes = Math.floor(t / 1000 / 60 % 60) * index,
7665                hours = Math.floor(t / (1000 * 60 * 60) % 24) * index,
7666                days = Math.floor(t / (1000 * 60 * 60 * 24)) * index;
7667            return {
7668                total: t,
7669                days: days,
7670                hours: hours,
7671                minutes: minutes,
7672                seconds: seconds
7673            };
7674        }
7675
7676        function initializeClock(clock, endtime) {
7677            if (clock) {
7678                var daysSpan = clock.querySelector(".bp-days");
7679                var hoursSpan = clock.querySelector(".bp-hours");
7680                var minutesSpan = clock.querySelector(".bp-minutes");
7681                var secondsSpan = clock.querySelector(".bp-seconds");
7682
7683                function updateClock() {
7684                    var t = getTimeRemaining(endtime);
7685                    daysSpan.innerHTML = t.days;
7686                    hoursSpan.innerHTML = ("0" + t.hours).slice(-2);
7687                    minutesSpan.innerHTML = ("0" + t.minutes).slice(-2);
7688                    secondsSpan.innerHTML = ("0" + t.seconds).slice(-2);
7689
7690                    if (t.total <= 0) {
7691                        clearInterval(timeinterval);
7692                    }
7693                }
7694
7695                updateClock();
7696                var timeinterval = setInterval(updateClock, 1000);
7697            }
7698        }
7699
7700        var countdown = $(".bp-countdown");
7701
7702        if (countdown.length) {
7703            countdown.each(function (index, count) {
7704                var dateTime = $(count).attr("data-time"),
7705                    deadline = new Date(Date.parse(dateTime));
7706                initializeClock(count, timeShift(deadline));
7707            });
7708        }
7709    }
7710
7711    function getAuctionCarCallback(response) {
7712        if (_.template !== undefined) {
7713            var carInfoTemplate = document.getElementById("car-info-template");
7714
7715            if (!bpIsset(carInfoTemplate)) {
7716                return;
7717            }
7718
7719            var html = _.template(carInfoTemplate.innerHTML),
7720                additionalInfoBlock = document.getElementById("additional-info-block");
7721
7722            response = response.response;
7723
7724            if (response.item !== undefined && response.item.carInfo !== undefined) {
7725                additionalInfoBlock.innerHTML = html({
7726                    data: response.item,
7727                    info: response.item.carInfo
7728                });
7729            }
7730        }
7731    }
7732
7733    function getAuctionApertmentCallback(response) {
7734        if (_.template !== undefined) {
7735            var apartmentTemplate = document.getElementById("apartment-info-template");
7736
7737            if (!bpIsset(apartmentTemplate)) {
7738                return;
7739            }
7740
7741            var html = _.template(apartmentTemplate.innerHTML),
7742                additionalInfoBlock = document.getElementById("additional-info-block");
7743
7744            response = response.response;
7745
7746            if (response.item !== undefined && response.item.realEstateInfo !== undefined) {
7747                additionalInfoBlock.innerHTML = html({
7748                    data: response.item,
7749                    info: response.item.realEstateInfo
7750                });
7751            }
7752        }
7753    }
7754
7755    function getAuctionIndustrialCallback(response) {
7756        if (_.template !== undefined) {
7757            var apartmentTemplate = document.getElementById("industrial-info-template");
7758
7759            if (!bpIsset(apartmentTemplate)) {
7760                return;
7761            }
7762
7763            var html = _.template(apartmentTemplate.innerHTML),
7764                additionalInfoBlock = document.getElementById("additional-info-block");
7765
7766            response = response.response;
7767
7768            if (response.item !== undefined && response.item.machineInfo !== undefined) {
7769                additionalInfoBlock.innerHTML = html({
7770                    data: response.item,
7771                    info: response.item.machineInfo
7772                });
7773            }
7774        }
7775    }
7776
7777    function afterInitAction() {
7778        let profileLink = $("#bp-profile-link");
7779    }
7780
7781    function afterLoginAction() {
7782        let href = window.location.href.replace(window.location.search, "");
7783        if (href === window.bs_data.sign_in_permalink) {
7784            window.location = window.bs_data.link_profile;
7785        }
7786    }
7787
7788    function adminBarTools() {
7789        function adminBarToolsCallback(response) {
7790            $("#wp-admin-bar-bp-single-sync a").on("click", function (event) {
7791                event.preventDefault();
7792                let data = response.response.item;
7793                $.ajax({
7794                    url: "/wp-json/plugin/v1/sync-lot/",
7795                    type: "POST",
7796                    dataType: "json",
7797                    data: {
7798                        item: data,
7799                        auctionId: data.auctionId,
7800                        itemIndex: data.itemIndex,
7801                        language: data.lang,
7802                        sessionId: bidspiritApi.getBidspiritSessionId()
7803                    }
7804                }).done(function (response) {
7805                    noticeSwall("info", window.bs_lang.lot_sync_is_queued);
7806                }).fail(function (response) {
7807                    noticeSwall("error", window.bs_lang.not_found);
7808                }).always(function () {
7809                });
7810            });
7811        }
7812
7813        if (document.body.classList.contains("admin-bar") && document.body.classList.contains("admin-bar")) {
7814            $(window).on("bp:get-auction-item", adminBarToolsCallback);
7815        }
7816    }
7817
7818    function menuSwitcher(langCode) {
7819        let pllSwitch = jQuery(".bt-header-row ul.cpel-switcher__list:not(.cpel-switcher__lang--active)"),
7820            langSwitch = pllSwitch.find('a[lang^="' + langCode + '"]').attr("href");
7821        if (langSwitch !== undefined) {
7822            window.location.href = langSwitch;
7823        }
7824    }
7825
7826    $(document).ready(function () {
7827        metaSlider();
7828        inquiryLot();
7829        shareLink();
7830        countDown();
7831        adminBarTools();
7832        $(window).on("bp:get-auction-item", getAuctionCarCallback);
7833        $(window).on("bp:get-auction-item", getAuctionApertmentCallback);
7834        $(window).on("bp:get-auction-item", getAuctionIndustrialCallback);
7835        $(window).on("bp:after-init", afterInitAction);
7836        $(window).on("bp:after-login", afterLoginAction);
7837    });
7838})(jQuery);

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