- Changed font from Open Sans to Roboto in layout files. - Added campaign and ad group filters in products main view. - Enhanced product history to include campaign and ad group IDs. - Updated migrations to support new campaign and ad group dimensions in product statistics. - Introduced new migration files for managing campaign types and dropping obsolete columns.
702 lines
26 KiB
PHP
702 lines
26 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>
|
||
<select id="products_ad_group_id" name="products_ad_group_id" class="form-control">
|
||
<option value="">- wszystkie grupy -</option>
|
||
</select>
|
||
</div>
|
||
<div class="filter-group filter-group-roas">
|
||
<label for="bestseller_min_roas"><i class="fa-solid fa-star"></i> Bestseller min ROAS</label>
|
||
<input type="text" id="bestseller_min_roas" name="bestseller_min_roas" class="form-control" placeholder="np. 500" value="" />
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 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>Nazwa produktu</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';
|
||
?>
|
||
<script type="text/javascript">
|
||
var AI_OPENAI_ENABLED = <?= $openai_enabled ? 'true' : 'false'; ?>;
|
||
var AI_CLAUDE_ENABLED = <?= $claude_enabled ? 'true' : 'false'; ?>;
|
||
|
||
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 );
|
||
}
|
||
|
||
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()
|
||
{
|
||
var products_table = new DataTable( '#products', {
|
||
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() || '';
|
||
}
|
||
},
|
||
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' },
|
||
{ name: 'name' },
|
||
{ 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: '50px', orderable: false, className: 'dt-center' }
|
||
],
|
||
order: [ [ 8, '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'
|
||
}
|
||
}
|
||
});
|
||
|
||
function reload_products_table()
|
||
{
|
||
products_table.ajax.reload( null, false );
|
||
}
|
||
|
||
function load_client_bestseller_min_roas( client_id )
|
||
{
|
||
if ( !client_id )
|
||
{
|
||
$( '#bestseller_min_roas' ).val( '' );
|
||
return;
|
||
}
|
||
|
||
$.ajax({
|
||
url: '/products/get_client_bestseller_min_roas/',
|
||
type: 'POST',
|
||
data: { client_id: client_id },
|
||
success: function( response ) {
|
||
var data = JSON.parse( response );
|
||
$( '#bestseller_min_roas' ).val( data.status == 'ok' ? data.min_roas : '' );
|
||
}
|
||
});
|
||
}
|
||
|
||
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 ) {
|
||
$campaign.append( '<option value="' + row.id + '">' + row.campaign_name + '</option>' );
|
||
} );
|
||
|
||
if ( selected_campaign_id && $campaign.find( 'option[value="' + selected_campaign_id + '"]' ).length )
|
||
{
|
||
$campaign.val( selected_campaign_id );
|
||
}
|
||
} );
|
||
}
|
||
|
||
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 )
|
||
{
|
||
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 );
|
||
}
|
||
} );
|
||
}
|
||
|
||
$( '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' );
|
||
|
||
load_client_bestseller_min_roas( client_id );
|
||
load_products_campaigns( client_id, '' ).done( function() {
|
||
load_products_ad_groups( '', '' ).done( 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' );
|
||
|
||
load_products_ad_groups( campaign_id, '' ).done( 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 );
|
||
reload_products_table();
|
||
});
|
||
|
||
var savedClient = localStorage.getItem( 'products_client_id' ) || '';
|
||
var savedCampaign = localStorage.getItem( 'products_campaign_id' ) || '';
|
||
var savedAdGroup = localStorage.getItem( 'products_ad_group_id' ) || '';
|
||
|
||
if ( savedClient && $( '#client_id option[value="' + savedClient + '"]' ).length )
|
||
{
|
||
$( '#client_id' ).val( savedClient );
|
||
}
|
||
|
||
load_client_bestseller_min_roas( $( '#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() {
|
||
reload_products_table();
|
||
} );
|
||
});
|
||
|
||
// 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 }
|
||
});
|
||
});
|
||
|
||
// 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 }
|
||
});
|
||
});
|
||
|
||
// Edycja produktu (tytuł, opis, kategoria Google)
|
||
$( 'body' ).on( 'click', '.edit-product-title', function( e )
|
||
{
|
||
$.confirm({
|
||
title: 'Edytuj produkt',
|
||
content: '' +
|
||
'<form action="" class="formName">' +
|
||
'<div class="form-group">' +
|
||
'<label>Tytuł produktu</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>' : '' ) +
|
||
'</div>' +
|
||
'<small>0/150 znaków</small>' +
|
||
'</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>' : '' ) +
|
||
'</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>' : '' ) +
|
||
'</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();
|
||
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 $charCount = this.$content.find( 'small' ).first();
|
||
var $description = this.$content.find( '.description' );
|
||
var $productUrl = this.$content.find( '.product-url' );
|
||
var $googleCategory = this.$content.find( '.google-category' );
|
||
var product_id = $inputField.attr( 'product_id' );
|
||
|
||
$.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.title ) {
|
||
$inputField.val( data.product_details.title );
|
||
$charCount.text( data.product_details.title.length + '/150 znaków' );
|
||
}
|
||
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;
|
||
$charCount.text( len + '/150 znaków' );
|
||
$( 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' : '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' ) {
|
||
$inputField.val( data.suggestion );
|
||
var len = data.suggestion.length;
|
||
$charCount.text( len + '/150 znaków' );
|
||
$inputField.toggleClass( 'is-invalid', len > 150 );
|
||
} 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 if ( data.page_fetched ) {
|
||
show_toast( providerLabel + ': Sugestia wygenerowana z treścią strony produktu', 'success' );
|
||
} else {
|
||
show_toast( providerLabel + ': Sugestia wygenerowana', '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 );
|
||
}
|
||
});
|
||
});
|
||
|
||
$form.on( 'submit', function( e ) {
|
||
e.preventDefault();
|
||
jc.$$formSubmit.trigger( 'click' );
|
||
});
|
||
}
|
||
});
|
||
});
|
||
|
||
// Zapis min ROAS klienta (bestseller)
|
||
$( 'body' ).on( 'blur', '#bestseller_min_roas', function()
|
||
{
|
||
var min_roas = $( this ).val();
|
||
var client_id = $( '#client_id' ).val();
|
||
|
||
$.ajax({
|
||
url: '/products/save_client_bestseller_min_roas/',
|
||
type: 'POST',
|
||
data: { client_id: client_id, min_roas: min_roas },
|
||
success: function( response ) {
|
||
data = JSON.parse( response );
|
||
if ( data.status == 'ok' ) {
|
||
$.alert({ title: 'Zapisano', content: 'Minimalny ROAS bestsellerów został zapisany.', type: 'green', autoClose: 'ok|2000', buttons: { ok: function() {} } });
|
||
}
|
||
}
|
||
});
|
||
});
|
||
|
||
// 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();
|
||
});
|
||
|
||
// 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>
|
||
|
||
|
||
|
||
|