import React, { useMemo, useState } from 'react'; import { ActivityIndicator, Modal, ScrollView, StyleSheet, Text, TouchableOpacity, useWindowDimensions, View, } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { green, dark, line } from '../constants/theme'; import type { SavedPlantProfile } from '../types/plantScan'; import type { SeedIdentificationResult } from '../services/plantIdentification/types'; /** * PlantSeedModal — Phase 3 (2026-09-07). * * The "Plant" flow for a saved seed. Shows the seed's own propagation methods * (from the AI scan), lets the user pick which method they're actually doing * (like the cutting modal), and adds it to the Garden as a seed plant. * * The guidance is per-seed — not a generic guide — because people don't know * terms like "orthodox" vs "recalcitrant" (Bekky, 2026-09-07). */ export function PlantSeedModal({ visible, plant, seed, onPlant, onClose, }: { visible: boolean; plant: SavedPlantProfile; seed: SeedIdentificationResult; /** Add the seed to the Garden with the chosen method (Bekky, 2026-09-07). */ onPlant: (method: string) => void; onClose: () => void; }) { const [selectedMethod, setSelectedMethod] = useState(null); // Guard: `seed` can be undefined when the modal is closed (plantingSeed is // null → seed={plantingSeed?.seed!} is undefined). Accessing .propagationMethods // on undefined would throw and crash the Garden tab (Bekky, 2026-09-07). const methods = useMemo(() => seed?.propagationMethods || [], [seed]); const insets = useSafeAreaInsets(); const { height: windowHeight } = useWindowDimensions(); const cardMaxHeight = Math.max(320, windowHeight - (insets.top + 24) - (insets.bottom + 24)); if (!visible) return null; const name = plant?.commonName || seed?.commonName || 'Unknown seed'; return ( 🌱 Plant Seed {name} {methods.length === 0 ? ( No specific planting methods were found for this seed. You can still add it to your Garden — Pixie will use the general seed-starting guidance. onPlant('direct_sow')}> Add to Garden ) : ( Choose how you're planting it {methods.map((method, i) => { const isOpen = selectedMethod === method.method; return ( setSelectedMethod(isOpen ? null : method.method)} > 🌱 {method.method} {method.timeframe ? {method.timeframe} : null} {method.difficulty ? Difficulty: {method.difficulty} : null} {isOpen && method.instructions && method.instructions.length ? ( {method.instructions.map((step, j) => ( - {step} ))} ) : null} ); })} selectedMethod && onPlant(selectedMethod)} > Add to Garden )} ); } const s = StyleSheet.create({ overlay: { flex: 1, backgroundColor: 'rgba(0,0,0,0.45)', alignItems: 'center', justifyContent: 'center', padding: 20 }, card: { width: '100%', maxWidth: 420, borderRadius: 24, backgroundColor: '#F8F4E8', padding: 18, overflow: 'hidden' }, header: { flexDirection: 'row', alignItems: 'center', marginBottom: 12 }, emoji: { fontSize: 26, marginRight: 8 }, title: { color: dark, fontSize: 18, fontWeight: '900' }, subtitle: { flex: 1, minWidth: 0, color: '#7A704D', fontSize: 13, fontWeight: '700', marginLeft: 8, marginRight: 8 }, headerClose: { minWidth: 32, height: 32, borderRadius: 16, backgroundColor: '#E8E0C8', alignItems: 'center', justifyContent: 'center' }, headerCloseText: { color: dark, fontSize: 14, fontWeight: '900' }, loadingWrap: { alignItems: 'center', paddingVertical: 24, paddingHorizontal: 8 }, loadingText: { color: dark, fontSize: 14, fontWeight: '800', textAlign: 'center', marginBottom: 8 }, noteText: { color: '#7A704D', fontSize: 12, lineHeight: 17, fontWeight: '600', textAlign: 'center', marginBottom: 16 }, methodsList: { flex: 1 }, methodsListContent: { paddingBottom: 8 }, sectionLabel: { color: dark, fontSize: 13, fontWeight: '900', marginBottom: 8 }, methodCard: { borderRadius: 16, borderWidth: 1, borderColor: line, backgroundColor: '#FFFDF7', padding: 12, marginBottom: 8 }, methodCardSelected: { borderColor: green, borderWidth: 1.5 }, methodHeader: { flexDirection: 'row', alignItems: 'center', gap: 10 }, methodIcon: { fontSize: 20 }, methodInfo: { flex: 1, minWidth: 0 }, methodName: { color: dark, fontSize: 14, fontWeight: '900' }, methodTimeframe: { color: '#6B7E6E', fontSize: 12, fontWeight: '600', marginTop: 1 }, methodDifficulty: { color: '#8A783D', fontSize: 11, fontWeight: '700', marginTop: 1 }, methodBody: { borderTopWidth: 1, borderTopColor: line, marginTop: 10, paddingTop: 8 }, stepText: { color: '#2F302A', fontSize: 12, lineHeight: 17, fontWeight: '600', marginBottom: 3 }, primaryButton: { minHeight: 48, borderRadius: 24, backgroundColor: green, alignItems: 'center', justifyContent: 'center', marginTop: 8 }, primaryButtonDisabled: { opacity: 0.5 }, primaryButtonText: { color: '#fff', fontSize: 15, fontWeight: '900' }, });