import { getTenantByNameDetail } from '@/services/tenant.service' import { CustomTenantDto } from '@/proxy/config/models' import { FaArrowLeft, FaArrowRight, FaDollarSign, FaMoneyBillWave, FaBuilding, FaGlobe, FaEnvelope, FaMap, FaMapPin, FaPhone, FaSearch, FaUser, FaUserPlus, } from 'react-icons/fa' import React, { useEffect, useState } from 'react' import { useNavigate } from 'react-router-dom' import { useLocalization } from '@/utils/hooks/useLocalization' import { ROUTES_ENUM } from '@/routes/route.constant' import { Button, Select } from '@/components/ui' import { CityDto, CountryDto, DistrictDto, getCities, getCountries, getDistricts, } from '@/services/location.service' interface LocationOption { label: string value: string data: T } const EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ const DEFAULT_PHONE_FORMAT = '000 000 000 000 000' const TURKEY_PHONE_FORMAT = '(000) 000-0000' const REQUIRED_NEW_CUSTOMER_FIELDS: Array = [ 'organizationName', 'founder', 'country', 'city', 'district', 'postalCode', 'address1', 'phoneNumber', 'email', 'taxOffice', 'vknTckn', ] const REQUIRED_EXISTING_CUSTOMER_FIELDS: Array = [ 'id', 'name', 'organizationName', 'founder', 'country', 'city', 'district', 'address1', 'email', ] const getPhoneFormat = (country?: CountryDto) => country?.phoneNumberFormat || (country?.phoneCode === 90 ? TURKEY_PHONE_FORMAT : DEFAULT_PHONE_FORMAT) const getPhoneMaxLength = (country?: CountryDto) => country?.phoneNumberMaxLength ?? getPhoneFormat(country).replace(/[^0]/g, '').length const getPhoneMinLength = (country?: CountryDto) => country?.phoneNumberMinLength ?? getPhoneMaxLength(country) const getNationalPhoneDigits = (value: string, country?: CountryDto) => { let digits = value.replace(/\D/g, '') if (!country) return digits const code = String(country.phoneCode) if (value.trimStart().startsWith('+') && digits.startsWith(code)) { digits = digits.slice(code.length) } return digits } const getPhoneValidationError = (value: string, country?: CountryDto) => { if (!country) return 'Lütfen önce ülke seçin.' const length = getNationalPhoneDigits(value, country).length const minLength = getPhoneMinLength(country) const maxLength = getPhoneMaxLength(country) if (length >= minLength && length <= maxLength) return '' return minLength === maxLength ? `Telefon numarası ${minLength} haneli olmalıdır.` : `Telefon numarası ${minLength}-${maxLength} hane arasında olmalıdır.` } const formatPhoneNumber = (value: string, country?: CountryDto) => { if (!country) return value.replace(/\D/g, '').slice(0, 15) const maxLength = getPhoneMaxLength(country) const digits = getNationalPhoneDigits(value, country).slice(0, maxLength) const format = getPhoneFormat(country) let digitIndex = 0 let nationalNumber = '' for (const character of format) { if (character === '0') { if (digitIndex >= digits.length) break nationalNumber += digits[digitIndex] digitIndex += 1 } else if (digitIndex === 0) { if (digits.length > 0) nationalNumber += character } else if (digitIndex < digits.length || character === ')') { nationalNumber += character } else { break } } return `+${country.phoneCode}${nationalNumber ? ` ${nationalNumber}` : ''}` } const isBlankValue = (value: unknown) => value === undefined || value === null || String(value).trim() === '' const hasRequiredFields = ( tenant: Partial, fields: Array, ) => fields.every((field) => !isBlankValue(tenant[field])) const normalizeCode = (value?: string) => value?.trim().toLowerCase() || '' interface TenantFormProps { onSubmit: (tenant: CustomTenantDto) => void onBack: () => void } export const TenantForm: React.FC = ({ onSubmit }) => { const [isExisting, setIsExisting] = useState(true) const [formData, setFormData] = useState>({}) const [countries, setCountries] = useState([]) const [cities, setCities] = useState([]) const [districts, setDistricts] = useState([]) const [isLoadingCountries, setIsLoadingCountries] = useState(false) const [isLoadingCities, setIsLoadingCities] = useState(false) const [isLoadingDistricts, setIsLoadingDistricts] = useState(false) const [isLoadingTenant, setIsLoadingTenant] = useState(false) const [emailError, setEmailError] = useState('') const [phoneError, setPhoneError] = useState('') const [existingTenantError, setExistingTenantError] = useState('') const [formError, setFormError] = useState('') const [foundTenantName, setFoundTenantName] = useState('') const navigate = useNavigate() const { translate } = useLocalization() useEffect(() => { const loadCountries = async () => { setIsLoadingCountries(true) try { const response = await getCountries() setCountries(response.data) const defaultCountry = response.data.find((country) => country.name === 'Türkiye') if (defaultCountry) { setFormData((prev) => prev.country ? prev : { ...prev, country: defaultCountry.name, city: '', district: '', phoneNumber: `+${defaultCountry.phoneCode}`, }, ) setIsLoadingCities(true) try { const cityResponse = await getCities(defaultCountry.name) setCities(cityResponse.data) } catch (error) { console.error('Şehirler alınırken hata:', error) } finally { setIsLoadingCities(false) } } } catch (error) { console.error('Ülkeler alınırken hata:', error) } finally { setIsLoadingCountries(false) } } void loadCountries() }, []) const selectedCountry = countries.find((country) => country.name === formData.country) const phoneMask = selectedCountry ? `+${selectedCountry.phoneCode} ${getPhoneFormat(selectedCountry)}` : DEFAULT_PHONE_FORMAT const canSubmitExistingTenant = Boolean( formData.id && formData.organizationName && normalizeCode(foundTenantName) === normalizeCode(formData.name), ) && !isLoadingTenant const handleSubmit = (e: React.FormEvent) => { e.preventDefault() let hasValidationError = false setFormError('') if (isExisting) { if (!formData.name?.trim()) { setExistingTenantError('Lütfen önce organization code girin.') return } if ( !formData.id || normalizeCode(foundTenantName) !== normalizeCode(formData.name) || !formData.organizationName ) { setExistingTenantError('Devam etmek için önce organization code ile kurum bilgisini bulun.') return } if (!hasRequiredFields(formData, REQUIRED_EXISTING_CUSTOMER_FIELDS)) { setExistingTenantError('Kurum bilgileri eksik geldi. Lütfen kurum kodunu tekrar aratın.') return } onSubmit({ ...formData, isExisting: true } as CustomTenantDto) return } if (!hasRequiredFields(formData, REQUIRED_NEW_CUSTOMER_FIELDS)) { setFormError('Lütfen zorunlu alanları eksiksiz doldurun.') hasValidationError = true } const nextPhoneError = getPhoneValidationError(formData.phoneNumber || '', selectedCountry) setPhoneError(nextPhoneError) if (nextPhoneError) { hasValidationError = true } if (!isExisting && !EMAIL_PATTERN.test(formData.email || '')) { setEmailError('Lütfen geçerli bir e-posta adresi girin.') hasValidationError = true } if (hasValidationError) return onSubmit({ ...formData, isExisting: false } as CustomTenantDto) } const handleInputChange = (field: keyof CustomTenantDto, value: string) => { setFormData((prev) => ({ ...prev, [field]: value })) } const resetExistingTenantDetails = (name: string) => { setFoundTenantName('') setExistingTenantError('') setFormError('') setFormData({ name }) } const handleCountryChange = async (option: LocationOption | null) => { const country = option?.data setFormData((prev) => ({ ...prev, country: country?.name || '', city: '', district: '', phoneNumber: country ? `+${country.phoneCode}` : '', })) setCities([]) setDistricts([]) setPhoneError('') if (!country) return setIsLoadingCities(true) try { const response = await getCities(country.name) setCities(response.data) } catch (error) { console.error('Şehirler alınırken hata:', error) } finally { setIsLoadingCities(false) } } const handleCityChange = async (option: LocationOption | null) => { const city = option?.data setFormData((prev) => ({ ...prev, city: city?.name || '', district: '' })) setDistricts([]) if (!city || !formData.country) return setIsLoadingDistricts(true) try { const response = await getDistricts(formData.country, city.name) setDistricts(response.data) } catch (error) { console.error('İlçeler alınırken hata:', error) } finally { setIsLoadingDistricts(false) } } const countryOptions: LocationOption[] = countries.map((country) => ({ label: country.name, value: country.name, data: country, })) const cityOptions: LocationOption[] = cities.map((city) => ({ label: city.name, value: city.name, data: city, })) const districtOptions: LocationOption[] = districts.map((district) => ({ label: district.name, value: district.name, data: district, })) const getTenantInfo = async () => { const tenantName = formData.name?.trim() if (!tenantName) { setExistingTenantError('Lütfen önce organization code girin.') return } setIsLoadingTenant(true) setExistingTenantError('') setFormError('') try { const tenant = await getTenantByNameDetail(tenantName) setFormData((prev) => ({ ...prev, id: tenant.data.id, name: tenant.data.name, isActive: tenant.data.isActive, organizationName: tenant.data.organizationName, founder: tenant.data.founder, vknTckn: tenant.data.vknTckn, taxOffice: tenant.data.taxOffice, address1: tenant.data.address1, address2: tenant.data.address2, district: tenant.data.district, country: tenant.data.country, city: tenant.data.city, postalCode: tenant.data.postalCode, phoneNumber: tenant.data.phoneNumber, mobileNumber: tenant.data.mobileNumber, faxNumber: tenant.data.faxNumber, email: tenant.data.email, website: tenant.data.website, menuGroup: tenant.data.menuGroup, })) setFoundTenantName(tenant.data.name) } catch (error) { setFoundTenantName('') setExistingTenantError('Kurum bulunamadı. Lütfen organization code bilgisini kontrol edin.') console.error('Kurum bilgisi alınırken hata:', error) } finally { setIsLoadingTenant(false) } } return (

{' '} {translate('::Public.payment.customerInfo')}

{isExisting !== null && (
{isExisting ? (
resetExistingTenantDetails(e.target.value)} onKeyDown={async (e) => { if (e.key === 'Enter') { e.preventDefault() await getTenantInfo() } }} className="h-[40px] w-full pl-10 pr-4 border border-gray-300 rounded-lg bg-white text-gray-900 placeholder-gray-500 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-100 dark:placeholder-gray-400 sm:rounded-l-lg sm:rounded-r-none focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all" />
{existingTenantError && (

{existingTenantError}

)} {!existingTenantError && formData.name && !canSubmitExistingTenant && !isLoadingTenant && (

Devam etmek için önce Find Organization ile kurum bilgilerini getirin.

)} {formData.organizationName && (
{translate('::LoginPanel.Profil')} {formData.founder}
{translate('::Public.payment.customer.company')} {formData.organizationName}
{translate('::Abp.Account.EmailAddress')}: {formData.email}
{translate('::blog.categories.mobile')}: {formData.mobileNumber}
{translate('::App.Address')}:
{formData.address1}
{translate('::Public.payment.customer.country')}: {formData.country}
{translate('::Public.common.city')}: {formData.city}
{translate('::Public.payment.customer.district')}: {formData.district}
{translate('::Public.payment.customer.postalCode')}: {formData.postalCode}
{translate('::Public.contact.taxOffice')}: {formData.taxOffice}
{translate('::Public.contact.taxNumber')}: {formData.vknTckn}
{formData.reference && (
{translate('::Public.payment.customer.reference')}: {formData.reference}
)}
)}
) : (
handleInputChange('organizationName', e.target.value)} className="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg bg-white text-gray-900 placeholder-gray-500 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-100 dark:placeholder-gray-400 focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all" />
handleInputChange('founder', e.target.value)} className="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg bg-white text-gray-900 placeholder-gray-500 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-100 dark:placeholder-gray-400 focus:ring-2 focus:ring-blue-500 focus:border-transparent" />
> required isClearable isLoading={isLoadingCountries} options={countryOptions} value={ countryOptions.find((option) => option.value === formData.country) || null } onChange={handleCountryChange} placeholder="Ülke seçin" />
> required isClearable isDisabled={!formData.country} isLoading={isLoadingCities} options={cityOptions} value={cityOptions.find((option) => option.value === formData.city) || null} onChange={handleCityChange} placeholder={formData.country ? 'Şehir seçin' : 'Önce ülke seçin'} />
> required isClearable isDisabled={!formData.city} isLoading={isLoadingDistricts} options={districtOptions} value={ districtOptions.find((option) => option.value === formData.district) || null } onChange={(option) => handleInputChange('district', option?.data.name || '') } placeholder={formData.city ? 'İlçe seçin' : 'Önce şehir seçin'} />
handleInputChange('postalCode', e.target.value)} className="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-lg bg-white text-gray-900 placeholder-gray-500 dark:border-gray-700 dark:bg-gray-800 dark:text-gray-100 dark:placeholder-gray-400 focus:ring-2 focus:ring-blue-500 focus:border-transparent" />