Skip to content

Commit

Permalink
Updated: Experience
Browse files Browse the repository at this point in the history
  • Loading branch information
jeeshumittal7 committed Nov 7, 2024
1 parent e5a81eb commit 55c5786
Show file tree
Hide file tree
Showing 23 changed files with 487 additions and 120 deletions.
3 changes: 0 additions & 3 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,3 @@ DATABASE_URL=

# Session secret string (must be unique to your server)
SESSION_SECRET=

# Path to the JavaScript loader file (example: /path/to/loader.js)
LOADER_JS_PATH=
9 changes: 5 additions & 4 deletions models/User.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ const bcrypt = require('bcrypt');
const { v4: uuidv4 } = require('uuid');

const userSchema = new mongoose.Schema({
username: { type: String, unique: true, required: true },
email: { type: String, unique: true, required: true },
password: { type: String, required: true },
apiKey: { type: String, unique: true }
apiKey: { type: String, unique: true },
allowedOrigins: [{ type: String }]
});

// Pre-save middleware for generating the API key and hashing the password
Expand All @@ -16,7 +17,7 @@ userSchema.pre('save', async function(next) {
if (user.isNew) {
try {
user.apiKey = uuidv4(); // Generate a unique API key
console.log(`API Key generated for user: ${user.username}`);
console.log(`API Key generated for user: ${user.email}`);
} catch (err) {
console.error('Error generating API key:', err.message, err.stack);
return next(err);
Expand All @@ -28,7 +29,7 @@ userSchema.pre('save', async function(next) {
try {
const hash = await bcrypt.hash(user.password, 10);
user.password = hash;
console.log(`Password hashed for user: ${user.username}`);
console.log(`Password hashed for user: ${user.email}`);
} catch (err) {
console.error('Error hashing password:', err.message, err.stack);
return next(err);
Expand Down
85 changes: 84 additions & 1 deletion public/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ body {
flex-direction: column;
min-height: 100vh;
margin: 0;
padding-bottom: 60px; /* Adjust this value as needed */
}
.container {
flex: 1;
Expand All @@ -16,4 +17,86 @@ body {
background: #f8f9fa;
padding: 1rem 0;
margin-top: auto;
}
}

/* Placeholder for custom styles */
.pythagora-logo {
height: 20px;
margin-left: 5px;
}

/* Add new styles for animations and modern look */
.fade-in {
animation: fadeIn 0.5s ease-in;
}

@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}

.slide-in {
animation: slideIn 0.5s ease-out;
}

@keyframes slideIn {
from { transform: translateY(20px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}

.pulse {
animation: pulse 2s infinite;
}

@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.05); }
100% { transform: scale(1); }
}

.card {
transition: all 0.3s ease;
}

.card:hover {
transform: translateY(-5px);
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}

.btn {
transition: all 0.3s ease;
}

.btn:hover {
transform: translateY(-2px);
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

.tooltip {
position: relative;
display: inline-block;
}

.tooltip .tooltiptext {
visibility: hidden;
width: 120px;
background-color: #555;
color: #fff;
text-align: center;
border-radius: 6px;
padding: 5px 0;
position: absolute;
z-index: 1;
bottom: 125%;
left: 50%;
margin-left: -60px;
opacity: 0;
transition: opacity 0.3s;
}

.tooltip:hover .tooltiptext {
visibility: visible;
opacity: 1;
}

/* Add more custom styles as needed */
37 changes: 37 additions & 0 deletions public/css/tooltipSlider.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
.tooltip-slider {
position: relative;
overflow: hidden;
height: 120px; /* Changed from 150px to 120px */
margin-bottom: 5px; /* Further reduce from 10px */
}

.tooltip-slide {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
transition: opacity 0.5s ease-in-out;
}

.tooltip-slide.active {
opacity: 1;
}

.tooltip-content {
background-color: #f8f9fa;
border: 1px solid #dee2e6;
border-radius: 5px;
padding: 15px;
text-align: center;
}

.slider-controls {
text-align: center;
margin-bottom: 5px; /* Further reduce from 10px */
}

.slider-controls button {
margin: 0 5px;
}
83 changes: 54 additions & 29 deletions public/js/abTests.js
Original file line number Diff line number Diff line change
@@ -1,57 +1,82 @@
document.addEventListener('DOMContentLoaded', function() {
console.log('A/B Tests Management Page Loaded');
console.log("A/B Tests Management Page Loaded");

const addPagePathButton = document.getElementById('addPagePath');
// Event listener for toggling test status
document.querySelectorAll('.toggle-test-status').forEach(button => {
button.addEventListener('click', function(e) {
e.preventDefault();

if (addPagePathButton) {
addPagePathButton.addEventListener('click', function() {
const pagePathsContainer = document.getElementById('pagePaths');
if (pagePathsContainer) {
const newInput = document.createElement('input');
newInput.type = 'text';
newInput.className = 'form-control mb-2';
newInput.name = 'pagePaths[]';
pagePathsContainer.appendChild(newInput);
console.log('Added new page path input field.');
} else {
console.error('Page paths container not found.');
const csrfTokenElement = document.getElementById('csrfToken');
if (!csrfTokenElement) {
console.log("CSRF token not found. User might not be logged in.");
return;
}
});
} else {
console.error('Add page path button not found.');
}

document.querySelectorAll('.toggle-test-status').forEach(button => {
button.addEventListener('click', function(event) {
event.preventDefault();
const testId = this.dataset.testid;
const currentStatus = this.dataset.status;
if (!testId) {
console.error("Test ID not found on button.");
return;
}

const csrfToken = csrfTokenElement.value;

fetch(`/tests/${testId}/toggle-status`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'CSRF-Token': document.getElementById('csrfToken').value
'CSRF-Token': csrfToken
},
body: JSON.stringify({ testStatus: currentStatus === 'Running' ? 'Stopped' : 'Running' }),
body: JSON.stringify({ testStatus: this.dataset.status === 'Running' ? 'Stopped' : 'Running' }),
credentials: 'same-origin'
})
.then(response => response.json())
.then(data => {
if (data.success) {
const newStatus = data.testStatus;
this.dataset.status = newStatus;
this.classList.toggle('btn-success', newStatus === 'Stopped');
this.classList.toggle('btn-danger', newStatus === 'Running');
this.classList.remove('btn-success', 'btn-danger');
this.classList.add(newStatus === 'Running' ? 'btn-danger' : 'btn-success');
this.textContent = newStatus === 'Running' ? 'Stop' : 'Start';
console.log(`Test status updated to: ${newStatus}`);
this.closest('.card-body').querySelector('.card-text').textContent = `Status: ${newStatus}`;
const statusElement = this.closest('.card-body').querySelector('.card-text');
if (statusElement) {
statusElement.textContent = `Status: ${newStatus}`;
}
} else {
console.error('Failed to toggle test status.');
console.error('Failed to toggle test status:', data.message);
}
})
.catch(error => {
console.error('Error toggling test status:', error.message, error.stack);
});
});
});

// Functionality for adding page paths on the A/B Tests Management page
function addPagePathFunctionality() {
const addPagePathButton = document.getElementById('addPagePath');
if (addPagePathButton) {
addPagePathButton.addEventListener('click', function() {
const pagePathsContainer = document.getElementById('pagePaths');
if (pagePathsContainer) {
const newInput = document.createElement('input');
newInput.type = 'text';
newInput.className = 'form-control mb-2';
newInput.name = 'pagePaths[]';
pagePathsContainer.appendChild(newInput);
console.log('Added new page path input field.');
} else {
console.error('Page paths container not found.');
}
});
} else {
console.error('Add page path button not found.');
}
}

// Check if we're on the A/B Tests Management page to add page paths
if (document.getElementById('testsList')) {
addPagePathFunctionality();
} else {
console.log("Not on A/B Tests Management page, skipping A/B test-specific operations.");
}
});
31 changes: 31 additions & 0 deletions public/js/animations.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
document.addEventListener('DOMContentLoaded', function() {
// Add fade-in effect to main content
const mainContent = document.querySelector('main');
if (mainContent) {
mainContent.classList.add('fade-in');
}

// Add slide-in effect to cards
const cards = document.querySelectorAll('.card');
cards.forEach((card, index) => {
card.classList.add('slide-in');
card.style.animationDelay = `${index * 0.1}s`;
});

// Add pulse effect to buttons
const buttons = document.querySelectorAll('.btn-primary');
buttons.forEach(button => {
button.classList.add('pulse');
});

// Initialize tooltips
const tooltips = document.querySelectorAll('[data-toggle="tooltip"]');
tooltips.forEach(tooltip => {
new bootstrap.Tooltip(tooltip);
});

// Error handling for missing elements
window.addEventListener('error', function(event) {
console.error("Error occurred in animations.js: ", event.message, event.error.stack);
});
});
15 changes: 14 additions & 1 deletion public/js/main.js
Original file line number Diff line number Diff line change
@@ -1 +1,14 @@
// Placeholder for future JavaScript code
document.addEventListener('DOMContentLoaded', function() {
console.log('Main script loaded');

// Initialize tooltips
const tooltips = document.querySelectorAll('[data-toggle="tooltip"]');
tooltips.forEach(tooltip => {
new bootstrap.Tooltip(tooltip);
});

// Error handling for missing elements
window.addEventListener('error', function(event) {
console.error("Error occurred in main.js: ", event.message, event.error.stack);
});
});
37 changes: 37 additions & 0 deletions public/js/tooltipSlider.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
document.addEventListener('DOMContentLoaded', function() {
const slides = document.querySelectorAll('.tooltip-slide');
const prevButton = document.getElementById('prevTip');
const nextButton = document.getElementById('nextTip');
let currentSlide = 0;

function showSlide(index) {
slides.forEach(slide => slide.classList.remove('active'));
slides[index].classList.add('active');
}

function nextSlide() {
currentSlide = (currentSlide + 1) % slides.length;
showSlide(currentSlide);
console.log(`Showing next slide: ${currentSlide}`);
}

function prevSlide() {
currentSlide = (currentSlide - 1 + slides.length) % slides.length;
showSlide(currentSlide);
console.log(`Showing previous slide: ${currentSlide}`);
}

nextButton.addEventListener('click', nextSlide);
prevButton.addEventListener('click', prevSlide);

showSlide(currentSlide);

// Auto-advance slides every 5 seconds
setInterval(function() {
try {
nextSlide();
} catch (error) {
console.error("Error auto-advancing slide: ", error.message, error.stack);
}
}, 5000);
});
6 changes: 3 additions & 3 deletions routes/abTestRoutes.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,16 @@ router.post('/tests/:testId/toggle-status', isAuthenticated, async (req, res) =>
try {
const test = await AbTest.findById(req.params.testId);
if (!test) {
console.log('Test not found with id:', req.params.testId);
return res.status(404).json({ success: false, message: 'Test not found.' });
console.error('Test not found with id:', req.params.testId);
return res.status(404).json({ success: false, message: 'Test not found' });
}
test.testStatus = test.testStatus === 'Running' ? 'Stopped' : 'Running';
await test.save();
console.log(`Test status toggled: ${test.testName} is now ${test.testStatus}`);
res.json({ success: true, testStatus: test.testStatus });
} catch (error) {
console.error('Error toggling test status:', error.message, error.stack);
res.status(500).json({ success: false, message: 'Error toggling test status.' });
res.status(500).json({ success: false, message: 'Error toggling test status' });
}
});

Expand Down
Loading

0 comments on commit 55c5786

Please sign in to comment.