feat: Add Supplemental Feeds feature with UI and backend support
- Implemented the main view for Supplemental Feeds, displaying clients with Merchant Account IDs and their associated feed files. - Added styling for the feeds page and its components, including headers, empty states, and dropdown menus for syncing actions. - Created backend logic to generate supplemental feeds for clients, including file handling and data sanitization. - Integrated new routes and views for managing feeds, ensuring proper data retrieval and display. - Updated navigation to include the new Supplemental Feeds section. - Added necessary documentation for CRON job management related to feed generation.
This commit is contained in:
@@ -68,24 +68,34 @@
|
||||
<button type="button" class="btn-icon btn-icon-sync" onclick="toggleClientActive(<?= $client['id']; ?>, this)" title="<?= $is_client_active ? 'Dezaktywuj klienta' : 'Aktywuj klienta'; ?>">
|
||||
<i class="fa-solid <?= $is_client_active ? 'fa-toggle-on' : 'fa-toggle-off'; ?>"></i>
|
||||
</button>
|
||||
<?php if ( $client['google_ads_customer_id'] ): ?>
|
||||
<button type="button" class="btn-icon btn-icon-sync client-sync-action" onclick="syncClient(<?= $client['id']; ?>, 'campaigns', this)" title="Odswiez kampanie" <?= $is_client_active ? '' : 'disabled'; ?>>
|
||||
<i class="fa-solid fa-bullhorn"></i>
|
||||
<div class="sync-dropdown" data-client-id="<?= $client['id']; ?>">
|
||||
<button type="button" class="btn-icon btn-icon-sync client-sync-action" onclick="toggleSyncMenu(this)" title="Odswiez dane" <?= $is_client_active ? '' : 'disabled'; ?>>
|
||||
<i class="fa-solid fa-arrows-rotate"></i>
|
||||
</button>
|
||||
<button type="button" class="btn-icon btn-icon-sync client-sync-action" onclick="syncClient(<?= $client['id']; ?>, 'products', this)" title="Odswiez produkty" <?= $is_client_active ? '' : 'disabled'; ?>>
|
||||
<i class="fa-solid fa-box-open"></i>
|
||||
</button>
|
||||
<?php if ( !empty( $client['google_merchant_account_id'] ) ): ?>
|
||||
<button type="button" class="btn-icon btn-icon-sync client-sync-action" onclick="syncClient(<?= $client['id']; ?>, 'campaigns_product_alerts_merchant', this)" title="Odswiez walidacje Merchant" <?= $is_client_active ? '' : 'disabled'; ?>>
|
||||
<i class="fa-solid fa-store"></i>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
<?php if ( !empty( $client['facebook_ads_account_id'] ) ): ?>
|
||||
<button type="button" class="btn-icon btn-icon-sync client-sync-action" onclick="syncClient(<?= $client['id']; ?>, 'facebook_ads', this)" title="Odswiez Facebook Ads" <?= $is_client_active ? '' : 'disabled'; ?>>
|
||||
<i class="fa-brands fa-facebook-f"></i>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
<div class="sync-dropdown-menu">
|
||||
<?php if ( $client['google_ads_customer_id'] ): ?>
|
||||
<button type="button" onclick="syncFromMenu(<?= $client['id']; ?>, 'campaigns', this)">
|
||||
<i class="fa-solid fa-bullhorn"></i> Kampanie
|
||||
</button>
|
||||
<button type="button" onclick="syncFromMenu(<?= $client['id']; ?>, 'products', this)">
|
||||
<i class="fa-solid fa-box-open"></i> Produkty
|
||||
</button>
|
||||
<?php if ( !empty( $client['google_merchant_account_id'] ) ): ?>
|
||||
<button type="button" onclick="syncFromMenu(<?= $client['id']; ?>, 'campaigns_product_alerts_merchant', this)">
|
||||
<i class="fa-solid fa-store"></i> Walidacja Merchant
|
||||
</button>
|
||||
<button type="button" onclick="syncFromMenu(<?= $client['id']; ?>, 'supplemental_feed', this)">
|
||||
<i class="fa-solid fa-file-csv"></i> Supplemental Feed
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
<?php if ( !empty( $client['facebook_ads_account_id'] ) ): ?>
|
||||
<button type="button" onclick="syncFromMenu(<?= $client['id']; ?>, 'facebook_ads', this)">
|
||||
<i class="fa-brands fa-facebook-f"></i> Facebook Ads
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn-icon btn-icon-edit" onclick="editClient(<?= $client['id']; ?>)" title="Edytuj">
|
||||
<i class="fa-solid fa-pen"></i>
|
||||
</button>
|
||||
@@ -253,8 +263,25 @@ function toggleClientActive( id, btn )
|
||||
} );
|
||||
}
|
||||
|
||||
function syncClient( id, pipeline, btn )
|
||||
// --- Sync dropdown menu ---
|
||||
function toggleSyncMenu( btn )
|
||||
{
|
||||
var $dropdown = $( btn ).closest( '.sync-dropdown' );
|
||||
var wasOpen = $dropdown.hasClass( 'is-open' );
|
||||
$( '.sync-dropdown.is-open' ).removeClass( 'is-open' );
|
||||
if ( !wasOpen ) $dropdown.addClass( 'is-open' );
|
||||
}
|
||||
|
||||
$( document ).on( 'click', function( e ) {
|
||||
if ( !$( e.target ).closest( '.sync-dropdown' ).length )
|
||||
{
|
||||
$( '.sync-dropdown.is-open' ).removeClass( 'is-open' );
|
||||
}
|
||||
});
|
||||
|
||||
function syncFromMenu( id, pipeline, btn )
|
||||
{
|
||||
$( '.sync-dropdown.is-open' ).removeClass( 'is-open' );
|
||||
var $btn = $( btn );
|
||||
var $icon = $btn.find( 'i' );
|
||||
var origClass = $icon.attr( 'class' );
|
||||
@@ -266,6 +293,7 @@ function syncClient( id, pipeline, btn )
|
||||
campaigns: 'kampanii',
|
||||
products: 'produktow',
|
||||
campaigns_product_alerts_merchant: 'walidacji Merchant',
|
||||
supplemental_feed: 'supplemental feed',
|
||||
facebook_ads: 'Facebook Ads'
|
||||
};
|
||||
|
||||
@@ -278,21 +306,18 @@ function syncClient( id, pipeline, btn )
|
||||
|
||||
if ( data.success )
|
||||
{
|
||||
$btn.addClass( 'is-queued' );
|
||||
|
||||
var cron_hint = pipeline === 'facebook_ads'
|
||||
? ' Dane zostana pobrane przy najblizszym uruchomieniu /cron/cron_facebook_ads.'
|
||||
: ' Dane zostana pobrane przy najblizszym uruchomieniu CRON.';
|
||||
var refresh_hint = pipeline === 'facebook_ads'
|
||||
? ' Wymuszenie Facebook Ads nadpisuje dane dla okresu z config.php i pobiera tylko aktywne kampanie/zestawy/reklamy.'
|
||||
: '';
|
||||
var msg = data.immediate
|
||||
? 'Supplemental feed wygenerowany pomyslnie.'
|
||||
: 'Synchronizacja ' + labels[ pipeline ] + ' zostala zakolejkowana. Dane zostana pobrane przy najblizszym uruchomieniu CRON.';
|
||||
|
||||
$.alert({
|
||||
title: 'Zakolejkowano',
|
||||
content: 'Synchronizacja ' + labels[ pipeline ] + ' zostala zakolejkowana.' + cron_hint + refresh_hint,
|
||||
title: data.immediate ? 'Gotowe' : 'Zakolejkowano',
|
||||
content: msg,
|
||||
type: 'green',
|
||||
autoClose: 'ok|3000'
|
||||
});
|
||||
|
||||
loadSyncStatus();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -390,6 +415,7 @@ function loadSyncStatus()
|
||||
if ( info.campaigns ) html += renderSyncBar( 'K:', info.campaigns[0], info.campaigns[1] );
|
||||
if ( info.products ) html += renderSyncBar( 'P:', info.products[0], info.products[1] );
|
||||
if ( info.merchant ) html += renderSyncBar( 'M:', info.merchant[0], info.merchant[1] );
|
||||
if ( info.feed ) html += renderSyncBar( 'F:', info.feed[0], info.feed[1] );
|
||||
if ( info.facebook_ads ) html += renderSyncBar( 'FB:', info.facebook_ads[0], info.facebook_ads[1] );
|
||||
html += '</div>';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user