feat(fasting): 完善断食通知系统并优化错误提示
在应用启动时添加断食通知初始化逻辑,改进错误消息提示,并新增后台任务支持断食通知同步。同时优化挑战加入后的数据刷新流程和会员卡片显示样式。 主要更改: - 添加断食通知启动检测和初始化 - 改进断食通知错误消息,提供更详细的用户指导 - 新增断食通知后台任务处理 - 优化挑战加入后自动刷新详情和排名数据 - 调整会员价格字体大小以提升视觉效果
This commit is contained in:
@@ -154,6 +154,17 @@ function Bootstrapper({ children }: { children: React.ReactNode }) {
|
||||
await WaterNotificationHelpers.scheduleRegularWaterReminders(profile.name || '用户');
|
||||
logger.info('默认喝水提醒已注册');
|
||||
|
||||
// 安排断食通知(如果存在活跃的断食计划)
|
||||
try {
|
||||
const fastingSchedule = store.getState().fasting.activeSchedule;
|
||||
if (fastingSchedule) {
|
||||
const fastingPlan = store.getState().fasting.activeSchedule ? null : null;
|
||||
// 断食通知将通过 useFastingNotifications hook 在页面加载时自动安排
|
||||
logger.info('检测到活跃的断食计划,将通过页面 hook 自动安排通知');
|
||||
}
|
||||
} catch (error) {
|
||||
logger.warn('安排断食通知失败:', error);
|
||||
}
|
||||
|
||||
// 初始化快捷动作
|
||||
await setupQuickActions();
|
||||
|
||||
@@ -206,7 +206,9 @@ export default function ChallengeDetailScreen() {
|
||||
}
|
||||
|
||||
try {
|
||||
await dispatch(joinChallenge(id));
|
||||
await dispatch(joinChallenge(id)).unwrap();
|
||||
await dispatch(fetchChallengeDetail(id)).unwrap();
|
||||
await dispatch(fetchChallengeRankings({ id }));
|
||||
setShowCelebration(true)
|
||||
} catch (error) {
|
||||
Toast.error('加入挑战失败')
|
||||
|
||||
@@ -1232,7 +1232,7 @@ const styles = StyleSheet.create({
|
||||
color: '#241F1F',
|
||||
},
|
||||
planCardPrice: {
|
||||
fontSize: 22,
|
||||
fontSize: 16,
|
||||
fontWeight: '700',
|
||||
marginTop: 12,
|
||||
},
|
||||
|
||||
@@ -52,7 +52,7 @@ export const useFastingNotifications = (
|
||||
...prev,
|
||||
isReady: false,
|
||||
isLoading: false,
|
||||
error: '通知权限未授予',
|
||||
error: '通知权限未开启。请前往"个人"页面开启消息推送,或检查系统通知权限设置。',
|
||||
}));
|
||||
return;
|
||||
}
|
||||
@@ -109,7 +109,7 @@ export const useFastingNotifications = (
|
||||
console.error('验证断食通知失败', error);
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
error: error instanceof Error ? error.message : '验证失败',
|
||||
error: '同步断食通知失败:' + (error instanceof Error ? error.message : '未知错误') + '。请点击"重试"按钮,或检查推送权限设置。',
|
||||
}));
|
||||
|
||||
// 验证失败时不立即强制同步,避免重复调用
|
||||
@@ -151,7 +151,7 @@ export const useFastingNotifications = (
|
||||
console.error('强制同步断食通知失败', error);
|
||||
setState(prev => ({
|
||||
...prev,
|
||||
error: error instanceof Error ? error.message : '同步失败',
|
||||
error: '强制同步断食通知失败:' + (error instanceof Error ? error.message : '未知错误') + '。请点击"重试"按钮,或检查推送权限设置。',
|
||||
}));
|
||||
} finally {
|
||||
isSyncingRef.current = false;
|
||||
|
||||
@@ -5,6 +5,8 @@ import AsyncStorage from '@/utils/kvStore';
|
||||
import { log } from '@/utils/logger';
|
||||
import { ChallengeNotificationHelpers, WaterNotificationHelpers } from '@/utils/notificationHelpers';
|
||||
import { getWaterGoalFromStorage } from '@/utils/userPreferences';
|
||||
import { resyncFastingNotifications } from '@/services/fastingNotifications';
|
||||
import { selectActiveFastingSchedule, selectActiveFastingPlan } from '@/store/fastingSlice';
|
||||
import dayjs from 'dayjs';
|
||||
import * as BackgroundTask from 'expo-background-task';
|
||||
import * as TaskManager from 'expo-task-manager';
|
||||
@@ -191,6 +193,54 @@ async function executeChallengeReminderTask(): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
// 执行断食通知后台任务
|
||||
async function executeFastingNotificationTask(): Promise<void> {
|
||||
try {
|
||||
console.log('执行断食通知后台任务...');
|
||||
|
||||
let state;
|
||||
try {
|
||||
state = store.getState();
|
||||
} catch (error) {
|
||||
console.log('无法获取 Redux state,跳过断食通知任务:', error);
|
||||
return;
|
||||
}
|
||||
|
||||
const activeSchedule = selectActiveFastingSchedule(state);
|
||||
const activePlan = selectActiveFastingPlan(state);
|
||||
|
||||
if (!activeSchedule || !activePlan) {
|
||||
console.log('没有激活的断食计划,跳过断食通知任务');
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查断食计划是否已结束
|
||||
const end = dayjs(activeSchedule.endISO);
|
||||
if (end.isBefore(dayjs())) {
|
||||
console.log('断食计划已结束,跳过断食通知任务');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('正在同步断食通知...', {
|
||||
planId: activePlan.id,
|
||||
start: activeSchedule.startISO,
|
||||
end: activeSchedule.endISO,
|
||||
});
|
||||
|
||||
// 重新同步断食通知
|
||||
await resyncFastingNotifications({
|
||||
schedule: activeSchedule,
|
||||
plan: activePlan,
|
||||
enabled: true,
|
||||
});
|
||||
|
||||
console.log('断食通知后台同步完成');
|
||||
|
||||
} catch (error) {
|
||||
console.error('执行断食通知后台任务失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// 发送测试通知以验证后台任务执行
|
||||
async function sendTestNotification(): Promise<void> {
|
||||
try {
|
||||
@@ -286,6 +336,9 @@ async function executeBackgroundTasks(): Promise<void> {
|
||||
// 执行挑战鼓励提醒任务
|
||||
await executeChallengeReminderTask();
|
||||
|
||||
// 执行断食通知任务
|
||||
await executeFastingNotificationTask();
|
||||
|
||||
console.log('后台任务执行完成');
|
||||
} catch (error) {
|
||||
console.error('执行后台任务失败:', error);
|
||||
@@ -318,7 +371,7 @@ export class BackgroundTaskManager {
|
||||
|
||||
try {
|
||||
// 定义后台任务
|
||||
TaskManager.defineTask(BACKGROUND_TASK_IDENTIFIER, async (body: TaskManagerTaskBody) => {
|
||||
TaskManager.defineTask(BACKGROUND_TASK_IDENTIFIER, async (_body: TaskManagerTaskBody) => {
|
||||
try {
|
||||
log.info(`[BackgroundTask] 后台任务执行, 任务 ID: ${BACKGROUND_TASK_IDENTIFIER}`);
|
||||
await executeBackgroundTasks();
|
||||
|
||||
Reference in New Issue
Block a user