recreate project
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
(function() {
|
||||
let trafficChartInstance = null;
|
||||
let incomeChartInstance = null;
|
||||
|
||||
document.addEventListener('DOMContentLoaded', (event) => {
|
||||
initializeCharts();
|
||||
});
|
||||
|
||||
function initializeCharts() {
|
||||
// Traffic Chart
|
||||
/*
|
||||
const trafficChartCanvas = document.getElementById('trafficChart');
|
||||
if (trafficChartInstance) {
|
||||
trafficChartInstance.destroy();
|
||||
}
|
||||
if (trafficChartCanvas) {
|
||||
const ctxTraffic = trafficChartCanvas.getContext('2d');
|
||||
trafficChartInstance = new Chart(ctxTraffic, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
|
||||
datasets: [{
|
||||
label: 'Traffic',
|
||||
data: [65, 59, 80, 81, 56, 55, 40],
|
||||
backgroundColor: 'rgba(75, 192, 192, 0.2)',
|
||||
borderColor: 'rgba(75, 192, 192, 1)',
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
*/
|
||||
// Income Chart
|
||||
/*
|
||||
const incomeChartCanvas = document.getElementById('incomeChart');
|
||||
if (incomeChartInstance) {
|
||||
incomeChartInstance.destroy();
|
||||
}
|
||||
if (incomeChartCanvas) {
|
||||
const ctxIncome = incomeChartCanvas.getContext('2d');
|
||||
incomeChartInstance = new Chart(ctxIncome, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
|
||||
datasets: [{
|
||||
label: 'Income',
|
||||
data: [12, 19, 3, 5, 2, 3, 7],
|
||||
backgroundColor: 'rgba(153, 102, 255, 0.2)',
|
||||
borderColor: 'rgba(153, 102, 255, 1)',
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}*/
|
||||
}
|
||||
})();
|
||||
@@ -0,0 +1,42 @@
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const ctx = document.getElementById('myChart').getContext('2d');
|
||||
|
||||
if (ctx) {
|
||||
const myChart = new Chart(ctx, {
|
||||
type: 'bar', // or 'line', 'pie', etc.
|
||||
data: {
|
||||
labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
|
||||
datasets: [{
|
||||
label: '# of Votes',
|
||||
data: [12, 19, 3, 5, 2, 3],
|
||||
backgroundColor: [
|
||||
'rgba(255, 99, 132, 0.2)',
|
||||
'rgba(54, 162, 235, 0.2)',
|
||||
'rgba(255, 206, 86, 0.2)',
|
||||
'rgba(75, 192, 192, 0.2)',
|
||||
'rgba(153, 102, 255, 0.2)',
|
||||
'rgba(255, 159, 64, 0.2)'
|
||||
],
|
||||
borderColor: [
|
||||
'rgba(255, 99, 132, 1)',
|
||||
'rgba(54, 162, 235, 1)',
|
||||
'rgba(255, 206, 86, 1)',
|
||||
'rgba(75, 192, 192, 1)',
|
||||
'rgba(153, 102, 255, 1)',
|
||||
'rgba(255, 159, 64, 1)'
|
||||
],
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.error('Canvas element not found');
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,21 @@
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var calendarEl = document.getElementById('calendar');
|
||||
|
||||
var calendar = new FullCalendar.Calendar(calendarEl, {
|
||||
initialView: 'dayGridMonth',
|
||||
events: '/calendar/events', // URL to fetch events from the backend
|
||||
headerToolbar: {
|
||||
left: 'prev,next today',
|
||||
center: 'title',
|
||||
right: 'dayGridMonth,timeGridWeek,timeGridDay'
|
||||
},
|
||||
eventClick: function(info) {
|
||||
alert('Event: ' + info.event.title + '\n' +
|
||||
'Start: ' + info.event.start + '\n' +
|
||||
'End: ' + info.event.end + '\n' +
|
||||
'Description: ' + info.event.extendedProps.description);
|
||||
}
|
||||
});
|
||||
|
||||
calendar.render();
|
||||
});
|
||||
@@ -0,0 +1,27 @@
|
||||
// initials.js
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
function getInitials(firstName, lastName) {
|
||||
if (firstName && lastName) {
|
||||
return firstName.charAt(0) + lastName.charAt(0);
|
||||
}
|
||||
return 'N/A';
|
||||
}
|
||||
|
||||
fetchUserData()
|
||||
.then(data => {
|
||||
if (data.error) {
|
||||
document.getElementById('user-name').textContent = 'Guest';
|
||||
document.getElementById('profile-picture').textContent = 'G';
|
||||
} else {
|
||||
const firstName = data.firstname || 'N/A';
|
||||
const lastName = data.lastname || 'N/A';
|
||||
document.getElementById('user-name').textContent = firstName + ' ' + lastName;
|
||||
document.getElementById('profile-picture').textContent = getInitials(firstName, lastName);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error fetching user data:', error);
|
||||
document.getElementById('user-name').textContent = 'Error loading user data';
|
||||
document.getElementById('profile-picture').textContent = 'E';
|
||||
});
|
||||
});
|
||||
Vendored
+2
File diff suppressed because one or more lines are too long
@@ -0,0 +1,81 @@
|
||||
(function ($) {
|
||||
"use strict";
|
||||
|
||||
// Initiate the wowjs
|
||||
new WOW().init();
|
||||
|
||||
|
||||
// Spinner
|
||||
var spinner = function () {
|
||||
setTimeout(function () {
|
||||
if ($('#spinner').length > 0) {
|
||||
$('#spinner').removeClass('show');
|
||||
}
|
||||
}, 1);
|
||||
};
|
||||
spinner();
|
||||
|
||||
|
||||
// Sticky Navbar
|
||||
$(window).scroll(function () {
|
||||
if ($(this).scrollTop() > 300) {
|
||||
$('.sticky-top').addClass('shadow-sm').css('top', '0px');
|
||||
} else {
|
||||
$('.sticky-top').removeClass('shadow-sm').css('top', '-100px');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Back to top button
|
||||
$(window).scroll(function () {
|
||||
if ($(this).scrollTop() > 300) {
|
||||
$('.back-to-top').fadeIn('slow');
|
||||
} else {
|
||||
$('.back-to-top').fadeOut('slow');
|
||||
}
|
||||
});
|
||||
$('.back-to-top').click(function () {
|
||||
$('html, body').animate({scrollTop: 0}, 1500, 'easeInOutExpo');
|
||||
return false;
|
||||
});
|
||||
|
||||
|
||||
// Header carousel
|
||||
$(".header-carousel").owlCarousel({
|
||||
autoplay: true,
|
||||
smartSpeed: 1500,
|
||||
items: 1,
|
||||
dots: true,
|
||||
loop: true,
|
||||
nav : true,
|
||||
navText : [
|
||||
'<i class="bi bi-chevron-left"></i>',
|
||||
'<i class="bi bi-chevron-right"></i>'
|
||||
]
|
||||
});
|
||||
|
||||
|
||||
// Testimonials carousel
|
||||
$(".testimonial-carousel").owlCarousel({
|
||||
autoplay: true,
|
||||
smartSpeed: 1000,
|
||||
margin: 24,
|
||||
dots: false,
|
||||
loop: true,
|
||||
nav : true,
|
||||
navText : [
|
||||
'<i class="bi bi-arrow-left"></i>',
|
||||
'<i class="bi bi-arrow-right"></i>'
|
||||
],
|
||||
responsive: {
|
||||
0:{
|
||||
items:1
|
||||
},
|
||||
992:{
|
||||
items:2
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
// Import Bootstrap CSS
|
||||
import 'bootstrap/dist/css/bootstrap.min.css';
|
||||
|
||||
// Import Bootstrap Bundle JS (includes Popper.js)
|
||||
import 'bootstrap/dist/js/bootstrap.bundle.min.js';
|
||||
|
||||
// Custom JS for the parent panel
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Add any custom JavaScript for your parent dashboard here
|
||||
});
|
||||
@@ -0,0 +1,244 @@
|
||||
class SessionTimeoutManager {
|
||||
constructor() {
|
||||
this.config = {
|
||||
timeout: 1800, // 30 minutes
|
||||
warning_time: 300, // 5 minutes before timeout
|
||||
check_interval: 60000, // 1 minute
|
||||
logout_url: '/auth/logout',
|
||||
keep_alive_url: '/session/ping-activity',
|
||||
check_url: '/session/check-timeout'
|
||||
};
|
||||
this.timers = {
|
||||
checkTimer: null,
|
||||
logoutTimer: null,
|
||||
warningTimer: null
|
||||
};
|
||||
this.modal = null;
|
||||
this.warningShown = false;
|
||||
this.csrfToken = this.getCsrfToken();
|
||||
}
|
||||
|
||||
getCsrfToken() {
|
||||
// Try to get CSRF token from meta tag
|
||||
const metaTag = document.querySelector('meta[name="csrf-token"]');
|
||||
if (metaTag) {
|
||||
return metaTag.getAttribute('content');
|
||||
}
|
||||
|
||||
// Try to get CSRF token from form input (fallback)
|
||||
const csrfInput = document.querySelector('input[name="' + csrf_token + '"]');
|
||||
if (csrfInput) {
|
||||
return csrfInput.value;
|
||||
}
|
||||
|
||||
console.warn('CSRF token not found');
|
||||
return '';
|
||||
}
|
||||
|
||||
async init() {
|
||||
this.setupEventListeners();
|
||||
this.startPeriodicChecks();
|
||||
console.log('Session timeout manager initialized with config:', this.config);
|
||||
}
|
||||
|
||||
// REMOVE the fetchConfig() method entirely
|
||||
|
||||
setupEventListeners() {
|
||||
// Reset timers on user activity
|
||||
const events = ['mousedown', 'keydown', 'scroll', 'touchstart', 'click', 'input'];
|
||||
events.forEach(event => {
|
||||
document.addEventListener(event, () => this.resetActivity(), { passive: true });
|
||||
});
|
||||
|
||||
// Handle visibility change
|
||||
document.addEventListener('visibilitychange', () => {
|
||||
if (!document.hidden) {
|
||||
this.checkSessionStatus();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async resetActivity() {
|
||||
try {
|
||||
await fetch(this.config.keep_alive_url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-Requested-With': 'XMLHttpRequest',
|
||||
'X-CSRF-TOKEN': this.csrfToken
|
||||
},
|
||||
credentials: 'same-origin'
|
||||
});
|
||||
this.clearWarning();
|
||||
} catch (error) {
|
||||
console.warn('Activity reset failed:', error);
|
||||
}
|
||||
}
|
||||
|
||||
startPeriodicChecks() {
|
||||
this.timers.checkTimer = setInterval(() => {
|
||||
this.checkSessionStatus();
|
||||
}, this.config.check_interval);
|
||||
}
|
||||
|
||||
async checkSessionStatus() {
|
||||
try {
|
||||
const response = await fetch(this.config.check_url, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'X-Requested-With': 'XMLHttpRequest',
|
||||
'X-CSRF-TOKEN': this.csrfToken
|
||||
},
|
||||
credentials: 'same-origin'
|
||||
});
|
||||
|
||||
if (response.status === 404) {
|
||||
// If check endpoint doesn't exist, skip checking
|
||||
console.log('Session check endpoint not available, skipping');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
switch (data.status) {
|
||||
case 'expired':
|
||||
this.handleSessionExpired(data);
|
||||
break;
|
||||
case 'warning':
|
||||
this.handleSessionWarning(data);
|
||||
break;
|
||||
case 'active':
|
||||
this.handleSessionActive(data);
|
||||
break;
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('Session status check failed:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// ... rest of the methods remain the same
|
||||
handleSessionExpired(data) {
|
||||
this.clearWarning();
|
||||
clearInterval(this.timers.checkTimer);
|
||||
|
||||
if (data.redirect) {
|
||||
alert(data.message || 'Your session has expired. Please log in again.');
|
||||
window.location.href = data.redirect;
|
||||
} else {
|
||||
window.location.href = this.config.logout_url;
|
||||
}
|
||||
}
|
||||
|
||||
handleSessionWarning(data) {
|
||||
if (!this.warningShown) {
|
||||
this.showWarning(data.time_remaining);
|
||||
} else {
|
||||
this.updateWarning(data.time_remaining);
|
||||
}
|
||||
}
|
||||
|
||||
handleSessionActive(data) {
|
||||
this.clearWarning();
|
||||
}
|
||||
|
||||
showWarning(timeRemaining) {
|
||||
this.warningShown = true;
|
||||
this.createWarningModal(timeRemaining);
|
||||
}
|
||||
|
||||
updateWarning(timeRemaining) {
|
||||
if (this.modal) {
|
||||
const countdownElement = this.modal.querySelector('.countdown');
|
||||
if (countdownElement) {
|
||||
countdownElement.textContent = Math.max(0, timeRemaining);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
createWarningModal(timeRemaining) {
|
||||
this.hideWarning();
|
||||
|
||||
this.modal = document.createElement('div');
|
||||
this.modal.className = 'session-timeout-modal';
|
||||
this.modal.style.cssText = `
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0,0,0,0.8);
|
||||
z-index: 99999;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-family: Arial, sans-serif;
|
||||
`;
|
||||
|
||||
this.modal.innerHTML = `
|
||||
<div style="background: white; padding: 30px; border-radius: 10px; text-align: center; max-width: 400px; box-shadow: 0 5px 25px rgba(0,0,0,0.3);">
|
||||
<h3 style="color: #d35400; margin-bottom: 20px; font-size: 1.5em;">Session About to Expire</h3>
|
||||
<p style="font-size: 1.1em; margin-bottom: 20px;">
|
||||
Your session will expire in <span class="countdown" style="font-weight: bold; color: #e74c3c;">${timeRemaining}</span> seconds due to inactivity.
|
||||
</p>
|
||||
<div style="margin-top: 25px;">
|
||||
<button onclick="sessionTimeout.continueSession()"
|
||||
style="background: #27ae60; color: white; border: none; padding: 12px 24px;
|
||||
border-radius: 5px; cursor: pointer; margin-right: 15px; font-size: 1em;">
|
||||
Continue Session
|
||||
</button>
|
||||
<button onclick="sessionTimeout.logout()"
|
||||
style="background: #e74c3c; color: white; border: none; padding: 12px 24px;
|
||||
border-radius: 5px; cursor: pointer; font-size: 1em;">
|
||||
Logout Now
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
document.body.appendChild(this.modal);
|
||||
document.body.style.overflow = 'hidden';
|
||||
}
|
||||
|
||||
hideWarning() {
|
||||
if (this.modal) {
|
||||
this.modal.remove();
|
||||
this.modal = null;
|
||||
}
|
||||
this.warningShown = false;
|
||||
document.body.style.overflow = '';
|
||||
}
|
||||
|
||||
clearWarning() {
|
||||
this.hideWarning();
|
||||
}
|
||||
|
||||
continueSession() {
|
||||
this.resetActivity();
|
||||
this.hideWarning();
|
||||
}
|
||||
|
||||
logout() {
|
||||
window.location.href = this.config.logout_url;
|
||||
}
|
||||
|
||||
destroy() {
|
||||
clearInterval(this.timers.checkTimer);
|
||||
this.hideWarning();
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize globally
|
||||
const sessionTimeout = new SessionTimeoutManager();
|
||||
|
||||
// Start when DOM is ready
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', () => sessionTimeout.init());
|
||||
} else {
|
||||
sessionTimeout.init();
|
||||
}
|
||||
|
||||
// Make available globally
|
||||
window.sessionTimeout = sessionTimeout;
|
||||
@@ -0,0 +1,22 @@
|
||||
$(document).ready(function() {
|
||||
$.getJSON('/load_images.php', function(images) {
|
||||
if (images.length) {
|
||||
images.forEach(function(image, index) {
|
||||
$('#slideshow').append('<img src="' + image + '" alt="Background Image ' + (index + 1) + '">');
|
||||
});
|
||||
|
||||
let currentIndex = 0;
|
||||
const imagesList = $('.slideshow img');
|
||||
const totalImages = imagesList.length;
|
||||
|
||||
function showNextImage() {
|
||||
imagesList.eq(currentIndex).css('opacity', 0);
|
||||
currentIndex = (currentIndex + 1) % totalImages;
|
||||
imagesList.eq(currentIndex).css('opacity', 1);
|
||||
}
|
||||
|
||||
imagesList.eq(0).css('opacity', 1); // Show the first image initially
|
||||
setInterval(showNextImage, 3000); // Change image every 3 seconds
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,60 @@
|
||||
// Import Bootstrap CSS
|
||||
import 'bootstrap/dist/css/bootstrap.min.css';
|
||||
|
||||
// Import Bootstrap Bundle JS (includes Popper.js)
|
||||
import 'bootstrap/dist/js/bootstrap.bundle.min.js';
|
||||
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var ctxAssignment = document.getElementById('assignmentChart').getContext('2d');
|
||||
var assignmentChart = new Chart(ctxAssignment, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: ['Week 1', 'Week 2', 'Week 3', 'Week 4'],
|
||||
datasets: [{
|
||||
label: 'Assignments',
|
||||
data: [5, 3, 2, 7],
|
||||
backgroundColor: 'rgba(75, 192, 192, 0.2)',
|
||||
borderColor: 'rgba(75, 192, 192, 1)',
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var ctxGrade = document.getElementById('gradeChart').getContext('2d');
|
||||
var gradeChart = new Chart(ctxGrade, {
|
||||
type: 'pie',
|
||||
data: {
|
||||
labels: ['A', 'B', 'C', 'D', 'F'],
|
||||
datasets: [{
|
||||
data: [12, 19, 3, 5, 2],
|
||||
backgroundColor: [
|
||||
'rgba(75, 192, 192, 0.2)',
|
||||
'rgba(54, 162, 235, 0.2)',
|
||||
'rgba(255, 206, 86, 0.2)',
|
||||
'rgba(255, 159, 64, 0.2)',
|
||||
'rgba(255, 99, 132, 0.2)'
|
||||
],
|
||||
borderColor: [
|
||||
'rgba(75, 192, 192, 1)',
|
||||
'rgba(54, 162, 235, 1)',
|
||||
'rgba(255, 206, 86, 1)',
|
||||
'rgba(255, 159, 64, 1)',
|
||||
'rgba(255, 99, 132, 1)'
|
||||
],
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user