Obok "Ulubione" i dzwonka powiadomien - dla kazdego zalogowanego konta, takze administratora - ikona prowadzaca do /wiadomosci z plakietka liczby nieprzeczytanych, na wzor Gieldy Komunalnej. Licznik nieprzeczytanych wydzielony do useMessagesUnreadCount, wspolnego dla menu konta i paska gornego; odswieza sie co 25 s i po zmianie strony. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+54
-32
@@ -6354,13 +6354,54 @@ function NegotiationPage({
|
||||
);
|
||||
}
|
||||
|
||||
// Nieprzeczytane wiadomosci (rozmowy o ogloszeniach + rozmowa z administracja) dla kazdego
|
||||
// zalogowanego konta - admin tez moze sprzedawac. Wspolne dla menu konta i paska gornego;
|
||||
// odswiezane co 25 s oraz po zmianie strony, np. po otwarciu rozmowy.
|
||||
function useMessagesUnreadCount(): number {
|
||||
const { user } = useAuth();
|
||||
const { pathname } = useLocation();
|
||||
const [count, setCount] = useState(0);
|
||||
|
||||
useEffect(() => {
|
||||
if (!user) {
|
||||
setCount(0);
|
||||
return;
|
||||
}
|
||||
|
||||
let cancelled = false;
|
||||
const loadUnread = () => {
|
||||
apiFetch<{ count: number }>('/messages/unread-count')
|
||||
.then((data) => {
|
||||
if (!cancelled) {
|
||||
setCount(data.count);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
if (!cancelled) {
|
||||
setCount(0);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
loadUnread();
|
||||
const intervalId = window.setInterval(loadUnread, 25000);
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
window.clearInterval(intervalId);
|
||||
};
|
||||
}, [user, pathname]);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
function AccountSidebar() {
|
||||
const { user } = useAuth();
|
||||
const location = useLocation();
|
||||
// Ustawienia obejmuja takze podglad profilu publicznego - podswietlamy je wspolna pozycja menu.
|
||||
const isSettingsSection = location.pathname === ROUTES.accountSettings
|
||||
|| location.pathname === ROUTES.accountPublicProfile;
|
||||
const [messagesUnreadCount, setMessagesUnreadCount] = useState(0);
|
||||
const messagesUnreadCount = useMessagesUnreadCount();
|
||||
// Liczba ogloszen konta pochodzi z serwera (/listings/mine) - tak samo jak lista na /konto/moje-oferty.
|
||||
const [allListingsCount, setAllListingsCount] = useState(0);
|
||||
// Spotkania zaplanowane na dzisiaj (odwolane sie nie licza).
|
||||
@@ -6394,37 +6435,6 @@ function AccountSidebar() {
|
||||
+ readUserJsonStorage<ListingPriceAlertSubscription[]>(user, LISTING_PRICE_ALERTS_STORAGE_SUFFIX, []).length
|
||||
: 0;
|
||||
|
||||
// Admin tez moze sprzedawac, wiec licznik rozmow o ogloszeniach dotyczy kazdego konta.
|
||||
useEffect(() => {
|
||||
if (!user) {
|
||||
setMessagesUnreadCount(0);
|
||||
return;
|
||||
}
|
||||
|
||||
let cancelled = false;
|
||||
const loadUnread = () => {
|
||||
apiFetch<{ count: number }>('/messages/unread-count')
|
||||
.then((data) => {
|
||||
if (!cancelled) {
|
||||
setMessagesUnreadCount(data.count);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
if (!cancelled) {
|
||||
setMessagesUnreadCount(0);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
loadUnread();
|
||||
const intervalId = window.setInterval(loadUnread, 25000);
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
window.clearInterval(intervalId);
|
||||
};
|
||||
}, [user]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!user) {
|
||||
setAllListingsCount(0);
|
||||
@@ -23368,6 +23378,7 @@ function Header({
|
||||
const { notifications: serverNotifications, unreadCount } = useNotifications();
|
||||
const isLoggedIn = Boolean(user);
|
||||
const isAdmin = user?.role === 'ADMIN';
|
||||
const messagesUnreadCount = useMessagesUnreadCount();
|
||||
const [isNotificationsOpen, setIsNotificationsOpen] = useState(false);
|
||||
const notificationPopoverRef = useRef<HTMLDivElement | null>(null);
|
||||
const [isAccountMenuOpen, setIsAccountMenuOpen] = useState(false);
|
||||
@@ -23482,6 +23493,17 @@ function Header({
|
||||
<span>Ulubione</span>
|
||||
{hasUnreadFavorites && <i aria-hidden="true" />}
|
||||
</NavLink>
|
||||
{isLoggedIn && (
|
||||
<NavLink
|
||||
to={ROUTES.messages}
|
||||
className={({ isActive }) => (isActive ? 'icon-text messages-shortcut active' : 'icon-text messages-shortcut')}
|
||||
aria-label={messagesUnreadCount > 0 ? `Wiadomości, nieprzeczytane: ${messagesUnreadCount}` : 'Wiadomości'}
|
||||
title="Wiadomości"
|
||||
>
|
||||
<Icon name="message" />
|
||||
{messagesUnreadCount > 0 && <b aria-hidden="true">{messagesUnreadCount > 99 ? '99+' : messagesUnreadCount}</b>}
|
||||
</NavLink>
|
||||
)}
|
||||
{isLoggedIn && (
|
||||
<div className="notify-bell-wrap" ref={notificationPopoverRef}>
|
||||
<button
|
||||
|
||||
@@ -288,6 +288,27 @@ svg {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* Skrot do wiadomosci w pasku gornym - plakietka z liczba nieprzeczytanych. */
|
||||
.messages-shortcut {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.messages-shortcut b {
|
||||
background: #14a45f;
|
||||
border: 2px solid #ffffff;
|
||||
border-radius: 999px;
|
||||
color: #ffffff;
|
||||
font-size: 10px;
|
||||
font-weight: 900;
|
||||
line-height: 14px;
|
||||
min-width: 18px;
|
||||
padding: 0 4px;
|
||||
position: absolute;
|
||||
right: -10px;
|
||||
text-align: center;
|
||||
top: -8px;
|
||||
}
|
||||
|
||||
.favorites-shortcut i {
|
||||
background: #14a45f;
|
||||
border: 2px solid #ffffff;
|
||||
|
||||
Reference in New Issue
Block a user