import React, { useState } from 'react'; import { View, Text, ScrollView, TouchableOpacity, TextInput, StyleSheet, Alert, } from 'react-native'; import { useRouter } from 'expo-router'; import { useForm, Controller } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { z } from 'zod'; import { Ionicons } from '@expo/vector-icons'; import { SafeAreaView } from 'react-native-safe-area-context'; import { usePresetStore } from '@store/presetStore'; import { useFilamentStore } from '@store/filamentStore'; import { Input } from '@presentation/components/ui/Input'; import { Button } from '@presentation/components/ui/Button'; import { Card } from '@presentation/components/ui/Card'; import { calcNetWeight } from '@domain/Filament'; import { colors, typography, spacing, radius } from '@shared/theme'; import { MATERIALS, type Material } from '@shared/constants'; import { formatWeight } from '@shared/utils/filament'; const schema = z.object({ brand: z.string().min(1, 'Marca obrigatória'), model: z.string().optional(), totalWeightG: z.coerce.number().min(1, 'Informe o peso total'), tempHotendC: z.coerce.number().optional(), tempBedC: z.coerce.number().optional(), flowFactorPct: z.coerce.number().optional(), notes: z.string().optional(), }); type FormData = z.infer; const PRESET_COLORS = ['#E05533', '#2563EB', '#FFFFFF', '#1E1B18', '#22C55E', '#EAB308', '#EC4899', '#A855F7', '#F97316']; /** * Tela de Cadastro de Filamento — 2X-0 */ export default function NewFilamentScreen(): React.ReactElement { const router = useRouter(); const { presets, systemPresets } = usePresetStore(); const { addFilament } = useFilamentStore(); const [selectedColor, setSelectedColor] = useState('#E05533'); const [hexInput, setHexInput] = useState('#E05533'); const [selectedMaterial, setSelectedMaterial] = useState('PLA'); const [selectedPresetId, setSelectedPresetId] = useState(systemPresets[0]?.id ?? null); const [isLoading, setIsLoading] = useState(false); const { control, handleSubmit, watch, formState: { errors } } = useForm({ resolver: zodResolver(schema), defaultValues: { brand: '', model: '', totalWeightG: 0, tempHotendC: 210, tempBedC: 60, flowFactorPct: 100 }, }); const totalWeight = watch('totalWeightG'); const selectedPreset = presets.find((p) => p.id === selectedPresetId); const netWeight = selectedPreset && totalWeight ? calcNetWeight(Number(totalWeight), selectedPreset.spoolWeightG) : 0; const pct = Math.min(100, Math.round((netWeight / 1000) * 100)); async function onSubmit(data: FormData): Promise { if (!selectedPresetId) { Alert.alert('Atenção', 'Selecione um preset de carretel.'); return; } setIsLoading(true); try { // TODO: CreateFilamentUseCase via container DI console.log('create filament', { ...data, material: selectedMaterial, colorHex: selectedColor, spoolPresetId: selectedPresetId }); router.back(); } catch { Alert.alert('Erro', 'Não foi possível salvar o filamento.'); } finally { setIsLoading(false); } } return ( {/* Header */} router.back()}> Novo Filamento {/* Cor */} COR DO FILAMENTO {hexInput} {PRESET_COLORS.map((c) => ( { setSelectedColor(c); setHexInput(c); }} style={[styles.colorDot, { backgroundColor: c }, selectedColor === c && styles.colorDotActive]} /> ))} {/* Material */} MATERIAL {MATERIALS.map((m) => ( setSelectedMaterial(m)} style={[styles.chip, selectedMaterial === m && styles.chipActive]} > {m} ))} {/* Marca e Modelo */} ( )} /> ( )} /> {/* Parâmetros de impressão */} PARÂMETROS DE IMPRESSÃO ( } /> )} /> ( } /> )} /> ( } /> )} /> {/* Preset */} PRESET DO CARRETEL router.push('/(app)/config/presets/new')}> + Personalizado {presets.map((p) => ( setSelectedPresetId(p.id)} style={[styles.presetItem, selectedPresetId === p.id && styles.presetItemActive]} > {p.name} {selectedPresetId === p.id && Carretel: {p.spoolWeightG}g} {p.spoolWeightG}g ))} {/* Calculadora */} CALCULADORA DE PESO Peso Total na Balança (g) ( g )} /> {netWeight > 0 && ( Filamento Disponível {totalWeight}g – {selectedPreset?.spoolWeightG}g {formatWeight(netWeight)} {pct}% )} {/* CTA fixo */}