import { useState, useEffect } from 'react' import { fetchUserIp } from '../api/latency' import { useLanguage } from '../contexts/LanguageContext' import './IpInput.css' interface IpInputProps { onTest: (target: string) => void testing: boolean } const IP_REGEX = /^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)$/ const DOMAIN_REGEX = /^([a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/ function normalizeTarget(value: string): string { let target = value.trim().toLowerCase() // Remove protocol prefix if present target = target.replace(/^https?:\/\//, '') // Strip userinfo if a full URL with credentials was pasted const atIndex = target.lastIndexOf('@') if (atIndex !== -1) { target = target.slice(atIndex + 1) } // Remove path, query, and fragment target = target.split(/[/?#]/)[0] // Remove port if present target = target.split(':')[0] return target } function isValidTarget(value: string): boolean { const normalized = normalizeTarget(value) return IP_REGEX.test(normalized) || DOMAIN_REGEX.test(normalized) } export default function IpInput({ onTest, testing }: IpInputProps) { const [target, setTarget] = useState('') const [loading, setLoading] = useState(true) const [error, setError] = useState('') const { t } = useLanguage() useEffect(() => { fetchUserIp() .then(setTarget) .catch(() => setError(t('IP检测失败', 'Failed to detect IP'))) .finally(() => setLoading(false)) }, [t]) const handleSubmit = (e: React.FormEvent) => { e.preventDefault() if (!isValidTarget(target)) { setError(t('无效的IP地址或域名', 'Invalid IP address or domain')) return } const normalized = normalizeTarget(target) setTarget(normalized) // Update display to show normalized value setError('') onTest(normalized) } return (
{ setTarget(e.target.value) setError('') }} placeholder={loading ? t('正在检测IP...', 'Detecting IP...') : t('输入IP或域名', 'Enter IP or domain')} className={`ip-input ${error ? 'ip-input-error' : ''}`} disabled={testing || loading} /> {error && {error}}
) }