import express from "express"; import pool from "../db/pool.js"; const router = express.Router(); // Get all listings router.get("/", async (req, res) => { const speciesId = req.query.species_id; const breedId = req.query.breed_id; const state = req.query.state; const district = req.query.district; const minPrice = req.query.min_price; const listingType = req.query.listing_type; let baseQuery = ` SELECT l.*, a.species_id, a.breed_id, loc.state, loc.district FROM listings l LEFT JOIN animals a ON a.id = l.animal_id LEFT JOIN locations loc ON loc.id = a.location_id WHERE 1=1 `; const queryParams = []; let paramIndex = 1; if (speciesId) { baseQuery += ` AND a.species_id = $${paramIndex}`; queryParams.push(speciesId); paramIndex++; } if (breedId) { baseQuery += ` AND a.breed_id = $${paramIndex}`; queryParams.push(breedId); paramIndex++; } if (state) { baseQuery += ` AND loc.state = $${paramIndex}`; queryParams.push(state); paramIndex++; } if (district) { baseQuery += ` AND loc.district = $${paramIndex}`; queryParams.push(district); paramIndex++; } if (minPrice) { baseQuery += ` AND l.price >= $${paramIndex}`; queryParams.push(minPrice); paramIndex++; } if (listingType) { baseQuery += ` AND l.listing_type = $${paramIndex}`; queryParams.push(listingType); paramIndex++; } try { const listingsResult = await pool.query(baseQuery, queryParams); res.status(200).json(listingsResult.rows); } catch (error) { res.status(500).json({ error: "Internal Server Error in fetching listings", }); } }); // Get listing by ID router.get("/:id", async (req, res) => { const listingId = req.params.id; try { const listingResult = await pool.query( "SELECT * FROM listings WHERE id = $1", [listingId] ); if (listingResult.rows.length === 0) { return res.status(404).json({ error: "Listing not found" }); } res.status(200).json(listingResult.rows[0]); } catch (error) { res.status(500).json({ error: `Internal Server Error in fetching the specified ${listingId} listing`, }); } }); // Update listing by ID router.put("/:id", async (req, res) => { const listingId = req.params.id; const { title, description, price } = req.body; try { const updateResult = await pool.query( "UPDATE listings SET title = $1, description = $2, price = $3, updated_at = NOW() WHERE id = $4 RETURNING *", [title, description, price, listingId] ); if (updateResult.rows.length === 0) { return res .status(404) .json({ error: "Listing not found for update" }); } res.status(200).json(updateResult.rows[0]); } catch (error) { res.status(500).json({ error: `Internal Server Error in updating the specified ${listingId} listing`, }); } }); // Submit a new listing router.post("/", async (req, res) => { const client = await pool.connect(); try { await client.query("BEGIN"); const { seller_id, title, price, currency, is_negotiable, listing_type, animal, } = req.body; // Add a new location if provided if (!animal.location_id && req.body.new_location) { const newLocation = { ...req.body.new_location, }; if ( newLocation.save_as_address && !newLocation.user_id && seller_id ) { newLocation.user_id = seller_id; } if (typeof newLocation.is_saved_address === "undefined") { newLocation.is_saved_address = Boolean( newLocation.save_as_address ); } animal.location_id = await addNewLocation(client, newLocation); } const animalId = await addAnimalToListing(client, animal); const listingInsertQuery = "INSERT INTO listings (seller_id, animal_id, title, price, currency, is_negotiable, listing_type, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6, $7, NOW(), NOW()) RETURNING *"; const listingValues = [ seller_id, animalId, title, price, currency, is_negotiable, listing_type, ]; const listingResult = await client.query( listingInsertQuery, listingValues ); await client.query("COMMIT"); res.status(201).json(listingResult.rows[0]); } catch (error) { await client.query("ROLLBACK"); res.status(500).json({ error: "Internal Server Error in creating new listing", }); } finally { client.release(); } }); const addAnimalToListing = async (client, animal) => { try { const animalInsertQuery = "INSERT INTO animals (species_id, breed_id, sex, age_months, weight_kg, color_markings, quantity, purpose, health_status, vaccinated, dewormed, previous_pregnancies_count, pregnancy_status, milk_yield_litre_per_day, ear_tag_no, description, suggested_care, location_id, created_from, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, NOW(), NOW()) RETURNING id"; const animalValues = [ animal.species_id, animal.breed_id, animal.sex, animal.age_months, animal.weight_kg, animal.color_markings, animal.quantity, animal.purpose, animal.health_status, animal.vaccinated, animal.dewormed, animal.previous_pregnancies_count, animal.pregnancy_status, animal.milk_yield_litre_per_day, animal.ear_tag_no, animal.description, animal.suggested_care, animal.location_id, animal.created_from || "listing", ]; const animalResult = await client.query( animalInsertQuery, animalValues ); const animalId = animalResult.rows[0].id; return animalId; } catch (error) { throw new Error("Error adding animal to listing: " + error.message); } }; const addNewLocation = async (client, location) => { try { const { user_id = null, is_saved_address = false, location_type = null, country = null, state = null, district = null, city_village = null, pincode = null, lat = null, lng = null, source_type = "unknown", source_confidence = "medium", } = location; const locationInsertQuery = "INSERT INTO locations (user_id, is_saved_address, location_type, country, state, district, city_village, pincode, lat, lng, source_type, source_confidence, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, NOW(), NOW()) RETURNING id"; const locationValues = [ user_id, is_saved_address, location_type, country, state, district, city_village, pincode, lat, lng, source_type, source_confidence, ]; const locationResult = await client.query( locationInsertQuery, locationValues ); return locationResult.rows[0].id; } catch (error) { throw new Error("Error adding new location: " + error.message); } }; // Delete listing by ID router.delete("/:id", async (req, res) => { const listingId = req.params.id; try { const deleteResult = await pool.query( "DELETE FROM listings WHERE id = $1 RETURNING *", [listingId] ); if (deleteResult.rows.length === 0) { return res .status(404) .json({ error: "Listing not found or already deleted" }); } res.status(200).json({ message: "Listing deleted successfully", listing: deleteResult.rows[0], }); } catch (error) { res.status(500).json({ error: `Internal Server Error in deleting the specified ${listingId} listing`, }); } }); // Get all listings for a user router.get("/user/:user_id", async (req, res) => { const userId = req.params.user_id; try { const listingsResult = await pool.query( "SELECT * FROM listings WHERE seller_id = $1 ORDER BY created_at DESC", [userId] ); res.status(200).json(listingsResult.rows); } catch (error) { res.status(500).json({ error: "Internal Server Error in fetching user listings", }); } }); // Mark listing as sold or update listing status router.patch("/:id/status", async (req, res) => { const listingId = req.params.id; const { status } = req.body; if (!status) { return res.status(400).json({ error: "Status must be provided" }); } try { const updateResult = await pool.query( "UPDATE listings SET status = $1, updated_at = NOW() WHERE id = $2 RETURNING *", [status, listingId] ); if (updateResult.rows.length === 0) { return res .status(404) .json({ error: "Listing not found for status update" }); } res.status(200).json({ message: "Listing status updated", listing: updateResult.rows[0], }); } catch (error) { res.status(500).json({ error: `Internal Server Error updating listing status for ${listingId}`, }); } }); export default router;