import { useState } from 'react' import axios from 'axios' import './App.css' const API_URL = 'http://localhost:8000' function App() { const [ipAddress, setIpAddress] = useState('') const [cidr, setCidr] = useState('24') const [subnetMask, setSubnetMask] = useState('') const [inputType, setInputType] = useState('cidr') // 'cidr' or 'mask' const [result, setResult] = useState(null) const [loading, setLoading] = useState(false) const [error, setError] = useState('') // Validate IP address format const validateIpAddress = (ip) => { if (!ip || !ip.trim()) { return 'IP address is required' } const ipPattern = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/ if (!ipPattern.test(ip)) { return 'Invalid IP format. Expected: xxx.xxx.xxx.xxx' } const octets = ip.split('.') for (let i = 0; i < octets.length; i++) { const num = parseInt(octets[i]) if (isNaN(num) || num < 0 || num > 255) { return `Invalid octet ${i + 1}: must be between 0-255` } } return null } // Validate subnet mask format const validateSubnetMask = (mask) => { if (!mask || !mask.trim()) { return 'Subnet mask is required' } const parts = mask.split('.') if (parts.length !== 4) { return 'Subnet mask must have 4 octets' } // Check each octet is 0-255 for (let part of parts) { const num = parseInt(part) if (isNaN(num) || num < 0 || num > 255) { return 'Each octet must be between 0-255' } } // Common valid subnet masks const validMasks = [ '255.255.255.255', '255.255.255.254', '255.255.255.252', '255.255.255.248', '255.255.255.240', '255.255.255.224', '255.255.255.192', '255.255.255.128', '255.255.255.0', '255.255.254.0', '255.255.252.0', '255.255.248.0', '255.255.240.0', '255.255.224.0', '255.255.192.0', '255.255.128.0', '255.255.0.0', '255.254.0.0', '255.252.0.0', '255.248.0.0', '255.240.0.0', '255.224.0.0', '255.192.0.0', '255.128.0.0', '255.0.0.0', '254.0.0.0', '252.0.0.0', '248.0.0.0', '240.0.0.0', '224.0.0.0', '192.0.0.0', '128.0.0.0', '0.0.0.0' ] if (!validMasks.includes(mask)) { return 'Invalid subnet mask (bits must be contiguous)' } return null } const calculateSubnet = async (e) => { e.preventDefault() setError('') setResult(null) // Frontend validation const ipError = validateIpAddress(ipAddress) if (ipError) { setError(ipError) return } if (inputType === 'cidr') { const cidrNum = parseInt(cidr) if (isNaN(cidrNum) || cidrNum < 0 || cidrNum > 32) { setError('CIDR must be between 0 and 32') return } } else { const maskError = validateSubnetMask(subnetMask) if (maskError) { setError(maskError) return } } setLoading(true) try { const payload = { ip_address: ipAddress, } if (inputType === 'cidr') { payload.cidr = parseInt(cidr) } else { payload.subnet_mask = subnetMask } const response = await axios.post(`${API_URL}/calculate`, payload) setResult(response.data) } catch (err) { const errorMessage = err.response?.data?.detail || err.message || 'Failed to calculate subnet' setError(errorMessage) } finally { setLoading(false) } } const InfoCard = ({ label, value, highlight }) => (