Files
dashboards/apps/business/src/components/PortfolioCard.tsx
T

122 lines
3.9 KiB
TypeScript

import { Link } from 'react-router-dom'
import { Pencil, MessageSquare, Trash2 } from 'lucide-react'
import type { Portfolio } from '../types/portfolio'
import { formatPortfolioCardDate } from '../services/portfolioService'
import { textLocaleAttrs } from '../utils/textLocale'
import { Tooltip } from './Tooltip'
import cardStyles from './PortfolioCard.module.css'
import controlStyles from './ProductCard.module.css'
interface PortfolioCardProps {
portfolio: Portfolio
commentCount: number
onEdit: (id: string) => void
onComments: (id: string) => void
onRemove: (id: string) => void
}
export function PortfolioCard({
portfolio,
commentCount,
onEdit,
onComments,
onRemove,
}: PortfolioCardProps) {
const publishDate = formatPortfolioCardDate(portfolio.publishedAt ?? portfolio.createdAt)
const titleFa = (portfolio.titleFa || portfolio.title || '').trim()
const titleEn = (portfolio.titleEn || '').trim()
const showBothTitles = Boolean(titleFa && titleEn)
const showAbstract = !showBothTitles
const abstractLocale = textLocaleAttrs(portfolio.abstract)
const hasAbstract = Boolean(portfolio.abstract?.trim())
return (
<article className={cardStyles.card}>
<Link to={`/portfolios/detail/${portfolio.id}`} className={cardStyles.clickable}>
<div className={cardStyles.imageWrap}>
{portfolio.titleImageUrl ? (
<img
src={portfolio.titleImageUrl}
alt={titleFa || titleEn || 'Portfolio'}
className={cardStyles.image}
loading="lazy"
/>
) : (
<div className={cardStyles.imagePlaceholder} aria-hidden="true" />
)}
</div>
<div className={cardStyles.body}>
{titleFa ? (
<h3 className={`${cardStyles.titleFa} faText`} lang="fa" dir="rtl">
{titleFa}
</h3>
) : null}
{titleEn ? (
<p className={cardStyles.titleEn} lang="en" dir="ltr">
{titleEn}
</p>
) : null}
{showAbstract ? (
hasAbstract ? (
<p
className={[cardStyles.abstract, abstractLocale.className]
.filter(Boolean)
.join(' ')}
lang={abstractLocale.lang}
dir={abstractLocale.dir}
>
{portfolio.abstract}
</p>
) : (
<p className={cardStyles.abstract} lang="en" dir="ltr">
No summary yet.
</p>
)
) : null}
<p className={cardStyles.meta}>
{portfolio.categoryName ? (
<>
<span>{portfolio.categoryName}</span>
<span className={cardStyles.metaDot}>·</span>
</>
) : null}
<span>{publishDate}</span>
</p>
</div>
</Link>
<div className={controlStyles.controls}>
<Tooltip label="Edit portfolio">
<button type="button" onClick={() => onEdit(portfolio.id)} aria-label="Edit">
<Pencil size={16} />
</button>
</Tooltip>
<Tooltip label="View comments">
<button
type="button"
className={controlStyles.iconBtn}
onClick={() => onComments(portfolio.id)}
aria-label={`Comments (${commentCount})`}
>
<MessageSquare size={16} />
{commentCount > 0 && (
<span className={controlStyles.commentBadge}>{commentCount}</span>
)}
</button>
</Tooltip>
<Tooltip label="Remove portfolio">
<button
type="button"
className={controlStyles.danger}
onClick={() => onRemove(portfolio.id)}
aria-label="Remove"
>
<Trash2 size={16} />
</button>
</Tooltip>
</div>
</article>
)
}