feat: enhance dashboard and canvas components with credit management features

- Integrated CreditOverview and RecentTransactions components into the dashboard for better credit visibility.
- Updated canvas toolbar to display current credit balance using CreditDisplay.
- Improved AI image and prompt nodes to show credit costs and handle credit availability checks during image generation.
- Added new queries for fetching recent transactions and monthly usage statistics to support dashboard features.
- Refactored existing code to streamline credit-related functionalities across components.
This commit is contained in:
2026-03-26 22:15:03 +01:00
parent 886a530f26
commit 8d62ee27a2
12 changed files with 796 additions and 297 deletions

View File

@@ -85,17 +85,30 @@ export const listTransactions = query({
});
/**
* Aktuelle Subscription des Users abrufen.
* Aktuelle Subscription des Users abrufen (kompakt, immer definiert für die UI).
*/
export const getSubscription = query({
args: {},
handler: async (ctx) => {
const user = await requireAuth(ctx);
return await ctx.db
const row = await ctx.db
.query("subscriptions")
.withIndex("by_user", (q) => q.eq("userId", user.userId))
.order("desc")
.first();
if (!row) {
return {
tier: "free" as const,
status: "active" as const,
};
}
return {
tier: row.tier,
status: row.status,
currentPeriodEnd: row.currentPeriodEnd,
};
},
});
@@ -119,6 +132,61 @@ export const getDailyUsage = query({
},
});
/**
* Neueste Transaktionen des Users abrufen (für Dashboard "Recent Activity").
* Ähnlich wie listTransactions, aber als dedizierter Query mit explizitem Limit.
*/
export const getRecentTransactions = query({
args: {
limit: v.optional(v.number()),
},
handler: async (ctx, args) => {
const user = await requireAuth(ctx);
const limit = args.limit ?? 10;
return await ctx.db
.query("creditTransactions")
.withIndex("by_user", (q) => q.eq("userId", user.userId))
.order("desc")
.take(limit);
},
});
/**
* Monatliche Credit-Statistiken des Users abrufen (für Dashboard Verbrauchsbalken).
* Berechnet: monatlicher Verbrauch (nur committed usage-Transaktionen) + Anzahl Generierungen.
*/
export const getUsageStats = query({
args: {},
handler: async (ctx) => {
const user = await requireAuth(ctx);
const now = new Date();
const monthStart = new Date(now.getFullYear(), now.getMonth(), 1).getTime();
const transactions = await ctx.db
.query("creditTransactions")
.withIndex("by_user", (q) => q.eq("userId", user.userId))
.order("desc")
.collect();
const monthlyTransactions = transactions.filter(
(t) =>
t._creationTime >= monthStart &&
t.status === "committed" &&
t.type === "usage"
);
return {
monthlyUsage: monthlyTransactions.reduce(
(sum, t) => sum + Math.abs(t.amount),
0
),
totalGenerations: monthlyTransactions.length,
};
},
});
// ============================================================================
// Mutations — Credit Balance Management
// ============================================================================
@@ -171,6 +239,49 @@ export const initBalance = mutation({
},
});
/**
* Nur Testphase: schreibt dem eingeloggten User Gutschrift gut.
* In Produktion deaktiviert, außer ALLOW_TEST_CREDIT_GRANT ist in Convex auf "true" gesetzt.
*/
export const grantTestCredits = mutation({
args: {
amount: v.optional(v.number()),
},
handler: async (ctx, { amount = 2000 }) => {
if (process.env.ALLOW_TEST_CREDIT_GRANT !== "true") {
throw new Error("Test-Gutschriften sind deaktiviert (ALLOW_TEST_CREDIT_GRANT).");
}
if (amount <= 0 || amount > 1_000_000) {
throw new Error("Ungültiger Betrag.");
}
const user = await requireAuth(ctx);
const balance = await ctx.db
.query("creditBalances")
.withIndex("by_user", (q) => q.eq("userId", user.userId))
.unique();
if (!balance) {
throw new Error("Keine Credit-Balance — zuerst einloggen / initBalance.");
}
const next = balance.balance + amount;
await ctx.db.patch(balance._id, {
balance: next,
updatedAt: Date.now(),
});
await ctx.db.insert("creditTransactions", {
userId: user.userId,
amount,
type: "subscription",
status: "committed",
description: `Testphase — Gutschrift (${amount} Cr)`,
});
return { newBalance: next };
},
});
// ============================================================================
// Mutations — Reservation + Commit (Kern des Credit-Systems)
// ============================================================================