Initial Commit

This commit is contained in:
Ahmad 2024-02-14 21:30:10 -05:00
commit f3e2f01bd7
No known key found for this signature in database
GPG key ID: 8FD8A93530D182BF
150 changed files with 13612 additions and 0 deletions

View file

@ -0,0 +1,69 @@
"use server";
import { auth } from "@clerk/nextjs";
import { revalidatePath } from "next/cache";
import { ACTION, ENTITY_TYPE } from "@prisma/client";
import { db } from "@/lib/db";
import { createAuditLog } from "@/lib/create-audit-log";
import { createSafeAction } from "@/lib/create-safe-action";
import { InputType, ReturnType } from "./types";
import { CopyCard } from "./schema";
const handler = async (data: InputType): Promise<ReturnType> => {
const { userId, orgId } = auth();
if (!userId || !orgId) return { error: "Unauthorized" };
const { id, boardId } = data;
let card;
try {
const cardToCopy = await db.card.findUnique({
where: {
id,
list: {
board: {
orgId,
},
},
},
});
if (!cardToCopy) return { error: "Card not found" };
const lastCard = await db.card.findFirst({
where: { listId: cardToCopy.listId },
orderBy: { order: "desc" },
select: { order: true },
});
const newOrder = lastCard ? lastCard.order + 1 : 1;
card = await db.card.create({
data: {
title: `${cardToCopy.title} - Copy`,
description: cardToCopy.description,
order: newOrder,
listId: cardToCopy.listId,
}
})
await createAuditLog({
entityTitle: card.title,
entityType: ENTITY_TYPE.CARD,
entityId: card.id,
action: ACTION.CREATE,
});
} catch (error) {
return {
error: "Failed to copy card",
};
}
revalidatePath(`/board/${boardId}`);
return { data: card };
};
export const copyCard = createSafeAction(CopyCard, handler);

View file

@ -0,0 +1,6 @@
import { z } from "zod";
export const CopyCard = z.object({
id: z.string(),
boardId: z.string(),
});

View file

@ -0,0 +1,9 @@
import { z } from "zod";
import { Card } from "@prisma/client";
import { ActionState } from "@/lib/create-safe-action";
import { CopyCard } from "./schema";
export type InputType = z.infer<typeof CopyCard>;
export type ReturnType = ActionState<InputType, Card>;

View file

@ -0,0 +1,82 @@
"use server";
import { auth } from "@clerk/nextjs";
import { revalidatePath } from "next/cache";
import { ACTION, ENTITY_TYPE } from "@prisma/client";
import { db } from "@/lib/db";
import { createAuditLog } from "@/lib/create-audit-log";
import { createSafeAction } from "@/lib/create-safe-action";
import { InputType, ReturnType } from "./types";
import { CopyList } from "./schema";
const handler = async (data: InputType): Promise<ReturnType> => {
const { userId, orgId } = auth();
if (!userId || !orgId) return { error: "Unauthorized" };
const { id, boardId } = data;
let list;
try {
const listToCopy = await db.list.findUnique({
where: {
id,
boardId,
board: {
orgId,
},
},
include: {
cards: true,
},
});
if (!listToCopy) return { error: "List not found" };
const lastList = await db.list.findFirst({
where: { boardId },
orderBy: { order: "desc" },
select: { order: true },
});
const newOrder = lastList ? lastList.order + 1 : 1;
list = await db.list.create({
data: {
boardId: listToCopy.boardId,
title: `${listToCopy.title} - Copy`,
order: newOrder,
cards: {
createMany: {
data: listToCopy.cards.map((card) => ({
title: card.title,
description: card.description,
order: card.order,
})),
},
},
},
include: {
cards: true,
},
});
await createAuditLog({
entityTitle: list.title,
entityType: ENTITY_TYPE.LIST,
entityId: list.id,
action: ACTION.CREATE,
});
} catch (error) {
return {
error: "Failed to copy list",
};
}
revalidatePath(`/board/${boardId}`);
return { data: list };
};
export const copyList = createSafeAction(CopyList, handler);

View file

@ -0,0 +1,6 @@
import { z } from "zod";
export const CopyList = z.object({
id: z.string(),
boardId: z.string(),
})

View file

@ -0,0 +1,9 @@
import { z } from "zod";
import { List } from "@prisma/client";
import { ActionState } from "@/lib/create-safe-action";
import { CopyList } from "./schema";
export type InputType = z.infer<typeof CopyList>;
export type ReturnType = ActionState<InputType, List>;

View file

@ -0,0 +1,87 @@
"use server";
import { auth } from "@clerk/nextjs";
import { revalidatePath } from "next/cache";
import { db } from "@/lib/db";
import { createSafeAction } from "@/lib/create-safe-action";
import { InputType, ReturnType } from "./types";
import { CreateBoard } from "./schema";
import { createAuditLog } from "@/lib/create-audit-log";
import { ACTION, ENTITY_TYPE } from "@prisma/client";
import { incrementAvailableCount, hasAvailableCount } from "@/lib/org-limit";
import { checkSubscription } from "@/lib/subscription";
const handler = async (data: InputType): Promise<ReturnType> => {
const { userId, orgId } = auth();
if (!userId || !orgId) {
return {
error: "Unauthorized",
};
}
const canCreate = await hasAvailableCount();
const isPro = await checkSubscription();
if (!canCreate && !isPro) {
return {
error:
"You have reached your limit of free boards. Please upgrade to create more.",
};
}
const { title, image } = data;
const [imageId, imageThumbUrl, imageFullUrl, imageLinkHTML, imageUserName] =
image.split("|");
if (
!imageId ||
!imageThumbUrl ||
!imageFullUrl ||
!imageUserName ||
!imageLinkHTML
) {
return {
error: "Missing fields. Failed to create board.",
};
}
let board;
try {
board = await db.board.create({
data: {
title,
orgId,
imageId,
imageThumbUrl,
imageFullUrl,
imageUserName,
imageLinkHTML,
},
});
if (!isPro) {
await incrementAvailableCount();
}
await createAuditLog({
entityTitle: board.title,
entityId: board.id,
entityType: ENTITY_TYPE.BOARD,
action: ACTION.CREATE,
});
} catch (error) {
return {
error: "Failed to create board",
};
}
revalidatePath(`/board/${board.id}`);
return { data: board };
};
export const createBoard = createSafeAction(CreateBoard, handler);

View file

@ -0,0 +1,14 @@
import { z } from "zod";
export const CreateBoard = z.object({
title: z.string({
required_error: "Title is required",
invalid_type_error: "Title must be a string",
}).min(3, {
message: "Title must be at least 3 characters",
}),
image: z.string({
required_error: "Image is required",
invalid_type_error: "Image must be a string",
})
});

View file

@ -0,0 +1,8 @@
import { z } from "zod";
import { Board } from "@prisma/client";
import { ActionState } from "@/lib/create-safe-action";
import { CreateBoard } from "./schema";
export type InputType = z.infer<typeof CreateBoard>;
export type ReturnType = ActionState<InputType, Board>;

View file

@ -0,0 +1,66 @@
"use server";
import { auth } from "@clerk/nextjs";
import { revalidatePath } from "next/cache";
import { ACTION, ENTITY_TYPE } from "@prisma/client";
import { db } from "@/lib/db";
import { createAuditLog } from "@/lib/create-audit-log";
import { createSafeAction } from "@/lib/create-safe-action";
import { InputType, ReturnType } from "./types";
import { CreateCard } from "./schema";
const handler = async (data: InputType): Promise<ReturnType> => {
const { userId, orgId } = auth();
if (!userId || !orgId) return { error: "Unauthorized" };
const { title, boardId, listId } = data;
let card;
try {
const list = await db.list.findUnique({
where: {
id: listId,
board: {
orgId,
},
},
});
if (!list) return { error: "List not found" };
const lastCard = await db.card.findFirst({
where: { listId },
orderBy: { order: "desc" },
select: { order: true },
});
const newOrder = lastCard ? lastCard.order + 1 : 1;
card = await db.card.create({
data: {
title,
listId,
order: newOrder,
},
});
await createAuditLog({
entityId: card.id,
entityTitle: card.title,
entityType: ENTITY_TYPE.CARD,
action: ACTION.CREATE,
});
} catch (error) {
return {
error: "Failed to create card",
};
}
revalidatePath(`/board/${boardId}`);
return { data: card };
};
export const createCard = createSafeAction(CreateCard, handler);

View file

@ -0,0 +1,12 @@
import { z } from "zod";
export const CreateCard = z.object({
title: z.string({
required_error: "Card title is required",
invalid_type_error: "Card title must be a string",
}).min(2, {
message: "Card title must be at least 2 characters",
}),
boardId: z.string(),
listId: z.string(),
})

View file

@ -0,0 +1,9 @@
import { z } from "zod";
import { Card } from "@prisma/client";
import { ActionState } from "@/lib/create-safe-action";
import { CreateCard } from "./schema";
export type InputType = z.infer<typeof CreateCard>;
export type ReturnType = ActionState<InputType, Card>;

View file

@ -0,0 +1,64 @@
"use server";
import { auth } from "@clerk/nextjs";
import { revalidatePath } from "next/cache";
import { ACTION, ENTITY_TYPE } from "@prisma/client";
import { db } from "@/lib/db";
import { createAuditLog } from "@/lib/create-audit-log";
import { createSafeAction } from "@/lib/create-safe-action";
import { InputType, ReturnType } from "./types";
import { CreateList } from "./schema";
const handler = async (data: InputType): Promise<ReturnType> => {
const { userId, orgId } = auth();
if (!userId || !orgId) return { error: "Unauthorized" };
const { title, boardId } = data;
let list;
try {
const board = await db.board.findUnique({
where: {
id: boardId,
orgId,
},
});
if (!board) return { error: "Board not found" };
const lastList = await db.list.findFirst({
where: { boardId: boardId },
orderBy: { order: "desc" },
select: { order: true },
});
const newOrder = lastList ? lastList.order + 1 : 1;
list = await db.list.create({
data: {
title,
boardId,
order: newOrder,
},
});
await createAuditLog({
entityTitle: list.title,
entityType: ENTITY_TYPE.LIST,
entityId: list.id,
action: ACTION.CREATE,
});
} catch (error) {
return {
error: "Failed to create list",
};
}
revalidatePath(`/board/${boardId}`);
return { data: list };
};
export const createList = createSafeAction(CreateList, handler);

View file

@ -0,0 +1,11 @@
import { z } from "zod";
export const CreateList = z.object({
title: z.string({
required_error: "List title is required",
invalid_type_error: "List title must be a string",
}).min(2, {
message: "List title must be at least 2 characters",
}),
boardId: z.string(),
})

View file

@ -0,0 +1,9 @@
import { z } from "zod";
import { List } from "@prisma/client";
import { ActionState } from "@/lib/create-safe-action";
import { CreateList } from "./schema";
export type InputType = z.infer<typeof CreateList>;
export type ReturnType = ActionState<InputType, List>;

View file

@ -0,0 +1,55 @@
"use server";
import { auth } from "@clerk/nextjs";
import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";
import { ACTION, ENTITY_TYPE } from "@prisma/client";
import { db } from "@/lib/db";
import { createAuditLog } from "@/lib/create-audit-log";
import { createSafeAction } from "@/lib/create-safe-action";
import { decreaseAvailableCount } from "@/lib/org-limit";
import { checkSubscription } from "@/lib/subscription";
import { InputType, ReturnType } from "./types";
import { DeleteBoard } from "./schema";
const handler = async (data: InputType): Promise<ReturnType> => {
const { userId, orgId } = auth();
if (!userId || !orgId) return { error: "Unauthorized" };
const isPro = await checkSubscription();
const { id } = data;
let board;
try {
board = await db.board.delete({
where: {
id,
orgId,
},
});
if (!isPro) {
await decreaseAvailableCount();
}
await createAuditLog({
entityTitle: board.title,
entityType: ENTITY_TYPE.BOARD,
entityId: board.id,
action: ACTION.DELETE,
});
} catch (error) {
return {
error: "Failed to delete board",
};
}
revalidatePath(`/organization/${orgId}`);
redirect(`/organization/${orgId}`);
};
export const deleteBoard = createSafeAction(DeleteBoard, handler);

View file

@ -0,0 +1,5 @@
import { z } from "zod";
export const DeleteBoard = z.object({
id: z.string(),
})

View file

@ -0,0 +1,9 @@
import { z } from "zod";
import { Board } from "@prisma/client";
import { ActionState } from "@/lib/create-safe-action";
import { DeleteBoard } from "./schema";
export type InputType = z.infer<typeof DeleteBoard>;
export type ReturnType = ActionState<InputType, Board>;

View file

@ -0,0 +1,50 @@
"use server";
import { auth } from "@clerk/nextjs";
import { revalidatePath } from "next/cache";
import { ACTION, ENTITY_TYPE } from "@prisma/client";
import { db } from "@/lib/db";
import { createAuditLog } from "@/lib/create-audit-log";
import { createSafeAction } from "@/lib/create-safe-action";
import { InputType, ReturnType } from "./types";
import { DeleteCard } from "./schema";
const handler = async (data: InputType): Promise<ReturnType> => {
const { userId, orgId } = auth();
if (!userId || !orgId) return { error: "Unauthorized" };
const { id, boardId } = data;
let card;
try {
card = await db.card.delete({
where: {
id,
list: {
board: {
orgId,
},
},
},
});
await createAuditLog({
entityTitle: card.title,
entityType: ENTITY_TYPE.CARD,
entityId: card.id,
action: ACTION.DELETE,
});
} catch (error) {
return {
error: "Failed to delete card",
};
}
revalidatePath(`/board/${boardId}`);
return { data: card };
};
export const deleteCard = createSafeAction(DeleteCard, handler);

View file

@ -0,0 +1,6 @@
import { z } from "zod";
export const DeleteCard = z.object({
id: z.string(),
boardId: z.string(),
});

View file

@ -0,0 +1,9 @@
import { z } from "zod";
import { Card } from "@prisma/client";
import { ActionState } from "@/lib/create-safe-action";
import { DeleteCard } from "./schema";
export type InputType = z.infer<typeof DeleteCard>;
export type ReturnType = ActionState<InputType, Card>;

View file

@ -0,0 +1,49 @@
"use server";
import { auth } from "@clerk/nextjs";
import { revalidatePath } from "next/cache";
import { ACTION, ENTITY_TYPE } from "@prisma/client";
import { db } from "@/lib/db";
import { createAuditLog } from "@/lib/create-audit-log";
import { createSafeAction } from "@/lib/create-safe-action";
import { InputType, ReturnType } from "./types";
import { DeleteList } from "./schema";
const handler = async (data: InputType): Promise<ReturnType> => {
const { userId, orgId } = auth();
if (!userId || !orgId) return { error: "Unauthorized" };
const { id, boardId } = data;
let list;
try {
list = await db.list.delete({
where: {
id,
boardId,
board: {
orgId,
},
},
});
await createAuditLog({
entityTitle: list.title,
entityType: ENTITY_TYPE.LIST,
entityId: list.id,
action: ACTION.DELETE,
});
} catch (error) {
return {
error: "Failed to delete list",
};
}
revalidatePath(`/board/${boardId}`);
return { data: list };
};
export const deleteList = createSafeAction(DeleteList, handler);

View file

@ -0,0 +1,6 @@
import { z } from "zod";
export const DeleteList = z.object({
id: z.string(),
boardId: z.string(),
})

View file

@ -0,0 +1,9 @@
import { z } from "zod";
import { List } from "@prisma/client";
import { ActionState } from "@/lib/create-safe-action";
import { DeleteList } from "./schema";
export type InputType = z.infer<typeof DeleteList>;
export type ReturnType = ActionState<InputType, List>;

View file

@ -0,0 +1,75 @@
"use server";
import { auth, currentUser } from "@clerk/nextjs";
import { revalidatePath } from "next/cache";
import { db } from "@/lib/db";
import { createSafeAction } from "@/lib/create-safe-action";
import { absoluteUrl } from "@/lib/utils";
import { stripe } from "@/lib/stripe";
import { InputType, ReturnType } from "./types";
import { StripeRedirect } from "./schema";
const handler = async (data: InputType): Promise<ReturnType> => {
const { userId, orgId } = auth();
const user = await currentUser();
if (!userId || !orgId || !user) return { error: "Unauthorized" };
const settingsUrl = absoluteUrl(`/organization/${orgId}`);
let url = "";
try {
const orgSubscription = await db.orgSubscription.findUnique({
where: { orgId },
});
if (orgSubscription?.stripeCustomerId) {
const stripeSession = await stripe.billingPortal.sessions.create({
customer: orgSubscription.stripeCustomerId,
return_url: settingsUrl,
});
url = stripeSession.url;
} else {
const stripeSession = await stripe.checkout.sessions.create({
success_url: settingsUrl,
cancel_url: settingsUrl,
payment_method_types: ["card", "paypal"],
mode: "subscription",
billing_address_collection: "auto",
customer_email: user.emailAddresses[0].emailAddress,
line_items: [
{
price_data: {
currency: "usd",
product_data: {
name: "Tasko Pro",
description: "Unlimited boards for your organization",
},
unit_amount: 2000,
recurring: { interval: "month" },
},
quantity: 1,
},
],
metadata: {
orgId,
},
});
url = stripeSession.url ?? "";
}
} catch (error) {
return {
error: "Something went wrong",
};
}
revalidatePath(`/organization/${orgId}`);
return { data: url };
};
export const stripeRedirect = createSafeAction(StripeRedirect, handler);

View file

@ -0,0 +1,3 @@
import { z } from "zod";
export const StripeRedirect = z.object({});

View file

@ -0,0 +1,8 @@
import { z } from "zod";
import { ActionState } from "@/lib/create-safe-action";
import { StripeRedirect } from "./schema";
export type InputType = z.infer<typeof StripeRedirect>;
export type ReturnType = ActionState<InputType, string>;

View file

@ -0,0 +1,49 @@
"use server";
import { auth } from "@clerk/nextjs";
import { revalidatePath } from "next/cache";
import { ACTION, ENTITY_TYPE } from "@prisma/client";
import { db } from "@/lib/db";
import { createAuditLog } from "@/lib/create-audit-log";
import { createSafeAction } from "@/lib/create-safe-action";
import { InputType, ReturnType } from "./types";
import { UpdateBoard } from "./schema";
const handler = async (data: InputType): Promise<ReturnType> => {
const { userId, orgId } = auth();
if (!userId || !orgId) return { error: "Unauthorized" };
const { title, id } = data;
let board;
try {
board = await db.board.update({
where: {
id,
orgId,
},
data: {
title,
},
});
await createAuditLog({
entityTitle: board.title,
entityType: ENTITY_TYPE.BOARD,
entityId: board.id,
action: ACTION.UPDATE,
});
} catch (error) {
return {
error: "Failed to update board",
};
}
revalidatePath(`/board/${id}`);
return { data: board };
};
export const updateBoard = createSafeAction(UpdateBoard, handler);

View file

@ -0,0 +1,11 @@
import { z } from "zod";
export const UpdateBoard = z.object({
title: z.string({
required_error: "Title is required",
invalid_type_error: "Title must be a string",
}).min(3, {
message: "Title must be at least 3 characters",
}),
id: z.string(),
})

View file

@ -0,0 +1,9 @@
import { z } from "zod";
import { Board } from "@prisma/client";
import { ActionState } from "@/lib/create-safe-action";
import { UpdateBoard } from "./schema";
export type InputType = z.infer<typeof UpdateBoard>;
export type ReturnType = ActionState<InputType, Board>;

View file

@ -0,0 +1,49 @@
"use server";
import { auth } from "@clerk/nextjs";
import { revalidatePath } from "next/cache";
import { db } from "@/lib/db";
import { createSafeAction } from "@/lib/create-safe-action";
import { InputType, ReturnType } from "./types";
import { UpdateCardOrder } from "./schema";
const handler = async (data: InputType): Promise<ReturnType> => {
const { userId, orgId } = auth();
if (!userId || !orgId) return { error: "Unauthorized" };
const { items, boardId } = data;
let updatedCards;
try {
const transaction = items.map((card) =>
db.card.update({
where: {
id: card.id,
list: {
board: {
orgId,
},
},
},
data: {
order: card.order,
listId: card.listId,
},
})
);
updatedCards = await db.$transaction(transaction);
} catch (error) {
return {
error: "Failed to reorder list",
};
}
revalidatePath(`/board/${boardId}`);
return { data: updatedCards };
};
export const updateCardOrder = createSafeAction(UpdateCardOrder, handler);

View file

@ -0,0 +1,15 @@
import { z } from "zod";
export const UpdateCardOrder = z.object({
items: z.array(
z.object({
id: z.string(),
title: z.string(),
order: z.number(),
listId: z.string(),
createdAt: z.date(),
updatedAt: z.date(),
})
),
boardId: z.string(),
});

View file

@ -0,0 +1,9 @@
import { z } from "zod";
import { Card } from "@prisma/client";
import { ActionState } from "@/lib/create-safe-action";
import { UpdateCardOrder } from "./schema";
export type InputType = z.infer<typeof UpdateCardOrder>;
export type ReturnType = ActionState<InputType, Card[]>;

View file

@ -0,0 +1,53 @@
"use server";
import { auth } from "@clerk/nextjs";
import { revalidatePath } from "next/cache";
import { ACTION, ENTITY_TYPE } from "@prisma/client";
import { db } from "@/lib/db";
import { createAuditLog } from "@/lib/create-audit-log";
import { createSafeAction } from "@/lib/create-safe-action";
import { InputType, ReturnType } from "./types";
import { UpdateCard } from "./schema";
const handler = async (data: InputType): Promise<ReturnType> => {
const { userId, orgId } = auth();
if (!userId || !orgId) return { error: "Unauthorized" };
const { id, boardId, ...values } = data;
let card;
try {
card = await db.card.update({
where: {
id,
list: {
board: {
orgId,
},
},
},
data: {
...values,
},
});
await createAuditLog({
entityTitle: card.title,
entityType: ENTITY_TYPE.CARD,
entityId: card.id,
action: ACTION.UPDATE,
});
} catch (error) {
return {
error: "Failed to update card",
};
}
revalidatePath(`/board/${boardId}`);
return { data: card };
};
export const updateCard = createSafeAction(UpdateCard, handler);

View file

@ -0,0 +1,26 @@
import { z } from "zod";
export const UpdateCard = z.object({
boardId: z.string(),
description: z.optional(
z
.string({
invalid_type_error: "Description must be a string",
required_error: "Description is required",
})
.min(3, {
message: "Description must be at least 3 characters",
})
),
title: z.optional(
z
.string({
required_error: "Title is required",
invalid_type_error: "Title must be a string",
})
.min(3, {
message: "Title must be at least 3 characters",
})
),
id: z.string(),
});

View file

@ -0,0 +1,9 @@
import { z } from "zod";
import { Card } from "@prisma/client";
import { ActionState } from "@/lib/create-safe-action";
import { UpdateCard } from "./schema";
export type InputType = z.infer<typeof UpdateCard>;
export type ReturnType = ActionState<InputType, Card>;

View file

@ -0,0 +1,46 @@
"use server";
import { auth } from "@clerk/nextjs";
import { revalidatePath } from "next/cache";
import { db } from "@/lib/db";
import { createSafeAction } from "@/lib/create-safe-action";
import { InputType, ReturnType } from "./types";
import { UpdateListOrder } from "./schema";
const handler = async (data: InputType): Promise<ReturnType> => {
const { userId, orgId } = auth();
if (!userId || !orgId) return { error: "Unauthorized" };
const { items, boardId } = data;
let lists;
try {
const transaction = items.map((list) =>
db.list.update({
where: {
id: list.id,
board: {
orgId,
},
},
data: {
order: list.order,
},
})
);
lists = await db.$transaction(transaction);
} catch (error) {
return {
error: "Failed to reorder list",
};
}
revalidatePath(`/board/${boardId}`);
return { data: lists };
};
export const updateListOrder = createSafeAction(UpdateListOrder, handler);

View file

@ -0,0 +1,14 @@
import { z } from "zod";
export const UpdateListOrder = z.object({
items: z.array(
z.object({
id: z.string(),
title: z.string(),
order: z.number(),
createdAt: z.date(),
updatedAt: z.date(),
})
),
boardId: z.string(),
});

View file

@ -0,0 +1,9 @@
import { z } from "zod";
import { List } from "@prisma/client";
import { ActionState } from "@/lib/create-safe-action";
import { UpdateListOrder } from "./schema";
export type InputType = z.infer<typeof UpdateListOrder>;
export type ReturnType = ActionState<InputType, List[]>;

View file

@ -0,0 +1,52 @@
"use server";
import { auth } from "@clerk/nextjs";
import { revalidatePath } from "next/cache";
import { ACTION, ENTITY_TYPE } from "@prisma/client";
import { db } from "@/lib/db";
import { createAuditLog } from "@/lib/create-audit-log";
import { createSafeAction } from "@/lib/create-safe-action";
import { InputType, ReturnType } from "./types";
import { UpdateList } from "./schema";
const handler = async (data: InputType): Promise<ReturnType> => {
const { userId, orgId } = auth();
if (!userId || !orgId) return { error: "Unauthorized" };
const { title, id, boardId } = data;
let list;
try {
list = await db.list.update({
where: {
id,
boardId,
board: {
orgId,
},
},
data: {
title,
},
});
await createAuditLog({
entityTitle: list.title,
entityType: ENTITY_TYPE.LIST,
entityId: list.id,
action: ACTION.UPDATE,
});
} catch (error) {
return {
error: "Failed to update list",
};
}
revalidatePath(`/board/${boardId}`);
return { data: list };
};
export const updateList = createSafeAction(UpdateList, handler);

View file

@ -0,0 +1,12 @@
import { z } from "zod";
export const UpdateList = z.object({
title: z.string({
required_error: "Title is required",
invalid_type_error: "Title must be a string",
}).min(2, {
message: "Title must be at least 2 characters",
}),
id: z.string(),
boardId: z.string(),
})

View file

@ -0,0 +1,9 @@
import { z } from "zod";
import { List } from "@prisma/client";
import { ActionState } from "@/lib/create-safe-action";
import { UpdateList } from "./schema";
export type InputType = z.infer<typeof UpdateList>;
export type ReturnType = ActionState<InputType, List>;