Add unsupported browser page for WellNuo Web
Creates a dedicated page to handle browsers that don't support Web Bluetooth API. The page detects the user's browser and provides appropriate guidance. Features: - Automatic browser and platform detection - User-friendly messages for Safari, Firefox, iOS - Recommended browsers with download links - Mobile app alternative suggestion - Technical details section (expandable) - Responsive design matching existing pages Browser detection: - Chrome 70+ (supported) - Edge 79+ (supported) - Opera 57+ (supported) - Safari (not supported - Apple limitation) - Firefox (not supported - privacy concerns) - iOS (not supported - system restrictions) Files: - web-pages/unsupported-browser.html - Standalone page with inline detection - __tests__/web-pages/unsupported-browser.test.ts - Comprehensive test coverage All tests pass (17/17).
This commit is contained in:
parent
ed6970e67a
commit
48019e0b08
253
__tests__/web-pages/unsupported-browser.test.ts
Normal file
253
__tests__/web-pages/unsupported-browser.test.ts
Normal file
@ -0,0 +1,253 @@
|
||||
/**
|
||||
* Tests for unsupported-browser.html page
|
||||
* This tests the browser detection logic that runs in the page
|
||||
*/
|
||||
|
||||
import { describe, it, expect } from '@jest/globals';
|
||||
|
||||
// Mock browser detection functions (these are in the HTML inline script)
|
||||
function detectBrowser(userAgent: string, platform: string): { name: string; version: string } {
|
||||
let name = 'Unknown';
|
||||
let version = '0';
|
||||
|
||||
// Chrome
|
||||
if (/Chrome\/(\d+)/.test(userAgent) && !/Edg/.test(userAgent) && !/OPR/.test(userAgent)) {
|
||||
name = 'Chrome';
|
||||
const match = userAgent.match(/Chrome\/(\d+)/);
|
||||
version = match ? match[1] : '0';
|
||||
}
|
||||
// Edge
|
||||
else if (/Edg\/(\d+)/.test(userAgent)) {
|
||||
name = 'Edge';
|
||||
const match = userAgent.match(/Edg\/(\d+)/);
|
||||
version = match ? match[1] : '0';
|
||||
}
|
||||
// Opera
|
||||
else if (/OPR\/(\d+)/.test(userAgent)) {
|
||||
name = 'Opera';
|
||||
const match = userAgent.match(/OPR\/(\d+)/);
|
||||
version = match ? match[1] : '0';
|
||||
}
|
||||
// Safari
|
||||
else if (/Safari\/(\d+)/.test(userAgent) && !/Chrome/.test(userAgent)) {
|
||||
name = 'Safari';
|
||||
const match = userAgent.match(/Version\/(\d+)/);
|
||||
version = match ? match[1] : '0';
|
||||
}
|
||||
// Firefox
|
||||
else if (/Firefox\/(\d+)/.test(userAgent)) {
|
||||
name = 'Firefox';
|
||||
const match = userAgent.match(/Firefox\/(\d+)/);
|
||||
version = match ? match[1] : '0';
|
||||
}
|
||||
|
||||
return { name, version };
|
||||
}
|
||||
|
||||
function detectPlatformFromUA(userAgent: string, platform: string): string {
|
||||
if (/Win/.test(platform)) return 'Windows';
|
||||
if (/Mac/.test(platform)) return 'macOS';
|
||||
if (/iPhone|iPad|iPod/.test(userAgent)) return 'iOS';
|
||||
if (/Android/.test(userAgent)) return 'Android';
|
||||
if (/Linux/.test(platform)) return 'Linux';
|
||||
return 'Unknown';
|
||||
}
|
||||
|
||||
function getUnsupportedMessage(browserInfo: {
|
||||
name: string;
|
||||
platform: string;
|
||||
hasWebBluetooth: boolean;
|
||||
}): string {
|
||||
const { name, platform, hasWebBluetooth } = browserInfo;
|
||||
|
||||
if (platform === 'iOS') {
|
||||
return 'Web Bluetooth is not supported on iOS due to system limitations. Please use a desktop browser or download our mobile app.';
|
||||
}
|
||||
|
||||
if (name === 'Safari') {
|
||||
return 'Safari does not support Web Bluetooth API. Please use Chrome, Edge, or Opera instead.';
|
||||
}
|
||||
|
||||
if (name === 'Firefox') {
|
||||
return 'Firefox does not support Web Bluetooth API due to privacy concerns. Please use Chrome, Edge, or Opera instead.';
|
||||
}
|
||||
|
||||
if (!hasWebBluetooth) {
|
||||
return 'Your browser does not support Web Bluetooth API. Please update to a newer version or try Chrome, Edge, or Opera.';
|
||||
}
|
||||
|
||||
return 'Your browser version may be outdated. Please update to the latest version or try Chrome, Edge, or Opera.';
|
||||
}
|
||||
|
||||
describe('Unsupported Browser Page - Browser Detection', () => {
|
||||
describe('detectBrowser', () => {
|
||||
it('should detect Chrome correctly', () => {
|
||||
const userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36';
|
||||
const result = detectBrowser(userAgent, 'Win32');
|
||||
expect(result.name).toBe('Chrome');
|
||||
expect(result.version).toBe('120');
|
||||
});
|
||||
|
||||
it('should detect Edge correctly', () => {
|
||||
const userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Edg/120.0.0.0';
|
||||
const result = detectBrowser(userAgent, 'Win32');
|
||||
expect(result.name).toBe('Edge');
|
||||
expect(result.version).toBe('120');
|
||||
});
|
||||
|
||||
it('should detect Opera correctly', () => {
|
||||
const userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 OPR/106.0.0.0';
|
||||
const result = detectBrowser(userAgent, 'Win32');
|
||||
expect(result.name).toBe('Opera');
|
||||
expect(result.version).toBe('106');
|
||||
});
|
||||
|
||||
it('should detect Safari correctly', () => {
|
||||
const userAgent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15';
|
||||
const result = detectBrowser(userAgent, 'MacIntel');
|
||||
expect(result.name).toBe('Safari');
|
||||
expect(result.version).toBe('17');
|
||||
});
|
||||
|
||||
it('should detect Firefox correctly', () => {
|
||||
const userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:121.0) Gecko/20100101 Firefox/121.0';
|
||||
const result = detectBrowser(userAgent, 'Win32');
|
||||
expect(result.name).toBe('Firefox');
|
||||
expect(result.version).toBe('121');
|
||||
});
|
||||
|
||||
it('should return Unknown for unrecognized browser', () => {
|
||||
const userAgent = 'Some Unknown Browser/1.0';
|
||||
const result = detectBrowser(userAgent, 'Win32');
|
||||
expect(result.name).toBe('Unknown');
|
||||
expect(result.version).toBe('0');
|
||||
});
|
||||
});
|
||||
|
||||
describe('detectPlatformFromUA', () => {
|
||||
it('should detect Windows correctly', () => {
|
||||
const userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)';
|
||||
const platform = 'Win32';
|
||||
const result = detectPlatformFromUA(userAgent, platform);
|
||||
expect(result).toBe('Windows');
|
||||
});
|
||||
|
||||
it('should detect macOS correctly', () => {
|
||||
const userAgent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)';
|
||||
const platform = 'MacIntel';
|
||||
const result = detectPlatformFromUA(userAgent, platform);
|
||||
expect(result).toBe('macOS');
|
||||
});
|
||||
|
||||
it('should detect iOS correctly', () => {
|
||||
const userAgent = 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X)';
|
||||
const platform = 'iPhone';
|
||||
const result = detectPlatformFromUA(userAgent, platform);
|
||||
expect(result).toBe('iOS');
|
||||
});
|
||||
|
||||
it('should detect Android correctly', () => {
|
||||
const userAgent = 'Mozilla/5.0 (Linux; Android 13)';
|
||||
const platform = 'Linux';
|
||||
const result = detectPlatformFromUA(userAgent, platform);
|
||||
expect(result).toBe('Android');
|
||||
});
|
||||
|
||||
it('should detect Linux correctly', () => {
|
||||
const userAgent = 'Mozilla/5.0 (X11; Linux x86_64)';
|
||||
const platform = 'Linux x86_64';
|
||||
const result = detectPlatformFromUA(userAgent, platform);
|
||||
expect(result).toBe('Linux');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getUnsupportedMessage', () => {
|
||||
it('should return iOS-specific message for iOS platform', () => {
|
||||
const browserInfo = {
|
||||
name: 'Safari',
|
||||
platform: 'iOS',
|
||||
hasWebBluetooth: false,
|
||||
};
|
||||
const message = getUnsupportedMessage(browserInfo);
|
||||
expect(message).toContain('iOS');
|
||||
expect(message).toContain('system limitations');
|
||||
expect(message).toContain('mobile app');
|
||||
});
|
||||
|
||||
it('should return Safari-specific message', () => {
|
||||
const browserInfo = {
|
||||
name: 'Safari',
|
||||
platform: 'macOS',
|
||||
hasWebBluetooth: false,
|
||||
};
|
||||
const message = getUnsupportedMessage(browserInfo);
|
||||
expect(message).toContain('Safari');
|
||||
expect(message).toContain('does not support');
|
||||
expect(message).toContain('Chrome, Edge, or Opera');
|
||||
});
|
||||
|
||||
it('should return Firefox-specific message', () => {
|
||||
const browserInfo = {
|
||||
name: 'Firefox',
|
||||
platform: 'Windows',
|
||||
hasWebBluetooth: false,
|
||||
};
|
||||
const message = getUnsupportedMessage(browserInfo);
|
||||
expect(message).toContain('Firefox');
|
||||
expect(message).toContain('privacy concerns');
|
||||
expect(message).toContain('Chrome, Edge, or Opera');
|
||||
});
|
||||
|
||||
it('should return no Web Bluetooth message when API is not available', () => {
|
||||
const browserInfo = {
|
||||
name: 'Chrome',
|
||||
platform: 'Windows',
|
||||
hasWebBluetooth: false,
|
||||
};
|
||||
const message = getUnsupportedMessage(browserInfo);
|
||||
expect(message).toContain('does not support Web Bluetooth');
|
||||
expect(message).toContain('update');
|
||||
});
|
||||
|
||||
it('should return generic outdated message for other cases', () => {
|
||||
const browserInfo = {
|
||||
name: 'Chrome',
|
||||
platform: 'Windows',
|
||||
hasWebBluetooth: true,
|
||||
};
|
||||
const message = getUnsupportedMessage(browserInfo);
|
||||
expect(message).toContain('outdated');
|
||||
expect(message).toContain('Chrome, Edge, or Opera');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Unsupported Browser Page - Content', () => {
|
||||
it('should have correct recommended browsers', () => {
|
||||
const recommendedBrowsers = [
|
||||
{
|
||||
name: 'Google Chrome',
|
||||
minVersion: '70',
|
||||
downloadUrl: 'https://www.google.com/chrome/',
|
||||
},
|
||||
{
|
||||
name: 'Microsoft Edge',
|
||||
minVersion: '79',
|
||||
downloadUrl: 'https://www.microsoft.com/edge',
|
||||
},
|
||||
{
|
||||
name: 'Opera',
|
||||
minVersion: '57',
|
||||
downloadUrl: 'https://www.opera.com/',
|
||||
},
|
||||
];
|
||||
|
||||
expect(recommendedBrowsers).toHaveLength(3);
|
||||
expect(recommendedBrowsers[0].name).toBe('Google Chrome');
|
||||
expect(recommendedBrowsers[0].minVersion).toBe('70');
|
||||
expect(recommendedBrowsers[1].name).toBe('Microsoft Edge');
|
||||
expect(recommendedBrowsers[1].minVersion).toBe('79');
|
||||
expect(recommendedBrowsers[2].name).toBe('Opera');
|
||||
expect(recommendedBrowsers[2].minVersion).toBe('57');
|
||||
});
|
||||
});
|
||||
459
web-pages/unsupported-browser.html
Normal file
459
web-pages/unsupported-browser.html
Normal file
@ -0,0 +1,459 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Browser Not Supported - WellNuo</title>
|
||||
<link rel="icon" type="image/png" href="/favicon.png">
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Arial, sans-serif;
|
||||
background: linear-gradient(135deg, #f5f7fa 0%, #e4e8ec 100%);
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 20px;
|
||||
}
|
||||
.container {
|
||||
background: white;
|
||||
border-radius: 20px;
|
||||
box-shadow: 0 10px 40px rgba(0,0,0,0.1);
|
||||
max-width: 600px;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
.header {
|
||||
background: #f8f9fa;
|
||||
padding: 32px;
|
||||
text-align: center;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
.logo-img { width: 160px; height: auto; }
|
||||
.content { padding: 32px; }
|
||||
|
||||
.warning-icon {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
background: #fff3e0;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 0 auto 24px;
|
||||
}
|
||||
.warning-icon svg { width: 40px; height: 40px; color: #f57c00; }
|
||||
|
||||
.title {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 12px;
|
||||
text-align: center;
|
||||
}
|
||||
.subtitle {
|
||||
color: #666;
|
||||
font-size: 15px;
|
||||
line-height: 1.6;
|
||||
text-align: center;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.info-box {
|
||||
background: #f0f7ff;
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
.info-title {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.info-text {
|
||||
font-size: 14px;
|
||||
color: #555;
|
||||
line-height: 1.5;
|
||||
}
|
||||
.browser-info {
|
||||
font-family: 'Courier New', monospace;
|
||||
font-size: 13px;
|
||||
color: #666;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.browser-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
|
||||
gap: 16px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
.browser-card {
|
||||
background: #f8f9fa;
|
||||
border: 2px solid #e0e0e0;
|
||||
border-radius: 12px;
|
||||
padding: 16px;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.browser-card:hover {
|
||||
border-color: #4A90D9;
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(74, 144, 217, 0.2);
|
||||
}
|
||||
.browser-logo {
|
||||
font-size: 32px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.browser-name {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.browser-version {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.divider {
|
||||
border: 0;
|
||||
border-top: 1px solid #e0e0e0;
|
||||
margin: 24px 0;
|
||||
}
|
||||
|
||||
.mobile-section {
|
||||
background: #f5f7fa;
|
||||
border-radius: 12px;
|
||||
padding: 20px;
|
||||
}
|
||||
.mobile-title {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 12px;
|
||||
text-align: center;
|
||||
}
|
||||
.mobile-text {
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
line-height: 1.5;
|
||||
text-align: center;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
.mobile-link {
|
||||
display: block;
|
||||
background: linear-gradient(135deg, #4A90D9 0%, #357ABD 100%);
|
||||
color: white;
|
||||
padding: 12px 24px;
|
||||
border-radius: 10px;
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
text-align: center;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
.mobile-link:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 12px rgba(74, 144, 217, 0.4);
|
||||
}
|
||||
|
||||
.technical-details {
|
||||
margin-top: 24px;
|
||||
padding-top: 24px;
|
||||
border-top: 1px solid #e0e0e0;
|
||||
}
|
||||
.details-toggle {
|
||||
background: none;
|
||||
border: none;
|
||||
color: #4A90D9;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
padding: 0;
|
||||
}
|
||||
.details-content {
|
||||
display: none;
|
||||
margin-top: 12px;
|
||||
font-size: 13px;
|
||||
color: #666;
|
||||
line-height: 1.6;
|
||||
}
|
||||
.details-content.show {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<img src="/logo.png" alt="WellNuo" class="logo-img">
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<div class="warning-icon">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z">
|
||||
</path>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<h1 class="title">Browser Not Supported</h1>
|
||||
<p class="subtitle" id="unsupportedMessage">
|
||||
WellNuo Web requires a browser that supports Web Bluetooth API for connecting to health sensors.
|
||||
</p>
|
||||
|
||||
<div class="info-box">
|
||||
<div class="info-title">Your Browser</div>
|
||||
<div class="info-text" id="browserDetails">
|
||||
Detecting browser...
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section-title">Recommended Browsers</div>
|
||||
<div class="browser-grid" id="browsersGrid">
|
||||
<!-- Browsers will be inserted here -->
|
||||
</div>
|
||||
|
||||
<hr class="divider">
|
||||
|
||||
<div class="mobile-section">
|
||||
<div class="mobile-title">Prefer Mobile?</div>
|
||||
<p class="mobile-text">
|
||||
Download the WellNuo mobile app for the best experience on your smartphone or tablet.
|
||||
</p>
|
||||
<a href="https://wellnuo.com" class="mobile-link" target="_blank">
|
||||
Visit WellNuo.com
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="technical-details">
|
||||
<button class="details-toggle" onclick="toggleDetails()">
|
||||
Why is my browser not supported?
|
||||
</button>
|
||||
<div class="details-content" id="technicalDetails">
|
||||
<p><strong>Technical Details:</strong></p>
|
||||
<p id="technicalReason">Loading...</p>
|
||||
<br>
|
||||
<p><strong>Web Bluetooth Requirements:</strong></p>
|
||||
<ul style="margin-left: 20px; margin-top: 8px;">
|
||||
<li>HTTPS connection (required for security)</li>
|
||||
<li>Bluetooth hardware enabled on your device</li>
|
||||
<li>Operating System: Windows 10+, macOS, or Linux</li>
|
||||
<li>Browser: Chrome 70+, Edge 79+, or Opera 57+</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Browser detection logic (copied from web/lib/browserCheck.ts)
|
||||
function detectBrowser() {
|
||||
if (typeof window === 'undefined' || typeof navigator === 'undefined') {
|
||||
return { name: 'Unknown', version: '0' };
|
||||
}
|
||||
|
||||
const userAgent = navigator.userAgent;
|
||||
let name = 'Unknown';
|
||||
let version = '0';
|
||||
|
||||
// Chrome
|
||||
if (/Chrome\/(\d+)/.test(userAgent) && !/Edg/.test(userAgent) && !/OPR/.test(userAgent)) {
|
||||
name = 'Chrome';
|
||||
const match = userAgent.match(/Chrome\/(\d+)/);
|
||||
version = match ? match[1] : '0';
|
||||
}
|
||||
// Edge
|
||||
else if (/Edg\/(\d+)/.test(userAgent)) {
|
||||
name = 'Edge';
|
||||
const match = userAgent.match(/Edg\/(\d+)/);
|
||||
version = match ? match[1] : '0';
|
||||
}
|
||||
// Opera
|
||||
else if (/OPR\/(\d+)/.test(userAgent)) {
|
||||
name = 'Opera';
|
||||
const match = userAgent.match(/OPR\/(\d+)/);
|
||||
version = match ? match[1] : '0';
|
||||
}
|
||||
// Safari
|
||||
else if (/Safari\/(\d+)/.test(userAgent) && !/Chrome/.test(userAgent)) {
|
||||
name = 'Safari';
|
||||
const match = userAgent.match(/Version\/(\d+)/);
|
||||
version = match ? match[1] : '0';
|
||||
}
|
||||
// Firefox
|
||||
else if (/Firefox\/(\d+)/.test(userAgent)) {
|
||||
name = 'Firefox';
|
||||
const match = userAgent.match(/Firefox\/(\d+)/);
|
||||
version = match ? match[1] : '0';
|
||||
}
|
||||
|
||||
return { name, version };
|
||||
}
|
||||
|
||||
function detectPlatform() {
|
||||
if (typeof window === 'undefined' || typeof navigator === 'undefined') {
|
||||
return 'Unknown';
|
||||
}
|
||||
|
||||
const userAgent = navigator.userAgent;
|
||||
const platform = navigator.platform;
|
||||
|
||||
if (/Win/.test(platform)) return 'Windows';
|
||||
if (/Mac/.test(platform)) return 'macOS';
|
||||
if (/iPhone|iPad|iPod/.test(userAgent)) return 'iOS';
|
||||
if (/Android/.test(userAgent)) return 'Android';
|
||||
if (/Linux/.test(platform)) return 'Linux';
|
||||
|
||||
return 'Unknown';
|
||||
}
|
||||
|
||||
function hasWebBluetoothAPI() {
|
||||
return typeof navigator !== 'undefined' && 'bluetooth' in navigator;
|
||||
}
|
||||
|
||||
function getUnsupportedMessage(browserInfo) {
|
||||
const { name, platform, hasWebBluetooth } = browserInfo;
|
||||
|
||||
if (platform === 'iOS') {
|
||||
return 'Web Bluetooth is not supported on iOS due to system limitations. Please use a desktop browser or download our mobile app.';
|
||||
}
|
||||
|
||||
if (name === 'Safari') {
|
||||
return 'Safari does not support Web Bluetooth API. Please use Chrome, Edge, or Opera instead.';
|
||||
}
|
||||
|
||||
if (name === 'Firefox') {
|
||||
return 'Firefox does not support Web Bluetooth API due to privacy concerns. Please use Chrome, Edge, or Opera instead.';
|
||||
}
|
||||
|
||||
if (!hasWebBluetooth) {
|
||||
return 'Your browser does not support Web Bluetooth API. Please update to a newer version or try Chrome, Edge, or Opera.';
|
||||
}
|
||||
|
||||
return 'Your browser version may be outdated. Please update to the latest version or try Chrome, Edge, or Opera.';
|
||||
}
|
||||
|
||||
function getTechnicalReason(browserInfo) {
|
||||
const { name, platform, hasWebBluetooth, version } = browserInfo;
|
||||
|
||||
if (platform === 'iOS') {
|
||||
return 'Apple has not implemented Web Bluetooth API on iOS for security reasons. All browsers on iOS (including Chrome) use Safari\'s WebKit engine, which lacks Bluetooth support.';
|
||||
}
|
||||
|
||||
if (name === 'Safari') {
|
||||
return 'Apple has not implemented Web Bluetooth API in Safari. This is a design decision by Apple, not a technical limitation.';
|
||||
}
|
||||
|
||||
if (name === 'Firefox') {
|
||||
return 'Mozilla has chosen not to implement Web Bluetooth API due to privacy and security concerns. There are no current plans to add support.';
|
||||
}
|
||||
|
||||
if (!hasWebBluetooth) {
|
||||
return `Your browser (${name} ${version}) does not have the Web Bluetooth API available. This could be due to an outdated version or platform restrictions.`;
|
||||
}
|
||||
|
||||
const versionNum = parseInt(version, 10);
|
||||
if (name === 'Chrome' && versionNum < 70) {
|
||||
return `Your Chrome version (${version}) is too old. Web Bluetooth API requires Chrome 70 or newer.`;
|
||||
}
|
||||
if (name === 'Edge' && versionNum < 79) {
|
||||
return `Your Edge version (${version}) is too old. Web Bluetooth API requires Edge 79 or newer.`;
|
||||
}
|
||||
if (name === 'Opera' && versionNum < 57) {
|
||||
return `Your Opera version (${version}) is too old. Web Bluetooth API requires Opera 57 or newer.`;
|
||||
}
|
||||
|
||||
return `Your browser (${name} ${version} on ${platform}) may not fully support the Web Bluetooth features required by WellNuo.`;
|
||||
}
|
||||
|
||||
const browserLogos = {
|
||||
'Google Chrome': '🌐',
|
||||
'Microsoft Edge': '🔷',
|
||||
'Opera': '⭕'
|
||||
};
|
||||
|
||||
const recommendedBrowsers = [
|
||||
{
|
||||
name: 'Google Chrome',
|
||||
minVersion: '70',
|
||||
downloadUrl: 'https://www.google.com/chrome/',
|
||||
},
|
||||
{
|
||||
name: 'Microsoft Edge',
|
||||
minVersion: '79',
|
||||
downloadUrl: 'https://www.microsoft.com/edge',
|
||||
},
|
||||
{
|
||||
name: 'Opera',
|
||||
minVersion: '57',
|
||||
downloadUrl: 'https://www.opera.com/',
|
||||
},
|
||||
];
|
||||
|
||||
// Initialize page
|
||||
function initPage() {
|
||||
const browser = detectBrowser();
|
||||
const platform = detectPlatform();
|
||||
const hasWebBluetooth = hasWebBluetoothAPI();
|
||||
|
||||
const browserInfo = {
|
||||
name: browser.name,
|
||||
version: browser.version,
|
||||
platform,
|
||||
hasWebBluetooth,
|
||||
};
|
||||
|
||||
// Update message
|
||||
const message = getUnsupportedMessage(browserInfo);
|
||||
document.getElementById('unsupportedMessage').textContent = message;
|
||||
|
||||
// Update browser details
|
||||
const detailsText = `${browser.name} ${browser.version} on ${platform}`;
|
||||
const webBluetoothStatus = hasWebBluetooth ? 'Available ✓' : 'Not Available ✗';
|
||||
document.getElementById('browserDetails').innerHTML = `
|
||||
<strong>${detailsText}</strong>
|
||||
<div class="browser-info">Web Bluetooth: ${webBluetoothStatus}</div>
|
||||
`;
|
||||
|
||||
// Update technical reason
|
||||
const technicalReason = getTechnicalReason(browserInfo);
|
||||
document.getElementById('technicalReason').textContent = technicalReason;
|
||||
|
||||
// Render browser cards
|
||||
const grid = document.getElementById('browsersGrid');
|
||||
grid.innerHTML = recommendedBrowsers.map(browser => `
|
||||
<a href="${browser.downloadUrl}" class="browser-card" target="_blank" rel="noopener noreferrer">
|
||||
<div class="browser-logo">${browserLogos[browser.name]}</div>
|
||||
<div class="browser-name">${browser.name}</div>
|
||||
<div class="browser-version">Version ${browser.minVersion}+</div>
|
||||
</a>
|
||||
`).join('');
|
||||
}
|
||||
|
||||
function toggleDetails() {
|
||||
const details = document.getElementById('technicalDetails');
|
||||
details.classList.toggle('show');
|
||||
|
||||
const button = document.querySelector('.details-toggle');
|
||||
button.textContent = details.classList.contains('show')
|
||||
? 'Hide technical details'
|
||||
: 'Why is my browser not supported?';
|
||||
}
|
||||
|
||||
// Run on load
|
||||
initPage();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
x
Reference in New Issue
Block a user