email working - remove clients - preview polish
This commit is contained in:
1 parent
2b1424d127
commit
da83beaec3
19 files changed
+1342
-1060
No files matched your search
+174
-117
@@ -23,20 +23,24 @@
|
||||
hasMore: false,
|
||||
filters: {
|
||||
status: '',
|
||||
site: '',
|
||||
client: ''
|
||||
site: ''
|
||||
},
|
||||
|
||||
// Edit mode state
|
||||
isEditMode: false,
|
||||
editingSlideId: null,
|
||||
currentSlides: null,
|
||||
focusSlideId: null,
|
||||
|
||||
// Initialize the dashboard
|
||||
init: function() {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
this.focusSlideId = params.get('hssm_focus') || null;
|
||||
|
||||
this.bindEvents();
|
||||
this.initializeTabs();
|
||||
this.addInitialSlideForm();
|
||||
this.populateFilterDropdowns();
|
||||
this.loadExistingSlides();
|
||||
// Initialize site data
|
||||
window.hssmSites = window.hssmSites || [];
|
||||
@@ -64,8 +68,6 @@
|
||||
$(document).on('click', '.hssm-remove-button', this.removeButtonRow.bind(this));
|
||||
|
||||
// Slide actions
|
||||
$(document).on('click', '.hssm-save-slide', this.saveSlide.bind(this));
|
||||
$(document).on('click', '#save-all-slides', this.saveAllSlides.bind(this));
|
||||
$(document).on('click', '.hssm-preview-slide', this.previewSlide.bind(this));
|
||||
$(document).on('click', '.hssm-schedule-slide', this.scheduleSlide.bind(this));
|
||||
$(document).on('click', '.hssm-publish-slide', this.publishSlide.bind(this));
|
||||
@@ -89,6 +91,8 @@
|
||||
|
||||
// Filtering and management (slide row edit/delete bound in bindSlideActions after list load)
|
||||
$(document).on('click', '#apply-filters', this.applyFilters.bind(this));
|
||||
$(document).on('click', '#clear-filters', this.clearFilters.bind(this));
|
||||
$(document).on('change', '#filter-site, #filter-status', this.applyFilters.bind(this));
|
||||
|
||||
// Edit form actions — register once; do not re-bind in populateEditForm (prevents duplicate toasts)
|
||||
$(document).on('click.hssmDashboard', '.hssm-cancel-edit, .hssm-cancel-edit-btn', (e) => {
|
||||
@@ -104,14 +108,18 @@
|
||||
// Additional functionality
|
||||
$(document).on('click', '#import-slides', this.importSlides.bind(this));
|
||||
$(document).on('click', '#export-slides', this.exportSlides.bind(this));
|
||||
$(document).on('click', '#save-draft-all', this.saveAllAsDrafts.bind(this));
|
||||
|
||||
|
||||
// Notification Settings
|
||||
$(document).on('submit', '#notification-settings-form', this.saveNotificationSettings.bind(this));
|
||||
},
|
||||
|
||||
// Initialize tab functionality
|
||||
initializeTabs: function() {
|
||||
// Confirmation / email links should land on the manage list.
|
||||
if (this.focusSlideId) {
|
||||
sessionStorage.setItem('hssm_active_tab', 'manage-slides');
|
||||
}
|
||||
|
||||
// Check for saved tab in sessionStorage
|
||||
const savedTab = sessionStorage.getItem('hssm_active_tab');
|
||||
|
||||
@@ -425,84 +433,6 @@
|
||||
});
|
||||
},
|
||||
|
||||
// Save individual slide
|
||||
saveSlide: function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const formId = $(e.currentTarget).data('form');
|
||||
const $form = $(`.hssm-slide-form[data-form-id="${formId}"]`);
|
||||
|
||||
this.submitSlideForm($form);
|
||||
},
|
||||
|
||||
// Save all slides
|
||||
saveAllSlides: function(e) {
|
||||
if (e) e.preventDefault();
|
||||
|
||||
const $forms = $('.hssm-slide-form');
|
||||
let savedCount = 0;
|
||||
let errorCount = 0;
|
||||
|
||||
$forms.each((index, form) => {
|
||||
this.submitSlideForm($(form), () => {
|
||||
savedCount++;
|
||||
this.checkAllSaved(savedCount, errorCount, $forms.length);
|
||||
}, () => {
|
||||
errorCount++;
|
||||
this.checkAllSaved(savedCount, errorCount, $forms.length);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
// Check if all forms have been processed
|
||||
checkAllSaved: function(savedCount, errorCount, totalCount) {
|
||||
if (savedCount + errorCount === totalCount) {
|
||||
if (errorCount === 0) {
|
||||
this.showMessage(`All ${savedCount} slides saved successfully!`, 'success');
|
||||
} else {
|
||||
this.showMessage(`${savedCount} slides saved, ${errorCount} failed.`, 'warning');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Submit individual slide form
|
||||
submitSlideForm: function($form, successCallback, errorCallback) {
|
||||
if (!this.validateForm($form)) {
|
||||
if (errorCallback) errorCallback();
|
||||
return;
|
||||
}
|
||||
|
||||
const formData = this.collectFormData($form);
|
||||
|
||||
$form.addClass('hssm-loading');
|
||||
|
||||
formData.append('nonce', hssmDashboard.nonce);
|
||||
$.ajax({
|
||||
url: hssmDashboard.ajaxurl,
|
||||
type: 'POST',
|
||||
data: formData,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
success: (response) => {
|
||||
$form.removeClass('hssm-loading');
|
||||
|
||||
if (response.success) {
|
||||
this.showMessage(response.data.message, 'success');
|
||||
this.clearForm($form);
|
||||
if (successCallback) successCallback();
|
||||
} else {
|
||||
this.showMessage(response.data.message || 'Save failed', 'error');
|
||||
if (errorCallback) errorCallback();
|
||||
}
|
||||
},
|
||||
error: () => {
|
||||
$form.removeClass('hssm-loading');
|
||||
this.showMessage('Save failed. Please try again.', 'error');
|
||||
if (errorCallback) errorCallback();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Clear all field errors in a form
|
||||
clearFieldErrors: function($form) {
|
||||
$form.find('.hssm-field-error').remove();
|
||||
@@ -771,7 +701,11 @@
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'hssm_get_slides',
|
||||
nonce: hssmDashboard.nonce
|
||||
nonce: hssmDashboard.nonce,
|
||||
page: this.currentPage,
|
||||
per_page: this.perPage,
|
||||
status_filter: this.filters.status || '',
|
||||
site_filter: this.filters.site || ''
|
||||
},
|
||||
beforeSend: function(xhr, settings) {
|
||||
// Optional: Add loading indicators
|
||||
@@ -779,6 +713,7 @@
|
||||
success: (response) => {
|
||||
if (response.success && response.data && response.data.slides) {
|
||||
this.renderSlidesList(response.data.slides);
|
||||
this.highlightFocusedSlide();
|
||||
} else {
|
||||
console.error('Failed to get slides:', response);
|
||||
$slidesList.html('<p>Failed to load slides. Response format unexpected.</p>');
|
||||
@@ -807,7 +742,7 @@
|
||||
<span class="dashicons dashicons-slides"></span>
|
||||
</div>
|
||||
<h3>No slides found</h3>
|
||||
<p>Create your first slide to get started!</p>
|
||||
<p>${this.hasActiveFilters() ? 'No slides match the current filters.' : 'Create your first slide to get started!'}</p>
|
||||
<button class="hssm-btn hssm-btn-primary" onclick="$('.hssm-nav-tabs a[data-tab=create-slides]').click()">
|
||||
<span class="dashicons dashicons-plus-alt"></span> Create First Slide
|
||||
</button>
|
||||
@@ -833,8 +768,11 @@
|
||||
slides.forEach(slide => {
|
||||
const imageUrl = slide.featured_image_url || '';
|
||||
const statusClass = this.getStatusClass(slide.status);
|
||||
const statusLabel = this.getStatusLabel(slide);
|
||||
const sitesText = this.formatSitesList(slide.sites || slide.target_sites);
|
||||
const scheduleText = this.formatScheduleText(slide);
|
||||
const isPending = slide.status === 'pending';
|
||||
const isApproved = slide.status === 'publish' || slide.status === 'future';
|
||||
|
||||
html += `
|
||||
<div class="hssm-slide-row" data-slide-id="${slide.id}">
|
||||
@@ -848,7 +786,7 @@
|
||||
<div class="hssm-slide-subtitle">${slide.subtitle || ''}</div>
|
||||
</div>
|
||||
<div class="hssm-col-status">
|
||||
<span class="hssm-status-badge hssm-status-${statusClass}">${slide.status}</span>
|
||||
<span class="hssm-status-badge hssm-status-${statusClass}">${statusLabel}</span>
|
||||
</div>
|
||||
<div class="hssm-col-dates">
|
||||
<div class="hssm-schedule-info">${scheduleText}</div>
|
||||
@@ -858,15 +796,28 @@
|
||||
</div>
|
||||
<div class="hssm-col-actions">
|
||||
<div class="hssm-slide-actions">
|
||||
<button class="hssm-btn hssm-btn-sm hssm-btn-secondary hssm-preview-slide" data-slide-id="${slide.id}" title="Preview banner">
|
||||
<span class="dashicons dashicons-visibility"></span>
|
||||
</button>
|
||||
<button class="hssm-btn hssm-btn-sm hssm-btn-secondary hssm-edit-slide" data-slide-id="${slide.id}" title="Edit">
|
||||
<span class="dashicons dashicons-edit"></span>
|
||||
</button>
|
||||
<button class="hssm-btn hssm-btn-sm hssm-btn-secondary hssm-duplicate-slide" data-slide-id="${slide.id}" title="Duplicate">
|
||||
<span class="dashicons dashicons-admin-page"></span>
|
||||
</button>
|
||||
${isPending ? `
|
||||
<button class="hssm-btn hssm-btn-sm hssm-btn-success hssm-approve-slide" data-slide-id="${slide.id}" data-approve-action="schedule" title="Approve">
|
||||
<span class="dashicons dashicons-yes"></span>
|
||||
</button>
|
||||
` : isApproved ? `
|
||||
<button type="button" class="hssm-btn hssm-btn-sm hssm-btn-primary hssm-approved-slide" title="Approved" disabled>
|
||||
<span class="dashicons dashicons-yes"></span>
|
||||
</button>
|
||||
` : `
|
||||
<button class="hssm-btn hssm-btn-sm hssm-btn-success hssm-toggle-status" data-slide-id="${slide.id}" title="Toggle Status">
|
||||
<span class="dashicons dashicons-${slide.status === 'publish' ? 'pause' : 'controls-play'}"></span>
|
||||
</button>
|
||||
`}
|
||||
<button class="hssm-btn hssm-btn-sm hssm-btn-danger hssm-delete-slide" data-slide-id="${slide.id}" title="Delete">
|
||||
<span class="dashicons dashicons-trash"></span>
|
||||
</button>
|
||||
@@ -885,17 +836,49 @@
|
||||
this.bindSlideActions();
|
||||
},
|
||||
|
||||
highlightFocusedSlide: function() {
|
||||
if (!this.focusSlideId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const $row = $('.hssm-slide-row[data-slide-id="' + this.focusSlideId + '"]');
|
||||
if (!$row.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
$row.addClass('hssm-slide-row-focus');
|
||||
if ($row[0] && $row[0].scrollIntoView) {
|
||||
$row[0].scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
}
|
||||
},
|
||||
|
||||
// Helper function to get status CSS class
|
||||
getStatusClass: function(status) {
|
||||
const statusMap = {
|
||||
'publish': 'published',
|
||||
'draft': 'draft',
|
||||
'future': 'scheduled',
|
||||
'pending': 'pending',
|
||||
'private': 'private'
|
||||
};
|
||||
return statusMap[status] || 'unknown';
|
||||
},
|
||||
|
||||
getStatusLabel: function(slide) {
|
||||
if (slide.status_display) {
|
||||
return slide.status_display;
|
||||
}
|
||||
|
||||
const labels = {
|
||||
publish: 'Published',
|
||||
draft: 'Draft',
|
||||
future: 'Scheduled',
|
||||
pending: 'Pending Approval',
|
||||
private: 'Private'
|
||||
};
|
||||
return labels[slide.status] || slide.status;
|
||||
},
|
||||
|
||||
// Helper function to format sites list
|
||||
formatSitesList: function(sites) {
|
||||
if (!sites || sites.length === 0) return 'No sites';
|
||||
@@ -943,6 +926,12 @@
|
||||
const slideId = $(e.currentTarget).data('slide-id');
|
||||
this.toggleSlideStatus(slideId);
|
||||
});
|
||||
|
||||
$(document).off('click.hssmSlideActions', '.hssm-approve-slide').on('click.hssmSlideActions', '.hssm-approve-slide', (e) => {
|
||||
e.preventDefault();
|
||||
const $btn = $(e.currentTarget);
|
||||
this.approveSlide($btn.data('slide-id'), $btn.data('approve-action') || 'schedule');
|
||||
});
|
||||
},
|
||||
|
||||
// Edit slide function
|
||||
@@ -1097,6 +1086,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="hssm-form-actions">
|
||||
<button type="button" class="hssm-btn hssm-btn-outline hssm-preview-slide" data-form="${this.formCounter}" data-slide-id="${slideData.id}">
|
||||
<span class="dashicons dashicons-visibility"></span> Preview Banner
|
||||
</button>
|
||||
<button type="button" class="hssm-btn hssm-btn-secondary hssm-schedule-updated-slide" data-form="${this.formCounter}" data-slide-id="${slideData.id}">
|
||||
<span class="dashicons dashicons-calendar-alt"></span> Schedule for Approval
|
||||
</button>
|
||||
@@ -1302,6 +1294,38 @@
|
||||
});
|
||||
},
|
||||
|
||||
approveSlide: function(slideId, approveAction) {
|
||||
const confirmText = (hssmDashboard.strings && hssmDashboard.strings.approve_confirm)
|
||||
? hssmDashboard.strings.approve_confirm
|
||||
: 'Approve this slide?';
|
||||
|
||||
if (!confirm(confirmText)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: hssmDashboard.ajaxurl,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'hssm_approve_slide',
|
||||
nonce: hssmDashboard.nonce,
|
||||
slide_id: slideId,
|
||||
approve_action: approveAction || 'schedule'
|
||||
},
|
||||
success: (response) => {
|
||||
if (response.success) {
|
||||
this.showMessage((hssmDashboard.strings && hssmDashboard.strings.approve_success) || 'Slide approved.', 'success');
|
||||
this.loadExistingSlides();
|
||||
} else {
|
||||
this.showMessage(response.data?.message || 'Failed to approve slide', 'error');
|
||||
}
|
||||
},
|
||||
error: () => {
|
||||
this.showMessage('Failed to approve slide. Please try again.', 'error');
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// Toggle slide status
|
||||
toggleSlideStatus: function(slideId) {
|
||||
$.ajax({
|
||||
@@ -1344,15 +1368,73 @@
|
||||
}, dismissMs);
|
||||
},
|
||||
|
||||
// Placeholder methods for future implementation
|
||||
previewSlide: function(e) {
|
||||
e.preventDefault();
|
||||
this.showMessage('Preview functionality coming soon!', 'info');
|
||||
populateFilterDropdowns: function() {
|
||||
const $site = $('#filter-site');
|
||||
|
||||
if ($site.length && window.hssmSites && $site.children().length <= 1) {
|
||||
window.hssmSites.forEach((site) => {
|
||||
$site.append(`<option value="${site.id}">${site.name}</option>`);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
hasActiveFilters: function() {
|
||||
return !!(this.filters.status || this.filters.site);
|
||||
},
|
||||
|
||||
readFiltersFromForm: function() {
|
||||
this.filters.status = $('#filter-status').val() || '';
|
||||
this.filters.site = $('#filter-site').val() || '';
|
||||
},
|
||||
|
||||
applyFilters: function(e) {
|
||||
if (e && e.preventDefault) {
|
||||
e.preventDefault();
|
||||
}
|
||||
this.readFiltersFromForm();
|
||||
this.currentPage = 1;
|
||||
this.loadExistingSlides();
|
||||
},
|
||||
|
||||
clearFilters: function(e) {
|
||||
if (e && e.preventDefault) {
|
||||
e.preventDefault();
|
||||
}
|
||||
this.filters = { status: '', site: '' };
|
||||
$('#filter-status, #filter-site').val('');
|
||||
this.currentPage = 1;
|
||||
this.loadExistingSlides();
|
||||
},
|
||||
|
||||
buildPreviewUrl: function(slide) {
|
||||
const base = (hssmDashboard.previewUrl || '/slide-preview/').replace(/\/?$/, '/');
|
||||
const params = new URLSearchParams();
|
||||
|
||||
if (slide && slide.id) {
|
||||
params.set('hssm_preview', slide.id);
|
||||
}
|
||||
if (slide && slide.start_date) {
|
||||
params.set('hssm_date', slide.start_date);
|
||||
}
|
||||
if (slide && slide.site_slugs && slide.site_slugs.length) {
|
||||
params.set('hssm_site', slide.site_slugs[0]);
|
||||
}
|
||||
|
||||
const query = params.toString();
|
||||
return query ? `${base}?${query}` : base;
|
||||
},
|
||||
|
||||
previewSlide: function(e) {
|
||||
e.preventDefault();
|
||||
this.showMessage('Filter functionality coming soon!', 'info');
|
||||
const slideId = $(e.currentTarget).data('slide-id') || this.editingSlideId;
|
||||
|
||||
if (!slideId) {
|
||||
this.showMessage((hssmDashboard.strings && hssmDashboard.strings.preview_save_first) || 'Save the slide first, then preview it as a banner.', 'info');
|
||||
return;
|
||||
}
|
||||
|
||||
const slide = this.findSlideById(slideId) || { id: slideId };
|
||||
window.open(this.buildPreviewUrl(slide), '_blank', 'noopener');
|
||||
},
|
||||
|
||||
// Load analytics data
|
||||
@@ -1386,31 +1468,6 @@
|
||||
this.showMessage('Slide export functionality coming soon!', 'info');
|
||||
},
|
||||
|
||||
// Save all slides as drafts
|
||||
saveAllAsDrafts: function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const $forms = $('.hssm-slide-form');
|
||||
let savedCount = 0;
|
||||
let errorCount = 0;
|
||||
|
||||
$forms.each((index, form) => {
|
||||
const $form = $(form);
|
||||
|
||||
// Override status to draft
|
||||
const formData = this.collectFormData($form);
|
||||
formData.append('post_status', 'draft');
|
||||
|
||||
this.submitSlideForm($form, () => {
|
||||
savedCount++;
|
||||
this.checkAllSaved(savedCount, errorCount, $forms.length);
|
||||
}, () => {
|
||||
errorCount++;
|
||||
this.checkAllSaved(savedCount, errorCount, $forms.length);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
// Load notification settings
|
||||
loadNotificationSettings: function() {
|
||||
$.ajax({
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
/**
|
||||
* Hi-School Slide Manager - Frontend JavaScript
|
||||
*/
|
||||
|
||||
jQuery(document).ready(function($) {
|
||||
'use strict';
|
||||
|
||||
// Initialize slide functionality
|
||||
initializeSlides();
|
||||
|
||||
/**
|
||||
* Initialize slide functionality
|
||||
*/
|
||||
function initializeSlides() {
|
||||
$('.hssm-slides-container').each(function() {
|
||||
var $container = $(this);
|
||||
var $slides = $container.find('.hssm-slide');
|
||||
|
||||
// Add fade-in animation
|
||||
$slides.each(function(index) {
|
||||
var $slide = $(this);
|
||||
setTimeout(function() {
|
||||
$slide.addClass('hssm-fade-in');
|
||||
}, index * 100);
|
||||
});
|
||||
|
||||
// Add click handlers for interactive slides
|
||||
$slides.on('click', function() {
|
||||
var $slide = $(this);
|
||||
$slide.toggleClass('hssm-slide-expanded');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle slide interactions
|
||||
*/
|
||||
$(document).on('click', '.hssm-slide-toggle', function(e) {
|
||||
e.preventDefault();
|
||||
var $button = $(this);
|
||||
var $slide = $button.closest('.hssm-slide');
|
||||
var $content = $slide.find('.hssm-slide-content');
|
||||
|
||||
$content.slideToggle(300);
|
||||
$button.text($content.is(':visible') ? 'Hide' : 'Show');
|
||||
});
|
||||
|
||||
/**
|
||||
* Handle keyboard navigation
|
||||
*/
|
||||
$(document).on('keydown', '.hssm-slide', function(e) {
|
||||
if (e.which === 13 || e.which === 32) { // Enter or Space
|
||||
e.preventDefault();
|
||||
$(this).click();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Add CSS classes via JavaScript for animations
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var style = document.createElement('style');
|
||||
style.textContent = `
|
||||
.hssm-slide {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
transition: opacity 0.5s ease, transform 0.5s ease;
|
||||
}
|
||||
|
||||
.hssm-slide.hssm-fade-in {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.hssm-slide.hssm-slide-expanded {
|
||||
transform: scale(1.02);
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
});
|
||||
@@ -110,7 +110,7 @@
|
||||
action: 'hssm_approve_slide',
|
||||
nonce: hssmPreview.nonce,
|
||||
slide_id: slideId,
|
||||
approve_action: 'schedule' // Smart approve: schedules if future date exists, otherwise publishes
|
||||
approve_action: $btn.data('approve-action') || 'schedule'
|
||||
},
|
||||
success: (response) => {
|
||||
if (response.success) {
|
||||
|
||||
Reference in new issue
Block a user