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() {
|
function AccountSidebar() {
|
||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
// Ustawienia obejmuja takze podglad profilu publicznego - podswietlamy je wspolna pozycja menu.
|
// Ustawienia obejmuja takze podglad profilu publicznego - podswietlamy je wspolna pozycja menu.
|
||||||
const isSettingsSection = location.pathname === ROUTES.accountSettings
|
const isSettingsSection = location.pathname === ROUTES.accountSettings
|
||||||
|| location.pathname === ROUTES.accountPublicProfile;
|
|| 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.
|
// Liczba ogloszen konta pochodzi z serwera (/listings/mine) - tak samo jak lista na /konto/moje-oferty.
|
||||||
const [allListingsCount, setAllListingsCount] = useState(0);
|
const [allListingsCount, setAllListingsCount] = useState(0);
|
||||||
// Spotkania zaplanowane na dzisiaj (odwolane sie nie licza).
|
// Spotkania zaplanowane na dzisiaj (odwolane sie nie licza).
|
||||||
@@ -6394,37 +6435,6 @@ function AccountSidebar() {
|
|||||||
+ readUserJsonStorage<ListingPriceAlertSubscription[]>(user, LISTING_PRICE_ALERTS_STORAGE_SUFFIX, []).length
|
+ readUserJsonStorage<ListingPriceAlertSubscription[]>(user, LISTING_PRICE_ALERTS_STORAGE_SUFFIX, []).length
|
||||||
: 0;
|
: 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(() => {
|
useEffect(() => {
|
||||||
if (!user) {
|
if (!user) {
|
||||||
setAllListingsCount(0);
|
setAllListingsCount(0);
|
||||||
@@ -23368,6 +23378,7 @@ function Header({
|
|||||||
const { notifications: serverNotifications, unreadCount } = useNotifications();
|
const { notifications: serverNotifications, unreadCount } = useNotifications();
|
||||||
const isLoggedIn = Boolean(user);
|
const isLoggedIn = Boolean(user);
|
||||||
const isAdmin = user?.role === 'ADMIN';
|
const isAdmin = user?.role === 'ADMIN';
|
||||||
|
const messagesUnreadCount = useMessagesUnreadCount();
|
||||||
const [isNotificationsOpen, setIsNotificationsOpen] = useState(false);
|
const [isNotificationsOpen, setIsNotificationsOpen] = useState(false);
|
||||||
const notificationPopoverRef = useRef<HTMLDivElement | null>(null);
|
const notificationPopoverRef = useRef<HTMLDivElement | null>(null);
|
||||||
const [isAccountMenuOpen, setIsAccountMenuOpen] = useState(false);
|
const [isAccountMenuOpen, setIsAccountMenuOpen] = useState(false);
|
||||||
@@ -23482,6 +23493,17 @@ function Header({
|
|||||||
<span>Ulubione</span>
|
<span>Ulubione</span>
|
||||||
{hasUnreadFavorites && <i aria-hidden="true" />}
|
{hasUnreadFavorites && <i aria-hidden="true" />}
|
||||||
</NavLink>
|
</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 && (
|
{isLoggedIn && (
|
||||||
<div className="notify-bell-wrap" ref={notificationPopoverRef}>
|
<div className="notify-bell-wrap" ref={notificationPopoverRef}>
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -288,6 +288,27 @@ svg {
|
|||||||
position: relative;
|
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 {
|
.favorites-shortcut i {
|
||||||
background: #14a45f;
|
background: #14a45f;
|
||||||
border: 2px solid #ffffff;
|
border: 2px solid #ffffff;
|
||||||
|
|||||||
Reference in New Issue
Block a user