WhatsApp Integration - luckydeva03/barbershop_app GitHub Wiki

📱 WhatsApp Integration

Panduan lengkap integrasi WhatsApp untuk booking appointment dan komunikasi customer dengan barbershop.

🎯 Overview

WhatsApp integration memungkinkan customer untuk:

  • Direct Booking: Klik tombol untuk langsung WhatsApp barbershop
  • Template Messages: Pesan booking yang sudah diformat
  • Store Contact: Kontak langsung ke nomor barbershop
  • Automated Response: (Optional) Auto-reply untuk booking

Integration Types

  1. Click-to-Chat: Simple WhatsApp URL redirection
  2. WhatsApp Business API: (Advanced) untuk automated messaging
  3. QR Code: (Optional) untuk quick contact
  4. Web Widget: (Optional) floating WhatsApp button

🚀 Implementation Methods

1. Basic Click-to-Chat Implementation

Helper Function (app/Helper/WhatsAppHelper.php)

<?php

namespace App\Helper;

class WhatsAppHelper
{
    /**
     * Format phone number for WhatsApp
     */
    public static function formatPhoneNumber($phone)
    {
        if (!$phone) return null;
        
        // Remove all non-numeric characters
        $phone = preg_replace('/[^0-9]/', '', $phone);
        
        // Handle Indonesian numbers
        if (substr($phone, 0, 1) === '0') {
            $phone = '62' . substr($phone, 1);
        } elseif (substr($phone, 0, 2) !== '62') {
            $phone = '62' . $phone;
        }
        
        return $phone;
    }

    /**
     * Generate WhatsApp chat URL
     */
    public static function generateChatUrl($phone, $message = '')
    {
        $formattedPhone = self::formatPhoneNumber($phone);
        
        if (!$formattedPhone) {
            return null;
        }
        
        $encodedMessage = urlencode($message);
        return "https://wa.me/{$formattedPhone}?text={$encodedMessage}";
    }

    /**
     * Generate booking message template
     */
    public static function generateBookingMessage($storeName, $customerName = '')
    {
        $greeting = $customerName ? "Hi, my name is {$customerName}." : "Hi!";
        
        return "{$greeting} I would like to book an appointment at {$storeName}. " .
               "Could you please let me know your available times? Thank you!";
    }

    /**
     * Generate QR code URL for WhatsApp
     */
    public static function generateQRCode($phone, $message = '', $size = 200)
    {
        $chatUrl = self::generateChatUrl($phone, $message);
        if (!$chatUrl) return null;
        
        return "https://api.qrserver.com/v1/create-qr-code/?size={$size}x{$size}&data=" . 
               urlencode($chatUrl);
    }

    /**
     * Check if phone number is valid for WhatsApp
     */
    public static function isValidWhatsAppNumber($phone)
    {
        $formatted = self::formatPhoneNumber($phone);
        return $formatted && strlen($formatted) >= 10 && strlen($formatted) <= 15;
    }

    /**
     * Generate different message templates
     */
    public static function getMessageTemplates()
    {
        return [
            'booking' => "Hi! I would like to book an appointment at {store_name}. Could you please let me know your available times? Thank you!",
            'inquiry' => "Hi! I would like to know more about the services at {store_name}. Could you provide me with more information?",
            'complaint' => "Hi! I have a concern regarding my recent visit to {store_name}. Could we discuss this please?",
            'feedback' => "Hi! I wanted to share some feedback about my experience at {store_name}.",
            'general' => "Hi! I have a question about {store_name}.",
        ];
    }

    /**
     * Replace template variables
     */
    public static function processTemplate($template, $variables = [])
    {
        foreach ($variables as $key => $value) {
            $template = str_replace('{' . $key . '}', $value, $template);
        }
        
        return $template;
    }
}

Store Model Enhancement

Add to existing Store model (app/Models/Store.php):

// Add to existing Store model

/**
 * Get formatted WhatsApp number
 */
public function getWhatsappNumberAttribute()
{
    return WhatsAppHelper::formatPhoneNumber($this->phone);
}

/**
 * Get WhatsApp chat URL
 */
public function getWhatsappUrlAttribute()
{
    if (!$this->phone) return null;
    
    $message = WhatsAppHelper::generateBookingMessage($this->name);
    return WhatsAppHelper::generateChatUrl($this->phone, $message);
}

/**
 * Check if store has WhatsApp
 */
public function getHasWhatsappAttribute()
{
    return WhatsAppHelper::isValidWhatsAppNumber($this->phone);
}

/**
 * Get WhatsApp QR code URL
 */
public function getWhatsappQrCodeAttribute()
{
    if (!$this->phone) return null;
    
    $message = WhatsAppHelper::generateBookingMessage($this->name);
    return WhatsAppHelper::generateQRCode($this->phone, $message);
}

/**
 * Generate custom WhatsApp message
 */
public function getWhatsAppUrl($messageType = 'booking', $customerName = '', $customMessage = '')
{
    if (!$this->phone) return null;
    
    if ($customMessage) {
        $message = $customMessage;
    } else {
        $templates = WhatsAppHelper::getMessageTemplates();
        $template = $templates[$messageType] ?? $templates['booking'];
        
        $message = WhatsAppHelper::processTemplate($template, [
            'store_name' => $this->name,
            'customer_name' => $customerName,
        ]);
    }
    
    return WhatsAppHelper::generateChatUrl($this->phone, $message);
}

2. Frontend Integration

WhatsApp Button Component (resources/views/components/whatsapp-button.blade.php)

@props([
    'store',
    'messageType' => 'booking',
    'customerName' => '',
    'customMessage' => '',
    'size' => 'md',
    'variant' => 'success',
    'showIcon' => true,
    'showText' => true,
    'target' => '_blank'
])

@php
    $whatsappUrl = $store->getWhatsAppUrl($messageType, $customerName, $customMessage);
    
    $sizeClasses = [
        'sm' => 'btn-sm',
        'md' => '',
        'lg' => 'btn-lg'
    ];
    
    $sizeClass = $sizeClasses[$size] ?? '';
@endphp

@if($whatsappUrl)
    <a href="{{ $whatsappUrl }}" 
       class="btn btn-{{ $variant }} {{ $sizeClass }} whatsapp-btn" 
       target="{{ $target }}"
       data-store="{{ $store->name }}"
       data-phone="{{ $store->phone }}"
       {{ $attributes }}>
        
        @if($showIcon)
            <i class="fab fa-whatsapp"></i>
        @endif
        
        @if($showText)
            @if($showIcon) @endif
            {{ $slot ?? 'WhatsApp' }}
        @endif
    </a>
@endif

@push('scripts')
<script>
document.addEventListener('DOMContentLoaded', function() {
    // Track WhatsApp button clicks
    document.querySelectorAll('.whatsapp-btn').forEach(button => {
        button.addEventListener('click', function() {
            const storeName = this.dataset.store;
            const phone = this.dataset.phone;
            
            // Analytics tracking (optional)
            if (typeof gtag !== 'undefined') {
                gtag('event', 'whatsapp_click', {
                    event_category: 'engagement',
                    event_label: storeName,
                    value: 1
                });
            }
            
            console.log(`WhatsApp clicked for ${storeName} (${phone})`);
        });
    });
});
</script>
@endpush

Store Card with WhatsApp Integration

<!-- resources/views/components/store-card.blade.php -->
<div class="card store-card h-100">
    <div class="card-img-container">
        <img src="{{ $store->image_url ?: asset('images/default-store.jpg') }}" 
             class="card-img-top" 
             alt="{{ $store->name }}"
             style="height: 200px; object-fit: cover;">
    </div>
    
    <div class="card-body">
        <h5 class="card-title">{{ $store->name }}</h5>
        
        <!-- Rating -->
        <div class="rating mb-2">
            @for($i = 1; $i <= 5; $i++)
                <i class="fas fa-star {{ $i <= $store->average_rating ? 'text-warning' : 'text-muted' }}"></i>
            @endfor
            <span class="ms-1 text-muted">({{ $store->reviews_count }})</span>
        </div>
        
        <!-- Address -->
        <p class="card-text">
            <i class="fas fa-map-marker-alt text-muted me-1"></i>
            <small>{{ Str::limit($store->address, 50) }}</small>
        </p>
        
        <!-- Operating Status -->
        <div class="mb-2">
            @if($store->isOpenNow())
                <span class="badge bg-success">Open Now</span>
            @else
                <span class="badge bg-secondary">Closed</span>
            @endif
        </div>
        
        <!-- Description -->
        <p class="card-text text-muted">
            {{ Str::limit($store->description, 80) }}
        </p>
    </div>
    
    <div class="card-footer bg-transparent">
        <div class="d-flex gap-2">
            <!-- View Details Button -->
            <a href="{{ route('stores.show', $store) }}" class="btn btn-outline-primary flex-fill">
                <i class="fas fa-eye"></i> Details
            </a>
            
            <!-- WhatsApp Booking Button -->
            @if($store->has_whatsapp)
                <x-whatsapp-button 
                    :store="$store" 
                    message-type="booking"
                    :customer-name="auth()->user()?->name ?? ''"
                    class="flex-fill">
                    <i class="fab fa-whatsapp"></i> Book Now
                </x-whatsapp-button>
            @else
                <button class="btn btn-secondary flex-fill" disabled>
                    <i class="fas fa-phone-slash"></i> No WhatsApp
                </button>
            @endif
        </div>
    </div>
</div>

3. Store Detail Page Integration

Enhanced Store Detail View (resources/views/stores/show.blade.php)

@extends('layouts.app')

@section('title', $store->name)

@section('content')
<div class="container">
    <!-- Store Header -->
    <div class="row mb-4">
        <div class="col-md-8">
            <h1>{{ $store->name }}</h1>
            <div class="d-flex align-items-center mb-3">
                <div class="rating me-3">
                    @for($i = 1; $i <= 5; $i++)
                        <i class="fas fa-star {{ $i <= $store->average_rating ? 'text-warning' : 'text-muted' }}"></i>
                    @endfor
                    <span class="ms-1">{{ $store->average_rating }}/5 ({{ $store->reviews_count }} reviews)</span>
                </div>
                
                @if($store->isOpenNow())
                    <span class="badge bg-success">Open Now</span>
                @else
                    <span class="badge bg-secondary">Closed</span>
                @endif
            </div>
        </div>
        
        <div class="col-md-4 text-md-end">
            <!-- WhatsApp Actions -->
            @if($store->has_whatsapp)
                <div class="whatsapp-actions">
                    <h6 class="text-muted mb-2">Book via WhatsApp:</h6>
                    
                    <div class="d-flex flex-column gap-2">
                        <!-- Quick Booking -->
                        <x-whatsapp-button 
                            :store="$store" 
                            message-type="booking"
                            :customer-name="auth()->user()?->name ?? ''"
                            size="lg"
                            class="w-100">
                            <i class="fab fa-whatsapp"></i> Book Appointment
                        </x-whatsapp-button>
                        
                        <!-- Service Inquiry -->
                        <x-whatsapp-button 
                            :store="$store" 
                            message-type="inquiry"
                            variant="outline-success"
                            class="w-100">
                            <i class="fas fa-question-circle"></i> Ask About Services
                        </x-whatsapp-button>
                    </div>
                    
                    <!-- Custom Message Modal Trigger -->
                    <button type="button" 
                            class="btn btn-link text-decoration-none p-0 mt-2" 
                            data-bs-toggle="modal" 
                            data-bs-target="#customMessageModal">
                        <i class="fas fa-edit"></i> Send Custom Message
                    </button>
                </div>
            @endif
        </div>
    </div>

    <!-- Store Info Tabs -->
    <div class="row">
        <div class="col-md-8">
            <ul class="nav nav-tabs" id="storeTab" role="tablist">
                <li class="nav-item" role="presentation">
                    <button class="nav-link active" id="info-tab" data-bs-toggle="tab" data-bs-target="#info" type="button" role="tab">
                        <i class="fas fa-info-circle"></i> Information
                    </button>
                </li>
                <li class="nav-item" role="presentation">
                    <button class="nav-link" id="services-tab" data-bs-toggle="tab" data-bs-target="#services" type="button" role="tab">
                        <i class="fas fa-cut"></i> Services
                    </button>
                </li>
                <li class="nav-item" role="presentation">
                    <button class="nav-link" id="contact-tab" data-bs-toggle="tab" data-bs-target="#contact" type="button" role="tab">
                        <i class="fas fa-phone"></i> Contact
                    </button>
                </li>
                <li class="nav-item" role="presentation">
                    <button class="nav-link" id="reviews-tab" data-bs-toggle="tab" data-bs-target="#reviews" type="button" role="tab">
                        <i class="fas fa-star"></i> Reviews
                    </button>
                </li>
            </ul>
            
            <div class="tab-content" id="storeTabContent">
                <!-- Information Tab -->
                <div class="tab-pane fade show active" id="info" role="tabpanel">
                    <div class="p-3">
                        <p class="lead">{{ $store->description }}</p>
                        
                        <h6>Operating Hours:</h6>
                        <div class="operating-hours">
                            {!! nl2br(e($store->operating_hours_formatted)) !!}
                        </div>
                    </div>
                </div>
                
                <!-- Services Tab -->
                <div class="tab-pane fade" id="services" role="tabpanel">
                    <div class="p-3">
                        @if($store->services)
                            <div class="row">
                                @foreach($store->services as $service)
                                    <div class="col-md-6 mb-2">
                                        <div class="d-flex align-items-center">
                                            <i class="fas fa-check-circle text-success me-2"></i>
                                            {{ $service }}
                                        </div>
                                    </div>
                                @endforeach
                            </div>
                        @else
                            <p class="text-muted">No services listed.</p>
                        @endif
                    </div>
                </div>
                
                <!-- Contact Tab -->
                <div class="tab-pane fade" id="contact" role="tabpanel">
                    <div class="p-3">
                        <div class="contact-info">
                            <!-- Address -->
                            <div class="contact-item mb-3">
                                <h6><i class="fas fa-map-marker-alt text-primary me-2"></i>Address</h6>
                                <p class="ms-4">{{ $store->address }}</p>
                            </div>
                            
                            <!-- Phone & WhatsApp -->
                            @if($store->phone)
                                <div class="contact-item mb-3">
                                    <h6><i class="fas fa-phone text-primary me-2"></i>Phone</h6>
                                    <div class="ms-4">
                                        <p class="mb-1">{{ $store->phone }}</p>
                                        
                                        @if($store->has_whatsapp)
                                            <div class="whatsapp-options">
                                                <small class="text-muted d-block mb-2">Available on WhatsApp:</small>
                                                
                                                <div class="btn-group" role="group">
                                                    <x-whatsapp-button 
                                                        :store="$store" 
                                                        message-type="booking"
                                                        size="sm">
                                                        Book
                                                    </x-whatsapp-button>
                                                    
                                                    <x-whatsapp-button 
                                                        :store="$store" 
                                                        message-type="inquiry"
                                                        variant="outline-success"
                                                        size="sm">
                                                        Inquire
                                                    </x-whatsapp-button>
                                                </div>
                                            </div>
                                        @endif
                                    </div>
                                </div>
                            @endif
                            
                            <!-- Email -->
                            @if($store->email)
                                <div class="contact-item mb-3">
                                    <h6><i class="fas fa-envelope text-primary me-2"></i>Email</h6>
                                    <p class="ms-4">
                                        <a href="mailto:{{ $store->email }}">{{ $store->email }}</a>
                                    </p>
                                </div>
                            @endif
                        </div>
                    </div>
                </div>
                
                <!-- Reviews Tab -->
                <div class="tab-pane fade" id="reviews" role="tabpanel">
                    <!-- Reviews content here -->
                </div>
            </div>
        </div>
        
        <!-- Sidebar -->
        <div class="col-md-4">
            <!-- WhatsApp QR Code -->
            @if($store->has_whatsapp)
                <div class="card mb-4">
                    <div class="card-header">
                        <h6 class="mb-0">
                            <i class="fab fa-whatsapp text-success"></i>
                            Quick WhatsApp Contact
                        </h6>
                    </div>
                    <div class="card-body text-center">
                        <img src="{{ $store->whatsapp_qr_code }}" 
                             alt="WhatsApp QR Code" 
                             class="img-fluid mb-3"
                             style="max-width: 150px;">
                        <p class="small text-muted">Scan to chat directly</p>
                        
                        <x-whatsapp-button 
                            :store="$store" 
                            message-type="booking"
                            class="w-100">
                            <i class="fab fa-whatsapp"></i> Open WhatsApp
                        </x-whatsapp-button>
                    </div>
                </div>
            @endif
            
            <!-- Location Map -->
            @if($store->latitude && $store->longitude)
                <div class="card">
                    <div class="card-header">
                        <h6 class="mb-0">
                            <i class="fas fa-map-marker-alt"></i>
                            Location
                        </h6>
                    </div>
                    <div class="card-body p-0">
                        <div id="store-map" style="height: 300px;"></div>
                    </div>
                </div>
            @endif
        </div>
    </div>
</div>

<!-- Custom Message Modal -->
<div class="modal fade" id="customMessageModal" tabindex="-1">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h5 class="modal-title">
                    <i class="fab fa-whatsapp text-success"></i>
                    Send Custom WhatsApp Message
                </h5>
                <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
            </div>
            
            <form id="customMessageForm">
                <div class="modal-body">
                    <div class="mb-3">
                        <label for="customerName" class="form-label">Your Name (Optional)</label>
                        <input type="text" 
                               class="form-control" 
                               id="customerName" 
                               value="{{ auth()->user()?->name ?? '' }}"
                               placeholder="Enter your name">
                    </div>
                    
                    <div class="mb-3">
                        <label for="messageType" class="form-label">Message Type</label>
                        <select class="form-select" id="messageType">
                            <option value="booking">Booking Appointment</option>
                            <option value="inquiry">Service Inquiry</option>
                            <option value="complaint">Complaint/Issue</option>
                            <option value="feedback">Feedback</option>
                            <option value="custom">Custom Message</option>
                        </select>
                    </div>
                    
                    <div class="mb-3">
                        <label for="customMessage" class="form-label">Message</label>
                        <textarea class="form-control" 
                                  id="customMessage" 
                                  rows="4"
                                  placeholder="Your message will appear here..."></textarea>
                        <div class="form-text">Preview of your WhatsApp message</div>
                    </div>
                </div>
                
                <div class="modal-footer">
                    <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
                        Cancel
                    </button>
                    <button type="button" class="btn btn-success" id="sendWhatsAppBtn">
                        <i class="fab fa-whatsapp"></i> Send via WhatsApp
                    </button>
                </div>
            </form>
        </div>
    </div>
</div>

@push('scripts')
<script>
document.addEventListener('DOMContentLoaded', function() {
    const store = @json($store->only(['name', 'phone']));
    const templates = @json(WhatsAppHelper::getMessageTemplates());
    
    const customerNameInput = document.getElementById('customerName');
    const messageTypeSelect = document.getElementById('messageType');
    const customMessageTextarea = document.getElementById('customMessage');
    const sendWhatsAppBtn = document.getElementById('sendWhatsAppBtn');
    
    // Update message preview
    function updateMessagePreview() {
        const customerName = customerNameInput.value.trim();
        const messageType = messageTypeSelect.value;
        
        if (messageType === 'custom') {
            // Don't auto-update for custom messages
            return;
        }
        
        let template = templates[messageType] || templates.booking;
        
        // Replace placeholders
        template = template.replace('{store_name}', store.name);
        if (customerName) {
            template = `Hi, my name is ${customerName}. ` + template.replace(/^Hi!\s*/, '');
        }
        
        customMessageTextarea.value = template;
    }
    
    // Event listeners
    customerNameInput.addEventListener('input', updateMessagePreview);
    messageTypeSelect.addEventListener('change', function() {
        if (this.value === 'custom') {
            customMessageTextarea.value = '';
            customMessageTextarea.focus();
        } else {
            updateMessagePreview();
        }
    });
    
    // Send WhatsApp message
    sendWhatsAppBtn.addEventListener('click', function() {
        const message = customMessageTextarea.value.trim();
        if (!message) {
            alert('Please enter a message');
            return;
        }
        
        const whatsappUrl = `https://wa.me/${store.phone.replace(/\D/g, '')}?text=${encodeURIComponent(message)}`;
        window.open(whatsappUrl, '_blank');
        
        // Close modal
        const modal = bootstrap.Modal.getInstance(document.getElementById('customMessageModal'));
        modal.hide();
    });
    
    // Initialize with default message
    updateMessagePreview();
});

// Google Maps (if available)
@if($store->latitude && $store->longitude)
function initMap() {
    const storeLocation = { lat: {{ $store->latitude }}, lng: {{ $store->longitude }} };
    
    const map = new google.maps.Map(document.getElementById('store-map'), {
        zoom: 15,
        center: storeLocation,
    });
    
    const marker = new google.maps.Marker({
        position: storeLocation,
        map: map,
        title: '{{ $store->name }}',
    });
    
    const infoWindow = new google.maps.InfoWindow({
        content: `
            <div>
                <h6>{{ $store->name }}</h6>
                <p>{{ $store->address }}</p>
                @if($store->has_whatsapp)
                <a href="{{ $store->whatsapp_url }}" target="_blank" class="btn btn-success btn-sm">
                    <i class="fab fa-whatsapp"></i> WhatsApp
                </a>
                @endif
            </div>
        `
    });
    
    marker.addListener('click', () => {
        infoWindow.open(map, marker);
    });
}
@endif
</script>

@if($store->latitude && $store->longitude)
<script async defer 
        src="https://maps.googleapis.com/maps/api/js?key={{ config('services.google.maps_api_key') }}&callback=initMap">
</script>
@endif
@endpush
@endsection

4. Advanced WhatsApp Business API Integration

WhatsApp Business API Service (app/Services/WhatsAppBusinessService.php)

<?php

namespace App\Services;

use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class WhatsAppBusinessService
{
    protected $apiUrl;
    protected $accessToken;
    protected $phoneNumberId;

    public function __construct()
    {
        $this->apiUrl = config('services.whatsapp.api_url');
        $this->accessToken = config('services.whatsapp.access_token');
        $this->phoneNumberId = config('services.whatsapp.phone_number_id');
    }

    /**
     * Send a text message
     */
    public function sendTextMessage($to, $message)
    {
        if (!$this->isConfigured()) {
            return $this->logError('WhatsApp Business API not configured');
        }

        try {
            $response = Http::withToken($this->accessToken)
                ->post("{$this->apiUrl}/{$this->phoneNumberId}/messages", [
                    'messaging_product' => 'whatsapp',
                    'to' => $to,
                    'type' => 'text',
                    'text' => ['body' => $message]
                ]);

            if ($response->successful()) {
                Log::info('WhatsApp message sent successfully', [
                    'to' => $to,
                    'message_id' => $response->json('messages.0.id')
                ]);
                return $response->json();
            } else {
                $this->logError('Failed to send WhatsApp message', [
                    'response' => $response->json(),
                    'status' => $response->status()
                ]);
                return false;
            }
        } catch (\Exception $e) {
            $this->logError('WhatsApp API exception', ['error' => $e->getMessage()]);
            return false;
        }
    }

    /**
     * Send a template message
     */
    public function sendTemplateMessage($to, $templateName, $languageCode = 'en', $parameters = [])
    {
        if (!$this->isConfigured()) {
            return $this->logError('WhatsApp Business API not configured');
        }

        try {
            $template = [
                'name' => $templateName,
                'language' => ['code' => $languageCode]
            ];

            if (!empty($parameters)) {
                $template['components'] = [
                    [
                        'type' => 'body',
                        'parameters' => array_map(function($param) {
                            return ['type' => 'text', 'text' => $param];
                        }, $parameters)
                    ]
                ];
            }

            $response = Http::withToken($this->accessToken)
                ->post("{$this->apiUrl}/{$this->phoneNumberId}/messages", [
                    'messaging_product' => 'whatsapp',
                    'to' => $to,
                    'type' => 'template',
                    'template' => $template
                ]);

            if ($response->successful()) {
                Log::info('WhatsApp template sent successfully', [
                    'to' => $to,
                    'template' => $templateName,
                    'message_id' => $response->json('messages.0.id')
                ]);
                return $response->json();
            } else {
                $this->logError('Failed to send WhatsApp template', [
                    'response' => $response->json(),
                    'status' => $response->status()
                ]);
                return false;
            }
        } catch (\Exception $e) {
            $this->logError('WhatsApp template API exception', ['error' => $e->getMessage()]);
            return false;
        }
    }

    /**
     * Handle incoming webhook
     */
    public function handleWebhook($payload)
    {
        try {
            if (isset($payload['entry'][0]['changes'][0]['value']['messages'])) {
                $messages = $payload['entry'][0]['changes'][0]['value']['messages'];
                
                foreach ($messages as $message) {
                    $this->processIncomingMessage($message);
                }
            }

            return true;
        } catch (\Exception $e) {
            $this->logError('Webhook processing error', ['error' => $e->getMessage()]);
            return false;
        }
    }

    /**
     * Process incoming message
     */
    protected function processIncomingMessage($message)
    {
        $from = $message['from'];
        $messageType = $message['type'];
        
        Log::info('Incoming WhatsApp message', [
            'from' => $from,
            'type' => $messageType,
            'message_id' => $message['id']
        ]);

        // Handle different message types
        switch ($messageType) {
            case 'text':
                $text = $message['text']['body'];
                $this->handleTextMessage($from, $text);
                break;
                
            case 'button':
                $buttonText = $message['button']['text'];
                $this->handleButtonMessage($from, $buttonText);
                break;
                
            default:
                Log::info('Unhandled message type', ['type' => $messageType]);
        }
    }

    /**
     * Handle incoming text message
     */
    protected function handleTextMessage($from, $text)
    {
        // Auto-responder logic
        $lowercaseText = strtolower($text);
        
        if (str_contains($lowercaseText, 'booking') || str_contains($lowercaseText, 'appointment')) {
            $this->sendAutoReply($from, 'booking');
        } elseif (str_contains($lowercaseText, 'price') || str_contains($lowercaseText, 'cost')) {
            $this->sendAutoReply($from, 'pricing');
        } elseif (str_contains($lowercaseText, 'hour') || str_contains($lowercaseText, 'open')) {
            $this->sendAutoReply($from, 'hours');
        } else {
            $this->sendAutoReply($from, 'general');
        }
    }

    /**
     * Send auto-reply based on context
     */
    protected function sendAutoReply($to, $context)
    {
        $replies = [
            'booking' => "Thank you for your interest in booking! Please let us know your preferred date and time, and we'll confirm your appointment.",
            'pricing' => "Thank you for your inquiry! Our service prices vary depending on the treatment. Please visit our store or call us for detailed pricing information.",
            'hours' => "Our operating hours are Monday-Friday 9 AM - 9 PM, Saturday-Sunday 8 AM - 10 PM. We look forward to serving you!",
            'general' => "Thank you for contacting us! We'll get back to you as soon as possible during business hours."
        ];

        $message = $replies[$context] ?? $replies['general'];
        $this->sendTextMessage($to, $message);
    }

    /**
     * Check if API is properly configured
     */
    protected function isConfigured()
    {
        return $this->apiUrl && $this->accessToken && $this->phoneNumberId;
    }

    /**
     * Log error with context
     */
    protected function logError($message, $context = [])
    {
        Log::error("WhatsApp Business API: {$message}", $context);
        return false;
    }
}

Configuration File (config/services.php)

Add to existing services config:

// Add to config/services.php

'whatsapp' => [
    'api_url' => env('WHATSAPP_API_URL', 'https://graph.facebook.com/v17.0'),
    'access_token' => env('WHATSAPP_ACCESS_TOKEN'),
    'phone_number_id' => env('WHATSAPP_PHONE_NUMBER_ID'),
    'verify_token' => env('WHATSAPP_VERIFY_TOKEN'),
    'webhook_url' => env('WHATSAPP_WEBHOOK_URL'),
],

Environment Variables (.env)

# WhatsApp Business API (Optional - for advanced features)
WHATSAPP_API_URL=https://graph.facebook.com/v17.0
WHATSAPP_ACCESS_TOKEN=your_access_token_here
WHATSAPP_PHONE_NUMBER_ID=your_phone_number_id_here
WHATSAPP_VERIFY_TOKEN=your_verify_token_here
WHATSAPP_WEBHOOK_URL=https://yourdomain.com/api/whatsapp/webhook

5. Webhook Controller

WhatsApp Webhook Controller (app/Http/Controllers/Api/WhatsAppWebhookController.php)

<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Services\WhatsAppBusinessService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;

class WhatsAppWebhookController extends Controller
{
    protected $whatsappService;

    public function __construct(WhatsAppBusinessService $whatsappService)
    {
        $this->whatsappService = $whatsappService;
    }

    /**
     * Verify webhook (GET request)
     */
    public function verify(Request $request)
    {
        $verifyToken = config('services.whatsapp.verify_token');
        
        if ($request->get('hub_verify_token') === $verifyToken) {
            return response($request->get('hub_challenge'));
        }
        
        return response('Forbidden', 403);
    }

    /**
     * Handle webhook (POST request)
     */
    public function handle(Request $request)
    {
        Log::info('WhatsApp webhook received', $request->all());
        
        $payload = $request->all();
        
        if ($this->whatsappService->handleWebhook($payload)) {
            return response('OK', 200);
        }
        
        return response('Error', 500);
    }
}

Routes for Webhook (routes/api.php)

// Add to routes/api.php

use App\Http\Controllers\Api\WhatsAppWebhookController;

Route::get('/whatsapp/webhook', [WhatsAppWebhookController::class, 'verify']);
Route::post('/whatsapp/webhook', [WhatsAppWebhookController::class, 'handle']);

6. Frontend Enhancements

Floating WhatsApp Button (resources/views/components/whatsapp-float.blade.php)

@props([
    'store' => null,
    'position' => 'bottom-right',
    'size' => 'md'
])

@php
    $positions = [
        'bottom-right' => 'bottom: 20px; right: 20px;',
        'bottom-left' => 'bottom: 20px; left: 20px;',
        'top-right' => 'top: 20px; right: 20px;',
        'top-left' => 'top: 20px; left: 20px;'
    ];

    $sizes = [
        'sm' => '50px',
        'md' => '60px',
        'lg' => '70px'
    ];

    $positionStyle = $positions[$position] ?? $positions['bottom-right'];
    $buttonSize = $sizes[$size] ?? $sizes['md'];
@endphp

@if($store && $store->has_whatsapp)
<div id="whatsapp-float" 
     class="whatsapp-float" 
     style="position: fixed; {{ $positionStyle }} z-index: 1000;">
    
    <a href="{{ $store->whatsapp_url }}" 
       target="_blank"
       class="btn btn-success rounded-circle shadow-lg d-flex align-items-center justify-content-center"
       style="width: {{ $buttonSize }}; height: {{ $buttonSize }}; text-decoration: none;"
       title="Chat on WhatsApp"
       data-bs-toggle="tooltip">
        
        <i class="fab fa-whatsapp" style="font-size: {{ $size === 'lg' ? '24px' : ($size === 'sm' ? '18px' : '20px') }};"></i>
    </a>
    
    <!-- Pulse animation -->
    <div class="whatsapp-pulse" 
         style="position: absolute; top: 0; left: 0; width: {{ $buttonSize }}; height: {{ $buttonSize }}; border-radius: 50%; background-color: rgba(37, 211, 102, 0.3); animation: whatsapp-pulse 2s infinite;"></div>
</div>

<style>
@keyframes whatsapp-pulse {
    0% {
        transform: scale(1);
        opacity: 1;
    }
    50% {
        transform: scale(1.2);
        opacity: 0.7;
    }
    100% {
        transform: scale(1.5);
        opacity: 0;
    }
}

.whatsapp-float:hover .btn {
    transform: scale(1.1);
    transition: transform 0.2s ease;
}
</style>

@push('scripts')
<script>
document.addEventListener('DOMContentLoaded', function() {
    // Initialize tooltip
    const floatButton = document.querySelector('#whatsapp-float [data-bs-toggle="tooltip"]');
    if (floatButton) {
        new bootstrap.Tooltip(floatButton);
    }
});
</script>
@endpush
@endif

Include in Layout

Add to your main layout (resources/views/layouts/app.blade.php):

<!-- Add before closing body tag -->
@if(isset($store))
    <x-whatsapp-float :store="$store" />
@endif

7. Analytics & Tracking

WhatsApp Analytics Service (app/Services/WhatsAppAnalyticsService.php)

<?php

namespace App\Services;

use Illuminate\Support\Facades\DB;
use Carbon\Carbon;

class WhatsAppAnalyticsService
{
    /**
     * Track WhatsApp click
     */
    public static function trackClick($storeId, $messageType = 'general', $userId = null)
    {
        DB::table('whatsapp_analytics')->insert([
            'store_id' => $storeId,
            'user_id' => $userId,
            'message_type' => $messageType,
            'action' => 'click',
            'ip_address' => request()->ip(),
            'user_agent' => request()->userAgent(),
            'created_at' => now(),
        ]);
    }

    /**
     * Get click statistics
     */
    public static function getClickStats($storeId = null, $days = 30)
    {
        $query = DB::table('whatsapp_analytics')
                   ->where('action', 'click')
                   ->where('created_at', '>=', now()->subDays($days));

        if ($storeId) {
            $query->where('store_id', $storeId);
        }

        return [
            'total_clicks' => $query->count(),
            'unique_users' => $query->whereNotNull('user_id')->distinct('user_id')->count(),
            'by_message_type' => $query->select('message_type', DB::raw('count(*) as count'))
                                     ->groupBy('message_type')
                                     ->pluck('count', 'message_type')
                                     ->toArray(),
            'daily_clicks' => $query->select(DB::raw('DATE(created_at) as date'), DB::raw('count(*) as count'))
                                   ->groupBy('date')
                                   ->orderBy('date')
                                   ->pluck('count', 'date')
                                   ->toArray(),
        ];
    }
}

Analytics Migration

<?php
// database/migrations/xxxx_create_whatsapp_analytics_table.php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up()
    {
        Schema::create('whatsapp_analytics', function (Blueprint $table) {
            $table->id();
            $table->foreignId('store_id')->constrained()->onDelete('cascade');
            $table->foreignId('user_id')->nullable()->constrained()->onDelete('set null');
            $table->string('message_type')->default('general');
            $table->string('action'); // click, sent, delivered, read
            $table->string('ip_address')->nullable();
            $table->text('user_agent')->nullable();
            $table->json('metadata')->nullable();
            $table->timestamps();
            
            $table->index(['store_id', 'created_at']);
            $table->index(['action', 'created_at']);
        });
    }

    public function down()
    {
        Schema::dropIfExists('whatsapp_analytics');
    }
};

📊 Usage Examples

Basic Implementation

<!-- Simple WhatsApp button -->
<x-whatsapp-button :store="$store">
    Book Appointment
</x-whatsapp-button>

<!-- Custom message type -->
<x-whatsapp-button 
    :store="$store" 
    message-type="inquiry"
    variant="outline-success">
    Ask Questions
</x-whatsapp-button>

<!-- With customer name -->
<x-whatsapp-button 
    :store="$store" 
    :customer-name="auth()->user()->name"
    custom-message="I'd like to book for tomorrow">
    Custom Booking
</x-whatsapp-button>

Programmatic Usage

// Generate WhatsApp URL
$url = $store->getWhatsAppUrl('booking', 'John Doe');

// Check if store has WhatsApp
if ($store->has_whatsapp) {
    // Show WhatsApp options
}

// Format phone number
$formatted = WhatsAppHelper::formatPhoneNumber('081234567890');
// Result: 6281234567890

// Generate custom message
$message = WhatsAppHelper::processTemplate(
    'Hi {customer_name}! I want to book at {store_name}',
    ['customer_name' => 'John', 'store_name' => 'Barbershop Central']
);

Next: Security Features untuk implementasi keamanan sistem.

⚠️ **GitHub.com Fallback** ⚠️