feat(groups): add active group switcher - #273
Conversation
Qodo reviews are paused for this user.Troubleshooting steps vary by plan Learn more → On a Teams plan? Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center? |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
ea31a03 to
4ccba62
Compare
4ccba62 to
afe4235
Compare
e842a09 to
44b4567
Compare
Playwright test resultsDetails
|
|
Deploy →
|
|
The This means staging is missing The auto-generated deploy-status comment on this thread suggests Generated by Claude Code |
7accc6c to
a623ddb
Compare
… toggle Turns the header's Groups indicator into a switcher listing Everyone plus every group the user belongs to; selecting an entry persists it as the profile's active_group_id and takes effect everywhere without a reload. Retires the Artists-tab-only groupId URL param and its dropdown, replacing it with a Vote Perspective toggle (Everyone vs Active Group) that re-scores and re-sorts sets without hiding any. Extracts the ad hoc group-membership vote filter into a shared, pure resolveVotesForScope function (Everyone/Me/ Group) so the next issue's Schedule tab scope can reuse it. Closes #124
The header's active-group indicator is now a DropdownMenu-driven switcher (a native <button>), not a plain link to /groups, so the role assertion needs to match.
- Extract the group-switcher dropdown out of GroupsIndicator into its own ActiveGroupSwitcher component. - Narrow resolveVotesForScope's groupMemberIds param to Set<string> only, since every real caller already passes a Set; drops the unused array-input overload and its dedicated test.
… users The single-group auto-activation from #123 stores "no active group set yet" as active_group_id = NULL, which is indistinguishable from an explicit "Everyone" choice made through the new switcher — so choosing Everyone was silently overridden back to the sole group. Add a active_group_selected flag so an explicit selection is trusted as-is, while auto-activation still applies for users who've never touched the switcher. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VGSj8prZCB1qAtR2Wz3qKL
There was no way to reach /groups once a user already belonged to a group, since the header CTA only shows for the zero-groups case. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VGSj8prZCB1qAtR2Wz3qKL
Epic #122 references CONTEXT.md vocabulary and docs/adr/0003-active-group-model.md as settled, but they were only ever written on claude/group-feature-design-f0nhvn, which never merged (and is now too stale to merge as-is, predating Festival Phase and Retrospective Rating). Reapply just the Active Group / Vote Perspective / Vote Scope vocabulary and the ADR (renumbered 0005, since 0003 and 0004 are now taken) onto current CONTEXT.md, updated to describe the active_group_selected flag actually shipped and to flag that its Everyone-persistence behavior is under active reconsideration. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VGSj8prZCB1qAtR2Wz3qKL
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VGSj8prZCB1qAtR2Wz3qKL
…ive scope Following further design work (grill session + prototype, see docs/adr/0005), the active_group_selected flag from the previous fix papered over a modeling bug rather than fixing it: "which group is mine" and "which lens am I viewing through" were conflated into one nullable column. Root-cause instead: - profiles.active_group_id: which group is yours (unchanged meaning, now scope-independent). - profiles.active_scope (new): group/everyone/me, the durable Settings-level pin. Both are set explicitly only from a new Settings page. - The header switcher no longer writes either column — picking an entry there is a transient, in-memory override for the current session only, with a "back to X" affordance when it diverges from the pin. Pinned entry always sorts first and is starred. This is asymmetric by design: real group picks stay sticky/default with no friction (the epic's whole point), while Everyone/Me default to a temporary lens, with friction pushed onto the explicit Settings pin instead of every header click. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VGSj8prZCB1qAtR2Wz3qKL
Split the 189-line switcher into three focused files per review feedback: scopeDisplay.ts (pure label/icon/key helpers), ScopeMenuBody.tsx (the dropdown list), and the trimmed-down ActiveGroupSwitcher.tsx (trigger + back-to-default pill). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VGSj8prZCB1qAtR2Wz3qKL
Per review feedback: the pinned entry already sorts first (starred) in the dropdown, so a separate "back to X" affordance next to the trigger was redundant and added an extra jumping element to the header. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VGSj8prZCB1qAtR2Wz3qKL
4148291 to
bbf96bc
Compare
Deriving activeGroupId from the header's transient current scope hid the toggle whenever a user with an Active Group switched away from "group". Also seed the initial perspective from current per ADR 0005 instead of hardcoding "group". Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Replace hand-rolled <button> + manual state classes with the shadcn ToggleGroup pattern already used by VotePerspectiveToggle for the same single-select choice shape. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Decompose FilteredSetsPanel.tsx (154 lines, four mixed concerns) into AuthedFilteredSetsPanel/GroupScopedSetsPanel/SetsPanelContent, matching the earlier ActiveGroupSwitcher/ScopeMenuBody split. This also removes the duplicated "everyone" SetsPanelContent call between the anonymous and authed-non-group branches. Also collapse useSetActiveGroupMutation/useSetActiveScopeMutation into a shared useProfileFieldMutation, and dedupe the ToggleGroupItem className repeated in ActiveGroupSetting/ActiveScopeSetting. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012hH41h18hKSvYxWAw17nhd
| return useMutation({ | ||
| mutationFn: async (variables: { | ||
| userId: string; | ||
| value: ProfileUpdate[K]; |
There was a problem hiding this comment.
Why should the mutation update not nly one value?
Adds a persistent header switcher (Everyone + your groups) that sets the Active Group everywhere, and retires the Artists-tab-only group filter in favor of a two-state Vote Perspective toggle built on a shared, tested vote-scope resolver.
Selecting a group in the header re-scores and re-sorts the Artists tab immediately, without a reload.
Closes #124
Verification
pnpm testpasses, including newsrc/lib/voteScope.test.tscovering Everyone/Me/Group scopes, a member vs. non-member group, no votes, and votes only from outside the group.pnpm run typecheckandpnpm run lintpass.Generated by Claude Code