From 3fa0ea383a89eb931f9f8ac2dd0e048ee6652bd9 Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Sat, 7 Mar 2026 11:58:46 -0600 Subject: [PATCH] feat: improve organization invitation UX - Show sender's full name in invitation emails - Use relative time for "Sent" column (more readable) - Use date format for "Expires" column (shorter) - Make invitation table horizontally scrollable Fixes display cropping issue where long timestamps caused the pending invitations table to overflow its container. --- lib/towerops/accounts/user_notifier.ex | 17 ++++++++++++++++- lib/towerops_web/live/org/settings_live.ex | 6 +++++- .../live/org/settings_live.html.heex | 6 +++--- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/lib/towerops/accounts/user_notifier.ex b/lib/towerops/accounts/user_notifier.ex index 17146005..8c0ad86d 100644 --- a/lib/towerops/accounts/user_notifier.ex +++ b/lib/towerops/accounts/user_notifier.ex @@ -122,10 +122,25 @@ defmodule Towerops.Accounts.UserNotifier do def deliver_invitation_email(invitation, accept_url) do subject = "You've been invited to join #{invitation.organization.name} on Towerops" + invited_by_name = + case invitation.invited_by do + %User{first_name: first, last_name: last} when not is_nil(first) and not is_nil(last) -> + "#{first} #{last}" + + %User{first_name: first} when not is_nil(first) -> + first + + %User{email: email} -> + email + + _ -> + "A team member" + end + body = """ Hi, - You've been invited to join #{invitation.organization.name} on Towerops as a #{invitation.role}. + #{invited_by_name} has invited you to join #{invitation.organization.name} on Towerops as a #{invitation.role}. You can accept this invitation by visiting the URL below: diff --git a/lib/towerops_web/live/org/settings_live.ex b/lib/towerops_web/live/org/settings_live.ex index b7c43eb0..fe4093b8 100644 --- a/lib/towerops_web/live/org/settings_live.ex +++ b/lib/towerops_web/live/org/settings_live.ex @@ -210,7 +210,11 @@ defmodule ToweropsWeb.Org.SettingsLive do case Organizations.create_invitation(attrs) do {:ok, invitation} -> - invitation = %{invitation | organization: organization} + invitation = + invitation + |> Towerops.Repo.preload(:invited_by) + |> Map.put(:organization, organization) + accept_url = url(~p"/invitations/#{invitation.token}") UserNotifier.deliver_invitation_email(invitation, accept_url) diff --git a/lib/towerops_web/live/org/settings_live.html.heex b/lib/towerops_web/live/org/settings_live.html.heex index abf5451f..74c86148 100644 --- a/lib/towerops_web/live/org/settings_live.html.heex +++ b/lib/towerops_web/live/org/settings_live.html.heex @@ -670,7 +670,7 @@
-
+
@@ -707,14 +707,14 @@ <.timestamp datetime={invitation.inserted_at} timezone={@timezone} - format="absolute" + format="relative" /> <%= if @membership.role in [:owner, :admin] do %>
<.timestamp datetime={invitation.expires_at} timezone={@timezone} - format="absolute" + format="date" />