diff --git a/src/lib/dtoParsers.ts b/src/lib/dtoParsers.ts index 29254de..21cacda 100644 --- a/src/lib/dtoParsers.ts +++ b/src/lib/dtoParsers.ts @@ -39,8 +39,8 @@ export function computeChamberMetrics(chambers: ChamberDto[]) { return sum + acm; }, 0); // Governors can be members of multiple chambers; use the largest chamber roster - // as a stable approximation of global governors for the summary tile. - const governors = chambers.reduce((max, chamber) => { + // as a stable approximation of global active governors for the summary tile. + const activeGovernors = chambers.reduce((max, chamber) => { const { governors } = getChamberNumericStats(chamber); return Math.max(max, governors); }, 0); @@ -50,7 +50,7 @@ export function computeChamberMetrics(chambers: ChamberDto[]) { ); return { totalChambers: chambers.length, - governors, + activeGovernors, totalAcm, liveProposals, }; diff --git a/src/pages/MyGovernance.tsx b/src/pages/MyGovernance.tsx index 174586c..ad31cd8 100644 --- a/src/pages/MyGovernance.tsx +++ b/src/pages/MyGovernance.tsx @@ -140,16 +140,13 @@ const governingStatusTermId = (label: GoverningStatus): string => { return "governing_status_losing_status"; }; -const formatDayHourMinuteSecond = (targetMs: number, nowMs: number): string => { +const formatDayHourMinute = (targetMs: number, nowMs: number): string => { const deltaMs = Math.max(0, targetMs - nowMs); - const totalSeconds = Math.floor(deltaMs / 1000); - const days = Math.floor(totalSeconds / (24 * 60 * 60)); - const hours = Math.floor((totalSeconds % (24 * 60 * 60)) / (60 * 60)); - const minutes = Math.floor((totalSeconds % (60 * 60)) / 60); - const seconds = totalSeconds % 60; - return `${days}d:${String(hours).padStart(2, "0")}h:${String( - minutes, - ).padStart(2, "0")}m:${String(seconds).padStart(2, "0")}s`; + const totalMinutes = Math.floor(deltaMs / 60_000); + const days = Math.floor(totalMinutes / (24 * 60)); + const hours = Math.floor((totalMinutes % (24 * 60)) / 60); + const minutes = totalMinutes % 60; + return `${days}d:${String(hours).padStart(2, "0")}h:${String(minutes).padStart(2, "0")}m`; }; const MyGovernance: React.FC = () => { @@ -159,22 +156,12 @@ const MyGovernance: React.FC = () => { const [cmSummary, setCmSummary] = useState(null); const [loadError, setLoadError] = useState(null); const [nowMs, setNowMs] = useState(() => Date.now()); - const [clockBaseMs, setClockBaseMs] = useState(null); - const [clockFetchedAtMs, setClockFetchedAtMs] = useState(null); useEffect(() => { const timer = window.setInterval(() => setNowMs(Date.now()), 1000); return () => window.clearInterval(timer); }, []); - useEffect(() => { - if (!clock?.now) return; - const parsed = new Date(clock.now).getTime(); - if (!Number.isFinite(parsed)) return; - setClockBaseMs(parsed); - setClockFetchedAtMs(Date.now()); - }, [clock?.now]); - useEffect(() => { let active = true; (async () => { @@ -221,21 +208,10 @@ const MyGovernance: React.FC = () => { ? new Date(clock.nextEraAt).getTime() : NaN; if (Number.isFinite(targetMs)) { - const simNowMs = - Number.isFinite(clockBaseMs ?? NaN) && - Number.isFinite(clockFetchedAtMs ?? NaN) - ? (clockBaseMs as number) + (nowMs - (clockFetchedAtMs as number)) - : nowMs; - return formatDayHourMinuteSecond(targetMs, simNowMs); + return formatDayHourMinute(targetMs, nowMs); } return eraActivity?.timeLeft ?? "—"; - }, [ - clock?.nextEraAt, - eraActivity?.timeLeft, - nowMs, - clockBaseMs, - clockFetchedAtMs, - ]); + }, [clock?.nextEraAt, eraActivity?.timeLeft, nowMs]); const myChambers = useMemo(() => { if (!gov || !chambers) return []; @@ -387,7 +363,7 @@ const MyGovernance: React.FC = () => {
Progress -
+
{ badge={ M × {chamber.multiplier} @@ -576,7 +552,7 @@ const MyGovernance: React.FC = () => { asChild size="md" variant="primary" - className="w-full sm:w-56" + className="w-56" > Enter diff --git a/src/pages/chambers/Chambers.tsx b/src/pages/chambers/Chambers.tsx index c7e8f48..be199e9 100644 --- a/src/pages/chambers/Chambers.tsx +++ b/src/pages/chambers/Chambers.tsx @@ -12,13 +12,12 @@ import { Button } from "@/components/primitives/button"; import { Link } from "react-router"; import { InlineHelp } from "@/components/InlineHelp"; import { NoDataYetBar } from "@/components/NoDataYetBar"; -import { apiChambers, apiClock } from "@/lib/apiClient"; +import { apiChambers } from "@/lib/apiClient"; import { computeChamberMetrics, getChamberNumericStats, } from "@/lib/dtoParsers"; import type { ChamberDto } from "@/types/api"; -import type { GetClockResponse } from "@/types/api"; import { Surface } from "@/components/Surface"; type Metric = { @@ -35,7 +34,6 @@ const metricCards: Metric[] = [ const Chambers: React.FC = () => { const [chambers, setChambers] = useState(null); - const [clock, setClock] = useState(null); const [loadError, setLoadError] = useState(null); const [search, setSearch] = useState(""); const [filters, setFilters] = useState<{ @@ -49,15 +47,12 @@ const Chambers: React.FC = () => { (async () => { try { const res = await apiChambers(); - const clockRes = await apiClock().catch(() => null); if (!active) return; setChambers(res.items); - setClock(clockRes); setLoadError(null); } catch (error) { if (!active) return; setChambers([]); - setClock(null); setLoadError((error as Error).message); } })(); @@ -95,12 +90,9 @@ const Chambers: React.FC = () => { const computedMetrics = useMemo((): Metric[] => { if (!chambers) return metricCards; - const { governors, totalAcm, liveProposals } = + const { activeGovernors, totalAcm, liveProposals } = computeChamberMetrics(chambers); - const activeGovernors = Math.min( - governors, - Math.max(0, Math.floor(clock?.activeGovernors ?? governors)), - ); + const governors = activeGovernors; return [ { label: "Total chambers", value: String(chambers.length) }, { @@ -110,7 +102,7 @@ const Chambers: React.FC = () => { { label: "Total ACM", value: totalAcm.toLocaleString() }, { label: "Live proposals", value: String(liveProposals) }, ]; - }, [chambers, clock]); + }, [chambers]); return (
@@ -208,19 +200,14 @@ const Chambers: React.FC = () => { badge={ M × {chamber.multiplier} } footer={
-
diff --git a/src/pages/factions/Faction.tsx b/src/pages/factions/Faction.tsx index da60ea6..927160e 100644 --- a/src/pages/factions/Faction.tsx +++ b/src/pages/factions/Faction.tsx @@ -183,7 +183,7 @@ const Faction: React.FC = () => {

{faction.name}

{faction.description}

-
+
Members: {faction.members} Votes: {faction.votes} {viewerRole ? ( @@ -193,7 +193,7 @@ const Faction: React.FC = () => { -
+
{canJoin ? (
-
+
{canManageMembers ? ( @@ -598,7 +598,7 @@ const Faction: React.FC = () => { key={thread.id} className="space-y-2 rounded-md border border-border px-3 py-2" > -
+

{thread.title} @@ -635,7 +635,7 @@ const Faction: React.FC = () => {

) : null} {canPost ? ( -
+
diff --git a/src/pages/factions/FactionCreate.tsx b/src/pages/factions/FactionCreate.tsx index 44c0cb7..1c47570 100644 --- a/src/pages/factions/FactionCreate.tsx +++ b/src/pages/factions/FactionCreate.tsx @@ -114,7 +114,7 @@ const FactionCreate: React.FC = () => { -
+
{[ { n: 1, label: "Identity" }, { n: 2, label: "Access & goals" }, diff --git a/src/types/api.ts b/src/types/api.ts index 0269ec5..c43a8dd 100644 --- a/src/types/api.ts +++ b/src/types/api.ts @@ -324,7 +324,6 @@ export type GetMyGovernanceResponse = { export type GetClockResponse = { currentEra: number; updatedAt: string; - now: string; eraSeconds: number; nextEraAt: string; activeGovernors: number;