Appearance
Scaffold a new Med Tracker page. First ask the user for:
- Page name (PascalCase, e.g.
Notifications) - Route path (e.g.
/notifications) - Nav label EN (e.g.
Notifications) - Nav label zh-TW (e.g.
通知) - Lucide icon (e.g.
Bell) - Nav section: add to sidebar nav or skip?
Then implement ALL of the following steps:
Step 1 — Create the page component
frontend/src/pages/{kebab-name}/{Name}Page.tsx
tsx
import { useTranslation } from 'react-i18next'
function {Name}Page() {
const { t } = useTranslation()
return (
<div className="p-6 space-y-6">
<div className="rounded-xl border border-border bg-surface p-6 nm-convex">
<h1 className="text-2xl font-semibold text-text-primary">
{t('nav.{camelName}')}
</h1>
<p className="mt-2 text-text-secondary">{t('common.comingSoon', 'Coming soon')}</p>
</div>
</div>
)
}
export default {Name}PageStep 2 — Register lazy route in App.tsx
In frontend/src/App.tsx, add:
tsx
const {Name}Page = React.lazy(() => import('./pages/{kebab-name}/{Name}Page'))And add route inside <Route path="/" element={<AppLayout />}>:
tsx
<Route path="{route-path}" element={<{Name}Page />} />Step 3 — Add sidebar nav item (if requested)
In frontend/src/components/layout/Sidebar.tsx, add to the appropriate nav array:
tsx
{ path: '{route-path}', label: t('nav.{camelName}'), icon: {Icon} }Import the Lucide icon at the top.
Step 4 — Add i18n keys to BOTH locale files
frontend/src/i18n/locales/en.json — add under "nav":
json
"{camelName}": "{EN label}"frontend/src/i18n/locales/zh-TW.json — add under "nav":
json
"{camelName}": "{zh-TW label}"Step 5 — Create test file
frontend/src/pages/{kebab-name}/{Name}Page.test.tsx
tsx
import { render, screen } from '@testing-library/react'
import { MemoryRouter } from 'react-router-dom'
import { describe, it, expect, vi } from 'vitest'
import {Name}Page from './{Name}Page'
vi.mock('@/hooks/useReminderScheduler', () => ({ useReminderScheduler: vi.fn() }))
vi.mock('@/hooks/useBiomarkerAlerts', () => ({ useBiomarkerAlerts: () => ({ alerts: [] }) }))
describe('{Name}Page', () => {
it('renders without crashing', () => {
render(<MemoryRouter><{Name}Page /></MemoryRouter>)
expect(screen.getByRole('heading')).toBeInTheDocument()
})
})Reminders
export defaultat the bottom is sufficient — no named export needed for React.lazynm-convexclass applies only in Neo themes; safe to include always (no-op in default theme)- Run
npx vitest run src/pages/{kebab-name}/to verify test passes - If adding to Sidebar, always update BOTH
en.jsonANDzh-TW.json