import React, { useState } from 'react'; import { View, Text, ScrollView, TouchableOpacity, TextInput, StyleSheet, Alert, } from 'react-native'; import { useLocalSearchParams, 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 Edição de Filamento — 13O-0 */ export default function EditFilamentScreen(): React.ReactElement { const { id } = useLocalSearchParams<{ id: string }>(); const router = useRouter(); const { presets, systemPresets } = usePresetStore(); const { filaments, updateFilament, removeFilament } = useFilamentStore(); const filament = filaments.find((f) => f.id === id); const [selectedColor, setSelectedColor] = useState(filament?.colorHex ?? '#E05533'); const [hexInput, setHexInput] = useState(filament?.colorHex ?? '#E05533'); const [selectedMaterial, setSelectedMaterial] = useState((filament?.material as Material) ?? 'PLA'); const [selectedPresetId, setSelectedPresetId] = useState(filament?.spoolPresetId ?? systemPresets[0]?.id ?? null); const [isLoading, setIsLoading] = useState(false); const { control, handleSubmit, watch, formState: { errors } } = useForm({ resolver: zodResolver(schema), defaultValues: { brand: filament?.brand ?? '', model: filament?.model ?? '', totalWeightG: filament?.totalWeightG ?? 0, tempHotendC: filament?.tempHotendC ?? 210, tempBedC: filament?.tempBedC ?? 60, flowFactorPct: filament?.flowFactorPct ?? 100, notes: filament?.notes ?? '', }, }); 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)); if (!filament) { return ( Filamento não encontrado router.back()}> Voltar ); } function handleDelete(): void { Alert.alert( 'Excluir filamento', `Deseja excluir "${filament!.brand}${filament!.model ? ` ${filament!.model}` : ''}"? Esta ação não pode ser desfeita.`, [ { text: 'Cancelar', style: 'cancel' }, { text: 'Excluir', style: 'destructive', onPress: () => { removeFilament(filament!.id); router.replace('/(app)/(tabs)/inventory'); }, }, ], ); } async function onSubmit(data: FormData): Promise { if (!selectedPresetId) { Alert.alert('Atenção', 'Selecione um preset de carretel.'); return; } setIsLoading(true); try { // TODO: UpdateFilamentUseCase via container DI const updated = { ...filament!, brand: data.brand, model: data.model ?? null, colorHex: selectedColor, material: selectedMaterial, spoolPresetId: selectedPresetId, totalWeightG: Number(data.totalWeightG), netWeightG: netWeight, tempHotendC: data.tempHotendC ?? null, tempBedC: data.tempBedC ?? null, flowFactorPct: data.flowFactorPct ?? null, notes: data.notes ?? null, updatedAt: new Date().toISOString(), }; updateFilament(updated); router.back(); } catch { Alert.alert('Erro', 'Não foi possível salvar as alterações.'); } finally { setIsLoading(false); } } return ( {/* Header */} router.back()}> Editar 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' as never)}> + 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 */}