refactor: migrate post operations to use case architecture with differential updates
Some checks failed
Frontend CI / build-and-push-web (push) Failing after 3m11s
Frontend CI / ota-android (push) Failing after 16m3s
Frontend CI / build-android-apk (push) Has been cancelled

Migrate post-related operations from direct service/store calls to a new use case architecture featuring differential updates. Key changes include: (1) introduce ProcessPostUseCase to handle like, unlike, favorite, unfavorite, delete, and fetch operations with proper state management, (2) add useDifferentialPosts hook for efficient list rendering with minimal re-renders, (3) add PostDiffCalculator and PostUpdateBatcher in infrastructure layer for incremental updates, (4) deprecate NotificationItem component in favor of SystemMessageItem, (5) remove deprecated interactive methods from userStore, (6) add posts_cache table to local datasource, (7) clean up legacy MessageDTO and ConversationDTO types, (8) remove deprecated hook useBreakpointCheck, (9) refactor MessageBubble to use measureInWindow directly for better React Native compatibility
This commit is contained in:
lafay
2026-03-21 20:55:36 +08:00
parent 25071d2303
commit d273569911
30 changed files with 4395 additions and 572 deletions

View File

@@ -1,147 +0,0 @@
/**
* NotificationItem 通知项组件
* 根据通知类型显示不同图标和内容
*
* @deprecated 请使用 SystemMessageItem 组件代替
* 该组件使用旧的 Notification 类型,新功能请使用 SystemMessageItem
*/
import React from 'react';
import { View, TouchableOpacity, StyleSheet } from 'react-native';
import { MaterialCommunityIcons } from '@expo/vector-icons';
import { formatDistanceToNow } from 'date-fns';
import { zhCN } from 'date-fns/locale';
import { colors, spacing, borderRadius } from '../../theme';
import { Notification, NotificationType } from '../../types';
import Text from '../common/Text';
import Avatar from '../common/Avatar';
interface NotificationItemProps {
notification: Notification;
onPress: () => void;
}
// 通知类型到图标和颜色的映射
const getNotificationIcon = (type: NotificationType): { icon: string; color: string } => {
switch (type) {
case 'like_post':
return { icon: 'heart', color: colors.error.main };
case 'like_comment':
return { icon: 'heart', color: colors.error.main };
case 'comment':
return { icon: 'comment', color: colors.info.main };
case 'reply':
return { icon: 'reply', color: colors.info.main };
case 'follow':
return { icon: 'account-plus', color: colors.primary.main };
case 'mention':
return { icon: 'at', color: colors.warning.main };
case 'system':
return { icon: 'information', color: colors.text.secondary };
default:
return { icon: 'bell', color: colors.text.secondary };
}
};
const NotificationItem: React.FC<NotificationItemProps> = ({
notification,
onPress,
}) => {
// 格式化时间
const formatTime = (dateString: string): string => {
try {
return formatDistanceToNow(new Date(dateString), {
addSuffix: true,
locale: zhCN,
});
} catch {
return '';
}
};
const { icon, color } = getNotificationIcon(notification.type);
return (
<TouchableOpacity
style={[styles.container, !notification.isRead && styles.unread]}
onPress={onPress}
activeOpacity={0.7}
>
{/* 通知图标/头像 */}
<View style={styles.iconContainer}>
{notification.type === 'follow' && notification.data.userId ? (
<Avatar
source={null}
size={40}
name={notification.title}
/>
) : (
<View style={[styles.iconWrapper, { backgroundColor: color + '20' }]}>
<MaterialCommunityIcons name={icon as any} size={20} color={color} />
</View>
)}
</View>
{/* 通知内容 */}
<View style={styles.content}>
<View style={styles.textContainer}>
<Text
variant="body"
numberOfLines={2}
style={!notification.isRead ? styles.unreadText : undefined}
>
{notification.content}
</Text>
</View>
<Text variant="caption" color={colors.text.secondary}>
{formatTime(notification.createdAt)}
</Text>
</View>
{/* 未读标记 */}
{!notification.isRead && <View style={styles.unreadDot} />}
</TouchableOpacity>
);
};
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
alignItems: 'center',
padding: spacing.lg,
backgroundColor: colors.background.paper,
borderBottomWidth: 1,
borderBottomColor: colors.divider,
},
unread: {
backgroundColor: colors.primary.light + '10',
},
iconContainer: {
marginRight: spacing.md,
},
iconWrapper: {
width: 40,
height: 40,
borderRadius: 20,
justifyContent: 'center',
alignItems: 'center',
},
content: {
flex: 1,
},
textContainer: {
marginBottom: spacing.xs,
},
unreadText: {
fontWeight: '600',
},
unreadDot: {
width: 8,
height: 8,
borderRadius: 4,
backgroundColor: colors.primary.main,
marginLeft: spacing.sm,
},
});
export default NotificationItem;

View File

@@ -5,7 +5,6 @@
export { default as PostCard } from './PostCard';
export { default as CommentItem } from './CommentItem';
export { default as UserProfileHeader } from './UserProfileHeader';
export { default as NotificationItem } from './NotificationItem';
export { default as SystemMessageItem } from './SystemMessageItem';
export { default as SearchBar } from './SearchBar';
export { default as TabBar } from './TabBar';