- Photos: guests and hosts can download all event photos as a ZIP; HEIC/HEIF uploads are now accepted, with a WebP thumbnail generated for gallery display while the original file is preserved for download; uploader name now always shows as a caption - Hosts can send a thank-you note (email/SMS) to guests who RSVP'd yes - Guests can add the event to Google Calendar or download an .ics file, and see a live countdown to the event - Hosts can override a theme's primary/accent colors per event - New textures for a few themes' card backgrounds
91 lines
3.3 KiB
TypeScript
91 lines
3.3 KiB
TypeScript
import Link from 'next/link';
|
|
import { prisma } from '@/lib/prisma';
|
|
import { requireUser } from '@/lib/session';
|
|
import { resolveTheme } from '@/lib/themes';
|
|
import { PageContainer } from '@/components/PageContainer';
|
|
|
|
export default async function DashboardPage() {
|
|
const user = await requireUser();
|
|
|
|
const events = await prisma.event.findMany({
|
|
where: {
|
|
OR: [{ hostId: user.id }, { collaborators: { some: { userId: user.id, status: 'ACCEPTED' } } }],
|
|
},
|
|
orderBy: { eventDate: 'asc' },
|
|
include: {
|
|
_count: { select: { comments: true } },
|
|
rsvps: { select: { status: true, numGuests: true } },
|
|
},
|
|
});
|
|
|
|
return (
|
|
<PageContainer>
|
|
<div className="flex items-center justify-between">
|
|
<h1 className="text-2xl font-bold text-gray-900">Your events</h1>
|
|
<Link
|
|
href="/dashboard/events/new"
|
|
className="rounded-md bg-indigo-600 px-4 py-2 text-sm font-medium text-white hover:bg-indigo-500"
|
|
>
|
|
New event
|
|
</Link>
|
|
</div>
|
|
|
|
{events.length === 0 ? (
|
|
<p className="mt-8 text-gray-600">
|
|
You haven't created any events yet.{' '}
|
|
<Link href="/dashboard/events/new" className="font-medium text-indigo-600 hover:text-indigo-500">
|
|
Create your first invite
|
|
</Link>
|
|
.
|
|
</p>
|
|
) : (
|
|
<ul className="mt-6 flex flex-col gap-3">
|
|
{events.map((event) => {
|
|
const theme = resolveTheme(event.theme, event.themePrimaryColor, event.themeAccentColor);
|
|
const yesCount = event.rsvps
|
|
.filter((r) => r.status === 'YES')
|
|
.reduce((sum, r) => sum + r.numGuests, 0);
|
|
return (
|
|
<li key={event.id}>
|
|
<Link
|
|
href={`/dashboard/events/${event.id}/guests`}
|
|
className="flex items-center justify-between rounded-lg border bg-white px-5 py-4 hover:border-indigo-300"
|
|
>
|
|
<div className="flex items-center gap-3">
|
|
<span
|
|
className="flex h-10 w-10 items-center justify-center rounded-full text-lg"
|
|
style={{ background: theme.colors.bg }}
|
|
>
|
|
{theme.emoji}
|
|
</span>
|
|
<div>
|
|
<p className="font-medium text-gray-900">
|
|
{event.title}
|
|
{event.hostId !== user.id && (
|
|
<span className="ml-2 rounded-full bg-gray-100 px-2 py-0.5 text-xs font-medium text-gray-500">
|
|
Co-hosting
|
|
</span>
|
|
)}
|
|
</p>
|
|
<p className="text-sm text-gray-500">
|
|
{event.eventDate.toLocaleDateString('en-US', {
|
|
dateStyle: 'medium',
|
|
timeZone: event.timezone,
|
|
})}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<div className="text-right text-sm text-gray-500">
|
|
<p>{yesCount} attending</p>
|
|
<p>{event._count.comments} comments</p>
|
|
</div>
|
|
</Link>
|
|
</li>
|
|
);
|
|
})}
|
|
</ul>
|
|
)}
|
|
</PageContainer>
|
|
);
|
|
}
|