mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
update mod queue
This commit is contained in:
@@ -17,6 +17,7 @@ import useTimeFilter from '../../hooks/use-time-filter';
|
|||||||
import CatalogFilters from '../catalog-filters';
|
import CatalogFilters from '../catalog-filters';
|
||||||
import CatalogSearch from '../catalog-search';
|
import CatalogSearch from '../catalog-search';
|
||||||
import Tooltip from '../tooltip';
|
import Tooltip from '../tooltip';
|
||||||
|
import { ModQueueButton } from '../../views/mod-queue/mod-queue';
|
||||||
import styles from './board-buttons.module.css';
|
import styles from './board-buttons.module.css';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
|
||||||
@@ -362,6 +363,7 @@ export const MobileBoardButtons = () => {
|
|||||||
)}
|
)}
|
||||||
{showVoteButton && <VoteButton />}
|
{showVoteButton && <VoteButton />}
|
||||||
{!(isInAllView || isInSubscriptionsView || isInModView) && <SubscribeButton address={subplebbitAddress} />}
|
{!(isInAllView || isInSubscriptionsView || isInModView) && <SubscribeButton address={subplebbitAddress} />}
|
||||||
|
{!(isInAllView || isInSubscriptionsView || isInModView) && <ModQueueButton boardIdentifier={boardIdentifier} isMobile={true} />}
|
||||||
<RefreshButton />
|
<RefreshButton />
|
||||||
{isInCatalogView && searchText ? (
|
{isInCatalogView && searchText ? (
|
||||||
<span className={styles.filteredThreadsCount}>
|
<span className={styles.filteredThreadsCount}>
|
||||||
@@ -496,6 +498,12 @@ export const DesktopBoardButtons = () => {
|
|||||||
[<VoteButton />]
|
[<VoteButton />]
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
{!(isInAllView || isInSubscriptionsView || isInModView) && (
|
||||||
|
<>
|
||||||
|
{' '}
|
||||||
|
[<ModQueueButton boardIdentifier={boardIdentifier} isMobile={false} />]
|
||||||
|
</>
|
||||||
|
)}
|
||||||
{isInCatalogView && searchText ? (
|
{isInCatalogView && searchText ? (
|
||||||
<span className={styles.filteredThreadsCount}>
|
<span className={styles.filteredThreadsCount}>
|
||||||
{' '}
|
{' '}
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import { useState, useEffect } from 'react';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current time in seconds, updating periodically.
|
||||||
|
* This prevents unnecessary rerenders by only updating every 60 seconds
|
||||||
|
* instead of on every render cycle.
|
||||||
|
*
|
||||||
|
* For visual updates like blinking animations, CSS handles that independently.
|
||||||
|
* This hook is for time-based calculations that don't need millisecond precision.
|
||||||
|
*/
|
||||||
|
export const useCurrentTime = (updateIntervalSeconds = 60) => {
|
||||||
|
const [currentTime, setCurrentTime] = useState(() => Date.now() / 1000);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Update immediately on mount
|
||||||
|
setCurrentTime(Date.now() / 1000);
|
||||||
|
|
||||||
|
// Then update periodically
|
||||||
|
const intervalId = setInterval(() => {
|
||||||
|
setCurrentTime(Date.now() / 1000);
|
||||||
|
}, updateIntervalSeconds * 1000);
|
||||||
|
|
||||||
|
return () => clearInterval(intervalId);
|
||||||
|
}, [updateIntervalSeconds]);
|
||||||
|
|
||||||
|
return currentTime;
|
||||||
|
};
|
||||||
+102
@@ -220,6 +220,23 @@
|
|||||||
--topbar-mobile-border-bottom: 2px solid #d9c5b7;
|
--topbar-mobile-border-bottom: 2px solid #d9c5b7;
|
||||||
--topbar-mobile-font-size: 10px;
|
--topbar-mobile-font-size: 10px;
|
||||||
--topbar-mobile-button-text-color: navy;
|
--topbar-mobile-button-text-color: navy;
|
||||||
|
|
||||||
|
/* mod queue */
|
||||||
|
--mod-queue-table-border: 1px solid #d9bfb7;
|
||||||
|
--mod-queue-header-background-color: #f0e0d6;
|
||||||
|
--mod-queue-header-border-bottom: 2px solid #d9bfb7;
|
||||||
|
--mod-queue-row-background-color: #ffe;
|
||||||
|
--mod-queue-row-border-bottom: 1px solid #d9bfb7;
|
||||||
|
--mod-queue-row-hover-background-color: #f0e0d6;
|
||||||
|
--mod-queue-button-text-color: #00e;
|
||||||
|
--mod-queue-button-text-color-hover: red;
|
||||||
|
--mod-queue-button-text-decoration: underline;
|
||||||
|
--mod-queue-approve-color: #00e;
|
||||||
|
--mod-queue-approve-color-hover: green;
|
||||||
|
--mod-queue-reject-color: #00e;
|
||||||
|
--mod-queue-reject-color-hover: red;
|
||||||
|
--mod-queue-time-color: #707070;
|
||||||
|
--mod-queue-alert-color: red;
|
||||||
}
|
}
|
||||||
|
|
||||||
:root .yotsuba-b {
|
:root .yotsuba-b {
|
||||||
@@ -440,6 +457,23 @@
|
|||||||
--topbar-mobile-border-bottom: 2px solid #b7c5d9;
|
--topbar-mobile-border-bottom: 2px solid #b7c5d9;
|
||||||
--topbar-mobile-font-size: 10px;
|
--topbar-mobile-font-size: 10px;
|
||||||
--topbar-mobile-button-text-color: #34345c;
|
--topbar-mobile-button-text-color: #34345c;
|
||||||
|
|
||||||
|
/* mod queue */
|
||||||
|
--mod-queue-table-border: 1px solid #b7c5d9;
|
||||||
|
--mod-queue-header-background-color: #d6daf0;
|
||||||
|
--mod-queue-header-border-bottom: 2px solid #b7c5d9;
|
||||||
|
--mod-queue-row-background-color: #eef2ff;
|
||||||
|
--mod-queue-row-border-bottom: 1px solid #b7c5d9;
|
||||||
|
--mod-queue-row-hover-background-color: #d6daf0;
|
||||||
|
--mod-queue-button-text-color: #34345c;
|
||||||
|
--mod-queue-button-text-color-hover: #d00;
|
||||||
|
--mod-queue-button-text-decoration: underline;
|
||||||
|
--mod-queue-approve-color: #34345c;
|
||||||
|
--mod-queue-approve-color-hover: green;
|
||||||
|
--mod-queue-reject-color: #34345c;
|
||||||
|
--mod-queue-reject-color-hover: #d00;
|
||||||
|
--mod-queue-time-color: #707070;
|
||||||
|
--mod-queue-alert-color: #d00;
|
||||||
}
|
}
|
||||||
|
|
||||||
:root .futaba {
|
:root .futaba {
|
||||||
@@ -631,6 +665,23 @@
|
|||||||
--topbar-mobile-border-bottom: 2px solid #d9c5b7;
|
--topbar-mobile-border-bottom: 2px solid #d9c5b7;
|
||||||
--topbar-mobile-font-size: 9pt;
|
--topbar-mobile-font-size: 9pt;
|
||||||
--topbar-mobile-button-text-color: #00f;
|
--topbar-mobile-button-text-color: #00f;
|
||||||
|
|
||||||
|
/* mod queue */
|
||||||
|
--mod-queue-table-border: 1px solid rgba(0, 0, 0, 0.20);
|
||||||
|
--mod-queue-header-background-color: #f0e0d6;
|
||||||
|
--mod-queue-header-border-bottom: 1px solid rgba(0, 0, 0, 0.20);
|
||||||
|
--mod-queue-row-background-color: #ffe;
|
||||||
|
--mod-queue-row-border-bottom: 1px solid rgba(0, 0, 0, 0.20);
|
||||||
|
--mod-queue-row-hover-background-color: #f0e0d6;
|
||||||
|
--mod-queue-button-text-color: #00e;
|
||||||
|
--mod-queue-button-text-color-hover: red;
|
||||||
|
--mod-queue-button-text-decoration: underline;
|
||||||
|
--mod-queue-approve-color: #00e;
|
||||||
|
--mod-queue-approve-color-hover: green;
|
||||||
|
--mod-queue-reject-color: #00e;
|
||||||
|
--mod-queue-reject-color-hover: red;
|
||||||
|
--mod-queue-time-color: #707070;
|
||||||
|
--mod-queue-alert-color: red;
|
||||||
}
|
}
|
||||||
|
|
||||||
:root .burichan {
|
:root .burichan {
|
||||||
@@ -826,6 +877,23 @@
|
|||||||
--topbar-mobile-border-bottom: 2px solid #b7c5d9;
|
--topbar-mobile-border-bottom: 2px solid #b7c5d9;
|
||||||
--topbar-mobile-font-size: 9pt;
|
--topbar-mobile-font-size: 9pt;
|
||||||
--topbar-mobile-button-text-color: #34345c;
|
--topbar-mobile-button-text-color: #34345c;
|
||||||
|
|
||||||
|
/* mod queue */
|
||||||
|
--mod-queue-table-border: 1px solid rgba(0, 0, 0, 0.20);
|
||||||
|
--mod-queue-header-background-color: #d6daf0;
|
||||||
|
--mod-queue-header-border-bottom: 1px solid rgba(0, 0, 0, 0.20);
|
||||||
|
--mod-queue-row-background-color: #eef2ff;
|
||||||
|
--mod-queue-row-border-bottom: 1px solid rgba(0, 0, 0, 0.20);
|
||||||
|
--mod-queue-row-hover-background-color: #d6daf0;
|
||||||
|
--mod-queue-button-text-color: #34345c;
|
||||||
|
--mod-queue-button-text-color-hover: #d00;
|
||||||
|
--mod-queue-button-text-decoration: underline;
|
||||||
|
--mod-queue-approve-color: #34345c;
|
||||||
|
--mod-queue-approve-color-hover: green;
|
||||||
|
--mod-queue-reject-color: #34345c;
|
||||||
|
--mod-queue-reject-color-hover: #d00;
|
||||||
|
--mod-queue-time-color: #707070;
|
||||||
|
--mod-queue-alert-color: #d00;
|
||||||
}
|
}
|
||||||
|
|
||||||
:root .tomorrow {
|
:root .tomorrow {
|
||||||
@@ -1056,6 +1124,23 @@
|
|||||||
--topbar-mobile-font-size: 10px;
|
--topbar-mobile-font-size: 10px;
|
||||||
--topbar-mobile-button-text-color: #81a2be;
|
--topbar-mobile-button-text-color: #81a2be;
|
||||||
--topbar-mobile-button-color: #81a2be;
|
--topbar-mobile-button-color: #81a2be;
|
||||||
|
|
||||||
|
/* mod queue */
|
||||||
|
--mod-queue-table-border: 1px solid #111;
|
||||||
|
--mod-queue-header-background-color: #282a2e;
|
||||||
|
--mod-queue-header-border-bottom: 1px solid #111;
|
||||||
|
--mod-queue-row-background-color: #1d1f21;
|
||||||
|
--mod-queue-row-border-bottom: 1px solid #111;
|
||||||
|
--mod-queue-row-hover-background-color: #282a2e;
|
||||||
|
--mod-queue-button-text-color: #81a2be;
|
||||||
|
--mod-queue-button-text-color-hover: #5f89ac;
|
||||||
|
--mod-queue-button-text-decoration: underline;
|
||||||
|
--mod-queue-approve-color: #81a2be;
|
||||||
|
--mod-queue-approve-color-hover: #b5bd68;
|
||||||
|
--mod-queue-reject-color: #81a2be;
|
||||||
|
--mod-queue-reject-color-hover: #cc6666;
|
||||||
|
--mod-queue-time-color: #707070;
|
||||||
|
--mod-queue-alert-color: #cc6666;
|
||||||
}
|
}
|
||||||
|
|
||||||
:root .photon {
|
:root .photon {
|
||||||
@@ -1268,4 +1353,21 @@
|
|||||||
--topbar-mobile-font-size: 10px;
|
--topbar-mobile-font-size: 10px;
|
||||||
--topbar-mobile-button-text-color: #f60;
|
--topbar-mobile-button-text-color: #f60;
|
||||||
--topbar-mobile-button-color: #f60;
|
--topbar-mobile-button-color: #f60;
|
||||||
|
|
||||||
|
/* mod queue */
|
||||||
|
--mod-queue-table-border: 1px solid #ccc;
|
||||||
|
--mod-queue-header-background-color: #ddd;
|
||||||
|
--mod-queue-header-border-bottom: 1px solid #ccc;
|
||||||
|
--mod-queue-row-background-color: #eee;
|
||||||
|
--mod-queue-row-border-bottom: 1px solid #ccc;
|
||||||
|
--mod-queue-row-hover-background-color: #ddd;
|
||||||
|
--mod-queue-button-text-color: #f60;
|
||||||
|
--mod-queue-button-text-color-hover: #f30;
|
||||||
|
--mod-queue-button-text-decoration: underline;
|
||||||
|
--mod-queue-approve-color: #f60;
|
||||||
|
--mod-queue-approve-color-hover: green;
|
||||||
|
--mod-queue-reject-color: #f60;
|
||||||
|
--mod-queue-reject-color-hover: red;
|
||||||
|
--mod-queue-time-color: #707070;
|
||||||
|
--mod-queue-alert-color: red;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,16 +34,20 @@
|
|||||||
.alertThresholdInput {
|
.alertThresholdInput {
|
||||||
width: 50px;
|
width: 50px;
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
border: 1px solid var(--border-color);
|
border: var(--mod-queue-table-border);
|
||||||
background: var(--input-background-color);
|
background: var(--mod-queue-header-background-color);
|
||||||
color: var(--text-color);
|
color: var(--body-font-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tableWrapper {
|
||||||
|
border: var(--mod-queue-table-border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.tableHeader {
|
.tableHeader {
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
border-bottom: 2px solid var(--border-color);
|
border-bottom: var(--mod-queue-header-border-bottom);
|
||||||
background: var(--header-background-color);
|
background: var(--mod-queue-header-background-color);
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
@@ -72,23 +76,26 @@
|
|||||||
.empty {
|
.empty {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: var(--secondary-text-color);
|
color: var(--mod-queue-time-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ModQueueRow styles */
|
/* ModQueueRow styles */
|
||||||
.row {
|
.row {
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 4px 8px;
|
padding: 4px 8px;
|
||||||
border-bottom: 1px solid var(--border-color);
|
border-top: none;
|
||||||
|
border-left: none;
|
||||||
|
border-right: none;
|
||||||
|
border-bottom: var(--mod-queue-row-border-bottom);
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
background-color: var(--post-background-color);
|
background-color: var(--mod-queue-row-background-color);
|
||||||
color: var(--text-color);
|
color: var(--body-font-color);
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.row:hover {
|
.row:hover {
|
||||||
background-color: var(--post-highlight-color);
|
background-color: var(--mod-queue-row-hover-background-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.board {
|
.board {
|
||||||
@@ -106,23 +113,24 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.excerpt a {
|
.excerpt a {
|
||||||
text-decoration: none;
|
text-decoration: var(--post-link-text-decoration);
|
||||||
color: var(--link-color);
|
color: var(--post-link-text-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.excerpt a:hover {
|
.excerpt a:hover {
|
||||||
text-decoration: underline;
|
text-decoration: var(--post-link-text-decoration-hover);
|
||||||
|
color: var(--post-link-text-color-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
.time {
|
.time {
|
||||||
width: 80px;
|
width: 80px;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
color: var(--secondary-text-color);
|
color: var(--mod-queue-time-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.time.alert {
|
.time.alert {
|
||||||
color: red;
|
color: var(--mod-queue-alert-color);
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
animation: blink 2s infinite;
|
animation: blink 2s infinite;
|
||||||
}
|
}
|
||||||
@@ -141,27 +149,39 @@
|
|||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button {
|
/* Desktop: buttons styled as text links */
|
||||||
cursor: pointer;
|
@media (min-width: 640px) {
|
||||||
padding: 2px 6px;
|
.button {
|
||||||
border: 1px solid var(--border-color);
|
all: unset;
|
||||||
background: var(--button-background);
|
cursor: pointer;
|
||||||
color: var(--button-text);
|
padding: 0;
|
||||||
font-size: 11px;
|
color: var(--mod-queue-button-text-color);
|
||||||
text-decoration: none;
|
font-size: 11px;
|
||||||
display: inline-block;
|
text-decoration: var(--mod-queue-button-text-decoration);
|
||||||
}
|
display: inline-block;
|
||||||
|
font-family: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
.button:hover {
|
.button:hover {
|
||||||
background: var(--button-hover-background);
|
color: var(--mod-queue-button-text-color-hover);
|
||||||
|
text-decoration: var(--mod-queue-button-text-decoration);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.approve {
|
.approve {
|
||||||
color: green;
|
color: var(--mod-queue-approve-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.approve:hover {
|
||||||
|
color: var(--mod-queue-approve-color-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
.reject {
|
.reject {
|
||||||
color: red;
|
color: var(--mod-queue-reject-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.reject:hover {
|
||||||
|
color: var(--mod-queue-reject-color-hover);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ModQueueBoardFilter styles */
|
/* ModQueueBoardFilter styles */
|
||||||
@@ -174,34 +194,31 @@
|
|||||||
|
|
||||||
.filterSelect {
|
.filterSelect {
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
border: 1px solid var(--border-color);
|
border: var(--mod-queue-table-border);
|
||||||
background: var(--input-background-color);
|
background: var(--mod-queue-header-background-color);
|
||||||
color: var(--text-color);
|
color: var(--body-font-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ModQueueButton styles */
|
/* ModQueueButton styles */
|
||||||
.modQueueButton {
|
|
||||||
cursor: pointer;
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
margin-left: 8px;
|
|
||||||
text-decoration: none;
|
|
||||||
color: var(--text-color);
|
|
||||||
font-size: 13px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modQueueButton:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modQueueButtonCount {
|
.modQueueButtonCount {
|
||||||
margin-left: 4px;
|
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modQueueButtonAlert {
|
/* Number blinking, changing color to red */
|
||||||
color: red;
|
.modQueueButtonCountAlert {
|
||||||
animation: blink 2s infinite;
|
animation: blinkColor 2s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes blinkColor {
|
||||||
|
0% {
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
color: var(--mod-queue-alert-color);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Mobile Layout */
|
/* Mobile Layout */
|
||||||
@@ -243,6 +260,14 @@
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
|
border: var(--button-border-mobile);
|
||||||
|
background: var(--button-background-color-mobile);
|
||||||
|
color: var(--button-text-color-mobile);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button:hover {
|
||||||
|
background: var(--button-background-color-mobile);
|
||||||
}
|
}
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
|
|||||||
@@ -148,16 +148,25 @@ export const ModQueueButton = ({ boardIdentifier, isMobile }: ModQueueButtonProp
|
|||||||
const { alertThresholdHours } = useModQueueStore();
|
const { alertThresholdHours } = useModQueueStore();
|
||||||
const { accountSubplebbits } = useAccountSubplebbits();
|
const { accountSubplebbits } = useAccountSubplebbits();
|
||||||
const accountSubplebbitAddresses = useMemo(() => Object.keys(accountSubplebbits || {}), [accountSubplebbits]);
|
const accountSubplebbitAddresses = useMemo(() => Object.keys(accountSubplebbits || {}), [accountSubplebbits]);
|
||||||
|
const defaultSubplebbits = useDefaultSubplebbits();
|
||||||
|
|
||||||
|
// Resolve boardIdentifier to address if it exists
|
||||||
|
const resolvedAddress = useMemo(() => {
|
||||||
|
if (boardIdentifier) {
|
||||||
|
return getSubplebbitAddress(boardIdentifier, defaultSubplebbits);
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}, [boardIdentifier, defaultSubplebbits]);
|
||||||
|
|
||||||
const subplebbitAddresses = useMemo(() => {
|
const subplebbitAddresses = useMemo(() => {
|
||||||
if (boardIdentifier) {
|
if (resolvedAddress) {
|
||||||
return [boardIdentifier];
|
return [resolvedAddress];
|
||||||
}
|
}
|
||||||
return accountSubplebbitAddresses;
|
return accountSubplebbitAddresses;
|
||||||
}, [boardIdentifier, accountSubplebbitAddresses]);
|
}, [resolvedAddress, accountSubplebbitAddresses]);
|
||||||
|
|
||||||
// If specific board, check if user is mod
|
// If specific board, check if user is mod using resolved address
|
||||||
const isModOfBoard = boardIdentifier ? accountSubplebbitAddresses.includes(boardIdentifier) : true;
|
const isModOfBoard = resolvedAddress ? accountSubplebbitAddresses.includes(resolvedAddress) : true;
|
||||||
|
|
||||||
// Only fetch if we have addresses to check and permissions
|
// Only fetch if we have addresses to check and permissions
|
||||||
const shouldFetch = subplebbitAddresses.length > 0 && isModOfBoard;
|
const shouldFetch = subplebbitAddresses.length > 0 && isModOfBoard;
|
||||||
@@ -172,29 +181,57 @@ export const ModQueueButton = ({ boardIdentifier, isMobile }: ModQueueButtonProp
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const count = feed.length;
|
// Separate comments into normal and urgent based on threshold
|
||||||
|
// Match ModQueueRow logic: use > (strictly greater) to be consistent
|
||||||
|
const { normalCount, urgentCount } = useMemo(() => {
|
||||||
|
const thresholdSeconds = alertThresholdHours * 3600;
|
||||||
|
const now = Date.now() / 1000;
|
||||||
|
|
||||||
const hasAlert = feed.some((item) => {
|
let normal = 0;
|
||||||
const timeWaiting = Date.now() / 1000 - item.timestamp;
|
let urgent = 0;
|
||||||
return timeWaiting > alertThresholdHours * 3600;
|
|
||||||
});
|
|
||||||
|
|
||||||
|
for (const item of feed) {
|
||||||
|
const timeWaiting = now - item.timestamp;
|
||||||
|
if (timeWaiting > thresholdSeconds) {
|
||||||
|
urgent++;
|
||||||
|
} else {
|
||||||
|
normal++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { normalCount: normal, urgentCount: urgent };
|
||||||
|
}, [feed, alertThresholdHours]);
|
||||||
|
|
||||||
|
const totalCount = normalCount + urgentCount;
|
||||||
|
|
||||||
|
// Use boardIdentifier for the route, but resolvedAddress for mod check
|
||||||
const to = boardIdentifier ? `/${boardIdentifier}/queue` : '/mod/queue';
|
const to = boardIdentifier ? `/${boardIdentifier}/queue` : '/mod/queue';
|
||||||
|
|
||||||
if (count === 0) {
|
|
||||||
// If we are on a specific board and the user is a mod, we still show the button
|
|
||||||
// If we are in global mod view, we show it too
|
|
||||||
return (
|
|
||||||
<Link to={to} className={styles.modQueueButton}>
|
|
||||||
[{t('mod_queue')}]
|
|
||||||
</Link>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link to={to} className={`${styles.modQueueButton} ${hasAlert ? styles.modQueueButtonAlert : ''}`}>
|
<button className='button'>
|
||||||
[{t('mod_queue')} <span className={styles.modQueueButtonCount}>{count}</span>]
|
<Link to={to}>
|
||||||
</Link>
|
{t('mod_queue')}
|
||||||
|
{totalCount > 0 && (
|
||||||
|
<strong>
|
||||||
|
(
|
||||||
|
{urgentCount > 0 && normalCount > 0 ? (
|
||||||
|
<>
|
||||||
|
<span className={styles.modQueueButtonCount}>{normalCount}</span>
|
||||||
|
<span className={`${styles.modQueueButtonCount} ${styles.modQueueButtonCountAlert}`}>
|
||||||
|
{'+'}
|
||||||
|
{urgentCount}
|
||||||
|
</span>
|
||||||
|
</>
|
||||||
|
) : urgentCount > 0 ? (
|
||||||
|
<span className={`${styles.modQueueButtonCount} ${styles.modQueueButtonCountAlert}`}>{urgentCount}</span>
|
||||||
|
) : (
|
||||||
|
<span className={styles.modQueueButtonCount}>{totalCount}</span>
|
||||||
|
)}
|
||||||
|
)
|
||||||
|
</strong>
|
||||||
|
)}
|
||||||
|
</Link>
|
||||||
|
</button>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user