'use client' /** * InvestorUpdateCard (pure presentation). * * Two densities — `default` (uses `AdminContentCard`) and `sm` (compact * horizontal). The card writes NO click logic — callers wrap with their * own anchor and pass the resolved detail URL via `href`. */ import React from 'react' import { Calendar } from 'lucide-react' import { AdminContentCard } from './admin-content-card' import { EntityPortraitCard } from './entity-portrait-card' import { formatInvestorUpdatePeriod, type InvestorUpdate } from '../types/entities/investor-update' import { useEntityCardLink } from './use-entity-card-link' import { useEntityCardPlaceholder } from './use-entity-card-placeholder' import { COMPACT_CARD_IMAGE_SLOT, COMPACT_CARD_META_ROW_BOX, COMPACT_CARD_OUTER, COMPACT_CARD_ROW_FILLER, COMPACT_CARD_SKELETON_IMAGE_SLOT, COMPACT_CARD_SKELETON_OUTER, COMPACT_CARD_SUBTITLE, COMPACT_CARD_SUMMARY, COMPACT_CARD_TEXT_COL, COMPACT_CARD_TITLE, COMPACT_CARD_TITLE_ROW, } from '../utils/compact-card-classes' export interface InvestorUpdateCardProps { update: InvestorUpdate href: string /** When `_blank`, opens in a new tab. Set by chat dispatch via * `computeIsNewTab`. Defaults to same-tab. */ target?: '_blank' rel?: 'noopener noreferrer' targetPlatform?: string | null /** OG placeholder URL used when `update.featured_image` is missing. */ placeholderUrl?: string | null size?: 'default' | 'sm' | 'portrait' /** Portrait density: render the content-type chip. Mixed rails only; single-type rails pass false. Default true. */ showTypeBadge?: boolean className?: string } /** `portrait` shares the default skeleton shape (same zone boxes). */ export function InvestorUpdateCardSkeleton({ size = 'default' }: { size?: 'default' | 'sm' | 'portrait' }) { if (size === 'sm') { return ( ) } return (
) } export function InvestorUpdateCard({ update, href, target: targetProp, rel: relProp, targetPlatform, placeholderUrl: placeholderUrlProp, size = 'default', showTypeBadge = true, className, }: InvestorUpdateCardProps) { const { target, rel } = useEntityCardLink({ href, targetPlatform, target: targetProp, rel: relProp, }) const placeholderUrl = useEntityCardPlaceholder({ title: update.title ?? `Update #${update.update_number ?? ''}`, placeholderUrl: placeholderUrlProp, aspect: size === 'sm' ? 'square' : 'wide', }) const coverImage = update.featured_image || placeholderUrl || null if (size === 'sm') { const periodText = formatInvestorUpdatePeriod(update.period_start, update.period_end) return ( {coverImage ? ( {update.title { ;(e.currentTarget as HTMLImageElement).style.display = 'none' }} /> ) : ( )} {update.title || `Update #${update.update_number ?? '?'}`} {update.update_number ? ( #{update.update_number} ) : null} {periodText || 'Investor update'} {(update.strategic_update || update.content || '').slice(0, 120) || COMPACT_CARD_ROW_FILLER} ) } if (size === 'portrait') { // Rail/strip density — shared shell. The reporting // period is the meaningful footer line (no fabricated author — no avatar // renders an initial circle). const periodText = formatInvestorUpdatePeriod(update.period_start, update.period_end) return ( ) } return ( #{update.update_number} ) : undefined } meta={ (update.period_start || update.period_end) ? (
{formatInvestorUpdatePeriod(update.period_start, update.period_end)}
) : undefined } />
) }