feat(challenges): 支持即将开始与已结束挑战的禁用态及睡眠挑战自动进度上报

This commit is contained in:
richarjiang
2025-09-30 10:21:50 +08:00
parent 8f847465ef
commit d32a822604
2 changed files with 108 additions and 11 deletions

View File

@@ -1,8 +1,12 @@
import { useAppDispatch, useAppSelector } from '@/hooks/redux';
import { ChallengeType } from '@/services/challengesApi';
import { reportChallengeProgress, selectChallengeList } from '@/store/challengesSlice';
import { logger } from '@/utils/logger';
import { fetchCompleteSleepData, formatSleepTime } from '@/utils/sleepHealthKit';
import dayjs from 'dayjs';
import { Image } from 'expo-image';
import { router } from 'expo-router';
import React, { useEffect, useState } from 'react';
import React, { useEffect, useMemo, useRef, useState } from 'react';
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
@@ -15,8 +19,15 @@ const SleepCard: React.FC<SleepCardProps> = ({
selectedDate,
style,
}) => {
const dispatch = useAppDispatch();
const challenges = useAppSelector(selectChallengeList);
const [sleepDuration, setSleepDuration] = useState<number | null>(null);
const [loading, setLoading] = useState(false);
const joinedSleepChallenges = useMemo(
() => challenges.filter((challenge) => challenge.type === ChallengeType.SLEEP && challenge.isJoined),
[challenges]
);
const lastReportedRef = useRef<{ date: string; value: number | null } | null>(null);
// 获取睡眠数据
useEffect(() => {
@@ -38,6 +49,41 @@ const SleepCard: React.FC<SleepCardProps> = ({
loadSleepData();
}, [selectedDate]);
useEffect(() => {
if (!selectedDate || !sleepDuration || !joinedSleepChallenges.length) {
return;
}
// 如果当前日期不是今天,不上报
if (!dayjs(selectedDate).isSame(dayjs(), 'day')) {
return;
}
const dateKey = dayjs(selectedDate).format('YYYY-MM-DD');
const lastReport = lastReportedRef.current;
if (lastReport && lastReport.date === dateKey && lastReport.value === sleepDuration) {
return;
}
const reportProgress = async () => {
const sleepChallenge = joinedSleepChallenges.find((c) => c.type === ChallengeType.SLEEP);
if (!sleepChallenge) {
return;
}
try {
await dispatch(reportChallengeProgress({ id: sleepChallenge.id, value: sleepDuration })).unwrap();
} catch (error) {
logger.warn('SleepCard: 挑战进度上报失败', { error, challengeId: sleepChallenge.id });
}
lastReportedRef.current = { date: dateKey, value: sleepDuration };
};
reportProgress();
}, [dispatch, joinedSleepChallenges, selectedDate, sleepDuration]);
const CardContent = (
<View style={[styles.container, style]}>
<View style={styles.cardHeaderRow}>
@@ -88,4 +134,4 @@ const styles = StyleSheet.create({
},
});
export default SleepCard;
export default SleepCard;