wip
This commit is contained in:
83
apps/website/components/feed/FeedItemCard.tsx
Normal file
83
apps/website/components/feed/FeedItemCard.tsx
Normal file
@@ -0,0 +1,83 @@
|
||||
import Card from '@/components/ui/Card';
|
||||
import Button from '@/components/ui/Button';
|
||||
import type { FeedItem } from '@gridpilot/social/domain/entities/FeedItem';
|
||||
import { friends } from '@gridpilot/testing-support';
|
||||
|
||||
function timeAgo(timestamp: Date): string {
|
||||
const diffMs = Date.now() - timestamp.getTime();
|
||||
const diffMinutes = Math.floor(diffMs / 60000);
|
||||
if (diffMinutes < 1) return 'Just now';
|
||||
if (diffMinutes < 60) return `${diffMinutes} min ago`;
|
||||
const diffHours = Math.floor(diffMinutes / 60);
|
||||
if (diffHours < 24) return `${diffHours} h ago`;
|
||||
const diffDays = Math.floor(diffHours / 24);
|
||||
return `${diffDays} d ago`;
|
||||
}
|
||||
|
||||
function getActor(item: FeedItem) {
|
||||
if (item.actorFriendId) {
|
||||
const friend = friends.find(f => f.driverId === item.actorFriendId);
|
||||
if (friend) {
|
||||
return {
|
||||
name: friend.displayName,
|
||||
avatarUrl: friend.avatarUrl
|
||||
};
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
interface FeedItemCardProps {
|
||||
item: FeedItem;
|
||||
}
|
||||
|
||||
export default function FeedItemCard({ item }: FeedItemCardProps) {
|
||||
const actor = getActor(item);
|
||||
|
||||
return (
|
||||
<div className="flex gap-4">
|
||||
<div className="flex-shrink-0">
|
||||
{actor ? (
|
||||
<div className="w-10 h-10 rounded-full overflow-hidden bg-charcoal-outline">
|
||||
<img
|
||||
src={actor.avatarUrl}
|
||||
alt={actor.name}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<Card className="w-10 h-10 flex items-center justify-center rounded-full bg-primary-blue/10 border-primary-blue/40 p-0">
|
||||
<span className="text-xs text-primary-blue font-semibold">
|
||||
{item.type.startsWith('friend') ? 'FR' : 'LG'}
|
||||
</span>
|
||||
</Card>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="flex items-start justify-between gap-2">
|
||||
<div>
|
||||
<p className="text-sm text-white">{item.headline}</p>
|
||||
{item.body && (
|
||||
<p className="text-xs text-gray-400 mt-1">{item.body}</p>
|
||||
)}
|
||||
</div>
|
||||
<span className="text-[11px] text-gray-500 whitespace-nowrap">
|
||||
{timeAgo(item.timestamp)}
|
||||
</span>
|
||||
</div>
|
||||
{(item.ctaHref && item.ctaLabel) && (
|
||||
<div className="mt-3">
|
||||
<Button
|
||||
as="a"
|
||||
href={item.ctaHref}
|
||||
variant="secondary"
|
||||
className="text-xs px-4 py-2"
|
||||
>
|
||||
{item.ctaLabel}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user