feat: card will indicate icons of comments and description (#222)

* feat: card will indicate icons of comments and description

* fix: comments limit to one

* feat: fetch comments for public boards

---------

Co-authored-by: Henry <henry_ball@hotmail.co.uk>
This commit is contained in:
Ridham Khandar
2025-10-24 01:10:04 +05:30
committed by GitHub
parent 4ffc7e3696
commit bb4784fd28
4 changed files with 82 additions and 33 deletions

View File

@@ -1,3 +1,5 @@
import { HiBars3BottomLeft, HiChatBubbleLeft } from "react-icons/hi2";
import Avatar from "~/components/Avatar"; import Avatar from "~/components/Avatar";
import Badge from "~/components/Badge"; import Badge from "~/components/Badge";
import CircularProgress from "~/components/CircularProgress"; import CircularProgress from "~/components/CircularProgress";
@@ -9,6 +11,8 @@ const Card = ({
labels, labels,
members, members,
checklists, checklists,
description,
comments,
}: { }: {
title: string; title: string;
labels: { name: string; colourCode: string | null }[]; labels: { name: string; colourCode: string | null }[];
@@ -27,6 +31,8 @@ const Card = ({
index: number; index: number;
}[]; }[];
}[]; }[];
description: string | null;
comments: { publicId: string }[];
}) => { }) => {
const completedItems = checklists.reduce((acc, checklist) => { const completedItems = checklists.reduce((acc, checklist) => {
return acc + checklist.items.filter((item) => item.completed).length; return acc + checklist.items.filter((item) => item.completed).length;
@@ -39,10 +45,17 @@ const Card = ({
const progress = const progress =
totalItems > 0 ? Math.round((completedItems / totalItems) * 100) : 0; totalItems > 0 ? Math.round((completedItems / totalItems) * 100) : 0;
const hasDescription =
description && description.replace(/<[^>]*>/g, "").trim().length > 0;
return ( return (
<div className="flex 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-200 dark:text-dark-1000 dark:hover:bg-dark-300"> <div className="flex 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-200 dark:text-dark-1000 dark:hover:bg-dark-300">
<span>{title}</span> <span>{title}</span>
{labels.length || members.length || checklists.length > 0 ? ( {labels.length ||
members.length ||
checklists.length > 0 ||
hasDescription ||
comments.length > 0 ? (
<div className="mt-2 flex flex-col justify-end"> <div className="mt-2 flex flex-col justify-end">
<div className="space-x-0.5"> <div className="space-x-0.5">
{labels.map((label) => ( {labels.map((label) => (
@@ -52,37 +65,51 @@ const Card = ({
/> />
))} ))}
</div> </div>
<div className="flex items-center justify-end gap-1"> <div className="mt-2 flex items-center justify-between gap-1">
{checklists.length > 0 && ( <div className="flex items-center gap-2">
<div className="flex items-center gap-1 rounded-full border-[1px] border-light-300 px-2 py-1 dark:border-dark-600"> {hasDescription && (
<CircularProgress <div className="flex items-center gap-1 text-light-700 dark:text-dark-800">
progress={progress || 2} <HiBars3BottomLeft className="h-4 w-4" />
size="sm" </div>
className="flex-shrink-0" )}
/> {comments.length > 0 && (
<span className="text-[10px] text-light-900 dark:text-dark-950"> <div className="flex items-center gap-1 text-light-700 dark:text-dark-800">
{completedItems}/{totalItems} <HiChatBubbleLeft className="h-4 w-4" />
</span> </div>
</div> )}
)} </div>
{members.length > 0 && ( <div className="flex items-center justify-end gap-1">
<div className="isolate flex justify-end -space-x-1 overflow-hidden"> {checklists.length > 0 && (
{members.map(({ user, email }) => { <div className="flex items-center gap-1 rounded-full border-[1px] border-light-300 px-2 py-1 dark:border-dark-600">
const avatarUrl = user?.image <CircularProgress
? getAvatarUrl(user.image) progress={progress || 2}
: undefined; size="sm"
className="flex-shrink-0"
/>
<span className="text-[10px] text-light-900 dark:text-dark-950">
{completedItems}/{totalItems}
</span>
</div>
)}
{members.length > 0 && (
<div className="isolate flex justify-end -space-x-1 overflow-hidden">
{members.map(({ user, email }) => {
const avatarUrl = user?.image
? getAvatarUrl(user.image)
: undefined;
return ( return (
<Avatar <Avatar
name={user?.name ?? ""} name={user?.name ?? ""}
email={user?.email ?? email} email={user?.email ?? email}
imageUrl={avatarUrl} imageUrl={avatarUrl}
size="sm" size="sm"
/> />
); );
})} })}
</div> </div>
)} )}
</div>
</div> </div>
</div> </div>
) : null} ) : null}

View File

@@ -546,6 +546,8 @@ export default function BoardPage({ isTemplate }: { isTemplate?: boolean }) {
labels={card.labels} labels={card.labels}
members={card.members} members={card.members}
checklists={card.checklists ?? []} checklists={card.checklists ?? []}
description={card.description ?? null}
comments={card.comments ?? []}
/> />
</Link> </Link>
)} )}

View File

@@ -45,7 +45,10 @@ export default function PublicBoardView() {
members: formatToArray(router.query.members), members: formatToArray(router.query.members),
labels: formatToArray(router.query.labels), labels: formatToArray(router.query.labels),
}, },
{ enabled: router.isReady && !!boardSlug, placeholderData: keepPreviousData }, {
enabled: router.isReady && !!boardSlug,
placeholderData: keepPreviousData,
},
); );
const CopyBoardLink = () => { const CopyBoardLink = () => {
@@ -156,7 +159,7 @@ export default function PublicBoardView() {
) : ( ) : (
<div className="flex"> <div className="flex">
<div className="min-w-[2rem]" /> <div className="min-w-[2rem]" />
{data.lists.map((list) => ( {data?.lists.map((list) => (
<div <div
key={list.publicId} key={list.publicId}
className="dark-text-dark-1000 mr-5 h-fit min-w-[18rem] max-w-[18rem] rounded-md border border-light-400 bg-light-300 py-2 pl-2 pr-1 text-neutral-900 dark:border-dark-300 dark:bg-dark-100" className="dark-text-dark-1000 mr-5 h-fit min-w-[18rem] max-w-[18rem] rounded-md border border-light-400 bg-light-300 py-2 pl-2 pr-1 text-neutral-900 dark:border-dark-300 dark:bg-dark-100"
@@ -182,6 +185,8 @@ export default function PublicBoardView() {
labels={card.labels} labels={card.labels}
checklists={card.checklists ?? []} checklists={card.checklists ?? []}
members={[]} members={[]}
description={card.description}
comments={card.comments ?? []}
/> />
</Link> </Link>
))} ))}

View File

@@ -10,6 +10,7 @@ import {
cardToWorkspaceMembers, cardToWorkspaceMembers,
checklistItems, checklistItems,
checklists, checklists,
comments,
labels, labels,
lists, lists,
workspaceMembers, workspaceMembers,
@@ -215,6 +216,13 @@ export const getByPublicId = async (
}, },
}, },
}, },
comments: {
columns: {
publicId: true,
},
where: isNull(comments.deletedAt),
limit: 1,
},
}, },
where: and( where: and(
cardIds.length > 0 ? inArray(cards.publicId, cardIds) : undefined, cardIds.length > 0 ? inArray(cards.publicId, cardIds) : undefined,
@@ -335,6 +343,13 @@ export const getBySlug = async (
}, },
}, },
}, },
comments: {
columns: {
publicId: true,
},
where: isNull(comments.deletedAt),
limit: 1,
},
checklists: { checklists: {
columns: { columns: {
publicId: true, publicId: true,