feat: create new lists

This commit is contained in:
Henry
2023-12-06 21:28:38 +00:00
parent e1e0ea1615
commit 956f5b131e
7 changed files with 155 additions and 12 deletions

View File

@@ -0,0 +1,86 @@
"use client";
import { api } from "~/trpc/react";
import { HiXMark } from "react-icons/hi2";
import { useBoard } from "~/app/providers/board";
import { useModal } from "~/app/providers/modal";
import { Formik, Form, Field } from "formik";
interface FormValues {
name: string;
}
interface boardPublicId {
boardPublicId: string;
}
export function NewListForm({ boardPublicId }: boardPublicId) {
const utils = api.useUtils();
const { boardData } = useBoard();
const { closeModal } = useModal();
const refetchBoard = () =>
utils.board.byId.refetch({ id: boardData.publicId });
const createList = api.list.create.useMutation({
onSuccess: async () => {
try {
await refetchBoard();
closeModal();
} catch (e) {
console.log(e);
}
},
});
return (
<>
<div className="flex w-full justify-between pb-4">
<h2 className="text-sm font-medium text-dark-1000">New list</h2>
<button
className="rounded p-1 hover:bg-dark-300"
onClick={() => closeModal()}
>
<HiXMark size={18} className="text-dark-900" />
</button>
</div>
<Formik
initialValues={{
name: "",
}}
onSubmit={(values: FormValues) => {
createList.mutate({
name: values.name,
boardPublicId,
});
}}
>
<Form>
<label
htmlFor="name"
className="block pb-2 text-sm font-normal leading-6 text-dark-1000"
>
Name
</label>
<Field
id="name"
name="name"
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 className="mt-5 sm:mt-6">
<button
type="submit"
className="inline-flex w-full justify-center rounded-md bg-dark-1000 px-3 py-2 text-sm font-semibold text-dark-50 shadow-sm focus-visible:outline-none"
>
Create list
</button>
</div>
</Form>
</Formik>
</>
);
}

View File

@@ -17,7 +17,9 @@ import { useBoard } from "~/app/providers/board";
import { useModal } from "~/app/providers/modal";
import Modal from "~/app/_components/modal";
import { NewCardForm } from "~/app/boards/[...id]/create";
import { NewCardForm } from "./NewCardForm";
import { NewListForm } from "./NewListForm";
interface List {
publicId: string;
@@ -40,7 +42,7 @@ type PublicListId = string;
export default function BoardPage() {
const params = useParams();
const { boardData, setBoardData, updateCard, updateList } = useBoard();
const { openModal } = useModal();
const { openModal, modalContentType } = useModal();
const [selectedPublicListId, setSelectedPublicListId] =
useState<PublicListId>("");
@@ -73,8 +75,13 @@ export default function BoardPage() {
},
);
const openNewListForm = (publicBoardId: string) => {
openModal("NEW_LIST");
setSelectedPublicListId(publicBoardId);
};
const openNewCardForm = (publicListId: PublicListId) => {
openModal();
openModal("NEW_CARD");
setSelectedPublicListId(publicListId);
};
@@ -153,6 +160,7 @@ export default function BoardPage() {
<button
type="button"
className="inline-flex items-center gap-x-1.5 rounded-md bg-dark-1000 px-3 py-2 text-sm font-semibold text-dark-50 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2"
onClick={() => openNewListForm(boardId)}
>
<HiOutlinePlusSmall
className="-mr-0.5 h-5 w-5"
@@ -240,7 +248,12 @@ export default function BoardPage() {
</Droppable>
</DragDropContext>
<Modal>
<NewCardForm listPublicId={selectedPublicListId} />
{modalContentType === "NEW_CARD" && (
<NewCardForm listPublicId={selectedPublicListId} />
)}
{modalContentType === "NEW_LIST" && (
<NewListForm boardPublicId={boardId} />
)}
</Modal>
</div>
);

View File

@@ -21,7 +21,7 @@ export default function BoardsPage() {
<button
type="button"
className="inline-flex items-center gap-x-1.5 rounded-md bg-dark-1000 px-3 py-2 text-sm font-semibold text-dark-50 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2"
onClick={() => openModal()}
onClick={() => openModal("NEW_BOARD")}
>
<HiOutlinePlusSmall
className="-mr-0.5 h-5 w-5"

View File

@@ -4,8 +4,9 @@ import { createContext, useContext, useState } from "react";
type ModalContextType = {
isOpen: boolean;
openModal: () => void;
openModal: (contentType: string) => void;
closeModal: () => void;
modalContentType: string;
};
interface Props {
@@ -16,17 +17,22 @@ const ModalContext = createContext<ModalContextType | undefined>(undefined);
export const ModalProvider: React.FC<Props> = ({ children }) => {
const [isOpen, setIsOpen] = useState(false);
const [modalContentType, setModalContentType] = useState("");
const openModal = () => {
const openModal = (contentType: string) => {
setIsOpen(true);
setModalContentType(contentType);
};
const closeModal = () => {
setIsOpen(false);
setModalContentType("");
};
return (
<ModalContext.Provider value={{ isOpen, openModal, closeModal }}>
<ModalContext.Provider
value={{ isOpen, openModal, closeModal, modalContentType }}
>
{children}
</ModalContext.Provider>
);

View File

@@ -22,8 +22,6 @@ export const cardRouter = createTRPCRouter({
if (!userId) return;
return ctx.db.transaction(async (tx) => {
const list = await tx.query.lists.findFirst({
where: eq(lists.publicId, input.listPublicId),

View File

@@ -1,7 +1,8 @@
import { z } from "zod";
import { eq, sql } from "drizzle-orm";
import { desc, eq, sql } from "drizzle-orm";
import { lists } from "~/server/db/schema";
import { boards, lists } from "~/server/db/schema";
import { generateUID } from "~/utils/generateUID";
import {
createTRPCRouter,
@@ -9,6 +10,45 @@ import {
} from "~/server/api/trpc";
export const listRouter = createTRPCRouter({
create: publicProcedure
.input(
z.object({
name: z.string().min(1),
boardPublicId: z.string().min(12)
}),
)
.mutation(({ ctx, input }) => {
const userId = ctx.session?.user.id;
if (!userId) return;
return ctx.db.transaction(async (tx) => {
const board = await tx.query.boards.findFirst({
where: eq(boards.publicId, input.boardPublicId),
columns: {
id: true
}
});
if (!board) return;
const latestList = await tx.query.lists.findFirst({
where: eq(lists.boardId, board.id),
columns: {
index: true
},
orderBy: desc(lists.index)
});
return tx.insert(lists).values({
publicId: generateUID(),
name: input.name,
createdBy: userId,
boardId: board.id,
index: latestList ? latestList.index + 1 : 0
});
})
}),
update: publicProcedure
.input(
z.object({