auth/public/test.html

482 lines
17 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Farm Auth Tester</title>
<style>
body { font-family: sans-serif; max-width: 600px; margin: 20px auto; }
h2 { margin-top: 24px; }
label { display: block; margin-top: 8px; }
input, select { width: 100%; padding: 6px; margin-top: 4px; }
button { margin-top: 10px; padding: 8px 12px; cursor: pointer; }
.section { border: 1px solid #ddd; padding: 12px; border-radius: 6px; margin-top: 16px; }
pre { background: #f7f7f7; padding: 8px; overflow-x: auto; }
</style>
</head>
<body>
<h1>Farm Auth Service Tester</h1>
<div class="section">
<h2>1. Request OTP</h2>
<label>Phone Number (E.164, e.g. +91XXXXXXXXXX)</label>
<input id="phone" type="text" placeholder="+91..." />
<button id="requestOtpBtn">Request OTP</button>
<pre id="requestOtpResult"></pre>
</div>
<div class="section">
<h2>2. Verify OTP</h2>
<label>OTP Code</label>
<input id="otp" type="text" placeholder="123456" />
<label>Device ID</label>
<input id="deviceId" type="text" value="web-test-device" />
<button id="verifyOtpBtn">Verify OTP</button>
<pre id="verifyOtpResult"></pre>
</div>
<div class="section">
<h2>3. Complete Profile (name + user_type)</h2>
<p><strong>⚠️ Requires OTP verification first (Step 2)</strong></p>
<p>Uses the <code>access_token</code> from step 2</p>
<label>Name</label>
<input id="name" type="text" placeholder="Your name" />
<label>User Type</label>
<select id="userType">
<option value="seller">Seller</option>
<option value="buyer">Buyer</option>
<option value="service_provider">Service Provider</option>
</select>
<button id="updateProfileBtn" disabled>Update Profile (Verify OTP First)</button>
<pre id="updateProfileResult"></pre>
</div>
<div class="section">
<h2>4. Get User Details</h2>
<p><strong>⚠️ Requires OTP verification first (Step 2)</strong></p>
<p>Authenticated GET request to fetch user profile with JWT token</p>
<p>Shows: phone number, name, profile type, location, last login, and all saved locations</p>
<button id="getUserDetailsBtn" disabled>Get User Details (Verify OTP First)</button>
<pre id="getUserDetailsResult"></pre>
</div>
<div class="section">
<h2>5. Add/Update Location</h2>
<p><strong>⚠️ Requires OTP verification first (Step 2)</strong></p>
<p>Save your current location or a custom address</p>
<label>Location Type</label>
<select id="locationType">
<option value="home">Home</option>
<option value="farm">Farm</option>
<option value="office">Office</option>
<option value="temporary_gps">Temporary GPS</option>
<option value="other_saved">Other Saved</option>
</select>
<label>
<input type="checkbox" id="useCurrentLocation" /> Use Current GPS Location
</label>
<label>Country</label>
<input id="country" type="text" placeholder="India" />
<label>State</label>
<input id="state" type="text" placeholder="Maharashtra" />
<label>District</label>
<input id="district" type="text" placeholder="Mumbai" />
<label>City/Village</label>
<input id="cityVillage" type="text" placeholder="Mumbai" />
<label>Pincode</label>
<input id="pincode" type="text" placeholder="400001" />
<label>
<input type="checkbox" id="isPrimaryLocation" /> Set as Primary Location
</label>
<button id="saveLocationBtn" disabled>Save Location (Verify OTP First)</button>
<pre id="saveLocationResult"></pre>
</div>
<script>
let accessToken = null;
let refreshToken = null;
// Add error handler for uncaught errors
window.addEventListener('error', (e) => {
console.error('Global error:', e);
alert('JavaScript error: ' + e.message);
});
async function requestOtp() {
const phone = document.getElementById('phone').value.trim();
const out = document.getElementById('requestOtpResult');
if (!phone) {
out.textContent = 'Error: Please enter a phone number';
alert('Please enter a phone number');
return;
}
out.textContent = 'Sending...';
console.log('Requesting OTP for:', phone);
try {
const res = await fetch('/auth/request-otp', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ phone_number: phone })
});
console.log('Response status:', res.status);
const data = await res.json();
console.log('Response data:', data);
out.textContent = JSON.stringify(data, null, 2);
if (res.ok) {
alert('OTP sent successfully! Check your phone or server logs.');
} else {
alert('Error: ' + (data.error || data.message || 'Failed to send OTP'));
}
} catch (err) {
console.error('Request OTP error:', err);
out.textContent = 'Error: ' + err.message;
alert('Error: ' + err.message);
}
}
async function verifyOtp() {
const phone = document.getElementById('phone').value.trim();
const otp = document.getElementById('otp').value.trim();
const deviceId = document.getElementById('deviceId').value.trim() || 'web-test-device';
const out = document.getElementById('verifyOtpResult');
if (!phone) {
out.textContent = 'Error: Please enter a phone number';
alert('Please enter a phone number');
return;
}
if (!otp) {
out.textContent = 'Error: Please enter an OTP code';
alert('Please enter an OTP code');
return;
}
out.textContent = 'Verifying...';
console.log('Verifying OTP for:', phone, 'code:', otp);
try {
const res = await fetch('/auth/verify-otp', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
phone_number: phone,
code: otp,
device_id: deviceId,
device_info: {
platform: 'web',
model: 'browser',
os_version: navigator.userAgent,
app_version: 'web-test',
language_code: navigator.language,
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
}
})
});
console.log('Response status:', res.status);
const data = await res.json();
console.log('Response data:', data);
out.textContent = JSON.stringify(data, null, 2);
if (res.ok) {
accessToken = data.access_token;
refreshToken = data.refresh_token;
console.log('Access token set:', accessToken);
console.log('Refresh token set:', refreshToken);
// Enable buttons that require authentication
const getUserDetailsBtn = document.getElementById('getUserDetailsBtn');
const updateProfileBtn = document.getElementById('updateProfileBtn');
const saveLocationBtn = document.getElementById('saveLocationBtn');
if (getUserDetailsBtn) {
getUserDetailsBtn.disabled = false;
getUserDetailsBtn.textContent = 'Get User Details';
}
if (updateProfileBtn) {
updateProfileBtn.disabled = false;
updateProfileBtn.textContent = 'Update Profile';
}
if (saveLocationBtn) {
saveLocationBtn.disabled = false;
saveLocationBtn.textContent = 'Save Location';
}
alert('OTP verified successfully! needs_profile = ' + data.needs_profile);
} else {
alert('Error: ' + (data.error || data.message || 'OTP verification failed'));
}
} catch (err) {
console.error('Verify OTP error:', err);
out.textContent = 'Error: ' + err.message;
alert('Error: ' + err.message);
}
}
async function updateProfile() {
const name = document.getElementById('name').value.trim();
const userType = document.getElementById('userType').value;
const out = document.getElementById('updateProfileResult');
if (!accessToken) {
alert('No access_token. Verify OTP first.');
out.textContent = 'Error: No access token. Please verify OTP first.';
return;
}
if (!name) {
alert('Please enter a name');
out.textContent = 'Error: Please enter a name';
return;
}
out.textContent = 'Updating profile...';
console.log('Updating profile:', { name, user_type: userType });
try {
const res = await fetch('/users/me', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + accessToken,
},
body: JSON.stringify({ name, user_type: userType })
});
console.log('Response status:', res.status);
const data = await res.json();
console.log('Response data:', data);
out.textContent = JSON.stringify(data, null, 2);
if (res.ok) {
alert('Profile updated successfully!');
} else {
alert('Error: ' + (data.error || data.message || 'Failed to update profile'));
}
} catch (err) {
console.error('Update profile error:', err);
out.textContent = 'Error: ' + err.message;
alert('Error: ' + err.message);
}
}
async function getUserDetails() {
const out = document.getElementById('getUserDetailsResult');
if (!accessToken) {
alert('No access_token. Verify OTP first.');
out.textContent = 'Error: No access token. Please verify OTP first.';
return;
}
out.textContent = 'Fetching user details...';
console.log('Fetching user details with token:', accessToken.substring(0, 20) + '...');
try {
const res = await fetch('/users/me', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + accessToken,
}
});
console.log('Response status:', res.status);
const data = await res.json();
console.log('Response data:', data);
if (res.ok) {
// Format user details with new schema fields
const formattedData = {
id: data.id,
phone_number: data.phone_number,
name: data.name,
user_type: data.user_type, // System role: user/admin/moderator
roles: data.roles, // Marketplace roles array
active_role: data.active_role, // Active marketplace role
rating_average: data.rating_average,
rating_count: data.rating_count,
subscription_plan_id: data.subscription_plan_id,
subscription_expires_at: data.subscription_expires_at,
avatar_url: data.avatar_url,
language: data.language,
timezone: data.timezone,
country_code: data.country_code,
created_at: data.created_at,
last_login_at: data.last_login_at,
active_devices_count: data.active_devices_count,
primary_location: data.location,
all_locations: data.locations
};
out.textContent = JSON.stringify(formattedData, null, 2);
alert('User details fetched successfully!');
// Auto-fill location fields if primary location exists
if (data.location) {
document.getElementById('country').value = data.location.country || '';
document.getElementById('state').value = data.location.state || '';
document.getElementById('district').value = data.location.district || '';
document.getElementById('cityVillage').value = data.location.city_village || '';
document.getElementById('pincode').value = data.location.pincode || '';
if (data.location.location_type) {
document.getElementById('locationType').value = data.location.location_type;
}
}
} else {
out.textContent = `Error ${res.status}: ${JSON.stringify(data, null, 2)}`;
// If token expired, try to refresh
if (res.status === 401) {
alert('Access token expired. Try refreshing the token or verify OTP again.');
} else {
alert('Error: ' + (data.error || data.message || 'Failed to fetch user details'));
}
}
} catch (err) {
console.error('Get user details error:', err);
out.textContent = 'Error: ' + err.message;
alert('Error: ' + err.message);
}
}
async function saveLocation() {
const out = document.getElementById('saveLocationResult');
let lat = null;
let lng = null;
if (!accessToken) {
alert('No access_token. Verify OTP first.');
out.textContent = 'Error: No access token. Please verify OTP first.';
return;
}
// Get current location if checkbox is checked
if (document.getElementById('useCurrentLocation').checked) {
try {
out.textContent = 'Getting current location...';
const position = await new Promise((resolve, reject) => {
navigator.geolocation.getCurrentPosition(resolve, reject);
});
lat = position.coords.latitude;
lng = position.coords.longitude;
console.log('Current location:', lat, lng);
} catch (err) {
alert('Error getting location: ' + err.message);
out.textContent = 'Error getting GPS location: ' + err.message;
return;
}
}
const locationData = {
location_type: document.getElementById('locationType').value,
country: document.getElementById('country').value.trim() || null,
state: document.getElementById('state').value.trim() || null,
district: document.getElementById('district').value.trim() || null,
city_village: document.getElementById('cityVillage').value.trim() || null,
pincode: document.getElementById('pincode').value.trim() || null,
is_saved_address: true,
selected_location: document.getElementById('isPrimaryLocation').checked,
};
if (lat !== null && lng !== null) {
locationData.lat = lat;
locationData.lng = lng;
}
out.textContent = 'Saving location...';
console.log('Saving location:', locationData);
try {
// Note: You'll need to add a POST /users/me/locations endpoint
// For now, we'll use a generic approach
const res = await fetch('/users/me/locations', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + accessToken,
},
body: JSON.stringify(locationData)
});
console.log('Response status:', res.status);
const data = await res.json();
console.log('Response data:', data);
out.textContent = JSON.stringify(data, null, 2);
if (res.ok) {
alert('Location saved successfully!');
// Refresh user details to show new location
getUserDetails();
} else {
alert('Error: ' + (data.error || data.message || 'Failed to save location'));
}
} catch (err) {
console.error('Save location error:', err);
out.textContent = 'Error: ' + err.message;
alert('Error: ' + err.message);
}
}
// Attach event listeners to buttons (replaces inline onclick handlers)
// Since script is at end of body, DOM is already loaded
(function() {
const requestOtpBtn = document.getElementById('requestOtpBtn');
const verifyOtpBtn = document.getElementById('verifyOtpBtn');
const updateProfileBtn = document.getElementById('updateProfileBtn');
const getUserDetailsBtn = document.getElementById('getUserDetailsBtn');
const saveLocationBtn = document.getElementById('saveLocationBtn');
if (requestOtpBtn) {
requestOtpBtn.addEventListener('click', requestOtp);
console.log('Request OTP button listener attached');
}
if (verifyOtpBtn) {
verifyOtpBtn.addEventListener('click', verifyOtp);
console.log('Verify OTP button listener attached');
}
if (updateProfileBtn) {
updateProfileBtn.addEventListener('click', updateProfile);
console.log('Update Profile button listener attached');
}
if (getUserDetailsBtn) {
getUserDetailsBtn.addEventListener('click', getUserDetails);
console.log('Get User Details button listener attached');
}
if (saveLocationBtn) {
saveLocationBtn.addEventListener('click', saveLocation);
console.log('Save Location button listener attached');
}
console.log('Test page loaded. All event listeners attached.');
})();
</script>
</body>
</html>