Organize/lib/actions/projects.ts

79 lines
2.6 KiB
TypeScript

"use server";
import { revalidatePath } from "next/cache";
import { prisma } from "@/lib/db";
import { requireUserId } from "@/lib/auth-helpers";
import { projectAccessFilter } from "@/lib/access";
import { ProjectTitleSchema, ProjectThemeSchema } from "@/lib/validation/project";
import type { ProjectDTO } from "@/types/project";
export async function createProject(title: string): Promise<ProjectDTO> {
const userId = await requireUserId();
const parsedTitle = ProjectTitleSchema.parse(title);
const project = await prisma.project.create({
data: { title: parsedTitle, ownerId: userId },
});
revalidatePath("/projects");
return { id: project.id, title: project.title, theme: null };
}
/**
* Assigns a theme to a project (or clears it back to "Default Theme" with
* null, which follows the user's global theme preference). Only the
* project's own page is themed -- see components/theme/project-theme-scope.tsx.
*/
export async function setProjectTheme(
projectId: string,
theme: string | null
): Promise<void> {
const userId = await requireUserId();
const parsed = ProjectThemeSchema.parse(theme);
const { count } = await prisma.project.updateMany({
where: { id: projectId, ...projectAccessFilter(userId) },
data: { theme: parsed },
});
if (count === 0) throw new Error("Project not found");
revalidatePath("/projects");
revalidatePath(`/projects/${projectId}`);
}
export async function renameProject(projectId: string, title: string): Promise<void> {
const userId = await requireUserId();
const parsedTitle = ProjectTitleSchema.parse(title);
const { count } = await prisma.project.updateMany({
where: { id: projectId, ...projectAccessFilter(userId) },
data: { title: parsedTitle },
});
if (count === 0) throw new Error("Project not found");
revalidatePath("/projects");
revalidatePath(`/projects/${projectId}`);
}
export type DeleteProjectResult = { error?: string };
/**
* Deletes a project and everything in it -- its categories, groups, and
* to-dos all cascade away with it (unlike deleting a single Category,
* which refuses if it still has groups). The confirmation dialog on the
* client carries the "this can't be undone" warning; this action doesn't
* re-check emptiness.
*/
export async function deleteProject(projectId: string): Promise<DeleteProjectResult> {
const userId = await requireUserId();
const { count } = await prisma.project.deleteMany({
where: { id: projectId, ...projectAccessFilter(userId) },
});
if (count === 0) return { error: "Project not found." };
revalidatePath("/projects");
return {};
}