Plugin Directory

Changeset 3317904


Ignore:
Timestamp:
06/25/2025 11:52:04 PM (9 months ago)
Author:
maxicomdev
Message:

2.0.1

Location:
andy-votre-assistant-intelligent
Files:
1 added
5 edited
6 copied

Legend:

Unmodified
Added
Removed
  • andy-votre-assistant-intelligent/tags/2.1.0/Andy-Wordress-Extension.php

    r3309069 r3317904  
    9191    $plugin_url = plugin_dir_url(__FILE__);
    9292
     93    // Get all contact methods
     94    $contact_methods = [];
     95    $contact_fields = [
     96        'messenger_dm', 'tiktok_page', 'insta_page', 'whatsapp_dm',
     97        'facebook_page', 'linkedin_page', 'mail', 'tel', 'adresse',
     98        'contact_page', 'twitter', 'youtube'
     99    ];
     100   
     101    foreach ($contact_fields as $field) {
     102        $value = get_option('andy_contact_' . $field, '');
     103        if (!empty($value)) {
     104            $contact_methods[$field] = $value;
     105        }
     106    }
     107
    93108    // Check WP version
    94109    global $wp_version;
     
    99114            'strategy' => 'defer',
    100115        ]);
     116       
     117        // Pass contact methods to JavaScript
     118        wp_localize_script('andy-script', 'andyContactMethods', $contact_methods);
    101119    } else {
    102120        // Old WordPress way
     
    414432        'andy_injector_section'
    415433    );
     434
     435    // Add Moyens de contact section
     436    add_settings_section(
     437        'andy_contact_section',
     438        esc_html__('Moyens de contact', 'andy-votre-assistant-intelligent'),
     439        'andy_contact_section_callback',
     440        'andyInjector'
     441    );
     442
     443    // Define contact methods with their specific configurations
     444    $contact_methods = [
     445        'messenger_dm' => [
     446            'label' => 'Lien Messenger DM',
     447            'type' => 'url',
     448            'placeholder' => 'https://m.me/votrenom',
     449            'sanitize' => 'esc_url_raw'
     450        ],
     451        'tiktok_page' => [
     452            'label' => 'Page TikTok',
     453            'type' => 'url',
     454            'placeholder' => 'https://www.tiktok.com/@votrenom',
     455            'sanitize' => 'esc_url_raw'
     456        ],
     457        'insta_page' => [
     458            'label' => 'Page Instagram',
     459            'type' => 'url',
     460            'placeholder' => 'https://www.instagram.com/votrenom',
     461            'sanitize' => 'esc_url_raw'
     462        ],
     463        'whatsapp_dm' => [
     464            'label' => 'Lien WhatsApp DM',
     465            'type' => 'url',
     466            'placeholder' => 'https://wa.me/33612345678',
     467            'sanitize' => 'esc_url_raw'
     468        ],
     469        'facebook_page' => [
     470            'label' => 'Page Facebook',
     471            'type' => 'url',
     472            'placeholder' => 'https://www.facebook.com/votrepage',
     473            'sanitize' => 'esc_url_raw'
     474        ],
     475        'linkedin_page' => [
     476            'label' => 'Page LinkedIn',
     477            'type' => 'url',
     478            'placeholder' => 'https://www.linkedin.com/company/votresociete',
     479            'sanitize' => 'esc_url_raw'
     480        ],
     481        'mail' => [
     482            'label' => 'Adresse email',
     483            'type' => 'email',
     484            'placeholder' => '[email protected]',
     485            'sanitize' => 'sanitize_email'
     486        ],
     487        'tel' => [
     488            'label' => 'Numéro de téléphone',
     489            'type' => 'tel',
     490            'placeholder' => '+33 6 12 34 56 78',
     491            'sanitize' => 'sanitize_text_field'
     492        ],
     493        'adresse' => [
     494            'label' => 'Adresse physique',
     495            'type' => 'text',
     496            'placeholder' => '123 Rue Exemple, 75000 Paris',
     497            'sanitize' => 'sanitize_text_field'
     498        ],
     499        'contact_page' => [
     500            'label' => 'Lien page de contact',
     501            'type' => 'url',
     502            'placeholder' => 'https://votresite.com/contact',
     503            'sanitize' => 'esc_url_raw'
     504        ],
     505        'twitter' => [
     506            'label' => 'Page Twitter (X)',
     507            'type' => 'url',
     508            'placeholder' => 'https://twitter.com/votrenom',
     509            'sanitize' => 'esc_url_raw'
     510        ],
     511        'youtube' => [
     512            'label' => 'Chaîne YouTube',
     513            'type' => 'url',
     514            'placeholder' => 'https://www.youtube.com/@votrechaine',
     515            'sanitize' => 'esc_url_raw'
     516        ]
     517    ];
     518
     519    // Register and add settings fields for each contact method
     520    foreach ($contact_methods as $key => $config) {
     521        $option_name = 'andy_contact_' . $key;
     522       
     523        register_setting('andyInjector', $option_name, [
     524            'sanitize_callback' => $config['sanitize'],
     525        ]);
     526
     527        add_settings_field(
     528            $option_name,
     529            esc_html__($config['label'], 'andy-votre-assistant-intelligent'),
     530            'andy_contact_field_render',
     531            'andyInjector',
     532            'andy_contact_section',
     533            [
     534                'label_for' => $option_name,
     535                'placeholder' => $config['placeholder'],
     536                'type' => $config['type']
     537            ]
     538        );
     539    }
    416540}
    417541
     
    435559}
    436560
     561/**
     562 * Adjust color brightness
     563 */
     564function andy_adjust_brightness($hex, $steps) {
     565    // Remove # from hex code if present
     566    $hex = ltrim($hex, '#');
     567   
     568    // Convert to RGB
     569    $r = hexdec(substr($hex, 0, 2));
     570    $g = hexdec(substr($hex, 2, 2));
     571    $b = hexdec(substr($hex, 4, 2));
     572   
     573    // Adjust brightness
     574    $r = max(0, min(255, $r + $steps));
     575    $g = max(0, min(255, $g + $steps));
     576    $b = max(0, min(255, $b + $steps));
     577   
     578    // Convert back to hex
     579    return '#' . str_pad(dechex($r), 2, '0', STR_PAD_LEFT)
     580                . str_pad(dechex($g), 2, '0', STR_PAD_LEFT)
     581                . str_pad(dechex($b), 2, '0', STR_PAD_LEFT);
     582}
     583
    437584add_action('wp_head', 'andy_injector_custom_style');
    438585function andy_injector_custom_style() {
     
    440587    $primary = get_option('andy_injector_primary_color', '#007bff');
    441588
     589    // Generate color variants
     590    $primary_dark = andy_adjust_brightness($primary, -25);
     591    $primary_light = andy_adjust_brightness($primary, 140);
     592   
    442593    // Dynamic CSS injection
    443     $custom_css = ":root { --primary-color: " . esc_attr($primary) . " !important; }";
     594    $custom_css = ":root {
     595        --primary-color: " . esc_attr($primary) . " !important;
     596        --primary-color-dark: " . $primary_dark . " !important;
     597        --primary-color-light: " . $primary_light . " !important;
     598        --primary-color-shadow: " . $primary . "33 !important; /* 20% opacity */
     599    }";
    444600
    445601    wp_enqueue_style('andy-style', $plugin_url . 'Andy/assets/Andy-Widget/styles/Andy.css', [], '2.0.7');
     
    478634 */
    479635function andy_injector_open_on_load_render() {
    480     $value = get_option('andy_injector_open_on_load', '0');
    481 
    482     echo '<input type="checkbox" id="andy_injector_open_on_load" name="andy_injector_open_on_load" value="1" ' . checked($value, '1', false) . ' /> ';
     636    $options = get_option('andy_injector_open_on_load', '0');
     637    ?>
     638    <input type='checkbox' name='andy_injector_open_on_load' value='1' <?php checked('1', $options); ?>>
     639    <label for="andy_injector_open_on_load">Cochez pour ouvrir automatiquement la fenêtre de chat au chargement de la page.</label>
     640    <?php
     641}
     642
     643// Contact section description
     644function andy_contact_section_callback() {
     645    echo '<p>' . esc_html__('Ajoutez vos liens de contact pour les intégrer au widget. Tous les champs sont optionnels.', 'andy-votre-assistant-intelligent') . '</p>';
     646}
     647
     648// Render contact field
     649function andy_contact_field_render($args) {
     650    $option = get_option($args['label_for']);
     651    $type = isset($args['type']) ? $args['type'] : 'text';
     652    $placeholder = isset($args['placeholder']) ? $args['placeholder'] : '';
     653   
     654    // Special handling for different field types
     655    switch ($type) {
     656        case 'email':
     657            $value = esc_attr($option);
     658            break;
     659        case 'tel':
     660            $value = esc_attr($option);
     661            break;
     662        case 'text':
     663            $value = esc_attr($option);
     664            break;
     665        default: // url
     666            $value = esc_url($option);
     667    }
     668    ?>
     669    <input type="<?php echo esc_attr($type); ?>"
     670           id="<?php echo esc_attr($args['label_for']); ?>"
     671           name="<?php echo esc_attr($args['label_for']); ?>"
     672           value="<?php echo $value; ?>"
     673           placeholder="<?php echo esc_attr($placeholder); ?>"
     674           class="regular-text">
     675    <?php
    483676}
    484677
  • andy-votre-assistant-intelligent/tags/2.1.0/Andy/Andy.html

    r3291395 r3317904  
    1717        <!-- ANDY WIDGET -->
    1818        <div class="andy-position-right">
    19             <!-- Tooltip -->
    20             <div id="chat-tooltip" class="medium">
    21                 <span id="tooltip-text" class="no-select"></span>
     19            <!-- Contact Methods Toggle -->
     20            <div id="contact-toggle" class="contact-methods-toggle medium" title="Contact Us">
     21                <?xml version="1.0" encoding="iso-8859-1"?>
     22                <!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
     23                <svg fill="#ffffff" height="800px" width="800px" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
     24                     viewBox="0 0 32.055 32.055" xml:space="preserve">
     25                <g>
     26                    <path d="M3.968,12.061C1.775,12.061,0,13.835,0,16.027c0,2.192,1.773,3.967,3.968,3.967c2.189,0,3.966-1.772,3.966-3.967
     27                        C7.934,13.835,6.157,12.061,3.968,12.061z M16.233,12.061c-2.188,0-3.968,1.773-3.968,3.965c0,2.192,1.778,3.967,3.968,3.967
     28                        s3.97-1.772,3.97-3.967C20.201,13.835,18.423,12.061,16.233,12.061z M28.09,12.061c-2.192,0-3.969,1.774-3.969,3.967
     29                        c0,2.19,1.774,3.965,3.969,3.965c2.188,0,3.965-1.772,3.965-3.965S30.278,12.061,28.09,12.061z"/>
     30                </g>
     31                </svg>
    2232            </div>
    2333
    24             <!-- Bulle de chat -->
    25             <div id="chat-bubble" class="no-select medium">
    26                 <svg
    27                     fill="#ffffff"
    28                    
    29                     version="1.1"
    30                     id="Capa_1"
    31                     xmlns="http://www.w3.org/2000/svg"
    32                     xmlns:xlink="http://www.w3.org/1999/xlink"
    33                    
    34                     viewBox="0 0 60 60"
    35                    
    36                     xml:space="preserve"
    37                 >
    38                     <path d="M30,1.5c-16.542,0-30,12.112-30,27c0,5.204,1.646,10.245,4.768,14.604c-0.591,6.537-2.175,11.39-4.475,13.689 c-0.304,0.304-0.38,0.769-0.188,1.153C0.275,58.289,0.625,58.5,1,58.5c0.046,0,0.092-0.003,0.139-0.01 c0.405-0.057,9.813-1.411,16.618-5.339C21.621,54.71,25.737,55.5,30,55.5c16.542,0,30-12.112,30-27S46.542,1.5,30,1.5z M16,32.5 c-2.206,0-4-1.794-4-4s1.794-4,4-4s4,1.794,4,4S18.206,32.5,16,32.5z M30,32.5c-2.206,0-4-1.794-4-4s1.794-4,4-4s4,1.794,4,4 S32.206,32.5,30,32.5z M44,32.5c-2.206,0-4-1.794-4-4s1.794-4,4-4s4,1.794,4,4S46.206,32.5,44,32.5z"/>
    39                 </svg>
     34            <!-- Contact Methods List -->
     35            <div id="contact-methods" class="contact-methods-list">
     36                <div class="contact-methods-header">
     37                    <h3>Nous contacter :</h3>
     38                    <button class="close-contact-methods">
     39                        <svg viewBox="0 0 24 24" fill="currentColor">
     40                            <path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>
     41                        </svg>
     42                    </button>
     43                </div>
     44                <div class="contact-methods-content">
     45                    <!-- Will be populated by JavaScript -->
     46                     
     47                </div>
    4048            </div>
    4149
  • andy-votre-assistant-intelligent/tags/2.1.0/Andy/assets/Andy-Widget/scripts/Andy.js

    r3309069 r3317904  
    22const WEB_SOCKET_URL = `wss://dashboard.essayez-andy.fr/ws/`;
    33
     4// DOM Elements
    45const chatTooltip = document.getElementById('chat-tooltip');
    56const chatTooltipSpan = document.getElementById('tooltip-text');
    6 const chatBubble = document.getElementById('chat-bubble');
    77const chatBox = document.getElementById('chatbox');
    88const chatContent = document.getElementById('chat-content');
    99const chatInput = document.getElementById('chat-input');
    10 
     10const contactToggle = document.getElementById('contact-toggle');
     11const contactMethodsList = document.getElementById('contact-methods');
     12const contactMethodsContent = document.querySelector('.contact-methods-content');
     13const closeContactMethods = document.querySelector('.close-contact-methods');
     14
     15// Buttons
    1116const sendButton = document.getElementById('send-button');
    1217const microphoneButton = document.getElementById('microphone-button');
    1318const closeButton = document.getElementById('close-button');
     19
     20// Icons for contact methods
     21const CONTACT_ICONS = {
     22    'messenger_dm': 'fab fa-facebook-messenger',
     23    'tiktok_page': 'fab fa-tiktok',
     24    'insta_page': 'fab fa-instagram',
     25    'whatsapp_dm': 'fab fa-whatsapp',
     26    'facebook_page': 'fab fa-facebook-f',
     27    'linkedin_page': 'fab fa-linkedin-in',
     28    'mail': 'fas fa-envelope',
     29    'tel': 'fas fa-phone',
     30    'adresse': 'fas fa-map-marker-alt',
     31    'contact_page': 'fas fa-link',
     32    'twitter': 'fab fa-twitter',
     33    'youtube': 'fab fa-youtube'
     34};
     35
     36// Labels for contact methods
     37const CONTACT_LABELS = {
     38    'messenger_dm': 'Messenger',
     39    'tiktok_page': 'TikTok',
     40    'insta_page': 'Instagram',
     41    'whatsapp_dm': 'WhatsApp',
     42    'facebook_page': 'Facebook',
     43    'linkedin_page': 'LinkedIn',
     44    'mail': 'Email',
     45    'tel': 'Téléphone',
     46    'adresse': 'Adresse',
     47    'contact_page': 'Contact',
     48    'twitter': 'Twitter',
     49    'youtube': 'YouTube'
     50};
    1451/* CONST SECTION END */
     52
     53// Initialize contact methods when DOM is loaded
     54document.addEventListener('DOMContentLoaded', function() {
     55    // Add Font Awesome if not already added
     56    if (!document.querySelector('link[href*="font-awesome"]')) {
     57        const fontAwesome = document.createElement('link');
     58        fontAwesome.rel = 'stylesheet';
     59        fontAwesome.href = 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css';
     60        document.head.appendChild(fontAwesome);
     61    }
     62
     63    // Initialize contact methods if they exist
     64    if (typeof andyContactMethods !== 'undefined') {
     65        initContactMethods();
     66    }
     67});
     68
     69// Toggle contact methods list
     70function toggleContactMethods() {
     71    contactMethodsList.classList.toggle('active');
     72}
     73
     74// Close contact methods list
     75function closeContactMethodsList() {
     76    contactMethodsList.classList.remove('active');
     77}
     78
     79// Initialize contact methods
     80function initContactMethods() {
     81    // Clear existing content
     82    contactMethodsContent.innerHTML = '';
     83   
     84    // Always add live chat first
     85    const liveChatItem = document.createElement('a');
     86    liveChatItem.className = 'contact-method-item';
     87    liveChatItem.href = '#';
     88    liveChatItem.title = 'Live Chat';
     89
     90    /* CHAT BUBBLE CLICK EVENT SECTION */
     91    // Lorsque la bulle de chat est cliquée, on affiche la fenêtre
     92    liveChatItem.onclick = function() {
     93        chatBox.style.display = (chatBox.style.display === 'none' || chatBox.style.display === '') ? 'flex' : 'none';
     94
     95        if (chatBox.style.display === 'flex') {
     96            closeContactMethodsList();
     97        }
     98   
     99        chatInput.focus();
     100       
     101        if (
     102            chatBox.style.display === 'flex' &&
     103            chatTooltip.classList.contains('visible')
     104        ) {
     105            chatTooltip.classList.remove('visible');
     106        }
     107   
     108        if (
     109            webSocket === null &&
     110   
     111            !doesCookieExist('Andy-Conversation-Uuid') &&
     112            !doesCookieExist('Andy-Conversation-Human-Requested')
     113        ) {
     114            initConversation();
     115        }
     116    };
     117    /* CHAT BUBBLE CLICK EVENT END */
     118   
     119    const liveChatIcon = document.createElement('i');
     120    liveChatIcon.className = 'fas fa-comment-dots';
     121    liveChatItem.appendChild(liveChatIcon);
     122    contactMethodsContent.appendChild(liveChatItem);
     123   
     124    // Add other contact methods
     125    Object.entries(andyContactMethods).forEach(([key, value]) => {
     126        if (!value) return;
     127       
     128        const contactItem = document.createElement('a');
     129        contactItem.className = 'contact-method-item';
     130        contactItem.href = getContactUrl(key, value);
     131        contactItem.target = key === 'mail' || key === 'tel' ? '_self' : '_blank';
     132        contactItem.rel = 'noopener noreferrer';
     133        contactItem.title = CONTACT_LABELS[key] || key.replace('_', ' ');
     134       
     135        const icon = document.createElement('i');
     136        icon.className = CONTACT_ICONS[key] || 'fas fa-link';
     137       
     138        contactItem.appendChild(icon);
     139        contactMethodsContent.appendChild(contactItem);
     140    });
     141   
     142    // Add event listeners
     143    if (contactToggle) {
     144        contactToggle.addEventListener('click', toggleContactMethods);
     145    }
     146   
     147    if (closeContactMethods) {
     148        closeContactMethods.addEventListener('click', closeContactMethodsList);
     149    }
     150   
     151    // Close when clicking outside
     152    document.addEventListener('click', (e) => {
     153        if (!contactMethodsList.contains(e.target) &&
     154            !contactToggle.contains(e.target) &&
     155            contactMethodsList.classList.contains('active')) {
     156            closeContactMethodsList();
     157        }
     158    });
     159}
     160
     161// Get proper URL for contact method
     162function getContactUrl(type, value) {
     163    switch (type) {
     164        case 'mail':
     165            return `mailto:${value}`;
     166        case 'tel':
     167            return `tel:${value.replace(/\s+/g, '')}`;
     168        case 'whatsapp_dm':
     169            return `https://wa.me/${value.replace(/[^0-9]/g, '')}`;
     170        default:
     171            return value;
     172    }
     173}
    15174
    16175/* VARIABLES SECTION */
     
    747906
    748907
    749 /* CHAT BUBBLE CLICK EVENT SECTION */
    750 // Lorsque la bulle de chat est cliquée, on affiche la fenêtre
    751 chatBubble.onclick = function() {
    752     chatBox.style.display = (chatBox.style.display === 'none' || chatBox.style.display === '') ? 'flex' : 'none';
    753 
    754     chatInput.focus();
    755    
    756     if (
    757         chatBox.style.display === 'flex' &&
    758         chatTooltip.classList.contains('visible')
    759     ) {
    760         chatTooltip.classList.remove('visible');
    761     }
    762 
    763     if (
    764         webSocket === null &&
    765 
    766         !doesCookieExist('Andy-Conversation-Uuid') &&
    767         !doesCookieExist('Andy-Conversation-Human-Requested')
    768     ) {
    769         initConversation();
    770     }
    771 };
    772 /* CHAT BUBBLE CLICK EVENT END */
    773908
    774909/* SEND MESSAGE ON ENTER SECTION */
     
    9351070/* MARKDOWN TO HTML SECTION END */
    9361071
    937 /* CODE SECTION FOR INACTIVITY AND POST-ACTIVITY DELAY */
    938 (async () => {
    939     try {
    940         const response = await fetch('https://dashboard.essayez-andy.fr/api/tooltip');
    941         const data = await response.json();
    942 
    943         chatTooltipSpan.textContent = data.tooltip;
    944     } catch (err) {
    945         console.error(err);
    946 
    947         return;
    948     }
    949 
    950     if (chatBox.style.display !== 'flex') {
    951         chatTooltip.classList.add('visible');
    952     }
    953 
    954     let inactivityDelay = 30000; // 30 secondes d'inactivité
    955     let postActivityDelay = 3000; // 3 secondes après retour d'activité
    956 
    957     let inactivityTimeout;
    958     let postActivityTimeout;
    959 
    960     let userIsInactive = false;
    961 
    962     function handleInactivity() {
    963     userIsInactive = true;
    964 
    965     if (chatBox.style.display === 'flex') {
    966         return;
    967     }
    968 
    969     if (!chatTooltip.classList.contains('visible')) {
    970         chatTooltip.classList.add('visible');
    971     }
    972     }
    973 
    974     function handlePostReactivity() {
    975     if (chatTooltip.classList.contains('visible')) {
    976         chatTooltip.classList.remove('visible');
    977     }
    978     }
    979 
    980     function onUserActivity() {
    981     // Si utilisateur était inactif, on déclenche un timer pour l'action post-réactivité
    982     if (userIsInactive) {
    983         clearTimeout(postActivityTimeout);
    984         postActivityTimeout = setTimeout(handlePostReactivity, postActivityDelay);
    985     }
    986 
    987     userIsInactive = false;
    988     clearTimeout(inactivityTimeout);
    989     inactivityTimeout = setTimeout(handleInactivity, inactivityDelay);
    990     }
    991 
    992     // Événements écoutés pour détecter l'activité
    993     ["mousemove", "keydown", "scroll", "click"].forEach(event =>
    994     document.addEventListener(event, onUserActivity)
    995     );
    996 
    997     // Démarre le premier timer
    998     inactivityTimeout = setTimeout(handleInactivity, inactivityDelay);
    999 
    1000     setTimeout(() => {
    1001         if (chatTooltip.classList.contains('visible')) {
    1002             chatTooltip.classList.remove('visible');
    1003         }
    1004     }, 5000);
    1005 
    1006     chatBubble.addEventListener('mouseenter', () => {
    1007         if (chatBox.style.display === 'flex') {
    1008             return ;
    1009         }
    1010 
    1011         if (!chatTooltip.classList.contains('visible')) {
    1012             chatTooltip.classList.add('visible');
    1013         }
    1014     });
    1015 
    1016     chatBubble.addEventListener('mouseleave', () => {
    1017         if (chatBox.style.display === 'flex') {
    1018             return ;
    1019         }
    1020 
    1021         if (chatTooltip.classList.contains('visible')) {
    1022             chatTooltip.classList.remove('visible');
    1023         }
    1024     })
    1025 
    1026     /*
    1027 
    1028         Tooltip shows:
    1029             -During 5s after page load then disappear
    1030             -After 30s inactivity then disappear after 3s of post-activity
    1031             -When hovering the bubble
    1032 
    1033     */
    1034 })();
    1035 /* #### TOOLTIP SECTION END #### */
    1036 
    10371072/* #### REQUEST HUMAN OVERLAY SECTION #### */
    10381073const openHumanRequestOverlayButton = document.getElementById("human-request-header-button");
  • andy-votre-assistant-intelligent/tags/2.1.0/Andy/assets/Andy-Widget/styles/Andy.css

    r3297562 r3317904  
    1616
    1717strong { font-weight: bold; }
     18
     19/* Contact Methods Styles */
     20.contact-methods-toggle {
     21    position: relative;
     22    display: flex;
     23    align-items: center;
     24    justify-content: center;
     25    width: 40px;
     26    height: 40px;
     27    background: var(--primary-color, #4a6cf7);
     28    border: none;
     29    border-radius: 50%;
     30    cursor: pointer;
     31    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
     32    transition: all 0.3s ease;
     33    padding: 0;
     34}
     35
     36.contact-methods-toggle:hover {
     37    background: var(--primary-color-dark, #3a5ce4);
     38    box-shadow: 0 4px 12px rgba(74, 108, 247, 0.2);
     39}
     40
     41.contact-methods-toggle svg {
     42    width: 24px;
     43    height: 24px;
     44    color: white;
     45    transition: all 0.2s ease;
     46}
     47
     48.contact-methods-toggle:hover svg {
     49    transform: scale(1.1);
     50    opacity: 0.9;
     51}
     52
     53.contact-methods-list {
     54    position: fixed;
     55    right: 24px;
     56    bottom: 80px;
     57    width: 300px;
     58    max-height: 70vh;
     59    background: white;
     60    border-radius: 12px;
     61    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
     62    overflow: hidden;
     63    transform: translateY(20px);
     64    opacity: 0;
     65    visibility: hidden;
     66    transition: all 0.3s ease;
     67    z-index: 999999;
     68}
     69
     70.contact-methods-list.active {
     71    transform: translateY(0);
     72    opacity: 1;
     73    visibility: visible;
     74}
     75
     76.contact-methods-header {
     77    display: flex;
     78    justify-content: space-between;
     79    align-items: center;
     80    padding: 16px 20px;
     81    background: #f8f9fa;
     82    border-bottom: 1px solid #e9ecef;
     83}
     84
     85.contact-methods-header h3 {
     86    margin: 0;
     87    font-size: 16px;
     88    color: #2d3748;
     89}
     90
     91.close-contact-methods {
     92    background: none;
     93    border: none;
     94    color: #6c757d;
     95    cursor: pointer;
     96    padding: 4px;
     97    border-radius: 4px;
     98    transition: all 0.2s ease;
     99}
     100
     101.close-contact-methods:hover {
     102    background: #e9ecef;
     103    color: #2d3748;
     104}
     105
     106.close-contact-methods svg {
     107    width: 20px;
     108    height: 20px;
     109}
     110
     111.contact-methods-content {
     112    max-height: calc(70vh - 60px);
     113    overflow-y: auto;
     114    /* padding: 16px 0; */
     115}
     116
     117.contact-method-item {
     118    display: flex;
     119    flex-direction: column;
     120    align-items: center;
     121    justify-content: center;
     122    width: 50px;
     123    height: 50px;
     124    margin: 10px;
     125    background: white;
     126    border-radius: 50%;
     127    color: var(--primary-color, #4a6cf7);
     128    text-decoration: none;
     129    transition: all 0.2s ease;
     130    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
     131    border: 2px solid var(--primary-color, #4a6cf7);
     132}
     133
     134.contact-method-item:hover {
     135    background: var(--primary-color-light, #f0f4ff);
     136    transform: translateY(-2px);
     137    box-shadow: 0 4px 12px var(--primary-color-shadow, rgba(74, 108, 247, 0.2));
     138}
     139
     140.contact-method-item i {
     141    font-size: 24px;
     142    transition: all 0.2s ease;
     143    color: var(--primary-color, #4a6cf7);
     144}
     145
     146.contact-method-item:hover i {
     147    transform: scale(1.1);
     148    color: var(--primary-color-dark, #3a5ce4);
     149}
     150
     151.contact-methods-content {
     152    display: flex;
     153    flex-wrap: wrap;
     154    justify-content: center;
     155    /* padding: 10px 10px; */
     156}
     157
     158/* Position classes */
     159.andy-position-right {
     160    position: fixed;
     161    right: 24px;
     162    bottom: 24px;
     163    z-index: 999998;
     164}
     165
     166.andy-position-left {
     167    position: fixed;
     168    left: 24px;
     169    bottom: 24px;
     170    z-index: 999998;
     171}
     172
     173.andy-position-left #chatbox {
     174    left: 24px;
     175    bottom: 24px;
     176}
     177
     178.andy-position-right #chatbox {
     179    right: 24px;
     180    bottom: 24px;
     181}
     182
     183/* Contact list positioning based on button size */
     184.contact-methods-list {
     185    bottom: 100px; /* Default for medium */
     186}
     187
     188/* Small button */
     189.contact-methods-toggle.small + .contact-methods-list {
     190    bottom: 85px;
     191}
     192
     193/* Medium button (default) */
     194.contact-methods-toggle.medium + .contact-methods-list {
     195    bottom: 100px;
     196}
     197
     198/* Big button */
     199.contact-methods-toggle.big + .contact-methods-list {
     200    bottom: 110px;
     201}
     202
     203/* Very big button */
     204.contact-methods-toggle.very-big + .contact-methods-list {
     205    bottom: 120px;
     206}
     207
     208/* Left position adjustments */
     209.andy-position-left .contact-methods-list {
     210    right: auto;
     211    left: 24px;
     212}
     213
     214/* Responsive */
     215@media (max-width: 480px) {
     216    .contact-methods-list {
     217        width: calc(100% - 32px);
     218        right: 16px;
     219        bottom: 72px;
     220    }
     221   
     222    .andy-position-left .contact-methods-list {
     223        left: 16px;
     224    }
     225}
    18226
    19227menu, ol, ul, li {
     
    24232}
    25233
    26 .andy-position-right #chat-bubble,
    27 .andy-position-right #chatbox {
    28     right: 20px;
    29     left: auto;
    30 }
    31 
    32 .andy-position-left #chat-bubble,
    33 .andy-position-left #chatbox {
    34     left: 20px;
    35     right: auto;
    36 }
    37 
    38234.andy-position-right #chat-tooltip.small {
    39235    bottom: 70px;
     
    117313}
    118314
    119 #chat-bubble.small {
     315#contact-toggle.small {
    120316    width: 50px;
    121317    height: 50px;
    122318}
    123319
    124 #chat-bubble.small svg {
     320#contact-toggle.small svg {
    125321    width: 25px;
    126322    height: 25px;
    127323}
    128324
    129 #chat-bubble.medium {
     325#contact-toggle.medium {
    130326    width: 60px;
    131327    height: 60px;
    132328}
    133329
    134 #chat-bubble.medium svg {
     330#contact-toggle.medium svg {
    135331    width: 30px;
    136332    height: 30px;
    137333}
    138334
    139 #chat-bubble.big {
     335#contact-toggle.big {
    140336    width: 70px;
    141337    height: 70px;
    142338}
    143339
    144 #chat-bubble.big svg {
     340#contact-toggle.big svg {
    145341    width: 35px;
    146342    height: 35px;
    147343}
    148344
    149 #chat-bubble.very-big {
     345#contact-toggle.very-big {
    150346    width: 80px;
    151347    height: 80px;
    152348}
    153349
    154 #chat-bubble.very-big svg {
     350#contact-toggle.very-big svg {
    155351    width: 40px;
    156352    height: 40px;
     
    185381    overscroll-behavior-y: contain;
    186382}
    187 
    188 #chat-bubble.small + #chatbox { bottom: 85px; }
    189 #chat-bubble.medium + #chatbox { bottom: 95px; }
    190 #chat-bubble.big + #chatbox { bottom: 105px; }
    191 #chat-bubble.very-big + #chatbox { bottom: 115px; }
    192383
    193384#chat-content {
  • andy-votre-assistant-intelligent/tags/2.1.0/readme.txt

    r3309069 r3317904  
    66Requires PHP: 7.3 
    77Donate link: https://essayez-andy.fr
    8 Stable tag: 2.0.7
     8Stable tag: 2.1.0
    99License: GPLv2 or later 
    1010License URI: https://www.gnu.org/licenses/gpl-2.0.html 
  • andy-votre-assistant-intelligent/trunk/Andy-Wordress-Extension.php

    r3309069 r3317904  
    9191    $plugin_url = plugin_dir_url(__FILE__);
    9292
     93    // Get all contact methods
     94    $contact_methods = [];
     95    $contact_fields = [
     96        'messenger_dm', 'tiktok_page', 'insta_page', 'whatsapp_dm',
     97        'facebook_page', 'linkedin_page', 'mail', 'tel', 'adresse',
     98        'contact_page', 'twitter', 'youtube'
     99    ];
     100   
     101    foreach ($contact_fields as $field) {
     102        $value = get_option('andy_contact_' . $field, '');
     103        if (!empty($value)) {
     104            $contact_methods[$field] = $value;
     105        }
     106    }
     107
    93108    // Check WP version
    94109    global $wp_version;
     
    99114            'strategy' => 'defer',
    100115        ]);
     116       
     117        // Pass contact methods to JavaScript
     118        wp_localize_script('andy-script', 'andyContactMethods', $contact_methods);
    101119    } else {
    102120        // Old WordPress way
     
    414432        'andy_injector_section'
    415433    );
     434
     435    // Add Moyens de contact section
     436    add_settings_section(
     437        'andy_contact_section',
     438        esc_html__('Moyens de contact', 'andy-votre-assistant-intelligent'),
     439        'andy_contact_section_callback',
     440        'andyInjector'
     441    );
     442
     443    // Define contact methods with their specific configurations
     444    $contact_methods = [
     445        'messenger_dm' => [
     446            'label' => 'Lien Messenger DM',
     447            'type' => 'url',
     448            'placeholder' => 'https://m.me/votrenom',
     449            'sanitize' => 'esc_url_raw'
     450        ],
     451        'tiktok_page' => [
     452            'label' => 'Page TikTok',
     453            'type' => 'url',
     454            'placeholder' => 'https://www.tiktok.com/@votrenom',
     455            'sanitize' => 'esc_url_raw'
     456        ],
     457        'insta_page' => [
     458            'label' => 'Page Instagram',
     459            'type' => 'url',
     460            'placeholder' => 'https://www.instagram.com/votrenom',
     461            'sanitize' => 'esc_url_raw'
     462        ],
     463        'whatsapp_dm' => [
     464            'label' => 'Lien WhatsApp DM',
     465            'type' => 'url',
     466            'placeholder' => 'https://wa.me/33612345678',
     467            'sanitize' => 'esc_url_raw'
     468        ],
     469        'facebook_page' => [
     470            'label' => 'Page Facebook',
     471            'type' => 'url',
     472            'placeholder' => 'https://www.facebook.com/votrepage',
     473            'sanitize' => 'esc_url_raw'
     474        ],
     475        'linkedin_page' => [
     476            'label' => 'Page LinkedIn',
     477            'type' => 'url',
     478            'placeholder' => 'https://www.linkedin.com/company/votresociete',
     479            'sanitize' => 'esc_url_raw'
     480        ],
     481        'mail' => [
     482            'label' => 'Adresse email',
     483            'type' => 'email',
     484            'placeholder' => '[email protected]',
     485            'sanitize' => 'sanitize_email'
     486        ],
     487        'tel' => [
     488            'label' => 'Numéro de téléphone',
     489            'type' => 'tel',
     490            'placeholder' => '+33 6 12 34 56 78',
     491            'sanitize' => 'sanitize_text_field'
     492        ],
     493        'adresse' => [
     494            'label' => 'Adresse physique',
     495            'type' => 'text',
     496            'placeholder' => '123 Rue Exemple, 75000 Paris',
     497            'sanitize' => 'sanitize_text_field'
     498        ],
     499        'contact_page' => [
     500            'label' => 'Lien page de contact',
     501            'type' => 'url',
     502            'placeholder' => 'https://votresite.com/contact',
     503            'sanitize' => 'esc_url_raw'
     504        ],
     505        'twitter' => [
     506            'label' => 'Page Twitter (X)',
     507            'type' => 'url',
     508            'placeholder' => 'https://twitter.com/votrenom',
     509            'sanitize' => 'esc_url_raw'
     510        ],
     511        'youtube' => [
     512            'label' => 'Chaîne YouTube',
     513            'type' => 'url',
     514            'placeholder' => 'https://www.youtube.com/@votrechaine',
     515            'sanitize' => 'esc_url_raw'
     516        ]
     517    ];
     518
     519    // Register and add settings fields for each contact method
     520    foreach ($contact_methods as $key => $config) {
     521        $option_name = 'andy_contact_' . $key;
     522       
     523        register_setting('andyInjector', $option_name, [
     524            'sanitize_callback' => $config['sanitize'],
     525        ]);
     526
     527        add_settings_field(
     528            $option_name,
     529            esc_html__($config['label'], 'andy-votre-assistant-intelligent'),
     530            'andy_contact_field_render',
     531            'andyInjector',
     532            'andy_contact_section',
     533            [
     534                'label_for' => $option_name,
     535                'placeholder' => $config['placeholder'],
     536                'type' => $config['type']
     537            ]
     538        );
     539    }
    416540}
    417541
     
    435559}
    436560
     561/**
     562 * Adjust color brightness
     563 */
     564function andy_adjust_brightness($hex, $steps) {
     565    // Remove # from hex code if present
     566    $hex = ltrim($hex, '#');
     567   
     568    // Convert to RGB
     569    $r = hexdec(substr($hex, 0, 2));
     570    $g = hexdec(substr($hex, 2, 2));
     571    $b = hexdec(substr($hex, 4, 2));
     572   
     573    // Adjust brightness
     574    $r = max(0, min(255, $r + $steps));
     575    $g = max(0, min(255, $g + $steps));
     576    $b = max(0, min(255, $b + $steps));
     577   
     578    // Convert back to hex
     579    return '#' . str_pad(dechex($r), 2, '0', STR_PAD_LEFT)
     580                . str_pad(dechex($g), 2, '0', STR_PAD_LEFT)
     581                . str_pad(dechex($b), 2, '0', STR_PAD_LEFT);
     582}
     583
    437584add_action('wp_head', 'andy_injector_custom_style');
    438585function andy_injector_custom_style() {
     
    440587    $primary = get_option('andy_injector_primary_color', '#007bff');
    441588
     589    // Generate color variants
     590    $primary_dark = andy_adjust_brightness($primary, -25);
     591    $primary_light = andy_adjust_brightness($primary, 140);
     592   
    442593    // Dynamic CSS injection
    443     $custom_css = ":root { --primary-color: " . esc_attr($primary) . " !important; }";
     594    $custom_css = ":root {
     595        --primary-color: " . esc_attr($primary) . " !important;
     596        --primary-color-dark: " . $primary_dark . " !important;
     597        --primary-color-light: " . $primary_light . " !important;
     598        --primary-color-shadow: " . $primary . "33 !important; /* 20% opacity */
     599    }";
    444600
    445601    wp_enqueue_style('andy-style', $plugin_url . 'Andy/assets/Andy-Widget/styles/Andy.css', [], '2.0.7');
     
    478634 */
    479635function andy_injector_open_on_load_render() {
    480     $value = get_option('andy_injector_open_on_load', '0');
    481 
    482     echo '<input type="checkbox" id="andy_injector_open_on_load" name="andy_injector_open_on_load" value="1" ' . checked($value, '1', false) . ' /> ';
     636    $options = get_option('andy_injector_open_on_load', '0');
     637    ?>
     638    <input type='checkbox' name='andy_injector_open_on_load' value='1' <?php checked('1', $options); ?>>
     639    <label for="andy_injector_open_on_load">Cochez pour ouvrir automatiquement la fenêtre de chat au chargement de la page.</label>
     640    <?php
     641}
     642
     643// Contact section description
     644function andy_contact_section_callback() {
     645    echo '<p>' . esc_html__('Ajoutez vos liens de contact pour les intégrer au widget. Tous les champs sont optionnels.', 'andy-votre-assistant-intelligent') . '</p>';
     646}
     647
     648// Render contact field
     649function andy_contact_field_render($args) {
     650    $option = get_option($args['label_for']);
     651    $type = isset($args['type']) ? $args['type'] : 'text';
     652    $placeholder = isset($args['placeholder']) ? $args['placeholder'] : '';
     653   
     654    // Special handling for different field types
     655    switch ($type) {
     656        case 'email':
     657            $value = esc_attr($option);
     658            break;
     659        case 'tel':
     660            $value = esc_attr($option);
     661            break;
     662        case 'text':
     663            $value = esc_attr($option);
     664            break;
     665        default: // url
     666            $value = esc_url($option);
     667    }
     668    ?>
     669    <input type="<?php echo esc_attr($type); ?>"
     670           id="<?php echo esc_attr($args['label_for']); ?>"
     671           name="<?php echo esc_attr($args['label_for']); ?>"
     672           value="<?php echo $value; ?>"
     673           placeholder="<?php echo esc_attr($placeholder); ?>"
     674           class="regular-text">
     675    <?php
    483676}
    484677
  • andy-votre-assistant-intelligent/trunk/Andy/Andy.html

    r3291395 r3317904  
    1717        <!-- ANDY WIDGET -->
    1818        <div class="andy-position-right">
    19             <!-- Tooltip -->
    20             <div id="chat-tooltip" class="medium">
    21                 <span id="tooltip-text" class="no-select"></span>
     19            <!-- Contact Methods Toggle -->
     20            <div id="contact-toggle" class="contact-methods-toggle medium" title="Contact Us">
     21                <?xml version="1.0" encoding="iso-8859-1"?>
     22                <!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
     23                <svg fill="#ffffff" height="800px" width="800px" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
     24                     viewBox="0 0 32.055 32.055" xml:space="preserve">
     25                <g>
     26                    <path d="M3.968,12.061C1.775,12.061,0,13.835,0,16.027c0,2.192,1.773,3.967,3.968,3.967c2.189,0,3.966-1.772,3.966-3.967
     27                        C7.934,13.835,6.157,12.061,3.968,12.061z M16.233,12.061c-2.188,0-3.968,1.773-3.968,3.965c0,2.192,1.778,3.967,3.968,3.967
     28                        s3.97-1.772,3.97-3.967C20.201,13.835,18.423,12.061,16.233,12.061z M28.09,12.061c-2.192,0-3.969,1.774-3.969,3.967
     29                        c0,2.19,1.774,3.965,3.969,3.965c2.188,0,3.965-1.772,3.965-3.965S30.278,12.061,28.09,12.061z"/>
     30                </g>
     31                </svg>
    2232            </div>
    2333
    24             <!-- Bulle de chat -->
    25             <div id="chat-bubble" class="no-select medium">
    26                 <svg
    27                     fill="#ffffff"
    28                    
    29                     version="1.1"
    30                     id="Capa_1"
    31                     xmlns="http://www.w3.org/2000/svg"
    32                     xmlns:xlink="http://www.w3.org/1999/xlink"
    33                    
    34                     viewBox="0 0 60 60"
    35                    
    36                     xml:space="preserve"
    37                 >
    38                     <path d="M30,1.5c-16.542,0-30,12.112-30,27c0,5.204,1.646,10.245,4.768,14.604c-0.591,6.537-2.175,11.39-4.475,13.689 c-0.304,0.304-0.38,0.769-0.188,1.153C0.275,58.289,0.625,58.5,1,58.5c0.046,0,0.092-0.003,0.139-0.01 c0.405-0.057,9.813-1.411,16.618-5.339C21.621,54.71,25.737,55.5,30,55.5c16.542,0,30-12.112,30-27S46.542,1.5,30,1.5z M16,32.5 c-2.206,0-4-1.794-4-4s1.794-4,4-4s4,1.794,4,4S18.206,32.5,16,32.5z M30,32.5c-2.206,0-4-1.794-4-4s1.794-4,4-4s4,1.794,4,4 S32.206,32.5,30,32.5z M44,32.5c-2.206,0-4-1.794-4-4s1.794-4,4-4s4,1.794,4,4S46.206,32.5,44,32.5z"/>
    39                 </svg>
     34            <!-- Contact Methods List -->
     35            <div id="contact-methods" class="contact-methods-list">
     36                <div class="contact-methods-header">
     37                    <h3>Nous contacter :</h3>
     38                    <button class="close-contact-methods">
     39                        <svg viewBox="0 0 24 24" fill="currentColor">
     40                            <path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>
     41                        </svg>
     42                    </button>
     43                </div>
     44                <div class="contact-methods-content">
     45                    <!-- Will be populated by JavaScript -->
     46                     
     47                </div>
    4048            </div>
    4149
  • andy-votre-assistant-intelligent/trunk/Andy/assets/Andy-Widget/scripts/Andy.js

    r3309069 r3317904  
    22const WEB_SOCKET_URL = `wss://dashboard.essayez-andy.fr/ws/`;
    33
     4// DOM Elements
    45const chatTooltip = document.getElementById('chat-tooltip');
    56const chatTooltipSpan = document.getElementById('tooltip-text');
    6 const chatBubble = document.getElementById('chat-bubble');
    77const chatBox = document.getElementById('chatbox');
    88const chatContent = document.getElementById('chat-content');
    99const chatInput = document.getElementById('chat-input');
    10 
     10const contactToggle = document.getElementById('contact-toggle');
     11const contactMethodsList = document.getElementById('contact-methods');
     12const contactMethodsContent = document.querySelector('.contact-methods-content');
     13const closeContactMethods = document.querySelector('.close-contact-methods');
     14
     15// Buttons
    1116const sendButton = document.getElementById('send-button');
    1217const microphoneButton = document.getElementById('microphone-button');
    1318const closeButton = document.getElementById('close-button');
     19
     20// Icons for contact methods
     21const CONTACT_ICONS = {
     22    'messenger_dm': 'fab fa-facebook-messenger',
     23    'tiktok_page': 'fab fa-tiktok',
     24    'insta_page': 'fab fa-instagram',
     25    'whatsapp_dm': 'fab fa-whatsapp',
     26    'facebook_page': 'fab fa-facebook-f',
     27    'linkedin_page': 'fab fa-linkedin-in',
     28    'mail': 'fas fa-envelope',
     29    'tel': 'fas fa-phone',
     30    'adresse': 'fas fa-map-marker-alt',
     31    'contact_page': 'fas fa-link',
     32    'twitter': 'fab fa-twitter',
     33    'youtube': 'fab fa-youtube'
     34};
     35
     36// Labels for contact methods
     37const CONTACT_LABELS = {
     38    'messenger_dm': 'Messenger',
     39    'tiktok_page': 'TikTok',
     40    'insta_page': 'Instagram',
     41    'whatsapp_dm': 'WhatsApp',
     42    'facebook_page': 'Facebook',
     43    'linkedin_page': 'LinkedIn',
     44    'mail': 'Email',
     45    'tel': 'Téléphone',
     46    'adresse': 'Adresse',
     47    'contact_page': 'Contact',
     48    'twitter': 'Twitter',
     49    'youtube': 'YouTube'
     50};
    1451/* CONST SECTION END */
     52
     53// Initialize contact methods when DOM is loaded
     54document.addEventListener('DOMContentLoaded', function() {
     55    // Add Font Awesome if not already added
     56    if (!document.querySelector('link[href*="font-awesome"]')) {
     57        const fontAwesome = document.createElement('link');
     58        fontAwesome.rel = 'stylesheet';
     59        fontAwesome.href = 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css';
     60        document.head.appendChild(fontAwesome);
     61    }
     62
     63    // Initialize contact methods if they exist
     64    if (typeof andyContactMethods !== 'undefined') {
     65        initContactMethods();
     66    }
     67});
     68
     69// Toggle contact methods list
     70function toggleContactMethods() {
     71    contactMethodsList.classList.toggle('active');
     72}
     73
     74// Close contact methods list
     75function closeContactMethodsList() {
     76    contactMethodsList.classList.remove('active');
     77}
     78
     79// Initialize contact methods
     80function initContactMethods() {
     81    // Clear existing content
     82    contactMethodsContent.innerHTML = '';
     83   
     84    // Always add live chat first
     85    const liveChatItem = document.createElement('a');
     86    liveChatItem.className = 'contact-method-item';
     87    liveChatItem.href = '#';
     88    liveChatItem.title = 'Live Chat';
     89
     90    /* CHAT BUBBLE CLICK EVENT SECTION */
     91    // Lorsque la bulle de chat est cliquée, on affiche la fenêtre
     92    liveChatItem.onclick = function() {
     93        chatBox.style.display = (chatBox.style.display === 'none' || chatBox.style.display === '') ? 'flex' : 'none';
     94
     95        if (chatBox.style.display === 'flex') {
     96            closeContactMethodsList();
     97        }
     98   
     99        chatInput.focus();
     100       
     101        if (
     102            chatBox.style.display === 'flex' &&
     103            chatTooltip.classList.contains('visible')
     104        ) {
     105            chatTooltip.classList.remove('visible');
     106        }
     107   
     108        if (
     109            webSocket === null &&
     110   
     111            !doesCookieExist('Andy-Conversation-Uuid') &&
     112            !doesCookieExist('Andy-Conversation-Human-Requested')
     113        ) {
     114            initConversation();
     115        }
     116    };
     117    /* CHAT BUBBLE CLICK EVENT END */
     118   
     119    const liveChatIcon = document.createElement('i');
     120    liveChatIcon.className = 'fas fa-comment-dots';
     121    liveChatItem.appendChild(liveChatIcon);
     122    contactMethodsContent.appendChild(liveChatItem);
     123   
     124    // Add other contact methods
     125    Object.entries(andyContactMethods).forEach(([key, value]) => {
     126        if (!value) return;
     127       
     128        const contactItem = document.createElement('a');
     129        contactItem.className = 'contact-method-item';
     130        contactItem.href = getContactUrl(key, value);
     131        contactItem.target = key === 'mail' || key === 'tel' ? '_self' : '_blank';
     132        contactItem.rel = 'noopener noreferrer';
     133        contactItem.title = CONTACT_LABELS[key] || key.replace('_', ' ');
     134       
     135        const icon = document.createElement('i');
     136        icon.className = CONTACT_ICONS[key] || 'fas fa-link';
     137       
     138        contactItem.appendChild(icon);
     139        contactMethodsContent.appendChild(contactItem);
     140    });
     141   
     142    // Add event listeners
     143    if (contactToggle) {
     144        contactToggle.addEventListener('click', toggleContactMethods);
     145    }
     146   
     147    if (closeContactMethods) {
     148        closeContactMethods.addEventListener('click', closeContactMethodsList);
     149    }
     150   
     151    // Close when clicking outside
     152    document.addEventListener('click', (e) => {
     153        if (!contactMethodsList.contains(e.target) &&
     154            !contactToggle.contains(e.target) &&
     155            contactMethodsList.classList.contains('active')) {
     156            closeContactMethodsList();
     157        }
     158    });
     159}
     160
     161// Get proper URL for contact method
     162function getContactUrl(type, value) {
     163    switch (type) {
     164        case 'mail':
     165            return `mailto:${value}`;
     166        case 'tel':
     167            return `tel:${value.replace(/\s+/g, '')}`;
     168        case 'whatsapp_dm':
     169            return `https://wa.me/${value.replace(/[^0-9]/g, '')}`;
     170        default:
     171            return value;
     172    }
     173}
    15174
    16175/* VARIABLES SECTION */
     
    747906
    748907
    749 /* CHAT BUBBLE CLICK EVENT SECTION */
    750 // Lorsque la bulle de chat est cliquée, on affiche la fenêtre
    751 chatBubble.onclick = function() {
    752     chatBox.style.display = (chatBox.style.display === 'none' || chatBox.style.display === '') ? 'flex' : 'none';
    753 
    754     chatInput.focus();
    755    
    756     if (
    757         chatBox.style.display === 'flex' &&
    758         chatTooltip.classList.contains('visible')
    759     ) {
    760         chatTooltip.classList.remove('visible');
    761     }
    762 
    763     if (
    764         webSocket === null &&
    765 
    766         !doesCookieExist('Andy-Conversation-Uuid') &&
    767         !doesCookieExist('Andy-Conversation-Human-Requested')
    768     ) {
    769         initConversation();
    770     }
    771 };
    772 /* CHAT BUBBLE CLICK EVENT END */
    773908
    774909/* SEND MESSAGE ON ENTER SECTION */
     
    9351070/* MARKDOWN TO HTML SECTION END */
    9361071
    937 /* CODE SECTION FOR INACTIVITY AND POST-ACTIVITY DELAY */
    938 (async () => {
    939     try {
    940         const response = await fetch('https://dashboard.essayez-andy.fr/api/tooltip');
    941         const data = await response.json();
    942 
    943         chatTooltipSpan.textContent = data.tooltip;
    944     } catch (err) {
    945         console.error(err);
    946 
    947         return;
    948     }
    949 
    950     if (chatBox.style.display !== 'flex') {
    951         chatTooltip.classList.add('visible');
    952     }
    953 
    954     let inactivityDelay = 30000; // 30 secondes d'inactivité
    955     let postActivityDelay = 3000; // 3 secondes après retour d'activité
    956 
    957     let inactivityTimeout;
    958     let postActivityTimeout;
    959 
    960     let userIsInactive = false;
    961 
    962     function handleInactivity() {
    963     userIsInactive = true;
    964 
    965     if (chatBox.style.display === 'flex') {
    966         return;
    967     }
    968 
    969     if (!chatTooltip.classList.contains('visible')) {
    970         chatTooltip.classList.add('visible');
    971     }
    972     }
    973 
    974     function handlePostReactivity() {
    975     if (chatTooltip.classList.contains('visible')) {
    976         chatTooltip.classList.remove('visible');
    977     }
    978     }
    979 
    980     function onUserActivity() {
    981     // Si utilisateur était inactif, on déclenche un timer pour l'action post-réactivité
    982     if (userIsInactive) {
    983         clearTimeout(postActivityTimeout);
    984         postActivityTimeout = setTimeout(handlePostReactivity, postActivityDelay);
    985     }
    986 
    987     userIsInactive = false;
    988     clearTimeout(inactivityTimeout);
    989     inactivityTimeout = setTimeout(handleInactivity, inactivityDelay);
    990     }
    991 
    992     // Événements écoutés pour détecter l'activité
    993     ["mousemove", "keydown", "scroll", "click"].forEach(event =>
    994     document.addEventListener(event, onUserActivity)
    995     );
    996 
    997     // Démarre le premier timer
    998     inactivityTimeout = setTimeout(handleInactivity, inactivityDelay);
    999 
    1000     setTimeout(() => {
    1001         if (chatTooltip.classList.contains('visible')) {
    1002             chatTooltip.classList.remove('visible');
    1003         }
    1004     }, 5000);
    1005 
    1006     chatBubble.addEventListener('mouseenter', () => {
    1007         if (chatBox.style.display === 'flex') {
    1008             return ;
    1009         }
    1010 
    1011         if (!chatTooltip.classList.contains('visible')) {
    1012             chatTooltip.classList.add('visible');
    1013         }
    1014     });
    1015 
    1016     chatBubble.addEventListener('mouseleave', () => {
    1017         if (chatBox.style.display === 'flex') {
    1018             return ;
    1019         }
    1020 
    1021         if (chatTooltip.classList.contains('visible')) {
    1022             chatTooltip.classList.remove('visible');
    1023         }
    1024     })
    1025 
    1026     /*
    1027 
    1028         Tooltip shows:
    1029             -During 5s after page load then disappear
    1030             -After 30s inactivity then disappear after 3s of post-activity
    1031             -When hovering the bubble
    1032 
    1033     */
    1034 })();
    1035 /* #### TOOLTIP SECTION END #### */
    1036 
    10371072/* #### REQUEST HUMAN OVERLAY SECTION #### */
    10381073const openHumanRequestOverlayButton = document.getElementById("human-request-header-button");
  • andy-votre-assistant-intelligent/trunk/Andy/assets/Andy-Widget/styles/Andy.css

    r3297562 r3317904  
    1616
    1717strong { font-weight: bold; }
     18
     19/* Contact Methods Styles */
     20.contact-methods-toggle {
     21    position: relative;
     22    display: flex;
     23    align-items: center;
     24    justify-content: center;
     25    width: 40px;
     26    height: 40px;
     27    background: var(--primary-color, #4a6cf7);
     28    border: none;
     29    border-radius: 50%;
     30    cursor: pointer;
     31    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
     32    transition: all 0.3s ease;
     33    padding: 0;
     34}
     35
     36.contact-methods-toggle:hover {
     37    background: var(--primary-color-dark, #3a5ce4);
     38    box-shadow: 0 4px 12px rgba(74, 108, 247, 0.2);
     39}
     40
     41.contact-methods-toggle svg {
     42    width: 24px;
     43    height: 24px;
     44    color: white;
     45    transition: all 0.2s ease;
     46}
     47
     48.contact-methods-toggle:hover svg {
     49    transform: scale(1.1);
     50    opacity: 0.9;
     51}
     52
     53.contact-methods-list {
     54    position: fixed;
     55    right: 24px;
     56    bottom: 80px;
     57    width: 300px;
     58    max-height: 70vh;
     59    background: white;
     60    border-radius: 12px;
     61    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
     62    overflow: hidden;
     63    transform: translateY(20px);
     64    opacity: 0;
     65    visibility: hidden;
     66    transition: all 0.3s ease;
     67    z-index: 999999;
     68}
     69
     70.contact-methods-list.active {
     71    transform: translateY(0);
     72    opacity: 1;
     73    visibility: visible;
     74}
     75
     76.contact-methods-header {
     77    display: flex;
     78    justify-content: space-between;
     79    align-items: center;
     80    padding: 16px 20px;
     81    background: #f8f9fa;
     82    border-bottom: 1px solid #e9ecef;
     83}
     84
     85.contact-methods-header h3 {
     86    margin: 0;
     87    font-size: 16px;
     88    color: #2d3748;
     89}
     90
     91.close-contact-methods {
     92    background: none;
     93    border: none;
     94    color: #6c757d;
     95    cursor: pointer;
     96    padding: 4px;
     97    border-radius: 4px;
     98    transition: all 0.2s ease;
     99}
     100
     101.close-contact-methods:hover {
     102    background: #e9ecef;
     103    color: #2d3748;
     104}
     105
     106.close-contact-methods svg {
     107    width: 20px;
     108    height: 20px;
     109}
     110
     111.contact-methods-content {
     112    max-height: calc(70vh - 60px);
     113    overflow-y: auto;
     114    /* padding: 16px 0; */
     115}
     116
     117.contact-method-item {
     118    display: flex;
     119    flex-direction: column;
     120    align-items: center;
     121    justify-content: center;
     122    width: 50px;
     123    height: 50px;
     124    margin: 10px;
     125    background: white;
     126    border-radius: 50%;
     127    color: var(--primary-color, #4a6cf7);
     128    text-decoration: none;
     129    transition: all 0.2s ease;
     130    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
     131    border: 2px solid var(--primary-color, #4a6cf7);
     132}
     133
     134.contact-method-item:hover {
     135    background: var(--primary-color-light, #f0f4ff);
     136    transform: translateY(-2px);
     137    box-shadow: 0 4px 12px var(--primary-color-shadow, rgba(74, 108, 247, 0.2));
     138}
     139
     140.contact-method-item i {
     141    font-size: 24px;
     142    transition: all 0.2s ease;
     143    color: var(--primary-color, #4a6cf7);
     144}
     145
     146.contact-method-item:hover i {
     147    transform: scale(1.1);
     148    color: var(--primary-color-dark, #3a5ce4);
     149}
     150
     151.contact-methods-content {
     152    display: flex;
     153    flex-wrap: wrap;
     154    justify-content: center;
     155    /* padding: 10px 10px; */
     156}
     157
     158/* Position classes */
     159.andy-position-right {
     160    position: fixed;
     161    right: 24px;
     162    bottom: 24px;
     163    z-index: 999998;
     164}
     165
     166.andy-position-left {
     167    position: fixed;
     168    left: 24px;
     169    bottom: 24px;
     170    z-index: 999998;
     171}
     172
     173.andy-position-left #chatbox {
     174    left: 24px;
     175    bottom: 24px;
     176}
     177
     178.andy-position-right #chatbox {
     179    right: 24px;
     180    bottom: 24px;
     181}
     182
     183/* Contact list positioning based on button size */
     184.contact-methods-list {
     185    bottom: 100px; /* Default for medium */
     186}
     187
     188/* Small button */
     189.contact-methods-toggle.small + .contact-methods-list {
     190    bottom: 85px;
     191}
     192
     193/* Medium button (default) */
     194.contact-methods-toggle.medium + .contact-methods-list {
     195    bottom: 100px;
     196}
     197
     198/* Big button */
     199.contact-methods-toggle.big + .contact-methods-list {
     200    bottom: 110px;
     201}
     202
     203/* Very big button */
     204.contact-methods-toggle.very-big + .contact-methods-list {
     205    bottom: 120px;
     206}
     207
     208/* Left position adjustments */
     209.andy-position-left .contact-methods-list {
     210    right: auto;
     211    left: 24px;
     212}
     213
     214/* Responsive */
     215@media (max-width: 480px) {
     216    .contact-methods-list {
     217        width: calc(100% - 32px);
     218        right: 16px;
     219        bottom: 72px;
     220    }
     221   
     222    .andy-position-left .contact-methods-list {
     223        left: 16px;
     224    }
     225}
    18226
    19227menu, ol, ul, li {
     
    24232}
    25233
    26 .andy-position-right #chat-bubble,
    27 .andy-position-right #chatbox {
    28     right: 20px;
    29     left: auto;
    30 }
    31 
    32 .andy-position-left #chat-bubble,
    33 .andy-position-left #chatbox {
    34     left: 20px;
    35     right: auto;
    36 }
    37 
    38234.andy-position-right #chat-tooltip.small {
    39235    bottom: 70px;
     
    117313}
    118314
    119 #chat-bubble.small {
     315#contact-toggle.small {
    120316    width: 50px;
    121317    height: 50px;
    122318}
    123319
    124 #chat-bubble.small svg {
     320#contact-toggle.small svg {
    125321    width: 25px;
    126322    height: 25px;
    127323}
    128324
    129 #chat-bubble.medium {
     325#contact-toggle.medium {
    130326    width: 60px;
    131327    height: 60px;
    132328}
    133329
    134 #chat-bubble.medium svg {
     330#contact-toggle.medium svg {
    135331    width: 30px;
    136332    height: 30px;
    137333}
    138334
    139 #chat-bubble.big {
     335#contact-toggle.big {
    140336    width: 70px;
    141337    height: 70px;
    142338}
    143339
    144 #chat-bubble.big svg {
     340#contact-toggle.big svg {
    145341    width: 35px;
    146342    height: 35px;
    147343}
    148344
    149 #chat-bubble.very-big {
     345#contact-toggle.very-big {
    150346    width: 80px;
    151347    height: 80px;
    152348}
    153349
    154 #chat-bubble.very-big svg {
     350#contact-toggle.very-big svg {
    155351    width: 40px;
    156352    height: 40px;
     
    185381    overscroll-behavior-y: contain;
    186382}
    187 
    188 #chat-bubble.small + #chatbox { bottom: 85px; }
    189 #chat-bubble.medium + #chatbox { bottom: 95px; }
    190 #chat-bubble.big + #chatbox { bottom: 105px; }
    191 #chat-bubble.very-big + #chatbox { bottom: 115px; }
    192383
    193384#chat-content {
  • andy-votre-assistant-intelligent/trunk/readme.txt

    r3309069 r3317904  
    66Requires PHP: 7.3 
    77Donate link: https://essayez-andy.fr
    8 Stable tag: 2.0.7
     8Stable tag: 2.1.0
    99License: GPLv2 or later 
    1010License URI: https://www.gnu.org/licenses/gpl-2.0.html 
Note: See TracChangeset for help on using the changeset viewer.