mirror of
https://github.com/QuantumNous/new-api.git
synced 2026-04-19 11:48:38 +00:00
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.
This commit is contained in:
@@ -53,8 +53,10 @@ const CheckinCalendar = ({ t, status }) => {
|
|||||||
const [currentMonth, setCurrentMonth] = useState(
|
const [currentMonth, setCurrentMonth] = useState(
|
||||||
new Date().toISOString().slice(0, 7),
|
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(() => {
|
const checkinRecordsMap = useMemo(() => {
|
||||||
@@ -77,17 +79,31 @@ const CheckinCalendar = ({ t, status }) => {
|
|||||||
|
|
||||||
// 获取签到状态
|
// 获取签到状态
|
||||||
const fetchCheckinStatus = async (month) => {
|
const fetchCheckinStatus = async (month) => {
|
||||||
|
const isFirstLoad = !initialLoaded;
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
const res = await API.get(`/api/user/checkin?month=${month}`);
|
const res = await API.get(`/api/user/checkin?month=${month}`);
|
||||||
const { success, data, message } = res.data;
|
const { success, data, message } = res.data;
|
||||||
if (success) {
|
if (success) {
|
||||||
setCheckinData(data);
|
setCheckinData(data);
|
||||||
|
// 首次加载时,根据签到状态设置折叠状态
|
||||||
|
if (isFirstLoad) {
|
||||||
|
setIsCollapsed(data.stats?.checked_in_today ?? false);
|
||||||
|
setInitialLoaded(true);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
showError(message || t('获取签到状态失败'));
|
showError(message || t('获取签到状态失败'));
|
||||||
|
if (isFirstLoad) {
|
||||||
|
setIsCollapsed(false);
|
||||||
|
setInitialLoaded(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showError(t('获取签到状态失败'));
|
showError(t('获取签到状态失败'));
|
||||||
|
if (isFirstLoad) {
|
||||||
|
setIsCollapsed(false);
|
||||||
|
setInitialLoaded(true);
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
@@ -121,15 +137,6 @@ const CheckinCalendar = ({ t, status }) => {
|
|||||||
}
|
}
|
||||||
}, [status?.checkin_enabled, currentMonth]);
|
}, [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) {
|
if (!status?.checkin_enabled) {
|
||||||
return null;
|
return null;
|
||||||
@@ -200,11 +207,13 @@ const CheckinCalendar = ({ t, status }) => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className='text-xs text-gray-500 dark:text-gray-400'>
|
<div className='text-xs text-gray-500 dark:text-gray-400'>
|
||||||
{checkinData.stats?.checked_in_today
|
{!initialLoaded
|
||||||
? t('今日已签到,累计签到') +
|
? t('正在加载签到状态...')
|
||||||
` ${checkinData.stats?.total_checkins || 0} ` +
|
: checkinData.stats?.checked_in_today
|
||||||
t('天')
|
? t('今日已签到,累计签到') +
|
||||||
: t('每日签到可获得随机额度奖励')}
|
` ${checkinData.stats?.total_checkins || 0} ` +
|
||||||
|
t('天')
|
||||||
|
: t('每日签到可获得随机额度奖励')}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -213,18 +222,20 @@ const CheckinCalendar = ({ t, status }) => {
|
|||||||
theme='solid'
|
theme='solid'
|
||||||
icon={<Gift size={16} />}
|
icon={<Gift size={16} />}
|
||||||
onClick={doCheckin}
|
onClick={doCheckin}
|
||||||
loading={checkinLoading}
|
loading={checkinLoading || !initialLoaded}
|
||||||
disabled={checkinData.stats?.checked_in_today}
|
disabled={!initialLoaded || checkinData.stats?.checked_in_today}
|
||||||
className='!bg-green-600 hover:!bg-green-700'
|
className='!bg-green-600 hover:!bg-green-700'
|
||||||
>
|
>
|
||||||
{checkinData.stats?.checked_in_today
|
{!initialLoaded
|
||||||
? t('今日已签到')
|
? t('加载中...')
|
||||||
: t('立即签到')}
|
: checkinData.stats?.checked_in_today
|
||||||
|
? t('今日已签到')
|
||||||
|
: t('立即签到')}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 可折叠内容 */}
|
{/* 可折叠内容 */}
|
||||||
<Collapsible isOpen={!isCollapsed} keepDOM>
|
<Collapsible isOpen={isCollapsed === false} keepDOM>
|
||||||
{/* 签到统计 */}
|
{/* 签到统计 */}
|
||||||
<div className='grid grid-cols-3 gap-3 mb-4 mt-4'>
|
<div className='grid grid-cols-3 gap-3 mb-4 mt-4'>
|
||||||
<div className='text-center p-2.5 bg-slate-50 dark:bg-slate-800 rounded-lg'>
|
<div className='text-center p-2.5 bg-slate-50 dark:bg-slate-800 rounded-lg'>
|
||||||
|
|||||||
@@ -2192,6 +2192,8 @@
|
|||||||
"每日签到可获得随机额度奖励": "Daily check-in rewards random quota",
|
"每日签到可获得随机额度奖励": "Daily check-in rewards random quota",
|
||||||
"今日已签到": "Checked in today",
|
"今日已签到": "Checked in today",
|
||||||
"立即签到": "Check in now",
|
"立即签到": "Check in now",
|
||||||
|
"加载中...": "Loading...",
|
||||||
|
"正在加载签到状态...": "Loading check-in status...",
|
||||||
"获取签到状态失败": "Failed to get check-in status",
|
"获取签到状态失败": "Failed to get check-in status",
|
||||||
"签到成功!获得": "Check-in successful! Received",
|
"签到成功!获得": "Check-in successful! Received",
|
||||||
"签到失败": "Check-in failed",
|
"签到失败": "Check-in failed",
|
||||||
|
|||||||
@@ -2241,6 +2241,8 @@
|
|||||||
"每日签到可获得随机额度奖励": "L'enregistrement quotidien récompense un quota aléatoire",
|
"每日签到可获得随机额度奖励": "L'enregistrement quotidien récompense un quota aléatoire",
|
||||||
"今日已签到": "Enregistré aujourd'hui",
|
"今日已签到": "Enregistré aujourd'hui",
|
||||||
"立即签到": "S'enregistrer maintenant",
|
"立即签到": "S'enregistrer maintenant",
|
||||||
|
"加载中...": "Chargement...",
|
||||||
|
"正在加载签到状态...": "Chargement du statut d'enregistrement...",
|
||||||
"获取签到状态失败": "Échec de la récupération du statut d'enregistrement",
|
"获取签到状态失败": "Échec de la récupération du statut d'enregistrement",
|
||||||
"签到成功!获得": "Enregistrement réussi ! Reçu",
|
"签到成功!获得": "Enregistrement réussi ! Reçu",
|
||||||
"签到失败": "Échec de l'enregistrement",
|
"签到失败": "Échec de l'enregistrement",
|
||||||
|
|||||||
@@ -2140,6 +2140,8 @@
|
|||||||
"每日签到可获得随机额度奖励": "毎日のチェックインでランダムなクォータ報酬を獲得できます",
|
"每日签到可获得随机额度奖励": "毎日のチェックインでランダムなクォータ報酬を獲得できます",
|
||||||
"今日已签到": "本日チェックイン済み",
|
"今日已签到": "本日チェックイン済み",
|
||||||
"立即签到": "今すぐチェックイン",
|
"立即签到": "今すぐチェックイン",
|
||||||
|
"加载中...": "読み込み中...",
|
||||||
|
"正在加载签到状态...": "チェックイン状態を読み込み中...",
|
||||||
"获取签到状态失败": "チェックイン状態の取得に失敗しました",
|
"获取签到状态失败": "チェックイン状態の取得に失敗しました",
|
||||||
"签到成功!获得": "チェックイン成功!獲得",
|
"签到成功!获得": "チェックイン成功!獲得",
|
||||||
"签到失败": "チェックインに失敗しました",
|
"签到失败": "チェックインに失敗しました",
|
||||||
|
|||||||
@@ -2251,6 +2251,8 @@
|
|||||||
"每日签到可获得随机额度奖励": "Ежедневная регистрация награждает случайной квотой",
|
"每日签到可获得随机额度奖励": "Ежедневная регистрация награждает случайной квотой",
|
||||||
"今日已签到": "Зарегистрирован сегодня",
|
"今日已签到": "Зарегистрирован сегодня",
|
||||||
"立即签到": "Зарегистрироваться сейчас",
|
"立即签到": "Зарегистрироваться сейчас",
|
||||||
|
"加载中...": "Загрузка...",
|
||||||
|
"正在加载签到状态...": "Загрузка статуса регистрации...",
|
||||||
"获取签到状态失败": "Не удалось получить статус регистрации",
|
"获取签到状态失败": "Не удалось получить статус регистрации",
|
||||||
"签到成功!获得": "Регистрация успешна! Получено",
|
"签到成功!获得": "Регистрация успешна! Получено",
|
||||||
"签到失败": "Регистрация не удалась",
|
"签到失败": "Регистрация не удалась",
|
||||||
|
|||||||
@@ -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à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 hôm nay",
|
||||||
"立即签到": "Đăng nhập ngay",
|
"立即签到": "Đă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",
|
"获取签到状态失败": "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ành công! Đã nhận",
|
||||||
"签到失败": "Đăng nhập thất bại",
|
"签到失败": "Đăng nhập thất bại",
|
||||||
|
|||||||
@@ -2218,6 +2218,8 @@
|
|||||||
"每日签到可获得随机额度奖励": "每日签到可获得随机额度奖励",
|
"每日签到可获得随机额度奖励": "每日签到可获得随机额度奖励",
|
||||||
"今日已签到": "今日已签到",
|
"今日已签到": "今日已签到",
|
||||||
"立即签到": "立即签到",
|
"立即签到": "立即签到",
|
||||||
|
"加载中...": "加载中...",
|
||||||
|
"正在加载签到状态...": "正在加载签到状态...",
|
||||||
"获取签到状态失败": "获取签到状态失败",
|
"获取签到状态失败": "获取签到状态失败",
|
||||||
"签到成功!获得": "签到成功!获得",
|
"签到成功!获得": "签到成功!获得",
|
||||||
"签到失败": "签到失败",
|
"签到失败": "签到失败",
|
||||||
|
|||||||
Reference in New Issue
Block a user