Claude-skill-registry customer-ui-components

Componentes de UI para clientes seguindo o padrão de components do Easy Budget.

install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/customer-ui-components" ~/.claude/skills/majiayu000-claude-skill-registry-customer-ui-components && rm -rf "$T"
manifest: skills/data/customer-ui-components/SKILL.md
source content

Componentes de UI para Clientes

Esta skill define os componentes Blade específicos para a gestão de clientes no Easy Budget, seguindo o padrão de components estabelecido no sistema.

Estrutura de Components

resources/views/components/
├── customer/
│   ├── customer-card.blade.php       # Card resumido de cliente
│   ├── customer-details.blade.php    # Detalhes completos do cliente
│   ├── customer-form.blade.php       # Formulário de criação/edição
│   ├── customer-status.blade.php     # Badge de status do cliente
│   ├── customer-contact.blade.php    # Informações de contato
│   ├── customer-address.blade.php    # Endereço do cliente
│   ├── customer-actions.blade.php    # Ações disponíveis para cliente
│   ├── customer-filters.blade.php    # Filtros específicos para clientes
│   ├── customer-interactions.blade.php # Histórico de interações
│   └── customer-summary.blade.php    # Resumo do cliente
└── ...

1. Customer Card Component

Componente para exibição resumida de clientes em listas e dashboards.

Uso Básico

<x-customer.customer-card :customer="$customer" :showType="true" :showStatus="true" />

Parâmetros

ParâmetroTipoDescriçãoPadrão
customer
Customer
Modelo do clienteObrigatório
showType
bool
Exibir tipo de cliente (PF/PJ)
true
showStatus
bool
Exibir status do cliente
true
variant
string
Estilo do card (primary, secondary, etc.)
primary

Estrutura

@props([
    'customer',
    'showType' => true,
    'showStatus' => true,
    'variant' => 'primary'
])

<div class="card border-0 shadow-sm h-100">
    <div class="card-body">
        <div class="d-flex justify-content-between align-items-start mb-3">
            <div class="d-flex align-items-center gap-3">
                <div class="avatar-circle bg-{{ $variant }} bg-gradient">
                    @if($customer->type === 'pf')
                        <i class="bi bi-person text-white"></i>
                    @else
                        <i class="bi bi-building text-white"></i>
                    @endif
                </div>
                <div>
                    <h6 class="mb-1 fw-bold">{{ $customer->display_name }}</h6>
                    <small class="text-muted">{{ $customer->created_at->format('d/m/Y') }}</small>
                </div>
            </div>
            @if($showStatus)
                <x-customer.customer-status :customer="$customer" />
            @endif
        </div>

        @if($showType)
            <div class="mb-3">
                <span class="badge bg-secondary">{{ $customer->type === 'pf' ? 'Pessoa Física' : 'Pessoa Jurídica' }}</span>
            </div>
        @endif

        @if($customer->contact)
            <div class="mb-3">
                <small class="text-muted">E-mail:</small>
                <div class="fw-semibold">{{ $customer->contact->email }}</div>
            </div>
        @endif

        @if($customer->address)
            <div class="mb-3">
                <small class="text-muted">Endereço:</small>
                <div class="fw-semibold">{{ $customer->address->city }}/{{ $customer->address->state }}</div>
            </div>
        @endif

        <div class="d-flex justify-content-between align-items-center">
            <div>
                <small class="text-muted">Total de Orçamentos</small>
                <div class="h6 mb-0 fw-bold text-{{ $variant }}">
                    {{ $customer->budgets->count() }}
                </div>
            </div>

            <div class="btn-group btn-group-sm" role="group">
                <a href="{{ route('provider.customers.show', $customer) }}" class="btn btn-outline-primary">
                    <i class="bi bi-eye"></i> Ver
                </a>
                <a href="{{ route('provider.customers.edit', $customer) }}" class="btn btn-outline-secondary">
                    <i class="bi bi-pencil"></i> Editar
                </a>
            </div>
        </div>
    </div>
</div>

2. Customer Details Component

Componente para exibição detalhada de informações do cliente.

Uso Básico

<x-customer.customer-details :customer="$customer" :showContact="true" :showAddress="true" />

Parâmetros

ParâmetroTipoDescriçãoPadrão
customer
Customer
Modelo do clienteObrigatório
showContact
bool
Exibir informações de contato
true
showAddress
bool
Exibir endereço
true
collapsible
bool
Permitir colapsar seções
false

Estrutura

@props([
    'customer',
    'showContact' => true,
    'showAddress' => true,
    'collapsible' => false
])

<div class="customer-details">
    <!-- Informações Básicas -->
    <div class="row g-3 mb-3">
        <div class="col-md-4">
            <div class="info-item">
                <label class="text-muted small">Nome/Razão Social</label>
                <div class="fw-bold">{{ $customer->display_name }}</div>
            </div>
        </div>
        <div class="col-md-4">
            <div class="info-item">
                <label class="text-muted small">Tipo</label>
                <div class="fw-bold">
                    <span class="badge bg-secondary">{{ $customer->type === 'pf' ? 'Pessoa Física' : 'Pessoa Jurídica' }}</span>
                </div>
            </div>
        </div>
        <div class="col-md-4">
            <div class="info-item">
                <label class="text-muted small">Status</label>
                <x-customer.customer-status :customer="$customer" />
            </div>
        </div>
    </div>

    <!-- Dados Pessoais/Empresariais -->
    @if($customer->commonData)
        <div class="row mb-3">
            <div class="col-12">
                <div class="card border-0">
                    <div class="card-header bg-transparent border-0">
                        <h6 class="mb-0">{{ $customer->type === 'pf' ? 'Dados Pessoais' : 'Dados Empresariais' }}</h6>
                    </div>
                    <div class="card-body">
                        <div class="row">
                            @if($customer->type === 'pf')
                                <div class="col-md-6">
                                    <div class="mb-2">
                                        <label class="text-muted small">Nome Completo</label>
                                        <div class="fw-bold">{{ $customer->commonData->first_name }} {{ $customer->commonData->last_name }}</div>
                                    </div>
                                    <div class="mb-2">
                                        <label class="text-muted small">Data de Nascimento</label>
                                        <div class="fw-bold">{{ $customer->commonData->birth_date?->format('d/m/Y') ?? 'Não informado' }}</div>
                                    </div>
                                    @if($customer->commonData->cpf)
                                        <div class="mb-2">
                                            <label class="text-muted small">CPF</label>
                                            <div class="fw-bold">{{ \App\Helpers\DocumentHelper::formatCpf($customer->commonData->cpf) }}</div>
                                        </div>
                                    @endif
                                </div>
                            @else
                                <div class="col-md-6">
                                    <div class="mb-2">
                                        <label class="text-muted small">Razão Social</label>
                                        <div class="fw-bold">{{ $customer->commonData->company_name }}</div>
                                    </div>
                                    @if($customer->commonData->cnpj)
                                        <div class="mb-2">
                                            <label class="text-muted small">CNPJ</label>
                                            <div class="fw-bold">{{ \App\Helpers\DocumentHelper::formatCnpj($customer->commonData->cnpj) }}</div>
                                        </div>
                                    @endif
                                    @if($customer->commonData->cpf)
                                        <div class="mb-2">
                                            <label class="text-muted small">CPF do Responsável</label>
                                            <div class="fw-bold">{{ \App\Helpers\DocumentHelper::formatCpf($customer->commonData->cpf) }}</div>
                                        </div>
                                    @endif
                                </div>
                            @endif

                            <div class="col-md-6">
                                @if($customer->commonData->areaOfActivity)
                                    <div class="mb-2">
                                        <label class="text-muted small">Área de Atuação</label>
                                        <div class="fw-bold">{{ $customer->commonData->areaOfActivity->name }}</div>
                                    </div>
                                @endif
                                @if($customer->commonData->profession)
                                    <div class="mb-2">
                                        <label class="text-muted small">Profissão</label>
                                        <div class="fw-bold">{{ $customer->commonData->profession->name }}</div>
                                    </div>
                                @endif
                                @if($customer->commonData->description)
                                    <div class="mb-2">
                                        <label class="text-muted small">Descrição</label>
                                        <div class="fw-bold">{{ $customer->commonData->description }}</div>
                                    </div>
                                @endif
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    @endif

    <!-- Contato -->
    @if($showContact && $customer->contact)
        <x-customer.customer-contact :contact="$customer->contact" />
    @endif

    <!-- Endereço -->
    @if($showAddress && $customer->address)
        <x-customer.customer-address :address="$customer->address" />
    @endif

    <!-- Resumo -->
    <x-customer.customer-summary :customer="$customer" />
</div>

3. Customer Status Component

Componente para exibição do status do cliente com cores e ícones apropriados.

Uso Básico

<x-customer.customer-status :customer="$customer" :showIcon="true" />

Parâmetros

ParâmetroTipoDescriçãoPadrão
customer
Customer
Modelo do clienteObrigatório
showIcon
bool
Exibir ícone ao lado do status
true
size
string
Tamanho do badge (sm, md, lg)
md

Estrutura

@props([
    'customer',
    'showIcon' => true,
    'size' => 'md'
])

@php
    $status = $customer->status;
    $color = match($status) {
        'active' => '#198754', // Verde
        'inactive' => '#6c757d', // Cinza
        'pending' => '#ffc107', // Amarelo
        default => '#6c757d'
    };

    $icon = match($status) {
        'active' => 'check-circle',
        'inactive' => 'x-circle',
        'pending' => 'clock',
        default => 'circle'
    };

    $description = match($status) {
        'active' => 'Ativo',
        'inactive' => 'Inativo',
        'pending' => 'Pendente',
        default => 'Status Desconhecido'
    };

    $sizeClass = match($size) {
        'sm' => 'badge-sm',
        'lg' => 'badge-lg',
        default => 'badge-md'
    };
@endphp

<span class="badge modern-badge {{ $sizeClass }}"
      style="background-color: {{ $color }}20; color: {{ $color }}; border: 1px solid {{ $color }}40;">
    @if($showIcon)
        <i class="bi bi-{{ $icon }} me-1"></i>
    @endif
    {{ $description }}
</span>

4. Customer Contact Component

Componente para exibição de informações de contato do cliente.

Uso Básico

<x-customer.customer-contact :contact="$contact" :showBusiness="true" />

Parâmetros

ParâmetroTipoDescriçãoPadrão
contact
Contact
Modelo de contatoObrigatório
showBusiness
bool
Exibir contatos comerciais
true
showWebsite
bool
Exibir website
true

Estrutura

@props([
    'contact',
    'showBusiness' => true,
    'showWebsite' => true
])

<div class="customer-contact">
    <div class="card border-0 shadow-sm">
        <div class="card-header bg-transparent border-0">
            <h6 class="mb-0">Informações de Contato</h6>
        </div>
        <div class="card-body">
            <div class="row">
                <div class="col-md-6">
                    <div class="mb-3">
                        <label class="text-muted small">E-mail Principal</label>
                        <div class="fw-bold">{{ $contact->email }}</div>
                    </div>
                    @if($contact->phone)
                        <div class="mb-3">
                            <label class="text-muted small">Telefone</label>
                            <div class="fw-bold">{{ $contact->phone }}</div>
                        </div>
                    @endif
                </div>

                @if($showBusiness)
                    <div class="col-md-6">
                        @if($contact->email_business)
                            <div class="mb-3">
                                <label class="text-muted small">E-mail Comercial</label>
                                <div class="fw-bold">{{ $contact->email_business }}</div>
                            </div>
                        @endif
                        @if($contact->phone_business)
                            <div class="mb-3">
                                <label class="text-muted small">Telefone Comercial</label>
                                <div class="fw-bold">{{ $contact->phone_business }}</div>
                            </div>
                        @endif
                    </div>
                @endif
            </div>

            @if($showWebsite && $contact->website)
                <div class="row">
                    <div class="col-12">
                        <div class="mb-3">
                            <label class="text-muted small">Website</label>
                            <div class="fw-bold">
                                <a href="{{ $contact->website }}" target="_blank" class="text-decoration-none">
                                    {{ $contact->website }}
                                </a>
                            </div>
                        </div>
                    </div>
                </div>
            @endif
        </div>
    </div>
</div>

5. Customer Address Component

Componente para exibição de endereço do cliente.

Uso Básico

<x-customer.customer-address :address="$address" />

Parâmetros

ParâmetroTipoDescriçãoPadrão
address
Address
Modelo de endereçoObrigatório

Estrutura

@props(['address'])

<div class="customer-address">
    <div class="card border-0 shadow-sm">
        <div class="card-header bg-transparent border-0">
            <h6 class="mb-0">Endereço</h6>
        </div>
        <div class="card-body">
            <div class="row">
                <div class="col-md-8">
                    <div class="mb-2">
                        <label class="text-muted small">Logradouro</label>
                        <div class="fw-bold">
                            {{ $address->address }}, {{ $address->address_number }}
                            @if($address->address_complement)
                                - {{ $address->address_complement }}
                            @endif
                        </div>
                    </div>
                    <div class="mb-2">
                        <label class="text-muted small">Bairro</label>
                        <div class="fw-bold">{{ $address->neighborhood }}</div>
                    </div>
                </div>
                <div class="col-md-4">
                    <div class="mb-2">
                        <label class="text-muted small">CEP</label>
                        <div class="fw-bold">{{ $address->cep }}</div>
                    </div>
                </div>
            </div>
            <div class="row">
                <div class="col-md-6">
                    <div class="mb-2">
                        <label class="text-muted small">Cidade</label>
                        <div class="fw-bold">{{ $address->city }}</div>
                    </div>
                </div>
                <div class="col-md-6">
                    <div class="mb-2">
                        <label class="text-muted small">Estado</label>
                        <div class="fw-bold">{{ $address->state }}</div>
                    </div>
                </div>
            </div>
            @if($address->country && $address->country !== 'Brasil')
                <div class="row">
                    <div class="col-12">
                        <div class="mb-2">
                            <label class="text-muted small">País</label>
                            <div class="fw-bold">{{ $address->country }}</div>
                        </div>
                    </div>
                </div>
            @endif
        </div>
    </div>
</div>

6. Customer Form Component

Componente para formulário de criação e edição de clientes.

Uso Básico

<x-customer.customer-form :customer="$customer ?? null" :areasOfActivity="$areasOfActivity" :professions="$professions" />

Parâmetros

ParâmetroTipoDescriçãoPadrão
customer
`Customernull`Modelo do cliente (para edição)
areasOfActivity
Collection
Áreas de atuação disponíveisObrigatório
professions
Collection
Profissões disponíveisObrigatório
type
string
Tipo de cliente (pf/pj)
pf

Estrutura

@props([
    'customer' => null,
    'areasOfActivity' => [],
    'professions' => [],
    'type' => 'pf'
])

<div class="customer-form">
    <form action="{{ isset($customer) ? route('provider.customers.update', $customer) : route('provider.customers.store') }}"
          method="POST"
          id="customerForm">
        @csrf
        @if(isset($customer)) @method('PUT') @endif

        <!-- Tipo de Cliente -->
        <div class="row g-3 mb-4">
            <div class="col-12">
                <div class="card border-0 shadow-sm">
                    <div class="card-body">
                        <div class="row">
                            <div class="col-md-6">
                                <label class="form-label small fw-bold text-muted text-uppercase">Tipo de Cliente *</label>
                                <div class="btn-group w-100" role="group">
                                    <input type="radio" class="btn-check" name="type" id="type_pf" value="pf"
                                           {{ (old('type', $customer->type ?? $type) == 'pf') ? 'checked' : '' }} required>
                                    <label class="btn btn-outline-primary" for="type_pf">
                                        <i class="bi bi-person me-2"></i>Pessoa Física
                                    </label>

                                    <input type="radio" class="btn-check" name="type" id="type_pj" value="pj"
                                           {{ (old('type', $customer->type ?? $type) == 'pj') ? 'checked' : '' }} required>
                                    <label class="btn btn-outline-secondary" for="type_pj">
                                        <i class="bi bi-building me-2"></i>Pessoa Jurídica
                                    </label>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <!-- Dados Pessoais/Empresariais -->
        <div class="row g-3 mb-4">
            <div class="col-12">
                <div class="card border-0 shadow-sm">
                    <div class="card-header bg-transparent border-0">
                        <h6 class="mb-0">{{ $type === 'pf' ? 'Dados Pessoais' : 'Dados Empresariais' }}</h6>
                    </div>
                    <div class="card-body">
                        @if($type === 'pf')
                            <!-- Pessoa Física -->
                            <div class="row">
                                <div class="col-md-6">
                                    <label class="form-label small fw-bold text-muted text-uppercase">Nome *</label>
                                    <input type="text"
                                           name="first_name"
                                           class="form-control @error('first_name') is-invalid @enderror"
                                           value="{{ old('first_name', $customer->commonData->first_name ?? '') }}" required>
                                    @error('first_name')
                                        <div class="invalid-feedback">{{ $message }}</div>
                                    @enderror
                                </div>
                                <div class="col-md-6">
                                    <label class="form-label small fw-bold text-muted text-uppercase">Sobrenome *</label>
                                    <input type="text"
                                           name="last_name"
                                           class="form-control @error('last_name') is-invalid @enderror"
                                           value="{{ old('last_name', $customer->commonData->last_name ?? '') }}" required>
                                    @error('last_name')
                                        <div class="invalid-feedback">{{ $message }}</div>
                                    @enderror
                                </div>
                                <div class="col-md-4">
                                    <label class="form-label small fw-bold text-muted text-uppercase">Data de Nascimento</label>
                                    <input type="date"
                                           name="birth_date"
                                           class="form-control @error('birth_date') is-invalid @enderror"
                                           value="{{ old('birth_date', $customer->commonData->birth_date?->format('Y-m-d') ?? '') }}">
                                    @error('birth_date')
                                        <div class="invalid-feedback">{{ $message }}</div>
                                    @enderror
                                </div>
                                <div class="col-md-4">
                                    <label class="form-label small fw-bold text-muted text-uppercase">CPF *</label>
                                    <input type="text"
                                           name="cpf"
                                           class="form-control @error('cpf') is-invalid @enderror"
                                           value="{{ old('cpf', $customer->commonData->cpf ?? '') }}" required>
                                    @error('cpf')
                                        <div class="invalid-feedback">{{ $message }}</div>
                                    @enderror
                                </div>
                            </div>
                        @else
                            <!-- Pessoa Jurídica -->
                            <div class="row">
                                <div class="col-md-6">
                                    <label class="form-label small fw-bold text-muted text-uppercase">Razão Social *</label>
                                    <input type="text"
                                           name="company_name"
                                           class="form-control @error('company_name') is-invalid @enderror"
                                           value="{{ old('company_name', $customer->commonData->company_name ?? '') }}" required>
                                    @error('company_name')
                                        <div class="invalid-feedback">{{ $message }}</div>
                                    @enderror
                                </div>
                                <div class="col-md-6">
                                    <label class="form-label small fw-bold text-muted text-uppercase">CNPJ *</label>
                                    <input type="text"
                                           name="cnpj"
                                           class="form-control @error('cnpj') is-invalid @enderror"
                                           value="{{ old('cnpj', $customer->commonData->cnpj ?? '') }}" required>
                                    @error('cnpj')
                                        <div class="invalid-feedback">{{ $message }}</div>
                                    @enderror
                                </div>
                                <div class="col-md-6">
                                    <label class="form-label small fw-bold text-muted text-uppercase">CPF do Responsável</label>
                                    <input type="text"
                                           name="cpf"
                                           class="form-control @error('cpf') is-invalid @enderror"
                                           value="{{ old('cpf', $customer->commonData->cpf ?? '') }}">
                                    @error('cpf')
                                        <div class="invalid-feedback">{{ $message }}</div>
                                    @enderror
                                </div>
                            </div>
                        @endif

                        <div class="row mt-3">
                            <div class="col-md-6">
                                <label class="form-label small fw-bold text-muted text-uppercase">Área de Atuação</label>
                                <select name="area_of_activity_id" class="form-select @error('area_of_activity_id') is-invalid @enderror">
                                    <option value="">Selecione uma área</option>
                                    @foreach($areasOfActivity as $area)
                                        <option value="{{ $area->id }}"
                                                {{ (old('area_of_activity_id', $customer->commonData->area_of_activity_id ?? '') == $area->id) ? 'selected' : '' }}>
                                            {{ $area->name }}
                                        </option>
                                    @endforeach
                                </select>
                                @error('area_of_activity_id')
                                    <div class="invalid-feedback">{{ $message }}</div>
                                @enderror
                            </div>
                            <div class="col-md-6">
                                <label class="form-label small fw-bold text-muted text-uppercase">Profissão</label>
                                <select name="profession_id" class="form-select @error('profession_id') is-invalid @enderror">
                                    <option value="">Selecione uma profissão</option>
                                    @foreach($professions as $profession)
                                        <option value="{{ $profession->id }}"
                                                {{ (old('profession_id', $customer->commonData->profession_id ?? '') == $profession->id) ? 'selected' : '' }}>
                                            {{ $profession->name }}
                                        </option>
                                    @endforeach
                                </select>
                                @error('profession_id')
                                    <div class="invalid-feedback">{{ $message }}</div>
                                @enderror
                            </div>
                        </div>

                        <div class="row mt-3">
                            <div class="col-12">
                                <label class="form-label small fw-bold text-muted text-uppercase">Descrição</label>
                                <textarea name="description"
                                          class="form-control @error('description') is-invalid @enderror"
                                          rows="3"
                                          placeholder="Descrição do cliente...">{{ old('description', $customer->commonData->description ?? '') }}</textarea>
                                @error('description')
                                    <div class="invalid-feedback">{{ $message }}</div>
                                @enderror
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <!-- Contato -->
        <div class="row g-3 mb-4">
            <div class="col-12">
                <div class="card border-0 shadow-sm">
                    <div class="card-header bg-transparent border-0">
                        <h6 class="mb-0">Informações de Contato</h6>
                    </div>
                    <div class="card-body">
                        <div class="row">
                            <div class="col-md-6">
                                <label class="form-label small fw-bold text-muted text-uppercase">E-mail Principal *</label>
                                <input type="email"
                                       name="email"
                                       class="form-control @error('email') is-invalid @enderror"
                                       value="{{ old('email', $customer->contact->email ?? '') }}" required>
                                @error('email')
                                    <div class="invalid-feedback">{{ $message }}</div>
                                @enderror
                            </div>
                            <div class="col-md-6">
                                <label class="form-label small fw-bold text-muted text-uppercase">Telefone</label>
                                <input type="tel"
                                       name="phone"
                                       class="form-control @error('phone') is-invalid @enderror"
                                       value="{{ old('phone', $customer->contact->phone ?? '') }}">
                                @error('phone')
                                    <div class="invalid-feedback">{{ $message }}</div>
                                @enderror
                            </div>
                            <div class="col-md-6">
                                <label class="form-label small fw-bold text-muted text-uppercase">E-mail Comercial</label>
                                <input type="email"
                                       name="email_business"
                                       class="form-control @error('email_business') is-invalid @enderror"
                                       value="{{ old('email_business', $customer->contact->email_business ?? '') }}">
                                @error('email_business')
                                    <div class="invalid-feedback">{{ $message }}</div>
                                @enderror
                            </div>
                            <div class="col-md-6">
                                <label class="form-label small fw-bold text-muted text-uppercase">Telefone Comercial</label>
                                <input type="tel"
                                       name="phone_business"
                                       class="form-control @error('phone_business') is-invalid @enderror"
                                       value="{{ old('phone_business', $customer->contact->phone_business ?? '') }}">
                                @error('phone_business')
                                    <div class="invalid-feedback">{{ $message }}</div>
                                @enderror
                            </div>
                            <div class="col-md-6">
                                <label class="form-label small fw-bold text-muted text-uppercase">Website</label>
                                <input type="url"
                                       name="website"
                                       class="form-control @error('website') is-invalid @enderror"
                                       value="{{ old('website', $customer->contact->website ?? '') }}">
                                @error('website')
                                    <div class="invalid-feedback">{{ $message }}</div>
                                @enderror
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <!-- Endereço -->
        <div class="row g-3 mb-4">
            <div class="col-12">
                <div class="card border-0 shadow-sm">
                    <div class="card-header bg-transparent border-0">
                        <h6 class="mb-0">Endereço</h6>
                    </div>
                    <div class="card-body">
                        <div class="row">
                            <div class="col-md-8">
                                <label class="form-label small fw-bold text-muted text-uppercase">Logradouro *</label>
                                <input type="text"
                                       name="address"
                                       class="form-control @error('address') is-invalid @enderror"
                                       value="{{ old('address', $customer->address->address ?? '') }}" required>
                                @error('address')
                                    <div class="invalid-feedback">{{ $message }}</div>
                                @enderror
                            </div>
                            <div class="col-md-4">
                                <label class="form-label small fw-bold text-muted text-uppercase">Número *</label>
                                <input type="text"
                                       name="address_number"
                                       class="form-control @error('address_number') is-invalid @enderror"
                                       value="{{ old('address_number', $customer->address->address_number ?? '') }}" required>
                                @error('address_number')
                                    <div class="invalid-feedback">{{ $message }}</div>
                                @enderror
                            </div>
                            <div class="col-md-6">
                                <label class="form-label small fw-bold text-muted text-uppercase">Complemento</label>
                                <input type="text"
                                       name="address_complement"
                                       class="form-control @error('address_complement') is-invalid @enderror"
                                       value="{{ old('address_complement', $customer->address->address_complement ?? '') }}">
                                @error('address_complement')
                                    <div class="invalid-feedback">{{ $message }}</div>
                                @enderror
                            </div>
                            <div class="col-md-6">
                                <label class="form-label small fw-bold text-muted text-uppercase">Bairro *</label>
                                <input type="text"
                                       name="neighborhood"
                                       class="form-control @error('neighborhood') is-invalid @enderror"
                                       value="{{ old('neighborhood', $customer->address->neighborhood ?? '') }}" required>
                                @error('neighborhood')
                                    <div class="invalid-feedback">{{ $message }}</div>
                                @enderror
                            </div>
                            <div class="col-md-4">
                                <label class="form-label small fw-bold text-muted text-uppercase">CEP *</label>
                                <input type="text"
                                       name="cep"
                                       class="form-control @error('cep') is-invalid @enderror"
                                       value="{{ old('cep', $customer->address->cep ?? '') }}" required>
                                @error('cep')
                                    <div class="invalid-feedback">{{ $message }}</div>
                                @enderror
                            </div>
                            <div class="col-md-4">
                                <label class="form-label small fw-bold text-muted text-uppercase">Cidade *</label>
                                <input type="text"
                                       name="city"
                                       class="form-control @error('city') is-invalid @enderror"
                                       value="{{ old('city', $customer->address->city ?? '') }}" required>
                                @error('city')
                                    <div class="invalid-feedback">{{ $message }}</div>
                                @enderror
                            </div>
                            <div class="col-md-4">
                                <label class="form-label small fw-bold text-muted text-uppercase">Estado *</label>
                                <input type="text"
                                       name="state"
                                       class="form-control @error('state') is-invalid @enderror"
                                       value="{{ old('state', $customer->address->state ?? '') }}" required>
                                @error('state')
                                    <div class="invalid-feedback">{{ $message }}</div>
                                @enderror
                            </div>
                            <div class="col-md-6">
                                <label class="form-label small fw-bold text-muted text-uppercase">País</label>
                                <input type="text"
                                       name="country"
                                       class="form-control @error('country') is-invalid @enderror"
                                       value="{{ old('country', $customer->address->country ?? 'Brasil') }}">
                                @error('country')
                                    <div class="invalid-feedback">{{ $message }}</div>
                                @enderror
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <!-- Ações -->
        <div class="d-flex justify-content-between">
            <a href="{{ route('provider.customers.index') }}" class="btn btn-outline-secondary">
                <i class="bi bi-arrow-left me-2"></i>Cancelar
            </a>
            <button type="submit" class="btn btn-primary">
                <i class="bi bi-check-circle me-2"></i>{{ isset($customer) ? 'Atualizar' : 'Criar' }} Cliente
            </button>
        </div>
    </form>
</div>

@push('scripts')
<script>
document.addEventListener('DOMContentLoaded', function() {
    // Formatar CPF/CNPJ
    const cpfInput = document.querySelector('input[name="cpf"]');
    const cnpjInput = document.querySelector('input[name="cnpj"]');

    if (cpfInput) {
        cpfInput.addEventListener('input', function() {
            let value = this.value.replace(/\D/g, '');
            if (value.length > 11) value = value.slice(0, 11);
            if (value.length > 3) {
                value = value.replace(/(\d{3})(\d)/, '$1.$2');
            }
            if (value.length > 7) {
                value = value.replace(/(\d{3})(\d)/, '$1.$2');
            }
            if (value.length > 11) {
                value = value.replace(/(\d{3})(\d{1})$/, '$1-$2');
            }
            this.value = value;
        });
    }

    if (cnpjInput) {
        cnpjInput.addEventListener('input', function() {
            let value = this.value.replace(/\D/g, '');
            if (value.length > 14) value = value.slice(0, 14);
            if (value.length > 2) {
                value = value.replace(/(\d{2})(\d)/, '$1.$2');
            }
            if (value.length > 6) {
                value = value.replace(/(\d{3})(\d)/, '$1.$2');
            }
            if (value.length > 10) {
                value = value.replace(/(\d{3})(\d)/, '$1/$2');
            }
            if (value.length > 15) {
                value = value.replace(/(\d{4})(\d{1})$/, '$1-$2');
            }
            this.value = value;
        });
    }

    // Formatar CEP
    const cepInput = document.querySelector('input[name="cep"]');
    if (cepInput) {
        cepInput.addEventListener('input', function() {
            let value = this.value.replace(/\D/g, '');
            if (value.length > 8) value = value.slice(0, 8);
            if (value.length > 5) {
                value = value.replace(/(\d{5})(\d)/, '$1-$2');
            }
            this.value = value;
        });
    }
});
</script>
@endpush

7. Customer Actions Component

Componente para exibição de ações disponíveis para um cliente.

Uso Básico

<x-customer.customer-actions :customer="$customer" :showBudget="true" :showInvoice="true" />

Parâmetros

ParâmetroTipoDescriçãoPadrão
customer
Customer
Modelo do clienteObrigatório
showBudget
bool
Exibir botão de novo orçamento
true
showInvoice
bool
Exibir botão de nova fatura
true
showSendEmail
bool
Exibir botão de envio de e-mail
true

Estrutura

@props([
    'customer',
    'showBudget' => true,
    'showInvoice' => true,
    'showSendEmail' => true
])

<div class="customer-actions btn-group" role="group">
    <!-- Visualizar -->
    <a href="{{ route('provider.customers.show', $customer) }}"
       class="btn btn-outline-primary"
       title="Visualizar Cliente">
        <i class="bi bi-eye"></i> Visualizar
    </a>

    <!-- Editar -->
    <a href="{{ route('provider.customers.edit', $customer) }}"
       class="btn btn-outline-secondary"
       title="Editar Cliente">
        <i class="bi bi-pencil"></i> Editar
    </a>

    <!-- Novo Orçamento -->
    @if($showBudget)
        <a href="{{ route('provider.budgets.create') }}?customer_id={{ $customer->id }}"
           class="btn btn-outline-info"
           title="Novo Orçamento">
            <i class="bi bi-file-earmark-text"></i> Orçamento
        </a>
    @endif

    <!-- Nova Fatura -->
    @if($showInvoice)
        <a href="{{ route('provider.invoices.create') }}?customer_id={{ $customer->id }}"
           class="btn btn-outline-success"
           title="Nova Fatura">
            <i class="bi bi-receipt"></i> Fatura
        </a>
    @endif

    <!-- Enviar E-mail -->
    @if($showSendEmail)
        <button type="button"
                class="btn btn-outline-warning"
                data-bs-toggle="modal"
                data-bs-target="#emailModal-{{ $customer->id }}"
                title="Enviar E-mail">
            <i class="bi bi-envelope"></i> E-mail
        </button>
    @endif

    <!-- Excluir -->
    <button type="button"
            class="btn btn-outline-danger"
            data-bs-toggle="modal"
            data-bs-target="#deleteModal-{{ $customer->id }}"
            title="Excluir Cliente">
        <i class="bi bi-trash"></i> Excluir
    </button>
</div>

8. Customer Filters Component

Componente para filtros específicos de listagem de clientes.

Uso Básico

<x-customer.customer-filters :filters="$filters" :showType="true" :showStatus="true" />

Parâmetros

ParâmetroTipoDescriçãoPadrão
filters
array
Filtros atuais
[]
showType
bool
Exibir filtro por tipo
true
showStatus
bool
Exibir filtro por status
true
showDateRange
bool
Exibir filtro por período
true

Estrutura

@props([
    'filters' => [],
    'showType' => true,
    'showStatus' => true,
    'showDateRange' => true
])

<div class="customer-filters">
    <form action="{{ request()->url() }}" method="GET" class="row g-3">
        @if($showType)
            <div class="col-md-3">
                <label class="form-label small fw-bold text-muted text-uppercase">Tipo</label>
                <select name="type" class="form-select form-select-sm">
                    <option value="">Todos os tipos</option>
                    <option value="pf" {{ ($filters['type'] ?? '') == 'pf' ? 'selected' : '' }}>Pessoa Física</option>
                    <option value="pj" {{ ($filters['type'] ?? '') == 'pj' ? 'selected' : '' }}>Pessoa Jurídica</option>
                </select>
            </div>
        @endif

        @if($showStatus)
            <div class="col-md-3">
                <label class="form-label small fw-bold text-muted text-uppercase">Status</label>
                <select name="status" class="form-select form-select-sm">
                    <option value="">Todos os status</option>
                    <option value="active" {{ ($filters['status'] ?? '') == 'active' ? 'selected' : '' }}>Ativo</option>
                    <option value="inactive" {{ ($filters['status'] ?? '') == 'inactive' ? 'selected' : '' }}>Inativo</option>
                    <option value="pending" {{ ($filters['status'] ?? '') == 'pending' ? 'selected' : '' }}>Pendente</option>
                </select>
            </div>
        @endif

        @if($showDateRange)
            <div class="col-md-3">
                <label class="form-label small fw-bold text-muted text-uppercase">Período</label>
                <div class="input-group input-group-sm">
                    <input type="date"
                           name="start_date"
                           class="form-control"
                           value="{{ $filters['start_date'] ?? '' }}">
                    <span class="input-group-text">até</span>
                    <input type="date"
                           name="end_date"
                           class="form-control"
                           value="{{ $filters['end_date'] ?? '' }}">
                </div>
            </div>
        @endif

        <div class="col-md-3">
            <label class="form-label small fw-bold text-muted text-uppercase">Busca</label>
            <input type="text"
                   name="search"
                   class="form-control form-control-sm"
                   value="{{ $filters['search'] ?? '' }}"
                   placeholder="Buscar por nome...">
        </div>

        <div class="col-12">
            <div class="d-flex justify-content-between">
                <div class="btn-group" role="group">
                    <button type="submit" class="btn btn-primary btn-sm">
                        <i class="bi bi-search me-2"></i>Filtrar
                    </button>
                    <a href="{{ route('provider.customers.index') }}" class="btn btn-outline-secondary btn-sm">
                        <i class="bi bi-x-circle me-2"></i>Limpar
                    </a>
                </div>

                <div class="btn-group" role="group">
                    <button type="button" class="btn btn-outline-success btn-sm" data-bs-toggle="modal" data-bs-target="#createModal">
                        <i class="bi bi-plus-circle me-2"></i>Novo Cliente
                    </button>
                </div>
            </div>
        </div>
    </form>
</div>

9. Customer Interactions Component

Componente para exibição do histórico de interações do cliente.

Uso Básico

<x-customer.customer-interactions :customer="$customer" :showRecent="true" />

Parâmetros

ParâmetroTipoDescriçãoPadrão
customer
Customer
Modelo do clienteObrigatório
showRecent
bool
Exibir apenas interações recentes
true
limit
int
Limite de interações a exibir
10

Estrutura

@props([
    'customer',
    'showRecent' => true,
    'limit' => 10
])

<div class="customer-interactions">
    <div class="card border-0 shadow-sm">
        <div class="card-header bg-transparent border-0">
            <h6 class="mb-0">Histórico de Interações</h6>
        </div>
        <div class="card-body p-0">
            @if($customer->activities->isNotEmpty())
                <div class="list-group list-group-flush">
                    @foreach($customer->activities->take($limit) as $activity)
                        <div class="list-group-item">
                            <div class="d-flex w-100 justify-content-between">
                                <h6 class="mb-1">{{ $activity->description }}</h6>
                                <small class="text-muted">{{ $activity->created_at->diffForHumans() }}</small>
                            </div>
                            <p class="mb-1 text-muted small">{{ $activity->metadata }}</p>
                            <small class="text-muted">{{ $activity->action_type }}</small>
                        </div>
                    @endforeach
                </div>
            @else
                <div class="text-center py-4">
                    <i class="bi bi-chat-dots text-muted" style="font-size: 3rem;"></i>
                    <p class="text-muted mt-2">Nenhuma interação registrada</p>
                </div>
            @endif
        </div>
    </div>
</div>

10. Customer Summary Component

Componente para exibição de resumo do cliente.

Uso Básico

<x-customer.customer-summary :customer="$customer" :showStats="true" />

Parâmetros

ParâmetroTipoDescriçãoPadrão
customer
Customer
Modelo do clienteObrigatório
showStats
bool
Exibir estatísticas
true
showLastInteraction
bool
Exibir última interação
true

Estrutura

@props([
    'customer',
    'showStats' => true,
    'showLastInteraction' => true
])

<div class="customer-summary">
    <div class="row g-3">
        @if($showStats)
            <!-- Estatísticas -->
            <div class="col-md-4">
                <div class="card border-0 shadow-sm">
                    <div class="card-body text-center">
                        <div class="avatar-circle bg-primary bg-gradient mb-2 mx-auto">
                            <i class="bi bi-file-earmark-text text-white"></i>
                        </div>
                        <div class="text-muted small">Orçamentos</div>
                        <div class="h4 mb-0 fw-bold">{{ $customer->budgets->count() }}</div>
                    </div>
                </div>
            </div>

            <div class="col-md-4">
                <div class="card border-0 shadow-sm">
                    <div class="card-body text-center">
                        <div class="avatar-circle bg-success bg-gradient mb-2 mx-auto">
                            <i class="bi bi-receipt text-white"></i>
                        </div>
                        <div class="text-muted small">Faturas</div>
                        <div class="h4 mb-0 fw-bold">{{ $customer->invoices->count() }}</div>
                    </div>
                </div>
            </div>

            <div class="col-md-4">
                <div class="card border-0 shadow-sm">
                    <div class="card-body text-center">
                        <div class="avatar-circle bg-info bg-gradient mb-2 mx-auto">
                            <i class="bi bi-currency-dollar text-white"></i>
                        </div>
                        <div class="text-muted small">Valor Total</div>
                        <div class="h4 mb-0 fw-bold">
                            R$ {{ number_format($customer->invoices->sum('total'), 2, ',', '.') }}
                        </div>
                    </div>
                </div>
            </div>
        @endif
    </div>

    @if($showLastInteraction && $customer->activities->isNotEmpty())
        <div class="row mt-3">
            <div class="col-12">
                <div class="card border-0 shadow-sm">
                    <div class="card-header bg-transparent border-0">
                        <h6 class="mb-0">Última Interação</h6>
                    </div>
                    <div class="card-body">
                        <div class="d-flex w-100 justify-content-between">
                            <div>
                                <h6 class="mb-1">{{ $customer->activities->first()->description }}</h6>
                                <p class="mb-0 text-muted small">{{ $customer->activities->first()->metadata }}</p>
                            </div>
                            <div class="text-end">
                                <small class="text-muted">{{ $customer->activities->first()->created_at->format('d/m/Y H:i') }}</small>
                                <br>
                                <small class="text-muted">{{ $customer->activities->first()->action_type }}</small>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    @endif
</div>

11. Integração com Padrões Existentes

Uso em Views

{{-- Dashboard --}}
<x-customer.customer-card :customer="$customer" />

{{-- Listagem --}}
<x-customer.customer-details :customer="$customer" />

{{-- Formulários --}}
<x-customer.customer-form :customer="$customer" :areasOfActivity="$areasOfActivity" :professions="$professions" />

{{-- Ações --}}
<x-customer.customer-actions :customer="$customer" />

Estilos CSS

/* Customer Components Styles */
.customer-form .btn-check:checked + .btn {
    background-color: #0d6efd;
    border-color: #0d6efd;
    color: white;
}

.customer-form .btn-check:checked + .btn-secondary {
    background-color: #6c757d;
    border-color: #6c757d;
}

.customer-actions .btn {
    transition: all 0.2s ease;
}

.customer-actions .btn:hover {
    transform: translateY(-1px);
    box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

.customer-summary .card {
    border-left: 4px solid #0d6efd;
}

12. JavaScript Interatividade

Formulário de Cliente

// customer-form.js
document.addEventListener('DOMContentLoaded', function() {
    // Alternar campos conforme tipo de cliente
    const typeRadios = document.querySelectorAll('input[name="type"]');
    const cpfField = document.querySelector('input[name="cpf"]');
    const cnpjField = document.querySelector('input[name="cnpj"]');

    function toggleFields() {
        const selectedType = document.querySelector('input[name="type"]:checked').value;

        if (selectedType === 'pf') {
            cnpjField.closest('.row').style.display = 'none';
            cpfField.closest('.row').style.display = 'block';
        } else {
            cnpjField.closest('.row').style.display = 'block';
            cpfField.closest('.row').style.display = 'block';
        }
    }

    typeRadios.forEach(radio => {
        radio.addEventListener('change', toggleFields);
    });

    // Inicializar campos
    toggleFields();
});

13. Validação e Segurança

Autorização

// CustomerPolicy.php
public function view(User $user, Customer $customer)
{
    return $user->tenant_id === $customer->tenant_id;
}

public function update(User $user, Customer $customer)
{
    return $user->tenant_id === $customer->tenant_id;
}

public function delete(User $user, Customer $customer)
{
    return $user->tenant_id === $customer->tenant_id &&
           $customer->budgets->isEmpty() &&
           $customer->invoices->isEmpty();
}

Validations

{{-- Customer Card com validação de permissões --}}
@can('view', $customer)
    <x-customer.customer-card :customer="$customer" />
@endcan

{{-- Customer Actions com validação de status --}}
@can('update', $customer)
    <x-customer.customer-actions :customer="$customer" />
@endcan

Este padrão de components para clientes garante consistência visual, reutilização de código e manutenibilidade, seguindo os mesmos princípios estabelecidos nos outros components do sistema.