PizzaV2
Plattformübergreifende Pizza-BestellungModerner Pizza-Bestellungs-App mit Telefonauthentifizierung, OTP-Verifizierung, anpassbaren Größen (S/M/L), Echtzeit-Warenkorbverwaltung und Bestellverfolgung mit Status-Badges. Erstellt mit React Native 0.76 und TypeScript.
Die Erstellung einer modernen Food-Bestellungs-App bedeutet die gleichzeitige Bewältigung von Telefonauthentifizierungsabläufen, komplexer Produktanpassung und Echtzeit-Warenkorbzustand — und das bei einem polierten nativen Erlebnis. Die meisten Lösungen wirken klobig, haben kein ordentliches OTP-UX und bewältigen die Nuancen der mobilen Bestellung wie Größenvarianten, Mengenverwaltung und Bestellungs-Lebenszyklus-Verfolgung nicht.


Eine dunkel getheme Pizza-Bestellungs-App mit nahtloser Telefonauthentifizierung, OTP-Verifizierung mit automatisch weiterschaltenden Eingabefeldern, einem durchsuchbaren Katalog von 10 Pizzen mit S/M/L-Größenoptionen, Echtzeit-Warenkorbverwaltung und vollständiger Bestellhistorie mit Status-Badges. Erstellt aus einer einzigen React Native CLI-Codebasis für Android mit Hermes-Engine.


React Navigation 7 steuert auth-geschützte Weiterleitung mit drei Navigatoren: `AuthNavigator` (Onboarding → Telefoneingabe → OTP), `TabNavigator` (Startseite, Verlauf, Warenkorb, Profil) und verschachtelter Stack für den Pizza-Detailfluss. Zustand wird über zwei React Context-Anbieter mit Guard-Clause-Hooks verwaltet. Eine vollständig benutzerdefinierte `BottomNavigation`-Komponente ersetzt die Standard-Tab-Leiste mit Emoji-Icons, aktivem Punkt-Indikator und einem mit Kontext synchronisierten Warenkorb-Badge.


Ein kohärentes dunkles Design-System mit orangefarbenem (#FF6B03) Akzent, 20px Border-Radius auf Karten, pillenförmigen Buttons und konsistenten Abstandstokens. Schwebende Produktbilder überlappen Karten mit negativen Margen. Sieben Bestellstatus-Badges haben jeweils einzigartige Farbpaare — Kochen (Orange auf Dunkelorange), Geliefert (Grün auf Dunkelgrün), Storniert (Rot auf Dunkelrot) — basierend auf einer tokenbasierten Stilkarte.


### Telefonauth & OTP Dreistufiger Auth-Ablauf: Onboarding → telefoneingabe → 4-stelliger OTP. Einzelne Eingabefelder mit automatischem Weiterschalten bei Eingabe und Rückwärts-Rewind bei Backspace — repliziert natives SMS-Code-Eingabe-UX. Dynamische Button-Zustände spiegeln die Eingabevollständigkeit wider. ### Durchsuchbarer Katalog Live-Suche filtert 10 Pizzen nach Name oder Zutat in Echtzeit. Schwebende Produktkarten mit überlappenden Bildern und einem „+"-Hinzufügen-Button. Leerer Zustand mit freundlichem Fallback. ### Größenanpassung S/M/L-Größenauswahler mit Gewicht und Preis pro Option. Mittlere Größe standardmäßig ausgewählt. Mengenzähler mit min-1-Schutz. Gesamtpreis abgeleitet von ausgewählter Option × Menge. ### Unveränderlicher Warenkorb Kontextgesteuerter Warenkorb mit `map` + `filter` unveränderlichem Aktualisierungsmuster. Mengenüberlauf entfernt Produkte automatisch bei null. Badge-Zähler synchronisiert über Bildschirme via benutzerdefinierte Tab-Leiste. Abgeleitete `totalCount` und `totalPrice` — kein veralteter Zustand. ### Bestellstatus-Badges Sieben-Stati-Enum (Abgeschlossen, Geliefert, Ausstehend, Kochend, Unterwegs, Angekommen, Storniert) mit tokenbasierter Farbkarte. Jedes Badge rendert mit semantischer Bezeichnung, Textfarbe und Hintergrund — keine bedingte Gestaltung. ### Benutzerdefinierte Tab-Leiste Vollständige Neuimplementierung von `BottomTabBarProps` mit Emoji-Icons, aktivem Punkt-Indikator und absolut positioniertem Warenkorb-Badge. Schwebendes Design mit 30px Border-Radius und 80px Höhe.









Unter der Haube
import React, { useRef, useState } from 'react';
import {
View, TextInput, Text, KeyboardAvoidingView,
Platform, ScrollView, TouchableOpacity,
} from 'react-native';
import { useRoute, RouteProp } from '@react-navigation/native';
import AppButton from '../components/AppButton';
import { useAuth } from '../context/AuthContext';
import { AuthStackParamList } from '../navigation/AuthNavigator';
type Route = RouteProp<AuthStackParamList, 'OtpVerification'>;
const OTP_LENGTH = 4;
const OtpVerificationScreen = () => {
const [otp, setOtp] = useState<string[]>(Array(OTP_LENGTH).fill(''));
const inputs = useRef<(TextInput | null)[]>([]);
const { login } = useAuth();
const route = useRoute<Route>();
const phone = route.params?.phone ?? '+1 555 123 4567';
const handleChange = (text: string, index: number) => {
if (text.length > 1) return;
const newOtp = [...otp];
newOtp[index] = text;
setOtp(newOtp);
if (text && index < OTP_LENGTH - 1) {
inputs.current[index + 1]?.focus();
}
};
const handleKeyPress = (e: any, index: number) => {
if (e.nativeEvent.key === 'Backspace' && !otp[index] && index > 0) {
inputs.current[index - 1]?.focus();
}
};
const isComplete = otp.every(d => d !== '');
return (
<KeyboardAvoidingView
style={{ flex: 1, backgroundColor: '#0F0F0F' }}
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
>
<ScrollView
contentContainerStyle={{
flexGrow: 1, alignItems: 'center',
paddingHorizontal: 20, paddingVertical: 40,
}}
keyboardShouldPersistTaps="handled"
>
<Text style={{ color: 'white', fontSize: 40, fontWeight: 'bold', marginTop: 20 }}>
SMS Code
</Text>
<Text style={{ color: '#9EA1AB', fontSize: 18, marginTop: 10, textAlign: 'center' }}>
We sent a 4-digit code to {'\n'}
<Text style={{ color: 'white' }}>{phone}</Text>
</Text>
<View style={{ flexDirection: 'row', gap: 12, marginTop: 40, marginBottom: 20 }}>
{otp.map((digit, index) => (
<TextInput
key={index}
ref={ref => (inputs.current[index] = ref)}
style={{
width: 75, height: 75, backgroundColor: '#121212',
borderRadius: 15, borderWidth: 2,
borderColor: digit ? '#FF6B00' : '#262626',
fontSize: 26, fontWeight: 'bold', color: 'white',
textAlign: 'center',
}}
value={digit}
onChangeText={text => handleChange(text, index)}
onKeyPress={e => handleKeyPress(e, index)}
keyboardType="numeric"
maxLength={1}
selectionColor="#FF6B00"
caretHidden
/>
))}
</View>
<View style={{ flex: 1, minHeight: 40 }} />
<AppButton
onPress={login}
title="Verify"
containerColor={isComplete ? '#FF6B00' : '#3A3A3A'}
contentColor="white"
/>
</ScrollView>
</KeyboardAvoidingView>
);
};Möchten Sie mehr sehen?
Durchstöbern Sie den vollständigen Projektkatalog oder laden Sie den Quellcode herunter.