1109 lines
46 KiB
HTML
1109 lines
46 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>BuySellService API Tester</title>
|
||
<style>
|
||
* {
|
||
margin: 0;
|
||
padding: 0;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
body {
|
||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
min-height: 100vh;
|
||
padding: 20px;
|
||
}
|
||
|
||
.container {
|
||
max-width: 1200px;
|
||
margin: 0 auto;
|
||
background: white;
|
||
border-radius: 15px;
|
||
box-shadow: 0 10px 40px rgba(0,0,0,0.2);
|
||
padding: 30px;
|
||
}
|
||
|
||
h1 {
|
||
color: #333;
|
||
text-align: center;
|
||
margin-bottom: 10px;
|
||
font-size: 2.5em;
|
||
}
|
||
|
||
.subtitle {
|
||
text-align: center;
|
||
color: #666;
|
||
margin-bottom: 30px;
|
||
font-size: 1.1em;
|
||
}
|
||
|
||
.section {
|
||
margin-bottom: 40px;
|
||
padding: 25px;
|
||
background: #f8f9fa;
|
||
border-radius: 10px;
|
||
border-left: 4px solid #667eea;
|
||
}
|
||
|
||
.section h2 {
|
||
color: #667eea;
|
||
margin-bottom: 20px;
|
||
font-size: 1.8em;
|
||
}
|
||
|
||
.form-group {
|
||
margin-bottom: 15px;
|
||
}
|
||
|
||
label {
|
||
display: block;
|
||
margin-bottom: 5px;
|
||
color: #333;
|
||
font-weight: 600;
|
||
}
|
||
|
||
input, textarea, select {
|
||
width: 100%;
|
||
padding: 10px;
|
||
border: 2px solid #ddd;
|
||
border-radius: 5px;
|
||
font-size: 14px;
|
||
transition: border-color 0.3s;
|
||
}
|
||
|
||
input:focus, textarea:focus, select:focus {
|
||
outline: none;
|
||
border-color: #667eea;
|
||
}
|
||
|
||
textarea {
|
||
resize: vertical;
|
||
min-height: 80px;
|
||
}
|
||
|
||
.btn {
|
||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
color: white;
|
||
padding: 12px 25px;
|
||
border: none;
|
||
border-radius: 5px;
|
||
cursor: pointer;
|
||
font-size: 16px;
|
||
font-weight: 600;
|
||
transition: transform 0.2s, box-shadow 0.2s;
|
||
margin-right: 10px;
|
||
margin-top: 10px;
|
||
}
|
||
|
||
.btn:hover {
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
|
||
}
|
||
|
||
.btn-secondary {
|
||
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
|
||
}
|
||
|
||
.btn-success {
|
||
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
|
||
}
|
||
|
||
.response {
|
||
margin-top: 20px;
|
||
padding: 15px;
|
||
background: #1e1e1e;
|
||
color: #d4d4d4;
|
||
border-radius: 5px;
|
||
font-family: 'Courier New', monospace;
|
||
font-size: 13px;
|
||
max-height: 400px;
|
||
overflow-y: auto;
|
||
white-space: pre-wrap;
|
||
word-wrap: break-word;
|
||
}
|
||
|
||
.response.success {
|
||
background: #1e3a1e;
|
||
color: #90ee90;
|
||
}
|
||
|
||
.response.error {
|
||
background: #3a1e1e;
|
||
color: #ff6b6b;
|
||
}
|
||
|
||
.grid {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: 15px;
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.grid {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
}
|
||
|
||
.endpoint-info {
|
||
background: #e8f4f8;
|
||
padding: 10px;
|
||
border-radius: 5px;
|
||
margin-bottom: 15px;
|
||
font-size: 0.9em;
|
||
color: #555;
|
||
}
|
||
|
||
.endpoint-info strong {
|
||
color: #667eea;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
<h1>🐄 BuySellService API Tester</h1>
|
||
<p class="subtitle">Test your Livestock Marketplace API endpoints</p>
|
||
|
||
<!-- Users Section -->
|
||
<div class="section">
|
||
<h2>👤 Users API</h2>
|
||
|
||
<div class="endpoint-info">
|
||
<strong>Base URL:</strong> http://localhost:3200/users<br>
|
||
<strong>Note:</strong> Create users before creating listings or saved addresses.
|
||
</div>
|
||
|
||
<div class="grid">
|
||
<div>
|
||
<h3>Get All Users</h3>
|
||
<button class="btn" onclick="getUsers()">Get Users</button>
|
||
</div>
|
||
|
||
<div>
|
||
<h3>Get Single User</h3>
|
||
<div class="form-group">
|
||
<label>User ID (UUID):</label>
|
||
<input type="text" id="getUserId" placeholder="Enter user UUID">
|
||
</div>
|
||
<button class="btn" onclick="getUser()">Get User</button>
|
||
</div>
|
||
</div>
|
||
|
||
<h3>Create User</h3>
|
||
<div class="endpoint-info" style="background: #d1ecf1; border-left-color: #0c5460;">
|
||
<strong>💡 Quick Create:</strong> You can create a user with a specific UUID (like the one in your error) by providing the "id" field.
|
||
</div>
|
||
<div class="grid">
|
||
<div>
|
||
<div class="form-group">
|
||
<label>User ID (UUID) - Optional:</label>
|
||
<input type="text" id="createUserId" placeholder="Leave empty to auto-generate">
|
||
<small style="color: #666; font-size: 0.85em; display: block; margin-top: 5px;">
|
||
Use: aaf295cb-a19e-4179-a2df-31c0c64ea9f4 (from your error)
|
||
</small>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Name:</label>
|
||
<input type="text" id="createUserName" placeholder="John Doe" required>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Phone Number:</label>
|
||
<input type="text" id="createUserPhone" placeholder="+919876543210" required>
|
||
</div>
|
||
</div>
|
||
<div>
|
||
<div class="form-group">
|
||
<label>Avatar URL (Optional):</label>
|
||
<input type="text" id="createUserAvatar" placeholder="https://example.com/avatar.jpg">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Language (Optional):</label>
|
||
<input type="text" id="createUserLanguage" value="en" placeholder="en">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Country Code:</label>
|
||
<input type="text" id="createUserCountryCode" value="+91" placeholder="+91">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<button class="btn btn-success" onclick="createUser()">Create User</button>
|
||
|
||
<h3 style="margin-top: 20px;">Update User</h3>
|
||
<div class="form-group">
|
||
<label>User ID to Update:</label>
|
||
<input type="text" id="updateUserId" placeholder="Enter user UUID">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>New Name:</label>
|
||
<input type="text" id="updateUserName" placeholder="Updated name">
|
||
</div>
|
||
<button class="btn btn-secondary" onclick="updateUser()">Update User</button>
|
||
|
||
<div id="usersResponse" class="response" style="display: none;"></div>
|
||
</div>
|
||
|
||
<!-- Listings Section -->
|
||
<div class="section">
|
||
<h2>📋 Listings API</h2>
|
||
|
||
<div class="endpoint-info">
|
||
<strong>Base URL:</strong> http://localhost:3200/listings<br>
|
||
<strong>Note:</strong> Species ID and Breed ID must be UUIDs (not integers). Use the dropdowns below or enter UUIDs manually.
|
||
</div>
|
||
|
||
<div class="grid" style="margin-bottom: 20px;">
|
||
<div>
|
||
<h3>Get Available Species</h3>
|
||
<button class="btn" onclick="loadSpeciesList()">Load Species</button>
|
||
<div id="speciesListResponse" class="response" style="display: none; margin-top: 10px;"></div>
|
||
</div>
|
||
<div>
|
||
<h3>Get Available Breeds</h3>
|
||
<div class="form-group">
|
||
<label>Filter by Species ID (optional):</label>
|
||
<input type="text" id="filterBreedsSpeciesId" placeholder="Enter species UUID">
|
||
</div>
|
||
<button class="btn" onclick="loadBreedsList()">Load Breeds</button>
|
||
<div id="breedsListResponse" class="response" style="display: none; margin-top: 10px;"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="grid">
|
||
<div>
|
||
<h3>Get All Listings</h3>
|
||
<div class="form-group">
|
||
<label>Status:</label>
|
||
<select id="listingStatus">
|
||
<option value="active">Active</option>
|
||
<option value="sold">Sold</option>
|
||
<option value="expired">Expired</option>
|
||
</select>
|
||
</div>
|
||
<button class="btn" onclick="getListings()">Get Listings</button>
|
||
</div>
|
||
|
||
<div>
|
||
<h3>Get Single Listing</h3>
|
||
<div class="form-group">
|
||
<label>Listing ID:</label>
|
||
<input type="text" id="listingId" placeholder="Enter listing UUID">
|
||
</div>
|
||
<button class="btn" onclick="getListing()">Get Listing</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="grid">
|
||
<div>
|
||
<h3>Search Listings</h3>
|
||
<div class="form-group">
|
||
<label>Search Query:</label>
|
||
<input type="text" id="searchQuery" placeholder="e.g., cow, buffalo">
|
||
</div>
|
||
<button class="btn btn-success" onclick="searchListings()">Search</button>
|
||
</div>
|
||
|
||
<div>
|
||
<h3>Near Me Search</h3>
|
||
<div class="form-group">
|
||
<label>Latitude:</label>
|
||
<input type="number" id="nearLat" placeholder="18.5204" step="any">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Longitude:</label>
|
||
<input type="number" id="nearLng" placeholder="73.8567" step="any">
|
||
</div>
|
||
<button class="btn btn-success" onclick="nearMeSearch()">Find Nearby</button>
|
||
</div>
|
||
</div>
|
||
|
||
<h3>Create Listing</h3>
|
||
<div class="endpoint-info" style="background: #fff3cd; border-left-color: #ffc107;">
|
||
<strong>⚠️ Important:</strong> The Seller ID must be a valid UUID that exists in the users table.
|
||
If you get a foreign key error, the user doesn't exist. You need to create the user first or use an existing user UUID.
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Seller ID (UUID):</label>
|
||
<input type="text" id="sellerId" placeholder="Enter seller UUID (must exist in users table)">
|
||
<small style="color: #666; font-size: 0.85em; display: block; margin-top: 5px;">
|
||
Example: aaf295cb-a19e-4179-a2df-31c0c64ea9f4
|
||
</small>
|
||
</div>
|
||
<div class="grid">
|
||
<div>
|
||
<div class="form-group">
|
||
<label>Title:</label>
|
||
<input type="text" id="listingTitle" placeholder="e.g., High-yield Gir cow">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Price:</label>
|
||
<input type="number" id="listingPrice" placeholder="55000">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Currency:</label>
|
||
<input type="text" id="listingCurrency" value="INR" placeholder="INR">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Listing Type:</label>
|
||
<select id="listingType">
|
||
<option value="sale">Sale</option>
|
||
<option value="stud_service">Stud Service</option>
|
||
<option value="adoption">Adoption</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<div>
|
||
<div class="form-group">
|
||
<label>Species:</label>
|
||
<select id="speciesId">
|
||
<option value="">Loading species...</option>
|
||
</select>
|
||
<small style="color: #666; font-size: 0.85em;">Or enter UUID manually below</small>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Species ID (UUID) - Manual Entry:</label>
|
||
<input type="text" id="speciesIdManual" placeholder="Enter UUID if not in dropdown">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Breed:</label>
|
||
<select id="breedId">
|
||
<option value="">Select species first</option>
|
||
</select>
|
||
<small style="color: #666; font-size: 0.85em;">Or enter UUID manually below</small>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Breed ID (UUID) - Manual Entry:</label>
|
||
<input type="text" id="breedIdManual" placeholder="Enter UUID if not in dropdown">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Sex:</label>
|
||
<select id="animalSex">
|
||
<option value="M">Male</option>
|
||
<option value="F">Female</option>
|
||
<option value="Neutered">Neutered</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Age (months):</label>
|
||
<input type="number" id="ageMonths" placeholder="36">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<button class="btn btn-success" onclick="createListing()">Create Listing</button>
|
||
|
||
<h3 style="margin-top: 20px;">Update Listing</h3>
|
||
<div class="form-group">
|
||
<label>Listing ID to Update:</label>
|
||
<input type="text" id="updateListingId" placeholder="Enter listing UUID">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>New Title:</label>
|
||
<input type="text" id="updateTitle" placeholder="Updated title">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>New Price:</label>
|
||
<input type="number" id="updatePrice" placeholder="New price">
|
||
</div>
|
||
<button class="btn btn-secondary" onclick="updateListing()">Update Listing</button>
|
||
|
||
<h3 style="margin-top: 20px;">Delete Listing</h3>
|
||
<div class="form-group">
|
||
<label>Listing ID to Delete:</label>
|
||
<input type="text" id="deleteListingId" placeholder="Enter listing UUID">
|
||
</div>
|
||
<button class="btn btn-secondary" onclick="deleteListing()">Delete Listing</button>
|
||
|
||
<div id="listingsResponse" class="response" style="display: none;"></div>
|
||
</div>
|
||
|
||
<!-- Locations Section -->
|
||
<div class="section">
|
||
<h2>📍 Locations API</h2>
|
||
|
||
<div class="endpoint-info">
|
||
<strong>Base URL:</strong> http://localhost:3200/locations
|
||
</div>
|
||
|
||
<div class="grid">
|
||
<div>
|
||
<h3>Get User Locations</h3>
|
||
<div class="form-group">
|
||
<label>User ID (UUID):</label>
|
||
<input type="text" id="locationUserId" placeholder="Enter user UUID">
|
||
</div>
|
||
<button class="btn" onclick="getUserLocations()">Get Locations</button>
|
||
</div>
|
||
|
||
<div>
|
||
<h3>Get Single Location</h3>
|
||
<div class="form-group">
|
||
<label>Location ID:</label>
|
||
<input type="text" id="singleLocationId" placeholder="Enter location UUID">
|
||
</div>
|
||
<button class="btn" onclick="getLocation()">Get Location</button>
|
||
</div>
|
||
</div>
|
||
|
||
<h3>Create Location</h3>
|
||
<div class="endpoint-info" style="background: #fff3cd; border-left-color: #ffc107;">
|
||
<strong>ℹ️ Note:</strong> User ID is optional for captured locations (is_saved_address = false),
|
||
but required and must exist in users table for saved addresses (is_saved_address = true).
|
||
</div>
|
||
<div class="grid">
|
||
<div>
|
||
<div class="form-group">
|
||
<label>User ID (UUID) - Optional:</label>
|
||
<input type="text" id="createLocationUserId" placeholder="Leave empty for captured locations">
|
||
<small style="color: #666; font-size: 0.85em; display: block; margin-top: 5px;">
|
||
Required only if "Is Saved Address" is Yes
|
||
</small>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Latitude:</label>
|
||
<input type="number" id="createLat" placeholder="18.5204" step="any">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Longitude:</label>
|
||
<input type="number" id="createLng" placeholder="73.8567" step="any">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Country:</label>
|
||
<input type="text" id="createCountry" value="India" placeholder="India">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>State:</label>
|
||
<input type="text" id="createState" placeholder="Maharashtra">
|
||
</div>
|
||
</div>
|
||
<div>
|
||
<div class="form-group">
|
||
<label>District:</label>
|
||
<input type="text" id="createDistrict" placeholder="Pune">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>City/Village:</label>
|
||
<input type="text" id="createCity" placeholder="Baramati">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Pincode:</label>
|
||
<input type="text" id="createPincode" placeholder="413102">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Location Type:</label>
|
||
<select id="createLocationType">
|
||
<option value="farm">Farm</option>
|
||
<option value="home">Home</option>
|
||
<option value="other">Other</option>
|
||
</select>
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Is Saved Address:</label>
|
||
<select id="createIsSaved">
|
||
<option value="true">Yes</option>
|
||
<option value="false">No</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<button class="btn btn-success" onclick="createLocation()">Create Location</button>
|
||
|
||
<h3 style="margin-top: 20px;">Update Location</h3>
|
||
<div class="form-group">
|
||
<label>Location ID to Update:</label>
|
||
<input type="text" id="updateLocationId" placeholder="Enter location UUID">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>New City/Village:</label>
|
||
<input type="text" id="updateCity" placeholder="Updated city">
|
||
</div>
|
||
<button class="btn btn-secondary" onclick="updateLocation()">Update Location</button>
|
||
|
||
<div id="locationsResponse" class="response" style="display: none;"></div>
|
||
</div>
|
||
|
||
<!-- Chat Section -->
|
||
<div class="section">
|
||
<h2>💬 Chat API</h2>
|
||
|
||
<div class="endpoint-info">
|
||
<strong>Base URL:</strong> http://localhost:3200/chat
|
||
</div>
|
||
|
||
<div class="grid">
|
||
<div>
|
||
<h3>Create/Get Conversation</h3>
|
||
<div class="form-group">
|
||
<label>Buyer ID (UUID):</label>
|
||
<input type="text" id="buyerId" placeholder="Enter buyer UUID">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Seller ID (UUID):</label>
|
||
<input type="text" id="sellerIdChat" placeholder="Enter seller UUID">
|
||
</div>
|
||
<button class="btn" onclick="createConversation()">Create/Get Conversation</button>
|
||
</div>
|
||
|
||
<div>
|
||
<h3>Get User Conversations</h3>
|
||
<div class="form-group">
|
||
<label>User ID (UUID):</label>
|
||
<input type="text" id="conversationUserId" placeholder="Enter user UUID">
|
||
</div>
|
||
<button class="btn" onclick="getUserConversations()">Get Conversations</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="grid">
|
||
<div>
|
||
<h3>Get Messages</h3>
|
||
<div class="form-group">
|
||
<label>Conversation ID (UUID):</label>
|
||
<input type="text" id="conversationId" placeholder="Enter conversation UUID">
|
||
</div>
|
||
<button class="btn" onclick="getMessages()">Get Messages</button>
|
||
</div>
|
||
|
||
<div>
|
||
<h3>Send Message</h3>
|
||
<div class="form-group">
|
||
<label>Conversation ID:</label>
|
||
<input type="text" id="messageConversationId" placeholder="Enter conversation UUID">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Sender ID:</label>
|
||
<input type="text" id="senderId" placeholder="Enter sender UUID">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Receiver ID:</label>
|
||
<input type="text" id="receiverId" placeholder="Enter receiver UUID">
|
||
</div>
|
||
<div class="form-group">
|
||
<label>Message Content:</label>
|
||
<textarea id="messageContent" placeholder="Type your message..."></textarea>
|
||
</div>
|
||
<button class="btn btn-success" onclick="sendMessage()">Send Message</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="chatResponse" class="response" style="display: none;"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
const API_BASE = 'http://localhost:3200';
|
||
|
||
// Load species and breeds on page load
|
||
let speciesList = [];
|
||
let breedsList = [];
|
||
|
||
async function loadSpecies() {
|
||
try {
|
||
const response = await fetch(`${API_BASE}/listings/species`);
|
||
speciesList = await response.json();
|
||
const select = document.getElementById('speciesId');
|
||
select.innerHTML = '<option value="">Select a species</option>';
|
||
speciesList.forEach(species => {
|
||
const option = document.createElement('option');
|
||
option.value = species.id;
|
||
option.textContent = species.name;
|
||
select.appendChild(option);
|
||
});
|
||
} catch (error) {
|
||
console.error('Error loading species:', error);
|
||
document.getElementById('speciesId').innerHTML = '<option value="">Error loading species</option>';
|
||
}
|
||
}
|
||
|
||
async function loadBreeds(speciesId) {
|
||
try {
|
||
const url = speciesId
|
||
? `${API_BASE}/listings/breeds?species_id=${speciesId}`
|
||
: `${API_BASE}/listings/breeds`;
|
||
const response = await fetch(url);
|
||
breedsList = await response.json();
|
||
const select = document.getElementById('breedId');
|
||
select.innerHTML = '<option value="">Select a breed</option>';
|
||
breedsList.forEach(breed => {
|
||
const option = document.createElement('option');
|
||
option.value = breed.id;
|
||
option.textContent = breed.name;
|
||
select.appendChild(option);
|
||
});
|
||
} catch (error) {
|
||
console.error('Error loading breeds:', error);
|
||
document.getElementById('breedId').innerHTML = '<option value="">Error loading breeds</option>';
|
||
}
|
||
}
|
||
|
||
// Load species on page load
|
||
window.addEventListener('DOMContentLoaded', () => {
|
||
loadSpecies();
|
||
|
||
// Load breeds when species is selected
|
||
document.getElementById('speciesId').addEventListener('change', (e) => {
|
||
const speciesId = e.target.value;
|
||
if (speciesId) {
|
||
loadBreeds(speciesId);
|
||
} else {
|
||
document.getElementById('breedId').innerHTML = '<option value="">Select species first</option>';
|
||
}
|
||
});
|
||
});
|
||
|
||
// Helper functions to display species and breeds
|
||
async function loadSpeciesList() {
|
||
try {
|
||
const response = await fetch(`${API_BASE}/listings/species`);
|
||
const data = await response.json();
|
||
showResponse('speciesListResponse', data, !response.ok);
|
||
} catch (error) {
|
||
showResponse('speciesListResponse', { error: error.message }, true);
|
||
}
|
||
}
|
||
|
||
async function loadBreedsList() {
|
||
try {
|
||
const speciesId = document.getElementById('filterBreedsSpeciesId').value;
|
||
const url = speciesId
|
||
? `${API_BASE}/listings/breeds?species_id=${speciesId}`
|
||
: `${API_BASE}/listings/breeds`;
|
||
const response = await fetch(url);
|
||
const data = await response.json();
|
||
showResponse('breedsListResponse', data, !response.ok);
|
||
} catch (error) {
|
||
showResponse('breedsListResponse', { error: error.message }, true);
|
||
}
|
||
}
|
||
|
||
function showResponse(elementId, data, isError = false) {
|
||
const element = document.getElementById(elementId);
|
||
element.style.display = 'block';
|
||
element.className = `response ${isError ? 'error' : 'success'}`;
|
||
element.textContent = JSON.stringify(data, null, 2);
|
||
}
|
||
|
||
// Listings API Functions
|
||
async function getListings() {
|
||
try {
|
||
const status = document.getElementById('listingStatus').value;
|
||
const response = await fetch(`${API_BASE}/listings?status=${status}`);
|
||
const data = await response.json();
|
||
showResponse('listingsResponse', data, !response.ok);
|
||
} catch (error) {
|
||
showResponse('listingsResponse', { error: error.message }, true);
|
||
}
|
||
}
|
||
|
||
async function getListing() {
|
||
try {
|
||
const id = document.getElementById('listingId').value;
|
||
if (!id) {
|
||
alert('Please enter a listing ID');
|
||
return;
|
||
}
|
||
const response = await fetch(`${API_BASE}/listings/${id}`);
|
||
const data = await response.json();
|
||
showResponse('listingsResponse', data, !response.ok);
|
||
} catch (error) {
|
||
showResponse('listingsResponse', { error: error.message }, true);
|
||
}
|
||
}
|
||
|
||
async function searchListings() {
|
||
try {
|
||
const q = document.getElementById('searchQuery').value;
|
||
if (!q) {
|
||
alert('Please enter a search query');
|
||
return;
|
||
}
|
||
const response = await fetch(`${API_BASE}/listings/search?q=${encodeURIComponent(q)}`);
|
||
const data = await response.json();
|
||
showResponse('listingsResponse', data, !response.ok);
|
||
} catch (error) {
|
||
showResponse('listingsResponse', { error: error.message }, true);
|
||
}
|
||
}
|
||
|
||
async function nearMeSearch() {
|
||
try {
|
||
const lat = document.getElementById('nearLat').value;
|
||
const lng = document.getElementById('nearLng').value;
|
||
if (!lat || !lng) {
|
||
alert('Please enter both latitude and longitude');
|
||
return;
|
||
}
|
||
const response = await fetch(`${API_BASE}/listings/near-me?lat=${lat}&lng=${lng}`);
|
||
const data = await response.json();
|
||
showResponse('listingsResponse', data, !response.ok);
|
||
} catch (error) {
|
||
showResponse('listingsResponse', { error: error.message }, true);
|
||
}
|
||
}
|
||
|
||
async function createListing() {
|
||
try {
|
||
// Get species_id - prefer dropdown, fallback to manual entry
|
||
const speciesId = document.getElementById('speciesId').value || document.getElementById('speciesIdManual').value;
|
||
// Get breed_id - prefer dropdown, fallback to manual entry (can be null)
|
||
const breedId = document.getElementById('breedId').value || document.getElementById('breedIdManual').value;
|
||
|
||
if (!speciesId) {
|
||
alert('Please select or enter a Species ID (UUID)');
|
||
return;
|
||
}
|
||
|
||
const listingData = {
|
||
seller_id: document.getElementById('sellerId').value,
|
||
title: document.getElementById('listingTitle').value,
|
||
price: parseFloat(document.getElementById('listingPrice').value),
|
||
currency: document.getElementById('listingCurrency').value,
|
||
is_negotiable: true,
|
||
listing_type: document.getElementById('listingType').value,
|
||
animal: {
|
||
species_id: speciesId, // UUID, not integer
|
||
breed_id: breedId || null, // UUID or null, not integer
|
||
sex: document.getElementById('animalSex').value,
|
||
age_months: parseInt(document.getElementById('ageMonths').value) || null,
|
||
purpose: 'dairy',
|
||
health_status: 'healthy',
|
||
vaccinated: true,
|
||
dewormed: true
|
||
}
|
||
};
|
||
|
||
const response = await fetch(`${API_BASE}/listings`, {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify(listingData)
|
||
});
|
||
const data = await response.json();
|
||
|
||
if (!response.ok) {
|
||
let errorMsg = data.error || 'Unknown error';
|
||
if (errorMsg.includes('does not exist')) {
|
||
errorMsg += '\n\n💡 Tip: Make sure the Seller ID is a valid UUID that exists in the users table. You may need to create the user first.';
|
||
}
|
||
showResponse('listingsResponse', { error: errorMsg }, true);
|
||
} else {
|
||
showResponse('listingsResponse', data, false);
|
||
}
|
||
} catch (error) {
|
||
showResponse('listingsResponse', {
|
||
error: `Network error: ${error.message}\n\n💡 Tip: Make sure the server is running and the Seller ID is a valid UUID.`
|
||
}, true);
|
||
}
|
||
}
|
||
|
||
async function updateListing() {
|
||
try {
|
||
const id = document.getElementById('updateListingId').value;
|
||
if (!id) {
|
||
alert('Please enter a listing ID');
|
||
return;
|
||
}
|
||
const updateData = {
|
||
title: document.getElementById('updateTitle').value,
|
||
price: parseFloat(document.getElementById('updatePrice').value)
|
||
};
|
||
|
||
const response = await fetch(`${API_BASE}/listings/${id}`, {
|
||
method: 'PUT',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify(updateData)
|
||
});
|
||
const data = await response.json();
|
||
showResponse('listingsResponse', data, !response.ok);
|
||
} catch (error) {
|
||
showResponse('listingsResponse', { error: error.message }, true);
|
||
}
|
||
}
|
||
|
||
async function deleteListing() {
|
||
try {
|
||
const id = document.getElementById('deleteListingId').value;
|
||
if (!id) {
|
||
alert('Please enter a listing ID');
|
||
return;
|
||
}
|
||
const response = await fetch(`${API_BASE}/listings/${id}`, {
|
||
method: 'DELETE',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({ deleted_reason: 'Test deletion' })
|
||
});
|
||
const data = await response.json();
|
||
showResponse('listingsResponse', data, !response.ok);
|
||
} catch (error) {
|
||
showResponse('listingsResponse', { error: error.message }, true);
|
||
}
|
||
}
|
||
|
||
// Locations API Functions
|
||
async function getUserLocations() {
|
||
try {
|
||
const userId = document.getElementById('locationUserId').value;
|
||
if (!userId) {
|
||
alert('Please enter a user ID');
|
||
return;
|
||
}
|
||
const response = await fetch(`${API_BASE}/locations/user/${userId}`);
|
||
const data = await response.json();
|
||
showResponse('locationsResponse', data, !response.ok);
|
||
} catch (error) {
|
||
showResponse('locationsResponse', { error: error.message }, true);
|
||
}
|
||
}
|
||
|
||
async function getLocation() {
|
||
try {
|
||
const id = document.getElementById('singleLocationId').value;
|
||
if (!id) {
|
||
alert('Please enter a location ID');
|
||
return;
|
||
}
|
||
const response = await fetch(`${API_BASE}/locations/${id}`);
|
||
const data = await response.json();
|
||
showResponse('locationsResponse', data, !response.ok);
|
||
} catch (error) {
|
||
showResponse('locationsResponse', { error: error.message }, true);
|
||
}
|
||
}
|
||
|
||
async function createLocation() {
|
||
try {
|
||
const locationData = {
|
||
user_id: document.getElementById('createLocationUserId').value || null,
|
||
lat: parseFloat(document.getElementById('createLat').value),
|
||
lng: parseFloat(document.getElementById('createLng').value),
|
||
country: document.getElementById('createCountry').value,
|
||
state: document.getElementById('createState').value,
|
||
district: document.getElementById('createDistrict').value,
|
||
city_village: document.getElementById('createCity').value,
|
||
pincode: document.getElementById('createPincode').value,
|
||
location_type: document.getElementById('createLocationType').value,
|
||
is_saved_address: document.getElementById('createIsSaved').value === 'true',
|
||
source_type: 'manual',
|
||
source_confidence: 'medium'
|
||
};
|
||
|
||
const response = await fetch(`${API_BASE}/locations`, {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify(locationData)
|
||
});
|
||
const data = await response.json();
|
||
|
||
if (!response.ok) {
|
||
let errorMsg = data.error || 'Unknown error';
|
||
if (errorMsg.includes('does not exist')) {
|
||
errorMsg += '\n\n💡 Tip: If creating a saved address (is_saved_address = true), the User ID must exist in the users table. For captured locations, leave User ID empty.';
|
||
}
|
||
showResponse('locationsResponse', { error: errorMsg }, true);
|
||
} else {
|
||
showResponse('locationsResponse', data, false);
|
||
}
|
||
} catch (error) {
|
||
showResponse('locationsResponse', {
|
||
error: `Network error: ${error.message}\n\n💡 Tip: Make sure the server is running. If creating a saved address, ensure the User ID is a valid UUID that exists in the users table.`
|
||
}, true);
|
||
}
|
||
}
|
||
|
||
async function updateLocation() {
|
||
try {
|
||
const id = document.getElementById('updateLocationId').value;
|
||
if (!id) {
|
||
alert('Please enter a location ID');
|
||
return;
|
||
}
|
||
const updateData = {
|
||
city_village: document.getElementById('updateCity').value
|
||
};
|
||
|
||
const response = await fetch(`${API_BASE}/locations/${id}`, {
|
||
method: 'PUT',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify(updateData)
|
||
});
|
||
const data = await response.json();
|
||
showResponse('locationsResponse', data, !response.ok);
|
||
} catch (error) {
|
||
showResponse('locationsResponse', { error: error.message }, true);
|
||
}
|
||
}
|
||
|
||
// Users API Functions
|
||
async function getUsers() {
|
||
try {
|
||
const response = await fetch(`${API_BASE}/users`);
|
||
const data = await response.json();
|
||
showResponse('usersResponse', data, !response.ok);
|
||
} catch (error) {
|
||
showResponse('usersResponse', { error: error.message }, true);
|
||
}
|
||
}
|
||
|
||
async function getUser() {
|
||
try {
|
||
const id = document.getElementById('getUserId').value;
|
||
if (!id) {
|
||
alert('Please enter a user ID');
|
||
return;
|
||
}
|
||
const response = await fetch(`${API_BASE}/users/${id}`);
|
||
const data = await response.json();
|
||
showResponse('usersResponse', data, !response.ok);
|
||
} catch (error) {
|
||
showResponse('usersResponse', { error: error.message }, true);
|
||
}
|
||
}
|
||
|
||
async function createUser() {
|
||
try {
|
||
const userData = {
|
||
name: document.getElementById('createUserName').value,
|
||
phone_number: document.getElementById('createUserPhone').value,
|
||
avatar_url: document.getElementById('createUserAvatar').value || null,
|
||
language: document.getElementById('createUserLanguage').value || null,
|
||
country_code: document.getElementById('createUserCountryCode').value || '+91'
|
||
};
|
||
|
||
// Add id if provided
|
||
const userId = document.getElementById('createUserId').value;
|
||
if (userId) {
|
||
userData.id = userId;
|
||
}
|
||
|
||
if (!userData.name || !userData.phone_number) {
|
||
alert('Name and Phone Number are required');
|
||
return;
|
||
}
|
||
|
||
const response = await fetch(`${API_BASE}/users`, {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify(userData)
|
||
});
|
||
const data = await response.json();
|
||
|
||
if (!response.ok) {
|
||
let errorMsg = data.error || 'Unknown error';
|
||
if (errorMsg.includes('already exists')) {
|
||
errorMsg += '\n\n💡 Tip: A user with this phone number or ID already exists. Try a different phone number or ID.';
|
||
}
|
||
showResponse('usersResponse', { error: errorMsg }, true);
|
||
} else {
|
||
showResponse('usersResponse', data, false);
|
||
// Clear form on success
|
||
document.getElementById('createUserName').value = '';
|
||
document.getElementById('createUserPhone').value = '';
|
||
document.getElementById('createUserAvatar').value = '';
|
||
}
|
||
} catch (error) {
|
||
showResponse('usersResponse', {
|
||
error: `Network error: ${error.message}\n\n💡 Tip: Make sure the server is running.`
|
||
}, true);
|
||
}
|
||
}
|
||
|
||
async function updateUser() {
|
||
try {
|
||
const id = document.getElementById('updateUserId').value;
|
||
if (!id) {
|
||
alert('Please enter a user ID');
|
||
return;
|
||
}
|
||
const updateData = {
|
||
name: document.getElementById('updateUserName').value
|
||
};
|
||
|
||
const response = await fetch(`${API_BASE}/users/${id}`, {
|
||
method: 'PUT',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify(updateData)
|
||
});
|
||
const data = await response.json();
|
||
showResponse('usersResponse', data, !response.ok);
|
||
} catch (error) {
|
||
showResponse('usersResponse', { error: error.message }, true);
|
||
}
|
||
}
|
||
|
||
// Chat API Functions
|
||
async function createConversation() {
|
||
try {
|
||
const buyerId = document.getElementById('buyerId').value;
|
||
const sellerId = document.getElementById('sellerIdChat').value;
|
||
if (!buyerId || !sellerId) {
|
||
alert('Please enter both buyer and seller IDs');
|
||
return;
|
||
}
|
||
const response = await fetch(`${API_BASE}/chat/conversations`, {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify({ buyer_id: buyerId, seller_id: sellerId })
|
||
});
|
||
const data = await response.json();
|
||
showResponse('chatResponse', data, !response.ok);
|
||
} catch (error) {
|
||
showResponse('chatResponse', { error: error.message }, true);
|
||
}
|
||
}
|
||
|
||
async function getUserConversations() {
|
||
try {
|
||
const userId = document.getElementById('conversationUserId').value;
|
||
if (!userId) {
|
||
alert('Please enter a user ID');
|
||
return;
|
||
}
|
||
const response = await fetch(`${API_BASE}/chat/conversations/user/${userId}`);
|
||
const data = await response.json();
|
||
showResponse('chatResponse', data, !response.ok);
|
||
} catch (error) {
|
||
showResponse('chatResponse', { error: error.message }, true);
|
||
}
|
||
}
|
||
|
||
async function getMessages() {
|
||
try {
|
||
const conversationId = document.getElementById('conversationId').value;
|
||
if (!conversationId) {
|
||
alert('Please enter a conversation ID');
|
||
return;
|
||
}
|
||
const response = await fetch(`${API_BASE}/chat/conversations/${conversationId}/messages`);
|
||
const data = await response.json();
|
||
showResponse('chatResponse', data, !response.ok);
|
||
} catch (error) {
|
||
showResponse('chatResponse', { error: error.message }, true);
|
||
}
|
||
}
|
||
|
||
async function sendMessage() {
|
||
try {
|
||
const messageData = {
|
||
conversation_id: document.getElementById('messageConversationId').value,
|
||
sender_id: document.getElementById('senderId').value,
|
||
receiver_id: document.getElementById('receiverId').value,
|
||
content: document.getElementById('messageContent').value,
|
||
message_type: 'text'
|
||
};
|
||
|
||
const response = await fetch(`${API_BASE}/chat/messages`, {
|
||
method: 'POST',
|
||
headers: { 'Content-Type': 'application/json' },
|
||
body: JSON.stringify(messageData)
|
||
});
|
||
const data = await response.json();
|
||
showResponse('chatResponse', data, !response.ok);
|
||
} catch (error) {
|
||
showResponse('chatResponse', { error: error.message }, true);
|
||
}
|
||
}
|
||
</script>
|
||
</body>
|
||
</html>
|
||
|