# Konfigurace vlastní mikrostránky

Vlastní mikrostránky slouží jako samostatné vstupní brány pro klienty do aplikace *mluvii*, svou funkčností jde v podstatě o velké widgety. Postup tvorby vyžaduje nastavit WebChat widget, vytvořit HTML dokument, přidat CSS styly, přidat Javascript a uložit stránku na libovolný hosting podporující protokol **HTTPS**.

Pro svou jednoduchost, tak jako v jiných návodech, budeme používat codepen.io. Začít můžete [zde](https://codepen.io/pen?template=KXZyGp).

### Nastavení konfiguračního balíčku

V administraci aplikace v sekci WebChat si vytvoříte nový / upravíte stávající WebChat widget. WebChat tlačítko nastavíte na "žádné tlačítko" - tím se vám tlačítko nebude zobrazovat, nicméně všechny funkcionality s tlačítkem spojené vám budou k dispozici. Nastavení chatovacího okna je libovolné.

### Postup tvorby

V tomto návodu si můžete vytvořit mikrostránku pro Callback/Pozvánku, příp. chat a AV hovor, která bude umět připojit uživatele do aplikace *mluvii*, budou umět zobrazit stav tlačítka a pracovat s parametry hovorů (přednastavenými i vlastními parametry). Konečná podoba bude následující (Live verze [zde](https://patricke004.github.io/formEntry/microSite001.html)):

#### Vytvoření HTML souboru

HTML dokument je následující. Použité obrázky jsou uloženy na github stránkách, kde celou mikrostránku nakonec uložíte.

#### Přidání CSS stylů

#### Přidání Javascriptu

Javascriptem přivedete vaší mikrostránku k životu. Nejdříve vložíte kód vašeho konfiguračního balíčku.

```js
(function () {
  var scr = document.createElement('script'); scr.type = 'text/javascript'; scr.async = true; scr.charset = 'UTF-8';
  scr.src = '//app.mluvii.com/widget/OOWidget.js';
  scr.$owidgetOnLoad = function (owidget) {
    if (!owidget.isSupported) { return; }
    owidget.init('295b1064-cf5b-4a5d-9e05-e7a74f86ae5e', 'navodMicroSite');
    owidget.connectToServer();
  };
  var ffs = document.getElementsByTagName('script')[0]; ffs.parentNode.insertBefore(scr, ffs);
})();
```

Do funkce $owidgetOnLoad vložíme téměř celý náš javascriptový kód:

```js
scr.$owidgetOnLoad = function (owidget) {
  // Náš kód
};
```

**Indikace stavu balíčku**

Jako první začněte s indikací stavu balíčku, tedy to, zdali jsou operátoři přiřazení k danému WebChat widgetu online, zaneprázdnění nebo offline. A to touto funkcí:

```js
owidget.setStatusUpdateCallback()
```

Tato funkce bere jako parametr callback funkci, která bude volána pokaždé, kdy ze serveru přijdou informace o stavu operátorů. Tento callback bere parametr `code`, tedy číslo 0 v případě, že operátoři jsou offline, 1 - v případě, že jsou online a 2 - v případě zaneprázdnění.

Kód funkce $owidgetOnLoad bude zatím vypadat takto:

```js
if (!owidget.isSupported) { return; }
owidget.init('295b1064-cf5b-4a5d-9e05-e7a74f86ae5e', 'navodMicroSite');

let widgetOnline = true;

owidget.setStatusUpdateCallback(function(code) {
    const statusIndicatorImage = document.getElementById('StatusIndicatorCore-imageSelf');
    const statusIndicatorText = document.getElementById('StatusIndicatorCore-textSelf');

    switch(code) {
        case 0:
            statusIndicatorImage.src = 'Images/ikonka_konverzace-01_offline.png';
            statusIndicatorText.innerText = 'Jsme offline';
            statusIndicatorText.style.color = '#bf464f';
            widgetOnline = false; 
            break;
         case 1:
            statusIndicatorImage.src = 'Images/ikonka_konverzace-01_online.png';
            statusIndicatorText.innerText = 'Jsme online';
            statusIndicatorText.style.color = '#8dc63f';
            widgetOnline = true;
            break;
         case 2:
            statusIndicatorImage.src = 'Images/ikonka_konverzace-01_busy.png';
            statusIndicatorText.innerText = 'Máme toho hodně';
            statusIndicatorText.style.color = '#ffbb06';                                           
            widgetOnline = true;                        
            break;
         }
    });
```

**Input a WebChat widget aplikace**

Dalším krokem je zprovoznění tlačítka pro vstup do aplikace *mluvii*. Nejprve se podívejme na variantu pro Callback/Pozvánku.

Na stránce máte input pro zadání čísla pozvánky nebo telefonního čísla a tlačítko pro vstup do aplikace. Na tomto tlačítku budete naslouchat klepnutí, jakmile se tak stane, otevřeme velkou místnost aplikace *mluvii*, pokud nejsou všichni operátoři offline:

```js
const widgetButton = document.getElementById('WidgetInput-button');
const widgetInput = document.getElementById('WidgetInput-input');

widgetButton.addEventListener('click', function() {
   if(!widgetOnline) return; // tuto proměnnou deklarujeme a nastavujeme výše.
   owidget.openApp('callshow', widgetInput.value);
}
```

Nyní přidáte validaci inputu regulárním výrazem, aby bylo možné na server posílat pouze šesti a devítimístná čísla a uživateli zobrazíte i zprávu o tomto stavu:

```js
const hints = document.getElementById('Hints');
const regNumberLength6 = new RegExp('^\\d{6}$');
const regNumberLength9 = new RegExp('^\\d{9}$');

widgetButton.addEventListener('click', function() {
   if(!widgetOnline) return; // tuto proměnnou deklarujete a nastavujete výše.
   
   // V případě, že input neprošel jedním z našich testů, zobrazíte nápovědu
   if(!regNumberLength6.test(widgetInput.value) || !regNumberLength9.test(widgetInput.value)) {
     hints.classList.remove('isHidden');
   }

   // Pokud je číslo šestimístné, zahájíte Pozvánku v novém okně
   if(regNumberLength6.test(widgetInput.value)) {
     owidget.openApp('callshow', widgetInput.value)
   }

   // Pokud je číslo devítimístné, zahájíte callback v novém okně
   if(regNumberLength9.test(widgetInput.value)) {
     owidget.openApp('callback', widgetInput.value);
   }
}
```

Případ pro callback musíte ještě poupravit a použít funkce:

```js
owidget.numberNormalization(string)
// nebo
owidget.setCustomNumberNormalization(vaseNormalizacniFunkce);
```

První z funkcí je přednastavená normalizační funkce, která telefonnímu číslu přidá mezinárodní předčíslí a případně odstraní mezery apod.

Druhá funkce umožňuje přidat vlastní normalizační funkci, např. s vlastním mezinárodním číslem apod.

Otevření callbacku pak bude vypadat takto:

```js
if(regNumberLength9.test(widgetInput.value)) {
    owidget.numberNormalization(widgetInput.value)
    const normalizedNumber = owidget.numberNormalization(widgetInput.value);
    owidget.openApp('callback', normalizedNumber);
}
```

Abyste si byli jistí, že nápověda zmizí, jakmile uživatel zadá šesti nebo devítimístné číslo do inputu, vytvořte „event listener“ pro tento případ:

```js
widgetInput.addEventListener('input', function() {
  if(regNumberLength6.test(widgetInput.value) || regNumberLength9.test(widgetInput.value)) {
     hints.classList.add('isHidden');
  }
});
```

Tím máte základní funkčnost vaší mikrostránky zajištěnou.

**Chat, videohovor**

Pokud byste chtěli zákazníkům místo Callback/Pozvánky poskytovat služby chatu nebo AV hovoru, stačí k tomu ve vašem případě vyměnit funkci pro inicializaci Callbacku/Pozvánky za funkce pro inicializaci chatu, nebo AV hovoru. Můžete také odstranit input pro číslo pozvánky /telefonní číslo, jelikož tyto funkce daný parametr nepotřebují - s tím odstraníte i vaše testování vloženého čísla.

Inicializace chatu:

```js
owidget.openChat();
```

Inicializace AV hovoru:

```js
owidget.openApp("av");
```

„Event listener“ na tlačítku začít hovor by tedy v případě AV hovoru vypadal takto:

```js
widgetButton.addEventListener('click', function() {
   if(!widgetOnline) return;
   owidget.openApp("av");
}
```

**Vlastní parametry**

Spolu s tel. číslem nebo číslem pozvánky můžete operátorům odeslat vlastní proměnné. Na mikrostránce jsme k tomuto účelu vytvořili input, který, bude-li vyplněn, pošle na server proměnnou (parametr hovoru). Kód vložíte před testy regulárními výrazy:

```js
const nameInput = document.getElementById('inputName');
if(nameInput.value !== '') {
    owidget.addCustomData('navod_clientName', nameInput.value);
}
```

Na mikrostránce můžete počítat i s dalšími libovolnými interakcemi, např. v podobě přihlášení /odhlášení uživatele. Za listenerem pro tlačítko „Začít hovor“ bychom vytvořili další listnery pro Login a Logout tlačítka, u kterých je předpoklad, že web má vlastní logiku autentizace uživatelů. V momentě zdařilé autentizace /odhlášení využijte funkcí *mluvii*:

```js
const login = document.getElementById('login');
const logout = document.getElementById('logout');

login.addEventListener('click', function() {
    // Logika autentizace zde, výsledek autentizace je přiřazené id uživatele, v callbacku autentizace bychom přidali naší funkci:
    const foundUserId = 'as3d21sad351as-as1d';
    owidget.addCustomData('navod_clientId', foundUserId);
});
logout.addEventListener('click', function() {
    // Logika odhlášení zde, v callbacku odhlášení pak použijeme funkce:
    owidget.removeCustomData('navod_clientId'); 
    // owidget.clearCustomData();
});
```

Funkce owidget.removeCustomData si bere jako parametr název proměnné, kterou chcete smazat. Funkce owidget.clearCustomData() smaže všechny proměnné.

Javascript vaší mikrostránky nakonec vypadá následovně:

#### Publikace mikrostránky

Pokud jste při tvorbě vlastního Pop-upu využili codepen.io, je nyní potřeba Pop-up exportovat. Klikněte na tlačítko „Save“, poté exportujte v „.zip“ formátu:

Vytvořený pop-up můžete uložit buď jako podstránku vašeho webu, nebo využít jakýkoliv webhosting, např. Github stránky.

Pokud jste využili textového editoru, výsledná stránka bude vypadat následovně:

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">    
    <link href="https://fonts.googleapis.com/css?family=Raleway" rel="stylesheet">    
    <title>Document</title>
    <style>
        body {
            background-image: linear-gradient(to right, #6ca6bd, #8dc63f);
            font-size: Raleway;
        }
        html, body {
            margin: 0;
            padding: 0;
        }
        input, button, p, label {
            font-family: Raleway;            
        }
        .Logo {
            position: absolute;
            width: 25%;
            margin: 20px;
            min-width: 200px;
        }
        .Page {
            display: flex;
            width: 100%;
            height: 100vh;
            align-items: center;
            justify-content: center;
        }
        .Frame {
            background-color: white;
            width: 450px;
            height: 350px;
            border-radius: 10px;
            display: flex;
            flex-direction: column;
            overflow: hidden;
        }
        .StatusIndicator {
            flex: 3;
            display: flex;
            flex-direction: row;
            justify-content: center;
        }
        .StatusIndicatorCore {
            width: 300px;
            display: flex;
        }
        .StatusIndicatorCore-image {
            flex: 3;
            display: flex;
            align-items: center;
        }
        .StatusIndicatorCore-image>img {
            max-height: 100%;
            max-width: 100%;
        }
        .StatusIndicatorCore-text {
            flex: 7;
            display: flex;
            align-items: center;
        }
        #StatusIndicatorCore-textSelf {
            font-size: 35px;
            font-family: Raleway;
            font-weight: bold;
            color: #8dc63f;
            text-align: center;
            margin: 0;
        }
        .WidgetInput {
            width: 100%;
            flex: 7;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            position: relative;
        }
        #WidgetInput-input {
            width: 60%;
            height: 40px;
            border-radius: 8px;
            border: 1px solid #6ca6bd;
            font-size: 20px;
            text-align: center;
            color: #8dc63f;
            margin-bottom: 10px;
            box-sizing: border-box;
        }
        #WidgetInput-input:focus, #WidgetInput-button:focus, .LoginButtons:focus {
            outline: 0;
            border: 2px solid #6ca6bd;            
        }
        #WidgetInput-button {
            width: 60%;
            border-radius: 8px;
            border: 1px solid #6ca6bd;
            background-color: #8dc63f;    
            transition: all 0.3s;
            color: #fff;
            height: 40px;
            font-size: 20px;
            margin-bottom: 20px;
        }
        #WidgetInput-button:hover, .LoginButtons:hover {
            background-color: #6ca6bd;
        }
        #Hints {
            position: absolute;
            bottom: 0;
            background-color: #bf464f;
            color: white;
            width: 100%;
            padding: 10px 8px;
            text-align: center;
            box-sizing: border-box;
            margin: 0;
            transition: all ease-out 0.3s;
        }
        #Hints.isHidden {
            transform: translateY(100%);
        }
        .CustomVariables {
            position: absolute;
            bottom: 0;
            margin: 0 auto;
            height: 50px;
            width: 800px;
            border-radius: 10px 10px 0 0;
            background-color: #fff;
            display: flex;
            flex-direction: row;
            align-content: center;
        }
        .CustomVariables-input {
            flex: 1;
            text-align: center;
        }
        .CustomVariables-input:first-of-type {
            flex: 2;
        }
        .CustomInput {
            width: 250px;
            height: 30px;
            border-radius: 8px;
            border: 1px solid #6ca6bd;
            font-size: 18px;
            text-align: center;
            color: #8dc63f;
            box-sizing: border-box;
            margin: 10px 0;
            margin-left: 5px;
            outline: 0;
        }
        .CustomInput:focus {
            border: 2px solid #6ca6bd;
        }
        label {
            font-size: 20px;
            color: #5b5b5b;
        }
        .LoginButtons {
            width: 150px;
            border-radius: 8px;
            border: 1px solid #6ca6bd;
            background-color: #8dc63f;    
            transition: all 0.3s;
            color: #fff;
            height: 30px;
            font-size: 20px;
            margin: 10px 0;
        }
    </style>
</head>
<body>
    <img src="Images/logo-transparent-no-safezone.png" alt="" class="Logo">
    <div class="Page">
        <div class="Frame">
            <div class="StatusIndicator">
                <div class="StatusIndicatorCore">
                    <div class="StatusIndicatorCore-image">
                        <img id="StatusIndicatorCore-imageSelf" src="Images/ikonka_konverzace-01_online.png" alt="">                        
                    </div>
                    <div class="StatusIndicatorCore-text">
                        <p id="StatusIndicatorCore-textSelf">
                            Jsme online
                        </p>
                    </div>
                </div>
            </div>
            <div class="WidgetInput">
                <p id="Hints" class="isHidden">Zadejte prosím devítimístné telefonní číslo nebo šestímístné číslo pozvánky.</p>
                <input type="text" id="WidgetInput-input" placeholder="Telefon / č. pozvánky">
                <button id="WidgetInput-button">Začít hovor</button>
            </div>
        </div>
        <div class="CustomVariables">
            <div class="CustomVariables-input">
                <label for="inputName">Jméno:</label>
                <input type="text" class="CustomInput" id="inputName">
            </div>
            <div class="CustomVariables-input">
                <button class="LoginButtons" id="login">Login</button>
            </div>
            <div class="CustomVariables-input">
                <button class="LoginButtons" id="logout">Logout</button>
            </div>
        </div>
    </div>


    <script type="text/javascript">
        (function () {
        var scr = document.createElement('script'); scr.type = 'text/javascript'; scr.async = true; scr.charset = 'UTF-8';
        scr.src = '//app.mluvii.com/widget/OOWidget.js';
        scr.$owidgetOnLoad = function (owidget) {
            if (!owidget.isSupported) { return; }
            owidget.init('295b1064-cf5b-4a5d-9e05-e7a74f86ae5e', 'navodMicroSite');

            let widgetOnline = true;

            owidget.setStatusUpdateCallback(function(code) {
                const statusIndicatorImage = document.getElementById('StatusIndicatorCore-imageSelf');
                const statusIndicatorText = document.getElementById('StatusIndicatorCore-textSelf');

                switch(code) {
                    case 0:
                        statusIndicatorImage.src = 'Images/ikonka_konverzace-01_offline.png';
                        statusIndicatorText.innerText = 'Jsme offline';
                        statusIndicatorText.style.color = '#bf464f';
                        widgetOnline = false; 
                        break;
                    case 1:
                        statusIndicatorImage.src = 'Images/ikonka_konverzace-01_online.png';
                        statusIndicatorText.innerText = 'Jsme online';
                        statusIndicatorText.style.color = '#8dc63f';
                        widgetOnline = true;
                        break;
                    case 2:
                        statusIndicatorImage.src = 'Images/ikonka_konverzace-01_busy.png';
                        statusIndicatorText.innerText = 'Máme toho hodně';
                        statusIndicatorText.style.color = '#ffbb06';                                           
                        widgetOnline = true;                        
                        break;
                }
            });


            const widgetButton = document.getElementById('WidgetInput-button');
            const widgetInput = document.getElementById('WidgetInput-input');
            const hints = document.getElementById('Hints');

            const nameInput = document.getElementById('inputName');

            const login = document.getElementById('login');
            const logout = document.getElementById('logout');

            const regNumberLength6 = new RegExp('^\\d{6}$');
            const regNumberLength9 = new RegExp('^\\d{9}$');

            widgetButton.addEventListener('click', function(e) {
                if(!widgetOnline) return;

                if(nameInput.value !== '') {
                    owidget.addCustomData('navod_clientName', nameInput.value);
                }

                
                if(!regNumberLength6.test(widgetInput.value) || !regNumberLength9.test(widgetInput.value)) {
                    hints.classList.remove('isHidden');
                }
                if(regNumberLength6.test(widgetInput.value)) {
                    owidget.openApp('callshow', widgetInput.value)
                }
                if(regNumberLength9.test(widgetInput.value)) {
                    owidget.numberNormalization(widgetInput.value)
                    const normalizedNumber = owidget.numberNormalization(widgetInput.value);
                    owidget.openApp('callback', normalizedNumber);
                }
            });

            widgetInput.addEventListener('input', function() {
                if(regNumberLength6.test(widgetInput.value) || regNumberLength9.test(widgetInput.value)) {
                    hints.classList.add('isHidden');
                }
            });

            login.addEventListener('click', function() {
                const foundUserId = 'as3d21sad351as-as1d';
                owidget.addCustomData('navod_clientId', foundUserId);
            });
            logout.addEventListener('click', function() {
                owidget.removeCustomData('navod_clientId');
                // owidget.clearCustomData();
            });

            owidget.connectToServer();
        };
        var ffs = document.getElementsByTagName('script')[0]; ffs.parentNode.insertBefore(scr, ffs);
        })();
    </script>
</body>
</html>
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.mluvii.com/pro-it-specialisty/customizace/konfigurace-vlastni-mikrostranky.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
