import { useState, useEffect, useCallback } from 'react'; import { Button, Input, Select, Modal } from '../ui'; import { pickupOptions } from '../../constants/pickup'; import { formatDateForInput, parseDateFromInput, getTodayFrontend } from '../../utils/date'; import type { Delivery, PickupLocation, DeliveryStatus } from '../../types'; interface DeliveryFormProps { isOpen: boolean; onClose: () => void; onSubmit: (delivery: Omit) => void | Promise; initialData?: Delivery | null; defaultDate?: string; isSubmitting?: boolean; } // Phone validation regex for Kazakhstan numbers const PHONE_REGEX = /^\+7\s?\(?\d{3}\)?\s?\d{3}[\s-]?\d{2}[\s-]?\d{2}$/; // City is not shown in UI but is included in the saved address (used for 2GIS search). const CITY_LABEL = 'Кокшетау'; const buildAddressString = ( street: string, house: string, apartment: string, entrance: string, ): string => { const parts: string[] = [CITY_LABEL]; if (street) parts.push(`ул. ${street}`); if (house) parts.push(`д. ${house}`); if (apartment) parts.push(`кв. ${apartment}`); if (entrance) parts.push(`подъезд ${entrance}`); return parts.join(', '); }; export const DeliveryForm = ({ isOpen, onClose, onSubmit, initialData, defaultDate, isSubmitting }: DeliveryFormProps) => { const [formData, setFormData] = useState({ date: defaultDate || getTodayFrontend(), pickupLocation: 'warehouse' as PickupLocation, pickupLocation2: null as PickupLocation | null, productName: '', productName2: '', customerName: '', address: '', street: '', house: '', apartment: '', entrance: '', floor: '', phone: '', additionalPhone: '', hasElevator: false, serviceInfo: '', comment: '', status: 'new' as DeliveryStatus, }); const [showSecondPickup, setShowSecondPickup] = useState(false); useEffect(() => { if (initialData) { setFormData({ date: initialData.date, pickupLocation: initialData.pickupLocation, pickupLocation2: initialData.pickupLocation2 || null, productName: initialData.productName, productName2: initialData.productName2 || '', customerName: initialData.customerName, address: initialData.address, street: initialData.street, house: initialData.house, apartment: initialData.apartment || '', entrance: initialData.entrance || '', floor: initialData.floor || '', phone: initialData.phone, additionalPhone: initialData.additionalPhone || '', hasElevator: initialData.hasElevator, serviceInfo: initialData.serviceInfo || '', comment: initialData.comment, status: initialData.status, }); setShowSecondPickup(!!initialData.pickupLocation2); } else if (defaultDate) { setFormData(prev => ({ ...prev, date: defaultDate })); } }, [initialData, defaultDate, isOpen]); const validatePhone = useCallback((phone: string): boolean => { if (!phone) return false; return PHONE_REGEX.test(phone); }, []); const isPhoneValid = !formData.phone || validatePhone(formData.phone); const isAdditionalPhoneValid = !formData.additionalPhone || validatePhone(formData.additionalPhone); const isFormValid = formData.productName && formData.phone && isPhoneValid && formData.customerName && formData.street && formData.house; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!isFormValid) return; try { const payload = { ...formData, address: buildAddressString(formData.street, formData.house, formData.apartment, formData.entrance), }; await onSubmit(payload); if (!initialData) { setFormData({ date: defaultDate || getTodayFrontend(), pickupLocation: 'warehouse', pickupLocation2: null, productName: '', productName2: '', customerName: '', address: '', street: '', house: '', apartment: '', entrance: '', floor: '', phone: '', additionalPhone: '', hasElevator: false, serviceInfo: '', comment: '', status: 'new', }); setShowSecondPickup(false); } onClose(); } catch { // Error is handled by parent, keep form open } }; return ( } >
setFormData({ ...formData, date: parseDateFromInput(e.target.value) })} className="w-full px-3 py-2 bg-[#f5f3f5] border border-[#c5c6cd] rounded-md text-[#1b1b1d] focus:outline-none focus:ring-2 focus:ring-[#1B263B] focus:border-transparent transition-colors" required />
setFormData({ ...formData, productName: e.target.value })} placeholder="Введите название товара" required /> {/* Address fields */}

Адрес доставки

setFormData({ ...formData, street: e.target.value })} className="w-full px-2 py-1.5 bg-white border border-[#c5c6cd] rounded text-sm" required />
setFormData({ ...formData, house: e.target.value })} className="w-full px-2 py-1.5 bg-white border border-[#c5c6cd] rounded text-sm" required />
setFormData({ ...formData, apartment: e.target.value })} className="w-full px-2 py-1.5 bg-white border border-[#c5c6cd] rounded text-sm" />
setFormData({ ...formData, entrance: e.target.value })} className="w-full px-2 py-1.5 bg-white border border-[#c5c6cd] rounded text-sm" />
setFormData({ ...formData, floor: e.target.value })} className="w-full px-2 py-1.5 bg-white border border-[#c5c6cd] rounded text-sm" />
setFormData({ ...formData, customerName: e.target.value })} placeholder="Иванов Иван Иванович" required /> setFormData({ ...formData, phone: e.target.value })} onFocus={(e) => { if (!e.target.value) { setFormData({ ...formData, phone: '+7' }); } }} placeholder="+7 (776)-567-89-01" required aria-invalid={!isPhoneValid} aria-describedby={!isPhoneValid ? 'phone-error' : undefined} /> {!isPhoneValid && formData.phone && (

Введите корректный номер: +7 (XXX) XXX-XX-XX

)} setFormData({ ...formData, additionalPhone: e.target.value })} onFocus={(e) => { if (!e.target.value) { setFormData({ ...formData, additionalPhone: '+7' }); } }} placeholder="+7 (776)-567-89-01" aria-invalid={!isAdditionalPhoneValid} aria-describedby={!isAdditionalPhoneValid ? 'additional-phone-error' : undefined} /> {!isAdditionalPhoneValid && formData.additionalPhone && (

Введите корректный номер: +7 (XXX) XXX-XX-XX

)} {/* Second pickup location */}
{ setShowSecondPickup(e.target.checked); if (!e.target.checked) { setFormData({ ...formData, pickupLocation2: null, productName2: '' }); } }} className="w-4 h-4 text-[#1B263B] border-[#c5c6cd] rounded focus:ring-[#1B263B]" />
{showSecondPickup && (

Вторая точка загрузки

setFormData({ ...formData, productName2: e.target.value })} placeholder="Название товара со второй точки" />
)}
setFormData({ ...formData, hasElevator: e.target.checked })} className="w-4 h-4 text-[#1B263B] border-[#c5c6cd] rounded focus:ring-[#1B263B]" />
setFormData({ ...formData, serviceInfo: e.target.value })} placeholder="Сборка 5000 тг, подъём на этаж 3000 тг" /> setFormData({ ...formData, comment: e.target.value })} placeholder="Дополнительная информация..." />
); };