Skip to content

Основа для системы подсказок

Notifications You must be signed in to change notification settings

63pokupki/onboarding-core

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

32 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Onboarding

Ссылка на админку Onboarding

Логика работы:

  • Ондобрдинг показывается при первом заходе в корзину, далее, на бэк улетает токен, который проверяется при следующем входе в корзину. Если токен есть, онбординг не запускается.
  • Чтобы тестировать, необходимо залогинится под Маркетинг на деве и перейти в админку по ссылке выше. Далее, перевести шаблон в редактирование. Для этого, в списке страниц слева, выбрать необходимую страницу и справа от инпута "Идентификатор страницы" нажать на кнопку с карандашом.
  • Есть кэш
  • Токен хранится сутки, потом онбординг снова показывается один раз
  • Переход от шага к шагу происходит по селекторам(класс, индентификатор) на странице.
  • Чтобы определить правильно селектор на который будет переходить следующий шаг , можно использовать атрибут ID или специальный класс типа onboarding_cart_step_1, где 1 соответственно номер шага, этот момент нужно обговаривать с маркетингом.

Подключение

  1. В папке Common создаём папку Onboarding, в ней создаём файл Onboarding.ts(src/common/Onboarding/Onboarding.ts)
const introJs = require('@63pokupki/onboarding-core');
import axios from 'axios';
import { uuid } from 'uuidv4';
import { P63OnboardingStepI, IOnboardingEvents } from './OnboardingI';
import * as config from '@/config/MainConfig';
import { OnboardingNoAuthR } from '@/ifc/core/OnboardingNoAuthR';

/**
 * Подсказки по сайту для пользователей
 */
class Onboarding {
    /**
     * Стандартные настройки
     */
    public options = {
        tooltipClass: 'onboarding-base-steps',
        skipLabel: 'Пропустить',
        doneLabel: 'Закончить',
        nextLabel: 'Далее',
        hidePrev: true,
        hideNext: true,
        showProgress: true,
        showBullets: false,
        showStepNumbers: false,
        scrollTo: 'tooltip',
        disableInteraction: true,
        exitOnOverlayClick: false,
        touchpoint: 1024,
    };

    /**
     * Список шагов для сценария
     */
    public steps;

    /**
     * Идентификатор человека
     */
    public uuid;

    /**
     * Ключ идентификатора человека в localstorage
     */
    public uuidLocalStorageKey: string = 'onboarding_uuid';

    /**
     * Идентификатор готовности
     */
    public isReady: boolean = true;

    /**
     * Возможные ошибки
     */
    private _errors = {
        enviromentIsNotExist: 'Окружение исполнения не доступно',
        aliasIsNotExist: 'Идентификатор страницы не передан',
        scenarioIsNotExist: 'Сценарий для данной страницы отсутствует',
    };

    private intro;

    private scrollTo: Function;

    constructor(public alias: string, public events?: IOnboardingEvents) {
        this.intro = new introJs();
        this.scrollTo = scrollTo;
    }

    /**
     * Запуск сценария, основная функция
     */
    public play() {
        try {
            this.intro.start();

            this.initCloseButton();

            setTimeout(() => this.scrollTo(), 500);

            this.setOverflowProperty();
        } catch (e) {
            console.error(e);
        }
    }

    /**
     * Инициализация
     */
    public async init() {
        try {
            // проверка на готовность
            if (!this.isEnviromentExist()) {
                throw new Error(this._errors.enviromentIsNotExist);
            }

            // проверка на идентификатор страницы
            if (!this.alias) {
                throw new Error(this._errors.aliasIsNotExist);
            }

            // получение uuid
            this.getUUID();

            // получение сценария с сервера
            await this.getStepsView();

            // сценария нет
            if (!this.steps) {
                console.log(this._errors.scenarioIsNotExist);
                return;
            }

            this.intro = this.fUpdatePropertiesStepByStepHook();

            return true;
        } catch (e) {
            console.error(e);
            return false;
        }
    }

    /**
     * Получение и установка uuid
     */
    private getUUID() {
        try {
            // uuid существует
            const existedId = localStorage.getItem(this.uuidLocalStorageKey);
            if (existedId) {
                this.uuid = existedId;
                return existedId;
            }

            // uuid не существует, генерируем
            const id = uuid();
            localStorage.setItem(this.uuidLocalStorageKey, id);
            this.uuid = id;
            return id;
        } catch (e) {
            console.error(e);
        }
    }

    /**
     * Установка uuid
     */
    private setUUID(id) {
        try {
            localStorage.setItem(this.uuidLocalStorageKey, id);
        } catch (e) {
            console.error(e);
        }
    }

    /**
     * Проверка на доступность среды
     */
    private isEnviromentExist() {
        if (window && window.document) {
            return true;
        }

        return false;
    }

    /**
     * Получить шаги для отображения пользователю
     */
    private async getStepsView() {
        try {
            const options = {
                obkey: this.uuid,
                alias: this.alias,
            };

            // const {
            //     data: { is_active, list_m_step, list_d_step, obkey },
            // }
            let is_active = null;
            let list_m_step = null;
            let list_d_step = null;
            let obkey = null;
            await axios
                .post(config.coreApi.baseURL + OnboardingNoAuthR.listStep.route, options)
                .then(function(response) {
                    is_active = response.data.data.is_active;
                    list_m_step = response.data.data.list_m_step;
                    list_d_step = response.data.data.list_d_step;
                    obkey = response.data.data.obkey;
                })
                .catch(function(error) {
                    console.log(error);
                });

            // переназначаем uuid в случае если пользователь сменился (уменьшает кол-во запросов к бд на беке)
            if (obkey) {
                this.setUUID(obkey);
            }

            // если сценарий не должен запуститься ничего не возвращаем
            if (!is_active) {
                return;
            }

            let steps = null;

            // определение ширины устройства
            if (this.isTouchDevice()) {
                if (list_m_step.length == 0) {
                    return;
                }
                steps = this.transformStepsForLibrary(list_m_step);
            } else {
                if (list_d_step.length == 0) {
                    return;
                }
                steps = this.transformStepsForLibrary(list_d_step);
            }

            this.steps = steps;

            return steps;
        } catch (e) {}
    }

    private transformStepsForLibrary(steps: P63OnboardingStepI[]) {
        try {
            const sorted_steps = steps.sort((a, b) => a.step_number - b.step_number);

            return sorted_steps.map(step => {
                return {
                    intro: step.text || 'Текст отсутствует',
                    element: step.selector ? this.getElement(step.selector) : null,
                    tooltipClass: step.tpl || this.options.tooltipClass,
                    skipLabel: step.btn_skip || this.options.skipLabel,
                    doneLabel: step.btn_end || this.options.doneLabel,
                    nextLabel: step.btn_next || this.options.nextLabel,
                    beforeStep: step.event_before,
                    afterStep: step.event_after,
                };
            });
        } catch (e) {
            console.error(e);
        }
    }

    /**
     * Определение режима показа - мобильные/десктоп
     */
    private isTouchDevice() {
        try {
            const w = document.documentElement.clientWidth;

            if (w <= this.options.touchpoint) {
                return true;
            } else {
                return false;
            }
        } catch (e) {
            console.error(e);
        }
    }

    /**
     * Проверка видимости (существования) элемента
     * @param {} element - элемент
     */
    private isElementExist(element) {
        try {
            if (!element) {
                throw new Error('Элемент не передан');
            }

            const { height, width } = element.getBoundingClientRect();

            if (height !== 0 && width !== 0) {
                return true;
            } else {
                return false;
            }
        } catch (e) {
            console.error(e);
        }
    }

    /**
     * Получение видимого элемента по css селектору
     * @param {String} selector - css валидный селектор
     */
    private getElement(selector) {
        try {
            if (!selector) {
                throw new Error('Селектор не передан');
            }

            const elements = Array.prototype.slice.call(document.querySelectorAll(selector));

            const visibleElement = elements.find(el => this.isElementExist(el));

            if (!visibleElement) {
                console.log('Элемент: ' + selector + ' не найден');
                return;
            }

            return visibleElement;
        } catch (e) {
            console.error(e);
        }
    }

    /**
     * Обновление настроек под каждый шаг подсказок, смена текста, оформления и тд
     */
    private fUpdatePropertiesStepByStepHook() {
        try {
            const self = this;
            // установка стандартных настроек
            self.intro.setOptions({
                ...self.options,
                steps: self.steps,
            });

            // переопределение настроек под каждый шаг
            self.intro.onbeforechange(() => {
                let step = self.steps[self.intro._currentStep];

                self.intro.setOptions({
                    ...self.options,
                    nextLabel: step.nextLabel || self.options.nextLabel,
                    doneLabel: step.doneLabel || self.options.doneLabel,
                    skipLabel: step.skipLabel || self.options.skipLabel,
                    tooltipClass: step.tooltipClass || self.options.tooltipClass,
                });

                // хук для события перед показом шага
                if (self.events && step.beforeStep) {
                    if (self.events.hasOwnProperty(step.beforeStep)) {
                        self.events[step.beforeStep]();
                    }
                }
            });

            // переопределение настроек под каждый шаг
            self.intro.onafterchange(() => {
                let step = self.steps[self.intro._currentStep];

                // хук для события после показа шага
                if (self.events && step.afterStep) {
                    if (self.events.hasOwnProperty(step.afterStep)) {
                        self.events[step.afterStep]();
                    }
                }
            });

            return self.intro;
        } catch (e) {
            console.error(e);
        }
    }

    /**
     * Инициализация кнопки Закрыть
     */
    private initCloseButton() {
        try {
            let el = document.querySelector('.introjs-tooltip');

            // создание иконки крестика
            let icon = document.createElement('i');
            icon.className = 'ds-icon icon-close';

            // создание кнопки
            let close = document.createElement('button');
            close.append(icon);
            close.className = `introjs-tooltip__close`;
            close.addEventListener('click', () => this.intro.exit(true));

            // добавление кнопки
            if (el) {
                el.append(close);
            }
        } catch (e) {
            console.error(e);
        }
    }

    private setOverflowProperty() {
        try {
            let el = document.querySelector('.introjs-tooltip');

            if (!el || !this.isTouchDevice()) {
                return;
            }

            el.scrollTop = 0;
        } catch (e) {
            console.error(e);
        }
    }
}

/**
 * Прокрутка
 * @param {Number} x - координата X прокрутки
 * @param {Number} y - координата Y прокрутки
 */
export const scrollTo = (x: number = 0, y: number = 0) => {
    try {
        const options: ScrollToOptions = {
            top: x,
            left: y,
            behavior: 'smooth',
        };

        setTimeout(() => {
            window.scrollTo(options);
        }, 25);
    } catch {
        window.scrollTo(x, y);
    }
};

export default Onboarding;
  1. Далее, там же, создаём файл OnboardingI.ts(src/common/Onboarding/OnboardingI.ts):
/**
 * Набор событий, котоыре могут быть выполнены перед/после шага
 */
export interface IOnboardingEvents {
    [event: string]: Function;
}

/**
 * Интерфейс таблицы Onboarding - шаги подсказок на странице
 */
export interface P63OnboardingStepI {
    id?: number; // ID
    onboarding_page_id?: number; // ID страницы
    name?: string; // понятное имя шага - например welcome / 1 шаг
    text?: string; // html - текст шага
    step_number?: number; // номер шага
    tpl?: string; // шаблон - внешний вид шага - css селектор
    selector?: string; // идентификатор класса или id елемена на странице на который навешан шаг
    type?: string; // шаг цепочки версии (мобильной или десктопной
    btn_view?: string; // текст кнопки просмотр
    btn_next?: string; // текст кнопки далее
    btn_skip?: string; // текст кнопки пропустить
    btn_end?: string; // текст кнопки закрыть',
    event_before?: string; // JS событие срабатывающее до отображения шага
    event_after?: string; // JS событие срабатывающее после скрытия шага
}

  1. Добавляем роуты src/ifc/core/OnboardingAdminR.ts

import { P63OnboardingPageIxI, P63OnboardingPageI } from './EntitySQL/P63OnboardingPageE';
import { P63OnboardingStepI } from './EntitySQL/P63OnboardingStepE';
import { P63OnboardingTplI } from './EntitySQL/P63OnboardingTplE';

/**
 * Онбординг модуль администратора
 */
export namespace OnboardingAdminR {
    export const Alias = 'OnboardingAdmin';

    // =======================================================
    /** Получить список страниц */
    export namespace listPage {

        /** APIURL */
        export const route = '/onboarding-admin/list-page';

        /** Alias действия */
        export const action = 'list-page';

        /** Параметры api запроса */
        export interface RequestI {
        }

        /** Параметры api ответа */
        export interface ResponseI {
            list_page: P63OnboardingPageI[];
        }
    }

    // =======================================================
    /** цепочку подсказок страницы */
    export namespace onePage {

        /** APIURL */
        export const route = '/onboarding-admin/one-page';

        /** Alias действия */
        export const action = 'one-page';

        /** Параметры api запроса */
        export interface RequestI {
            onboarding_page_id: number;
        }

        /** Параметры api ответа */
        export interface ResponseI {
            one_page: P63OnboardingPageIxI;
        }
    }

    // =======================================================
    /** Добавить страницу */
    export namespace addPage {

        /** APIURL */
        export const route = '/onboarding-admin/add-page';

        /** Alias действия */
        export const action = 'add-page';

        /** Параметры api запроса */
        export interface RequestI {
            name: string; // Понятно имя страницы
            alias: string; //  Псевдоним страницы
        }

        /** Параметры api ответа */
        export interface ResponseI {
            onboarding_page_id: number;
            one_page: P63OnboardingPageI;
        }
    }

    // =======================================================
    /** Создать страницу черновик */
    export namespace addPageTest {

        /** APIURL */
        export const route = '/onboarding-admin/add-page-test';

        /** Alias действия */
        export const action = 'add-page-test';

        /** Параметры api запроса */
        export interface RequestI {
            alias: string; //  Псевдоним страницы
        }

        /** Параметры api ответа */
        export interface ResponseI {
            onboarding_page_id: number;
            one_page: P63OnboardingPageI;
        }
    }

    // =======================================================
    /** Сделать тестовую страницу по умолчанию */
    export namespace makePageTestByDefault {

        /** APIURL */
        export const route = '/onboarding-admin/make-page-test-by-default';

        /** Alias действия */
        export const action = 'make-page-test-by-default';

        /** Параметры api запроса */
        export interface RequestI {
            alias: string; //  Псевдоним страницы
        }

        /** Параметры api ответа */
        export interface ResponseI {
            one_page: P63OnboardingPageIxI;
        }
    }

    // =======================================================
    /** Сохранить основные параметры цепочки */
    export namespace savePage {

        /** APIURL */
        export const route = '/onboarding-admin/save-page';

        /** Alias действия */
        export const action = 'save-page';

        /** Параметры api запроса */
        export interface RequestI {
            onboarding_page_id: number; // ID По которуму сохраняется страница
            name?: string; // понятное имя страницы
            descript?: string; // Описание
        }

        /** Параметры api ответа */
        export interface ResponseI {
            one_page: P63OnboardingPageI;
        }
    }

    // =======================================================
    /** Удалить страницу */
    export namespace delPage {

        /** APIURL */
        export const route = '/onboarding-admin/del-page';

        /** Alias действия */
        export const action = 'del-page';

        /** Параметры api запроса */
        export interface RequestI {
            alias: string;
        }

        /** Параметры api ответа */
        export interface ResponseI {
            one_page: P63OnboardingPageI;
        }
    }

    // =======================================================
    /** Удалить тестовую цепочку */
    export namespace delPageTest {

        /** APIURL */
        export const route = '/onboarding-admin/del-page-test';

        /** Alias действия */
        export const action = 'del-page-test';

        /** Параметры api запроса */
        export interface RequestI {
            alias: string;
        }

        /** Параметры api ответа */
        export interface ResponseI {
            one_page: P63OnboardingPageI;
        }
    }

    // =======================================================
    /** Получить список шагов цепочки */
    export namespace listStep {

        /** APIURL */
        export const route = '/onboarding-admin/list-step';

        /** Alias действия */
        export const action = 'list-step';

        /** Параметры api запроса */
        export interface RequestI {
            alias: string; // Псевдоним страницы
            is_test: boolean; // тестовая цепочка?
            type: string; // mobile|desktop
        }

        /** Параметры api ответа */
        export interface ResponseI {
            list_step: P63OnboardingStepI[];
        }
    }

    // =======================================================
    /** добавить шаблон шаблонов */
    export namespace addTpl {

        /** APIURL */
        export const route = '/onboarding-admin/add-tpl';

        /** Alias действия */
        export const action = 'add-tpl';

        /** Параметры api запроса */
        export interface RequestI {
            name:string; // Название шаблона
            tpl:string; // CSS селектор для шаблона в дизайн системе
        }

        /** Параметры api ответа */
        export interface ResponseI {
            onboarding_tpl_id: number;
            one_onboarding_tpl: P63OnboardingTplI;
        }
    }

    // =======================================================
    /** сохранить шаблон */
    export namespace saveTpl {

        /** APIURL */
        export const route = '/onboarding-admin/save-tpl';

        /** Alias действия */
        export const action = 'save-tpl';

        /** Параметры api запроса */
        export interface RequestI {
            onboarding_tpl_id: number;
            name:string; // Название шаблона
            tpl:string; // CSS селектор для шаблона в дизайн системе
        }

        /** Параметры api ответа */
        export interface ResponseI {
            one_onboarding_tpl: P63OnboardingTplI;
        }
    }

    // =======================================================
    /** Получить список шаблонов */
    export namespace listTpl {

        /** APIURL */
        export const route = '/onboarding-admin/list-tpl';

        /** Alias действия */
        export const action = 'list-tpl';

        /** Параметры api запроса */
        export interface RequestI {
        }

        /** Параметры api ответа */
        export interface ResponseI {
            list_tpl:P63OnboardingTplI[];
        }
    }

    // =======================================================
    /** удалить шаблон */
    export namespace delTpl {

        /** APIURL */
        export const route = '/onboarding-admin/del-tpl';

        /** Alias действия */
        export const action = 'del-tpl';

        /** Параметры api запроса */
        export interface RequestI {
            onboarding_tpl_id:number;
        }

        /** Параметры api ответа */
        export interface ResponseI {
        }
    }

    // =======================================================
    /** Добавить шаг цепочки */
    export namespace addStep {

        /** APIURL */
        export const route = '/onboarding-admin/add-step';

        /** Alias действия */
        export const action = 'add-step';

        /** Параметры api запроса */
        export interface RequestI {
            onboarding_page_id: number;
            name: string; // Имя шага
            step_number: number; // Номер шага
            type: string; // mobile|desktop
        }

        /** Параметры api ответа */
        export interface ResponseI {
            step_id: number;
            one_step: P63OnboardingStepI;
        }
    }

    // =======================================================
    /** Удалить шаг цепочки */
    export namespace delStep {

        /** APIURL */
        export const route = '/onboarding-admin/del-step';

        /** Alias действия */
        export const action = 'del-step';

        /** Параметры api запроса */
        export interface RequestI {
            onboarding_step_id: number;
        }

        /** Параметры api ответа */
        export interface ResponseI {
        }
    }

    // =======================================================
    /** Сохранить шаг цепочки */
    export namespace saveStep {

        /** APIURL */
        export const route = '/onboarding-admin/save-step';

        /** Alias действия */
        export const action = 'save-step';

        /** Параметры api запроса */
        export interface RequestI {
            onboarding_step_id: number; // ID шага по которому сохраняется запись
            name?: string; // понятное имя шага - например welcome / 1 шаг
            text?: string; // html - текст шага
            step_number?: number; // номер шага
            event_before?: string; // JS событие срабатывающее до отображения шага
            event_after?: string; // JS событие срабатывающее после скрытия шага
            onboarding_tpl_id?: number; // шаблон - внешний вид шага - css селектор
            selector?: string; // идентификатор класса или id елемена на странице на который навешан шаг
            type?: string; // шаг цепочки версии (мобильной или десктопной
            btn_view?: string; // текст кнопки просмотр
            btn_next?: string; // текст кнопки далее
            btn_skip?: string; // текст кнопки пропустить
            btn_end?: string;// текст кнопки закрыть',
        }

        /** Параметры api ответа */
        export interface ResponseI {
            one_step: P63OnboardingStepI;
        }
    }

}

///

  • src/ifc/core/OnboardingNoAuthR.ts

import { P63OnboardingPageIxI, P63OnboardingPageI } from './EntitySQL/P63OnboardingPageE';
import { P63OnboardingStepI } from './EntitySQL/P63OnboardingStepE';

/**
 * Онбоардинг модуль пользователя
 */
export namespace OnboardingNoAuthR {
    export const Alias = 'OnboardingNoAuth';

    // =======================================================
    /** Получить список шагов цепочки */
    export namespace listStep {

        /** APIURL */
        export const route = '/onboarding-no-auth/list-step';

        /** Alias действия */
        export const action = 'list-step';

        /** Параметры api запроса */
        export interface RequestI {
            obkey: string; // onboarding key
            alias: string; // Псевдоним страницы
        }

        /** Параметры api ответа */
        export interface ResponseI {
            is_active: boolean; // Показывать или нет
            obkey: string; // Фронтовый или новый токен если фронтовый не актуальный
            list_m_step: P63OnboardingStepI[]; // Шаги для мобильной версии
            list_d_step: P63OnboardingStepI[]; // Шаги для десктопной версии
        }
    }

    // =======================================================
    /** Инкрементировать действие пользователя */
    export namespace incrAction {

        /** APIURL */
        export const route = '/onboarding-no-auth/incr-action';

        /** Alias действия */
        export const action = 'incr-action';

        /** Параметры api запроса */
        export interface RequestI {
            obkey: string; // onboarding key
            alias: string; // Псевдоним страницы
            next?: boolean; // 0/1 - Продолжить
            skip?: boolean; // 0/1 - Пропустить
            view?: boolean; // 0/1 - Посмотреть
            end?: boolean; // 0/1 - Закрыть
        }

        /** Параметры api ответа */
        export interface ResponseI {
        }
    }

}

///

  1. Интерфейсы
  • src/ifc/core/EntitySQL/P63OnboardingPageE.ts

/**
 * Интерфейс таблицы Onboarding - подсказок на странице
 */
export interface P63OnboardingPageIxI {
    id?: number; // ID
    name?: string; // понятное имя страницы
    alias?: string; // Ключ страницы
    is_test?: boolean; // Тестовая цепочка?
}

/**
 * Интерфейс таблицы Onboarding - подсказок на странице
 */
export interface P63OnboardingPageI {
    id?: number; // ID
    name?: string; // понятное имя страницы
    alias?: string; // Ключ страницы
    descript?: string; // Описание
    is_test?: boolean; // Тестовая цепочка?
}

///

Интерфейсы шагов

  • src/ifc/core/EntitySQL/P63OnboardingStepE.ts

/**
 * Интерфейс таблицы Onboarding - шаги подсказок на странице
 */
export interface P63OnboardingStepI {
    id?: number; // ID
    onboarding_page_id?: number; // ID страницы
    name?: string; // понятное имя шага - например welcome / 1 шаг
    text?: string; // html - текст шага
    step_number?: number; // номер шага
    event_before?: string; // JS событие срабатывающее до отображения шага
    event_after?: string; // JS событие срабатывающее после скрытия шага
    onboarding_tpl_id?: number; // шаблон - внешний вид шага - css селектор
    selector?: string; // идентификатор класса или id елемена на странице на который навешан шаг
    type?: string; // шаг цепочки версии (мобильной или десктопной
    btn_view?: string; // текст кнопки просмотр
    btn_next?: string; // текст кнопки далее
    btn_skip?: string; // текст кнопки пропустить
    btn_end?: string;// текст кнопки закрыть',
}


///

Интерфейсы токена

  • src/ifc/core/EntitySQL/P63OnboardingTokenE.ts
/**
 * Интерфейс таблицы Onboarding - подсказок на странице
 */
export interface P63OnboardingTokenIxI {
    id?: number; // ID
    alias?: string; // Ключ страницы
    token?: string; // Тестовая цепочка?
    user_id?: number; // ID пользователя
}

/**
 * Интерфейс таблицы Onboarding - подсказок на странице
 */
export interface P63OnboardingTokenI {
    id?: number; // ID
    alias?: string; // Псевдоним страницы для onboarding
    token?: string; // obkey - токен для onboarding
    user_id?: number; // ID пользователя
    show_counter?: number; // Счетчик показов
    view?: number; // Счетчик - Просмотренно
    next?: number; // Счетчик - Далее
    skip?: number; // Счетчик - Пропустить
    end?: number; // Счетчик - Закрыть
    created_at?: string; // Дата создания
    updated_at?: string; // Дата обновления
}

Интерфейс таблицы

  • src/ifc/core/EntitySQL/P63OnboardingTplE.ts
/**
 * Интерфейс таблицы Onboarding - подсказок на странице
 */
export interface P63OnboardingTplI {
    id?: number; // ID
    name?: string; // Имя шаблона
    tpl?: string; // шаблон
}

///

Инициализация

  • Необходимо подключить библиотеку @63pokupki/onboarding-core
  • Лучшее место для подключения подсказок, при инициализации страницы в методе init в контролере
  • Пример инициализации подсказок(проект client.front src/pages/cart/view/ctrl_cart.ts):
...
import Onboarding from '@/common/Onboarding/Onboarding';
import { PurchaseStatusT } from '@/ifc/core/EntitySQL/PurchaseE';

export class CartCtrl extends BaseCtrl {
    public conf = conf;

    public status: CartStoreI.Status = gVuexSys.registerModuleStatus(new CartStoreI.Status());
    public error: CartStoreI.Error = gVuexSys.registerModuleError(new CartStoreI.Error());
    public list: CartStoreI.List = gVuexSys.registerModuleList(new CartStoreI.List());
    public tree: CartStoreI.Tree = gVuexSys.registerModuleTree(new CartStoreI.Tree());
    public cmd: CartStoreI.Cmd = gVuexSys.registerModuleCmd(new CartStoreI.Cmd());
    public one: CartStoreI.One = gVuexSys.registerModuleOne(new CartStoreI.One());
    public ix: CartStoreI.Ix = gVuexSys.registerModuleIx(new CartStoreI.Ix());

    private querySys: QuerySys = null;

    constructor(vuexSys: VuexSys) {
        super(vuexSys);

        this.querySys = new QuerySys();
        this.querySys.fConfig(conf.coreApi);
    }

    /** Инициализация страницы */
    public async fInit() {
        if (this.status.curr_tab === CartN.TabsT.active) {
            this.fGetListActiveInvoice()

        } else {
            this.fGetListArchiveInvoice();
        }

        const onboarding = new Onboarding('onboarding_cart_page');
        if (this.status.cart_owner_user_id ) {
            this.fGetUserData();
        }
        await Promise.all([
			this.fGetListFavoriteStockID(),
            // Получить баннеры
            this.fGetListBanner(),
            // Получить топ подборки
            this.fGetListTopSale(),
            this.fGetListTopItemByCategory(),
            this.fGetListTopItemByStock(),
            // Получить организаторов для поиска
            this.fGetListOrgUser(),
            onboarding.init()
		])
        onboarding.play();
    }
    ...

Импортируем в инит файле

  • src/pages/cart/view/init_cart.ts
import "@63pokupki/onboarding-core/index.css"
import "@63pokupki/onboarding-core/index.js"

Стилизация

Все стили лежат в дизайн системе

Если что то съехало или необходимо изменить позиционирование, всё это необходимо делать в дизайн системе.

Возможные проблемы

  • Подсказка всплывает, но не указывает на нужный элемент. Вероятнее всего не указан селектор или указан не верно(в админке).
  • Подсказки не появляется.
    • Проверить проинициализирован ли онбординг на странице
    • Правильно ли указан ID страницы к которой привязан онбординг
    • Праписаны ли шаги в админке
  • Стили не подгрузились. Проверить, подключена ли дизайн система.

About

Основа для системы подсказок

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published