Initial commit: Meshkee dashboards monorepo.

Includes business, customer, and super-admin apps with shared packages and production deploy scripts.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Alireza Hassani
2026-07-22 13:48:53 +03:30
co-authored by Cursor
commit f566387c61
509 changed files with 62690 additions and 0 deletions
@@ -0,0 +1,93 @@
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 { 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)
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={portfolio.title}
className={cardStyles.image}
loading="lazy"
/>
) : (
<div className={cardStyles.imagePlaceholder} aria-hidden="true" />
)}
</div>
<div className={cardStyles.body}>
<h3 className={cardStyles.title}>{portfolio.title}</h3>
{portfolio.abstract ? (
<p className={cardStyles.abstract}>{portfolio.abstract}</p>
) : (
<p className={cardStyles.abstract}>No summary yet.</p>
)}
<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>
)
}