From ccdbd9fa140fde1471263b90eed22d983decbe22 Mon Sep 17 00:00:00 2001 From: Henry Date: Tue, 13 Aug 2024 22:57:04 +0100 Subject: [PATCH] feat: add description on create new card --- package-lock.json | 265 +++++++++--------- package.json | 2 +- src/components/CheckboxDropdown.tsx | 4 +- src/components/modal.tsx | 15 +- src/providers/board.tsx | 37 ++- src/server/api/routers/card.ts | 2 + src/server/db/repository/card.repo.ts | 2 + .../components/DeleteBoardConfirmation.tsx | 4 +- .../components/DeleteListConfirmation.tsx | 4 +- src/views/board/components/NewCardForm.tsx | 67 +++-- src/views/board/components/NewListForm.tsx | 6 +- src/views/board/index.tsx | 14 +- .../boards/components/ImportBoardsForm.tsx | 4 +- .../components/DeleteCardConfirmation.tsx | 37 ++- src/views/card/components/NewLabelForm.tsx | 4 +- 15 files changed, 267 insertions(+), 200 deletions(-) diff --git a/package-lock.json b/package-lock.json index dc1d65d4..7559fe71 100644 --- a/package-lock.json +++ b/package-lock.json @@ -56,7 +56,7 @@ "postcss": "^8.4.34", "prettier": "^3.2.5", "prettier-plugin-tailwindcss": "^0.5.11", - "supabase": "^1.187.3", + "supabase": "^1.188.4", "tailwind": "^4.0.0", "tailwind-scrollbar": "^3.0.5", "tailwindcss": "^3.4.1", @@ -737,6 +737,126 @@ "node": ">= 10" } }, + "node_modules/@next/swc-darwin-x64": { + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.1.4.tgz", + "integrity": "sha512-b0Xo1ELj3u7IkZWAKcJPJEhBop117U78l70nfoQGo4xUSvv0PJSTaV4U9xQBLvZlnjsYkc8RwQN1HoH/oQmLlQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.1.4.tgz", + "integrity": "sha512-457G0hcLrdYA/u1O2XkRMsDKId5VKe3uKPvrKVOyuARa6nXrdhJOOYU9hkKKyQTMru1B8qEP78IAhf/1XnVqKA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.1.4.tgz", + "integrity": "sha512-l/kMG+z6MB+fKA9KdtyprkTQ1ihlJcBh66cf0HvqGP+rXBbOXX0dpJatjZbHeunvEHoBBS69GYQG5ry78JMy3g==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.1.4.tgz", + "integrity": "sha512-BapIFZ3ZRnvQ1uWbmqEGJuPT9cgLwvKtxhK/L2t4QYO7l+/DxXuIGjvp1x8rvfa/x1FFSsipERZK70pewbtJtw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.1.4.tgz", + "integrity": "sha512-mqVxTwk4XuBl49qn2A5UmzFImoL1iLm0KQQwtdRJRKl21ylQwwGCxJtIYo2rbfkZHoSKlh/YgztY0qH3wG1xIg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.1.4.tgz", + "integrity": "sha512-xzxF4ErcumXjO2Pvg/wVGrtr9QQJLk3IyQX1ddAC/fi6/5jZCZ9xpuL9Tzc4KPWMFq8GGWFVDMshZOdHGdkvag==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-ia32-msvc": { + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.1.4.tgz", + "integrity": "sha512-WZiz8OdbkpRw6/IU/lredZWKKZopUMhcI2F+XiMAcPja0uZYdMTZQRoQ0WZcvinn9xZAidimE7tN9W5v9Yyfyw==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.1.4.tgz", + "integrity": "sha512-4Rto21sPfw555sZ/XNLqfxDUNeLhNYGO2dlPqsnuCg8N8a2a9u1ltqBOPQ4vj1Gf7eJC0W2hHG2eYUHuiXgY2w==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "license": "MIT", @@ -6693,9 +6813,9 @@ } }, "node_modules/minizlib/node_modules/rimraf": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.9.tgz", - "integrity": "sha512-3i7b8OcswU6CpU8Ej89quJD4O98id7TtVM5U4Mybh84zQXdrFmDLouWBEEaD/QfO3gDDfH+AGFCGsR7kngzQnA==", + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", + "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", "dev": true, "dependencies": { "glob": "^10.3.7" @@ -6703,9 +6823,6 @@ "bin": { "rimraf": "dist/esm/bin.mjs" }, - "engines": { - "node": "14 >=14.20 || 16 >=16.20 || >=18" - }, "funding": { "url": "https://github.com/sponsors/isaacs" } @@ -9236,16 +9353,16 @@ } }, "node_modules/supabase": { - "version": "1.187.3", - "resolved": "https://registry.npmjs.org/supabase/-/supabase-1.187.3.tgz", - "integrity": "sha512-44yzHpxMrd88cUKWw3GVPPIUx6oCqgfqmN4Mlxp7a7GeNNZSTe433vmKBcj+ue3E7K08XcIyEX6G1TjhVyto+g==", + "version": "1.188.4", + "resolved": "https://registry.npmjs.org/supabase/-/supabase-1.188.4.tgz", + "integrity": "sha512-ntOhjrBlnMdacbcmGmuv7Q2JuH6oeukc5iCHFtjZxQRmE583p02HdsALEq7KdITEMjFJOvjM4xJ5/32HAYuRQQ==", "dev": true, "hasInstallScript": true, "dependencies": { "bin-links": "^4.0.3", "https-proxy-agent": "^7.0.2", "node-fetch": "^3.3.2", - "tar": "7.4.0" + "tar": "7.4.3" }, "bin": { "supabase": "bin/supabase" @@ -9389,9 +9506,9 @@ } }, "node_modules/tar": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.0.tgz", - "integrity": "sha512-XQs0S8fuAkQWuqhDeCdMlJXDX80D7EOVLDPVFkna9yQfzS+PHKgfxcei0jf6/+QAWcjqrnC8uM3fSAnrQl+XYg==", + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz", + "integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==", "dev": true, "dependencies": { "@isaacs/fs-minipass": "^4.0.0", @@ -10124,126 +10241,6 @@ "@react-email/components": "0.0.12", "react-email": "^1.10.0" } - }, - "node_modules/@next/swc-darwin-x64": { - "version": "14.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.1.4.tgz", - "integrity": "sha512-b0Xo1ELj3u7IkZWAKcJPJEhBop117U78l70nfoQGo4xUSvv0PJSTaV4U9xQBLvZlnjsYkc8RwQN1HoH/oQmLlQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-gnu": { - "version": "14.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.1.4.tgz", - "integrity": "sha512-457G0hcLrdYA/u1O2XkRMsDKId5VKe3uKPvrKVOyuARa6nXrdhJOOYU9hkKKyQTMru1B8qEP78IAhf/1XnVqKA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-musl": { - "version": "14.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.1.4.tgz", - "integrity": "sha512-l/kMG+z6MB+fKA9KdtyprkTQ1ihlJcBh66cf0HvqGP+rXBbOXX0dpJatjZbHeunvEHoBBS69GYQG5ry78JMy3g==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-gnu": { - "version": "14.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.1.4.tgz", - "integrity": "sha512-BapIFZ3ZRnvQ1uWbmqEGJuPT9cgLwvKtxhK/L2t4QYO7l+/DxXuIGjvp1x8rvfa/x1FFSsipERZK70pewbtJtw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-musl": { - "version": "14.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.1.4.tgz", - "integrity": "sha512-mqVxTwk4XuBl49qn2A5UmzFImoL1iLm0KQQwtdRJRKl21ylQwwGCxJtIYo2rbfkZHoSKlh/YgztY0qH3wG1xIg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-arm64-msvc": { - "version": "14.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.1.4.tgz", - "integrity": "sha512-xzxF4ErcumXjO2Pvg/wVGrtr9QQJLk3IyQX1ddAC/fi6/5jZCZ9xpuL9Tzc4KPWMFq8GGWFVDMshZOdHGdkvag==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-ia32-msvc": { - "version": "14.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.1.4.tgz", - "integrity": "sha512-WZiz8OdbkpRw6/IU/lredZWKKZopUMhcI2F+XiMAcPja0uZYdMTZQRoQ0WZcvinn9xZAidimE7tN9W5v9Yyfyw==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-x64-msvc": { - "version": "14.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.1.4.tgz", - "integrity": "sha512-4Rto21sPfw555sZ/XNLqfxDUNeLhNYGO2dlPqsnuCg8N8a2a9u1ltqBOPQ4vj1Gf7eJC0W2hHG2eYUHuiXgY2w==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } } } } diff --git a/package.json b/package.json index 28b4932f..b0f3e5aa 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,7 @@ "postcss": "^8.4.34", "prettier": "^3.2.5", "prettier-plugin-tailwindcss": "^0.5.11", - "supabase": "^1.187.3", + "supabase": "^1.188.4", "tailwind": "^4.0.0", "tailwind-scrollbar": "^3.0.5", "tailwindcss": "^3.4.1", diff --git a/src/components/CheckboxDropdown.tsx b/src/components/CheckboxDropdown.tsx index 48c5da67..fc792a78 100644 --- a/src/components/CheckboxDropdown.tsx +++ b/src/components/CheckboxDropdown.tsx @@ -22,7 +22,9 @@ export default function CheckboxDropdown({ as="div" className="relative flex w-full flex-wrap items-center text-left" > - {children} + + {children} + = ({ children }) => { +const Modal: React.FC = ({ children, modalSize = "sm" }) => { const { isOpen, closeModal } = useModal(); + console.log({ modalSize }); + + const modalSizeMap = { + sm: "max-w-[400px]", + md: "max-w-[550px]", + lg: "max-w-[800px]", + }; + return ( @@ -36,7 +45,9 @@ const Modal: React.FC = ({ children }) => { leaveFrom="opacity-100 translate-y-0 sm:scale-100" leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95" > - + {children} diff --git a/src/providers/board.tsx b/src/providers/board.tsx index c4772176..66c862e2 100644 --- a/src/providers/board.tsx +++ b/src/providers/board.tsx @@ -24,7 +24,8 @@ interface BoardContextProps { updateCard: (params: ReorderCardInput) => void; addCard: (params: NewCardInput) => void; addList: (params: NewListInput) => void; - refetchBoard: () => void; + removeCard: (params: { cardPublicId: string }) => void; + refetchBoard: () => Promise; } const initialBoardData: GetBoardByIdOutput = { @@ -66,9 +67,11 @@ export const BoardProvider: React.FC<{ children: ReactNode }> = ({ }; const updateCardMutation = api.card.reorder.useMutation({ - onSuccess: () => refetchBoard(), - onError: () => { - refetchBoard(); + onSuccess: async () => { + await refetchBoard(); + }, + onError: async () => { + await refetchBoard(); showPopup({ header: "Unable to update card", message: "Please try again later, or contact customer support.", @@ -77,9 +80,11 @@ export const BoardProvider: React.FC<{ children: ReactNode }> = ({ }); const updateListMutation = api.list.reorder.useMutation({ - onSuccess: () => refetchBoard(), - onError: () => { - refetchBoard(); + onSuccess: async () => { + await refetchBoard(); + }, + onError: async () => { + await refetchBoard(); showPopup({ header: "Unable to update list", message: "Please try again later, or contact customer support.", @@ -105,7 +110,7 @@ export const BoardProvider: React.FC<{ children: ReactNode }> = ({ const updatedLists = boardData.lists.map((list) => { if (list.publicId === listPublicId) { const newCard = { - publicId: generateUID(), + publicId: `PLACEHOLDER_${generateUID()}`, title, listId: 2, description: "", @@ -115,7 +120,7 @@ export const BoardProvider: React.FC<{ children: ReactNode }> = ({ members: boardData.workspace?.members.filter((member) => memberPublicIds.includes(member.publicId), - ) || [], + ) ?? [], index: position === "start" ? 0 : list.cards.length, }; @@ -148,6 +153,19 @@ export const BoardProvider: React.FC<{ children: ReactNode }> = ({ setBoardData({ ...boardData, lists: updatedLists }); }; + const removeCard = ({ cardPublicId }: { cardPublicId: string }) => { + if (!boardData) return; + + const updatedLists = boardData.lists.map((list) => { + const updatedCards = list.cards.filter( + (card) => card.publicId !== cardPublicId, + ); + return { ...list, cards: updatedCards }; + }); + + setBoardData({ ...boardData, lists: updatedLists }); + }; + const updateList = ({ boardId, listId, @@ -179,6 +197,7 @@ export const BoardProvider: React.FC<{ children: ReactNode }> = ({ updateCard, addCard, addList, + removeCard, refetchBoard, }} > diff --git a/src/server/api/routers/card.ts b/src/server/api/routers/card.ts index d5ea5738..bdab654d 100644 --- a/src/server/api/routers/card.ts +++ b/src/server/api/routers/card.ts @@ -13,6 +13,7 @@ export const cardRouter = createTRPCRouter({ .input( z.object({ title: z.string().min(1), + description: z.string().max(10000), listPublicId: z.string().min(12), labelPublicIds: z.array(z.string().min(12)), memberPublicIds: z.array(z.string().min(12)), @@ -56,6 +57,7 @@ export const cardRouter = createTRPCRouter({ const newCard = await cardRepo.create(ctx.db, { title: input.title, + description: input.description, createdBy: userId, listId: list.id, index, diff --git a/src/server/db/repository/card.repo.ts b/src/server/db/repository/card.repo.ts index 2a18e5df..b8b57408 100644 --- a/src/server/db/repository/card.repo.ts +++ b/src/server/db/repository/card.repo.ts @@ -6,6 +6,7 @@ export const create = async ( db: SupabaseClient, cardInput: { title: string; + description: string; createdBy: string; listId: number; index: number; @@ -16,6 +17,7 @@ export const create = async ( .insert({ publicId: generateUID(), title: cardInput.title, + description: cardInput.description, createdBy: cardInput.createdBy, listId: cardInput.listId, index: cardInput.index, diff --git a/src/views/board/components/DeleteBoardConfirmation.tsx b/src/views/board/components/DeleteBoardConfirmation.tsx index b144fd89..261ef25a 100644 --- a/src/views/board/components/DeleteBoardConfirmation.tsx +++ b/src/views/board/components/DeleteBoardConfirmation.tsx @@ -24,7 +24,7 @@ export function DeleteBoardConfirmation() { }; return ( - <> +

Are you sure you want to delete this board? @@ -47,6 +47,6 @@ export function DeleteBoardConfirmation() { Delete

- +
); } diff --git a/src/views/board/components/DeleteListConfirmation.tsx b/src/views/board/components/DeleteListConfirmation.tsx index 894c3434..0ed6e4a8 100644 --- a/src/views/board/components/DeleteListConfirmation.tsx +++ b/src/views/board/components/DeleteListConfirmation.tsx @@ -31,7 +31,7 @@ export function DeleteListConfirmation({ }); return ( - <> +

Are you sure you want to delete this list? @@ -58,6 +58,6 @@ export function DeleteListConfirmation({ Delete

- +
); } diff --git a/src/views/board/components/NewCardForm.tsx b/src/views/board/components/NewCardForm.tsx index 11fdef58..0ff9deea 100644 --- a/src/views/board/components/NewCardForm.tsx +++ b/src/views/board/components/NewCardForm.tsx @@ -1,5 +1,6 @@ import { useEffect } from "react"; import { useForm } from "react-hook-form"; +import ContentEditable from "react-contenteditable"; import { api } from "~/utils/api"; import { @@ -39,6 +40,7 @@ export function NewCardForm({ listPublicId }: NewCardFormProps) { useForm({ defaultValues: { title: "", + description: "", listPublicId, labelPublicIds: [], memberPublicIds: [], @@ -53,10 +55,10 @@ export function NewCardForm({ listPublicId }: NewCardFormProps) { const position = watch("position"); const createCard = api.card.create.useMutation({ - onSuccess: async () => { + onSuccess: () => { refetchBoard(); }, - onError: async () => { + onError: () => { closeModal(); refetchBoard(); showPopup({ @@ -107,6 +109,7 @@ export function NewCardForm({ listPublicId }: NewCardFormProps) { createCard.mutate({ title: data.title, + description: data.description, listPublicId: data.listPublicId, labelPublicIds: data.labelPublicIds, memberPublicIds: data.memberPublicIds, @@ -147,32 +150,38 @@ export function NewCardForm({ listPublicId }: NewCardFormProps) { const selectedList = formattedLists.find((item) => item.selected); return ( - <> -
-

- New card -

- -
- -
-
-