Exemples d'intégration

Implémentations complètes du widget pour différents cas d'utilisation.

Implémentation basique

L'exemple le plus simple : un widget inline sur votre page de réservations.

HTML
<!DOCTYPE html>
<html lang="es">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Réserver un rendez-vous | Mi Salon</title>
    <style>
        body {
            font-family: system-ui, sans-serif;
            max-width: 600px;
            margin: 40px auto;
            padding: 0 20px;
        }
        h1 {
            text-align: center;
            margin-bottom: 30px;
        }
    </style>
</head>
<body>

    <h1>Réservez votre rendez-vous</h1>

    <div id="salonbookit-widget"></div>

    <script src="https://app.salonbookit.com/static/widget/v1/salonbookit-widget.min.js"></script>
    <script>
        SalonBookIt.init({
            apiKey: 'VOTRE_CLE_API',
            container: '#salonbookit-widget',
            theme: 'light',
            locale: 'es'
        });
    </script>

</body>
</html>

Bouton qui ouvre une modale

Un bouton flottant qui ouvre le widget dans un popup. Idéal pour les landing pages.

HTML

Service présélectionné

Utile pour les pages de services individuels où vous voulez que le widget ait déjà un service sélectionné.

HTML
<!-- Page : /servicios/corte-clasico -->

<div class="service-page">
    <h1>Coupe Classique</h1>
    <p>Notre coupe de cheveux la plus populaire pour hommes.</p>
    <p><strong>Prix : 25€</strong> | <strong>Durée : 30 min</strong></p>

    <h2>Réserver ce service</h2>
    <div id="widget"></div>
</div>

<script src="https://app.salonbookit.com/static/widget/v1/salonbookit-widget.min.js"></script>
<script>
    // L'ID du service s'obtient depuis votre backend ou l'URL
    const serviceId = 15; // ID del "Coupe Classique"

    SalonBookIt.init({
        apiKey: 'VOTRE_CLE_API',
        container: '#widget',
        serviceId: serviceId, // Présélectionne ce service
        allowMultipleServices: false // N'autorise que ce service
    });
</script>

Intégration avec Google Analytics

Suivez chaque étape du tunnel de réservation.

JavaScript
SalonBookIt.init({
    apiKey: 'VOTRE_CLE_API',
    container: '#widget',

    onReady: (business) => {
        gtag('event', 'widget_loaded', {
            'business_name': business.nombre
        });
    },

    onStepChange: (step, data) => {
        gtag('event', 'booking_step', {
            'step_name': step,
            'services_count': data.services?.length || 0
        });
    },

    onServiceSelect: (service, selected, allSelected) => {
        if (selected) {
            gtag('event', 'add_to_cart', {
                'items': [{
                    'id': service.id,
                    'name': service.nombre,
                    'price': service.precio
                }]
            });
        }
    },

    onBookingComplete: (booking) => {
        gtag('event', 'purchase', {
            'transaction_id': booking.id,
            'value': booking.total,
            'currency': 'EUR',
            'items': booking.servicios.map(s => ({
                'id': s.id,
                'name': s.nombre,
                'price': s.precio
            }))
        });

        // Facebook Pixel
        fbq('track', 'Purchase', {
            value: booking.total,
            currency: 'EUR'
        });
    },

    onPaymentComplete: (payment) => {
        gtag('event', 'payment_complete', {
            'payment_method': 'stripe',
            'amount': payment.amount
        });
    },

    onError: (error) => {
        gtag('event', 'exception', {
            'description': error.message,
            'fatal': false
        });
    }
});

Styles personnalisés

Personnalisez entièrement l'apparence du widget pour qu'il corresponde à votre marque.

HTML + CSS
<style>
/* Thème personnalisé */
#mi-widget .sbk-widget {
    /* Couleurs de marque */
    --sbk-primary: #ff6b6b;
    --sbk-primary-hover: #ee5a5a;
    --sbk-background: #fafafa;
    --sbk-surface: #ffffff;
    --sbk-text: #2d3436;
    --sbk-text-secondary: #636e72;
    --sbk-border: #dfe6e9;

    /* Bords plus arrondis */
    --sbk-radius-sm: 8px;
    --sbk-radius-md: 12px;
    --sbk-radius-lg: 20px;

    /* Police personnalisée */
    --sbk-font-family: 'Poppins', sans-serif;

    /* Ombres plus prononcées */
    --sbk-shadow-md: 0 10px 40px rgba(0,0,0,0.15);
}

/* Style du bouton principal */
#mi-widget .sbk-btn-primary {
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.5px;
}

/* Cartes de services */
#mi-widget .sbk-service-card {
    border: 2px solid transparent;
    transition: all 0.3s ease;
}

#mi-widget .sbk-service-card:hover {
    border-color: var(--sbk-primary);
    transform: translateY(-2px);
}

#mi-widget .sbk-service-card.selected {
    border-color: var(--sbk-primary);
    background: rgba(255, 107, 107, 0.05);
}
</style>

<div id="mi-widget"></div>

<script src="https://app.salonbookit.com/static/widget/v1/salonbookit-widget.min.js"></script>
<script>
    SalonBookIt.init({
        apiKey: 'VOTRE_CLE_API',
        container: '#mi-widget',
        primaryColor: '#ff6b6b',
        borderRadius: '20px',
        fontFamily: 'Poppins, sans-serif'
    });
</script>

Composant React complet

React (TypeScript)
import React, { useEffect, useRef, useState } from 'react';

interface BookingWidgetProps {
    apiKey: string;
    serviceId?: number;
    staffId?: number;
    onBookingComplete?: (booking: any) => void;
    onError?: (error: any) => void;
}

declare global {
    interface Window {
        SalonBookIt: any;
    }
}

const BookingWidget: React.FC<BookingWidgetProps> = ({
    apiKey,
    serviceId,
    staffId,
    onBookingComplete,
    onError
}) => {
    const containerRef = useRef<HTMLDivElement>(null);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState<string | null>(null);

    useEffect(() => {
        const loadScript = () => {
            return new Promise<void>((resolve, reject) => {
                if (window.SalonBookIt) {
                    resolve();
                    return;
                }

                const script = document.createElement('script');
                script.src = 'https://app.salonbookit.com/static/widget/v1/salonbookit-widget.min.js';
                script.async = true;
                script.onload = () => resolve();
                script.onerror = () => reject(new Error('Erreur lors du chargement du widget'));
                document.body.appendChild(script);
            });
        };

        const initWidget = async () => {
            try {
                await loadScript();

                if (!containerRef.current) return;

                window.SalonBookIt.init({
                    apiKey,
                    container: containerRef.current,
                    serviceId,
                    staffId,
                    locale: 'es',
                    onReady: () => setLoading(false),
                    onBookingComplete: (booking: any) => {
                        onBookingComplete?.(booking);
                    },
                    onError: (err: any) => {
                        setError(err.message);
                        onError?.(err);
                    }
                });
            } catch (err) {
                setError('Erreur lors du chargement du widget');
            }
        };

        initWidget();

        return () => {
            // Cleanup si nécessaire
        };
    }, [apiKey, serviceId, staffId]);

    if (error) {
        return (
            <div className="widget-error">
                <p>Error: {error}</p>
                <button onClick={() => window.location.reload()}>
                    Réessayer
                </button>
            </div>
        );
    }

    return (
        <div className="widget-wrapper">
            {loading && (
                <div className="widget-loading">
                    <div className="spinner" />
                    <p>Chargement...</p>
                </div>
            )}
            <div ref={containerRef} style={{ opacity: loading ? 0 : 1 }} />
        </div>
    );
};

export default BookingWidget;

// Utilisation :
// <BookingWidget
//     apiKey="hh_pub_live_..."
//     serviceId={15}
//     onBookingComplete={(booking) => navigate(`/confirmacion/${booking.id}`)}
// />

WordPress avec Shortcode

Créez un shortcode pour insérer facilement le widget dans les articles et pages.

PHP (functions.php)
<?php
/**
 * Shortcode pour le widget SalonBookIt
 * Utilisation : [salonbookit_widget service="15" staff="3"]
 */
function salonbookit_widget_shortcode($atts) {
    $atts = shortcode_atts([
        'service' => '',
        'staff' => '',
        'mode' => 'inline',
        'button_text' => 'Réserver un rendez-vous'
    ], $atts);

    // Générer un ID unique pour le conteneur
    $container_id = 'sbk-widget-' . uniqid();

    // Construire les options JS
    $options = [
        'apiKey' => get_option('salonbookit_api_key'),
        'container' => '#' . $container_id,
        'mode' => esc_attr($atts['mode']),
        'buttonText' => esc_attr($atts['button_text']),
        'locale' => substr(get_locale(), 0, 2)
    ];

    if (!empty($atts['service'])) {
        $options['serviceId'] = intval($atts['service']);
    }
    if (!empty($atts['staff'])) {
        $options['staffId'] = intval($atts['staff']);
    }

    $options_json = json_encode($options);

    ob_start();
    ?>
    <div id="<?php echo esc_attr($container_id); ?>"></div>
    <script>
    document.addEventListener('DOMContentLoaded', function() {
        if (window.SalonBookIt) {
            SalonBookIt.init(<?php echo $options_json; ?>);
        }
    });
    </script>
    <?php
    return ob_get_clean();
}
add_shortcode('salonbookit_widget', 'salonbookit_widget_shortcode');

// Mettre en file d'attente le script
function salonbookit_enqueue_scripts() {
    wp_enqueue_script(
        'salonbookit-widget',
        'https://app.salonbookit.com/static/widget/v1/salonbookit-widget.min.js',
        [],
        '1.0',
        true
    );
}
add_action('wp_enqueue_scripts', 'salonbookit_enqueue_scripts');

Utilisation dans l'éditeur WordPress :

Shortcode
[salonbookit_widget]

[salonbookit_widget service="15"]

[salonbookit_widget mode="button" button_text="Prendre Rendez-vous"]