([]);
const [isLoading, setIsLoading] = useState(true);
const [isNavigating, setIsNavigating] = useState(false);
+ const [event, setEvent] = useState<{ isArchived: boolean } | null>(null);
const { data: session } = useSession();
- const canEdit = session?.role === "ADMIN" || session?.role === "EDITOR";
+ const canEdit = (session?.role === "ADMIN" || session?.role === "EDITOR") && !event?.isArchived;
// added state
const [locationAdderOpen, setLocationAdderOpen] = useState(false);
@@ -55,7 +56,10 @@ export default function LocationList({ eventId, eventName }: Props) {
eventData?.locations.some((evLoc) => evLoc.locationId === l.id)
)
.sort((a, b) => a.name.localeCompare(b.name)) || [];
- if (active) setLocations(filtered);
+ if (active) {
+ setLocations(filtered);
+ setEvent(eventData ? { isArchived: eventData.isArchived } : null);
+ }
} finally {
if (active) setIsLoading(false);
}
diff --git a/components/layout/ArchivedEventsButton.tsx b/components/layout/ArchivedEventsButton.tsx
new file mode 100644
index 0000000..f0a6e72
--- /dev/null
+++ b/components/layout/ArchivedEventsButton.tsx
@@ -0,0 +1,25 @@
+"use client";
+
+import { Archive } from "lucide-react";
+import { Button } from "../ui/button";
+import { useState } from "react";
+import ArchivedEventsDialog from "../ArchivedEventsDialog";
+
+export default function ArchivedEventsButton() {
+ const [open, setOpen] = useState(false);
+
+ return (
+ <>
+ setOpen(true)}
+ >
+
Archived Events
+
+
+
+ >
+ );
+}
diff --git a/components/layout/sidebar.tsx b/components/layout/sidebar.tsx
index f385ec0..45a2039 100644
--- a/components/layout/sidebar.tsx
+++ b/components/layout/sidebar.tsx
@@ -8,6 +8,7 @@ import Image from "next/image";
import Logo from "@/public/pinpoint-logo-color.png";
import { getRecents } from "@/lib/recents/read";
import Link from "next/link";
+import ArchivedEventsButton from "./ArchivedEventsButton";
export default async function Sidebar() {
const session = await getServerSession();
@@ -47,6 +48,7 @@ export default async function Sidebar() {
))}
+
Settings
diff --git a/lib/api/create/duplicateEvent.ts b/lib/api/create/duplicateEvent.ts
new file mode 100644
index 0000000..0f456b0
--- /dev/null
+++ b/lib/api/create/duplicateEvent.ts
@@ -0,0 +1,75 @@
+"use server";
+
+import CreateEvent from "./createEvent";
+import { SyncLocations, UpdateGettingStarted, UpdateCampusChristmas } from "../update/Event";
+import { GetEventLocationInfo } from "../read/GetEventLocationInfo";
+import SaveState from "../update/ReactFlowSave";
+import { EventWithLocationIds } from "@/types/Event";
+import { revalidatePath } from "next/cache";
+
+/**
+ * Duplicates an event with all its locations and node states
+ * @param eventToCopy - The event to duplicate
+ * @param options - Optional configuration
+ * @returns The newly created event
+ */
+export async function duplicateEvent(
+ eventToCopy: EventWithLocationIds,
+ options?: {
+ nameSuffix?: string;
+ isArchived?: boolean;
+ }
+) {
+ const { nameSuffix = " (Copy)" } = options || {};
+
+ // Create the new event
+ const newEvent = await CreateEvent(eventToCopy.name + nameSuffix);
+
+ // Copy all locations and their states
+ const locationLinks = eventToCopy.locations;
+
+ if (locationLinks && locationLinks.length > 0) {
+ // Extract location IDs directly from the links
+ const locationIds = locationLinks.map((link) => link.locationId);
+
+ if (locationIds.length > 0) {
+ await SyncLocations(newEvent, locationIds);
+
+ // For each location, copy the state from the original event
+ for (const locationId of locationIds) {
+ // Get the original event's state for this location
+ const originalEventLocation = await GetEventLocationInfo(
+ eventToCopy.id,
+ locationId
+ );
+
+ if (originalEventLocation?.state) {
+ // Save the same state to the new event's location
+ await SaveState(
+ newEvent.id,
+ locationId,
+ originalEventLocation.state,
+ "" // Empty client ID since this is a copy operation
+ );
+ }
+ }
+ }
+ }
+
+ // Copy the isGS and isCC flags
+ if (eventToCopy.isGS !== undefined) {
+ await UpdateGettingStarted(newEvent.id, eventToCopy.isGS);
+ }
+ if (eventToCopy.isCC !== undefined) {
+ await UpdateCampusChristmas(newEvent.id, eventToCopy.isCC);
+ }
+
+ // The new event's archive status is determined by the options parameter
+ // By default it's false (not archived) since newly created events start as isArchived: false
+ // If you want to explicitly set it, you can add UpdateArchive call here
+
+ // Revalidate the home page to show the new event
+ revalidatePath("/home");
+
+ return newEvent;
+}
diff --git a/lib/api/read/GetArchivedEvents.ts b/lib/api/read/GetArchivedEvents.ts
new file mode 100644
index 0000000..c795e20
--- /dev/null
+++ b/lib/api/read/GetArchivedEvents.ts
@@ -0,0 +1,28 @@
+"use server";
+
+import { prisma } from "../db";
+
+export async function GetArchivedEvents() {
+ const events = await prisma.event.findMany({
+ where: {
+ isArchived: true,
+ },
+ select: {
+ id: true,
+ name: true,
+ isGS: true,
+ isCC: true,
+ isArchived: true,
+ locations: {
+ select: {
+ id: true,
+ locationId: true,
+ },
+ },
+ },
+ orderBy: {
+ name: 'asc',
+ },
+ });
+ return events;
+}
diff --git a/lib/api/update/Event.ts b/lib/api/update/Event.ts
index e273c4d..c2ce300 100644
--- a/lib/api/update/Event.ts
+++ b/lib/api/update/Event.ts
@@ -62,3 +62,28 @@ export async function UpdateGettingStarted(eventId: string, isGS: boolean) {
},
});
}
+
+export async function UpdateArchive(eventId: string, isArchived: boolean) {
+ revalidatePath("event/");
+ revalidatePath("/home");
+ return await prisma.event.update({
+ where: {
+ id: eventId,
+ },
+ data: {
+ isArchived,
+ },
+ });
+}
+
+export async function UpdateCampusChristmas(eventId: string, isCC: boolean) {
+ revalidatePath("event/");
+ return await prisma.event.update({
+ where: {
+ id: eventId,
+ },
+ data: {
+ isCC,
+ },
+ });
+}
diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index 7f15d45..d396815 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -8,11 +8,13 @@ datasource db {
}
model Event {
- id String @id @default(cuid())
- name String
- isGS Boolean @default(false)
- locations EventToLocation[]
- Recents Recents[]
+ id String @id @default(cuid())
+ name String
+ isGS Boolean @default(false)
+ isCC Boolean @default(false)
+ isArchived Boolean @default(false)
+ locations EventToLocation[]
+ Recents Recents[]
}
model EventToLocation {
diff --git a/types/Event.ts b/types/Event.ts
index 9e8ac18..1ad5252 100644
--- a/types/Event.ts
+++ b/types/Event.ts
@@ -18,5 +18,6 @@ export type EventWithLocations = {
export interface EventWithLocationIds extends Event {
locations: Array<{
id: string;
+ locationId: string;
}>;
}