Address Manager - Copy this React, Tailwind Component to your project
Import React, { useState } from "react"; import { FaEdit, FaTimes, FaPlus } from "react icons/fa"; const AddressManager = () => { const [addresses, setAddresses] = useState([ { id: 1, address: "123 Main Street, Apt 4B", city: "New York", state: "NY", pincode: "10001", phone: "212 555 0123", notes: "Ring doorbell twice" }, { id: 2, address: "Delivered to My Neighbour if i am not at home", city: "Los Angeles", state: "CA", pincode: "90012", phone: "323 555 0189", notes: "Delivered to My Neighbour if i am not at home" } ]); const [isModalOpen, setIsModalOpen] = useState(false); const [currentAddress, setCurrentAddress] = useState(null); const [formErrors, setFormErrors] = useState({}); const handleEdit = (address) => { setCurrentAddress(address); setIsModalOpen(true); }; const handleAddNew = () => { setCurrentAddress({ id: addresses.length + 1, address: "", city: "", state: "", pincode: "", phone: "", notes: "" }); setIsModalOpen(true); }; const validateForm = (address) => { const errors = {}; if (!address.address.trim()) errors.address = "Address is required"; if (!address.city.trim()) errors.city = "City is required"; if (!address.state.trim()) errors.state = "State is required"; if (!address.pincode.trim()) errors.pincode = "Pincode is required"; if (!/^\d{10}$/.test(address.phone.replace(/\D/g, ""))) { errors.phone = "Valid phone number is required"; } return errors; }; const handleSave = (e) => { e.preventDefault(); const errors = validateForm(currentAddress); if (Object.keys(errors).length > 0) { setFormErrors(errors); return; } if (addresses.find(addr => addr.id === currentAddress.id)) { setAddresses(addresses.map((addr) => addr.id === currentAddress.id ? currentAddress : addr )); } else { setAddresses([...addresses, currentAddress]); } setIsModalOpen(false); setFormErrors({}); }; const handleInputChange = (e) => { const { name, value } = e.target; setCurrentAddress({ ...currentAddress, [name]: value }); }; return ( <div className="container mx auto px 4 py 8"> <div className="flex justify between items center mb 8"> <h1 className="text 3xl font bold">My Addresses</h1> <button onClick={handleAddNew} className="flex items center gap 2 px 4 py 2 bg blue 600 text white rounded md hover:bg blue 700 transition colors" > <FaPlus /> Add New Address </button> </div> <div className="grid gap 6 md:grid cols 2 lg:grid cols 3"> {addresses.map((address) => ( <div key={address.id} className="bg white rounded lg shadow md p 6 hover:shadow lg transition shadow duration 300 h [200px] overflow hidden" > <div className="flex justify between items start mb 4"> <div className="flex 1 overflow hidden"> <h2 className="text xl font semibold mb 2 truncate">{address.city}</h2> <p className="text gray 600 mb 1 truncate">{address.address}</p> <p className="text gray 600 mb 1 truncate">{`${address.city}, ${address.state} ${address.pincode}`}</p> <p className="text gray 600 mb 1 truncate">{address.phone}</p> {address.notes && ( <p className="text gray 500 italic text sm truncate">{address.notes}</p> )} </div> <button onClick={() => handleEdit(address)} className="text blue 600 hover:text blue 800 p 2" aria label="Edit address" > <FaEdit className="text xl" /> </button> </div> </div> ))} </div> {isModalOpen && currentAddress && ( <div className="fixed inset 0 bg black bg opacity 50 flex items center justify center p 4"> <div className="bg white rounded lg w full max w md p 6 relative"> <button onClick={() => { setIsModalOpen(false); setFormErrors({}); }} className="absolute right 4 top 4 text gray 600 hover:text gray 800" aria label="Close modal" > <FaTimes className="text xl" /> </button> <h2 className="text 2xl font bold mb 6"> {addresses.find(addr => addr.id === currentAddress.id) ? "Edit" : "Add New"} Address </h2> <form onSubmit={handleSave} className="space y 4"> <div> <label className="block text gray 700 mb 2" htmlFor="address"> Address </label> <input type="text" id="address" name="address" value={currentAddress.address} onChange={handleInputChange} className={`w full p 2 border rounded md ${formErrors.address ? "border red 500" : "border gray 300"}`} /> {formErrors.address && ( <p className="text red 500 text sm mt 1">{formErrors.address}</p> )} </div> <div className="grid grid cols 2 gap 4"> <div> <label className="block text gray 700 mb 2" htmlFor="city"> City </label> <input type="text" id="city" name="city" value={currentAddress.city} onChange={handleInputChange} className={`w full p 2 border rounded md ${formErrors.city ? "border red 500" : "border gray 300"}`} /> {formErrors.city && ( <p className="text red 500 text sm mt 1">{formErrors.city}</p> )} </div> <div> <label className="block text gray 700 mb 2" htmlFor="state"> State </label> <input type="text" id="state" name="state" value={currentAddress.state} onChange={handleInputChange} className={`w full p 2 border rounded md ${formErrors.state ? "border red 500" : "border gray 300"}`} /> {formErrors.state && ( <p className="text red 500 text sm mt 1">{formErrors.state}</p> )} </div> </div> <div className="grid grid cols 2 gap 4"> <div> <label className="block text gray 700 mb 2" htmlFor="pincode"> Pincode </label> <input type="text" id="pincode" name="pincode" value={currentAddress.pincode} onChange={handleInputChange} className={`w full p 2 border rounded md ${formErrors.pincode ? "border red 500" : "border gray 300"}`} /> {formErrors.pincode && ( <p className="text red 500 text sm mt 1">{formErrors.pincode}</p> )} </div> <div> <label className="block text gray 700 mb 2" htmlFor="phone"> Phone </label> <input type="tel" id="phone" name="phone" value={currentAddress.phone} onChange={handleInputChange} className={`w full p 2 border rounded md ${formErrors.phone ? "border red 500" : "border gray 300"}`} /> {formErrors.phone && ( <p className="text red 500 text sm mt 1">{formErrors.phone}</p> )} </div> </div> <div> <label className="block text gray 700 mb 2" htmlFor="notes"> Notes </label> <textarea id="notes" name="notes" value={currentAddress.notes} onChange={handleInputChange} rows="3" className="w full p 2 border border gray 300 rounded md" /> </div> <div className="flex justify end space x 4 mt 6"> <button type="button" onClick={() => { setIsModalOpen(false); setFormErrors({}); }} className="px 4 py 2 text gray 600 bg gray 100 rounded md hover:bg gray 200" > Cancel </button> <button type="submit" className="px 4 py 2 text white bg blue 600 rounded md hover:bg blue 700" > Save Changes </button> </div> </form> </div> </div> )} </div> ); }; export default AddressManager;
