2006 lines
69 KiB
PHP
2006 lines
69 KiB
PHP
<div class="products-page">
|
|
<div class="products-header">
|
|
<h2><i class="fa-solid fa-box-open"></i> Produkty</h2>
|
|
</div>
|
|
|
|
<!-- Filtry -->
|
|
<div class="products-filters">
|
|
<div class="filter-group filter-group-client">
|
|
<label for="client_id"><i class="fa-solid fa-building"></i> Klient</label>
|
|
<select id="client_id" name="client_id" class="form-control">
|
|
<option value="">— wybierz klienta —</option>
|
|
<?php foreach ( $this -> clients as $client ): ?>
|
|
<option value="<?= $client['id']; ?>"><?= htmlspecialchars( $client['name'] ); ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
<div class="filter-group filter-group-campaign">
|
|
<label for="products_campaign_id"><i class="fa-solid fa-bullhorn"></i> Kampania</label>
|
|
<select id="products_campaign_id" name="products_campaign_id" class="form-control">
|
|
<option value="">- wszystkie kampanie -</option>
|
|
</select>
|
|
</div>
|
|
<div class="filter-group filter-group-ad-group">
|
|
<label for="products_ad_group_id"><i class="fa-solid fa-layer-group"></i> Grupa reklam</label>
|
|
<div class="ad-group-filter-actions">
|
|
<select id="products_ad_group_id" name="products_ad_group_id" class="form-control">
|
|
<option value="">- wszystkie grupy -</option>
|
|
</select>
|
|
<button type="button" id="delete-products-ad-group" class="btn-icon btn-icon-delete" title="Usun wybrana grupe reklam" disabled>
|
|
<i class="fa-solid fa-trash"></i>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="filter-group filter-group-search">
|
|
<label for="products_search"><i class="fa-solid fa-magnifying-glass"></i> Szukaj</label>
|
|
<input type="text" id="products_search" class="form-control" placeholder="Nazwa, ID oferty..." />
|
|
</div>
|
|
<div class="filter-group filter-group-cl4">
|
|
<label for="products_cl4"><i class="fa-solid fa-tag"></i> CL4</label>
|
|
<input type="text" id="products_cl4" class="form-control" placeholder="np. bestseller, deleted..." />
|
|
</div>
|
|
<div class="filter-group filter-group-columns">
|
|
<label><i class="fa-solid fa-table-columns"></i> Kolumny</label>
|
|
<details class="products-columns-control">
|
|
<summary>Widocznosc kolumn</summary>
|
|
<div class="products-columns-list" id="products_columns_list"></div>
|
|
</details>
|
|
</div>
|
|
</div>
|
|
|
|
<details id="products_scope_alerts_box" class="products-scope-alerts hide">
|
|
<summary>
|
|
<i class="fa-solid fa-triangle-exclamation"></i>
|
|
Alerty dla wybranej kampanii (i opcjonalnie grupy reklam)
|
|
(<span id="products_scope_alerts_count">0</span>)
|
|
</summary>
|
|
<div class="products-scope-alerts-list" id="products_scope_alerts_list"></div>
|
|
</details>
|
|
|
|
<details id="products_zero_impressions_box" class="products-scope-alerts hide">
|
|
<summary>
|
|
<i class="fa-solid fa-magnifying-glass"></i>
|
|
Produkty do sprawdzenia (0 wyswietlen w ostatnich 30 dniach)
|
|
(<span id="products_zero_impressions_count">0</span>)
|
|
</summary>
|
|
<div class="products-scope-alerts-list">
|
|
<select id="products_zero_impressions_select" class="form-control" size="8"></select>
|
|
</div>
|
|
</details>
|
|
|
|
<!-- Akcje bulk -->
|
|
<div class="products-actions">
|
|
<button type="button" class="btn btn-danger btn-sm" id="delete-selected-products" disabled>
|
|
<i class="fa-solid fa-trash"></i> Usuń zaznaczone (<span id="selected-count">0</span>)
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Tabela produktów -->
|
|
<div class="products-table-wrap">
|
|
<table class="table table-sm" id="products">
|
|
<thead>
|
|
<tr>
|
|
<th><input type="checkbox" id="select-all-products" title="Zaznacz wszystkie" /></th>
|
|
<th>Id</th>
|
|
<th>Id oferty</th>
|
|
<th>Kampania</th>
|
|
<th>Grupa reklam</th>
|
|
<th>URL</th>
|
|
<th>Nazwa produktu</th>
|
|
<th title="Ostrzezenia produktowe"><i class="fa-solid fa-triangle-exclamation"></i></th>
|
|
<th>Wyśw.</th>
|
|
<th>Wyśw. (30d)</th>
|
|
<th>Klik.</th>
|
|
<th>Klik. (30d)</th>
|
|
<th>CTR</th>
|
|
<th>Koszt</th>
|
|
<th>CPC</th>
|
|
<th>Konw.</th>
|
|
<th>Wart. konw.</th>
|
|
<th>ROAS</th>
|
|
<th>Min. ROAS</th>
|
|
<th>CL3</th>
|
|
<th>CL4</th>
|
|
<th>Akcje</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<?php
|
|
$openai_enabled = \services\GoogleAdsApi::get_setting( 'openai_enabled' ) !== '0';
|
|
$claude_enabled = \services\GoogleAdsApi::get_setting( 'claude_enabled' ) !== '0';
|
|
$gemini_enabled = \services\GoogleAdsApi::get_setting( 'gemini_enabled' ) !== '0';
|
|
?>
|
|
<script type="text/javascript">
|
|
var AI_OPENAI_ENABLED = <?= $openai_enabled ? 'true' : 'false'; ?>;
|
|
var AI_CLAUDE_ENABLED = <?= $claude_enabled ? 'true' : 'false'; ?>;
|
|
var AI_GEMINI_ENABLED = <?= $gemini_enabled ? 'true' : 'false'; ?>;
|
|
var PRODUCTS_COLUMNS_STORAGE_KEY = 'products.columns.visibility';
|
|
var PRODUCTS_LOCKED_COLUMNS = [ 0, 21 ];
|
|
|
|
function show_toast( message, type )
|
|
{
|
|
var bg = type === 'error' ? '#dc3545' : '#28a745';
|
|
var icon = type === 'error' ? 'fa-circle-xmark' : 'fa-circle-check';
|
|
var $toast = $( '<div class="app-toast"><i class="fa-solid ' + icon + '"></i> ' + message + '</div>' );
|
|
$toast.css({
|
|
position: 'fixed', bottom: '30px', right: '30px', zIndex: 99999,
|
|
background: bg, color: '#fff', padding: '12px 24px', borderRadius: '8px',
|
|
boxShadow: '0 4px 16px rgba(0,0,0,.25)', fontSize: '14px', fontWeight: 500,
|
|
opacity: 0, transform: 'translateY(20px)', transition: 'all .3s ease'
|
|
});
|
|
$( 'body' ).append( $toast );
|
|
setTimeout( function() { $toast.css({ opacity: 1, transform: 'translateY(0)' }); }, 10 );
|
|
setTimeout( function() {
|
|
$toast.css({ opacity: 0, transform: 'translateY(20px)' });
|
|
setTimeout( function() { $toast.remove(); }, 300 );
|
|
}, 3000 );
|
|
}
|
|
|
|
function escape_html( value )
|
|
{
|
|
return $( '<div>' ).text( value == null ? '' : String( value ) ).html();
|
|
}
|
|
|
|
var GOOGLE_TAXONOMY_ENDPOINT = '/tools/google-taxonomy.php';
|
|
var googleCategories = [];
|
|
|
|
function loadGoogleCategories( callback )
|
|
{
|
|
if ( googleCategories.length ) {
|
|
callback( googleCategories );
|
|
return;
|
|
}
|
|
$.ajax({
|
|
url: GOOGLE_TAXONOMY_ENDPOINT,
|
|
dataType: 'json',
|
|
success: function( res ) {
|
|
if ( res.status === 'ok' ) {
|
|
googleCategories = res.categories || [];
|
|
callback( googleCategories );
|
|
} else {
|
|
callback( [] );
|
|
}
|
|
},
|
|
error: function() { callback( [] ); }
|
|
});
|
|
}
|
|
|
|
|
|
function products_storage_set( key, value )
|
|
{
|
|
try
|
|
{
|
|
if ( value === null || typeof value === 'undefined' )
|
|
{
|
|
localStorage.removeItem( key );
|
|
}
|
|
else
|
|
{
|
|
localStorage.setItem( key, String( value ) );
|
|
}
|
|
}
|
|
catch ( e ) {}
|
|
}
|
|
|
|
function products_storage_get( key )
|
|
{
|
|
try
|
|
{
|
|
return localStorage.getItem( key ) || '';
|
|
}
|
|
catch ( e )
|
|
{
|
|
return '';
|
|
}
|
|
}
|
|
|
|
function products_is_locked_column( idx )
|
|
{
|
|
return PRODUCTS_LOCKED_COLUMNS.indexOf( Number( idx ) ) !== -1;
|
|
}
|
|
|
|
function products_get_saved_columns_visibility( columns_count )
|
|
{
|
|
var raw = products_storage_get( PRODUCTS_COLUMNS_STORAGE_KEY );
|
|
if ( !raw )
|
|
{
|
|
return null;
|
|
}
|
|
|
|
try
|
|
{
|
|
var saved = JSON.parse( raw );
|
|
if ( !Array.isArray( saved ) || saved.length !== columns_count )
|
|
{
|
|
return null;
|
|
}
|
|
return saved;
|
|
}
|
|
catch ( e )
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
function products_save_columns_visibility( table_instance )
|
|
{
|
|
if ( !table_instance || !table_instance.columns )
|
|
{
|
|
return;
|
|
}
|
|
|
|
var columns_count = table_instance.columns().count();
|
|
var visible_map = [];
|
|
var i;
|
|
|
|
for ( i = 0; i < columns_count; i++ )
|
|
{
|
|
visible_map.push( table_instance.column( i ).visible() );
|
|
}
|
|
|
|
products_storage_set( PRODUCTS_COLUMNS_STORAGE_KEY, JSON.stringify( visible_map ) );
|
|
}
|
|
|
|
function products_apply_saved_columns_visibility( table_instance )
|
|
{
|
|
if ( !table_instance || !table_instance.columns )
|
|
{
|
|
return;
|
|
}
|
|
|
|
var columns_count = table_instance.columns().count();
|
|
var saved_visibility = products_get_saved_columns_visibility( columns_count );
|
|
var i;
|
|
|
|
if ( !saved_visibility )
|
|
{
|
|
return;
|
|
}
|
|
|
|
for ( i = 0; i < columns_count; i++ )
|
|
{
|
|
if ( products_is_locked_column( i ) )
|
|
{
|
|
table_instance.column( i ).visible( true, false );
|
|
continue;
|
|
}
|
|
|
|
table_instance.column( i ).visible( !!saved_visibility[i], false );
|
|
}
|
|
|
|
table_instance.columns.adjust().draw( false );
|
|
}
|
|
|
|
function products_render_columns_picker( table_instance )
|
|
{
|
|
var $list = $( '#products_columns_list' );
|
|
var columns_count = ( table_instance && table_instance.columns ) ? table_instance.columns().count() : 0;
|
|
var i;
|
|
|
|
if ( !$list.length )
|
|
{
|
|
return;
|
|
}
|
|
|
|
$list.empty();
|
|
|
|
if ( !columns_count )
|
|
{
|
|
$list.append( '<div class="products-col-item">Brak kolumn.</div>' );
|
|
return;
|
|
}
|
|
|
|
for ( i = 0; i < columns_count; i++ )
|
|
{
|
|
if ( products_is_locked_column( i ) )
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var id = 'products-col-toggle-' + i;
|
|
var header_node = table_instance.column( i ).header();
|
|
var th = header_node ? $( header_node ) : $();
|
|
var title = $.trim( th.find( '.dt-column-title' ).first().text() || th.text() ) || ( 'Kolumna ' + i );
|
|
var checked = table_instance.column( i ).visible() ? ' checked' : '';
|
|
|
|
$list.append(
|
|
'<label class="products-col-item" for="' + id + '">' +
|
|
'<input type="checkbox" class="products-col-toggle" id="' + id + '" data-col-index="' + i + '"' + checked + '>' +
|
|
'<span>' + title + '</span>' +
|
|
'</label>'
|
|
);
|
|
}
|
|
}
|
|
$( function()
|
|
{
|
|
var products_table = new DataTable( '#products', {
|
|
stateSave: true,
|
|
ajax: {
|
|
type: 'POST',
|
|
url: '/products/get_products/',
|
|
data: function( d ) {
|
|
d.client_id = $( '#client_id' ).val() || '';
|
|
d.campaign_id = $( '#products_campaign_id' ).val() || '';
|
|
d.ad_group_id = $( '#products_ad_group_id' ).val() || '';
|
|
d.search_text = $( '#products_search' ).val() || '';
|
|
d.filter_cl4 = $( '#products_cl4' ).val() || '';
|
|
}
|
|
},
|
|
processing: true,
|
|
serverSide: true,
|
|
autoWidth: false,
|
|
searching: false,
|
|
lengthChange: false,
|
|
pageLength: 25,
|
|
columns: [
|
|
{ width: '30px', orderable: false, className: 'select-checkbox', render: function( data, type, row ) {
|
|
return '<input type="checkbox" class="product-checkbox" value="' + row[1] + '" />';
|
|
}
|
|
},
|
|
{ width: '50px', orderable: false },
|
|
{ width: '80px', name: 'offer_id' },
|
|
{ width: '200px', name: 'campaign_name' },
|
|
{ width: '200px', name: 'ad_group_name' },
|
|
{ width: '120px', orderable: false, searchable: false },
|
|
{ name: 'name' },
|
|
{ width: '35px', orderable: false, searchable: false, className: 'dt-center' },
|
|
{ width: '50px', name: 'impressions' },
|
|
{ width: '80px', name: 'impressions_30' },
|
|
{ width: '50px', name: 'clicks' },
|
|
{ width: '80px', name: 'clicks_30' },
|
|
{ width: '50px', name: 'ctr' },
|
|
{ width: '80px', name: 'cost', className: "dt-type-numeric" },
|
|
{ width: '50px', name: 'cpc', className: "dt-type-numeric" },
|
|
{ width: '50px', name: 'conversions' },
|
|
{ width: '90px', name: 'conversions_value', className: "dt-type-numeric" },
|
|
{ width: '60px', name: 'roas' },
|
|
{ width: '70px', name: 'min_roas' },
|
|
{ width: '50px', name: 'cl3', orderable: false },
|
|
{ width: '120px', orderable: false },
|
|
{ width: '190px', orderable: false, className: 'dt-center' }
|
|
],
|
|
createdRow: function( row, data ) {
|
|
var cl4Val = $( data[20] ).val();
|
|
if ( cl4Val && cl4Val.toLowerCase() === 'niedostępny' ) {
|
|
$( row ).addClass( 'product-row-unavailable' );
|
|
}
|
|
},
|
|
order: [ [ 10, 'desc' ] ],
|
|
language: {
|
|
processing: 'Ładowanie...',
|
|
emptyTable: 'Brak produktów do wyświetlenia',
|
|
info: 'Produkty _START_ - _END_ z _TOTAL_',
|
|
infoEmpty: '',
|
|
paginate: {
|
|
first: 'Pierwsza',
|
|
last: 'Ostatnia',
|
|
next: 'Dalej',
|
|
previous: 'Wstecz'
|
|
}
|
|
}
|
|
});
|
|
|
|
products_apply_saved_columns_visibility( products_table );
|
|
products_render_columns_picker( products_table );
|
|
|
|
function reload_products_table()
|
|
{
|
|
products_table.ajax.reload( null, false );
|
|
}
|
|
|
|
// Filtr: szukaj po nazwie/offer_id (debounce 400ms)
|
|
var _searchTimer = null;
|
|
$( '#products_search' ).on( 'keyup', function() {
|
|
localStorage.setItem( 'products_search', $( this ).val() || '' );
|
|
clearTimeout( _searchTimer );
|
|
_searchTimer = setTimeout( function() { reload_products_table(); }, 400 );
|
|
});
|
|
|
|
// Filtr: custom_label_4 (debounce 400ms)
|
|
var _cl4Timer = null;
|
|
$( '#products_cl4' ).on( 'keyup', function() {
|
|
localStorage.setItem( 'products_cl4', $( this ).val() || '' );
|
|
clearTimeout( _cl4Timer );
|
|
_cl4Timer = setTimeout( function() { reload_products_table(); }, 400 );
|
|
});
|
|
|
|
function submit_delete_campaign_ad_group( campaign_id, ad_group_id, delete_scope, on_success )
|
|
{
|
|
function parse_json_loose( raw )
|
|
{
|
|
if ( typeof raw !== 'string' || !raw )
|
|
{
|
|
return null;
|
|
}
|
|
|
|
var text = $.trim( raw );
|
|
if ( !text )
|
|
{
|
|
return null;
|
|
}
|
|
|
|
try
|
|
{
|
|
return JSON.parse( text );
|
|
}
|
|
catch ( e )
|
|
{
|
|
var start = text.indexOf( '{' );
|
|
var end = text.lastIndexOf( '}' );
|
|
|
|
if ( start !== -1 && end > start )
|
|
{
|
|
try
|
|
{
|
|
return JSON.parse( text.substring( start, end + 1 ) );
|
|
}
|
|
catch ( e2 ) {}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
function handle_success( message )
|
|
{
|
|
show_toast( message || 'Grupa reklam zostala usunieta.', 'success' );
|
|
|
|
if ( typeof on_success === 'function' )
|
|
{
|
|
on_success();
|
|
}
|
|
|
|
localStorage.removeItem( 'products_ad_group_id' );
|
|
load_products_ad_groups( campaign_id, '' ).done( function() {
|
|
$.when( load_scope_alerts(), load_zero_impressions_products() ).always( function() {
|
|
reload_products_table();
|
|
} );
|
|
} );
|
|
}
|
|
|
|
function check_if_ad_group_still_exists()
|
|
{
|
|
var deferred = $.Deferred();
|
|
|
|
if ( !campaign_id || !ad_group_id )
|
|
{
|
|
deferred.resolve( true );
|
|
return deferred.promise();
|
|
}
|
|
|
|
$.ajax({
|
|
url: '/products/get_campaign_ad_groups/campaign_id=' + campaign_id,
|
|
type: 'GET',
|
|
dataType: 'json'
|
|
}).done( function( res ) {
|
|
var still_exists = false;
|
|
|
|
( res.ad_groups || [] ).forEach( function( row ) {
|
|
if ( String( row.id || '' ) === String( ad_group_id ) )
|
|
{
|
|
still_exists = true;
|
|
}
|
|
} );
|
|
|
|
deferred.resolve( still_exists );
|
|
}).fail( function() {
|
|
deferred.resolve( true );
|
|
} );
|
|
|
|
return deferred.promise();
|
|
}
|
|
|
|
var request_data = {
|
|
campaign_id: campaign_id,
|
|
ad_group_id: ad_group_id,
|
|
delete_scope: delete_scope
|
|
};
|
|
|
|
$.ajax({
|
|
url: '/products/delete_campaign_ad_group/',
|
|
type: 'POST',
|
|
data: request_data,
|
|
success: function( response )
|
|
{
|
|
var res = ( typeof response === 'object' && response !== null )
|
|
? response
|
|
: parse_json_loose( response );
|
|
|
|
if ( res && res.status === 'ok' )
|
|
{
|
|
handle_success( res.message );
|
|
}
|
|
else
|
|
{
|
|
check_if_ad_group_still_exists().done( function( still_exists ) {
|
|
if ( !still_exists )
|
|
{
|
|
handle_success( ( res && res.message ) ? res.message : 'Grupa reklam zostala usunieta.' );
|
|
return;
|
|
}
|
|
|
|
$.alert({
|
|
title: 'Blad',
|
|
content: ( res && res.message ) ? res.message : 'Nie udalo sie usunac grupy reklam.',
|
|
type: 'red'
|
|
});
|
|
} );
|
|
}
|
|
},
|
|
error: function( jqXHR )
|
|
{
|
|
var res = parse_json_loose( jqXHR && jqXHR.responseText ? jqXHR.responseText : '' );
|
|
|
|
if ( res && res.status === 'ok' )
|
|
{
|
|
handle_success( res.message );
|
|
return;
|
|
}
|
|
check_if_ad_group_still_exists().done( function( still_exists ) {
|
|
if ( !still_exists )
|
|
{
|
|
handle_success( ( res && res.message ) ? res.message : 'Grupa reklam zostala usunieta.' );
|
|
return;
|
|
}
|
|
|
|
$.alert({
|
|
title: 'Blad',
|
|
content: ( res && res.message ) ? res.message : 'Wystapil blad podczas usuwania grupy reklam.',
|
|
type: 'red'
|
|
});
|
|
} );
|
|
}
|
|
});
|
|
|
|
return false;
|
|
}
|
|
|
|
function load_products_campaigns( client_id, selected_campaign_id )
|
|
{
|
|
var $campaign = $( '#products_campaign_id' );
|
|
$campaign.empty().append( '<option value="">- wszystkie kampanie -</option>' );
|
|
|
|
if ( !client_id )
|
|
{
|
|
return $.Deferred().resolve().promise();
|
|
}
|
|
|
|
return $.ajax({
|
|
url: '/products/get_campaigns_list/client_id=' + client_id,
|
|
type: 'GET',
|
|
dataType: 'json'
|
|
}).done( function( res ) {
|
|
( res.campaigns || [] ).forEach( function( row ) {
|
|
var channel_type = String( row.advertising_channel_type || '' ).toUpperCase();
|
|
$campaign.append(
|
|
'<option value="' + row.id + '" data-channel-type="' + channel_type + '">' + escape_html( row.campaign_name || '' ) + '</option>'
|
|
);
|
|
} );
|
|
|
|
if ( selected_campaign_id && $campaign.find( 'option[value="' + selected_campaign_id + '"]' ).length )
|
|
{
|
|
$campaign.val( selected_campaign_id );
|
|
}
|
|
|
|
update_delete_ad_group_button_state();
|
|
} );
|
|
}
|
|
|
|
function get_selected_products_campaign_channel_type()
|
|
{
|
|
var campaign_id = $( '#products_campaign_id' ).val() || '';
|
|
|
|
if ( !campaign_id )
|
|
{
|
|
return '';
|
|
}
|
|
|
|
return String(
|
|
$( '#products_campaign_id option[value="' + campaign_id + '"]' ).attr( 'data-channel-type' ) || ''
|
|
).toUpperCase();
|
|
}
|
|
|
|
function load_products_ad_groups( campaign_id, selected_ad_group_id )
|
|
{
|
|
var $ad_group = $( '#products_ad_group_id' );
|
|
$ad_group.empty().append( '<option value="">- wszystkie grupy -</option>' );
|
|
|
|
if ( !campaign_id )
|
|
{
|
|
update_delete_ad_group_button_state();
|
|
return $.Deferred().resolve().promise();
|
|
}
|
|
|
|
return $.ajax({
|
|
url: '/products/get_campaign_ad_groups/campaign_id=' + campaign_id,
|
|
type: 'GET',
|
|
dataType: 'json'
|
|
}).done( function( res ) {
|
|
( res.ad_groups || [] ).forEach( function( row ) {
|
|
$ad_group.append( '<option value="' + row.id + '">' + row.ad_group_name + '</option>' );
|
|
} );
|
|
|
|
if ( selected_ad_group_id && $ad_group.find( 'option[value="' + selected_ad_group_id + '"]' ).length )
|
|
{
|
|
$ad_group.val( selected_ad_group_id );
|
|
}
|
|
|
|
update_delete_ad_group_button_state();
|
|
} );
|
|
}
|
|
|
|
function update_delete_ad_group_button_state()
|
|
{
|
|
var campaign_channel_type = get_selected_products_campaign_channel_type();
|
|
var ad_group_id = $( '#products_ad_group_id' ).val() || '';
|
|
var is_shopping_campaign = campaign_channel_type === 'SHOPPING';
|
|
var can_delete = is_shopping_campaign && ad_group_id !== '';
|
|
var $btn = $( '#delete-products-ad-group' );
|
|
|
|
$btn.prop( 'disabled', !can_delete );
|
|
|
|
if ( !is_shopping_campaign )
|
|
{
|
|
$btn.attr( 'title', 'Opcja dostepna tylko dla kampanii produktowych (Shopping)' );
|
|
}
|
|
else if ( ad_group_id === '' )
|
|
{
|
|
$btn.attr( 'title', 'Wybierz grupe reklam do usuniecia' );
|
|
}
|
|
else
|
|
{
|
|
$btn.attr( 'title', 'Usun wybrana grupe reklam' );
|
|
}
|
|
}
|
|
|
|
function render_scope_alerts_box( alerts )
|
|
{
|
|
var $box = $( '#products_scope_alerts_box' );
|
|
var $count = $( '#products_scope_alerts_count' );
|
|
var $list = $( '#products_scope_alerts_list' );
|
|
var rows = Array.isArray( alerts ) ? alerts : [];
|
|
|
|
if ( !rows.length )
|
|
{
|
|
$count.text( '0' );
|
|
$list.empty();
|
|
$box.addClass( 'hide' ).removeAttr( 'open' );
|
|
return;
|
|
}
|
|
|
|
var html = '';
|
|
|
|
rows.forEach( function( row ) {
|
|
var date_text = row.date_detected || row.date_add || '';
|
|
var type_text = row.alert_type ? String( row.alert_type ) : '';
|
|
var message_text = row.message ? String( row.message ) : '';
|
|
|
|
html += ''
|
|
+ '<div class="products-scope-alert-item">'
|
|
+ '<div class="products-scope-alert-meta">'
|
|
+ '<span class="products-scope-alert-date">' + escape_html( date_text ) + '</span>'
|
|
+ ( type_text ? '<span class="products-scope-alert-type">' + escape_html( type_text ) + '</span>' : '' )
|
|
+ '</div>'
|
|
+ '<div class="products-scope-alert-message">' + escape_html( message_text ) + '</div>'
|
|
+ '</div>';
|
|
} );
|
|
|
|
$count.text( rows.length );
|
|
$list.html( html );
|
|
$box.removeClass( 'hide' ).attr( 'open', 'open' );
|
|
}
|
|
|
|
function load_scope_alerts()
|
|
{
|
|
var client_id = $( '#client_id' ).val() || '';
|
|
var campaign_id = $( '#products_campaign_id' ).val() || '';
|
|
var ad_group_id = $( '#products_ad_group_id' ).val() || '';
|
|
|
|
if ( !client_id || !campaign_id )
|
|
{
|
|
render_scope_alerts_box( [] );
|
|
return $.Deferred().resolve().promise();
|
|
}
|
|
|
|
return $.ajax({
|
|
url: '/products/get_scope_alerts/',
|
|
type: 'POST',
|
|
dataType: 'json',
|
|
data: {
|
|
client_id: client_id,
|
|
campaign_id: campaign_id,
|
|
ad_group_id: ad_group_id
|
|
}
|
|
}).done( function( res ) {
|
|
if ( res && res.status === 'ok' )
|
|
{
|
|
render_scope_alerts_box( res.alerts || [] );
|
|
}
|
|
else
|
|
{
|
|
render_scope_alerts_box( [] );
|
|
}
|
|
}).fail( function() {
|
|
render_scope_alerts_box( [] );
|
|
} );
|
|
}
|
|
|
|
function render_zero_impressions_box( products )
|
|
{
|
|
var $box = $( '#products_zero_impressions_box' );
|
|
var $count = $( '#products_zero_impressions_count' );
|
|
var $select = $( '#products_zero_impressions_select' );
|
|
var rows = Array.isArray( products ) ? products : [];
|
|
|
|
$select.empty();
|
|
|
|
if ( !rows.length )
|
|
{
|
|
$count.text( '0' );
|
|
$box.addClass( 'hide' ).removeAttr( 'open' );
|
|
return;
|
|
}
|
|
|
|
rows.forEach( function( row ) {
|
|
var product_id = parseInt( row.product_id || 0, 10 );
|
|
var offer_id = row.offer_id ? String( row.offer_id ) : '';
|
|
var product_name = row.name ? String( row.name ) : '';
|
|
var label = '#' + product_id + ( offer_id ? ' | ' + offer_id : '' ) + ' | ' + product_name;
|
|
|
|
$select.append( '<option value="' + product_id + '">' + escape_html( label ) + '</option>' );
|
|
} );
|
|
|
|
$count.text( rows.length );
|
|
$box.removeClass( 'hide' );
|
|
}
|
|
|
|
function load_zero_impressions_products()
|
|
{
|
|
var client_id = $( '#client_id' ).val() || '';
|
|
var campaign_id = $( '#products_campaign_id' ).val() || '';
|
|
var ad_group_id = $( '#products_ad_group_id' ).val() || '';
|
|
|
|
if ( !client_id || !campaign_id )
|
|
{
|
|
render_zero_impressions_box( [] );
|
|
return $.Deferred().resolve().promise();
|
|
}
|
|
|
|
return $.ajax({
|
|
url: '/products/get_products_without_impressions_30/',
|
|
type: 'POST',
|
|
dataType: 'json',
|
|
data: {
|
|
client_id: client_id,
|
|
campaign_id: campaign_id,
|
|
ad_group_id: ad_group_id
|
|
}
|
|
}).done( function( res ) {
|
|
if ( res && res.status === 'ok' )
|
|
{
|
|
render_zero_impressions_box( res.products || [] );
|
|
}
|
|
else
|
|
{
|
|
render_zero_impressions_box( [] );
|
|
}
|
|
}).fail( function() {
|
|
render_zero_impressions_box( [] );
|
|
} );
|
|
}
|
|
|
|
$( 'body' ).on( 'click', '.assign-product-scope', function( e )
|
|
{
|
|
e.preventDefault();
|
|
|
|
var product_id = $( this ).attr( 'product_id' );
|
|
var client_id = $( '#client_id' ).val() || '';
|
|
|
|
if ( !client_id )
|
|
{
|
|
$.alert({ title: 'Brak klienta', content: 'Najpierw wybierz klienta, aby przypisać produkt do kampanii i grupy reklam.', type: 'orange' });
|
|
return;
|
|
}
|
|
|
|
$.confirm({
|
|
title: 'Dodaj produkt do kampanii/grupy',
|
|
content: '' +
|
|
'<form class="assign-product-form">' +
|
|
'<div class="assign-step assign-step-1">' +
|
|
'<h4 style="margin-top:0">Krok 1 z 2: Kampania</h4>' +
|
|
'<div class="form-group">' +
|
|
'<label style="display:block"><input type="radio" name="campaign_mode" value="existing" checked> Istniejąca kampania</label>' +
|
|
'<select class="form-control assign-campaign-id" style="margin-top:8px"><option value="">— wybierz kampanię —</option></select>' +
|
|
'</div>' +
|
|
'<div class="form-group">' +
|
|
'<label style="display:block"><input type="radio" name="campaign_mode" value="new"> Nowa kampania</label>' +
|
|
'<input type="text" class="form-control assign-campaign-name" placeholder="Nazwa nowej kampanii" style="margin-top:8px;display:none">' +
|
|
'<div class="assign-new-campaign-options" style="display:none;margin-top:8px">' +
|
|
'<div style="display:flex;gap:8px">' +
|
|
'<input type="number" min="1" step="0.01" class="form-control assign-campaign-budget" value="50.00" placeholder="Budżet dzienny (np. 50.00 PLN)">' +
|
|
'<input type="number" min="0.1" step="0.01" class="form-control assign-default-cpc" value="1.00" placeholder="Domyślne CPC (np. 1.00 PLN)">' +
|
|
'</div>' +
|
|
'<small class="text-muted">Dotyczy tylko tworzenia nowej kampanii Standard Shopping.</small>' +
|
|
'</div>' +
|
|
'</div>' +
|
|
'</div>' +
|
|
'<div class="assign-step assign-step-2" style="display:none">' +
|
|
'<h4 style="margin-top:0">Krok 2 z 2: Grupa reklam</h4>' +
|
|
'<div class="form-group">' +
|
|
'<label style="display:block"><input type="radio" name="ad_group_mode" value="existing" checked> Istniejąca grupa reklam</label>' +
|
|
'<select class="form-control assign-ad-group-id" style="margin-top:8px"><option value="">— wybierz grupę reklam —</option></select>' +
|
|
'</div>' +
|
|
'<div class="form-group">' +
|
|
'<label style="display:block"><input type="radio" name="ad_group_mode" value="new"> Nowa grupa reklam</label>' +
|
|
'<input type="text" class="form-control assign-ad-group-name" placeholder="Nazwa nowej grupy reklam" style="margin-top:8px;display:none">' +
|
|
'</div>' +
|
|
'</div>' +
|
|
'</form>',
|
|
useBootstrap: false,
|
|
boxWidth: '720px',
|
|
theme: 'modern',
|
|
buttons: {
|
|
back: {
|
|
text: 'Wstecz',
|
|
isHidden: true,
|
|
action: function() {
|
|
this.$content.find( '.assign-step-1' ).show();
|
|
this.$content.find( '.assign-step-2' ).hide();
|
|
this.$$back.hide();
|
|
this.$$next.show();
|
|
this.$$save.hide();
|
|
return false;
|
|
}
|
|
},
|
|
next: {
|
|
text: 'Dalej',
|
|
btnClass: 'btn-blue',
|
|
action: function() {
|
|
var $content = this.$content;
|
|
var campaign_mode = $content.find( 'input[name="campaign_mode"]:checked' ).val();
|
|
var campaign_id = $content.find( '.assign-campaign-id' ).val();
|
|
var campaign_name = $.trim( $content.find( '.assign-campaign-name' ).val() );
|
|
var campaign_daily_budget = parseFloat( $content.find( '.assign-campaign-budget' ).val() || '0' );
|
|
var default_cpc = parseFloat( $content.find( '.assign-default-cpc' ).val() || '0' );
|
|
|
|
if ( campaign_mode === 'existing' && !campaign_id )
|
|
{
|
|
$.alert( 'Wybierz kampanię.' );
|
|
return false;
|
|
}
|
|
|
|
if ( campaign_mode === 'new' && !campaign_name )
|
|
{
|
|
$.alert( 'Podaj nazwę nowej kampanii.' );
|
|
return false;
|
|
}
|
|
|
|
if ( campaign_mode === 'new' && ( isNaN( campaign_daily_budget ) || campaign_daily_budget <= 0 ) )
|
|
{
|
|
$.alert( 'Podaj poprawny budżet dzienny (większy od 0).' );
|
|
return false;
|
|
}
|
|
|
|
if ( campaign_mode === 'new' && ( isNaN( default_cpc ) || default_cpc <= 0 ) )
|
|
{
|
|
$.alert( 'Podaj poprawne domyślne CPC (większe od 0).' );
|
|
return false;
|
|
}
|
|
|
|
this.$content.find( '.assign-step-1' ).hide();
|
|
this.$content.find( '.assign-step-2' ).show();
|
|
this.$$back.show();
|
|
this.$$next.hide();
|
|
this.$$save.show();
|
|
return false;
|
|
}
|
|
},
|
|
save: {
|
|
text: 'Zapisz',
|
|
btnClass: 'btn-green',
|
|
isHidden: true,
|
|
action: function() {
|
|
var jc = this;
|
|
var $content = jc.$content;
|
|
|
|
var campaign_mode = $content.find( 'input[name="campaign_mode"]:checked' ).val();
|
|
var campaign_id = $content.find( '.assign-campaign-id' ).val() || '';
|
|
var campaign_name = $.trim( $content.find( '.assign-campaign-name' ).val() );
|
|
var campaign_daily_budget = parseFloat( $content.find( '.assign-campaign-budget' ).val() || '0' );
|
|
var default_cpc = parseFloat( $content.find( '.assign-default-cpc' ).val() || '0' );
|
|
|
|
var ad_group_mode = $content.find( 'input[name="ad_group_mode"]:checked' ).val();
|
|
var ad_group_id = $content.find( '.assign-ad-group-id' ).val() || '';
|
|
var ad_group_name = $.trim( $content.find( '.assign-ad-group-name' ).val() );
|
|
|
|
if ( campaign_mode === 'existing' && !campaign_id )
|
|
{
|
|
$.alert( 'Wybierz kampanię.' );
|
|
return false;
|
|
}
|
|
|
|
if ( campaign_mode === 'new' && !campaign_name )
|
|
{
|
|
$.alert( 'Podaj nazwę nowej kampanii.' );
|
|
return false;
|
|
}
|
|
|
|
if ( campaign_mode === 'new' && ( isNaN( campaign_daily_budget ) || campaign_daily_budget <= 0 ) )
|
|
{
|
|
$.alert( 'Podaj poprawny budżet dzienny (większy od 0).' );
|
|
return false;
|
|
}
|
|
|
|
if ( campaign_mode === 'new' && ( isNaN( default_cpc ) || default_cpc <= 0 ) )
|
|
{
|
|
$.alert( 'Podaj poprawne domyślne CPC (większe od 0).' );
|
|
return false;
|
|
}
|
|
|
|
if ( ad_group_mode === 'existing' && !ad_group_id )
|
|
{
|
|
$.alert( 'Wybierz grupę reklam.' );
|
|
return false;
|
|
}
|
|
|
|
if ( ad_group_mode === 'new' && !ad_group_name )
|
|
{
|
|
$.alert( 'Podaj nazwę nowej grupy reklam.' );
|
|
return false;
|
|
}
|
|
|
|
jc.showLoading( true );
|
|
|
|
$.ajax({
|
|
url: '/products/assign_product_scope/',
|
|
type: 'POST',
|
|
dataType: 'json',
|
|
data: {
|
|
product_id: product_id,
|
|
campaign_mode: campaign_mode,
|
|
campaign_id: campaign_id,
|
|
campaign_name: campaign_name,
|
|
campaign_daily_budget: campaign_daily_budget,
|
|
default_cpc: default_cpc,
|
|
ad_group_mode: ad_group_mode,
|
|
ad_group_id: ad_group_id,
|
|
ad_group_name: ad_group_name
|
|
},
|
|
success: function( res ) {
|
|
jc.hideLoading();
|
|
|
|
if ( res && res.status === 'ok' )
|
|
{
|
|
jc.close();
|
|
reload_products_table();
|
|
show_toast( 'Produkt został przypisany do kampanii i grupy reklam.', 'success' );
|
|
}
|
|
else
|
|
{
|
|
show_toast( ( res && res.message ) ? res.message : 'Nie udało się zapisać przypisania.', 'error' );
|
|
}
|
|
},
|
|
error: function() {
|
|
jc.hideLoading();
|
|
show_toast( 'Błąd połączenia podczas przypisywania produktu.', 'error' );
|
|
}
|
|
});
|
|
|
|
return false;
|
|
}
|
|
},
|
|
cancel: {
|
|
text: 'Anuluj'
|
|
}
|
|
},
|
|
onContentReady: function() {
|
|
var jc = this;
|
|
var $content = jc.$content;
|
|
var $campaignModeInputs = $content.find( 'input[name="campaign_mode"]' );
|
|
var $campaignSelect = $content.find( '.assign-campaign-id' );
|
|
var $campaignName = $content.find( '.assign-campaign-name' );
|
|
var $newCampaignOptions = $content.find( '.assign-new-campaign-options' );
|
|
|
|
var $adGroupModeInputs = $content.find( 'input[name="ad_group_mode"]' );
|
|
var $adGroupSelect = $content.find( '.assign-ad-group-id' );
|
|
var $adGroupName = $content.find( '.assign-ad-group-name' );
|
|
|
|
function loadCampaignsForStep()
|
|
{
|
|
$campaignSelect.empty().append( '<option value="">— wybierz kampanię —</option>' );
|
|
|
|
return $.ajax({
|
|
url: '/products/get_campaigns_list/client_id=' + client_id,
|
|
type: 'GET',
|
|
dataType: 'json'
|
|
}).done( function( res ) {
|
|
( res.campaigns || [] ).forEach( function( row ) {
|
|
$campaignSelect.append( '<option value="' + row.id + '">' + escape_html( row.campaign_name || '' ) + '</option>' );
|
|
} );
|
|
} );
|
|
}
|
|
|
|
function loadAdGroupsForStep( campaign_id )
|
|
{
|
|
$adGroupSelect.empty().append( '<option value="">— wybierz grupę reklam —</option>' );
|
|
|
|
if ( !campaign_id )
|
|
{
|
|
return;
|
|
}
|
|
|
|
$.ajax({
|
|
url: '/products/get_campaign_ad_groups/campaign_id=' + campaign_id,
|
|
type: 'GET',
|
|
dataType: 'json',
|
|
success: function( res ) {
|
|
( res.ad_groups || [] ).forEach( function( row ) {
|
|
$adGroupSelect.append( '<option value="' + row.id + '">' + escape_html( row.ad_group_name || '' ) + '</option>' );
|
|
} );
|
|
}
|
|
});
|
|
}
|
|
|
|
function toggleCampaignMode()
|
|
{
|
|
var mode = $campaignModeInputs.filter( ':checked' ).val();
|
|
var isExisting = mode === 'existing';
|
|
|
|
$campaignSelect.toggle( isExisting );
|
|
$campaignName.toggle( !isExisting );
|
|
$newCampaignOptions.toggle( !isExisting );
|
|
|
|
if ( isExisting )
|
|
{
|
|
$adGroupModeInputs.filter( '[value="existing"]' ).prop( 'disabled', false );
|
|
loadAdGroupsForStep( $campaignSelect.val() || '' );
|
|
}
|
|
else
|
|
{
|
|
$adGroupModeInputs.filter( '[value="existing"]' ).prop( 'disabled', true );
|
|
$adGroupModeInputs.filter( '[value="new"]' ).prop( 'checked', true );
|
|
$adGroupSelect.empty().append( '<option value="">— wybierz grupę reklam —</option>' );
|
|
}
|
|
|
|
toggleAdGroupMode();
|
|
}
|
|
|
|
function toggleAdGroupMode()
|
|
{
|
|
var mode = $adGroupModeInputs.filter( ':checked' ).val();
|
|
var isExisting = mode === 'existing';
|
|
|
|
$adGroupSelect.toggle( isExisting );
|
|
$adGroupName.toggle( !isExisting );
|
|
}
|
|
|
|
$campaignModeInputs.on( 'change', toggleCampaignMode );
|
|
$adGroupModeInputs.on( 'change', toggleAdGroupMode );
|
|
|
|
$campaignSelect.on( 'change', function() {
|
|
if ( $campaignModeInputs.filter( ':checked' ).val() === 'existing' )
|
|
{
|
|
loadAdGroupsForStep( $( this ).val() || '' );
|
|
}
|
|
} );
|
|
|
|
loadCampaignsForStep().always( function() {
|
|
toggleCampaignMode();
|
|
} );
|
|
}
|
|
});
|
|
});
|
|
|
|
$( 'body' ).on( 'change', '#client_id', function()
|
|
{
|
|
var client_id = $( this ).val() || '';
|
|
localStorage.setItem( 'products_client_id', client_id );
|
|
localStorage.removeItem( 'products_campaign_id' );
|
|
localStorage.removeItem( 'products_ad_group_id' );
|
|
localStorage.removeItem( 'products_search' );
|
|
localStorage.removeItem( 'products_cl4' );
|
|
$( '#products_search' ).val( '' );
|
|
$( '#products_cl4' ).val( '' );
|
|
update_delete_ad_group_button_state();
|
|
|
|
load_products_campaigns( client_id, '' ).done( function() {
|
|
load_products_ad_groups( '', '' ).done( function() {
|
|
update_delete_ad_group_button_state();
|
|
$.when( load_scope_alerts(), load_zero_impressions_products() ).always( function() {
|
|
reload_products_table();
|
|
} );
|
|
} );
|
|
} );
|
|
});
|
|
|
|
$( 'body' ).on( 'change', '#products_campaign_id', function()
|
|
{
|
|
var campaign_id = $( this ).val() || '';
|
|
localStorage.setItem( 'products_campaign_id', campaign_id );
|
|
localStorage.removeItem( 'products_ad_group_id' );
|
|
update_delete_ad_group_button_state();
|
|
|
|
load_products_ad_groups( campaign_id, '' ).done( function() {
|
|
$.when( load_scope_alerts(), load_zero_impressions_products() ).always( function() {
|
|
reload_products_table();
|
|
} );
|
|
} );
|
|
});
|
|
|
|
$( 'body' ).on( 'change', '#products_ad_group_id', function()
|
|
{
|
|
var ad_group_id = $( this ).val() || '';
|
|
localStorage.setItem( 'products_ad_group_id', ad_group_id );
|
|
update_delete_ad_group_button_state();
|
|
$.when( load_scope_alerts(), load_zero_impressions_products() ).always( function() {
|
|
reload_products_table();
|
|
} );
|
|
});
|
|
|
|
$( 'body' ).on( 'click', '#delete-products-ad-group', function( e )
|
|
{
|
|
e.preventDefault();
|
|
|
|
var campaign_id = $( '#products_campaign_id' ).val() || '';
|
|
var ad_group_id = $( '#products_ad_group_id' ).val() || '';
|
|
var campaign_channel_type = get_selected_products_campaign_channel_type();
|
|
|
|
if ( campaign_channel_type !== 'SHOPPING' )
|
|
{
|
|
$.alert({
|
|
title: 'Niedostepne',
|
|
content: 'Usuwanie grup reklam jest dostepne tylko dla kampanii produktowych (Shopping).',
|
|
type: 'orange'
|
|
});
|
|
return;
|
|
}
|
|
|
|
if ( !campaign_id || !ad_group_id )
|
|
{
|
|
$.alert({
|
|
title: 'Brak wyboru',
|
|
content: 'Wybierz kampanie i grupe reklam do usuniecia.',
|
|
type: 'orange'
|
|
});
|
|
return;
|
|
}
|
|
|
|
var ad_group_name = $.trim( $( '#products_ad_group_id option:selected' ).text() || '' );
|
|
var campaign_name = $.trim( $( '#products_campaign_id option:selected' ).text() || '' );
|
|
|
|
$.confirm({
|
|
title: 'Usuwanie grupy reklam',
|
|
content:
|
|
'Jak chcesz usunac grupe reklam <strong>' + escape_html( ad_group_name ) + '</strong> z kampanii <strong>' + escape_html( campaign_name ) + '</strong>?'
|
|
+ '<br><br><small>Opcja API usunie grupe reklam rowniez w Google Ads.</small>',
|
|
type: 'red',
|
|
buttons: {
|
|
local: {
|
|
text: 'Tylko lokalnie',
|
|
btnClass: 'btn-default',
|
|
action: function()
|
|
{
|
|
var modal = this;
|
|
submit_delete_campaign_ad_group( campaign_id, ad_group_id, 'local', function()
|
|
{
|
|
modal.close();
|
|
} );
|
|
return false;
|
|
}
|
|
},
|
|
google: {
|
|
text: 'Lokalnie + Google Ads',
|
|
btnClass: 'btn-red',
|
|
action: function()
|
|
{
|
|
var modal = this;
|
|
submit_delete_campaign_ad_group( campaign_id, ad_group_id, 'google', function()
|
|
{
|
|
modal.close();
|
|
} );
|
|
return false;
|
|
}
|
|
},
|
|
cancel: {
|
|
text: 'Anuluj'
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
var savedClient = localStorage.getItem( 'products_client_id' ) || '';
|
|
var savedCampaign = localStorage.getItem( 'products_campaign_id' ) || '';
|
|
var savedAdGroup = localStorage.getItem( 'products_ad_group_id' ) || '';
|
|
var savedSearch = localStorage.getItem( 'products_search' ) || '';
|
|
var savedCl4 = localStorage.getItem( 'products_cl4' ) || '';
|
|
|
|
if ( savedClient && $( '#client_id option[value="' + savedClient + '"]' ).length )
|
|
{
|
|
$( '#client_id' ).val( savedClient );
|
|
}
|
|
|
|
$( '#products_search' ).val( savedSearch );
|
|
$( '#products_cl4' ).val( savedCl4 );
|
|
|
|
load_cl4_suggestions( $( '#client_id' ).val() || '' );
|
|
|
|
load_products_campaigns( $( '#client_id' ).val() || '', savedCampaign ).done( function() {
|
|
var selected_campaign_id = $( '#products_campaign_id' ).val() || '';
|
|
load_products_ad_groups( selected_campaign_id, savedAdGroup ).done( function() {
|
|
update_delete_ad_group_button_state();
|
|
$.when( load_scope_alerts(), load_zero_impressions_products() ).always( function() {
|
|
reload_products_table();
|
|
} );
|
|
} );
|
|
});
|
|
|
|
$( 'body' ).on( 'click', '.view-merchant-logs', function( e )
|
|
{
|
|
e.preventDefault();
|
|
|
|
var product_id = $( this ).attr( 'product_id' );
|
|
|
|
$.confirm({
|
|
title: 'Logi zmian produktu',
|
|
content: '<div class="merchant-logs-wrap" style="max-height:460px;overflow:auto">Ładowanie logów...</div>',
|
|
useBootstrap: false,
|
|
boxWidth: '1100px',
|
|
theme: 'modern',
|
|
buttons: {
|
|
close: {
|
|
text: 'Zamknij',
|
|
btnClass: 'btn-blue'
|
|
}
|
|
},
|
|
onContentReady: function()
|
|
{
|
|
var jc = this;
|
|
var $wrap = jc.$content.find( '.merchant-logs-wrap' );
|
|
|
|
function load_logs()
|
|
{
|
|
$wrap.html( 'Ładowanie logów...' );
|
|
|
|
$.ajax({
|
|
url: '/products/get_product_merchant_sync_logs/',
|
|
type: 'POST',
|
|
data: { product_id: product_id, limit: 100 },
|
|
success: function( response )
|
|
{
|
|
var data;
|
|
|
|
try
|
|
{
|
|
data = JSON.parse( response );
|
|
}
|
|
catch ( err )
|
|
{
|
|
$wrap.html( '<div class="text-danger">Nie udało się odczytać odpowiedzi serwera.</div>' );
|
|
return;
|
|
}
|
|
|
|
if ( data.status !== 'ok' )
|
|
{
|
|
$wrap.html( '<div class="text-danger">' + escape_html( data.message || 'Błąd pobierania logów.' ) + '</div>' );
|
|
return;
|
|
}
|
|
|
|
if ( !data.logs || !data.logs.length )
|
|
{
|
|
$wrap.html( '<div class="text-muted">Brak logów dla tego produktu.</div>' );
|
|
return;
|
|
}
|
|
|
|
var rows_html = '';
|
|
$.each( data.logs, function( _, log ) {
|
|
var status_class = log.sync_status === 'success'
|
|
? 'text-success'
|
|
: ( log.sync_status === 'error' ? 'text-danger' : 'text-muted' );
|
|
|
|
rows_html += '<tr>' +
|
|
'<td>' + escape_html( log.date_add || '' ) + '</td>' +
|
|
'<td>' + escape_html( log.field_name || '' ) + '</td>' +
|
|
'<td class="' + status_class + '"><b>' + escape_html( log.sync_status || '' ) + '</b></td>' +
|
|
'<td>' + escape_html( log.sync_source || '' ) + '</td>' +
|
|
'<td>' + escape_html( log.old_value || '' ) + '</td>' +
|
|
'<td>' + escape_html( log.new_value || '' ) + '</td>' +
|
|
'<td class="text-center"><button type="button" class="btn btn-sm btn-danger delete-merchant-log" data-log-id="' + log.id + '" title="Usuń log"><i class="fa fa-trash"></i></button></td>' +
|
|
'</tr>';
|
|
} );
|
|
|
|
$wrap.html(
|
|
'<table class="table table-sm table-bordered table-striped" style="font-size:12px;">' +
|
|
'<thead>' +
|
|
'<tr>' +
|
|
'<th style="min-width:140px;">Data</th>' +
|
|
'<th style="min-width:120px;">Pole</th>' +
|
|
'<th style="min-width:90px;">Status</th>' +
|
|
'<th style="min-width:110px;">Źródło</th>' +
|
|
'<th style="min-width:180px;">Stara wartość</th>' +
|
|
'<th style="min-width:180px;">Nowa wartość</th>' +
|
|
'<th style="width:60px;"></th>' +
|
|
'</tr>' +
|
|
'</thead>' +
|
|
'<tbody>' + rows_html + '</tbody>' +
|
|
'</table>'
|
|
);
|
|
},
|
|
error: function()
|
|
{
|
|
$wrap.html( '<div class="text-danger">Nie udało się pobrać logów.</div>' );
|
|
}
|
|
});
|
|
}
|
|
|
|
load_logs();
|
|
|
|
$wrap.on( 'click', '.delete-merchant-log', function()
|
|
{
|
|
var $btn = $( this );
|
|
var log_id = $btn.data( 'log-id' );
|
|
|
|
$btn.prop( 'disabled', true );
|
|
|
|
$.ajax({
|
|
url: '/products/delete_product_merchant_sync_log/',
|
|
type: 'POST',
|
|
data: { log_id: log_id },
|
|
success: function( response )
|
|
{
|
|
var data;
|
|
|
|
try { data = JSON.parse( response ); } catch( e ) { return; }
|
|
|
|
if ( data.status === 'ok' )
|
|
{
|
|
load_logs();
|
|
}
|
|
else
|
|
{
|
|
$btn.prop( 'disabled', false );
|
|
}
|
|
},
|
|
error: function()
|
|
{
|
|
$btn.prop( 'disabled', false );
|
|
}
|
|
});
|
|
});
|
|
}
|
|
});
|
|
});
|
|
|
|
// Usuwanie produktu
|
|
$( 'body' ).on( 'click', '.delete-product', function( e )
|
|
{
|
|
e.preventDefault();
|
|
var product_id = $( this ).attr( 'product_id' );
|
|
var row = $( this ).closest( 'tr' );
|
|
|
|
$.confirm({
|
|
title: 'Potwierdzenie',
|
|
content: 'Czy na pewno chcesz usunąć ten produkt?',
|
|
type: 'red',
|
|
buttons: {
|
|
confirm: {
|
|
text: 'Usuń',
|
|
btnClass: 'btn-red',
|
|
keys: ['enter'],
|
|
action: function() {
|
|
$.ajax({
|
|
url: '/products/delete_product/',
|
|
type: 'POST',
|
|
data: { product_id: product_id },
|
|
success: function( response ) {
|
|
data = JSON.parse( response );
|
|
if ( data.status == 'ok' ) {
|
|
$.alert({
|
|
title: 'Sukces',
|
|
content: 'Produkt został usunięty.',
|
|
type: 'green',
|
|
autoClose: 'ok|2000',
|
|
buttons: { ok: function() {} }
|
|
});
|
|
var table = $( '#products' ).DataTable();
|
|
table.row( row ).remove().draw( false );
|
|
} else {
|
|
$.alert({ title: 'Błąd', content: response, type: 'red' });
|
|
}
|
|
},
|
|
error: function() {
|
|
$.alert({ title: 'Błąd', content: 'Wystąpił błąd podczas usuwania produktu.', type: 'red' });
|
|
}
|
|
});
|
|
}
|
|
},
|
|
cancel: { text: 'Anuluj' }
|
|
}
|
|
});
|
|
});
|
|
|
|
// Zapis min ROAS produktu
|
|
$( 'body' ).on( 'change', '.min_roas', function()
|
|
{
|
|
var product_id = $( this ).attr( 'product_id' );
|
|
var min_roas = $( this ).val();
|
|
$.ajax({
|
|
url: '/products/save_min_roas/',
|
|
type: 'POST',
|
|
data: { product_id: product_id, min_roas: min_roas }
|
|
});
|
|
});
|
|
|
|
// CL4 autocomplete — datalist z unikalnymi wartościami
|
|
var cl4_values_cache = [];
|
|
var cl4_datalist_id = 'cl4-suggestions';
|
|
|
|
function load_cl4_suggestions( client_id )
|
|
{
|
|
if ( !client_id )
|
|
{
|
|
cl4_values_cache = [];
|
|
return;
|
|
}
|
|
|
|
$.ajax({
|
|
url: '/products/get_distinct_cl4/client_id=' + client_id,
|
|
type: 'GET',
|
|
dataType: 'json'
|
|
}).done( function( res ) {
|
|
cl4_values_cache = ( res && res.values ) ? res.values : [];
|
|
render_cl4_datalist();
|
|
});
|
|
}
|
|
|
|
function render_cl4_datalist()
|
|
{
|
|
var $dl = $( '#' + cl4_datalist_id );
|
|
|
|
if ( !$dl.length )
|
|
{
|
|
$dl = $( '<datalist id="' + cl4_datalist_id + '"></datalist>' );
|
|
$( 'body' ).append( $dl );
|
|
}
|
|
|
|
var html = '';
|
|
|
|
for ( var i = 0; i < cl4_values_cache.length; i++ )
|
|
{
|
|
html += '<option value="' + escape_html( cl4_values_cache[i] ) + '">';
|
|
}
|
|
|
|
$dl.html( html );
|
|
}
|
|
|
|
function bind_cl4_datalist()
|
|
{
|
|
$( '.custom_label_4' ).attr( 'list', cl4_datalist_id );
|
|
}
|
|
|
|
// Podłącz datalist po każdym renderze tabeli
|
|
$( '#products' ).on( 'draw.dt', function() {
|
|
bind_cl4_datalist();
|
|
});
|
|
|
|
// Załaduj sugestie po zmianie klienta
|
|
$( 'body' ).on( 'change', '#client_id', function() {
|
|
load_cl4_suggestions( $( this ).val() || '' );
|
|
});
|
|
|
|
// Odśwież cache po zapisie CL4
|
|
function refresh_cl4_cache_after_save()
|
|
{
|
|
var client_id = $( '#client_id' ).val() || '';
|
|
if ( client_id )
|
|
{
|
|
load_cl4_suggestions( client_id );
|
|
}
|
|
}
|
|
|
|
// Zapis custom_label_4
|
|
$( 'body' ).on( 'change', '.custom_label_4', function()
|
|
{
|
|
var product_id = $( this ).attr( 'product_id' );
|
|
var custom_label_4 = $( this ).val();
|
|
$.ajax({
|
|
url: '/products/save_custom_label_4/',
|
|
type: 'POST',
|
|
data: { product_id: product_id, custom_label_4: custom_label_4 },
|
|
success: function( response )
|
|
{
|
|
var data;
|
|
|
|
try
|
|
{
|
|
data = JSON.parse( response );
|
|
}
|
|
catch ( e )
|
|
{
|
|
show_toast( 'Custom Label 4: nieprawidłowa odpowiedź serwera.', 'error' );
|
|
return;
|
|
}
|
|
|
|
if ( data.status === 'ok' )
|
|
{
|
|
show_toast( 'Custom Label 4 zapisany.', 'success' );
|
|
refresh_cl4_cache_after_save();
|
|
}
|
|
else
|
|
{
|
|
show_toast( 'Custom Label 4: zapis nie powiódł się.', 'error' );
|
|
}
|
|
},
|
|
error: function()
|
|
{
|
|
show_toast( 'Custom Label 4: błąd połączenia podczas zapisu.', 'error' );
|
|
}
|
|
});
|
|
});
|
|
|
|
// Edycja produktu (tytuł, opis, kategoria Google)
|
|
$( 'body' ).on( 'click', '.edit-product-title', function( e )
|
|
{
|
|
var current_product_name = $.trim( $( this ).closest( '.table-product-title' ).find( 'a' ).text() );
|
|
|
|
$.confirm({
|
|
title: 'Edytuj produkt',
|
|
content: '' +
|
|
'<form action="" class="formName">' +
|
|
'<div class="form-group">' +
|
|
'<label>Tytuł produktu <small class="text-muted" style="font-weight:normal">— ' + escape_html( current_product_name ) + '</small></label>' +
|
|
'<div class="input-with-ai">' +
|
|
'<input type="text" value="" product_id="' + $( this ).attr( 'product_id' ) + '" placeholder="Tytuł produktu" class="name form-control" required />' +
|
|
( AI_OPENAI_ENABLED ? '<button type="button" class="btn btn-sm btn-ai-suggest" data-field="title" data-provider="openai" title="Zaproponuj tytuł przez ChatGPT"><i class="fa-solid fa-wand-magic-sparkles"></i> GPT</button>' : '' ) +
|
|
( AI_CLAUDE_ENABLED ? '<button type="button" class="btn btn-sm btn-ai-suggest btn-ai-claude" data-field="title" data-provider="claude" title="Zaproponuj tytuł przez Claude"><i class="fa-solid fa-brain"></i> Claude</button>' : '' ) +
|
|
( AI_GEMINI_ENABLED ? '<button type="button" class="btn btn-sm btn-ai-suggest btn-ai-gemini" data-field="title" data-provider="gemini" title="Zaproponuj tytuł przez Gemini"><i class="fa-solid fa-diamond"></i> Gemini</button>' : '' ) +
|
|
'</div>' +
|
|
'<div class="original-title-row" style="display:flex;align-items:center;gap:8px;margin-top:6px;">' +
|
|
'<small class="text-muted">Oryginalny tytul:</small>' +
|
|
'<small class="js-original-product-title" style="flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;" title="' + escape_html( current_product_name ) + '">' + escape_html( current_product_name ) + '</small>' +
|
|
'<button type="button" class="btn btn-xs btn-default js-copy-original-title" title="Kopiuj oryginalny tytul" aria-label="Kopiuj oryginalny tytul">' +
|
|
'<i class="fa-regular fa-copy"></i>' +
|
|
'</button>' +
|
|
'</div>' +
|
|
'<div class="title-ai-alternatives" style="margin-top:8px;display:none;"></div>' +
|
|
'</div>' +
|
|
'<div class="form-group">' +
|
|
'<label>URL strony produktu <small class="text-muted">(opcjonalnie, dla lepszego kontekstu AI)</small></label>' +
|
|
'<input type="url" class="form-control product-url" placeholder="https://sklep.pl/produkt/..." />' +
|
|
'</div>' +
|
|
'<div class="form-group">' +
|
|
'<div class="desc-header">' +
|
|
'<label>Opis produktu</label>' +
|
|
'<div class="desc-tabs">' +
|
|
'<button type="button" class="desc-tab active" data-tab="edit"><i class="fa-solid fa-code"></i> Edycja</button>' +
|
|
'<button type="button" class="desc-tab" data-tab="preview"><i class="fa-solid fa-eye"></i> Podgląd</button>' +
|
|
'</div>' +
|
|
'</div>' +
|
|
'<div class="input-with-ai">' +
|
|
'<div class="desc-wrap">' +
|
|
'<textarea class="form-control description" style="height:220px;resize:vertical" placeholder="Opis produktu (opcjonalnie)"></textarea>' +
|
|
'<div class="desc-preview" style="display:none;height:220px;overflow-y:auto;padding:10px 12px;border:1px solid #ddd;border-radius:4px;background:#fff;font-size:13px;line-height:1.6"></div>' +
|
|
'</div>' +
|
|
( AI_OPENAI_ENABLED ? '<button type="button" class="btn btn-sm btn-ai-suggest" data-field="description" data-provider="openai" title="Zaproponuj opis przez ChatGPT"><i class="fa-solid fa-wand-magic-sparkles"></i> GPT</button>' : '' ) +
|
|
( AI_CLAUDE_ENABLED ? '<button type="button" class="btn btn-sm btn-ai-suggest btn-ai-claude" data-field="description" data-provider="claude" title="Zaproponuj opis przez Claude"><i class="fa-solid fa-brain"></i> Claude</button>' : '' ) +
|
|
( AI_GEMINI_ENABLED ? '<button type="button" class="btn btn-sm btn-ai-suggest btn-ai-gemini" data-field="description" data-provider="gemini" title="Zaproponuj opis przez Gemini"><i class="fa-solid fa-diamond"></i> Gemini</button>' : '' ) +
|
|
'</div>' +
|
|
'</div>' +
|
|
'<div class="form-group">' +
|
|
'<label>Kategoria Google</label>' +
|
|
'<div class="input-with-ai">' +
|
|
'<select class="form-control google-category" id="google_category" style="width: calc(100% - 60px)">' +
|
|
'<option value="">— wybierz kategorię —</option>' +
|
|
'</select>' +
|
|
( AI_OPENAI_ENABLED ? '<button type="button" class="btn btn-sm btn-ai-suggest" data-field="category" data-provider="openai" title="Zaproponuj kategorię przez ChatGPT"><i class="fa-solid fa-wand-magic-sparkles"></i> GPT</button>' : '' ) +
|
|
( AI_CLAUDE_ENABLED ? '<button type="button" class="btn btn-sm btn-ai-suggest btn-ai-claude" data-field="category" data-provider="claude" title="Zaproponuj kategorię przez Claude"><i class="fa-solid fa-brain"></i> Claude</button>' : '' ) +
|
|
( AI_GEMINI_ENABLED ? '<button type="button" class="btn btn-sm btn-ai-suggest btn-ai-gemini" data-field="category" data-provider="gemini" title="Zaproponuj kategorię przez Gemini"><i class="fa-solid fa-diamond"></i> Gemini</button>' : '' ) +
|
|
'</div>' +
|
|
'</div>' +
|
|
'</form>',
|
|
useBootstrap: false,
|
|
boxWidth: '1280px',
|
|
theme: 'modern',
|
|
draggable: true,
|
|
buttons: {
|
|
formSubmit: {
|
|
text: 'Zapisz',
|
|
btnClass: 'btn-blue',
|
|
action: function() {
|
|
var jc = this;
|
|
var product_id = this.$content.find( '.name' ).attr( 'product_id' );
|
|
var customTitle = this.$content.find( '.name' ).val();
|
|
var googleProductCategory = this.$content.find( '.google-category' ).val();
|
|
|
|
if ( customTitle && customTitle.length > 150 ) {
|
|
$.alert( 'Pole tytuł nie może przekraczać 150 znaków!' );
|
|
this.$content.find( '.name' ).addClass( 'is-invalid' );
|
|
return false;
|
|
}
|
|
|
|
jc.showLoading( true );
|
|
|
|
$.ajax({
|
|
url: '/products/save_product_data/',
|
|
type: 'POST',
|
|
data: {
|
|
product_id: product_id,
|
|
custom_title: customTitle,
|
|
custom_description: this.$content.find( '.description' ).val(),
|
|
google_product_category: googleProductCategory,
|
|
product_url: this.$content.find( '.product-url' ).val()
|
|
},
|
|
success: function( response ) {
|
|
data = JSON.parse( response );
|
|
jc.hideLoading();
|
|
if ( data.status == 'ok' ) {
|
|
jc.close();
|
|
reload_products_table();
|
|
show_toast( 'Dane produktu zostały zapisane.', 'success' );
|
|
} else {
|
|
show_toast( 'Błąd: ' + response, 'error' );
|
|
}
|
|
},
|
|
error: function() {
|
|
jc.hideLoading();
|
|
show_toast( 'Wystąpił błąd podczas zapisywania. Spróbuj ponownie.', 'error' );
|
|
}
|
|
});
|
|
}
|
|
},
|
|
cancel: { text: 'Anuluj', btnClass: 'btn-red' }
|
|
},
|
|
onContentReady: function() {
|
|
var jc = this;
|
|
var $form = this.$content.find( 'form' );
|
|
var $inputField = this.$content.find( '.name' );
|
|
var $originalTitle = this.$content.find( '.js-original-product-title' );
|
|
var $description = this.$content.find( '.description' );
|
|
var $productUrl = this.$content.find( '.product-url' );
|
|
var $googleCategory = this.$content.find( '.google-category' );
|
|
var $titleAlternatives = this.$content.find( '.title-ai-alternatives' );
|
|
var originalProductName = current_product_name;
|
|
var product_id = $inputField.attr( 'product_id' );
|
|
|
|
function set_title_value( value ) {
|
|
value = String( value || '' );
|
|
$inputField.val( value );
|
|
var len = value.length;
|
|
$inputField.toggleClass( 'is-invalid', len > 150 );
|
|
}
|
|
|
|
function render_title_alternatives( bestTitle, candidates ) {
|
|
var current = $.trim( String( bestTitle || '' ) );
|
|
var seen = {};
|
|
var list = [];
|
|
|
|
( candidates || [] ).forEach( function( item ) {
|
|
var title = $.trim( String( item || '' ) );
|
|
if ( !title ) {
|
|
return;
|
|
}
|
|
|
|
var key = title.toLowerCase();
|
|
if ( key === current.toLowerCase() || seen[ key ] ) {
|
|
return;
|
|
}
|
|
|
|
seen[ key ] = true;
|
|
list.push( title );
|
|
} );
|
|
|
|
if ( !list.length ) {
|
|
$titleAlternatives.hide().empty();
|
|
return;
|
|
}
|
|
|
|
var html = '<div class="js-title-alts-list" style="margin-top:8px;"><small class="text-muted">Alternatywy:</small>';
|
|
|
|
list.forEach( function( title, idx ) {
|
|
html += '<div style="margin-top:4px;">'
|
|
+ '<button type="button" class="btn btn-xs btn-default js-title-alt-apply" data-title-alt="' + escape_html( title ) + '" style="width:100%;text-align:left;">'
|
|
+ ( idx + 1 ) + '. ' + escape_html( title )
|
|
+ '</button>'
|
|
+ '</div>';
|
|
} );
|
|
|
|
html += '</div>';
|
|
$titleAlternatives.html( html ).show();
|
|
}
|
|
|
|
$.ajax({
|
|
url: '/products/get_product_data/',
|
|
type: 'POST',
|
|
data: { product_id: product_id },
|
|
success: function( response ) {
|
|
var data = JSON.parse( response );
|
|
if ( data.status == 'ok' ) {
|
|
if ( data.product_details.name ) {
|
|
originalProductName = String( data.product_details.name );
|
|
$originalTitle.text( originalProductName ).attr( 'title', originalProductName );
|
|
}
|
|
if ( data.product_details.title ) {
|
|
set_title_value( data.product_details.title );
|
|
}
|
|
if ( data.product_details.description ) {
|
|
$description.val( data.product_details.description );
|
|
}
|
|
if ( data.product_details.product_url ) {
|
|
$productUrl.val( data.product_details.product_url );
|
|
}
|
|
jc.preselectedGoogleCategory = data.product_details.google_product_category || "";
|
|
}
|
|
}
|
|
});
|
|
|
|
loadGoogleCategories( function( cats ) {
|
|
jc.googleCategoriesData = cats;
|
|
if ( typeof $.fn.select2 !== 'undefined' ) {
|
|
$googleCategory.select2({
|
|
placeholder: 'Wpisz fragment nazwy kategorii...',
|
|
allowClear: true,
|
|
data: cats,
|
|
dropdownParent: jc.$content.closest( '.jconfirm-box' )
|
|
});
|
|
if ( jc.preselectedGoogleCategory ) {
|
|
$googleCategory.val( jc.preselectedGoogleCategory ).trigger( 'change' );
|
|
}
|
|
}
|
|
});
|
|
|
|
$inputField.on( 'input', function() {
|
|
var len = $( this ).val().length;
|
|
$( this ).toggleClass( 'is-invalid', len > 150 );
|
|
});
|
|
|
|
// Opis — przełączanie zakładek Edycja / Podgląd
|
|
var $descPreview = this.$content.find( '.desc-preview' );
|
|
this.$content.on( 'click', '.desc-tab', function() {
|
|
var tab = $( this ).data( 'tab' );
|
|
jc.$content.find( '.desc-tab' ).removeClass( 'active' );
|
|
$( this ).addClass( 'active' );
|
|
if ( tab === 'preview' ) {
|
|
$descPreview.html( $description.val() || '<span style="color:#999">Brak opisu</span>' ).show();
|
|
$description.hide();
|
|
} else {
|
|
$description.show();
|
|
$descPreview.hide();
|
|
}
|
|
});
|
|
|
|
// AI suggest buttons
|
|
this.$content.on( 'click', '.btn-ai-suggest', function() {
|
|
var $btn = $( this );
|
|
var field = $btn.data( 'field' );
|
|
var provider = $btn.data( 'provider' ) || 'openai';
|
|
var originalHtml = $btn.html();
|
|
var providerLabel = provider === 'claude' ? 'Claude' : ( provider === 'gemini' ? 'Gemini' : 'ChatGPT' );
|
|
|
|
$btn.prop( 'disabled', true ).html( '<i class="fa-solid fa-spinner fa-spin"></i>' );
|
|
|
|
$.ajax({
|
|
url: '/products/ai_suggest/',
|
|
type: 'POST',
|
|
data: { product_id: product_id, field: field, product_url: $productUrl.val(), provider: provider },
|
|
success: function( response ) {
|
|
var data = JSON.parse( response );
|
|
if ( data.status == 'ok' ) {
|
|
if ( field == 'title' ) {
|
|
set_title_value( data.suggestion );
|
|
render_title_alternatives( data.suggestion, data.title_candidates || [] );
|
|
} else if ( field == 'description' ) {
|
|
$description.val( data.suggestion );
|
|
} else if ( field == 'category' ) {
|
|
var catId = data.suggestion.trim();
|
|
if ( $googleCategory.find( 'option[value="' + catId + '"]' ).length ) {
|
|
$googleCategory.val( catId ).trigger( 'change' );
|
|
} else {
|
|
$.alert({ title: 'AI sugestia (' + providerLabel + ')', content: 'Sugerowana kategoria: ' + catId, type: 'blue' });
|
|
}
|
|
}
|
|
if ( data.warning ) {
|
|
show_toast( providerLabel + ': ' + data.warning, 'error' );
|
|
} else {
|
|
var successMessage = data.page_fetched
|
|
? providerLabel + ': Sugestia wygenerowana z treścią strony produktu'
|
|
: providerLabel + ': Sugestia wygenerowana';
|
|
|
|
if ( ( field == 'title' || field == 'description' ) && data.keyword_planner_terms_used ) {
|
|
var kwCount = parseInt( data.keyword_planner_terms_count || 0, 10 );
|
|
var kwLabel = kwCount > 0 ? ' (' + kwCount + ' fraz)' : '';
|
|
successMessage += '; użyto fraz z Keyword Planner' + kwLabel;
|
|
}
|
|
|
|
show_toast( successMessage, 'success' );
|
|
}
|
|
} else {
|
|
show_toast( providerLabel + ': ' + ( data.message || 'Wystąpił błąd AI.' ), 'error' );
|
|
}
|
|
},
|
|
error: function() {
|
|
$.alert({ title: 'Błąd', content: 'Nie udało się połączyć z API ' + providerLabel + '.', type: 'red' });
|
|
},
|
|
complete: function() {
|
|
$btn.prop( 'disabled', false ).html( originalHtml );
|
|
}
|
|
});
|
|
});
|
|
|
|
this.$content.on( 'click', '.js-title-alts-toggle', function() {
|
|
var $list = jc.$content.find( '.js-title-alts-list' );
|
|
$list.toggle();
|
|
|
|
$( this ).html(
|
|
$list.is( ':visible' )
|
|
? '<i class="fa-solid fa-eye-slash"></i> Ukryj alternatywy'
|
|
: '<i class="fa-solid fa-list"></i> Pokaż alternatywy (' + $list.find( '.js-title-alt-apply' ).length + ')'
|
|
);
|
|
} );
|
|
this.$content.on( 'click', '.js-title-alt-apply', function() {
|
|
var selectedTitle = $( this ).attr( 'data-title-alt' ) || '';
|
|
set_title_value( selectedTitle );
|
|
} );
|
|
|
|
this.$content.on( 'click', '.js-copy-original-title', function() {
|
|
var originalTitle = $.trim( String( originalProductName || '' ) );
|
|
|
|
if ( !originalTitle ) {
|
|
show_toast( 'Brak oryginalnego tytulu do skopiowania.', 'error' );
|
|
return;
|
|
}
|
|
|
|
if ( navigator.clipboard && typeof navigator.clipboard.writeText === 'function' ) {
|
|
navigator.clipboard.writeText( originalTitle )
|
|
.then( function() {
|
|
show_toast( 'Oryginalny tytul skopiowany.', 'success' );
|
|
} )
|
|
.catch( function() {
|
|
show_toast( 'Nie udalo sie skopiowac tytulu.', 'error' );
|
|
} );
|
|
return;
|
|
}
|
|
|
|
var $tmp = $( '<textarea>' ).css({
|
|
position: 'fixed',
|
|
opacity: 0,
|
|
pointerEvents: 'none'
|
|
}).val( originalTitle ).appendTo( 'body' );
|
|
|
|
$tmp.trigger( 'focus' );
|
|
$tmp.trigger( 'select' );
|
|
|
|
try {
|
|
var copied = document.execCommand( 'copy' );
|
|
show_toast( copied ? 'Oryginalny tytul skopiowany.' : 'Nie udalo sie skopiowac tytulu.', copied ? 'success' : 'error' );
|
|
} catch ( err ) {
|
|
show_toast( 'Nie udalo sie skopiowac tytulu.', 'error' );
|
|
}
|
|
|
|
$tmp.remove();
|
|
} );
|
|
|
|
$form.on( 'submit', function( e ) {
|
|
e.preventDefault();
|
|
jc.$$formSubmit.trigger( 'click' );
|
|
});
|
|
}
|
|
});
|
|
});
|
|
|
|
// Checkbox: zaznacz/odznacz wszystkie
|
|
function updateSelectedCount() {
|
|
var count = $( '.product-checkbox:checked' ).length;
|
|
$( '#selected-count' ).text( count );
|
|
$( '#delete-selected-products' ).prop( 'disabled', count === 0 );
|
|
}
|
|
|
|
$( 'body' ).on( 'change', '#select-all-products', function() {
|
|
$( '.product-checkbox' ).prop( 'checked', $( this ).is( ':checked' ) );
|
|
updateSelectedCount();
|
|
});
|
|
|
|
$( 'body' ).on( 'change', '.product-checkbox', function() {
|
|
updateSelectedCount();
|
|
var allChecked = $( '.product-checkbox' ).length === $( '.product-checkbox:checked' ).length;
|
|
$( '#select-all-products' ).prop( 'checked', allChecked );
|
|
});
|
|
|
|
$( '#products' ).on( 'draw.dt', function() {
|
|
$( '#select-all-products' ).prop( 'checked', false );
|
|
updateSelectedCount();
|
|
});
|
|
|
|
$( 'body' ).on( 'click', '.product-warning-icon', function()
|
|
{
|
|
var warnings = $( this ).data( 'warnings' ) || '';
|
|
if ( !warnings ) return;
|
|
|
|
var lines = String( warnings ).split( '\n' );
|
|
var html = '<ul style="text-align:left;padding-left:18px;margin:0;">';
|
|
for ( var i = 0; i < lines.length; i++ )
|
|
{
|
|
if ( $.trim( lines[i] ) !== '' )
|
|
html += '<li style="margin-bottom:6px;">' + $('<span>').text( lines[i] ).html() + '</li>';
|
|
}
|
|
html += '</ul>';
|
|
|
|
$.alert({
|
|
title: 'Ostrzezenia produktu',
|
|
columnClass: 'col-md-5 col-md-offset-4',
|
|
content: html,
|
|
type: 'orange'
|
|
});
|
|
});
|
|
|
|
$( 'body' ).on( 'change', '.products-col-toggle', function()
|
|
{
|
|
var col_index = Number( $( this ).data( 'col-index' ) );
|
|
var is_visible = $( this ).is( ':checked' );
|
|
|
|
if ( !products_table || Number.isNaN( col_index ) || products_is_locked_column( col_index ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
products_table.column( col_index ).visible( is_visible, false );
|
|
products_table.columns.adjust().draw( false );
|
|
products_save_columns_visibility( products_table );
|
|
products_render_columns_picker( products_table );
|
|
});
|
|
|
|
// Usuwanie zaznaczonych produktów
|
|
$( 'body' ).on( 'click', '#delete-selected-products', function()
|
|
{
|
|
var selectedIds = [];
|
|
$( '.product-checkbox:checked' ).each( function() { selectedIds.push( $( this ).val() ); });
|
|
|
|
if ( selectedIds.length === 0 ) {
|
|
$.alert( 'Nie zaznaczono żadnych produktów.' );
|
|
return;
|
|
}
|
|
|
|
$.confirm({
|
|
title: 'Potwierdzenie',
|
|
content: 'Czy na pewno chcesz usunąć ' + selectedIds.length + ' zaznaczonych produktów?',
|
|
type: 'red',
|
|
buttons: {
|
|
confirm: {
|
|
text: 'Usuń',
|
|
btnClass: 'btn-red',
|
|
keys: ['enter'],
|
|
action: function() {
|
|
$.ajax({
|
|
url: '/products/delete_products/',
|
|
type: 'POST',
|
|
data: { product_ids: selectedIds },
|
|
success: function( response ) {
|
|
var data = JSON.parse( response );
|
|
if ( data.status == 'ok' ) {
|
|
$.alert({
|
|
title: 'Sukces',
|
|
content: 'Usunięto ' + selectedIds.length + ' produktów.',
|
|
type: 'green',
|
|
autoClose: 'ok|2000',
|
|
buttons: { ok: function() {} }
|
|
});
|
|
$( '#products' ).DataTable().ajax.reload( null, false );
|
|
}
|
|
}
|
|
});
|
|
}
|
|
},
|
|
cancel: { text: 'Anuluj' }
|
|
}
|
|
});
|
|
});
|
|
});
|
|
</script>
|
|
|
|
|
|
|
|
|