52 lines
1.6 KiB
TypeScript
52 lines
1.6 KiB
TypeScript
|
|
"use server";
|
||
|
|
|
||
|
|
import { revalidatePath } from "next/cache";
|
||
|
|
import { z } from "zod";
|
||
|
|
import { getServerSession } from "@/lib/auth/guards";
|
||
|
|
import { prisma } from "@/lib/db";
|
||
|
|
|
||
|
|
const brandingSchema = z.object({
|
||
|
|
brandName: z.string().max(60).optional(),
|
||
|
|
primaryColor: z
|
||
|
|
.string()
|
||
|
|
.regex(/^#([0-9a-fA-F]{6})$/, "Use a hex colour like #7c3aed")
|
||
|
|
.optional()
|
||
|
|
.or(z.literal("")),
|
||
|
|
logoUrl: z.string().url().optional().or(z.literal("")),
|
||
|
|
removePoweredBy: z.boolean().optional(),
|
||
|
|
});
|
||
|
|
|
||
|
|
export async function saveBrandingAction(
|
||
|
|
organizationId: string,
|
||
|
|
data: z.infer<typeof brandingSchema>
|
||
|
|
): Promise<{ ok: boolean; error?: string }> {
|
||
|
|
const session = await getServerSession();
|
||
|
|
if (!session) return { ok: false, error: "You must be signed in." };
|
||
|
|
|
||
|
|
const member = await prisma.member.findFirst({
|
||
|
|
where: { organizationId, userId: session.user.id },
|
||
|
|
select: { role: true },
|
||
|
|
});
|
||
|
|
if (!member || !["owner", "admin"].includes(member.role)) {
|
||
|
|
return { ok: false, error: "Only workspace owners can edit branding." };
|
||
|
|
}
|
||
|
|
|
||
|
|
const parsed = brandingSchema.safeParse(data);
|
||
|
|
if (!parsed.success) return { ok: false, error: parsed.error.issues[0]?.message ?? "Invalid input." };
|
||
|
|
|
||
|
|
const payload = {
|
||
|
|
brandName: parsed.data.brandName || null,
|
||
|
|
primaryColor: parsed.data.primaryColor || null,
|
||
|
|
logoUrl: parsed.data.logoUrl || null,
|
||
|
|
removePoweredBy: parsed.data.removePoweredBy ?? false,
|
||
|
|
};
|
||
|
|
|
||
|
|
await prisma.orgBranding.upsert({
|
||
|
|
where: { organizationId },
|
||
|
|
create: { organizationId, ...payload },
|
||
|
|
update: payload,
|
||
|
|
});
|
||
|
|
revalidatePath("/team");
|
||
|
|
return { ok: true };
|
||
|
|
}
|