feat: add description on create new card
This commit is contained in:
265
package-lock.json
generated
265
package-lock.json
generated
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -22,7 +22,9 @@ export default function CheckboxDropdown({
|
||||
as="div"
|
||||
className="relative flex w-full flex-wrap items-center text-left"
|
||||
>
|
||||
<Menu.Button>{children}</Menu.Button>
|
||||
<Menu.Button className="focus-visible:outline-none">
|
||||
{children}
|
||||
</Menu.Button>
|
||||
|
||||
<Transition
|
||||
as={Fragment}
|
||||
|
||||
@@ -5,11 +5,20 @@ import { useModal } from "~/providers/modal";
|
||||
|
||||
interface Props {
|
||||
children: React.ReactNode;
|
||||
modalSize?: "sm" | "md" | "lg";
|
||||
}
|
||||
|
||||
const Modal: React.FC<Props> = ({ children }) => {
|
||||
const Modal: React.FC<Props> = ({ 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 (
|
||||
<Transition.Root show={isOpen} as={Fragment}>
|
||||
<Dialog as="div" className="relative z-10" onClose={closeModal}>
|
||||
@@ -36,7 +45,9 @@ const Modal: React.FC<Props> = ({ children }) => {
|
||||
leaveFrom="opacity-100 translate-y-0 sm:scale-100"
|
||||
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||
>
|
||||
<Dialog.Panel className="relative mt-[25vh] transform rounded-lg border border-light-600 bg-light-50 px-4 pb-4 pt-5 text-left shadow-3xl-light transition-all dark:border-dark-600 dark:bg-dark-100/20 dark:shadow-3xl-dark dark:backdrop-blur-lg sm:mb-8 sm:w-full sm:max-w-sm sm:p-6">
|
||||
<Dialog.Panel
|
||||
className={`relative mt-[25vh] w-full transform rounded-lg border border-light-600 bg-dark-1000 bg-light-50 text-left shadow-3xl-light transition-all dark:border-dark-600 dark:bg-dark-100/20 dark:shadow-3xl-dark dark:backdrop-blur-lg ${modalSizeMap[modalSize]}`}
|
||||
>
|
||||
{children}
|
||||
</Dialog.Panel>
|
||||
</Transition.Child>
|
||||
|
||||
@@ -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<void>;
|
||||
}
|
||||
|
||||
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,
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -6,6 +6,7 @@ export const create = async (
|
||||
db: SupabaseClient<Database>,
|
||||
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,
|
||||
|
||||
@@ -24,7 +24,7 @@ export function DeleteBoardConfirmation() {
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="p-5">
|
||||
<div className="flex w-full flex-col justify-between pb-4">
|
||||
<h2 className="text-md pb-4 font-medium text-neutral-900 dark:text-dark-1000">
|
||||
Are you sure you want to delete this board?
|
||||
@@ -47,6 +47,6 @@ export function DeleteBoardConfirmation() {
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ export function DeleteListConfirmation({
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="p-5">
|
||||
<div className="flex w-full flex-col justify-between pb-4">
|
||||
<h2 className="text-md pb-4 font-medium text-neutral-900 dark:text-dark-1000">
|
||||
Are you sure you want to delete this list?
|
||||
@@ -58,6 +58,6 @@ export function DeleteListConfirmation({
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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<NewCardFormInput>({
|
||||
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 (
|
||||
<>
|
||||
<div className="flex w-full items-center justify-between pb-4">
|
||||
<h2 className="text-sm font-bold text-neutral-900 dark:text-dark-1000">
|
||||
New card
|
||||
</h2>
|
||||
<button
|
||||
className="rounded p-1 hover:bg-light-200 focus:outline-none dark:hover:bg-dark-300"
|
||||
onClick={() => closeModal()}
|
||||
>
|
||||
<HiXMark size={18} className="text-light-900 dark:text-dark-900" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<div>
|
||||
<label
|
||||
htmlFor="title"
|
||||
className="block pb-2 text-sm font-normal leading-6 text-neutral-900 dark:text-dark-1000"
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<div className="px-5 pt-5">
|
||||
<div className="flex w-full items-center justify-between pb-5">
|
||||
<h2 className="text-sm font-bold text-neutral-900 dark:text-dark-1000">
|
||||
New card
|
||||
</h2>
|
||||
<button
|
||||
className="rounded p-1 hover:bg-light-200 focus:outline-none dark:hover:bg-dark-300"
|
||||
onClick={(e) => {
|
||||
closeModal();
|
||||
e.preventDefault();
|
||||
}}
|
||||
>
|
||||
Title
|
||||
</label>
|
||||
<HiXMark size={18} className="text-light-900 dark:text-dark-900" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<input
|
||||
id="title"
|
||||
type="text"
|
||||
{...register("title")}
|
||||
className="block w-full rounded-md border-0 bg-dark-300 bg-white/5 py-1.5 text-neutral-900 shadow-sm ring-1 ring-inset ring-light-600 focus:ring-2 focus:ring-inset focus:ring-light-600 dark:text-dark-1000 dark:ring-dark-700 dark:focus:ring-dark-700 sm:text-sm sm:leading-6"
|
||||
placeholder="Card title"
|
||||
className="block w-full rounded-md border-0 bg-dark-300 bg-white/5 py-1.5 text-neutral-900 placeholder-dark-800 shadow-sm ring-1 ring-inset ring-light-600 focus:ring-2 focus:ring-inset focus:ring-light-600 dark:text-dark-1000 dark:ring-dark-700 dark:focus:ring-dark-700 sm:text-sm sm:leading-6"
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-2 ">
|
||||
<ContentEditable
|
||||
placeholder="Add description..."
|
||||
html={watch("description") || ""}
|
||||
onChange={(e) => setValue("description", e.target.value)}
|
||||
className="block min-h-[70px] w-full rounded-md border-0 bg-dark-300 bg-white/5 px-3 py-1.5 text-light-900 text-neutral-900 shadow-sm ring-1 ring-inset ring-light-600 focus:ring-2 focus:ring-inset focus:ring-light-600 focus-visible:outline-none dark:text-dark-1000 dark:ring-dark-700 dark:focus:ring-dark-700 sm:text-sm sm:leading-6"
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-2 flex space-x-1">
|
||||
@@ -280,7 +289,7 @@ export function NewCardForm({ listPublicId }: NewCardFormProps) {
|
||||
e.preventDefault();
|
||||
setValue("position", position === "start" ? "end" : "start");
|
||||
}}
|
||||
className="flex h-auto items-center rounded-[5px] border-[1px] border-light-600 bg-light-200 px-1.5 py-1 text-left text-xs text-light-800 hover:bg-light-300 dark:border-dark-600 dark:bg-dark-400 dark:text-dark-1000 dark:hover:bg-dark-500"
|
||||
className="flex h-auto items-center rounded-[5px] border-[1px] border-light-600 bg-light-200 px-1.5 py-1 text-left text-xs text-light-800 hover:bg-light-300 focus-visible:outline-none dark:border-dark-600 dark:bg-dark-400 dark:text-dark-1000 dark:hover:bg-dark-500"
|
||||
>
|
||||
{position === "start" ? (
|
||||
<HiOutlineBarsArrowUp size={14} />
|
||||
@@ -289,8 +298,10 @@ export function NewCardForm({ listPublicId }: NewCardFormProps) {
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-3 flex items-center justify-end">
|
||||
<div className="mt-5 flex items-center justify-end border-t border-light-600 px-5 pb-5 pt-5 dark:border-dark-600">
|
||||
<div className="mr-4 flex items-center justify-end">
|
||||
<span className="mr-2 text-xs text-light-900 dark:text-dark-900">
|
||||
Create more
|
||||
</span>
|
||||
@@ -315,7 +326,7 @@ export function NewCardForm({ listPublicId }: NewCardFormProps) {
|
||||
</Switch>
|
||||
</div>
|
||||
|
||||
<div className="mt-5 sm:mt-6">
|
||||
<div>
|
||||
<button
|
||||
type="submit"
|
||||
className="inline-flex w-full justify-center rounded-md bg-light-1000 px-3 py-2 text-sm font-semibold text-light-50 shadow-sm focus-visible:outline-none dark:bg-dark-1000 dark:text-dark-50"
|
||||
@@ -323,7 +334,7 @@ export function NewCardForm({ listPublicId }: NewCardFormProps) {
|
||||
Create card
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { api } from "~/utils/api";
|
||||
import { useForm } from "react-hook-form";
|
||||
|
||||
@@ -69,7 +69,7 @@ export function NewListForm({ boardPublicId }: { boardPublicId: string }) {
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="p-5">
|
||||
<div className="flex w-full items-center justify-between pb-4">
|
||||
<h2 className="text-sm font-bold text-neutral-900 dark:text-dark-1000">
|
||||
New list
|
||||
@@ -129,6 +129,6 @@ export function NewListForm({ boardPublicId }: { boardPublicId: string }) {
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -212,9 +212,19 @@ export default function BoardPage() {
|
||||
>
|
||||
{(provided) => (
|
||||
<Link
|
||||
onClick={(e) => {
|
||||
if (
|
||||
card.publicId.startsWith("PLACEHOLDER")
|
||||
)
|
||||
e.preventDefault();
|
||||
}}
|
||||
key={card.publicId}
|
||||
href={`/cards/${card.publicId}`}
|
||||
className="mb-2 flex !cursor-pointer flex-col rounded-md border border-light-200 bg-light-50 px-3 py-2 text-sm text-neutral-900 dark:border-dark-200 dark:bg-dark-300 dark:text-dark-1000 dark:hover:bg-dark-400"
|
||||
className={`mb-2 flex !cursor-pointer flex-col rounded-md border border-light-200 bg-light-50 px-3 py-2 text-sm text-neutral-900 dark:border-dark-200 dark:bg-dark-300 dark:text-dark-1000 dark:hover:bg-dark-400 ${
|
||||
card.publicId.startsWith("PLACEHOLDER")
|
||||
? "pointer-events-none"
|
||||
: ""
|
||||
}`}
|
||||
ref={provided.innerRef}
|
||||
{...provided.draggableProps}
|
||||
{...provided.dragHandleProps}
|
||||
@@ -280,7 +290,7 @@ export default function BoardPage() {
|
||||
</DragDropContext>
|
||||
)}
|
||||
</div>
|
||||
<Modal>
|
||||
<Modal modalSize={modalContentType === "NEW_CARD" ? "md" : "sm"}>
|
||||
{modalContentType === "DELETE_BOARD" && <DeleteBoardConfirmation />}
|
||||
{modalContentType === "DELETE_LIST" && (
|
||||
<DeleteListConfirmation listPublicId={selectedPublicListId} />
|
||||
|
||||
@@ -251,7 +251,7 @@ export function ImportBoardsForm() {
|
||||
const [step, setStep] = useState(1);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="p-5">
|
||||
<div className="flex w-full justify-between pb-4">
|
||||
<h2 className="text-sm font-medium text-neutral-900 dark:text-dark-1000">
|
||||
New import
|
||||
@@ -266,6 +266,6 @@ export function ImportBoardsForm() {
|
||||
|
||||
{step === 1 && <SelectSource handleNextStep={() => setStep(step + 1)} />}
|
||||
{step === 2 && <ImportTrello />}
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { useRouter } from "next/navigation";
|
||||
import { api } from "~/utils/api";
|
||||
import { useModal } from "~/providers/modal";
|
||||
import { useBoard } from "~/providers/board";
|
||||
import { usePopup } from "~/providers/popup";
|
||||
|
||||
interface DeleteCardConfirmationProps {
|
||||
cardPublicId: string;
|
||||
@@ -13,16 +15,31 @@ export function DeleteCardConfirmation({
|
||||
}: DeleteCardConfirmationProps) {
|
||||
const { closeModal } = useModal();
|
||||
const router = useRouter();
|
||||
const { removeCard, refetchBoard } = useBoard();
|
||||
const { showPopup } = usePopup();
|
||||
|
||||
const deleteCard = api.card.delete.useMutation({
|
||||
onSuccess: () => {
|
||||
closeModal();
|
||||
router.push(`/boards/${boardPublicId}`);
|
||||
},
|
||||
const deleteCardMutation = api.card.delete.useMutation({
|
||||
onSuccess: () => refetchBoard(),
|
||||
onError: () =>
|
||||
showPopup({
|
||||
header: "Error deleting card",
|
||||
message: "Please try again later, or contact customer support.",
|
||||
}),
|
||||
});
|
||||
|
||||
const handleDeleteCard = () => {
|
||||
removeCard({
|
||||
cardPublicId,
|
||||
});
|
||||
closeModal();
|
||||
router.push(`/boards/${boardPublicId}`);
|
||||
deleteCardMutation.mutate({
|
||||
cardPublicId,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="p-5">
|
||||
<div className="flex w-full flex-col justify-between pb-4">
|
||||
<h2 className="text-md pb-4 font-medium text-neutral-900 dark:text-dark-1000">
|
||||
Are you sure you want to delete this card?
|
||||
@@ -39,16 +56,12 @@ export function DeleteCardConfirmation({
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
onClick={() =>
|
||||
deleteCard.mutate({
|
||||
cardPublicId,
|
||||
})
|
||||
}
|
||||
onClick={handleDeleteCard}
|
||||
className="inline-flex justify-center rounded-md bg-light-1000 px-3 py-2 text-sm font-semibold text-light-50 shadow-sm focus-visible:outline-none dark:bg-dark-1000 dark:text-dark-50"
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ export function NewLabelForm({ cardPublicId }: cardPublicId) {
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="p-5">
|
||||
<div className="flex w-full items-center justify-between pb-4 text-neutral-900 dark:text-dark-1000">
|
||||
<h2 className="text-sm font-medium">New label</h2>
|
||||
<button
|
||||
@@ -158,6 +158,6 @@ export function NewLabelForm({ cardPublicId }: cardPublicId) {
|
||||
</div>
|
||||
</Form>
|
||||
</Formik>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user