· yebor974 · Advanced Techniques, Tutorials

Automatically detect and set the user's timezone in registration

Learn how to automatically detect and set a user's timezone during registration in Laravel. Enhance user experience with seamless timezone handling.

Automatically detect and set the user's timezone in registration - picture

When building applications with Laravel, adding timezone selection to your user registration form enhances the user experience. This feature ensures that user-specific timestamps align with their local time. To make it even more convenient, you can use JavaScript to automatically detect the user's timezone and prefill the field. This article demonstrates how to implement such functionality using Laravel, Filament, and Alpine.js.

Step 1: Extend the default Register page in Filament

To begin, we need to extend the default Register page provided by Filament and customize it to include our timezone component. Here's how you can achieve it:

  1. Create a Custom Register Page
    Generate a custom Register page that will override the default. Use the following command to scaffold a new page:

    php artisan make:filament-page Register
    
  2. Extend your page by default Register Filament page:

namespace App\Filament\Admin\Pages;

class Register extends \Filament\Pages\Auth\Register
{
    //
}

There’s no need to define a specific view, so you can remove the generated one.

  1. Register the custom page on your panel
    Add your custom Register page to the panel by registering it within your PanelServiceProvider. This example uses a Member panel:

    use App\Filament\Member\Pages\Register;
    
    public function panel(Panel $panel): Panel
    {
         return $panel
             ...
             ->registration(Register::class),
             ...
    }
    

This setup ensures that Filament's default registration flow is replaced with your extended version, allowing you to introduce tailored features such as timezone detection and selection.

Step 2: Add a timezone select field

Before implementing the select field, you have to add a string attribute named timezone to your User model (fillable attribute) and a associated migration.

We override the getForms function and declare a getTimezoneFormComponent function to add our timezone select field.

namespace App\Filament\Admin\Pages;

use App\Models\User;
use Filament\Forms\Components\Actions\Action;
use Filament\Forms\Components\Checkbox;
use Filament\Forms\Components\Component;
use Filament\Support\Enums\IconSize;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\HtmlString;
use Yebor974\FilamentTermsGuard\Models\Term;

class Register extends \Filament\Pages\Auth\Register
{
    protected function getForms(): array
    {
        return [
            'form' => $this->form(
                $this->makeForm()
                    ->schema([
                        $this->getNameFormComponent(),
                        $this->getEmailFormComponent(),
                        $this->getPasswordFormComponent(),
                        $this->getPasswordConfirmationFormComponent(),
                        $this->getTimezoneFormComponent(), // call our getTimezoneFormComponent function to get a timezone select field
                    ])
                    ->statePath('data'),
            ),
        ];
    }

    protected function getTimezoneFormComponent(): Component
    {
        return Select::make('timezone')
            ->options(
                collect(CarbonTimeZone::listIdentifiers())
                    ->mapWithKeys(function ($timezone) {
                        return [$timezone => $timezone];
                    })
                    ->toArray()
            )
            ->searchable()
            ->optionsLimit(500)
            ->required()
            ->in(CarbonTimeZone::listIdentifiers())
            ->extraAlpineAttributes(['x-init' => '$wire.set("data.timezone", Intl.DateTimeFormat().resolvedOptions().timeZone)']);
    }
}

Key Points:

  1. Options: The timezone list is fetched using CarbonTimeZone::listIdentifiers() and mapped to create a key-value array for the dropdown.
  2. Validation: The selected value is validated to ensure it matches one of the valid timezones.
  3. Searchability: The searchable() option allows users to quickly find their timezone from the long list.
  4. Auto-Detection: The x-init Alpine.js attribute detects the user's timezone using Intl.DateTimeFormat().resolvedOptions().timeZone and sets it automatically.

Auto-Detecting the timezone

The extraAlpineAttributes method integrates Alpine.js attributes into the Filament form component. Here, the x-init directive runs a script when the component is initialized:

x-init='$wire.set("data.timezone", Intl.DateTimeFormat().resolvedOptions().timeZone)'

This script fetches the user's timezone using the browser's JavaScript API and updates the state (data.timezone).

User experience benefits:

  • Convenience: Users don’t need to scroll through the timezone list; their local timezone is pre-selected.
  • Accuracy: By auto-detecting the timezone, you minimize the chances of user error.
  • Efficiency: The searchable dropdown provides a backup option for users whose timezone detection might fail.

This simple enhancement to your registration form makes it more user-friendly and modern. By combining Laravel, Filament, and Alpine.js, you can deliver seamless experiences while maintaining code clarity and reusability. You can find this implementation on Filament Mastery

Avatar of yebor974
yebor974
Freelance - French IT Engineer passionate about Laravel and Filament PHP, creating innovative solutions to simplify web development.
React
Share post

Stay ahead in the Filament Mastery adventure

Join our community of Filament PHP enthusiasts! Get exclusive tips, tutorials, and updates delivered straight to your inbox.