mirror of
https://github.com/fromchat-messenger/web.git
synced 2026-09-22 19:15:08 +03:00
Restructure code and documentation
This commit is contained in:
@@ -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();
|
||||
@@ -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");
|
||||
|
||||
@@ -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";
|
||||
@@ -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();
|
||||
+1
-18
@@ -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 {
|
||||
@@ -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
@@ -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);
|
||||
Reference in New Issue
Block a user