[refactor] redesign & rewrite Hackathon home page#59
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthrough重构并类型化 hackathon 详情页:建立 FormGroup 模型、重做 hero 与入口(主/次表单 CTA 与 Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
TechQuery
left a comment
There was a problem hiding this comment.
做就做通用的,把你的新设计融入到现有页面。我不接受为某次活动做专页,那样整个代码库就乱了去了。
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
pages/hackathon/[id].tsx (1)
70-90: 别把“泛化”又收回成四个硬编码分组
FormGroupKey和FormButtonBar仍然把可展示表单白名单锁死为这四类。只要databaseSchema.forms里出现新的公开分组,这里就会被静默忽略,页面入口也不会显示。既然这次目标是按 schema 驱动页面,建议按实际formskey 迭代,再让FormSectionMeta只做已知分组的展示覆写。Also applies to: 132-139
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@pages/hackathon/`[id].tsx around lines 70 - 90, FormButtonBar and FormGroupKey are hardcoded to four groups, so change the rendering to derive available form groups from the runtime schema (databaseSchema.forms) instead of the fixed FormGroupKey/FormButtonBar list: iterate Object.keys(databaseSchema.forms) (or the schema's forms map) to build the list of FormGroup entries used by the UI and the button bar, and keep FormSectionMeta only as an optional override map for known keys (use it when a key matches, otherwise use schema-provided title/description). Update any code referencing FormButtonBar/FormGroupKey (including the code that builds form sections and the logic currently relying on those constants) to consume the dynamically generated keys so new public groups appear automatically.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@pages/hackathon/`[id].tsx:
- Around line 92-113: FormSectionMeta and other hardcoded user-facing strings
(e.g., CTA texts, "Agenda Preview", "Action Hub · Forms", step labels) bypass
i18n; replace the literal strings with translation keys in the data objects
(keep keys like FormSectionMeta.Person.eyebrow, .title, .description) and update
the rendering components to call t() when displaying these fields (e.g., map
over FormSectionMeta entries and pass t(meta.title) / t(meta.description) to the
UI), and similarly change CTA, Agenda Preview, Action Hub · Forms and Step label
sources to store keys and use t() in their components so all UI text goes
through i18n.
- Around line 164-171: 将页面中原生 span/div 切换为 React Bootstrap 组件以保持样式一致:在使用
styles.heroTag 的位置(activityType 和 hostTags 渲染处)用 <Badge> 替代 <span
className={styles.heroTag}> 并保留 key 和内容;将渲染 stat chip 的区域(使用 styles.statChip
的地方)改用 <Stack>(或用 React Bootstrap 的水平 Stack)包裹多个 <Badge> 并保持原有类名/样式映射;将
heroVisualList/Item 列表(styles.heroVisualList 和 styles.heroVisualListItem)改用
<ListGroup> 和 <ListGroup.Item>(或等价的 Card/List 组件)来渲染每一项。别忘了在文件顶部从
react-bootstrap 导入 Badge、Stack、ListGroup,并保留现有 key/props 和可访问性属性。
- Around line 273-297: Change the step cards container from a plain Row/Col
mapping to an ordered list by rendering the Row as an <ol> with className
"list-unstyled" and rendering each Col as an <li> so screen readers get proper
counting; specifically, update the JSX where formGroups is mapped (symbols:
formGroups, Row, Col, Card) to use Row as="ol" className="list-unstyled mt-4
g-3" (preserve md={2} xl={4}) and Col as="li" (keep key={key}), leaving Card and
its children unchanged so layout and styles remain identical while providing
correct <ol>/<li> semantics.
---
Nitpick comments:
In `@pages/hackathon/`[id].tsx:
- Around line 70-90: FormButtonBar and FormGroupKey are hardcoded to four
groups, so change the rendering to derive available form groups from the runtime
schema (databaseSchema.forms) instead of the fixed FormGroupKey/FormButtonBar
list: iterate Object.keys(databaseSchema.forms) (or the schema's forms map) to
build the list of FormGroup entries used by the UI and the button bar, and keep
FormSectionMeta only as an optional override map for known keys (use it when a
key matches, otherwise use schema-provided title/description). Update any code
referencing FormButtonBar/FormGroupKey (including the code that builds form
sections and the logic currently relying on those constants) to consume the
dynamically generated keys so new public groups appear automatically.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 70bd4d76-de5f-4139-869d-775b6b32051d
⛔ Files ignored due to path filters (1)
styles/Hackathon.module.lessis excluded by none and included by none
📒 Files selected for processing (1)
pages/hackathon/[id].tsx
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
pages/hackathon/[id].tsx (1)
401-404:⚠️ Potential issue | 🟡 Minor
members可能为undefined,需添加空值保护根据
ProjectModel.extractFields的实现,members字段经过?.map()处理后可能返回undefined。当前代码直接断言为string[]并调用.join(),若members为空会导致运行时错误。🐛 建议修改
<div className="text-white-50 small"> - <strong>{t('members')}:</strong> {(members as string[]).join(', ')} + <strong>{t('members')}:</strong> {(members as string[] | undefined)?.join(', ') || '-'} </div>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@pages/hackathon/`[id].tsx around lines 401 - 404, The code renders members with a direct cast and .join() which can throw if members is undefined; update the render in the component that uses the members variable (from ProjectModel.extractFields) to guard against undefined by using a safe default or conditional rendering—e.g., treat members as (members ?? []) before calling .join(', ') or render a fallback like "—" when members is falsy; locate the usage where members is cast to string[] and replace it with a null-safe expression or an if-check to prevent runtime errors.
🧹 Nitpick comments (1)
pages/hackathon/[id].tsx (1)
73-73: 移除冗余类型别名,直接使用TableFormView
FormLink只是TableFormView的别名,增加了不必要的间接层。按照之前的 review 建议,应直接使用TableFormView。♻️ 建议修改
-type FormLink = TableFormView; - interface FormGroupMeta { description: I18nKey; eyebrow: I18nKey; title: I18nKey; } interface FormGroup { key: FormGroupKey; - list: FormLink[]; + list: TableFormView[]; meta: FormGroupMeta; }同时更新
isPublicForm函数签名:-const isPublicForm = ({ shared, shared_limit }: FormLink) => +const isPublicForm = ({ shared, shared_limit }: TableFormView) => shared || ['tenant_editable', 'anyone_editable'].includes(shared_limit as string);以及
forms变量类型:const forms = (((databaseSchema as BiTableSchema).forms || {}) as Partial< - Record<FormGroupKey, FormLink[]> + Record<FormGroupKey, TableFormView[]> >)!;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@pages/hackathon/`[id].tsx at line 73, Remove the redundant type alias FormLink and use TableFormView directly: delete the declaration "type FormLink = TableFormView" and update all references — including the isPublicForm function signature (replace any parameter or return types that use FormLink with TableFormView) and the forms variable type (use TableFormView[] or ReadonlyArray<TableFormView> as appropriate). Ensure imports/types still resolve and run type-checking to catch any remaining FormLink occurrences to replace.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@pages/hackathon/`[id].tsx:
- Around line 401-404: The code renders members with a direct cast and .join()
which can throw if members is undefined; update the render in the component that
uses the members variable (from ProjectModel.extractFields) to guard against
undefined by using a safe default or conditional rendering—e.g., treat members
as (members ?? []) before calling .join(', ') or render a fallback like "—" when
members is falsy; locate the usage where members is cast to string[] and replace
it with a null-safe expression or an if-check to prevent runtime errors.
---
Nitpick comments:
In `@pages/hackathon/`[id].tsx:
- Line 73: Remove the redundant type alias FormLink and use TableFormView
directly: delete the declaration "type FormLink = TableFormView" and update all
references — including the isPublicForm function signature (replace any
parameter or return types that use FormLink with TableFormView) and the forms
variable type (use TableFormView[] or ReadonlyArray<TableFormView> as
appropriate). Ensure imports/types still resolve and run type-checking to catch
any remaining FormLink occurrences to replace.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 1c4562ce-9328-4863-9cc3-2c9fc2d78fed
⛔ Files ignored due to path filters (4)
styles/Hackathon.module.lessis excluded by none and included by nonetranslation/en-US.tsis excluded by none and included by nonetranslation/zh-CN.tsis excluded by none and included by nonetranslation/zh-TW.tsis excluded by none and included by none
📒 Files selected for processing (1)
pages/hackathon/[id].tsx
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@pages/hackathon/`[id].tsx:
- Around line 460-462: The JSX renders {score as number} inside the score circle
but score can be undefined; change the rendering in the component that uses
score (the element with className={styles.scoreCircle}) to use a safe fallback
like (score ?? 0) or a placeholder string (e.g., "—") so it never renders
undefined, and ensure any numeric formatting (e.g., Math.round or toFixed) is
applied after the nullish coalescing.
- Around line 138-140: The code accesses databaseSchema.forms directly which can
throw if databaseSchema is undefined; update the extraction of forms (the line
using (databaseSchema as BiTableSchema).forms) to use optional chaining and a
safe default (e.g., treat forms as ((databaseSchema as BiTableSchema)?.forms ??
{}) cast to Partial<Record<FormGroupKey, TableFormView[]>>) so forms is always a
defined object; ensure this change references the same identifiers
(databaseSchema, BiTableSchema, forms, FormGroupKey, TableFormView) so
downstream code still compiles.
- Line 43: The code unconditionally destructures const { appId, tableIdMap } =
activity.databaseSchema as BiTableSchema; but activity.databaseSchema can be
null/undefined; update the handler in pages/hackathon/[id].tsx to defensively
check activity.databaseSchema (or use optional chaining) before destructuring—if
it's missing, return a 404 response (or render the not-found path) instead of
proceeding; reference the activity.databaseSchema and BiTableSchema usage and
ensure any downstream code that expects appId/tableIdMap only runs after the
existence check.
- Line 369: The Agenda.type field is currently a generic TableCellValue and may
produce unexpected class names; update the Agenda type in models/Hackathon.ts to
a string union of the five allowed values ("formation" | "enrollment" |
"competition" | "break" | "evaluation") so TypeScript enforces valid values,
then replace the direct indexing in pages/hackathon/[id].tsx (the expression
styles[type?.toString().toLowerCase() || "break"]) with a defensive mapping or
type-guard: create a const record/map of allowedClassNames keyed by the union
and look up the normalized type via a narrow function (or check against the
union keys) and fall back to "break" for any out-of-spec value, ensuring no
undefined className is applied.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 07f1f8a4-4e6b-459a-a14d-00892aa27867
⛔ Files ignored due to path filters (1)
styles/Hackathon.module.lessis excluded by none and included by none
📒 Files selected for processing (1)
pages/hackathon/[id].tsx
pages/hackathon/[id].tsx
Outdated
| {agenda.map(({ name, type, summary, startedAt, endedAt }) => ( | ||
| <li | ||
| key={name as string} | ||
| className={`${styles.agendaItem} ${styles[type?.toString().toLowerCase() || "break"]}`} |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# 检查 Hackathon.module.less 中定义的 agendaItem 相关样式类
rg -n "agendaItem|\.break|\.session|\.keynote|\.workshop" styles/Hackathon.module.lessRepository: Open-Source-Bazaar/Open-Source-Bazaar.github.io
Length of output: 124
🏁 Script executed:
# 查看 Hackathon.module.less 中 agendaItem 及其嵌套样式的完整定义
sed -n '238,300p' styles/Hackathon.module.lessRepository: Open-Source-Bazaar/Open-Source-Bazaar.github.io
Length of output: 1477
🏁 Script executed:
# 在页面文件中查找 type 的数据来源和可能的值
rg -n "type" pages/hackathon/\[id\].tsx | head -20Repository: Open-Source-Bazaar/Open-Source-Bazaar.github.io
Length of output: 574
🏁 Script executed:
# 查看整个样式模块中所有的嵌套选择器结构
grep -n "^\s*&\." styles/Hackathon.module.lessRepository: Open-Source-Bazaar/Open-Source-Bazaar.github.io
Length of output: 190
🏁 Script executed:
# 查看 pages/hackathon/[id].tsx 的数据获取逻辑和 type 定义
grep -n "getStaticProps\|agenda\|interface\|type.*=" pages/hackathon/\[id\].tsx | head -30Repository: Open-Source-Bazaar/Open-Source-Bazaar.github.io
Length of output: 1137
🏁 Script executed:
# 查找 agenda 相关的类型定义
rg -n "agenda|ActivityType" pages/hackathon/\[id\].tsx -A 3 -B 1Repository: Open-Source-Bazaar/Open-Source-Bazaar.github.io
Length of output: 2536
🏁 Script executed:
# 查找是否有其他地方定义了所有可能的 type 值
rg -n "formation|enrollment|competition|evaluation" --type tsx --type ts | grep -E "(type|enum|const.*=)" | head -20Repository: Open-Source-Bazaar/Open-Source-Bazaar.github.io
Length of output: 118
🏁 Script executed:
# 查找 Agenda 接口的定义位置
rg -n "interface Agenda|type Agenda" --type ts --type tsxRepository: Open-Source-Bazaar/Open-Source-Bazaar.github.io
Length of output: 118
🏁 Script executed:
# 查找可能的 ActivityModel 或相关类型定义
rg -n "ActivityModel|Activity.*type" --type ts --type tsx | head -20Repository: Open-Source-Bazaar/Open-Source-Bazaar.github.io
Length of output: 118
🏁 Script executed:
# 搜索所有导入,找到 Agenda 的来源
rg -n "^import.*Agenda|from.*agenda" pages/hackathon/\[id\].tsxRepository: Open-Source-Bazaar/Open-Source-Bazaar.github.io
Length of output: 73
🏁 Script executed:
# 不使用 --type 标志,直接搜索 Agenda 接口定义
rg -n "interface Agenda|type Agenda|export.*Agenda" pages/ lib/ models/ types/ 2>/dev/null | head -20Repository: Open-Source-Bazaar/Open-Source-Bazaar.github.io
Length of output: 225
🏁 Script executed:
# 查找页面文件的导入语句
head -50 pages/hackathon/\[id\].tsx | grep -n "import"Repository: Open-Source-Bazaar/Open-Source-Bazaar.github.io
Length of output: 905
🏁 Script executed:
# 搜索 ActivityModel 相关的类型
rg -n "ActivityModel|class Activity" . 2>/dev/null | head -10Repository: Open-Source-Bazaar/Open-Source-Bazaar.github.io
Length of output: 1020
🏁 Script executed:
# 在整个仓库中搜索 type 字段定义,包含所有可能值
rg -n "formation|enrollment|competition|evaluation" --max-count 30Repository: Open-Source-Bazaar/Open-Source-Bazaar.github.io
Length of output: 1316
🏁 Script executed:
# 查看 models/Hackathon.ts 中 Agenda 接口的完整定义
cat -n models/Hackathon.ts | head -40Repository: Open-Source-Bazaar/Open-Source-Bazaar.github.io
Length of output: 1247
🏁 Script executed:
# 搜索 Agenda 类型定义的具体内容
rg -n -A 10 "export type Agenda" models/Hackathon.tsRepository: Open-Source-Bazaar/Open-Source-Bazaar.github.io
Length of output: 500
动态样式类名缺少类型约束和防御
Agenda 类型定义中,type 字段为通用 TableCellValue 类型,未使用联合类型约束可能的值。代码在 line 369 使用 styles[type?.toString().toLowerCase() || "break"] 时,仅为 falsy 值提供了 "break" 的兜底,但无法处理后端返回超出预期的类型值。
现有 CSS 类仅涵盖 5 种:formation、enrollment、competition、break、evaluation。若后端引入新类型而样式未同步,会导致 undefined 类名被应用。
建议:
- 在
models/Hackathon.ts中为Agenda.type定义联合类型,明确列出所有可能值,利用 TypeScript 强类型 - 增加防御性兜底:使用完整的类型检查或 CSS 类名映射表,确保任何超出预期的值都有默认样式处理
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@pages/hackathon/`[id].tsx at line 369, The Agenda.type field is currently a
generic TableCellValue and may produce unexpected class names; update the Agenda
type in models/Hackathon.ts to a string union of the five allowed values
("formation" | "enrollment" | "competition" | "break" | "evaluation") so
TypeScript enforces valid values, then replace the direct indexing in
pages/hackathon/[id].tsx (the expression styles[type?.toString().toLowerCase()
|| "break"]) with a defensive mapping or type-guard: create a const record/map
of allowedClassNames keyed by the union and look up the normalized type via a
narrow function (or check against the union keys) and fall back to "break" for
any out-of-spec value, ensuring no undefined className is applied.
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
pages/hackathon/[id].tsx (2)
38-46:⚠️ Potential issue | 🔴 Critical
databaseSchema防御性检查不完整,仍会导致运行时错误当前
(activity.databaseSchema || {})的写法在databaseSchema为空时会得到{},解构后appId和tableIdMap均为undefined,传入后续 Model 构造函数会抛出异常。建议在访问前校验并返回 404:
🛡️ 建议修复
const activity = await new ActivityModel().getOne(params!.id); - const { appId, tableIdMap } = (activity.databaseSchema || {}) as BiTableSchema; + const schema = activity.databaseSchema as BiTableSchema | undefined; + if (!schema?.appId || !schema?.tableIdMap) { + return { notFound: true }; + } + const { appId, tableIdMap } = schema; const [people, organizations, agenda, prizes, templates, projects] = await Promise.all([🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@pages/hackathon/`[id].tsx around lines 38 - 46, The code destructures appId and tableIdMap from activity.databaseSchema without validating it so appId/tableIdMap can be undefined and will throw when used to construct models (PersonModel, OrganizationModel, AgendaModel, PrizeModel, TemplateModel, ProjectModel) and call getAll(); fix by checking activity.databaseSchema is present and matches BiTableSchema (has appId and tableIdMap) before creating the models, and if missing return a 404 response (or throw a NotFound) instead of proceeding.
318-321:⚠️ Potential issue | 🟡 Minor动态样式类名缺少防御性兜底
当
type值不在预定义的 CSS 类名集合(formation、enrollment、competition、break、evaluation)中时,styles[...]返回undefined,导致无效的className。建议使用类名映射表确保安全:
🛡️ 建议修复
+const AgendaTypeStyles = ['formation', 'enrollment', 'competition', 'break', 'evaluation'] as const; +type AgendaStyleKey = (typeof AgendaTypeStyles)[number]; + +const getAgendaStyle = (type: unknown): AgendaStyleKey => { + const normalized = type?.toString().toLowerCase() as AgendaStyleKey; + return AgendaTypeStyles.includes(normalized) ? normalized : 'break'; +}; // 在 render 中使用: -className={`${styles.agendaItem} ${styles[type?.toString().toLowerCase() || 'break']}`} +className={`${styles.agendaItem} ${styles[getAgendaStyle(type)]}`}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@pages/hackathon/`[id].tsx around lines 318 - 321, 在渲染 agenda 列表时动态访问样式(styles[type?.toString().toLowerCase() || 'break'])在 type 不在预期集合时会返回 undefined;为修复,在使用 agenda.map 的渲染处引入一个安全的类名映射(例如 const TYPE_CLASS_MAP = { formation: styles.formation, enrollment: styles.enrollment, competition: styles.competition, break: styles.break, evaluation: styles.evaluation }),然后用 lookup = TYPE_CLASS_MAP[(type?.toString().toLowerCase() ?? '')] || styles.break(或其他默认类)代替直接索引,保持现有 styles.agendaItem 串联,从而保证 className 始终有效且有兜底样式。
♻️ Duplicate comments (1)
pages/hackathon/[id].tsx (1)
389-389:⚠️ Potential issue | 🟡 Minor
score可能为undefined,需要增加兜底显示当项目没有评分时,直接渲染
{score as number}会显示空白或undefined。建议增加兜底值:-<div className={styles.scoreCircle}>{score as number}</div> +<div className={styles.scoreCircle}>{(score as number) ?? '-'}</div>,
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@pages/hackathon/`[id].tsx at line 389, The score value can be undefined and currently renders as `{score as number}`; update the rendering inside the div with className `styles.scoreCircle` to use a safe fallback (e.g. `score ?? 0` or a display string like `'—'`) so an explicit default is shown when score is missing; change the expression from casting to a nullish-coalescing or conditional expression (refer to the `score` variable and the `styles.scoreCircle` div) to ensure a predictable fallback display.
🧹 Nitpick comments (2)
pages/api/Lark/document/copy/[...slug].ts (2)
16-19: 可选:简化冗余的类型断言当前三元表达式中
type === 'wiki'的判断与类型断言as 'wiki'/as LarkDocumentPathType重复。由于copyFile方法签名可能已经处理了这两种情况,可以考虑简化:♻️ 简化建议
- const copiedFile = - type === 'wiki' - ? await lark.copyFile(`${type as 'wiki'}/${id}`, name, parentToken) - : await lark.copyFile(`${type as LarkDocumentPathType}/${id}`, name, parentToken); + const copiedFile = await lark.copyFile( + `${type as LarkDocumentPathType | 'wiki'}/${id}`, + name, + parentToken, + );如果
mobx-lark的类型定义要求区分处理,则保持现状即可。🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@pages/api/Lark/document/copy/`[...slug].ts around lines 16 - 19, The ternary uses redundant type assertions when calling lark.copyFile: remove the duplicated casts and pass the same constructed path string for both branches (use `${type}/${id}`) or, if the library requires a specific union type, narrow `type` once before the call (e.g., ensure `type` has the correct union/LarkDocumentPathType) and then call lark.copyFile(path, name, parentToken) without per-branch `as` assertions; update the code around the copiedFile assignment and lark.copyFile invocation to use the simplified single call and keep id, name, parentToken unchanged.
23-31: 所有权转移失败处理方式可接受,但建议增强日志当前
transferOwner失败时仅打印错误日志,不影响主流程返回。这种"尽力而为"的模式是合理的,但建议在日志中增加上下文信息(如type、newId),便于后续排查:♻️ 增强日志建议
} catch (error) { - console.error(JSON.stringify(error, null, 2)); + console.error('transferOwner failed:', { type, newId, ownerType, ownerId, error }); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@pages/api/Lark/document/copy/`[...slug].ts around lines 23 - 31, When transferOwner fails in the block calling lark.driveFileStore.transferOwner(type, newId, { member_type: ownerType, member_id: ownerId }), enhance the catch to log contextual info (type and newId and ownerType/ownerId) along with the error so failures are diagnosable; update the catch for the transferOwner call to include a descriptive message and the relevant identifiers (type, newId, ownerType, ownerId) plus the error object instead of only JSON.stringify(error).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@pages/api/Lark/document/copy/`[...slug].ts:
- Line 21: newId currently falls back to a non-existent copiedFile.node_token;
change logic to use copiedFile.token directly (remove the 'token' in copiedFile
? ... : copiedFile.node_token fallback) because CopiedFile only exposes token;
if you actually need a WikiNode (node_token) instead, first call
WikiNodeModel.moveDocument({ obj_type, obj_token }, ...) to mount the doc into
Wiki and obtain a WikiNode, then use that node's node_token—update references to
copiedFile and newId accordingly and remove any assumptions about node_token on
CopiedFile.
In `@pages/hackathon/`[id].tsx:
- Around line 122-125: The destructuring const { forms } = (databaseSchema ||
{}) as BiTableSchema can leave forms undefined and cause forms[key] to throw;
update the code to provide a safe default (e.g., const { forms = {} } =
(databaseSchema || {}) as BiTableSchema) or use optional chaining/fallback when
accessing forms (e.g., (forms?.[key] || []) ) inside the FormButtonBar.flatMap
callback so FormButtonBar, formGroups and isPublicForm logic never attempt to
index into undefined.
---
Outside diff comments:
In `@pages/hackathon/`[id].tsx:
- Around line 38-46: The code destructures appId and tableIdMap from
activity.databaseSchema without validating it so appId/tableIdMap can be
undefined and will throw when used to construct models (PersonModel,
OrganizationModel, AgendaModel, PrizeModel, TemplateModel, ProjectModel) and
call getAll(); fix by checking activity.databaseSchema is present and matches
BiTableSchema (has appId and tableIdMap) before creating the models, and if
missing return a 404 response (or throw a NotFound) instead of proceeding.
- Around line 318-321: 在渲染 agenda
列表时动态访问样式(styles[type?.toString().toLowerCase() || 'break'])在 type 不在预期集合时会返回
undefined;为修复,在使用 agenda.map 的渲染处引入一个安全的类名映射(例如 const TYPE_CLASS_MAP = {
formation: styles.formation, enrollment: styles.enrollment, competition:
styles.competition, break: styles.break, evaluation: styles.evaluation }),然后用
lookup = TYPE_CLASS_MAP[(type?.toString().toLowerCase() ?? '')] ||
styles.break(或其他默认类)代替直接索引,保持现有 styles.agendaItem 串联,从而保证 className 始终有效且有兜底样式。
---
Duplicate comments:
In `@pages/hackathon/`[id].tsx:
- Line 389: The score value can be undefined and currently renders as `{score as
number}`; update the rendering inside the div with className
`styles.scoreCircle` to use a safe fallback (e.g. `score ?? 0` or a display
string like `'—'`) so an explicit default is shown when score is missing; change
the expression from casting to a nullish-coalescing or conditional expression
(refer to the `score` variable and the `styles.scoreCircle` div) to ensure a
predictable fallback display.
---
Nitpick comments:
In `@pages/api/Lark/document/copy/`[...slug].ts:
- Around line 16-19: The ternary uses redundant type assertions when calling
lark.copyFile: remove the duplicated casts and pass the same constructed path
string for both branches (use `${type}/${id}`) or, if the library requires a
specific union type, narrow `type` once before the call (e.g., ensure `type` has
the correct union/LarkDocumentPathType) and then call lark.copyFile(path, name,
parentToken) without per-branch `as` assertions; update the code around the
copiedFile assignment and lark.copyFile invocation to use the simplified single
call and keep id, name, parentToken unchanged.
- Around line 23-31: When transferOwner fails in the block calling
lark.driveFileStore.transferOwner(type, newId, { member_type: ownerType,
member_id: ownerId }), enhance the catch to log contextual info (type and newId
and ownerType/ownerId) along with the error so failures are diagnosable; update
the catch for the transferOwner call to include a descriptive message and the
relevant identifiers (type, newId, ownerType, ownerId) plus the error object
instead of only JSON.stringify(error).
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: a38f5fa5-e9d2-46d5-ae97-5eee6d660871
⛔ Files ignored due to path filters (1)
styles/Hackathon.module.lessis excluded by none and included by none
📒 Files selected for processing (2)
pages/api/Lark/document/copy/[...slug].tspages/hackathon/[id].tsx
TechQuery
left a comment
There was a problem hiding this comment.
重写 pages/hackathon/[id].tsx 的 JSX 结构:
- 结构与样式:https://github.com/lichang333/niuma-hackthon-2026/blob/3e8004241167ae4ed5d4d4151cea0e1a32c87760/docs/index.html
- 数据沿用页面现有数据
- 文案尽量沿用现有 i18n 数据,没有的再翻译
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@pages/hackathon/`[id].tsx:
- Around line 648-650: The string "PHASE" is hard-coded in the span with
className styles.dayNo; replace it with the i18n translator call (e.g.,
t('hackathon_phase')) so the label is localized, ensuring the component
imports/uses the t() from your i18n hook/context (where applicable) and preserve
the numeric formatting String(index + 1).padStart(2, "0"); also add the key
hackathon_phase to translation files (zh-CN.ts, en-US.ts, zh-TW.ts) with the
suggested values.
- Around line 879-890: The rendering assumes languages and tags are always
defined; to prevent runtime errors replace the direct casts and .map calls with
defensive checks (e.g., use nullish coalescing or optional chaining) so the
component maps over an empty array when values are undefined; update the JSX
around languages and tags (the expressions producing the list items using
languages and tags, and the ul with styles.topicList/topicChip/topicChipMuted)
to use (languages ?? []) and (tags ?? []) or languages?.map(...) || [] so
mapping only happens on arrays.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 18a63c55-e30e-4474-9d8c-5d53992ffcaf
⛔ Files ignored due to path filters (1)
styles/Hackathon.module.lessis excluded by none and included by none
📒 Files selected for processing (1)
pages/hackathon/[id].tsx
TechQuery
left a comment
There was a problem hiding this comment.
同类问题通篇都该,CSS 要跟着组件创建同名 .module.less。
[fix] some CodeX bugs
What changed
/hackathon/[id]page (closes 重新设计并开发【开源黑客松】飞书版主页 #60)activity.databaseSchema.forms, so different activities can reuse the same layout without route-specific branchesWhy
TechQuery asked that the redesign be made generic instead of adding a one-off page for a single event. This update keeps the current data model and applies the new presentation layer to the shared hackathon detail page.
Impact
Activityand its configured tablesValidation
git diff --cached --checkpages/hackathon/[id].tsxwith esbuildpages/hackathon/[id]/team/[tid].tsxwith esbuildtscremain blocked locally because@open-source-bazaar/china-ngo-databasecould not be fetched from GitHub Packages with the current token permissionsSummary by CodeRabbit
新功能
修复