feat: Implement mobile application and lead processing utilities.

This commit is contained in:
2026-02-19 14:21:51 +01:00
parent fca42db4d2
commit c53a71a5f9
120 changed files with 24080 additions and 851 deletions

View File

@@ -1,47 +1,69 @@
import { TouchableOpacity, Text, ActivityIndicator } from 'react-native'
import { Text, TouchableOpacity, ActivityIndicator } from 'react-native'
import { cn } from '../../lib/utils'
interface ButtonProps {
label: string
onPress: () => void
variant?: 'primary' | 'secondary' | 'ghost'
variant?: 'primary' | 'secondary' | 'ghost' | 'destructive' | 'outline'
size?: 'default' | 'sm' | 'lg'
loading?: boolean
disabled?: boolean
icon?: string
className?: string
}
export function Button({
label,
onPress,
variant = 'primary',
size = 'default',
loading,
disabled,
icon,
className,
}: 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',
}
const isDisabled = disabled || loading
return (
<TouchableOpacity
onPress={onPress}
disabled={disabled || loading}
className={`${variants[variant]} ${disabled || loading ? 'opacity-50' : ''}`}
disabled={isDisabled}
className={cn(
'flex-row items-center justify-center rounded-xl',
{
'bg-primary shadow-sm': variant === 'primary',
'bg-secondary border border-border': variant === 'secondary',
'bg-transparent': variant === 'ghost',
'bg-destructive': variant === 'destructive',
'bg-background border border-input': variant === 'outline',
'h-10 px-4 py-2': size === 'default',
'h-9 rounded-md px-3': size === 'sm',
'h-11 rounded-md px-8': size === 'lg',
'opacity-50': isDisabled,
},
className
)}
activeOpacity={0.8}
>
{loading ? (
<ActivityIndicator color={variant === 'primary' ? 'white' : '#E63946'} />
<ActivityIndicator
color={variant === 'primary' || variant === 'destructive' ? 'white' : 'black'}
/>
) : (
<>
{icon && <Text className="text-xl">{icon}</Text>}
<Text className={textVariants[variant]}>{label}</Text>
</>
<Text
className={cn(
'text-sm font-medium',
{
'text-primary-foreground': variant === 'primary',
'text-secondary-foreground': variant === 'secondary',
'text-primary': variant === 'ghost',
'text-destructive-foreground': variant === 'destructive',
'text-foreground': variant === 'outline',
}
)}
>
{label}
</Text>
)}
</TouchableOpacity>
)