diff --git a/backend/server.js b/backend/server.js
index e174b1e..1c3d4b8 100644
--- a/backend/server.js
+++ b/backend/server.js
@@ -857,10 +857,10 @@ app.get("/api/notes/search", requireApiAuth, (req, res) => {
let whereClause = "WHERE n.user_id = ? AND n.is_archived = 0";
let params = [req.session.userId];
- // Поиск по тексту
+ // Поиск по тексту (регистронезависимый)
if (q && q.trim()) {
- whereClause += " AND n.content LIKE ?";
- params.push(`%${q.trim()}%`);
+ whereClause += " AND LOWER(n.content) LIKE ?";
+ params.push(`%${q.trim().toLowerCase()}%`);
}
// Поиск по тегу (регистронезависимый)
@@ -2549,6 +2549,23 @@ app.post("/logout", (req, res) => {
});
});
+// API для выхода (для фронтенда)
+app.post("/api/logout", (req, res) => {
+ const userId = req.session.userId;
+
+ // Логируем выход
+ if (userId) {
+ logAction(userId, "logout", "Выход из системы");
+ }
+
+ req.session.destroy((err) => {
+ if (err) {
+ return res.status(500).json({ error: "Ошибка выхода" });
+ }
+ res.json({ success: true, message: "Выход выполнен успешно" });
+ });
+});
+
// API для удаления аккаунта
app.delete("/api/user/delete-account", requireApiAuth, async (req, res) => {
const { password } = req.body;
diff --git a/dev-dist/sw.js b/dev-dist/sw.js
index 79f7624..02d7e81 100644
--- a/dev-dist/sw.js
+++ b/dev-dist/sw.js
@@ -82,7 +82,7 @@ define(['./workbox-9dc17825'], (function (workbox) { 'use strict';
"revision": "3ca0b8505b4bec776b69afdba2768812"
}, {
"url": "index.html",
- "revision": "0.2vg2p27g3bg"
+ "revision": "0.mib567t8mr8"
}], {});
workbox.cleanupOutdatedCaches();
workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), {
diff --git a/src/api/axiosClient.ts b/src/api/axiosClient.ts
index bd76eaa..0bbe5bd 100644
--- a/src/api/axiosClient.ts
+++ b/src/api/axiosClient.ts
@@ -1,4 +1,5 @@
import axios from "axios";
+import { dbManager } from "../utils/indexedDB";
const axiosClient = axios.create({
baseURL: "/api",
@@ -48,6 +49,10 @@ axiosClient.interceptors.response.use(
// Разлогиниваем только если это НЕ запрос с проверкой пароля
if (!isPasswordProtected) {
+ // Очищаем IndexedDB при автоматическом разлогинивании
+ dbManager.clearAll().catch((err) => {
+ console.error("Ошибка очистки IndexedDB при 401:", err);
+ });
localStorage.removeItem("isAuthenticated");
window.location.href = "/";
}
diff --git a/src/components/ProtectedRoute.tsx b/src/components/ProtectedRoute.tsx
index 0310ba3..f57eafb 100644
--- a/src/components/ProtectedRoute.tsx
+++ b/src/components/ProtectedRoute.tsx
@@ -4,11 +4,13 @@ import { useAppSelector, useAppDispatch } from "../store/hooks";
import { setAuth, clearAuth } from "../store/slices/authSlice";
import { authApi } from "../api/authApi";
import { LoadingOverlay } from "./common/LoadingOverlay";
+import { dbManager } from "../utils/indexedDB";
export const ProtectedRoute: React.FC<{ children: React.ReactNode }> = ({
children,
}) => {
const isAuthenticated = useAppSelector((state) => state.auth.isAuthenticated);
+ const currentUserId = useAppSelector((state) => state.auth.userId);
const dispatch = useAppDispatch();
const [isChecking, setIsChecking] = useState(true);
@@ -17,9 +19,17 @@ export const ProtectedRoute: React.FC<{ children: React.ReactNode }> = ({
try {
const authStatus = await authApi.checkStatus();
if (authStatus.authenticated) {
+ const newUserId = authStatus.userId!;
+
+ // Если пользователь изменился, очищаем IndexedDB
+ if (currentUserId && currentUserId !== newUserId) {
+ console.log(`[ProtectedRoute] User changed from ${currentUserId} to ${newUserId}, clearing IndexedDB`);
+ await dbManager.clearAll();
+ }
+
dispatch(
setAuth({
- userId: authStatus.userId!,
+ userId: newUserId,
username: authStatus.username!,
})
);
@@ -36,7 +46,7 @@ export const ProtectedRoute: React.FC<{ children: React.ReactNode }> = ({
// Всегда проверяем статус аутентификации при монтировании,
// независимо от начального состояния Redux (localStorage может быть устаревшим)
checkAuth();
- }, [dispatch]);
+ }, [dispatch, currentUserId]);
if (isChecking) {
return ;
diff --git a/src/pages/LoginPage.tsx b/src/pages/LoginPage.tsx
index 2cbffd1..546d124 100644
--- a/src/pages/LoginPage.tsx
+++ b/src/pages/LoginPage.tsx
@@ -6,6 +6,7 @@ import { authApi } from "../api/authApi";
import { useNotification } from "../hooks/useNotification";
import { ThemeToggle } from "../components/common/ThemeToggle";
import { Icon } from "@iconify/react";
+import { dbManager } from "../utils/indexedDB";
const LoginPage: React.FC = () => {
const [username, setUsername] = useState("");
@@ -15,6 +16,7 @@ const LoginPage: React.FC = () => {
const dispatch = useAppDispatch();
const { showNotification } = useNotification();
const isAuthenticated = useAppSelector((state) => state.auth.isAuthenticated);
+ const currentUserId = useAppSelector((state) => state.auth.userId);
const [searchParams] = useSearchParams();
useEffect(() => {
@@ -48,9 +50,17 @@ const LoginPage: React.FC = () => {
if (data.success) {
// Получаем информацию о пользователе
const authStatus = await authApi.checkStatus();
+ const newUserId = authStatus.userId!;
+
+ // Если пользователь изменился, очищаем IndexedDB
+ if (currentUserId && currentUserId !== newUserId) {
+ console.log(`[Login] User changed from ${currentUserId} to ${newUserId}, clearing IndexedDB`);
+ await dbManager.clearAll();
+ }
+
dispatch(
setAuth({
- userId: authStatus.userId!,
+ userId: newUserId,
username: authStatus.username!,
})
);
diff --git a/src/pages/ProfilePage.tsx b/src/pages/ProfilePage.tsx
index 8a87862..53b2563 100644
--- a/src/pages/ProfilePage.tsx
+++ b/src/pages/ProfilePage.tsx
@@ -11,6 +11,7 @@ import { setAccentColor } from "../utils/colorUtils";
import { useNotification } from "../hooks/useNotification";
import { Modal } from "../components/common/Modal";
import { ThemeToggle } from "../components/common/ThemeToggle";
+import { dbManager } from "../utils/indexedDB";
const ProfilePage: React.FC = () => {
const navigate = useNavigate();
@@ -211,6 +212,8 @@ const ProfilePage: React.FC = () => {
setIsDeleting(true);
try {
await userApi.deleteAccount(deletePassword);
+ // Очищаем IndexedDB при удалении аккаунта
+ await dbManager.clearAll();
showNotification("Аккаунт успешно удален", "success");
dispatch(clearAuth());
setTimeout(() => {
@@ -259,10 +262,13 @@ const ProfilePage: React.FC = () => {
onClick={async () => {
try {
await authApi.logout();
- dispatch(clearAuth());
- navigate("/");
} catch (error) {
console.error("Ошибка выхода:", error);
+ } finally {
+ // Очищаем IndexedDB в фоне (не блокируем выход)
+ dbManager.clearAll().catch((err) => {
+ console.error("Ошибка очистки IndexedDB при выходе:", err);
+ });
dispatch(clearAuth());
navigate("/");
}
diff --git a/src/pages/RegisterPage.tsx b/src/pages/RegisterPage.tsx
index aed3c19..62eb4a7 100644
--- a/src/pages/RegisterPage.tsx
+++ b/src/pages/RegisterPage.tsx
@@ -6,6 +6,7 @@ import { authApi } from "../api/authApi";
import { useNotification } from "../hooks/useNotification";
import { ThemeToggle } from "../components/common/ThemeToggle";
import { Icon } from "@iconify/react";
+import { dbManager } from "../utils/indexedDB";
const RegisterPage: React.FC = () => {
const [username, setUsername] = useState("");
@@ -57,9 +58,15 @@ const RegisterPage: React.FC = () => {
if (data.success) {
// Получаем информацию о пользователе
const authStatus = await authApi.checkStatus();
+ const newUserId = authStatus.userId!;
+
+ // При регистрации нового пользователя всегда очищаем IndexedDB
+ // (на случай, если в базе остались данные предыдущего пользователя)
+ await dbManager.clearAll();
+
dispatch(
setAuth({
- userId: authStatus.userId!,
+ userId: newUserId,
username: authStatus.username!,
})
);
diff --git a/src/pages/SettingsPage.tsx b/src/pages/SettingsPage.tsx
index 48a0cda..e839034 100644
--- a/src/pages/SettingsPage.tsx
+++ b/src/pages/SettingsPage.tsx
@@ -553,10 +553,13 @@ const SettingsPage: React.FC = () => {
onClick={async () => {
try {
await authApi.logout();
- dispatch(clearAuth());
- navigate("/");
} catch (error) {
console.error("Ошибка выхода:", error);
+ } finally {
+ // Очищаем IndexedDB в фоне (не блокируем выход)
+ dbManager.clearAll().catch((err) => {
+ console.error("Ошибка очистки IndexedDB при выходе:", err);
+ });
dispatch(clearAuth());
navigate("/");
}
diff --git a/src/utils/indexedDB.ts b/src/utils/indexedDB.ts
index 916c471..766c28f 100644
--- a/src/utils/indexedDB.ts
+++ b/src/utils/indexedDB.ts
@@ -225,6 +225,16 @@ class IndexedDBManager {
});
}
+ /**
+ * Полная очистка всех данных из IndexedDB (заметки и очередь синхронизации)
+ */
+ async clearAll(): Promise {
+ await Promise.all([
+ this.clearAllNotes(),
+ this.clearSyncQueue(),
+ ]);
+ }
+
// ===== Утилиты =====
async getPendingSyncCount(): Promise {