import { type ComponentPropsWithRef, type ReactNode, useMemo } from 'react'; import { PiCalendarBlank } from 'react-icons/pi'; import { type AnyResource, getTitleOfResource } from '@wener/common/resource'; import { DataViewLayout } from './DataViewLayout'; type IAnyResource = AnyResource & { createdBy?: AnyResource; updatedBy?: AnyResource; }; /** * Get description from resource */ export function getDescriptionOfResource(res?: any): string | undefined { if (res && typeof res === 'object') { return res.description || res.remark; } return undefined; } /** * Format resource title with code */ export function formatResourceTitle(data: IAnyResource): ReactNode { const { code } = data; let primary: ReactNode = data.title || data.fullName; let sec = data.displayName; primary ||= sec; if (sec === primary) { sec = undefined; } return ( {code && {code}} {Boolean(primary) && {primary}} {sec && ({sec})} ); } /** * Format resource meta info (dates, owner, etc.) */ export function formatResourceMeta(data: IAnyResource): ReactNode { const { createdAt, updatedAt, createdBy, updatedBy } = data; const parts: ReactNode[] = []; // Created by if (createdBy) { const creatorName = getTitleOfResource(createdBy); if (creatorName) { parts.push( 创建者: {creatorName} , ); } } // Updated by if (updatedBy && updatedBy.id !== createdBy?.id) { const updaterName = getTitleOfResource(updatedBy); if (updaterName) { parts.push( 更新者: {updaterName} , ); } } // Dates if (createdAt || updatedAt) { const dates: ReactNode[] = []; if (updatedAt) { dates.push( {typeof updatedAt === 'string' ? new Date(updatedAt).toLocaleDateString() : updatedAt.toLocaleDateString()} , ); } if (createdAt && createdAt !== updatedAt) { dates.push( (创建:{' '} {typeof createdAt === 'string' ? new Date(createdAt).toLocaleDateString() : createdAt.toLocaleDateString()} ) , ); } parts.push( {dates} , ); } return parts.length > 0 ? <>{parts.map((p, i) => (i > 0 ? [' • ', p] : p))} : null; } export type ResourceListItemProps = Omit< ComponentPropsWithRef, 'data' | 'title' | 'description' | 'meta' > & { data: AnyResource; showCode?: boolean; // Whether to show resource code in title showMeta?: boolean; // Whether to show meta info (dates, creator, etc.) customTitle?: (data: AnyResource) => ReactNode; customDescription?: (data: AnyResource) => ReactNode; customMeta?: (data: AnyResource) => ReactNode; }; export const ResourceListItem = ({ data, showCode = true, showMeta = true, customTitle, customDescription, customMeta, ...props }: ResourceListItemProps) => { const title = useMemo(() => { if (customTitle) return customTitle(data); return showCode ? formatResourceTitle(data) : getTitleOfResource(data); }, [data, showCode, customTitle]); const description = useMemo(() => { if (customDescription) return customDescription(data); return getDescriptionOfResource(data); }, [data, customDescription]); const meta = useMemo(() => { if (customMeta) return customMeta(data); if (!showMeta) return null; return formatResourceMeta(data); }, [data, showMeta, customMeta]); return ; };