import { t } from "@lingui/core/macro"; import { Trans } from "@lingui/react/macro"; import { formatDistanceToNow } from "date-fns"; import { de, enGB, es, fr, it, nl } from "date-fns/locale"; import { HiOutlineArrowLeft, HiOutlineArrowRight, HiOutlinePencil, HiOutlinePlus, HiOutlineTag, HiOutlineUserMinus, HiOutlineUserPlus, } from "react-icons/hi2"; import type { GetCardByIdOutput } from "@kan/api/types"; import { authClient } from "@kan/auth/client"; import Avatar from "~/components/Avatar"; import { useLocalisation } from "~/hooks/useLocalisation"; import Comment from "./Comment"; type ActivityType = NonNullable["activities"][number]["type"]; const dateLocaleMap = { en: enGB, fr: fr, de: de, es: es, it: it, nl: nl, } as const; const getActivityText = ({ type, toTitle, fromList, toList, memberName, isSelf, label, }: { type: ActivityType; toTitle: string | null; fromList: string | null; toList: string | null; memberName: string | null; isSelf: boolean; label: string | null; }) => { const ACTIVITY_TYPE_MAP = { "card.created": t`created the card`, "card.updated.title": t`updated the title`, "card.updated.description": t`updated the description`, "card.updated.list": t`moved the card to another list`, "card.updated.label.added": t`added a label to the card`, "card.updated.label.removed": t`removed a label from the card`, "card.updated.member.added": t`added a member to the card`, "card.updated.member.removed": t`removed a member from the card`, } as const; if (!(type in ACTIVITY_TYPE_MAP)) return null; const baseText = ACTIVITY_TYPE_MAP[type as keyof typeof ACTIVITY_TYPE_MAP]; const TextHighlight = ({ children }: { children: React.ReactNode }) => ( {children} ); if (type === "card.updated.title" && toTitle) { return ( updated the title to {toTitle} ); } if (type === "card.updated.list" && fromList && toList) { return ( moved the card from {fromList} to {toList} ); } if (type === "card.updated.member.added" && memberName) { if (isSelf) return self-assigned the card; return ( assigned {memberName} to the card ); } if (type === "card.updated.member.removed" && memberName) { if (isSelf) return unassigned themselves from the card; return ( unassigned {memberName} from the card ); } if (type === "card.updated.label.added" && label) { return ( added label {label} ); } if (type === "card.updated.label.removed" && label) { return ( removed label {label} ); } return baseText; }; const ACTIVITY_ICON_MAP: Partial> = { "card.created": , "card.updated.title": , "card.updated.description": , "card.updated.label.added": , "card.updated.label.removed": , "card.updated.member.added": , "card.updated.member.removed": , } as const; const getActivityIcon = ( type: ActivityType, fromIndex?: number | null, toIndex?: number | null, ): React.ReactNode | null => { if (type === "card.updated.list" && fromIndex != null && toIndex != null) { return fromIndex > toIndex ? ( ) : ( ); } return ACTIVITY_ICON_MAP[type] ?? null; }; const ActivityList = ({ activities, cardPublicId, isLoading, isAdmin, }: { activities: NonNullable["activities"]; cardPublicId: string; isLoading: boolean; isAdmin?: boolean; }) => { const { data } = authClient.useSession(); const { locale } = useLocalisation(); const currentDateLocale = dateLocaleMap[locale] || enGB; return (
{activities.map((activity, index) => { const activityText = getActivityText({ type: activity.type, toTitle: activity.toTitle, fromList: activity.fromList?.name ?? null, toList: activity.toList?.name ?? null, memberName: activity.member?.user?.name ?? null, isSelf: activity.member?.user?.id === data?.user.id, label: activity.label?.name ?? null, }); if (activity.type === "card.updated.comment.added") return ( ); if (!activityText) return null; return (
{index !== activities.length - 1 && activities[index + 1]?.type !== "card.updated.comment.added" && (
)}

{`${activity.user?.name} `} {activityText} ยท {formatDistanceToNow(new Date(activity.createdAt), { addSuffix: true, locale: currentDateLocale, })}

); })}
); }; export default ActivityList;