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
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Mon Salon de Beauté</title>
<style>
.hero {
text-align: center;
padding: 100px 20px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
}
.hero h1 {
font-size: 3rem;
margin-bottom: 20px;
}
</style>
</head>
<body>
<section class="hero">
<h1>Bienvenue à Mon Salon</h1>
<p>Les meilleurs professionnels vous attendent</p>
<!-- Le bouton sera rendu ici -->
<div id="booking-button" style="margin-top: 30px;"></div>
</section>
<script src="https://app.salonbookit.com/static/widget/v1/salonbookit-widget.min.js"></script>
<script>
SalonBookIt.init({
apiKey: 'VOTRE_CLE_API',
container: '#booking-button',
mode: 'button',
buttonText: 'Réserver Maintenant',
buttonStyle: 'solid',
primaryColor: '#ffffff',
theme: 'dark',
onBookingComplete: (booking) => {
// Rediriger vers la page de confirmation
window.location.href = '/gracias?reserva=' + booking.codigo;
}
});
</script>
</body>
</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"]