Skip to content

SEO: server-render list pages, GET-based search, URL pagination (size=10), SSR locale fallback, and MobX i18n unification#9

Open
Copilot wants to merge 14 commits into
mainfrom
copilot/seo-goodactionhub
Open

SEO: server-render list pages, GET-based search, URL pagination (size=10), SSR locale fallback, and MobX i18n unification#9
Copilot wants to merge 14 commits into
mainfrom
copilot/seo-goodactionhub

Conversation

Copilot AI commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

PR-9 PR-9 PR-9 Powered by Pull Request Badge

This PR addresses SEO for the three list surfaces by moving rendering/filtering state into URL-driven server pages. It also standardizes pagination to URL parameters with a 10-item page size and visible page links at the end of each list, and fully unifies translation handling on mobx-i18n.

  • Scope (issue requirements)

    • Convert list pages to server-rendered components.
    • Switch list search to same-page GET form submissions.
    • Add URL-param pagination in units of 10 with centered page links.
  • Server-rendered list pages

    • Reworked:
      • app/activities/page.tsx
      • app/restaurants/page.tsx
      • app/tutoring/page.tsx
    • Pages now read searchParams on the server, compute filtered datasets, and slice results by page.
    • SSR language selection now normalizes cookie/query/header inputs and loads fallback copy through mobx-i18n.
  • URL-driven search + filtering

    • Replaced client-local search state with GET forms:
      • /activities?keywords=...
      • /restaurants?keywords=...&filter=...
      • /tutoring?keywords=...&tag=...
    • Filter/tag interactions now generate navigable links so state is crawlable/shareable.
  • Pagination behavior

    • Introduced shared pagination helpers in lib/pagination.ts.
    • Vendored the pager component at components/ui/mobx-restful-shadcn/pager.tsx to match the current imports and keep builds reproducible.
    • All three list pages now use:
      • PAGE_SIZE = 10
      • pageIndex query param
      • centered numbered links + prev/next controls
  • Data access alignment

    • Added fetchActivitiesCatalog() in lib/activities.ts and reused it in activities list/detail and /api/data path to keep fetch behavior consistent.
  • Client i18n unification

    • Replaced the remaining i18next / react-i18next client integration with a shared mobx-i18n hook/store.
    • Flattened existing locale JSON resources into the MobX translation store so client and server use the same translation source.
    • Removed obsolete i18next-related config and dependencies.
<form action="/tutoring" method="get">
  <input name="keywords" defaultValue={keywords} />
  {selectedTag && <input type="hidden" name="tag" value={selectedTag} />}
  <button type="submit">搜索</button>
</form>

// URL shape: /tutoring?keywords=数学&tag=小学&pageIndex=2

Human changes

  1. [refactor] simplify Source Code with MobX-i18n & MobX-RESTful-Shadcn
  2. [add] Traditional Chinese translation data
  3. [optimize] update Upstream packages

Copilot AI linked an issue Jun 6, 2026 that may be closed by this pull request
@TechQuery TechQuery added the feature New feature or request label Jun 6, 2026
Copilot AI changed the title [WIP] Implement SEO improvements for GoodActionHub SEO: server-render list pages, GET-based search, and URL pagination (size=10) Jun 6, 2026
Copilot AI requested a review from TechQuery June 6, 2026 23:58

@TechQuery TechQuery left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

先合并主分支最新代码,再通篇修改以下建议。

Comment thread lib/activities.ts Outdated
Comment thread app/activities/page.tsx Outdated
Comment thread app/activities/page.tsx Outdated
Comment thread app/activities/page.tsx Outdated
Comment thread app/activities/page.tsx Outdated
Comment thread app/restaurants/page.tsx Outdated
Comment thread app/restaurants/page.tsx Outdated
Comment thread app/restaurants/page.tsx Outdated
Comment thread app/restaurants/page.tsx Outdated
Comment thread app/tutoring/page.tsx Outdated
Copilot AI changed the title SEO: server-render list pages, GET-based search, and URL pagination (size=10) SEO: server-render list pages, GET-based search, URL pagination (size=10), and SSR locale fallback Jun 7, 2026
Copilot AI requested a review from TechQuery June 7, 2026 21:25
[add] Traditional Chinese translation data
[optimize] update Upstream packages
@TechQuery TechQuery marked this pull request as ready for review June 8, 2026 00:54
Copilot AI review requested due to automatic review settings June 8, 2026 00:54

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to improve SEO and shareability of the three “list” surfaces by moving search/filter/pagination state into URL-driven server-rendered pages, and by adding SSR language selection/fallback for list-page UI text.

Changes:

  • Reworked /activities, /restaurants, and /tutoring list pages to be server components with GET-based search and URL pagination (page size = 10).
  • Introduced SSR language loading via mobx-i18n + new translation maps for zh-CN, zh-TW, and en-US.
  • Aligned activities data fetching by adding fetchActivitiesCatalog() and reusing it in the API route and activities pages.

Reviewed changes

Copilot reviewed 20 out of 22 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
public/locales/zh-TW/translation.json Adds Traditional Chinese i18next translation namespace data.
public/locales/zh-TW/common.json Adds Traditional Chinese i18next common namespace data.
package.json Updates scripts/deps; introduces shadcn-helper install hook and dependency upgrades.
lib/pagination.ts Adds shared page parsing + visible page calculation helpers.
lib/activities.ts Adds fetchActivitiesCatalog() to centralize activities fetch behavior.
i18n/zh-TW.ts Adds SSR translation map for Traditional Chinese.
i18n/zh-CN.ts Adds SSR translation map for Simplified Chinese.
i18n/en-US.ts Adds SSR translation map for English (US).
i18n/index.ts Adds SSR i18n store + cookie/header/query language loading.
i18n/config.ts Extends client i18next config to support zh-TW and formatting tweaks.
eslint.config.ts Adds React version setting and keeps existing TS-eslint rule override.
components/index.ini Declares a shadcn registry component to be installed (pager).
components.json Adds a custom shadcn registry URL.
app/tutoring/page.tsx Converts tutoring list to SSR with GET search + URL tag selection + pagination.
app/tutoring/[slug]/page.tsx Adds SSR i18n text usage in tutoring detail page.
app/restaurants/page.tsx Converts restaurants list to SSR with GET search + URL filter + pagination.
app/restaurants/[id]/page.tsx Adds SSR i18n text usage in restaurant detail page.
app/api/data/route.ts Uses fetchActivitiesCatalog() for consistent upstream fetch behavior.
app/activities/page.tsx Converts activities list to SSR with GET search + pagination and SSR locale loading.
app/activities/[id]/page.tsx Uses fetchActivitiesCatalog() + SSR i18n text usage in activity detail page.
.gitignore Ignores components/ui/ (shadcn UI components).
Comments suppressed due to low confidence (1)

app/api/data/route.ts:14

  • fetchActivitiesCatalog() now throws on upstream fetch errors, but the API route catches everything and returns HTTP 500. Previously, upstream fetch failures returned 502 (bad gateway), which more accurately signals an upstream dependency issue. Consider preserving 502 for fetch failures so monitoring/clients can distinguish upstream vs server errors.
export async function GET() {
  try {
    const externalData = await fetchActivitiesCatalog();
    const data = externalData.map(transformItem);
    return NextResponse.json(data);
  } catch (err) {
    console.error('Failed to fetch data from external API:', err);
    return NextResponse.json({ error: 'Failed to load data' }, { status: 500 });
  }

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lib/pagination.ts
Comment on lines +1 to +4
export function parsePage(rawPage?: string): number {
const parsed = Number.parseInt(rawPage ?? '1', 10);
return Number.isFinite(parsed) && parsed > 0 ? parsed : 1;
}
Comment thread app/tutoring/page.tsx
Comment on lines +11 to +13
import { createI18nStore, loadSSRLanguage } from '@/i18n';
import { Pager } from '@/components/ui/mobx-restful-shadcn/pager';
import { parsePage } from '@/lib/pagination';
Comment thread app/restaurants/page.tsx
Comment on lines +5 to +9
import { createI18nStore, loadSSRLanguage } from '@/i18n';
import FoodAIDialog from '@/components/FoodAIDialog';
import SafeTranslation from '@/components/SafeTranslation';
import { Pager } from '@/components/ui/mobx-restful-shadcn/pager';
import { fetchBitesCatalog, BitesRestaurant } from '@/lib/bitesCatalog';
import { parsePage } from '@/lib/pagination';
Comment thread app/activities/page.tsx
Comment on lines +6 to +10
import { createI18nStore, loadSSRLanguage } from '@/i18n';
import { EventCard } from '@/components/EventCard';
import { FilterBar } from '@/components/FilterBar';
import { GitCodeIcon } from '@/components/icons/GitCodeIcon';
import { GitHubIcon } from '@/components/icons/GitHubIcon';

import { DeadlineItem, EventData } from '@/lib/data';
import { useEventStore } from '@/lib/store';
import Fuse from 'fuse.js';

import { DateTime } from 'luxon';
import Link from 'next/link';
import { useEffect, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { Pager } from '@/components/ui/mobx-restful-shadcn/pager';
Comment thread app/activities/page.tsx Outdated
Comment on lines +161 to +165
<div className="bg-white/80 backdrop-blur-sm rounded-xl p-6 shadow-lg border border-white/20 mb-8">
<FilterBar />
<form action="/activities" method="get" className="flex gap-3">
<input
type="text"
name="query"
Comment thread package.json
Comment on lines 13 to 15
"start": "next start",
"test": "next typegen && lint-staged && tsc --noEmit",
"test": "next typegen && lint-staged && git add . && tsc --noEmit",
"knip": "knip",
Comment thread components.json
Comment on lines +6 to +8
"registries": {
"@mobx-restful-shadcn": "https://mobx-restful-shadcn.idea2.app/r/{name}.json"
},
Comment thread i18n/index.ts Outdated
Comment on lines +11 to +15
const i18nData = {
'zh-CN': zhCN,
'zh-TW': () => import('./zh-TW'),
'en-US': () => import('./en-US'),
};
Comment thread i18n/index.ts

@TechQuery TechQuery left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

完全使用 mobx-i18n 替代 i18next

Copilot AI requested a review from TechQuery June 13, 2026 21:22
@TechQuery

Copy link
Copy Markdown
Member

@copilot 完全使用 mobx-i18n 替代 i18next

Copilot AI commented Jun 13, 2026

Copy link
Copy Markdown
Contributor Author

@copilot 完全使用 mobx-i18n 替代 i18next

已在 822f0a4 完成替换:移除了剩余的 i18next / react-i18next 代码与依赖,统一改为 mobx-i18n,并补齐了当前分页组件路径。npm run buildnpm run test 已通过。

Copilot AI changed the title SEO: server-render list pages, GET-based search, URL pagination (size=10), and SSR locale fallback SEO: server-render list pages, GET-based search, URL pagination (size=10), SSR locale fallback, and MobX i18n unification Jun 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

对 GoodActionHub 进行 SEO

3 participants