2026-02-18 21:23:15 +00:00
|
|
|
defmodule BerrypodWeb.Plugs.CountryDetect do
|
2026-02-14 10:48:00 +00:00
|
|
|
@moduledoc """
|
|
|
|
|
Plug that detects the visitor's country from cookies or Accept-Language.
|
|
|
|
|
|
|
|
|
|
Priority:
|
|
|
|
|
1. `shipping_country` cookie (set when user explicitly changes country)
|
|
|
|
|
2. Accept-Language header (locale tags like `en-GB` → `GB`)
|
|
|
|
|
3. Falls back to `"GB"`
|
|
|
|
|
|
|
|
|
|
The result is stored in the session as `country_code` so LiveViews can
|
|
|
|
|
read it. Only runs once per session — skips if `country_code` is already
|
|
|
|
|
set (unless the cookie has changed).
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
import Plug.Conn
|
|
|
|
|
|
|
|
|
|
@default_country "GB"
|
|
|
|
|
@cookie_name "shipping_country"
|
|
|
|
|
|
|
|
|
|
def init(opts), do: opts
|
|
|
|
|
|
|
|
|
|
def call(conn, _opts) do
|
|
|
|
|
cookie_country = conn.cookies[@cookie_name]
|
|
|
|
|
session_country = get_session(conn, "country_code")
|
|
|
|
|
|
|
|
|
|
cond do
|
|
|
|
|
# Cookie takes priority — user explicitly chose this country
|
|
|
|
|
cookie_country not in [nil, ""] and cookie_country != session_country ->
|
|
|
|
|
put_session(conn, "country_code", cookie_country)
|
|
|
|
|
|
|
|
|
|
# Session already set and no cookie override
|
|
|
|
|
session_country != nil ->
|
|
|
|
|
conn
|
|
|
|
|
|
|
|
|
|
# First visit: detect from Accept-Language
|
|
|
|
|
true ->
|
|
|
|
|
country = detect_from_header(conn)
|
|
|
|
|
put_session(conn, "country_code", country)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
defp detect_from_header(conn) do
|
|
|
|
|
conn
|
|
|
|
|
|> get_req_header("accept-language")
|
|
|
|
|
|> List.first("")
|
|
|
|
|
|> parse_country()
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
defp parse_country(header) do
|
|
|
|
|
case Regex.run(~r/[a-z]{2}-([A-Z]{2})/, header) do
|
|
|
|
|
[_, country] -> country
|
|
|
|
|
nil -> @default_country
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|