Saltar al contenido
Filament Contact Form
code

Detalles del ejemplo

Filament Contact Form

Formulario de contacto con gestión completa en Filament y componente Livewire para frontend con 3 variantes de estilos, honeypot, rate limiting y mapa Leaflet opcional.

Instalación

composer require cursosdesarrolloweb/filament-contact-form

Configuración

1. Registrar el plugin en tu panel

use CursosDesarrolloWeb\ContactForm\ContactFormPlugin;

public function panel(Panel $panel): Panel
{
    return $panel
        // ...
        ->plugins([
            ContactFormPlugin::make(),
        ]);
}

2. Publicar y ejecutar migraciones

php artisan vendor:publish --tag=filament-contact-form-migrations
php artisan migrate

Publicar recursos opcionales

Configuración

php artisan vendor:publish --tag=filament-contact-form-config

Traducciones

php artisan vendor:publish --tag=filament-contact-form-translations

Los archivos se publican en lang/vendor/filament-contact-form/.

Vistas

php artisan vendor:publish --tag=filament-contact-form-views

Uso en Frontend

El paquete incluye un componente Livewire con 3 variantes de estilos:

{{-- Sin estilos (clases CSS personalizables) --}}
<livewire:contact-form />

{{-- Con Tailwind CSS --}}
<livewire:contact-form theme="tailwind" />

{{-- Con Bootstrap 5 --}}
<livewire:contact-form theme="bootstrap" />

Con Mapa Leaflet

Si configuras coordenadas en el archivo de configuración, puedes mostrar un mapa:

<livewire:contact-form theme="tailwind" show-map />

Importante: Para que el mapa funcione, tu layout debe incluir @stack('scripts') antes de cerrar </body>:

<body>
    {{ $slot }}

    @stack('scripts')
</body>

Usando la variante Tailwind

La variante Tailwind usa clases estándar de Tailwind CSS. Para que los estilos se compilen correctamente, debes añadir las vistas del paquete al source de Tailwind.

En Tailwind v4 (CSS), añade en tu archivo CSS principal:

@source '../../vendor/cursosdesarrolloweb/filament-contact-form/resources/views/**/*.blade.php';

En Tailwind v3 (tailwind.config.js), añade al array content:

content: [
    // ...
    './vendor/cursosdesarrolloweb/filament-contact-form/resources/views/**/*.blade.php',
]

Después ejecuta npm run build para recompilar los estilos.

Funcionalidades del Backoffice

  • Listado de mensajes: Ver todos los mensajes con filtros por estado
  • Ver mensaje: Detalle completo del mensaje (marca automáticamente como leído)
  • Responder: Acción para responder directamente por email
  • Estados: Nuevo (rojo), Leído (amarillo), Respondido (verde)

Personalización

Modelo personalizado

Publica la configuración y modifica el modelo:

// config/filament-contact-form.php
return [
    'model' => \App\Models\ContactMessage::class,
];

Tu modelo debe extender el modelo del paquete:

use CursosDesarrolloWeb\ContactForm\Models\ContactMessage as BaseContactMessage;

class ContactMessage extends BaseContactMessage
{
    // Tus personalizaciones
}

Notificación de respuesta personalizada

Por defecto, el paquete envía un email con formato Laravel estándar al responder un mensaje. Puedes crear tu propia notificación:

// config/filament-contact-form.php
return [
    'reply' => [
        'notification' => \App\Notifications\MyCustomReplyNotification::class,
    ],
];

Tu notificación debe aceptar los mismos parámetros en el constructor:

use CursosDesarrolloWeb\ContactForm\Models\ContactMessage;
use Illuminate\Notifications\Notification;

class MyCustomReplyNotification extends Notification
{
    public function __construct(
        public ContactMessage $contactMessage,
        public string $replyMessage,
    ) {}

    public function via(object $notifiable): array
    {
        return ['mail'];
    }

    public function toMail(object $notifiable): MailMessage
    {
        return (new MailMessage)
            ->subject('Re: ' . $this->contactMessage->subject)
            ->view('emails.contact-reply', [
                'contactMessage' => $this->contactMessage,
                'replyMessage' => $this->replyMessage,
            ]);
    }
}

Grupo de navegación

Por defecto, el recurso aparece en el grupo "Contenido". Puedes cambiarlo en la configuración:

// config/filament-contact-form.php
return [
    'navigation' => [
        'group' => 'Mi Grupo',  // null para sin grupo
        'sort' => 20,
    ],
];

Evento

El paquete dispara un evento ContactFormSubmitted cuando se envía un mensaje. Puedes escucharlo para enviar notificaciones al administrador:

use CursosDesarrolloWeb\ContactForm\Events\ContactFormSubmitted;

class SendContactNotification
{
    public function handle(ContactFormSubmitted $event): void
    {
        $message = $event->contactMessage;
        
        // Enviar email, notificación de Slack, etc.
    }
}

Scopes disponibles

El modelo ContactMessage incluye los siguientes scopes:

Scope Descripción
new() Solo mensajes nuevos
read() Solo mensajes leídos
replied() Solo mensajes respondidos
unread() Mensajes nuevos y leídos (sin responder)
use CursosDesarrolloWeb\ContactForm\Models\ContactMessage;

// Obtener mensajes sin responder
$pending = ContactMessage::unread()->get();

// Contar mensajes nuevos
$newCount = ContactMessage::new()->count();

Métodos del modelo

Método Descripción
markAsRead() Marca el mensaje como leído
markAsReplied($message) Marca como respondido con el mensaje de respuesta
isNew() Devuelve true si el estado es "new"
isRead() Devuelve true si el estado es "read"
isReplied() Devuelve true si el estado es "replied"

Personalización de estilos

La variante sin estilos usa clases CSS que puedes personalizar:

Clase Elemento
.contact-form Contenedor principal
.contact-form-field Contenedor de cada campo
.contact-form-label Etiquetas
.contact-form-input Campos de texto
.contact-form-textarea Área de mensaje
.contact-form-button Botón de envío
.contact-form-error Mensajes de error
.contact-form-success Mensaje de éxito

Configuración completa

// config/filament-contact-form.php

return [
    // Navegación en Filament
    'navigation' => [
        'group' => 'Content',
        'sort' => 20,
    ],

    // Modelo personalizado
    'model' => \CursosDesarrolloWeb\ContactForm\Models\ContactMessage::class,

    // Tabla de base de datos
    'table' => 'contact_messages',

    // Rate limiting
    'rate_limit' => [
        'enabled' => true,
        'max_attempts' => 5,
        'decay_minutes' => 60,
    ],

    // Honeypot anti-spam
    'honeypot' => [
        'enabled' => true,
        'field_name' => 'website',
    ],

    // Mapa Leaflet (opcional)
    'map' => [
        'latitude' => null,  // ej: 40.4168
        'longitude' => null, // ej: -3.7038
        'zoom' => 15,
    ],

    // Email de respuesta
    'reply' => [
        'from_name' => null,  // Si null, usa config('mail.from.name')
        'from_email' => null, // Si null, usa config('mail.from.address')
        'notification' => \CursosDesarrolloWeb\ContactForm\Notifications\ContactReplyNotification::class,
    ],
];

Estructura de la base de datos

Tabla contact_messages

Campo Tipo Descripción
id bigint Primary key
name string Nombre del remitente
email string Email del remitente
phone string Teléfono (opcional)
subject string Asunto del mensaje
message text Contenido del mensaje
status enum new, read, replied
ip_address string IP del remitente
user_agent string User agent del navegador
replied_at timestamp Fecha de respuesta
replied_message text Mensaje de respuesta
timestamps created_at, updated_at

Requisitos

  • PHP 8.2+
  • Laravel 11+
  • Filament 4.x|5.x
  • Livewire 3.x|4.x

Licencia

Propietario - Solo para suscriptores de CursosDesarrolloWeb.