KI-AGENT: Mobile Termine und Kalender ergänzen

This commit is contained in:
2026-09-08 22:05:18 +02:00
parent 5e1631e2d3
commit 92c354c1b9
8 changed files with 1122 additions and 1 deletions

View File

@@ -17,10 +17,13 @@ import * as DocumentPicker from 'expo-document-picker';
import * as ImagePicker from 'expo-image-picker';
import * as WebBrowser from 'expo-web-browser';
import { EventCreateModal } from '@/components/event-create-modal';
import { HistorySection } from '@/components/history-section';
import {
CalendarEvent,
createProjectTask,
fetchProjectById,
fetchProjectEvents,
fetchProjectFiles,
fetchProjectTasks,
Project,
@@ -70,12 +73,14 @@ export default function ProjectDetailScreen() {
const [project, setProject] = useState<Project | null>(null);
const [files, setFiles] = useState<ProjectFile[]>([]);
const [tasks, setTasks] = useState<Task[]>([]);
const [events, setEvents] = useState<CalendarEvent[]>([]);
const [loading, setLoading] = useState(true);
const [refreshing, setRefreshing] = useState(false);
const [uploading, setUploading] = useState(false);
const [creatingTask, setCreatingTask] = useState(false);
const [updatingTaskId, setUpdatingTaskId] = useState<number | null>(null);
const [createTaskModalOpen, setCreateTaskModalOpen] = useState(false);
const [createEventModalOpen, setCreateEventModalOpen] = useState(false);
const [createTaskError, setCreateTaskError] = useState<string | null>(null);
const [newTaskName, setNewTaskName] = useState('');
const [newTaskDescription, setNewTaskDescription] = useState('');
@@ -122,14 +127,16 @@ export default function ProjectDetailScreen() {
setError(null);
try {
const [projectData, fileData, taskData] = await Promise.all([
const [projectData, fileData, taskData, eventData] = await Promise.all([
fetchProjectById(token, projectId),
fetchProjectFiles(token, projectId),
fetchProjectTasks(token, projectId),
fetchProjectEvents(token, projectId),
]);
setProject(projectData);
setFiles(fileData);
setTasks(taskData);
setEvents(eventData.sort((a, b) => new Date(a.startDate).getTime() - new Date(b.startDate).getTime()));
} catch (err) {
setError(err instanceof Error ? err.message : 'Projektdaten konnten nicht geladen werden.');
} finally {
@@ -369,6 +376,35 @@ export default function ProjectDetailScreen() {
<HistorySection resource="projects" resourceId={projectId} />
<View style={styles.card}>
<View style={styles.sectionHeader}>
<Text style={styles.sectionTitle}>Termine ({events.length})</Text>
<Pressable style={styles.smallPrimaryButton} onPress={() => setCreateEventModalOpen(true)}>
<Text style={styles.smallPrimaryButtonText}>Neuer Termin</Text>
</Pressable>
</View>
{events.length === 0 ? (
<Text style={styles.empty}>Keine Termine für dieses Projekt vorhanden.</Text>
) : (
events.map((event) => (
<Pressable
key={String(event.id)}
style={styles.eventRow}
onPress={() => router.push(`/more/event/${event.id}` as any)}>
<View style={[styles.eventColor, { backgroundColor: event.color || PRIMARY }]} />
<View style={styles.eventMain}>
<Text style={styles.eventName}>{event.name}</Text>
<Text style={styles.eventDate}>
{formatDateTime(event.startDate)}
{event.endDate ? ` ${formatDateTime(event.endDate)}` : ''}
</Text>
</View>
<Text style={styles.eventArrow}></Text>
</Pressable>
))
)}
</View>
<View style={styles.card}>
<View style={styles.sectionHeader}>
<Text style={styles.sectionTitle}>Aufgaben ({tasks.length})</Text>
@@ -508,6 +544,14 @@ export default function ProjectDetailScreen() {
</KeyboardAvoidingView>
</View>
</Modal>
<EventCreateModal
visible={createEventModalOpen}
projects={project ? [project] : []}
initialProjectId={projectId}
onClose={() => setCreateEventModalOpen(false)}
onCreated={() => load(false)}
/>
</ScrollView>
);
}
@@ -591,6 +635,38 @@ const styles = StyleSheet.create({
fontSize: 16,
fontWeight: '700',
},
eventRow: {
minHeight: 60,
flexDirection: 'row',
alignItems: 'stretch',
borderWidth: 1,
borderColor: '#e5e7eb',
borderRadius: 9,
overflow: 'hidden',
},
eventColor: {
width: 5,
},
eventMain: {
flex: 1,
padding: 9,
gap: 2,
},
eventName: {
color: '#111827',
fontSize: 14,
fontWeight: '700',
},
eventDate: {
color: '#6b7280',
fontSize: 12,
},
eventArrow: {
alignSelf: 'center',
color: '#9ca3af',
fontSize: 24,
paddingRight: 9,
},
sectionHeaderActions: {
alignItems: 'flex-end',
gap: 8,