Restructure code and documentation

This commit is contained in:
2025-08-25 16:28:43 +03:00
Unverified
parent 2999579bc5
commit 0f0db2041d
42 changed files with 198 additions and 306 deletions
+72
View File
@@ -0,0 +1,72 @@
import { API_BASE_URL } from "../core/config";
import { showLogin } from "../navigation";
import type { Headers, User } from "../core/types";
import { clearAlerts } from "./auth";
/**
* Current authenticated user information
* @type {User | null}
*/
export let currentUser: User | null = null;
/**
* JWT authentication token
* @type {string | null}
*/
export let authToken: string | null = null;
/**
* Sets the current user to the values provided.
* @param token The authentication JWT token.
* @param user The current authenticated user.
*/
export function setUser(token: string, user: User) {
authToken = token
currentUser = user
}
/**
* Generates authentication headers for API requests
* @param {boolean} json - Whether to include JSON content type header
* @returns {Headers} Headers object with authentication and content type
*/
export function getAuthHeaders(json: boolean = true): Headers {
const headers: Headers = {};
if (json) {
headers["Content-Type"] = "application/json";
}
if (authToken) {
headers['Authorization'] = `Bearer ${authToken}`;
}
return headers;
}
/**
* Checks authentication status on page load
*/
export async function checkAuthStatus(): Promise<void> {
// For JWT, we don't have a persistent token on page load
// So we'll just show the login form
showLogin();
}
/**
* Logs out the current user and clears session data
*/
export async function logout(): Promise<void> {
try {
await fetch(`${API_BASE_URL}/logout`, {
method: 'GET',
headers: getAuthHeaders()
});
} catch (error) {
console.error('Logout error:', error);
}
currentUser = null;
authToken = null;
showLogin();
clearAlerts();
}
@@ -5,90 +5,14 @@
* @version 1.0.0
*/
import { loadMessages } from "./chat";
import { initializeProfile } from "./profile";
import type { Headers, ErrorResponse, User, LoginResponse, LoginRequest, RegisterRequest } from "./types";
import { API_BASE_URL } from "./config";
/**
* Current authenticated user information
* @type {User | null}
*/
export let currentUser: User | null = null;
/**
* JWT authentication token
* @type {string | null}
*/
export let authToken: string | null = null;
/**
* Generates authentication headers for API requests
* @param {boolean} json - Whether to include JSON content type header
* @returns {Headers} Headers object with authentication and content type
* @function getAuthHeaders
* @example
* const headers = getAuthHeaders();
* fetch('/api/endpoint', { headers });
*/
export function getAuthHeaders(json: boolean = true): Headers {
const headers: Headers = {};
if (json) {
headers["Content-Type"] = "application/json";
}
if (authToken) {
headers['Authorization'] = `Bearer ${authToken}`;
}
return headers;
}
/**
* Shows the login form and hides other interfaces
* @function showLogin
* @example
* showLogin();
*/
export function showLogin(): void {
document.getElementById('login-form')!.style.display = 'flex';
document.getElementById('register-form')!.style.display = 'none';
document.getElementById('chat-interface')!.style.display = 'none';
clearAlerts();
document.getElementById("electron-title-bar")!.classList.add("color-surface");
}
/**
* Shows the registration form and hides other interfaces
* @function showRegister
* @example
* showRegister();
*/
export function showRegister(): void {
document.getElementById('login-form')!.style.display = 'none';
document.getElementById('register-form')!.style.display = 'flex';
document.getElementById('chat-interface')!.style.display = 'none';
clearAlerts();
document.getElementById("electron-title-bar")!.classList.add("color-surface");
}
/**
* Shows the chat interface and hides authentication forms
* @function showChat
* @example
* showChat();
*/
export function showChat(): void {
document.getElementById('login-form')!.style.display = 'none';
document.getElementById('register-form')!.style.display = 'none';
document.getElementById('chat-interface')!.style.display = 'block';
loadMessages();
document.getElementById("electron-title-bar")!.classList.remove("color-surface");
}
import { initializeProfile } from "../userPanel/profile/profile";
import type { ErrorResponse, LoginResponse, LoginRequest, RegisterRequest } from "../core/types";
import { API_BASE_URL } from "../core/config";
import { loadChat, showLogin, showRegister } from "../navigation";
import { setUser } from "./api";
/**
* Clears all alert messages from authentication forms
* @function clearAlerts
* @private
*/
export function clearAlerts(): void {
@@ -101,9 +25,6 @@ export function clearAlerts(): void {
* @param {string} containerId - ID of the container to show the alert in
* @param {string} message - Alert message to display
* @param {'success' | 'danger'} type - Type of alert (success or danger)
* @function showAlert
* @example
* showAlert('login-alerts', 'Login successful!', 'success');
*/
export function showAlert(containerId: string, message: string, type: "success" | "danger" = 'danger'): void {
const container = document.getElementById(containerId)!;
@@ -115,10 +36,7 @@ export function showAlert(containerId: string, message: string, type: "success"
/**
* Handles login form submission
* @async
* @function handleLogin
* @param {Event} e - Form submission event
* @private
*/
async function handleLogin(e: Event): Promise<void> {
e.preventDefault();
@@ -151,10 +69,8 @@ async function handleLogin(e: Event): Promise<void> {
if (response.ok) {
const data: LoginResponse = await response.json();
// Store the JWT token
authToken = data.token;
currentUser = data.user;
showChat();
loadMessages(); // Start loading messages
setUser(data.token, data.user)
loadChat();
initializeProfile(); // Initialize profile after login
} else {
const data: ErrorResponse = await response.json();
@@ -167,8 +83,6 @@ async function handleLogin(e: Event): Promise<void> {
/**
* Handles registration form submission
* @async
* @function handleRegister
* @param {Event} e - Form submission event
* @private
*/
@@ -234,72 +148,15 @@ async function handleRegister(e: Event): Promise<void> {
}
/**
* Logs out the current user and clears session data
* @async
* @function logout
* @example
* await logout();
*/
export async function logout(): Promise<void> {
try {
await fetch(`${API_BASE_URL}/logout`, {
method: 'GET',
headers: getAuthHeaders()
});
} catch (error) {
console.error('Logout error:', error);
}
currentUser = null;
authToken = null;
showLogin();
clearAlerts();
}
/**
* Loads the chat interface and initializes messaging
* @function loadChat
* @example
* loadChat();
*/
export function loadChat(): void {
showChat();
loadMessages();
}
/**
* Checks authentication status on page load
* @async
* @function checkAuthStatus
* @example
* await checkAuthStatus();
*/
export async function checkAuthStatus(): Promise<void> {
// For JWT, we don't have a persistent token on page load
// So we'll just show the login form
showLogin();
}
/**
* Sets up authentication form event listeners
* @function setupAuthForms
* Initializes authentication functionality
* @private
*/
function setupAuthForms(): void {
function init(): void {
document.getElementById('login-form-element')!.addEventListener('submit', handleLogin);
document.getElementById('register-form-element')!.addEventListener('submit', handleRegister);
}
/**
* Initializes links
* @function setupLinks
* @private
*/
function setupLinks(): void {
document.getElementById("login-link")!.addEventListener("click", showLogin);
document.getElementById("register-link")!.addEventListener("click", showRegister);
}
// Initialize authentication forms
setupAuthForms();
setupLinks();
init();
@@ -5,22 +5,19 @@
* @version 1.0.0
*/
import { getAuthHeaders, currentUser, authToken } from "./auth";
import { API_BASE_URL } from "./config";
import { websocket } from "./websocket";
import type { Message, Messages, WebSocketMessage } from "./types";
import { formatTime } from "./utils/utils";
import { show as showContextMenu } from "./message-context-menu";
import { show as showUserProfileDialog } from "./user-profile-dialog";
import defaultAvatar from "./images/default-avatar.png";
import { API_BASE_URL } from "../core/config";
import { websocket } from "../websocket";
import type { Message, Messages, WebSocketMessage } from "../core/types";
import { formatTime } from "../utils/utils";
import { show as showContextMenu } from "./contextMenu";
import { show as showUserProfileDialog } from "./profileDialog";
import defaultAvatar from "../resources/images/default-avatar.png";
import { authToken, currentUser, getAuthHeaders } from "../auth/api";
/**
* Adds a new message to the chat interface
* @param {Message} message - Message object to display
* @param {boolean} isAuthor - Whether the current user is the message author
* @function addMessage
* @example
* addMessage(messageData, messageData.username === currentUser.username);
*/
export function addMessage(message: Message, isAuthor: boolean): void {
const messagesContainer = document.querySelector('.chat-messages') as HTMLElement;
@@ -127,9 +124,6 @@ export function addMessage(message: Message, isAuthor: boolean): void {
/**
* Loads chat messages from the server
* @function loadMessages
* @example
* loadMessages();
*/
export function loadMessages(): void {
fetch(`${API_BASE_URL}/get_messages`, {
@@ -158,9 +152,6 @@ export function loadMessages(): void {
/**
* Sends a message via WebSocket
* @function sendMessage
* @example
* sendMessage();
*/
export function sendMessage(): void {
const input = document.querySelector('.message-input') as HTMLInputElement;
@@ -202,7 +193,6 @@ document.getElementById('message-form')!.addEventListener('submit', (e) => {
/**
* Updates an existing message in the chat interface
* @param {Message} message - Updated message object
* @function updateMessage
*/
export function updateMessage(message: Message): void {
const messageElement = document.querySelector(`[data-id="${message.id}"]`) as HTMLElement;
@@ -227,7 +217,6 @@ export function updateMessage(message: Message): void {
/**
* Removes a message from the chat interface
* @param {number} messageId - ID of the message to remove
* @function removeMessage
*/
export function removeMessage(messageId: number): void {
const messageElement = document.querySelector(`[data-id="${messageId}"]`) as HTMLElement;
@@ -239,7 +228,6 @@ export function removeMessage(messageId: number): void {
/**
* Handles WebSocket message updates
* @param {WebSocketMessage} response - WebSocket response
* @function handleWebSocketMessage
*/
export function handleWebSocketMessage(response: WebSocketMessage): void {
switch (response.type) {
@@ -5,13 +5,13 @@
* @version 1.0.0
*/
import { currentUser, authToken } from "./auth";
import { websocket } from "./websocket";
import type { Message, WebSocketMessage } from "./types";
import { showSuccess, showError } from "./utils/notification";
import { delay } from "./utils/utils";
import { websocket } from "../websocket";
import type { Message, WebSocketMessage } from "../core/types";
import { showSuccess, showError } from "../utils/notification";
import { delay } from "../utils/utils";
import type { Dialog } from "mdui/components/dialog";
import type { TextField } from "mdui/components/text-field";
import { currentUser, authToken } from "../auth/api";
let menu = document.getElementById("message-context-menu")!;
@@ -83,7 +83,7 @@ export function show(message: Message, x: number, y: number): void {
const deleteItem = menu.querySelector('[data-action="delete"]') as HTMLElement;
const isAuthor = message.username === currentUser?.username;
const isOwner = !!currentUser?.admin;
const isOwner = currentUser?.admin;
editItem.style.display = isAuthor ? 'flex' : 'none';
deleteItem.style.display = (isAuthor || isOwner) ? 'flex' : 'none';
@@ -5,12 +5,12 @@
* @version 1.0.0
*/
import { getAuthHeaders, currentUser } from "./auth";
import { API_BASE_URL } from "./config";
import type { UserProfile } from "./types";
import { showError, showSuccess } from "./utils/notification";
import { formatTime } from "./utils/utils";
import defaultAvatar from "./images/default-avatar.png";
import { getAuthHeaders, currentUser } from "../auth/api";
import { API_BASE_URL } from "../core/config";
import type { UserProfile } from "../core/types";
import { showError, showSuccess } from "../utils/notification";
import { formatTime } from "../utils/utils";
import defaultAvatar from "../resources/images/default-avatar.png";
let dialog = document.getElementById("user-profile-dialog")!;
@@ -7,21 +7,18 @@
/**
* Base API endpoint for all backend requests
* @type {string}
* @constant
*/
export const API_BASE_URL: string = '/api';
export const API_BASE_URL = `${location.host || "https://fromchat.toolbox-io.ru"}/api`;
/**
* Full API URL including hostname and port for WebSocket connections
* @type {string}
* @constant
*/
export const API_FULL_BASE_URL: string = `${location.host}/api`;
export const API_WS_BASE_URL = `${location.host || "fromchat.toolbox-io.ru"}/api`;
/**
* Application name displayed in UI and document title
* @type {string}
* @constant
*/
export const PRODUCT_NAME: string = "FromChat";
export const PRODUCT_NAME = "FromChat";
@@ -5,7 +5,7 @@
* @version 1.0.0
*/
import { showLogin } from "./auth";
import { showLogin } from "../navigation";
import { PRODUCT_NAME } from "./config";
showLogin();
+8 -1
View File
@@ -1,5 +1,12 @@
/**
* @fileoverview Electron-specific code
* @description This module initializes Electron-specific functionality.
* @author denis0001-dev
* @version 1.0.0
*/
import "../../electron.d.ts";
import { PRODUCT_NAME } from "../config.ts";
import { PRODUCT_NAME } from "../core/config.ts";
if (window.electronInterface !== undefined) {
console.log("Running in Electron");
+8 -8
View File
@@ -5,15 +5,15 @@
* @version 1.0.0
*/
import './css/style.scss';
import './resources/css/style.scss';
import "mdui/mdui.css";
import "./utils/material";
import "./chat";
import "./settings";
import "./leftpanel";
import "./init";
import "./profile";
import "./message-context-menu";
import "./user-profile-dialog";
import "./chat/chat";
import "./userPanel/settings";
import "./userPanel/leftpanel";
import "./core/init";
import "./userPanel/profile/profile";
import "./chat/contextMenu";
import "./chat/profileDialog";
import "./electron/electron";
+43
View File
@@ -0,0 +1,43 @@
import { clearAlerts } from "./auth/auth";
import { loadMessages } from "./chat/chat";
/**
* Shows the login form and hides other interfaces.
*/
export function showLogin(): void {
document.getElementById('login-form')!.style.display = 'flex';
document.getElementById('register-form')!.style.display = 'none';
document.getElementById('chat-interface')!.style.display = 'none';
clearAlerts();
document.getElementById("electron-title-bar")!.classList.add("color-surface");
}
/**
* Shows the registration form and hides other interfaces.
*/
export function showRegister(): void {
document.getElementById('login-form')!.style.display = 'none';
document.getElementById('register-form')!.style.display = 'flex';
document.getElementById('chat-interface')!.style.display = 'none';
clearAlerts();
document.getElementById("electron-title-bar")!.classList.add("color-surface");
}
/**
* Shows the chat interface and hides authentication forms.
*/
export function showChat(): void {
document.getElementById('login-form')!.style.display = 'none';
document.getElementById('register-form')!.style.display = 'none';
document.getElementById('chat-interface')!.style.display = 'block';
loadMessages();
document.getElementById("electron-title-bar")!.classList.remove("color-surface");
}
/**
* Loads the chat interface and initializes messaging.
*/
export function loadChat(): void {
showChat();
loadMessages();
}

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

@@ -20,7 +20,6 @@ const dialogClose = document.getElementById("profile-dialog-close")!;
/**
* Sets up chat collapse functionality
* @function setupChatCollapse
* @private
*/
function setupChatCollapse(): void {
@@ -32,7 +31,6 @@ function setupChatCollapse(): void {
/**
* Sets up chat switching functionality
* @function setupChatSwitching
* @private
*/
function setupChatSwitching(): void {
@@ -51,7 +49,6 @@ function setupChatSwitching(): void {
/**
* Sets up profile dialog functionality
* @function setupProfileDialog
* @private
*/
function setupProfileDialog(): void {
@@ -5,14 +5,13 @@
* @version 1.0.0
*/
import { getAuthHeaders } from '../auth';
import { getAuthHeaders } from '../../auth/api';
import type { ProfileData, UploadResponse } from './types';
/**
* Loads user profile data from the server
* @async
* @function loadProfile
* @returns {Promise<ProfileData | null>} User profile data or null if failed
* @returns User profile data or null if failed
* @example
* const profile = await loadProfile();
* if (profile) {
@@ -38,8 +37,6 @@ export async function loadProfile(): Promise<ProfileData | null> {
/**
* Uploads a profile picture to the server
* @async
* @function uploadProfilePicture
* @param {Blob} file - The image file to upload
* @returns {Promise<UploadResponse | null>} Upload response with URL or null if failed
* @example
@@ -47,7 +44,7 @@ export async function loadProfile(): Promise<ProfileData | null> {
* const file = fileInput.files[0];
* const result = await uploadProfilePicture(file);
* if (result) {
* console.log('Uploaded to:', result.profile_picture_url);
* console.log('Uploaded to:', result.profile_picture_url);
* }
*/
export async function uploadProfilePicture(file: Blob): Promise<UploadResponse | null> {
@@ -73,8 +70,6 @@ export async function uploadProfilePicture(file: Blob): Promise<UploadResponse |
/**
* Updates user profile information
* @async
* @function updateProfile
* @param {Partial<ProfileData>} data - Profile data to update
* @returns {Promise<boolean>} True if update was successful, false otherwise
* @example
@@ -103,8 +98,6 @@ export async function updateProfile(data: Partial<ProfileData>): Promise<boolean
/**
* Updates user bio
* @async
* @function updateBio
* @param {string} bio - New bio text
* @returns {Promise<boolean>} True if update was successful, false otherwise
* @example
@@ -7,7 +7,7 @@
import { updateProfile } from './api';
import { loadProfile } from './api';
import { showSuccess, showError } from '../utils/notification';
import { showSuccess, showError } from '../../utils/notification';
import type { TextField } from 'mdui/components/text-field';
let profileForm = document.getElementById('profile-form')!;
@@ -23,9 +23,6 @@ let isInitialized = false;
/**
* Sets the username field value
* @param {string} value - The username value to set
* @function setUsernameValue
* @example
* setUsernameValue('John Doe');
*/
export function setUsernameValue(value: string): void {
if (nicknameField && nicknameField.value !== undefined) {
@@ -36,9 +33,6 @@ export function setUsernameValue(value: string): void {
/**
* Sets the description field value
* @param {string} value - The description value to set
* @function setDescriptionValue
* @example
* setDescriptionValue('Software Developer');
*/
export function setDescriptionValue(value: string): void {
if (descriptionField && descriptionField.value !== undefined) {
@@ -49,10 +43,6 @@ export function setDescriptionValue(value: string): void {
/**
* Gets the current username field value
* @returns {string} The current username value
* @function getUsernameValue
* @example
* const username = getUsernameValue();
* console.log('Current username:', username);
*/
export function getUsernameValue(): string {
if (nicknameField && nicknameField.value !== undefined) {
@@ -64,10 +54,6 @@ export function getUsernameValue(): string {
/**
* Gets the current description field value
* @returns {string} The current description value
* @function getDescriptionValue
* @example
* const description = getDescriptionValue();
* console.log('Current description:', description);
*/
export function getDescriptionValue(): string {
if (descriptionField && descriptionField.value !== undefined) {
@@ -78,10 +64,6 @@ export function getDescriptionValue(): string {
/**
* Loads profile data from the server and populates the form fields
* @async
* @function loadProfileData
* @example
* await loadProfileData();
*/
export async function loadProfileData(): Promise<void> {
const userData = await loadProfile();
@@ -97,8 +79,6 @@ export async function loadProfileData(): Promise<void> {
/**
* Handles profile form submission
* @async
* @function handleFormSubmission
* @param {Event} e - Form submission event
* @private
*/
@@ -124,7 +104,6 @@ async function handleFormSubmission(e: Event): Promise<void> {
/**
* Sets up form submission handler
* @function setupFormHandler
* @private
*/
function setupFormHandler(): void {
@@ -142,9 +121,6 @@ function setupFormHandler(): void {
/**
* Initializes profile editor functionality
* @function initializeProfileEditor
* @example
* initializeProfileEditor();
*/
export function initializeProfileEditor(): void {
setupFormHandler();
@@ -5,7 +5,7 @@
* @version 1.0.0
*/
import type { Size2D } from "../types";
import type { Size2D } from "../../core/types";
/**
* Image cropper class for circular profile picture cropping
@@ -63,7 +63,6 @@ export class ImageCropper {
/**
* Sets up mouse and touch event listeners
* @function setupEventListeners
* @private
*/
private setupEventListeners(): void {
@@ -78,7 +77,6 @@ export class ImageCropper {
/**
* Handles mouse down events
* @param {MouseEvent} e - Mouse event
* @function onMouseDown
* @private
*/
private onMouseDown(e: MouseEvent): void {
@@ -89,7 +87,6 @@ export class ImageCropper {
/**
* Handles mouse move events during dragging
* @param {MouseEvent} e - Mouse event
* @function onMouseMove
* @private
*/
private onMouseMove(e: MouseEvent): void {
@@ -107,7 +104,6 @@ export class ImageCropper {
/**
* Handles mouse up events
* @function onMouseUp
* @private
*/
private onMouseUp(): void {
@@ -117,7 +113,6 @@ export class ImageCropper {
/**
* Handles touch start events
* @param {TouchEvent} e - Touch event
* @function onTouchStart
* @private
*/
private onTouchStart(e: TouchEvent): void {
@@ -130,7 +125,6 @@ export class ImageCropper {
/**
* Handles touch move events during dragging
* @param {TouchEvent} e - Touch event
* @function onTouchMove
* @private
*/
private onTouchMove(e: TouchEvent): void {
@@ -150,7 +144,6 @@ export class ImageCropper {
/**
* Handles touch end events
* @function onTouchEnd
* @private
*/
private onTouchEnd(): void {
@@ -161,9 +154,6 @@ export class ImageCropper {
* Loads an image file for cropping
* @param {File} file - Image file to load
* @returns {Promise<void>} Promise that resolves when image is loaded
* @async
* @example
* await cropper.loadImage(fileInput.files[0]);
*/
loadImage(file: File): Promise<void> {
return new Promise((resolve) => {
@@ -178,7 +168,6 @@ export class ImageCropper {
/**
* Renders the image with circular crop overlay
* @function render
* @private
*/
private render(): void {
@@ -216,9 +205,6 @@ export class ImageCropper {
/**
* Gets the cropped image as a data URL
* @returns {string} Data URL of the cropped image
* @example
* const croppedImage = cropper.getCroppedImage();
* // Use croppedImage as src for an img element
*/
getCroppedImage(): string {
return this.canvas.toDataURL('image/jpeg', 0.8);
@@ -226,9 +212,6 @@ export class ImageCropper {
/**
* Destroys the cropper and removes the canvas from DOM
* @function destroy
* @example
* cropper.destroy();
*/
destroy(): void {
if (this.canvas.parentNode) {
@@ -6,9 +6,9 @@
*/
import type { Dialog } from "mdui/components/dialog";
import { loadProfileData } from './profile/editor';
import { loadProfilePicture, initializeProfileUpload } from "./profile/upload";
import { initializeProfileEditor } from './profile/editor';
import { loadProfileData } from './editor';
import { loadProfilePicture, initializeProfileUpload } from "./upload";
import { initializeProfileEditor } from './editor';
// Handle profile form submission
const form = document.getElementById("profile-form")!;
@@ -24,10 +24,6 @@ form.addEventListener("submit", async (e) => {
/**
* Initializes profile functionality after user login
* @function initializeProfile
* @example
* // Called after successful authentication
* initializeProfile();
*/
export function initializeProfile(): void {
// Initialize profile modules
@@ -6,10 +6,10 @@
*/
import type { Dialog } from "mdui/components/dialog";
import { ImageCropper } from './image-cropper';
import { ImageCropper } from './imageCropper';
import { uploadProfilePicture } from './api';
import { loadProfile } from './api';
import { showSuccess, showError } from '../utils/notification';
import { showSuccess, showError } from '../../utils/notification';
/**
* Global image cropper instance
@@ -33,8 +33,6 @@ let cropperArea = document.getElementById('cropper-area')!;
/**
* Opens the image cropper with the selected file
* @async
* @function openCropper
* @param {File} file - The image file to crop
* @private
*/
@@ -54,7 +52,6 @@ async function openCropper(file: File): Promise<void> {
/**
* Closes the image cropper and cleans up resources
* @function closeCropper
* @private
*/
function closeCropper(): void {
@@ -69,8 +66,6 @@ function closeCropper(): void {
/**
* Saves the cropped image and uploads it to the server
* @async
* @function saveCroppedImage
* @private
*/
async function saveCroppedImage(): Promise<void> {
@@ -87,7 +82,7 @@ async function saveCroppedImage(): Promise<void> {
if (result) {
// Update profile picture display
const profilePicture = document.getElementById('profile-picture') as HTMLImageElement;
profilePicture.src = result.profile_picture_url + '?t=' + Date.now(); // Cache bust
profilePicture.src = `${result.profile_picture_url}?t=${Date.now()}`; // Cache bust
// Close cropper
closeCropper();
@@ -101,7 +96,6 @@ async function saveCroppedImage(): Promise<void> {
/**
* Sets up event listeners for upload functionality
* @function setupEventListeners
* @private
*/
function setupEventListeners(): void {
@@ -136,9 +130,6 @@ function setupEventListeners(): void {
/**
* Loads and displays the user's profile picture
* @async
* @function loadProfilePicture
* @example
* await loadProfilePicture();
*/
export async function loadProfilePicture(): Promise<void> {
const userData = await loadProfile();
@@ -154,9 +145,6 @@ export async function loadProfilePicture(): Promise<void> {
/**
* Initializes profile upload functionality
* @function initializeProfileUpload
* @example
* initializeProfileUpload();
*/
export function initializeProfileUpload(): void {
setupEventListeners();
@@ -32,7 +32,6 @@ const panelMapping = {
/**
* Handles click events on settings list items
* @param {Element} item - The clicked list item element
* @function handleListItemClick
* @private
*/
function handleListItemClick(item: Element): void {
@@ -58,7 +57,6 @@ function handleListItemClick(item: Element): void {
/**
* Sets up click listeners for all settings list items
* @function setupSettingsNavigation
* @private
*/
function setupSettingsNavigation(): void {
@@ -70,7 +68,6 @@ function setupSettingsNavigation(): void {
/**
* Resets settings dialog to show the first panel
* @function resetToFirstPanel
* @private
*/
function resetToFirstPanel(): void {
@@ -86,7 +83,6 @@ function resetToFirstPanel(): void {
/**
* Sets up dialog event listeners
* @function setupDialogListeners
* @private
*/
function setupDialogListeners(): void {
-7
View File
@@ -15,7 +15,6 @@ export type NotificationType = 'success' | 'error';
* Shows a notification with the specified message and type
* @param {string} message - The message to display
* @param {NotificationType} type - The type of notification (success or error)
* @function showNotification
* @private
*/
function showNotification(message: string, type: NotificationType): void {
@@ -49,9 +48,6 @@ function showNotification(message: string, type: NotificationType): void {
/**
* Shows a success notification
* @param {string} message - The success message to display
* @function showSuccess
* @example
* showSuccess('Profile updated successfully!');
*/
export function showSuccess(message: string): void {
showNotification(message, 'success');
@@ -60,9 +56,6 @@ export function showSuccess(message: string): void {
/**
* Shows an error notification
* @param {string} message - The error message to display
* @function showError
* @example
* showError('Failed to update profile');
*/
export function showError(message: string): void {
showNotification(message, 'error');
+21 -15
View File
@@ -5,14 +5,12 @@
* @version 1.0.0
*/
import { handleWebSocketMessage } from "./chat";
import { API_FULL_BASE_URL } from "./config";
import type { WebSocketMessage } from "./types";
import { handleWebSocketMessage } from "./chat/chat";
import { API_WS_BASE_URL } from "./core/config";
import { delay } from "./utils/utils";
/**
* Creates a new WebSocket connection to the chat server
* @function create
* @returns {WebSocket} New WebSocket instance
* @private
*/
@@ -22,7 +20,7 @@ function create(): WebSocket {
prefix = "wss://";
}
return new WebSocket(`${prefix}${API_FULL_BASE_URL}/chat/ws`);
return new WebSocket(`${prefix}${API_WS_BASE_URL}/chat/ws`);
}
/**
@@ -31,16 +29,14 @@ function create(): WebSocket {
*/
export let websocket: WebSocket = create();
// --------------
// Initialization
// --------------
websocket.addEventListener("message", (e) => {
const message: WebSocketMessage = JSON.parse(e.data);
handleWebSocketMessage(message);
});
websocket.addEventListener("error", async () => {
/**
* This function will wait 3 seconds and them attempts to reconnect the WebSocket.
* If it fails, tries again in an endless loop until the connection is established
* again.
*
* @private
*/
async function onError() {
console.warn("WebSocket disconnected, retrying in 3 seconds...");
await delay(3000);
websocket = create();
@@ -52,4 +48,14 @@ websocket.addEventListener("error", async () => {
}
websocket.addEventListener("open", listener);
websocket.addEventListener("error", onError);
}
// --------------
// Initialization
// --------------
websocket.addEventListener("message", (e) => {
handleWebSocketMessage(JSON.parse(e.data));
});
websocket.addEventListener("error", onError);