New analytics feature (#2150)

* New analytics feature

Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com>

* Fix eslint swaggerJsdoc

Signed-off-by: Gregoire Parant <g.parant@thecodingmachine.com>
This commit is contained in:
grégoire parant 2022-04-29 20:53:33 +02:00 committed by GitHub
parent 5e156ade74
commit 755ca93d49
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 421 additions and 37 deletions

View File

@ -17,7 +17,7 @@ class AnalyticsClient {
} }
} }
identifyUser(uuid: string, email: string | null) { identifyUser(uuid: string, email: string | null): void {
this.posthogPromise this.posthogPromise
?.then((posthog) => { ?.then((posthog) => {
posthog.identify(uuid, { uuid, email, wa: true }); posthog.identify(uuid, { uuid, email, wa: true });
@ -25,7 +25,7 @@ class AnalyticsClient {
.catch((e) => console.error(e)); .catch((e) => console.error(e));
} }
loggedWithSso() { loggedWithSso(): void {
this.posthogPromise this.posthogPromise
?.then((posthog) => { ?.then((posthog) => {
posthog.capture("wa-logged-sso"); posthog.capture("wa-logged-sso");
@ -33,7 +33,7 @@ class AnalyticsClient {
.catch((e) => console.error(e)); .catch((e) => console.error(e));
} }
loggedWithToken() { loggedWithToken(): void {
this.posthogPromise this.posthogPromise
?.then((posthog) => { ?.then((posthog) => {
posthog.capture("wa-logged-token"); posthog.capture("wa-logged-token");
@ -41,7 +41,7 @@ class AnalyticsClient {
.catch((e) => console.error(e)); .catch((e) => console.error(e));
} }
enteredRoom(roomId: string, roomGroup: string | null) { enteredRoom(roomId: string, roomGroup: string | null): void {
this.posthogPromise this.posthogPromise
?.then((posthog) => { ?.then((posthog) => {
posthog.capture("$pageView", { roomId, roomGroup }); posthog.capture("$pageView", { roomId, roomGroup });
@ -50,7 +50,7 @@ class AnalyticsClient {
.catch((e) => console.error(e)); .catch((e) => console.error(e));
} }
openedMenu() { openedMenu(): void {
this.posthogPromise this.posthogPromise
?.then((posthog) => { ?.then((posthog) => {
posthog.capture("wa-opened-menu"); posthog.capture("wa-opened-menu");
@ -58,7 +58,7 @@ class AnalyticsClient {
.catch((e) => console.error(e)); .catch((e) => console.error(e));
} }
launchEmote(emote: string) { launchEmote(emote: string): void {
this.posthogPromise this.posthogPromise
?.then((posthog) => { ?.then((posthog) => {
posthog.capture("wa-emote-launch", { emote }); posthog.capture("wa-emote-launch", { emote });
@ -66,7 +66,7 @@ class AnalyticsClient {
.catch((e) => console.error(e)); .catch((e) => console.error(e));
} }
enteredJitsi(roomName: string, roomId: string) { enteredJitsi(roomName: string, roomId: string): void {
this.posthogPromise this.posthogPromise
?.then((posthog) => { ?.then((posthog) => {
posthog.capture("wa-entered-jitsi", { roomName, roomId }); posthog.capture("wa-entered-jitsi", { roomName, roomId });
@ -74,7 +74,7 @@ class AnalyticsClient {
.catch((e) => console.error(e)); .catch((e) => console.error(e));
} }
validationName() { validationName(): void {
this.posthogPromise this.posthogPromise
?.then((posthog) => { ?.then((posthog) => {
posthog.capture("wa-name-validation"); posthog.capture("wa-name-validation");
@ -82,7 +82,7 @@ class AnalyticsClient {
.catch((e) => console.error(e)); .catch((e) => console.error(e));
} }
validationWoka(scene: string) { validationWoka(scene: string): void {
this.posthogPromise this.posthogPromise
?.then((posthog) => { ?.then((posthog) => {
posthog.capture("wa-woka-validation", { scene }); posthog.capture("wa-woka-validation", { scene });
@ -90,12 +90,309 @@ class AnalyticsClient {
.catch((e) => console.error(e)); .catch((e) => console.error(e));
} }
validationVideo() { validationVideo(): void {
this.posthogPromise this.posthogPromise
?.then((posthog) => { ?.then((posthog) => {
posthog.capture("wa-video-validation"); posthog.capture("wa-video-validation");
}) })
.catch((e) => console.error(e)); .catch((e) => console.error(e));
} }
/** New feature analytics **/
openedChat(): void {
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa-opened-chat");
})
.catch((e) => console.error(e));
}
openRegister(): void {
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa-opened-register");
})
.catch((e) => console.error(e));
}
openInvite(): void {
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa-opened-invite");
})
.catch((e) => console.error(e));
}
lockDiscussion(): void {
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa_lockroom");
})
.catch((e) => console.error(e));
}
screenSharing(): void {
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa-screensharing");
})
.catch((e) => console.error(e));
}
follow(): void {
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa_follow");
})
.catch((e) => console.error(e));
}
camera(): void {
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa_camera");
})
.catch((e) => console.error(e));
}
microphone(): void {
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa_microphone");
})
.catch((e) => console.error(e));
}
settingMicrophone(value: string): void {
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa_setting_microphone", {
checkbox: value,
});
})
.catch((e) => console.error(e));
}
settingCamera(value: string): void {
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa_setting_camera", {
checkbox: value,
});
})
.catch((e) => console.error(e));
}
settingNotification(value: string): void {
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa_setting_notification", {
checkbox: value,
});
})
.catch((e) => console.error(e));
}
settingFullscreen(value: string): void {
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa_setting_fullscreen", {
checkbox: value,
});
})
.catch((e) => console.error(e));
}
settingAskWebsite(value: string): void {
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa_setting_ask_website", {
checkbox: value,
});
})
.catch((e) => console.error(e));
}
settingRequestFollow(value: string): void {
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa_setting_request_follow", {
checkbox: value,
});
})
.catch((e) => console.error(e));
}
settingDecreaseAudioVolume(value: string): void {
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa_setting_decrease_audio_volume", {
checkbox: value,
});
})
.catch((e) => console.error(e));
}
login(): void {
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa_login");
})
.catch((e) => console.error(e));
}
logout(): void {
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa_logout");
})
.catch((e) => console.error(e));
}
switchMultiIframe(): void {
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa_multiiframe_switch");
})
.catch((e) => console.error(e));
}
closeMultiIframe(): void {
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa_multiiframe_close");
})
.catch((e) => console.error(e));
}
fullScreenMultiIframe(): void {
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa_multiiframe_fullscreen");
})
.catch((e) => console.error(e));
}
stackOpenCloseMultiIframe(): void {
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa_multiiframe_stack_open_close");
})
.catch((e) => console.error(e));
}
menuCredit(): void {
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa_menu_credit");
})
.catch((e) => console.error(e));
}
menuProfile(): void {
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa_menu_profile");
})
.catch((e) => console.error(e));
}
menuSetting() {
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa_menu_setting");
})
.catch((e) => console.error(e));
}
menuInvite(): void {
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa_menu_invite");
})
.catch((e) => console.error(e));
}
globalMessage(): void {
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa_menu_globalmessage");
})
.catch((e) => console.error(e));
}
menuContact(): void {
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa_menu_contact");
})
.catch((e) => console.error(e));
}
inviteCopyLink(): void {
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa_menu_invite_copylink");
})
.catch((e) => console.error(e));
}
inviteCopyLinkWalk(value: string): void {
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa_menu_invite_copylink_walk", {
checkbox: value,
});
})
.catch((e) => console.error(e));
}
editCompanion(): void {
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa_edit_companion");
})
.catch((e) => console.error(e));
}
editCamera(): void {
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa_edit_camera");
})
.catch((e) => console.error(e));
}
editName(): void {
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa_edit_name");
})
.catch((e) => console.error(e));
}
editWoka(): void {
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa_edit_woka");
})
.catch((e) => console.error(e));
}
selectWoka(): void {
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa_wokascene_select");
})
.catch((e) => console.error(e));
}
selectCustomWoka(): void {
this.posthogPromise
?.then((posthog) => {
posthog.capture("wa_wokascene_custom");
})
.catch((e) => console.error(e));
}
} }
export const analyticsClient = new AnalyticsClient(); export const analyticsClient = new AnalyticsClient();

View File

@ -17,6 +17,7 @@
import { followRoleStore, followStateStore, followUsersStore } from "../Stores/FollowStore"; import { followRoleStore, followStateStore, followUsersStore } from "../Stores/FollowStore";
import { gameManager } from "../Phaser/Game/GameManager"; import { gameManager } from "../Phaser/Game/GameManager";
import { currentPlayerGroupLockStateStore } from "../Stores/CurrentPlayerGroupStore"; import { currentPlayerGroupLockStateStore } from "../Stores/CurrentPlayerGroupStore";
import { analyticsClient } from "../Administration/AnalyticsClient";
const gameScene = gameManager.getCurrentGameScene(); const gameScene = gameManager.getCurrentGameScene();
@ -89,6 +90,7 @@
class="btn-follow" class="btn-follow"
class:hide={($peerStore.size === 0 && $followStateStore === "off") || $silentStore} class:hide={($peerStore.size === 0 && $followStateStore === "off") || $silentStore}
class:disabled={$followStateStore !== "off"} class:disabled={$followStateStore !== "off"}
on:click={() => analyticsClient.follow()}
on:click={followClick} on:click={followClick}
> >
<img class="noselect" src={followImg} alt="" /> <img class="noselect" src={followImg} alt="" />
@ -98,6 +100,7 @@
class="btn-lock" class="btn-lock"
class:hide={$peerStore.size === 0 || $silentStore} class:hide={$peerStore.size === 0 || $silentStore}
class:disabled={$currentPlayerGroupLockStateStore} class:disabled={$currentPlayerGroupLockStateStore}
on:click={() => analyticsClient.lockDiscussion()}
on:click={lockClick} on:click={lockClick}
> >
<img class="noselect" src={lockImg} alt="" /> <img class="noselect" src={lockImg} alt="" />
@ -105,6 +108,7 @@
<div <div
class="btn-monitor" class="btn-monitor"
on:click={() => analyticsClient.screenSharing()}
on:click={screenSharingClick} on:click={screenSharingClick}
class:hide={!$screenSharingAvailableStore || $silentStore} class:hide={!$screenSharingAvailableStore || $silentStore}
class:enabled={$requestedScreenSharingState} class:enabled={$requestedScreenSharingState}
@ -116,7 +120,12 @@
{/if} {/if}
</div> </div>
<div class="btn-video" on:click={cameraClick} class:disabled={!$requestedCameraState || $silentStore}> <div
class="btn-video"
on:click={() => analyticsClient.camera()}
on:click={cameraClick}
class:disabled={!$requestedCameraState || $silentStore}
>
{#if $requestedCameraState && !$silentStore} {#if $requestedCameraState && !$silentStore}
<img class="noselect" src={cinemaImg} alt="Turn on webcam" /> <img class="noselect" src={cinemaImg} alt="Turn on webcam" />
{:else} {:else}
@ -124,7 +133,12 @@
{/if} {/if}
</div> </div>
<div class="btn-micro" on:click={microphoneClick} class:disabled={!$requestedMicrophoneState || $silentStore}> <div
class="btn-micro"
on:click={() => analyticsClient.microphone()}
on:click={microphoneClick}
class:disabled={!$requestedMicrophoneState || $silentStore}
>
{#if $requestedMicrophoneState && !$silentStore} {#if $requestedMicrophoneState && !$silentStore}
<img class="noselect" src={microphoneImg} alt="Turn on microphone" /> <img class="noselect" src={microphoneImg} alt="Turn on microphone" />
{:else} {:else}

View File

@ -10,6 +10,7 @@
import { coWebsiteManager } from "../../WebRtc/CoWebsiteManager"; import { coWebsiteManager } from "../../WebRtc/CoWebsiteManager";
import uploadFile from "../images/jitsi.png"; import uploadFile from "../images/jitsi.png";
import { analyticsClient } from "../../Administration/AnalyticsClient";
export let index: number; export let index: number;
export let coWebsite: CoWebsite; export let coWebsite: CoWebsite;
@ -89,6 +90,7 @@
class:ready={$state === "ready"} class:ready={$state === "ready"}
class:displayed={isMain || isHighlight} class:displayed={isMain || isHighlight}
class:vertical class:vertical
on:click={() => analyticsClient.stackOpenCloseMultiIframe()}
on:click={onClick} on:click={onClick}
> >
<img <img

View File

@ -2,6 +2,7 @@
import LL from "../../i18n/i18n-svelte"; import LL from "../../i18n/i18n-svelte";
import { gameManager } from "../../Phaser/Game/GameManager"; import { gameManager } from "../../Phaser/Game/GameManager";
import { startLayerNamesStore } from "../../Stores/StartLayerNamesStore"; import { startLayerNamesStore } from "../../Stores/StartLayerNamesStore";
import { analyticsClient } from "../../Administration/AnalyticsClient";
let entryPoint: string = $startLayerNamesStore[0]; let entryPoint: string = $startLayerNamesStore[0];
let walkAutomatically: boolean = false; let walkAutomatically: boolean = false;
@ -54,16 +55,26 @@
class="link-url nes-input is-dark" class="link-url nes-input is-dark"
value={location.toString()} value={location.toString()}
/> />
<button type="button" class="nes-btn is-primary" on:click={copyLink}>{$LL.menu.invite.copy()}</button> <button
type="button"
class="nes-btn is-primary"
on:click={() => analyticsClient.inviteCopyLink()}
on:click={copyLink}>{$LL.menu.invite.copy()}</button
>
</section> </section>
{:else} {:else}
<section class="is-mobile"> <section class="is-mobile">
<h3>{$LL.menu.invite.description()}</h3> <h3>{$LL.menu.invite.description()}</h3>
<input type="hidden" readonly id="input-share-link" value={location.toString()} /> <input type="hidden" readonly id="input-share-link" value={location.toString()} />
<button type="button" class="nes-btn is-primary" on:click={shareLink}>{$LL.menu.invite.share()}</button> <button
type="button"
class="nes-btn is-primary"
on:click={() => analyticsClient.inviteCopyLink()}
on:click={shareLink}>{$LL.menu.invite.share()}</button
>
</section> </section>
{/if} {/if}
<h3>Select an entry point</h3> <h3>{$LL.menu.invite.selectEntryPoint()}</h3>
<section class="nes-select is-dark starting-points"> <section class="nes-select is-dark starting-points">
<select <select
bind:value={entryPoint} bind:value={entryPoint}
@ -81,11 +92,12 @@
type="checkbox" type="checkbox"
class="nes-checkbox is-dark" class="nes-checkbox is-dark"
bind:checked={walkAutomatically} bind:checked={walkAutomatically}
on:change={(e) => analyticsClient.inviteCopyLinkWalk(e.currentTarget.value)}
on:change={() => { on:change={() => {
updateInputFieldValue(); updateInputFieldValue();
}} }}
/> />
<span>{$LL.menu.invite.walk_automatically_to_position()}</span> <span>{$LL.menu.invite.walkAutomaticallyToPosition()}</span>
</label> </label>
</section> </section>
</div> </div>

View File

@ -18,6 +18,7 @@
import type { Unsubscriber } from "svelte/store"; import type { Unsubscriber } from "svelte/store";
import { sendMenuClickedEvent } from "../../Api/iframe/Ui/MenuItem"; import { sendMenuClickedEvent } from "../../Api/iframe/Ui/MenuItem";
import LL from "../../i18n/i18n-svelte"; import LL from "../../i18n/i18n-svelte";
import { analyticsClient } from "../../Administration/AnalyticsClient";
let activeSubMenu: MenuItem = $subMenusStore[0]; let activeSubMenu: MenuItem = $subMenusStore[0];
let activeComponent: typeof ProfileSubMenu | typeof CustomSubMenu = ProfileSubMenu; let activeComponent: typeof ProfileSubMenu | typeof CustomSubMenu = ProfileSubMenu;
@ -47,21 +48,27 @@
activeSubMenu = menu; activeSubMenu = menu;
switch (menu.key) { switch (menu.key) {
case SubMenusInterface.settings: case SubMenusInterface.settings:
analyticsClient.menuSetting();
activeComponent = SettingsSubMenu; activeComponent = SettingsSubMenu;
break; break;
case SubMenusInterface.profile: case SubMenusInterface.profile:
analyticsClient.menuProfile();
activeComponent = ProfileSubMenu; activeComponent = ProfileSubMenu;
break; break;
case SubMenusInterface.invite: case SubMenusInterface.invite:
analyticsClient.menuInvite();
activeComponent = GuestSubMenu; activeComponent = GuestSubMenu;
break; break;
case SubMenusInterface.aboutRoom: case SubMenusInterface.aboutRoom:
analyticsClient.menuCredit();
activeComponent = AboutRoomSubMenu; activeComponent = AboutRoomSubMenu;
break; break;
case SubMenusInterface.globalMessages: case SubMenusInterface.globalMessages:
analyticsClient.globalMessage();
activeComponent = (await import("./GlobalMessagesSubMenu.svelte")).default; activeComponent = (await import("./GlobalMessagesSubMenu.svelte")).default;
break; break;
case SubMenusInterface.contact: case SubMenusInterface.contact:
analyticsClient.menuContact();
activeComponent = ContactSubMenu; activeComponent = ContactSubMenu;
break; break;
} }

View File

@ -10,6 +10,7 @@
import { ADMIN_URL } from "../../Enum/EnvironmentVariable"; import { ADMIN_URL } from "../../Enum/EnvironmentVariable";
import { showShareLinkMapModalStore } from "../../Stores/ModalStore"; import { showShareLinkMapModalStore } from "../../Stores/ModalStore";
import LL from "../../i18n/i18n-svelte"; import LL from "../../i18n/i18n-svelte";
import { analyticsClient } from "../../Administration/AnalyticsClient";
function showMenu() { function showMenu() {
menuVisiblilityStore.set(!get(menuVisiblilityStore)); menuVisiblilityStore.set(!get(menuVisiblilityStore));
@ -42,7 +43,8 @@
class="nes-pointer" class="nes-pointer"
draggable="false" draggable="false"
on:dragstart|preventDefault={noDrag} on:dragstart|preventDefault={noDrag}
on:click|preventDefault={showInvite} on:click={() => analyticsClient.openInvite()}
on:click={showInvite}
/> />
<img <img
src={logoRegister} src={logoRegister}
@ -50,7 +52,8 @@
class="nes-pointer" class="nes-pointer"
draggable="false" draggable="false"
on:dragstart|preventDefault={noDrag} on:dragstart|preventDefault={noDrag}
on:click|preventDefault={register} on:click={() => analyticsClient.openRegister()}
on:click={register}
/> />
{:else} {:else}
<img <img
@ -59,7 +62,8 @@
class="nes-pointer" class="nes-pointer"
draggable="false" draggable="false"
on:dragstart|preventDefault={noDrag} on:dragstart|preventDefault={noDrag}
on:click|preventDefault={showMenu} on:click={() => analyticsClient.openedMenu()}
on:click={showMenu}
/> />
{/if} {/if}
<img <img
@ -68,7 +72,8 @@
class="nes-pointer" class="nes-pointer"
draggable="false" draggable="false"
on:dragstart|preventDefault={noDrag} on:dragstart|preventDefault={noDrag}
on:click|preventDefault={showChat} on:click={() => analyticsClient.openedMenu()}
on:click={showChat}
/> />
</main> </main>

View File

@ -23,6 +23,7 @@
import Woka from "../Woka/Woka.svelte"; import Woka from "../Woka/Woka.svelte";
import Companion from "../Companion/Companion.svelte"; import Companion from "../Companion/Companion.svelte";
import LL from "../../i18n/i18n-svelte"; import LL from "../../i18n/i18n-svelte";
import { analyticsClient } from "../../Administration/AnalyticsClient";
function disableMenuStores() { function disableMenuStores() {
menuVisiblilityStore.set(false); menuVisiblilityStore.set(false);
@ -62,19 +63,39 @@
<div class="customize-main"> <div class="customize-main">
<div class="submenu"> <div class="submenu">
<section> <section>
<button type="button" class="nes-btn" on:click|preventDefault={openEditNameScene}> <button
type="button"
class="nes-btn"
on:click={() => analyticsClient.editName()}
on:click={openEditNameScene}
>
<img src={btnProfileSubMenuIdentity} alt={$LL.menu.profile.edit.name()} /> <img src={btnProfileSubMenuIdentity} alt={$LL.menu.profile.edit.name()} />
<span class="btn-hover">{$LL.menu.profile.edit.name()}</span> <span class="btn-hover">{$LL.menu.profile.edit.name()}</span>
</button> </button>
<button type="button" class="nes-btn" on:click|preventDefault={openEditSkinScene}> <button
type="button"
class="nes-btn"
on:click={() => analyticsClient.editWoka()}
on:click={openEditSkinScene}
>
<Woka userId={-1} placeholderSrc="" width="26px" height="26px" /> <Woka userId={-1} placeholderSrc="" width="26px" height="26px" />
<span class="btn-hover">{$LL.menu.profile.edit.woka()}</span> <span class="btn-hover">{$LL.menu.profile.edit.woka()}</span>
</button> </button>
<button type="button" class="nes-btn" on:click|preventDefault={openEditCompanionScene}> <button
type="button"
class="nes-btn"
on:click={() => analyticsClient.editCompanion()}
on:click={openEditCompanionScene}
>
<Companion userId={-1} placeholderSrc={btnProfileSubMenuCompanion} width="26px" height="26px" /> <Companion userId={-1} placeholderSrc={btnProfileSubMenuCompanion} width="26px" height="26px" />
<span class="btn-hover">{$LL.menu.profile.edit.companion()}</span> <span class="btn-hover">{$LL.menu.profile.edit.companion()}</span>
</button> </button>
<button type="button" class="nes-btn" on:click|preventDefault={openEnableCameraScene}> <button
type="button"
class="nes-btn"
on:click={() => analyticsClient.editCamera()}
on:click={openEnableCameraScene}
>
<img src={btnProfileSubMenuCamera} alt={$LL.menu.profile.edit.camera()} /> <img src={btnProfileSubMenuCamera} alt={$LL.menu.profile.edit.camera()} />
<span class="btn-hover">{$LL.menu.profile.edit.camera()}</span> <span class="btn-hover">{$LL.menu.profile.edit.camera()}</span>
</button> </button>
@ -89,13 +110,15 @@
{/if} {/if}
</section> </section>
<section> <section>
<button type="button" class="nes-btn" on:click|preventDefault={logOut} <button type="button" class="nes-btn" on:click={() => analyticsClient.logout()} on:click={logOut}
>{$LL.menu.profile.logout()}</button >{$LL.menu.profile.logout()}</button
> >
</section> </section>
{:else} {:else}
<section> <section>
<a type="button" class="nes-btn" href="/login">{$LL.menu.profile.login()}</a> <a type="button" class="nes-btn" href="/login" on:click={() => analyticsClient.login()}
>{$LL.menu.profile.login()}</a
>
</section> </section>
{/if} {/if}
</div> </div>

View File

@ -10,6 +10,7 @@
import { audioManagerVolumeStore } from "../../Stores/AudioManagerStore"; import { audioManagerVolumeStore } from "../../Stores/AudioManagerStore";
import infoImg from "../images/info.svg"; import infoImg from "../images/info.svg";
import { analyticsClient } from "../../Administration/AnalyticsClient";
let fullscreen: boolean = localUserStore.getFullscreen(); let fullscreen: boolean = localUserStore.getFullscreen();
let notification: boolean = localUserStore.getNotification() === "granted"; let notification: boolean = localUserStore.getNotification() === "granted";
@ -191,11 +192,21 @@
</div> </div>
</div> </div>
<label> <label>
<input type="checkbox" class="nes-checkbox is-dark" bind:checked={valueCameraPrivacySettings} /> <input
type="checkbox"
class="nes-checkbox is-dark"
on:change={(event) => analyticsClient.settingCamera(event.currentTarget.value)}
bind:checked={valueCameraPrivacySettings}
/>
<span>{$LL.menu.settings.privacySettings.cameraToggle()}</span> <span>{$LL.menu.settings.privacySettings.cameraToggle()}</span>
</label> </label>
<label> <label>
<input type="checkbox" class="nes-checkbox is-dark" bind:checked={valueMicrophonePrivacySettings} /> <input
type="checkbox"
class="nes-checkbox is-dark"
on:change={(event) => analyticsClient.settingMicrophone(event.currentTarget.value)}
bind:checked={valueMicrophonePrivacySettings}
/>
<span>{$LL.menu.settings.privacySettings.microphoneToggle()}</span> <span>{$LL.menu.settings.privacySettings.microphoneToggle()}</span>
</label> </label>
</section> </section>
@ -211,6 +222,7 @@
type="checkbox" type="checkbox"
class="nes-checkbox is-dark" class="nes-checkbox is-dark"
bind:checked={fullscreen} bind:checked={fullscreen}
on:change={(event) => analyticsClient.settingFullscreen(event.currentTarget.value)}
on:change={changeFullscreen} on:change={changeFullscreen}
/> />
<span>{$LL.menu.settings.fullscreen()}</span> <span>{$LL.menu.settings.fullscreen()}</span>
@ -220,6 +232,7 @@
type="checkbox" type="checkbox"
class="nes-checkbox is-dark" class="nes-checkbox is-dark"
bind:checked={notification} bind:checked={notification}
on:change={(event) => analyticsClient.settingNotification(event.currentTarget.value)}
on:change={changeNotification} on:change={changeNotification}
/> />
<span>{$LL.menu.settings.notifications()}</span> <span>{$LL.menu.settings.notifications()}</span>
@ -229,6 +242,7 @@
type="checkbox" type="checkbox"
class="nes-checkbox is-dark" class="nes-checkbox is-dark"
bind:checked={forceCowebsiteTrigger} bind:checked={forceCowebsiteTrigger}
on:change={(event) => analyticsClient.settingAskWebsite(event.currentTarget.value)}
on:change={changeForceCowebsiteTrigger} on:change={changeForceCowebsiteTrigger}
/> />
<span>{$LL.menu.settings.cowebsiteTrigger()}</span> <span>{$LL.menu.settings.cowebsiteTrigger()}</span>
@ -238,6 +252,7 @@
type="checkbox" type="checkbox"
class="nes-checkbox is-dark" class="nes-checkbox is-dark"
bind:checked={ignoreFollowRequests} bind:checked={ignoreFollowRequests}
on:change={(event) => analyticsClient.settingRequestFollow(event.currentTarget.value)}
on:change={changeIgnoreFollowRequests} on:change={changeIgnoreFollowRequests}
/> />
<span>{$LL.menu.settings.ignoreFollowRequest()}</span> <span>{$LL.menu.settings.ignoreFollowRequest()}</span>
@ -246,6 +261,7 @@
type="checkbox" type="checkbox"
class="nes-checkbox is-dark" class="nes-checkbox is-dark"
bind:checked={decreaseAudioPlayerVolumeWhileTalking} bind:checked={decreaseAudioPlayerVolumeWhileTalking}
on:change={(event) => analyticsClient.settingDecreaseAudioVolume(event.currentTarget.value)}
on:change={changeDecreaseAudioPlayerVolumeWhileTalking} on:change={changeDecreaseAudioPlayerVolumeWhileTalking}
/> />
<span>{$LL.audio.manager.reduce()}</span> <span>{$LL.audio.manager.reduce()}</span>

View File

@ -3,6 +3,7 @@
import { SelectCharacterScene, SelectCharacterSceneName } from "../../Phaser/Login/SelectCharacterScene"; import { SelectCharacterScene, SelectCharacterSceneName } from "../../Phaser/Login/SelectCharacterScene";
import LL from "../../i18n/i18n-svelte"; import LL from "../../i18n/i18n-svelte";
import { customizeAvailableStore, selectedCollection } from "../../Stores/SelectCharacterSceneStore"; import { customizeAvailableStore, selectedCollection } from "../../Stores/SelectCharacterSceneStore";
import { analyticsClient } from "../../Administration/AnalyticsClient";
export let game: Game; export let game: Game;
@ -40,13 +41,15 @@
<button <button
type="submit" type="submit"
class="selectCharacterSceneFormSubmit nes-btn is-primary" class="selectCharacterSceneFormSubmit nes-btn is-primary"
on:click|preventDefault={cameraScene}>{$LL.woka.selectWoka.continue()}</button on:click={() => analyticsClient.selectWoka()}
on:click={cameraScene}>{$LL.woka.selectWoka.continue()}</button
> >
{#if $customizeAvailableStore} {#if $customizeAvailableStore}
<button <button
type="submit" type="submit"
class="selectCharacterSceneFormCustomYourOwnSubmit nes-btn" class="selectCharacterSceneFormCustomYourOwnSubmit nes-btn"
on:click|preventDefault={customizeScene}>{$LL.woka.selectWoka.customize()}</button on:click={() => analyticsClient.selectCustomWoka()}
on:click={customizeScene}>{$LL.woka.selectWoka.customize()}</button
> >
{/if} {/if}
</section> </section>

View File

@ -2,7 +2,6 @@ import { get, writable } from "svelte/store";
import Timeout = NodeJS.Timeout; import Timeout = NodeJS.Timeout;
import { userIsAdminStore } from "./GameStore"; import { userIsAdminStore } from "./GameStore";
import { CONTACT_URL, IDENTITY_URL, PROFILE_URL } from "../Enum/EnvironmentVariable"; import { CONTACT_URL, IDENTITY_URL, PROFILE_URL } from "../Enum/EnvironmentVariable";
import { analyticsClient } from "../Administration/AnalyticsClient";
import type { Translation } from "../i18n/i18n-types"; import type { Translation } from "../i18n/i18n-types";
import axios from "axios"; import axios from "axios";
import { localUserStore } from "../Connexion/LocalUserStore"; import { localUserStore } from "../Connexion/LocalUserStore";
@ -14,7 +13,6 @@ export const userIsConnected = writable(false);
export const profileAvailable = writable(true); export const profileAvailable = writable(true);
menuVisiblilityStore.subscribe((value) => { menuVisiblilityStore.subscribe((value) => {
if (value) analyticsClient.openedMenu();
if (userIsConnected && value && IDENTITY_URL != null) { if (userIsConnected && value && IDENTITY_URL != null) {
axios.get(getMeUrl()).catch((err) => { axios.get(getMeUrl()).catch((err) => {
console.error("menuVisiblilityStore => err => ", err); console.error("menuVisiblilityStore => err => ", err);

View File

@ -8,6 +8,7 @@ import { isMediaBreakpointDown } from "../Utils/BreakpointsUtils";
import { LayoutMode } from "./LayoutManager"; import { LayoutMode } from "./LayoutManager";
import type { CoWebsite } from "./CoWebsite/CoWesbite"; import type { CoWebsite } from "./CoWebsite/CoWesbite";
import type CancelablePromise from "cancelable-promise"; import type CancelablePromise from "cancelable-promise";
import { analyticsClient } from "../Administration/AnalyticsClient";
export enum iframeStates { export enum iframeStates {
closed = 1, closed = 1,
@ -126,6 +127,7 @@ class CoWebsiteManager {
const buttonCloseCoWebsite = HtmlUtils.getElementByIdOrFail(cowebsiteCloseButtonId); const buttonCloseCoWebsite = HtmlUtils.getElementByIdOrFail(cowebsiteCloseButtonId);
buttonCloseCoWebsite.addEventListener("click", () => { buttonCloseCoWebsite.addEventListener("click", () => {
analyticsClient.closeMultiIframe();
const coWebsite = this.getMainCoWebsite(); const coWebsite = this.getMainCoWebsite();
if (!coWebsite) { if (!coWebsite) {
@ -143,6 +145,7 @@ class CoWebsiteManager {
const buttonFullScreenFrame = HtmlUtils.getElementByIdOrFail(cowebsiteFullScreenButtonId); const buttonFullScreenFrame = HtmlUtils.getElementByIdOrFail(cowebsiteFullScreenButtonId);
buttonFullScreenFrame.addEventListener("click", () => { buttonFullScreenFrame.addEventListener("click", () => {
analyticsClient.fullScreenMultiIframe();
buttonFullScreenFrame.blur(); buttonFullScreenFrame.blur();
this.fullscreen(); this.fullscreen();
}); });
@ -159,6 +162,7 @@ class CoWebsiteManager {
}); });
buttonSwipe.addEventListener("click", () => { buttonSwipe.addEventListener("click", () => {
analyticsClient.switchMultiIframe();
const mainCoWebsite = this.getMainCoWebsite(); const mainCoWebsite = this.getMainCoWebsite();
const highlightedEmbed = get(highlightedEmbedScreen); const highlightedEmbed = get(highlightedEmbedScreen);
if (highlightedEmbed?.type === "cowebsite") { if (highlightedEmbed?.type === "cowebsite") {

View File

@ -77,7 +77,8 @@ const menu: NonNullable<Translation["menu"]> = {
description: "Link zu diesem Raum teilen!", description: "Link zu diesem Raum teilen!",
copy: "Kopieren", copy: "Kopieren",
share: "Teilen", share: "Teilen",
walk_automatically_to_position: "Automatisch zu meiner Position gehen", walkAutomaticallyToPosition: "Automatisch zu meiner Position gehen",
selectEntryPoint: "Select an entry point",
}, },
globalMessage: { globalMessage: {
text: "Text", text: "Text",

View File

@ -77,7 +77,8 @@ const menu: BaseTranslation = {
description: "Share the link of the room!", description: "Share the link of the room!",
copy: "Copy", copy: "Copy",
share: "Share", share: "Share",
walk_automatically_to_position: "Walk automatically to my position", walkAutomaticallyToPosition: "Walk automatically to my position",
selectEntryPoint: "Select an entry point",
}, },
globalMessage: { globalMessage: {
text: "Text", text: "Text",

View File

@ -77,7 +77,8 @@ const menu: NonNullable<Translation["menu"]> = {
description: "Partager le lien de la salle!", description: "Partager le lien de la salle!",
copy: "Copier", copy: "Copier",
share: "Partager", share: "Partager",
walk_automatically_to_position: "Marcher automatiquement jusqu'à ma position", walkAutomaticallyToPosition: "Marcher automatiquement jusqu'à ma position",
selectEntryPoint: "Selectionner la zone de départ",
}, },
globalMessage: { globalMessage: {
text: "Texte", text: "Texte",

View File

@ -77,7 +77,8 @@ const menu: NonNullable<Translation["menu"]> = {
description: "分享该房间的链接!", description: "分享该房间的链接!",
copy: "复制", copy: "复制",
share: "分享", share: "分享",
walk_automatically_to_position: "自动走到我的位置", walkAutomaticallyToPosition: "自动走到我的位置",
selectEntryPoint: "Select an entry point",
}, },
globalMessage: { globalMessage: {
text: "文本", text: "文本",

View File

@ -2,7 +2,6 @@ import { BaseHttpController } from "./BaseHttpController";
import * as fs from "fs"; import * as fs from "fs";
import { ADMIN_URL } from "../Enum/EnvironmentVariable"; import { ADMIN_URL } from "../Enum/EnvironmentVariable";
import SwaggerGenerator from "../Services/SwaggerGenerator"; import SwaggerGenerator from "../Services/SwaggerGenerator";
import swaggerJsdoc from "swagger-jsdoc";
export class SwaggerController extends BaseHttpController { export class SwaggerController extends BaseHttpController {
routes() { routes() {