diff --git a/docker-compose.yaml b/docker-compose.yaml index a33706c0..23302041 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -29,6 +29,7 @@ services: PUSHER_URL: //pusher.workadventure.localhost UPLOADER_URL: //uploader.workadventure.localhost ADMIN_URL: //workadventure.localhost + ICON_URL: //icon.workadventure.localhost STARTUP_COMMAND_1: ./templater.sh STARTUP_COMMAND_2: yarn install STUN_SERVER: "stun:stun.l.google.com:19302" @@ -177,6 +178,17 @@ services: - "traefik.http.routers.redisinsight-ssl.tls=true" - "traefik.http.routers.redisinsight-ssl.service=redisinsight" + icon: + image: matthiasluedtke/iconserver:v3.13.0 + labels: + - "traefik.http.routers.icon.rule=Host(`icon.workadventure.localhost`)" + - "traefik.http.routers.icon.entryPoints=web" + - "traefik.http.services.icon.loadbalancer.server.port=8080" + - "traefik.http.routers.icon-ssl.rule=Host(`icon.workadventure.localhost`)" + - "traefik.http.routers.icon-ssl.entryPoints=websecure" + - "traefik.http.routers.icon-ssl.tls=true" + - "traefik.http.routers.icon-ssl.service=icon" + # coturn: # image: coturn/coturn:4.5.2 # command: diff --git a/front/Dockerfile b/front/Dockerfile index 5d048c1c..b12b2ee7 100644 --- a/front/Dockerfile +++ b/front/Dockerfile @@ -18,6 +18,7 @@ ARG DEBUG_MODE ARG JITSI_URL ARG JITSI_PRIVATE_MODE ARG PUSHER_URL +ARG ICON_URL ARG ADMIN_URL ARG STUN_SERVER ARG TURN_SERVER @@ -40,6 +41,7 @@ RUN \ JITSI_URL=$JITSI_URL \ JITSI_PRIVATE_MODE=$JITSI_PRIVATE_MODE \ PUSHER_URL=$PUSHER_URL \ + ICON_URL=$ICON_URL \ ADMIN_URL=$ADMIN_URL \ STUN_SERVER=$STUN_SERVER \ TURN_SERVER=$TURN_SERVER \ diff --git a/front/src/Components/EmoteMenu/EmoteMenu.svelte b/front/src/Components/EmoteMenu/EmoteMenu.svelte index cf56f73f..aaa0d473 100644 --- a/front/src/Components/EmoteMenu/EmoteMenu.svelte +++ b/front/src/Components/EmoteMenu/EmoteMenu.svelte @@ -19,13 +19,18 @@ }, theme: 'dark', emojisPerRow: isMobile() ? 6 : 8, - autoFocusSearch: false + autoFocusSearch: false, + style: 'twemoji', }); //the timeout is here to prevent the menu from flashing setTimeout(() => picker.showPicker(emojiContainer), 100); picker.on("emoji", (selection) => { - emoteStore.set(selection.emoji); + emoteStore.set({ + unicode: selection.emoji, + url: selection.url, + name: selection.name + }); }); picker.on("hidden", () => { diff --git a/front/src/Components/Menu/MenuIcon.svelte b/front/src/Components/Menu/MenuIcon.svelte index 08eb8692..066ac11a 100644 --- a/front/src/Components/Menu/MenuIcon.svelte +++ b/front/src/Components/Menu/MenuIcon.svelte @@ -1,25 +1,19 @@ - +
diff --git a/front/src/Enum/EnvironmentVariable.ts b/front/src/Enum/EnvironmentVariable.ts index c0c19f1c..cf76a87d 100644 --- a/front/src/Enum/EnvironmentVariable.ts +++ b/front/src/Enum/EnvironmentVariable.ts @@ -4,6 +4,7 @@ const START_ROOM_URL: string = const PUSHER_URL = process.env.PUSHER_URL || "//pusher.workadventure.localhost"; export const ADMIN_URL = process.env.ADMIN_URL || "//workadventu.re"; const UPLOADER_URL = process.env.UPLOADER_URL || "//uploader.workadventure.localhost"; +const ICON_URL = process.env.ICON_URL || "//icon.workadventure.localhost"; const STUN_SERVER: string = process.env.STUN_SERVER || "stun:stun.l.google.com:19302"; const TURN_SERVER: string = process.env.TURN_SERVER || ""; const SKIP_RENDER_OPTIMIZATIONS: boolean = process.env.SKIP_RENDER_OPTIMIZATIONS == "true"; @@ -32,6 +33,7 @@ export { DISABLE_NOTIFICATIONS, PUSHER_URL, UPLOADER_URL, + ICON_URL, POSITION_DELAY, MAX_EXTRAPOLATION_TIME, STUN_SERVER, diff --git a/front/src/Phaser/Entity/Character.ts b/front/src/Phaser/Entity/Character.ts index 2af294ce..a8e4f674 100644 --- a/front/src/Phaser/Entity/Character.ts +++ b/front/src/Phaser/Entity/Character.ts @@ -3,6 +3,7 @@ import { SpeechBubble } from "./SpeechBubble"; import Text = Phaser.GameObjects.Text; import Container = Phaser.GameObjects.Container; import Sprite = Phaser.GameObjects.Sprite; +import DOMElement = Phaser.GameObjects.DOMElement; import { TextureError } from "../../Exception/TextureError"; import { Companion } from "../Companion/Companion"; import type { GameScene } from "../Game/GameScene"; @@ -33,7 +34,7 @@ export abstract class Character extends Container { //private teleportation: Sprite; private invisible: boolean; public companion?: Companion; - private emote: Phaser.GameObjects.Text | null = null; + private emote: Phaser.GameObjects.DOMElement | null = null; private emoteTween: Phaser.Tweens.Tween | null = null; scene: GameScene; @@ -300,8 +301,9 @@ export abstract class Character extends Container { playEmote(emote: string) { this.cancelPreviousEmote(); const emoteY = -45; - this.playerName.setVisible(false); - this.emote = new Text(this.scene, -10, 0, emote, { fontFamily: '"Twemoji Mozilla"', fontSize: "20px" }); + const image = new Image(16, 16); + image.src = emote; + this.emote = new DOMElement(this.scene, -1, 0, image, "z-index:10;"); this.emote.setAlpha(0); this.add(this.emote); this.createStartTransition(emoteY); diff --git a/front/src/Phaser/Game/GameScene.ts b/front/src/Phaser/Game/GameScene.ts index e34c2033..9ca31f76 100644 --- a/front/src/Phaser/Game/GameScene.ts +++ b/front/src/Phaser/Game/GameScene.ts @@ -15,10 +15,7 @@ import type { import { DEBUG_MODE, JITSI_PRIVATE_MODE, MAX_PER_GROUP, POSITION_DELAY } from "../../Enum/EnvironmentVariable"; import { Queue } from "queue-typescript"; -import { - Box, - ON_ACTION_TRIGGER_BUTTON, -} from "../../WebRtc/LayoutManager"; +import { Box, ON_ACTION_TRIGGER_BUTTON } from "../../WebRtc/LayoutManager"; import { CoWebsite, coWebsiteManager } from "../../WebRtc/CoWebsiteManager"; import type { UserMovedMessage } from "../../Messages/generated/messages_pb"; import { ProtobufClientUtils } from "../../Network/ProtobufClientUtils"; @@ -501,7 +498,10 @@ export class GameScene extends DirtyScene { object.properties, 'in the "' + object.name + '" object of type "website"' ); - const allowApi = PropertyUtils.findBooleanProperty(GameMapProperties.ALLOW_API, object.properties); + const allowApi = PropertyUtils.findBooleanProperty( + GameMapProperties.ALLOW_API, + object.properties + ); // TODO: add a "allow" property to iframe this.embeddedWebsiteManager.createEmbeddedWebsite( @@ -618,10 +618,10 @@ export class GameScene extends DirtyScene { oldPeerNumber = newPeerNumber; }); - this.emoteUnsubscribe = emoteStore.subscribe((emoteKey) => { - if (emoteKey) { - this.CurrentPlayer?.playEmote(emoteKey); - this.connection?.emitEmoteEvent(emoteKey); + this.emoteUnsubscribe = emoteStore.subscribe((emote) => { + if (emote) { + this.CurrentPlayer?.playEmote(emote.url); + this.connection?.emitEmoteEvent(emote.url); emoteStore.set(null); } }); @@ -767,14 +767,14 @@ export class GameScene extends DirtyScene { this.gameMap.setPosition(this.CurrentPlayer.x, this.CurrentPlayer.y); // Init layer change listener - this.gameMap.onEnterLayer(layers => { - layers.forEach(layer => { + this.gameMap.onEnterLayer((layers) => { + layers.forEach((layer) => { iframeListener.sendEnterLayerEvent(layer.name); }); }); - this.gameMap.onLeaveLayer(layers => { - layers.forEach(layer => { + this.gameMap.onLeaveLayer((layers) => { + layers.forEach((layer) => { iframeListener.sendLeaveLayerEvent(layer.name); }); }); @@ -1882,7 +1882,8 @@ export class GameScene extends DirtyScene { public startJitsi(roomName: string, jwt?: string): void { const allProps = this.gameMap.getCurrentProperties(); const jitsiConfig = this.safeParseJSONstring( - allProps.get(GameMapProperties.JITSI_CONFIG) as string | undefined, GameMapProperties.JITSI_CONFIG + allProps.get(GameMapProperties.JITSI_CONFIG) as string | undefined, + GameMapProperties.JITSI_CONFIG ); const jitsiInterfaceConfig = this.safeParseJSONstring( allProps.get(GameMapProperties.JITSI_INTERFACE_CONFIG) as string | undefined, diff --git a/front/src/Phaser/Player/Player.ts b/front/src/Phaser/Player/Player.ts index 28a1d3bd..a1924457 100644 --- a/front/src/Phaser/Player/Player.ts +++ b/front/src/Phaser/Player/Player.ts @@ -3,8 +3,6 @@ import type { GameScene } from "../Game/GameScene"; import { UserInputEvent, UserInputManager } from "../UserInput/UserInputManager"; import { Character } from "../Entity/Character"; import { userMovingStore } from "../../Stores/GameStore"; -import { get } from "svelte/store"; -import { emoteMenuStore } from "../../Stores/EmoteStore"; export const hasMovedEventName = "hasMoved"; export const requestEmoteEventName = "requestEmote"; @@ -68,10 +66,24 @@ export class Player extends Character { } else if (this.wasMoving && moving) { // slow joystick movement this.move(0, 0); - this.emit(hasMovedEventName, { moving, direction: this.previousDirection, x: this.x, y: this.y, oldX: x, oldY: y }); + this.emit(hasMovedEventName, { + moving, + direction: this.previousDirection, + x: this.x, + y: this.y, + oldX: x, + oldY: y, + }); } else if (this.wasMoving && !moving) { this.stop(); - this.emit(hasMovedEventName, { moving, direction: this.previousDirection, x: this.x, y: this.y, oldX: x, oldY: y }); + this.emit(hasMovedEventName, { + moving, + direction: this.previousDirection, + x: this.x, + y: this.y, + oldX: x, + oldY: y, + }); } if (direction !== null) { diff --git a/front/src/Stores/EmoteStore.ts b/front/src/Stores/EmoteStore.ts index 56b06659..3f6c3cf5 100644 --- a/front/src/Stores/EmoteStore.ts +++ b/front/src/Stores/EmoteStore.ts @@ -1,5 +1,11 @@ import { writable } from "svelte/store"; +export interface Emoji { + unicode: string; + url: string; + name: string; +} + function createEmoteMenuStore() { const { subscribe, set } = writable(false); @@ -14,5 +20,5 @@ function createEmoteMenuStore() { }; } -export const emoteStore = writable(null); +export const emoteStore = writable(null); export const emoteMenuStore = createEmoteMenuStore(); diff --git a/front/src/WebRtc/CoWebsiteManager.ts b/front/src/WebRtc/CoWebsiteManager.ts index b1b4cc21..2c8499c4 100644 --- a/front/src/WebRtc/CoWebsiteManager.ts +++ b/front/src/WebRtc/CoWebsiteManager.ts @@ -3,6 +3,7 @@ import { Subject } from "rxjs"; import { iframeListener } from "../Api/IframeListener"; import { touchScreenManager } from "../Touch/TouchScreenManager"; import { waScaleManager } from "../Phaser/Services/WaScaleManager"; +import { ICON_URL } from "../Enum/EnvironmentVariable"; enum iframeStates { closed = 1, @@ -32,16 +33,17 @@ export enum CoWebsiteState { CLOSED, } -export type CoWebsite = { - iframe: HTMLIFrameElement, - state : CoWebsiteState, - position: number -} +export type CoWebsite = { + iframe: HTMLIFrameElement; + // icon: HTMLDivElement; + position: number; + state : CoWebsiteState; +}; type CoWebsiteSlot = { - container: HTMLElement, - position: number -} + container: HTMLElement; + position: number; +}; class CoWebsiteManager { private openedMain: iframeStates = iframeStates.closed; @@ -66,7 +68,7 @@ class CoWebsiteManager { private slots: CoWebsiteSlot[]; - private resizeObserver = new ResizeObserver(entries => { + private resizeObserver = new ResizeObserver((entries) => { this.resizeAllIframes(); }); @@ -113,23 +115,23 @@ class CoWebsiteManager { this.slots = [ { container: this.cowebsiteMainDom, - position: 0 + position: 0, }, { - container: HtmlUtils.getElementByIdOrFail('cowebsite-slot-1'), - position: 1 + container: HtmlUtils.getElementByIdOrFail("cowebsite-slot-1"), + position: 1, }, { - container: HtmlUtils.getElementByIdOrFail('cowebsite-slot-2'), - position: 2 + container: HtmlUtils.getElementByIdOrFail("cowebsite-slot-2"), + position: 2, }, { - container: HtmlUtils.getElementByIdOrFail('cowebsite-slot-3'), - position: 3 + container: HtmlUtils.getElementByIdOrFail("cowebsite-slot-3"), + position: 3, }, { - container: HtmlUtils.getElementByIdOrFail('cowebsite-slot-4'), - position: 4 + container: HtmlUtils.getElementByIdOrFail("cowebsite-slot-4"), + position: 4, }, ]; @@ -168,8 +170,10 @@ class CoWebsiteManager { } private isSmallScreen(): boolean { - return window.matchMedia("(max-aspect-ratio: 1/1)").matches || - window.matchMedia("(max-width:960px) and (max-height:768px)").matches; + return ( + window.matchMedia("(max-aspect-ratio: 1/1)").matches || + window.matchMedia("(max-width:960px) and (max-height:768px)").matches + ); } private initResizeListeners(touchMode: boolean) { @@ -240,12 +244,12 @@ class CoWebsiteManager { private initActionsListeners() { this.slots.forEach((slot: CoWebsiteSlot) => { - const expandButton = slot.container.querySelector('.expand'); - const highlightButton = slot.container.querySelector('.hightlight'); - const closeButton = slot.container.querySelector('.close'); + const expandButton = slot.container.querySelector(".expand"); + const highlightButton = slot.container.querySelector(".hightlight"); + const closeButton = slot.container.querySelector(".close"); if (expandButton) { - expandButton.addEventListener('click', (event) => { + expandButton.addEventListener("click", (event) => { event.preventDefault(); const coWebsite = this.getCoWebsiteByPosition(slot.position); @@ -258,7 +262,7 @@ class CoWebsiteManager { } if (highlightButton) { - highlightButton.addEventListener('click', (event) => { + highlightButton.addEventListener("click", (event) => { event.preventDefault(); const coWebsite = this.getCoWebsiteByPosition(slot.position); @@ -271,7 +275,7 @@ class CoWebsiteManager { } if (closeButton) { - closeButton.addEventListener('click', (event) => { + closeButton.addEventListener("click", (event) => { event.preventDefault(); const coWebsite = this.getCoWebsiteByPosition(slot.position); @@ -289,37 +293,37 @@ class CoWebsiteManager { return this.coWebsites; } - public getCoWebsiteById(coWebsiteId: string): CoWebsite|undefined { + public getCoWebsiteById(coWebsiteId: string): CoWebsite | undefined { return this.coWebsites.find((coWebsite: CoWebsite) => coWebsite.iframe.id === coWebsiteId); } - private getSlotByPosition(position: number): CoWebsiteSlot|undefined { + private getSlotByPosition(position: number): CoWebsiteSlot | undefined { return this.slots.find((slot: CoWebsiteSlot) => slot.position === position); } - private getCoWebsiteByPosition(position: number): CoWebsite|undefined { + private getCoWebsiteByPosition(position: number): CoWebsite | undefined { return this.coWebsites.find((coWebsite: CoWebsite) => coWebsite.position === position); } private setIframeOffset(coWebsite: CoWebsite, slot: CoWebsiteSlot) { const bounding = slot.container.getBoundingClientRect(); - if (coWebsite.iframe.classList.contains('thumbnail')) { - coWebsite.iframe.style.width = ((bounding.right - bounding.left) * 2) + 'px'; - coWebsite.iframe.style.height = ((bounding.bottom - bounding.top) * 2) + 'px'; - coWebsite.iframe.style.top = (bounding.top - (Math.floor(bounding.height * 0.5))) + 'px'; - coWebsite.iframe.style.left = (bounding.left - (Math.floor(bounding.width * 0.5))) + 'px'; + if (coWebsite.iframe.classList.contains("thumbnail")) { + coWebsite.iframe.style.width = (bounding.right - bounding.left) * 2 + "px"; + coWebsite.iframe.style.height = (bounding.bottom - bounding.top) * 2 + "px"; + coWebsite.iframe.style.top = bounding.top - Math.floor(bounding.height * 0.5) + "px"; + coWebsite.iframe.style.left = bounding.left - Math.floor(bounding.width * 0.5) + "px"; } else { - coWebsite.iframe.style.top = bounding.top + 'px'; - coWebsite.iframe.style.left = bounding.left + 'px'; - coWebsite.iframe.style.width = (bounding.right - bounding.left) + 'px'; - coWebsite.iframe.style.height = (bounding.bottom - bounding.top) + 'px'; + coWebsite.iframe.style.top = bounding.top + "px"; + coWebsite.iframe.style.left = bounding.left + "px"; + coWebsite.iframe.style.width = bounding.right - bounding.left + "px"; + coWebsite.iframe.style.height = bounding.bottom - bounding.top + "px"; } } private resizeAllIframes() { this.coWebsites.forEach((coWebsite: CoWebsite) => { - const slot = this.getSlotByPosition(coWebsite.position); + const slot = this.getSlotByPosition(coWebsite.position); if (slot) { this.setIframeOffset(coWebsite, slot); @@ -338,32 +342,34 @@ class CoWebsiteManager { coWebsite.iframe.scrolling = newPosition === 0 || newPosition === 1 ? "yes" : "no"; if (newPosition === 0) { - coWebsite.iframe.classList.add('main'); + coWebsite.iframe.classList.add("main"); + // coWebsite.icon.style.display = "none"; } else { - coWebsite.iframe.classList.remove('main'); + coWebsite.iframe.classList.remove("main"); + // coWebsite.icon.style.display = "flex"; } if (newPosition === 1) { - coWebsite.iframe.classList.add('sub-main'); + coWebsite.iframe.classList.add("sub-main"); } else { - coWebsite.iframe.classList.remove('sub-main'); + coWebsite.iframe.classList.remove("sub-main"); } if (newPosition >= 2) { - coWebsite.iframe.classList.add('thumbnail'); + coWebsite.iframe.classList.add("thumbnail"); } else { - coWebsite.iframe.classList.remove('thumbnail'); + coWebsite.iframe.classList.remove("thumbnail"); } coWebsite.position = newPosition; if (oldSlot && !this.getCoWebsiteByPosition(oldSlot.position)) { - oldSlot.container.style.display = 'none'; + oldSlot.container.style.display = "none"; } - newSlot.container.style.display = 'block'; + newSlot.container.style.display = "block"; - coWebsite.iframe.classList.remove('pixel'); + coWebsite.iframe.classList.remove("pixel"); this.resizeAllIframes(); } @@ -387,11 +393,7 @@ class CoWebsiteManager { this.moveCoWebsite(coWebsite, newPosition); - if (newPosition === 4 || - !currentCoWebsite || - currentCoWebsite.iframe.id === coWebsite.iframe.id - ) - { + if (newPosition === 4 || !currentCoWebsite || currentCoWebsite.iframe.id === coWebsite.iframe.id) { return; } @@ -414,12 +416,12 @@ class CoWebsiteManager { if (coWebsite.position > 0) { const slot = this.getSlotByPosition(coWebsite.position); if (slot) { - slot.container.style.display = 'none'; + slot.container.style.display = "none"; } } - const previousCoWebsite = this.coWebsites.find((coWebsiteToCheck: CoWebsite) => - coWebsite.position + 1 === coWebsiteToCheck.position + const previousCoWebsite = this.coWebsites.find( + (coWebsiteToCheck: CoWebsite) => coWebsite.position + 1 === coWebsiteToCheck.position ); if (previousCoWebsite) { @@ -431,12 +433,25 @@ class CoWebsiteManager { iframeListener.unregisterIframe(coWebsite.iframe); } - public searchJitsi(): CoWebsite|undefined { - return this.coWebsites.find((coWebsite : CoWebsite) => - coWebsite.iframe.id.toLowerCase().includes('jitsi') - ); + public searchJitsi(): CoWebsite | undefined { + return this.coWebsites.find((coWebsite: CoWebsite) => coWebsite.iframe.id.toLowerCase().includes("jitsi")); } + // private generateCoWebsiteIcon(iframe: HTMLIFrameElement): HTMLDivElement { + // const icon = document.createElement("div"); + // icon.id = "cowebsite-icon-" + iframe.id; + // icon.style.display = "none"; + + // const iconImage = document.createElement("img"); + // iconImage.src = `${ICON_URL}/icon?url=${iframe.src}&size=16..30..256`; + // const url = new URL(iframe.src); + // iconImage.alt = url.hostname; + + // icon.appendChild(iconImage); + + // return icon; + // } + public loadCoWebsite( url: string, base: string, @@ -445,27 +460,30 @@ class CoWebsiteManager { widthPercent?: number, position?: number ): Promise { + return this.addCoWebsite( + (iframeBuffer) => { + const iframe = document.createElement("iframe"); + iframe.src = new URL(url, base).toString(); - return this.addCoWebsite((iframeBuffer) => { - const iframe = document.createElement("iframe"); - iframe.src = new URL(url, base).toString() + if (allowPolicy) { + iframe.allow = allowPolicy; + } - if (allowPolicy) { - iframe.allow = allowPolicy; - } + if (allowApi) { + iframeListener.registerIframe(iframe); + } - if (allowApi) { - iframeListener.registerIframe(iframe); - } + iframeBuffer.appendChild(iframe); - iframeBuffer.appendChild(iframe); - - return iframe; - }, widthPercent, position); + return iframe; + }, + widthPercent, + position + ); } public async addCoWebsite( - callback: (iframeBuffer: HTMLDivElement) => PromiseLike|HTMLIFrameElement, + callback: (iframeBuffer: HTMLDivElement) => PromiseLike | HTMLIFrameElement, widthPercent?: number, position?: number ): Promise { @@ -473,10 +491,10 @@ class CoWebsiteManager { if (this.coWebsites.length < 1) { this.loadMain(); } else if (this.coWebsites.length === 5) { - throw new Error('Too many we') + throw new Error("Too many we"); } - Promise.resolve(callback(this.cowebsiteBufferDom)).then(iframe =>{ + Promise.resolve(callback(this.cowebsiteBufferDom)).then((iframe) => { iframe?.classList.add("pixel"); if (!iframe.id) { @@ -489,8 +507,11 @@ class CoWebsiteManager { iframe.onload = () => resolve(); }); + // const icon = this.generateCoWebsiteIcon(iframe); + const coWebsite = { iframe, + // icon, state : CoWebsiteState.OPENED, position: position ?? this.coWebsites.length, }; @@ -512,14 +533,14 @@ class CoWebsiteManager { setTimeout(() => { this.fire(); - position !== undefined ? - this.moveRightPreviousCoWebsite(coWebsite, coWebsite.position) : - this.moveCoWebsite(coWebsite, coWebsite.position); + position !== undefined + ? this.moveRightPreviousCoWebsite(coWebsite, coWebsite.position) + : this.moveCoWebsite(coWebsite, coWebsite.position); }, animationTime); } else { - position !== undefined ? - this.moveRightPreviousCoWebsite(coWebsite, coWebsite.position) : - this.moveCoWebsite(coWebsite, coWebsite.position); + position !== undefined + ? this.moveRightPreviousCoWebsite(coWebsite, coWebsite.position) + : this.moveCoWebsite(coWebsite, coWebsite.position); } return resolve(coWebsite); @@ -558,8 +579,7 @@ class CoWebsiteManager { } public closeCoWebsites(): Promise { - this.currentOperationPromise = this.currentOperationPromise - .then(() => { + this.currentOperationPromise = this.currentOperationPromise.then(() => { this.coWebsites.forEach((coWebsite: CoWebsite) => { this.closeCoWebsite(coWebsite); }); diff --git a/front/webpack.config.ts b/front/webpack.config.ts index 2446f2b1..9a464e40 100644 --- a/front/webpack.config.ts +++ b/front/webpack.config.ts @@ -193,6 +193,7 @@ module.exports = { ADMIN_URL: undefined, CONTACT_URL: null, PROFILE_URL: null, + ICON_URL: null, DEBUG_MODE: null, STUN_SERVER: null, TURN_SERVER: null,