8000 feat: return to where you came from after sign in, else your groups' agenda with Nearby by MichaelDimmitt · Pull Request #679 · huddlz-hq/huddlz · GitHub
[go: up one dir, main page]

Skip to content

feat: return to where you came from after sign in, else your groups' agenda with Nearby - #679

Closed
MichaelDimmitt wants to merge 6 commits into
huddlz-hq:mainfrom
MichaelDimmitt:feat/678-post-login-landing
Closed

MichaelDimmitt wants to merge 6 commits into
huddlz-hq:mainfrom
MichaelDimmitt:feat/678-post-login-landing

Conversation

@MichaelDimmitt
@MichaelDimmitt MichaelDimmitt commented Oct 10, 2026 •
Copy link
Copy Markdown
Contributor

Summary

The approach chosen in #670: after signing in, a person lands back on the page they came for, or, with nothing to return to, on everything their groups have scheduled, with huddlz near them one click away. It combines A (#672), B's (#675) default without B's preference, and C (#676) with a 100-mile range.

Where sign-in sends a person:

 sign in
-  -> /agenda                          # your RSVPs only, so the huddl you came for is missing
+  -> the page you came from, if any   # header sign-in/up, pages needing an account, Discover's yours filters
+  -> else /agenda on the Groups filter

Every sign-in entry point now carries a return destination:

 huddl / group page, signed out
-  header "Sign in" / "Sign up"         -> /sign-in, /register
+  header "Sign in" / "Sign up"         -> ...?return_to=<this page>
   "Sign in to RSVP" / "Sign in to join" -> ...?return_to=<this page>   (already)

 page that needs an account (:live_user_required, :admin_required)
-  -> /sign-in
+  -> /sign-in?return_to=<requested page>

 /discover?yours=attending|hosting, signed out
-  -> /sign-in
+  -> /sign-in?return_to=<requested page>

Every destination still goes through AuthReturnTo.validate/1. AuthReturnTo.sign_in_path/1 builds the sign-in address from a path or request URI and falls back to a bare /sign-in for anything unsafe.

The agenda's filters:

 /agenda
-  [ RSVPs ] (default)  [ Groups ]
+  [ RSVPs ]  [ Groups ] (default)  [ Nearby ]

 parse_scope(param, view)
-  "groups" -> :groups, else :mine
+  "mine"   -> :mine
+  "nearby" -> :nearby        # agenda only; week and month fall back to Groups
+  else     -> :groups

Nearby reuses Discover's :search query (upcoming, PostGIS distance, no relationship filter) around the person's home search location, within 100 miles, and leaves out anything they already RSVP'd to or that their groups have scheduled. It loads asynchronously and redraws through the same put_view_state/1 path as the other two filters.

Out of scope, per #678: D (agenda search), E's question, F's nudge, B's preference, and measuring intent.

Evidence

Screenshots

The agenda opening on Groups

A member signs in with nothing to return to. The agenda opens on Groups 3: two Portland Elixir huddlz they haven't responded to, alongside the one they're going to. Nearby sits beside it.

The Nearby filter

Nearby, one click away: huddlz within 100 miles of St. Augustine from groups the person hasn't joined, including Gainesville (about 63 miles), which the POC's 25-mile range would have missed.

Both were captured with the mix test.browser Playwright harness.

Before: the agenda opened on RSVPs only:

Scenario: The agenda opens on everything my groups have on
  [failed] Then the agenda lists "Hands-on with Ash Framework" without an RSVP status

After: passes.

Before: at the POC's 25 miles, a huddl a reasonable drive away was missing:

Scenario: Nearby reaches a couple of hours' drive but no further
  [failed] Then the agenda lists "Gainesville game night" without an RSVP status

After: at 100 miles, Gainesville (about 63 miles) is listed and Tampa (about 150 miles) is not.

Before: a page that needed an account forgot where you were going:

Scenario: A page that needs an account returns me to it after signing in
  Expected path to be "/notifications" but got "/agenda"
Scenario: An admin page returns an admin to it after signing in
  Expected path to be "/admin/users" but got "/agenda"
Scenario: Discover's huddlz I am attending returns me to that filter after signing in
  Expected path to be "/discover" but got "/agenda"

After: all three pass. The header sign-in scenarios and the unsafe-destination scenario come from A (#672), where their before/after is recorded.

Clicks, measured against #670's target of 2 or fewer:

Journey Before After
From a huddl page, through the header sign-in, to attending it 5–7, or never 2
Sign in to a huddl in my groups 3 1
Sign in to a huddl near me outside my groups 3 (via /discover) 2 (Nearby)

Merge Danger

Door: two-way.

No migration, no new resource, no stored preference. Reverting restores the RSVPs default, removes the Nearby filter, and restores the bare sign-in redirects.

Blast Radius: the signed-in home.

  • Every signed-in person's agenda, week and month views open on Groups on their next visit, with no opt-out. RSVPs is one click away and bookmarkable at ?scope=mine.
  • Calendar URLs change shape: scope=groups is now omitted, and scope=mine and scope=nearby are written out. Old ?scope=groups links still work. ?scope=nearby on week or month falls back to Groups.
  • The agenda now runs a PostGIS search when Nearby is selected, and only then. It's async with a stale-ref guard, so a slow or failing search shows an empty state instead of blocking the page.
  • CalendarLive's handle_params/3 is split into a load step plus put_view_state/1. All three calendar views render through it, so a mistake there would affect all of them, not only Nearby.
  • Redirects that already went to /agenda (impersonation, the error page, the fallback after email confirmation) now open on Groups as well.
  • Open redirect: the sign-in redirects have more reach now, but each one still goes through AuthReturnTo.validate/1, with unit tests and A's unsafe-destination scenario.

What you should know

  • The agenda and calendar subtitle now follows the filter. It used to describe only RSVPs ("hosting, attending, or watching from the waitlist"), which was wrong once Groups became the default. RSVPs keeps that wording; Groups reads "What's next across your groups, plus anything else you've RSVP'd to."; Nearby reads "huddlz near you that aren't on your agenda yet."
  • Nearby's chip has no count, unlike RSVPs and Groups. Those are counted from two in-memory lists, while Nearby is a paginated search. Counting it after the search returns would make a number appear a beat late. The chip row is asymmetric on purpose.
  • Nearby needs a home search location. Without one, it asks the person to set one in their profile instead of guessing.
  • You can't land on Nearby. It's a search, so landing there could open the signed-in home on a spinner or a location prompt. It stays one click from Groups.
  • 100 miles is wider than Discover's default, because Nearby has no distance control and should find something instead of coming up empty. It still fetches at most 60 huddlz, sorted soonest first, which is more than the agenda's 7-day window shows.
  • first_run? is now decided per filter, and never for Nearby. G (POC G: the A + B + C combination for post-login landing #677) found that C's version, combined with B's default, made the first-run message for Groups unreachable without any merge conflict. This branch uses the per-filter version.
  • endpoint.ex now declares :uri connect info on the LiveView socket. Without it, the requested page is only known on the first page load, not when someone navigates within the app.
  • Two existing tests changed their expectations. auth_controller_test.exs now expects /sign-in?return_to=/profile instead of a bare /sign-in. C's "RSVPs and Groups filters still behave as before" now starts from ?scope=mine, since a bare /agenda opens on Groups.
  • B's step asserting the active filter used the is-active class. It now uses aria-current, per AGENTS.md's rule against asserting on classes.
  • A's and C's commits are cherry-picked, apart from dropping A's edits to the research doc, which isn't on main, and resolving C against B's default.

Part of #670. Closes #678.

Model: Claude Opus 5.5 (claude-opus-5-5)

🤖 Generated with Claude Code

A person who arrives on a huddl page from a link or a QR code and reaches
for the header's "Sign in" loses the huddl they came for: the header's link
is a bare /sign-in, so they land on the agenda, which by definition does not
list a huddl they have not RSVP'd to yet.

These scenarios describe the journey the person expects. Four of the five
fail: signing in or signing up from the header does not come back. The fifth
passes already and is meant to — it documents that AuthReturnTo.validate/1
refuses an off-site return destination before any of this work.

- Cover sign-in from a huddl page and from a group page
- Cover sign-up, where email confirmation intervenes
- Cover a tagged arrival, so join attribution survives the sign-in hop

Part of huddlz-hq#670
The return_to plumbing was already complete and already safe. What it was
missing was reach: only the huddl page's RSVP call to action and the group
page's join button produced a return destination. The topbar's "Sign in" and
"Sign up" — the buttons that look like the way to sign in — were bare paths,
so the two sign-in links on the same page disagreed about whether the
person's intent was worth keeping.

Layouts.app now takes a return_to a page can fill in, and the topbar's
sign-in and sign-up carry it. Validation happens inside the component rather
than at the call sites, so no page can hand the header an off-site
destination and any future caller is covered without having to remember.

The huddl page and the group page pass the destination they already computed
for their own buttons, so the header and the in-page call to action cannot
drift apart. On the group page that address still carries the join source
tag, so attribution survives the trip through auth.

- Add a validated return_to attr to Layouts.app
- Point the topbar's sign-in and sign-up at it
- Pass each page's existing return destination from huddl and group show

Part of huddlz-hq#678
The agenda is the signed-in home, but it opened on a person's own RSVPs, so
the huddl someone arrived for was missing from it by definition: their group
had it scheduled and they had not responded yet. Seeing it cost a click on
the Groups filter on every visit.

The agenda, week and month views now open on the Groups filter.
`?scope=mine` narrows to the person's own RSVPs, and the RSVPs filter links
there, so both filters stay one click away and bookmarkable. There is no
per-person preference; the default is what people get.

- Default `parse_scope/1` to groups and emit `scope=mine` instead
- Word the first-run and empty agenda copy for the Groups filter
- Reframe the scenario that asserted the old starting point to begin from
  `?scope=mine`; its behaviour and coverage are unchanged

Part of huddlz-hq#678
A signed-out person opening a page that needs an account, or Discover's
"attending" or "hosting" filter, was sent to a bare sign-in page and then
landed on the agenda, losing the page they had opened.

Those redirects now carry the requested page as `return_to`, validated by
`AuthReturnTo` like every other sign-in destination, so an unsafe address
still falls back to the bare sign-in page.

- Add `AuthReturnTo.sign_in_path/1`, built from a path or a request URI
- Use it for `:live_user_required`, `:admin_required` and Discover's
  personal filters
- Declare `:uri` connect info so the requested page is known on a connected
  mount as well as the first render

Part of huddlz-hq#678
MichaelDimmitt added a commit to MichaelDimmitt/huddlz that referenced this pull request Oct 10, 2026
The agenda only ever showed huddlz the person already has a relationship
to, so somebody who signs in looking for something to go to has to leave
for /discover. This adds a third scope beside RSVPs and Groups, showing
upcoming huddlz near their home search location that they have not
responded to, with no filters to configure.

Nearby reuses Discover's query whole rather than adding a second search
path: the same :search action, the same upcoming date filter and the same
PostGIS distance filter, with no relationship argument so it reaches
huddlz the person has nothing to do with. Results are put into the
agenda's own entry shape, so the existing day grouping, status logic and
list rendering draw them unchanged — a stranger's huddl reads as
"No RSVP".

- Nearby looks 100 miles out, wider than Discover's default. It has no
  distance control, so it should find something rather than come up empty.
- parse_scope/2 now takes the view mode: nearby is agenda-only, since a
  stranger's huddl is not a calendar fact and does not belong in a month
  cell, so week and month fall back to Groups. scope_param/2 drops the
  param from links leaving the agenda.
- first_run?/1 is decided per filter and never for Nearby, so the Groups
  first-run copy stays reachable alongside the new scope.
- handle_params/3 is split: it loads the two synchronous scopes and sets
  URL state, and put_view_state/1 derives everything the views draw from
  whichever scope is selected. handle_async/3 calls put_view_state/1
  again, so the async scope redraws through exactly the same path as the
  synchronous ones. A stale-ref guard drops a late reply.
- The Nearby chip carries no count. RSVPs and Groups are counted by
  comparing two in-memory lists; a paginated search cannot be 
8000
counted the
  same way, and a number arriving a beat late reads as a bug.
- Three states the other scopes do not have, each answered in place: no
  saved location points at /profile, a search in flight draws placeholder
  rows in the agenda's shape, and nothing in range offers Discover.
- The window is the agenda's existing @agenda_days, so the scopes stay
  comparable; the search overfills it, so Nearby never paginates.

Part of huddlz-hq#678
MichaelDimmitt added a commit to MichaelDimmitt/huddlz that referenced this pull request Oct 10, 2026
@MichaelDimmitt MichaelDimmitt changed the title feat: return to where you came from after sign in, else your groups' agenda feat: return to where you came from after sign in, else your groups' agenda with Nearby Oct 10, 2026
…itle

The page head still described only a person's own RSVPs ("hosting,
attending, or watching from the waitlist"), which was wrong once the
agenda and calendar opened on Groups and gained Nearby.

The subtitle now says what the selected filter holds: RSVPs keeps the old
wording, Groups names the groups plus other RSVPs, and Nearby names
huddlz near the person that are not on their agenda yet.

Part of huddlz-hq#678
MichaelDimmitt added a commit to MichaelDimmitt/huddlz that referenced this pull request Oct 10, 2026
@MichaelDimmitt
Copy link
Copy Markdown
Contributor Author

Screenshots with the subtitle that follows the filter:

Groups (the default after sign-in)

The agenda opening on Groups

Nearby (within 100 miles)

The Nearby filter

@mwoods79 mwoods79 closed this Oct 10, 2026
Copy link
Copy Markdown
Contributor

Thanks for digging into the lost sign-in destination, Michael. That finding is useful. I’m closing this version because changing the Groups default and adding Nearby make it a broader change than we need for the return fix. Review also found filtering and page-state issues. We’re preparing a focused replacement for the sign-in return behavior.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Post-login landing H: return to origin and open the agenda on Groups

2 participants

0