diff --git a/apps/dashboard/features/governance/components/proposal-overview/ProposalSection.tsx b/apps/dashboard/features/governance/components/proposal-overview/ProposalSection.tsx index abf7448d8..e55705f07 100644 --- a/apps/dashboard/features/governance/components/proposal-overview/ProposalSection.tsx +++ b/apps/dashboard/features/governance/components/proposal-overview/ProposalSection.tsx @@ -41,7 +41,6 @@ import { HoldersAndDelegatesDrawer } from "@/features/holders-and-delegates"; import { ProposalHeaderProvider } from "@/features/governance/context/ProposalHeaderContext"; import { Button } from "@/shared/components"; import { ConnectWalletCustom } from "@/shared/components/wallet/ConnectWalletCustom"; -import { TelegramBotMessage } from "@/shared/components/messages"; import daoConfig from "@/shared/dao-config"; import { DaoIdEnum } from "@/shared/types/daos"; @@ -276,11 +275,6 @@ export const ProposalSection = ({ proposal={proposal} isOffchain={isOffchain} /> - {!isOffchain && supportValue !== undefined ? ( -
- -
- ) : null} = { const KPI_COUNT = 3; +const PERCENTAGE_POINTS_TOOLTIP = + "Percentage points: the absolute change between two percentages. Going from 30% to 39% is +9pp, not +9%."; + export const KpiRow = () => { const [timePeriod, setTimePeriod] = useState("1y"); @@ -116,23 +119,9 @@ export const KpiRow = () => { "border-border-default border-b lg:border-b-0 lg:border-r", )} > -
-

- {kpi.title} -

- {kpi.tooltip && ( - - {kpi.tooltip} -

- } - triggerClassName="inline-flex cursor-help items-center border-0 bg-transparent p-0" - > - -
- )} -
+

+ {kpi.title} +

{kpi.value}

@@ -152,7 +141,29 @@ export const KpiRow = () => { : "text-secondary" } > - {kpi.subtext} + {kpi.delta ? ( + <> + {kpi.delta.value} + {kpi.delta.unit === "pp" ? ( + + {PERCENTAGE_POINTS_TOOLTIP} +

+ } + triggerClassName="cursor-help underline decoration-dotted underline-offset-2" + > + {kpi.delta.unit} +
+ ) : ( + kpi.delta.unit + )}{" "} + {kpi.delta.comparison} + + ) : ( + kpi.subtext + )}

diff --git a/apps/dashboard/features/revenue/types.ts b/apps/dashboard/features/revenue/types.ts index 97d6349ba..5deb94a0d 100644 --- a/apps/dashboard/features/revenue/types.ts +++ b/apps/dashboard/features/revenue/types.ts @@ -22,6 +22,10 @@ export type KpiCard = { title: string; value: string; subtext: string; + delta?: { + value: string; + unit: string; + comparison: string; + }; trend?: "up" | "down"; - tooltip?: string; }; diff --git a/apps/dashboard/features/revenue/utils/transform/kpis.ts b/apps/dashboard/features/revenue/utils/transform/kpis.ts index cd85155f6..07a5d3dcc 100644 --- a/apps/dashboard/features/revenue/utils/transform/kpis.ts +++ b/apps/dashboard/features/revenue/utils/transform/kpis.ts @@ -35,7 +35,6 @@ function buildFlowKpi(args: { /** "pct" for sums, "pp" for averages-of-percentages */ deltaKind: "pct" | "pp"; window: KpiWindow; - tooltip?: string; }): KpiCard { const sinceLabel = buildSinceLabel(args.items); const { current, previous } = splitIntoWindows( @@ -55,17 +54,23 @@ function buildFlowKpi(args: { const presentation = args.window.months !== null && rawDelta !== null - ? presentDelta(rawDelta, args.deltaKind === "pct" ? "%" : "pp") + ? presentDelta(rawDelta) : null; + const unit = args.deltaKind === "pct" ? "%" : "pp"; + return { title: args.title, value: current.length > 0 ? args.formatValue(currentValue) : "—", - subtext: presentation - ? `${presentation.text} vs prev. ${args.window.label}` - : sinceLabel, + subtext: sinceLabel, + delta: presentation + ? { + value: presentation.text, + unit, + comparison: `vs prev. ${args.window.label}`, + } + : undefined, trend: presentation?.trend, - tooltip: args.tooltip, }; } @@ -99,8 +104,6 @@ export function computeKpis( formatValue: (n) => `${n.toFixed(0)}%`, deltaKind: "pp", window, - tooltip: - "Share of expiring names that were renewed. 'pp' (percentage points) is the absolute change between two percentages.", }), buildFlowKpi({ title: "Revenue", diff --git a/apps/dashboard/features/revenue/utils/window.ts b/apps/dashboard/features/revenue/utils/window.ts index e12916d58..cdf2ab446 100644 --- a/apps/dashboard/features/revenue/utils/window.ts +++ b/apps/dashboard/features/revenue/utils/window.ts @@ -51,25 +51,15 @@ export type DeltaPresentation = { trend: "up" | "down" | undefined; }; -/** - * Formats a percentage-ish delta with adaptive precision: up to 2 decimals - * for small magnitudes (<0.1), 1 decimal for [0.1, 1), 0 decimals otherwise. - * Returns the trend in lockstep with the rendered value — when the value - * rounds to 0 at the chosen precision, the trend is `undefined` (neutral). - * - * The point: a real +0.4% change should display as "+0.4%" with an up arrow, - * not "+0%" (which would erase the signal) and not "+0%" with an arrow - * (which would conflict with the rendered value). - */ -export function presentDelta(value: number, suffix: string): DeltaPresentation { +export function presentDelta(value: number): DeltaPresentation { const abs = Math.abs(value); const precision = abs >= 1 ? 0 : abs >= 0.1 ? 1 : 2; // Snap to display precision so text and trend can never disagree. const snapped = Number(value.toFixed(precision)); - if (snapped === 0) return { text: `0${suffix}`, trend: undefined }; + if (snapped === 0) return { text: "0", trend: undefined }; const prefix = snapped > 0 ? "+" : ""; return { - text: `${prefix}${snapped.toFixed(precision)}${suffix}`, + text: `${prefix}${snapped.toFixed(precision)}`, trend: snapped > 0 ? "up" : "down", }; } diff --git a/apps/dashboard/shared/components/messages/TelegramBotMessage.tsx b/apps/dashboard/shared/components/messages/TelegramBotMessage.tsx deleted file mode 100644 index d6d648007..000000000 --- a/apps/dashboard/shared/components/messages/TelegramBotMessage.tsx +++ /dev/null @@ -1,39 +0,0 @@ -"use client"; - -import { ArrowRight, Send } from "lucide-react"; -import { useParams } from "next/navigation"; - -import { ANTICAPTURE_TELEGRAM_BOT } from "@/shared/constants/social-media"; -import daoConfigByDaoId from "@/shared/dao-config"; -import type { DaoIdEnum } from "@/shared/types/daos"; - -export const TelegramBotMessage = () => { - const { daoId } = useParams() as { daoId: string }; - return ( -
- -
-
- - RECEIVE REAL-TIME{" "} - {daoConfigByDaoId[ - daoId.toUpperCase() as DaoIdEnum - ].name.toUpperCase()}{" "} - SECURITY UPDATES. - -
- -
-
- ); -}; diff --git a/apps/dashboard/shared/components/messages/index.ts b/apps/dashboard/shared/components/messages/index.ts deleted file mode 100644 index c51609159..000000000 --- a/apps/dashboard/shared/components/messages/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "@/shared/components/messages/TelegramBotMessage"; diff --git a/apps/dashboard/widgets/WhitelabelSidebar.tsx b/apps/dashboard/widgets/WhitelabelSidebar.tsx index f860b2eba..4e4379346 100644 --- a/apps/dashboard/widgets/WhitelabelSidebar.tsx +++ b/apps/dashboard/widgets/WhitelabelSidebar.tsx @@ -233,7 +233,7 @@ export const WhitelabelSidebar = ({ rel="noopener noreferrer" className="text-link" > - Blockful + blockful

)}