pricing
This commit is contained in:
310
static/js/settings/pricing.js
Normal file
310
static/js/settings/pricing.js
Normal file
@@ -0,0 +1,310 @@
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Feature management for add form
|
||||
const addFeatureBtn = document.getElementById('addFeatureBtn');
|
||||
const featuresContainer = document.getElementById('featuresContainer');
|
||||
|
||||
if (addFeatureBtn) {
|
||||
addFeatureBtn.addEventListener('click', function() {
|
||||
addFeatureField(featuresContainer);
|
||||
});
|
||||
}
|
||||
|
||||
// Feature management for edit form
|
||||
const editAddFeatureBtn = document.getElementById('editAddFeatureBtn');
|
||||
const editFeaturesContainer = document.getElementById('editFeaturesContainer');
|
||||
|
||||
if (editAddFeatureBtn) {
|
||||
editAddFeatureBtn.addEventListener('click', function() {
|
||||
addFeatureField(editFeaturesContainer);
|
||||
});
|
||||
}
|
||||
|
||||
// Remove feature buttons
|
||||
document.addEventListener('click', function(e) {
|
||||
if (e.target.classList.contains('remove-feature-btn')) {
|
||||
e.target.closest('.input-group').remove();
|
||||
}
|
||||
});
|
||||
|
||||
// Add Pricing Plan Form
|
||||
const addPricingPlanForm = document.getElementById('addPricingPlanForm');
|
||||
if (addPricingPlanForm) {
|
||||
addPricingPlanForm.addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
submitPricingPlanForm(this, 'POST', '/api/admin/pricing-plans');
|
||||
});
|
||||
}
|
||||
|
||||
// Edit Pricing Plan Form
|
||||
const editPricingPlanForm = document.getElementById('editPricingPlanForm');
|
||||
if (editPricingPlanForm) {
|
||||
editPricingPlanForm.addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
const planId = document.getElementById('editPlanId').value;
|
||||
submitPricingPlanForm(this, 'PUT', `/api/admin/pricing-plans/${planId}`);
|
||||
});
|
||||
}
|
||||
|
||||
// Edit Plan Buttons
|
||||
document.addEventListener('click', function(e) {
|
||||
if (e.target.classList.contains('edit-plan-btn')) {
|
||||
const planId = e.target.getAttribute('data-plan-id');
|
||||
loadPlanForEdit(planId);
|
||||
}
|
||||
});
|
||||
|
||||
// Delete Plan Buttons
|
||||
document.addEventListener('click', function(e) {
|
||||
if (e.target.classList.contains('delete-plan-btn')) {
|
||||
const planId = e.target.getAttribute('data-plan-id');
|
||||
const planName = e.target.closest('.card').querySelector('.card-header h5').textContent;
|
||||
showDeleteConfirmation(planId, planName);
|
||||
}
|
||||
});
|
||||
|
||||
// Confirm Delete Button
|
||||
const confirmDeleteBtn = document.getElementById('confirmDeletePlan');
|
||||
if (confirmDeleteBtn) {
|
||||
confirmDeleteBtn.addEventListener('click', function() {
|
||||
const planId = this.getAttribute('data-plan-id');
|
||||
deletePricingPlan(planId);
|
||||
});
|
||||
}
|
||||
|
||||
// Toggle switches
|
||||
document.addEventListener('change', function(e) {
|
||||
if (e.target.classList.contains('plan-status-toggle')) {
|
||||
const planId = e.target.getAttribute('data-plan-id');
|
||||
const isActive = e.target.checked;
|
||||
updatePlanStatus(planId, 'is_active', isActive);
|
||||
}
|
||||
|
||||
if (e.target.classList.contains('plan-popular-toggle')) {
|
||||
const planId = e.target.getAttribute('data-plan-id');
|
||||
const isPopular = e.target.checked;
|
||||
updatePlanStatus(planId, 'is_popular', isPopular);
|
||||
}
|
||||
|
||||
if (e.target.classList.contains('plan-custom-toggle')) {
|
||||
const planId = e.target.getAttribute('data-plan-id');
|
||||
const isCustom = e.target.checked;
|
||||
updatePlanStatus(planId, 'is_custom', isCustom);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function addFeatureField(container) {
|
||||
const featureGroup = document.createElement('div');
|
||||
featureGroup.className = 'input-group mb-2';
|
||||
featureGroup.innerHTML = `
|
||||
<input type="text" class="form-control feature-input" name="features[]" required>
|
||||
<button type="button" class="btn btn-outline-danger remove-feature-btn">
|
||||
<i class="fas fa-times"></i>
|
||||
</button>
|
||||
`;
|
||||
container.appendChild(featureGroup);
|
||||
}
|
||||
|
||||
function submitPricingPlanForm(form, method, url) {
|
||||
const formData = new FormData(form);
|
||||
|
||||
// Convert features array
|
||||
const features = [];
|
||||
form.querySelectorAll('input[name="features[]"]').forEach(input => {
|
||||
if (input.value.trim()) {
|
||||
features.push(input.value.trim());
|
||||
}
|
||||
});
|
||||
|
||||
// Remove features from formData and add as JSON
|
||||
formData.delete('features[]');
|
||||
formData.append('features', JSON.stringify(features));
|
||||
|
||||
// Convert checkboxes to boolean values
|
||||
const checkboxes = ['is_popular', 'is_custom', 'is_active'];
|
||||
checkboxes.forEach(field => {
|
||||
formData.set(field, formData.get(field) === 'on');
|
||||
});
|
||||
|
||||
fetch(url, {
|
||||
method: method,
|
||||
body: formData,
|
||||
headers: {
|
||||
'X-Requested-With': 'XMLHttpRequest'
|
||||
}
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
showNotification('Pricing plan saved successfully!', 'success');
|
||||
setTimeout(() => {
|
||||
window.location.reload();
|
||||
}, 1000);
|
||||
} else {
|
||||
showNotification(data.error || 'Error saving pricing plan', 'error');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
showNotification('Error saving pricing plan', 'error');
|
||||
});
|
||||
}
|
||||
|
||||
function loadPlanForEdit(planId) {
|
||||
fetch(`/api/admin/pricing-plans/${planId}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
const plan = data.plan;
|
||||
|
||||
// Populate form fields
|
||||
document.getElementById('editPlanId').value = plan.id;
|
||||
document.getElementById('editPlanName').value = plan.name;
|
||||
document.getElementById('editPlanDescription').value = plan.description || '';
|
||||
document.getElementById('editMonthlyPrice').value = plan.monthly_price;
|
||||
document.getElementById('editAnnualPrice').value = plan.annual_price;
|
||||
document.getElementById('editButtonText').value = plan.button_text;
|
||||
document.getElementById('editButtonUrl').value = plan.button_url;
|
||||
document.getElementById('editIsPopular').checked = plan.is_popular;
|
||||
document.getElementById('editIsCustom').checked = plan.is_custom;
|
||||
document.getElementById('editIsActive').checked = plan.is_active;
|
||||
|
||||
// Populate quota fields
|
||||
document.getElementById('editRoomQuota').value = plan.room_quota || 0;
|
||||
document.getElementById('editConversationQuota').value = plan.conversation_quota || 0;
|
||||
document.getElementById('editStorageQuota').value = plan.storage_quota_gb || 0;
|
||||
document.getElementById('editManagerQuota').value = plan.manager_quota || 0;
|
||||
document.getElementById('editAdminQuota').value = plan.admin_quota || 0;
|
||||
|
||||
// Populate features
|
||||
const editFeaturesContainer = document.getElementById('editFeaturesContainer');
|
||||
editFeaturesContainer.innerHTML = '';
|
||||
|
||||
plan.features.forEach(feature => {
|
||||
const featureGroup = document.createElement('div');
|
||||
featureGroup.className = 'input-group mb-2';
|
||||
featureGroup.innerHTML = `
|
||||
<input type="text" class="form-control feature-input" name="features[]" value="${feature}" required>
|
||||
<button type="button" class="btn btn-outline-danger remove-feature-btn">
|
||||
<i class="fas fa-times"></i>
|
||||
</button>
|
||||
`;
|
||||
editFeaturesContainer.appendChild(featureGroup);
|
||||
});
|
||||
|
||||
// Add one empty feature field if no features
|
||||
if (plan.features.length === 0) {
|
||||
addFeatureField(editFeaturesContainer);
|
||||
}
|
||||
} else {
|
||||
showNotification(data.error || 'Error loading plan', 'error');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
showNotification('Error loading plan', 'error');
|
||||
});
|
||||
}
|
||||
|
||||
function showDeleteConfirmation(planId, planName) {
|
||||
document.getElementById('deletePlanName').textContent = planName;
|
||||
document.getElementById('confirmDeletePlan').setAttribute('data-plan-id', planId);
|
||||
|
||||
const deleteModal = new bootstrap.Modal(document.getElementById('deletePricingPlanModal'));
|
||||
deleteModal.show();
|
||||
}
|
||||
|
||||
function deletePricingPlan(planId) {
|
||||
fetch(`/api/admin/pricing-plans/${planId}`, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'X-Requested-With': 'XMLHttpRequest',
|
||||
'X-CSRFToken': document.querySelector('input[name="csrf_token"]').value
|
||||
}
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
showNotification('Pricing plan deleted successfully!', 'success');
|
||||
|
||||
// Close modal
|
||||
const deleteModal = bootstrap.Modal.getInstance(document.getElementById('deletePricingPlanModal'));
|
||||
deleteModal.hide();
|
||||
|
||||
// Remove from DOM
|
||||
const planElement = document.querySelector(`[data-plan-id="${planId}"]`);
|
||||
if (planElement) {
|
||||
planElement.remove();
|
||||
}
|
||||
|
||||
// Check if no plans left
|
||||
const remainingPlans = document.querySelectorAll('[data-plan-id]');
|
||||
if (remainingPlans.length === 0) {
|
||||
window.location.reload();
|
||||
}
|
||||
} else {
|
||||
showNotification(data.error || 'Error deleting plan', 'error');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
showNotification('Error deleting plan', 'error');
|
||||
});
|
||||
}
|
||||
|
||||
function updatePlanStatus(planId, field, value) {
|
||||
fetch(`/api/admin/pricing-plans/${planId}/status`, {
|
||||
method: 'PATCH',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Requested-With': 'XMLHttpRequest',
|
||||
'X-CSRFToken': document.querySelector('input[name="csrf_token"]').value
|
||||
},
|
||||
body: JSON.stringify({
|
||||
field: field,
|
||||
value: value
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
showNotification('Plan status updated successfully!', 'success');
|
||||
} else {
|
||||
showNotification(data.error || 'Error updating plan status', 'error');
|
||||
// Revert the toggle
|
||||
const toggle = document.querySelector(`[data-plan-id="${planId}"].${field.replace('is_', 'plan-')}-toggle`);
|
||||
if (toggle) {
|
||||
toggle.checked = !value;
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
showNotification('Error updating plan status', 'error');
|
||||
// Revert the toggle
|
||||
const toggle = document.querySelector(`[data-plan-id="${planId}"].${field.replace('is_', 'plan-')}-toggle`);
|
||||
if (toggle) {
|
||||
toggle.checked = !value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function showNotification(message, type) {
|
||||
// Create notification element
|
||||
const notification = document.createElement('div');
|
||||
notification.className = `alert alert-${type === 'success' ? 'success' : 'danger'} alert-dismissible fade show position-fixed`;
|
||||
notification.style.cssText = 'top: 20px; right: 20px; z-index: 9999; min-width: 300px;';
|
||||
notification.innerHTML = `
|
||||
${message}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
`;
|
||||
|
||||
document.body.appendChild(notification);
|
||||
|
||||
// Auto-remove after 5 seconds
|
||||
setTimeout(() => {
|
||||
if (notification.parentNode) {
|
||||
notification.remove();
|
||||
}
|
||||
}, 5000);
|
||||
}
|
||||
Reference in New Issue
Block a user