import React, { useEffect, useState } from 'react'; import { Box, Text, useInput } from 'ink'; import type { CustomerType, CountryDTO } from '@effigenix/api-client'; import { useNavigation } from '../../../state/navigation-context.js'; import { useCustomers } from '../../../hooks/useCustomers.js'; import { FormInput } from '../../shared/FormInput.js'; import { CountryPicker } from '../../shared/CountryPicker.js'; import { LoadingSpinner } from '../../shared/LoadingSpinner.js'; import { ErrorDisplay } from '../../shared/ErrorDisplay.js'; import { client } from '../../../utils/api-client.js'; import { DEFAULT_COUNTRY, DACH_FALLBACK } from '../../shared/country-defaults.js'; type Field = 'name' | 'phone' | 'email' | 'street' | 'houseNumber' | 'postalCode' | 'city' | 'countryPicker' | 'paymentDueDays'; const FIELDS: Field[] = ['name', 'phone', 'email', 'street', 'houseNumber', 'postalCode', 'city', 'countryPicker', 'paymentDueDays']; const FIELD_LABELS: Record = { name: 'Name *', phone: 'Telefon *', email: 'E-Mail', street: 'Straße *', houseNumber: 'Hausnummer *', postalCode: 'PLZ *', city: 'Stadt *', countryPicker: 'Land *', paymentDueDays: 'Zahlungsziel (Tage)', }; const TYPES: CustomerType[] = ['B2B', 'B2C']; export function CustomerCreateScreen() { const { replace, back } = useNavigation(); const { createCustomer, loading, error, clearError } = useCustomers(); const [values, setValues] = useState, string>>({ name: '', phone: '', email: '', street: '', houseNumber: '', postalCode: '', city: '', paymentDueDays: '', }); const [typeIndex, setTypeIndex] = useState(0); const [activeField, setActiveField] = useState('name'); const [fieldErrors, setFieldErrors] = useState>>({}); const [countryQuery, setCountryQuery] = useState(''); const [countryCode, setCountryCode] = useState(DEFAULT_COUNTRY.code); const [countryName, setCountryName] = useState(DEFAULT_COUNTRY.name); const [countries, setCountries] = useState([]); useEffect(() => { client.countries.search().then(setCountries).catch(() => setCountries(DACH_FALLBACK)); }, []); const setField = (field: Exclude) => (value: string) => { setValues((v) => ({ ...v, [field]: value })); }; useInput((_input, key) => { if (loading) return; if (activeField === 'type') { if (key.leftArrow) setTypeIndex((i) => Math.max(0, i - 1)); if (key.rightArrow) setTypeIndex((i) => Math.min(TYPES.length - 1, i + 1)); if (key.tab || key.downArrow || key.return) setActiveField('name'); } else { if (key.tab || key.downArrow) { setActiveField((f) => { if (f === 'type') return 'name'; const idx = FIELDS.indexOf(f as Field); return FIELDS[(idx + 1) % FIELDS.length] ?? f; }); } if (key.upArrow) { setActiveField((f) => { if (f === 'type') return f; const idx = FIELDS.indexOf(f as Field); if (idx === 0) return 'type'; return FIELDS[idx - 1] ?? f; }); } } if (key.escape) back(); }); const handleSubmit = async () => { const errors: Partial> = {}; if (!values.name.trim()) errors.name = 'Name ist erforderlich.'; if (!values.phone.trim()) errors.phone = 'Telefon ist erforderlich.'; if (!values.street.trim()) errors.street = 'Straße ist erforderlich.'; if (!values.houseNumber.trim()) errors.houseNumber = 'Hausnummer ist erforderlich.'; if (!values.postalCode.trim()) errors.postalCode = 'PLZ ist erforderlich.'; if (!values.city.trim()) errors.city = 'Stadt ist erforderlich.'; if (!countryCode) errors.countryPicker = 'Land ist erforderlich.'; setFieldErrors(errors); if (Object.keys(errors).length > 0) return; const result = await createCustomer({ name: values.name.trim(), type: TYPES[typeIndex] ?? 'B2B', phone: values.phone.trim(), street: values.street.trim(), houseNumber: values.houseNumber.trim(), postalCode: values.postalCode.trim(), city: values.city.trim(), country: countryCode, ...(values.email.trim() ? { email: values.email.trim() } : {}), ...(values.paymentDueDays.trim() ? { paymentDueDays: parseInt(values.paymentDueDays, 10) } : {}), }); if (result) replace('customer-list'); }; const handleFieldSubmit = (field: Field) => (_value: string) => { const idx = FIELDS.indexOf(field); if (idx < FIELDS.length - 1) { setActiveField(FIELDS[idx + 1] ?? field); } else { void handleSubmit(); } }; if (loading) return ; return ( Neuer Kunde {error && } {/* Type Selector */} Typ * {'< '} {TYPES[typeIndex]} {' >'} {activeField === 'type' && ←→ Typ · Tab/Enter weiter} {FIELDS.map((field) => { if (field === 'countryPicker') { return ( { setCountryCode(c.code); setCountryName(c.name); setCountryQuery(''); const idx = FIELDS.indexOf('countryPicker'); if (idx < FIELDS.length - 1) { setActiveField(FIELDS[idx + 1] ?? 'countryPicker'); } }} focus={activeField === 'countryPicker'} selectedName={countryName} /> ); } const f = field as Exclude; return ( ); })} Tab/↑↓ Feld · ←→ Typ · Enter auf letztem Feld speichern · Escape Abbrechen ); }