refactor: remove broken Community Trust chart (TrustBar)
- Remove TrustBar component and chart - Remove trust data from game-stats API response - Remove trust section from game detail page - DB columns and vote endpoints preserved for future voting system
This commit is contained in:
@@ -31,7 +31,6 @@ import { UpscalerBarChart } from "@/components/charts/UpscalerBarChart"
|
|||||||
import { FpsBoxplot } from "@/components/charts/FpsBoxplot"
|
import { FpsBoxplot } from "@/components/charts/FpsBoxplot"
|
||||||
import { FpsRangeChart } from "@/components/charts/FpsRangeChart"
|
import { FpsRangeChart } from "@/components/charts/FpsRangeChart"
|
||||||
import { DeviceDonut } from "@/components/charts/DeviceDonut"
|
import { DeviceDonut } from "@/components/charts/DeviceDonut"
|
||||||
import { TrustBar } from "@/components/charts/TrustBar"
|
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
interface Game {
|
interface Game {
|
||||||
@@ -140,15 +139,6 @@ interface StatsResponse {
|
|||||||
hardwareName: string
|
hardwareName: string
|
||||||
count: number
|
count: number
|
||||||
}>
|
}>
|
||||||
trust: Array<{
|
|
||||||
id: string
|
|
||||||
hardwareSlug: string
|
|
||||||
upvotes: number
|
|
||||||
downvotes: number
|
|
||||||
verifiedAt: string | null
|
|
||||||
userNotes: string | null
|
|
||||||
createdAt: string
|
|
||||||
}>
|
|
||||||
filterOptions: {
|
filterOptions: {
|
||||||
protonVersions: string[]
|
protonVersions: string[]
|
||||||
osVersions: string[]
|
osVersions: string[]
|
||||||
@@ -323,7 +313,6 @@ export function GamePageClient({
|
|||||||
upscalerStats: filterUpscaler(stats.upscalerStats),
|
upscalerStats: filterUpscaler(stats.upscalerStats),
|
||||||
fpsRange: filterByDevice(stats.fpsRange),
|
fpsRange: filterByDevice(stats.fpsRange),
|
||||||
deviceBreakdown: filterByDevice(stats.deviceBreakdown),
|
deviceBreakdown: filterByDevice(stats.deviceBreakdown),
|
||||||
trust: filterByDevice(stats.trust),
|
|
||||||
}
|
}
|
||||||
}, [stats, selectedDevices, filters])
|
}, [stats, selectedDevices, filters])
|
||||||
|
|
||||||
@@ -388,6 +377,7 @@ export function GamePageClient({
|
|||||||
className='object-cover'
|
className='object-cover'
|
||||||
priority
|
priority
|
||||||
onError={handleImgError}
|
onError={handleImgError}
|
||||||
|
loading="eager"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div className='w-full h-full flex items-center justify-center'>
|
<div className='w-full h-full flex items-center justify-center'>
|
||||||
@@ -990,15 +980,6 @@ export function GamePageClient({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Row 4 — Trust Bar */}
|
|
||||||
{filteredStats && filteredStats.trust.length > 0 && (
|
|
||||||
<div className='rounded-xl border border-border bg-text/3 p-4'>
|
|
||||||
<h3 className='text-sm font-medium text-text/80 mb-2'>
|
|
||||||
Community Trust
|
|
||||||
</h3>
|
|
||||||
<TrustBar data={filteredStats.trust} />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -1,102 +0,0 @@
|
|||||||
"use client"
|
|
||||||
|
|
||||||
import { useMemo } from "react"
|
|
||||||
import { EChartWrapper, CHART_THEME } from "./EChartWrapper"
|
|
||||||
import type { EChartsOption } from "echarts"
|
|
||||||
|
|
||||||
interface TrustEntry {
|
|
||||||
id: string
|
|
||||||
hardwareSlug: string
|
|
||||||
upvotes: number
|
|
||||||
downvotes: number
|
|
||||||
verifiedAt: string | null
|
|
||||||
userNotes: string | null
|
|
||||||
createdAt: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export function TrustBar({
|
|
||||||
data,
|
|
||||||
className,
|
|
||||||
}: {
|
|
||||||
data: TrustEntry[]
|
|
||||||
className?: string
|
|
||||||
}) {
|
|
||||||
const option = useMemo<EChartsOption>(() => {
|
|
||||||
const sorted = [...data]
|
|
||||||
.sort((a, b) => b.upvotes - b.downvotes - (a.upvotes - a.downvotes))
|
|
||||||
.slice(0, 20)
|
|
||||||
|
|
||||||
const labels = sorted.map((e) => {
|
|
||||||
const date = new Date(e.createdAt).toLocaleDateString("en-US", {
|
|
||||||
month: "short",
|
|
||||||
day: "numeric",
|
|
||||||
})
|
|
||||||
return e.userNotes
|
|
||||||
? `${e.userNotes.slice(0, 20)}...`
|
|
||||||
: `Entry ${date}`
|
|
||||||
})
|
|
||||||
|
|
||||||
const scores = sorted.map((e) => e.upvotes - e.downvotes)
|
|
||||||
|
|
||||||
return {
|
|
||||||
tooltip: {
|
|
||||||
trigger: "axis",
|
|
||||||
backgroundColor: "#1a1025",
|
|
||||||
borderColor: CHART_THEME.border,
|
|
||||||
textStyle: { color: CHART_THEME.text, fontSize: 12 },
|
|
||||||
formatter: (params) => {
|
|
||||||
const p = Array.isArray(params) ? params[0] : null
|
|
||||||
if (!p) return ""
|
|
||||||
const idx = (p as { dataIndex: number }).dataIndex
|
|
||||||
const entry = sorted[idx]
|
|
||||||
if (!entry) return ""
|
|
||||||
return `↑${entry.upvotes} ↓${entry.downvotes}${entry.verifiedAt ? " ✅ Verified" : ""}`
|
|
||||||
},
|
|
||||||
},
|
|
||||||
grid: { top: 8, right: 16, bottom: 8, left: 120 },
|
|
||||||
xAxis: {
|
|
||||||
type: "value",
|
|
||||||
axisLabel: { color: CHART_THEME.textMuted, fontSize: 10 },
|
|
||||||
splitLine: { lineStyle: { color: CHART_THEME.border, opacity: 0.3 } },
|
|
||||||
},
|
|
||||||
yAxis: {
|
|
||||||
type: "category",
|
|
||||||
data: labels,
|
|
||||||
inverse: true,
|
|
||||||
axisLabel: {
|
|
||||||
color: CHART_THEME.textMuted,
|
|
||||||
fontSize: 10,
|
|
||||||
width: 100,
|
|
||||||
overflow: "truncate",
|
|
||||||
},
|
|
||||||
axisLine: { show: false },
|
|
||||||
axisTick: { show: false },
|
|
||||||
},
|
|
||||||
series: [
|
|
||||||
{
|
|
||||||
type: "bar",
|
|
||||||
data: scores.map((score, idx) => ({
|
|
||||||
value: score,
|
|
||||||
itemStyle: {
|
|
||||||
color: sorted[idx].verifiedAt
|
|
||||||
? CHART_THEME.success
|
|
||||||
: CHART_THEME.textSubtle,
|
|
||||||
borderRadius: [0, 4, 4, 0],
|
|
||||||
},
|
|
||||||
})),
|
|
||||||
barWidth: "60%",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
}, [data])
|
|
||||||
|
|
||||||
if (data.length === 0) return null
|
|
||||||
|
|
||||||
return (
|
|
||||||
<EChartWrapper
|
|
||||||
option={option}
|
|
||||||
height={Math.min(300, data.length * 28 + 16)}
|
|
||||||
className={className}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
+1
-14
@@ -74,7 +74,6 @@ export const gameStatsRoutes = new Elysia({ prefix: "/games" }).get(
|
|||||||
upscalerStats: [],
|
upscalerStats: [],
|
||||||
fpsRange: [],
|
fpsRange: [],
|
||||||
deviceBreakdown: [],
|
deviceBreakdown: [],
|
||||||
trust: [],
|
|
||||||
filterOptions: { protonVersions: [], osVersions: [] },
|
filterOptions: { protonVersions: [], osVersions: [] },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -239,18 +238,7 @@ export const gameStatsRoutes = new Elysia({ prefix: "/games" }).get(
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
// ── 9. Community trust ────────────────────────────────────────
|
// ── 9. Filter options ────────────────────────────────────────
|
||||||
const trust = entries.map((e) => ({
|
|
||||||
id: e.id,
|
|
||||||
hardwareSlug: e.hardwareSlug,
|
|
||||||
upvotes: e.upvotes,
|
|
||||||
downvotes: e.downvotes,
|
|
||||||
verifiedAt: e.verifiedAt ? e.verifiedAt.toISOString() : null,
|
|
||||||
userNotes: e.userNotes,
|
|
||||||
createdAt: e.createdAt.toISOString(),
|
|
||||||
}))
|
|
||||||
|
|
||||||
// ── 10. Filter options ────────────────────────────────────────
|
|
||||||
const protonVersions = [
|
const protonVersions = [
|
||||||
...new Set(entries.map((e) => e.protonVersion).filter(Boolean)),
|
...new Set(entries.map((e) => e.protonVersion).filter(Boolean)),
|
||||||
] as string[]
|
] as string[]
|
||||||
@@ -273,7 +261,6 @@ export const gameStatsRoutes = new Elysia({ prefix: "/games" }).get(
|
|||||||
upscalerStats,
|
upscalerStats,
|
||||||
fpsRange,
|
fpsRange,
|
||||||
deviceBreakdown,
|
deviceBreakdown,
|
||||||
trust,
|
|
||||||
filterOptions: { protonVersions, osVersions },
|
filterOptions: { protonVersions, osVersions },
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user