Merge pull request #704 from thecodingmachine/develop
Deploy 2021-02-04
@ -100,11 +100,12 @@ class AdminApi {
|
||||
return res.data;
|
||||
}
|
||||
|
||||
reportPlayer(reportedUserUuid: string, reportedUserComment: string, reporterUserUuid: string) {
|
||||
reportPlayer(reportedUserUuid: string, reportedUserComment: string, reporterUserUuid: string, reportWorldSlug: string) {
|
||||
return Axios.post(`${ADMIN_API_URL}/api/report`, {
|
||||
reportedUserUuid,
|
||||
reportedUserComment,
|
||||
reporterUserUuid,
|
||||
reportWorldSlug,
|
||||
},
|
||||
{
|
||||
headers: {"Authorization": `${ADMIN_API_TOKEN}`}
|
||||
|
12
front/dist/resources/html/gameMenu.html
vendored
@ -15,6 +15,14 @@
|
||||
#gameMenu section {
|
||||
margin: 10px;
|
||||
}
|
||||
section#socialLinks{
|
||||
position: absolute;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
section#socialLinks img{
|
||||
width: 32px;
|
||||
cursor: url('/resources/logos/cursor_pointer.png'), pointer;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="gameMenu" hidden>
|
||||
@ -38,5 +46,9 @@
|
||||
<section id="adminConsoleSection" hidden>
|
||||
<button id="adminConsoleButton">Admin console</button>
|
||||
</section>
|
||||
<section id="socialLinks" hidden>
|
||||
<a class="not-button" href="https://www.facebook.com/workadventurebytcm" target="_blank"><img class="not-button" src="/resources/objects/facebook-icon.png"/></a>
|
||||
<a class="not-button" href="https://twitter.com/Workadventure_" target="_blank"><img class="not-button" src="/resources/objects/twitter-icon.png"/></a>
|
||||
</section>
|
||||
</main>
|
||||
</div>
|
||||
|
104
front/dist/resources/html/gameReport.html
vendored
Normal file
@ -0,0 +1,104 @@
|
||||
<style>
|
||||
*{
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
cursor: url('/resources/logos/cursor_normal.png'), auto;
|
||||
}
|
||||
* a, button, input{
|
||||
cursor: url('/resources/logos/cursor_pointer.png'), pointer;
|
||||
}
|
||||
#gameReport {
|
||||
background: #eceeee;
|
||||
border: 1px solid #42464b;
|
||||
border-radius: 6px;
|
||||
margin: 2px auto 0;
|
||||
width: 298px;
|
||||
height: 220px;
|
||||
}
|
||||
#gameReport .cautiousText {
|
||||
font-size: 50%;
|
||||
}
|
||||
#gameReport h1 {
|
||||
background-image: linear-gradient(top, #f1f3f3, #d4dae0);
|
||||
border-bottom: 1px solid #a6abaf;
|
||||
border-radius: 6px 6px 0 0;
|
||||
box-sizing: border-box;
|
||||
color: #727678;
|
||||
display: block;
|
||||
height: 43px;
|
||||
padding-top: 10px;
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
text-shadow: 0 -1px 0 rgba(0,0,0,0.2), 0 1px 0 #fff;
|
||||
}
|
||||
#gameReport textarea {
|
||||
font-size: 70%;
|
||||
background: linear-gradient(top, #d6d7d7, #dee0e0);
|
||||
border: 1px solid #a1a3a3;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 1px #fff;
|
||||
box-sizing: border-box;
|
||||
color: #696969;
|
||||
height: 100px;
|
||||
transition: box-shadow 0.3s;
|
||||
width: 100%;
|
||||
}
|
||||
#gameReport section {
|
||||
margin: 10px;
|
||||
}
|
||||
#gameReport section.action{
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
}
|
||||
#gameReport button {
|
||||
margin-top: 10px;
|
||||
background-color: black;
|
||||
color: white;
|
||||
border-radius: 7px;
|
||||
padding-bottom: 4px;
|
||||
width: 60px;
|
||||
}
|
||||
#gameReport button#gameReportFormCancel {
|
||||
background-color: #c7c7c700;
|
||||
color: #292929;
|
||||
}
|
||||
#gameReport section a{
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
margin: 0 6px;
|
||||
color: black;
|
||||
}
|
||||
#gameReport section h6,
|
||||
#gameReport section h5{
|
||||
margin: 1px;
|
||||
}
|
||||
#gameReport section.text-center{
|
||||
text-align: center;
|
||||
}
|
||||
#gameReport section p{
|
||||
font-size: 8px;
|
||||
margin: 0px 70px;
|
||||
}
|
||||
#gameReport section p.err{
|
||||
color: red;
|
||||
display: none;
|
||||
}
|
||||
#gameReport section p.info{
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
<form id="gameReport" hidden>
|
||||
<section class="text-center">
|
||||
<h5 id="nameReported"></h5>
|
||||
<input type="hidden" id="idUserReported"/>
|
||||
</section>
|
||||
<section>
|
||||
<h6>Message</h6>
|
||||
<textarea type="text" name="report" id="gameReportInput"></textarea>
|
||||
<p class="err" id="gameReportErr"></p>
|
||||
</section>
|
||||
<section class="action">
|
||||
<button type="submit" id="gameReportFormSubmit">Submit</button>
|
||||
<button type="submit" id="gameReportFormCancel">Close</button>
|
||||
</section>
|
||||
</form>
|
BIN
front/dist/resources/logos/logo.png
vendored
Normal file
After Width: | Height: | Size: 16 KiB |
1
front/dist/resources/logos/report.back.svg
vendored
Normal file
@ -0,0 +1 @@
|
||||
<svg id="Calque_1" data-name="Calque 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 56.48 56.48"><defs><style>.cls-1{fill:#e76e54;}.cls-2{fill:#fff;}</style></defs><path class="cls-1" d="M39.94,512H16.54L0,495.46v-23.4l16.54-16.54h23.4l16.54,16.54v23.4Z" transform="translate(0 -455.52)"/><path class="cls-2" d="M33.54,485.52H23l-1.77-21.18H35.3Z" transform="translate(0 -455.52)"/><path class="cls-2" d="M23,492.58H33.54v10.59H23Z" transform="translate(0 -455.52)"/></svg>
|
After Width: | Height: | Size: 477 B |
2
front/dist/resources/logos/report.svg
vendored
Before Width: | Height: | Size: 477 B After Width: | Height: | Size: 6.1 KiB |
BIN
front/dist/resources/objects/facebook-icon.png
vendored
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
front/dist/resources/objects/talk.png
vendored
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 516 B |
BIN
front/dist/resources/objects/twitter-icon.png
vendored
Normal file
After Width: | Height: | Size: 3.0 KiB |
59
front/dist/resources/style/style.css
vendored
@ -39,6 +39,7 @@ body .message-info.warning{
|
||||
position: relative;
|
||||
transition: all 0.2s ease;
|
||||
background-color: #00000099;
|
||||
cursor: url('/resources/logos/cursor_pointer.png'), pointer;
|
||||
}
|
||||
.video-container i{
|
||||
position: absolute;
|
||||
@ -53,25 +54,62 @@ body .message-info.warning{
|
||||
font-size: 28px;
|
||||
color: white;
|
||||
}
|
||||
.video-container img.active{
|
||||
display: block;
|
||||
}
|
||||
|
||||
.video-container img{
|
||||
position: absolute;
|
||||
display: none;
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
background: #d93025;
|
||||
border-radius: 48px;
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
left: 5px;
|
||||
bottom: 5px;
|
||||
padding: 10px;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.video-container img.report{
|
||||
.video-container button.report{
|
||||
display: block;
|
||||
cursor: url('/resources/logos/cursor_pointer.png'), pointer;
|
||||
background: none;
|
||||
background-color: rgba(0, 0, 0, 0);
|
||||
border: none;
|
||||
background-color: black;
|
||||
border-radius: 15px;
|
||||
position: absolute;
|
||||
width: 0px;
|
||||
height: 35px;
|
||||
right: 5px;
|
||||
left: auto;
|
||||
bottom: 5px;
|
||||
padding: 0px;
|
||||
overflow: hidden;
|
||||
z-index: 2;
|
||||
transition: all .5s ease;
|
||||
}
|
||||
|
||||
.video-container:hover button.report{
|
||||
width: 35px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.video-container button.report:hover {
|
||||
width: 94px;
|
||||
}
|
||||
|
||||
.video-container button.report img{
|
||||
position: absolute;
|
||||
display: block;
|
||||
bottom: 5px;
|
||||
left: 5px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
cursor: url('/resources/logos/cursor_pointer.png'), pointer;
|
||||
}
|
||||
.video-container button.report span{
|
||||
position: absolute;
|
||||
bottom: 8px;
|
||||
left: 36px;
|
||||
color: white;
|
||||
font-size: 16px;
|
||||
cursor: url('/resources/logos/cursor_pointer.png'), pointer;
|
||||
}
|
||||
|
||||
.video-container video{
|
||||
@ -352,6 +390,7 @@ body {
|
||||
#cowebsite {
|
||||
position: fixed;
|
||||
transition: transform 0.5s;
|
||||
background-color: white;
|
||||
}
|
||||
#cowebsite.loading {
|
||||
background-color: gray;
|
||||
@ -1078,7 +1117,7 @@ div.modal-report-user{
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
.discussion .messages .message p.a{
|
||||
.discussion .messages .message p a{
|
||||
color: white;
|
||||
}
|
||||
|
||||
|
@ -1,14 +1,50 @@
|
||||
import ImageFrameConfig = Phaser.Types.Loader.FileTypes.ImageFrameConfig;
|
||||
|
||||
export const addLoader = (scene:Phaser.Scene): void => {
|
||||
const loadingText = scene.add.text(scene.game.renderer.width / 2, 200, 'Loading');
|
||||
const LogoNameIndex: string = 'logoLoading';
|
||||
const TextName: string = 'Loading...';
|
||||
const LogoResource: string = 'resources/logos/logo.png';
|
||||
const LogoFrame: ImageFrameConfig = {frameWidth: 307, frameHeight: 59};
|
||||
|
||||
export const addLoader = (scene: Phaser.Scene): void => {
|
||||
let loadingText: Phaser.GameObjects.Text|null = null;
|
||||
const loadingBarWidth: number = Math.floor(scene.game.renderer.width / 3);
|
||||
const loadingBarHeight: number = 16;
|
||||
const padding: number = 5;
|
||||
|
||||
const promiseLoadLogoTexture = new Promise<Phaser.GameObjects.Image>((res) => {
|
||||
if(scene.load.textureManager.exists(LogoNameIndex)){
|
||||
return res(scene.add.image(scene.game.renderer.width / 2, scene.game.renderer.height / 2 - 150, LogoNameIndex));
|
||||
}else{
|
||||
//add loading if logo image is not ready
|
||||
loadingText = scene.add.text(scene.game.renderer.width / 2, scene.game.renderer.height / 2 - 50, TextName);
|
||||
}
|
||||
scene.load.spritesheet(LogoNameIndex, LogoResource, LogoFrame);
|
||||
scene.load.once(`filecomplete-spritesheet-${LogoNameIndex}`, () => {
|
||||
if(loadingText){
|
||||
loadingText.destroy();
|
||||
}
|
||||
return res(scene.add.image(scene.game.renderer.width / 2, scene.game.renderer.height / 2 - 150, LogoNameIndex));
|
||||
});
|
||||
});
|
||||
|
||||
const progressContainer = scene.add.graphics();
|
||||
const progress = scene.add.graphics();
|
||||
progressContainer.fillStyle(0x444444, 0.8);
|
||||
progressContainer.fillRect((scene.game.renderer.width - loadingBarWidth) / 2 - padding, scene.game.renderer.height / 2 + 50 - padding, loadingBarWidth + padding * 2, loadingBarHeight + padding * 2);
|
||||
|
||||
scene.load.on('progress', (value: number) => {
|
||||
progress.clear();
|
||||
progress.fillStyle(0xffffff, 1);
|
||||
progress.fillRect(0, 270, 800 * value, 60);
|
||||
progress.fillStyle(0xBBBBBB, 1);
|
||||
progress.fillRect((scene.game.renderer.width - loadingBarWidth) / 2, scene.game.renderer.height / 2 + 50, loadingBarWidth * value, loadingBarHeight);
|
||||
});
|
||||
scene.load.on('complete', () => {
|
||||
loadingText.destroy();
|
||||
if(loadingText){
|
||||
loadingText.destroy();
|
||||
}
|
||||
promiseLoadLogoTexture.then((resLoadingImage: Phaser.GameObjects.Image) => {
|
||||
resLoadingImage.destroy();
|
||||
});
|
||||
progress.destroy();
|
||||
progressContainer.destroy();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -3,14 +3,12 @@ import {discussionManager} from "../../WebRtc/DiscussionManager";
|
||||
export const openChatIconName = 'openChatIcon';
|
||||
export class OpenChatIcon extends Phaser.GameObjects.Image {
|
||||
constructor(scene: Phaser.Scene, x: number, y: number) {
|
||||
super(scene, x, y, openChatIconName);
|
||||
super(scene, x, y, openChatIconName, 3);
|
||||
scene.add.existing(this);
|
||||
this.setScrollFactor(0, 0);
|
||||
this.setOrigin(0, 1);
|
||||
this.displayWidth = 30;
|
||||
this.displayHeight = 30;
|
||||
this.setInteractive();
|
||||
this.setVisible(false)
|
||||
this.setVisible(false);
|
||||
this.setDepth(99999);
|
||||
|
||||
this.on("pointerup", () => discussionManager.showDiscussionPart());
|
||||
|
@ -154,7 +154,7 @@ export class GameScene extends ResizableScene implements CenterListener {
|
||||
private actionableItems: Map<number, ActionableItem> = new Map<number, ActionableItem>();
|
||||
// The item that can be selected by pressing the space key.
|
||||
private outlinedItem: ActionableItem|null = null;
|
||||
private userInputManager!: UserInputManager;
|
||||
public userInputManager!: UserInputManager;
|
||||
private isReconnecting: boolean = false;
|
||||
private startLayerName!: string | null;
|
||||
private openChatIcon!: OpenChatIcon;
|
||||
@ -644,7 +644,7 @@ export class GameScene extends ResizableScene implements CenterListener {
|
||||
coWebsiteManager.closeCoWebsite();
|
||||
}else{
|
||||
const openWebsiteFunction = () => {
|
||||
coWebsiteManager.loadCoWebsite(newValue as string);
|
||||
coWebsiteManager.loadCoWebsite(newValue as string, allProps.get('openWebsitePolicy') as string | undefined);
|
||||
layoutManager.removeActionButton('openWebsite', this.userInputManager);
|
||||
};
|
||||
|
||||
@ -1202,6 +1202,7 @@ export class GameScene extends ResizableScene implements CenterListener {
|
||||
private reposition(): void {
|
||||
this.presentationModeSprite.setY(this.game.renderer.height - 2);
|
||||
this.chatModeSprite.setY(this.game.renderer.height - 2);
|
||||
this.openChatIcon.setY(this.game.renderer.height - 2);
|
||||
|
||||
// Recompute camera offset if needed
|
||||
this.updateCameraOffset();
|
||||
|
@ -2,14 +2,17 @@ import {LoginScene, LoginSceneName} from "../Login/LoginScene";
|
||||
import {SelectCharacterScene, SelectCharacterSceneName} from "../Login/SelectCharacterScene";
|
||||
import {gameManager} from "../Game/GameManager";
|
||||
import {localUserStore} from "../../Connexion/LocalUserStore";
|
||||
import {mediaManager} from "../../WebRtc/MediaManager";
|
||||
import {mediaManager, ReportCallback, ShowReportCallBack} from "../../WebRtc/MediaManager";
|
||||
import {coWebsiteManager} from "../../WebRtc/CoWebsiteManager";
|
||||
import {GameConnexionTypes} from "../../Url/UrlManager";
|
||||
import {connectionManager} from "../../Connexion/ConnectionManager";
|
||||
|
||||
export const MenuSceneName = 'MenuScene';
|
||||
const gameMenuKey = 'gameMenu';
|
||||
const gameMenuIconKey = 'gameMenuIcon';
|
||||
const gameSettingsMenuKey = 'gameSettingsMenu';
|
||||
const gameShare = 'gameShare';
|
||||
const gameReport = 'gameReport';
|
||||
|
||||
const closedSideMenuX = -200;
|
||||
const openedSideMenuX = 0;
|
||||
@ -21,9 +24,11 @@ export class MenuScene extends Phaser.Scene {
|
||||
private menuElement!: Phaser.GameObjects.DOMElement;
|
||||
private gameQualityMenuElement!: Phaser.GameObjects.DOMElement;
|
||||
private gameShareElement!: Phaser.GameObjects.DOMElement;
|
||||
private gameReportElement!: Phaser.GameObjects.DOMElement;
|
||||
private sideMenuOpened = false;
|
||||
private settingsMenuOpened = false;
|
||||
private gameShareOpened = false;
|
||||
private gameReportOpened = false;
|
||||
private gameQualityValue: number;
|
||||
private videoQualityValue: number;
|
||||
private menuButton!: Phaser.GameObjects.DOMElement;
|
||||
@ -40,6 +45,7 @@ export class MenuScene extends Phaser.Scene {
|
||||
this.load.html(gameMenuIconKey, 'resources/html/gameMenuIcon.html');
|
||||
this.load.html(gameSettingsMenuKey, 'resources/html/gameQualityMenu.html');
|
||||
this.load.html(gameShare, 'resources/html/gameShare.html');
|
||||
this.load.html(gameReport, 'resources/html/gameReport.html');
|
||||
}
|
||||
|
||||
create() {
|
||||
@ -64,6 +70,19 @@ export class MenuScene extends Phaser.Scene {
|
||||
}
|
||||
});
|
||||
|
||||
this.gameReportElement = this.add.dom(middleX, -400).createFromCache(gameReport);
|
||||
this.revealMenusAfterInit(this.gameReportElement, gameReport);
|
||||
this.gameReportElement.addListener('click');
|
||||
this.gameReportElement.on('click', (event:MouseEvent) => {
|
||||
event.preventDefault();
|
||||
if((event?.target as HTMLInputElement).id === 'gameReportFormSubmit') {
|
||||
this.submitReport();
|
||||
}else if((event?.target as HTMLInputElement).id === 'gameReportFormCancel') {
|
||||
this.closeGameReport();
|
||||
}
|
||||
});
|
||||
mediaManager.setShowReportModalCallBacks(this.openGameReport.bind(this));
|
||||
|
||||
this.input.keyboard.on('keyup-TAB', () => {
|
||||
this.sideMenuOpened ? this.closeSideMenu() : this.openSideMenu();
|
||||
});
|
||||
@ -98,6 +117,11 @@ export class MenuScene extends Phaser.Scene {
|
||||
const adminSection = this.menuElement.getChildByID('adminConsoleSection') as HTMLElement;
|
||||
adminSection.hidden = false;
|
||||
}
|
||||
//TODO bind with future metadata of card
|
||||
//if (connectionManager.getConnexionType === GameConnexionTypes.anonymous){
|
||||
const adminSection = this.menuElement.getChildByID('socialLinks') as HTMLElement;
|
||||
adminSection.hidden = false;
|
||||
//}
|
||||
this.tweens.add({
|
||||
targets: this.menuElement,
|
||||
x: openedSideMenuX,
|
||||
@ -221,7 +245,75 @@ export class MenuScene extends Phaser.Scene {
|
||||
});
|
||||
}
|
||||
|
||||
private openGameReport(userId: string, userName: string|undefined){
|
||||
if (this.gameReportOpened) {
|
||||
this.closeGameReport();
|
||||
return;
|
||||
}
|
||||
|
||||
//close all
|
||||
this.closeAll();
|
||||
|
||||
const gameTitleReport = this.gameReportElement.getChildByID('nameReported') as HTMLElement;
|
||||
gameTitleReport.innerText = userName ? `Report user: ${userName}` : 'Report user';
|
||||
const gameIdUserReported = this.gameReportElement.getChildByID('idUserReported') as HTMLInputElement;
|
||||
gameIdUserReported.value = userId;
|
||||
|
||||
this.gameReportOpened = true;
|
||||
let middleY = (window.innerHeight / 3) - (257);
|
||||
if(middleY < 0){
|
||||
middleY = 0;
|
||||
}
|
||||
let middleX = (window.innerWidth / 3) - 298;
|
||||
if(middleX < 0){
|
||||
middleX = 0;
|
||||
}
|
||||
|
||||
gameManager.getCurrentGameScene(this).userInputManager.clearAllInputKeyboard();
|
||||
|
||||
this.tweens.add({
|
||||
targets: this.gameReportElement,
|
||||
y: middleY,
|
||||
x: middleX,
|
||||
duration: 1000,
|
||||
ease: 'Power3'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
private closeGameReport(): void{
|
||||
this.gameReportOpened = false;
|
||||
gameManager.getCurrentGameScene(this).userInputManager.initKeyBoardEvent();
|
||||
this.tweens.add({
|
||||
targets: this.gameReportElement,
|
||||
y: -400,
|
||||
duration: 1000,
|
||||
ease: 'Power3'
|
||||
});
|
||||
}
|
||||
|
||||
private submitReport(): void{
|
||||
const gamePError = this.gameReportElement.getChildByID('gameReportErr') as HTMLParagraphElement;
|
||||
gamePError.innerText = '';
|
||||
gamePError.style.display = 'none';
|
||||
const gameTextArea = this.gameReportElement.getChildByID('gameReportInput') as HTMLInputElement;
|
||||
const gameIdUserReported = this.gameReportElement.getChildByID('idUserReported') as HTMLInputElement;
|
||||
if(!gameTextArea || !gameTextArea.value || !gameIdUserReported || !gameIdUserReported.value){
|
||||
gamePError.innerText = 'Report message cannot to be empty.';
|
||||
gamePError.style.display = 'block';
|
||||
return;
|
||||
}
|
||||
gameManager.getCurrentGameScene(this).connection.emitReportPlayerMessage(
|
||||
parseInt(gameIdUserReported.value),
|
||||
gameTextArea.value
|
||||
);
|
||||
this.closeGameReport();
|
||||
}
|
||||
|
||||
private onMenuClick(event:MouseEvent) {
|
||||
if((event?.target as HTMLInputElement).classList.contains('not-button')){
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
|
||||
switch ((event?.target as HTMLInputElement).id) {
|
||||
@ -280,5 +372,6 @@ export class MenuScene extends Phaser.Scene {
|
||||
private closeAll(){
|
||||
this.closeGameQualityMenu();
|
||||
this.closeGameShare();
|
||||
this.closeGameReport();
|
||||
}
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ class CoWebsiteManager {
|
||||
this.opened = iframeStates.opened;
|
||||
}
|
||||
|
||||
public loadCoWebsite(url: string): void {
|
||||
public loadCoWebsite(url: string, allowPolicy?: string): void {
|
||||
this.load();
|
||||
this.cowebsiteDiv.innerHTML = `<button class="close-btn" id="cowebsite-close">
|
||||
<img src="resources/logos/close.svg">
|
||||
@ -56,6 +56,9 @@ class CoWebsiteManager {
|
||||
const iframe = document.createElement('iframe');
|
||||
iframe.id = 'cowebsite-iframe';
|
||||
iframe.src = url;
|
||||
if (allowPolicy) {
|
||||
iframe.allow = allowPolicy;
|
||||
}
|
||||
const onloadPromise = new Promise((resolve) => {
|
||||
iframe.onload = () => resolve();
|
||||
});
|
||||
|
@ -1,5 +1,5 @@
|
||||
import {HtmlUtils} from "./HtmlUtils";
|
||||
import {mediaManager, ReportCallback} from "./MediaManager";
|
||||
import {mediaManager, ReportCallback, ShowReportCallBack} from "./MediaManager";
|
||||
import {UserInputManager} from "../Phaser/UserInput/UserInputManager";
|
||||
import {connectionManager} from "../Connexion/ConnectionManager";
|
||||
import {GameConnexionTypes} from "../Url/UrlManager";
|
||||
@ -99,7 +99,7 @@ export class DiscussionManager {
|
||||
name: string|undefined,
|
||||
img?: string|undefined,
|
||||
isMe: boolean = false,
|
||||
reportCallback?: ReportCallback
|
||||
showReportCallBack?: ShowReportCallBack
|
||||
) {
|
||||
const divParticipant: HTMLDivElement = document.createElement('div');
|
||||
divParticipant.classList.add('participant');
|
||||
@ -128,8 +128,8 @@ export class DiscussionManager {
|
||||
reportBanUserAction.classList.add('report-btn')
|
||||
reportBanUserAction.innerText = 'Report';
|
||||
reportBanUserAction.addEventListener('click', () => {
|
||||
if(reportCallback) {
|
||||
mediaManager.showReportModal(`${userId}`, name ?? '', reportCallback);
|
||||
if(showReportCallBack) {
|
||||
showReportCallBack(`${userId}`, name);
|
||||
}else{
|
||||
console.info('report feature is not activated!');
|
||||
}
|
||||
|
@ -7,6 +7,14 @@ export class HtmlUtils {
|
||||
throw new Error("Cannot find HTML element with id '"+id+"'");
|
||||
}
|
||||
|
||||
public static querySelectorOrFail<T extends HTMLElement>(selector: string): T {
|
||||
const elem = document.querySelector<T>(selector);
|
||||
if (HtmlUtils.isHtmlElement<T>(elem)) {
|
||||
return elem;
|
||||
}
|
||||
throw new Error("Cannot find HTML element with selector '"+selector+"'");
|
||||
}
|
||||
|
||||
public static removeElementByIdOrFail<T extends HTMLElement>(id: string): T {
|
||||
const elem = document.getElementById(id);
|
||||
if (HtmlUtils.isHtmlElement<T>(elem)) {
|
||||
|
@ -212,7 +212,7 @@ class LayoutManager {
|
||||
* Tries to find the biggest available box of remaining space (this is a space where we can center the character)
|
||||
*/
|
||||
public findBiggestAvailableArray(): {xStart: number, yStart: number, xEnd: number, yEnd: number} {
|
||||
const game = HtmlUtils.getElementByIdOrFail<HTMLDivElement>('game');
|
||||
const game = HtmlUtils.querySelectorOrFail<HTMLCanvasElement>('#game canvas');
|
||||
if (this.mode === LayoutMode.VideoChat) {
|
||||
const children = document.querySelectorAll<HTMLDivElement>('div.chat-mode > div');
|
||||
const htmlChildren = Array.from(children.values());
|
||||
|
@ -3,6 +3,8 @@ import {HtmlUtils} from "./HtmlUtils";
|
||||
import {discussionManager, SendMessageCallback} from "./DiscussionManager";
|
||||
import {UserInputManager} from "../Phaser/UserInput/UserInputManager";
|
||||
import {VIDEO_QUALITY_SELECT} from "../Administration/ConsoleGlobalMessageManager";
|
||||
import {connectionManager} from "../Connexion/ConnectionManager";
|
||||
import {GameConnexionTypes} from "../Url/UrlManager";
|
||||
declare const navigator:any; // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
|
||||
const localValueVideo = localStorage.getItem(VIDEO_QUALITY_SELECT);
|
||||
@ -23,6 +25,7 @@ export type UpdatedLocalStreamCallback = (media: MediaStream|null) => void;
|
||||
export type StartScreenSharingCallback = (media: MediaStream) => void;
|
||||
export type StopScreenSharingCallback = (media: MediaStream) => void;
|
||||
export type ReportCallback = (message: string) => void;
|
||||
export type ShowReportCallBack = (userId: string, userName: string|undefined) => void;
|
||||
|
||||
// TODO: Split MediaManager in 2 classes: MediaManagerUI (in charge of HTML) and MediaManager (singleton in charge of the camera only)
|
||||
// TODO: verify that microphone event listeners are not triggered plenty of time NOW (since MediaManager is created many times!!!!)
|
||||
@ -46,6 +49,7 @@ export class MediaManager {
|
||||
updatedLocalStreamCallBacks : Set<UpdatedLocalStreamCallback> = new Set<UpdatedLocalStreamCallback>();
|
||||
startScreenSharingCallBacks : Set<StartScreenSharingCallback> = new Set<StartScreenSharingCallback>();
|
||||
stopScreenSharingCallBacks : Set<StopScreenSharingCallback> = new Set<StopScreenSharingCallback>();
|
||||
showReportModalCallBacks : Set<ShowReportCallBack> = new Set<ShowReportCallBack>();
|
||||
private microphoneBtn: HTMLDivElement;
|
||||
private cinemaBtn: HTMLDivElement;
|
||||
private monitorBtn: HTMLDivElement;
|
||||
@ -469,7 +473,7 @@ export class MediaManager {
|
||||
return this.getCamera();
|
||||
}
|
||||
|
||||
addActiveVideo(userId: string, reportCallBack: ReportCallback|undefined, userName: string = ""){
|
||||
addActiveVideo(userId: string, userName: string = "", anonymous: boolean = true){
|
||||
this.webrtcInAudio.play();
|
||||
|
||||
userName = userName.toUpperCase();
|
||||
@ -482,7 +486,13 @@ export class MediaManager {
|
||||
<i id="name-${userId}" style="background-color: ${color};">${userName}</i>
|
||||
<img id="microphone-${userId}" src="resources/logos/microphone-close.svg">
|
||||
` +
|
||||
((reportCallBack!==undefined)?`<img id="report-${userId}" class="report active" src="resources/logos/report.svg">`:'')
|
||||
((anonymous === false)?`
|
||||
<button id="report-${userId}" class="report">
|
||||
<img src="resources/logos/report.svg">
|
||||
<span>Report</span>
|
||||
</button>
|
||||
`:''
|
||||
)
|
||||
+
|
||||
`<video id="${userId}" autoplay></video>
|
||||
</div>
|
||||
@ -490,18 +500,23 @@ export class MediaManager {
|
||||
|
||||
layoutManager.add(DivImportance.Normal, userId, html);
|
||||
|
||||
if (reportCallBack) {
|
||||
const reportBtn = HtmlUtils.getElementByIdOrFail<HTMLDivElement>(`report-${userId}`);
|
||||
reportBtn.addEventListener('click', (e: MouseEvent) => {
|
||||
e.preventDefault();
|
||||
this.showReportModal(userId, userName, reportCallBack);
|
||||
});
|
||||
}
|
||||
|
||||
this.remoteVideo.set(userId, HtmlUtils.getElementByIdOrFail<HTMLVideoElement>(userId));
|
||||
|
||||
//permit to create participant in discussion part
|
||||
this.addNewParticipant(userId, userName, undefined, reportCallBack);
|
||||
const showReportUser = () => {
|
||||
for(const callBack of this.showReportModalCallBacks){
|
||||
callBack(userId, userName);
|
||||
}
|
||||
};
|
||||
this.addNewParticipant(userId, userName, undefined, showReportUser);
|
||||
|
||||
if(!anonymous){
|
||||
const reportBanUserAction: HTMLImageElement = HtmlUtils.getElementByIdOrFail<HTMLImageElement>(`report-${userId}`);
|
||||
reportBanUserAction.addEventListener('click', (e) => {
|
||||
e.preventDefault();
|
||||
showReportUser();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
addScreenSharingActiveVideo(userId: string, divImportance: DivImportance = DivImportance.Important){
|
||||
@ -645,65 +660,8 @@ export class MediaManager {
|
||||
return color;
|
||||
}
|
||||
|
||||
public showReportModal(userId: string, userName: string, reportCallBack: ReportCallback){
|
||||
//create report text area
|
||||
const mainContainer = HtmlUtils.getElementByIdOrFail<HTMLDivElement>('main-container');
|
||||
|
||||
const divReport = document.createElement('div');
|
||||
divReport.classList.add('modal-report-user');
|
||||
|
||||
const inputHidden = document.createElement('input');
|
||||
inputHidden.id = 'input-report-user';
|
||||
inputHidden.type = 'hidden';
|
||||
inputHidden.value = userId;
|
||||
divReport.appendChild(inputHidden);
|
||||
|
||||
const titleMessage = document.createElement('p');
|
||||
titleMessage.id = 'title-report-user';
|
||||
titleMessage.innerText = 'Open a report';
|
||||
divReport.appendChild(titleMessage);
|
||||
|
||||
const bodyMessage = document.createElement('p');
|
||||
bodyMessage.id = 'body-report-user';
|
||||
bodyMessage.innerText = `You are about to open a report regarding an offensive conduct from user ${userName.toUpperCase()}. Please explain to us how you think ${userName.toUpperCase()} breached the code of conduct.`;
|
||||
divReport.appendChild(bodyMessage);
|
||||
|
||||
const imgReportUser = document.createElement('img');
|
||||
imgReportUser.id = 'img-report-user';
|
||||
imgReportUser.src = 'resources/logos/report.svg';
|
||||
divReport.appendChild(imgReportUser);
|
||||
|
||||
const textareaUser = document.createElement('textarea');
|
||||
textareaUser.id = 'textarea-report-user';
|
||||
textareaUser.placeholder = 'Write ...';
|
||||
divReport.appendChild(textareaUser);
|
||||
|
||||
const buttonReport = document.createElement('button');
|
||||
buttonReport.id = 'button-save-report-user';
|
||||
buttonReport.innerText = 'Report';
|
||||
buttonReport.addEventListener('click', () => {
|
||||
if(!textareaUser.value){
|
||||
textareaUser.style.border = '1px solid red'
|
||||
return;
|
||||
}
|
||||
reportCallBack(textareaUser.value);
|
||||
divReport.remove();
|
||||
});
|
||||
divReport.appendChild(buttonReport);
|
||||
|
||||
const buttonCancel = document.createElement('img');
|
||||
buttonCancel.id = 'cancel-report-user';
|
||||
buttonCancel.src = 'resources/logos/close.svg';
|
||||
buttonCancel.addEventListener('click', () => {
|
||||
divReport.remove();
|
||||
});
|
||||
divReport.appendChild(buttonCancel);
|
||||
|
||||
mainContainer.appendChild(divReport);
|
||||
}
|
||||
|
||||
public addNewParticipant(userId: number|string, name: string|undefined, img?: string, reportCallBack?: ReportCallback){
|
||||
discussionManager.addParticipant(userId, name, img, false, reportCallBack);
|
||||
public addNewParticipant(userId: number|string, name: string|undefined, img?: string, showReportUserCallBack?: ShowReportCallBack){
|
||||
discussionManager.addParticipant(userId, name, img, false, showReportUserCallBack);
|
||||
}
|
||||
|
||||
public removeParticipant(userId: number|string){
|
||||
@ -769,6 +727,10 @@ export class MediaManager {
|
||||
this.checkActiveUser();
|
||||
}, this.focused ? 10000 : 1000);
|
||||
}
|
||||
|
||||
public setShowReportModalCallBacks(callback: ShowReportCallBack){
|
||||
this.showReportModalCallBacks.add(callback);
|
||||
}
|
||||
}
|
||||
|
||||
export const mediaManager = new MediaManager();
|
||||
|
@ -11,6 +11,8 @@ import {
|
||||
import {ScreenSharingPeer} from "./ScreenSharingPeer";
|
||||
import {MESSAGE_TYPE_CONSTRAINT, MESSAGE_TYPE_MESSAGE, VideoPeer} from "./VideoPeer";
|
||||
import {RoomConnection} from "../Connexion/RoomConnection";
|
||||
import {connectionManager} from "../Connexion/ConnectionManager";
|
||||
import {GameConnexionTypes} from "../Url/UrlManager";
|
||||
|
||||
export interface UserSimplePeerInterface{
|
||||
userId: number;
|
||||
@ -134,11 +136,7 @@ export class SimplePeer {
|
||||
|
||||
mediaManager.removeActiveVideo("" + user.userId);
|
||||
|
||||
const reportCallback = this.enableReporting ? (comment: string) => {
|
||||
this.reportUser(user.userId, comment);
|
||||
} : undefined;
|
||||
|
||||
mediaManager.addActiveVideo("" + user.userId, reportCallback, name);
|
||||
mediaManager.addActiveVideo("" + user.userId, name, connectionManager.getConnexionType === GameConnexionTypes.anonymous);
|
||||
|
||||
const peer = new VideoPeer(user.userId, user.initiator ? user.initiator : false, this.Connection);
|
||||
|
||||
@ -391,13 +389,6 @@ export class SimplePeer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggered locally when clicking on the report button
|
||||
*/
|
||||
public reportUser(userId: number, message: string) {
|
||||
this.Connection.emitReportPlayerMessage(userId, message)
|
||||
}
|
||||
|
||||
private sendLocalScreenSharingStreamToUser(userId: number): void {
|
||||
// If a connection already exists with user (because it is already sharing a screen with us... let's use this connection)
|
||||
if (this.PeerScreenSharingConnectionArray.has(userId)) {
|
||||
|
@ -105,11 +105,12 @@ class AdminApi {
|
||||
return res.data;
|
||||
}
|
||||
|
||||
reportPlayer(reportedUserUuid: string, reportedUserComment: string, reporterUserUuid: string) {
|
||||
reportPlayer(reportedUserUuid: string, reportedUserComment: string, reporterUserUuid: string, reportWorldSlug: string) {
|
||||
return Axios.post(`${ADMIN_API_URL}/api/report`, {
|
||||
reportedUserUuid,
|
||||
reportedUserComment,
|
||||
reporterUserUuid,
|
||||
reportWorldSlug
|
||||
},
|
||||
{
|
||||
headers: {"Authorization": `${ADMIN_API_TOKEN}`}
|
||||
|
@ -304,7 +304,7 @@ export class SocketManager implements ZoneEventListener {
|
||||
throw 'reported socket user not found';
|
||||
}
|
||||
//TODO report user on admin application
|
||||
await adminApi.reportPlayer(reportedSocket.userUuid, reportPlayerMessage.getReportcomment(), client.userUuid)
|
||||
await adminApi.reportPlayer(reportedSocket.userUuid, reportPlayerMessage.getReportcomment(), client.userUuid, client.roomId.split('/')[2])
|
||||
} catch (e) {
|
||||
console.error('An error occurred on "handleReportMessage"');
|
||||
console.error(e);
|
||||
|