From 0cf35cd494f1bf5c26958087af3971b926a4ca0a Mon Sep 17 00:00:00 2001 From: salltech Date: Sat, 23 Aug 2025 21:15:12 +0000 Subject: [PATCH] add assets --- assets/bankily-admin.css | 844 +++++++++++++++++++++++++++++++++++++++ assets/bankily-admin.js | 721 +++++++++++++++++++++++++++++++++ assets/bankily-bpay.js | 435 ++++++++++++++++++++ 3 files changed, 2000 insertions(+) create mode 100644 assets/bankily-admin.css create mode 100644 assets/bankily-admin.js create mode 100644 assets/bankily-bpay.js diff --git a/assets/bankily-admin.css b/assets/bankily-admin.css new file mode 100644 index 0000000..5dc5cf3 --- /dev/null +++ b/assets/bankily-admin.css @@ -0,0 +1,844 @@ +/** + * Styles CSS pour l'interface d'administration B-PAY Bankily + * Fichier: assets/bankily-admin.css + * Version: 1.0.0 + */ + +/* === VARIABLES CSS === */ +:root { + --bankily-primary: #007cba; + --bankily-success: #28a745; + --bankily-warning: #ffc107; + --bankily-danger: #dc3545; + --bankily-info: #17a2b8; + --bankily-light: #f8f9fa; + --bankily-dark: #343a40; + --bankily-border: #dee2e6; + --bankily-shadow: 0 2px 4px rgba(0,0,0,0.1); + --bankily-shadow-lg: 0 4px 8px rgba(0,0,0,0.15); + --bankily-border-radius: 8px; + --bankily-transition: all 0.3s ease; +} + +/* === LAYOUT GÉNÉRAL === */ +.wrap .bankily-stats-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); + gap: 20px; + margin: 20px 0 30px 0; +} + +.bankily-stat-card { + background: #fff; + border: 1px solid var(--bankily-border); + border-radius: var(--bankily-border-radius); + padding: 24px; + text-align: center; + box-shadow: var(--bankily-shadow); + transition: var(--bankily-transition); + position: relative; + overflow: hidden; +} + +.bankily-stat-card:hover { + transform: translateY(-2px); + box-shadow: var(--bankily-shadow-lg); +} + +.bankily-stat-card::before { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + height: 4px; + background: var(--bankily-primary); +} + +.bankily-stat-card h3 { + font-size: 2.8em; + margin: 0 0 10px 0; + font-weight: 700; + line-height: 1; +} + +.bankily-stat-card p { + margin: 0; + color: #666; + font-size: 14px; + text-transform: uppercase; + letter-spacing: 0.8px; + font-weight: 500; +} + +/* Couleurs des cartes statistiques */ +.bankily-stat-card.total::before { background: var(--bankily-primary); } +.bankily-stat-card.total h3 { color: var(--bankily-primary); } + +.bankily-stat-card.success::before { background: var(--bankily-success); } +.bankily-stat-card.success h3 { color: var(--bankily-success); } + +.bankily-stat-card.pending::before { background: var(--bankily-warning); } +.bankily-stat-card.pending h3 { color: var(--bankily-warning); } + +.bankily-stat-card.failed::before { background: var(--bankily-danger); } +.bankily-stat-card.failed h3 { color: var(--bankily-danger); } + +.bankily-stat-card.amount::before { background: var(--bankily-info); } +.bankily-stat-card.amount h3 { color: var(--bankily-info); } + +/* === ACTIONS RAPIDES === */ +.bankily-quick-actions { + background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%); + border: 1px solid var(--bankily-border); + border-radius: var(--bankily-border-radius); + padding: 24px; + margin: 20px 0 30px 0; + position: relative; +} + +.bankily-quick-actions::before { + content: '⚡'; + position: absolute; + top: -10px; + left: 20px; + background: var(--bankily-warning); + color: white; + width: 30px; + height: 30px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + font-size: 14px; +} + +.bankily-quick-actions h2 { + margin-top: 0; + color: var(--bankily-dark); + font-size: 18px; + margin-bottom: 16px; +} + +.bankily-action-buttons { + display: flex; + gap: 12px; + flex-wrap: wrap; + align-items: center; +} + +.bankily-action-buttons .button { + margin: 0; + font-weight: 500; + transition: var(--bankily-transition); +} + +.bankily-action-buttons .button-primary { + background: var(--bankily-primary); + border-color: var(--bankily-primary); +} + +.bankily-action-buttons .button-primary:hover { + background: #005a87; + border-color: #005a87; + transform: translateY(-1px); +} + +/* === STATUTS DES TRANSACTIONS === */ +.bankily-status { + display: inline-block; + padding: 6px 12px; + border-radius: 20px; + font-size: 11px; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.8px; + border: 2px solid transparent; + transition: var(--bankily-transition); +} + +.bankily-status-ts { + background: linear-gradient(135deg, #d4edda, #c3e6cb); + color: #155724; + border-color: #c3e6cb; +} + +.bankily-status-tf { + background: linear-gradient(135deg, #f8d7da, #f5c6cb); + color: #721c24; + border-color: #f5c6cb; +} + +.bankily-status-ta { + background: linear-gradient(135deg, #fff3cd, #ffeaa7); + color: #856404; + border-color: #ffeaa7; + animation: pulse-warning 2s infinite; +} + +@keyframes pulse-warning { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.8; } +} + +/* === FILTRES ET RECHERCHE === */ +.bankily-filters { + background: #fff; + border: 1px solid var(--bankily-border); + border-radius: var(--bankily-border-radius); + padding: 20px; + margin: 20px 0; + box-shadow: var(--bankily-shadow); +} + +.bankily-search-box { + display: flex; + gap: 12px; + align-items: center; + flex-wrap: wrap; +} + +.bankily-search-box input[type="text"] { + flex: 1; + min-width: 300px; + padding: 10px 16px; + border: 2px solid var(--bankily-border); + border-radius: 6px; + font-size: 14px; + transition: var(--bankily-transition); +} + +.bankily-search-box input[type="text"]:focus { + outline: none; + border-color: var(--bankily-primary); + box-shadow: 0 0 0 3px rgba(0, 124, 186, 0.1); +} + +.bankily-advanced-filters { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); + gap: 16px; + margin-top: 16px; + padding-top: 16px; + border-top: 1px solid var(--bankily-border); +} + +.bankily-filter-group label { + display: block; + font-weight: 600; + margin-bottom: 6px; + color: var(--bankily-dark); + font-size: 13px; +} + +.bankily-filter-group select, +.bankily-filter-group input { + width: 100%; + padding: 8px 12px; + border: 1px solid var(--bankily-border); + border-radius: 4px; + font-size: 13px; + transition: var(--bankily-transition); +} + +.bankily-filter-group select:focus, +.bankily-filter-group input:focus { + outline: none; + border-color: var(--bankily-primary); +} + +/* === ACTIONS EN LOT === */ +.bankily-bulk-actions { + display: flex; + justify-content: space-between; + align-items: center; + padding: 12px 0; + border-bottom: 2px solid var(--bankily-border); + margin-bottom: 15px; + background: linear-gradient(90deg, rgba(0, 124, 186, 0.05) 0%, rgba(0, 124, 186, 0.02) 100%); + padding: 16px; + border-radius: 6px; + margin: 10px 0 20px 0; +} + +.bankily-bulk-actions select { + margin-right: 8px; + padding: 6px 10px; + border-radius: 4px; +} + +.bankily-bulk-actions .button.action:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +.bankily-bulk-actions .displaying-num { + color: #666; + font-size: 13px; + font-weight: 500; +} + +/* === TABLEAU DES TRANSACTIONS === */ +.wp-list-table { + border-radius: var(--bankily-border-radius); + overflow: hidden; + box-shadow: var(--bankily-shadow); +} + +.wp-list-table .transaction-row { + transition: var(--bankily-transition); +} + +.wp-list-table .transaction-row:hover { + background-color: rgba(0, 124, 186, 0.05); +} + +.wp-list-table .transaction-row.updated { + background-color: rgba(40, 167, 69, 0.1); + border-left: 4px solid var(--bankily-success); +} + +.wp-list-table .transaction-row.bankily-checking { + background-color: rgba(0, 124, 186, 0.1); + opacity: 0.7; +} + +.wp-list-table .transaction-row.bankily-success { + background-color: rgba(40, 167, 69, 0.15); + animation: flash-success 1.5s ease; +} + +.wp-list-table .transaction-row.bankily-error { + background-color: rgba(220, 53, 69, 0.15); + animation: flash-error 1.5s ease; +} + +@keyframes flash-success { + 0%, 100% { background-color: rgba(40, 167, 69, 0.15); } + 50% { background-color: rgba(40, 167, 69, 0.3); } +} + +@keyframes flash-error { + 0%, 100% { background-color: rgba(220, 53, 69, 0.15); } + 50% { background-color: rgba(220, 53, 69, 0.3); } +} + +.wp-list-table .operation-id { + font-family: 'Monaco', 'Menlo', 'Consolas', monospace; + font-size: 12px; + font-weight: 600; +} + +.wp-list-table .operation-id small { + color: #666; + font-size: 10px; + font-weight: normal; +} + +.wp-list-table .actions { + white-space: nowrap; +} + +.wp-list-table .actions .button { + margin: 2px; + font-size: 11px; + padding: 4px 8px; + border-radius: 4px; + font-weight: 500; + transition: var(--bankily-transition); +} + +.wp-list-table .actions .button:hover { + transform: translateY(-1px); +} + +.wp-list-table .actions .button.bankily-loading { + position: relative; + color: transparent !important; +} + +.wp-list-table .actions .button.bankily-loading::after { + content: ''; + position: absolute; + width: 12px; + height: 12px; + top: 50%; + left: 50%; + margin-left: -6px; + margin-top: -6px; + border: 2px solid #fff; + border-radius: 50%; + border-top-color: transparent; + animation: spin 1s linear infinite; +} + +@keyframes spin { + to { transform: rotate(360deg); } +} + +.wp-list-table .error-message { + color: var(--bankily-danger); + font-style: italic; + cursor: help; + font-size: 11px; +} + +.wp-list-table .error-message:hover { + text-decoration: underline; +} + +/* Statuts des commandes */ +.order-status-completed { color: var(--bankily-success); font-weight: 600; } +.order-status-processing { color: var(--bankily-info); font-weight: 600; } +.order-status-on-hold { color: var(--bankily-warning); font-weight: 600; } +.order-status-cancelled { color: var(--bankily-danger); font-weight: 600; } +.order-status-refunded { color: #6c757d; font-weight: 600; } +.order-status-failed { color: var(--bankily-danger); font-weight: 600; } +.order-status-pending { color: #fd7e14; font-weight: 600; } + +/* === BARRE DE PROGRESSION === */ +#bankily-progress-overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.8); + z-index: 999999; + display: flex; + align-items: center; + justify-content: center; + backdrop-filter: blur(5px); +} + +.bankily-progress-container { + background: #fff; + border-radius: var(--bankily-border-radius); + padding: 40px; + min-width: 450px; + max-width: 90vw; + text-align: center; + box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3); + border: 3px solid var(--bankily-primary); +} + +.bankily-progress-container h3 { + margin: 0 0 24px 0; + color: var(--bankily-dark); + font-size: 20px; +} + +.bankily-progress-bar { + width: 100%; + height: 24px; + background: #e9ecef; + border-radius: 12px; + overflow: hidden; + margin-bottom: 16px; + border: 2px solid var(--bankily-border); +} + +.bankily-progress-fill { + height: 100%; + background: linear-gradient(45deg, var(--bankily-primary), var(--bankily-info)); + transition: width 0.5s ease; + position: relative; + border-radius: 10px; +} + +.bankily-progress-fill::after { + content: ''; + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; + background-image: linear-gradient( + 45deg, + rgba(255, 255, 255, 0.3) 25%, + transparent 25%, + transparent 50%, + rgba(255, 255, 255, 0.3) 50%, + rgba(255, 255, 255, 0.3) 75%, + transparent 75%, + transparent + ); + background-size: 24px 24px; + animation: progress-stripes 1.5s linear infinite; +} + +@keyframes progress-stripes { + 0% { background-position: 0 0; } + 100% { background-position: 24px 0; } +} + +.bankily-progress-text { + color: var(--bankily-dark); + font-weight: 600; + font-size: 16px; + margin-bottom: 16px; +} + +.bankily-progress-container p { + margin-bottom: 20px; +} + +.bankily-progress-container small { + color: #666; + font-style: italic; +} + +/* === PAGINATION === */ +.bankily-pagination { + text-align: center; + margin: 30px 0; +} + +.bankily-pagination .page-numbers { + display: inline-block; + padding: 10px 14px; + margin: 0 3px; + border: 2px solid var(--bankily-border); + border-radius: 6px; + color: var(--bankily-primary); + text-decoration: none; + transition: var(--bankily-transition); + font-weight: 500; +} + +.bankily-pagination .page-numbers:hover { + background: var(--bankily-primary); + color: #fff; + border-color: var(--bankily-primary); + transform: translateY(-1px); +} + +.bankily-pagination .page-numbers.current { + background: var(--bankily-primary); + color: #fff; + border-color: var(--bankily-primary); +} + +/* === NOTICES === */ +.bankily-notice { + margin: 15px 0; + animation: slideDown 0.4s ease; + border-left: 4px solid var(--bankily-primary); + box-shadow: var(--bankily-shadow); +} + +@keyframes slideDown { + from { + transform: translateY(-20px); + opacity: 0; + } + to { + transform: translateY(0); + opacity: 1; + } +} + +.bankily-notice.notice-success { + border-left-color: var(--bankily-success); +} + +.bankily-notice.notice-error { + border-left-color: var(--bankily-danger); +} + +.bankily-notice.notice-warning { + border-left-color: var(--bankily-warning); +} + +.bankily-notice.notice-info { + border-left-color: var(--bankily-info); +} + +/* === INDICATEUR DE CONNEXION === */ +#bankily-connection-status { + position: fixed; + bottom: 20px; + right: 20px; + padding: 10px 16px; + border-radius: 25px; + font-size: 12px; + font-weight: 600; + z-index: 10000; + transition: var(--bankily-transition); + box-shadow: var(--bankily-shadow-lg); + border: 2px solid transparent; +} + +#bankily-connection-status.online { + background: linear-gradient(135deg, var(--bankily-success), #20c997); + color: #fff; + border-color: var(--bankily-success); +} + +#bankily-connection-status.offline { + background: linear-gradient(135deg, var(--bankily-danger), #e83e8c); + color: #fff; + border-color: var(--bankily-danger); + animation: pulse-offline 2s infinite; +} + +@keyframes pulse-offline { + 0%, 100% { opacity: 1; transform: scale(1); } + 50% { opacity: 0.8; transform: scale(1.05); } +} + +/* === TOOLTIPS === */ +#bankily-tooltip { + background: var(--bankily-dark); + color: #fff; + padding: 8px 12px; + border-radius: 6px; + font-size: 12px; + max-width: 300px; + word-wrap: break-word; + box-shadow: var(--bankily-shadow-lg); + z-index: 999999; + border: 1px solid rgba(255, 255, 255, 0.1); +} + +/* === BADGES ET ICÔNES === */ +.bankily-badge { + display: inline-block; + padding: 3px 8px; + font-size: 10px; + font-weight: 700; + border-radius: 3px; + text-transform: uppercase; + letter-spacing: 0.5px; +} + +.bankily-badge.new { + background: linear-gradient(135deg, #e3f2fd, #bbdefb); + color: #1976d2; + border: 1px solid #90caf9; +} + +.bankily-badge.urgent { + background: linear-gradient(135deg, #ffebee, #ffcdd2); + color: #c62828; + border: 1px solid #ef9a9a; + animation: pulse-urgent 2s infinite; +} + +@keyframes pulse-urgent { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.7; } +} + +/* === RESPONSIVE === */ +@media (max-width: 1200px) { + .bankily-stats-grid { + grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); + gap: 16px; + } + + .bankily-stat-card { + padding: 20px; + } + + .bankily-stat-card h3 { + font-size: 2.4em; + } +} + +@media (max-width: 782px) { + .bankily-stats-grid { + grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); + gap: 12px; + } + + .bankily-stat-card { + padding: 16px; + } + + .bankily-stat-card h3 { + font-size: 2em; + } + + .bankily-search-box { + flex-direction: column; + align-items: stretch; + } + + .bankily-search-box input[type="text"] { + min-width: auto; + margin-bottom: 10px; + } + + .bankily-action-buttons { + flex-direction: column; + align-items: stretch; + } + + .bankily-action-buttons .button { + margin-bottom: 8px; + } + + .bankily-bulk-actions { + flex-direction: column; + align-items: stretch; + gap: 10px; + } + + .bankily-advanced-filters { + grid-template-columns: 1fr; + } + + .wp-list-table .actions { + white-space: normal; + } + + .wp-list-table .actions .button { + display: block; + margin-bottom: 5px; + width: 100%; + text-align: center; + } + + .bankily-progress-container { + padding: 20px; + min-width: auto; + max-width: 95vw; + } + + #bankily-connection-status { + bottom: 10px; + right: 10px; + font-size: 11px; + padding: 8px 12px; + } +} + +@media (max-width: 480px) { + .bankily-stats-grid { + grid-template-columns: 1fr; + } + + .bankily-quick-actions { + padding: 16px; + } + + .bankily-filters { + padding: 16px; + } + + .wp-list-table { + font-size: 12px; + } + + .wp-list-table th, + .wp-list-table td { + padding: 8px 4px; + } +} + +/* === DARK MODE (optionnel) === */ +@media (prefers-color-scheme: dark) { + :root { + --bankily-light: #2c3e50; + --bankily-border: #34495e; + --bankily-dark: #ecf0f1; + } + + .bankily-stat-card { + background: var(--bankily-light); + border-color: var(--bankily-border); + color: var(--bankily-dark); + } + + .bankily-quick-actions { + background: linear-gradient(135deg, #2c3e50 0%, #34495e 100%); + border-color: var(--bankily-border); + color: var(--bankily-dark); + } + + .bankily-filters { + background: var(--bankily-light); + border-color: var(--bankily-border); + color: var(--bankily-dark); + } + + .bankily-progress-container { + background: var(--bankily-light); + color: var(--bankily-dark); + border-color: var(--bankily-primary); + } +} + +/* === ANIMATIONS SUPPLÉMENTAIRES === */ +@keyframes fadeInUp { + from { + opacity: 0; + transform: translateY(20px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +.bankily-stats-grid .bankily-stat-card { + animation: fadeInUp 0.5s ease forwards; +} + +.bankily-stats-grid .bankily-stat-card:nth-child(1) { animation-delay: 0.1s; } +.bankily-stats-grid .bankily-stat-card:nth-child(2) { animation-delay: 0.2s; } +.bankily-stats-grid .bankily-stat-card:nth-child(3) { animation-delay: 0.3s; } +.bankily-stats-grid .bankily-stat-card:nth-child(4) { animation-delay: 0.4s; } +.bankily-stats-grid .bankily-stat-card:nth-child(5) { animation-delay: 0.5s; } + +/* === ACCESSIBILITÉ === */ +.sr-only { + position: absolute !important; + width: 1px !important; + height: 1px !important; + padding: 0 !important; + margin: -1px !important; + overflow: hidden !important; + clip: rect(0, 0, 0, 0) !important; + white-space: nowrap !important; + border: 0 !important; +} + +/* Focus visible pour la navigation clavier */ +.bankily-stat-card:focus, +.button:focus, +input:focus, +select:focus, +.bankily-status:focus { + outline: 2px solid var(--bankily-primary); + outline-offset: 2px; +} + +/* === IMPRESSION === */ +@media print { + .bankily-action-buttons, + .bankily-bulk-actions, + .wp-list-table .actions, + #bankily-connection-status, + .notice, + #bankily-progress-overlay { + display: none !important; + } + + .bankily-stat-card { + break-inside: avoid; + box-shadow: none; + border: 1px solid #000; + } + + .wp-list-table { + font-size: 10px; + } + + .bankily-status { + border: 1px solid #000 !important; + background: #fff !important; + color: #000 !important; + } +} \ No newline at end of file diff --git a/assets/bankily-admin.js b/assets/bankily-admin.js new file mode 100644 index 0000000..4a4bdbd --- /dev/null +++ b/assets/bankily-admin.js @@ -0,0 +1,721 @@ +/** + * Script JavaScript pour l'interface d'administration B-PAY Bankily + * Fichier: assets/bankily-admin.js + * Version: 1.0.0 + */ + +jQuery(document).ready(function($) { + 'use strict'; + + // Variables globales + var checking = false; + var autoRefreshInterval; + + // Initialisation + initializeAdminInterface(); + + function initializeAdminInterface() { + // Gestion des checkboxes + $('#cb-select-all').on('change', function() { + $('input[name="transaction_ids[]"]').prop('checked', this.checked); + updateBulkActionsState(); + }); + + // Mise à jour de l'état des actions groupées + $(document).on('change', 'input[name="transaction_ids[]"]', function() { + updateBulkActionsState(); + }); + + // Auto-refresh pour les transactions en attente + if (window.location.href.indexOf('bankily-pending') > -1) { + startAutoRefresh(); + } + + // Initialiser les tooltips + initializeTooltips(); + + // Gestion du temps réel + updateTimeStamps(); + setInterval(updateTimeStamps, 60000); // Mettre à jour chaque minute + + // Recherche en temps réel + setupLiveSearch(); + + // Raccourcis clavier + setupKeyboardShortcuts(); + + // Indicateur de connexion + checkConnectionStatus(); + setInterval(checkConnectionStatus, 30000); + } + + function updateBulkActionsState() { + var selectedCount = $('input[name="transaction_ids[]"]:checked').length; + var $bulkButton = $('.button.action'); + + if (selectedCount > 0) { + $bulkButton.prop('disabled', false).text('Appliquer (' + selectedCount + ')'); + } else { + $bulkButton.prop('disabled', true).text('Appliquer'); + } + } + + function initializeTooltips() { + $('.error-message, [data-tooltip]').each(function() { + var $this = $(this); + var title = $this.attr('title') || $this.data('tooltip'); + + if (title) { + $this.on('mouseenter', function(e) { + showTooltip(e.pageX, e.pageY, title); + }); + + $this.on('mouseleave', function() { + hideTooltip(); + }); + + $this.on('mousemove', function(e) { + updateTooltipPosition(e.pageX, e.pageY); + }); + } + }); + } + + function showTooltip(x, y, text) { + var $tooltip = $('#bankily-tooltip'); + if ($tooltip.length === 0) { + $tooltip = $('
').appendTo('body'); + } + + $tooltip.text(text) + .css({ + position: 'absolute', + left: x + 10, + top: y - 30, + background: '#333', + color: '#fff', + padding: '5px 10px', + borderRadius: '4px', + fontSize: '12px', + zIndex: 9999, + maxWidth: '300px', + wordWrap: 'break-word' + }) + .fadeIn(200); + } + + function hideTooltip() { + $('#bankily-tooltip').fadeOut(200); + } + + function updateTooltipPosition(x, y) { + $('#bankily-tooltip').css({ + left: x + 10, + top: y - 30 + }); + } + + function updateTimeStamps() { + $('.transaction-row').each(function() { + var $row = $(this); + var createdAt = $row.find('[data-timestamp]').data('timestamp'); + + if (createdAt) { + var timeAgo = formatTimeAgo(new Date(createdAt * 1000)); + $row.find('.time-ago').text(timeAgo); + } + }); + } + + function formatTimeAgo(date) { + var now = new Date(); + var diffMs = now - date; + var diffMins = Math.floor(diffMs / 60000); + var diffHours = Math.floor(diffMins / 60); + var diffDays = Math.floor(diffHours / 24); + + if (diffDays > 0) { + return diffDays + ' jour' + (diffDays > 1 ? 's' : ''); + } else if (diffHours > 0) { + return diffHours + ' heure' + (diffHours > 1 ? 's' : ''); + } else if (diffMins > 0) { + return diffMins + ' minute' + (diffMins > 1 ? 's' : ''); + } else { + return 'À l\'instant'; + } + } + + function startAutoRefresh() { + // Rafraîchir automatiquement toutes les 30 secondes si il y a des transactions en attente + if ($('.bankily-status-ta').length > 0) { + autoRefreshInterval = setTimeout(function() { + if (!checking) { + showNotice('info', 'Actualisation automatique...', 2000); + setTimeout(function() { + window.location.reload(); + }, 1000); + } + }, 30000); + } + } + + function setupLiveSearch() { + var searchTimeout; + var $searchInput = $('input[name="search"]'); + + if ($searchInput.length) { + $searchInput.on('input', function() { + clearTimeout(searchTimeout); + var query = $(this).val().toLowerCase(); + + searchTimeout = setTimeout(function() { + filterTransactions(query); + }, 300); + }); + } + } + + function filterTransactions(query) { + if (!query) { + $('.transaction-row').show(); + updateDisplayedCount(); + return; + } + + $('.transaction-row').each(function() { + var $row = $(this); + var text = $row.text().toLowerCase(); + + if (text.indexOf(query) !== -1) { + $row.show(); + } else { + $row.hide(); + } + }); + + updateDisplayedCount(); + } + + function updateDisplayedCount() { + var visibleCount = $('.transaction-row:visible').length; + $('.displaying-num').text(visibleCount + ' élément' + (visibleCount > 1 ? 's' : '')); + } + + function setupKeyboardShortcuts() { + $(document).on('keydown', function(e) { + // Ctrl+R pour rafraîchir + if (e.ctrlKey && e.keyCode === 82) { + e.preventDefault(); + window.location.reload(); + } + + // Ctrl+A pour sélectionner tout + if (e.ctrlKey && e.keyCode === 65 && $('.transaction-row').length > 0) { + e.preventDefault(); + $('#cb-select-all').prop('checked', true).trigger('change'); + } + + // Échap pour désélectionner + if (e.keyCode === 27) { + $('#cb-select-all').prop('checked', false).trigger('change'); + hideProgressBar(); + } + }); + } + + function checkConnectionStatus() { + $.ajax({ + url: bankily_admin_ajax.ajax_url, + type: 'POST', + data: { + action: 'bankily_ping', + nonce: bankily_admin_ajax.nonce + }, + timeout: 5000, + success: function() { + updateConnectionStatus(true); + }, + error: function() { + updateConnectionStatus(false); + } + }); + } + + function updateConnectionStatus(isOnline) { + var $indicator = $('#bankily-connection-status'); + if ($indicator.length === 0) { + $indicator = $('
').appendTo('body'); + } + + $indicator.removeClass('online offline') + .addClass(isOnline ? 'online' : 'offline') + .text(isOnline ? '🟢 En ligne' : '🔴 Hors ligne'); + } + + // Fonctions globales pour les boutons (exposées au scope global) + window.bankilyCheckTransaction = function(operationId, transactionId) { + if (checking) { + return; + } + + checking = true; + var $button = $('button[onclick*="' + transactionId + '"]').first(); + var originalText = $button.text(); + var $row = $('#transaction-' + transactionId); + + $button.prop('disabled', true).addClass('bankily-loading').text(bankily_admin_ajax.strings.checking); + $row.addClass('bankily-checking'); + + $.ajax({ + url: bankily_admin_ajax.ajax_url, + type: 'POST', + data: { + action: 'bankily_check_transaction', + operation_id: operationId, + transaction_id: transactionId, + nonce: bankily_admin_ajax.nonce + }, + success: function(response) { + if (response.success) { + updateTransactionRow(transactionId, response.data); + showNotice('success', response.data.message); + + // Animation de succès + $row.addClass('bankily-success'); + setTimeout(function() { + $row.removeClass('bankily-success'); + }, 2000); + } else { + showNotice('error', response.data); + $row.addClass('bankily-error'); + setTimeout(function() { + $row.removeClass('bankily-error'); + }, 2000); + } + }, + error: function(xhr, status, error) { + showNotice('error', 'Erreur de connexion: ' + error); + $row.addClass('bankily-error'); + setTimeout(function() { + $row.removeClass('bankily-error'); + }, 2000); + }, + complete: function() { + $button.prop('disabled', false) + .removeClass('bankily-loading') + .text(originalText); + $row.removeClass('bankily-checking'); + checking = false; + } + }); + }; + + window.bankilyCheckAllPending = function() { + if (checking) { + return; + } + + var $pendingRows = $('.bankily-status-ta').closest('tr'); + if ($pendingRows.length === 0) { + showNotice('info', 'Aucune transaction en attente à vérifier.'); + return; + } + + if (!confirm('Vérifier toutes les ' + $pendingRows.length + ' transactions en attente ?\n\nCela peut prendre plusieurs minutes.')) { + return; + } + + checking = true; + var transactionIds = []; + + $pendingRows.each(function() { + var $checkbox = $(this).find('input[name="transaction_ids[]"]'); + if ($checkbox.length > 0) { + transactionIds.push($checkbox.val()); + } + }); + + if (transactionIds.length === 0) { + checking = false; + showNotice('warning', 'Impossible de récupérer les IDs des transactions.'); + return; + } + + var $progressBar = showProgressBar(transactionIds.length); + + // Traitement par lots pour éviter de surcharger le serveur + processBatch(transactionIds, 0, $progressBar, 5); // Taille de lot : 5 + }; + + function processBatch(transactionIds, startIndex, $progressBar, batchSize) { + var batch = transactionIds.slice(startIndex, startIndex + batchSize); + + if (batch.length === 0) { + hideProgressBar(); + checking = false; + showNotice('success', 'Vérification terminée pour toutes les transactions.'); + + // Rafraîchir la page après un délai + setTimeout(function() { + window.location.reload(); + }, 2000); + return; + } + + updateProgressBar($progressBar, startIndex, transactionIds.length); + + $.ajax({ + url: bankily_admin_ajax.ajax_url, + type: 'POST', + data: { + action: 'bankily_bulk_check', + transaction_ids: batch, + nonce: bankily_admin_ajax.nonce + }, + success: function(response) { + if (response.success) { + response.data.forEach(function(result) { + if (result.status === 'success') { + updateTransactionRow(result.id, { + status: result.new_status, + status_label: getStatusLabel(result.new_status) + }); + } + }); + } + + // Délai entre les lots + setTimeout(function() { + processBatch(transactionIds, startIndex + batchSize, $progressBar, batchSize); + }, 2000); // 2 secondes entre les lots + }, + error: function() { + hideProgressBar(); + checking = false; + showNotice('error', 'Erreur lors de la vérification groupée.'); + } + }); + } + + function updateTransactionRow(transactionId, data) { + var $row = $('#transaction-' + transactionId); + + if (data.status) { + var $statusCell = $row.find('.bankily-status'); + $statusCell.removeClass('bankily-status-ts bankily-status-tf bankily-status-ta') + .addClass('bankily-status-' + data.status.toLowerCase()) + .text(data.status_label || getStatusLabel(data.status)); + } + + if (data.transaction_id) { + var $operationCell = $row.find('.operation-id'); + if (!$operationCell.find('small').length) { + $operationCell.append('
TXN: ' + data.transaction_id + ''); + } + } + + // Mettre à jour le compteur de tentatives + var $attemptsCell = $row.find('td').eq(-2); + var currentAttempts = parseInt($attemptsCell.text()) || 0; + $attemptsCell.text(currentAttempts + 1); + + // Mettre à jour l'heure de dernière vérification + var now = new Date(); + var $lastCheckedCell = $row.find('td').eq(-3); + $lastCheckedCell.text(formatDateTime(now)); + + // Animation de mise à jour + $row.addClass('updated'); + setTimeout(function() { + $row.removeClass('updated'); + }, 2000); + } + + function getStatusLabel(status) { + var labels = { + 'TS': bankily_admin_ajax.strings.success, + 'TF': bankily_admin_ajax.strings.failed, + 'TA': bankily_admin_ajax.strings.pending + }; + return labels[status] || status; + } + + function formatDateTime(date) { + return date.toLocaleDateString('fr-FR', { + day: '2-digit', + month: '2-digit', + year: 'numeric', + hour: '2-digit', + minute: '2-digit' + }); + } + + function showProgressBar(total) { + var progressHtml = ` +
+
+

🔄 Vérification des transactions en cours...

+
+
+
+
0 / ${total}
+

⏱ Cette opération peut prendre plusieurs minutes. Veuillez patienter...

+ +
+
+ `; + + $('body').append(progressHtml); + return $('#bankily-progress-overlay'); + } + + function updateProgressBar($progressBar, current, total) { + var percentage = (current / total) * 100; + $progressBar.find('.bankily-progress-fill').css('width', percentage + '%'); + $progressBar.find('.bankily-progress-text').text(current + ' / ' + total + ' (' + Math.round(percentage) + '%)'); + } + + function hideProgressBar() { + $('#bankily-progress-overlay').fadeOut(function() { + $(this).remove(); + }); + } + + window.bankilyStopProcessing = function() { + if (confirm('Êtes-vous sûr de vouloir arrêter le processus ?')) { + checking = false; + hideProgressBar(); + showNotice('warning', 'Processus arrêté par l\'utilisateur.'); + } + }; + + window.bankilyBulkAction = function() { + var action = $('#bulk-action-selector-top').val(); + var selectedIds = []; + + $('input[name="transaction_ids[]"]:checked').each(function() { + selectedIds.push($(this).val()); + }); + + if (selectedIds.length === 0) { + showNotice('warning', 'Veuillez sélectionner au moins une transaction.'); + return; + } + + if (!confirm(bankily_admin_ajax.strings.confirm_bulk + '\n\n' + selectedIds.length + ' transactions sélectionnées.')) { + return; + } + + switch (action) { + case 'check': + bankilyBulkCheck(selectedIds); + break; + case 'mark-failed': + bankilyBulkMarkFailed(selectedIds); + break; + default: + showNotice('warning', 'Veuillez sélectionner une action.'); + } + }; + + function bankilyBulkCheck(transactionIds) { + if (checking) { + return; + } + + checking = true; + var $progressBar = showProgressBar(transactionIds.length); + + processBatch(transactionIds, 0, $progressBar, 3); // Taille de lot réduite pour les actions manuelles + } + + function bankilyBulkMarkFailed(transactionIds) { + if (checking) { + return; + } + + checking = true; + + $.ajax({ + url: bankily_admin_ajax.ajax_url, + type: 'POST', + data: { + action: 'bankily_bulk_mark_failed', + transaction_ids: transactionIds, + nonce: bankily_admin_ajax.nonce + }, + success: function(response) { + if (response.success) { + transactionIds.forEach(function(id) { + updateTransactionRow(id, { + status: 'TF', + status_label: getStatusLabel('TF') + }); + }); + showNotice('success', response.data.message); + } else { + showNotice('error', 'Erreur lors du marquage des transactions.'); + } + }, + error: function() { + showNotice('error', bankily_admin_ajax.strings.error); + }, + complete: function() { + checking = false; + } + }); + } + + window.bankilyMarkAsFailed = function(transactionId) { + if (!confirm('Êtes-vous sûr de vouloir marquer cette transaction comme échouée ?\n\nCette action est irréversible.')) { + return; + } + + bankilyBulkMarkFailed([transactionId]); + }; + + window.bankilyExportTransactions = function() { + showNotice('info', 'Préparation de l\'export...'); + var url = bankily_admin_ajax.ajax_url + '?action=bankily_export_transactions&nonce=' + bankily_admin_ajax.nonce; + + // Créer un lien de téléchargement invisible + var $link = $('').attr({ + href: url, + download: 'bankily-transactions-' + new Date().toISOString().split('T')[0] + '.csv' + }).appendTo('body'); + + $link[0].click(); + $link.remove(); + + showNotice('success', 'Export lancé. Le téléchargement va commencer.', 3000); + }; + + window.bankilyCleanOldTransactions = function() { + if (!confirm('Êtes-vous sûr de vouloir supprimer les transactions de plus de 6 mois ?\n\n⚠️ Cette action est irréversible !')) { + return; + } + + $.ajax({ + url: bankily_admin_ajax.ajax_url, + type: 'POST', + data: { + action: 'bankily_clean_old_transactions', + nonce: bankily_admin_ajax.nonce + }, + success: function(response) { + if (response.success) { + showNotice('success', response.data.message); + } else { + showNotice('error', 'Erreur lors du nettoyage.'); + } + }, + error: function() { + showNotice('error', bankily_admin_ajax.strings.error); + } + }); + }; + + function showNotice(type, message, autoHide = 5000) { + // Supprimer les anciennes notices + $('.bankily-notice').remove(); + + var noticeClass = 'notice-' + type; + var icon = { + 'success': '✅', + 'error': '❌', + 'warning': '⚠️', + 'info': 'ℹ️' + }[type] || ''; + + var noticeHtml = ` +
+

${icon} ${message}

+ +
+ `; + + // Ajouter la nouvelle notice + $('.wrap h1').first().after(noticeHtml); + + // Gestion du bouton de fermeture + $('.notice-dismiss').on('click', function() { + $(this).closest('.notice').fadeOut(); + }); + + // Auto-fermeture + if (autoHide && autoHide > 0) { + setTimeout(function() { + $('.bankily-notice').fadeOut(); + }, autoHide); + } + + // Faire défiler vers la notice + $('html, body').animate({ + scrollTop: $('.bankily-notice').offset().top - 100 + }, 300); + } + + // Amélioration UX : Confirmation avant fermeture de page si traitement en cours + window.addEventListener('beforeunload', function(e) { + if (checking) { + e.preventDefault(); + e.returnValue = 'Une vérification est en cours. Êtes-vous sûr de vouloir quitter ?'; + return e.returnValue; + } + }); + + // Nettoyage lors du déchargement de la page + $(window).on('unload', function() { + if (autoRefreshInterval) { + clearTimeout(autoRefreshInterval); + } + checking = false; + }); + + // Stats en temps réel (si sur le tableau de bord) + if (window.location.href.indexOf('bankily-transactions') > -1 && window.location.href.indexOf('pending') === -1) { + setInterval(function() { + if (!checking) { + updateDashboardStats(); + } + }, 60000); // Mettre à jour toutes les minutes + } + + function updateDashboardStats() { + $.ajax({ + url: bankily_admin_ajax.ajax_url, + type: 'POST', + data: { + action: 'bankily_get_dashboard_stats', + nonce: bankily_admin_ajax.nonce + }, + success: function(response) { + if (response.success) { + updateStatCards(response.data); + } + }, + error: function() { + console.log('Erreur lors de la mise à jour des stats'); + } + }); + } + + function updateStatCards(stats) { + $('.bankily-stat-card.total h3').text(stats.total || 0); + $('.bankily-stat-card.success h3').text(stats.success || 0); + $('.bankily-stat-card.pending h3').text(stats.pending || 0); + $('.bankily-stat-card.failed h3').text(stats.failed || 0); + $('.bankily-stat-card.amount h3').text((stats.total_amount || 0).toLocaleString('fr-FR') + ' MRU'); + } + + // Log d'initialisation + console.log('[B-PAY Admin] Interface d\'administration initialisée', { + checking: checking, + page: window.location.href, + ajax_url: bankily_admin_ajax.ajax_url + }); +}); \ No newline at end of file diff --git a/assets/bankily-bpay.js b/assets/bankily-bpay.js new file mode 100644 index 0000000..47fde71 --- /dev/null +++ b/assets/bankily-bpay.js @@ -0,0 +1,435 @@ +/** + * Script JavaScript pour le frontend B-PAY Bankily + * Fichier: assets/bankily-bpay.js + * Version: 1.0.0 + */ + +jQuery(document).ready(function($) { + 'use strict'; + + // Variables globales + var bankily_form = 'form.checkout, form#order_review'; + var bankily_gateway = '#payment_method_bankily_bpay'; + + // Initialisation + initializeBankilyCheckout(); + + function initializeBankilyCheckout() { + // Gestion de la sélection de la méthode de paiement + $(document).on('change', 'input[name="payment_method"]', function() { + toggleBankilyFields(); + if ($(this).val() === 'bankily_bpay') { + // Focus sur le premier champ et pré-remplir en mode test + setTimeout(function() { + $('#bankily_phone').focus(); + if (bankily_bpay_params.testmode === '1') { + fillTestData(); + } + }, 100); + } + }); + + // Validation en temps réel + setupRealtimeValidation(); + + // Formatage des champs + setupFieldFormatting(); + + // Gestion de la soumission + $(bankily_form).on('checkout_place_order_bankily_bpay', function() { + return validateBankilyForm(); + }); + + // Stylisation CSS + addBankilyStyles(); + + // État initial + toggleBankilyFields(); + } + + function setupRealtimeValidation() { + // Validation du numéro de téléphone + $(document).on('input blur', '#bankily_phone', function() { + validatePhoneField($(this)); + }); + + // Validation du code PIN + $(document).on('input blur', '#bankily_passcode', function() { + validatePasscodeField($(this)); + }); + } + + function validatePhoneField($field) { + var phone = $field.val().replace(/\D/g, ''); // Supprimer tous les caractères non numériques + var isValid = /^[0-9]{8}$/.test(phone); + + // Mettre à jour la valeur avec uniquement les chiffres + $field.val(phone); + + // Validation visuelle + updateFieldValidation($field, isValid, phone.length > 0, + 'Format requis: 8 chiffres (ex: 22123456)'); + + // Limiter à 8 chiffres + if (phone.length > 8) { + $field.val(phone.substring(0, 8)); + } + } + + function validatePasscodeField($field) { + var passcode = $field.val(); + var isValid = passcode.length >= 4 && passcode.length <= 6; + + updateFieldValidation($field, isValid, passcode.length > 0, + 'Le code PIN doit contenir entre 4 et 6 caractères'); + } + + function updateFieldValidation($field, isValid, hasContent, errorMessage) { + $field.removeClass('valid invalid'); + $field.next('.bankily-field-error').remove(); + + if (hasContent) { + if (isValid) { + $field.addClass('valid'); + } else { + $field.addClass('invalid'); + $field.after('' + errorMessage + ''); + } + } + } + + function setupFieldFormatting() { + // Permettre uniquement les chiffres pour le téléphone + $(document).on('keypress', '#bankily_phone', function(e) { + // Permettre uniquement les chiffres, backspace, delete, tab, escape, enter + if ($.inArray(e.keyCode, [46, 8, 9, 27, 13]) !== -1 || + // Permettre Ctrl+A, Ctrl+C, Ctrl+V, Ctrl+X + (e.keyCode === 65 && e.ctrlKey === true) || + (e.keyCode === 67 && e.ctrlKey === true) || + (e.keyCode === 86 && e.ctrlKey === true) || + (e.keyCode === 88 && e.ctrlKey === true)) { + return; + } + + // S'assurer que c'est un chiffre + if ((e.shiftKey || (e.keyCode < 48 || e.keyCode > 57)) && (e.keyCode < 96 || e.keyCode > 105)) { + e.preventDefault(); + } + }); + + // Permettre uniquement les chiffres pour le code PIN + $(document).on('keypress', '#bankily_passcode', function(e) { + if ($.inArray(e.keyCode, [46, 8, 9, 27, 13]) !== -1 || + (e.keyCode === 65 && e.ctrlKey === true) || + (e.keyCode === 67 && e.ctrlKey === true) || + (e.keyCode === 86 && e.ctrlKey === true) || + (e.keyCode === 88 && e.ctrlKey === true)) { + return; + } + + if ((e.shiftKey || (e.keyCode < 48 || e.keyCode > 57)) && (e.keyCode < 96 || e.keyCode > 105)) { + e.preventDefault(); + } + }); + } + + function validateBankilyForm() { + if (!$(bankily_gateway).is(':checked')) { + return true; // Pas notre méthode de paiement + } + + var isValid = true; + var $phone = $('#bankily_phone'); + var $passcode = $('#bankily_passcode'); + + // Supprimer les anciens messages d'erreur + $('.bankily-checkout-error').remove(); + + // Validation du téléphone + var phone = $phone.val().replace(/\D/g, ''); + if (!phone || !/^[0-9]{8}$/.test(phone)) { + showCheckoutError($phone, 'Veuillez entrer un numéro de téléphone valide (8 chiffres)'); + isValid = false; + } + + // Validation du code PIN + var passcode = $passcode.val(); + if (!passcode || passcode.length < 4 || passcode.length > 6) { + showCheckoutError($passcode, 'Veuillez entrer votre code PIN B-PAY (4 à 6 chiffres)'); + isValid = false; + } + + if (!isValid) { + // Faire défiler vers le premier champ avec erreur + $('html, body').animate({ + scrollTop: $('.payment_method_bankily_bpay').offset().top - 100 + }, 500); + + // Focus sur le premier champ invalide + setTimeout(function() { + $('.payment_method_bankily_bpay .invalid').first().focus(); + }, 600); + } + + return isValid; + } + + function showCheckoutError($field, message) { + $field.addClass('invalid'); + if (!$field.next('.bankily-checkout-error').length) { + $field.after('
' + message + '
'); + } + } + + function toggleBankilyFields() { + if ($(bankily_gateway).is(':checked')) { + $('.payment_method_bankily_bpay').slideDown(300); + } else { + $('.payment_method_bankily_bpay').slideUp(300); + } + } + + function fillTestData() { + if (bankily_bpay_params.testmode === '1') { + $('#bankily_phone').val('22123456'); + $('#bankily_passcode').val('1234'); + } + } + + function addBankilyStyles() { + var styles = ` + + `; + + if (!$('#bankily-bpay-frontend-styles').length) { + $('head').append(styles); + } + } + + // Gestion du chargement lors de la soumission + $(document).on('submit', bankily_form, function() { + if ($(bankily_gateway).is(':checked')) { + $('.payment_method_bankily_bpay').addClass('processing'); + } + }); + + // Nettoyer l'état de chargement si la soumission échoue + $(document).on('checkout_error', function() { + $('.payment_method_bankily_bpay').removeClass('processing'); + }); + + // Écouter les changements de checkout (pour WooCommerce AJAX) + $(document).on('updated_checkout', function() { + toggleBankilyFields(); + + // Réappliquer la validation sur les champs existants + setTimeout(function() { + $('#bankily_phone').trigger('blur'); + $('#bankily_passcode').trigger('blur'); + }, 100); + }); + + // Amélioration UX: Auto-complétion du préfixe + $(document).on('focus', '#bankily_phone', function() { + var $this = $(this); + if ($this.val() === '' && bankily_bpay_params.testmode !== '1') { + // Suggestion visuelle pour le format attendu + $this.attr('placeholder', '22XXXXXX'); + } + }); + + $(document).on('blur', '#bankily_phone', function() { + $(this).attr('placeholder', 'Exemple: 22123456'); + }); + + // Gestion des raccourcis clavier + $(document).on('keydown', '#bankily_phone, #bankily_passcode', function(e) { + // Enter pour aller au champ suivant + if (e.keyCode === 13) { + e.preventDefault(); + var $current = $(this); + var $next = $current.closest('.form-row').next('.form-row').find('input'); + + if ($next.length) { + $next.focus(); + } else { + // Si c'est le dernier champ, déclencher la soumission + $(bankily_form).find('.place-order').click(); + } + } + }); + + // Validation immédiate lors du collage + $(document).on('paste', '#bankily_phone', function() { + var $this = $(this); + setTimeout(function() { + validatePhoneField($this); + }, 10); + }); + + // Messages d'aide contextuelle + $(document).on('focus', '#bankily_phone', function() { + if (!$(this).next('.bankily-help').length) { + $(this).after('💡 Saisissez votre numéro sans l\'indicatif (+222)'); + } + }); + + $(document).on('blur', '#bankily_phone', function() { + $(this).next('.bankily-help').fadeOut(300, function() { + $(this).remove(); + }); + }); + + $(document).on('focus', '#bankily_passcode', function() { + if (!$(this).next('.bankily-help').length) { + $(this).after('🔐 Votre code PIN personnel B-PAY'); + } + }); + + $(document).on('blur', '#bankily_passcode', function() { + $(this).next('.bankily-help').fadeOut(300, function() { + $(this).remove(); + }); + }); + + // Fonctions utilitaires + function logDebug(message, data) { + if (typeof console !== 'undefined' && console.log && bankily_bpay_params.testmode === '1') { + console.log('[B-PAY Frontend] ' + message, data || ''); + } + } + + // Log d'initialisation + logDebug('Script B-PAY initialisé', { + testmode: bankily_bpay_params.testmode, + gateway_selector: bankily_gateway + }); + + // Nettoyage lors du changement de page + $(window).on('beforeunload', function() { + $('.payment_method_bankily_bpay').removeClass('processing'); + $('.bankily-field-error, .bankily-checkout-error, .bankily-help').remove(); + }); +}); \ No newline at end of file