feat: update list name

This commit is contained in:
Henry
2024-01-02 17:38:13 +00:00
parent decbcadb07
commit 20ef0f5ca2
4 changed files with 180 additions and 92 deletions

View File

@@ -0,0 +1,108 @@
"use client";
import { type ReactNode } from "react";
import { HiOutlinePlusSmall } from "react-icons/hi2";
import { Draggable } from "react-beautiful-dnd";
import { useFormik } from "formik";
import { api } from "~/trpc/react";
import { useModal } from "~/app/providers/modal";
import ListDropdown from "./ListDropdown";
interface ListProps {
children: ReactNode;
index: number;
list: List;
setSelectedPublicListId: (publicListId: PublicListId) => void;
}
interface List {
publicId: string;
name: string;
}
interface FormValues {
listPublicId: string;
name: string;
}
type PublicListId = string;
export default function List({
children,
index,
list,
setSelectedPublicListId,
}: ListProps) {
const { openModal } = useModal();
const openNewCardForm = (publicListId: PublicListId) => {
openModal("NEW_CARD");
setSelectedPublicListId(publicListId);
};
const updateList = api.list.update.useMutation();
const formik = useFormik({
initialValues: {
listPublicId: list.publicId,
name: list.name,
},
onSubmit: (values: FormValues) => {
updateList.mutate({
listPublicId: values.listPublicId,
name: values.name,
});
},
enableReinitialize: true,
});
return (
<Draggable key={list.publicId} draggableId={list.publicId} index={index}>
{(provided) => (
<div
key={list.publicId}
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
className="mr-5 h-fit min-w-[18rem] max-w-[18rem] rounded-md border border-dark-400 bg-dark-200 py-2 pl-2 pr-1"
>
<div className="flex justify-between">
<form
onSubmit={formik.handleSubmit}
className="focus-visible:outline-none"
>
<input
type="name"
id="name"
name="name"
value={formik.values.name}
onChange={formik.handleChange}
onBlur={formik.submitForm}
className="mb-4 block border-0 bg-transparent px-4 pt-1 text-sm font-medium text-dark-1000 focus:ring-0 focus-visible:outline-none"
/>
</form>
<div>
<button
className="mx-1 inline-flex h-fit items-center rounded-md p-1 px-1 text-sm font-semibold text-dark-50 hover:bg-dark-400"
onClick={() => openNewCardForm(list.publicId)}
>
<HiOutlinePlusSmall
className="h-5 w-5 text-dark-900"
aria-hidden="true"
/>
</button>
<ListDropdown
setSelectedPublicListId={() =>
setSelectedPublicListId(list.publicId)
}
/>
</div>
</div>
{children}
</div>
)}
</Draggable>
);
}

View File

@@ -21,7 +21,7 @@ import Modal from "~/app/_components/modal";
import BoardDropdown from "./components/BoardDropdown"; import BoardDropdown from "./components/BoardDropdown";
import { DeleteBoardConfirmation } from "./components/DeleteBoardConfirmation"; import { DeleteBoardConfirmation } from "./components/DeleteBoardConfirmation";
import { DeleteListConfirmation } from "./components/DeleteListConfirmation"; import { DeleteListConfirmation } from "./components/DeleteListConfirmation";
import ListDropdown from "./components/ListDropdown"; import List from "./components/List";
import { NewCardForm } from "./components/NewCardForm"; import { NewCardForm } from "./components/NewCardForm";
import { NewListForm } from "./components/NewListForm"; import { NewListForm } from "./components/NewListForm";
@@ -95,11 +95,6 @@ export default function BoardPage() {
setSelectedPublicListId(publicBoardId); setSelectedPublicListId(publicBoardId);
}; };
const openNewCardForm = (publicListId: PublicListId) => {
openModal("NEW_CARD");
setSelectedPublicListId(publicListId);
};
const onDragEnd = ({ const onDragEnd = ({
source, source,
destination, destination,
@@ -198,40 +193,14 @@ export default function BoardPage() {
> >
<div className="min-w-[2rem]" /> <div className="min-w-[2rem]" />
{boardData?.lists?.map((list: List, index) => ( {boardData?.lists?.map((list: List, index) => (
<Draggable <List
key={list.publicId}
draggableId={list.publicId}
index={index} index={index}
> key={index}
{(provided) => ( list={list}
<div setSelectedPublicListId={(publicListId) =>
key={list.publicId} setSelectedPublicListId(publicListId)
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
className="mr-5 h-fit min-w-[18rem] max-w-[18rem] rounded-md border border-dark-400 bg-dark-200 py-2 pl-2 pr-1"
>
<div className="flex justify-between">
<p className="mb-4 px-4 pt-1 text-sm font-medium text-dark-1000">
{list.name}
</p>
<div>
<button
className="mx-1 inline-flex h-fit items-center rounded-md p-1 px-1 text-sm font-semibold text-dark-50 hover:bg-dark-400"
onClick={() => openNewCardForm(list.publicId)}
>
<HiOutlinePlusSmall
className="h-5 w-5 text-dark-900"
aria-hidden="true"
/>
</button>
<ListDropdown
setSelectedPublicListId={() =>
setSelectedPublicListId(list.publicId)
} }
/> >
</div>
</div>
<Droppable droppableId={`${list.publicId}`} type="CARD"> <Droppable droppableId={`${list.publicId}`} type="CARD">
{(provided) => ( {(provided) => (
<div <div
@@ -283,9 +252,7 @@ export default function BoardPage() {
</div> </div>
)} )}
</Droppable> </Droppable>
</div> </List>
)}
</Draggable>
))} ))}
<div className="min-w-[0.75rem]" /> <div className="min-w-[0.75rem]" />
{provided.placeholder} {provided.placeholder}

View File

@@ -77,7 +77,7 @@ export const BoardProvider: React.FC<{ children: ReactNode }> = ({
}, },
}); });
const updateListMutation = api.list.update.useMutation({ const updateListMutation = api.list.reorder.useMutation({
onSuccess: async () => { onSuccess: async () => {
try { try {
await refetchBoard(); await refetchBoard();

View File

@@ -1,5 +1,5 @@
import { z } from "zod"; import { z } from "zod";
import { desc, eq, sql } from "drizzle-orm"; import { and, desc, eq, sql, isNull } from "drizzle-orm";
import { boards, cards, lists } from "~/server/db/schema"; import { boards, cards, lists } from "~/server/db/schema";
import { generateUID } from "~/utils/generateUID"; import { generateUID } from "~/utils/generateUID";
@@ -49,7 +49,7 @@ export const listRouter = createTRPCRouter({
}); });
}) })
}), }),
update: publicProcedure reorder: publicProcedure
.input( .input(
z.object({ z.object({
boardId: z.string().min(12), boardId: z.string().min(12),
@@ -104,4 +104,17 @@ export const listRouter = createTRPCRouter({
await tx.execute(sql`UPDATE ${lists} SET ${lists.index} = ${lists.index} - 1 WHERE ${lists.boardId} = ${list.boardId} AND ${lists.index} > ${list.index} AND ${lists.deletedAt} IS NULL;`); await tx.execute(sql`UPDATE ${lists} SET ${lists.index} = ${lists.index} - 1 WHERE ${lists.boardId} = ${list.boardId} AND ${lists.index} > ${list.index} AND ${lists.deletedAt} IS NULL;`);
}) })
}), }),
update: publicProcedure
.input(
z.object({
listPublicId: z.string().min(12),
name: z.string().min(1),
}))
.mutation(({ ctx, input }) => {
const userId = ctx.session?.user.id;
if (!userId) return;
return ctx.db.update(lists).set({ name: input.name }).where(and(eq(lists.publicId, input.listPublicId), isNull(lists.deletedAt)));
}),
}); });