PhoenixKit.Users.TimeZoneAlert (phoenix_kit v2.16.0)

Copy Markdown View Source

Notices when someone is browsing from a timezone their account does not use, and tells them once.

The browser is the only party that knows where a person actually is, so the TimezoneDetector hook reports its IANA zone from every authenticated page. This module decides whether that is worth saying anything about.

What counts as a mismatch

Only a difference that would put the wrong clock time on screen:

  • Zones in the same behaviour group are not a mismatch. Europe/Tallinn and Europe/Helsinki never disagree, in any season, so an account set to one while browsing from the other is fine and silent.
  • A legacy numeric offset is always worth replacing. Even when it is right today it cannot follow the next daylight-saving change, which is the defect the identifiers were introduced to fix.

Telling them once

A notification fires at most once per detected zone, remembered in the user's custom_fields. Someone who travels for a week gets one notification on arrival, not one per page view — and one more when they get home, because that is a different zone from the one last alerted about.

The activity is logged with no actor: nobody did this, the system observed it. That also matters mechanically, since Notifications.maybe_create_from_activity/1 skips fan-out when the actor is the target, and here the target is the only person involved.

Summary

Functions

Whether detected disagrees with what user has saved.

Records what the browser reported and notifies if it disagrees with the account. Returns :ok regardless — this is a background courtesy, never something that should break the page that triggered it.

Functions

mismatch?(user, detected)

@spec mismatch?(map(), String.t()) :: boolean()

Whether detected disagrees with what user has saved.

observe(user, detected)

@spec observe(map() | nil, String.t() | any()) :: :ok

Records what the browser reported and notifies if it disagrees with the account. Returns :ok regardless — this is a background courtesy, never something that should break the page that triggered it.