| 1 |
<?php |
| 2 |
namespace SuperFrete_API\Admin; |
| 3 |
|
| 4 |
use SuperFrete_API\Http\Request; |
| 5 |
use SuperFrete_API\Helpers\Logger; |
| 6 |
if (!defined('ABSPATH')) { |
| 7 |
exit; // Segurança para evitar acesso direto |
| 8 |
} |
| 9 |
|
| 10 |
class SuperFrete_Settings { |
| 11 |
|
| 12 |
/** |
| 13 |
* Recupera as configurações antigas do plugin. |
| 14 |
*/ |
| 15 |
public static function get_legacy_settings() { |
| 16 |
return get_option('superfrete-calculator-setting', []); |
| 17 |
} |
| 18 |
|
| 19 |
/** |
| 20 |
* Inicializa as configurações do SuperFrete se ainda não existirem |
| 21 |
*/ |
| 22 |
public static function migrate_old_settings() { |
| 23 |
$legacy_settings = self::get_legacy_settings(); |
| 24 |
|
| 25 |
// Recupera as novas configurações |
| 26 |
$sandbox_enabled = get_option('superfrete_sandbox_mode', null); |
| 27 |
$token_production = get_option('superfrete_api_token', null); |
| 28 |
$token_sandbox = get_option('superfrete_api_token_sandbox', null); |
| 29 |
|
| 30 |
|
| 31 |
// Se os novos valores ainda não existem, usa os valores antigos e salva no banco de dados |
| 32 |
if (strlen($sandbox_enabled) < 1&& isset($legacy_settings['superfrete_sandbox_enabled'])) { |
| 33 |
update_option('superfrete_sandbox_mode', $legacy_settings['superfrete_sandbox_enabled'] ? 'yes' : 'no'); |
| 34 |
} |
| 35 |
|
| 36 |
if (strlen($token_production) < 1 && isset($legacy_settings['superfrete_api_token'])) { |
| 37 |
update_option('superfrete_api_token', $legacy_settings['superfrete_api_token']); |
| 38 |
} |
| 39 |
|
| 40 |
if (strlen($token_sandbox) < 1 && isset($legacy_settings['superfrete_api_token_sandbox'])) { |
| 41 |
update_option('superfrete_api_token_sandbox', $legacy_settings['superfrete_api_token_sandbox']); |
| 42 |
} |
| 43 |
|
| 44 |
// Auto-register webhooks for existing installations (migration from pre-OAuth to OAuth) |
| 45 |
$webhook_migrated = get_option('superfrete_webhook_migrated', 'no'); |
| 46 |
$webhook_registered = get_option('superfrete_webhook_registered', 'no'); |
| 47 |
|
| 48 |
if ($webhook_migrated !== 'yes' && $webhook_registered !== 'yes') { |
| 49 |
// Check if we have existing tokens (indicating this is an existing installation) |
| 50 |
$current_sandbox_mode = get_option('superfrete_sandbox_mode', 'no'); |
| 51 |
$current_token = ($current_sandbox_mode === 'yes') ? |
| 52 |
get_option('superfrete_api_token_sandbox') : |
| 53 |
get_option('superfrete_api_token'); |
| 54 |
|
| 55 |
if (!empty($current_token)) { |
| 56 |
Logger::log('SuperFrete', 'Migration: Found existing API token, attempting webhook auto-registration'); |
| 57 |
|
| 58 |
try { |
| 59 |
$request = new Request(); |
| 60 |
|
| 61 |
// Validate token first |
| 62 |
$user_response = $request->call_superfrete_api('/api/v0/user', 'GET', [], true); |
| 63 |
|
| 64 |
if ($user_response && isset($user_response['id'])) { |
| 65 |
Logger::log('SuperFrete', 'Migration: Token validated, registering webhook'); |
| 66 |
|
| 67 |
// Register webhook |
| 68 |
$webhook_url = rest_url('superfrete/v1/webhook'); |
| 69 |
$webhook_result = $request->register_webhook($webhook_url); |
| 70 |
|
| 71 |
if ($webhook_result) { |
| 72 |
update_option('superfrete_webhook_registered', 'yes'); |
| 73 |
update_option('superfrete_webhook_url', $webhook_url); |
| 74 |
Logger::log('SuperFrete', 'Migration: Webhook registered successfully: ' . wp_json_encode($webhook_result)); |
| 75 |
} else { |
| 76 |
Logger::log('SuperFrete', 'Migration: Webhook registration failed'); |
| 77 |
} |
| 78 |
} else { |
| 79 |
Logger::log('SuperFrete', 'Migration: Token validation failed, skipping webhook registration'); |
| 80 |
} |
| 81 |
} catch (Exception $e) { |
| 82 |
Logger::log('SuperFrete', 'Migration: Webhook registration error: ' . $e->getMessage()); |
| 83 |
// Don't break migration for webhook issues |
| 84 |
} catch (Error $e) { |
| 85 |
Logger::log('SuperFrete', 'Migration: Webhook registration fatal error: ' . $e->getMessage()); |
| 86 |
} |
| 87 |
|
| 88 |
// Mark migration as attempted regardless of success/failure |
| 89 |
update_option('superfrete_webhook_migrated', 'yes'); |
| 90 |
} else { |
| 91 |
Logger::log('SuperFrete', 'Migration: No existing token found, skipping webhook auto-registration'); |
| 92 |
// Mark as migrated since there's nothing to migrate |
| 93 |
update_option('superfrete_webhook_migrated', 'yes'); |
| 94 |
} |
| 95 |
} |
| 96 |
} |
| 97 |
|
| 98 |
/** |
| 99 |
* Adiciona a aba de configuração do SuperFrete no WooCommerce > Configurações > Entrega |
| 100 |
*/ |
| 101 |
public static function add_superfrete_settings($settings) { |
| 102 |
|
| 103 |
// Add custom field renderer for webhook status |
| 104 |
add_action('woocommerce_admin_field_superfrete_webhook_status', [__CLASS__, 'render_webhook_status_field']); |
| 105 |
|
| 106 |
// Add custom field renderer for preview |
| 107 |
add_action('woocommerce_admin_field_superfrete_preview', [__CLASS__, 'render_preview_field']); |
| 108 |
|
| 109 |
$request = new Request(); |
| 110 |
$response = $request->call_superfrete_api('/api/v0/user', 'GET', [], true); |
| 111 |
|
| 112 |
$is_connected = ($response && isset($response['id'])); |
| 113 |
$user_name = $is_connected ? $response['firstname'] . " " . $response['lastname'] : ''; |
| 114 |
|
| 115 |
// Check webhook status |
| 116 |
$webhook_status = self::get_webhook_status(); |
| 117 |
|
| 118 |
// Garante que as configurações antigas sejam migradas antes de exibir a página de configurações |
| 119 |
self::migrate_old_settings(); |
| 120 |
|
| 121 |
$settings[] = [ |
| 122 |
'title' => 'Configuração do SuperFrete', |
| 123 |
'type' => 'title', |
| 124 |
'desc' => 'Defina suas credenciais da SuperFrete.', |
| 125 |
'id' => 'superfrete_settings_section' |
| 126 |
]; |
| 127 |
|
| 128 |
if ($is_connected) { |
| 129 |
// Show connected status and reconnect option |
| 130 |
$settings[] = [ |
| 131 |
'type' => 'title', |
| 132 |
'title' => '� |
| 133 |
Conectado como: ' . $user_name, |
| 134 |
'id' => 'superfrete_connected_notice' |
| 135 |
]; |
| 136 |
|
| 137 |
$settings[] = [ |
| 138 |
'title' => 'Gerenciar Conexão', |
| 139 |
'desc' => 'Sua conta SuperFrete está conectada e funcionando.<br><br>' . |
| 140 |
'<button type="button" id="superfrete-oauth-btn" class="button" style="margin-top:15px; padding:6px 12px; background:#f0ad4e; color:white; text-decoration:none; border-radius:4px; border:none; cursor:pointer;" onclick="return confirm(\'Tem certeza que deseja reconectar? Isso irá substituir a conexão atual.\');">' . |
| 141 |
'Reconectar Integração' . |
| 142 |
'</button>' . |
| 143 |
'<div id="superfrete-oauth-status" style="margin-top:10px;"></div>', |
| 144 |
'id' => 'superfrete_oauth_reconnection', |
| 145 |
'type' => 'title', |
| 146 |
'desc_tip' => 'Use apenas se houver problemas com a conexão atual.', |
| 147 |
]; |
| 148 |
} else { |
| 149 |
// Show connection setup |
| 150 |
$settings[] = [ |
| 151 |
'type' => 'title', |
| 152 |
'title' => '❌ Não Conectado', |
| 153 |
'id' => 'superfrete_disconnected_notice' |
| 154 |
]; |
| 155 |
|
| 156 |
$settings[] = [ |
| 157 |
'title' => 'Conexão SuperFrete', |
| 158 |
'desc' => 'Conecte sua conta SuperFrete automaticamente via OAuth.<br><br>' . |
| 159 |
'<button type="button" id="superfrete-oauth-btn" class="button button-primary" style="margin-top:15px; padding:6px 12px; background:#0fae79; color:white; text-decoration:none; border-radius:4px; border:none; cursor:pointer;">' . |
| 160 |
'Conectar com SuperFrete' . |
| 161 |
'</button>' . |
| 162 |
'<div id="superfrete-oauth-status" style="margin-top:10px;"></div>', |
| 163 |
'id' => 'superfrete_oauth_connection', |
| 164 |
'type' => 'title', |
| 165 |
'desc_tip' => 'Use o botão acima para conectar sua conta SuperFrete de forma segura.', |
| 166 |
]; |
| 167 |
} |
| 168 |
|
| 169 |
$settings[] = [ |
| 170 |
'title' => 'Ativar Calculadora', |
| 171 |
'desc' => 'Habilitar calculadora de frete na página do produto', |
| 172 |
'id' => 'superfrete_enable_calculator', |
| 173 |
'type' => 'checkbox', |
| 174 |
'default' => 'yes', |
| 175 |
'desc_tip' => 'Ativar a calculadora de frete na página do produto.', |
| 176 |
]; |
| 177 |
|
| 178 |
$settings[] = [ |
| 179 |
'title' => 'Cálculo Automático', |
| 180 |
'desc' => 'Calcular frete automaticamente ao carregar a página do produto', |
| 181 |
'id' => 'superfrete_auto_calculation', |
| 182 |
'type' => 'checkbox', |
| 183 |
'default' => 'no', // Disabled by default for better performance |
| 184 |
'desc_tip' => 'Quando desabilitado, o frete só será calculado quando o usuário clicar no botão. Recomendado para melhor performance.', |
| 185 |
]; |
| 186 |
|
| 187 |
|
| 188 |
|
| 189 |
$settings[] = [ |
| 190 |
'type' => 'sectionend', |
| 191 |
'id' => 'superfrete_settings_section' |
| 192 |
]; |
| 193 |
|
| 194 |
// Visual Customization Section |
| 195 |
$settings[] = [ |
| 196 |
'title' => 'Personalização Visual', |
| 197 |
'type' => 'title', |
| 198 |
'desc' => 'Personalize as cores e aparência da calculadora de frete.<br><br>' . |
| 199 |
'<div style="margin: 15px 0; padding: 15px; background: #f9f9f9; border-radius: 5px;">' . |
| 200 |
'<strong>Presets de Tema:</strong><br>' . |
| 201 |
'<button type="button" id="superfrete-preset-light" class="button" style="margin: 5px 10px 5px 0;">🌞 Tema Claro</button>' . |
| 202 |
'<button type="button" id="superfrete-preset-dark" class="button" style="margin: 5px 10px 5px 0;">🌙 Tema Escuro</button>' . |
| 203 |
'<button type="button" id="superfrete-preset-auto" class="button" style="margin: 5px 0;">🎨 Auto-Detectar</button>' . |
| 204 |
'</div>', |
| 205 |
'id' => 'superfrete_visual_section' |
| 206 |
]; |
| 207 |
|
| 208 |
$settings[] = [ |
| 209 |
'title' => 'Pré-visualização', |
| 210 |
'desc' => 'Veja como a calculadora ficará com suas personalizações', |
| 211 |
'id' => 'superfrete_preview', |
| 212 |
'type' => 'superfrete_preview', |
| 213 |
]; |
| 214 |
|
| 215 |
$settings[] = [ |
| 216 |
'title' => 'Cor Principal', |
| 217 |
'desc' => 'Cor principal dos botões, preços e elementos interativos', |
| 218 |
'id' => 'superfrete_custom_primary_color', |
| 219 |
'type' => 'color', |
| 220 |
'default' => '#0fae79', |
| 221 |
'css' => 'width: 6em;', |
| 222 |
'desc_tip' => 'Usada para botões, preços, bordas de foco e elementos de destaque.', |
| 223 |
]; |
| 224 |
|
| 225 |
$settings[] = [ |
| 226 |
'title' => 'Cor de Erro', |
| 227 |
'desc' => 'Cor para mensagens de erro e alertas', |
| 228 |
'id' => 'superfrete_custom_error_color', |
| 229 |
'type' => 'color', |
| 230 |
'default' => '#e74c3c', |
| 231 |
'css' => 'width: 6em;', |
| 232 |
'desc_tip' => 'Usada para indicar erros e alertas.', |
| 233 |
]; |
| 234 |
|
| 235 |
$settings[] = [ |
| 236 |
'title' => 'Fundo da Calculadora', |
| 237 |
'desc' => 'Cor de fundo principal da calculadora', |
| 238 |
'id' => 'superfrete_custom_bg_color', |
| 239 |
'type' => 'color', |
| 240 |
'default' => '#ffffff', |
| 241 |
'css' => 'width: 6em;', |
| 242 |
'desc_tip' => 'Cor de fundo do container principal da calculadora.', |
| 243 |
]; |
| 244 |
|
| 245 |
$settings[] = [ |
| 246 |
'title' => 'Fundo dos Resultados', |
| 247 |
'desc' => 'Cor de fundo da área de resultados', |
| 248 |
'id' => 'superfrete_custom_results_bg_color', |
| 249 |
'type' => 'color', |
| 250 |
'default' => '#ffffff', |
| 251 |
'css' => 'width: 6em;', |
| 252 |
'desc_tip' => 'Cor de fundo onde são exibidos os métodos de envio.', |
| 253 |
]; |
| 254 |
|
| 255 |
$settings[] = [ |
| 256 |
'title' => 'Cor do Texto Principal', |
| 257 |
'desc' => 'Cor do texto principal e títulos', |
| 258 |
'id' => 'superfrete_custom_text_color', |
| 259 |
'type' => 'color', |
| 260 |
'default' => '#1a1a1a', |
| 261 |
'css' => 'width: 6em;', |
| 262 |
'desc_tip' => 'Cor do texto principal, títulos e labels.', |
| 263 |
]; |
| 264 |
|
| 265 |
$settings[] = [ |
| 266 |
'title' => 'Cor do Texto Secundário', |
| 267 |
'desc' => 'Cor do texto secundário e placeholders', |
| 268 |
'id' => 'superfrete_custom_text_light_color', |
| 269 |
'type' => 'color', |
| 270 |
'default' => '#777777', |
| 271 |
'css' => 'width: 6em;', |
| 272 |
'desc_tip' => 'Cor do texto secundário, placeholders e descrições.', |
| 273 |
]; |
| 274 |
|
| 275 |
$settings[] = [ |
| 276 |
'title' => 'Cor das Bordas', |
| 277 |
'desc' => 'Cor das bordas dos elementos', |
| 278 |
'id' => 'superfrete_custom_border_color', |
| 279 |
'type' => 'color', |
| 280 |
'default' => '#e0e0e0', |
| 281 |
'css' => 'width: 6em;', |
| 282 |
'desc_tip' => 'Cor das bordas dos campos de input e containers.', |
| 283 |
]; |
| 284 |
|
| 285 |
$settings[] = [ |
| 286 |
'title' => 'Tamanho da Fonte', |
| 287 |
'desc' => 'Tamanho base da fonte na calculadora', |
| 288 |
'id' => 'superfrete_custom_font_size', |
| 289 |
'type' => 'select', |
| 290 |
'default' => '14px', |
| 291 |
'options' => [ |
| 292 |
'12px' => 'Pequeno (12px)', |
| 293 |
'14px' => 'Médio (14px)', |
| 294 |
'16px' => 'Grande (16px)', |
| 295 |
'18px' => 'Muito Grande (18px)', |
| 296 |
], |
| 297 |
'desc_tip' => 'Ajuste o tamanho da fonte para melhor legibilidade.', |
| 298 |
]; |
| 299 |
|
| 300 |
$settings[] = [ |
| 301 |
'title' => 'Bordas Arredondadas', |
| 302 |
'desc' => 'Nível de arredondamento das bordas', |
| 303 |
'id' => 'superfrete_custom_border_radius', |
| 304 |
'type' => 'select', |
| 305 |
'default' => '4px', |
| 306 |
'options' => [ |
| 307 |
'0px' => 'Sem Arredondamento', |
| 308 |
'2px' => 'Pouco Arredondado', |
| 309 |
'4px' => 'Médio', |
| 310 |
'8px' => 'Muito Arredondado', |
| 311 |
'12px' => 'Extremamente Arredondado', |
| 312 |
], |
| 313 |
'desc_tip' => 'Ajuste o estilo das bordas dos elementos.', |
| 314 |
]; |
| 315 |
|
| 316 |
$settings[] = [ |
| 317 |
'title' => 'Resetar Personalização', |
| 318 |
'desc' => 'Voltar às configurações visuais padrão do SuperFrete', |
| 319 |
'id' => 'superfrete_reset_customization', |
| 320 |
'type' => 'button', |
| 321 |
'desc_tip' => 'Clique para restaurar todas as configurações visuais para os valores padrão.', |
| 322 |
'custom' => '<button type="button" id="superfrete-reset-customization" class="button button-secondary">Resetar para Padrão</button>', |
| 323 |
]; |
| 324 |
|
| 325 |
$settings[] = [ |
| 326 |
'type' => 'sectionend', |
| 327 |
'id' => 'superfrete_visual_section' |
| 328 |
]; |
| 329 |
|
| 330 |
// Advanced Configuration Section (Accordion) |
| 331 |
$settings[] = [ |
| 332 |
'title' => 'Configurações Avançadas', |
| 333 |
'type' => 'title', |
| 334 |
'desc' => '<div id="superfrete-advanced-toggle" style="cursor: pointer; padding: 10px; background: #f1f1f1; border: 1px solid #ddd; border-radius: 4px; margin: 10px 0;">' . |
| 335 |
'<span style="font-weight: bold;">▼ Mostrar Configurações Avançadas</span>' . |
| 336 |
'</div>', |
| 337 |
'id' => 'superfrete_advanced_section' |
| 338 |
]; |
| 339 |
|
| 340 |
$settings[] = [ |
| 341 |
'title' => 'Ativar Sandbox', |
| 342 |
'desc' => 'Habilitar ambiente de testes', |
| 343 |
'id' => 'superfrete_sandbox_mode', |
| 344 |
'type' => 'checkbox', |
| 345 |
'default' => get_option('superfrete_sandbox_mode', 'no'), |
| 346 |
'desc_tip' => 'Ao ativar o modo sandbox, a API usará o ambiente de testes da SuperFrete.' |
| 347 |
]; |
| 348 |
|
| 349 |
$settings[] = [ |
| 350 |
'type' => 'superfrete_webhook_status', |
| 351 |
'title' => 'Status dos Webhooks', |
| 352 |
'id' => 'superfrete_webhook_status', |
| 353 |
'webhook_status' => $webhook_status, |
| 354 |
'class' => 'superfrete-advanced-field' |
| 355 |
]; |
| 356 |
|
| 357 |
$settings[] = [ |
| 358 |
'type' => 'sectionend', |
| 359 |
'id' => 'superfrete_advanced_section' |
| 360 |
]; |
| 361 |
|
| 362 |
return $settings; |
| 363 |
} |
| 364 |
|
| 365 |
/** |
| 366 |
* Adiciona JavaScript para exibir/esconder o campo de Token de Sandbox dinamicamente. |
| 367 |
*/ |
| 368 |
public static function enqueue_admin_scripts() { |
| 369 |
// Check if we're on a WooCommerce settings page |
| 370 |
if (self::is_woocommerce_settings_page()) { |
| 371 |
// Ensure jQuery is loaded |
| 372 |
wp_enqueue_script('jquery'); |
| 373 |
|
| 374 |
// Enqueue calculator CSS for preview |
| 375 |
wp_enqueue_style('superfrete-calculator-css', plugin_dir_url(__FILE__) . '../../../assets/styles/superfrete-calculator.css', [], '1.0'); |
| 376 |
|
| 377 |
// Add inline script |
| 378 |
add_action('admin_footer', function() { |
| 379 |
?> |
| 380 |
<script type="text/javascript"> |
| 381 |
jQuery(document).ready(function($) { |
| 382 |
console.log('SuperFrete admin scripts loading...'); // Debug log |
| 383 |
|
| 384 |
// Make sure ajaxurl is available |
| 385 |
if (typeof ajaxurl === 'undefined') { |
| 386 |
window.ajaxurl = '<?php echo admin_url('admin-ajax.php'); ?>'; |
| 387 |
} |
| 388 |
|
| 389 |
// Advanced settings accordion toggle |
| 390 |
$('#superfrete-advanced-toggle').on('click', function() { |
| 391 |
// Target specific field IDs for advanced settings |
| 392 |
var $sandboxField = $('#superfrete_sandbox_mode').closest('tr'); |
| 393 |
var $webhookField = $('.superfrete-advanced-field').closest('tr'); |
| 394 |
var $advancedFields = $sandboxField.add($webhookField); |
| 395 |
var $toggle = $(this).find('span'); |
| 396 |
|
| 397 |
if ($advancedFields.is(':visible')) { |
| 398 |
$advancedFields.slideUp(); |
| 399 |
$toggle.text('▼ Mostrar Configurações Avançadas'); |
| 400 |
} else { |
| 401 |
$advancedFields.slideDown(); |
| 402 |
$toggle.text('▲ Ocultar Configurações Avançadas'); |
| 403 |
} |
| 404 |
}); |
| 405 |
|
| 406 |
// Initially hide advanced fields |
| 407 |
// $('#superfrete_sandbox_mode').closest('tr').hide(); // Show sandbox mode by default |
| 408 |
$('.superfrete-advanced-field').closest('tr').hide(); |
| 409 |
|
| 410 |
// Add OAuth functionality |
| 411 |
$('#superfrete-oauth-btn').on('click', function() { |
| 412 |
console.log('SuperFrete OAuth button clicked'); |
| 413 |
|
| 414 |
var $button = $(this); |
| 415 |
var $status = $('#superfrete-oauth-status'); |
| 416 |
|
| 417 |
// Disable button and show loading |
| 418 |
var originalText = $button.text(); |
| 419 |
var isReconnecting = originalText.includes('Reconectar'); |
| 420 |
$button.prop('disabled', true).text(isReconnecting ? 'Reconectando...' : 'Conectando...'); |
| 421 |
$status.html('<span style="color: #0073aa;">Iniciando ' + (isReconnecting ? 'reconexão' : 'conexão') + ' com SuperFrete...</span>'); |
| 422 |
|
| 423 |
// Get API URL based on environment settings |
| 424 |
<?php |
| 425 |
$use_dev_env = get_option('superfrete_sandbox_mode', 'no') === 'yes'; |
| 426 |
$api_url = $use_dev_env ? 'https://api.dev.superintegrador.superfrete.com' : 'https://api.superintegrador.superfrete.com'; |
| 427 |
?> |
| 428 |
|
| 429 |
var apiUrl = '<?php echo $api_url; ?>'; |
| 430 |
var siteUrl = '<?php echo get_site_url(); ?>'; |
| 431 |
var oauthUrl = apiUrl + '/headless/oauth/init?callback_url=' + encodeURIComponent(siteUrl + '/wp-admin/admin-ajax.php?action=superfrete_oauth_callback'); |
| 432 |
|
| 433 |
// Open OAuth popup |
| 434 |
var popup = window.open( |
| 435 |
oauthUrl, |
| 436 |
'superfrete_oauth', |
| 437 |
'width=600,height=700,scrollbars=yes,resizable=yes' |
| 438 |
); |
| 439 |
|
| 440 |
// Extract session ID from the OAuth URL for polling |
| 441 |
var sessionId = null; |
| 442 |
|
| 443 |
// Listen for session ID from popup |
| 444 |
var sessionListener = function(event) { |
| 445 |
if (event.origin !== apiUrl) { |
| 446 |
return; |
| 447 |
} |
| 448 |
|
| 449 |
if (event.data.type === 'superfrete_session_id') { |
| 450 |
sessionId = event.data.session_id; |
| 451 |
console.log('Received session ID:', sessionId); |
| 452 |
// Start polling now that we have the session ID |
| 453 |
setTimeout(pollForToken, 2000); |
| 454 |
} |
| 455 |
}; |
| 456 |
|
| 457 |
window.addEventListener('message', sessionListener); |
| 458 |
|
| 459 |
// Poll for token completion |
| 460 |
var pollForToken = function() { |
| 461 |
if (!sessionId) { |
| 462 |
console.log('No session ID yet, waiting...'); |
| 463 |
return; |
| 464 |
} |
| 465 |
|
| 466 |
// Poll the WordPress proxy for token (bypasses CORS) |
| 467 |
// Try REST API first, fallback to AJAX if needed |
| 468 |
var restUrl = '<?php echo rest_url('superfrete/v1/oauth/token'); ?>?session_id=' + sessionId; |
| 469 |
var ajaxUrl = ajaxurl + '?action=superfrete_oauth_proxy&session_id=' + sessionId + '&nonce=' + encodeURIComponent('<?php echo wp_create_nonce('wp_rest'); ?>'); |
| 470 |
|
| 471 |
$.ajax({ |
| 472 |
url: restUrl, |
| 473 |
type: 'GET', |
| 474 |
beforeSend: function(xhr) { |
| 475 |
xhr.setRequestHeader('X-WP-Nonce', '<?php echo wp_create_nonce('wp_rest'); ?>'); |
| 476 |
}, |
| 477 |
success: function(response) { |
| 478 |
if (response.ready && response.access_token) { |
| 479 |
// Token is ready - validate and save it |
| 480 |
$status.html('<span style="color: #0073aa;">Validando token...</span>'); |
| 481 |
|
| 482 |
// Send token to WordPress for validation and storage |
| 483 |
$.ajax({ |
| 484 |
url: ajaxurl, |
| 485 |
type: 'POST', |
| 486 |
data: { |
| 487 |
action: 'superfrete_oauth_callback', |
| 488 |
token: response.access_token, |
| 489 |
session_id: sessionId, |
| 490 |
nonce: '<?php echo wp_create_nonce('superfrete_oauth_nonce'); ?>' |
| 491 |
}, |
| 492 |
success: function(wpResponse) { |
| 493 |
if (wpResponse.success) { |
| 494 |
oauthSuccessful = true; // Mark OAuth as successful |
| 495 |
$status.html('<span style="color: #46b450;">✓ ' + wpResponse.data.message + '</span>'); |
| 496 |
$button.prop('disabled', false).text('Reconectar'); |
| 497 |
|
| 498 |
// Show success message with user info |
| 499 |
var userInfo = wpResponse.data.user_info; |
| 500 |
var successMsg = 'SuperFrete conectado com sucesso!'; |
| 501 |
if (userInfo && userInfo.name) { |
| 502 |
successMsg += '<br>Usuário: ' + userInfo.name; |
| 503 |
if (userInfo.email) { |
| 504 |
successMsg += ' (' + userInfo.email + ')'; |
| 505 |
} |
| 506 |
if (userInfo.balance !== undefined) { |
| 507 |
successMsg += '<br>Saldo: R$ ' + parseFloat(userInfo.balance).toFixed(2); |
| 508 |
} |
| 509 |
} |
| 510 |
if (wpResponse.data.webhook_registered) { |
| 511 |
successMsg += '<br>� |
| 512 |
Webhooks registrados automaticamente'; |
| 513 |
} |
| 514 |
|
| 515 |
$('<div class="notice notice-success is-dismissible"><p>' + successMsg + '</p></div>') |
| 516 |
.insertAfter('.wrap h1'); |
| 517 |
|
| 518 |
// Refresh the page to update connection status |
| 519 |
setTimeout(function() { |
| 520 |
location.reload(); |
| 521 |
}, 3000); |
| 522 |
} else { |
| 523 |
$status.html('<span style="color: #dc3232;">✗ Erro: ' + wpResponse.data + '</span>'); |
| 524 |
$button.prop('disabled', false).text('Tentar Novamente'); |
| 525 |
} |
| 526 |
}, |
| 527 |
error: function(xhr, status, error) { |
| 528 |
$status.html('<span style="color: #dc3232;">✗ Erro de comunicação: ' + error + '</span>'); |
| 529 |
$button.prop('disabled', false).text('Tentar Novamente'); |
| 530 |
} |
| 531 |
}); |
| 532 |
|
| 533 |
// Close popup |
| 534 |
popup.close(); |
| 535 |
} else if (!response.ready) { |
| 536 |
// Token not ready yet, continue polling |
| 537 |
setTimeout(pollForToken, 2000); |
| 538 |
} |
| 539 |
}, |
| 540 |
error: function(xhr, status, error) { |
| 541 |
if (xhr.status === 404 && xhr.responseJSON && xhr.responseJSON.message === 'Not Found') { |
| 542 |
// REST API endpoint not found, try AJAX fallback |
| 543 |
console.log('REST API failed, trying AJAX fallback...'); |
| 544 |
$.ajax({ |
| 545 |
url: ajaxUrl, |
| 546 |
type: 'GET', |
| 547 |
success: function(response) { |
| 548 |
// Handle the same way as REST API response |
| 549 |
if (response.ready && response.access_token) { |
| 550 |
// Process token the same way |
| 551 |
$status.html('<span style="color: #0073aa;">Validando token...</span>'); |
| 552 |
|
| 553 |
// Send token to WordPress for validation and storage |
| 554 |
$.ajax({ |
| 555 |
url: ajaxurl, |
| 556 |
type: 'POST', |
| 557 |
data: { |
| 558 |
action: 'superfrete_oauth_callback', |
| 559 |
token: response.access_token, |
| 560 |
session_id: sessionId, |
| 561 |
nonce: '<?php echo wp_create_nonce('superfrete_oauth_nonce'); ?>' |
| 562 |
}, |
| 563 |
success: function(wpResponse) { |
| 564 |
if (wpResponse.success) { |
| 565 |
oauthSuccessful = true; // Mark OAuth as successful |
| 566 |
$status.html('<span style="color: #46b450;">✓ ' + wpResponse.data.message + '</span>'); |
| 567 |
$button.prop('disabled', false).text('Reconectar'); |
| 568 |
|
| 569 |
var userInfo = wpResponse.data.user_info; |
| 570 |
var successMsg = 'SuperFrete conectado com sucesso!'; |
| 571 |
if (userInfo && userInfo.name) { |
| 572 |
successMsg += '<br>Usuário: ' + userInfo.name; |
| 573 |
if (userInfo.email) { |
| 574 |
successMsg += ' (' + userInfo.email + ')'; |
| 575 |
} |
| 576 |
if (userInfo.balance !== undefined) { |
| 577 |
successMsg += '<br>Saldo: R$ ' + parseFloat(userInfo.balance).toFixed(2); |
| 578 |
} |
| 579 |
} |
| 580 |
if (wpResponse.data.webhook_registered) { |
| 581 |
successMsg += '<br>� |
| 582 |
Webhooks registrados automaticamente'; |
| 583 |
} |
| 584 |
|
| 585 |
$('<div class="notice notice-success is-dismissible"><p>' + successMsg + '</p></div>') |
| 586 |
.insertAfter('.wrap h1'); |
| 587 |
|
| 588 |
setTimeout(function() { |
| 589 |
location.reload(); |
| 590 |
}, 3000); |
| 591 |
} else { |
| 592 |
$status.html('<span style="color: #dc3232;">✗ Erro: ' + wpResponse.data + '</span>'); |
| 593 |
$button.prop('disabled', false).text('Tentar Novamente'); |
| 594 |
} |
| 595 |
}, |
| 596 |
error: function(xhr, status, error) { |
| 597 |
$status.html('<span style="color: #dc3232;">✗ Erro de comunicação: ' + error + '</span>'); |
| 598 |
$button.prop('disabled', false).text('Tentar Novamente'); |
| 599 |
} |
| 600 |
}); |
| 601 |
|
| 602 |
popup.close(); |
| 603 |
} else if (!response.ready) { |
| 604 |
// Token not ready yet, continue polling with AJAX |
| 605 |
setTimeout(function() { |
| 606 |
// Switch to AJAX polling |
| 607 |
pollForTokenAjax(); |
| 608 |
}, 2000); |
| 609 |
} |
| 610 |
}, |
| 611 |
error: function(xhr, status, error) { |
| 612 |
if (xhr.status === 404) { |
| 613 |
// Session not found or expired |
| 614 |
$status.html('<span style="color: #dc3232;">✗ Sessão expirada. Tente novamente.</span>'); |
| 615 |
$button.prop('disabled', false).text('Tentar Novamente'); |
| 616 |
popup.close(); |
| 617 |
} else { |
| 618 |
// Continue polling on other errors |
| 619 |
setTimeout(pollForToken, 2000); |
| 620 |
} |
| 621 |
} |
| 622 |
}); |
| 623 |
} else if (xhr.status === 404) { |
| 624 |
// Session not found or expired |
| 625 |
$status.html('<span style="color: #dc3232;">✗ Sessão expirada. Tente novamente.</span>'); |
| 626 |
$button.prop('disabled', false).text('Tentar Novamente'); |
| 627 |
popup.close(); |
| 628 |
} else { |
| 629 |
// Continue polling on other errors |
| 630 |
setTimeout(pollForToken, 2000); |
| 631 |
} |
| 632 |
} |
| 633 |
}); |
| 634 |
}; |
| 635 |
|
| 636 |
// AJAX polling function (fallback) |
| 637 |
var pollForTokenAjax = function() { |
| 638 |
if (!sessionId) { |
| 639 |
console.log('No session ID yet, waiting...'); |
| 640 |
return; |
| 641 |
} |
| 642 |
|
| 643 |
$.ajax({ |
| 644 |
url: ajaxUrl, |
| 645 |
type: 'GET', |
| 646 |
success: function(response) { |
| 647 |
if (response.ready && response.access_token) { |
| 648 |
// Token is ready - validate and save it |
| 649 |
$status.html('<span style="color: #0073aa;">Validando token...</span>'); |
| 650 |
|
| 651 |
// Send token to WordPress for validation and storage |
| 652 |
$.ajax({ |
| 653 |
url: ajaxurl, |
| 654 |
type: 'POST', |
| 655 |
data: { |
| 656 |
action: 'superfrete_oauth_callback', |
| 657 |
token: response.access_token, |
| 658 |
session_id: sessionId, |
| 659 |
nonce: '<?php echo wp_create_nonce('superfrete_oauth_nonce'); ?>' |
| 660 |
}, |
| 661 |
success: function(wpResponse) { |
| 662 |
if (wpResponse.success) { |
| 663 |
oauthSuccessful = true; // Mark OAuth as successful |
| 664 |
$status.html('<span style="color: #46b450;">✓ ' + wpResponse.data.message + '</span>'); |
| 665 |
$button.prop('disabled', false).text('Reconectar'); |
| 666 |
|
| 667 |
var userInfo = wpResponse.data.user_info; |
| 668 |
var successMsg = 'SuperFrete conectado com sucesso!'; |
| 669 |
if (userInfo && userInfo.name) { |
| 670 |
successMsg += '<br>Usuário: ' + userInfo.name; |
| 671 |
if (userInfo.email) { |
| 672 |
successMsg += ' (' + userInfo.email + ')'; |
| 673 |
} |
| 674 |
if (userInfo.balance !== undefined) { |
| 675 |
successMsg += '<br>Saldo: R$ ' + parseFloat(userInfo.balance).toFixed(2); |
| 676 |
} |
| 677 |
} |
| 678 |
if (wpResponse.data.webhook_registered) { |
| 679 |
successMsg += '<br>� |
| 680 |
Webhooks registrados automaticamente'; |
| 681 |
} |
| 682 |
|
| 683 |
$('<div class="notice notice-success is-dismissible"><p>' + successMsg + '</p></div>') |
| 684 |
.insertAfter('.wrap h1'); |
| 685 |
|
| 686 |
setTimeout(function() { |
| 687 |
location.reload(); |
| 688 |
}, 3000); |
| 689 |
} else { |
| 690 |
$status.html('<span style="color: #dc3232;">✗ Erro: ' + wpResponse.data + '</span>'); |
| 691 |
$button.prop('disabled', false).text('Tentar Novamente'); |
| 692 |
} |
| 693 |
}, |
| 694 |
error: function(xhr, status, error) { |
| 695 |
$status.html('<span style="color: #dc3232;">✗ Erro de comunicação: ' + error + '</span>'); |
| 696 |
$button.prop('disabled', false).text('Tentar Novamente'); |
| 697 |
} |
| 698 |
}); |
| 699 |
|
| 700 |
popup.close(); |
| 701 |
} else if (!response.ready) { |
| 702 |
// Token not ready yet, continue polling |
| 703 |
setTimeout(pollForTokenAjax, 2000); |
| 704 |
} |
| 705 |
}, |
| 706 |
error: function(xhr, status, error) { |
| 707 |
if (xhr.status === 404) { |
| 708 |
// Session not found or expired |
| 709 |
$status.html('<span style="color: #dc3232;">✗ Sessão expirada. Tente novamente.</span>'); |
| 710 |
$button.prop('disabled', false).text('Tentar Novamente'); |
| 711 |
popup.close(); |
| 712 |
} else { |
| 713 |
// Continue polling on other errors |
| 714 |
setTimeout(pollForTokenAjax, 2000); |
| 715 |
} |
| 716 |
} |
| 717 |
}); |
| 718 |
}; |
| 719 |
|
| 720 |
// Handle popup closed manually |
| 721 |
var pollingActive = true; |
| 722 |
var oauthSuccessful = false; // Track if OAuth was successful |
| 723 |
var manualClose = false; // Track if popup was closed manually |
| 724 |
var checkClosed = setInterval(function() { |
| 725 |
if (popup.closed) { |
| 726 |
clearInterval(checkClosed); |
| 727 |
pollingActive = false; |
| 728 |
window.removeEventListener('message', sessionListener); |
| 729 |
|
| 730 |
// Only show "Conexão cancelada" if the popup was closed manually |
| 731 |
// and OAuth wasn't successful |
| 732 |
if (manualClose && !oauthSuccessful) { |
| 733 |
$button.prop('disabled', false).text(originalText); |
| 734 |
$status.html('<span style="color: #dc3232;">Conexão cancelada</span>'); |
| 735 |
} |
| 736 |
} |
| 737 |
}, 1000); |
| 738 |
|
| 739 |
// Track manual popup close |
| 740 |
popup.onbeforeunload = function() { |
| 741 |
manualClose = true; |
| 742 |
}; |
| 743 |
|
| 744 |
// Update polling function to check if still active |
| 745 |
var originalPollForToken = pollForToken; |
| 746 |
pollForToken = function() { |
| 747 |
if (!pollingActive) { |
| 748 |
return; |
| 749 |
} |
| 750 |
originalPollForToken(); |
| 751 |
}; |
| 752 |
}); |
| 753 |
|
| 754 |
// Handle visual customization settings |
| 755 |
function updateCSSVariables() { |
| 756 |
var primaryColor = $('#superfrete_custom_primary_color').val(); |
| 757 |
var errorColor = $('#superfrete_custom_error_color').val(); |
| 758 |
var fontSize = $('#superfrete_custom_font_size').val(); |
| 759 |
var borderRadius = $('#superfrete_custom_border_radius').val(); |
| 760 |
|
| 761 |
// Background and text colors |
| 762 |
var bgColor = $('#superfrete_custom_bg_color').val(); |
| 763 |
var resultsBgColor = $('#superfrete_custom_results_bg_color').val(); |
| 764 |
var textColor = $('#superfrete_custom_text_color').val(); |
| 765 |
var textLightColor = $('#superfrete_custom_text_light_color').val(); |
| 766 |
var borderColor = $('#superfrete_custom_border_color').val(); |
| 767 |
|
| 768 |
// Update preview immediately |
| 769 |
updatePreview(primaryColor, errorColor, fontSize, borderRadius, bgColor, resultsBgColor, textColor, textLightColor, borderColor); |
| 770 |
|
| 771 |
// Save to database via AJAX |
| 772 |
$.ajax({ |
| 773 |
url: ajaxurl, |
| 774 |
type: 'POST', |
| 775 |
data: { |
| 776 |
action: 'superfrete_save_customization', |
| 777 |
nonce: '<?php echo wp_create_nonce('superfrete_customization_nonce'); ?>', |
| 778 |
primary_color: primaryColor, |
| 779 |
error_color: errorColor, |
| 780 |
font_size: fontSize, |
| 781 |
border_radius: borderRadius, |
| 782 |
bg_color: bgColor, |
| 783 |
results_bg_color: resultsBgColor, |
| 784 |
text_color: textColor, |
| 785 |
text_light_color: textLightColor, |
| 786 |
border_color: borderColor |
| 787 |
}, |
| 788 |
success: function(response) { |
| 789 |
if (response.success) { |
| 790 |
// Silently saved - no notification needed for real-time updates |
| 791 |
console.log('Customization saved successfully'); |
| 792 |
} else { |
| 793 |
console.error('Error saving customization:', response.data); |
| 794 |
} |
| 795 |
}, |
| 796 |
error: function(xhr, status, error) { |
| 797 |
console.error('AJAX error:', error); |
| 798 |
} |
| 799 |
}); |
| 800 |
} |
| 801 |
|
| 802 |
// Function to update the preview in real-time |
| 803 |
function updatePreview(primaryColor, errorColor, fontSize, borderRadius, bgColor, resultsBgColor, textColor, textLightColor, borderColor) { |
| 804 |
// Helper function to darken color |
| 805 |
function darkenColor(color, percent) { |
| 806 |
var num = parseInt(color.replace('#', ''), 16), |
| 807 |
amt = Math.round(2.55 * percent), |
| 808 |
R = (num >> 16) - amt, |
| 809 |
G = (num >> 8 & 0x00FF) - amt, |
| 810 |
B = (num & 0x0000FF) - amt; |
| 811 |
return '#' + (0x1000000 + (R < 255 ? R < 1 ? 0 : R : 255) * 0x10000 + |
| 812 |
(G < 255 ? G < 1 ? 0 : G : 255) * 0x100 + |
| 813 |
(B < 255 ? B < 1 ? 0 : B : 255)).toString(16).slice(1); |
| 814 |
} |
| 815 |
|
| 816 |
// Helper function to lighten color |
| 817 |
function lightenColor(color, percent) { |
| 818 |
var num = parseInt(color.replace('#', ''), 16), |
| 819 |
amt = Math.round(2.55 * percent), |
| 820 |
R = (num >> 16) + amt, |
| 821 |
G = (num >> 8 & 0x00FF) + amt, |
| 822 |
B = (num & 0x0000FF) + amt; |
| 823 |
return '#' + (0x1000000 + (R < 255 ? R < 1 ? 0 : R : 255) * 0x10000 + |
| 824 |
(G < 255 ? G < 1 ? 0 : G : 255) * 0x100 + |
| 825 |
(B < 255 ? B < 1 ? 0 : B : 255)).toString(16).slice(1); |
| 826 |
} |
| 827 |
|
| 828 |
// Helper function to scale size |
| 829 |
function scaleSize(size, multiplier) { |
| 830 |
var numericValue = parseFloat(size); |
| 831 |
var unit = size.replace(numericValue, ''); |
| 832 |
return (numericValue * multiplier) + unit; |
| 833 |
} |
| 834 |
|
| 835 |
// Generate comprehensive CSS variables with all necessary variables |
| 836 |
var css = '#super-frete-shipping-calculator-preview {' + |
| 837 |
// Primary colors |
| 838 |
'--superfrete-primary-color: ' + primaryColor + ';' + |
| 839 |
'--superfrete-primary-hover: ' + darkenColor(primaryColor, 10) + ';' + |
| 840 |
'--superfrete-error-color: ' + errorColor + ';' + |
| 841 |
|
| 842 |
// Background colors |
| 843 |
'--superfrete-bg-color: ' + bgColor + ';' + |
| 844 |
'--superfrete-bg-white: ' + resultsBgColor + ';' + |
| 845 |
'--superfrete-bg-light: ' + lightenColor(bgColor, 5) + ';' + |
| 846 |
|
| 847 |
// Text colors |
| 848 |
'--superfrete-text-color: ' + textColor + ';' + |
| 849 |
'--superfrete-text-light: ' + textLightColor + ';' + |
| 850 |
'--superfrete-heading-color: ' + textColor + ';' + |
| 851 |
|
| 852 |
// Border colors |
| 853 |
'--superfrete-border-color: ' + borderColor + ';' + |
| 854 |
'--superfrete-border-light: ' + lightenColor(borderColor, 10) + ';' + |
| 855 |
'--superfrete-border-dark: ' + darkenColor(borderColor, 15) + ';' + |
| 856 |
|
| 857 |
// Typography |
| 858 |
'--superfrete-font-size-base: ' + fontSize + ';' + |
| 859 |
'--superfrete-font-size-small: ' + scaleSize(fontSize, 0.85) + ';' + |
| 860 |
'--superfrete-font-size-large: ' + scaleSize(fontSize, 1.15) + ';' + |
| 861 |
'--superfrete-font-family: Poppins, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;' + |
| 862 |
'--superfrete-line-height: 1.5;' + |
| 863 |
|
| 864 |
// Border radius |
| 865 |
'--superfrete-radius-sm: ' + borderRadius + ';' + |
| 866 |
'--superfrete-radius-md: ' + scaleSize(borderRadius, 1.5) + ';' + |
| 867 |
'--superfrete-radius-lg: ' + scaleSize(borderRadius, 2) + ';' + |
| 868 |
|
| 869 |
// Spacing (essential for layout) |
| 870 |
'--superfrete-spacing-xs: 4px;' + |
| 871 |
'--superfrete-spacing-sm: 8px;' + |
| 872 |
'--superfrete-spacing-md: 12px;' + |
| 873 |
'--superfrete-spacing-lg: 16px;' + |
| 874 |
'--superfrete-spacing-xl: 24px;' + |
| 875 |
|
| 876 |
// Shadows |
| 877 |
'--superfrete-shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.1);' + |
| 878 |
'--superfrete-shadow-md: 0 2px 6px rgba(0, 0, 0, 0.1);' + |
| 879 |
|
| 880 |
// Z-index |
| 881 |
'--superfrete-z-base: 1;' + |
| 882 |
'--superfrete-z-overlay: 100;' + |
| 883 |
'--superfrete-z-loading: 101;' + |
| 884 |
|
| 885 |
// Animation |
| 886 |
'--superfrete-transition-fast: 0.15s ease;' + |
| 887 |
'--superfrete-transition-normal: 0.3s ease;' + |
| 888 |
'}'; |
| 889 |
|
| 890 |
// Update the preview styles |
| 891 |
$('#superfrete-preview-styles').html(css); |
| 892 |
} |
| 893 |
|
| 894 |
// Debounce function to prevent excessive updates |
| 895 |
function debounce(func, wait) { |
| 896 |
let timeout; |
| 897 |
return function executedFunction(...args) { |
| 898 |
const later = () => { |
| 899 |
clearTimeout(timeout); |
| 900 |
func(...args); |
| 901 |
}; |
| 902 |
clearTimeout(timeout); |
| 903 |
timeout = setTimeout(later, wait); |
| 904 |
}; |
| 905 |
} |
| 906 |
|
| 907 |
// Create debounced update function |
| 908 |
const debouncedUpdateCSS = debounce(function() { |
| 909 |
// Save current scroll position |
| 910 |
const scrollTop = window.pageYOffset || document.documentElement.scrollTop; |
| 911 |
const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft; |
| 912 |
|
| 913 |
// Update CSS |
| 914 |
updateCSSVariables(); |
| 915 |
|
| 916 |
// Restore scroll position |
| 917 |
window.scrollTo(scrollLeft, scrollTop); |
| 918 |
}, 300); |
| 919 |
|
| 920 |
// Auto-save on color picker changes |
| 921 |
$('#superfrete_custom_primary_color, #superfrete_custom_error_color, #superfrete_custom_bg_color, #superfrete_custom_results_bg_color, #superfrete_custom_text_color, #superfrete_custom_text_light_color, #superfrete_custom_border_color').on('change', function() { |
| 922 |
updateCSSVariables(); |
| 923 |
}); |
| 924 |
|
| 925 |
// Disable WordPress Iris color picker and use HTML5 color inputs |
| 926 |
$('input[type="color"]').each(function() { |
| 927 |
var $this = $(this); |
| 928 |
// Remove any WordPress color picker initialization |
| 929 |
if ($this.hasClass('wp-color-picker')) { |
| 930 |
$this.wpColorPicker('destroy'); |
| 931 |
} |
| 932 |
// Remove wp-color-picker class to prevent auto-initialization |
| 933 |
$this.removeClass('wp-color-picker'); |
| 934 |
}); |
| 935 |
|
| 936 |
// Auto-save on dropdown changes |
| 937 |
$('#superfrete_custom_font_size, #superfrete_custom_border_radius').on('change', function() { |
| 938 |
updateCSSVariables(); |
| 939 |
}); |
| 940 |
|
| 941 |
// Theme preset handlers |
| 942 |
$('#superfrete-preset-light').on('click', function() { |
| 943 |
// Light theme preset |
| 944 |
$('#superfrete_custom_bg_color').val('#ffffff').trigger('change'); |
| 945 |
$('#superfrete_custom_results_bg_color').val('#ffffff').trigger('change'); |
| 946 |
$('#superfrete_custom_text_color').val('#1a1a1a').trigger('change'); |
| 947 |
$('#superfrete_custom_text_light_color').val('#777777').trigger('change'); |
| 948 |
$('#superfrete_custom_border_color').val('#e0e0e0').trigger('change'); |
| 949 |
|
| 950 |
// Force update of color picker UI |
| 951 |
setTimeout(function() { |
| 952 |
updateCSSVariables(); |
| 953 |
}, 100); |
| 954 |
}); |
| 955 |
|
| 956 |
$('#superfrete-preset-dark').on('click', function() { |
| 957 |
// Dark theme preset |
| 958 |
$('#superfrete_custom_bg_color').val('#2a2a2a').trigger('change'); |
| 959 |
$('#superfrete_custom_results_bg_color').val('#333333').trigger('change'); |
| 960 |
$('#superfrete_custom_text_color').val('#ffffff').trigger('change'); |
| 961 |
$('#superfrete_custom_text_light_color').val('#cccccc').trigger('change'); |
| 962 |
$('#superfrete_custom_border_color').val('#555555').trigger('change'); |
| 963 |
|
| 964 |
// Force update of color picker UI |
| 965 |
setTimeout(function() { |
| 966 |
updateCSSVariables(); |
| 967 |
}, 100); |
| 968 |
}); |
| 969 |
|
| 970 |
$('#superfrete-preset-auto').on('click', function() { |
| 971 |
// Auto-detect theme from page background |
| 972 |
var bodyBg = $('body').css('background-color'); |
| 973 |
var isLightTheme = true; |
| 974 |
|
| 975 |
// Simple light/dark detection |
| 976 |
if (bodyBg && bodyBg !== 'rgba(0, 0, 0, 0)') { |
| 977 |
var rgb = bodyBg.match(/\\d+/g); |
| 978 |
if (rgb && rgb.length >= 3) { |
| 979 |
var brightness = (parseInt(rgb[0]) * 299 + parseInt(rgb[1]) * 587 + parseInt(rgb[2]) * 114) / 1000; |
| 980 |
isLightTheme = brightness > 128; |
| 981 |
} |
| 982 |
} |
| 983 |
|
| 984 |
if (isLightTheme) { |
| 985 |
$('#superfrete-preset-light').click(); |
| 986 |
} else { |
| 987 |
$('#superfrete-preset-dark').click(); |
| 988 |
} |
| 989 |
}); |
| 990 |
|
| 991 |
// Handle reset customization |
| 992 |
$('#superfrete-reset-customization').on('click', function() { |
| 993 |
if (confirm('Tem certeza que deseja resetar todas as personalizações visuais?')) { |
| 994 |
$.ajax({ |
| 995 |
url: ajaxurl, |
| 996 |
type: 'POST', |
| 997 |
data: { |
| 998 |
action: 'superfrete_reset_customization', |
| 999 |
nonce: '<?php echo wp_create_nonce('superfrete_customization_nonce'); ?>' |
| 1000 |
}, |
| 1001 |
success: function(response) { |
| 1002 |
if (response.success) { |
| 1003 |
// Reset form values to defaults and trigger change events |
| 1004 |
$('#superfrete_custom_primary_color').val('#0fae79').trigger('change'); |
| 1005 |
$('#superfrete_custom_error_color').val('#e74c3c').trigger('change'); |
| 1006 |
$('#superfrete_custom_font_size').val('14px').trigger('change'); |
| 1007 |
$('#superfrete_custom_border_radius').val('4px').trigger('change'); |
| 1008 |
$('#superfrete_custom_bg_color').val('#ffffff').trigger('change'); |
| 1009 |
$('#superfrete_custom_results_bg_color').val('#ffffff').trigger('change'); |
| 1010 |
$('#superfrete_custom_text_color').val('#1a1a1a').trigger('change'); |
| 1011 |
$('#superfrete_custom_text_light_color').val('#777777').trigger('change'); |
| 1012 |
$('#superfrete_custom_border_color').val('#e0e0e0').trigger('change'); |
| 1013 |
|
| 1014 |
// Update preview with default values |
| 1015 |
updatePreview('#0fae79', '#e74c3c', '14px', '4px', '#ffffff', '#ffffff', '#1a1a1a', '#777777', '#e0e0e0'); |
| 1016 |
|
| 1017 |
// Show success notification |
| 1018 |
$('<div class="notice notice-success is-dismissible"><p>Personalização resetada com sucesso!</p></div>') |
| 1019 |
.insertAfter('.wrap h1').delay(3000).fadeOut(); |
| 1020 |
} else { |
| 1021 |
console.error('Error resetting customization:', response.data); |
| 1022 |
} |
| 1023 |
}, |
| 1024 |
error: function(xhr, status, error) { |
| 1025 |
console.error('AJAX error:', error); |
| 1026 |
} |
| 1027 |
}); |
| 1028 |
} |
| 1029 |
}); |
| 1030 |
|
| 1031 |
// Initialize preview with current values |
| 1032 |
function initializePreview() { |
| 1033 |
var primaryColor = $('#superfrete_custom_primary_color').val() || '#0fae79'; |
| 1034 |
var errorColor = $('#superfrete_custom_error_color').val() || '#e74c3c'; |
| 1035 |
var fontSize = $('#superfrete_custom_font_size').val() || '14px'; |
| 1036 |
var borderRadius = $('#superfrete_custom_border_radius').val() || '4px'; |
| 1037 |
var bgColor = $('#superfrete_custom_bg_color').val() || '#ffffff'; |
| 1038 |
var resultsBgColor = $('#superfrete_custom_results_bg_color').val() || '#ffffff'; |
| 1039 |
var textColor = $('#superfrete_custom_text_color').val() || '#1a1a1a'; |
| 1040 |
var textLightColor = $('#superfrete_custom_text_light_color').val() || '#777777'; |
| 1041 |
var borderColor = $('#superfrete_custom_border_color').val() || '#e0e0e0'; |
| 1042 |
|
| 1043 |
updatePreview(primaryColor, errorColor, fontSize, borderRadius, bgColor, resultsBgColor, textColor, textLightColor, borderColor); |
| 1044 |
} |
| 1045 |
|
| 1046 |
// Initialize preview on page load |
| 1047 |
initializePreview(); |
| 1048 |
|
| 1049 |
console.log('SuperFrete admin scripts loaded successfully!'); |
| 1050 |
}); |
| 1051 |
</script> |
| 1052 |
<?php |
| 1053 |
}); |
| 1054 |
} |
| 1055 |
} |
| 1056 |
|
| 1057 |
/** |
| 1058 |
* Check if we're on a WooCommerce settings page |
| 1059 |
*/ |
| 1060 |
private static function is_woocommerce_settings_page() { |
| 1061 |
global $pagenow; |
| 1062 |
|
| 1063 |
// Check URL parameters |
| 1064 |
$page = $_GET['page'] ?? ''; |
| 1065 |
$tab = $_GET['tab'] ?? ''; |
| 1066 |
|
| 1067 |
return ( |
| 1068 |
$pagenow === 'admin.php' && |
| 1069 |
$page === 'wc-settings' && |
| 1070 |
($tab === 'shipping' || $tab === '') |
| 1071 |
); |
| 1072 |
} |
| 1073 |
|
| 1074 |
/** |
| 1075 |
* Render custom webhook status field |
| 1076 |
*/ |
| 1077 |
public static function render_webhook_status_field($field) { |
| 1078 |
$webhook_status = $field['webhook_status']; |
| 1079 |
$css_class = isset($field['class']) ? $field['class'] : ''; |
| 1080 |
?> |
| 1081 |
<tr valign="top" class="<?php echo esc_attr($css_class); ?>"> |
| 1082 |
<th scope="row" class="titledesc"> |
| 1083 |
<label for="<?php echo esc_attr($field['id']); ?>"><?php echo esc_html($field['title']); ?></label> |
| 1084 |
</th> |
| 1085 |
<td class="forminp"> |
| 1086 |
<div style="<?php echo esc_attr($webhook_status['css']); ?>"> |
| 1087 |
<?php if (strpos($webhook_status['message'], 'Registrados e Ativos') !== false): ?> |
| 1088 |
� |
| 1089 |
Webhooks Registrados e Ativos |
| 1090 |
<button type="button" id="superfrete-register-webhook" class="button button-secondary" style="margin-left: 10px;"> |
| 1091 |
Reregistrar |
| 1092 |
</button> |
| 1093 |
<?php else: ?> |
| 1094 |
❌ Webhooks Não Registrados |
| 1095 |
<button type="button" id="superfrete-register-webhook" class="button button-primary" style="margin-left: 10px;"> |
| 1096 |
Registrar Agora |
| 1097 |
</button> |
| 1098 |
<?php endif; ?> |
| 1099 |
</div> |
| 1100 |
<p class="description">Status atual dos webhooks do SuperFrete.</p> |
| 1101 |
</td> |
| 1102 |
</tr> |
| 1103 |
<?php |
| 1104 |
} |
| 1105 |
|
| 1106 |
/** |
| 1107 |
* Render custom preview field |
| 1108 |
*/ |
| 1109 |
public static function render_preview_field($field) { |
| 1110 |
?> |
| 1111 |
<tr valign="top"> |
| 1112 |
<th scope="row" class="titledesc"> |
| 1113 |
<label for="<?php echo esc_attr($field['id']); ?>"><?php echo esc_html($field['title']); ?></label> |
| 1114 |
</th> |
| 1115 |
<td class="forminp"> |
| 1116 |
<?php echo self::render_preview_html(); ?> |
| 1117 |
<p class="description"><?php echo esc_html($field['desc']); ?></p> |
| 1118 |
</td> |
| 1119 |
</tr> |
| 1120 |
<?php |
| 1121 |
} |
| 1122 |
|
| 1123 |
/** |
| 1124 |
* Get webhook status information |
| 1125 |
*/ |
| 1126 |
public static function get_webhook_status() { |
| 1127 |
$is_registered = get_option('superfrete_webhook_registered') === 'yes'; |
| 1128 |
$webhook_url = get_option('superfrete_webhook_url'); |
| 1129 |
|
| 1130 |
if ($is_registered && $webhook_url) { |
| 1131 |
return [ |
| 1132 |
'message' => 'Webhooks Registrados e Ativos', |
| 1133 |
'css' => 'color: #008000; font-weight: bold;' |
| 1134 |
]; |
| 1135 |
} else { |
| 1136 |
return [ |
| 1137 |
'message' => 'Webhooks Não Registrados', |
| 1138 |
'css' => 'color: #cc0000; font-weight: bold;' |
| 1139 |
]; |
| 1140 |
} |
| 1141 |
} |
| 1142 |
|
| 1143 |
/** |
| 1144 |
* Handle webhook registration AJAX request |
| 1145 |
*/ |
| 1146 |
public static function handle_webhook_registration() { |
| 1147 |
// Log the request for debugging |
| 1148 |
Logger::log('SuperFrete', 'Webhook registration AJAX request received'); |
| 1149 |
|
| 1150 |
// Verify nonce |
| 1151 |
if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'superfrete_webhook_nonce')) { |
| 1152 |
Logger::log('SuperFrete', 'Webhook registration failed: Invalid nonce'); |
| 1153 |
wp_send_json_error('Falha na verificação de segurança'); |
| 1154 |
return; |
| 1155 |
} |
| 1156 |
|
| 1157 |
// Check permissions |
| 1158 |
if (!current_user_can('manage_woocommerce')) { |
| 1159 |
Logger::log('SuperFrete', 'Webhook registration failed: Insufficient permissions'); |
| 1160 |
wp_send_json_error('Permissões insuficientes'); |
| 1161 |
return; |
| 1162 |
} |
| 1163 |
|
| 1164 |
try { |
| 1165 |
$webhook_url = rest_url('superfrete/v1/webhook'); |
| 1166 |
Logger::log('SuperFrete', 'Attempting webhook registration for URL: ' . $webhook_url); |
| 1167 |
|
| 1168 |
$request = new Request(); |
| 1169 |
|
| 1170 |
// Try to register webhook |
| 1171 |
$result = $request->register_webhook($webhook_url); |
| 1172 |
|
| 1173 |
if ($result) { |
| 1174 |
Logger::log('SuperFrete', 'Webhook registration successful: ' . wp_json_encode($result)); |
| 1175 |
wp_send_json_success('Webhook registrado com sucesso!'); |
| 1176 |
} else { |
| 1177 |
Logger::log('SuperFrete', 'Webhook registration failed: No result returned'); |
| 1178 |
wp_send_json_error('Falha ao registrar webhook. Verifique suas credenciais da API e conexão.'); |
| 1179 |
} |
| 1180 |
} catch (Exception $e) { |
| 1181 |
Logger::log('SuperFrete', 'Webhook registration exception: ' . $e->getMessage()); |
| 1182 |
wp_send_json_error('Erro: ' . $e->getMessage()); |
| 1183 |
} catch (Error $e) { |
| 1184 |
Logger::log('SuperFrete', 'Webhook registration error: ' . $e->getMessage()); |
| 1185 |
wp_send_json_error('Erro interno: ' . $e->getMessage()); |
| 1186 |
} |
| 1187 |
} |
| 1188 |
|
| 1189 |
/** |
| 1190 |
* Handle OAuth callback AJAX request |
| 1191 |
*/ |
| 1192 |
public static function handle_oauth_callback() { |
| 1193 |
// Verify nonce for security |
| 1194 |
if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'superfrete_oauth_nonce')) { |
| 1195 |
wp_send_json_error('Falha na verificação de segurança'); |
| 1196 |
return; |
| 1197 |
} |
| 1198 |
|
| 1199 |
// Check permissions |
| 1200 |
if (!current_user_can('manage_woocommerce')) { |
| 1201 |
wp_send_json_error('Permissões insuficientes'); |
| 1202 |
return; |
| 1203 |
} |
| 1204 |
|
| 1205 |
// Get the token from the request |
| 1206 |
$token = sanitize_text_field($_POST['token'] ?? ''); |
| 1207 |
$session_id = sanitize_text_field($_POST['session_id'] ?? ''); |
| 1208 |
|
| 1209 |
if (empty($token)) { |
| 1210 |
wp_send_json_error('Token não fornecido'); |
| 1211 |
return; |
| 1212 |
} |
| 1213 |
|
| 1214 |
try { |
| 1215 |
// Determine which environment we're using |
| 1216 |
$sandbox_enabled = get_option('superfrete_sandbox_mode') === 'yes'; |
| 1217 |
$site_url = get_site_url(); |
| 1218 |
$is_dev_site = ( |
| 1219 |
strpos($site_url, 'localhost') !== false || |
| 1220 |
strpos($site_url, '.local') !== false || |
| 1221 |
( |
| 1222 |
strpos($site_url, 'dev.') !== false && |
| 1223 |
strpos($site_url, 'dev.wordpress.superintegrador.superfrete.com') === false |
| 1224 |
) |
| 1225 |
); |
| 1226 |
$use_dev_env = ($sandbox_enabled || $is_dev_site); |
| 1227 |
$option_key = $use_dev_env ? 'superfrete_api_token_sandbox' : 'superfrete_api_token'; |
| 1228 |
$old_token = get_option($option_key); |
| 1229 |
|
| 1230 |
// Temporarily set the token to test it |
| 1231 |
update_option($option_key, $token); |
| 1232 |
|
| 1233 |
// Validate token using superfrete-api package |
| 1234 |
$request = new Request(); |
| 1235 |
|
| 1236 |
// Add detailed logging before API call |
| 1237 |
Logger::log('SuperFrete', 'About to validate token with API call to /api/v0/user'); |
| 1238 |
Logger::log('SuperFrete', 'Token being validated: ' . substr($token, 0, 20) . '...'); |
| 1239 |
Logger::log('SuperFrete', 'Environment: ' . ($use_dev_env ? 'dev' : 'production')); |
| 1240 |
Logger::log('SuperFrete', 'Option key: ' . $option_key); |
| 1241 |
|
| 1242 |
$response = $request->call_superfrete_api('/api/v0/user', 'GET', [], true); |
| 1243 |
|
| 1244 |
// Log the response |
| 1245 |
Logger::log('SuperFrete', 'API response received: ' . wp_json_encode($response)); |
| 1246 |
Logger::log('SuperFrete', 'Response has id: ' . (isset($response['id']) ? 'yes' : 'no')); |
| 1247 |
Logger::log('SuperFrete', 'Response is truthy: ' . ($response ? 'yes' : 'no')); |
| 1248 |
|
| 1249 |
if ($response && isset($response['id'])) { |
| 1250 |
// Token is valid, keep it |
| 1251 |
Logger::log('SuperFrete', 'OAuth token validated successfully for user: ' . ($response['firstname'] ?? 'Unknown')); |
| 1252 |
|
| 1253 |
// Register webhooks automatically after successful token validation |
| 1254 |
try { |
| 1255 |
$webhook_url = rest_url('superfrete/v1/webhook'); |
| 1256 |
$webhook_result = $request->register_webhook($webhook_url); |
| 1257 |
|
| 1258 |
if ($webhook_result) { |
| 1259 |
Logger::log('SuperFrete', 'Webhook registered automatically after OAuth: ' . wp_json_encode($webhook_result)); |
| 1260 |
update_option('superfrete_webhook_registered', 'yes'); |
| 1261 |
update_option('superfrete_webhook_url', $webhook_url); |
| 1262 |
} else { |
| 1263 |
Logger::log('SuperFrete', 'Webhook registration failed after OAuth'); |
| 1264 |
} |
| 1265 |
} catch (Exception $webhook_error) { |
| 1266 |
Logger::log('SuperFrete', 'Webhook registration error after OAuth: ' . $webhook_error->getMessage()); |
| 1267 |
// Don't fail the OAuth process if webhook registration fails |
| 1268 |
} |
| 1269 |
|
| 1270 |
wp_send_json_success([ |
| 1271 |
'message' => 'Token OAuth obtido e validado com sucesso!', |
| 1272 |
'user_info' => [ |
| 1273 |
'name' => ($response['firstname'] ?? '') . ' ' . ($response['lastname'] ?? ''), |
| 1274 |
'email' => $response['email'] ?? '', |
| 1275 |
'id' => $response['id'] ?? '', |
| 1276 |
'balance' => $response['balance'] ?? 0, |
| 1277 |
'limits' => $response['limits'] ?? [] |
| 1278 |
], |
| 1279 |
'webhook_registered' => isset($webhook_result) && $webhook_result ? true : false |
| 1280 |
]); |
| 1281 |
} else { |
| 1282 |
// Token is invalid, restore old token |
| 1283 |
update_option($option_key, $old_token); |
| 1284 |
Logger::log('SuperFrete', 'OAuth token validation failed'); |
| 1285 |
wp_send_json_error('Token inválido ou expirado'); |
| 1286 |
} |
| 1287 |
} catch (Exception $e) { |
| 1288 |
// Restore old token on error |
| 1289 |
if (isset($old_token)) { |
| 1290 |
update_option($option_key, $old_token); |
| 1291 |
} |
| 1292 |
Logger::log('SuperFrete', 'OAuth token validation error: ' . $e->getMessage()); |
| 1293 |
wp_send_json_error('Erro ao validar token: ' . $e->getMessage()); |
| 1294 |
} |
| 1295 |
} |
| 1296 |
|
| 1297 |
/** |
| 1298 |
* Handle save customization AJAX request |
| 1299 |
*/ |
| 1300 |
public static function handle_save_customization() { |
| 1301 |
// Verify nonce |
| 1302 |
if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'superfrete_customization_nonce')) { |
| 1303 |
wp_send_json_error('Falha na verificação de segurança'); |
| 1304 |
return; |
| 1305 |
} |
| 1306 |
|
| 1307 |
// Check permissions |
| 1308 |
if (!current_user_can('manage_woocommerce')) { |
| 1309 |
wp_send_json_error('Permissões insuficientes'); |
| 1310 |
return; |
| 1311 |
} |
| 1312 |
|
| 1313 |
try { |
| 1314 |
// Get and sanitize input values |
| 1315 |
$primary_color = sanitize_hex_color($_POST['primary_color'] ?? '#0fae79'); |
| 1316 |
$error_color = sanitize_hex_color($_POST['error_color'] ?? '#e74c3c'); |
| 1317 |
$font_size = sanitize_text_field($_POST['font_size'] ?? '14px'); |
| 1318 |
$border_radius = sanitize_text_field($_POST['border_radius'] ?? '4px'); |
| 1319 |
|
| 1320 |
// Background and text colors |
| 1321 |
$bg_color = sanitize_hex_color($_POST['bg_color'] ?? '#ffffff'); |
| 1322 |
$results_bg_color = sanitize_hex_color($_POST['results_bg_color'] ?? '#ffffff'); |
| 1323 |
$text_color = sanitize_hex_color($_POST['text_color'] ?? '#1a1a1a'); |
| 1324 |
$text_light_color = sanitize_hex_color($_POST['text_light_color'] ?? '#666666'); |
| 1325 |
$border_color = sanitize_hex_color($_POST['border_color'] ?? '#e0e0e0'); |
| 1326 |
|
| 1327 |
// Validate values |
| 1328 |
$valid_font_sizes = ['12px', '14px', '16px', '18px']; |
| 1329 |
$valid_border_radius = ['0px', '2px', '4px', '8px', '12px']; |
| 1330 |
|
| 1331 |
if (!in_array($font_size, $valid_font_sizes)) { |
| 1332 |
$font_size = '14px'; |
| 1333 |
} |
| 1334 |
if (!in_array($border_radius, $valid_border_radius)) { |
| 1335 |
$border_radius = '4px'; |
| 1336 |
} |
| 1337 |
|
| 1338 |
// Build comprehensive CSS variables array |
| 1339 |
$css_variables = array( |
| 1340 |
// Primary colors and variations |
| 1341 |
'--superfrete-primary-color' => $primary_color, |
| 1342 |
'--superfrete-primary-hover' => self::darken_color($primary_color, 10), |
| 1343 |
'--superfrete-error-color' => $error_color, |
| 1344 |
|
| 1345 |
// Background colors |
| 1346 |
'--superfrete-bg-color' => $bg_color, |
| 1347 |
'--superfrete-bg-white' => $results_bg_color, |
| 1348 |
'--superfrete-bg-light' => self::lighten_color($bg_color, 5), |
| 1349 |
|
| 1350 |
// Text colors |
| 1351 |
'--superfrete-text-color' => $text_color, |
| 1352 |
'--superfrete-text-light' => $text_light_color, |
| 1353 |
'--superfrete-heading-color' => $text_color, |
| 1354 |
|
| 1355 |
// Border colors |
| 1356 |
'--superfrete-border-color' => $border_color, |
| 1357 |
'--superfrete-border-light' => self::lighten_color($border_color, 10), |
| 1358 |
'--superfrete-border-dark' => self::darken_color($border_color, 15), |
| 1359 |
|
| 1360 |
// Interactive element colors (use primary color) |
| 1361 |
'--superfrete-interactive-color' => $primary_color, |
| 1362 |
'--superfrete-interactive-hover' => self::darken_color($primary_color, 10), |
| 1363 |
|
| 1364 |
// Typography |
| 1365 |
'--superfrete-font-size-base' => $font_size, |
| 1366 |
'--superfrete-font-size-small' => self::scale_size($font_size, 0.85), |
| 1367 |
'--superfrete-font-size-large' => self::scale_size($font_size, 1.15), |
| 1368 |
|
| 1369 |
// Border radius |
| 1370 |
'--superfrete-radius-sm' => $border_radius, |
| 1371 |
'--superfrete-radius-md' => self::scale_size($border_radius, 1.5), |
| 1372 |
'--superfrete-radius-lg' => self::scale_size($border_radius, 2), |
| 1373 |
|
| 1374 |
// Derived colors based on primary color for better theming |
| 1375 |
'--superfrete-focus-color' => $primary_color, |
| 1376 |
'--superfrete-accent-color' => $primary_color, |
| 1377 |
); |
| 1378 |
|
| 1379 |
// Save to database |
| 1380 |
update_option('superfrete_custom_css_vars', $css_variables); |
| 1381 |
|
| 1382 |
wp_send_json_success('Personalização salva com sucesso!'); |
| 1383 |
} catch (Exception $e) { |
| 1384 |
wp_send_json_error('Erro ao salvar personalização: ' . $e->getMessage()); |
| 1385 |
} |
| 1386 |
} |
| 1387 |
|
| 1388 |
/** |
| 1389 |
* Handle reset customization AJAX request |
| 1390 |
*/ |
| 1391 |
public static function handle_reset_customization() { |
| 1392 |
// Verify nonce |
| 1393 |
if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'superfrete_customization_nonce')) { |
| 1394 |
wp_send_json_error('Falha na verificação de segurança'); |
| 1395 |
return; |
| 1396 |
} |
| 1397 |
|
| 1398 |
// Check permissions |
| 1399 |
if (!current_user_can('manage_woocommerce')) { |
| 1400 |
wp_send_json_error('Permissões insuficientes'); |
| 1401 |
return; |
| 1402 |
} |
| 1403 |
|
| 1404 |
try { |
| 1405 |
// Remove custom CSS variables from database |
| 1406 |
delete_option('superfrete_custom_css_vars'); |
| 1407 |
|
| 1408 |
wp_send_json_success('Personalização resetada com sucesso!'); |
| 1409 |
} catch (Exception $e) { |
| 1410 |
wp_send_json_error('Erro ao resetar personalização: ' . $e->getMessage()); |
| 1411 |
} |
| 1412 |
} |
| 1413 |
|
| 1414 |
/** |
| 1415 |
* Helper function to darken a color |
| 1416 |
*/ |
| 1417 |
private static function darken_color($color, $percent) { |
| 1418 |
// Remove # if present |
| 1419 |
$color = str_replace('#', '', $color); |
| 1420 |
|
| 1421 |
// Convert to RGB |
| 1422 |
$r = hexdec(substr($color, 0, 2)); |
| 1423 |
$g = hexdec(substr($color, 2, 2)); |
| 1424 |
$b = hexdec(substr($color, 4, 2)); |
| 1425 |
|
| 1426 |
// Darken by percent |
| 1427 |
$r = max(0, min(255, $r - ($r * $percent / 100))); |
| 1428 |
$g = max(0, min(255, $g - ($g * $percent / 100))); |
| 1429 |
$b = max(0, min(255, $b - ($b * $percent / 100))); |
| 1430 |
|
| 1431 |
// Convert back to hex |
| 1432 |
return sprintf('#%02x%02x%02x', $r, $g, $b); |
| 1433 |
} |
| 1434 |
|
| 1435 |
/** |
| 1436 |
* Helper function to scale a size value |
| 1437 |
*/ |
| 1438 |
private static function scale_size($size, $multiplier) { |
| 1439 |
$numeric_value = floatval($size); |
| 1440 |
$unit = str_replace($numeric_value, '', $size); |
| 1441 |
return ($numeric_value * $multiplier) . $unit; |
| 1442 |
} |
| 1443 |
|
| 1444 |
/** |
| 1445 |
* Helper function to lighten a color |
| 1446 |
*/ |
| 1447 |
private static function lighten_color($color, $percent) { |
| 1448 |
// Remove # if present |
| 1449 |
$color = str_replace('#', '', $color); |
| 1450 |
|
| 1451 |
// Convert to RGB |
| 1452 |
$r = hexdec(substr($color, 0, 2)); |
| 1453 |
$g = hexdec(substr($color, 2, 2)); |
| 1454 |
$b = hexdec(substr($color, 4, 2)); |
| 1455 |
|
| 1456 |
// Lighten by percent |
| 1457 |
$r = min(255, max(0, $r + (255 - $r) * $percent / 100)); |
| 1458 |
$g = min(255, max(0, $g + (255 - $g) * $percent / 100)); |
| 1459 |
$b = min(255, max(0, $b + (255 - $b) * $percent / 100)); |
| 1460 |
|
| 1461 |
// Convert back to hex |
| 1462 |
return sprintf('#%02x%02x%02x', $r, $g, $b); |
| 1463 |
} |
| 1464 |
|
| 1465 |
/** |
| 1466 |
* Render preview HTML for the freight calculator |
| 1467 |
*/ |
| 1468 |
private static function render_preview_html() { |
| 1469 |
ob_start(); |
| 1470 |
?> |
| 1471 |
<div id="superfrete-preview-container" style="margin-top: 20px; padding: 20px; background: #f9f9f9; border-radius: 8px;"> |
| 1472 |
<h4 style="margin-top: 0;">Pré-visualização da Calculadora</h4> |
| 1473 |
<div id="superfrete-preview-calculator" style="max-width: 500px;"> |
| 1474 |
<!-- Exact replica of the real calculator structure --> |
| 1475 |
<div id="super-frete-shipping-calculator-preview" class="superfrete-calculator-wrapper"> |
| 1476 |
<!-- CEP Input Section - Always Visible --> |
| 1477 |
<div class="superfrete-input-section"> |
| 1478 |
<div class="form-row form-row-wide" id="calc_shipping_postcode_field"> |
| 1479 |
<input type="text" class="input-text" value="22775-360" |
| 1480 |
placeholder="Digite seu CEP (00000-000)" |
| 1481 |
readonly style="pointer-events: none;" /> |
| 1482 |
</div> |
| 1483 |
</div> |
| 1484 |
|
| 1485 |
<!-- Results Section --> |
| 1486 |
<div id="superfrete-results-container-preview" class="superfrete-results-container"> |
| 1487 |
<div class="superfrete-shipping-methods"> |
| 1488 |
<h3>Opções de Entrega</h3> |
| 1489 |
<div class="superfrete-shipping-method"> |
| 1490 |
<div class="superfrete-shipping-method-name">PAC - (5 dias úteis)</div> |
| 1491 |
<div class="superfrete-shipping-method-price">R$ 20,78</div> |
| 1492 |
</div> |
| 1493 |
<div class="superfrete-shipping-method"> |
| 1494 |
<div class="superfrete-shipping-method-name">SEDEX - (1 dia útil)</div> |
| 1495 |
<div class="superfrete-shipping-method-price">R$ 13,20</div> |
| 1496 |
</div> |
| 1497 |
</div> |
| 1498 |
</div> |
| 1499 |
</div> |
| 1500 |
</div> |
| 1501 |
<p style="font-style: italic; color: #666; margin-bottom: 0;"> |
| 1502 |
Esta é uma pré-visualização. As alterações são aplicadas automaticamente conforme você modifica as configurações acima. |
| 1503 |
</p> |
| 1504 |
</div> |
| 1505 |
|
| 1506 |
<!-- Ensure the preview gets the same CSS as the real calculator --> |
| 1507 |
<style id="superfrete-preview-base-styles"> |
| 1508 |
/* Copy the calculator styles for preview */ |
| 1509 |
#super-frete-shipping-calculator-preview { |
| 1510 |
background-color: var(--superfrete-bg-color); |
| 1511 |
padding: var(--superfrete-spacing-lg); |
| 1512 |
border-radius: var(--superfrete-radius-lg); |
| 1513 |
margin-bottom: var(--superfrete-spacing-lg); |
| 1514 |
max-width: 500px; |
| 1515 |
box-shadow: var(--superfrete-shadow-sm); |
| 1516 |
font-size: var(--superfrete-font-size-base); |
| 1517 |
line-height: var(--superfrete-line-height); |
| 1518 |
font-family: var(--superfrete-font-family); |
| 1519 |
color: var(--superfrete-text-color); |
| 1520 |
} |
| 1521 |
|
| 1522 |
#super-frete-shipping-calculator-preview .superfrete-input-section { |
| 1523 |
margin-bottom: var(--superfrete-spacing-md); |
| 1524 |
} |
| 1525 |
|
| 1526 |
#super-frete-shipping-calculator-preview #calc_shipping_postcode_field input { |
| 1527 |
width: 100%; |
| 1528 |
padding: var(--superfrete-spacing-sm) var(--superfrete-spacing-md); |
| 1529 |
border: 1px solid var(--superfrete-border-color); |
| 1530 |
border-radius: var(--superfrete-radius-sm); |
| 1531 |
font-size: var(--superfrete-font-size-base); |
| 1532 |
transition: all 0.3s ease; |
| 1533 |
letter-spacing: 0.5px; |
| 1534 |
font-weight: 500; |
| 1535 |
font-family: var(--superfrete-font-family); |
| 1536 |
color: var(--superfrete-text-color); |
| 1537 |
background-color: var(--superfrete-bg-white); |
| 1538 |
box-sizing: border-box; |
| 1539 |
} |
| 1540 |
|
| 1541 |
#super-frete-shipping-calculator-preview .superfrete-results-container { |
| 1542 |
background-color: var(--superfrete-bg-white); |
| 1543 |
border: 1px solid var(--superfrete-border-light); |
| 1544 |
border-radius: var(--superfrete-radius-sm); |
| 1545 |
padding: var(--superfrete-spacing-md); |
| 1546 |
box-shadow: var(--superfrete-shadow-sm); |
| 1547 |
} |
| 1548 |
|
| 1549 |
#super-frete-shipping-calculator-preview .superfrete-shipping-methods h3 { |
| 1550 |
font-size: var(--superfrete-font-size-base); |
| 1551 |
margin-bottom: var(--superfrete-spacing-sm); |
| 1552 |
border-bottom: 1px solid var(--superfrete-border-light); |
| 1553 |
padding-bottom: var(--superfrete-spacing-sm); |
| 1554 |
color: var(--superfrete-heading-color); |
| 1555 |
font-weight: 600; |
| 1556 |
margin-top: 0; |
| 1557 |
} |
| 1558 |
|
| 1559 |
#super-frete-shipping-calculator-preview .superfrete-shipping-method { |
| 1560 |
display: flex; |
| 1561 |
justify-content: space-between; |
| 1562 |
padding: var(--superfrete-spacing-sm) 0; |
| 1563 |
border-bottom: 1px solid var(--superfrete-border-light); |
| 1564 |
align-items: center; |
| 1565 |
} |
| 1566 |
|
| 1567 |
#super-frete-shipping-calculator-preview .superfrete-shipping-method:last-child { |
| 1568 |
border-bottom: none; |
| 1569 |
} |
| 1570 |
|
| 1571 |
#super-frete-shipping-calculator-preview .superfrete-shipping-method-name { |
| 1572 |
font-weight: 600; |
| 1573 |
color: var(--superfrete-text-color); |
| 1574 |
font-size: var(--superfrete-font-size-small); |
| 1575 |
flex: 1; |
| 1576 |
} |
| 1577 |
|
| 1578 |
#super-frete-shipping-calculator-preview .superfrete-shipping-method-price { |
| 1579 |
font-weight: 600; |
| 1580 |
color: var(--superfrete-primary-color); |
| 1581 |
font-size: var(--superfrete-font-size-small); |
| 1582 |
text-align: right; |
| 1583 |
} |
| 1584 |
</style> |
| 1585 |
|
| 1586 |
<style id="superfrete-preview-styles"> |
| 1587 |
/* Dynamic preview styles will be injected here by JavaScript */ |
| 1588 |
</style> |
| 1589 |
<?php |
| 1590 |
return ob_get_clean(); |
| 1591 |
} |
| 1592 |
} |
| 1593 |
|
| 1594 |
// Executa a migração assim que o plugin for carregado |
| 1595 |
add_action('admin_init', ['SuperFrete_API\Admin\SuperFrete_Settings', 'migrate_old_settings']); |
| 1596 |
|
| 1597 |
// Hook para adicionar a aba dentro de "Entrega" |
| 1598 |
add_filter('woocommerce_shipping_settings', ['SuperFrete_API\Admin\SuperFrete_Settings', 'add_superfrete_settings']); |
| 1599 |
add_action('admin_init', ['SuperFrete_API\Admin\SuperFrete_Settings', 'enqueue_admin_scripts']); |
| 1600 |
|
| 1601 |
// AJAX hooks for webhook management |
| 1602 |
add_action('wp_ajax_superfrete_register_webhook', ['SuperFrete_API\Admin\SuperFrete_Settings', 'handle_webhook_registration']); |
| 1603 |
add_action('wp_ajax_superfrete_oauth_callback', ['SuperFrete_API\Admin\SuperFrete_Settings', 'handle_oauth_callback']); |
| 1604 |
|
| 1605 |
// AJAX hooks for visual customization |
| 1606 |
add_action('wp_ajax_superfrete_save_customization', ['SuperFrete_API\Admin\SuperFrete_Settings', 'handle_save_customization']); |
| 1607 |
add_action('wp_ajax_superfrete_reset_customization', ['SuperFrete_API\Admin\SuperFrete_Settings', 'handle_reset_customization']); |
| 1608 |
|