feat(ui): add UserButton controller - #9185
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🦋 Changeset detectedLatest commit: 93aa6f2 The changes in this PR will be included in the next version bump. This PR includes changesets to release 0 packagesWhen changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository YAML (base), Repository UI (inherited) Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
8786841 to
ba22f92
Compare
ba22f92 to
c9bdf23
Compare
dfae67d to
ef35f2d
Compare
ef35f2d to
8f7ffa2
Compare
c9bdf23 to
93aa6f2
Compare
075c15d to
4e052b8
Compare
Summary
Stacked on #9184 (the presentational view). Adds the controller layer that connects
UserButtonto live Clerk data, plus its tests (TDD).useUserButtonController()(user-button.controller.tsx) — a plain hook (no machine) returning a'loading' | 'hidden' | 'ready'discriminated union. Whenreadyit carriesUserButtonData & UserButtonCallbacks1:1 with the contract inuser-button.view.tsx.UserButton(user-button.tsx) — the connected container. Owns popover open state and close-on-success (Option A: wraps each one-shot callback with.finally(close); manage/create navigations do not auto-close).UserButton→UserButtonView, reserving the bareUserButtonfor the connected container. Updated the swingset story + mdx.Data mapping (Clerk → contract)
activeSessionfromuseUser()+useSession(), name fallback first+last > username > email.activeOrganizationIdfromuseOrganization()(null= personal).memberships/suggestions/invitationsfromuseOrganizationList(organizationListParams)(reused from the legacy switcher).hasOrganizationsfromuserMemberships.count(never array length).additionalSessionsfromclerk.client.signedInSessions, excluding the active user's session.membershipRequestCountonly on the active-org row and only withorg:sys_memberships:manage.planLabel/upgradeabledeferred (undefined).Actions (navigation mode)
setActivefor select/switch,signOutfor sign-out,router.navigate(clerk.build*Url())for manage/create,.accept()+revalidate()for invitations/suggestions.Tests
12 controller tests (
__tests__/user-button.controller.test.tsx) using the mosaicvi.mock('@clerk/shared/react')harness (copied fromorganization-profile-delete-section.controller.test.tsx). Written failing first, then implemented to green.Notes / deviations from the handoff
Two points where the handoff wasn't directly implementable; resolved as follows:
onSelectOrganizationnavigation. The handoff referenceddisplayConfig.afterSelectOrganizationUrl, but that field only exists as a component prop, not on the environment. Per decision, navigation goes throughsetActive({ organization, redirectUrl })(matching the legacy switcher), usingdisplayConfig.afterCreateOrganizationUrlas the redirect. Fully type-safe, no cast.loading → <UserButtonView status="loading" />, but the view requiresactiveSession(which is only present whenready) and the view was out of scope to restructure. The container rendersnullwhile loading/hidden and the view only whenready. The controller still exposesstatus: 'loading'for future use.Checklist
turbo test --filter @clerk/ui(12 new + full suite: 2666 passing)type-checkcleaneslintclean (0 errors)