import React from 'react';
import {
View,
Text,
StyleSheet,
TouchableOpacity,
useColorScheme,
} from 'react-native';
import { Ionicons } from '@expo/vector-icons';
import { Colors } from '../constants/Colors';
import { TaskStatusBadge } from './TaskStatusBadge';
import type { TaskSummary } from '../lib/api';
interface TaskListItemProps {
task: TaskSummary;
onPress: (task: TaskSummary) => void;
}
/**
* Format relative time from a date string
*/
function formatRelativeTime(dateString: string): string {
const date = new Date(dateString);
const now = new Date();
const diffMs = now.getTime() - date.getTime();
const diffSec = Math.floor(diffMs / 1000);
const diffMin = Math.floor(diffSec / 60);
const diffHour = Math.floor(diffMin / 60);
const diffDay = Math.floor(diffHour / 24);
if (diffSec < 60) return 'just now';
if (diffMin < 60) return `${diffMin}m ago`;
if (diffHour < 24) return `${diffHour}h ago`;
if (diffDay < 7) return `${diffDay}d ago`;
return date.toLocaleDateString();
}
/**
* Truncate text with ellipsis
*/
function truncate(text: string, maxLength: number): string {
if (text.length <= maxLength) return text;
return text.slice(0, maxLength - 3) + '...';
}
export function TaskListItem({ task, onPress }: TaskListItemProps) {
const colorScheme = useColorScheme() ?? 'light';
const colors = Colors[colorScheme];
const isRunning = ['running', 'initializing', 'starting'].includes(task.status);
const isCompleted = ['done', 'merged'].includes(task.status);
const isFailed = task.status === 'failed';
return (
<TouchableOpacity
style={[
styles.container,
{
backgroundColor: colors.card,
borderColor: colors.border,
},
]}
onPress={() => onPress(task)}
activeOpacity={0.7}
>
<View style={styles.leftSection}>
<TaskStatusBadge status={task.status} size="medium" />
</View>
<View style={styles.content}>
<View style={styles.header}>
<Text
style={[styles.name, { color: colors.text }]}
numberOfLines={1}
>
{task.name}
</Text>
{task.isSupervisor && (
<View style={styles.supervisorBadge}>
<Ionicons name="star" size={12} color={colors.tint} />
</View>
)}
</View>
{task.contractName && (
<Text
style={[styles.contractName, { color: colors.secondaryText }]}
numberOfLines={1}
>
{task.contractName}
</Text>
)}
{task.progressSummary && (
<Text
style={[styles.progressSummary, { color: colors.secondaryText }]}
numberOfLines={2}
>
{truncate(task.progressSummary, 100)}
</Text>
)}
<View style={styles.footer}>
<Text style={[styles.time, { color: colors.secondaryText }]}>
{isRunning
? `Started ${formatRelativeTime(task.updatedAt)}`
: isCompleted
? `Completed ${formatRelativeTime(task.updatedAt)}`
: isFailed
? `Failed ${formatRelativeTime(task.updatedAt)}`
: `Created ${formatRelativeTime(task.createdAt)}`}
</Text>
{task.subtaskCount > 0 && (
<View style={styles.subtaskBadge}>
<Ionicons
name="git-branch-outline"
size={12}
color={colors.secondaryText}
/>
<Text style={[styles.subtaskCount, { color: colors.secondaryText }]}>
{task.subtaskCount}
</Text>
</View>
)}
</View>
</View>
<View style={styles.rightSection}>
<Ionicons
name="chevron-forward"
size={20}
color={colors.secondaryText}
/>
</View>
</TouchableOpacity>
);
}
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
alignItems: 'center',
paddingVertical: 12,
paddingHorizontal: 16,
borderBottomWidth: StyleSheet.hairlineWidth,
minHeight: 64,
},
leftSection: {
marginRight: 12,
alignItems: 'center',
justifyContent: 'center',
},
content: {
flex: 1,
gap: 2,
},
header: {
flexDirection: 'row',
alignItems: 'center',
gap: 6,
},
name: {
fontSize: 16,
fontWeight: '600',
flex: 1,
},
supervisorBadge: {
padding: 2,
},
contractName: {
fontSize: 13,
},
progressSummary: {
fontSize: 13,
marginTop: 2,
},
footer: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
marginTop: 4,
},
time: {
fontSize: 12,
},
subtaskBadge: {
flexDirection: 'row',
alignItems: 'center',
gap: 4,
},
subtaskCount: {
fontSize: 12,
},
rightSection: {
marginLeft: 8,
},
});