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:
48
innungsapp/apps/mobile/components/ui/Button.tsx
Normal file
48
innungsapp/apps/mobile/components/ui/Button.tsx
Normal file
@@ -0,0 +1,48 @@
|
||||
import { TouchableOpacity, Text, ActivityIndicator } from 'react-native'
|
||||
|
||||
interface ButtonProps {
|
||||
label: string
|
||||
onPress: () => void
|
||||
variant?: 'primary' | 'secondary' | 'ghost'
|
||||
loading?: boolean
|
||||
disabled?: boolean
|
||||
icon?: string
|
||||
}
|
||||
|
||||
export function Button({
|
||||
label,
|
||||
onPress,
|
||||
variant = 'primary',
|
||||
loading,
|
||||
disabled,
|
||||
icon,
|
||||
}: ButtonProps) {
|
||||
const base = 'rounded-2xl py-4 flex-row items-center justify-center gap-2'
|
||||
const variants = {
|
||||
primary: `${base} bg-brand-500`,
|
||||
secondary: `${base} bg-white border border-gray-200`,
|
||||
ghost: `${base}`,
|
||||
}
|
||||
const textVariants = {
|
||||
primary: 'text-white font-semibold text-base',
|
||||
secondary: 'text-gray-900 font-semibold text-base',
|
||||
ghost: 'text-brand-500 font-semibold text-base',
|
||||
}
|
||||
|
||||
return (
|
||||
<TouchableOpacity
|
||||
onPress={onPress}
|
||||
disabled={disabled || loading}
|
||||
className={`${variants[variant]} ${disabled || loading ? 'opacity-50' : ''}`}
|
||||
>
|
||||
{loading ? (
|
||||
<ActivityIndicator color={variant === 'primary' ? 'white' : '#E63946'} />
|
||||
) : (
|
||||
<>
|
||||
{icon && <Text className="text-xl">{icon}</Text>}
|
||||
<Text className={textVariants[variant]}>{label}</Text>
|
||||
</>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
26
innungsapp/apps/mobile/components/ui/Card.tsx
Normal file
26
innungsapp/apps/mobile/components/ui/Card.tsx
Normal file
@@ -0,0 +1,26 @@
|
||||
import { View, TouchableOpacity } from 'react-native'
|
||||
|
||||
interface CardProps {
|
||||
children: React.ReactNode
|
||||
onPress?: () => void
|
||||
className?: string
|
||||
}
|
||||
|
||||
export function Card({ children, onPress, className = '' }: CardProps) {
|
||||
if (onPress) {
|
||||
return (
|
||||
<TouchableOpacity
|
||||
onPress={onPress}
|
||||
className={`bg-white rounded-2xl border border-gray-100 p-4 ${className}`}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
{children}
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<View className={`bg-white rounded-2xl border border-gray-100 p-4 ${className}`}>
|
||||
{children}
|
||||
</View>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user