Unverified 提交 3ab40cd8 authored 作者: wwwillchen-bot's avatar wwwillchen-bot 提交者: GitHub

Refetch user budget on app load and after saving Dyad Pro key (#2632)

## Summary - Prefetch user budget on app initialization to ensure budget info is available immediately on load - Invalidate user budget query when Dyad Pro API key is saved to reflect updated subscription status immediately - Added documentation for React Query prefetch and invalidation patterns to AGENTS.md ## Test plan - Verify that user budget data loads on app startup - Test saving a Dyad Pro API key and confirm the budget information updates automatically - Check that the app continues to work correctly without a Dyad Pro subscription 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- devin-review-badge-begin --> --- <a href="https://app.devin.ai/review/dyad-sh/dyad/pull/2632" target="_blank"> <picture> <source media="(prefers-color-scheme: dark)" srcset="https://static.devin.ai/assets/gh-open-in-devin-review-dark.svg?v=1"> <img src="https://static.devin.ai/assets/gh-open-in-devin-review-light.svg?v=1" alt="Open with Devin"> </picture> </a> <!-- devin-review-badge-end --> <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Prefetches the user budget on app load and invalidates the budget query after saving a Dyad Pro API key, so subscription status and budget update instantly. Adds React Query docs for prefetch and invalidation patterns. <sup>Written for commit 92b15f29cda8b9b19ba04d281c6e3774ea3928c8. Summary will update on new commits.</sup> <!-- End of auto-generated description by cubic. --> Co-authored-by: 's avatarWill Chen <willchen90@gmail.com> Co-authored-by: 's avatarClaude Opus 4.5 <noreply@anthropic.com>
上级 a335e96d
...@@ -139,3 +139,26 @@ Content here ...@@ -139,3 +139,26 @@ Content here
``` ```
Valid states: `"finished"`, `"in-progress"`, `"aborted"` Valid states: `"finished"`, `"in-progress"`, `"aborted"`
### React Query prefetch and invalidation patterns
For app-level data that should be available immediately on load (like user budget/subscription info), use `prefetchQuery` in the root `App` component:
```tsx
const queryClient = useQueryClient();
useEffect(() => {
queryClient.prefetchQuery({
queryKey: queryKeys.userBudget.info,
queryFn: () => ipc.system.getUserBudget(),
});
}, [queryClient]);
```
When a mutation (like saving an API key) affects data managed by a different query, invalidate that query to trigger a refetch:
```tsx
// After saving Dyad Pro key, refetch user budget since subscription status may change
queryClient.invalidateQueries({ queryKey: queryKeys.userBudget.info });
```
This ensures related data stays in sync without tight coupling between components.
...@@ -3,6 +3,8 @@ import { useRouter } from "@tanstack/react-router"; ...@@ -3,6 +3,8 @@ import { useRouter } from "@tanstack/react-router";
import { ArrowLeft, AlertTriangle } from "lucide-react"; import { ArrowLeft, AlertTriangle } from "lucide-react";
import { useSettings } from "@/hooks/useSettings"; import { useSettings } from "@/hooks/useSettings";
import { useLanguageModelProviders } from "@/hooks/useLanguageModelProviders"; import { useLanguageModelProviders } from "@/hooks/useLanguageModelProviders";
import { useQueryClient } from "@tanstack/react-query";
import { queryKeys } from "@/lib/queryKeys";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
import { Skeleton } from "@/components/ui/skeleton"; import { Skeleton } from "@/components/ui/skeleton";
...@@ -62,6 +64,7 @@ export function ProviderSettingsPage({ provider }: ProviderSettingsPageProps) { ...@@ -62,6 +64,7 @@ export function ProviderSettingsPage({ provider }: ProviderSettingsPageProps) {
const [isSaving, setIsSaving] = useState(false); const [isSaving, setIsSaving] = useState(false);
const [saveError, setSaveError] = useState<string | null>(null); const [saveError, setSaveError] = useState<string | null>(null);
const router = useRouter(); const router = useRouter();
const queryClient = useQueryClient();
// Use fetched data (or defaults for Dyad) // Use fetched data (or defaults for Dyad)
const providerDisplayName = isDyad const providerDisplayName = isDyad
...@@ -148,7 +151,11 @@ export function ProviderSettingsPage({ provider }: ProviderSettingsPageProps) { ...@@ -148,7 +151,11 @@ export function ProviderSettingsPage({ provider }: ProviderSettingsPageProps) {
} }
await updateSettings(settingsUpdate); await updateSettings(settingsUpdate);
setApiKeyInput(""); // Clear input on success setApiKeyInput(""); // Clear input on success
// Optionally show a success message
// Refetch user budget when Dyad Pro key is saved
if (isDyad) {
queryClient.invalidateQueries({ queryKey: queryKeys.userBudget.info });
}
} catch (error: any) { } catch (error: any) {
console.error("Error saving API key:", error); console.error("Error saving API key:", error);
setSaveError(error.message || "Failed to save API key."); setSaveError(error.message || "Failed to save API key.");
......
...@@ -13,6 +13,7 @@ import { ...@@ -13,6 +13,7 @@ import {
QueryClient, QueryClient,
QueryClientProvider, QueryClientProvider,
MutationCache, MutationCache,
useQueryClient,
} from "@tanstack/react-query"; } from "@tanstack/react-query";
import { showError, showMcpConsentToast } from "./lib/toast"; import { showError, showMcpConsentToast } from "./lib/toast";
import { ipc } from "./ipc/types"; import { ipc } from "./ipc/types";
...@@ -99,6 +100,16 @@ const posthogClient = posthog.init( ...@@ -99,6 +100,16 @@ const posthogClient = posthog.init(
); );
function App() { function App() {
const queryClient = useQueryClient();
// Fetch user budget on app load
useEffect(() => {
queryClient.prefetchQuery({
queryKey: queryKeys.userBudget.info,
queryFn: () => ipc.system.getUserBudget(),
});
}, [queryClient]);
useEffect(() => { useEffect(() => {
// Subscribe to navigation state changes // Subscribe to navigation state changes
const unsubscribe = router.subscribe("onResolved", (navigation) => { const unsubscribe = router.subscribe("onResolved", (navigation) => {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论