feat: assign members on new card

This commit is contained in:
Henry
2024-03-24 11:18:31 +00:00
parent 9a89a31d6a
commit f524d49d7f
4 changed files with 124 additions and 11 deletions

View File

@@ -14,6 +14,7 @@ import { useModal } from "~/app/providers/modal";
interface FormData {
title: string;
listPublicId: string;
memberPublicIds: string[];
}
interface NewCardFormProps {
@@ -34,9 +35,12 @@ export function NewCardForm({ listPublicId }: NewCardFormProps) {
defaultValues: {
title: "",
listPublicId,
memberPublicIds: [],
},
});
const memberPublicIds = watch("memberPublicIds") || [];
const refetchBoard = () =>
utils.board.byId.refetch({ id: boardData.publicId });
@@ -64,10 +68,18 @@ export function NewCardForm({ listPublicId }: NewCardFormProps) {
selected: list.publicId === watch("listPublicId"),
})) ?? [];
const formattedMembers =
boardData?.workspace?.members?.map((member) => ({
key: member.publicId,
value: member.user.name,
selected: memberPublicIds.includes(member.publicId),
})) ?? [];
const onSubmit = (data: FormData) => {
createCard.mutate({
title: data.title,
listPublicId: data.listPublicId,
memberPublicIds: data.memberPublicIds,
});
reset();
};
@@ -76,6 +88,17 @@ export function NewCardForm({ listPublicId }: NewCardFormProps) {
setValue("listPublicId", listPublicId);
};
const handleSelectMembers = (memberPublicId: string): void => {
const currentIndex = memberPublicIds.indexOf(memberPublicId);
if (currentIndex === -1) {
setValue("memberPublicIds", [...memberPublicIds, memberPublicId]);
} else {
const newMemberPublicIds = [...memberPublicIds];
newMemberPublicIds.splice(currentIndex, 1);
setValue("memberPublicIds", newMemberPublicIds);
}
};
const selectedList = formattedLists.find((item) => item.selected);
return (
@@ -105,16 +128,59 @@ export function NewCardForm({ listPublicId }: NewCardFormProps) {
className="block w-full rounded-md border-0 bg-dark-300 bg-white/5 py-1.5 text-dark-1000 shadow-sm ring-1 ring-inset ring-dark-700 focus:ring-2 focus:ring-inset focus:ring-dark-700 sm:text-sm sm:leading-6"
/>
</div>
<div className="mt-2 w-fit">
<CheckboxDropdown
items={formattedLists}
handleSelect={(list: { key: string }) => handleSelectList(list.key)}
>
<div className="flex h-full w-full items-center rounded-[5px] border-[1px] border-dark-600 bg-dark-400 px-2 py-1.5 text-left text-xs text-dark-1000 hover:bg-dark-500">
{selectedList?.value}
</div>
</CheckboxDropdown>
<div className="mt-2 flex space-x-1">
<div className="w-fit">
<CheckboxDropdown
items={formattedLists}
handleSelect={(list: { key: string }) =>
handleSelectList(list.key)
}
>
<div className="flex h-full w-full items-center rounded-[5px] border-[1px] border-dark-600 bg-dark-400 px-2 py-1 text-left text-xs text-dark-1000 hover:bg-dark-500">
{selectedList?.value}
</div>
</CheckboxDropdown>
</div>
<div className="w-fit">
<CheckboxDropdown
items={formattedMembers}
handleSelect={(list: { key: string }) =>
handleSelectMembers(list.key)
}
>
<div className="flex h-full w-full items-center rounded-[5px] border-[1px] border-dark-600 bg-dark-400 px-2 py-1 text-left text-xs text-dark-1000 hover:bg-dark-500">
{!memberPublicIds.length ? (
"Members"
) : (
<>
{memberPublicIds.map((memberPublicId) => {
const member = formattedMembers.find(
(member) => member.key === memberPublicId,
);
return (
<span
key={member?.key}
className="inline-flex h-4 w-4 items-center justify-center rounded-full bg-gray-400 ring-1 ring-dark-500"
>
<span className="text-[8px] font-medium leading-none text-white">
{member?.value
.split(" ")
.map((namePart) =>
namePart.charAt(0).toUpperCase(),
)
.join("")}
</span>
</span>
);
})}
</>
)}
</div>
</CheckboxDropdown>
</div>
</div>
<div className="mt-3 flex items-center justify-end">
<span className="mr-2 text-xs text-dark-900">Create more</span>
<Switch

View File

@@ -20,6 +20,9 @@ interface BoardData {
name: string;
publicId: string;
lists: List[];
workspace: {
members: Members[];
};
}
interface List {
@@ -30,6 +33,13 @@ interface List {
cards: Card[];
}
interface Members {
publicId: string;
user: {
name: string;
};
}
interface Card {
publicId: string;
title: string;
@@ -52,6 +62,9 @@ const initialBoardData: BoardData = {
name: "",
publicId: "",
lists: [],
workspace: {
members: [],
},
};
const BoardContext = createContext<BoardContextProps | undefined>(undefined);

View File

@@ -43,6 +43,25 @@ export const boardRouter = createTRPCRouter({
name: true,
},
with: {
workspace: {
columns: {
publicId: true,
},
with: {
members: {
columns: {
publicId: true,
},
with: {
user: {
columns: {
name: true
}
}
}
}
}
},
lists: {
orderBy: [asc(lists.index)],
where: isNull(cards.deletedAt),

View File

@@ -1,5 +1,5 @@
import { z } from "zod";
import { and, desc, eq, isNull, sql } from "drizzle-orm";
import { and, desc, eq, isNull, inArray, sql } from "drizzle-orm";
import { cards, cardsToLabels, cardToWorkspaceMembers, labels, lists, workspaceMembers } from "~/server/db/schema";
import { generateUID } from "~/utils/generateUID";
@@ -15,6 +15,7 @@ export const cardRouter = createTRPCRouter({
z.object({
title: z.string().min(1),
listPublicId: z.string().min(12),
memberPublicIds: z.array(z.string().min(12))
}),
)
.mutation(({ ctx, input }) => {
@@ -40,13 +41,27 @@ export const cardRouter = createTRPCRouter({
orderBy: desc(cards.index)
});
return tx.insert(cards).values({
const newCard = await tx.insert(cards).values({
publicId: generateUID(),
title: input.title,
createdBy: userId,
listId: list.id,
index: latestCard ? latestCard.index + 1 : 0
});
if (newCard.insertId && input.memberPublicIds.length) {
const members = await tx.query.workspaceMembers.findMany({
where: inArray(workspaceMembers.publicId, input.memberPublicIds),
});
if (!members.length) return;
const membersInsert = members.map((member) => ({ cardId: Number(newCard.insertId), workspaceMemberId: member.id}))
await tx.insert(cardToWorkspaceMembers).values(membersInsert);
}
return newCard;
})
}),
addOrRemoveLabel: publicProcedure