mirror of
https://github.com/xCyanGrizzly/DragonsStash.git
synced 2026-05-11 06:11:15 +00:00
feat: fix channel scanning bugs, add package tags, and kickstarters tab
Bug fixes: - Fix channels not being scanned by paginating TDLib getChats (was only loading first batch, additional channels were unknown to TDLib) - Add per-channel getChat pre-load as safety net before scanning - Fix preview pictures not loading by checking previewData instead of previewMsgId for hasPreview flag - Prevent previewMsgId from being set when preview download fails Package Tags: - Add tags Text[] column to Package with migration backfilling from channel categories - Worker auto-inherits source channel category as initial tag - Tag filter dropdown and Tags column in STL Files table - Server actions for individual and bulk tag editing Kickstarters Tab: - New KickstarterHost, Kickstarter, and KickstarterPackage models - Full CRUD with delivery status, payment status, host management - Package linking (many-to-many with existing packages) - Sidebar entry with Gift icon - Table with search, filters, modal forms Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
148
src/app/(app)/kickstarters/actions.ts
Normal file
148
src/app/(app)/kickstarters/actions.ts
Normal file
@@ -0,0 +1,148 @@
|
||||
"use server";
|
||||
|
||||
import { auth } from "@/lib/auth";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { kickstarterSchema, kickstarterHostSchema } from "@/schemas/kickstarter.schema";
|
||||
import { revalidatePath } from "next/cache";
|
||||
import type { ActionResult } from "@/types/api.types";
|
||||
|
||||
const REVALIDATE_PATH = "/kickstarters";
|
||||
|
||||
export async function createKickstarter(
|
||||
input: unknown
|
||||
): Promise<ActionResult<{ id: string }>> {
|
||||
const session = await auth();
|
||||
if (!session?.user?.id) return { success: false, error: "Unauthorized" };
|
||||
|
||||
const parsed = kickstarterSchema.safeParse(input);
|
||||
if (!parsed.success) return { success: false, error: "Validation failed" };
|
||||
|
||||
try {
|
||||
const ks = await prisma.kickstarter.create({
|
||||
data: {
|
||||
name: parsed.data.name,
|
||||
link: parsed.data.link || null,
|
||||
filesUrl: parsed.data.filesUrl || null,
|
||||
deliveryStatus: parsed.data.deliveryStatus,
|
||||
paymentStatus: parsed.data.paymentStatus,
|
||||
hostId: parsed.data.hostId || null,
|
||||
notes: parsed.data.notes || null,
|
||||
userId: session.user.id,
|
||||
},
|
||||
});
|
||||
revalidatePath(REVALIDATE_PATH);
|
||||
return { success: true, data: { id: ks.id } };
|
||||
} catch {
|
||||
return { success: false, error: "Failed to create kickstarter" };
|
||||
}
|
||||
}
|
||||
|
||||
export async function updateKickstarter(
|
||||
id: string,
|
||||
input: unknown
|
||||
): Promise<ActionResult> {
|
||||
const session = await auth();
|
||||
if (!session?.user?.id) return { success: false, error: "Unauthorized" };
|
||||
|
||||
const parsed = kickstarterSchema.safeParse(input);
|
||||
if (!parsed.success) return { success: false, error: "Validation failed" };
|
||||
|
||||
const existing = await prisma.kickstarter.findFirst({
|
||||
where: { id, userId: session.user.id },
|
||||
});
|
||||
if (!existing) return { success: false, error: "Not found" };
|
||||
|
||||
try {
|
||||
await prisma.kickstarter.update({
|
||||
where: { id },
|
||||
data: {
|
||||
name: parsed.data.name,
|
||||
link: parsed.data.link || null,
|
||||
filesUrl: parsed.data.filesUrl || null,
|
||||
deliveryStatus: parsed.data.deliveryStatus,
|
||||
paymentStatus: parsed.data.paymentStatus,
|
||||
hostId: parsed.data.hostId || null,
|
||||
notes: parsed.data.notes || null,
|
||||
},
|
||||
});
|
||||
revalidatePath(REVALIDATE_PATH);
|
||||
return { success: true, data: undefined };
|
||||
} catch {
|
||||
return { success: false, error: "Failed to update kickstarter" };
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteKickstarter(id: string): Promise<ActionResult> {
|
||||
const session = await auth();
|
||||
if (!session?.user?.id) return { success: false, error: "Unauthorized" };
|
||||
|
||||
const existing = await prisma.kickstarter.findFirst({
|
||||
where: { id, userId: session.user.id },
|
||||
});
|
||||
if (!existing) return { success: false, error: "Not found" };
|
||||
|
||||
try {
|
||||
await prisma.kickstarter.delete({ where: { id } });
|
||||
revalidatePath(REVALIDATE_PATH);
|
||||
return { success: true, data: undefined };
|
||||
} catch {
|
||||
return { success: false, error: "Failed to delete kickstarter" };
|
||||
}
|
||||
}
|
||||
|
||||
export async function createHost(
|
||||
input: unknown
|
||||
): Promise<ActionResult<{ id: string; name: string }>> {
|
||||
const session = await auth();
|
||||
if (!session?.user?.id) return { success: false, error: "Unauthorized" };
|
||||
|
||||
const parsed = kickstarterHostSchema.safeParse(input);
|
||||
if (!parsed.success) return { success: false, error: "Validation failed" };
|
||||
|
||||
try {
|
||||
const host = await prisma.kickstarterHost.create({
|
||||
data: { name: parsed.data.name },
|
||||
});
|
||||
revalidatePath(REVALIDATE_PATH);
|
||||
return { success: true, data: { id: host.id, name: host.name } };
|
||||
} catch (err: unknown) {
|
||||
if (
|
||||
err instanceof Error &&
|
||||
err.message.includes("Unique constraint")
|
||||
) {
|
||||
return { success: false, error: "A host with that name already exists" };
|
||||
}
|
||||
return { success: false, error: "Failed to create host" };
|
||||
}
|
||||
}
|
||||
|
||||
export async function linkPackages(
|
||||
kickstarterId: string,
|
||||
packageIds: string[]
|
||||
): Promise<ActionResult> {
|
||||
const session = await auth();
|
||||
if (!session?.user?.id) return { success: false, error: "Unauthorized" };
|
||||
|
||||
const existing = await prisma.kickstarter.findFirst({
|
||||
where: { id: kickstarterId, userId: session.user.id },
|
||||
});
|
||||
if (!existing) return { success: false, error: "Not found" };
|
||||
|
||||
try {
|
||||
// Replace all linked packages
|
||||
await prisma.$transaction([
|
||||
prisma.kickstarterPackage.deleteMany({
|
||||
where: { kickstarterId },
|
||||
}),
|
||||
...packageIds.map((packageId) =>
|
||||
prisma.kickstarterPackage.create({
|
||||
data: { kickstarterId, packageId },
|
||||
})
|
||||
),
|
||||
]);
|
||||
revalidatePath(REVALIDATE_PATH);
|
||||
return { success: true, data: undefined };
|
||||
} catch {
|
||||
return { success: false, error: "Failed to link packages" };
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user