feat: create new card immediately displays new card
This commit is contained in:
@@ -6,10 +6,12 @@ import React, {
|
||||
} from "react";
|
||||
|
||||
import { api } from "~/utils/api";
|
||||
import { generateUID } from "~/utils/generateUID";
|
||||
import { usePopup } from "~/providers/popup";
|
||||
|
||||
import {
|
||||
type GetBoardByIdOutput,
|
||||
type NewCardInput,
|
||||
type ReorderCardInput,
|
||||
type ReorderListInput,
|
||||
} from "~/types/router.types";
|
||||
@@ -19,6 +21,8 @@ interface BoardContextProps {
|
||||
setBoardData: React.Dispatch<React.SetStateAction<GetBoardByIdOutput>>;
|
||||
updateList: (params: ReorderListInput) => void;
|
||||
updateCard: (params: ReorderCardInput) => void;
|
||||
addCard: (params: NewCardInput) => void;
|
||||
refetchBoard: () => void;
|
||||
}
|
||||
|
||||
const initialBoardData: GetBoardByIdOutput = {
|
||||
@@ -44,12 +48,18 @@ export const BoardProvider: React.FC<{ children: ReactNode }> = ({
|
||||
const { showPopup } = usePopup();
|
||||
|
||||
const refetchBoard = async () => {
|
||||
if (boardData?.publicId) {
|
||||
try {
|
||||
await utils.board.byId.refetch({ boardPublicId: boardData.publicId });
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
if (!boardData?.publicId) return;
|
||||
|
||||
try {
|
||||
const data = await utils.board.byId.fetch({
|
||||
boardPublicId: boardData.publicId,
|
||||
});
|
||||
if (data) setBoardData(data);
|
||||
} catch (e) {
|
||||
showPopup({
|
||||
header: "Error fetching board",
|
||||
message: "Please try again later, or contact customer support.",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -75,6 +85,50 @@ export const BoardProvider: React.FC<{ children: ReactNode }> = ({
|
||||
},
|
||||
});
|
||||
|
||||
const addCard = ({
|
||||
title,
|
||||
listPublicId,
|
||||
labelPublicIds,
|
||||
memberPublicIds,
|
||||
position,
|
||||
}: {
|
||||
title: string;
|
||||
listPublicId: string;
|
||||
labelPublicIds: string[];
|
||||
memberPublicIds: string[];
|
||||
position: "start" | "end";
|
||||
}) => {
|
||||
if (!boardData) return;
|
||||
|
||||
const updatedLists = boardData.lists.map((list) => {
|
||||
if (list.publicId === listPublicId) {
|
||||
const newCard = {
|
||||
publicId: generateUID(),
|
||||
title,
|
||||
listId: 2,
|
||||
description: "",
|
||||
labels: boardData.labels.filter((label) =>
|
||||
labelPublicIds.includes(label.publicId),
|
||||
),
|
||||
members:
|
||||
boardData.workspace?.members.filter((member) =>
|
||||
memberPublicIds.includes(member.publicId),
|
||||
) || [],
|
||||
index: position === "start" ? 0 : list.cards.length,
|
||||
};
|
||||
|
||||
const updatedCards =
|
||||
position === "start"
|
||||
? [newCard, ...list.cards]
|
||||
: [...list.cards, newCard];
|
||||
return { ...list, cards: updatedCards };
|
||||
}
|
||||
return list;
|
||||
});
|
||||
|
||||
setBoardData({ ...boardData, lists: updatedLists });
|
||||
};
|
||||
|
||||
const updateList = ({
|
||||
boardId,
|
||||
listId,
|
||||
@@ -99,16 +153,23 @@ export const BoardProvider: React.FC<{ children: ReactNode }> = ({
|
||||
|
||||
return (
|
||||
<BoardContext.Provider
|
||||
value={{ boardData, setBoardData, updateList, updateCard }}
|
||||
value={{
|
||||
boardData,
|
||||
setBoardData,
|
||||
updateList,
|
||||
updateCard,
|
||||
addCard,
|
||||
refetchBoard,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</BoardContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useBoard = (): BoardContextProps => {
|
||||
export const useBoard = () => {
|
||||
const context = useContext(BoardContext);
|
||||
if (!context) {
|
||||
if (context === undefined) {
|
||||
throw new Error("useBoard must be used within a BoardProvider");
|
||||
}
|
||||
return context;
|
||||
|
||||
@@ -11,8 +11,10 @@ import {
|
||||
import { Switch } from "@headlessui/react";
|
||||
|
||||
import CheckboxDropdown from "~/components/CheckboxDropdown";
|
||||
|
||||
import { useBoard } from "~/providers/board";
|
||||
import { useModal } from "~/providers/modal";
|
||||
import { usePopup } from "~/providers/popup";
|
||||
|
||||
import { type NewCardInput } from "~/types/router.types";
|
||||
|
||||
@@ -30,7 +32,8 @@ function classNames(...classes: string[]): string {
|
||||
|
||||
export function NewCardForm({ listPublicId }: NewCardFormProps) {
|
||||
const utils = api.useUtils();
|
||||
const { boardData } = useBoard();
|
||||
const { boardData, addCard, refetchBoard } = useBoard();
|
||||
const { showPopup } = usePopup();
|
||||
const { closeModal } = useModal();
|
||||
|
||||
const { register, handleSubmit, reset, setValue, watch } =
|
||||
@@ -50,31 +53,17 @@ export function NewCardForm({ listPublicId }: NewCardFormProps) {
|
||||
const isCreateAnotherEnabled = watch("isCreateAnotherEnabled");
|
||||
const position = watch("position");
|
||||
|
||||
const refetchBoard = async () => {
|
||||
if (boardData?.publicId) {
|
||||
try {
|
||||
await utils.board.byId.refetch({ boardPublicId: boardData.publicId });
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const createCard = api.card.create.useMutation({
|
||||
onSuccess: async () => {
|
||||
try {
|
||||
await refetchBoard();
|
||||
if (!isCreateAnotherEnabled) closeModal();
|
||||
reset({
|
||||
title: "",
|
||||
listPublicId: watch("listPublicId"),
|
||||
labelPublicIds: [],
|
||||
memberPublicIds: [],
|
||||
isCreateAnotherEnabled: watch("isCreateAnotherEnabled"),
|
||||
});
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
refetchBoard();
|
||||
},
|
||||
onError: async () => {
|
||||
closeModal();
|
||||
refetchBoard();
|
||||
showPopup({
|
||||
header: "Unable to create card",
|
||||
message: "Please try again later, or contact customer support.",
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@@ -106,6 +95,17 @@ export function NewCardForm({ listPublicId }: NewCardFormProps) {
|
||||
})) ?? [];
|
||||
|
||||
const onSubmit = (data: NewCardInput) => {
|
||||
addCard(data);
|
||||
const isCreateAnotherEnabled = watch("isCreateAnotherEnabled");
|
||||
if (!isCreateAnotherEnabled) closeModal();
|
||||
reset({
|
||||
title: "",
|
||||
listPublicId: watch("listPublicId"),
|
||||
labelPublicIds: [],
|
||||
memberPublicIds: [],
|
||||
isCreateAnotherEnabled,
|
||||
});
|
||||
|
||||
createCard.mutate({
|
||||
title: data.title,
|
||||
listPublicId: data.listPublicId,
|
||||
@@ -277,9 +277,10 @@ export function NewCardForm({ listPublicId }: NewCardFormProps) {
|
||||
</CheckboxDropdown>
|
||||
</div>
|
||||
<button
|
||||
onClick={() =>
|
||||
setValue("position", position === "start" ? "end" : "start")
|
||||
}
|
||||
onClick={(e) => {
|
||||
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"
|
||||
>
|
||||
{position === "start" ? (
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState } from "react";
|
||||
import { useState, useEffect } from "react";
|
||||
import Link from "next/link";
|
||||
import { useParams } from "next/navigation";
|
||||
import { HiOutlinePlusSmall } from "react-icons/hi2";
|
||||
@@ -61,9 +61,11 @@ export default function BoardPage() {
|
||||
},
|
||||
);
|
||||
|
||||
if (isSuccess && data) {
|
||||
setBoardData(data);
|
||||
}
|
||||
useEffect(() => {
|
||||
if (isSuccess && data) {
|
||||
setBoardData(data);
|
||||
}
|
||||
}, [isSuccess, data, setBoardData]);
|
||||
|
||||
if (!boardId || !boardData) return <></>;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user