140 lines
3.4 KiB
TypeScript
140 lines
3.4 KiB
TypeScript
import React from 'react';
|
|
import { View, Text, StyleSheet, TouchableOpacity } from 'react-native';
|
|
import { Ionicons } from '@expo/vector-icons';
|
|
import { theme } from '../theme';
|
|
import { Event } from '../types';
|
|
import { safeParseDate } from '../utils/recurrence';
|
|
|
|
interface EventCardProps {
|
|
event: Event;
|
|
onEdit: (event: Event) => void;
|
|
onToggleComplete: (event: Event) => void;
|
|
onDelete: (event: Event) => void;
|
|
}
|
|
|
|
export default function EventCard({
|
|
event,
|
|
onEdit,
|
|
onToggleComplete,
|
|
onDelete,
|
|
}: EventCardProps) {
|
|
const formatTime = (dateString: string) => {
|
|
const date = safeParseDate(dateString);
|
|
return date.toLocaleTimeString('zh-CN', {
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
});
|
|
};
|
|
|
|
return (
|
|
<TouchableOpacity
|
|
style={[styles.container, event.completed && styles.completedContainer]}
|
|
onPress={() => onEdit(event)}
|
|
activeOpacity={0.7}
|
|
>
|
|
<TouchableOpacity
|
|
style={styles.checkbox}
|
|
onPress={() => onToggleComplete(event)}
|
|
>
|
|
{event.completed ? (
|
|
<Ionicons name="checkmark-circle" size={28} color={theme.colors.primary} />
|
|
) : (
|
|
<View style={styles.checkboxEmpty} />
|
|
)}
|
|
</TouchableOpacity>
|
|
|
|
<View style={styles.content}>
|
|
<Text
|
|
style={[
|
|
styles.title,
|
|
event.completed && styles.completedText,
|
|
]}
|
|
numberOfLines={2}
|
|
>
|
|
{event.title}
|
|
</Text>
|
|
{event.content ? (
|
|
<Text
|
|
style={[
|
|
styles.contentText,
|
|
event.completed && styles.completedText,
|
|
]}
|
|
numberOfLines={2}
|
|
>
|
|
{event.content}
|
|
</Text>
|
|
) : null}
|
|
<View style={styles.timeContainer}>
|
|
<Ionicons
|
|
name="time-outline"
|
|
size={16}
|
|
color={theme.colors.textSecondary}
|
|
/>
|
|
<Text style={styles.timeText}>{formatTime(event.start)}</Text>
|
|
</View>
|
|
</View>
|
|
|
|
<TouchableOpacity
|
|
style={styles.deleteButton}
|
|
onPress={() => onDelete(event)}
|
|
>
|
|
<Ionicons name="trash-outline" size={20} color={theme.colors.error} />
|
|
</TouchableOpacity>
|
|
</TouchableOpacity>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
flexDirection: 'row',
|
|
backgroundColor: theme.colors.surface,
|
|
borderRadius: theme.borderRadius.lg,
|
|
padding: theme.spacing.md,
|
|
marginBottom: theme.spacing.sm,
|
|
alignItems: 'center',
|
|
borderWidth: 1,
|
|
borderColor: theme.colors.surfaceVariant,
|
|
},
|
|
completedContainer: {
|
|
opacity: 0.6,
|
|
},
|
|
checkbox: {
|
|
marginRight: theme.spacing.sm,
|
|
},
|
|
checkboxEmpty: {
|
|
width: 28,
|
|
height: 28,
|
|
borderRadius: 14,
|
|
borderWidth: 2,
|
|
borderColor: theme.colors.textSecondary,
|
|
},
|
|
content: {
|
|
flex: 1,
|
|
},
|
|
title: {
|
|
...theme.typography.h3,
|
|
color: theme.colors.text,
|
|
marginBottom: theme.spacing.xs,
|
|
},
|
|
contentText: {
|
|
...theme.typography.bodySmall,
|
|
color: theme.colors.textSecondary,
|
|
marginBottom: theme.spacing.xs,
|
|
},
|
|
completedText: {
|
|
textDecorationLine: 'line-through',
|
|
},
|
|
timeContainer: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
gap: theme.spacing.xs,
|
|
},
|
|
timeText: {
|
|
...theme.typography.caption,
|
|
color: theme.colors.textSecondary,
|
|
},
|
|
deleteButton: {
|
|
padding: theme.spacing.sm,
|
|
},
|
|
});
|