HEX
Server: nginx/1.18.0
System: Linux test-ipsremont 5.4.0-214-generic #234-Ubuntu SMP Fri Mar 14 23:50:27 UTC 2025 x86_64
User: ips (1000)
PHP: 8.0.30
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: /var/www/nebonutyye/js/script.js
const frontData = {
    certificates: false,
    certificatesSpeed: false,
    pilot: false,
    modifiers: [],
    name: '',
    number: '',
    phone: '',
    email: '',
    place: 1,
    address: '',
    addressSpeed: '',
    text: '',
    summ: 0,
    summCommission: 0,

    updateCertificates() {
        this.certificates = !this.certificates;
    },

    updateCertificatesSpeed() {
        this.certificatesSpeed = !this.certificatesSpeed;
    },

    updatePilot() {
        this.pilot = !this.pilot;
    },

    updateName(text) {
        this.name = text;
    },

    updateNumber(text) {
        this.number = text;
    },

    updatePhone(text) {
        this.phone = text;
    },

    updateEmail(text) {
        this.email = text;
    },

    updatePlace(number) {
        this.place = number;
    },

    updateAddress(text) {
        this.address = text;
    },

    updateAddressSpeed(text) {
        this.addressSpeed = text;
    },

    updateModifiers(id, add) {
        if (add) {
            this.modifiers.push(id);
        } else {
            this.modifiers = this.modifiers.filter((item) => item !== id);
        }
    },

    recalculateSumm() {
        const buttonP = document.querySelector('[data-tour-price]');
        const headerP = document.querySelector('[data-tour-header-price]');

        this.summ = this.config?.tour * this.place;

        if (this.pilot && this.place !== 3) {
            this.summ += this.config?.pilot;
        }

        if (this.certificates) {
            this.summ += this.config?.delivery;
        }

        if (this.modifiers && this.modifiers?.length && this.config?.modifiers && this.config?.modifiers?.length) {
            this.config.modifiers.forEach((item) => {
                if (this.modifiers.includes(item.number)) {
                    this.summ += item.price;
                }
            });
        }

        if (this.config?.commission) {
            this.summCommission = ((this.summ / (100 - this.config?.commission)) * this.config?.commission);

            this.summ += this.summCommission;
        }

        if (buttonP) {
            buttonP.innerHTML = `${generatePrice(this.summ.toFixed(2))} ₽ | Оформить`;
        }

        if (headerP) {
            headerP.innerHTML = `${generatePrice(this.summ.toFixed(2))} ₽`;
        }

        this.rerenderTotal();
    },

    rerenderTotal() {
        const total = document.querySelector('[data-tour-total]');

        if (!total) {
            return;
        }

        const list = total.querySelector('.tourFormTotal__list');

        if (!list) {
            return;
        }

        list.innerHTML = `
            <div class="tourFormTotal__listItem">
                <p>${this.config?.type} ${this.config?.allPlaces ? this.config?.allPlacesText : this.place + ' ' + declOfNum(this.place, [' место', ' места', ' мест'])}<br /> на путешествие ${this.config?.title}</p>
                <p>1 шт.</p>
                <p>${generatePrice(this.config?.tour * this.place)} ₽</p>
            </div>
        `;

        if (this.modifiers && this.modifiers?.length && this.config?.modifiers && this.config?.modifiers?.length) {
            this.config.modifiers.forEach((item) => {
                if (this.modifiers.includes(item.number)) {
                    list.innerHTML += `
                        <div class="tourFormTotal__listItem">
                            <p>ViewPoint #${item.number} ${item.name}</p>
                            <p>1 шт.</p>
                            <p>${generatePrice(item.price)} ₽</p>
                        </div>
                    `;
                }
            });
        }

        if (this.pilot && this.place !== 3) {
            list.innerHTML += `
                <div class="tourFormTotal__listItem">
                    <p>Лететь на Месте пилота</p>
                    <p>1 шт.</p>
                    <p>${generatePrice(this.config?.pilot)} ₽</p>
                </div>
            `;
        }

        if (this.certificates) {
            list.innerHTML += `
                <div class="tourFormTotal__listItem">
                    <p>Доставка сертификата</p>
                    <p>1 шт.</p>
                    <p>${generatePrice(this.config?.delivery)} ₽</p>
                </div>
            `;
        }

        if (this.config?.commission) {
            list.innerHTML += `
                <div class="tourFormTotal__listItem">
                    <p>Комиссия платежной системы Platron ${this.config?.commission}%</p>
                    <p>—</p>
                    <p>${generatePrice(this.summCommission.toFixed(2))} ₽</p>
                </div>
            `;
        }
    }
};

window.addEventListener('load', async () => {
    const config = await fetchConfig();

    if (config) {
        frontData.config = {
            ...config
        }
    }

    frontData.recalculateSumm();

    renderConfig(frontData.config);

    document.body.removeAttribute('data-loader');

    const name = document.getElementById('name');
    const number = document.getElementById('number');
    const phone = document.getElementById('phone');
    const email = document.getElementById('email');
    const address = document.getElementById('address');
    const addressSpeed = document.getElementById('address-speed');

    const certificate = document.querySelector('.tourCertificate__checkbox');
    const certificateSpeed = document.querySelector('.tourCertificateSpeed__checkbox');
    const certificateForm = document.querySelector('.tourCertificateForm');
    const certificateFormSpeed = document.querySelector('.tourCertificateFormSpeed');
    const pilotCheckbox = document.querySelector('.tourPilot__checkbox');

    const elCertificate = document.querySelector('[data-tour-delivery]');
    const elCertificateSpeed = document.querySelector('[data-tour-delivery-speed]');
    const elCertificateFormSpeed = document.querySelector('[data-tour-delivery-form-speed]');
    const elCertificateForm = document.querySelector('[data-tour-delivery-form]');
    const modifiers = document.querySelector('[data-tour-modifiers]');

    const places = document.querySelectorAll('.tourPlace__listItem');
    const modifiersItems = document.querySelectorAll('.tourModifiers__listItemContentButton');
    const textSpoiler = document.querySelector('.tourPoster__text');

    const button = document.querySelector('.tourForm__button');

    if (certificate) {
        certificate.addEventListener('click', () => {
            frontData.updateCertificates();

            if (certificate.classList.contains('active')) {
                certificate.classList.remove('active');
            } else {
                certificate.classList.add('active');
            }

            if (frontData.certificates) {
                elCertificateSpeed.classList.add('hide');
                elCertificateFormSpeed.classList.add('hide');
                certificateForm.classList.add('active');
            } else {
                elCertificateSpeed.classList.remove('hide');
                elCertificateFormSpeed.classList.remove('hide');
                certificateForm.classList.remove('active');
            }

            frontData.recalculateSumm();
        });
    }

    if (certificateSpeed) {
        certificateSpeed.addEventListener('click', () => {
            frontData.updateCertificatesSpeed();

            if (certificateSpeed.classList.contains('active')) {
                certificateSpeed.classList.remove('active');
            } else {
                certificateSpeed.classList.add('active');
            }

            if (frontData.certificatesSpeed) {
                elCertificate.classList.add('hide');
                elCertificateForm.classList.add('hide');
                certificateFormSpeed.classList.add('active');
            } else {
                certificateFormSpeed.classList.remove('active');
                elCertificate.classList.remove('hide');
                elCertificateForm.classList.remove('hide');
            }

            frontData.recalculateSumm();
        });
    }

    if (pilotCheckbox) {
        pilotCheckbox.addEventListener('click', () => {
            frontData.updatePilot();

            if (pilotCheckbox.classList.contains('active')) {
                pilotCheckbox.classList.remove('active');
            } else {
                pilotCheckbox.classList.add('active');
            }

            frontData.recalculateSumm();
        });
    }

    if (textSpoiler) {
        textSpoiler.addEventListener('click', () => {
            if (textSpoiler.classList.contains('active')) {
                textSpoiler.classList.remove('active');
            } else {
                textSpoiler.classList.add('active');
            }
        });
    }

    if (number) {
        const maskOptions = {
            mask: '0000-000',

        };

        IMask(number, maskOptions);

        number.addEventListener('input', (e) => {
            frontData.updateNumber(e.target.value);
        })
    }

    if (name) {
        name.addEventListener('input', (e) => {
            frontData.updateName(e.target.value);
        })
    }

    if (phone) {
        const maskOptions = {
            mask: '+{7}(000) 000-00-00'
        };

        IMask(phone, maskOptions);

        phone.addEventListener('input', (e) => {
            frontData.updatePhone(e.target.value);
        })
    }

    if (email) {
        email.addEventListener('input', (e) => {
            frontData.updateEmail(e.target.value);
        })
    }

    if (address) {
        address.addEventListener('input', (e) => {
            frontData.updateAddress(e.target.value);
        })
    }

    if (addressSpeed) {
        addressSpeed.addEventListener('input', (e) => {
            frontData.updateAddressSpeed(e.target.value);
        })
    }

    if (places && places?.length) {
        places.forEach((item, index) => {
            item.addEventListener('click', () => {
                frontData.updatePlace(Number(item.dataset.value));

                places.forEach((item, index) => {
                    if (index + 1 <= frontData.place) {
                        item.classList.add('active');
                    } else {
                        item.classList.remove('active');
                    }
                });

                const placeAllText = document.querySelector('.tourPlace__all');
                const pilot = document.querySelector('[data-tour-pilot]');

                if (placeAllText && Number(item.dataset.value) === 3) {
                    placeAllText.classList.add('active');
                } else {
                    placeAllText.classList.remove('active');
                }

                if (pilot) {
                    if (frontData.place === 3) {
                        pilot.classList.add('disabled');
                        frontData.pilot = false;
                        pilotCheckbox.classList.remove('active');
                    } else {
                        pilot.classList.remove('disabled');
                    }
                }

                if (modifiers) {
                    if (frontData.place === 3) {
                        modifiers.classList.remove('disabled');
                    } else {
                        modifiers.classList.add('disabled');
                    }
                }

                frontData.recalculateSumm();
            });

            if (index + 1 <= frontData.place) {
                item.classList.add('active');
            } else {
                item.classList.remove('active');
            }
        });
    } else {
        if (frontData.config.allPlaces && modifiers) {
            modifiers.classList.remove('disabled');
        }
    }

    if (modifiersItems && modifiersItems?.length) {
        modifiersItems.forEach((item) => {
           item.addEventListener('click', () => {
               if (item.classList.contains('active')) {
                   frontData.updateModifiers(Number(item.dataset.number), false)
                   item.classList.remove('active');
               } else {
                   item.classList.add('active');
                   frontData.updateModifiers(Number(item.dataset.number), true)
               }

               frontData.recalculateSumm();
           });
        });
    }

    if (button) {
        button.addEventListener('click', () => {
            frontData.recalculateSumm();

            console.log(frontData)

            const error = [];

            const name = document.getElementById('name');
            const number = document.getElementById('number');
            const phone = document.getElementById('phone');
            const email = document.getElementById('email');

            if (frontData.config.numberOrder) {
                if (!frontData.number) {
                    error.push(true);
                    number.classList.add('error');
                } else {
                    number.classList.remove('error');
                }
            }

            if (!frontData.name) {
                error.push(true);
                name.classList.add('error');
            } else {
                name.classList.remove('error');
            }

            if (!frontData.phone) {
                error.push(true);
                phone.classList.add('error')
            } else {
                phone.classList.remove('error');
            }

            if (!frontData.email) {
                error.push(true);
                email.classList.add('error')
            } else {
                email.classList.remove('error');
            }

            const formData = new FormData();
            formData.append('name', frontData.name);
            formData.append('email', frontData.email);
            formData.append('phone', frontData.phone);
            formData.append('price', frontData.summ.toFixed(2));
            formData.append('wishes', frontData.text);
            formData.append('positon',  frontData.config?.title);

            if (frontData.config.numberOrder) {
                formData.append('number', frontData.number);
            }

            if (frontData.certificatesSpeed) {
                formData.append('address', frontData.addressSpeed);
            }

            if (frontData.certificates) {
                formData.append('address', frontData.address);
            }

            if (!error.includes(true)) {
                fetch('https://overheadcitytour.ru/api/platron.php', {
                    method: 'POST',
                    body: formData,
                }).then((res) => {
                    return res.json();
                }).then((resultData) => {
                    console.log(resultData);

                    let form = '<form action="https:/' + '/www.platron.ru/payment.php" method="post">';
                    for (let key in resultData) {
                        if (resultData.hasOwnProperty(key)) {
                            form += '<input type="hidden" name="' + key + '" value="' + resultData[key] + '" />';
                        }
                    }
                    form += '</form>';

                    const div = document.createElement('div');
                    div.innerHTML = form.trim();
                    const formElement = div.firstChild;
                    document.body.appendChild(div);
                    formElement.submit();
                });
            }
        });
    }
});

const renderConfig = (config) => {
    const titles = document.querySelectorAll('[data-tour-title]');
    const type = document.querySelector('[data-tour-type]');
    const image = document.querySelector('[data-tour-image]');
    const desc = document.querySelector('[data-tour-desc]');
    const text = document.querySelector('[data-tour-text]');
    const list = document.querySelector('[data-tour-list]');
    const allPlace = document.querySelector('[data-tour-allPlace]');
    const place = document.querySelector('[data-tour-place]');
    const places = document.querySelectorAll('[data-tour-places]');
    const pilot = document.querySelector('[data-tour-pilot]');
    const delivery = document.querySelector('[data-tour-delivery]');
    const deliveryForm = document.querySelector('[data-tour-delivery-form]');
    const modifiers = document.querySelector('[data-tour-modifiers]');
    const modifiersList = document.querySelector('[data-tour-modifiers-list]');
    const number = document.getElementById('number');

    console.log(config);

    if (titles.length) {
        titles.forEach((item) => {
           item.innerHTML = config?.title;
        });
    }

    if (type) {
        type.innerHTML = config?.type;
    }

    if (config?.typeText) {
        tippy('#why-tooltip', {
            content: config?.typeText,
            theme: 'nebo',
            placement: 'bottom',
        });
    }

    if (image && config?.image) {
        image.src = config.image.includes('http') ? config.image : `./images/${config.image}`;
    } else {
        image.remove();
    }

    if (!config?.desc || !config?.text) {
        desc.remove();
        text.remove();
    } else {
        desc.innerHTML = config.desc;
        text.innerHTML = config.text;
    }

    if (list && config?.list?.length) {
        list.innerHTML = '';

        config.list.forEach((item) => {
            list.innerHTML += `
                <div class="tourPoster__listItem">
                    <p>${item.name}</p><span>${item.value}</span>
                </div>
            `;
        });
    } else {
        list.remove();
    }

    if (config?.allPlaces) {
        if (place) {
            place.remove();
        }

        if (pilot) {
            pilot.remove();
        }

        if (allPlace)  {
            const title = allPlace.querySelector('.tourAllPlace__headerTitle');
            const subtitle = allPlace.querySelector('.tourAllPlace__headerSubTitle');

            if (title && config?.allPlacesText) {
                title.innerHTML = config.allPlacesText;
            }
            if (subtitle && config?.allPlacesDesc) {
                subtitle.innerHTML = config.allPlacesDesc;
            }
        }
    } else {
       if (allPlace)  {
           allPlace.remove()
       }
    }

    if (places.length) {
        places.forEach((item, index) => {
            const price = item.querySelector('.tourPlace__listItemPrice');
            if (price) {
                if (index + 1 === 1) {
                    price.innerHTML = `${generateIntegerPrice(config?.tour)} ₽`;
                } else {
                    price.innerHTML = `+ ${generateIntegerPrice(config?.tour * (index))} ₽`;
                }
            }
        });
    }

    if (pilot && config?.pilot) {
        const price = pilot.querySelector('.tourPilot__price');

        price.innerHTML = `+ ${config?.pilot} ₽`;
    } else {
        pilot.remove();
    }

    if (delivery && config?.delivery) {
        const price = delivery.querySelector('.tourCertificate__price');

        price.innerHTML = `+ ${config.delivery} ₽`;
    } else {
        delivery.remove();

        if (deliveryForm) {
            deliveryForm.remove();
        }
    }

    if (!config.numberOrder && number) {
        number.remove();
    }

    if (config.modifiers && config.modifiers?.length && modifiersList) {
        modifiersList.innerHTML = '';

        config.modifiers.forEach((item) => {
            modifiersList.innerHTML += `
                <div class="tourModifiers__listItem">
                    <div class="tourModifiers__listItemInformation">
                        <svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
                            <g filter="url(#filter0_b_1079_865)">
                                <circle cx="20" cy="20" r="20" fill="white" fill-opacity="0.1"/>
                                <circle cx="20" cy="20" r="19" stroke="white" stroke-opacity="0.2" stroke-width="2"/>
                            </g>
                            <path opacity="0.5" d="M21.1816 27H18.8086V16.4336H21.1816V27ZM18.6621 13.6895C18.6621 13.3249 18.776 13.0221 19.0039 12.7812C19.2383 12.5404 19.5703 12.4199 20 12.4199C20.4297 12.4199 20.7617 12.5404 20.9961 12.7812C21.2305 13.0221 21.3477 13.3249 21.3477 13.6895C21.3477 14.0475 21.2305 14.347 20.9961 14.5879C20.7617 14.8223 20.4297 14.9395 20 14.9395C19.5703 14.9395 19.2383 14.8223 19.0039 14.5879C18.776 14.347 18.6621 14.0475 18.6621 13.6895Z" fill="white"/>
                            <defs>
                                <filter id="filter0_b_1079_865" x="-10" y="-10" width="60" height="60" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
                                    <feFlood flood-opacity="0" result="BackgroundImageFix"/>
                                    <feGaussianBlur in="BackgroundImageFix" stdDeviation="5"/>
                                    <feComposite in2="SourceAlpha" operator="in" result="effect1_backgroundBlur_1079_865"/>
                                    <feBlend mode="normal" in="SourceGraphic" in2="effect1_backgroundBlur_1079_865" result="shape"/>
                                </filter>
                            </defs>
                        </svg>
                    </div>
                    <img src="${item.img.includes('http') ? item.img : './images/' + item.img}" alt="">
                    <div class="tourModifiers__listItemContent">
                        <div class="tourModifiers__listItemContentItem">
                            <div class="tourModifiers__listItemContentTitle"><span>#${item.number}</span> ${item.name}</div>
                            <div class="tourModifiers__listItemContentPrice">+ ${generateIntegerPrice(item.price)} ₽</div>
                        </div>
                        <div class="tourModifiers__listItemContentItem">
                            <div class="tourModifiers__listItemContentButton" data-number="${item.number}">
                                <span>+ Добавить</span>
                                <p>
                                    <svg width="38" height="38" viewBox="0 0 38 38" fill="none" xmlns="http://www.w3.org/2000/svg">
                                        <path d="M11.25 19.25L16.25 24.25L26.25 14.25" stroke="white" stroke-width="3"/>
                                    </svg>
                                </p>
                            </div>
                        </div>
                    </div>
                </div>
            `;
        });
    } else {
        if (modifiers) {
            modifiers.remove();
        }
    }
};

window.addEventListener('scroll', function () {
    const back = document.querySelector('.tourBack svg');

    if (window.scrollY > 0) {
        back.style.display = 'none';
        back.style.pointerEvents = 'none';
    } else {
        back.style.display = 'block';
        back.style.pointerEvents = 'all';
    }
});

const declOfNum = (number, titles) => {
    const cases = [2, 0, 1, 1, 1, 2];
    return titles[
        number % 100 > 4 && number % 100 < 20 ? 2 : cases[number % 10 < 5 ? number % 10 : 5]
        ];
};

const generateIntegerPrice = (str) => {
    let [_, num, suffix] = str.toString().match(/^(.*?)((?:[,.]\d+)?|)$/);

    return `${num.replace(/\B(?=(?:\d{3})*$)/g, '.')}`;
}

const generatePrice = (str) => {
    let [_, num, suffix] = str.toString().match(/^(.*?)((?:[,.]\d+)?|)$/);

    return `${num.replace(/\B(?=(?:\d{3})*$)/g, '.')}<span style="opacity: 0.6;">${suffix.replace('.', ',')}</span>`;
}

const fetchConfig = async () => {
    let configName = window.location.pathname.substring(1).length ? window.location.pathname.substring(1) + '.json' : 'config.json';

    return await fetch('./' + configName).then((response) => response.json()).catch(() => {
        return fetch('./polet-15-helicopter-sertificate-12.json').then((response) => response.json()).catch((error) => {
            throw Error('Конфиг для данной страницы не найден!' + error)
        })
    });
};