-
Notifications
You must be signed in to change notification settings - Fork 811
devtools: toggle for Cap Pro #1061
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
The latest updates on your projects. Learn more about Vercel for GitHub.
|
WalkthroughAdds two server actions to toggle a user’s Pro status in development and exposes them via two forms in the CapDevtools UI. Actions validate development environment, require an active session, and update Stripe-related fields for the current user in the database. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor Dev as Developer (browser)
participant UI as CapDevtools UI
participant SA as Server Action (promoteToPro/demoteFromPro)
participant Auth as getCurrentUser
participant DB as DB (users)
Dev->>UI: Click "Promote" or "Demote"
UI->>SA: Submit form (server action)
SA->>SA: Check NODE_ENV === "development"
SA->>Auth: getCurrentUser()
Auth-->>SA: user | null
alt user present
SA->>DB: update users set stripe* = {active/dev or null} where id = user.id
DB-->>SA: ok
SA-->>UI: success (no payload)
UI-->>Dev: UI reflects devtools action completion
else no session
SA-->>UI: error (no session)
UI-->>Dev: show error
end
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (6)
apps/web/app/Layout/providers.tsx (2)
74-74
: Rename module to kebab-case and update import pathFollow repo convention: use kebab-case for TS/JS module filenames.
Apply this diff after renaming
devtoolsServer.ts
→devtools-server.ts
:-import { demoteFromPro, promoteToPro } from "./devtoolsServer"; +import { demoteFromPro, promoteToPro } from "./devtools-server";Please confirm the file was renamed on disk and any other imports were updated.
126-149
: Prefer useEffectMutation over plain form actions and perform targeted cache updatesAlign with client guidelines: use useEffectMutation to call Server Actions and update caches (e.g., current-user) via setQueryData/setQueriesData or refresh affected UI.
Apply this diff to replace forms with buttons invoking mutations:
- <div className="flex items-center space-x-2"> - <form action={promoteToPro}> - <button - type="submit" - className="rounded bg-green-600 px-2 py-1 text-xs font-medium text-white hover:bg-green-700" - > - Promote to Pro - </button> - </form> - <form action={demoteFromPro}> - <button - type="submit" - className="rounded bg-red-600 px-2 py-1 text-xs font-medium text-white hover:bg-red-700" - > - Demote from Pro - </button> - </form> - </div> + <div className="flex items-center space-x-2"> + <button + type="button" + className="rounded bg-green-600 px-2 py-1 text-xs font-medium text-white hover:bg-green-700 disabled:opacity-50" + onClick={() => promote.mutate()} + disabled={promote.isPending} + > + Promote to Pro + </button> + <button + type="button" + className="rounded bg-red-600 px-2 py-1 text-xs font-medium text-white hover:bg-red-700 disabled:opacity-50" + onClick={() => demote.mutate()} + disabled={demote.isPending} + > + Demote from Pro + </button> + </div>Add these supporting changes outside the selected range:
// imports import { useEffectMutation } from "@/lib/EffectRuntime"; import { useQueryClient } from "@tanstack/react-query"; import { useRouter } from "next/navigation";Inside CapDevtools(), before return:
const qc = useQueryClient(); const router = useRouter(); const promote = useEffectMutation(promoteToPro, { onSuccess: () => { // Prefer targeted cache updates. Adjust queryKey to your actual current-user key. qc.setQueriesData({ queryKey: ["current-user"] }, (u: any) => u ? { ...u, stripeCustomerId: "development", stripeSubscriptionId: "development", stripeSubscriptionStatus: "active" } : u, ); router.refresh(); // optional, if parts of UI rely on RSC data }, }); const demote = useEffectMutation(demoteFromPro, { onSuccess: () => { qc.setQueriesData({ queryKey: ["current-user"] }, (u: any) => u ? { ...u, stripeCustomerId: null, stripeSubscriptionId: null, stripeSubscriptionStatus: null } : u, ); router.refresh(); // optional }, });
- Replace ["current-user"] with the real query key used for the signed-in user in this app.
- If the app doesn’t cache the user with TanStack Query, keep router.refresh() to update RSC-derived UI.
apps/web/app/Layout/devtoolsServer.ts (4)
9-10
: Remove redundant "use server" inside a server-only moduleThe file is already server-only via the top-level directive. Per Next.js guidance, inner "use server" is unnecessary.
export async function promoteToPro() { - "use server";
27-28
: Remove redundant "use server" here as wellSame rationale as above.
export async function demoteFromPro() { - "use server";
18-23
: Also set related Stripe fields to a consistent dev stateTo prevent partial/inconsistent state, consider setting price and clearing third-party fields when promoting in dev.
.set({ stripeCustomerId: "development", stripeSubscriptionId: "development", stripeSubscriptionStatus: "active", + stripeSubscriptionPriceId: "development", + thirdPartyStripeSubscriptionId: null, })Confirm these fields are used in entitlement checks; adjust values if a specific dev price id exists.
36-41
: Clear all Stripe-related fields on demotionMirror the promote path to avoid lingering identifiers.
.set({ stripeCustomerId: null, stripeSubscriptionId: null, stripeSubscriptionStatus: null, + stripeSubscriptionPriceId: null, + thirdPartyStripeSubscriptionId: null, })
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
apps/web/app/Layout/devtoolsServer.ts
(1 hunks)apps/web/app/Layout/providers.tsx
(2 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
apps/web/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/web/**/*.{ts,tsx}
: Use TanStack Query v5 for all client-side server state and data fetching in the web app
Web mutations should call Server Actions directly and perform targeted cache updates with setQueryData/setQueriesData rather than broad invalidations
Client code should use useEffectQuery/useEffectMutation and useRpcClient from apps/web/lib/EffectRuntime.ts; do not create ManagedRuntime inside components
Files:
apps/web/app/Layout/devtoolsServer.ts
apps/web/app/Layout/providers.tsx
apps/web/app/**/*.{tsx,ts}
📄 CodeRabbit inference engine (CLAUDE.md)
Prefer Server Components for initial data in the Next.js App Router and pass initialData to client components
Files:
apps/web/app/Layout/devtoolsServer.ts
apps/web/app/Layout/providers.tsx
**/*.{ts,tsx,js,jsx,rs}
📄 CodeRabbit inference engine (CLAUDE.md)
Do not add inline, block, or docstring comments in any language; code must be self-explanatory
Files:
apps/web/app/Layout/devtoolsServer.ts
apps/web/app/Layout/providers.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use strict TypeScript and avoid any; leverage shared types from packages
**/*.{ts,tsx}
: Use a 2-space indent for TypeScript code.
Use Biome for formatting and linting TypeScript/JavaScript files by runningpnpm format
.
Files:
apps/web/app/Layout/devtoolsServer.ts
apps/web/app/Layout/providers.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,js,jsx}
: Use kebab-case for filenames for TypeScript/JavaScript modules (e.g.,user-menu.tsx
).
Use PascalCase for React/Solid components.
Files:
apps/web/app/Layout/devtoolsServer.ts
apps/web/app/Layout/providers.tsx
apps/web/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
On the client, always use
useEffectQuery
oruseEffectMutation
from@/lib/EffectRuntime
; never callEffectRuntime.run*
directly in components.
Files:
apps/web/app/Layout/devtoolsServer.ts
apps/web/app/Layout/providers.tsx
🧬 Code graph analysis (2)
apps/web/app/Layout/devtoolsServer.ts (2)
packages/database/index.ts (1)
db
(30-35)packages/database/schema.ts (1)
users
(46-94)
apps/web/app/Layout/providers.tsx (1)
apps/web/app/Layout/devtoolsServer.ts (2)
promoteToPro
(8-24)demoteFromPro
(26-42)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Build Desktop (x86_64-pc-windows-msvc, windows-latest)
- GitHub Check: Build Desktop (aarch64-apple-darwin, macos-latest)
- GitHub Check: Analyze (rust)
🔇 Additional comments (1)
apps/web/app/Layout/devtoolsServer.ts (1)
11-13
: Dev-only guard looks goodExplicitly blocking non-dev usage is correct for these actions.
If this might be used in preview/staging where NODE_ENV=production, ensure the UI is hidden (it is) and consider an environment flag if you need to enable it there.
Summary by CodeRabbit
New Features
Chores