import Link from "next/link";
import { useRouter } from "next/router";
import { t } from "@lingui/core/macro";
import { useEffect, useState } from "react";
import { useForm } from "react-hook-form";
import { IoChevronForwardSharp } from "react-icons/io5";
import Avatar from "~/components/Avatar";
import Editor from "~/components/Editor";
import FeedbackModal from "~/components/FeedbackModal";
import { LabelForm } from "~/components/LabelForm";
import LabelIcon from "~/components/LabelIcon";
import Modal from "~/components/modal";
import { NewWorkspaceForm } from "~/components/NewWorkspaceForm";
import { PageHead } from "~/components/PageHead";
import { useModal } from "~/providers/modal";
import { usePopup } from "~/providers/popup";
import { useWorkspace } from "~/providers/workspace";
import { api } from "~/utils/api";
import { invalidateCard } from "~/utils/cardInvalidation";
import { formatMemberDisplayName, getAvatarUrl } from "~/utils/helpers";
import { DeleteLabelConfirmation } from "../../components/DeleteLabelConfirmation";
import ActivityList from "./components/ActivityList";
import { AttachmentThumbnails } from "./components/AttachmentThumbnails";
import { AttachmentUpload } from "./components/AttachmentUpload";
import Checklists from "./components/Checklists";
import { DeleteCardConfirmation } from "./components/DeleteCardConfirmation";
import { DeleteChecklistConfirmation } from "./components/DeleteChecklistConfirmation";
import { DeleteCommentConfirmation } from "./components/DeleteCommentConfirmation";
import Dropdown from "./components/Dropdown";
import { DueDateSelector } from "./components/DueDateSelector";
import LabelSelector from "./components/LabelSelector";
import ListSelector from "./components/ListSelector";
import MemberSelector from "./components/MemberSelector";
import { NewChecklistForm } from "./components/NewChecklistForm";
import NewCommentForm from "./components/NewCommentForm";
interface FormValues {
cardId: string;
title: string;
description: string;
}
export function CardRightPanel({ isTemplate }: { isTemplate?: boolean }) {
const router = useRouter();
const cardId = Array.isArray(router.query.cardId)
? router.query.cardId[0]
: router.query.cardId;
const { data: card } = api.card.byId.useQuery({
cardPublicId: cardId ?? "",
});
const board = card?.list.board;
const labels = board?.labels;
const workspaceMembers = board?.workspace.members;
const selectedLabels = card?.labels;
const selectedMembers = card?.members;
const formattedLabels =
labels?.map((label) => {
const isSelected = selectedLabels?.some(
(selectedLabel) => selectedLabel.publicId === label.publicId,
);
return {
key: label.publicId,
value: label.name,
selected: isSelected ?? false,
leftIcon: ,
};
}) ?? [];
const formattedLists =
board?.lists.map((list) => ({
key: list.publicId,
value: list.name,
selected: list.publicId === card?.list.publicId,
})) ?? [];
const formattedMembers =
workspaceMembers?.map((member) => {
const isSelected = selectedMembers?.some(
(assignedMember) => assignedMember.publicId === member.publicId,
);
return {
key: member.publicId,
value: formatMemberDisplayName(
member.user?.name ?? null,
member.user?.email ?? member.email,
),
imageUrl: member.user?.image
? getAvatarUrl(member.user.image)
: undefined,
selected: isSelected ?? false,
leftIcon: (
),
};
}) ?? [];
return (
);
}
export default function CardPage({ isTemplate }: { isTemplate?: boolean }) {
const router = useRouter();
const utils = api.useUtils();
const {
modalContentType,
entityId,
openModal,
getModalState,
clearModalState,
isOpen,
modalStates,
} = useModal();
const { showPopup } = usePopup();
const { workspace } = useWorkspace();
const [activeChecklistForm, setActiveChecklistForm] = useState(
null,
);
const cardId = Array.isArray(router.query.cardId)
? router.query.cardId[0]
: router.query.cardId;
const { data: card, isLoading } = api.card.byId.useQuery({
cardPublicId: cardId ?? "",
});
const refetchCard = async () => {
if (cardId) await utils.card.byId.refetch({ cardPublicId: cardId });
};
const board = card?.list.board;
const boardId = board?.publicId;
const updateCard = api.card.update.useMutation({
onError: () => {
showPopup({
header: t`Unable to update card`,
message: t`Please try again later, or contact customer support.`,
icon: "error",
});
},
onSettled: async () => {
if (cardId) await invalidateCard(utils, cardId);
},
});
const addOrRemoveLabel = api.card.addOrRemoveLabel.useMutation({
onError: () => {
showPopup({
header: t`Unable to add label`,
message: t`Please try again later, or contact customer support.`,
icon: "error",
});
},
onSettled: async () => {
if (cardId) {
await utils.card.byId.invalidate({ cardPublicId: cardId });
}
},
});
const { register, handleSubmit, setValue, watch } = useForm({
values: {
cardId: cardId ?? "",
title: card?.title ?? "",
description: card?.description ?? "",
},
});
const onSubmit = (values: FormValues) => {
updateCard.mutate({
cardPublicId: values.cardId,
title: values.title,
description: values.description,
});
};
// this adds the new created label to selected labels
useEffect(() => {
const newLabelId = modalStates.NEW_LABEL_CREATED;
if (newLabelId && cardId) {
const isAlreadyAdded = card?.labels.some(
(label) => label.publicId === newLabelId,
);
if (!isAlreadyAdded) {
addOrRemoveLabel.mutate({
cardPublicId: cardId,
labelPublicId: newLabelId,
});
}
clearModalState("NEW_LABEL_CREATED");
}
}, [modalStates.NEW_LABEL_CREATED, card, cardId]);
// Open the new item form after creating a new checklist
useEffect(() => {
if (!card) return;
const state = getModalState("ADD_CHECKLIST");
const createdId: string | undefined = state?.createdChecklistId;
if (createdId) {
setActiveChecklistForm(createdId);
clearModalState("ADD_CHECKLIST");
}
}, [card, getModalState, clearModalState]);
// Auto-resize title textarea
useEffect(() => {
const titleTextarea = document.getElementById(
"title",
) as HTMLTextAreaElement;
if (titleTextarea) {
titleTextarea.style.height = "auto";
titleTextarea.style.height = `${titleTextarea.scrollHeight}px`;
}
}, [card]);
if (!cardId) return <>>;
return (
<>
{/* Full-width top strip with board link and dropdown */}
{!card && isLoading && (
)}
{card && (
<>
{workspace.name}
{board?.name}
>
)}
{!card && !isLoading && (
{t`Card not found`}
)}
{!card && isLoading && (
)}
{card && (
)}
{!card && !isLoading && (
{t`Card not found`}
)}
{card && (
<>
{!isTemplate && (
<>
{card?.attachments.length > 0 && (
)}
>
)}
{t`Activity`}
{!isTemplate && (
)}
>
)}
<>
>
>
);
}