Keeping a user's timezone up to date with Livewire

Overview

In this article, we outline an approach to using Livewire to keep a user's timezone (stored in the database) up to date.

We'll create a Livewire component (with empty content) intended to be included in an application's layout (Blade template). Whenever a page using the layout is loaded, some JavaScript will execute that checks if the authenticated user's browser's timezone matches what is currently stored in the database for that user.

If the browser's timezone is different, we'll use a Livewire Event to communicate to our back end that the authenticated user's timezone stored in the database needs to be updated. Finally, we'll update the timezone property on the authenticated user's Eloquent model and save the changes to our database.

If you want the user's timezone to be an explicitly set preference the user can control, this approach may not be for you. You'd need to modify the code in this article to only update the user's timezone if a value doesn't already exist.

Use case

For when you want to keep the user's current timezone (from the browser) updated on your User model.

Examples of why you'd want to do this include:

  • formatting a date on your back end that's local to a specific user
  • accepting a date and/or time in a form request and parsing it in the authenticated user's time zone
  • relative time comparisons on your back end, based on where your user is physically located

Assumptions

You have a working Laravel project with:

  • Livewire installed with the scripts included in your application's layout template
    • or wherever you'd like to include the component to update the database with the browser's timezone
  • an authenticatable User model with a string column to persist a User's timezone
    • in this article a string (varchar) column named timezone is assumed

Creating the Livewire component

Scaffolding command

Run the following artisan command to scaffold a new Livewire component named UpdateUserTimezone.

1php artisan make:livewire UpdateUserTimezone

Two new files will be created for you:

  • app/Livewire/UpdateUserTimezone.php
    • the PHP class for our Livewire component
  • resources/views/livewire/update-user-timezone.blade.php
    • the Blade template for our Livewire component

PHP class

The Livewire component's PHP class consists of two pieces of functionality:

  1. Rendering the component's Blade template with the authenticated user's (if any) timezone available as a property
  2. Updating the authenticated user's timezone on their Eloquent model (and saving to the database) upon a Livewire Event firing
📁
app/Livewire/UpdateUserTimezone.php
1<?php
2 
3namespace App\Livewire;
4 
5use Illuminate\View\View;
6use Livewire\Attributes\On;
7use Livewire\Component;
8 
9class UpdateUserTimezone extends Component
10{
11 public function render(): View
12 {
13 return view('livewire.update-user-timezone', [
14 'timezone' => auth()->user()?->timezone,
15 ]);
16 }
17 
18 #[On('update-user-timezone')]
19 public function updateUserTimezone(string $timezone): void
20 {
21 auth()->user()->update([
22 'timezone' => $timezone,
23 ]);
24 }
25}
  • Note the safe access to the auth()->user()?->timezone property on line 14
  • Note the On PHP attribute on the updateUserTimezone method (line 18) that listens for the update-user-timezone event

Blade template

The functionality of the Blade template for the component consists of:

  1. The @auth Blade directive which only includes the directive's contents if the current user is authenticated
  2. The @script Blade directive which will execute the contained script once per page load, after Livewire has been initialized
  3. A declaration of a timezone JavaScript variable with a value equal to the browser's timezone
  4. A conditional check to determine if a timezone has been resolved and if it is different from the user's current timezone property
  5. An invocation of Livewire's $dispatch method which fires an event to our back end containing the resolved timezone
📁
resources/views/livewire/update-user-timezone.blade.php
1<div></div>
2 
3@auth
4 @script
5 <script>
6 const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
7 
8 if (timezone && timezone !== '{{ $timezone }}') {
9 $wire.dispatch('update-user-timezone', {timezone});
10 }
11 </script>
12 @endscript
13@endauth

Placement of the component

Place the component in your application's layout (Blade template), above the closing </body> tag.

📁
resources/views/layouts/app.blade.php
1<!DOCTYPE html>
2<html>
3 <head>
4 <!-- other HTML here -->
5 </head>
6 <body>
7 <!-- other HTML here -->
8 <livewire:update-user-timezone />
9 </body>
10</html>

Conclusion

That's it!

Now whenever an authenticated user loads a page that extends your application's layout (Blade template), the logic will update your user's Eloquent model's timezone property and save the changes to the database.

This will only happen when the user's browser's resolved timezone differs from the timezone value currently saved in the database for the authenticated user.

🤖
Did you spot a mistake in this article? Have a suggestion for how something can be improved? Even if you'd just like to comment or chat about something else, I'd love to hear from you! Contact me.

Syntax highlighting by Torchlight.dev

End of article