---
# System prepended metadata

title: Virtual Showroom (front-end)

---

# Virtual Showroom (front-end)
Sivuston dokumentaatio on jaettu kahteen osioon: "Virtual Showroom" ja "Moderaattorisivu". Tämä dokumentaatio sisältää vain kuvaukset front-end -puolen komponenteista ja arkkitehtuurista. Mikäli haluat tarkastella sivuston back-endin arkkitehtuuria sekä muuta tietoa projektin käyttöönotosta ja asetuksista, ne ovat saatavilla: https://hackmd.io/@4yjCuTxmQDesKaLCP1gl9Q/H1tOzcUBt

<br></br>

## Yleistietoa
Sivusto käyttää React-sovelluskehystä JavaScript-pohjaisten komponenttien piirtoon. Komponentit ovat pyritty rajaamaan eri kokonaisuuksien mukaan (kuten organisaatioiden esitysruutu, chat, opaste), ja ovat tyypiltään funktio-komponentteja. Kehittäjiltä odotetaan kokemusta Reactin käytöstä ja toimintaperiaatteista. Sivustolla käytetyt audioassetit ja graafinen materiaali löytyvät `3d\assets\` kansiosta. Tyylittelyssä React-komponentit käyttävät lähinnä tyylitettyjä komponentteja ([styled-components](https://styled-components.com/)).

Sivustolla käytettyjä toteutustekniikoita/kirjastoja:
- [React](https://reactjs.org/) **-- pohjana toimiva sovelluskehys**
- [styled-components](https://styled-components.com/) **-- komponenttien tyylitys**
- [A-Frame](https://aframe.io/) (React-integraatio) **-- 3D-ominaisuudet**
- [Nominatim](https://nominatim.org/) **-- sijaintipalvelu**
- [OpenLayers](https://openlayers.org/) **-- interaktiivinen kartta**
- [react-device-detect](https://github.com/duskload/react-device-detect) **-- laitteen tunnistus** (työpöytä vai mobiili)

### Callback
Dokumentaatiossa käytetään puhutaan usein *callbackeistä*. Koska projekti käyttää funktiokomponentteja, alikomponentteilla ei ole pääsyä parent-komponenteissa määriteltyihin funktioihin tai muuttujiin. Jotta alikomponentit voivat suorittaa parentin funktioita, parent-komponenttien on lähetettävä alikomponenteille viite funktioihin proppien avulla. Callbackeihin viitataan sivuston lähdekoodissa usein termillä *hook*.

<br></br>

## LanguageManager.js
LanguageManageria käytetään sivuston kielen asettamiseen ja käännöksien hakemiseen käännöstiedostoista (.JSON), jotka sijaitsevat `Language\packs\` kansiossa. LanguageManager-luokka ei ole React-komponentti eikä siitä ole tarkoitus luoda ilmentymää missään vaiheessa. Luokka käyttää Window.localStoragea valitun käännöstiedoston stringifoidun JSONin tallentamiseen. 

Sivun kielen voi asettaa `LanguageManager.setLanguage(lang)` metodia käyttäen. Luokassa on myös `LanguageManager.getLanguage()` metodin, jolla tämän hetkisen käännöstiedoston JSONin voi hakea, mutta asetetun kielen tarkistukseen suositellaan `LanguageManager.isCurrentLanguage(lang)` metodia, jonka syötteenä toimii LanguageManagerin staattiset vakiot:
- `LanguageManager.FIN`
- `LanguageManager.ENG`
- `LanguageManager.JPN`

Tietyn käännöksen saa haettua käännöstiedostosta `LanguageManager.getTranslation(field)` metodia käyttäen.

### Käännöstiedostoista
Käännöstiedostot ovat .JSON-tiedostja, jotka sisältävät kaikki tarpeelliset käännökset. Jokaisella käännöksellä on oma kenttä-avaimensa, jonka perusteella käännöksen voi hakea `LanguageManager.getTranslation(field)` metodilla. Tiedoston alussa on kuitenkin oltava `LANG` kenttä, joka toimii ID:nä käännökselle. LanguageManager käyttää tätä ID:tä erottelemaan tiedostot toisistaan. Käännöstiedostojen tulisi olla yhteneväisiä (kaikissa samat kenttä-avaimet) ongelmien välttämiseksi.

<br></br>

## View.js

View.js piirtää sovellukseen 360-näkymän ja sen päälle asetetut elementit. Näkymän piirtoon käytetään A-Frame -kirjaston React-integraatiota (aframe-react), joka pohjautuu Three.js-kirjastoon. View toimii juurikomponenttina, johon kaikki muut komponenti tulisi yhdistää. View sisältää myös useita toiminnallisuuksia, jotka ovat sen react-komponentin ulkopuolisia, kuten A-Frame, komponenttien rekisteröinti.

### Props
Ei ole.
<br></br>

## Overlay.js
Overlay piirtää organisaatioiden esittelyruudun, joka sisältää yleistieto-, yhteydenotto- ja liitevälilehden. Välilehtiä voidaan vaihtaa käyttämällä esittelyruudun alareunassa olevia navigaationäppäimiä, joita ei toistaiseksi luoda dynaamisesti.

### Props
**companyData** - Sisältää avatun organisaatioesittelyn tiedot, jotka ovat haettu tietokannasta.

**open** - Määrittelee, onko esittelyruutu auki vai suljettu.

**close** - Callback, joka suorittaa View.js:ssä esittelyruudun sulkufunktion.

**closeInfo** - Ei käytössä.

**tutorialPhaseSetter** - Callback, jota käytetään asettamaan seuraava vaihe sivuston ohjeistuksessa (TutorialOverlay.js).

<br></br>

## CloseButton.js
Yleiseksi sulkunäppäimeksi tarkoitettu komponentti, joka suorittaa annetun callbackin klikkauksesta.

### Props
**onClick** - Callback, joka suoritetaan elementtiä klikattaessa.

<br></br>

## TabSwitch.js
Navigaationäppäin, josta käyttäjä voi siirtyä välilehdeltä toiselle organisaatioiden esittelyruudussa (Overlay.js). Mikäli näppäimen edustama välilehti on jo auki, näppäimen väritys on hieman tummempi. Komponentti käyttää callbackia vaihtamaan välilehden parent-komponentissa (Overlay.js:ssä).

### Props
**title** - Kentän nimi, jonka perusteella haetaan käännös navigaationäppäimen otsikolle.

**tab** - Välilehden indeksi, johon vaihdetaan navigaationäppäintä klikattaessa.

**changeTab** - Callback, jolla vaihdetaan välilehti **tab**-indeksin mukaan.

**isOpen** - Määrittelee, onko tämän navigaationäppäimen edustama välilehti auki.

**tutorialPhaseHook** - Callback, jolla siirrytään Overlay.js:ssä määriteltyyn vaiheeseen sivuston ohjeistuksessa (TutorialOverlay.js).

<br></br>

## ContactInfo.js
Overlay.js:n alaisuudessa oleva välilehti, joka sisältää organisaatioesittelyn yhteystiedot: osoitteet, sivuston linkin, puhelinnumeron, säköpostin sekä SOME-linkit. Tällä hetkellä välilehti näyttää alustan logon seuraaville sivustoille:
- YouTube
- Twitter
- Instagram
- Facebook
- LinkedIn
- WhatsApp
SOME-alusta tunnistetaan tarkistamalla, onko linkissä sivuston osoite; esimerkiksi, www.youtube.com.

Yhteystiedot piirretään välilehdelle dynaamisesti jättäen tyhjät yhteystiedot pois. Lisäksi välilehdellä näytetään organisaation sijainti kartalla, jossa oleva karttamerkki piirretään ensisijaisesti organisaation tiedoissa olevien koordinaattien (leveys- ja pituuspiiri) avulla. Mikäli koordinaatteja ei ole syötetty, sijainti pyritään määrittelemään Nominatim-palvelusta. Karttaratkaisu käyttää OpenLayers-kirjastoa.

### Props
**companyData** - Sisältää kaikki tiedot organisaatioista. Käytetään yhteystietojen listaukseen ja kartan merkkien asetteluun.

<br></br>

## SocialMedias.js
Overlay.js:n alaisuudessa oleva välilehti, joka sisältää organisaatioesittelyn liitteet, jotka voivat olla tyypiltään videoita, linkkejä tai tiedostoja. Jokaisella tyypilla on oma kuvakkeensa. Käytännössä kaikki liitteet ovat linkkejä, eli liitettä klikattaessa käyttäjä siirtyy toiselle sivustolla uudessa selaimen välilehdessä. Liitteet piirretään näkymään dynaamisesti jättäen tyhjät liitteet pois.

### Props
**companyData** - Sisältää kaikki tiedot organisaatiosta. Käytetään liitteiden listaukseen.

<br></br>

## MapPreview.js
Piirtää karttanäkymän käyttäen OpenLayers-kirjastoa. Näkymään asetellaan annetut koordinaatit, ja näkymä asetetaan koordinaattien keskelle riittävästi zoomattuna. Karttaan voidaan asettaa teoriassa loputon määrä merkkejä. Mikäli koordinaatteja ei ole saatavilla, sijainti pyritään määritellään osoiteen perusteella käyttäen Nominatim-palvelua. Koordinaattien käyttöä kuitenkin suositellaan.

### Props
**markers** - Sisältää karttamerkkien tiedot *names*- ja *coords*-kentissä, jossa *names* on taulukko, joka sisältää merkkien nimet, ja *coords* on taulukko, joka sisältää merkkien koordinaatit siten, että joka kaksi peräkkäistä elementtiä ovat yhden merkin leveys- ja pituuspiirit.

    {
        names: [Wärtsilä-kampus, Tikkarinne-kampus],
        coords: [123.45, 44.44,  678.90, 55.55]
    }

**address** - Osoite, jota käytetään sijainnin selvitykseen Nominatim-palvelun kautta, mikäli koordinaatteja ei ole saatavilla **markers**-oliossa.

<br></br>

## ContactInfoPanel.js
Yleinen paneeli, jota ContactInfo.js ja SocialMedias.js käyttävät piirtämään listatun elementin. Jokaisella paneelilla on vasemmassa laidassa pieni kuvake, jonka oikealla puolella on otsikko, joka voi olla staattinen tai käännös. Komponentti suorittaa callbackin klikkauksesta.

### Props
**caption** - Kenttä, jonka perusteella pyritään ensisijaisesti hakemaan käännös paneelin otsikolle. Mikäli **caption** on *null*, käytetään **text**-propin oletustekstiä.

**text** - Staattinen oletusotsikko (ei käännöstä).

**click** - Callback, joka suoritetaan paneelia klikattaessa.

**enablePopup** - Mikäli paneeli piirtää otsikkonsa pop-uppiin, kun käyttäjä vie hiiren paneelin päälle (tai näpäyttää paneelia kosketusnäytöllä). Tämä on hyödyllistä laitteilla tai resoluutioilla, joilla paneelin otsikko jää piiloon tilan puutteen vuoksi.

**popupStyle** - Ylimääräinen tyylittely, joka voidaan asettaa pop-upin CSS:ään.

<br></br>

## ContactPopup.js
ContactInfoPanel.js:n alaisuuteen tarkoitettu pieni pop-up-elementti, jolla on tarkoitus selkeyttää paneelin otsikkoa, mikäli se on osittain tai kokonaan piilossa tilan puutteen vuoksi.

### Props
**text** - Teksti, joka tullaan piirtämään pop-uppiin.

**additionalStyle** - Ylimääräinen tyylittely, joka voidaan lisätä pop-upin CSS:ään tarpeen tullen.

<br></br>

## CompanyInfo.js
Overlay.js:n alaisuudessa oleva välilehti, joka sisältää organisaatioesittelyn yleistietosivun: esittelytekstin ja pienet esikatselukuvakkeet. Välilehdellä on näppäin, jota klikkaamalla esittelytekstiä voi pienentää/laajentaa, ja pikkukuvakkeita, joita klikkaamalla avautuu organisaation kuvagalleria. Kuvat piirretään dynaamisesti, ja ne liukuvat hitaasti oikealta vasemmalle kierrättäen. Mikäli kuvien määrä on vähäinen, niitä toistetaan.

### Props
**name** - Esiteltävän organisaation nimi.

**description** - Organisaation esittelyteksti, jossa lyhennettynä esillä oleva versio on erotettu lopusta tekstistä valuuttamerkillä (¤).

**thumbnails** - Taulukko, joka sisältää linkit jokaiseen organisaation kuvagallerian kuviin.

**address** - Ei käytössä.

<br></br>

## CompanyThumbnail.js
CompanyInfo.js:n alaisuudessa oleva komponentti, joka piirtää organisaation pikkukuvat *kuvakarusellissä* (kuvat rullaavat oikealta vasemmalle). Klikatessa kuvaketta CompanyThumbnail menee laajennettuun tilaan, jolloin valittu kuva piirretään suurennettuna näytölle. Kuvat piirretään dynaamisesti, ja niitä toistetaan mikäli kuvia on liian vähän. Laajennetussa tilassa pikkukuvat eivät rullaa enää automaattisesti vaan niitä on vedettävä hiirellä. Kuvat voidaan myös asettaa vaihtumaan automaattisesti laajennetussa tilassa klikkaamalla oikeassa yläkulmassa olevaa näppäintä.

### Props
**thumbnails** - Taulukko, joka sisältää linkit jokaiseen organisaation kuvagallerian kuviin.

**maxRow** - Maksimimäärä samaan aikaan näkyvissä oleville pikkukuville.

**overlayHook** - Callback, jota käytetään päivittämään tällä hetkellä auki olevan pikkukuvan indeksi parent-komponentissa (CompanyInfo.js:ssä) pikkukuvaa klikatessa.

**openImageIndex** - Tällä hetkellä laajennetun pikkukuvan indeksi.

**startAt** - Ensimmäisen näkyvissä olevan pikkukuvan indeksi.

**lastSavedPreviewPosition** - Pikkukuvien viimeisin sijainti rullauksessa.

**overflow** - Laskuri, jota käytetään ensimmäisen näkyvissä olevan pikkukuvan vaihtoon aina, kun arvo nousee yhden kuvan leveyden verran.

**lastActiveThumbnail** - Viimeisimmän avatun pikkukuvan indeksi (käytetään kuvan korostamiseen).

**lastActiveThumbnailHook** - Callback, jolla viimeisimmän avatun pikkukuvan indeksi päivitetään parent-komponentissa (CompanyInfo.js).

<br></br>

## PreviewImageOverlay.js
CompanyThumbnail.js:n alaisuudessa oleva komponentti, joka piirtää valitun pikkukuvan laajennettuna ruudulle. Kuvan yläkulmassa on näppäin, josta automaattisen kuvanvaihdon voi asettaa päälle/pois päältä. Kuvat vaihtuvat fade-siirtymällä. Kuvan oikeassa yläkulmassa on myös ikkunan sulkunäppäin.

### Props
**image** - Linkki kuvaan, joka on tarkoitus piirtää.

**click** - Callback, joka suoritetaan, kun sulkunäppäintä klikataan.

**autoSwitchHook** - Callback, joka ilmoittaa parent-komponentille (CompanyThumbnail.js:lle) automaattisen vaihtumisen säädöstä, jotta parent-komponentti voi päivittää omaa puoltaan vaihtojen mukaan.

<br></br>

## UpperMarginMenu.js
Sivun yläpalkki, josta käyttäjä voi suodattaa organisaatioita tyypin mukaan tai etsiä organisaatioita nimen mukaan. Käyttäjä voi myös uudelleenkatsoa sivun opasteen info-kuvakkeesta, asettaa taustamusiikin päälle/pois päältä kaiuttimen kuvasta tai asettaa 360-näkymän pyörimisen päälle/pois päältä 360-kuvakkeesta. Lisäksi käyttäjä voi vaihtaa sivun käännöksen klikkaamalla vasemmassa yläkulmassa olevia lippuja.

Suodatusvalikko voi sisältää eri tyyppisiä näppäimiä. Suurinosa näppäimistä tällä hetkellä on suodatusnäppäimiä, mutta ne voivat olla myös linkkejä tai. Uusia näppäintyyppejä voi lisätä helposti komponentissa luotuihin valikoihin.

### Props
**setCategories** - Callback, jolla parent-komponentissa (View.js) päivitetään näkyvissä olevat organisaatiopallot suodatusnäppäintä klikatessa.

**setShowForm** - Ei käytössä.

**categories** - Taulukko, joka sisältää käytössä olevat kohderyhmät.

**setSearchInput** - Callback, jolla päivitetään parent-komponentti (View.js) etsintäkentän syötteellä. Parent-komponentti hoitaa oikean organisaation esittelyn avaamisen mikäli etsintäkenttään asetettu 

**setShowTutorialOverlay** - Callback, jolla sivuston opaste käynnistetään.

**companyData** - Sisältää kaiken tiedon organisaatioista.

**handleCompanyClick** - Callback, jolla suodatusvalikossa valittuun popup-näppäimeen sidotun organisaation esittelyruutu avataan. (HUOM! Tällä hetkellä suodatusvalikossa ei ole popup-tyyppisiä näppäimiä.)

**toggleSpin** - Callback, jolla 360-näkymän pyöriminen asetetaan päälle/pois päältä.

**isSpinning** - Määrittelee, pyöriikö 360-näkymä tällä hetkellä. Käytetään 360-kuvakkeen ulkoasun muuttamiseen.

<br></br>

## LanguageSelection.js
UpperMarginMenun alaisuudessa oleva komponentti, joka piirtää lippunäppäimet saatavilla olevia käännösvaihtoehtoja varten. Lippua klikattaessa sivuston kieli vaihtuu, ja sivu uudelleenladataan. Toistaiseksi vain suomen- ja englanninkieliset käännökset ovat varsinaisesti saatavilla.

### Props
Ei ole.

<br></br>

## Flag.js
LanguageSelection.js:n alaiseuuteen tarkoitettu lippunäppäin, jota klikkaamalla sivuston kieli vaihtuu. Kun käyttäjä vie osoittimen lipun päälle, kieli, johon tullaan vaihtamaan, näytetään käyttäjälle *tooltippinä*.

### Props
**tooltip** - Teksti, joka näytetään käyttäjälle, kun osoitin viedään lippuelementin päälle.

**icon** - Lipun kuvakkeen osoite.

**lang** - Kieli (ks. LanguageManager), johon vaihdetaan lippuelementtiä klikattaessa.

<br></br>

## Landscape.js
Täyttää ruudun virheilmoituksella, mikäli mobiililaite on landscape-tilassa. Sivuston elementit eivät asetu landscape-tilassa oikein, joten käyttäjiä ehdotetaan vaihtamaan laitteen suuntaus portrait-tilaan. Kun suuntaus on vaihdettu, virheilmoitus poistuu.

### Props
Ei ole.

<br></br>

## Chat.js
Asiakkaan puolen chat-ikkuna, joka piirretään ruudun oikeaan alalaitaan. Ikkuna kuuntelee palvelimelta tulevia viestejä, ja piirtää tulleet viestit ruudulle soittaen samalla äänimerkin. Jokainen viesti sisältää koko keskustelun. Käyttäjä voi lähettää viestin asiakaspalveluun klikkaamalla *Lähetä*-näppäintä tai painamalla ENTER-näppäintä, kun ikkuna on auki. Mikäli käyttäjä on "scrollannut" keskustelua ylöspäin uuden viestin tullessa, chattiin ilmestyy ilmoitus alempana olevista uusista viesteistä. Jos asiakaspalvelussa ei ole ketään paikalla, ruudulla näytetään ilmoitus käyttäen GeneralNotification.js:ssää.

### Props
**isOpen** - Määrittelee, onko chat-ikkuna auki (eli piirretäänkö se).

**onClose** - Callback, jolla chat-ikkuna suljetaan.

<br></br>

## StartOverlay.js
Sivuston ensimmäinen näkymä, joka sisältää Karelia-ammattikorkeakoulun, EU:n vipuvoimaa ja EU:n aluekehitysrahaston logot, sekä Pohjois-Karjala hahmot. Näkymä avautuu fade-in efektillä ja sisältää aloitusnäppäimen, jota klikkaamalla sivun varsinainen käyttö alkaa.

### Props
**click** - Callback, jolla parent-komponenttille (View.js) ilmoitetaan aloitusnäkymän sulkemisesta aloitusnäppäintä klikatessa.

<br></br>

## TutorialOverlay.js
Piirtää ruudulle sivuston opasteen tämän hetkisen vaiheen. Opaste muodostuu seuraavista välilehtikomponenteista:
- TutorialCategories.js
- TutorialChat.js
- TutorialCompanies.js
- TutorialCompanyInfo.js
- TutorialCompanyInfoContacts.js
- TutorialCompanyInfoSome.js
- TutorialConfirmation.js
- TutorialLanguage.js
- TutorialMusic.js
- TutorialSpin.js

Kaikki yllämainitut välilehtikomponentit käyttävät TutorialWindow.js-komponenttia piirtämään välilehden (ks. TutorialWindow.js), sekä piirtävät ylimääräistä sisältöä, kuten vilkkuvia nuolia (ks. BlinkingArrow.js). TutorialOverlay sisältää funktiot välilehtien vaihtoon.

### Props
**endTutorialHook** - Callback, jolla opaste päätetään. (HUOM! Ei sama kuin opasteen sulkeminen.)

**viewPhase** - Asettaa opasteen vaiheen vain tietyissä tilanteissa. (Yleensä opasteen vaihe muutetaan klikkaamalla opasteen navigaationäppäimiä, mutta organisaatioiden esittelyruutu muuttaa myös vaihetta.)

**closeTutorial** - Callback, jolla opaste suljetaan.

<br></br>

## TutorialWindow.js
Piirtää ruudulle opasteikkunan tekstisisällön sekä navigaationäppäimet, joita klikattaessa suoritetaan parent-välilehtikomponentin (ks. lista TutorialOverlay.js:stä) määräämä toiminto (yleensä siirtyminen opasteessa eteen-/taaksepäin). TutorialWindow on yleinen opasteikkuna, joten suurinosa sen sisällöstä määräytyy parent-välilehtikomponentin mukaan.

### Props
**explanation** - Opasteikkunan selitysteksti. Tekstiin voi lisätä tyhjiä rivejä lisäämällä &lt;br> tagin.

**buttons** - JSON, joka sisältää navigaationäppäimet, jotka piirretään opasteen yhteyteen. **buttons** sisältää kentät *caption* ja *action*. *caption*-kenttä määrää näppäimen otsikon, kun taas *action*-kenttä on callback, joka suoritetaan näppäintä klikattaessa.

    {
        caption: "Testi näppäin",
        action:  () => { console.log("hello world"); }
    }

**additionalStyles** - Sisältää mahdolliset ylimääräiset tyylitykset opasteikkunan selitystekstille ja navigaationäppäimille. Tämä on hyödyllistä mikäli esimerkiksi opasteikkunan selitystekstin pituus on poikkeuksellisen suuri, tai mikäli tekstien pituuden vaihtelevat huomattavasti eri kieliversioilla.

    {
        explantion: "font-size: 12px;",
        button: "font-size: 15px;",
        buttonWidthMul: 1.5,            // Näppäimen leveyskerroin
        buttonHeightMul: 1.5            // Näppäimen korkeuskerroin
    }

**closeTutorial** - Callback, joka sulkee opasteen.

<br></br>

## BlinkingArrow.js
Piirtää ruudulle vilkkuvan nuolen (yleensä TutorialOverlay.js:n alaisuudessa olevaan välilehtikomponenttiin). Nuolen vilkkumistahti on vakio kaikille komponentin ilmentymille (750 ms).

### Props
Ei ole.

<br></br>

## GeneralNotification.js
GeneralNotification piirtää yleisen ilmoitus pop-upin ruudulle. Komponentti on suunniteltu siten, että sitä voidaan käyttää missä tahansa komponentissa. Tällä hetkellä GeneralNotifiactionia käytetään vain Chat.js:n alaisuudessa.

Komponentti piirtää ruudulle pop-up ikkunan, joka sisältää otsikon, ilmoituksen ja kuittausnäppäimen.

### Props
**title** - Ilmoituksen otsikko.

**content** - Ilmoitusviesti.

**clickOk** - Callback, jolla käyttäjä kuittaa ilmoituksen ja sulkee ikkunan.

<br></br>
<br></br>


# Moderaattorisivu
Tässä osiossa käydään läpi moderaattorin sivuston komponentteja ja toiminnallisuuksia. Sivustolla ylläpitäjä voi lisätä uusia organisaatioita tietokantaan lisäyslomakkeen kautta, lukea ja vastata asiakkaiden chat-viesteihin sekä nähdä sivuston kävijämäärän. Sivustoon pääse vain antamalla käyttäjätunnuksen ja salasanan.

Sivustolla käytettyjä toteutustekniikoita/kirjastoja:
- [React](https://reactjs.org/) **-- pohjana toimiva sovelluskehys**
- [styled-components](https://styled-components.com/) **-- komponenttien tyylitys**
- [Formik](https://formik.org/docs/overview) **-- organisaatioiden lisäyslomake**
- [Yup](https://www.npmjs.com/package/yup) **-- tarkistaa lomakkeen pakolliset kentät**

Moderaattorisivun komponentit, audioassetit ja graafinen sisältö löytyy kansiosita `InfoForm\` ja `chatmoderator\`.

<br></br>

## LoginScreen.js
ChatModerator.js:n alaisuudessa oleva komponentti, joka piirtää ruudulle sisäänkirjautumisikkunan moderaattorisivulle. Ikkunassa on käyttäjätunnus- ja salasanakenttä. "Kirjaudu"-näppäintä klikattaessa käyttäjä siirtyy moderaattorisivulle mikäli käyttäjätunnus on olemassa ja salasana täsmää. Muussa tapauksessa käyttäjä saa virheilmoituksen.

### Props
**onLoginClick** -- Callback, jota käyttäen moderaattorisivu näytetään onnistuneet kirjautumisen jälkeen.

<br></br>

## ChatModerator.js
ChatModerator toimii moderaattorisivun pohjimmaisimpana komponenttina piirtäen sisäänkirjautumisikkunan (LoginScreen.js) mikäli käyttäjä ei ole kirjautunut sisään, tai moderaattorichatin näkymän, jos käyttäjä on kirjautunut onnistuneesti.

ChatModerator piirtää sivun vasempaan laitaan sessiolistan, jossa näkyy jokainen asiakas, jolla on avoin chat ikkuna. Listassa olevia sessioita klikkaamalla käyttäjä voi avata ikkunan, joka sisältää kyseisen asiakkaan ja moderaattorin väliset viestit mikäli niitä on. Kun asiakas poistuu sivulta, hänen sessionsa poistetaan myös sessiolistasta. Jos asiakas lähettää moderaattorille viestin asiakkaan ikkunan ollessa kiinni moderaattorin puolella, kyseisen asiakkaan sessio alkaa välkkymään sessiolistassa. Samalla soitetaan myös äänimerkki, joka toistetaan 2 minuutin välein mikäli moderaattori ei ole reagoinut avaamalla asiakkaan sessiota.

### Sijoitusjärjestelmä
ChatModerator-komponentti sisältää myös sijoitusjärjestelmän, jonka avulla sessioiden chatikkunoita (ChatView.js) asetetaan näkymään. Oletuksena ikkunoita voi olla horisontaalisti korkeintaan 2 ja vertikaalisti korkeintaan 10 ( *yht. 20* ). Kun ikkuna avataan, järjestelmä varaa sille paikan ruudulta, mikäli vapaita paikkoja on. Jos vapaita paikkoja ei ole, ikkunaa ei avata. Ikkunan sulkeutuessa sen paikka vapautetaan sijoitusjärjestelmässä.

### Chattien tietorakenne
Chattien sessiot tallennetaan ChatModerator-komponentissa *chatSessionsRef* taulukkoon. Jokainen sessio on JSON-objekti, joka sisältää session ID:n ( *guid* ), session ikkunan sijoituksen ( *spot* ), tiedon ikkunan aktiivisuudesta ( *isActive* ) sekä taulukon viesteistä moderaattorin ja asiakkaan välillä ( *msgs* ).

Esimerkki *chatSessionsRef*-taulukosta (ei sisällä viestien rakennetta, ks. ChatView.js:n *messages*-proppi):

    [
        {
            guid: "gzO4lzUMHo",
            spot: { x: 0, y: 0 },
            msgs: [...],
            isActive: true
        },
        {
            guid: "12v4cJeAAr",
            spot: { x: 1, y: 0 },
            msgs: [...],
            isActive: true
        }
    ]

### Props
Ei ole.

<br></br>


## ChatView.js
ChatModerator.js:n alaisuudessa oleva komponentti, joak piirtää moderaattorisivulle chat-ikkunan, joka edustaa tietyn asiakkaan sessiota. Ikkunan otsikkona on asiakkaan session ID. Ikkunassa näkyy tummanharmaissa kuplissa asiakkaan viestit. Moderaattorin lähettämät viestit näkyvät vaaleanharmaissa kuplissa paksulla tekstillä. Ikkunan voi sulkea oikeassa ylälulmassa olevaa näppäintä käyttäen.

Käyttäjä voi lähettää asiakkaalle tekstikenttään kirjoitettuja viestejä *Lähetä* -näppäintä painamalla tai *ENTER* -näppäimellä. Viestejä voi lähettää vain mikäli ikkuna on aktiivinen, jolloin ikkuna on selkeästi näkyvissä. Ei-aktiiviset näkyvät *himmeinä* (korkeampi läpinäkyvyys).

### Props
**messages** -- Taulukko, joka sisältää moderaattorin ja asiakkaan välisiä viestejä edustavia JSON-objekteja. Jokaisessa viestissä on *isAdmin*-, *guid*- ja *usermessage*-kentät. *isAdmin* määrittää, onko viesti moderaattorin vai asiakkaan. *guid* sisältää session ID:n. *usermessage* sisältää itse viestin.

    [
        {
            isAdmin: false,
            guid: "gzO4lzUMHo",
            usermessage: "Hei!"
        },
        {
            isAdmin: true,
            guid: "gzO4lzUMHo",
            usermessage: "Hei! Kuinka voin auttaa?"
        }
    ]

**closeWindow** -- Callback, jolla ikkuna suljetaan.

**send** -- Callback, jolla parent-komponentti (ChatModerator.js) lähettää tekstikenttään kirjoitetun viestin asiakkaalle.

**userId** -- Asiakkaan session ID, joka piirretään ikkunan otsikoksi.

**spot** -- JSON-objekti, joka sisältää tiedon siitä, kuinka monentena ikkuna on horisontaalissa järjestyksessä ( *x* ) ja vertikaalisessa järjestyksessä ( *y* ).

    {
        x: 1
        y: 0
    }

**activate** -- Callback, jolla ikkuna aktivoidaan.

**focusedOn** -- Määrittää, onko ikkuna tällä hetkellä aktiivinen.

**clientLeft** -- Määrittää, onko ikkunan edustama asiakas poistunut chatista.

<br></br>

## ViewCounter.js
ChatModerator.js:n alaisuudessa oleva komponentti, joka piirtää ruudulle sivuston kävijämittarin. Mittarissa näkyy tällä hetkellä chatissa olevien vierailijoiden määrä sekä vierailujen kokonaismäärä. Parent-komponentti (ChatModerator.js) lähettää vierailujen määrät **propsien** kautta.

### Props
**total** -- Vierailujen määrä yhteensä sivun alusta saakka.
**inChat** -- Chatissa tällä hetkellä olevien vierailijoiden määrä.