/home/awneajlw/www/codestechvista.com/assets/js/main.js
// Main JavaScript for Opti-Vision Eye Clinic
document.addEventListener('DOMContentLoaded', function() {
// Initialize tooltips
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl);
});
// Initialize popovers
var popoverTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]'));
var popoverList = popoverTriggerList.map(function (popoverTriggerEl) {
return new bootstrap.Popover(popoverTriggerEl);
});
// Smooth scrolling for anchor links
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function (e) {
e.preventDefault();
const target = document.querySelector(this.getAttribute('href'));
if (target) {
target.scrollIntoView({
behavior: 'smooth',
block: 'start'
});
}
});
});
// Form validation
const forms = document.querySelectorAll('.needs-validation');
Array.from(forms).forEach(form => {
form.addEventListener('submit', event => {
if (!form.checkValidity()) {
event.preventDefault();
event.stopPropagation();
}
form.classList.add('was-validated');
}, false);
});
// Auto-hide alerts after 5 seconds
setTimeout(function() {
const alerts = document.querySelectorAll('.alert');
alerts.forEach(alert => {
const bsAlert = new bootstrap.Alert(alert);
bsAlert.close();
});
}, 5000);
// Loading states for buttons
const submitButtons = document.querySelectorAll('button[type="submit"]');
submitButtons.forEach(button => {
button.addEventListener('click', function() {
if (this.form && this.form.checkValidity()) {
this.innerHTML = '<span class="spinner me-2"></span>Processing...';
this.disabled = true;
}
});
});
// Navbar scroll effect
const navbar = document.querySelector('.navbar');
if (navbar) {
window.addEventListener('scroll', function() {
if (window.scrollY > 50) {
navbar.classList.add('navbar-scrolled');
} else {
navbar.classList.remove('navbar-scrolled');
}
});
}
// Appointment time validation
const appointmentDate = document.getElementById('appointment_date');
const appointmentTime = document.getElementById('appointment_time');
if (appointmentDate && appointmentTime) {
appointmentDate.addEventListener('change', function() {
const selectedDate = new Date(this.value);
const today = new Date();
today.setHours(0, 0, 0, 0);
if (selectedDate < today) {
this.setCustomValidity('Appointment date cannot be in the past');
} else {
this.setCustomValidity('');
}
});
}
// Password strength indicator
const passwordInputs = document.querySelectorAll('input[type="password"]');
passwordInputs.forEach(input => {
input.addEventListener('input', function() {
const password = this.value;
const strength = getPasswordStrength(password);
updatePasswordStrength(this, strength);
});
});
// Confirm password validation
const confirmPassword = document.getElementById('confirm_password');
const newPassword = document.getElementById('new_password');
if (confirmPassword && newPassword) {
confirmPassword.addEventListener('input', function() {
if (this.value !== newPassword.value) {
this.setCustomValidity('Passwords do not match');
} else {
this.setCustomValidity('');
}
});
}
});
// Password strength checker
function getPasswordStrength(password) {
let strength = 0;
if (password.length >= 6) strength++;
if (password.length >= 8) strength++;
if (/[a-z]/.test(password)) strength++;
if (/[A-Z]/.test(password)) strength++;
if (/[0-9]/.test(password)) strength++;
if (/[^A-Za-z0-9]/.test(password)) strength++;
return strength;
}
// Update password strength indicator
function updatePasswordStrength(input, strength) {
const strengthIndicator = input.parentNode.querySelector('.password-strength');
if (!strengthIndicator) {
const indicator = document.createElement('div');
indicator.className = 'password-strength mt-2';
input.parentNode.appendChild(indicator);
}
const indicator = input.parentNode.querySelector('.password-strength');
const strengthText = ['Very Weak', 'Weak', 'Fair', 'Good', 'Strong', 'Very Strong'];
const strengthColors = ['danger', 'danger', 'warning', 'info', 'success', 'success'];
if (strength > 0) {
indicator.innerHTML = `
<div class="progress" style="height: 5px;">
<div class="progress-bar bg-${strengthColors[strength - 1]}"
style="width: ${(strength / 6) * 100}%"></div>
</div>
<small class="text-${strengthColors[strength - 1]}">${strengthText[strength - 1]}</small>
`;
} else {
indicator.innerHTML = '';
}
}
// Utility functions
function showAlert(message, type = 'info') {
const alertContainer = document.querySelector('.alert-container') || createAlertContainer();
const alert = document.createElement('div');
alert.className = `alert alert-${type} alert-dismissible fade show`;
alert.innerHTML = `
${message}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
`;
alertContainer.appendChild(alert);
// Auto-remove after 5 seconds
setTimeout(() => {
if (alert.parentNode) {
alert.remove();
}
}, 5000);
}
function createAlertContainer() {
const container = document.createElement('div');
container.className = 'alert-container position-fixed top-0 end-0 p-3';
container.style.zIndex = '9999';
document.body.appendChild(container);
return container;
}
// AJAX helper functions
function makeRequest(url, method = 'GET', data = null) {
return fetch(url, {
method: method,
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest'
},
body: data ? JSON.stringify(data) : null
})
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
});
}
// Form submission with AJAX
function submitForm(form, successCallback = null, errorCallback = null) {
const formData = new FormData(form);
const data = Object.fromEntries(formData);
makeRequest(form.action, form.method, data)
.then(response => {
if (successCallback) {
successCallback(response);
} else {
showAlert(response.message || 'Operation completed successfully', 'success');
}
})
.catch(error => {
if (errorCallback) {
errorCallback(error);
} else {
showAlert('An error occurred. Please try again.', 'danger');
}
});
}
// Date and time utilities
function formatDate(date) {
return new Date(date).toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric'
});
}
function formatTime(time) {
return new Date('1970-01-01T' + time).toLocaleTimeString('en-US', {
hour: 'numeric',
minute: '2-digit',
hour12: true
});
}
// Animation utilities
function fadeIn(element, duration = 300) {
element.style.opacity = 0;
element.style.display = 'block';
let start = performance.now();
function animate(timestamp) {
let progress = (timestamp - start) / duration;
if (progress > 1) progress = 1;
element.style.opacity = progress;
if (progress < 1) {
requestAnimationFrame(animate);
}
}
requestAnimationFrame(animate);
}
function fadeOut(element, duration = 300) {
let start = performance.now();
function animate(timestamp) {
let progress = (timestamp - start) / duration;
if (progress > 1) progress = 1;
element.style.opacity = 1 - progress;
if (progress < 1) {
requestAnimationFrame(animate);
} else {
element.style.display = 'none';
}
}
requestAnimationFrame(animate);
}