theabhishekin/filament-location

A Filament package for collecting and displaying user locations with Google Maps integration

Installs: 6

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 0

Forks: 0

Open Issues: 0

pkg:composer/theabhishekin/filament-location

v1.0.0 2025-06-07 09:35 UTC

This package is auto-updated.

Last update: 2025-12-07 11:54:57 UTC


README

Latest Version on Packagist GitHub Tests Action Status GitHub Code Style Action Status Total Downloads

A powerful Filament package for collecting and displaying user locations with Google Maps integration. This package provides easy-to-use location picker and display components for your Filament admin panels.

Features

  • πŸ—ΊοΈ LocationPicker: Interactive Google Maps component for forms
  • πŸ“ LocationColumn: Display locations in tables with clickable map modals
  • 🎯 Current Location: Get user's current location with GPS
  • πŸ”§ Highly Customizable: Configurable zoom, map types, controls, and styling
  • πŸ“± Responsive Design: Works perfectly on desktop and mobile
  • 🌍 Multiple Location Types: Support for home, office, check-in/out locations
  • πŸ“Š Distance Calculations: Built-in distance calculation utilities
  • 🎨 Custom Icons: Predefined and custom icon support

Installation

You can install the package via Composer:

composer require theabhishekin/filament-location

Publish the configuration file:

php artisan vendor:publish --tag="filament-location-config"

Add your Google Maps API key to your .env file:

GOOGLE_MAPS_API_KEY=your_google_maps_api_key_here

Note: Make sure to enable the Maps JavaScript API and Geocoding API in your Google Cloud Console.

Configuration

The configuration file allows you to customize default settings:

return [
    'google_maps_api_key' => env('GOOGLE_MAPS_API_KEY'),
    'default_zoom' => 15,
    'map_height' => '400px',
    'enable_street_view' => true,
    'map_type' => 'standard', // standard, satellite, hybrid, terrain
    'location_accuracy' => 100,
    'location_timeout' => 10000,
    'enable_high_accuracy' => true,
    'map_controls' => [
        'zoom_control' => true,
        'map_type_control' => true,
        'scale_control' => true,
        'street_view_control' => true,
        'rotate_control' => true,
        'fullscreen_control' => true,
    ],
];

Database Migration

Add location fields to your model's migration:

Schema::table('users', function (Blueprint $table) {
    $table->json('location')->nullable();
    $table->timestamp('location_updated_at')->nullable();
});

Model Setup

Add the HasLocation trait to your model:

<?php

namespace App\Models;

use TheAbhishekIN\FilamentLocation\Concerns\HasLocation;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use HasLocation;

    protected $fillable = [
        'name',
        'email',
        'location',
        'location_updated_at',
    ];

    protected $casts = [
        'location' => 'array',
        'location_updated_at' => 'datetime',
    ];
}

Quick Example: User Resource

Here's a complete example of how to use the location components in a Filament resource:

<?php

namespace App\Filament\Resources;

use App\Models\User;
use TheAbhishekIN\FilamentLocation\Forms\Components\LocationPicker;
use TheAbhishekIN\FilamentLocation\Tables\Columns\LocationColumn;
use Filament\Forms;
use Filament\Forms\Form;
use Filament\Resources\Resource;
use Filament\Tables;
use Filament\Tables\Table;

class UserResource extends Resource
{
    protected static ?string $model = User::class;

    protected static ?string $navigationIcon = 'heroicon-o-users';

    public static function form(Form $form): Form
    {
        return $form
            ->schema([
                Forms\Components\TextInput::make('name')
                    ->required()
                    ->maxLength(255),

                Forms\Components\TextInput::make('email')
                    ->email()
                    ->required()
                    ->unique(ignoreRecord: true)
                    ->maxLength(255),

                LocationPicker::make('location')
                    ->label('User Location')
                    ->required()
                    ->zoom(16)
                    ->height('400px')
                    ->mapType('standard')
                    ->showCoordinates(true)
                    ->helperText('Click on the map or use "Get Current Location" to set the location'),

                Forms\Components\DateTimePicker::make('location_updated_at')
                    ->label('Location Updated At')
                    ->disabled(),
            ]);
    }

    public static function table(Table $table): Table
    {
        return $table
            ->columns([
                Tables\Columns\TextColumn::make('name')
                    ->searchable()
                    ->sortable(),

                Tables\Columns\TextColumn::make('email')
                    ->searchable()
                    ->sortable(),

                LocationColumn::make('location')
                    ->label('Location')
                    ->iconType('home')
                    ->iconSize('lg')
                    ->iconColor('primary')
                    ->title('User Location')
                    ->showTooltip(true)
                    ->tooltipText('Click to view location on map')
                    ->getLatitudeUsing(fn($record) => $record->location['latitude'] ?? null)
                    ->getLongitudeUsing(fn($record) => $record->location['longitude'] ?? null),

                Tables\Columns\TextColumn::make('location_updated_at')
                    ->label('Location Updated')
                    ->dateTime()
                    ->sortable()
                    ->toggleable(isToggledHiddenByDefault: true),
            ])
            ->filters([
                Tables\Filters\Filter::make('has_location')
                    ->label('Has Location')
                    ->query(fn($query) => $query->whereNotNull('location'))
                    ->toggle(),
            ])
            ->actions([
                Tables\Actions\EditAction::make(),
            ])
            ->bulkActions([
                Tables\Actions\BulkActionGroup::make([
                    Tables\Actions\DeleteBulkAction::make(),
                ]),
            ]);
    }

    public static function getPages(): array
    {
        return [
            'index' => Pages\ListUsers::route('/'),
            'create' => Pages\CreateUser::route('/create'),
            'edit' => Pages\EditUser::route('/{record}/edit'),
        ];
    }
}

Usage

LocationPicker Component

LocationPicker::make('location')
    ->label('Select Location')
    ->required()
    ->zoom(15)                    // Map zoom level (1-20)
    ->height('400px')             // Map container height
    ->mapType('standard')         // standard, satellite, hybrid, terrain
    ->showCoordinates(true)       // Show latitude/longitude coordinates
    ->showMap(true)               // Show/hide the map
    ->mapControls([               // Configure map controls
        'zoom_control' => true,
        'street_view_control' => false,
    ])
    ->helperText('Click on the map to select a location');

LocationColumn Component

LocationColumn::make('location')
    ->label('Location')
    ->iconType('home')                    // home, office, check-in, check-out, travel
    ->iconSize('lg')                      // sm, md, lg, xl
    ->iconColor('primary')                // primary, success, warning, danger
    ->title('Location Details')           // Modal title
    ->showTooltip(true)                   // Show hover tooltip
    ->tooltipText('View on map')          // Custom tooltip text
    ->getLatitudeUsing(fn($record) => $record->location['latitude'] ?? null)
    ->getLongitudeUsing(fn($record) => $record->location['longitude'] ?? null);

Available Icon Types

Icon Type Description Default Color
home Home locations Blue
office Office locations Purple
check-in Check-in locations Green
check-out Check-out locations Orange
travel Travel locations Red

Use Cases

  • Employee Management: Track employee locations for check-in/check-out
  • Customer Management: Store customer addresses and locations
  • Venue Management: Manage multiple business locations
  • Event Management: Record event locations and venue details
  • Delivery Services: Track delivery addresses and routes
  • Real Estate: Manage property locations
  • Healthcare: Patient and facility location management

Distance Calculations

The HasLocation trait provides distance calculation utilities:

// Calculate distance between two points
$distance = $user->distanceTo(26.9124, 75.7873); // Returns distance in kilometers

// Calculate distance to another model
$distance = $user->distanceToModel($otherUser);

// Find users within 10km radius
$nearbyUsers = User::withinDistance(26.9124, 75.7873, 10)->get();

// Order users by distance from a point
$usersByDistance = User::orderByDistance(26.9124, 75.7873)->get();

Security & HTTPS Requirements

⚠️ Important Security Notice:

The browser's Geolocation API requires a secure context to function properly. This means:

  • βœ… HTTPS connections (recommended for production)
  • βœ… localhost (for development)
  • ❌ HTTP connections will be blocked by modern browsers

Error Handling

The package provides comprehensive error handling with user-friendly messages:

Error Type Message Description
HTTPS Required πŸ”’ Location services require a secure connection (HTTPS) Browser blocks geolocation on non-secure origins
Permission Denied 🚫 Location access denied. Please allow location permission User explicitly denied location access
Position Unavailable πŸ“ Location information is unavailable Device can't determine location
Timeout ⏱️ Location request timed out Location request exceeded timeout limit

All errors are displayed in a prominent red banner below the location button with:

  • 🎨 Enhanced styling with gradient background
  • πŸ“± Responsive design for mobile devices
  • ✨ Smooth slide-in animation
  • πŸ” Clear iconography and user-friendly messages

Development Setup

For local development, ensure you're using:

# Use localhost (secure context)
http://localhost:8000

# Or use Herd/Valet with HTTPS
https://your-app.test

Troubleshooting

Common Issues

1. Livewire Entanglement Error

Error: Livewire property ['data.location'] cannot be found

Solution: Ensure your Livewire component has the property that matches your field name:

// ❌ Wrong - Component doesn't have 'location' property
class OrdersStep extends Component
{
    public $data = []; // Missing 'location' key
}

// βœ… Correct - Component has the location property
class OrdersStep extends Component
{
    public $location = null; // Direct property
    // OR
    public $data = [
        'location' => null, // Nested property
    ];
}

2. HTTPS/Security Errors

Error: Only secure origins are allowed

Solutions:

  • Use HTTPS in production: https://yourdomain.com
  • Use localhost for development: http://localhost:8000
  • Use Valet/Herd with SSL: https://yourapp.test

3. Error Messages Not Showing

If error messages aren't displaying:

  1. Check console logs for JavaScript errors
  2. Verify Alpine.js is loaded before the LocationPicker
  3. Ensure CSS is published: php artisan vendor:publish --tag=filament-location-assets

Contributing

Please see CONTRIBUTING for details.

Security Vulnerabilities

Please review our security policy on how to report security vulnerabilities.

Credits

License

The MIT License (MIT). Please see License File for more information.