561 lines
19 KiB
JavaScript
561 lines
19 KiB
JavaScript
(function( $ ) {
|
|
'use strict';
|
|
|
|
/**
|
|
* Validate all required fields in a form.
|
|
*/
|
|
function validateRequiredFields( $form ) {
|
|
let isValid = true;
|
|
|
|
$form.find( '[required]' ).each(function() {
|
|
if ( ! validateRequiredField( $( this ) ) ) {
|
|
isValid = false;
|
|
}
|
|
});
|
|
|
|
return isValid;
|
|
}
|
|
|
|
/**
|
|
* Validate single required field in a form.
|
|
*/
|
|
function validateRequiredField( $el ) {
|
|
let isValid = true;
|
|
|
|
const $field = $el.closest( '.aiovg-form-control' );
|
|
const value = $el.val().trim();
|
|
|
|
if ( value === '' ) {
|
|
$field.addClass( 'aiovg-form-invalid' );
|
|
isValid = false;
|
|
} else {
|
|
$field.removeClass( 'aiovg-form-invalid' );
|
|
}
|
|
|
|
return isValid;
|
|
}
|
|
|
|
/**
|
|
* Validate CSV columns.
|
|
*/
|
|
function validateCSVColumns() {
|
|
let isValid = true;
|
|
let selected = [];
|
|
|
|
// Collect all selected values
|
|
$( '#aiovg-field-csv_columns select' ).each(function() {
|
|
const value = $( this ).val().trim();
|
|
|
|
if ( value ) {
|
|
selected.push( value );
|
|
}
|
|
});
|
|
|
|
// Validation: Check if both required fields are selected
|
|
const hasTitle = selected.indexOf( 'post_title' ) !== -1;
|
|
const hasVideo = selected.indexOf( 'video' ) !== -1;
|
|
|
|
if ( ! hasTitle || ! hasVideo ) {
|
|
$( '#aiovg-field-csv_columns' ).addClass( 'aiovg-form-invalid' );
|
|
isValid = false;
|
|
} else {
|
|
$( '#aiovg-field-csv_columns' ).removeClass( 'aiovg-form-invalid' );
|
|
}
|
|
|
|
return isValid;
|
|
}
|
|
|
|
/**
|
|
* Removes a dot (.) at the end of a string.
|
|
*/
|
|
function removeEndingDot( str ) {
|
|
return str.charAt( str.length - 1 ) === '.' ? str.slice( 0, -1 ) : str;
|
|
}
|
|
|
|
/**
|
|
* Called when the page has loaded.
|
|
*/
|
|
$(function() {
|
|
|
|
// Initialize date pickers
|
|
$( '.aiovg-date-picker' ).each(function() {
|
|
if ( typeof flatpickr === 'undefined' ) {
|
|
return;
|
|
}
|
|
|
|
const config = {
|
|
dateFormat: 'Y-m-d',
|
|
allowInput: true,
|
|
disableMobile: true
|
|
};
|
|
|
|
flatpickr( this, config );
|
|
} );
|
|
|
|
// Validate required fields
|
|
$( '#aiovg-import-export' ).find( '[required]' ).each(function() {
|
|
$( this ).on( 'blur keyup', function() {
|
|
validateRequiredField( $( this ) );
|
|
});
|
|
});
|
|
|
|
// Validate CSV Columns
|
|
$( '#aiovg-field-csv_columns' ).on( 'change', 'select', function() {
|
|
let selected = [];
|
|
|
|
// Collect all selected values
|
|
$( '#aiovg-field-csv_columns select' ).each(function() {
|
|
const value = $( this ).val().trim();
|
|
|
|
if ( value ) {
|
|
selected.push( value );
|
|
}
|
|
});
|
|
|
|
if ( selected.length === 0 ) {
|
|
$( '#aiovg-field-csv_columns' ).addClass( 'aiovg-form-invalid' );
|
|
} else {
|
|
$( '#aiovg-field-csv_columns' ).removeClass( 'aiovg-form-invalid' );
|
|
}
|
|
});
|
|
|
|
// Fetch and render column mapping fields via AJAX
|
|
$( '#aiovg-csv_file' ).on( 'change file.uploaded', function() {
|
|
const $container = $( '#aiovg-field-csv_columns' );
|
|
const $button = $( '#aiovg-button-import-csv' );
|
|
const $status = $( '#aiovg-import-csv-status' );
|
|
|
|
$container.find( '.aiovg-form-grid' ).html( '' );
|
|
$container.hide();
|
|
|
|
const csvFile = $( '#aiovg-csv_file' ).val().trim();
|
|
if ( ! csvFile ) return;
|
|
|
|
$button.prop( 'disabled', true );
|
|
$status.html( '<span class="spinner"></span> <span class="aiovg-text-success">' + removeEndingDot( aiovg_import_export.i18n.fetching_csv_columns ) + '</span><span class="aiovg-animate-dots"></span>' );
|
|
|
|
const formData = {
|
|
action: 'aiovg_get_csv_columns',
|
|
security: aiovg_admin.ajax_nonce,
|
|
csv_file: csvFile,
|
|
columns_separator: $( '#aiovg-columns_separator' ).val()
|
|
};
|
|
|
|
$.post( ajaxurl, formData, function( response ) {
|
|
if ( ! response.success ) {
|
|
$status.html( '<span class="aiovg-text-error"><span class="dashicons dashicons-dismiss"></span> ' + response.data.error + '</span>' );
|
|
$button.prop( 'disabled', false );
|
|
return;
|
|
}
|
|
|
|
$status.html( '<span class="dashicons dashicons-info-outline"></span> <span>' + aiovg_import_export.i18n.csv_columns_loaded + '</span>' );
|
|
$button.prop( 'disabled', false );
|
|
|
|
$container.find( '.aiovg-form-grid' ).html( response.data.html );
|
|
$container.fadeIn( 200 );
|
|
}, 'json' );
|
|
});
|
|
|
|
// Import from Folder
|
|
$( '#aiovg-form-import-folder' ).on( 'submit', function( event ) {
|
|
event.preventDefault();
|
|
|
|
const $form = $( this );
|
|
const $button = $form.find( 'button[type="submit"]' );
|
|
const $status = $form.find( '.aiovg-form-status' );
|
|
|
|
if ( ! validateRequiredFields( $form ) ) {
|
|
$status.html( '<span class="aiovg-text-error"><span class="dashicons dashicons-dismiss"></span> ' + aiovg_import_export.i18n.fields_required + '</span>' );
|
|
|
|
$( 'html, body' ).animate({
|
|
scrollTop: $form.find( '.aiovg-form-invalid' ).first().offset().top - 75
|
|
}, 300 );
|
|
|
|
return;
|
|
}
|
|
|
|
$button.prop( 'disabled', true );
|
|
$status.html( '<span class="spinner"></span> <span class="aiovg-text-success">' + removeEndingDot( aiovg_import_export.i18n.preparing_import ) + '</span><span class="aiovg-animate-dots"></span>' );
|
|
|
|
// Local variables to track progress
|
|
const limit = 20;
|
|
|
|
let offset = 0;
|
|
let imported = [];
|
|
let skipped = [];
|
|
let failed = [];
|
|
|
|
// Prepare serialized array
|
|
let formArray = $form.serializeArray();
|
|
|
|
// Add static fields
|
|
formArray.push({ name: 'action', value: 'aiovg_import_folder' });
|
|
formArray.push({ name: 'security', value: aiovg_admin.ajax_nonce });
|
|
formArray.push({ name: 'limit', value: limit });
|
|
formArray.push({ name: 'offset', value: offset });
|
|
|
|
// Recursive import function
|
|
const importBatch = function() {
|
|
// Update offset in formArray
|
|
formArray = formArray.map(( field ) => {
|
|
return ( field.name === 'offset' ) ? { name: 'offset', value: offset } : field;
|
|
});
|
|
|
|
$.ajax({
|
|
url: ajaxurl,
|
|
type: 'POST',
|
|
data: formArray,
|
|
dataType: 'json',
|
|
timeout: 60000,
|
|
success: function( response ) {
|
|
if ( ! response.success ) {
|
|
$status.html( '<span class="aiovg-text-error"><span class="dashicons dashicons-dismiss"></span> ' + response.data.error + '</span>' );
|
|
$button.prop( 'disabled', false );
|
|
return;
|
|
}
|
|
|
|
offset = parseInt( response.data.offset );
|
|
imported = imported.concat( response.data.imported );
|
|
skipped = skipped.concat( response.data.skipped );
|
|
failed = failed.concat( response.data.failed );
|
|
|
|
let message = response.data.message;
|
|
message = message.replace( '%%imported%%', imported.length );
|
|
message = message.replace( '%%skipped%%', skipped.length );
|
|
message = message.replace( '%%failed%%', failed.length );
|
|
|
|
if ( response.data.step === 'process' ) {
|
|
$status.html( '<span class="spinner"></span> <span class="aiovg-text-success">' + removeEndingDot( message ) + '</span><span class="aiovg-animate-dots"></span>' );
|
|
setTimeout( importBatch, 100 ); // Import next batch
|
|
} else if ( response.data.step === 'done' ) {
|
|
let html = '<span class="aiovg-text-success"><span class="dashicons dashicons-yes-alt"></span> ' + message + '</span>';
|
|
|
|
if ( failed.length > 0 ) {
|
|
html += '<div class="aiovg-form-fieldset">';
|
|
html += '<h3 class="aiovg-text-error">' + aiovg_import_export.i18n.import_folder_failed_status_heading + '</h3>';
|
|
|
|
failed.forEach(( item ) => {
|
|
const fileName = $( '<span>' ).text( item.split( '/' ).pop() ).html();
|
|
html += '<a class="aiovg-status-item" href="' + encodeURI( item ) + '" target="_blank">' + fileName + '</a>';
|
|
});
|
|
|
|
html += '</div>';
|
|
}
|
|
|
|
$status.html( html );
|
|
$button.prop( 'disabled', false );
|
|
}
|
|
},
|
|
error: function() {
|
|
$status.html( '<span class="aiovg-text-error"><span class="dashicons dashicons-dismiss"></span> ' + aiovg_import_export.i18n.request_failed + '</span>' );
|
|
$button.prop( 'disabled', false );
|
|
}
|
|
});
|
|
};
|
|
|
|
// Start first batch
|
|
importBatch();
|
|
});
|
|
|
|
// Import from CSV file
|
|
$( '#aiovg-form-import-csv' ).on( 'submit', function( event ) {
|
|
event.preventDefault();
|
|
|
|
const $form = $( this );
|
|
const $button = $form.find( 'button[type="submit"]' );
|
|
const $status = $form.find( '.aiovg-form-status' );
|
|
|
|
if ( ! validateRequiredFields( $form ) || ! validateCSVColumns() ) {
|
|
$status.html( '<span class="aiovg-text-error"><span class="dashicons dashicons-dismiss"></span> ' + aiovg_import_export.i18n.fields_required + '</span>' );
|
|
|
|
$( 'html, body' ).animate({
|
|
scrollTop: $form.find( '.aiovg-form-invalid' ).first().offset().top - 75
|
|
}, 300 );
|
|
|
|
return;
|
|
}
|
|
|
|
$button.prop( 'disabled', true );
|
|
$status.html( '<span class="spinner"></span> <span class="aiovg-text-success">' + removeEndingDot( aiovg_import_export.i18n.preparing_import ) + '</span><span class="aiovg-animate-dots"></span>' );
|
|
|
|
// Local variables to track progress
|
|
const limit = 20;
|
|
|
|
let offset = 0;
|
|
let imported = [];
|
|
let updated = [];
|
|
let skipped = [];
|
|
let failed = [];
|
|
let errors = [];
|
|
|
|
// Prepare serialized array
|
|
let formArray = $form.serializeArray();
|
|
|
|
// Add static fields
|
|
formArray.push({ name: 'action', value: 'aiovg_import_csv' });
|
|
formArray.push({ name: 'security', value: aiovg_admin.ajax_nonce });
|
|
formArray.push({ name: 'limit', value: limit });
|
|
formArray.push({ name: 'offset', value: offset });
|
|
|
|
// Recursive import function
|
|
const importBatch = function() {
|
|
// Update offset in formArray
|
|
formArray = formArray.map(( field ) => {
|
|
return ( field.name === 'offset' ) ? { name: 'offset', value: offset } : field;
|
|
});
|
|
|
|
$.ajax({
|
|
url: ajaxurl,
|
|
type: 'POST',
|
|
data: formArray,
|
|
dataType: 'json',
|
|
timeout: 60000,
|
|
success: function( response ) {
|
|
if ( ! response.success ) {
|
|
$status.html( '<span class="aiovg-text-error"><span class="dashicons dashicons-dismiss"></span> ' + response.data.error + '</span>' );
|
|
$button.prop( 'disabled', false );
|
|
return;
|
|
}
|
|
|
|
offset = parseInt( response.data.offset );
|
|
imported = imported.concat( response.data.imported );
|
|
updated = updated.concat( response.data.updated );
|
|
skipped = skipped.concat( response.data.skipped );
|
|
failed = failed.concat( response.data.failed );
|
|
errors = errors.concat( response.data.errors );
|
|
|
|
let message = response.data.message;
|
|
message = message.replace( '%%imported%%', imported.length );
|
|
message = message.replace( '%%updated%%', updated.length );
|
|
message = message.replace( '%%skipped%%', skipped.length );
|
|
message = message.replace( '%%failed%%', failed.length );
|
|
|
|
if ( response.data.step === 'process' ) {
|
|
$status.html( '<span class="spinner"></span> <span class="aiovg-text-success">' + removeEndingDot( message ) + '</span><span class="aiovg-animate-dots"></span>' );
|
|
setTimeout( importBatch, 100 ); // Import next batch
|
|
} else if ( response.data.step === 'done' ) {
|
|
$( '#aiovg-csv_file, #aiovg-zip_file' ).val( '' );
|
|
|
|
let html = '<span class="aiovg-text-success"><span class="dashicons dashicons-yes-alt"></span> ' + message + '</span>';
|
|
|
|
if ( errors.length > 0 ) {
|
|
html += '<div class="aiovg-form-fieldset">';
|
|
html += '<h3 class="aiovg-text-error">' + aiovg_import_export.i18n.import_csv_error_status_heading + '</h3>';
|
|
|
|
errors.forEach(( error ) => {
|
|
html += '<span class="aiovg-status-item">' + error + '</span>';
|
|
});
|
|
|
|
html += '</div>';
|
|
}
|
|
|
|
$status.html( html );
|
|
$button.prop( 'disabled', false );
|
|
}
|
|
},
|
|
error: function() {
|
|
$status.html( '<span class="aiovg-text-error"><span class="dashicons dashicons-dismiss"></span> ' + aiovg_import_export.i18n.request_failed + '</span>' );
|
|
$button.prop( 'disabled', false );
|
|
}
|
|
});
|
|
};
|
|
|
|
// Start first batch
|
|
importBatch();
|
|
});
|
|
|
|
// Export to CSV file
|
|
$( '#aiovg-button-export-csv' ).on( 'click', function( event ) {
|
|
event.preventDefault();
|
|
|
|
const $button = $( this );
|
|
const $status = $( '#aiovg-export-status' );
|
|
|
|
$button.prop( 'disabled', true );
|
|
$status.html( '<span class="spinner"></span> <span class="aiovg-text-success">' + removeEndingDot( aiovg_import_export.i18n.preparing_export ) + '</span><span class="aiovg-animate-dots"></span>' );
|
|
|
|
// Persistent formData across batches
|
|
const formData = {
|
|
action: 'aiovg_export_csv',
|
|
security: aiovg_admin.ajax_nonce,
|
|
offset: 0,
|
|
limit: 200,
|
|
total: 0, // Will be set by first batch
|
|
timestamp: ( new Date().toISOString().replace( /[-:T.Z]/g, '' ).slice( 0, 14 ) ),
|
|
file_name: '' // Will be set by first batch
|
|
};
|
|
|
|
// Recursive export function
|
|
const exportBatch = function() {
|
|
$.ajax({
|
|
url: ajaxurl,
|
|
type: 'POST',
|
|
data: formData,
|
|
dataType: 'json',
|
|
timeout: 60000,
|
|
success: function( response ) {
|
|
if ( ! response.success ) {
|
|
$status.html( '<span class="aiovg-text-error"><span class="dashicons dashicons-dismiss"></span> ' + response.data.error + '</span>' );
|
|
$button.prop( 'disabled', false );
|
|
return;
|
|
}
|
|
|
|
formData.offset = parseInt( response.data.offset );
|
|
formData.total = parseInt( response.data.total );
|
|
formData.file_name = response.data.file_name;
|
|
|
|
if ( response.data.step === 'process' ) {
|
|
$status.html( '<span class="spinner"></span> <span class="aiovg-text-success">' + removeEndingDot( response.data.message ) + '</span><span class="aiovg-animate-dots"></span>' );
|
|
setTimeout( exportBatch, 100 ); // Export next batch
|
|
} else if ( response.data.step === 'done' ) {
|
|
$status.html( '<span class="aiovg-text-success"><span class="dashicons dashicons-yes-alt"></span> ' + response.data.message + '</span>' );
|
|
$button.prop( 'disabled', false );
|
|
}
|
|
},
|
|
error: function() {
|
|
$status.html( '<span class="aiovg-text-error"><span class="dashicons dashicons-dismiss"></span> ' + aiovg_import_export.i18n.request_failed + '</span>' );
|
|
$button.prop( 'disabled', false );
|
|
}
|
|
});
|
|
};
|
|
|
|
// Start first batch
|
|
exportBatch();
|
|
});
|
|
|
|
// Export to ZIP file
|
|
$( '#aiovg-button-export-zip' ).on( 'click', function( event ) {
|
|
event.preventDefault();
|
|
|
|
const $button = $( this );
|
|
const $status = $( '#aiovg-export-status' );
|
|
|
|
$button.prop( 'disabled', true );
|
|
$status.html( '<span class="spinner"></span> <span class="aiovg-text-success">' + removeEndingDot( aiovg_import_export.i18n.preparing_export ) + '</span><span class="aiovg-animate-dots"></span>' );
|
|
|
|
// Local variables to track progress
|
|
let zip_files = [];
|
|
let skipped = [];
|
|
let total = 0;
|
|
|
|
// Persistent formData across batches
|
|
const formData = {
|
|
action: 'aiovg_export_zip',
|
|
security: aiovg_admin.ajax_nonce,
|
|
offset: 0,
|
|
limit: 50,
|
|
total: total, // Will be set by first batch
|
|
timestamp: ( new Date().toISOString().replace( /[-:T.Z]/g, '' ).slice( 0, 14 ) )
|
|
};
|
|
|
|
// Recursive export function
|
|
const exportBatch = function() {
|
|
$.ajax({
|
|
url: ajaxurl,
|
|
type: 'POST',
|
|
data: formData,
|
|
dataType: 'json',
|
|
timeout: 60000,
|
|
success: function( response ) {
|
|
if ( ! response.success ) {
|
|
$status.html( '<span class="aiovg-text-error"><span class="dashicons dashicons-dismiss"></span> ' + response.data.error + '</span>' );
|
|
$button.prop( 'disabled', false );
|
|
return;
|
|
}
|
|
|
|
if ( Array.isArray( response.data.zip_files ) ) {
|
|
response.data.zip_files.forEach( function( file ) {
|
|
if ( zip_files.indexOf( file ) === -1 ) {
|
|
zip_files.push( file );
|
|
}
|
|
} );
|
|
}
|
|
|
|
skipped = skipped.concat( response.data.skipped );
|
|
total = parseInt( response.data.total );
|
|
|
|
formData.offset = parseInt( response.data.offset );
|
|
formData.total = total;
|
|
|
|
if ( response.data.step === 'process' ) {
|
|
$status.html( '<span class="spinner"></span> <span class="aiovg-text-success">' + removeEndingDot( response.data.message ) + '</span><span class="aiovg-animate-dots"></span>' );
|
|
setTimeout( exportBatch, 100 ); // Export next batch
|
|
} else if ( response.data.step === 'done' ) {
|
|
let message = response.data.message;
|
|
if ( zip_files.length === 0 ) {
|
|
message = aiovg_import_export.i18n.export_zip_empty_status;
|
|
}
|
|
|
|
message = message.replace( '%%skipped%%', skipped.length );
|
|
message = message.replace( '%%exported%%', ( total - skipped.length ) );
|
|
|
|
let html = '<span class="aiovg-text-success"><span class="dashicons dashicons-yes-alt"></span> ' + message + '</span>';
|
|
|
|
if ( zip_files.length > 0 ) {
|
|
html += '<div class="aiovg-form-fieldset">';
|
|
html += '<h3>' + aiovg_import_export.i18n.export_zip_success_status_heading + '</h3>';
|
|
|
|
zip_files.forEach(( item ) => {
|
|
const fileName = $( '<span>' ).text( item.split( '/' ).pop() ).html();
|
|
html += '<a class="aiovg-status-item" href="' + encodeURI( item ) + '" target="_blank">' + fileName + '</a>';
|
|
});
|
|
|
|
html += '</div>';
|
|
}
|
|
|
|
if ( skipped.length > 0 ) {
|
|
html += '<div class="aiovg-form-fieldset">';
|
|
html += '<h3 class="aiovg-text-error">' + aiovg_import_export.i18n.export_zip_failed_status_heading + '</h3>';
|
|
|
|
skipped.forEach(( item ) => {
|
|
const fileName = $( '<span>' ).text( item.split( '/' ).pop() ).html();
|
|
html += '<a class="aiovg-status-item" href="' + encodeURI( item ) + '" target="_blank">' + fileName + '</a>';
|
|
});
|
|
|
|
html += '</div>';
|
|
}
|
|
|
|
$status.html( html );
|
|
$button.prop( 'disabled', false );
|
|
}
|
|
},
|
|
error: function() {
|
|
$status.html( '<span class="aiovg-text-error"><span class="dashicons dashicons-dismiss"></span> ' + aiovg_import_export.i18n.request_failed + '</span>' );
|
|
$button.prop( 'disabled', false );
|
|
}
|
|
});
|
|
};
|
|
|
|
// Start first batch
|
|
exportBatch();
|
|
});
|
|
|
|
// Export email leads to CSV
|
|
$( document ).on( 'click', '.aiovg-export-email-leads', function( event ) {
|
|
event.preventDefault();
|
|
|
|
const $btn = $( this );
|
|
const videoId = parseInt( $btn.data( 'video-id' ) ) || 0;
|
|
|
|
let dateFrom = '';
|
|
let dateTo = '';
|
|
|
|
const $form = $btn.closest( '#aiovg-form-export-email-leads' );
|
|
if ( $form.length ) {
|
|
dateFrom = $form.find( '[name="date_from"]' ).val() || '';
|
|
dateTo = $form.find( '[name="date_to"]' ).val() || '';
|
|
}
|
|
|
|
let params = 'action=aiovg_export_email_leads_csv';
|
|
params += '&security=' + encodeURIComponent( aiovg_admin.ajax_nonce );
|
|
params += '&video_id=' + videoId;
|
|
params += '&date_from=' + encodeURIComponent( dateFrom );
|
|
params += '&date_to=' + encodeURIComponent( dateTo );
|
|
|
|
window.location.href = ajaxurl + '?' + params;
|
|
});
|
|
|
|
});
|
|
|
|
})( jQuery );
|