Nigel/block user (#60)
* WIP block users * Add test to check if the person for user X is blocked or not * Added function isBlocked return true if user x is blocked by user y * Added block ans un block messages * Route / broadcast added ny Maix * notification block and un block with icon now works, started clean up * cleaning up the code * cleaning up the code - WIP * cleaning up the code - WIP * clean up code - WIP * clean up code - WIP * WIP block users * Add test to check if the person for user X is blocked or not * Added function isBlocked return true if user x is blocked by user y * Added block ans un block messages * REBASE -trying * REBASE trying * REBASE problems * REBASE problems * REBASE problems * MERGE problems * REBASE problem * REBASE problem * clean up code - WIP * MERGED master into nigel/blockUser * linter OK * TTT problem with package * Deletes tic tac and icons
This commit is contained in:
parent
64a820c0f0
commit
85eca5d301
60 changed files with 2613 additions and 1891 deletions
|
|
@ -11,15 +11,15 @@
|
|||
"devDependencies": {
|
||||
"@types/js-cookie": "^3.0.6",
|
||||
"typescript": "~5.9.3",
|
||||
"vite": "^7.2.7",
|
||||
"vite": "^7.3.0",
|
||||
"vite-tsconfig-paths": "^5.1.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tailwindcss/vite": "^4.1.17",
|
||||
"@tailwindcss/vite": "^4.1.18",
|
||||
"@types/qrcode": "^1.5.6",
|
||||
"js-cookie": "^3.0.5",
|
||||
"qrcode": "^1.5.4",
|
||||
"socket.io-client": "^4.8.1",
|
||||
"tailwindcss": "^4.1.17"
|
||||
"tailwindcss": "^4.1.18"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
572
frontend/pnpm-lock.yaml
generated
572
frontend/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load diff
|
|
@ -9,8 +9,6 @@ models/ChangePassword400Response.ts
|
|||
models/ChangePassword401Response.ts
|
||||
models/ChangePassword500Response.ts
|
||||
models/ChangePasswordRequest.ts
|
||||
models/ChatTest200Response.ts
|
||||
models/ChatTest200ResponsePayload.ts
|
||||
models/DisableOtp200Response.ts
|
||||
models/DisableOtp400Response.ts
|
||||
models/DisableOtp500Response.ts
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ import type {
|
|||
ChangePassword401Response,
|
||||
ChangePassword500Response,
|
||||
ChangePasswordRequest,
|
||||
ChatTest200Response,
|
||||
DisableOtp200Response,
|
||||
DisableOtp400Response,
|
||||
DisableOtp500Response,
|
||||
|
|
@ -74,8 +73,6 @@ import {
|
|||
ChangePassword500ResponseToJSON,
|
||||
ChangePasswordRequestFromJSON,
|
||||
ChangePasswordRequestToJSON,
|
||||
ChatTest200ResponseFromJSON,
|
||||
ChatTest200ResponseToJSON,
|
||||
DisableOtp200ResponseFromJSON,
|
||||
DisableOtp200ResponseToJSON,
|
||||
DisableOtp400ResponseFromJSON,
|
||||
|
|
@ -291,48 +288,6 @@ export class OpenapiOtherApi extends runtime.BaseAPI {
|
|||
return await response.value();
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
async chatTestRaw(initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<ChatTest200Response | StatusOtp401Response>> {
|
||||
const queryParameters: any = {};
|
||||
|
||||
const headerParameters: runtime.HTTPHeaders = {};
|
||||
|
||||
|
||||
let urlPath = `/api/chat/test`;
|
||||
|
||||
const response = await this.request({
|
||||
path: urlPath,
|
||||
method: 'GET',
|
||||
headers: headerParameters,
|
||||
query: queryParameters,
|
||||
}, initOverrides);
|
||||
|
||||
// CHANGED: Handle all status codes defined in the OpenAPI spec, not just 2xx responses
|
||||
// This allows typed access to error responses (4xx, 5xx) and other status codes.
|
||||
// The code routes responses based on the actual HTTP status code and returns
|
||||
// appropriately typed ApiResponse wrappers for each status code.
|
||||
if (response.status === 200) {
|
||||
// Object response for status 200
|
||||
return new runtime.JSONApiResponse(response, (jsonValue) => ChatTest200ResponseFromJSON(jsonValue));
|
||||
}
|
||||
if (response.status === 401) {
|
||||
// Object response for status 401
|
||||
return new runtime.JSONApiResponse(response, (jsonValue) => StatusOtp401ResponseFromJSON(jsonValue));
|
||||
}
|
||||
// CHANGED: Throw error if status code is not handled by any of the defined responses
|
||||
// This ensures all code paths return a value and provides clear error messages for unexpected status codes
|
||||
// Only throw if responses were defined but none matched the actual status code
|
||||
throw new runtime.ResponseError(response, `Unexpected status code: ${response.status}. Expected one of: 200, 401`);
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
async chatTest(initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<ChatTest200Response | StatusOtp401Response> {
|
||||
const response = await this.chatTestRaw(initOverrides);
|
||||
return await response.value();
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
async disableOtpRaw(initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<DisableOtp200Response | DisableOtp400Response | ChangePassword401Response | DisableOtp500Response>> {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,66 @@
|
|||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* @fastify/swagger
|
||||
* No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
|
||||
*
|
||||
* The version of the OpenAPI document: 9.6.1
|
||||
*
|
||||
*
|
||||
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
|
||||
* https://openapi-generator.tech
|
||||
* Do not edit the class manually.
|
||||
*/
|
||||
|
||||
import { mapValues } from '../runtime';
|
||||
/**
|
||||
*
|
||||
* @export
|
||||
* @interface ApiChatBroadcastPostRequest
|
||||
*/
|
||||
export interface ApiChatBroadcastPostRequest {
|
||||
/**
|
||||
*
|
||||
* @type {string}
|
||||
* @memberof ApiChatBroadcastPostRequest
|
||||
*/
|
||||
nextGame: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a given object implements the ApiChatBroadcastPostRequest interface.
|
||||
*/
|
||||
export function instanceOfApiChatBroadcastPostRequest(value: object): value is ApiChatBroadcastPostRequest {
|
||||
if (!('nextGame' in value) || value['nextGame'] === undefined) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
export function ApiChatBroadcastPostRequestFromJSON(json: any): ApiChatBroadcastPostRequest {
|
||||
return ApiChatBroadcastPostRequestFromJSONTyped(json, false);
|
||||
}
|
||||
|
||||
export function ApiChatBroadcastPostRequestFromJSONTyped(json: any, ignoreDiscriminator: boolean): ApiChatBroadcastPostRequest {
|
||||
if (json == null) {
|
||||
return json;
|
||||
}
|
||||
return {
|
||||
|
||||
'nextGame': json['nextGame'],
|
||||
};
|
||||
}
|
||||
|
||||
export function ApiChatBroadcastPostRequestToJSON(json: any): ApiChatBroadcastPostRequest {
|
||||
return ApiChatBroadcastPostRequestToJSONTyped(json, false);
|
||||
}
|
||||
|
||||
export function ApiChatBroadcastPostRequestToJSONTyped(value?: ApiChatBroadcastPostRequest | null, ignoreDiscriminator: boolean = false): any {
|
||||
if (value == null) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
'nextGame': value['nextGame'],
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -8,8 +8,6 @@ export * from './ChangePassword400Response';
|
|||
export * from './ChangePassword401Response';
|
||||
export * from './ChangePassword500Response';
|
||||
export * from './ChangePasswordRequest';
|
||||
export * from './ChatTest200Response';
|
||||
export * from './ChatTest200ResponsePayload';
|
||||
export * from './DisableOtp200Response';
|
||||
export * from './DisableOtp400Response';
|
||||
export * from './DisableOtp500Response';
|
||||
|
|
|
|||
|
|
@ -77,6 +77,23 @@
|
|||
relative; /* needed for overlay */
|
||||
}
|
||||
|
||||
.modal-messages {
|
||||
@apply
|
||||
h-[80px]
|
||||
bg-white
|
||||
text-gray-700
|
||||
p-3
|
||||
rounded-3xl
|
||||
mb-2 border
|
||||
border-gray-200
|
||||
text-center
|
||||
shadow
|
||||
overflow-y-auto
|
||||
justify-end /* 👈 forces text to bottom */
|
||||
relative; /* needed for overlay */
|
||||
}
|
||||
|
||||
|
||||
|
||||
.text-info {
|
||||
@apply
|
||||
|
|
@ -230,6 +247,12 @@ div-private {
|
|||
right-12
|
||||
}
|
||||
|
||||
.popup-b-block {
|
||||
@apply
|
||||
absolute
|
||||
bottom-62
|
||||
right-12
|
||||
}
|
||||
|
||||
.popUpMessage {
|
||||
@apply
|
||||
|
|
|
|||
13
frontend/src/pages/chat/actionBtnPopUpBlock.ts
Normal file
13
frontend/src/pages/chat/actionBtnPopUpBlock.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
import { Socket } from 'socket.io-client';
|
||||
import type { ClientProfil } from './types_front';
|
||||
import { blockUser } from './blockUser';
|
||||
|
||||
export function actionBtnPopUpBlock(block: ClientProfil, senderSocket: Socket) {
|
||||
setTimeout(() => {
|
||||
const blockUserBtn = document.querySelector("#popup-b-block");
|
||||
blockUserBtn?.addEventListener("click", () => {
|
||||
block.text = '';
|
||||
blockUser(block, senderSocket);
|
||||
});
|
||||
}, 0)
|
||||
};
|
||||
13
frontend/src/pages/chat/actionBtnPopUpClear.ts
Normal file
13
frontend/src/pages/chat/actionBtnPopUpClear.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
import { clearChatWindow } from './clearChatWindow';
|
||||
import { Socket } from 'socket.io-client';
|
||||
import type { ClientProfil } from './types_front';
|
||||
|
||||
|
||||
export function actionBtnPopUpClear(profil: ClientProfil, senderSocket: Socket) {
|
||||
setTimeout(() => {
|
||||
const clearTextBtn = document.querySelector("#popup-b-clear");
|
||||
clearTextBtn?.addEventListener("click", () => {
|
||||
clearChatWindow(senderSocket);
|
||||
});
|
||||
}, 0)
|
||||
};
|
||||
18
frontend/src/pages/chat/addMessage.ts
Normal file
18
frontend/src/pages/chat/addMessage.ts
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
import { color } from './chat';
|
||||
|
||||
/**
|
||||
* function adds a message to the frontend chatWindow
|
||||
* @param text
|
||||
* @returns
|
||||
*/
|
||||
|
||||
export function addMessage(text: string) {
|
||||
const chatWindow = document.getElementById("t-chatbox") as HTMLDivElement;
|
||||
if (!chatWindow) return;
|
||||
const messageElement = document.createElement("div-test");
|
||||
messageElement.textContent = text;
|
||||
chatWindow.appendChild(messageElement);
|
||||
chatWindow.scrollTop = chatWindow.scrollHeight;
|
||||
console.log(`%c DEBUG LOG: Added new message:%c ${text}`, color.red, color.reset);
|
||||
return ;
|
||||
};
|
||||
11
frontend/src/pages/chat/blockUser.ts
Normal file
11
frontend/src/pages/chat/blockUser.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import { Socket } from 'socket.io-client';
|
||||
import type { ClientProfil } from './types_front';
|
||||
import { getUser } from "@app/auth";
|
||||
|
||||
|
||||
export function blockUser(profil: ClientProfil, senderSocket: Socket) {
|
||||
profil.SenderName = getUser()?.name ?? '';
|
||||
if (profil.SenderName === profil.user) return;
|
||||
// addMessage(`${profil.Sendertext}: ${profil.user}⛔`)
|
||||
senderSocket.emit('blockUser', JSON.stringify(profil));
|
||||
};
|
||||
28
frontend/src/pages/chat/broadcastMsg.ts
Normal file
28
frontend/src/pages/chat/broadcastMsg.ts
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
import { addMessage } from "./addMessage";
|
||||
import { Socket } from 'socket.io-client';
|
||||
import { getUser } from "@app/auth";
|
||||
|
||||
/**
|
||||
* function sends socket.emit to the backend to active and broadcast a message to all sockets
|
||||
* echos the message with addMessage to the sender
|
||||
* @param socket
|
||||
* @param msgCommand
|
||||
*/
|
||||
export function broadcastMsg (socket: Socket, msgCommand: string[]): void {
|
||||
let msgText = msgCommand[1] ?? "";
|
||||
addMessage(msgText);
|
||||
const user = getUser();
|
||||
if (user && socket?.connected) {
|
||||
const message = {
|
||||
command: msgCommand,
|
||||
destination: '',
|
||||
type: "chat",
|
||||
user: user.name,
|
||||
token: document.cookie,
|
||||
text: msgText,
|
||||
timestamp: Date.now(),
|
||||
SenderWindowID: socket.id,
|
||||
};
|
||||
socket.emit('message', JSON.stringify(message));
|
||||
}
|
||||
};
|
||||
|
|
@ -37,14 +37,16 @@
|
|||
</div>
|
||||
<div id="game-modal" class="gamePopup hidden">
|
||||
<div class="popUpMessage">
|
||||
<p class="" id="modal-message"></p>
|
||||
<div id="game-info">
|
||||
<p class="modal-messages " id="modal-message"></p>
|
||||
</div>
|
||||
<button id="close-modal-message" class="btn-style absolute bottom-67 right-12">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-gray-400 mt-2">From this Chat Box you can send messages to other players</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -4,58 +4,30 @@ import authHtml from './chat.html?raw';
|
|||
import client from '@app/api'
|
||||
import { getUser, updateUser } from "@app/auth";
|
||||
import io, { Socket } from 'socket.io-client';
|
||||
import { listBuddies } from './listBuddies';
|
||||
import { getProfil } from './getProfil';
|
||||
import { addMessage } from './addMessage';
|
||||
import { broadcastMsg } from './broadcastMsg';
|
||||
import { isLoggedIn } from './isLoggedIn';
|
||||
import type { ClientMessage, ClientProfil } from './types_front';
|
||||
import { openProfilePopup } from './openProfilePopup';
|
||||
import { actionBtnPopUpClear } from './actionBtnPopUpClear';
|
||||
import { actionBtnPopUpBlock } from './actionBtnPopUpBlock';
|
||||
import { windowStateHidden } from './windowStateHidden';
|
||||
|
||||
const color = {
|
||||
export const color = {
|
||||
red: 'color: red;',
|
||||
green: 'color: green;',
|
||||
yellow: 'color: orange;',
|
||||
blue: 'color: blue;',
|
||||
reset: '',
|
||||
reset: '',
|
||||
};
|
||||
|
||||
export type ClientMessage = {
|
||||
command: string
|
||||
destination: string;
|
||||
user: string;
|
||||
text: string;
|
||||
SenderWindowID: string;
|
||||
};
|
||||
|
||||
|
||||
export type ClientProfil = {
|
||||
command: string,
|
||||
destination: string,
|
||||
type: string,
|
||||
user: string,
|
||||
loginName: string,
|
||||
userID: string,
|
||||
text: string,
|
||||
timestamp: number,
|
||||
SenderWindowID:string,
|
||||
SenderName: string,
|
||||
innerHtml?: string,
|
||||
|
||||
};
|
||||
|
||||
// export type inviteGame = {
|
||||
// command?: string,
|
||||
// destination?: string,
|
||||
// type?: string,
|
||||
// user?: string,
|
||||
// loginName?: string,
|
||||
// userID?: string,
|
||||
// innerHtml?: string,
|
||||
// timestamp?: number,
|
||||
// SenderWindowID?:string,
|
||||
// };
|
||||
|
||||
|
||||
|
||||
// get the name of the machine used to connect
|
||||
// get the name of the machine used to connect
|
||||
const machineHostName = window.location.hostname;
|
||||
console.log('connect to login at %chttps://' + machineHostName + ':8888/app/login',color.yellow);
|
||||
|
||||
let __socket: Socket | undefined = undefined;
|
||||
export let __socket: Socket | undefined = undefined;
|
||||
document.addEventListener('ft:pageChange', () => {
|
||||
if (__socket !== undefined)
|
||||
__socket.close();
|
||||
|
|
@ -63,7 +35,7 @@ document.addEventListener('ft:pageChange', () => {
|
|||
console.log("Page changed");
|
||||
});
|
||||
|
||||
function getSocket(): Socket {
|
||||
export function getSocket(): Socket {
|
||||
let addressHost = `wss://${machineHostName}:8888`;
|
||||
// let addressHost = `wss://localhost:8888`;
|
||||
if (__socket === undefined)
|
||||
|
|
@ -76,29 +48,6 @@ function getSocket(): Socket {
|
|||
return __socket;
|
||||
};
|
||||
|
||||
function addMessage(text: string) {
|
||||
const chatWindow = document.getElementById("t-chatbox") as HTMLDivElement;
|
||||
if (!chatWindow) return;
|
||||
const messageElement = document.createElement("div-test");
|
||||
messageElement.textContent = text;
|
||||
chatWindow.appendChild(messageElement);
|
||||
chatWindow.scrollTop = chatWindow.scrollHeight;
|
||||
console.log(`Added new message: ${text}`)
|
||||
return ;
|
||||
};
|
||||
|
||||
function clear(senderSocket: Socket) {
|
||||
const chatWindow = document.getElementById("t-chatbox") as HTMLDivElement;
|
||||
if (!chatWindow) return;
|
||||
chatWindow.innerHTML = "";
|
||||
// senderSocket.emit('nextGame');
|
||||
|
||||
}
|
||||
|
||||
function isLoggedIn() {
|
||||
return getUser() || null;
|
||||
};
|
||||
|
||||
function inviteToPlayPong(profil: ClientProfil, senderSocket: Socket) {
|
||||
profil.SenderName = getUser()?.name ?? '';
|
||||
if (profil.SenderName === profil.user) return;
|
||||
|
|
@ -106,18 +55,6 @@ function inviteToPlayPong(profil: ClientProfil, senderSocket: Socket) {
|
|||
senderSocket.emit('inviteGame', JSON.stringify(profil));
|
||||
};
|
||||
|
||||
|
||||
|
||||
function actionBtnPopUpClear(profil: ClientProfil, senderSocket: Socket) {
|
||||
setTimeout(() => {
|
||||
const clearTextBtn = document.querySelector("#popup-b-clear");
|
||||
clearTextBtn?.addEventListener("click", () => {
|
||||
clear(senderSocket);
|
||||
});
|
||||
}, 0)
|
||||
};
|
||||
|
||||
|
||||
function actionBtnPopUpInvite(invite: ClientProfil, senderSocket: Socket) {
|
||||
setTimeout(() => {
|
||||
const InvitePongBtn = document.querySelector("#popup-b-invite");
|
||||
|
|
@ -127,48 +64,29 @@ function actionBtnPopUpInvite(invite: ClientProfil, senderSocket: Socket) {
|
|||
}, 0)
|
||||
};
|
||||
|
||||
// async function windowStateHidden() {
|
||||
// const socketId = __socket || undefined;
|
||||
// // let oldName = localStorage.getItem("oldName") ?? undefined;
|
||||
// let oldName: string;
|
||||
// if (socketId === undefined) return;
|
||||
// let userName = await updateUser();
|
||||
// oldName = userName?.name ?? "";
|
||||
// if (oldName === "") return;
|
||||
// localStorage.setItem('oldName', oldName);
|
||||
// socketId.emit('client_left', {
|
||||
// user: userName?.name,
|
||||
// why: 'tab window hidden - socket not dead',
|
||||
// });
|
||||
// return;
|
||||
// };
|
||||
|
||||
|
||||
// getProfil get the profil of user
|
||||
function getProfil(socket: Socket, user: string) {
|
||||
if (!socket.connected) return;
|
||||
const profil = {
|
||||
command: '@profil',
|
||||
destination: 'profilMessage',
|
||||
type: "chat",
|
||||
user: user,
|
||||
token: document.cookie ?? "",
|
||||
text: user,
|
||||
timestamp: Date.now(),
|
||||
SenderWindowID: socket.id,
|
||||
};
|
||||
// addMessage(JSON.stringify(profil));
|
||||
socket.emit('profilMessage', JSON.stringify(profil));
|
||||
}
|
||||
|
||||
async function windowStateHidden() {
|
||||
const socketId = __socket || undefined;
|
||||
// let oldName = localStorage.getItem("oldName") ?? undefined;
|
||||
let oldName: string;
|
||||
if (socketId === undefined) return;
|
||||
let userName = await updateUser();
|
||||
oldName = userName?.name ?? "";
|
||||
if (oldName === "") return;
|
||||
localStorage.setItem('oldName', oldName);
|
||||
socketId.emit('client_left', {
|
||||
user: userName?.name,
|
||||
why: 'tab window hidden - socket not dead',
|
||||
});
|
||||
return;
|
||||
};
|
||||
|
||||
async function windowStateVisable() {
|
||||
|
||||
const buddies = document.getElementById('div-buddies') as HTMLDivElement;
|
||||
const buddies = document.getElementById('div-buddies') as HTMLDivElement;
|
||||
const socketId = __socket || undefined;
|
||||
let oldName = localStorage.getItem("oldName") || undefined;
|
||||
console.log("%c WINDOW VISIBLE - oldName :'" + oldName + "'", color.green);
|
||||
|
||||
|
||||
if (socketId === undefined || oldName === undefined) {console.log("%SOCKET ID", color.red); return;}
|
||||
let user = await updateUser();
|
||||
if(user === null) return;
|
||||
|
|
@ -203,7 +121,7 @@ function parseCmdMsg(msgText: string): string[] | undefined {
|
|||
|
||||
const ArgCommands = ['@profil', '@block'];
|
||||
const userName = msgText.indexOf(" ");
|
||||
const cmd2 = msgText.slice(0, userName).trim() ?? "";
|
||||
const cmd2 = msgText.slice(0, userName).trim() ?? "";
|
||||
const user = msgText.slice(userName + 1).trim();
|
||||
if (ArgCommands.includes(cmd2)) {
|
||||
command[0] = cmd2;
|
||||
|
|
@ -216,41 +134,41 @@ function parseCmdMsg(msgText: string): string[] | undefined {
|
|||
command[1] = '';
|
||||
return command;
|
||||
}
|
||||
const cmd = msgText.slice(0, colonIndex).trim();
|
||||
const rest = msgText.slice(colonIndex + 1).trim();
|
||||
const cmd = msgText.slice(0, colonIndex).trim();
|
||||
const rest = msgText.slice(colonIndex + 1).trim();
|
||||
command[0] = cmd;
|
||||
command[1] = rest;
|
||||
return command;
|
||||
}
|
||||
|
||||
async function listBuddies(socket: Socket, buddies: HTMLDivElement, listBuddies: string) {
|
||||
// async function listBuddies(socket: Socket, buddies: HTMLDivElement, listBuddies: string) {
|
||||
|
||||
if (!buddies) return;
|
||||
const sendtextbox = document.getElementById('t-chat-window') as HTMLButtonElement;
|
||||
const buddiesElement = document.createElement("div-buddies-list");
|
||||
buddiesElement.textContent = listBuddies + '\n';
|
||||
const user = getUser()?.name ?? "";
|
||||
// if (!buddies) return;
|
||||
// const sendtextbox = document.getElementById('t-chat-window') as HTMLButtonElement;
|
||||
// const buddiesElement = document.createElement("div-buddies-list");
|
||||
// buddiesElement.textContent = listBuddies + '\n';
|
||||
// const user = getUser()?.name ?? "";
|
||||
// buddies.appendChild(buddiesElement);
|
||||
// buddies.scrollTop = buddies.scrollHeight;
|
||||
// console.log(`Added buddies: ${listBuddies}`);
|
||||
|
||||
buddiesElement.style.cursor = "pointer";
|
||||
buddiesElement.addEventListener("click", () => {
|
||||
navigator.clipboard.writeText(listBuddies);
|
||||
if (listBuddies !== user && user !== "") {
|
||||
sendtextbox.value = `@${listBuddies}: `;
|
||||
console.log("Copied to clipboard:", listBuddies);
|
||||
sendtextbox.focus();
|
||||
}
|
||||
});
|
||||
// buddiesElement.style.cursor = "pointer";
|
||||
// buddiesElement.addEventListener("click", () => {
|
||||
// navigator.clipboard.writeText(listBuddies);
|
||||
// if (listBuddies !== user && user !== "") {
|
||||
// sendtextbox.value = `@${listBuddies}: `;
|
||||
// console.log("Copied to clipboard:", listBuddies);
|
||||
// sendtextbox.focus();
|
||||
// }
|
||||
// });
|
||||
|
||||
buddiesElement.addEventListener("dblclick", () => {
|
||||
console.log("Open profile:", listBuddies);
|
||||
getProfil(socket, listBuddies);
|
||||
sendtextbox.value = "";
|
||||
});
|
||||
// buddiesElement.addEventListener("dblclick", () => {
|
||||
// console.log("Open profile:", listBuddies);
|
||||
// getProfil(socket, listBuddies);
|
||||
// sendtextbox.value = "";
|
||||
// });
|
||||
|
||||
buddies.appendChild(buddiesElement);
|
||||
buddies.scrollTop = buddies.scrollHeight;
|
||||
console.log(`Added buddies: ${listBuddies}`);
|
||||
}
|
||||
// }
|
||||
|
||||
|
||||
function waitSocketConnected(socket: Socket): Promise<void> {
|
||||
|
|
@ -278,7 +196,7 @@ function quitChat (socket: Socket) {
|
|||
console.error("Quit Chat error:", e);
|
||||
showError('Failed to Quit Chat: Unknown error');
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
// const bconnected = document.getElementById('b-help') as HTMLButtonElement;
|
||||
|
|
@ -295,32 +213,13 @@ function logout(socket: Socket) {
|
|||
// window.location.href = "/login";
|
||||
};
|
||||
|
||||
function broadcastMsg (socket: Socket, msgCommand: string[]): void {
|
||||
let msgText = msgCommand[1] ?? "";
|
||||
console.log('%cmsgText:', color.red, msgText);
|
||||
addMessage(msgText);
|
||||
const user = getUser();
|
||||
if (user && socket?.connected) {
|
||||
const message = {
|
||||
command: msgCommand,
|
||||
destination: '',
|
||||
type: "chat",
|
||||
user: user.name,
|
||||
token: document.cookie,
|
||||
text: msgText,
|
||||
timestamp: Date.now(),
|
||||
SenderWindowID: socket.id,
|
||||
};
|
||||
socket.emit('message', JSON.stringify(message));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
async function connected(socket: Socket): Promise<void> {
|
||||
|
||||
|
||||
try {
|
||||
const buddies = document.getElementById('div-buddies') as HTMLDivElement;
|
||||
const loggedIn = isLoggedIn();
|
||||
if (!loggedIn) throw('Not Logged in');
|
||||
console.log('%cloggedIn:',color.blue, loggedIn?.name);
|
||||
let oldUser = localStorage.getItem("oldName") ?? "";
|
||||
console.log('%coldUser:',color.yellow, oldUser);
|
||||
|
|
@ -348,9 +247,9 @@ async function whoami(socket: Socket) {
|
|||
const chatWindow = document.getElementById("t-chatbox") as HTMLDivElement;
|
||||
const loggedIn = isLoggedIn();
|
||||
|
||||
const res = await client.guestLogin();
|
||||
switch (res.kind) {
|
||||
case 'success': {
|
||||
const res = (getUser());
|
||||
console.log('loginGuest():', res?.name);
|
||||
if (res) {
|
||||
let user = await updateUser();
|
||||
if (chatWindow) {
|
||||
socket.emit('updateClientName', {
|
||||
|
|
@ -361,53 +260,61 @@ async function whoami(socket: Socket) {
|
|||
if (user === null)
|
||||
return showError('Failed to get user: no user ?');
|
||||
setTitle(`Welcome ${user.guest ? '[GUEST] ' : ''}${user.name}`);
|
||||
break;
|
||||
} else {
|
||||
showError(`Failed to login: ${res}`);
|
||||
}
|
||||
case 'failed': {
|
||||
showError(`Failed to login: ${res.msg}`);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (e) {
|
||||
console.error("Login error:", e);
|
||||
showError('Failed to login: Unknown error');
|
||||
}
|
||||
};
|
||||
|
||||
async function openProfilePopup(profil: ClientProfil) {
|
||||
// async function openProfilePopup(profil: ClientProfil) {
|
||||
|
||||
|
||||
const modalname = document.getElementById("modal-name") ?? null;
|
||||
if (modalname)
|
||||
modalname.innerHTML = `
|
||||
<div class="profile-info">
|
||||
<div-profil-name id="profilName"> Profil of ${profil.user} </div>
|
||||
<div-login-name id="loginName"> Login Name: '${profil.loginName ?? 'Guest'}' </div>
|
||||
</br>
|
||||
<div-login-name id="loginName"> Login ID: '${profil.userID ?? ''}' </div>
|
||||
</br>
|
||||
<button id="popup-b-clear" class="btn-style popup-b-clear">Clear Text</button>
|
||||
<button id="popup-b-invite" class="btn-style popup-b-invite">U Game ?</button>
|
||||
<div id="profile-about">About: '${profil.text}' </div>
|
||||
</div>
|
||||
`;
|
||||
const profilList = document.getElementById("profile-modal") ?? null;
|
||||
if (profilList)
|
||||
profilList.classList.remove("hidden");
|
||||
// The popup now exists → attach the event
|
||||
|
||||
// const modalname = document.getElementById("modal-name") ?? null;
|
||||
// if (modalname)
|
||||
// modalname.innerHTML = `
|
||||
// <div class="profile-info">
|
||||
// <div-profil-name id="profilName"> Profil of ${profil.user} </div>
|
||||
// <div-login-name id="loginName"> Login Name: '${profil.loginName ?? 'Guest'}' </div>
|
||||
// </br>
|
||||
// <div-login-name id="loginName"> Login ID: '${profil.userID ?? ''}' </div>
|
||||
// </br>
|
||||
// <button id="popup-b-clear" class="btn-style popup-b-clear">Clear Text</button>
|
||||
// <button id="popup-b-invite" class="btn-style popup-b-invite">U Game ?</button>
|
||||
// <button id="popup-b-block" class="btn-style popup-b-block">Block User</button>
|
||||
// <div id="profile-about">About: '${profil.text}' </div>
|
||||
// </div>
|
||||
// `;
|
||||
// const profilList = document.getElementById("profile-modal") ?? null;
|
||||
// if (profilList)
|
||||
// profilList.classList.remove("hidden");
|
||||
// // The popup now exists → attach the event
|
||||
// }
|
||||
|
||||
let count = 0;
|
||||
function incrementCounter(): number {
|
||||
count += 1;
|
||||
return count;
|
||||
}
|
||||
|
||||
async function openMessagePopup(message: string) {
|
||||
|
||||
|
||||
const modalmessage = document.getElementById("modal-message") ?? null;
|
||||
if(!message) return
|
||||
const obj:any = JSON.parse(message);
|
||||
if (modalmessage)
|
||||
modalmessage.innerHTML = `
|
||||
if (modalmessage) {
|
||||
const messageElement = document.createElement("div");
|
||||
messageElement.innerHTML = `
|
||||
<div class="profile-info">
|
||||
</br>
|
||||
<div id="profile-about">Next Game Message: ${obj.link}</div>
|
||||
<div id="profile-about">Next Game Message ${incrementCounter()}: ${obj.link}</div>
|
||||
</div>`;
|
||||
modalmessage.appendChild(messageElement);
|
||||
modalmessage.scrollTop = modalmessage.scrollHeight;
|
||||
|
||||
}
|
||||
const gameMessage = document.getElementById("game-modal") ?? null;
|
||||
if (gameMessage)
|
||||
gameMessage.classList.remove("hidden");
|
||||
|
|
@ -418,11 +325,9 @@ async function openMessagePopup(message: string) {
|
|||
|
||||
|
||||
function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn {
|
||||
|
||||
|
||||
|
||||
let socket = getSocket();
|
||||
|
||||
|
||||
|
||||
// Listen for the 'connect' event
|
||||
socket.on("connect", async () => {
|
||||
|
|
@ -458,9 +363,9 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
|
|||
const bconnected = document.getElementById('b-help') as HTMLButtonElement;
|
||||
|
||||
if (bconnected) {
|
||||
connected(socket);
|
||||
connected(socket);
|
||||
}
|
||||
|
||||
|
||||
if (chatWindow && data.message.destination === "") {
|
||||
const messageElement = document.createElement("div");
|
||||
messageElement.textContent = `${data.message.user}: ${data.message.text}`;
|
||||
|
|
@ -474,7 +379,7 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
|
|||
chatWindow.scrollTop = chatWindow.scrollHeight;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const MAX_SYSTEM_MESSAGES = 10;
|
||||
|
||||
if (systemWindow && data.message.destination === "system-info") {
|
||||
|
|
@ -491,20 +396,36 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
|
|||
console.log("Getuser():", getUser());
|
||||
});
|
||||
|
||||
socket.on('profilMessage', (profil: ClientProfil) => {
|
||||
openProfilePopup(profil);
|
||||
socket.on('profilMessage', (profil: ClientProfil) => {
|
||||
openProfilePopup(profil);
|
||||
actionBtnPopUpClear(profil, socket);
|
||||
actionBtnPopUpInvite(profil, socket);
|
||||
actionBtnPopUpBlock(profil, socket);
|
||||
});
|
||||
|
||||
socket.on('inviteGame', (invite: ClientProfil) => {
|
||||
socket.on('inviteGame', (invite: ClientProfil) => {
|
||||
const chatWindow = document.getElementById("t-chatbox") as HTMLDivElement;
|
||||
const messageElement = document.createElement("div");
|
||||
messageElement.innerHTML =`🏓${invite.SenderName}: ${invite.innerHtml}`;
|
||||
chatWindow.appendChild(messageElement);
|
||||
chatWindow.scrollTop = chatWindow.scrollHeight;
|
||||
});
|
||||
|
||||
socket.on('logout', () => {
|
||||
|
||||
socket.on('blockUser', (blocked: ClientProfil) => {
|
||||
let icon = '⛔';
|
||||
const chatWindow = document.getElementById("t-chatbox") as HTMLDivElement;
|
||||
const messageElement = document.createElement("div");
|
||||
if (`${blocked.text}` === '\'I have un-blocked you\'' ) { icon = '💚'};
|
||||
messageElement.innerText =`${icon}${blocked.SenderName}: ${blocked.text}`;
|
||||
chatWindow.appendChild(messageElement);
|
||||
chatWindow.scrollTop = chatWindow.scrollHeight;
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
socket.on('logout', () => {
|
||||
quitChat(socket);
|
||||
});
|
||||
|
||||
|
|
@ -513,7 +434,7 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
|
|||
})
|
||||
|
||||
//receives broadcast of the next GAME
|
||||
socket.on('nextGame', (message) => {
|
||||
socket.on('nextGame', (message: string) => {
|
||||
openMessagePopup(message);
|
||||
// addMessage(message);
|
||||
})
|
||||
|
|
@ -547,7 +468,7 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
|
|||
|
||||
socket.on('listBud', async (myBuddies: string) => {
|
||||
const buddies = document.getElementById('div-buddies') as HTMLDivElement;
|
||||
console.log('List buddies connected ', myBuddies);
|
||||
console.log('%cList buddies connected ',color.yellow, myBuddies);
|
||||
listBuddies(socket, buddies, myBuddies);
|
||||
});
|
||||
|
||||
|
|
@ -584,18 +505,6 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
|
|||
buddies.textContent = '';
|
||||
buddies.innerHTML = '';
|
||||
|
||||
|
||||
const value = await client.chatTest();
|
||||
if (value.kind === "success") {
|
||||
console.log(value.payload);
|
||||
} else if (value.kind === "notLoggedIn") {
|
||||
console.log('not logged in');
|
||||
} else {
|
||||
console.log('unknown response: ', value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
const buttonPro = document.getElementById("close-modal") ?? null;
|
||||
|
||||
if (buttonPro)
|
||||
|
|
@ -613,6 +522,9 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
|
|||
buttonMessage.addEventListener("click", () => {
|
||||
const gameMessage = document.getElementById("game-modal") ?? null;
|
||||
if (gameMessage) gameMessage.classList.add("hidden");
|
||||
const modalmessage = document.getElementById("modal-message") ?? null;
|
||||
if (modalmessage) {modalmessage.innerHTML = "";}
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
|
@ -638,7 +550,7 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
|
|||
break;
|
||||
case '@quit':
|
||||
quitChat(socket);
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
const user = getUser()?.name;
|
||||
// Ensure we have a user AND socket is connected
|
||||
|
|
@ -669,7 +581,7 @@ function handleChat(_url: string, _args: RouteHandlerParams): RouteHandlerReturn
|
|||
if (chatWindow) {
|
||||
chatWindow.innerHTML = '';
|
||||
}
|
||||
clear(socket); //DEV testing broadcastGames
|
||||
//clearChatWindow(socket); //DEV testing broadcastGames
|
||||
});
|
||||
|
||||
// Dev Game message button
|
||||
|
|
|
|||
13
frontend/src/pages/chat/clearChatWindow.ts
Normal file
13
frontend/src/pages/chat/clearChatWindow.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
import io, { Socket } from 'socket.io-client';
|
||||
|
||||
/**
|
||||
* function clears all messages in the chat window
|
||||
* @param senderSocket
|
||||
* @returns
|
||||
*/
|
||||
export function clearChatWindow(senderSocket: Socket) {
|
||||
const chatWindow = document.getElementById("t-chatbox") as HTMLDivElement;
|
||||
if (!chatWindow) return;
|
||||
chatWindow.innerHTML = "";
|
||||
// senderSocket.emit('nextGame');
|
||||
}
|
||||
24
frontend/src/pages/chat/getProfil.ts
Normal file
24
frontend/src/pages/chat/getProfil.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
import { Socket } from 'socket.io-client';
|
||||
|
||||
/**
|
||||
* getProfil of a user
|
||||
* @param socket
|
||||
* @param user
|
||||
* @returns
|
||||
*/
|
||||
|
||||
export function getProfil(socket: Socket, user: string) {
|
||||
if (!socket.connected) return;
|
||||
const profil = {
|
||||
command: '@profil',
|
||||
destination: 'profilMessage',
|
||||
type: "chat",
|
||||
user: user,
|
||||
token: document.cookie ?? "",
|
||||
text: user,
|
||||
timestamp: Date.now(),
|
||||
SenderWindowID: socket.id,
|
||||
};
|
||||
// addMessage(JSON.stringify(profil));
|
||||
socket.emit('profilMessage', JSON.stringify(profil));
|
||||
}
|
||||
9
frontend/src/pages/chat/isLoggedIn.ts
Normal file
9
frontend/src/pages/chat/isLoggedIn.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import { getUser } from "@app/auth";
|
||||
import type { User } from '@app/auth'
|
||||
/**
|
||||
* function checks if logged in
|
||||
* @returns either user | null
|
||||
*/
|
||||
export function isLoggedIn(): User | null {
|
||||
return getUser() || null;
|
||||
};
|
||||
45
frontend/src/pages/chat/listBuddies.ts
Normal file
45
frontend/src/pages/chat/listBuddies.ts
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
import { getUser } from "@app/auth";
|
||||
import { Socket } from 'socket.io-client';
|
||||
import { getProfil } from './getProfil';
|
||||
|
||||
/**
|
||||
* function adds a user to the ping Buddies window\
|
||||
* it also acts as click or double click\
|
||||
* activates two possible actions:\
|
||||
* click => private Mag\
|
||||
* dbl click => get Profil of the name\
|
||||
* collected in the clipBoard
|
||||
* @param socket
|
||||
* @param buddies
|
||||
* @param listBuddies
|
||||
* @returns
|
||||
*/
|
||||
|
||||
export async function listBuddies(socket: Socket, buddies: HTMLDivElement, listBuddies: string) {
|
||||
|
||||
if (!buddies) return;
|
||||
const sendtextbox = document.getElementById('t-chat-window') as HTMLButtonElement;
|
||||
const buddiesElement = document.createElement("div-buddies-list");
|
||||
buddiesElement.textContent = listBuddies + '\n';
|
||||
const user = getUser()?.name ?? "";
|
||||
buddies.appendChild(buddiesElement);
|
||||
buddies.scrollTop = buddies.scrollHeight;
|
||||
console.log(`Added buddies: ${listBuddies}`);
|
||||
|
||||
buddiesElement.style.cursor = "pointer";
|
||||
buddiesElement.addEventListener("click", () => {
|
||||
navigator.clipboard.writeText(listBuddies);
|
||||
if (listBuddies !== user && user !== "") {
|
||||
sendtextbox.value = `@${listBuddies}: `;
|
||||
console.log("Copied to clipboard:", listBuddies);
|
||||
sendtextbox.focus();
|
||||
}
|
||||
});
|
||||
|
||||
buddiesElement.addEventListener("dblclick", () => {
|
||||
console.log("Open profile:", listBuddies);
|
||||
getProfil(socket, listBuddies);
|
||||
sendtextbox.value = "";
|
||||
});
|
||||
|
||||
}
|
||||
24
frontend/src/pages/chat/openProfilePopup.ts
Normal file
24
frontend/src/pages/chat/openProfilePopup.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
import type { ClientProfil } from './types_front';
|
||||
|
||||
export async function openProfilePopup(profil: ClientProfil) {
|
||||
const modalname = document.getElementById("modal-name") ?? null;
|
||||
if (modalname)
|
||||
modalname.innerHTML =
|
||||
`
|
||||
<div class="profile-info">
|
||||
<div-profil-name id="profilName"> Profil of ${profil.user} </div>
|
||||
<div-login-name id="loginName"> Login Name: '${profil.loginName ?? 'Guest'}' </div>
|
||||
</br>
|
||||
<div-login-name id="loginName"> Login ID: '${profil.userID ?? ''}' </div>
|
||||
</br>
|
||||
<button id="popup-b-clear" class="btn-style popup-b-clear">Clear Text</button>
|
||||
<button id="popup-b-invite" class="btn-style popup-b-invite">U Game ?</button>
|
||||
<button id="popup-b-block" class="btn-style popup-b-block">Block User</button>
|
||||
<div id="profile-about">About: '${profil.text}' </div>
|
||||
</div>
|
||||
`;
|
||||
const profilList = document.getElementById("profile-modal") ?? null;
|
||||
if (profilList)
|
||||
profilList.classList.remove("hidden");
|
||||
// The popup now exists → attach the event
|
||||
}
|
||||
23
frontend/src/pages/chat/types_front.ts
Normal file
23
frontend/src/pages/chat/types_front.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
export type ClientMessage = {
|
||||
command: string
|
||||
destination: string;
|
||||
user: string;
|
||||
text: string;
|
||||
SenderWindowID: string;
|
||||
};
|
||||
|
||||
|
||||
export type ClientProfil = {
|
||||
command: string,
|
||||
destination: string,
|
||||
type: string,
|
||||
user: string,
|
||||
loginName: string,
|
||||
userID: string,
|
||||
text: string,
|
||||
timestamp: number,
|
||||
SenderWindowID:string,
|
||||
SenderName: string,
|
||||
Sendertext: string,
|
||||
innerHtml?: string,
|
||||
};
|
||||
18
frontend/src/pages/chat/windowStateHidden.ts
Normal file
18
frontend/src/pages/chat/windowStateHidden.ts
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
import { __socket } from './chat';
|
||||
import { updateUser } from "@app/auth";
|
||||
|
||||
export async function windowStateHidden() {
|
||||
const socketId = __socket || undefined;
|
||||
// let oldName = localStorage.getItem("oldName") ?? undefined;
|
||||
let oldName: string;
|
||||
if (socketId === undefined) return;
|
||||
let userName = await updateUser();
|
||||
oldName = userName?.name ?? "";
|
||||
if (oldName === "") return;
|
||||
localStorage.setItem('oldName', oldName);
|
||||
socketId.emit('client_left', {
|
||||
user: userName?.name,
|
||||
why: 'tab window hidden - socket not dead',
|
||||
});
|
||||
return;
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue