deleted full likes

This commit is contained in:
SlimusMinus
2026-09-24 00:20:41 +03:00
parent 1d4c0c169c
commit 58352267fa
11 changed files with 18 additions and 265 deletions

View File

@@ -12,7 +12,7 @@ import { removePostForChat } from "../stores/chatPostStore";
* deleteChat возвращает { success, error } вместо голого boolean — так
* вызывающий код получает актуальный текст ошибки сразу, без риска прочитать
* устаревшее значение error state до его обновления React'ом (тот же паттерн,
* что в useDeletePost/useFavorites/usePostStatus).
* что в useDeletePost/usePostStatus).
*
* @returns {Object} { deleteChat, loading, error }
*/

View File

@@ -1,93 +0,0 @@
import { useState, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { API_URL } from '../config/authConstants';
import { apiFetch } from '../api/apiClient';
/**
* Хук для работы с лайками (избранное).
* Использует backend API для добавления/удаления лайков.
*/
export function useFavorites() {
const { t } = useTranslation();
const [error, setError] = useState("");
/**
* Переключает лайк на посте через API.
* @param {number} postId - ID поста
* @returns {Promise<{success: boolean, error: string|null}>}
*/
const toggleFavorite = useCallback(async (postId) => {
setError("");
try {
const response = await apiFetch(`${API_URL}/api/v1/favorites/${postId}/toggle`, {
method: 'POST',
});
if (!response.ok) {
throw new Error(t('favorites.toggleError'));
}
return { success: true, error: null };
} catch (err) {
console.error('Error toggling favorite:', err);
const message = err.message || t('favorites.toggleError');
setError(message);
return { success: false, error: message };
}
}, [t]);
/**
* Загружает список лайкнутых постов текущего пользователя.
* @returns {Promise<Array>} - массив ID лайкнутых постов
*/
const loadFavorites = useCallback(async () => {
setError("");
try {
const response = await apiFetch(`${API_URL}/api/v1/favorites`);
if (!response.ok) {
throw new Error(t('favorites.loadError'));
}
const data = await response.json();
return Array.isArray(data) ? data.map(post => post.id) : [];
} catch (err) {
console.error('Error loading favorites:', err);
setError(err.message || t('favorites.loadError'));
return [];
}
}, [t]);
/**
* Загружает полные посты из избранного текущего пользователя.
* @returns {Promise<Array>} - массив постов (PostResponse)
*/
const loadFavoritePosts = useCallback(async () => {
setError("");
try {
const response = await apiFetch(`${API_URL}/api/v1/favorites/posts`);
if (!response.ok) {
throw new Error(t('favorites.loadError'));
}
const data = await response.json();
const posts = Array.isArray(data) ? data : [];
return posts.map(post => ({
...post,
type: post.type ? post.type.toLowerCase() : "loss",
}));
} catch (err) {
console.error('Error loading favorite posts:', err);
setError(err.message || t('favorites.loadError'));
return [];
}
}, [t]);
return {
toggleFavorite,
loadFavorites,
loadFavoritePosts,
error,
};
}

View File

@@ -1,18 +1,17 @@
// src/hooks/useFeedActions.js
import { useState, useCallback, useRef } from "react";
import { useState, useCallback } from "react";
import { useDeletePost } from "./useDeletePost";
import { useFavorites } from "./useFavorites";
import { usePostStatus } from "./usePostStatus";
/**
* Объединяет действия над объявлениями (лайк, удаление, отметка "найдено")
* Объединяет действия над объявлениями (удаление, отметка "найдено")
* и общий паттерн "выполнить действие -> перезагрузить ленту и мои объявления".
*
* Авторизация (Authorization header + авто-обновление токена) обрабатывается
* внутри apiFetch — сам token сюда передавать не нужно, только isAuthenticated
* как ранняя проверка перед запросом.
*
* Каждое действие (deletePost/toggleFavorite/markAsFound) возвращает
* Каждое действие (deletePost/markAsFound) возвращает
* { success, error } напрямую из вызова — это исключает гонку между
* обновлением error state дочернего хука и его чтением здесь же в том же
* тике (React batching иначе мог бы подставить устаревшее значение).
@@ -22,59 +21,17 @@ import { usePostStatus } from "./usePostStatus";
* @param {Function} onAuthRequired — вызывается когда нужна авторизация
* @param {boolean} isAuthenticated
*/
export function useFeedActions({ refresh, loadMyPosts, onAuthRequired, isAuthenticated, t, setLiked, setLikeCountAdj }) {
export function useFeedActions({ refresh, loadMyPosts, onAuthRequired, isAuthenticated, t }) {
const { deletePost } = useDeletePost();
const { toggleFavorite } = useFavorites();
const { markAsFound } = usePostStatus();
const [error, setError] = useState("");
const likedRef = useRef(new Set());
const syncLikedRef = useCallback((prev) => {
likedRef.current = prev instanceof Set ? prev : new Set(prev);
return prev;
}, []);
const afterMutation = useCallback(() => {
refresh();
loadMyPosts();
}, [refresh, loadMyPosts]);
const toggleLike = useCallback(async (id) => {
if (!isAuthenticated) {
onAuthRequired();
return;
}
if (setLiked) {
const wasCurrentlyLiked = likedRef.current.has(id);
const delta = wasCurrentlyLiked ? -1 : 1;
setLiked(prev => {
const next = new Set(prev);
if (next.has(id)) next.delete(id); else next.add(id);
likedRef.current = next;
return next;
});
if (setLikeCountAdj) {
setLikeCountAdj(prev => ({ ...prev, [id]: (prev[id] || 0) + delta }));
}
const result = await toggleFavorite(id);
if (!result.success) {
setLiked(prev => {
const next = new Set(prev);
if (next.has(id)) next.delete(id); else next.add(id);
likedRef.current = next;
return next;
});
if (setLikeCountAdj) {
setLikeCountAdj(prev => ({ ...prev, [id]: (prev[id] || 0) - delta }));
}
setError(result.error);
}
}
}, [isAuthenticated, onAuthRequired, toggleFavorite, setLiked, setLikeCountAdj]);
const handleDelete = useCallback(async (postId) => {
if (!window.confirm(t('feed.confirmDelete'))) return;
const result = await deletePost(postId);
@@ -98,12 +55,10 @@ export function useFeedActions({ refresh, loadMyPosts, onAuthRequired, isAuthent
const clearError = useCallback(() => setError(""), []);
return {
toggleLike,
handleDelete,
handleMarkFound,
handleNewAd: afterMutation,
handleEditSave: afterMutation,
syncLiked: syncLikedRef,
error,
clearError,
};