Source: widget/companionCore/data/Tour.js

(function() {
    /**
     * @typedef {Object} Help4.widget.tourlist.TileParams
     * @property {Object} _metadata
     * @property {Help4.widget.help.CatalogueKeys} _metadata.catalogueKey
     * @property {Help4.widget.help.CatalogueTypes} _metadata.catalogueType
     * @property {Help4.widget.help.DataTypes} _metadata.dataType
     * @property {string} _metadata.projectId
     * @property {Help4.widget.help.ContextTypes} _metadata.contextType
     * @property {string} controlType
     * @property {string} caption
     * @property {boolean} hidden
     * @property {Help4.widget.help.PUBLISHED_STATUS} status
     * @property {string} contentLanguage
     */

    /** tour functionality */
    Help4.widget.companionCore.data.Tour = class {
        /**
         * get tour projects
         * @param {Object} [params = {}]
         * @param {boolean} [params.whatsnew = false]
         * @param {?Help4.widget.help.CatalogueKeys} [params.catalogueKey = null]
         * @param {Help4.widget.help.CatalogueProject[]} [params.projects = null]
         * @returns {Help4.widget.help.CatalogueProject[]}
         */
        static getTourProjects({whatsnew = false, catalogueKey = null, projects = null} = {}) {
            const {widgetName, widget} = _getWidget(false);

            const context = widget.getContext();
            const {configuration} = context;

            const {Core} = Help4.widget.companionCore;
            catalogueKey ||= Core.getCatalogueKey({configuration});

            if (whatsnew) {
                return (projects || [])
                .sort(_sortTourProjects);
            } else {
                const {widget: {tourlist: {data}}} = context;

                return data.catalogues[catalogueKey]
                .map(projectId => data.getCatalogueProject(projectId, catalogueKey))  // projectId -> project
                .filter(project => !!project)  // remove null
                .sort(_sortTourProjects);
            }
        }

        /**
         * filter by conditions and hidden information
         * @param {Object} [params = {}]
         * @param {boolean} [params.whatsnew = false]
         * @param {?Help4.widget.help.CatalogueKeys} [params.catalogueKey = null]
         * @param {?Help4.widget.help.CatalogueProject[]} [params.projects = null]
         * @returns {Promise<Help4.widget.help.CatalogueProject[]>}
         */
        static async getFilteredTourProjects({whatsnew = false, catalogueKey = null, projects = null} = {}) {
            projects = this.getTourProjects({whatsnew, catalogueKey, projects});
            return await _filterTourProjects(projects, {whatsnew});
        }

        /**
         * convert projects into tile params for panel integration
         * @param {Help4.widget.help.CatalogueProject[]} projects
         * @param {Object} [params = {}]
         * @param {boolean} [params.whatsnew = false]
         * @returns {Help4.widget.tourlist.TileParams[]}
         */
        static tourProjectsToTileParams(projects, {whatsnew = false} = {}) {
            const {
                widget: {
                    companionCore: {Core},
                    help: {PUBLISHED_STATUS}
                },
                Placeholder
            } = Help4;

            const {widget} = _getWidget(whatsnew);

            const {
                /** @type {Help4.typedef.SystemConfiguration} */ configuration,
            } = widget.getContext();
            const {
                core: {/** @type {boolean} */ isEditorView},
                help: {/** @type {'uacp'|'wpb'|'ext'} */ serviceLayer}
            } = configuration;

            /**
             * clamp invalid to new as panel is unable to handle invalid
             * @param {Help4.widget.help.PUBLISHED_STATUS} published
             * @returns {Help4.widget.help.PUBLISHED_STATUS}
             */
            const getStatus = published => published === PUBLISHED_STATUS.invalid ? PUBLISHED_STATUS.new : published;

            const catalogueKey = Core.getCatalogueKey({configuration});
            const tileParams = /** @type {Help4.widget.tourlist.TileParams[]} */ [];

            for (const project of projects) {
                const {id, title, published, hidden, language, _dataType, _catalogueType, contextType} = project;

                const status = _dataType === 'SEN' && isEditorView && (serviceLayer !== 'ext' || _catalogueType === 'SEN2')
                    ? (getStatus(published) || null)
                    : null;

                tileParams.push({
                    _metadata: {
                        catalogueKey,
                        catalogueType: _catalogueType,
                        dataType: _dataType,
                        projectId: id,
                        contextType
                    },
                    controlType: 'Help4.widget.tourlist.TileControl',
                    caption: Placeholder.resolve(title),
                    hidden,
                    status,
                    contentLanguage: language
                });
            }

            return tileParams;
        }
    }

    /**
     * get widget
     * @memberof Help4.widget.companionCore.data.Tour
     * @private
     * @param {boolean} whatsnew
     * @returns {{widgetName: string, widget: Help4.widget.whatsnew.Widget|Help4.widget.tourlist.Widget}}
     */
    function _getWidget(whatsnew) {
        const widgetName = whatsnew ? 'whatsnew' : 'tourlist';
        return {
            widgetName,
            widget: /** @type {Help4.widget.whatsnew.Widget|Help4.widget.tourlist.Widget} */ Help4.widget.getInstance(widgetName)
        }
    }

    /**
     * filter by conditions and hidden information
     * @memberof Help4.widget.companionCore.data.Tour
     * @private
     * @param {Help4.widget.help.CatalogueProject[]} projects
     * @param {Object} [params = {}]
     * @param {boolean} [params.whatsnew = false]
     * @returns {Promise<Help4.widget.help.CatalogueProject[]>}
     */
    async function _filterTourProjects(projects, {whatsnew = false} = {}) {
        const {widget} = _getWidget(whatsnew);
        const {
            /** @type {Help4.typedef.SystemConfiguration} */ configuration: {
                core: {isEditorView}
            },
            service: {/** @type {Help4.service.ConditionService} */ conditionService}
        } = widget.getContext();

        /** @type {Help4.widget.help.CatalogueProject[]} */ const filtered = [];
        /** @type {Array<Promise<void>>} */ const promises = [];

        for (const project of projects) {
            const {id, conditions, hidden} = project || {};

            // do not show hidden tours outside of edit mode / editor view
            if (!id || !isEditorView && hidden) continue;

            // filter by conditions
            const promise =  /** @type {Promise<void>} */ conditionService.checkConditions({conditions})
            .then(success => void (success && filtered.push(project)));

            promises.push(promise);
        }

        await Help4.Promise.all(promises);
        return filtered;
    }

    /**
     * sort tour project list by title
     * @memberof Help4.widget.companionCore.data.Tour
     * @private
     * @param {Help4.widget.help.CatalogueProject} project1
     * @param {Help4.widget.help.CatalogueProject} project2
     * @returns {number}
     */
    function _sortTourProjects({title: t1}, {title: t2}) {
        t1 = t1.toLowerCase();
        t2 = t2.toLowerCase();
        return t1 < t2 ? -1 : (t1 > t2 ? 1 : 0);
    }
})();