From 3a6ed3a5f81661eeee6b3da306478ddf82119bba Mon Sep 17 00:00:00 2001 From: Saravana Kumar Date: Sat, 30 May 2026 19:50:15 +0000 Subject: [PATCH] feat(tracker-web): add public submission status page --- dashboards/tracker-web/e2e/tracker.spec.ts | 24 +++ .../tracker-web/src/app/status/[id]/page.tsx | 167 ++++++++++++++++++ 2 files changed, 191 insertions(+) create mode 100644 dashboards/tracker-web/src/app/status/[id]/page.tsx diff --git a/dashboards/tracker-web/e2e/tracker.spec.ts b/dashboards/tracker-web/e2e/tracker.spec.ts index 91621e87..abb0d282 100644 --- a/dashboards/tracker-web/e2e/tracker.spec.ts +++ b/dashboards/tracker-web/e2e/tracker.spec.ts @@ -109,6 +109,13 @@ async function mockRoadmap(page: Page): Promise { if (url.includes('/public/roadmap/stats')) { return route.fulfill({ json: ROADMAP_STATS }); } + if (url.includes('/public/items/')) { + const id = url.split('/public/items/')[1]?.split(/[?#]/)[0]; + const item = ROADMAP_ITEMS.find(entry => entry.id === id); + return item + ? route.fulfill({ json: item }) + : route.fulfill({ status: 404, json: { error: 'Item not found' } }); + } if (url.includes('/public/roadmap')) { return route.fulfill({ json: { items: ROADMAP_ITEMS, total: ROADMAP_ITEMS.length, limit: 100, offset: 0 }, @@ -329,6 +336,23 @@ test.describe('Tracker — Public Roadmap', () => { await expect(page.getByRole('heading', { name: /enter your email to vote/i })).toBeVisible(); }); + test('links submitted users to a public status page for an item', async ({ page }) => { + await page.goto('/status/1'); + await expect(page.getByRole('heading', { name: 'Dark mode toggle' })).toBeVisible(); + await expect(page.getByText('Submission status')).toBeVisible(); + await expect( + page.getByText('We received this submission and it is waiting for triage.') + ).toBeVisible(); + await expect(page.getByText('12 votes')).toBeVisible(); + await expect(page.getByRole('link', { name: /back to roadmap/i })).toBeVisible(); + }); + + test('shows a helpful message for an unknown public status item', async ({ page }) => { + await page.goto('/status/missing'); + await expect(page.getByRole('heading', { name: /submission not found/i })).toBeVisible(); + await expect(page.getByRole('link', { name: /view roadmap/i })).toBeVisible(); + }); + test('has no serious accessibility violations', async ({ page }) => { await page.goto('/roadmap'); await expect(page.getByRole('heading', { name: 'Dark mode toggle' })).toBeVisible(); diff --git a/dashboards/tracker-web/src/app/status/[id]/page.tsx b/dashboards/tracker-web/src/app/status/[id]/page.tsx new file mode 100644 index 00000000..b24e8b50 --- /dev/null +++ b/dashboards/tracker-web/src/app/status/[id]/page.tsx @@ -0,0 +1,167 @@ +'use client'; + +import Link from 'next/link'; +import { useParams } from 'next/navigation'; +import { useEffect, useState } from 'react'; +import { getPublicItem, type TrackerItem } from '@/lib/tracker-client'; + +const STATUS_COPY: Record = { + open: { + label: 'Open', + description: 'We received this submission and it is waiting for triage.', + }, + in_progress: { + label: 'In Progress', + description: 'This item is actively being worked on.', + }, + done: { + label: 'Complete', + description: 'This item has been shipped or otherwise completed.', + }, + closed: { + label: 'Closed', + description: 'This item has been closed.', + }, + wont_fix: { + label: "Won't Fix", + description: 'This item was reviewed but is not currently planned.', + }, +}; + +function formatStatus(status: string) { + return STATUS_COPY[status]?.label ?? status.replaceAll('_', ' '); +} + +function formatDate(value: string) { + return new Intl.DateTimeFormat('en', { month: 'short', day: 'numeric', year: 'numeric' }).format( + new Date(value) + ); +} + +export default function SubmissionStatusPage() { + const params = useParams<{ id: string }>(); + const id = params?.id; + const [item, setItem] = useState(null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + + useEffect(() => { + let cancelled = false; + + async function loadItem() { + if (!id) return; + setLoading(true); + setError(null); + try { + const nextItem = await getPublicItem(id); + if (!cancelled) setItem(nextItem); + } catch (_err) { + if (!cancelled) setError('not_found'); + } finally { + if (!cancelled) setLoading(false); + } + } + + void loadItem(); + return () => { + cancelled = true; + }; + }, [id]); + + if (loading) { + return ( +
+
+

Submission status

+

Loading submission…

+
+
+ ); + } + + if (error || !item) { + return ( +
+
+

Submission status

+

Submission not found

+

+ We could not find a public roadmap item for this status link. It may have been made + internal, merged into another item, or removed. +

+ + View roadmap + +
+
+ ); + } + + const status = STATUS_COPY[item.status] ?? { + label: formatStatus(item.status), + description: 'This submission is being tracked by the ByteLyst roadmap team.', + }; + + return ( +
+
+ + Back to roadmap + + +
+

Submission status

+
+
+

{item.title}

+

{item.description}

+
+ + {status.label} + +
+ +
+
+

Status

+

{status.label}

+

{status.description}

+
+
+

+ Votes +

+

{item.voteCount} votes

+

Community interest signal.

+
+
+

+ Activity +

+

{item.commentCount} comments

+

+ Last updated {formatDate(item.updatedAt)}. +

+
+
+ +
+

+ What happens next? +

+

+ Keep this link to check progress. Public roadmap status updates, votes, and completion + state will appear here without requiring an account. +

+
+
+
+
+ ); +}