Skip to content

feat: display multi organization in event detail#304

Merged
PaiJi merged 4 commits intomainfrom
feat/support-multi-org
Apr 22, 2026
Merged

feat: display multi organization in event detail#304
PaiJi merged 4 commits intomainfrom
feat/support-multi-org

Conversation

@PaiJi
Copy link
Copy Markdown
Member

@PaiJi PaiJi commented Apr 22, 2026

Summary by CodeRabbit

发布说明

  • 新功能

    • 事件页面现支持多个主办组织的显示和切换
  • 本地化支持

    • 为主办组织切换功能新增英文、俄文、简体中文和繁体中文本地化
  • 基础设施

    • 更新构建工作流依赖版本

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 22, 2026

Warning

Rate limit exceeded

@PaiJi has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 33 minutes and 47 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 33 minutes and 47 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ac4aeb67-8985-4e0a-ab10-91dc8e841881

📥 Commits

Reviewing files that changed from the base of the PR and between 6026235 and 18d5ceb.

📒 Files selected for processing (6)
  • public/locales/en/common.json
  • public/locales/ru/common.json
  • public/locales/zh-Hans/common.json
  • public/locales/zh-Hant/common.json
  • src/components/event/EventOrganizationCard.tsx
  • src/pages/[organization]/[slug].tsx
📝 Walkthrough

总览

本PR为事件页面引入多个主办组织的支持,包括一个新的组织卡片组件以及相应的多语言UI文本(支持英文、俄文、简体中文和繁体中文),同时更新GitHub Actions工作流中的Docker工具版本。

变更

衍合体 / 文件 总结
GitHub Actions 工作流版本更新
.github/workflows/deploy-prod-cn.yml, .github/workflows/reusable-docker-build.yml
升级Docker相关的GitHub Actions:docker/login-action 从v3升至v4;docker/setup-buildx-action 从v3升至v4;docker/build-push-action 从v6升至v7。
多语言本地化支持
public/locales/en/common.json, public/locales/ru/common.json, public/locales/zh-Hans/common.json, public/locales/zh-Hant/common.json
新增三个事件相关的翻译键值:event.hostSwitchGroupAriaevent.prevHostOrganizationevent.nextHostOrganization,用于支持主办组织切换UI。
事件组织卡片组件和页面重构
src/components/event/EventOrganizationCard.tsx, src/pages/[organization]/[slug].tsx
新增 EventOrganizationCard 组件,用于展示事件的多个主办组织,支持通过前后按钮循环切换;页面中的组织面板UI从内联实现重构为使用该新组件。
事件类型定义扩展
src/types/event.ts
EventSchema 中新增 organizations 属性,定义为 OrganizationSchema 数组,用于支持多个主办组织。

预期代码审查工作量

🎯 3 (Moderate) | ⏱️ ~25 minutes

可能相关的PR

诗歌

🐰 主办组织多声俱鸣,
三两按钮轻轻切换,
国际语言齐声唱和,
事件页面更显风采!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 标题准确概括了主要变更:添加了多组织支持在事件详情页面中,与所有代码修改高度对应。
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/support-multi-org

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown

📦 Next.js Bundle Analysis for furrycons-site

This analysis was generated by the Next.js Bundle Analysis action. 🤖

⚠️ Global Bundle Size Increased

Page Size (compressed)
global 356.46 KB (🟡 +210 B)
Details

The global bundle is the javascript bundle that loads alongside every page. It is in its own category because its impact is much higher - an increase to its size means that every page on your website loads slower, and a decrease means every page loads faster.

Any third party scripts you have added directly to your app using the <script> tag are not accounted for in this analysis

If you want further insight into what is behind the changes, give @next/bundle-analyzer a try!

One Page Changed Size

The following page changed size from the code in this PR compared to its base branch:

Page Size (compressed) First Load % of Budget (350 KB)
/[organization]/[slug] 12.62 KB 369.07 KB 105.45% (🟡 +0.13%)
Details

Only the gzipped size is provided here based on an expert tip.

First Load is the size of the global bundle plus the bundle for the individual page. If a user were to show up to your website and land on a given page, the first load size represents the amount of javascript that user would need to download. If next/link is used, subsequent page loads would only need to download that page's bundle (the number in the "Size" column), since the global bundle has already been downloaded.

Any third party scripts you have added directly to your app using the <script> tag are not accounted for in this analysis

The "Budget %" column shows what percentage of your performance budget the First Load total takes up. For example, if your budget was 100kb, and a given page's first load size was 10kb, it would be 10% of your budget. You can also see how much this has increased or decreased compared to the base branch of your PR. If this percentage has increased by 20% or more, there will be a red status indicator applied, indicating that special attention should be given to this. If you see "+/- <0.01%" it means that there was a change in bundle size, but it is a trivial enough amount that it can be ignored.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 8

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/deploy-prod-cn.yml (1)

1-62: ⚠️ Potential issue | 🟠 Major

PR 标题与实际变更内容不一致。

PR 标题为 "feat: display multi organization in event detail"(功能:在活动详情中显示多个组织),但实际的代码变更仅包含 CI/CD 工作流中 Docker GitHub Actions 的版本升级。这两个文件中的所有变更都是基础设施相关的依赖项升级,与多组织显示功能或活动详情无关。

请确认:

  1. 是否推送了错误的分支?
  2. 是否缺少实现多组织显示功能的代码文件?
  3. 或者 PR 标题/描述是否需要更新以反映实际的变更内容(例如:"chore: upgrade Docker GitHub Actions versions")?
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/deploy-prod-cn.yml around lines 1 - 62, PR title "feat:
display multi organization in event detail" doesn't match the changes (only CI
workflow updates: jobs build-image, docker-smoke, push-and-notify and steps like
"Login to Qcloud Hongkong Container Registry" and "Push tags"); either update
the PR title/body to accurately describe this chore (e.g., "chore: upgrade
Docker GitHub Actions versions / update CI workflows") or add the missing
feature commits that implement the multi-organization display (ensure you
include the relevant frontend/backend files and mention the feature-specific
functions/components in the commit), and verify you pushed the correct branch
before merging.
🧹 Nitpick comments (1)
src/components/event/EventOrganizationCard.tsx (1)

60-75: 切换按钮在 orgList.length <= 1 时是死代码,但仍建议禁用状态处理以防边界情况。

当前通过 showOrgSwitcher 控制整体显示,逻辑正确。可选建议:为 prev/next 按钮添加 disabled 状态或当 orgList.length === 1 时不渲染按钮组(已做),并考虑键盘左右方向键快捷切换以提升可访问性。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/event/EventOrganizationCard.tsx` around lines 60 - 75, The
prev/next buttons in EventOrganizationCard are effectively dead when
orgList.length <= 1 but lack explicit disabled state and keyboard support;
update the rendering of the IoChevronBack/IoChevronForward buttons (the elements
using onClick handlers goToPrev and goToNext) to include a disabled attribute
and appropriate aria-disabled when orgList.length <= 1, add a visual disabled
style class to match existing styles, and wire a keyboard handler on the parent
(or the component) to call goToPrev/goToNext on ArrowLeft/ArrowRight so keyboard
users can switch organizations; keep the existing showOrgSwitcher guard but
ensure the disabled state and aria attributes are present for accessibility.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/deploy-prod-cn.yml:
- Line 48: The workflow currently references docker/login-action@v4; before
upgrading, verify your self-hosted/production runners meet the Node24/Actions
Runner v2.327.1+ requirement, test the login step end-to-end against your
registries (ECR, Docker Hub, etc.), and validate that any custom
scripts/extensions tolerate the action's ESM migration; also check compatibility
of updated dependencies (`@actions/core` -> 3.0.0 and `@docker/actions-toolkit` ->
0.77.0) or pin to a prior minor version of docker/login-action if your
environment cannot be upgraded yet.

In @.github/workflows/reusable-docker-build.yml:
- Line 50: The workflow now references docker/build-push-action@v7 which
introduced breaking changes (Node 24 requirement, removed env vars
DOCKER_BUILD_NO_SUMMARY and DOCKER_BUILD_EXPORT_RETENTION_DAYS, ESM migration,
and dependency upgrades); to fix, either pin the action to the last v6 release
or update the repository to meet v7 requirements: ensure your Actions Runner is
>= v2.327.1, remove/replace any usage of DOCKER_BUILD_NO_SUMMARY and
DOCKER_BUILD_EXPORT_RETENTION_DAYS with DOCKER_BUILD_SUMMARY=false, test and
adapt any code that relies on CommonJS to the action’s ESM behavior, and
validate any integrations that depended on previous
`@actions/core/`@docker/actions-toolkit behavior before switching to
docker/build-push-action@v7.

In `@src/components/event/EventOrganizationCard.tsx`:
- Around line 94-118: The two Link components that both navigate to
`/${organization.slug}` are inconsistent: remove the target="_blank" from the
top Link so both open in the same tab, and move the analytics call from the
inner button to the outer Link's onClick (so tracking always fires) — update the
Link wrapping the button to add onClick={() => sendTrack({...})} and keep the
button as a plain element; if you decide to keep opening in a new tab instead,
apply target="_blank" and rel="noopener noreferrer" to both Links instead;
adjust usages of Link, sendTrack, organization.slug, OrganizationStatus and t
accordingly.
- Around line 52-54: The hard-coded Chinese label in EventOrganizationCard
(inside the JSX branch guarded by showOrgSwitcher) should be replaced with a
i18n lookup: add a translation key event.hostSwitchIndex (with placeholders like
{{current}} and {{total}}) to each of the four common.json locale files, then
call t('event.hostSwitchIndex', { current: activeIndex + 1, total:
orgList.length }) in the component instead of the literal string so the
component uses localized text; keep the same JSX structure and import/use the
existing t() from your i18n hook/context.
- Around line 29-33: orgList can contain duplicates and undefined, and
organization uses a non-null assertion that can still be undefined; fix by
building orgList from props.event.organization and props.event.organizations
after filtering out null/undefined and deduplicating by a stable key (slug or
id), e.g., dedupe by slug/id, then set showOrgSwitcher = dedupedList.length > 1,
compute organization = dedupedList[activeIndex] ?? dedupedList[0] (without using
!) and ensure activeIndex is clamped/reset to 0 if it is out of bounds after
dedupe; if dedupedList is empty, return early (or render a safe placeholder) to
avoid accessing organization.logoUrl/slug.
- Line 84: The alt text in the EventOrganizationCard is hardcoded as
`${organization.name}'s logo`; change it to use the existing i18n key
organization.logoAlt instead — call the translation function (e.g., t or i18n.t)
inside EventOrganizationCard to produce the alt value and pass organization.name
as the name variable (e.g., t('organization.logoAlt', { name: organization.name
})), then set alt to that translated string so localized punctuation/wording is
used.

In `@src/pages/`[organization]/[slug].tsx:
- Around line 74-78: The host display currently concatenates names with a
hard-coded Chinese delimiter and may duplicate event.organization if it's also
present in event.organizations; update the rendering in the component that calls
t("event.hostBy", ...) to (1) build the hostName using Intl.ListFormat (fallback
to locale-appropriate separator) instead of the literal "、" so it localizes for
en/ru/etc., (2) deduplicate names by creating a unique list from
event.organization?.name plus event.organizations.map(o => o.name) before
formatting, and (3) consistently use optional chaining on event.organization
(e.g., event.organization?.name) and guard the whole block so it won’t throw
when organization is missing; pass the formatted, deduped hostName into
t("event.hostBy", { hostName }).

In `@src/types/event.ts`:
- Line 85: EventSchema 将 organizations 定为必填并且使用 EventSchema.parse()
严格校验,这会在后端未对历史事件返回 organizations 时导致 getEventDetail 抛错并触发 404;请将 EventSchema 中的
organizations 字段改为可选(例如从 z.array(OrganizationSchema) 改为
z.array(OrganizationSchema).optional() 或
z.array(...).nullable(),视需返回形态),并更新任何依赖位置(如 EventSchema.parse() 的调用处和
pages/[organization]/[slug].tsx 中对 event.organizations 的访问)以做兼容性处理,或确认并保证后端
internal/website/event/detail 接口对所有事件均返回 organizations 数组后再保留必填约束。

---

Outside diff comments:
In @.github/workflows/deploy-prod-cn.yml:
- Around line 1-62: PR title "feat: display multi organization in event detail"
doesn't match the changes (only CI workflow updates: jobs build-image,
docker-smoke, push-and-notify and steps like "Login to Qcloud Hongkong Container
Registry" and "Push tags"); either update the PR title/body to accurately
describe this chore (e.g., "chore: upgrade Docker GitHub Actions versions /
update CI workflows") or add the missing feature commits that implement the
multi-organization display (ensure you include the relevant frontend/backend
files and mention the feature-specific functions/components in the commit), and
verify you pushed the correct branch before merging.

---

Nitpick comments:
In `@src/components/event/EventOrganizationCard.tsx`:
- Around line 60-75: The prev/next buttons in EventOrganizationCard are
effectively dead when orgList.length <= 1 but lack explicit disabled state and
keyboard support; update the rendering of the IoChevronBack/IoChevronForward
buttons (the elements using onClick handlers goToPrev and goToNext) to include a
disabled attribute and appropriate aria-disabled when orgList.length <= 1, add a
visual disabled style class to match existing styles, and wire a keyboard
handler on the parent (or the component) to call goToPrev/goToNext on
ArrowLeft/ArrowRight so keyboard users can switch organizations; keep the
existing showOrgSwitcher guard but ensure the disabled state and aria attributes
are present for accessibility.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b45edb1d-4990-4ff4-b49d-48c923a2a23a

📥 Commits

Reviewing files that changed from the base of the PR and between 29f01cb and 6026235.

📒 Files selected for processing (9)
  • .github/workflows/deploy-prod-cn.yml
  • .github/workflows/reusable-docker-build.yml
  • public/locales/en/common.json
  • public/locales/ru/common.json
  • public/locales/zh-Hans/common.json
  • public/locales/zh-Hant/common.json
  • src/components/event/EventOrganizationCard.tsx
  • src/pages/[organization]/[slug].tsx
  • src/types/event.ts

Comment thread .github/workflows/deploy-prod-cn.yml
Comment thread .github/workflows/reusable-docker-build.yml
Comment on lines +29 to +33
const orgList = [props.event.organization, ...props.event.organizations];
const [activeIndex, setActiveIndex] = useState(0);
const showOrgSwitcher = orgList.length > 1;

const organization = orgList[activeIndex] ?? orgList[0]!;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

orgList 可能重复且存在空值风险。

  • orgList = [props.event.organization, ...props.event.organizations] 未去重。若后端在 organizations 中已包含主办方本身,切换器会出现相同主办方重复出现的条目。
  • organization = orgList[activeIndex] ?? orgList[0]! 使用了非空断言,但若 event.organization 为空且 event.organizations 为空,orgList[0] 仍为 undefined,下方 organization.logoUrlorganization.slug 等访问将抛错。

建议按 slug/id 去重并对空情形提前返回:

♻️ 建议修改
-  const orgList = [props.event.organization, ...props.event.organizations];
+  const orgList = [props.event.organization, ...(props.event.organizations ?? [])]
+    .filter((o): o is NonNullable<typeof o> => !!o)
+    .filter((o, i, arr) => arr.findIndex((x) => x.slug === o.slug) === i);
+  if (orgList.length === 0) return null;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const orgList = [props.event.organization, ...props.event.organizations];
const [activeIndex, setActiveIndex] = useState(0);
const showOrgSwitcher = orgList.length > 1;
const organization = orgList[activeIndex] ?? orgList[0]!;
const orgList = [props.event.organization, ...(props.event.organizations ?? [])]
.filter((o): o is NonNullable<typeof o> => !!o)
.filter((o, i, arr) => arr.findIndex((x) => x.slug === o.slug) === i);
if (orgList.length === 0) return null;
const [activeIndex, setActiveIndex] = useState(0);
const showOrgSwitcher = orgList.length > 1;
const organization = orgList[activeIndex] ?? orgList[0]!;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/event/EventOrganizationCard.tsx` around lines 29 - 33, orgList
can contain duplicates and undefined, and organization uses a non-null assertion
that can still be undefined; fix by building orgList from
props.event.organization and props.event.organizations after filtering out
null/undefined and deduplicating by a stable key (slug or id), e.g., dedupe by
slug/id, then set showOrgSwitcher = dedupedList.length > 1, compute organization
= dedupedList[activeIndex] ?? dedupedList[0] (without using !) and ensure
activeIndex is clamped/reset to 0 if it is out of bounds after dedupe; if
dedupedList is empty, return early (or render a safe placeholder) to avoid
accessing organization.logoUrl/slug.

Comment thread src/components/event/EventOrganizationCard.tsx Outdated
Comment thread src/components/event/EventOrganizationCard.tsx Outdated
Comment thread src/components/event/EventOrganizationCard.tsx Outdated
Comment thread src/pages/[organization]/[slug].tsx
Comment thread src/types/event.ts
@github-actions
Copy link
Copy Markdown

📦 Next.js Bundle Analysis for furrycons-site

This analysis was generated by the Next.js Bundle Analysis action. 🤖

⚠️ Global Bundle Size Increased

Page Size (compressed)
global 356.46 KB (🟡 +217 B)
Details

The global bundle is the javascript bundle that loads alongside every page. It is in its own category because its impact is much higher - an increase to its size means that every page on your website loads slower, and a decrease means every page loads faster.

Any third party scripts you have added directly to your app using the <script> tag are not accounted for in this analysis

If you want further insight into what is behind the changes, give @next/bundle-analyzer a try!

One Page Changed Size

The following page changed size from the code in this PR compared to its base branch:

Page Size (compressed) First Load % of Budget (350 KB)
/[organization]/[slug] 12.6 KB 369.06 KB 105.45% (🟡 +0.12%)
Details

Only the gzipped size is provided here based on an expert tip.

First Load is the size of the global bundle plus the bundle for the individual page. If a user were to show up to your website and land on a given page, the first load size represents the amount of javascript that user would need to download. If next/link is used, subsequent page loads would only need to download that page's bundle (the number in the "Size" column), since the global bundle has already been downloaded.

Any third party scripts you have added directly to your app using the <script> tag are not accounted for in this analysis

The "Budget %" column shows what percentage of your performance budget the First Load total takes up. For example, if your budget was 100kb, and a given page's first load size was 10kb, it would be 10% of your budget. You can also see how much this has increased or decreased compared to the base branch of your PR. If this percentage has increased by 20% or more, there will be a red status indicator applied, indicating that special attention should be given to this. If you see "+/- <0.01%" it means that there was a change in bundle size, but it is a trivial enough amount that it can be ignored.

@github-actions
Copy link
Copy Markdown

📦 Next.js Bundle Analysis for furrycons-site

This analysis was generated by the Next.js Bundle Analysis action. 🤖

⚠️ Global Bundle Size Increased

Page Size (compressed)
global 356.46 KB (🟡 +212 B)
Details

The global bundle is the javascript bundle that loads alongside every page. It is in its own category because its impact is much higher - an increase to its size means that every page on your website loads slower, and a decrease means every page loads faster.

Any third party scripts you have added directly to your app using the <script> tag are not accounted for in this analysis

If you want further insight into what is behind the changes, give @next/bundle-analyzer a try!

One Page Changed Size

The following page changed size from the code in this PR compared to its base branch:

Page Size (compressed) First Load % of Budget (350 KB)
/[organization]/[slug] 12.6 KB 369.06 KB 105.45% (🟡 +0.12%)
Details

Only the gzipped size is provided here based on an expert tip.

First Load is the size of the global bundle plus the bundle for the individual page. If a user were to show up to your website and land on a given page, the first load size represents the amount of javascript that user would need to download. If next/link is used, subsequent page loads would only need to download that page's bundle (the number in the "Size" column), since the global bundle has already been downloaded.

Any third party scripts you have added directly to your app using the <script> tag are not accounted for in this analysis

The "Budget %" column shows what percentage of your performance budget the First Load total takes up. For example, if your budget was 100kb, and a given page's first load size was 10kb, it would be 10% of your budget. You can also see how much this has increased or decreased compared to the base branch of your PR. If this percentage has increased by 20% or more, there will be a red status indicator applied, indicating that special attention should be given to this. If you see "+/- <0.01%" it means that there was a change in bundle size, but it is a trivial enough amount that it can be ignored.

@PaiJi PaiJi merged commit 720f3ee into main Apr 22, 2026
9 checks passed
@PaiJi PaiJi deleted the feat/support-multi-org branch April 22, 2026 20:08
@coderabbitai coderabbitai Bot mentioned this pull request May 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant