Лаборатория   Фронтенд   Форма обратной связи во всплывающем окне

Форма обратной связи во всплывающем окне

Есть вещи, которые кочуют из проекта в проект по сути в неизенном виде. С каждой итерацией они, конечно, становятся лучше, да и внешний вид в зависимости от контекста меняется, но суть остается прежней.

Одним из таких модулей является для меня самая обычная форма обратной связи во всплывающем окне, вызываемая по клику на кнопку.

Некогда позаимствованная на просторах интернета схема, за долгое время использования настолько изменилась (в лучшую сторону), что я даже не стану искать первоисточник и с полным правом выдам за свою. Хотя нет, PHP, мне помог доработать добрый товарищ Лёха. Но обо всём по порядку.

Форма оформляется при помощи SASS, при организации структуры по-полной вдохновляюсь БЭМ, хотя местами делаю по-своему, ну а обработку формы выполняют JS-скрипт и PHP-обработчик. Скрипт вовсю использует инструментарий Jquery.

HTML

Для начала разметка. У нас имеется слой-перекрытие для контента, контейнер для содержимого всплывающего блока с кнопкой закрытия, обёртка для формы и, собственно, сама форма.

<div class="popup-overlayer"></div>
<div class="popup-window popup-window--form popup-window--a">
    <button class="button button--close-popup">Закрыть</button>
    <div class="form-wr">
        <form class="form form--a">
            <div class="form__send-statusbar" sendstatus="1">
                <div class="form__send-statusbar-text-wr">
                    <p class="form__send-status">Мы получили вашу заявку и бла-бла. Хотя нет, это просто рыба для разработки.</p>
                    <a href="" class="form__close-send-statusbar">Скрыть уведомление</a>
                </div>
            </div>

            <h5 class="form__header">Заявка на что-то</h5>
            <p class="form__description">Кратко расскажем о том, что произойдёт после того, как вы отправите форму.</p>

            <input name="name" type="text" class="form__input form__input--hidden">

            <label class="form__label" for="phone">Телефон*:</label>
            <input name="phone" type="text" class="form__input form__input--text">
            <label class="form__label" for="phone">Электропочта:</label>
            <input name="email" type="text" class="form__input form__input--text">
            <label class="form__label" for="text">Здесь можно высказаться:</label>
            <textarea name="text" class="form__input form__input--textarea" id="" cols="30" rows="10"></textarea>

            <input type="submit" class="form__input form__input--submit" name="send" value="Отправить">
        </form>
    </div>
</div>


<button class="button button--sample-form">Показать форму</button>

SASS

Классы для всех элементов сделаны по БЭМ (может местами не совсем, но во всяком случае с оглядкой). Выделяются блоки всплывающего окна, формы и кнопки. Расширяя их модификаторами можно размещать без большой боли в любом месте сайта. Ну а сами стили подобраны под дизайн моего блога — переписать делов на 15 минут.

// POPUP WINDOW

.popup-overlayer {
    display: none;
    width: 100vw;
    max-width: 100%;
    height: 100vh;
    position: fixed;
    top: 0;
    left: 0;
    z-index: 1001;
    background: rgba(0,0,0,0.75);
}

.popup-window {
    display: none;
    padding: 40px 0 16px;
    @include border-radius(4px);
    border: 1px solid #ccc;
    margin: auto;
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
    z-index: 1002;
    background: white;
    &--form {
        width: 320px;
    }
    &--a {
        height: 534px;
    }
}


// FORMS

.form-wr {
    width: 320px;
}

.form {
    width: 100%;
    max-width: 480px;
    padding: 16px;
    position: relative;
    @include box-shadow(1px 1px 2px rgba(0,0,0,0.15));
    &__send-statusbar {
        display: none;
        width: -webkit-calc(100% - 16px);
        width: -moz-calc(100% - 16px);
        width: calc(100% - 16px);
        height: -webkit-calc(100% - 16px);
        height: -moz-calc(100% - 16px);
        height: calc(100% - 16px);
        padding: 8px;
        @include border-radius(4px);
        position: absolute;
        top: 8px;
        left: 8px;
        z-index: 11;
        background: rgba(227,227,227,0.98);
        @include box-shadow(1px 1px 2px rgba(0,0,0,0.15));
    }
    &__send-statusbar-text-wr {
        @include flexbox();
        @include flex-direction(column);
        @include justify-content(center);
        width: 100%;
        height: 100%;
        text-align: center;
    }
    &__send-status {
        padding-bottom: 16px;
    }
    &__close-send-statusbar {
        width: 176px;
        padding: 2px 4px;
        border: 1px solid white;
        @include border-radius(4px);
        margin: 0 auto;
        text-decoration: none;
        color: white;
        &:hover {
            border-color: #333;
            color: #333;
        }
    }
    &__header {
        font: bold 16px 'pt sans', 'helvetica', 'roboto', 'trebuchet', sans-serif;
    }
    &__description {
        padding-bottom: 8px;
        font: normal 16px 'pt sans', 'helvetica', 'roboto', 'trebuchet', sans-serif;
    }
    &__label {
        display: inline-block;
        padding-bottom: 4px;
        color: #999;
    }
    &__input {
        display: block;
        width: 100%;
        height: 40px;
        padding: 2px 4px;
        @include border-radius(4px);
        border: 1px solid #ccc;
        margin: 0 0 20px;
        font: normal 16px 'pt sans', 'helvetica', 'roboto', 'trebuchet', sans-serif;
        &--hidden {
            display: none;
        }
        &--text {}
        &--textarea {
            height: 120px;
            resize: vertical;
        }
        &--submit {
            max-width: 320px;
            border: 1px solid #FFAB00;
            position: relative;
            font-weight: 700;
            background: white;
            color: #FFAB00;
            cursor: pointer;
            &:hover {
                background: #FFAB00;
                color: white;
            }
            &:active {
                width: -webkit-calc(100% - 2px);
                width: -moz-calc(100% - 2px);
                width: calc(100% - 2px);
                height: 38px;
                left: 1px;
                top: 1px;
            }
        }
    }
}


// BUTTONS

.button {
    display: block;
    border: 1px solid #333;
    @include border-radius(4px);
    font-family: 'pt sans', 'helvetica', 'roboto', 'trebuchet', sans-serif;
    color: #333;
    background: white;
    cursor: pointer;
    &:hover {
        border-color: #f29224;
        color: #f29224;
    }
    &:focus {
        border-color: #cc7d21;
        color: #cc7d21;
    }
    &:active {
        border-color: #cc7d21;
        color: #cc7d21;
    }
    &--sample-form {
        height: 40px;
        width: 136px;
        margin: 20px auto;
        font-weight: 700;
        font-size: 16px;
    }
    &--close-popup {
        height: 24px;
        width: 64px;
        position: absolute;
        top: 8px;
        right: 8px;
        font-weight: 400;
        font-size: 16px;
    }
}

JS

Здесь всё просто и понятно, думаю, лишних комментариев не требуется, а там где требуется они есть в коде.

$(document).ready(function() {
    
    // ПЕРЕМЕННЫЕ
    var delay = 5000; //Задержка для скрытия окна уведомления
    var okText             = 'Всё отлично. Письмо ушло.'; // Текст для успешной отправки сообщения
    var    doubleErrorText = 'Второй раз форму отправляешь.'; // Текст для попытки повторной отправки сообщения в короткий срок
    var    errorText         = 'Кажется форма сломалась. Скоро починю.'; // Текст для сообщения об ошибке
    var    phoneErrorText     = 'Ну хоть телефон укажи, чтобы форма отправилась'; // Текст если не заполнены обязательные поля
    
    
    // РАЗНЫЕ ФУНКЦИИ
    
    //Функции отображающие или скрывающие слой-перекрытие
    function show_overlayer() {
        $('.popup-overlayer').fadeIn(500);
    };
    function hide_overlayer() {
        $('.popup-overlayer').fadeOut(500);
    };
    //Функции отображающие или скрывающие конкретное всплывающее окно (в примере одно, а может быть много).
    function show_window_a() {
        show_overlayer();
        $('.popup-window--a').fadeIn(500);
    };
    function hide_popup() {
        $('.popup-window').fadeOut(500);
        hide_overlayer();
    };
    //Функции показывающие или скрывающие окно уведомления о статусе отправки формы
    function show_statusbar() {
        $('.form__send-statusbar').fadeIn(300);
    };
    function hide_statusbar() {
        $('.form__send-statusbar').fadeOut(300);
    };
    
    // ОБРАБОТЧИКИ КЛИКОВ
    
    $('.button--sample-form').click(function() {
        show_window_a();
    });
    
    $('.popup-overlayer').click(function() {
        hide_popup();
    });
    
    $('.button--close-popup').click(function() {
        hide_popup();
    });
    
    $('.form__close-send-statusbar').on('click',function(e){
        e.preventDefault();
        hide_statusbar();
    });
    
    
    // ОБРАБОТЧИК ФОРМЫ.
    
    $(".form--a").submit(function () {
            var control = $(".form--a input[name='name']").val();
        
            var phone   = $(".form--a input[name='phone']").val();
            var email   = $(".form--a input[name='email']").val();
            var text    = $(".form--a textarea[name='text']").val();

            if (phone !== '' && control == '' ) {
                $.post('/files/lab_files/feedback_sample.php', {
                    'phone': phone,
                    'email': email,
                    'text': text
                }, function (data) {
                if (data == 1) {
                    show_statusbar();
                    $('.form__send-statusbar').attr('sendstatus','1');
                    $('p.form__send-status').text(okText);        
                    setTimeout(hide_statusbar, delay);
                    setTimeout(hide_popup, delay);
                    } else {

                        if (data == 3) {
                            show_statusbar();
                            $('.form__send-statusbar').attr('sendstatus','2');
                            $('p.form__send-status').text(doubleErrorText);
                            setTimeout(hide_statusbar, delay);
                            setTimeout(hide_popup, delay);
                        } else {
                            show_statusbar();
                            $('.form__send-statusbar').attr('sendstatus','3');
                            $('p.form__send-status').text(errorText);
                            setTimeout(hide_statusbar, delay);
                        }

                }
                });
            return false;
            } else {
                show_statusbar();
                $('.form__send-statusbar').attr('sendstatus','4');
                $('p.form__send-status').text(phoneErrorText);
                setTimeout(hide_statusbar, delay);
                return false;
            }
    });
    // Конец обработчика формы
    
});

PHP

В обработчике формы, помимо стандартной функции отправки реализована функция, которая не позволяет в течение указанного времени отправить форму два раза подряд.

 <?php

ob_start();
session_start();
if (!isset($_SESSION['mail_send_tracker'])) {
    $_SESSION['mail_send_tracker'] = false;
} 
if (!isset($_SESSION['time_tracker'])) {
    $_SESSION['time_tracker'] = time();
} 

$can_send = !$_SESSION['mail_send_tracker'];

if (!$can_send) {
    if (time()-$_SESSION['time_tracker']>1*60) {
        $can_send = true;
    }
}


if ($can_send) {
    if (isset($_POST["text"]) && isset($_POST["phone"]) && isset($_POST["email"])) {

        $text = $_POST['text'];
        $phone = $_POST['phone'];
        $email = $_POST['email'];
        
        $text = stripslashes (htmlspecialchars($text));
        $phone = stripslashes (htmlspecialchars($phone));
        $email = stripslashes (htmlspecialchars($email));
        
        
        $from = 'Тестовое письмо из записи в лаборатории';
        $mailheaders = "Content-type: text/html; charset=utf-8 \r\n";
        $message = "<p>Телефон: $phone<br>
        Эл.почта: $email<br>
        Текст сообщения: $text</p>";
        $email_to = "mail@nikolaywerner.ru";
        
        if (mail($email_to,$from,$message,$mailheaders)) {
            $_SESSION['mail_send_tracker'] = true;
            $_SESSION['time_tracker'] = time();
            echo 1;
        } else {
            $_SESSION['mail_send_tracker'] = false;
            echo 0;
        }
    }

    

} else {

    $_SESSION['mail_send_tracker'] = true;
    echo 3;
}

?>

Форма в действии

comments powered by HyperComments