UrbanFlow / frontend /js /shared.js
Subh775's picture
RELEASE: auth; pf section added; bug/crash/ major improvements & fixes; refactoring pending..
5cd1866
/**
* UrbanFlow — shared.js
* Shared utilities, modal management, and legal content injection.
* Loaded on every page before page-specific scripts.
*/
// =============================================
// Modal Management
// =============================================
function openAppModal(id) {
const el = document.getElementById('appModal-' + id);
if (el) { el.style.display = 'flex'; document.body.style.overflow = 'hidden'; }
}
function closeAppModal(id) {
const el = document.getElementById('appModal-' + id);
if (el) { el.style.display = 'none'; document.body.style.overflow = ''; }
}
// =============================================
// Legal Modals — Single Source of Truth
// =============================================
const LEGAL_CONTENT = {
privacy: {
title: 'Privacy Policy',
subtitle: 'Last Updated: 28th April 2026',
content: `
<p><strong>1. WHO WE ARE</strong><br>
UrbanFlow is a computer vision software that analyses traffic video footage to produce structured traffic data. It is hosted on Hugging Face Spaces as a demonstration and research product by Perception365.<br>
Contact: <strong style="color:#f0c674">support.urbanflow365@gmail.com</strong></p>
<p><strong>2. WHAT DATA WE COLLECT</strong><br>
<strong>a) Account Data:</strong> When you sign in with Google, we receive your name, email address, and profile picture. We store only what is necessary to identify your session.<br>
<strong>b) Uploaded Video Footage:</strong> Videos you upload are processed temporarily for inference only. We do not store your original footage. All uploaded files are deleted automatically once processing is complete and session cache is cleared each run.<br>
<strong>c) Analysis Outputs:</strong> Processed results are tied to your active session only. We do not sell or share this data with anyone.<br>
<strong>d) Usage Logs:</strong> We collect standard server logs (IP address, browser type, timestamps) for security monitoring and platform improvement only.</p>
<p><strong>3. HOW WE USE YOUR DATA</strong><br>
We use your data solely to:<br>
- Authenticate your identity and maintain your session<br>
- Process uploaded footage and return results to you<br>
- Detect and prevent misuse of the platform<br>
- Comply with legal obligations<br>
We do not use your data for advertising. We do not sell your data to any third party under any circumstances.</p>
<p><strong>4. DATA SHARING</strong><br>
We do not share your personal data with third parties except:<br>
- Google — for authentication (governed by Google's Privacy Policy)<br>
- Hugging Face — infrastructure hosting (see huggingface.co/privacy)<br>
- Legal authorities — only if required by law<br>
We have no control over Hugging Face's infrastructure-level data handling.</p>
<p><strong>5. DATA SECURITY</strong><br>
We apply reasonable technical measures to protect data in transit and at rest. However, no system is perfectly secure. We operate on shared cloud infrastructure and cannot guarantee absolute security. By using UrbanFlow, you acknowledge and accept this risk.<br>
You should not upload footage containing sensitive personal information, private property interiors, classified content, or any material you are not authorised to share.</p>
<p><strong>6. YOUR RIGHTS</strong><br>
Since UrbanFlow does not maintain permanent user accounts, signing out clears your session and associated data entirely. You may also contact us to ask what data is held or to report a concern.<br>
Contact: <strong style="color:#f0c674">support.urbanflow365@gmail.com</strong><br>
We will respond within 30 days.</p>
<p><strong>7. CHANGES TO THIS POLICY</strong><br>
We may update this policy as the platform evolves. The "Last Updated" date at the top reflects the most recent revision. Continued use after changes constitutes acceptance of the updated policy.</p>
`
},
terms: {
title: 'Terms & Conditions',
subtitle: 'Last Updated: 28th April 2026',
content: `
<p><strong>1. ACCEPTANCE</strong><br>
By accessing or using UrbanFlow, you confirm that you have read, understood, and agree to these Terms and Conditions in full. If you do not agree, do not use the platform.<br>
We are not responsible for any risks arising from future use of the platform beyond what is expressly stated here.</p>
<p><strong>2. NATURE OF THE PLATFORM</strong><br>
UrbanFlow is a beta product provided for research, evaluation, and non-critical use only. It is not intended for use in life-safety systems, emergency response, legal proceedings, or any context where errors in traffic data could cause harm.<br>
The platform may be modified, suspended, or discontinued at any time without prior notice.</p>
<p><strong>3. ELIGIBILITY</strong><br>
You must be at least 18 years old and hold a valid Google account to use UrbanFlow. By signing in, you confirm you meet these requirements.</p>
<p><strong>4. ACCEPTABLE USE</strong><br>
You agree to use UrbanFlow only for its intended purpose: analysing road or traffic video footage to obtain traffic flow data.<br>
You must NOT:<br>
a) Upload footage unrelated to traffic or road monitoring — including personal recordings, indoor footage, private events, or surveillance of individuals.<br>
b) Upload footage you do not have the legal right to use or process.<br>
c) Upload footage containing nudity, violence, illegal activity, or any content that violates applicable law.<br>
d) Attempt to reverse-engineer, scrape, or abuse the platform or its API.<br>
e) Use the platform to identify, track, or surveil specific individuals without their explicit consent.<br>
f) Upload classified, confidential, or government-restricted materials.<br>
g) Use bots or automated scripts to interact with the platform.<br>
Violation of these terms may result in immediate access termination and, where applicable, reporting to relevant authorities.</p>
<p><strong>5. YOUR RESPONSIBILITY FOR UPLOADED CONTENT</strong><br>
You are solely responsible for any footage you upload. By uploading, you confirm that:<br>
- You own the footage or hold explicit authorisation to process it<br>
- The footage is relevant to traffic or road monitoring<br>
- You are not violating any third party's rights, including privacy rights<br>
- The footage does not contain content prohibited under Section 4<br>
We do not review uploaded footage before processing and are not responsible for its content.</p>
<p><strong>6. LIMITATION OF LIABILITY</strong><br>
To the fullest extent permitted by applicable law:<br>
a) UrbanFlow is not liable for any direct, indirect, incidental, or consequential damages arising from your use of the platform.<br>
b) Analysis results are provided as-is. They should not be used as the sole basis for engineering, legal, or policy decisions without independent verification.<br>
c) In the event of a data breach, system failure, or security incident, our liability is limited to the maximum extent permitted by law. We will make reasonable efforts to notify affected users but are not liable for resulting harm.<br>
d) We are not responsible for platform availability or uptime, as it operates on Hugging Face's third-party infrastructure.</p>
<p><strong>7. DATA BREACH NOTICE</strong><br>
If a breach affecting user data occurs, we will notify affected users via their registered email address within a reasonable timeframe of becoming aware of the incident. Given that we collect only session-level identifiers and no permanent video data, the risk of significant harm from a breach is inherently limited.</p>
<p><strong>8. INTELLECTUAL PROPERTY</strong><br>
UrbanFlow, its models, interface, design, and associated technology are the intellectual property of Perception365. You may not copy, reproduce, or redistribute any part of the platform without written permission.<br>
You retain ownership of all footage you upload. By uploading, you grant us a limited, temporary licence to process that footage for analysis. This licence expires once processing is complete and the footage is deleted.</p>
<p><strong>9. THIRD-PARTY SERVICES</strong><br>
UrbanFlow uses:<br>
- Google Identity Services (authentication)<br>
- Hugging Face Spaces (hosting and compute)<br>
Use of these services is governed by their own terms and privacy policies. We are not responsible for the practices of these providers.</p>
<p><strong>10. TERMINATION</strong><br>
We reserve the right to suspend or terminate access to UrbanFlow at any time, with or without notice, for violations of these Terms or misuse of the platform.</p>
<p><strong>11. GOVERNING LAW</strong><br>
These Terms are governed by the laws of India. Any disputes shall be subject to the exclusive jurisdiction of the courts of Indore, Madhya Pradesh, India.</p>
<p><strong>12. CHANGES TO THESE TERMS</strong><br>
We may revise these Terms at any time. Continued use of the platform after changes are posted constitutes acceptance of the revised Terms.</p>
<p><strong>CONTACT</strong><br>
For any questions, concerns, or to report misuse:<br>
Email: <strong style="color:#f0c674">support.urbanflow365@gmail.com</strong></p>
`
},
};
function injectLegalModals() {
const container = document.createElement('div');
container.id = 'legal-modals-container';
// Privacy Modal
const p = LEGAL_CONTENT.privacy;
const privacyHTML = getPrivacyModalTemplate(p);
// Terms Modal
const t = LEGAL_CONTENT.terms;
const termsHTML = getTermsModalTemplate(t);
container.innerHTML = privacyHTML + termsHTML;
document.body.appendChild(container);
}
// =============================================
// Keyboard Shortcuts Modal (vehicles.html only)
// =============================================
const SHORTCUTS = [
{ label: 'About', key: '1' },
{ label: 'Overview', key: '2' },
{ label: 'Results', key: '3' },
{ label: 'Settings', key: '4' },
{ label: 'Guide', key: '5' },
{ label: 'Feedback', key: '6' },
{ label: 'Profile', key: '7' },
{ label: 'Download Artifacts', key: 'D' },
];
function injectShortcutsModal() {
const rows = SHORTCUTS.map(s =>
`<div class="shortcut-row">
<span class="shortcut-label">${s.label}</span>
<kbd class="kbd-key">${s.key}</kbd>
</div>`
).join('');
const html = getShortcutsModalTemplate(rows);
const container = document.createElement('div');
container.innerHTML = html;
document.body.appendChild(container.firstElementChild);
}
// =============================================
// Mobile Legal Menu Toggle
// =============================================
function toggleLegalMenu(e) {
if (e) e.stopPropagation();
const menu = document.getElementById('legal-menu');
if (menu) menu.classList.toggle('hidden');
}
document.addEventListener('click', function() {
const menu = document.getElementById('legal-menu');
if (menu) menu.classList.add('hidden');
});
// =============================================
// Global Key Handler
// =============================================
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') {
closeAppModal('privacyModal');
closeAppModal('termsModal');
closeAppModal('shortcutsModal');
if (typeof hideLogoutConfirm === 'function') hideLogoutConfirm();
if (typeof closeLandingProfileMenu === 'function') closeLandingProfileMenu();
const legalMenu = document.getElementById('legal-menu');
if (legalMenu) legalMenu.classList.add('hidden');
}
});
// =============================================
// Auto-inject legal modals on DOMContentLoaded
// =============================================
document.addEventListener('DOMContentLoaded', injectLegalModals);
// =============================================
// Navigation — Single Source of Truth
// =============================================
const NAV_ITEMS = [
{ id: 'about', icon: 'fa-circle-info', label: 'About' },
{ id: 'overview', icon: 'fa-desktop', label: 'Overview' },
{ id: 'results', icon: 'fa-file-lines', label: 'Results' },
{ id: 'settings', icon: 'fa-gear', label: 'Settings' },
{ id: 'help', icon: 'fa-circle-question', label: 'Guide' },
{ id: 'feedback', icon: 'fa-comment-dots', label: 'Feedback' },
{ id: 'profile', icon: 'fa-circle-user', label: 'Profile' },
];
function injectNavigation() {
// Sidebar nav (desktop)
const sidebarNav = document.getElementById('sidebar-nav');
if (sidebarNav) {
sidebarNav.innerHTML = NAV_ITEMS.map(n =>
`<a onclick="switchTab('${n.id}')" id="nav-${n.id}" class="flex items-center px-4 py-2.5 rounded-lg transition cursor-pointer nav-item-inactive">
<i class="fa-solid ${n.icon} w-6"></i> <span class="font-medium">${n.label}</span>
</a>`
).join('');
}
// Mobile bottom nav
const bottomNav = document.getElementById('mobile-bottom-nav');
if (bottomNav) {
bottomNav.innerHTML = NAV_ITEMS.map(n =>
`<button class="mob-nav-item" id="mob-nav-${n.id}" onclick="switchTab('${n.id}')">
<i class="fa-solid ${n.icon}"></i>
</button>`
).join('');
}
}
// =============================================
// Service Worker Registration
// =============================================
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('./sw.js');
});
}