(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( ' ' + removeEndingDot( aiovg_import_export.i18n.fetching_csv_columns ) + '' ); 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( ' ' + response.data.error + '' ); $button.prop( 'disabled', false ); return; } $status.html( ' ' + aiovg_import_export.i18n.csv_columns_loaded + '' ); $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( ' ' + aiovg_import_export.i18n.fields_required + '' ); $( 'html, body' ).animate({ scrollTop: $form.find( '.aiovg-form-invalid' ).first().offset().top - 75 }, 300 ); return; } $button.prop( 'disabled', true ); $status.html( ' ' + removeEndingDot( aiovg_import_export.i18n.preparing_import ) + '' ); // 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( ' ' + response.data.error + '' ); $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( ' ' + removeEndingDot( message ) + '' ); setTimeout( importBatch, 100 ); // Import next batch } else if ( response.data.step === 'done' ) { let html = ' ' + message + ''; if ( failed.length > 0 ) { html += '
'; html += '

' + aiovg_import_export.i18n.import_folder_failed_status_heading + '

'; failed.forEach(( item ) => { const fileName = $( '' ).text( item.split( '/' ).pop() ).html(); html += '' + fileName + ''; }); html += '
'; } $status.html( html ); $button.prop( 'disabled', false ); } }, error: function() { $status.html( ' ' + aiovg_import_export.i18n.request_failed + '' ); $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( ' ' + aiovg_import_export.i18n.fields_required + '' ); $( 'html, body' ).animate({ scrollTop: $form.find( '.aiovg-form-invalid' ).first().offset().top - 75 }, 300 ); return; } $button.prop( 'disabled', true ); $status.html( ' ' + removeEndingDot( aiovg_import_export.i18n.preparing_import ) + '' ); // 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( ' ' + response.data.error + '' ); $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( ' ' + removeEndingDot( message ) + '' ); setTimeout( importBatch, 100 ); // Import next batch } else if ( response.data.step === 'done' ) { $( '#aiovg-csv_file, #aiovg-zip_file' ).val( '' ); let html = ' ' + message + ''; if ( errors.length > 0 ) { html += '
'; html += '

' + aiovg_import_export.i18n.import_csv_error_status_heading + '

'; errors.forEach(( error ) => { html += '' + error + ''; }); html += '
'; } $status.html( html ); $button.prop( 'disabled', false ); } }, error: function() { $status.html( ' ' + aiovg_import_export.i18n.request_failed + '' ); $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( ' ' + removeEndingDot( aiovg_import_export.i18n.preparing_export ) + '' ); // 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( ' ' + response.data.error + '' ); $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( ' ' + removeEndingDot( response.data.message ) + '' ); setTimeout( exportBatch, 100 ); // Export next batch } else if ( response.data.step === 'done' ) { $status.html( ' ' + response.data.message + '' ); $button.prop( 'disabled', false ); } }, error: function() { $status.html( ' ' + aiovg_import_export.i18n.request_failed + '' ); $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( ' ' + removeEndingDot( aiovg_import_export.i18n.preparing_export ) + '' ); // 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( ' ' + response.data.error + '' ); $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( ' ' + removeEndingDot( response.data.message ) + '' ); 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 = ' ' + message + ''; if ( zip_files.length > 0 ) { html += '
'; html += '

' + aiovg_import_export.i18n.export_zip_success_status_heading + '

'; zip_files.forEach(( item ) => { const fileName = $( '' ).text( item.split( '/' ).pop() ).html(); html += '' + fileName + ''; }); html += '
'; } if ( skipped.length > 0 ) { html += '
'; html += '

' + aiovg_import_export.i18n.export_zip_failed_status_heading + '

'; skipped.forEach(( item ) => { const fileName = $( '' ).text( item.split( '/' ).pop() ).html(); html += '' + fileName + ''; }); html += '
'; } $status.html( html ); $button.prop( 'disabled', false ); } }, error: function() { $status.html( ' ' + aiovg_import_export.i18n.request_failed + '' ); $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 );