fix(ui): add distinct page metadata

This commit is contained in:
SimpleTest 2026-07-24 21:14:50 +03:00
parent a753af688a
commit ba872dda63
15 changed files with 114 additions and 22 deletions

View File

@ -17,7 +17,13 @@
"Who Need Help connects adults who need urgent local help with nearby volunteers." "Who Need Help connects adults who need urgent local help with nearby volunteers."
} }
/> />
<.live_title default="Who Need Help" suffix=" · Who Need Help" phx-no-format>{assigns[:page_title]}</.live_title> <.live_title
default="Who Need Help"
suffix={
if assigns[:page_title] in [nil, "", "Who Need Help"], do: "", else: " · Who Need Help"
}
phx-no-format
>{assigns[:page_title]}</.live_title>
<link rel="manifest" href={~p"/manifest.webmanifest"} /> <link rel="manifest" href={~p"/manifest.webmanifest"} />
<link rel="icon" type="image/svg+xml" sizes="any" href={~p"/images/logo.svg"} /> <link rel="icon" type="image/svg+xml" sizes="any" href={~p"/images/logo.svg"} />
<link rel="icon" type="image/png" sizes="48x48" href={~p"/images/favicon-48.png"} /> <link rel="icon" type="image/png" sizes="48x48" href={~p"/images/favicon-48.png"} />

View File

@ -6,7 +6,11 @@ defmodule WhoNeedHelpWeb.ContentRemovalController do
def index(conn, _params) do def index(conn, _params) do
notices = ContentRemoval.list_for_user(conn.assigns.current_scope) notices = ContentRemoval.list_for_user(conn.assigns.current_scope)
render(conn, :index, notices: notices)
render(conn, :index,
notices: notices,
page_title: gettext("Your content-removal notices")
)
end end
def new(conn, params) do def new(conn, params) do
@ -46,8 +50,14 @@ defmodule WhoNeedHelpWeb.ContentRemovalController do
end end
case result do case result do
{:ok, notice} -> render(conn, :show, notice: notice) {:ok, notice} ->
{:error, :not_found} -> send_resp(conn, :not_found, "Not found") render(conn, :show,
notice: notice,
page_title: gettext("Content-removal notice %{reference}", reference: notice.reference)
)
{:error, :not_found} ->
send_resp(conn, :not_found, "Not found")
end end
end end
@ -72,7 +82,10 @@ defmodule WhoNeedHelpWeb.ContentRemovalController do
end end
def received(conn, %{"reference" => reference}) when is_binary(reference) do def received(conn, %{"reference" => reference}) when is_binary(reference) do
render(conn, :received, reference: String.slice(reference, 0, 64)) render(conn, :received,
reference: String.slice(reference, 0, 64),
page_title: gettext("Content-removal notice received")
)
end end
def received(conn, _params), do: redirect(conn, to: ~p"/legal/content-removal") def received(conn, _params), do: redirect(conn, to: ~p"/legal/content-removal")
@ -80,7 +93,8 @@ defmodule WhoNeedHelpWeb.ContentRemovalController do
defp render_form(conn, regime, %Ecto.Changeset{} = changeset, _attrs) do defp render_form(conn, regime, %Ecto.Changeset{} = changeset, _attrs) do
render(conn, form_template(regime), render(conn, form_template(regime),
form: Phoenix.Component.to_form(changeset, as: :notice), form: Phoenix.Component.to_form(changeset, as: :notice),
contact_email: current_email(conn) contact_email: current_email(conn),
page_title: content_removal_page_title(regime)
) )
end end
@ -94,6 +108,9 @@ defmodule WhoNeedHelpWeb.ContentRemovalController do
defp form_template(:take_it_down), do: :take_it_down defp form_template(:take_it_down), do: :take_it_down
defp form_template(_regime), do: :new defp form_template(_regime), do: :new
defp content_removal_page_title(:take_it_down), do: gettext("TAKE IT DOWN request")
defp content_removal_page_title(_regime), do: gettext("Report content")
defp with_contact_email(conn, attrs) do defp with_contact_email(conn, attrs) do
case current_email(conn) do case current_email(conn) do
nil -> attrs nil -> attrs

View File

@ -12,6 +12,19 @@
"Provide exact Who Need Help URLs. Do not upload or paste intimate imagery, identity documents, passwords, access codes, or unnecessary medical information." "Provide exact Who Need Help URLs. Do not upload or paste intimate imagery, identity documents, passwords, access codes, or unnecessary medical information."
)} )}
</div> </div>
<div class="mt-3 rounded-2xl border border-error/30 bg-error/5 p-4 text-sm">
<p class="font-semibold">
{gettext("Reporting non-consensual intimate visual material?")}
</p>
<p class="mt-1 text-base-content/70">
{gettext(
"Use the dedicated urgent process. Never upload or reproduce the image or video."
)}
</p>
<.link navigate={~p"/legal/take-it-down"} class="btn btn-error btn-outline btn-sm mt-3">
{gettext("Open TAKE IT DOWN request")}
</.link>
</div>
<.link <.link
:if={@current_scope} :if={@current_scope}
navigate={~p"/legal/content-removal/requests"} navigate={~p"/legal/content-removal/requests"}

View File

@ -3,6 +3,7 @@ defmodule WhoNeedHelpWeb.FeedbackController do
def show(conn, _params) do def show(conn, _params) do
render(conn, :show, render(conn, :show,
page_title: gettext("Build feedback"),
session_id: Application.get_env(:who_need_help, :codex_session_id, "not-configured") session_id: Application.get_env(:who_need_help, :codex_session_id, "not-configured")
) )
end end

View File

@ -74,7 +74,8 @@ defmodule WhoNeedHelpWeb.GoogleAuthController do
existing_account -> existing_account ->
render(conn, :complete, render(conn, :complete,
pending: pending, pending: pending,
existing_account: not is_nil(existing_account) existing_account: not is_nil(existing_account),
page_title: gettext("Continue with Google")
) )
end end

View File

@ -17,7 +17,13 @@ defmodule WhoNeedHelpWeb.PageController do
end end
def safety(conn, _params) do def safety(conn, _params) do
render(conn, :safety) render(conn, :safety,
page_title: gettext("Safety rules"),
page_description:
gettext(
"Safety guidance for voluntary help, medicine pickup, roadside requests, location sharing, and in-person activities."
)
)
end end
def terms(conn, _params) do def terms(conn, _params) do

View File

@ -11,7 +11,10 @@ defmodule WhoNeedHelpWeb.SupportController do
scope -> Support.list_for_user(scope) scope -> Support.list_for_user(scope)
end end
render(conn, :index, requests: requests) render(conn, :index,
requests: requests,
page_title: gettext("Your support requests")
)
end end
def new(conn, _params) do def new(conn, _params) do
@ -149,7 +152,10 @@ defmodule WhoNeedHelpWeb.SupportController do
end end
def received(conn, %{"reference" => reference}) when is_binary(reference) do def received(conn, %{"reference" => reference}) when is_binary(reference) do
render(conn, :received, reference: String.slice(reference, 0, 64)) render(conn, :received,
reference: String.slice(reference, 0, 64),
page_title: gettext("Support request received")
)
end end
def received(conn, _params), do: redirect(conn, to: ~p"/support") def received(conn, _params), do: redirect(conn, to: ~p"/support")
@ -171,7 +177,8 @@ defmodule WhoNeedHelpWeb.SupportController do
defp render_form(conn, %Ecto.Changeset{} = changeset, _attrs, page) do defp render_form(conn, %Ecto.Changeset{} = changeset, _attrs, page) do
render(conn, page, render(conn, page,
form: Phoenix.Component.to_form(changeset, as: :support_request), form: Phoenix.Component.to_form(changeset, as: :support_request),
contact_email: current_email(conn) contact_email: current_email(conn),
page_title: support_page_title(page)
) )
end end
@ -189,4 +196,7 @@ defmodule WhoNeedHelpWeb.SupportController do
defp current_email(%{assigns: %{current_scope: %{user: %{email: email}}}}), do: email defp current_email(%{assigns: %{current_scope: %{user: %{email: email}}}}), do: email
defp current_email(_conn), do: nil defp current_email(_conn), do: nil
defp support_page_title(:delete_account), do: gettext("Request account deletion")
defp support_page_title(_page), do: gettext("Contact support")
end end

View File

@ -16,7 +16,13 @@ defmodule WhoNeedHelpWeb.UserRegistrationController do
def sent(conn, params) do def sent(conn, params) do
email_flow = if params["flow"] == "register", do: "register", else: "login" email_flow = if params["flow"] == "register", do: "register", else: "login"
render(conn, :sent, email_flow: email_flow)
page_title =
if email_flow == "register",
do: gettext("Check your email to finish registration"),
else: gettext("Sign-in request processed")
render(conn, :sent, email_flow: email_flow, page_title: page_title)
end end
def create(conn, %{"user" => user_params}) when is_map(user_params) do def create(conn, %{"user" => user_params}) when is_map(user_params) do
@ -131,7 +137,8 @@ defmodule WhoNeedHelpWeb.UserRegistrationController do
defp render_registration(conn, changeset) do defp render_registration(conn, changeset) do
render(conn, :new, render(conn, :new,
changeset: changeset, changeset: changeset,
google_auth_enabled: GoogleAuth.enabled?() google_auth_enabled: GoogleAuth.enabled?(),
page_title: gettext("Register")
) )
end end

View File

@ -9,6 +9,7 @@ defmodule WhoNeedHelpWeb.UserSessionController do
alias WhoNeedHelpWeb.{GoogleAuthPending, UserAuth} alias WhoNeedHelpWeb.{GoogleAuthPending, UserAuth}
plug :assign_magic_link_form plug :assign_magic_link_form
plug :assign_page_title
plug :put_no_store plug :put_no_store
def new(conn, params) do def new(conn, params) do
@ -206,4 +207,6 @@ defmodule WhoNeedHelpWeb.UserSessionController do
end end
defp put_no_store(conn, _opts), do: put_resp_header(conn, "cache-control", "no-store") defp put_no_store(conn, _opts), do: put_resp_header(conn, "cache-control", "no-store")
defp assign_page_title(conn, _opts), do: assign(conn, :page_title, gettext("Log in"))
end end

View File

@ -11,6 +11,7 @@ defmodule WhoNeedHelpWeb.UserSettingsController do
plug :require_sudo_mode when action in [:edit, :update] plug :require_sudo_mode when action in [:edit, :update]
plug :assign_email_and_password_changesets when action in [:edit, :update] plug :assign_email_and_password_changesets when action in [:edit, :update]
plug :assign_page_title
def edit(conn, _params) do def edit(conn, _params) do
render(conn, :edit) render(conn, :edit)
@ -107,6 +108,15 @@ defmodule WhoNeedHelpWeb.UserSettingsController do
|> assign(:google_auth_connected, Accounts.google_auth_connected?(user)) |> assign(:google_auth_connected, Accounts.google_auth_connected?(user))
end end
defp assign_page_title(conn, _opts) do
title =
if conn.private.phoenix_action == :confirm_email_page,
do: gettext("Confirm email change"),
else: gettext("Account settings")
assign(conn, :page_title, title)
end
defp deliver_email_change_instructions(conn, user, changeset) do defp deliver_email_change_instructions(conn, user, changeset) do
case Accounts.deliver_user_update_email_instructions( case Accounts.deliver_user_update_email_instructions(
Ecto.Changeset.apply_action!(changeset, :insert), Ecto.Changeset.apply_action!(changeset, :insert),

View File

@ -16,6 +16,8 @@ defmodule WhoNeedHelpWeb.PageControllerTest do
assert html =~ "You stay in control of the match" assert html =~ "You stay in control of the match"
assert html =~ "Find company for coffee, cinema, a walk, or a hike" assert html =~ "Find company for coffee, cinema, a walk, or a hike"
assert html =~ "Before you create a request" assert html =~ "Before you create a request"
assert html =~ ~r/<title[^>]*>Who Need Help<\/title>/
refute html =~ "Who Need Help · Who Need Help"
assert content_security_policy =~ "default-src 'self'" assert content_security_policy =~ "default-src 'self'"
assert content_security_policy =~ "script-src 'self'" assert content_security_policy =~ "script-src 'self'"
refute content_security_policy =~ "script-src 'self' 'unsafe-inline'" refute content_security_policy =~ "script-src 'self' 'unsafe-inline'"
@ -153,8 +155,12 @@ defmodule WhoNeedHelpWeb.PageControllerTest do
test "GET /safety", %{conn: conn} do test "GET /safety", %{conn: conn} do
conn = get(conn, ~p"/safety") conn = get(conn, ~p"/safety")
assert html_response(conn, 200) =~ "Safety rules" html = html_response(conn, 200)
assert html_response(conn, 200) =~ "Not for emergencies"
assert html =~ "Safety rules"
assert html =~ "Not for emergencies"
assert html =~ "Safety rules · Who Need Help"
assert html =~ "Safety guidance for voluntary help"
end end
test "GET /privacy publishes the Google data disclosure and user controls", %{conn: conn} do test "GET /privacy publishes the Google data disclosure and user controls", %{conn: conn} do

View File

@ -7,19 +7,26 @@ defmodule WhoNeedHelpWeb.SupportControllerTest do
describe "public support and removal intake" do describe "public support and removal intake" do
test "renders each public form", %{conn: conn} do test "renders each public form", %{conn: conn} do
assert html_response(get(conn, ~p"/support"), 200) =~ "Contact Who Need Help" support = html_response(get(conn, ~p"/support"), 200)
assert html_response(get(conn, ~p"/account/delete"), 200) =~ "Request account deletion" deletion = html_response(get(conn, ~p"/account/delete"), 200)
removal = html_response(get(conn, ~p"/legal/content-removal"), 200)
take_it_down = html_response(get(conn, ~p"/legal/take-it-down"), 200)
assert html_response(get(conn, ~p"/legal/content-removal"), 200) =~ assert support =~ "Contact Who Need Help"
"Report illegal or harmful content" assert support =~ "Contact support · Who Need Help"
assert deletion =~ "Request account deletion"
assert deletion =~ "Request account deletion · Who Need Help"
assert removal =~ "Report illegal or harmful content"
assert removal =~ "Report content · Who Need Help"
assert removal =~ "Open TAKE IT DOWN request"
assert removal =~ ~s(href="/legal/take-it-down")
assert take_it_down =~ "Do not upload the image or video"
assert take_it_down =~ "TAKE IT DOWN request · Who Need Help"
assert html_response( assert html_response(
get(conn, ~p"/legal/content-removal?location=/requests/specific-id"), get(conn, ~p"/legal/content-removal?location=/requests/specific-id"),
200 200
) =~ "/requests/specific-id" ) =~ "/requests/specific-id"
assert html_response(get(conn, ~p"/legal/take-it-down"), 200) =~
"Do not upload the image or video"
end end
test "creates support request without exposing its status token in the redirect", %{ test "creates support request without exposing its status token in the redirect", %{

View File

@ -10,6 +10,7 @@ defmodule WhoNeedHelpWeb.UserRegistrationControllerTest do
response = html_response(conn, 200) response = html_response(conn, 200)
assert get_resp_header(conn, "cache-control") == ["no-store"] assert get_resp_header(conn, "cache-control") == ["no-store"]
assert response =~ "Register" assert response =~ "Register"
assert response =~ "Register · Who Need Help"
assert response =~ ~p"/users/log-in" assert response =~ ~p"/users/log-in"
assert response =~ ~p"/users/register" assert response =~ ~p"/users/register"
assert response =~ "A password is not required" assert response =~ "A password is not required"
@ -35,6 +36,7 @@ defmodule WhoNeedHelpWeb.UserRegistrationControllerTest do
assert get_resp_header(conn, "cache-control") == ["no-store"] assert get_resp_header(conn, "cache-control") == ["no-store"]
assert response =~ "Sign-in request processed" assert response =~ "Sign-in request processed"
assert response =~ "Sign-in request processed · Who Need Help"
assert response =~ "Signing in does not create a new account" assert response =~ "Signing in does not create a new account"
assert response =~ "Sign-in request accepted" assert response =~ "Sign-in request accepted"
assert response =~ "cannot reveal whether an account exists" assert response =~ "cannot reveal whether an account exists"
@ -48,6 +50,7 @@ defmodule WhoNeedHelpWeb.UserRegistrationControllerTest do
response = conn |> get(~p"/users/check-email?flow=register") |> html_response(200) response = conn |> get(~p"/users/check-email?flow=register") |> html_response(200)
assert response =~ "Check your email to finish registration" assert response =~ "Check your email to finish registration"
assert response =~ "Check your email to finish registration · Who Need Help"
assert response =~ "Registration request accepted" assert response =~ "Registration request accepted"
assert response =~ "You do not need to enter your address again" assert response =~ "You do not need to enter your address again"
refute response =~ "cannot reveal whether an account exists" refute response =~ "cannot reveal whether an account exists"

View File

@ -15,6 +15,7 @@ defmodule WhoNeedHelpWeb.UserSessionControllerTest do
response = html_response(conn, 200) response = html_response(conn, 200)
assert get_resp_header(conn, "cache-control") == ["no-store"] assert get_resp_header(conn, "cache-control") == ["no-store"]
assert response =~ "Log in" assert response =~ "Log in"
assert response =~ "Log in · Who Need Help"
assert response =~ ~p"/users/register" assert response =~ ~p"/users/register"
assert response =~ "Email me a sign-in link" assert response =~ "Email me a sign-in link"
assert response =~ "Continue with Google" assert response =~ "Continue with Google"

View File

@ -12,6 +12,7 @@ defmodule WhoNeedHelpWeb.UserSettingsControllerTest do
conn = get(conn, ~p"/users/settings") conn = get(conn, ~p"/users/settings")
response = html_response(conn, 200) response = html_response(conn, 200)
assert response =~ "Settings" assert response =~ "Settings"
assert response =~ "Account settings · Who Need Help"
assert response =~ ~s(id="update_password_username") assert response =~ ~s(id="update_password_username")
assert response =~ ~s(autocomplete="username") assert response =~ ~s(autocomplete="username")
assert response =~ "Google sign-in" assert response =~ "Google sign-in"