Skip to content

fix(checkin): prevent visual flicker when loading check-in component - #2566

Merged
seefs001 merged 2 commits into
QuantumNous:mainfrom
RedwindA:fix/checkin-frontend-collapse
Jan 3, 2026
Merged

fix(checkin): prevent visual flicker when loading check-in component#2566
seefs001 merged 2 commits into
QuantumNous:mainfrom
RedwindA:fix/checkin-frontend-collapse

Conversation

@RedwindA

@RedwindA RedwindA commented Jan 2, 2026

Copy link
Copy Markdown
Contributor

PR 类型

  • Bug 修复
  • 新功能
  • 文档更新
  • 其他

PR 是否包含破坏性更新?

PR 描述

问题描述

在签到功能中,当用户从其他页面切换到个人设置页面时,如果用户当天已签到,签到组件会出现视觉闪烁问题:

  • 组件初始以折叠状态渲染,加载中时展开,加载后如果已签到又立即折叠
  • 这种状态变化导致明显的视觉闪烁,影响用户体验

此外,在数据加载完成前,按钮和描述文本会显示"未签到"状态,容易造成误解。

解决方案

  1. 添加初始加载状态追踪:引入 initialLoaded 状态变量,用于标记首次数据是否加载完成

  2. 延迟确定折叠状态:将 isCollapsed 初始值设为 null(未确定),仅在首次数据加载完成后根据 checked_in_today 设置最终状态

  3. 改进加载状态展示

    • 按钮在数据加载前显示 loading 状态和"加载中..."文本
    • 描述文本显示"正在加载签到状态..."
    • 折叠面板仅在 isCollapsed === false 时展开(null 时保持关闭)
  4. 删除自动折叠效果:移除根据 checked_in_today 自动设置折叠状态的 useEffect,避免数据刷新时改变用户手动设置的折叠状态

  5. 国际化支持:在 6 种语言文件中添加"加载中..."和"正在加载签到状态..."的翻译

技术细节

  • fetchCheckinStatus 中使用闭包捕获 isFirstLoad 状态,确保在异步操作完成时正确判断是否为首次加载
  • 错误处理分支也考虑了首次加载的情况,确保即使 API 失败也能正确初始化状态
  • 使用严格相等判断 isCollapsed === false 替代 !isCollapsed,明确区分 nulltruefalse 三种状态

测试场景

  • 已签到用户切换到个人页面:组件以加载状态显示,完成后保持折叠
  • 未签到用户切换到个人页面:组件以加载状态显示,完成后自动展开

Summary by CodeRabbit

  • Bug Fixes

    • Improved check-in initialization to prevent UI flicker and ensure consistent collapsed state on first load
    • Refined button and panel behavior so loading/disabled states respect initial load status
  • New Features

    • Added explicit loading indicators for check-in status and calendar date rendering
  • Localization

    • Added corresponding loading-state translations for EN, FR, JA, RU, VI, and ZH

✏️ Tip: You can customize this high-level summary in your review settings.

- Add initialLoaded state to track first data load completion
- Set isCollapsed to null initially, determined after data loads
- Show loading state on button and description text before data arrives
- Remove auto-collapse effect that caused visual flicker
- Add i18n translations for loading states (en/fr/ja/ru/vi/zh)

Fixes issue where component would collapse/expand after data loads,
causing visual flicker when navigating to personal settings page.
@coderabbitai

coderabbitai Bot commented Jan 2, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

Introduces an explicit initialLoaded loading flag and changes initial/collapsed logic in the CheckinCalendar component to avoid flicker; fetch behavior now treats the first load specially. Adds a new "loading check-in status" localization key across six locale files (en, fr, ja, ru, vi, zh).

Changes

Cohort / File(s) Summary
Check-in Calendar Logic
web/src/components/settings/personal/cards/CheckinCalendar.jsx
Add initialLoaded state; set isCollapsed to null initially; modify fetchCheckinStatus to handle first-load vs subsequent loads (init isCollapsed from data.stats?.checked_in_today on success, fallback to false on first-load failure); remove automatic sync effect; update UI text, button loading/disabled conditions, panel visibility (isOpen now checks isCollapsed === false), and per-date rendering to show loading until initialLoaded.
i18n Localization Additions
web/src/i18n/locales/{en,fr,ja,ru,vi,zh}.json
Add a new translation entry for the loading message key: "正在加载签到状态..." → localized strings in English, French, Japanese, Russian, Vietnamese, and Chinese; used by the calendar while initialLoaded is false.

Sequence Diagram(s)

(omitted — change is localized to a single component's internal loading/collapse behavior and does not introduce multi-component sequential flows)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 I hopped in to smooth a loading beat,
Set flags and edges tidy at my feet,
No flicker now — the calendar holds tight,
Six tongues hum softly through the night,
A quiet check-in, snug and bright.

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title directly describes the main change: preventing visual flicker in the check-in component during loading. This aligns perfectly with the PR's core objective of fixing render state management to avoid the component expanding and collapsing.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (3)
web/src/i18n/locales/ja.json (1)

2143-2144: Avoid duplicate 加载中... key; keep a single entry

There is already a "加载中...""読み込み中..." entry earlier in this file, so this new one is redundant. JSON will keep only the last value, but duplicate keys make the locale harder to maintain. You can keep the existing global key and only add the new, specific "正在加载签到状态..." entry here.

Proposed minimal cleanup
-    "加载中...": "読み込み中...",
-    "正在加载签到状态...": "チェックイン状態を読み込み中...",
+    "正在加载签到状态...": "チェックイン状態を読み込み中...",
web/src/i18n/locales/ru.json (1)

2254-2255: Deduplicate Russian "加载中..." translation

As in ja.json, "加载中..." is defined twice here with the same Russian text "Загрузка...". Only the last one is effective, so this is redundant and may surprise future editors. Recommend keeping one "加载中..." entry and just adding the new "正在加载签到状态..." key for the check‑in UI.

Proposed minimal cleanup
-    "加载中...": "Загрузка...",
-    "正在加载签到状态...": "Загрузка статуса регистрации...",   
+    "正在加载签到状态...": "Загрузка статуса регистрации...",   
web/src/components/settings/personal/cards/CheckinCalendar.jsx (1)

56-59: Align tri‑state collapse logic and avoid first‑click no‑op while loading

Using null / true / false for isCollapsed is reasonable, but the current combination of:

  • onClick={() => setIsCollapsed(!isCollapsed)},
  • chevron selection via isCollapsed ? <ChevronDown> : <ChevronUp>, and
  • Collapsible isOpen={isCollapsed === false}

leads to inconsistent behavior before the first load:

  • Initial isCollapsed === null → panel is closed (isOpen is false) but the arrow shows as if open (Up).
  • First header click sets isCollapsed to true, which still keeps the panel closed (true === false is false), so the first click effectively does nothing from the user’s perspective.
  • !isCollapsed with a tri-state is also fragile for very fast repeated clicks.

You can keep the “only false means open” contract and make everything consistent by:

  • Using a functional updater that treats any non‑false as collapsed, and
  • Driving the icon off the same === false check you use for Collapsible.
Proposed collapse toggle & icon refactor
-        <div
-          className='flex items-center flex-1 cursor-pointer'
-          onClick={() => setIsCollapsed(!isCollapsed)}
-        >
+        <div
+          className='flex items-center flex-1 cursor-pointer'
+          onClick={() =>
+            setIsCollapsed((prev) => (prev === false ? true : false))
+          }
+        >
@@
-              {isCollapsed ? (
-                <ChevronDown size={16} className='text-gray-400' />
-              ) : (
-                <ChevronUp size={16} className='text-gray-400' />
-              )}
+              {isCollapsed === false ? (
+                <ChevronUp size={16} className='text-gray-400' />
+              ) : (
+                <ChevronDown size={16} className='text-gray-400' />
+              )}
@@
-      <Collapsible isOpen={isCollapsed === false} keepDOM>
+      <Collapsible isOpen={isCollapsed === false} keepDOM>

(Last line is unchanged, shown only to highlight the shared === false contract.)

Also applies to: 193-207, 238-238

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3402d09 and a0328b2.

📒 Files selected for processing (7)
  • web/src/components/settings/personal/cards/CheckinCalendar.jsx
  • web/src/i18n/locales/en.json
  • web/src/i18n/locales/fr.json
  • web/src/i18n/locales/ja.json
  • web/src/i18n/locales/ru.json
  • web/src/i18n/locales/vi.json
  • web/src/i18n/locales/zh.json
🧰 Additional context used
🧬 Code graph analysis (1)
web/src/components/settings/personal/cards/CheckinCalendar.jsx (2)
web/src/helpers/secureApiCall.js (1)
  • data (55-55)
web/src/helpers/utils.jsx (1)
  • showError (122-151)
🔇 Additional comments (2)
web/src/components/settings/personal/cards/CheckinCalendar.jsx (2)

82-107: First-load handling & error paths look correct

isFirstLoad derived from initialLoaded, plus setting isCollapsed and initialLoaded only on that first load (including both non‑success and error branches), cleanly separates initial behavior from later month changes and should eliminate the original flicker.


210-216: Loading/status copy and button gating match the new UX

The header text and button state correctly:

  • Show a dedicated “正在加载签到状态...” message until the first status fetch completes.
  • Disable and show “加载中...” on the button until initialLoaded is true.
  • Then switch to “今日已签到…” vs “每日签到可获得随机额度奖励” / “立即签到” based on checked_in_today, while preventing repeat check‑ins.

This matches the described UX changes and should prevent the incorrect “未签到” state during initial load.

Also applies to: 225-233

Comment thread web/src/i18n/locales/en.json Outdated
Comment thread web/src/i18n/locales/fr.json Outdated
Comment thread web/src/i18n/locales/vi.json Outdated
Comment thread web/src/i18n/locales/zh.json Outdated
@seefs001
seefs001 merged commit e567910 into QuantumNous:main Jan 3, 2026
1 check passed
ennnnny pushed a commit to ennnnny/new-api that referenced this pull request Mar 17, 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.

2 participants