fixed image and name chat

This commit is contained in:
SlimusMinus
2026-08-13 00:37:41 +03:00
parent 6b1b41d423
commit 66ff0dc5bf
6 changed files with 70 additions and 13 deletions

View File

@@ -2,7 +2,7 @@ import { getChatDisplayInfo } from "../../utils/chatDisplay";
import TrashIcon from "../icons/TrashIcon";
export default function ChatListItem({ chat, post, unreadMap, t, onOpen, onDelete }) {
const { title, imgSrc, emoji, unreadCount } = getChatDisplayInfo(chat, post, unreadMap, t);
const { title, imgSrc, emoji, unreadCount, preview } = getChatDisplayInfo(chat, post, unreadMap, t);
return (
<div
@@ -13,13 +13,13 @@ export default function ChatListItem({ chat, post, unreadMap, t, onOpen, onDelet
{imgSrc ? (
<img src={imgSrc} alt="" className="chat-list-avatar-img" />
) : (
emoji || chat.otherUser?.name?.[0] || "?"
emoji || chat.otherUserName?.[0] || chat.otherUser?.name?.[0] || "?"
)}
</div>
<div className="chat-list-info">
<div className="chat-list-name">{title}</div>
<div className="chat-list-preview">
{chat.lastMessage?.content || t('chat.noMessages')}
{preview}
</div>
</div>
{unreadCount > 0 && (

View File

@@ -1,7 +1,6 @@
// src/context/AuthContext.jsx
import { createContext, useContext, useState, useCallback } from "react";
import { saveTokens, clearTokens, getAccessToken } from "../api/apiClient";
import { clearPostCache } from "../stores/chatPostStore";
const AuthContext = createContext(null);
@@ -35,14 +34,13 @@ export function AuthProvider({ children }) {
}, []);
/**
* Очищает все данные аутентификации (access, refresh, user) и модульные
* кеши, привязанные к сессии пользователя (например, chatPostStore), —
* иначе данные предыдущего пользователя могут "пережить" logout на этом
* же устройстве.
* Очищает все данные аутентификации (access, refresh, user).
* Кеш постов чатов (chatPostStore) НЕ очищаем: посты — публичные данные
* из ленты, а id чатов глобально уникальны, поэтому кеш не "протекает"
* между пользователями и сохраняет title/картинку чата после повторного входа.
*/
const logout = useCallback(() => {
clearTokens();
clearPostCache();
setUser(null);
setToken(null);
}, []);

View File

@@ -28,6 +28,7 @@ export function useContactSeller(post) {
if (!post) return;
try {
const chat = await createOrGetChat(post.userId, post.id, {
id: post.id,
title: post.title,
images: post.images,
emoji: post.emoji,

View File

@@ -15,7 +15,7 @@ export default function ChatListPage() {
const navigate = useNavigate();
const { chats, loading, fetchChats } = useChats();
const { isAuthenticated } = useAuthContext();
const { unreadMap } = useUnread();
const { unreadMap, totalUnread } = useUnread();
const { deleteChat } = useDeleteChat();
const [deleteError, setDeleteError] = useState("");
@@ -25,6 +25,17 @@ export default function ChatListPage() {
}
}, [isAuthenticated, fetchChats]);
// При поступлении непрочитанного сообщения (WS) обновляем список, чтобы
// превью показывало новое сообщение и подсветку, не дожидаясь ручного обновления.
useEffect(() => {
if (!isAuthenticated) return;
const timer = setTimeout(() => fetchChats(), 500);
return () => clearTimeout(timer);
// totalUnread — числовое значение, поэтому изменение состава чатов с той же
// суммой не создаст цикл обновлений.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [totalUnread, isAuthenticated, fetchChats]);
const handleDeleteChat = useCallback(async (chatId) => {
if (!window.confirm(t('chat.confirmDeleteChat'))) return;
const result = await deleteChat(chatId);

View File

@@ -1,7 +1,39 @@
const STORAGE_KEY = "nakhodka:chatPosts";
const postByChatId = new Map();
/** Восстанавливает кеш постов из localStorage (выживает при перезагрузке страницы). */
function loadFromStorage() {
try {
const raw = localStorage.getItem(STORAGE_KEY);
if (!raw) return;
const obj = JSON.parse(raw);
for (const [chatId, post] of Object.entries(obj)) {
postByChatId.set(chatId, post);
}
} catch (e) {
// Повреждённый/пустой storage игнорируем
}
}
/** Пишет текущий кеш постов в localStorage. */
function persist() {
try {
const obj = {};
postByChatId.forEach((post, chatId) => {
obj[chatId] = post;
});
localStorage.setItem(STORAGE_KEY, JSON.stringify(obj));
} catch (e) {
// Недостаточно места / приватный режим — игнорируем
}
}
loadFromStorage();
export function setPostForChat(chatId, post) {
postByChatId.set(chatId, post);
persist();
}
export function getPostForChat(chatId) {
@@ -14,14 +46,21 @@ export function cachePostsFromChats(chats) {
postByChatId.set(chat.id, chat.post);
}
}
if (chats.length) persist();
}
/** Удаляет запись при удалении конкретного чата. */
export function removePostForChat(chatId) {
postByChatId.delete(chatId);
persist();
}
/** Полностью очищает кеш — вызывать при logout(), чтобы не хранить данные предыдущей сессии. */
export function clearPostCache() {
postByChatId.clear();
try {
localStorage.removeItem(STORAGE_KEY);
} catch (e) {
// ignore
}
}

View File

@@ -24,11 +24,19 @@ export function sortMessages(messages) {
});
}
/** Текст последнего сообщения. Бэкенд отдаёт lastMessage и строкой, и объектом — поддерживаем оба. */
export function getLastMessageText(chat) {
const lm = chat?.lastMessage;
if (typeof lm === "string") return lm;
return lm?.content || "";
}
export function getChatDisplayInfo(chat, post, unreadMap, t) {
const title = post?.title || chat.otherUser?.name || t('chat.user');
const title = post?.title || chat.otherUserName || chat.otherUser?.name || t('chat.user');
const imgSrc = getImageUrl(post?.images?.[0]);
const emoji = post?.emoji;
const unreadCount = unreadMap[chat.id] ?? chat.unreadCount ?? chat.unreadMessages ?? 0;
const preview = getLastMessageText(chat) || t('chat.noMessages');
return { title, imgSrc, emoji, unreadCount };
return { title, imgSrc, emoji, unreadCount, preview };
}