Implement the register screen and make auth work

This commit is contained in:
2025-08-30 11:21:24 +03:00
Unverified
parent 1b98ee1b51
commit 5804775927
6 changed files with 20 additions and 111 deletions
+3 -3
View File
@@ -1,5 +1,5 @@
import { API_BASE_URL } from "../core/config"; import { API_BASE_URL } from "../core/config";
import { showLogin } from "../navigation"; // import { showLogin } from "../navigation";
import type { Headers, User, WebSocketMessage } from "../core/types"; import type { Headers, User, WebSocketMessage } from "../core/types";
import { clearAlerts } from "./auth"; import { clearAlerts } from "./auth";
import { request } from "../websocket"; import { request } from "../websocket";
@@ -65,7 +65,7 @@ export function getAuthHeaders(json: boolean = true): Headers {
export async function checkAuthStatus(): Promise<void> { export async function checkAuthStatus(): Promise<void> {
// For JWT, we don't have a persistent token on page load // For JWT, we don't have a persistent token on page load
// So we'll just show the login form // So we'll just show the login form
showLogin(); // showLogin();
} }
/** /**
@@ -83,6 +83,6 @@ export async function logout(): Promise<void> {
currentUser = null; currentUser = null;
authToken = null; authToken = null;
showLogin(); // showLogin();
clearAlerts(); clearAlerts();
} }
+1 -94
View File
@@ -5,9 +5,6 @@
* @version 1.0.0 * @version 1.0.0
*/ */
import type { ErrorResponse, RegisterRequest } from "../core/types";
import { API_BASE_URL } from "../core/config";
import { showLogin } from "../navigation";
import { id } from "../utils/utils"; import { id } from "../utils/utils";
/** /**
@@ -17,94 +14,4 @@ import { id } from "../utils/utils";
export function clearAlerts(): void { export function clearAlerts(): void {
id('login-alerts').innerHTML = ''; id('login-alerts').innerHTML = '';
id('register-alerts').innerHTML = ''; id('register-alerts').innerHTML = '';
} }
/**
* Shows an alert message in the specified container
* @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)
*/
export function showAlert(containerId: string, message: string, type: "success" | "danger" = 'danger'): void {
const container = id(containerId);
const alertDiv = document.createElement('div');
alertDiv.className = `alert alert-${type}`;
alertDiv.textContent = message;
container.appendChild(alertDiv);
}
/**
* Handles registration form submission
* @param {Event} e - Form submission event
* @private
*/
async function handleRegister(e: Event): Promise<void> {
e.preventDefault();
const usernameElement = id<HTMLInputElement>('register-username');
const passwordElement = id<HTMLInputElement>('register-password');
const confirmPasswordElement = id<HTMLInputElement>('register-confirm-password');
const username = usernameElement.value.trim();
const password = passwordElement.value.trim();
const confirmPassword = confirmPasswordElement.value.trim();
if (!username || !password || !confirmPassword) {
showAlert('register-alerts', 'Пожалуйста, заполните все поля', 'danger');
return;
}
if (password !== confirmPassword) {
showAlert('register-alerts', 'Пароли не совпадают', 'danger');
return;
}
if (username.length < 3 || username.length > 20) {
showAlert('register-alerts', 'Имя пользователя должно быть от 3 до 20 символов', 'danger');
return;
}
if (password.length < 5 || password.length > 50) {
showAlert('register-alerts', 'Пароль должен быть от 5 до 50 символов', 'danger');
return;
}
try {
const request: RegisterRequest = {
username: username,
password: password,
confirm_password: confirmPassword
}
const response = await fetch(`${API_BASE_URL}/register`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(request)
});
if (response.ok) {
// Registration successful
showAlert('register-alerts', 'Регистрация прошла успешно! Теперь вы можете войти.', 'success');
setTimeout(() => {
showLogin();
}, 2000);
} else {
const data: ErrorResponse = await response.json();
showAlert('register-alerts', data.message || 'Ошибка при регистрации', 'danger');
}
} catch (error) {
showAlert('register-alerts', 'Ошибка соединения с сервером', 'danger');
}
}
/**
* Initializes authentication functionality
* @private
*/
function init(): void {
id('register-form-element').addEventListener('submit', handleRegister);
}
init();
+2 -2
View File
@@ -8,8 +8,8 @@ export interface Alert {
export function AlertsContainer({ alerts }: { alerts: Alert[]}) { export function AlertsContainer({ alerts }: { alerts: Alert[]}) {
return ( return (
<div> <div>
{alerts.map(alert => { {alerts.slice(-3).map((alert, i) => {
return <div className={`alert alert-${alert.type}`}>{alert.message}</div> return <div className={`alert alert-${alert.type}`} key={i}>{alert.message}</div>
})} })}
</div> </div>
) )
+7 -6
View File
@@ -1,20 +1,21 @@
import { useImmer } from "use-immer"; import { useImmer } from "use-immer";
import { showChat, showRegister } from "../../navigation";
import { AlertsContainer, type Alert, type AlertType } from "../components/Alerts"; import { AlertsContainer, type Alert, type AlertType } from "../components/Alerts";
import { AuthContainer, AuthHeader } from "../components/Auth"; import { AuthContainer, AuthHeader } from "../components/Auth";
import type { ErrorResponse, LoginRequest, LoginResponse } from "../../core/types"; import type { ErrorResponse, LoginRequest, LoginResponse } from "../../core/types";
import { setUser } from "../../auth/api"; import { setUser } from "../../auth/api";
import { ensureKeysOnLogin } from "../../auth/crypto"; import { ensureKeysOnLogin } from "../../auth/crypto";
import { API_BASE_URL } from "../../core/config"; import { API_BASE_URL } from "../../core/config";
import { initializeProfile } from "../../userPanel/profile/profile"; // import { initializeProfile } from "../../userPanel/profile/profile";
import { useRef } from "react"; import { useRef } from "react";
import type { TextField } from "mdui/components/text-field"; import type { TextField } from "mdui/components/text-field";
import { useAppState } from "../state";
export default function LoginScreen() { export default function LoginScreen() {
const [alerts, updateAlerts] = useImmer<Alert[]>([]); const [alerts, updateAlerts] = useImmer<Alert[]>([]);
const setCurrentPage = useAppState(state => state.setCurrentPage);
function showAlert(type: AlertType, message: string) { function showAlert(type: AlertType, message: string) {
updateAlerts((alerts) => alerts.push({type: type, message: message})); updateAlerts((alerts) => { alerts.push({type: type, message: message}) });
} }
const usernameElement = useRef<TextField>(null); const usernameElement = useRef<TextField>(null);
@@ -61,8 +62,8 @@ export default function LoginScreen() {
} catch (e) { } catch (e) {
console.error("Key setup failed:", e); console.error("Key setup failed:", e);
} }
showChat(); setCurrentPage("chat");
initializeProfile(); // Initialize profile after login // initializeProfile(); // Initialize profile after login
} else { } else {
const data: ErrorResponse = await response.json(); const data: ErrorResponse = await response.json();
showAlert("danger", data.message || "Неверное имя пользователя или пароль"); showAlert("danger", data.message || "Неверное имя пользователя или пароль");
@@ -103,7 +104,7 @@ export default function LoginScreen() {
<a <a
href="#" href="#"
className="link" className="link"
onClick={showRegister}> onClick={() => setCurrentPage("register")}>
Зарегистрируйтесь Зарегистрируйтесь
</a> </a>
</p> </p>
+6 -4
View File
@@ -1,5 +1,5 @@
import { useImmer } from "use-immer"; import { useImmer } from "use-immer";
import { showLogin } from "../../navigation"; // import { showLogin } from "../../navigation";
import { AuthContainer, AuthHeader } from "../components/Auth"; import { AuthContainer, AuthHeader } from "../components/Auth";
import { AlertsContainer, type Alert, type AlertType } from "../components/Alerts"; import { AlertsContainer, type Alert, type AlertType } from "../components/Alerts";
import { useRef } from "react"; import { useRef } from "react";
@@ -7,12 +7,14 @@ import { TextField } from "mdui/components/text-field";
import type { ErrorResponse, RegisterRequest } from "../../core/types"; import type { ErrorResponse, RegisterRequest } from "../../core/types";
import { API_BASE_URL } from "../../core/config"; import { API_BASE_URL } from "../../core/config";
import { delay } from "../../utils/utils"; import { delay } from "../../utils/utils";
import { useAppState } from "../state";
export default function RegisterScreen() { export default function RegisterScreen() {
const [alerts, updateAlerts] = useImmer<Alert[]>([]); const [alerts, updateAlerts] = useImmer<Alert[]>([]);
const setCurrentPage = useAppState(state => state.setCurrentPage);
function showAlert(type: AlertType, message: string) { function showAlert(type: AlertType, message: string) {
updateAlerts((alerts) => alerts.push({type: type, message: message})); updateAlerts((alerts) => { alerts.push({type: type, message: message}) });
} }
const usernameElement = useRef<TextField>(null); const usernameElement = useRef<TextField>(null);
@@ -71,7 +73,7 @@ export default function RegisterScreen() {
// Registration successful // Registration successful
showAlert("success", "Регистрация прошла успешно! Теперь вы можете войти."); showAlert("success", "Регистрация прошла успешно! Теперь вы можете войти.");
await delay(2000); await delay(2000);
showLogin(); setCurrentPage("login");
} else { } else {
const data: ErrorResponse = await response.json(); const data: ErrorResponse = await response.json();
showAlert("danger", data.message || "Ошибка при регистрации"); showAlert("danger", data.message || "Ошибка при регистрации");
@@ -127,7 +129,7 @@ export default function RegisterScreen() {
href="#" href="#"
id="login-link" id="login-link"
className="link" className="link"
onClick={showLogin}> onClick={() => setCurrentPage("login")}>
Войдите Войдите
</a> </a>
</p> </p>
+1 -2
View File
@@ -5,7 +5,6 @@
* @version 1.0.0 * @version 1.0.0
*/ */
import { handleWebSocketMessage } from "./chat/chat";
import { API_WS_BASE_URL } from "./core/config"; import { API_WS_BASE_URL } from "./core/config";
import type { WebSocketMessage } from "./core/types"; import type { WebSocketMessage } from "./core/types";
import { delay } from "./utils/utils"; import { delay } from "./utils/utils";
@@ -71,6 +70,6 @@ async function onError() {
// -------------- // --------------
websocket.addEventListener("message", (e) => { websocket.addEventListener("message", (e) => {
handleWebSocketMessage(JSON.parse(e.data)); // handleWebSocketMessage(JSON.parse(e.data));
}); });
websocket.addEventListener("error", onError); websocket.addEventListener("error", onError);