feat: organizers, meetups UI, Plausible analytics, and migration tooling
- Add organizer model/API, admin and public organizer pages, meetup cards - Refresh events/home/contact; add calendar dialog and carousel components - Optional Plausible via NEXT_PUBLIC_PLAUSIBLE_* env vars in root layout - Prisma migration, seed updates, baseline-and-migrate script Made-with: Cursor
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
import { MapPin, Clock, ArrowRight, CalendarPlus } from "lucide-react";
|
||||
import { MapPin, Clock, ArrowRight } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { AddToCalendarButton } from "@/components/public/AddToCalendarDialog";
|
||||
import { formatMeetupCivilDate } from "@/lib/meetupEventTime";
|
||||
|
||||
interface MeetupData {
|
||||
id?: string;
|
||||
@@ -9,21 +11,13 @@ interface MeetupData {
|
||||
location?: string;
|
||||
link?: string;
|
||||
description?: string;
|
||||
organizer?: { name: string; slug?: string };
|
||||
}
|
||||
|
||||
interface MeetupsSectionProps {
|
||||
meetups: MeetupData[];
|
||||
}
|
||||
|
||||
function formatMeetupDate(dateStr: string) {
|
||||
const d = new Date(dateStr);
|
||||
return {
|
||||
month: d.toLocaleString("en-US", { month: "short" }).toUpperCase(),
|
||||
day: String(d.getDate()),
|
||||
full: d.toLocaleString("en-US", { weekday: "long", month: "long", day: "numeric", year: "numeric" }),
|
||||
};
|
||||
}
|
||||
|
||||
export function MeetupsSection({ meetups }: MeetupsSectionProps) {
|
||||
return (
|
||||
<section className="py-24 px-8 border-t border-zinc-800/50">
|
||||
@@ -36,14 +30,7 @@ export function MeetupsSection({ meetups }: MeetupsSectionProps) {
|
||||
<h2 className="text-3xl font-black tracking-tight">Upcoming Meetups</h2>
|
||||
</div>
|
||||
<div className="hidden md:flex items-center gap-4">
|
||||
<a
|
||||
href="/calendar.ics"
|
||||
title="Subscribe to get all future meetups automatically"
|
||||
className="flex items-center gap-1.5 text-xs text-on-surface-variant/60 hover:text-primary border border-zinc-700 hover:border-primary/50 rounded-lg px-3 py-1.5 transition-all"
|
||||
>
|
||||
<CalendarPlus size={14} />
|
||||
Add to Calendar
|
||||
</a>
|
||||
<AddToCalendarButton />
|
||||
<Link
|
||||
href="/events"
|
||||
className="flex items-center gap-2 text-sm text-primary font-semibold hover:gap-3 transition-all"
|
||||
@@ -62,7 +49,10 @@ export function MeetupsSection({ meetups }: MeetupsSectionProps) {
|
||||
) : (
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-5">
|
||||
{meetups.map((meetup, i) => {
|
||||
const { month, day, full } = formatMeetupDate(meetup.date);
|
||||
const civil = formatMeetupCivilDate(meetup.date);
|
||||
const month = civil?.monthShort ?? "—";
|
||||
const day = civil?.day ?? "--";
|
||||
const full = civil?.full ?? "";
|
||||
const href = meetup.id ? `/events/${meetup.id}` : "#upcoming-meetups";
|
||||
|
||||
return (
|
||||
@@ -92,6 +82,13 @@ export function MeetupsSection({ meetups }: MeetupsSectionProps) {
|
||||
</p>
|
||||
)}
|
||||
|
||||
<p className="text-[11px] text-on-surface-variant/50 font-medium uppercase tracking-wide mb-2">
|
||||
Organized by{" "}
|
||||
<span className="text-on-surface-variant/70 normal-case tracking-normal">
|
||||
{meetup.organizer?.name || "Belgian Bitcoin Embassy"}
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<div className="flex flex-col gap-1.5 mt-auto pt-4 border-t border-zinc-800/60">
|
||||
{meetup.location && (
|
||||
<p className="flex items-center gap-1.5 text-xs text-on-surface-variant/60">
|
||||
@@ -123,13 +120,7 @@ export function MeetupsSection({ meetups }: MeetupsSectionProps) {
|
||||
>
|
||||
All events <ArrowRight size={16} />
|
||||
</Link>
|
||||
<a
|
||||
href="/calendar.ics"
|
||||
className="flex items-center gap-1.5 text-xs text-on-surface-variant/60 hover:text-primary border border-zinc-700 hover:border-primary/50 rounded-lg px-3 py-1.5 transition-all"
|
||||
>
|
||||
<CalendarPlus size={14} />
|
||||
Add to Calendar
|
||||
</a>
|
||||
<AddToCalendarButton />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
Reference in New Issue
Block a user