129 lines
4.4 KiB
TypeScript
129 lines
4.4 KiB
TypeScript
import { Link } from 'react-router-dom'
|
|
import { FileText, Zap, PenTool, LayoutGrid, ChevronRight } from 'lucide-react'
|
|
import type { CreateType } from '../../data/createData'
|
|
import type { DocumentRecord } from '../../lib/documents'
|
|
import {
|
|
formatRelativeTime,
|
|
getActivityDate,
|
|
getProjectColor,
|
|
getProjectIcon,
|
|
typeColors,
|
|
typeLabels,
|
|
} from '../../lib/documentUtils'
|
|
|
|
const typeIcons: Record<CreateType, typeof FileText> = {
|
|
silo: FileText,
|
|
shed: Zap,
|
|
sketch: PenTool,
|
|
stead: LayoutGrid,
|
|
}
|
|
|
|
function getActionLabel(doc: DocumentRecord): string {
|
|
const created = new Date(doc.createdAt).getTime()
|
|
const updated = new Date(doc.updatedAt).getTime()
|
|
if (Math.abs(updated - created) < 5000) {
|
|
return `Created by ${doc.createdBy}`
|
|
}
|
|
return `Updated by ${doc.createdBy}`
|
|
}
|
|
|
|
interface RecentActivitiesProps {
|
|
documents: DocumentRecord[]
|
|
loading?: boolean
|
|
onViewAll?: () => void
|
|
}
|
|
|
|
export default function RecentActivities({
|
|
documents,
|
|
loading,
|
|
onViewAll,
|
|
}: RecentActivitiesProps) {
|
|
const items = documents.slice(0, 8)
|
|
|
|
return (
|
|
<div className="rounded-2xl border border-silos-cream-dark bg-white">
|
|
<div className="flex items-center justify-between border-b border-silos-cream-dark px-5 py-4">
|
|
<h3 className="font-semibold text-silos-text">Recent Activities</h3>
|
|
{items.length > 0 && (
|
|
<button
|
|
type="button"
|
|
onClick={onViewAll}
|
|
className="text-sm font-medium text-silos-tan hover:text-silos-brown"
|
|
>
|
|
View all
|
|
</button>
|
|
)}
|
|
</div>
|
|
|
|
{loading ? (
|
|
<ul className="divide-y divide-silos-cream-dark">
|
|
{Array.from({ length: 4 }).map((_, i) => (
|
|
<li key={i} className="px-5 py-4">
|
|
<div className="h-10 animate-pulse rounded-lg bg-silos-cream" />
|
|
</li>
|
|
))}
|
|
</ul>
|
|
) : items.length === 0 ? (
|
|
<div className="px-5 py-12 text-center text-sm text-silos-muted">
|
|
No activity yet. Create a Silo, Sketch, Shed, or Stead to get started.
|
|
</div>
|
|
) : (
|
|
<ul className="divide-y divide-silos-cream-dark">
|
|
{items.map((doc) => {
|
|
const Icon = typeIcons[doc.type]
|
|
const color = doc.type === 'stead' ? getProjectColor(doc) : typeColors[doc.type]
|
|
const initial = doc.createdBy[0]?.toUpperCase() ?? '?'
|
|
|
|
return (
|
|
<li key={doc.id}>
|
|
<Link
|
|
to={`/workspace/${doc.type}/${doc.id}`}
|
|
className="flex w-full items-center gap-4 px-5 py-4 text-left transition-colors hover:bg-silos-cream/40"
|
|
>
|
|
<div
|
|
className="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg"
|
|
style={{ backgroundColor: `${color}22` }}
|
|
>
|
|
{doc.type === 'stead' ? (
|
|
<span className="text-lg">{getProjectIcon(doc)}</span>
|
|
) : (
|
|
<Icon className="h-5 w-5" style={{ color }} />
|
|
)}
|
|
</div>
|
|
<div className="min-w-0 flex-1">
|
|
<p className="truncate font-medium text-silos-text">{doc.title}</p>
|
|
<p className="mt-0.5 truncate text-sm text-silos-muted">
|
|
{getActionLabel(doc)} · {typeLabels[doc.type]}
|
|
</p>
|
|
</div>
|
|
<div className="flex shrink-0 items-center gap-3">
|
|
<span className="hidden text-xs text-silos-muted sm:inline">
|
|
{formatRelativeTime(getActivityDate(doc))}
|
|
</span>
|
|
<div
|
|
className="flex h-7 w-7 items-center justify-center rounded-full text-xs font-semibold text-white"
|
|
style={{ backgroundColor: color }}
|
|
>
|
|
{initial}
|
|
</div>
|
|
</div>
|
|
</Link>
|
|
</li>
|
|
)
|
|
})}
|
|
</ul>
|
|
)}
|
|
|
|
{items.length > 0 && (
|
|
<button
|
|
type="button"
|
|
onClick={onViewAll}
|
|
className="flex w-full items-center justify-center gap-1 border-t border-silos-cream-dark py-3.5 text-sm font-medium text-silos-brown transition-colors hover:bg-silos-cream/40"
|
|
>
|
|
View all recent activities
|
|
<ChevronRight className="h-4 w-4" />
|
|
</button>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|