diff --git a/modules/frontend/src/App.tsx b/modules/frontend/src/App.tsx
index de7101c..f8ebdf5 100644
--- a/modules/frontend/src/App.tsx
+++ b/modules/frontend/src/App.tsx
@@ -5,6 +5,7 @@ import UserPage from "./pages/UserPage/UserPage";
import TitlesPage from "./pages/TitlesPage/TitlesPage";
import TitlePage from "./pages/TitlePage/TitlePage";
import { LoginPage } from "./pages/LoginPage/LoginPage";
+import { SettingsPage } from "./pages/SettingsPage/SettingsPage";
import { Header } from "./components/Header/Header";
// import { OpenAPI } from "./api";
@@ -46,6 +47,12 @@ const App: React.FC = () => {
element={userId ? : }
/>
+ {/*settings*/}
+ : }
+ />
+
{/* titles */}
} />
} />
diff --git a/modules/frontend/src/components/Header/Header.tsx b/modules/frontend/src/components/Header/Header.tsx
index 36cbd5a..9c3b39a 100644
--- a/modules/frontend/src/components/Header/Header.tsx
+++ b/modules/frontend/src/components/Header/Header.tsx
@@ -32,6 +32,8 @@ export const Header: React.FC = () => {
localStorage.removeItem("user_id");
localStorage.removeItem("user_name");
setUsername(null);
+ setDropdownOpen(false);
+ setMenuOpen(false);
navigate("/login");
} catch (err) {
console.error(err);
@@ -74,14 +76,38 @@ export const Header: React.FC = () => {
{dropdownOpen && (
-
-
setDropdownOpen(false)}>Profile
-
+
+
setDropdownOpen(false)}
+ >
+ Profile
+
+
+ {/* КНОПКА SETTINGS */}
+
setDropdownOpen(false)}
+ >
+ Settings
+
+
+
+
+
)}
@@ -107,11 +133,16 @@ export const Header: React.FC = () => {
setMenuOpen(false)}>Titles
setMenuOpen(false)}>Users
setMenuOpen(false)}>About
+
{username ? (
- <>
-
setMenuOpen(false)}>Profile
-
- >
+
+ setMenuOpen(false)}>Profile
+
+ {/* SETTINGS (Mobile) */}
+ setMenuOpen(false)}>Settings
+
+
+
) : (
setMenuOpen(false)}>Login
)}
diff --git a/modules/frontend/src/pages/SettingsPage/SettingsPage.tsx b/modules/frontend/src/pages/SettingsPage/SettingsPage.tsx
index 16c7e9e..d3b6fc6 100644
--- a/modules/frontend/src/pages/SettingsPage/SettingsPage.tsx
+++ b/modules/frontend/src/pages/SettingsPage/SettingsPage.tsx
@@ -1,154 +1,212 @@
-// import React, { useEffect, useState } from "react";
-// import { updateUser, getUsersId } from "../../api";
-// import { useNavigate } from "react-router-dom";
+import React, { useEffect, useState, useRef } from "react";
+import { updateUser, getUsersId, postMediaUpload } from "../../api";
+import { useNavigate } from "react-router-dom";
+import { useCookies } from 'react-cookie';
-// export const SettingsPage: React.FC = () => {
-// const navigate = useNavigate();
+export const SettingsPage: React.FC = () => {
+ const [cookies] = useCookies(['xsrf_token']);
+ const xsrfToken = cookies['xsrf_token'] || null;
-// const userId = Number(localStorage.getItem("user_id"));
-// const initialNickname = localStorage.getItem("user_name") || "";
-// const [mail, setMail] = useState("");
-// const [nickname, setNickname] = useState(initialNickname);
-// const [dispName, setDispName] = useState("");
-// const [userDesc, setUserDesc] = useState("");
-// const [avatarId, setAvatarId] = useState
(null);
+ const navigate = useNavigate();
+ const fileInputRef = useRef(null);
-// const [loading, setLoading] = useState(false);
-// const [success, setSuccess] = useState(null);
-// const [error, setError] = useState(null);
+ const userId = Number(localStorage.getItem("user_id"));
+
+ // Состояния для полей формы
+ const [mail, setMail] = useState("");
+ const [nickname, setNickname] = useState("");
+ const [dispName, setDispName] = useState("");
+ const [userDesc, setUserDesc] = useState("");
+ const [avatarId, setAvatarId] = useState(null);
+ const [avatarUrl, setAvatarUrl] = useState(null);
-// useEffect(() => {
-// const fetch = async () => {
-// const res = await getUsersId({
-// path: { user_id: String(userId) },
-// });
+ const [loading, setLoading] = useState(false);
+ const [uploading, setUploading] = useState(false);
+ const [success, setSuccess] = useState(null);
+ const [error, setError] = useState(null);
-// setProfile(res.data);
-// };
+ // Загружаем текущие данные пользователя при входе
+ useEffect(() => {
+ const fetchUserData = async () => {
+ try {
+ const res = await getUsersId({
+ path: { user_id: String(userId) },
+ });
+ if (res.data) {
+ setMail(res.data.mail || "");
+ setNickname(res.data.nickname || "");
+ setDispName(res.data.disp_name || "");
+ setUserDesc(res.data.user_desc || "");
+ setAvatarId(res.data.image?.id ?? null);
+ setAvatarUrl(res.data.image?.image_path ?? null);
+ }
+ } catch (err) {
+ console.error("Failed to fetch user:", err);
+ }
+ };
+ fetchUserData();
+ }, [userId]);
-// fetch();
-// }, [userId]);
+ // Обработка загрузки файла
+ const handleFileChange = async (e: React.ChangeEvent) => {
+ const file = e.target.files?.[0];
+ if (!file) return;
-// const saveSettings = async (e: React.FormEvent) => {
-// e.preventDefault();
-// setLoading(true);
-// setSuccess(null);
-// setError(null);
+ setUploading(true);
+ setError(null);
-// try {
-// const res = await updateUser({
-// path: { user_id: userId },
-// body: {
-// ...(mail ? { mail } : {}),
-// ...(nickname ? { nickname } : {}),
-// ...(dispName ? { disp_name: dispName } : {}),
-// ...(userDesc ? { user_desc: userDesc } : {}),
-// ...(avatarId !== undefined ? { avatar_id: avatarId } : {}),
-// }
-// });
+ const formData = new FormData();
+ formData.append("file", file);
-// // Обновляем локальное отображение username
-// if (nickname) {
-// localStorage.setItem("user_name", nickname);
-// window.dispatchEvent(new Event("storage")); // чтобы Header обновился
-// }
+ try {
+ const res = await postMediaUpload({
+ body: formData,
+ // Сбрасываем заголовок, чтобы браузер сам поставил multipart/form-data + boundary
+ headers: { "Content-Type": undefined as any },
+ });
-// setSuccess("Settings updated!");
-// setTimeout(() => navigate("/profile"), 800);
+ if (res.data && res.data.id) {
+ setAvatarId(res.data.id);
+ setAvatarUrl(res.data.image_path ?? null); // Для мгновенного превью
+ setSuccess("Image uploaded!");
+ }
+ } catch (err: any) {
+ setError("Failed to upload image");
+ } finally {
+ setUploading(false);
+ }
+ };
-// } catch (err: any) {
-// console.error(err);
-// setError(err?.message || "Failed to update settings");
-// } finally {
-// setLoading(false);
-// }
-// };
+ const saveSettings = async (e: React.FormEvent) => {
+ e.preventDefault();
+ setLoading(true);
+ setSuccess(null);
+ setError(null);
-// return (
-//
-//
User Settings
+ try {
+ await updateUser({
+ path: { user_id: userId },
+ body: {
+ mail: mail || undefined,
+ nickname: nickname || undefined,
+ disp_name: dispName || undefined,
+ user_desc: userDesc || undefined,
+ avatar_id: avatarId, // Может быть числом или null для удаления
+ },
+ headers: { "X-XSRF-TOKEN": xsrfToken },
+ });
-// {success &&
{success}
}
-// {error &&
{error}
}
+ localStorage.setItem("user_name", nickname);
+ window.dispatchEvent(new Event("storage"));
-//
+
+ );
+};
\ No newline at end of file