diff --git a/app/onboarding/slides.tsx b/app/onboarding/slides.tsx new file mode 100644 index 0000000..4add317 --- /dev/null +++ b/app/onboarding/slides.tsx @@ -0,0 +1,495 @@ +import React, { useEffect, useState } from 'react'; +import { Image, StyleSheet, Text, TouchableOpacity, View } from 'react-native'; +import { SafeAreaView } from 'react-native-safe-area-context'; +import { useRouter } from 'expo-router'; +import { Ionicons } from '@expo/vector-icons'; +import { useSafeAnalytics } from '../../services/analytics'; +import { useColors } from '../../constants/Colors'; +import { useApp } from '../../context/AppContext'; +import { Language } from '../../types'; + +type ColorsType = ReturnType; + +const getSlidesCopy = (language: Language) => { + if (language === 'de') { + return { + slides: [ + { + title: 'Scanne jede Pflanze', + body: 'Richte die Kamera auf eine Pflanze und GreenLens erkennt sie in Sekunden.', + }, + { + title: 'Health Check & Pflegeplan', + body: 'GreenLens erkennt Probleme früh und erstellt deinen Rettungsplan.', + }, + { + title: 'Nie mehr Gießen vergessen', + body: 'Smarte Erinnerungen und deine Pflanzen-Bibliothek halten alles im Blick.', + }, + ], + resultChip: 'Monstera · 98%', + healthCheckLabel: 'Health Check', + overwateringDetected: 'Überwässerung erkannt', + rescuePlanReady: '7-Tage-Rettungsplan bereit', + waterReminder: 'Monstera gießen — heute', + fertilizeReminder: 'Basilikum düngen — in 3 Tagen', + continueLabel: 'Weiter', + }; + } + if (language === 'es') { + return { + slides: [ + { + title: 'Escanea cualquier planta', + body: 'Apunta la cámara a una planta y GreenLens la identifica en segundos.', + }, + { + title: 'Chequeo de salud y plan de cuidados', + body: 'GreenLens detecta problemas a tiempo y crea tu plan de rescate.', + }, + { + title: 'No olvides regar nunca más', + body: 'Recordatorios inteligentes y tu biblioteca de plantas lo mantienen todo al día.', + }, + ], + resultChip: 'Monstera · 98%', + healthCheckLabel: 'Chequeo de salud', + overwateringDetected: 'Exceso de riego detectado', + rescuePlanReady: 'Plan de rescate de 7 días listo', + waterReminder: 'Regar Monstera — hoy', + fertilizeReminder: 'Abonar albahaca — en 3 días', + continueLabel: 'Continuar', + }; + } + return { + slides: [ + { + title: 'Scan Any Plant', + body: 'Point your camera at a plant and GreenLens identifies it in seconds.', + }, + { + title: 'Health Check & Care Plan', + body: 'GreenLens spots problems early and builds a rescue plan for you.', + }, + { + title: 'Never Forget Watering', + body: 'Smart reminders and your personal plant library keep everything on track.', + }, + ], + resultChip: 'Monstera · 98%', + healthCheckLabel: 'Health Check', + overwateringDetected: 'Overwatering detected', + rescuePlanReady: '7-day rescue plan ready', + waterReminder: 'Water Monstera — today', + fertilizeReminder: 'Fertilize Basil — in 3 days', + continueLabel: 'Continue', + }; +}; + +function ScanFrameOverlay({ resultChip, colors }: { resultChip: string; colors: ColorsType }) { + return ( + <> + + + + + + + + + {resultChip} + + + ); +} + +function HealthCardOverlay({ + label, + overwateringDetected, + rescuePlanReady, +}: { + label: string; + overwateringDetected: string; + rescuePlanReady: string; +}) { + return ( + + + + + + {label} + + + + {overwateringDetected} + + + + {rescuePlanReady} + + + ); +} + +function ReminderChipsOverlay({ waterReminder, fertilizeReminder }: { waterReminder: string; fertilizeReminder: string }) { + const [waterLabel, waterMeta] = splitReminder(waterReminder); + const [fertilizeLabel, fertilizeMeta] = splitReminder(fertilizeReminder); + return ( + <> + + + + + + {waterLabel} + {waterMeta} + + + + + + + + {fertilizeLabel} + {fertilizeMeta} + + + + ); +} + +// Splits "Water Monstera — today" into ["Water Monstera", "today"] for a two-line chip. +function splitReminder(text: string): [string, string] { + const parts = text.split('—').map((part) => part.trim()); + if (parts.length === 2) return [parts[0], parts[1]]; + return [text, '']; +} + +export default function OnboardingSlidesScreen() { + const router = useRouter(); + const { language, isDarkMode, colorPalette } = useApp(); + const colors = useColors(isDarkMode, colorPalette); + const posthog = useSafeAnalytics(); + const [page, setPage] = useState(0); + const copy = getSlidesCopy(language); + const slide = copy.slides[page]; + + useEffect(() => { + posthog.capture('onboarding_slide_viewed', { index: page }); + }, [page, posthog]); + + const next = () => { + if (page < copy.slides.length - 1) { + setPage(page + 1); + } else { + router.replace('/onboarding/source'); + } + }; + + const back = () => { + if (page > 0) { + setPage(page - 1); + } else { + router.back(); + } + }; + + return ( + + + + + + + + + {page === 0 && } + {page === 1 && ( + + )} + {page === 2 && ( + + )} + + + {slide.title} + {slide.body} + + {copy.slides.map((_, index) => ( + + ))} + + + {copy.continueLabel} + + + + ); +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + }, + imageArea: { + height: '58%', + position: 'relative', + overflow: 'hidden', + }, + image: { + width: '100%', + height: '100%', + position: 'absolute', + }, + imageSafeArea: { + position: 'absolute', + top: 0, + left: 0, + right: 0, + }, + backBtn: { + marginLeft: 16, + marginTop: 8, + width: 38, + height: 38, + borderRadius: 19, + backgroundColor: 'rgba(255,255,255,0.85)', + alignItems: 'center', + justifyContent: 'center', + }, + // Scan frame overlay (slide 1) + scanFrameWrap: { + position: 'absolute', + top: '22%', + left: '20%', + right: '20%', + bottom: '26%', + }, + cornerTL: { + position: 'absolute', + top: 0, + left: 0, + width: 30, + height: 30, + borderTopWidth: 4, + borderLeftWidth: 4, + borderTopLeftRadius: 8, + }, + cornerTR: { + position: 'absolute', + top: 0, + right: 0, + width: 30, + height: 30, + borderTopWidth: 4, + borderRightWidth: 4, + borderTopRightRadius: 8, + }, + cornerBL: { + position: 'absolute', + bottom: 0, + left: 0, + width: 30, + height: 30, + borderBottomWidth: 4, + borderLeftWidth: 4, + borderBottomLeftRadius: 8, + }, + cornerBR: { + position: 'absolute', + bottom: 0, + right: 0, + width: 30, + height: 30, + borderBottomWidth: 4, + borderRightWidth: 4, + borderBottomRightRadius: 8, + }, + resultChip: { + position: 'absolute', + bottom: '10%', + left: 20, + right: 20, + flexDirection: 'row', + alignItems: 'center', + gap: 8, + backgroundColor: 'rgba(255,255,255,0.94)', + borderRadius: 999, + paddingHorizontal: 16, + paddingVertical: 12, + }, + resultChipText: { + fontSize: 15, + fontWeight: '700', + color: '#1f2520', + }, + // Health card overlay (slide 2) + healthCard: { + position: 'absolute', + bottom: 16, + left: 16, + right: 16, + backgroundColor: 'rgba(255,255,255,0.96)', + borderRadius: 18, + padding: 14, + gap: 8, + }, + healthCardHeader: { + flexDirection: 'row', + alignItems: 'center', + gap: 8, + marginBottom: 2, + }, + healthCardIcon: { + width: 28, + height: 28, + borderRadius: 14, + backgroundColor: '#fdeaea', + alignItems: 'center', + justifyContent: 'center', + }, + healthCardTitle: { + fontSize: 16, + fontWeight: '800', + color: '#1f2520', + }, + healthRow: { + flexDirection: 'row', + alignItems: 'center', + gap: 8, + borderRadius: 10, + paddingHorizontal: 10, + paddingVertical: 8, + }, + healthRowWarning: { + backgroundColor: '#fdeaea', + }, + healthRowWarningText: { + fontSize: 13.5, + fontWeight: '700', + color: '#C62828', + }, + healthRowSuccess: { + backgroundColor: '#e8f3e3', + }, + healthRowSuccessText: { + fontSize: 13.5, + fontWeight: '700', + color: '#2e7d32', + }, + // Reminder chips overlay (slide 3) + reminderChip: { + position: 'absolute', + flexDirection: 'row', + alignItems: 'center', + gap: 10, + backgroundColor: 'rgba(255,255,255,0.96)', + borderRadius: 999, + paddingVertical: 8, + paddingRight: 18, + paddingLeft: 8, + }, + reminderChipTop: { + top: '24%', + right: 20, + }, + reminderChipBottom: { + top: '42%', + left: 20, + }, + reminderIcon: { + width: 32, + height: 32, + borderRadius: 16, + alignItems: 'center', + justifyContent: 'center', + }, + reminderLabel: { + fontSize: 14, + fontWeight: '800', + color: '#1f2520', + }, + reminderMeta: { + fontSize: 12, + fontWeight: '600', + color: '#5a8a3d', + }, + // Bottom sheet + sheet: { + flex: 1, + borderTopLeftRadius: 28, + borderTopRightRadius: 28, + marginTop: -24, + paddingHorizontal: 24, + paddingTop: 32, + alignItems: 'center', + }, + title: { + fontSize: 30, + fontWeight: '900', + textAlign: 'center', + marginBottom: 10, + }, + body: { + fontSize: 15.5, + lineHeight: 22, + textAlign: 'center', + maxWidth: 320, + marginBottom: 20, + }, + dots: { + flexDirection: 'row', + alignItems: 'center', + gap: 8, + marginBottom: 'auto', + }, + dot: { + width: 8, + height: 8, + borderRadius: 4, + }, + dotActive: { + width: 26, + height: 8, + borderRadius: 4, + }, + cta: { + alignSelf: 'stretch', + height: 58, + borderRadius: 14, + alignItems: 'center', + justifyContent: 'center', + marginBottom: 24, + }, + ctaText: { + fontSize: 17, + fontWeight: '800', + }, +});