import React, { useState, useEffect } from "react"; import { useNavigate } from "react-router-dom"; import { useAuth } from "../contexts/AuthContext"; import api, { addressAPI, userAPI, itemAPI } from "../services/api"; import AvailabilitySettings from "../components/AvailabilitySettings"; import ImageUpload from "../components/ImageUpload"; import ItemInformation from "../components/ItemInformation"; import LocationForm from "../components/LocationForm"; import DeliveryOptions from "../components/DeliveryOptions"; import PricingForm from "../components/PricingForm"; import RulesForm from "../components/RulesForm"; import { Address } from "../types"; interface ItemFormData { name: string; description: string; pickUpAvailable: boolean; inPlaceUseAvailable: boolean; pricePerHour?: number | string; pricePerDay?: number | string; replacementCost: number | string; address1: string; address2: string; city: string; state: string; zipCode: string; country: string; latitude?: number; longitude?: number; rules?: string; minimumRentalDays: number; needsTraining: boolean; generalAvailableAfter: string; generalAvailableBefore: string; specifyTimesPerDay: boolean; weeklyTimes: { sunday: { availableAfter: string; availableBefore: string }; monday: { availableAfter: string; availableBefore: string }; tuesday: { availableAfter: string; availableBefore: string }; wednesday: { availableAfter: string; availableBefore: string }; thursday: { availableAfter: string; availableBefore: string }; friday: { availableAfter: string; availableBefore: string }; saturday: { availableAfter: string; availableBefore: string }; }; } const CreateItem: React.FC = () => { const navigate = useNavigate(); const { user } = useAuth(); const [loading, setLoading] = useState(false); const [error, setError] = useState(""); const [formData, setFormData] = useState({ name: "", description: "", pickUpAvailable: false, inPlaceUseAvailable: false, pricePerDay: "", replacementCost: "", address1: "", address2: "", city: "", state: "", zipCode: "", country: "US", minimumRentalDays: 1, needsTraining: false, generalAvailableAfter: "09:00", generalAvailableBefore: "17:00", specifyTimesPerDay: false, weeklyTimes: { sunday: { availableAfter: "09:00", availableBefore: "17:00" }, monday: { availableAfter: "09:00", availableBefore: "17:00" }, tuesday: { availableAfter: "09:00", availableBefore: "17:00" }, wednesday: { availableAfter: "09:00", availableBefore: "17:00" }, thursday: { availableAfter: "09:00", availableBefore: "17:00" }, friday: { availableAfter: "09:00", availableBefore: "17:00" }, saturday: { availableAfter: "09:00", availableBefore: "17:00" }, }, }); const [imageFiles, setImageFiles] = useState([]); const [imagePreviews, setImagePreviews] = useState([]); const [priceType, setPriceType] = useState<"hour" | "day">("day"); const [userAddresses, setUserAddresses] = useState([]); const [selectedAddressId, setSelectedAddressId] = useState(""); const [addressesLoading, setAddressesLoading] = useState(true); useEffect(() => { fetchUserAddresses(); fetchUserAvailability(); }, []); const fetchUserAvailability = async () => { try { const response = await userAPI.getAvailability(); const userAvailability = response.data; setFormData((prev) => ({ ...prev, generalAvailableAfter: userAvailability.generalAvailableAfter, generalAvailableBefore: userAvailability.generalAvailableBefore, specifyTimesPerDay: userAvailability.specifyTimesPerDay, weeklyTimes: userAvailability.weeklyTimes, })); } catch (error) { console.error("Error fetching user availability:", error); // Use default values if fetch fails } }; useEffect(() => { // Auto-populate if user has exactly one address and addresses have finished loading if ( !addressesLoading && userAddresses.length === 1 && selectedAddressId === "" ) { const address = userAddresses[0]; setFormData((prev) => ({ ...prev, address1: address.address1, address2: address.address2 || "", city: address.city, state: address.state, zipCode: address.zipCode, country: address.country, latitude: address.latitude, longitude: address.longitude, })); setSelectedAddressId(address.id); } }, [userAddresses, addressesLoading]); const fetchUserAddresses = async () => { try { const response = await addressAPI.getAddresses(); setUserAddresses(response.data); } catch (error) { console.error("Error fetching addresses:", error); } finally { setAddressesLoading(false); } }; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); if (!user) { setError("You must be logged in to create a listing"); return; } setLoading(true); setError(""); try { // For now, we'll store image URLs as base64 strings // In production, you'd upload to a service like S3 const imageUrls = imagePreviews; // Construct location from address components const locationParts = [ formData.address1, formData.address2, formData.city, formData.state, formData.zipCode, formData.country, ].filter((part) => part && part.trim()); const location = locationParts.join(", "); const response = await api.post("/items", { ...formData, pricePerDay: formData.pricePerDay ? parseFloat(formData.pricePerDay.toString()) : undefined, pricePerHour: formData.pricePerHour ? parseFloat(formData.pricePerHour.toString()) : undefined, replacementCost: formData.replacementCost ? parseFloat(formData.replacementCost.toString()) : 0, availableAfter: formData.generalAvailableAfter, availableBefore: formData.generalAvailableBefore, specifyTimesPerDay: formData.specifyTimesPerDay, weeklyTimes: formData.weeklyTimes, location, images: imageUrls, }); // Auto-save address if user has no addresses and entered manual address if (userAddresses.length === 0 && formData.address1) { try { await addressAPI.createAddress({ address1: formData.address1, address2: formData.address2, city: formData.city, state: formData.state, zipCode: formData.zipCode, country: formData.country, latitude: formData.latitude, longitude: formData.longitude, isPrimary: true, }); } catch (addressError) { console.error("Failed to save address:", addressError); // Don't fail item creation if address save fails } } // Check if this is user's first item and save availability settings try { const userItemsResponse = await itemAPI.getItems({ owner: user.id }); const userItems = userItemsResponse.data.items || []; // If this is their first item (the one we just created), save availability to user if (userItems.length <= 1) { await userAPI.updateAvailability({ generalAvailableAfter: formData.generalAvailableAfter, generalAvailableBefore: formData.generalAvailableBefore, specifyTimesPerDay: formData.specifyTimesPerDay, weeklyTimes: formData.weeklyTimes, }); } } catch (availabilityError) { console.error("Failed to save availability:", availabilityError); // Don't fail item creation if availability save fails } navigate(`/items/${response.data.id}`); } catch (err: any) { setError(err.response?.data?.error || "Failed to create listing"); } finally { setLoading(false); } }; const handleChange = ( e: React.ChangeEvent< HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement > ) => { const { name, value, type } = e.target; if (type === "checkbox") { const checked = (e.target as HTMLInputElement).checked; setFormData((prev) => ({ ...prev, [name]: checked })); } else if (type === "number") { setFormData((prev) => ({ ...prev, [name]: value === "" ? "" : parseFloat(value) || 0, })); } else { setFormData((prev) => ({ ...prev, [name]: value })); } }; const handleAddressSelect = (addressId: string) => { if (addressId === "new") { // Clear form for new address entry setFormData((prev) => ({ ...prev, address1: "", address2: "", city: "", state: "", zipCode: "", country: "US", })); setSelectedAddressId(""); } else { const selectedAddress = userAddresses.find( (addr) => addr.id === addressId ); if (selectedAddress) { setFormData((prev) => ({ ...prev, address1: selectedAddress.address1, address2: selectedAddress.address2 || "", city: selectedAddress.city, state: selectedAddress.state, zipCode: selectedAddress.zipCode, country: selectedAddress.country, latitude: selectedAddress.latitude, longitude: selectedAddress.longitude, })); setSelectedAddressId(addressId); } } }; const formatAddressDisplay = (address: Address) => { return `${address.address1}, ${address.city}, ${address.state} ${address.zipCode}`; }; const handleWeeklyTimeChange = ( day: string, field: "availableAfter" | "availableBefore", value: string ) => { setFormData((prev) => ({ ...prev, weeklyTimes: { ...prev.weeklyTimes, [day]: { ...prev.weeklyTimes[day as keyof typeof prev.weeklyTimes], [field]: value, }, }, })); }; const handleImageChange = (e: React.ChangeEvent) => { const files = Array.from(e.target.files || []); // Limit to 5 images if (imageFiles.length + files.length > 5) { setError("You can upload a maximum of 5 images"); return; } const newImageFiles = [...imageFiles, ...files]; setImageFiles(newImageFiles); // Create previews files.forEach((file) => { const reader = new FileReader(); reader.onloadend = () => { setImagePreviews((prev) => [...prev, reader.result as string]); }; reader.readAsDataURL(file); }); }; const removeImage = (index: number) => { setImageFiles((prev) => prev.filter((_, i) => i !== index)); setImagePreviews((prev) => prev.filter((_, i) => i !== index)); }; return (

List an Item for Rent

{error && (
{error}
)}
{/* Availability Card */}
{ setFormData((prev) => ({ ...prev, [field]: value })); }} onWeeklyTimeChange={handleWeeklyTimeChange} />
); }; export default CreateItem;