Files
stack/apps/web/src/components/dashboard/UpcomingEventsWidget.tsx
T
Jason Woltje f47dd8bc92 feat: add domains, ideas, layouts, widgets API modules
- Add DomainsModule with full CRUD, search, and activity logging
- Add IdeasModule with quick capture endpoint
- Add LayoutsModule for user dashboard layouts
- Add WidgetsModule for widget definitions (read-only)
- Update ActivityService with domain/idea logging methods
- Register all new modules in AppModule
2026-01-29 13:47:03 -06:00

67 lines
2.3 KiB
TypeScript

import type { Event } from "@mosaic/shared";
import { formatTime, formatDate } from "@/lib/utils/date-format";
import Link from "next/link";
interface UpcomingEventsWidgetProps {
events: Event[];
isLoading: boolean;
}
export function UpcomingEventsWidget({ events, isLoading }: UpcomingEventsWidgetProps) {
if (isLoading) {
return (
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
<div className="flex justify-center items-center">
<div className="animate-spin rounded-full h-6 w-6 border-b-2 border-gray-900"></div>
<span className="ml-3 text-gray-600">Loading events...</span>
</div>
</div>
);
}
const upcomingEvents = events.slice(0, 4);
return (
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
<div className="flex items-center justify-between mb-4">
<h2 className="text-lg font-semibold text-gray-900">Upcoming Events</h2>
<Link
href="/calendar"
className="text-sm text-blue-600 hover:text-blue-700"
>
View calendar
</Link>
</div>
{upcomingEvents.length === 0 ? (
<p className="text-sm text-gray-500 text-center py-4">No upcoming events</p>
) : (
<div className="space-y-3">
{upcomingEvents.map((event) => (
<div
key={event.id}
className="flex items-start gap-3 p-3 rounded-lg border-l-4 border-blue-500 bg-gray-50"
>
<div className="flex-shrink-0 text-center min-w-[3.5rem]">
<div className="text-xs text-gray-500 uppercase font-semibold">
{formatDate(event.startTime).split(',')[0]}
</div>
<div className="text-sm font-medium text-gray-900">
{formatTime(event.startTime)}
</div>
</div>
<div className="flex-1 min-w-0">
<h3 className="font-medium text-gray-900 text-sm truncate">
{event.title}
</h3>
{event.location && (
<p className="text-xs text-gray-500 mt-0.5">📍 {event.location}</p>
)}
</div>
</div>
))}
</div>
)}
</div>
);
}