From 24f180d8b43606b5615006245bee0c94fc7fb5b0 Mon Sep 17 00:00:00 2001 From: Simo Date: Tue, 7 Apr 2026 10:27:06 +0300 Subject: [PATCH 1/3] wip Signed-off-by: Simo --- .../leaderboard/time/TimelineToggleHeader.tsx | 65 ++++++++++--------- package-lock.json | 57 ---------------- 2 files changed, 34 insertions(+), 88 deletions(-) diff --git a/components/waves/leaderboard/time/TimelineToggleHeader.tsx b/components/waves/leaderboard/time/TimelineToggleHeader.tsx index a723e93faf..b97f632e31 100644 --- a/components/waves/leaderboard/time/TimelineToggleHeader.tsx +++ b/components/waves/leaderboard/time/TimelineToggleHeader.tsx @@ -28,43 +28,43 @@ export const TimelineToggleHeader: FC = ({ wave, }) => { const waveData = useWave(wave); - const hasNextDecision = !!nextDecisionTime; + const hasNextDecision = typeof nextDecisionTime === "number"; // Extract the status display logic const getStatusDisplay = () => { if (isPaused && currentPause) { return ( - - - Congrats to last SZN winners! + + + Decisions paused - - Next SZN starts:{" "} + + Next decision after{" "} {(() => { const mintingDate = - wave && waveData ? waveData.pauses.calculateMintingDate(nextDecisionTime) : null; - return mintingDate + waveData.pauses.calculateMintingDate(nextDecisionTime); + return typeof mintingDate === "number" ? new Date(mintingDate).toLocaleDateString(undefined, { - month: "short", - day: "numeric", - }) - : new Date(currentPause.end_time).toLocaleDateString( - undefined, - { month: "short", day: "numeric", - } - ); + }) + : new Date(currentPause.end_time).toLocaleDateString( + undefined, + { + month: "short", + day: "numeric", + } + ); })()} ); } - if (nextDecisionTime) { + if (hasNextDecision) { return ( - + {new Date(nextDecisionTime).toLocaleDateString(undefined, { month: "short", day: "numeric", @@ -76,34 +76,37 @@ export const TimelineToggleHeader: FC = ({ } return ( - No upcoming events + No upcoming events ); }; return (
setIsOpen(!isOpen)}> -
- + className="tw-group tw-cursor-pointer tw-rounded-t-lg tw-border tw-border-solid tw-border-iron-700/50 tw-bg-iron-800/95 tw-px-3 tw-py-1.5 tw-shadow-sm tw-transition-all tw-duration-300 tw-ease-out tw-@container desktop-hover:hover:tw-bg-iron-700/80" + onClick={() => setIsOpen(!isOpen)} + > +
+ className={`tw-flex-shrink-0 tw-whitespace-nowrap tw-text-xs tw-font-semibold ${ + hasNextDecision ? "tw-text-iron-100" : "tw-text-iron-400" + }`} + > {hasNextDecision ? "Decision Timeline" : "Announcement history"} - -
+
{getStatusDisplay()}
diff --git a/package-lock.json b/package-lock.json index 40fae7f965..d9845da546 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12556,21 +12556,6 @@ "ws": "^7.5.1" } }, - "node_modules/@walletconnect/jsonrpc-ws-connection/node_modules/utf-8-validate": { - "version": "5.0.10", - "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", - "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "node-gyp-build": "^4.3.0" - }, - "engines": { - "node": ">=6.14.2" - } - }, "node_modules/@walletconnect/jsonrpc-ws-connection/node_modules/ws": { "version": "7.5.10", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", @@ -20063,21 +20048,6 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "license": "MIT" }, - "node_modules/jayson/node_modules/utf-8-validate": { - "version": "5.0.10", - "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", - "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "node-gyp-build": "^4.3.0" - }, - "engines": { - "node": ">=6.14.2" - } - }, "node_modules/jayson/node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -26837,7 +26807,6 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, @@ -30881,7 +30850,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -30898,7 +30866,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -30915,7 +30882,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -30932,7 +30898,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -30949,7 +30914,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -30966,7 +30930,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -30983,7 +30946,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -31000,7 +30962,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -31017,7 +30978,6 @@ "cpu": [ "arm" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -31034,7 +30994,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -31051,7 +31010,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -31068,7 +31026,6 @@ "cpu": [ "loong64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -31085,7 +31042,6 @@ "cpu": [ "mips64el" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -31102,7 +31058,6 @@ "cpu": [ "ppc64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -31119,7 +31074,6 @@ "cpu": [ "riscv64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -31136,7 +31090,6 @@ "cpu": [ "s390x" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -31153,7 +31106,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -31170,7 +31122,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -31187,7 +31138,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -31204,7 +31154,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -31221,7 +31170,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -31238,7 +31186,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -31255,7 +31202,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -31272,7 +31218,6 @@ "cpu": [ "arm64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -31289,7 +31234,6 @@ "cpu": [ "ia32" ], - "dev": true, "license": "MIT", "optional": true, "os": [ @@ -31306,7 +31250,6 @@ "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ From e01b80e8321293cf022a09e999bde287d4b3686c Mon Sep 17 00:00:00 2001 From: Simo Date: Tue, 7 Apr 2026 11:14:29 +0300 Subject: [PATCH 2/3] wip Signed-off-by: Simo --- .../time/TimelineToggleHeader.test.tsx | 87 ++++++++++++++++--- .../leaderboard/time/TimelineToggleHeader.tsx | 28 ++---- 2 files changed, 85 insertions(+), 30 deletions(-) diff --git a/__tests__/components/waves/leaderboard/time/TimelineToggleHeader.test.tsx b/__tests__/components/waves/leaderboard/time/TimelineToggleHeader.test.tsx index 951ad264c0..e8cd9f4db1 100644 --- a/__tests__/components/waves/leaderboard/time/TimelineToggleHeader.test.tsx +++ b/__tests__/components/waves/leaderboard/time/TimelineToggleHeader.test.tsx @@ -2,28 +2,39 @@ import React from "react"; import { render, screen, fireEvent } from "@testing-library/react"; import { TimelineToggleHeader } from "@/components/waves/leaderboard/time/TimelineToggleHeader"; import { SeizeSettingsProvider } from "@/contexts/SeizeSettingsContext"; +import type { ApiWaveDecisionPause } from "@/generated/models/ApiWaveDecisionPause"; jest.mock("@/helpers/waves/time.utils", () => ({ - calculateTimeLeft: jest.fn(() => ({ days: 0, hours: 1, minutes: 2, seconds: 3 })), -})); - - -jest.mock("@/hooks/useWave", () => ({ - useWave: jest.fn(() => null), + calculateTimeLeft: jest.fn(() => ({ + days: 0, + hours: 1, + minutes: 2, + seconds: 3, + })), })); jest.mock("@/services/6529api", () => ({ - fetchUrl: jest.fn(() => Promise.resolve({ - memes_wave_id: "test-wave-id" - })), + fetchUrl: jest.fn(() => + Promise.resolve({ + memes_wave_id: "test-wave-id", + }) + ), })); describe("TimelineToggleHeader", () => { + afterEach(() => { + jest.restoreAllMocks(); + }); + it("renders Decision Timeline when next decision time provided", () => { const setIsOpen = jest.fn(); render( - + ); expect(screen.getByText("Decision Timeline")).toBeInTheDocument(); @@ -34,4 +45,60 @@ describe("TimelineToggleHeader", () => { fireEvent.click(toggle); expect(setIsOpen).toHaveBeenCalledWith(true); }); + + it("uses the actual next decision date in the paused banner", () => { + const nextDecisionTime = Date.UTC(2026, 3, 10, 12, 0, 0); + const currentPause: ApiWaveDecisionPause = { + start_time: Date.UTC(2026, 3, 8, 12, 0, 0), + end_time: Date.UTC(2026, 3, 9, 12, 0, 0), + }; + const formatSpy = jest + .spyOn(Date.prototype, "toLocaleDateString") + .mockImplementation(function mockToLocaleDateString() { + return `formatted:${this.getTime()}`; + }); + + render( + + + + ); + + expect( + screen.getByText(`Next decision after formatted:${nextDecisionTime}`) + ).toBeInTheDocument(); + expect( + screen.queryByText( + `Next decision after formatted:${currentPause.end_time}` + ) + ).not.toBeInTheDocument(); + expect(formatSpy).toHaveBeenCalled(); + }); + + it("shows no decision scheduled when paused without a next decision time", () => { + const currentPause: ApiWaveDecisionPause = { + start_time: Date.UTC(2026, 3, 8, 12, 0, 0), + end_time: Date.UTC(2026, 3, 9, 12, 0, 0), + }; + + render( + + + + ); + + expect(screen.getByText("No decision scheduled")).toBeInTheDocument(); + }); }); diff --git a/components/waves/leaderboard/time/TimelineToggleHeader.tsx b/components/waves/leaderboard/time/TimelineToggleHeader.tsx index b97f632e31..18a43a73de 100644 --- a/components/waves/leaderboard/time/TimelineToggleHeader.tsx +++ b/components/waves/leaderboard/time/TimelineToggleHeader.tsx @@ -4,7 +4,6 @@ import type { FC } from "react"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faChevronDown } from "@fortawesome/free-solid-svg-icons"; import type { ApiWaveDecisionPause } from "@/generated/models/ApiWaveDecisionPause"; -import { useWave } from "@/hooks/useWave"; import type { ApiWave } from "@/generated/models/ApiWave"; interface TimelineToggleHeaderProps { @@ -25,9 +24,7 @@ export const TimelineToggleHeader: FC = ({ nextDecisionTime, isPaused = false, currentPause, - wave, }) => { - const waveData = useWave(wave); const hasNextDecision = typeof nextDecisionTime === "number"; // Extract the status display logic @@ -40,23 +37,14 @@ export const TimelineToggleHeader: FC = ({ - Next decision after{" "} - {(() => { - const mintingDate = - waveData.pauses.calculateMintingDate(nextDecisionTime); - return typeof mintingDate === "number" - ? new Date(mintingDate).toLocaleDateString(undefined, { - month: "short", - day: "numeric", - }) - : new Date(currentPause.end_time).toLocaleDateString( - undefined, - { - month: "short", - day: "numeric", - } - ); - })()} + {hasNextDecision + ? `Next decision after ${new Date( + nextDecisionTime + ).toLocaleDateString(undefined, { + month: "short", + day: "numeric", + })}` + : "No decision scheduled"} ); From 1e64fdb8767e1ca5c10ef826a8b325d7679ece3b Mon Sep 17 00:00:00 2001 From: Simo Date: Tue, 7 Apr 2026 13:15:53 +0300 Subject: [PATCH 3/3] wip Signed-off-by: Simo --- components/waves/leaderboard/time/TimelineToggleHeader.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/components/waves/leaderboard/time/TimelineToggleHeader.tsx b/components/waves/leaderboard/time/TimelineToggleHeader.tsx index 18a43a73de..e77d6cd8c9 100644 --- a/components/waves/leaderboard/time/TimelineToggleHeader.tsx +++ b/components/waves/leaderboard/time/TimelineToggleHeader.tsx @@ -4,7 +4,6 @@ import type { FC } from "react"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faChevronDown } from "@fortawesome/free-solid-svg-icons"; import type { ApiWaveDecisionPause } from "@/generated/models/ApiWaveDecisionPause"; -import type { ApiWave } from "@/generated/models/ApiWave"; interface TimelineToggleHeaderProps { readonly isOpen: boolean; @@ -12,7 +11,6 @@ interface TimelineToggleHeaderProps { readonly nextDecisionTime: number | null; readonly isPaused?: boolean | undefined; readonly currentPause?: ApiWaveDecisionPause | null | undefined; - readonly wave?: ApiWave | undefined; } /**