Rebuild as InnungsApp project: replace stadtwerke analysis with full documentation

- PRD: vollständige Produktspezifikation (5 Module, Scope, Akzeptanzkriterien)
- ARCHITECTURE: Tech Stack, Ordnerstruktur, Multi-Tenancy, Push, Kosten
- DATABASE_SCHEMA: Vollständiges SQL-Schema mit RLS Policies und Views
- USER_STORIES: 40+ Stories nach Rolle (Admin, Mitglied, Azubi, Obermeister)
- PERSONAS: 5 detaillierte Nutzerprofile mit Alltag, Zitaten und Erwartungen
- BUSINESS_MODEL: Preistabellen, Unit Economics, Revenue-Projektionen, Distribution
- ROADMAP: 6 Phasen, Sprint-Planung, Meilensteine und KPIs
- COMPETITIVE_ANALYSIS: Wettbewerbsmatrix, USPs, Preispositionierung
- API_DESIGN: Supabase Query Patterns, Edge Functions, Realtime Subscriptions
- ONBOARDING_FLOWS: 7 User Flows von Setup bis Fehlerfall
- GTM_STRATEGY: 3-Phasen-Vertrieb, Outreach-Sequenz, Einwandbehandlung
- AZUBI_MODULE: Video-Feed, 1-Click-Apply, Chat, Berichtsheft, Quiz
- DSGVO_KONZEPT: Rechtsgrundlagen, TOMs, AVV, Minderjährige, Incident Response
- FEATURES_BACKLOG: 72 Features nach MoSCoW + Technische Schulden

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Timo Knuth
2026-02-18 19:03:37 +01:00
parent fc68285cf1
commit fca42db4d2
116 changed files with 9329 additions and 6479 deletions

View File

@@ -0,0 +1,82 @@
import {
View,
Text,
FlatList,
TouchableOpacity,
RefreshControl,
} from 'react-native'
import { SafeAreaView } from 'react-native-safe-area-context'
import { useState } from 'react'
import { useRouter } from 'expo-router'
import { trpc } from '@/lib/trpc'
import { TerminCard } from '@/components/termine/TerminCard'
import { EmptyState } from '@/components/ui/EmptyState'
import { LoadingSpinner } from '@/components/ui/LoadingSpinner'
export default function TermineScreen() {
const router = useRouter()
const [tab, setTab] = useState<'kommend' | 'vergangen'>('kommend')
const { data, isLoading, refetch, isRefetching } = trpc.termine.list.useQuery({
upcoming: tab === 'kommend',
})
return (
<SafeAreaView className="flex-1 bg-gray-50" edges={['top']}>
{/* Header */}
<View className="bg-white px-4 py-3 border-b border-gray-100">
<Text className="text-xl font-bold text-gray-900 mb-3">Termine</Text>
{/* Tabs */}
<View className="flex-row gap-1 bg-gray-100 p-1 rounded-xl">
{(['kommend', 'vergangen'] as const).map((t) => (
<TouchableOpacity
key={t}
onPress={() => setTab(t)}
className={`flex-1 py-2 rounded-lg items-center ${
tab === t ? 'bg-white shadow-sm' : ''
}`}
>
<Text
className={`text-sm font-medium ${
tab === t ? 'text-gray-900' : 'text-gray-500'
}`}
>
{t === 'kommend' ? 'Bevorstehend' : 'Vergangen'}
</Text>
</TouchableOpacity>
))}
</View>
</View>
{isLoading ? (
<LoadingSpinner />
) : (
<FlatList
data={data ?? []}
keyExtractor={(item) => item.id}
contentContainerStyle={{ padding: 12, gap: 8 }}
refreshControl={
<RefreshControl
refreshing={isRefetching}
onRefresh={refetch}
tintColor="#E63946"
/>
}
renderItem={({ item }) => (
<TerminCard
termin={item}
onPress={() => router.push(`/(app)/termine/${item.id}`)}
/>
)}
ListEmptyComponent={
<EmptyState
icon="📅"
title={tab === 'kommend' ? 'Keine Termine' : 'Keine vergangenen Termine'}
subtitle="Es sind aktuell keine Termine eingetragen"
/>
}
/>
)}
</SafeAreaView>
)
}