<!DOCTYPE html>
<html lang="en">
{{> head}}

<body>
    <div class="i_w">
        <div class="top">
            {{#if notice}}
                <crowdin-alert
                        id="notice"
                        title="{{notice.title}}"
                        {{#unless notice.icon}}
                            no-icon="true"
                        {{/unless}}
                        {{#if notice.type}}
                            type={{notice.type}}
                        {{/if}}
                        style="display: none; margin-bottom: 12px;"
                >
                    <div class="box-center">
                        <p class="m-0">{{{notice.content}}}</p>
                    </div>
                    {{#if notice.close}}
                        <crowdin-button onclick="closeAlert(this, 'notice')" class="dismiss-alert" icon>close</crowdin-button>
                    {{/if}}
                </crowdin-alert>
            {{/if}}
            {{#if checkSubscription}}
                <crowdin-alert id="subscription-info" no-icon="true" type="warning" style="display: none; margin-bottom: 12px;">
                    <div class="box-center">
                        <p class="m-0"></p>
                        <crowdin-button class="ml-1" primary onclick="window.open(subscriptionLink,'_blank')">Subscribe</crowdin-button>
                    </div>
                </crowdin-alert>
            {{/if}}
            <div id="buttons">
                <crowdin-button id="show-integration-btn" class="hidden" icon-before="arrow_back" onclick="showIntegration();">Integration</crowdin-button>
                <crowdin-button id="show-error-logs-btn" icon-before="list" onclick="showErrorLogs();">Error logs</crowdin-button>
                <crowdin-button icon-before="link" onclick="showPermissionsDialog()">Share</crowdin-button>
                {{#if infoModal}}
                    <crowdin-button icon-before="info" onclick="openModal(infoModal);">{{infoModal.title}}</crowdin-button>
                {{/if}}
                {{#if configurationFields}}
                    <crowdin-button icon-before="settings" onclick="openModal(settingsModal);fillSettingsForm();">Settings</crowdin-button>
                {{/if}}
                <crowdin-button
                    {{#unless isOwner}}
                        disabled
                        title="Only the owner can log out"
                    {{/unless}}
                    icon-before="account_circle"
                    onclick="integrationLogout()"
                >Log out</crowdin-button>
            </div>
        </div>
        <crowdin-simple-integration
                async-progress
                {{#if syncNewElements.crowdin}}
                    skip-crowdin-auto-schedule
                {{/if}}
                {{#if syncNewElements.integration}}
                    skip-integration-auto-schedule
                {{/if}}
                {{#or withCronSync.crowdin webhooks.crowdin}}
                    crowdin-schedule="true"
                {{/or}}
                {{#or withCronSync.integration webhooks.integration}}
                    integration-schedule="true"
                {{/or}}
                {{#if integrationOneLevelFetching}}
                    integration-one-level-fetching="true"
                {{/if}}
                {{#if integrationSearchListener}}
                    allow-integration-filter-change-listener="true"
                {{/if}}
                {{#if integrationPagination}}
                    integration-load-more-files="true"
                {{/if}}
                integration-name="{{name}}"
                integration-logo="logo.png"
                {{#if uploadTranslations}}
                  {{#if excludedTargetLanguages}}
                      integration-button-menu-items='[{"label":"Sync translations", "title":"Sync translations to Crowdin", "action":"uploadTranslations"}, {"label":"Select target languages", "title":"Upload file for translation into selected languages", "action":"excludedTargetLanguages"}]'
                  {{else}}
                      integration-button-menu-items='[{"label":"Sync translations", "title":"Sync translations to Crowdin", "action":"uploadTranslations"}]'
                  {{/if}}
                {{else}}
                  {{#if excludedTargetLanguages}}
                      integration-button-menu-items='[{"label":"Select target languages", "title":"Upload file for translation into selected languages", "action":"excludedTargetLanguages"}]'
                  {{/if}}
                {{/if}}
                {{#if filtering.crowdinLanguages}}
                crowdin-filter
                {{/if}}
        >
        </crowdin-simple-integration>
        <div id="user-errors" class="hidden">
            <crowdin-show-as-table
                    is-loading
                    id="user-errors-table"
                    is-searchable
                    total-records="25"
                    search-placeholder="Search something"
            ></crowdin-show-as-table>
            <crowdin-alert>This table displays the most recent error logs from the past month. Logs older than one month will be automatically deleted.</crowdin-alert>
        </div>
    </div>
    <crowdin-toasts></crowdin-toasts>
    <crowdin-async-progress
        cancelAsyncAction=""
    ></crowdin-async-progress>
    <crowdin-modal
        style="display: none;"
        id="subscription-modal"
        modal-width="50"
        close-button="false"
    >
        <div>
            <crowdin-alert type="warning">Subscribe to continue using the {{name}} app.</crowdin-alert>
        </div>
        <div slot="footer">
             <crowdin-button primary onclick="window.open(subscriptionLink,'_blank')">Subscribe</crowdin-button>
             <crowdin-button outlined onclick="window.open('https://crowdin.com/contacts','_blank')">Contact us</crowdin-button>
             <crowdin-button class="ml-10" secondary onclick="integrationLogout()">Log out</crowdin-button>
         </div>
    </crowdin-modal>

    <crowdin-modal
        style="display: none;"
        id="permissions-modal"
        modal-title="Share"
        close-button-title="Close"
        close-button
        body-overflow-unset
    >
        <div class="loader hidden">
            <crowdin-progress-indicator></crowdin-progress-indicator>
        </div>
        <div class="permissions-modal-content">
            <div class="select-users-block">
                <crowdin-users-select
                    allow-new-options
                    is-multi
                    is-searchable
                    id="users"
                    key="users"
                    label="Users"
                    help-text="Search for members by name, username, email, or invite new ones using their email."
                    is-position-fixed
                    onchange="inviteUsers()"
                    >
                </crowdin-select>
            </div>
            <div class="select-users-info">
                <div class="confirm-users-block mt-2 hidden">
                    <table>
                        <thead>
                            <tr>
                                <th style="width: 40%;">Access</th>
                                <th style="width: 35%;">Users</th>
                                <th class="status" style="width: 20%;">Upcoming changes</th>
                            </tr>
                        </thead>
                        <tbody>
                            {{#if hasOrganization}}
                                <tr class="organization-invite">
                                    <td>
                                        <crowdin-p>Registration in Organization</crowdin-p>
                                        <div class="permission-description"></div>
                                    </td>
                                    <td class="affected-users"></td>
                                    <td class="status"></td>
                                </tr>
                            {{/if}}
                            <tr class="project-invite">
                                <td>
                                    <crowdin-p>Project Manager Access</crowdin-p>
                                </td>
                                <td class="affected-users"></td>
                                <td class="status"></td>
                            </tr>
                            <tr class="application-settings-invite">
                                <td>
                                    <crowdin-p>Application Visibility Access</crowdin-p>
                                    <div class="permission-description"></div>
                                </td>
                                <td class="affected-users"></td>
                                <td class="status"></td>
                            </tr>
                            <tr class="application-credentials-invite">
                                <td>
                                    <crowdin-p>Access to the Integration</crowdin-p>
                                    <div class="permission-description">This provides access to sync files and modify the current integration settings.</div>
                                </td>
                                <td class="affected-users"></td>
                                <td class="status"></td>
                            </tr>
                        </tbody>
                    </table>
                </div>
                {{#if zenModeUrl}}
                    <div class="mt-2">
                        <crowdin-input
                            with-fixed-height
                            label="Zen Mode link"
                            help-text="This focused view allows you to concentrate solely on the Integrations section, eliminating other distractions."
                            value="{{zenModeUrl}}"
                            name="zenModeLink"
                            with-copy-button
                        ></crowdin-input>
                    </div>
                {{/if}}
            </div>
        </div>

        <div slot="footer">
            <crowdin-button id="confirm-users-btn" outlined onclick="inviteUsers(false)">Save</crowdin-button>
        </div>
    </crowdin-modal>

    {{#if excludedTargetLanguages}}
      <crowdin-modal
        modal-width="50"
        modal-title="Select Target Languages for Translation"
        id="excluded-languages"
      >
      </crowdin-modal>
    {{/if}}

    {{#if infoModal}}
        <crowdin-modal
            style="display: none;"
            id="info-modal"
            modal-width="50"
            modal-title="{{infoModal.title}}"
            close-button-title="Close"
        >
             <div>
                 {{{infoModal.content}}}
             </div>
        </crowdin-modal>
    {{/if}}

    {{#if configurationFields}}
        <crowdin-modal
            style="display: none;"
            id="settings-modal"
            body-overflow-unset="{{#checkLength configurationFields 3}}false{{else}}true{{/checkLength}}"
            modal-width="65"
            modal-title="Settings"
            close-button-title="Close"
        >
            <div class="loader hidden">
                <crowdin-progress-indicator></crowdin-progress-indicator>
            </div>
            <div id="modal-content">
                {{#each configurationFields}}
                    {{#if key}}
                        {{#ifeq type "checkbox"}}
                            <crowdin-checkbox
                                id="{{key}}-settings"
                                key="{{key}}"
                                label="{{label}}"
                                value="false"
                                use-switch
                                {{#if helpText}}
                                    help-text="{{helpText}}"
                                {{/if}}
                                {{#if helpTextHtml}}
                                    help-text-html="{{helpTextHtml}}"
                                {{/if}}
                                {{#ifeq defaultValue true}}
                                    checked="{{defaultValue}}"
                                {{/ifeq}}
                                {{#if dependencySettings}}
                                    data-dependency="{{dependencySettings}}"
                                {{/if}}
                            >
                            </crowdin-checkbox>
                        {{/ifeq}}
                        {{#ifeq type "select"}}
                            <crowdin-select
                                {{#if isMulti}}
                                    is-multi
                                    close-on-select="false"
                                {{/if}}
                                {{#if isSearchable}}
                                    is-searchable
                                {{/if}}
                                    id="{{key}}-settings"
                                    key="{{key}}"
                                    label="{{label}}"
                                {{#if helpText}}
                                    help-text="{{helpText}}"
                                {{/if}}
                                {{#if helpTextHtml}}
                                    help-text-html="{{helpTextHtml}}"
                                {{/if}}
                                {{#if dependencySettings}}
                                    data-dependency="{{dependencySettings}}"
                                {{/if}}
                                is-position-fixed
                            >
                                {{#each options}}
                                    <option
                                        {{#if ../defaultValue}}
                                            {{#ifeq ../defaultValue value}} selected {{/ifeq}}
                                            {{#in value ../defaultValue}} selected {{/in}}
                                        {{/if}}
                                        value="{{value}}">{{label}}
                                    </option>
                                {{/each}}
                            </crowdin-select>
                        {{/ifeq}}
                        {{#ifeq type "text"}}
                            <crowdin-input
                                id="{{key}}-settings"
                                label="{{label}}"
                                key="{{key}}"
                                with-fixed-height
                                {{#if helpText}}
                                    help-text="{{helpText}}"
                                {{/if}}
                                {{#if helpTextHtml}}
                                    help-text-html="{{helpTextHtml}}"
                                {{/if}}
                                {{#if dependencySettings}}
                                    data-dependency="{{dependencySettings}}"
                                {{/if}}
                                value="{{#if defaultValue}}{{defaultValue}}{{/if}}"
                            >
                            </crowdin-input>
                        {{/ifeq}}
                        {{#ifeq type "textarea"}}
                            <crowdin-textarea
                                id="{{key}}-settings"
                                label="{{label}}"
                                key="{{key}}"
                                {{#if helpText}}
                                    help-text="{{helpText}}"
                                {{/if}}
                                {{#if helpTextHtml}}
                                    help-text-html="{{helpTextHtml}}"
                                {{/if}}
                                {{#if dependencySettings}}
                                    data-dependency="{{dependencySettings}}"
                                {{/if}}
                                value="{{#if defaultValue}}{{defaultValue}}{{/if}}">
                            </crowdin-textarea>
                        {{/ifeq}}
                        {{#ifeq type "notice"}}
                            <crowdin-alert
                                {{#if noticeType}}
                                    type="{{noticeType}}"
                                {{/if}}
                                {{#if label}}
                                    title="{{label}}"
                                {{/if}}
                                {{#if noIcon}}
                                    no-icon="{{noIcon}}"
                                {{/if}}
                                {{#if dependencySettings}}
                                    data-dependency="{{dependencySettings}}"
                                {{/if}}
                            >
                              {{{helpText}}}
                            </crowdin-alert>
                        {{/ifeq}}
                    {{else}}
                        {{#if labelHtml}}
                            <crowdin-p
                                {{#if dependencySettings}}
                                    data-dependency="{{dependencySettings}}"
                                {{/if}}
                            >
                                {{{labelHtml}}}
                            </crowdin-p>
                        {{else}}
                            <crowdin-p
                                {{#if dependencySettings}}
                                    data-dependency="{{dependencySettings}}"
                                {{/if}}
                            >
                                {{label}}
                            </crowdin-p>
                        {{/if}}
                    {{/if}}
                    <div
                        style="padding: 8px"
                        {{#if dependencySettings}}
                            data-dependency="{{dependencySettings}}"
                        {{/if}}
                    ></div>
                {{/each}}
            </div>
            <div slot="footer">
                <crowdin-button id="settings-save-btn" outlined onclick="saveSettings()">Save</crowdin-button>
            </div>
        </crowdin-modal>
    {{/if}}
    {{#or syncNewElements.crowdin syncNewElements.integration}}
        <crowdin-modal
            style="display: none;"
            id="confirm-schedule-modal"
            modal-width="50"
            modal-title="Synchronization options"
            close-button-title="Close"
            close-button="true"
            body-overflow-unset
        >
            <crowdin-checkbox
                id="selected-files"
                name="selected-files"
                label="Selected files"
                class="hydrated"
                onchange="onChangeAutoSynchronizationOptions(this)"
            >
            </crowdin-checkbox>
            <crowdin-checkbox
                id="new-files"
                name="new-files"
                label="New files"
                class="hydrated"
                onchange="onChangeAutoSynchronizationOptions(this)"
            >
            </crowdin-checkbox>
            <div slot="footer">
                <crowdin-button outlined id="save-schedule-sync" onclick="saveScheduleSync()">Save</crowdin-button>
            </div>
        </crowdin-modal>
    {{/or}}

    <crowdin-modal
        style="display: none;"
        id="user-error-detail"
        close-button-title="Close"
        close-button="true"
    >
    </crowdin-modal>
</body>
<script type="text/javascript">
    document.body.addEventListener('refreshFilesList', (e) => {
        if (e.detail.refreshIntegration) {
            getIntegrationData(true);
        } else if (e.detail.refreshCrowdin) {
            getCrowdinData();
        }
    });
    document.body.addEventListener('crowdinFilesFolderToggled', (event) => {
        if (event.detail.componentId === 'crowdin-files' && event.detail.isOpen && event.detail.type === '1') {
            getFileProgress(event.detail.id);
        }
        {{#if integrationOneLevelFetching}}
            if (event.detail.componentId === 'integration-files' && event.detail.isOpen) {
                getIntegrationData(false, event.detail.id);
            }
        {{/if}}
    });
    document.body.addEventListener('uploadFilesToCrowdin', uploadFilesToCrowdin);
    document.body.addEventListener('uploadFilesToIntegration', uploadFilesToIntegration);
    document.body.addEventListener('cancelAsyncAction', (e) => {
      cancelJob(e.detail);
    });
    {{#if integrationSearchListener}}
        document.body.addEventListener("integrationFilterChange", (event) => {
            getIntegrationData(false, 0, event.detail);
        })
    {{/if}}
    const appComponent = document.querySelector('crowdin-simple-integration');
    const subscriptionModal = document.getElementById('subscription-modal');

    const folderType = '0';
    const fileType = '1';
    const branchType = '2';

    const JOB_TYPE = {
        updateCrowdin: 'updateCrowdin',
        updateIntegration: 'updateIntegration',
        integrationSyncSettingsSave: 'integrationSyncSettingsSave',
        crowdinSyncSettingsSave: 'crowdinSyncSettingsSave',
    };

    const JOB_STATUS = {
        created: 'created',
        inProgress: 'inProgress',
        failed: 'failed',
        canceled: 'canceled',
        finished: 'finished',
    };

    const silentJobs = [
        JOB_TYPE.integrationSyncSettingsSave,
        JOB_TYPE.crowdinSyncSettingsSave,
    ];

    const asyncJobs = {};

    let project = {};
    let crowdinData = [];
    let fileToSync = [];

    getCrowdinData();
    getIntegrationData();
    getActiveJobs();

    function integrationLogout() {
        checkOrigin()
            .then(queryParams => fetch(`api/logout${queryParams}`, { method: 'POST' }))
            .then(checkResponse)
            .then(reloadLocation)
            .then(localStorage.removeItem('revised_{{name}}'))
            .catch(e => catchRejection(e, e.error || 'Looks like you are not logged in'));
    }

    function getCrowdinData() {
        appComponent.setAttribute('is-crowdin-loading', true);
        checkOrigin()
            .then(restParams => fetch('api/crowdin/files' + restParams))
            .then(checkResponse)
            .then((res) => {
                const tree = res.map(e => {
                    const item = {
                        parent_id: e.parentId ? e.parentId : '0',
                        name: e.name,
                        id: e.id,
                        customContent: e.customContent,
                        labels: e.labels,
                    };
                    if (e.type) {
                        item.type = e.type;
                        item.node_type = fileType;
                        item.failed = e.failed;
                        item.excludedTargetLanguages = e.excludedTargetLanguages;
                    } else {
                        item.node_type = e.nodeType || folderType;
                    }
                    return item;
                });
                crowdinData = tree;
                appComponent.setCrowdinFilesData(tree);
                return checkOrigin();
            })
            .then(restParams => fetch('api/crowdin/project' + restParams))
            .then(checkResponse)
            .then((res) => {
                project = res;
                const languagesSorted = project.targetLanguages.map(language => ({
                  sourceLanguageId: res.sourceLanguage.editorCode,
                  projectEditorLink: res.projectEditorLink,
                  ...language,
                })).sort((a, b) => a.name.localeCompare(b.name));

                if (project.inContext && config?.inContext) {
                    languagesSorted.push({...project.inContextPseudoLanguage, inContext: true});
                }

                setLanguagesForTranslation(languagesSorted);

                appComponent.setCrowdinLanguagesData(languagesSorted)
            })
            {{#or withCronSync webhooks}}
                .then(() => getSyncSettings('crowdin'))
            {{/or}}
            .catch(e => catchRejection(e, 'Can\'t fetch Crowdin data'))
            .finally(() => (appComponent.setAttribute('is-crowdin-loading', false)));
    }

    function getIntegrationData(hardReload = false, parentId = '', search = '', page = 0) {
        appComponent.setAttribute('is-integration-loading', true);
        checkOrigin()
            .then(restParams => fetch(`api/integration/data${restParams}&parent_id=${encodeURIComponent(parentId)}&search=${encodeURIComponent(search)}&page=${page}`))
            .then(checkResponse)
            .then((res) => {
                const files = res.data;
                const stopPagination = res.stopPagination;
                const tree = files.map(e => {
                    const item = {
                        parent_id: e.parentId ? e.parentId : '0',
                        name: e.name,
                        id: e.id,
                        customContent: e.customContent,
                        labels: e.labels,
                    };
                    if (e.type) {
                        item.type = e.type;
                        item.node_type = fileType;
                    } else {
                        item.node_type = e.nodeType || folderType;
                    }
                    return item;
                });

                const appIntegrationFiles = appComponent.querySelector('#integration-files');
                if (hardReload) {
                    appComponent.setIntegrationFilesData(tree);
                } else if (tree.length) {
                    appComponent.pushIntegrationFilesData(tree).then(() => {
                        if (parentId) {
                            appIntegrationFiles.getSelected().then(async selection => {
                              const selectedIds = selection?.filter((node) => node).map(({id}) => id.toString());
                              const filteredNodes = tree.filter((node) => !selectedIds.includes(node.id.toString()) && selectedIds.includes(node.parent_id.toString()));

                              if (filteredNodes?.length) {
                                const filteredNodesId = filteredNodes.map(({id}) => id.toString());
                                await appIntegrationFiles.setSelected(filteredNodesId);
                              }
                            });
                        }
                    });
                }
                {{#if integrationPagination}}
                    if (stopPagination) {
                        appIntegrationFiles.setAttribute('load-more-disabled', true);
                    } else {
                        appIntegrationFiles.setAttribute('load-more-disabled', false);
                    }
                {{/if}}
                if (search) {
                    const openIds = files.filter(e => !e.type).map(e => e.id);
                    appComponent.setIntegrationOpenedFolders(openIds);
                }
            })
            {{#or withCronSync webhooks}}
                .then(() => getSyncSettings('integration'))
            {{/or}}
            .catch(e => catchRejection(e, 'Can\'t fetch {{name}} templates'))
            .finally(() => (appComponent.setAttribute('is-integration-loading', false)));
    }

    function getSyncSettings(provider) {
        checkOrigin()
            .then(restParams => fetch(`/api/sync-settings/${provider}` + restParams))
            .then(checkResponse)
            .then((res) => {
                if (provider === 'crowdin') {
                    {{#if syncNewElements.crowdin}}
                        appComponent.setCrowdinScheduleSync(res, true, true);
                    {{else}}
                        appComponent.setCrowdinScheduleSync(res);
                    {{/if}}
                } else {
                    {{#if syncNewElements.integration}}
                        appComponent.setIntegrationScheduleSync(res, true, true);
                    {{else}}
                        appComponent.setIntegrationScheduleSync(res);
                    {{/if}}

                }
            })
            .catch(e => catchRejection(e, 'Can\'t fetch file progress'));
    }

    function getFileProgress(fileId) {
        checkOrigin()
            .then(restParams => fetch(`api/crowdin/file-progress/${fileId}` + restParams))
            .then(checkResponse)
            .then((res) => (appComponent.addCrowdinFileProgress(res)))
            .catch(e => catchRejection(e, 'Can\'t fetch file progress'));
    }

    function uploadFilesToCrowdin(event, languages = []) {
        let files = [];
        let uploadTranslations = false;
        if (event.detail?.action === 'uploadTranslations') {
            files = event.detail.files;
            uploadTranslations = true;
        } else if (event.detail?.action === 'excludedTargetLanguages') {
          fileToSync = event.detail.files;
          openLanguageModal();
          return;
        } else {
            files = event.detail;
        }

        if (event.detail?.length === 0 || !event.detail) {
            showToast('Select templates which will be pushed to Crowdin');
            return;
        }
        appComponent.setAttribute('is-to-crowdin-process', true);
        let req;
        {{#if integrationOneLevelFetching}}
            req = files.map(f => ({
                name: f.name,
                id: f.id,
                type: f.type,
                parentId: f.parent_id,
                nodeType: f.node_type
            }));
        {{else}}
            req = files.filter(f => f.node_type !== folderType).map(f => ({
                name: f.name,
                id: f.id,
                type: f.type,
                parentId: f.parent_id
            }));
        {{/if}}
        checkOrigin()
            .then(restParams => fetch(`api/crowdin/update${restParams}&uploadTranslations=${uploadTranslations}&languages=${languages}`, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(req)
            }))
            .then(checkResponse)
            .then((res) => {
                checkJob({
                    jobId: res?.jobId,
                    jobType: JOB_TYPE.updateCrowdin,
                })
            })
            .catch(e => catchRejection(e, 'Can\'t upload templates to Crowdin'))
    }

    function getActiveJobs() {
        checkOrigin()
            .then(restParams => fetch(`api/jobs${restParams}`))
            .then(checkResponse)
            .then((jobs) => {
                if (!Array.isArray(jobs)) {
                  return;
                }

                jobs.forEach((job) => {
                    switch (job.type) {
                        case JOB_TYPE.updateCrowdin:
                            appComponent.setAttribute('is-to-crowdin-process', true);
                            break;
                        case JOB_TYPE.updateIntegration:
                            appComponent.setAttribute('is-to-integration-process', true);
                            break;
                        case JOB_TYPE.crowdinSyncSettingsSave:
                            appComponent.setAttribute(`is-crowdin-sync-settings-in-progress`, true)
                            break;
                        case JOB_TYPE.integrationSyncSettingsSave:
                            appComponent.setAttribute(`is-integration-sync-settings-in-progress`, true)
                            break;
                        default:
                    }

                    checkJob({
                        jobId: job.id,
                        jobType: job.type,
                    })
                })
            })
            .catch(e => catchRejection(e, 'Sync status check failed'))
    }

    function cancelJob(jobId) {
        if (asyncJobs[jobId]?.isFailed) {
            return;
        }

        checkOrigin()
            .then(restParams => fetch('api/jobs' + restParams + '&jobId=' + jobId, {
                method: 'DELETE',
                headers: { 'Content-Type': 'application/json' },
            }))
            .then(checkResponse)
            .then(() => showToast('Cancellation…'))
            .catch(e => catchRejection(e, 'Sync cancellation failed'));
    }

    function checkJob({jobId, jobType, onSuccess, onError, onFinally}) {
        switch (jobType) {
            case JOB_TYPE.updateCrowdin:
                if (!onSuccess) {
                    onSuccess = ((job) => {
                        getCrowdinData();
                    });
                }

                if (!onFinally) {
                    onFinally = (() => appComponent.setAttribute('is-to-crowdin-process', false));
                }
                break;
            case JOB_TYPE.updateIntegration:
                if (!onFinally) {
                    onFinally = (() => appComponent.setAttribute('is-to-integration-process', false));
                }
                break;
            case JOB_TYPE.crowdinSyncSettingsSave:
                if (!onFinally) {
                    onFinally = (() => appComponent.setAttribute(`is-crowdin-sync-settings-in-progress`, false));
                }
                break;
            case JOB_TYPE.integrationSyncSettingsSave:
                if (!onFinally) {
                    onFinally = (() => appComponent.setAttribute(`is-integration-sync-settings-in-progress`, false));
                }
                break;
            default:
        }

        checkOrigin()
            .then(restParams => fetch('api/jobs' + restParams + '&jobId=' + jobId))
            .then(checkResponse)
            .then((job) => {
                const isFailed = [JOB_STATUS.failed, JOB_STATUS.canceled].includes(job.status);
                const progress = isFailed || JOB_STATUS.finished === job.status ? 100 : job.progress;
                const info = JOB_STATUS.canceled === job.status ? `Cancelled\n${job.info || ''}` : job.info;

                !silentJobs.find((type) => type === jobType) && pushJobs([ {
                    id: job.id,
                    title: job.title,
                    progress,
                    info,
                    isFailed,
                } ]);

                if (isFailed) {
                    onError && onError();
                } else if ([JOB_STATUS.created, JOB_STATUS.inProgress].includes(job.status) && job.progress < 100) {
                    setTimeout(() => {
                        checkJob({jobId, jobType, onSuccess, onError, onFinally});
                    }, {{asyncProgress.checkInterval}});
                    return;
                } else {
                    onSuccess && onSuccess(job);
                }

                onFinally && onFinally(job);
            })
            .catch((e) => {
                onFinally && onFinally();

                !silentJobs.find((type) => type === jobType) && pushJobs([ {
                    id: jobId,
                    isFailed: true,
                } ]);

                showToast('Sync status check failed');
            });
    }

    function pushJobs(jobs) {
        const el = document.querySelector('crowdin-async-progress');
        if (el && el.pushJobs) {
            el.pushJobs(jobs);
            jobs.forEach((job) => (asyncJobs[job.id] = job));
        } else {
            setTimeout(() => {
                pushJobs(jobs);
            }, 300);
        }
    }

    function uploadFilesToIntegration(e) {
        if (Object.keys(e.detail).length === 0) {
            showToast('Select files which will be uploaded to {{name}}');
            return;
        }
        appComponent.setAttribute('is-to-integration-process', true);
        const req = {};
        Object.keys(e.detail)
            .filter(id => crowdinData.find(c => c.id === id).node_type === fileType)
            .forEach(id => (req[id] = e.detail[id]));
        checkOrigin()
            .then(restParams => fetch('api/integration/update' + restParams, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(req)
            }))
            .then(checkResponse)
            .then((res) => {
                checkJob({
                    jobId: res?.jobId,
                    jobType: JOB_TYPE.updateIntegration,
                })
            })
            .catch(e => catchRejection(e, 'Can\'t upload files to {{name}}'))
    }

    function openLanguageModal() {
      openModal(languageModal);
    }

    async function uploadFilesToCrowdinWithExcludedLanguages() {
      const languageSelect = document.querySelector('#language-select');
      const selectedLanguages = await languageSelect.getValue();
      closeModal(languageModal);
      uploadFilesToCrowdin({ detail: fileToSync }, selectedLanguages);
    }

    async function setLanguagesForTranslation(languages) {
      const languageIds = languages.map(language => language.id);
      if (languageModal) {
        let modalContent = `
      <div>
        <crowdin-select
          is-multi
          is-searchable
          is-position-fixed
          close-on-select="false"
          name="languages"
          id="language-select"
          label="Languages"
        >`;

        for (const language of languages) {
          modalContent += `<option value="${language.id}">${language.name}</option>`;
        }

        modalContent += `
        </crowdin-select>
        </div>
        <div slot="footer">
            <crowdin-button id="upload-exclude-languages" outlined onclick="uploadFilesToCrowdinWithExcludedLanguages()">
                <div class="integration-icon-button">
                  <span>Sync to</span>
                  <crowdin-logo is-icon/>
                </div>
            </crowdin-button>
        </div>
    `;

        languageModal.innerHTML = modalContent;

        const select = document.querySelector('#language-select')
        await select.setValue(languageIds);
      }
    }

    function hideConfirmUsersBlock() {
        const confirmUsersBlock = document.querySelector('.confirm-users-block');
        confirmUsersBlock.classList.add('hidden');

        const permissionsModal = document.getElementById('permissions-modal');
        permissionsModal.setAttribute('body-overflow-unset', true)
    }

    function showPermissionsDialog() {
        hideConfirmUsersBlock();
        openModal(permissions)
        setLoader('#permissions-modal');
        const select = document.getElementById('users');

        select.value = '[]';

        checkOrigin()
            .then(restParams => fetch('api/users' + restParams))
            .then(checkResponse)
            .then((res) => {
                let userOptions = res.data.users.map(user => `<option value="${user.id}">${sanitizeHTML(user.name)}</option>`).join('');
                select.innerHTML = userOptions;
                select.value = JSON.stringify(res.data.managers);
            })
            .catch(e => catchRejection(e, 'Can\'t fetch users'))
            .finally(() => unsetLoader('#permissions-modal'));
    }

    function showConfirmUsersBlock() {
        const confirmUsersBlock = document.querySelector('.confirm-users-block');
        confirmUsersBlock.classList.remove('hidden');

        const permissionsModal = document.getElementById('permissions-modal');
        permissionsModal.removeAttribute('body-overflow-unset')
    }

    async function inviteUsers(onlyCheck = true) {
        setLoader('#permissions-modal');

        const select = document.getElementById('users');

        if (onlyCheck && select.value === '[]') {
            hideConfirmUsersBlock();
            unsetLoader('#permissions-modal');
            return;
        }

        const params = {
            users: JSON.parse(select.value),
            onlyCheck,
        };

        checkOrigin()
            .then(restParams => fetch('api/invite-users' + restParams, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(params)
            }))
            .then(checkResponse)
            .then((response) => {
                if (!onlyCheck) {
                    showToast('Users successfully updated');
                    hideConfirmUsersBlock();
                    closeModal(permissions);
                    return;
                }

                prepareUsersConfirmBlock(response.data);
            })
            .catch(e => {
                catchRejection(e, e?.error || 'Can\'t invite users')
            })
            .finally(() => unsetLoader('#permissions-modal'));
    }

    function prepareUsersConfirmBlock(usersData) {
        showConfirmUsersBlock();

        const organizationInvite = document.querySelector('.organization-invite');
        const projectInvite = document.querySelector('.project-invite');
        const applicationCredentialsInvite = document.querySelector('.application-credentials-invite');

        const grantedElement = '<crowdin-p>&horbar;</crowdin-p>';
        const willGrantedElement = '<span class="badge badge-will-be-granted">Will Be Granted</span>';
        const notAvailableElement = '<span class="badge badge-not-available">Action Required</span>';

        // only in enterprise
        if (organizationInvite) {
            const organizationWillGrantElement = `<span class="badge badge-will-be-granted">Will Be Registered</span>`;

            processUsersWhoWillBeInvitedToOrganization(organizationInvite, usersData, organizationWillGrantElement, grantedElement, notAvailableElement);
        }

        processUsersWhoWillBeInvited(projectInvite, usersData.usersWhoWillBeInvitedToProject, willGrantedElement, grantedElement);
        processUsersWhoWillBeInvited(applicationCredentialsInvite, usersData.usersWhoNotIssetInIntegration, willGrantedElement, grantedElement);

        processUsersWhoWillBeInvitedApplicationSettings(usersData, willGrantedElement, grantedElement, notAvailableElement);
    }

    function processUsersWhoWillBeInvitedToOrganization(element, usersData, willGrantedElement, alreadyGrantedMessage, notAvailableElement) {
        const tooltip = element.querySelector('.status');
        const description = element.querySelector('.permission-description');
        const userList = element.querySelector('.affected-users');

        description.classList.remove('text-warning');
        description.innerText = '';

        const users = usersData.usersWhoWillBeInvitedToOrganization;

        if (users.length) {
            if (usersData.inviteRestricted) {
                description.classList.add('text-warning');
                description.innerText = 'New user invitations are restricted to administrators.';

                tooltip.innerHTML = notAvailableElement;
            } else {
                tooltip.innerHTML = willGrantedElement;
            }

            let affectedUsers = '<ul>';
            for (const user of users) {
                affectedUsers += `<li><crowdin-p>${sanitizeHTML(user.name)}</crowdin-p></li>`;
            }
            affectedUsers += '</ul>';
            userList.innerHTML = affectedUsers;
        } else {
            tooltip.innerHTML = alreadyGrantedMessage;
            userList.innerHTML = alreadyGrantedMessage;
        }
    }

    function processUsersWhoWillBeInvited(element, users, grantMessage, alreadyGrantedMessage) {
        const tooltip = element.querySelector('.status');
        const userList = element.querySelector('.affected-users');

        if (users.length) {
            tooltip.innerHTML = grantMessage;

            let affectedUsers = '<ul>';
            for (const user of users) {
                affectedUsers += `<li><crowdin-p>${sanitizeHTML(user.name)}</crowdin-p></li>`;
            }
            affectedUsers += '</ul>';
            userList.innerHTML = affectedUsers;
        } else {
            tooltip.innerHTML = alreadyGrantedMessage;
            userList.innerHTML = alreadyGrantedMessage;
        }
    }

    function processUsersWhoWillBeInvitedApplicationSettings(usersData, willGrantedElement, grantedElement, notAvailableElement) {
        const applicationSettingsInvite = document.querySelector('.application-settings-invite');

        const tooltip = applicationSettingsInvite.querySelector('.status');
        const description = applicationSettingsInvite.querySelector('.permission-description');
        const userList = applicationSettingsInvite.querySelector('.affected-users');

        let descriptionMessage = 'This can be configured in organization settings (Apps section).';
        description.classList.remove('text-warning');
        description.innerText = descriptionMessage;

        let affectedUsers = '<ul>';

        if (!usersData.editApplicationAvailable) {
            descriptionMessage += ' The application doesn\'t have permission to update this setting.';
            descriptionMessage += usersData.isAdmin ? ' Please reinstall the app.' : ' Please ask the organization admin to reinstall the app.';

            description.classList.add('text-warning');
            description.innerText = descriptionMessage;

            tooltip.innerHTML = notAvailableElement;
            for (const user of usersData.usersWhoNotIssetInApplicationInstallation) {
                affectedUsers += `<li><crowdin-p>${sanitizeHTML(user.name)}</crowdin-p></li>`;
            }
            userList.innerHTML = affectedUsers + '</ul>';
        } else if (!usersData.usersWhoNotIssetInApplicationInstallation.length) {
            tooltip.innerHTML = grantedElement;
            userList.innerHTML = grantedElement;
        } else {
            if (usersData.isAdmin) {
                tooltip.innerHTML = willGrantedElement;
                for (const user of usersData.usersWhoNotIssetInApplicationInstallation) {
                    affectedUsers += `<li><crowdin-p>${sanitizeHTML(user.name)}</crowdin-p></li>`;
                }
                userList.innerHTML = affectedUsers + '</ul>';
            } else {
                descriptionMessage += ' Only organization admins have permission to update this setting.';

                description.classList.add('text-warning');
                description.innerText = descriptionMessage;

                tooltip.innerHTML = notAvailableElement;
                for (const user of usersData.usersWhoNotIssetInApplicationInstallation) {
                    affectedUsers += `<li><crowdin-p>${sanitizeHTML(user.name)}</crowdin-p></li>`;
                }
                userList.innerHTML = affectedUsers + '</ul>';
            }
        }
    }

    function setLoader(id) {
        const loader = document.querySelector(`${id} .loader`);
        loader.classList.remove('hidden');
    }

    function unsetLoader(id) {
        const loader = document.querySelector(`${id} .loader`);
        setTimeout(function() {
            loader.classList.add('hidden');
        }, 500)
    }

    {{#if configurationFields}}
        const settingsModal = document.getElementById('settings-modal');
        const settingsSaveBtn = document.getElementById('settings-save-btn');
        let config = JSON.parse('{{{config}}}');
        const newCrowdinFiles = config?.['new-crowdin-files'];
        const newIntegrationFiles = config?.['new-integration-files'];

        function triggerEvent(el, type) {
            const e = document.createEvent('HTMLEvents');
            e.initEvent(type, false, true);
            el.dispatchEvent(e);
        }

        function fillSettingsForm() {
            Object.entries(config).forEach(([key, value]) => {
                const el = document.getElementById(`${key}-settings`);
                if (el && (value || el.tagName.toLowerCase() === 'crowdin-checkbox')) {
                    if (el.tagName.toLowerCase() === 'crowdin-select') {
                        if (el.hasAttribute('is-multi')) {
                            el.value = JSON.stringify(value);
                        } else {
                            el.value = JSON.stringify([value]);
                        }
                    } else if (el.tagName.toLowerCase() === 'crowdin-checkbox') {
                        el.checked = !!value;
                    } else {
                        el.value = value;
                    }

                    triggerEvent(el, 'change');
                }
            });
        }

        function saveSettings() {
            setLoader('#settings-modal');
            const settingsElements = Array.from(document.getElementById('modal-content').children);
            const tags = ['crowdin-checkbox', 'crowdin-select', 'crowdin-input'];
            const configReq = {};
            settingsElements
                .filter(e => tags.includes(e.tagName.toLowerCase()))
                .forEach(e => {
                    const key = e.getAttribute('key');
                    let value;
                    if (e.tagName.toLowerCase() === 'crowdin-select') {
                        value = JSON.parse(e.value);
                        if (!e.hasAttribute('is-multi')) {
                            value = value.length > 0 ? value[0] : undefined;
                        }
                    } else if (e.tagName.toLowerCase() === 'crowdin-checkbox') {
                        value = !!e.checked;
                    } else {
                        value = e.value;
                    }
                    configReq[key] = value;
                });
            settingsSaveBtn.setAttribute('disabled', true);
            checkOrigin()
                .then(restParams => fetch('api/settings' + restParams, {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ config: configReq })
                }))
                .then(checkResponse)
                .then(() => {
                    showToast('Settings successfully saved');
                    config = configReq;
                })
                .catch(e => catchRejection(e, 'Can\'t save settings'))
                .finally(() => {
                    unsetLoader('#settings-modal');
                    settingsSaveBtn.removeAttribute('disabled');
                    closeModal(settingsModal);
                    {{#if reloadOnConfigSave}}
                        getIntegrationData(true);
                        getCrowdinData();
                    {{/if}}
                });
        }
    {{else}}
         const settingsModal = undefined;
    {{/if}}

    const permissions = document.getElementById('permissions-modal');

    {{#if excludedTargetLanguages}}
         const languageModal = document.getElementById('excluded-languages');
    {{else}}
         const languageModal = undefined;
    {{/if}}

    {{#if infoModal}}
         const infoModal = document.getElementById('info-modal');
    {{else}}
         const infoModal = undefined;
    {{/if}}

    document.addEventListener('keydown', (event) => {
        if (event.keyCode == 27) {
            if (users) {
                closeModal(permissions);
            }
            if (infoModal) {
                closeModal(infoModal);
            }
            if (settingsModal) {
                closeModal(settingsModal);
            }
            if (languageModal) {
              closeModal(languageModal);
            }
        }
    });

    {{#if integrationPagination}}
        document.body.addEventListener('fileListEnd', (e) => {
            getIntegrationData(false, 0, '', e.detail.page)
        })
    {{/if}}

    {{#or withCronSync webhooks}}
        const scheduleModal = document.getElementById('confirm-schedule-modal');
        let syncData;

        document.body.addEventListener('integrationScheduleSync', setIntegrationScheduleSync);
        document.body.addEventListener('crowdinScheduleSync', setCrowdinScheduleSync);
        document.body.addEventListener('crowdinDisableSync', disableCrowdinSync);
        document.body.addEventListener('integrationDisableSync', disableIntegrationSync);

        function getIntegrationFoldersToExpand(allData, syncedFiles) {
            return Array.isArray(allData)
                ? allData.filter(
                        node => (node.node_type === folderType && !syncedFiles.find((syncedFile) => syncedFile.parent_id === node.id))
                    ).map(node => ({
                        ...node,
                        nodeType: node.node_type,
                        parentId: node.parent_id,
                    }))
                : [];
        }

        async function saveScheduleSync() {
            const newFile = scheduleModal.querySelector('#new-files').checked || false;
            const selectedFiles = scheduleModal.querySelector('#selected-files').checked || false;

            const type = scheduleModal.getAttribute('data-type');

            if (type === 'crowdin') {
                appComponent.setCrowdinScheduleSync(syncData, newFile, selectedFiles);
                appComponent.setCrowdinFilesHasSyncOption(true);
                const syncedFiles = await appComponent.getCrowdinScheduleSync(true);
                appComponent.setAttribute('is-crowdin-sync-settings-in-progress', true);
                updateSyncSettings(syncedFiles, 'schedule', 'crowdin');
            } else if (type === 'integration') {
                appComponent.setIntegrationScheduleSync(syncData, newFile, selectedFiles);
                appComponent.setIntegrationFilesHasSyncOption(true);
                const syncedFiles = await appComponent.getIntegrationScheduleSync(true);
                appComponent.setAttribute('is-integration-sync-settings-in-progress', true);
                {{#if integrationOneLevelFetching}}
                    updateSyncSettings(
                        syncedFiles,
                        'schedule',
                        'integration',
                        selectedFiles ? getIntegrationFoldersToExpand(syncData, syncedFiles) : [],
                    );
                {{else}}
                    updateSyncSettings(syncedFiles, 'schedule', 'integration');
                {{/if}}
            }

            closeModal(scheduleModal);
        }

        async function openScheduleModal(type) {
            const newFile = scheduleModal.querySelector('#new-files')
            const selectedFiles = scheduleModal.querySelector('#selected-files');
            let newFileStatus = 'unChecked';

            const integrationSyncFolders = (await document.querySelector('crowdin-simple-integration').getIntegrationScheduleSync(true))
                .filter(elements => elements.node_type === '0');

            const selectedIntegrationFolders = (await document.getElementById('integration-files').getSelected(true))
                .filter(elements => elements.node_type === '0');

            for (let i = 0; i < selectedIntegrationFolders.length; i++) {
                const selectedElement = selectedIntegrationFolders[i];

                const found = integrationSyncFolders.some(integrationElement =>
                    integrationElement.id === selectedElement.id
                );

                if (found) {
                    newFileStatus = 'checked';
                } else if (!found && newFileStatus === 'checked') {
                    newFileStatus = 'clear-selection';
                    break;
                } else {
                    newFileStatus = 'unChecked';
                }
            }

            if (newFileStatus === 'checked') {
                newFile[newFileStatus] = true;
                newFile.value = true;
                newFile.removeAttribute('clear-selection');
            } else if (newFileStatus === 'clear-selection') {
                newFile.checked = false;
                newFile.value = false;
                newFile.setAttribute(newFileStatus, '');
            } else {
                newFile.checked = false;
                newFile.value = false;
                newFile.removeAttribute('clear-selection');
            }

            selectedFiles.checked = true;
            selectedFiles.value = true;
            scheduleModal.querySelector('#save-schedule-sync').setAttribute('disabled', false);
            scheduleModal.setAttribute('data-type', type);
            openModal(scheduleModal);
        }

        function onChangeAutoSynchronizationOptions() {
            const newFiles = document.getElementById('new-files');
            newFiles.removeAttribute('clear-selection');

            const newFilesStatus = newFiles.checked || false;
            const selectedFiles = document.getElementById('selected-files').checked || false;
            const buttonSaveScheduleSync = document.getElementById('save-schedule-sync');

            if (newFilesStatus || selectedFiles) {
                buttonSaveScheduleSync.removeAttribute('disabled');
            } else {
                buttonSaveScheduleSync.setAttribute('disabled', true);
            }
        }

        async function hasFolder(selectedFiles) {
            let isFolder;
            if (Array.isArray(selectedFiles)) {
                isFolder = selectedFiles.find((file) => file.node_type === folderType || file.node_type === branchType);
            } else {
                const files = await appComponent.getCrowdinFilesData();
                const folders = files.filter((file) => file.node_type === folderType || file.node_type === branchType);
                isFolder = folders.find((folder) => selectedFiles.hasOwnProperty(folder.id));
            }

            return isFolder !== undefined;
        }

        async function setIntegrationScheduleSync(e) {
            if (e.detail.length === 0) {
                showToast('Select templates which will be pushed to Crowdin');
                return;
            }

            {{#if syncNewElements.integration}}
                syncData = e.detail;
                const isFolder = await hasFolder(e.detail);
                if (isFolder && !newIntegrationFiles) {
                    await openScheduleModal('integration');
                    return;
                }

                appComponent.setIntegrationScheduleSync(e.detail);
                appComponent.setIntegrationFilesHasSyncOption(true);
                const syncedFiles = await appComponent.getIntegrationScheduleSync(true);
            {{else}}
                const syncedFiles = await appComponent.getIntegrationScheduleSync();
            {{/if}}

            appComponent.setAttribute('is-integration-sync-settings-in-progress', true);
            {{#if integrationOneLevelFetching}}
                updateSyncSettings(syncedFiles, 'schedule', 'integration', getIntegrationFoldersToExpand(e.detail, syncedFiles));
            {{else}}
                updateSyncSettings(syncedFiles, 'schedule', 'integration');
            {{/if}}
        }

        async function setCrowdinScheduleSync(e) {
            if (e.detail.length === 0) {
                showToast('Select templates which will be pushed to Crowdin');
                return;
            }

            {{#if syncNewElements.crowdin}}
                syncData = e.detail;
                const isFolder = await hasFolder(e.detail);
                if (isFolder && !newCrowdinFiles) {
                    await openScheduleModal('crowdin');
                    return;
                }

                appComponent.setCrowdinScheduleSync(e.detail);
                appComponent.setCrowdinFilesHasSyncOption(true);
                const syncedFiles = await appComponent.getCrowdinScheduleSync(true);
            {{else}}
                const syncedFiles = await appComponent.getCrowdinScheduleSync();
            {{/if}}
            appComponent.setAttribute('is-crowdin-sync-settings-in-progress', true);
            updateSyncSettings(syncedFiles, 'schedule', 'crowdin');
        }

        async function disableIntegrationSync(e) {
            if (e.detail.length === 0) {
                showToast('Select templates which will be pushed to Crowdin');
                return;
            }
            appComponent.setAttribute('is-integration-sync-settings-in-progress', true);
            {{#if syncNewElements.integration}}
                const syncedFiles = await appComponent.getIntegrationScheduleSync(true);
            {{else}}
                const syncedFiles = await appComponent.getIntegrationScheduleSync();
            {{/if}}

            updateSyncSettings(syncedFiles, 'schedule', 'integration');
        }

        async function disableCrowdinSync(e) {
            if (e.detail.length === 0) {
                showToast('Select templates which will be pushed to Crowdin');
                return;
            }
            appComponent.setAttribute('is-crowdin-sync-settings-in-progress', true);
            {{#if syncNewElements.crowdin}}
                const syncedFiles = await appComponent.getCrowdinScheduleSync(true);
            {{else}}
                const syncedFiles = await appComponent.getCrowdinScheduleSync();
            {{/if}}

            updateSyncSettings(syncedFiles, 'schedule', 'crowdin');
        }

        function updateSyncSettings(files, type, provider, expandIntegrationFolders = []) {
            checkOrigin()
                .then(restParams => fetch('api/sync-settings' + restParams, {
                    method: 'POST',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ files, type,  provider, expandIntegrationFolders })
                }))
                .then(checkResponse)
                .then((res) => {
                    checkJob({
                        jobId: res?.jobId,
                        jobType: JOB_TYPE[`${provider}SyncSettingsSave`],
                    })
                })
                .catch(e => catchRejection(e, 'Can\'t save schedule sync settings'));
        }
    {{/or}}

    {{#if checkSubscription}}
        const subscriptionInfo = document.getElementById('subscription-info');
        const subscriptionInfoText = subscriptionInfo.getElementsByTagName('p')[0];
        function getSubscriptionInfo() {
            checkOrigin()
                .then(restParams => fetch('api/subscription-info' + restParams))
                .then(checkResponse)
                .then((res) => {
                    if (res.showInfo) {
                        subscriptionLink = res.subscribeLink;
                        subscriptionInfoText.textContent = `Your trial expires in ${res.daysLeft} days.`
                        subscriptionInfo.style.display = 'block';
                    }
                });
        }

        getSubscriptionInfo();
    {{/if}}

    function checkAlert(alert, suffix) {
        const name = suffix ?? '{{name}}';
        const revised = localStorage.getItem(`revised_${name}`) === '1';
        if (!revised) {
            alert.style.display = 'block';
        }
    }
    function closeAlert(el, suffix) {
        const name = suffix ?? '{{name}}';
        const alert = el.closest('crowdin-alert');
        alert.style.display = 'none';
        localStorage.setItem(`revised_${name}`, 1);
    }

    {{#if notice}}
        const notice = document.getElementById('notice');
        checkAlert(notice, 'notice');
    {{/if}}

    function showErrorLogs() {
        document.getElementById('show-error-logs-btn').classList.add('hidden');
        document.getElementById('show-integration-btn').classList.remove('hidden');

        appComponent.classList.add('hidden');
        document.getElementById('user-errors').classList.remove('hidden');

        checkOrigin()
            .then(restParams => fetch('api/user-errors' + restParams))
            .then(checkResponse)
            .then((res) => {
                const table = document.getElementById('user-errors-table');

                const clickRow = (field, index, item) => {
                    const modal = document.getElementById('user-error-detail');
                    openModal(modal);
                    modal.innerHTML = getUserErrorDetail(item);
                };

                const formatDate = (field, index, item) => {
                  return item.formattedDate;
                }

                table.setTableConfig && table.setTableConfig({
                    defaultSortingColumn: "createdAt",
                    defaultSortingDir: "desc",
                    headerFields: [
                        {
                            field: "createdAt",
                            name: "Date",
                            isSortable: true,
                            clickFn: clickRow,
                            formatFn: formatDate,
                        },
                        {
                            field: "action",
                            name: "Action",
                            clickFn: clickRow,
                        },
                        {
                            field: "message",
                            name: "Message",
                            clickFn: clickRow,
                        }
                    ],
                });

                table.setTableData(JSON.stringify(res));
                table.setAttribute(`is-loading`, false);
            })
            .catch(e => catchRejection(e, 'Can\'t fetch error logs'));
    }

    function showIntegration() {
        document.getElementById('show-error-logs-btn').classList.remove('hidden');
        document.getElementById('show-integration-btn').classList.add('hidden');

        appComponent.classList.remove('hidden');
        document.getElementById('user-errors').classList.add('hidden');
    }

    function isJSON(string) {
      try {
        JSON.parse(string);
        return true;
      } catch (e) {
        return false;
      }
    }

    function getUserErrorDetail(error) {
      const data = JSON.parse(error.data);

      let html = '<div class="error-detail-table"><table>';
      html += `<tr><td>Action</td><td>${sanitizeHTML(error.action)}</td></tr>`;
      if (isJSON(error.message)) {
        html += `<tr><td>Message</td><td><pre>${sanitizeHTML(error.message)}<pre></td></tr>`;
      } else {
        html += `<tr><td>Message</td><td>${sanitizeHTML(error.message)}</td></tr>`;
      }
      html += `<tr><td>Date/time</td><td>${sanitizeHTML(error.formattedDate)}</td></tr>`;

      if (data.requestParams) {
        html += `<tr><td>Method</td><td>${sanitizeHTML(data.requestParams.method)}</td></tr>`;
      }

      if (data.responseData) {
        html += `<tr><td>Response Data</td><td><pre>${sanitizeHTML(JSON.stringify(data.responseData, null, 2))}</pre></td></tr>`;
      }

      if (data.appData) {
        if (Array.isArray(data.appData)) {
          html += `<tr><td>App Data</td><td><pre>${sanitizeHTML(JSON.stringify(data.appData, null, 2))}</pre></td></tr>`;
        } else if (typeof data.appData === 'object') {
          for (const key in data.appData) {
            html += `<tr><td>${sanitizeHTML(key.charAt(0).toUpperCase() + key.slice(1))}</td><td><pre>${sanitizeHTML(JSON.stringify(data.appData[key], null, 2))}</pre></td></tr>`;
          }
        } else {
          html += `<tr><td>App Data</td><td>${sanitizeHTML(data.appData)}</td></tr>`;
        }
      }

        html += '</table></div>';

        return html;
    }

    function sanitizeHTML(str) {
      const tempDiv = document.createElement('div');
      tempDiv.textContent = str;
      return tempDiv.innerHTML;
    }

    function openModal(modal) {
      modal.style.display = 'block';
      modal.open()
    }

    function closeModal(modal) {
      modal.style.display = 'none';
      modal.close()
    }
</script>

</html>
