From 3474297e6976bffe5e5d385602517f9c1f348bc3 Mon Sep 17 00:00:00 2001 From: Matthias Meister Date: Fri, 3 Apr 2026 15:47:34 +0200 Subject: [PATCH] Refactor user initialization and balance retrieval logic - Updated the `InitUser` component to handle session state more effectively by incorporating a loading state. - Removed the unused `useAuthQuery` hook and adjusted the balance initialization logic to only proceed when the session is confirmed. - Enhanced the `getBalance` query with improved error handling and logging for better debugging. - Modified the `initBalance` mutation to return an object indicating whether a new balance was created, improving clarity in the initialization process. --- components/init-user.tsx | 19 ++++------- convex/credits.ts | 69 +++++++++++++++++++++++++++++----------- 2 files changed, 57 insertions(+), 31 deletions(-) diff --git a/components/init-user.tsx b/components/init-user.tsx index 7cfe09b..bc418a1 100644 --- a/components/init-user.tsx +++ b/components/init-user.tsx @@ -2,7 +2,6 @@ import { authClient } from "@/lib/auth-client"; import { useMutation } from "convex/react"; -import { useAuthQuery } from "@/hooks/use-auth-query"; import { api } from "@/convex/_generated/api"; import { useEffect, useRef } from "react"; import { useTranslations } from "next-intl"; @@ -15,32 +14,28 @@ import { toast } from "@/lib/toast"; */ export function InitUser() { const t = useTranslations('toasts'); - const { data: session } = authClient.useSession(); + const { data: session, isPending: isSessionPending } = authClient.useSession(); - const balance = useAuthQuery(api.credits.getBalance); const initBalance = useMutation(api.credits.initBalance); const initStartedRef = useRef(false); useEffect(() => { - if ( - !session?.user || - !balance || - balance.balance !== 0 || - balance.monthlyAllocation !== 0 - ) { + if (isSessionPending || !session?.user) { return; } if (initStartedRef.current) return; initStartedRef.current = true; void initBalance() - .then(() => { - toast.success(t('auth.initialSetupTitle'), t('auth.initialSetupDesc')); + .then((result) => { + if (result.created) { + toast.success(t('auth.initialSetupTitle'), t('auth.initialSetupDesc')); + } }) .catch(() => { initStartedRef.current = false; }); - }, [t, session?.user, balance, initBalance]); + }, [t, initBalance, isSessionPending, session?.user]); return null; } diff --git a/convex/credits.ts b/convex/credits.ts index 004f4a1..0f40633 100644 --- a/convex/credits.ts +++ b/convex/credits.ts @@ -60,25 +60,54 @@ const PERFORMANCE_LOG_THRESHOLD_MS = 250; export const getBalance = query({ args: {}, handler: async (ctx) => { - const user = await optionalAuth(ctx); - if (!user) { - return { balance: 0, reserved: 0, available: 0, monthlyAllocation: 0 }; - } - const balance = await ctx.db - .query("creditBalances") - .withIndex("by_user", (q) => q.eq("userId", user.userId)) - .unique(); + const startedAt = Date.now(); - if (!balance) { - return { balance: 0, reserved: 0, available: 0, monthlyAllocation: 0 }; - } + try { + console.info("[credits.getBalance] start", { + durationMs: Date.now() - startedAt, + }); - return { - balance: balance.balance, - reserved: balance.reserved, - available: balance.balance - balance.reserved, - monthlyAllocation: balance.monthlyAllocation, - }; + const user = await optionalAuth(ctx); + console.info("[credits.getBalance] auth resolved", { + durationMs: Date.now() - startedAt, + userId: user?.userId ?? null, + }); + + if (!user) { + return { balance: 0, reserved: 0, available: 0, monthlyAllocation: 0 }; + } + const balance = await ctx.db + .query("creditBalances") + .withIndex("by_user", (q) => q.eq("userId", user.userId)) + .unique(); + + console.info("[credits.getBalance] balance query resolved", { + durationMs: Date.now() - startedAt, + userId: user.userId, + foundBalance: Boolean(balance), + }); + + if (!balance) { + return { balance: 0, reserved: 0, available: 0, monthlyAllocation: 0 }; + } + + return { + balance: balance.balance, + reserved: balance.reserved, + available: balance.balance - balance.reserved, + monthlyAllocation: balance.monthlyAllocation, + }; + } catch (error) { + const identity = await ctx.auth.getUserIdentity(); + console.error("[credits.getBalance] failed", { + durationMs: Date.now() - startedAt, + hasIdentity: Boolean(identity), + identityIssuer: identity?.issuer ?? null, + identitySubject: identity?.subject ?? null, + message: error instanceof Error ? error.message : String(error), + }); + throw error; + } }, }); @@ -295,7 +324,9 @@ export const initBalance = mutation({ .withIndex("by_user", (q) => q.eq("userId", user.userId)) .unique(); - if (existing) return existing._id; + if (existing) { + return { balanceId: existing._id, created: false }; + } // Free-Tier Credits als Startguthaben const balanceId = await ctx.db.insert("creditBalances", { @@ -324,7 +355,7 @@ export const initBalance = mutation({ description: "Startguthaben — Free Tier", }); - return balanceId; + return { balanceId, created: true }; }, });