feat(challenges): 优化挑战列表与详情页交互体验
- 替换 Image 为 expo-image 并启用缓存策略 - 调整礼物按钮尺寸与图标大小 - 加入挑战失败时弹出 Toast 提示 - 统一异步流程并移除冗余状态监听 - 清理调试日志与多余空行
This commit is contained in:
@@ -17,6 +17,7 @@ import {
|
||||
selectProgressError,
|
||||
selectProgressStatus,
|
||||
} from '@/store/challengesSlice';
|
||||
import { Toast } from '@/utils/toast.utils';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import { BlurView } from 'expo-blur';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
@@ -82,6 +83,7 @@ export default function ChallengeDetailScreen() {
|
||||
const challengeSelector = useMemo(() => (id ? selectChallengeById(id) : undefined), [id]);
|
||||
const challenge = useAppSelector((state) => (challengeSelector ? challengeSelector(state) : undefined));
|
||||
|
||||
|
||||
const detailStatusSelector = useMemo(() => (id ? selectChallengeDetailStatus(id) : undefined), [id]);
|
||||
const detailStatus = useAppSelector((state) => (detailStatusSelector ? detailStatusSelector(state) : 'idle'));
|
||||
const detailErrorSelector = useMemo(() => (id ? selectChallengeDetailError(id) : undefined), [id]);
|
||||
@@ -103,22 +105,22 @@ export default function ChallengeDetailScreen() {
|
||||
const progressError = useAppSelector((state) => (progressErrorSelector ? progressErrorSelector(state) : undefined));
|
||||
|
||||
useEffect(() => {
|
||||
if (id) {
|
||||
dispatch(fetchChallengeDetail(id));
|
||||
const getData = async (id: string) => {
|
||||
try {
|
||||
await dispatch(fetchChallengeDetail(id)).unwrap;
|
||||
} catch (error) {
|
||||
}
|
||||
}
|
||||
|
||||
if (id) {
|
||||
getData(id);
|
||||
}
|
||||
|
||||
}, [dispatch, id]);
|
||||
|
||||
|
||||
const [showCelebration, setShowCelebration] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setShowCelebration(false);
|
||||
}, [id]);
|
||||
|
||||
useEffect(() => {
|
||||
if (joinStatus === 'succeeded') {
|
||||
setShowCelebration(true);
|
||||
}
|
||||
}, [joinStatus]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!showCelebration) {
|
||||
@@ -179,11 +181,16 @@ export default function ChallengeDetailScreen() {
|
||||
}
|
||||
};
|
||||
|
||||
const handleJoin = () => {
|
||||
const handleJoin = async () => {
|
||||
if (!id || joinStatus === 'loading') {
|
||||
return;
|
||||
}
|
||||
dispatch(joinChallenge(id));
|
||||
try {
|
||||
await dispatch(joinChallenge(id));
|
||||
setShowCelebration(true)
|
||||
} catch (error) {
|
||||
Toast.error('加入挑战失败')
|
||||
}
|
||||
};
|
||||
|
||||
const handleLeave = () => {
|
||||
@@ -259,7 +266,7 @@ export default function ChallengeDetailScreen() {
|
||||
<View style={styles.safeArea}>
|
||||
<StatusBar barStyle="light-content" />
|
||||
<View style={styles.container}>
|
||||
<View pointerEvents="box-none" style={[styles.headerOverlay, { paddingTop: insets.top }]}>
|
||||
<View pointerEvents="box-none" style={[styles.headerOverlay, { paddingTop: insets.top }]}>
|
||||
<HeaderBar
|
||||
title=""
|
||||
backColor="white"
|
||||
@@ -426,7 +433,7 @@ export default function ChallengeDetailScreen() {
|
||||
<View style={styles.detailIconWrapper}>
|
||||
<Ionicons name="people-outline" size={20} color="#4F5BD5" />
|
||||
</View>
|
||||
<View style={[styles.detailTextWrapper, { flex: 1 }]}>
|
||||
<View style={[styles.detailTextWrapper, { flex: 1 }]}>
|
||||
<Text style={styles.detailLabel}>{participantsLabel}</Text>
|
||||
{participantAvatars.length ? (
|
||||
<View style={styles.avatarRow}>
|
||||
|
||||
Reference in New Issue
Block a user