From a0328b2f5e979a2211476153853fb0b146aeab51 Mon Sep 17 00:00:00 2001 From: RedwindA Date: Sat, 3 Jan 2026 00:43:52 +0800 Subject: [PATCH] fix(checkin): prevent visual flicker when loading check-in component - 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. --- .../personal/cards/CheckinCalendar.jsx | 55 +++++++++++-------- web/src/i18n/locales/en.json | 2 + web/src/i18n/locales/fr.json | 2 + web/src/i18n/locales/ja.json | 2 + web/src/i18n/locales/ru.json | 2 + web/src/i18n/locales/vi.json | 2 + web/src/i18n/locales/zh.json | 2 + 7 files changed, 45 insertions(+), 22 deletions(-) diff --git a/web/src/components/settings/personal/cards/CheckinCalendar.jsx b/web/src/components/settings/personal/cards/CheckinCalendar.jsx index 4b6266ee4..d6f57cf69 100644 --- a/web/src/components/settings/personal/cards/CheckinCalendar.jsx +++ b/web/src/components/settings/personal/cards/CheckinCalendar.jsx @@ -53,8 +53,10 @@ const CheckinCalendar = ({ t, status }) => { const [currentMonth, setCurrentMonth] = useState( new Date().toISOString().slice(0, 7), ); - // 折叠状态:如果已签到则默认折叠 - const [isCollapsed, setIsCollapsed] = useState(true); + // 初始加载状态,用于避免折叠状态闪烁 + const [initialLoaded, setInitialLoaded] = useState(false); + // 折叠状态:null 表示未确定(等待首次加载) + const [isCollapsed, setIsCollapsed] = useState(null); // 创建日期到额度的映射,方便快速查找 const checkinRecordsMap = useMemo(() => { @@ -77,17 +79,31 @@ const CheckinCalendar = ({ t, status }) => { // 获取签到状态 const fetchCheckinStatus = async (month) => { + const isFirstLoad = !initialLoaded; setLoading(true); try { const res = await API.get(`/api/user/checkin?month=${month}`); const { success, data, message } = res.data; if (success) { setCheckinData(data); + // 首次加载时,根据签到状态设置折叠状态 + if (isFirstLoad) { + setIsCollapsed(data.stats?.checked_in_today ?? false); + setInitialLoaded(true); + } } else { showError(message || t('获取签到状态失败')); + if (isFirstLoad) { + setIsCollapsed(false); + setInitialLoaded(true); + } } } catch (error) { showError(t('获取签到状态失败')); + if (isFirstLoad) { + setIsCollapsed(false); + setInitialLoaded(true); + } } finally { setLoading(false); } @@ -121,15 +137,6 @@ const CheckinCalendar = ({ t, status }) => { } }, [status?.checkin_enabled, currentMonth]); - // 当签到状态加载完成后,根据是否已签到设置折叠状态 - useEffect(() => { - if (checkinData.stats?.checked_in_today) { - setIsCollapsed(true); - } else { - setIsCollapsed(false); - } - }, [checkinData.stats?.checked_in_today]); - // 如果签到功能未启用,不显示组件 if (!status?.checkin_enabled) { return null; @@ -200,11 +207,13 @@ const CheckinCalendar = ({ t, status }) => { )}
- {checkinData.stats?.checked_in_today - ? t('今日已签到,累计签到') + - ` ${checkinData.stats?.total_checkins || 0} ` + - t('天') - : t('每日签到可获得随机额度奖励')} + {!initialLoaded + ? t('正在加载签到状态...') + : checkinData.stats?.checked_in_today + ? t('今日已签到,累计签到') + + ` ${checkinData.stats?.total_checkins || 0} ` + + t('天') + : t('每日签到可获得随机额度奖励')}
@@ -213,18 +222,20 @@ const CheckinCalendar = ({ t, status }) => { theme='solid' icon={} onClick={doCheckin} - loading={checkinLoading} - disabled={checkinData.stats?.checked_in_today} + loading={checkinLoading || !initialLoaded} + disabled={!initialLoaded || checkinData.stats?.checked_in_today} className='!bg-green-600 hover:!bg-green-700' > - {checkinData.stats?.checked_in_today - ? t('今日已签到') - : t('立即签到')} + {!initialLoaded + ? t('加载中...') + : checkinData.stats?.checked_in_today + ? t('今日已签到') + : t('立即签到')} {/* 可折叠内容 */} - + {/* 签到统计 */}
diff --git a/web/src/i18n/locales/en.json b/web/src/i18n/locales/en.json index e8a79ead8..ab923ce7a 100644 --- a/web/src/i18n/locales/en.json +++ b/web/src/i18n/locales/en.json @@ -2192,6 +2192,8 @@ "每日签到可获得随机额度奖励": "Daily check-in rewards random quota", "今日已签到": "Checked in today", "立即签到": "Check in now", + "加载中...": "Loading...", + "正在加载签到状态...": "Loading check-in status...", "获取签到状态失败": "Failed to get check-in status", "签到成功!获得": "Check-in successful! Received", "签到失败": "Check-in failed", diff --git a/web/src/i18n/locales/fr.json b/web/src/i18n/locales/fr.json index d8f32661a..6c4b0601f 100644 --- a/web/src/i18n/locales/fr.json +++ b/web/src/i18n/locales/fr.json @@ -2241,6 +2241,8 @@ "每日签到可获得随机额度奖励": "L'enregistrement quotidien récompense un quota aléatoire", "今日已签到": "Enregistré aujourd'hui", "立即签到": "S'enregistrer maintenant", + "加载中...": "Chargement...", + "正在加载签到状态...": "Chargement du statut d'enregistrement...", "获取签到状态失败": "Échec de la récupération du statut d'enregistrement", "签到成功!获得": "Enregistrement réussi ! Reçu", "签到失败": "Échec de l'enregistrement", diff --git a/web/src/i18n/locales/ja.json b/web/src/i18n/locales/ja.json index 073142256..cb64e9211 100644 --- a/web/src/i18n/locales/ja.json +++ b/web/src/i18n/locales/ja.json @@ -2140,6 +2140,8 @@ "每日签到可获得随机额度奖励": "毎日のチェックインでランダムなクォータ報酬を獲得できます", "今日已签到": "本日チェックイン済み", "立即签到": "今すぐチェックイン", + "加载中...": "読み込み中...", + "正在加载签到状态...": "チェックイン状態を読み込み中...", "获取签到状态失败": "チェックイン状態の取得に失敗しました", "签到成功!获得": "チェックイン成功!獲得", "签到失败": "チェックインに失敗しました", diff --git a/web/src/i18n/locales/ru.json b/web/src/i18n/locales/ru.json index 5235440e0..a790e6477 100644 --- a/web/src/i18n/locales/ru.json +++ b/web/src/i18n/locales/ru.json @@ -2251,6 +2251,8 @@ "每日签到可获得随机额度奖励": "Ежедневная регистрация награждает случайной квотой", "今日已签到": "Зарегистрирован сегодня", "立即签到": "Зарегистрироваться сейчас", + "加载中...": "Загрузка...", + "正在加载签到状态...": "Загрузка статуса регистрации...", "获取签到状态失败": "Не удалось получить статус регистрации", "签到成功!获得": "Регистрация успешна! Получено", "签到失败": "Регистрация не удалась", diff --git a/web/src/i18n/locales/vi.json b/web/src/i18n/locales/vi.json index e37e30fa4..8fe2861bb 100644 --- a/web/src/i18n/locales/vi.json +++ b/web/src/i18n/locales/vi.json @@ -2751,6 +2751,8 @@ "每日签到可获得随机额度奖励": "Đăng nhập hàng ngày để nhận phần thưởng hạn mức ngẫu nhiên", "今日已签到": "Đã đăng nhập hôm nay", "立即签到": "Đăng nhập ngay", + "加载中...": "Đang tải...", + "正在加载签到状态...": "Đang tải trạng thái đăng nhập...", "获取签到状态失败": "Không thể lấy trạng thái đăng nhập", "签到成功!获得": "Đăng nhập thành công! Đã nhận", "签到失败": "Đăng nhập thất bại", diff --git a/web/src/i18n/locales/zh.json b/web/src/i18n/locales/zh.json index 3347d8c3c..0877286ea 100644 --- a/web/src/i18n/locales/zh.json +++ b/web/src/i18n/locales/zh.json @@ -2218,6 +2218,8 @@ "每日签到可获得随机额度奖励": "每日签到可获得随机额度奖励", "今日已签到": "今日已签到", "立即签到": "立即签到", + "加载中...": "加载中...", + "正在加载签到状态...": "正在加载签到状态...", "获取签到状态失败": "获取签到状态失败", "签到成功!获得": "签到成功!获得", "签到失败": "签到失败",