// Frontend JavaScript with various technical debt examples
// TODO: Move configuration to separate file
const API_BASE_URL = "https://api.example.com";
const API_KEY = "abc123def456"; // FIXME: Should be in environment
// Global variables - should be encapsulated
var userCache = {};
var authToken = null;
var currentUser = null;
// HACK: Polyfill for older browsers - should use proper build system
if (!String.prototype.includes) {
String.prototype.includes = function(search) {
return this.indexOf(search) !== -1;
};
}
class UserInterface {
constructor() {
this.components = {};
this.eventHandlers = [];
// Long parameter list in constructor
this.init(document, window, localStorage, sessionStorage, navigator, history, location);
}
// Function with too many parameters
init(doc, win, localStorage, sessionStorage, nav, hist, loc) {
this.document = doc;
this.window = win;
this.localStorage = localStorage;
this.sessionStorage = sessionStorage;
this.navigator = nav;
this.history = hist;
this.location = loc;
// Deep nesting example
if (this.localStorage) {
if (this.localStorage.getItem('user')) {
if (JSON.parse(this.localStorage.getItem('user'))) {
if (JSON.parse(this.localStorage.getItem('user')).preferences) {
if (JSON.parse(this.localStorage.getItem('user')).preferences.theme) {
if (JSON.parse(this.localStorage.getItem('user')).preferences.theme === 'dark') {
document.body.classList.add('dark-theme');
} else if (JSON.parse(this.localStorage.getItem('user')).preferences.theme === 'light') {
document.body.classList.add('light-theme');
} else {
document.body.classList.add('default-theme');
}
}
}
}
}
}
}
// Large function that does too many things
renderUserDashboard(userId, includeStats, includeRecent, includeNotifications, includeSettings, includeHelp) {
let user = this.getUser(userId);
if (!user) {
console.log("User not found"); // Should use proper logging
return;
}
let html = '
';
// Inline HTML generation - should use templates
html += '';
html += '
Welcome, ' + user.name + '
';
html += '
';
html += '';
html += '
';
html += '';
// Repeated validation pattern
if (includeStats && includeStats === true) {
html += '';
html += '
Your Statistics
';
// Magic numbers everywhere
if (user.loginCount > 100) {
html += '
Frequent User (100+ logins)
';
} else if (user.loginCount > 50) {
html += '
Regular User (50+ logins)
';
} else if (user.loginCount > 10) {
html += '
Casual User (10+ logins)
';
} else {
html += '
New User
';
}
html += '';
}
if (includeRecent && includeRecent === true) {
html += '';
html += '
Recent Activity
';
// No error handling for API calls
let recentActivity = this.fetchRecentActivity(userId);
if (recentActivity && recentActivity.length > 0) {
html += '
';
for (let i = 0; i < recentActivity.length; i++) {
let activity = recentActivity[i];
html += '
';
html += '' + activity.type + '';
html += '' + activity.description + '';
html += '' + this.formatTime(activity.timestamp) + '';
html += '
';
}
html += '
';
} else {
html += '
No recent activity
';
}
html += '';
}
if (includeNotifications && includeNotifications === true) {
html += '';
html += '
Notifications
';
let notifications = this.getNotifications(userId);
// Duplicate HTML generation pattern
if (notifications && notifications.length > 0) {
html += '
';
for (let i = 0; i < notifications.length; i++) {
let notification = notifications[i];
html += '
';
html += '' + notification.title + '';
html += '' + notification.message + '';
html += '' + this.formatTime(notification.timestamp) + '';
html += '
';
}
html += '
';
} else {
html += '
No notifications
';
}
html += '';
}
html += '
';
// Direct DOM manipulation without cleanup
document.getElementById('main-content').innerHTML = html;
// Event handler attachment without cleanup
let buttons = document.querySelectorAll('.action-button');
for (let i = 0; i < buttons.length; i++) {
buttons[i].addEventListener('click', function(event) {
// Nested event handlers - memory leak risk
let buttonType = event.target.getAttribute('data-type');
if (buttonType === 'edit') {
// Inline event handling - should be separate methods
let modal = document.createElement('div');
modal.className = 'modal';
modal.innerHTML = '
Edit Profile
';
document.body.appendChild(modal);
} else if (buttonType === 'delete') {
if (confirm('Are you sure?')) { // Using confirm - poor UX
// No error handling
fetch(API_BASE_URL + '/users/' + userId, {
method: 'DELETE',
headers: {'Authorization': 'Bearer ' + authToken}
});
}
} else if (buttonType === 'share') {
// Hardcoded share logic
if (navigator.share) {
navigator.share({
title: 'Check out my profile',
url: window.location.href
});
} else {
// Fallback for browsers without Web Share API
let shareUrl = 'https://twitter.com/intent/tweet?url=' + encodeURIComponent(window.location.href);
window.open(shareUrl, '_blank');
}
}
});
}
}
// Duplicate code - similar to above but for admin dashboard
renderAdminDashboard(adminId) {
let admin = this.getUser(adminId);
if (!admin) {
console.log("Admin not found");
return;
}
let html = '
';
html += '';
html += '
Admin Panel - Welcome, ' + admin.name + '
';
html += '
';
html += '';
html += '
';
html += '';
// Same pattern repeated
html += '';
html += '
System Statistics
';
let stats = this.getSystemStats();
if (stats) {
html += '
';
html += '
Total Users: ' + stats.totalUsers + '
';
html += '
Active Users: ' + stats.activeUsers + '
';
html += '
New Today: ' + stats.newToday + '
';
html += '
';
}
html += '';
html += '
';
document.getElementById('main-content').innerHTML = html;
}
getUser(userId) {
// Check cache first - but cache never expires
if (userCache[userId]) {
return userCache[userId];
}
// Synchronous AJAX - blocks UI
let xhr = new XMLHttpRequest();
xhr.open('GET', API_BASE_URL + '/users/' + userId, false);
xhr.setRequestHeader('Authorization', 'Bearer ' + authToken);
xhr.send();
if (xhr.status === 200) {
let user = JSON.parse(xhr.responseText);
userCache[userId] = user;
return user;
} else {
// Generic error handling
console.error('Failed to fetch user');
return null;
}
}
fetchRecentActivity(userId) {
// Another synchronous call
try {
let xhr = new XMLHttpRequest();
xhr.open('GET', API_BASE_URL + '/users/' + userId + '/activity', false);
xhr.setRequestHeader('Authorization', 'Bearer ' + authToken);
xhr.send();
if (xhr.status === 200) {
return JSON.parse(xhr.responseText);
} else {
return [];
}
} catch (error) {
// Swallowing errors
return [];
}
}
getNotifications(userId) {
// Yet another sync call - should be async
let xhr = new XMLHttpRequest();
xhr.open('GET', API_BASE_URL + '/users/' + userId + '/notifications', false);
xhr.setRequestHeader('Authorization', 'Bearer ' + authToken);
xhr.send();
if (xhr.status === 200) {
return JSON.parse(xhr.responseText);
} else {
return [];
}
}
formatTime(timestamp) {
// Basic time formatting - should use proper library
let date = new Date(timestamp);
return date.getMonth() + '/' + date.getDate() + '/' + date.getFullYear();
}
// XXX: This method is never used
formatCurrency(amount, currency) {
if (currency === 'USD') {
return '$' + amount.toFixed(2);
} else if (currency === 'EUR') {
return '€' + amount.toFixed(2);
} else {
return amount.toFixed(2) + ' ' + currency;
}
}
getSystemStats() {
// Hardcoded test data - should come from API
return {
totalUsers: 12534,
activeUsers: 8765,
newToday: 23
};
}
}
// Global functions - should be methods or modules
function closeModal() {
// Assumes modal exists - no error checking
document.querySelector('.modal').remove();
}
function validateEmail(email) {
// Regex without explanation - magic pattern
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
function validatePassword(password) {
// Duplicate validation logic from backend
if (password.length < 8) return false;
if (!/[A-Z]/.test(password)) return false;
if (!/[a-z]/.test(password)) return false;
if (!/\d/.test(password)) return false;
return true;
}
// jQuery-style utility - reinventing the wheel
function $(selector) {
return document.querySelector(selector);
}
function $all(selector) {
return document.querySelectorAll(selector);
}
// Global event handlers - should be encapsulated
document.addEventListener('DOMContentLoaded', function() {
// Inline anonymous function
let ui = new UserInterface();
// Event delegation would be better
document.body.addEventListener('click', function(event) {
if (event.target.classList.contains('login-button')) {
// Inline login logic
let username = $('#username').value;
let password = $('#password').value;
if (!username || !password) {
alert('Please enter username and password'); // Poor UX
return;
}
// No CSRF protection
fetch(API_BASE_URL + '/auth/login', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({username: username, password: password})
})
.then(response => response.json())
.then(data => {
if (data.success) {
authToken = data.token;
currentUser = data.user;
localStorage.setItem('authToken', authToken); // Storing sensitive data
localStorage.setItem('currentUser', JSON.stringify(currentUser));
window.location.reload(); // Poor navigation
} else {
alert('Login failed: ' + data.error);
}
})
.catch(error => {
console.error('Login error:', error);
alert('Login failed');
});
}
});
});
// // Old code left as comments - should be removed
// function oldRenderFunction() {
// var html = '
Old implementation
';
// document.body.innerHTML = html;
// }
// Commented out feature - should be removed or implemented
// function darkModeToggle() {
// if (document.body.classList.contains('dark-theme')) {
// document.body.classList.remove('dark-theme');
// document.body.classList.add('light-theme');
// } else {
// document.body.classList.remove('light-theme');
// document.body.classList.add('dark-theme');
// }
// }