Skip to content

feat(lfg): Looking for group - #6920

Open
idoshamun wants to merge 9 commits into
mainfrom
lfg
Open

idoshamun wants to merge 9 commits into
mainfrom
lfg

Conversation

@idoshamun

@idoshamun idoshamun commented Oct 15, 2026 •

Copy link
Copy Markdown
Member

Looking for group, built from the Storybook prototype (#6914) on the API in dailydotdev/daily-api#4414, #4417, #4419, #4420 and dailydotdev/daily-api#4428. The prototype's stories are removed in a separate commit.

Routes

  • /lfg is the board. Before launch it's the Opening soon page.
  • /lfg/:id is a post.
  • /lfg/new and /lfg/:id/edit are the composer.

All of them are signed-in only and noindex.

Flags (both off by default)

  • lfg controls who has Looking for group at all: the board, posts, reach-outs, the badge, the hover strip, the profile section, the nav entries and the notification switches. It's evaluated only for people who have direct messages (direct_messages plus a chat server), because an accepted reach-out becomes a chat. Anyone outside it is redirected home.
  • lfg_launched off is "Opening soon". People can post and opt in to helping, and the badge shows. Nothing posted is listed, and nobody can reach out. Turning it on opens the board.

What's in it

  • Board:
    • Kind tabs (Everything, Build, Learn, Help) and the Time zone, Topics and Reputation filters live in the header strip, using the squad directory's tab item and Float dropdowns. On phones they're shell chips and a Filters sheet.
    • One list, newest first, with infinite scroll.
    • Widgets: Find your people, Your post (or a prompt to write one) and Open to helping. On the Help tab, Open to helping saves the current filters.
  • Post page:
    • The squad sub-page header with Report.
    • An About widget with receipts: reputation, member since, verified workplace, work experience, verified GitHub and reading streak.
    • Reach out, the credits left, and every non-reachable state (requested, accepted, filled, found, expired, paused, pre-launch).
    • The author gets stats, Review responses, Found someone (which picks among the accepted reach-outs), Renew, Edit and Delete.
  • Composer: kind, headline, the one description box, the standing freelance warning, topics from daily.dev tags (followed tags suggested), time commitment, time zone and country, up to 3 asks plus a custom one, and a live preview row. House rules show before a first post. A second open post is blocked with a link to the first.
  • Reach-out modal:
    • The pitch and the poster's asks, with a link check against the sender's verified GitHub.
    • Stand out nudges into the real flows: link GitHub, work experience settings, CV upload.
    • The receipts that go with the request, the DMs-off and out-of-credits states, and the API's error cases.
  • Messages:
    • The Requests tab lists reach-outs grouped under the post, plus a filtered folder. ?reachOut=<id> opens a pane to Accept (into the chat), Decline (Undo restores it) or Report, which reports, blocks and declines their other requests.
    • The Requests count includes reach-outs.
    • A chat that started from a reach-out shows which post it came from, with a dismissible safety note.
  • Badge and profiles:
    • The LFG badge appears on comment and post author avatars (lfgKind is added to UserAuthor; it's already live in prod).
    • Hover cards get a strip, or a teaser before launch.
    • Profiles get the ring and ribbon on the avatar, a Looking for group section, and your own private Open to helping.
  • Navigation: an LFG tab on the v2 rail (with a small panel) and the phone bar, a legacy sidebar entry, and the Signal mark as a proper icon (icons/Signal).
  • Notifications: switches in both settings tabs for lfg_reach_out_received, lfg_help_match and lfg_still_looking.
  • Analytics:
    • open lfg board, filter lfg board, open lfg post
    • start / publish / edit / delete / renew lfg post, agree lfg house rules, mark lfg post found, report lfg post
    • start / send lfg reach out, click lfg stand out
    • open / accept / decline / restore / report lfg reach out
    • save / remove lfg helper, click lfg strip
    • Ids go in target_id, with TargetType.LfgPost / LfgReachOut.
  • Batching: the widget and secondary reads go through gqlBatchRequest: facets, your post, helper, credits, inbox, person, streak, user post and conversation post. The board and the post itself stay on gqlClient.request.

Decisions worth a look

  • Content checks: the prototype blocked pay, contact and duplicate pitches client-side. Those checks aren't carried over, matching test: callback page #4420, which dropped the same regexes because they rejected normal developer text. The standing warning stays, and spam is left to vordr and jev.
  • Copy and Remind me: copy that promised a heads-up to people who follow a post's tags is gone, because only Help posts notify (Open to helping). "Remind me" on the pre-launch post page is gone too: nothing would send that reminder.
  • Report post uses the existing Report user modal on the author. An LfgPost report with the post attached would give moderators more context; that would be an API follow-up.
  • Modals on phones: the composer modals use formProps, because Modal.Footer renders nothing in a phone sheet. A spec caught this: the prototype's footers would have had no Send button on phones.
  • Shared components changed: SquadSubPageHeader gets phoneActions, UserEntityCard gets footer, and ProfileHeader gets avatarBadge. ReportUserModal exports its reasons.

Deploy order

  1. dailydotdev/daily-api#4428 must deploy. test: callback page #4420 is already merged; it must be deployed too.
  2. Then turn on lfg for a cohort that has direct_messages.
  3. Then turn on lfg_launched when connections open.

Merging this before the API deploys is safe, since nothing LFG-specific runs while lfg is off. The one always-on change is lfgKind on UserAuthor and the hover query, which production already serves.

Testing

  • New specs:
    • row status and reach-out rules
    • offset formatting and profile time zones
    • GitHub link verification
    • the reach-out modal (answers in ask order, the link check, credits)
    • the Requests section (grouping, the filtered folder, flag off)
  • The full shared (530 suites) and webapp (83 suites) Jest runs pass.
  • Strict changed-files typecheck passes, the webapp tsc passes and lint is clean. The shared and extension tsc errors are pre-existing on main.
  • Checked in Chrome against the local dev server with the flags forced and the LFG operations stubbed in the page: the board, a post, the reach-out modal through send, the Requests tab and reach-out pane, Opening soon, the composer, the profile section and ribbon, and the Open to helping modal.
  • Not checked in a browser yet: phone widths, the comment and hover-card badge on real data, and a real two-account run. Those wait for the preview with the API deployed.

Preview domain

https://lfg.preview.app.daily.dev

Builds Looking for group from the Storybook prototype on the API in
daily-api #4414, #4417, #4419, #4420 and the gaps PR that adds
LfgPost.utcOffset, LfgPost.acceptedReachOuts and userLfgPost.

- /lfg is the board (kind tabs, time zone, topics and reputation filters
  in the header, one list newest first) or, before launch, the Opening
  soon page. /lfg/:id is a post, /lfg/new and /lfg/:id/edit the composer.
- Two flags, both off by default: `lfg` gates every surface and rides on
  direct messages, since an accepted reach-out is a chat. `lfg_launched`
  off keeps the board in Opening soon: people post and opt in to helping,
  nothing is listed and nobody can reach out.
- Reach-outs open from the board, a post and a profile, with the poster's
  asks, a link check against the sender's verified GitHub, Stand out
  nudges into the real GitHub link, work experience and CV flows, and the
  receipts the author will see.
- The author answers in Messages' Requests tab: reach-outs grouped under
  the post, a filtered folder, and a pane to accept into a chat, decline
  with undo or report and block. A chat that started from a reach-out
  names the post and carries a safety note.
- The LFG badge on comment and post author avatars, a strip under hover
  cards, a section and ribbon on profiles, an LFG tab on the v2 rail and
  the phone bar, an entry in the legacy sidebar, and switches for the
  three LFG notifications.
- Board widgets, the helper count and other secondary reads go through
  gqlBatchRequest; the board and the post stay on their own requests.

The prototype's client-side pay, contact and duplicate-pitch blocks are
not carried over: the API dropped the same regexes (#4420) because they
rejected normal developer text, and spam is left to vordr and jev.
Copy that promised a heads-up to people who follow a post's tags is gone,
since only Help posts notify (Open to helping). Remind me on the
pre-launch post page is gone too, with nothing behind it.

The modals put their action in the sheet's pinned bar on phones
(formProps), where Modal.Footer renders nothing.
Looking for group now lives in the app, so the prototype flows in
packages/storybook/stories/lfg go.
@vercel

vercel Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
daily-webapp Ready Ready Preview Oct 15, 2026 8:51pm UTC
storybook Ready Ready Preview Oct 15, 2026 8:51pm UTC

Request Review

…real link

Found in the two-account test on the preview. A post that failed to load
said it wasn't there anymore, which reads like the author deleted it; it
now offers a retry. A link answer without http(s) kept Send disabled with
only the GitHub verification line under it; it now says what's missing.
Found in the two-account test: the title in the LFG strip under a hover
card inherited the tooltip's dark text color and was nearly invisible on
the card.
The note about blocking the sender sits beside Submit in the dialog
footer. The global flex-shrink reset kept it at full width, so it pushed
the button past the dialog's right edge. It now shrinks and wraps.
Accepting a reach-out from someone the poster already chats with reuses
that conversation, so its request message stays the old one and the new
pitch never appeared. The conversation query now reads the pair's
accepted reach-outs (daily-api#4432), and the thread places each pitch it
doesn't already open with as the sender's message, before the first
message sent after it.

Needs daily-api#4432 deployed: until then the conversation query fails
validation and the "You met through" card hides.
Product gaps:
- Report post calls reportLfgPost with a reason picker (the reasons the
  API takes) instead of reporting the author, logs once it's sent, and
  the board drops the post.
- "Your past posts" on the board lists found and expired posts from
  myLfgPosts, so an author can get back to one and reopen it. A post past
  its expiresAt reads as expired even before the expiry cron runs.
- A GitHub or GitLab link in a chat that began with a reach-out asks
  before it opens ("Before you open this"), with Report and Open anyway.
- The Messages dot counts reach-outs waiting on the viewer's posts,
  seeded by the shell state query (lfgReachOutWaitingCount).
- A reach-out shows the sender's time zone, their job title as a
  receipt, and "Not verified" under links that aren't their own repos.
  Opened by link after it was answered, it says what came of it.
- The pitch no longer claims copy-paste pitches get held back; nothing
  checks for that.

Fixes:
- Deleting a post or marking it found refreshes Messages, so the closed
  reach-outs leave Requests; accept shows the API's reason when the post
  closed meanwhile.
- The edit form locks kind and asks on the API's hasReachOuts, which
  counts declined reach-outs too.
- The reach-out pane in Messages follows the lfg flag.
- Hitting the hourly send cap no longer reads as used-up credits.
- A profile without a time zone shows UTC+0 like the API, with a link to
  set one.
- A failed background refetch keeps a loaded post on screen; the board
  drops rows a later page repeats; Requests keeps reach-outs when message
  requests fail and doesn't flash "No message requests" while they load.
- Connect GitHub opens its window on the click (Safari blocked the one
  opened after an await) and says when it fails.
- Open to helping prefilled from the board keeps to its 10-topic cap; a
  first post shows the house rules while actions load; a blank custom ask
  is dropped; notes the API keeps (a request, a pitch) can't be reacted to.

Needs daily-api#4432 and #4434 deployed first: the shell state query
asks for lfgReachOutWaitingCount, and the conversation query for
lfgReachOuts.
- The repo-link warning also catches middle clicks (auxclick), and gists,
  raw files and archive downloads on any GitHub, githubusercontent or
  GitLab subdomain. It guards the reach-out pane too, where a stranger's
  repo answer is the first link a poster sees, and its Report starts
  with Block ticked.
- People with direct messages off see a "Turn on" notice in the composer
  and the Open to helping modal, as the reach-out modal already did:
  every reach-out becomes a chat, so both dead-end without it.
- A declined reach-out opened later can be restored, past the toast's
  Undo.
- Connect GitHub hides where the window can't open (the iOS app, mobile
  Brave); a redirect there would lose the pitch being written.
- After a post mutation the post query reloads, since the result lacks
  hasReachOuts and the edit lock read stale counts. Answering a
  reach-out refreshes the board, where your row counts what waits.
- Analytics: sends carry the reach-out id so they join accepts and
  declines; found, renew, delete, report, accept, decline and restore
  carry the post kind; board row clicks (click lfg post, with position)
  and opening Open to helping (open lfg helper) are logged; agreeing to
  the house rules logs once the first post is saved, not on every try.
Signing in on an LFG page, or a boot that swaps the user, renders once
with the new user before GrowthBookProvider's effect hands GrowthBook
their id. The lfg flag reads false for that render, the gate's redirect
fires before the attributes land, and someone inside the flag is sent
home. Found in the round-2 test, where a freshly signed-in profile
loading /lfg landed on the feed. The gate now waits until GrowthBook's
userId matches the signed-in user; setAttributes re-renders the tree, so
the real answer follows right after.

This branch was successfully deployed

2 active deployments
Preview – daily-webapp — 5e0089d8 Deployed Oct 15, 2026 by vercel[bot]
Preview – storybook — 5e0089d8 Deployed Oct 15, 2026 by vercel[bot]
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.

1 participant