🔥 Remove deprecated event model (#1775)

This commit is contained in:
Luke Vella 2025-06-14 12:39:02 +02:00 committed by GitHub
parent b1b76b4bec
commit 37b7ed5e19
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 85 additions and 248 deletions

View file

@ -159,7 +159,6 @@ export default async function Page(props: {
title={event.title} title={event.title}
start={event.start} start={event.start}
end={event.end} end={event.end}
status={event.status}
allDay={event.allDay} allDay={event.allDay}
invites={event.invites} invites={event.invites}
/> />

View file

@ -22,6 +22,7 @@ import { Trans } from "@/components/trans";
import { IfCloudHosted } from "@/contexts/environment"; import { IfCloudHosted } from "@/contexts/environment";
import { getTranslation } from "@/i18n/server"; import { getTranslation } from "@/i18n/server";
import { prisma } from "@rallly/database"; import { prisma } from "@rallly/database";
import dayjs from "dayjs";
import { FeedbackAlert } from "./feedback-alert"; import { FeedbackAlert } from "./feedback-alert";
async function loadData() { async function loadData() {
@ -34,7 +35,10 @@ async function loadData() {
}; };
} }
const todayStart = dayjs().startOf("day").toDate();
const todayEnd = dayjs().endOf("day").toDate();
const now = new Date(); const now = new Date();
const [livePollCount, upcomingEventCount] = await Promise.all([ const [livePollCount, upcomingEventCount] = await Promise.all([
prisma.poll.count({ prisma.poll.count({
where: { where: {
@ -43,12 +47,16 @@ async function loadData() {
deleted: false, deleted: false,
}, },
}), }),
prisma.event.count({ prisma.scheduledEvent.count({
where: { where: {
userId: user.id, userId: user.id,
start: { OR: [
gte: now, { allDay: false, start: { gte: now } },
}, {
allDay: true,
start: { gte: todayStart, lte: todayEnd },
},
],
}, },
}), }),
]); ]);

View file

@ -4,7 +4,6 @@ import { CalendarIcon } from "lucide-react";
import { AddToCalendarButton } from "@/components/add-to-calendar-button"; import { AddToCalendarButton } from "@/components/add-to-calendar-button";
import { ParticipantAvatarBar } from "@/components/participant-avatar-bar"; import { ParticipantAvatarBar } from "@/components/participant-avatar-bar";
import { useVisibleParticipants } from "@/components/participants-provider";
import { Trans } from "@/components/trans"; import { Trans } from "@/components/trans";
import { IfParticipantsVisible } from "@/components/visibility"; import { IfParticipantsVisible } from "@/components/visibility";
import { usePoll } from "@/contexts/poll"; import { usePoll } from "@/contexts/poll";
@ -49,15 +48,8 @@ function FinalTime({ start, duration }: { start: Date; duration: number }) {
} }
function useAttendees() { function useAttendees() {
const participants = useVisibleParticipants();
const poll = usePoll(); const poll = usePoll();
return participants.filter((participant) => return poll.event?.attendees ?? [];
participant.votes.some(
(vote) =>
vote.optionId === poll?.event?.optionId &&
(vote.type === "yes" || vote.type === "ifNeedBe"),
),
);
} }
function Attendees() { function Attendees() {
@ -117,8 +109,8 @@ export function ScheduledEvent() {
: undefined : undefined
} }
guests={attendees guests={attendees
.filter((participant) => !!participant.email) .filter((attendee) => !!attendee.email)
.map((participant) => participant.email as string)} .map((attendee) => attendee.email as string)}
/> />
</div> </div>
</div> </div>

View file

@ -48,12 +48,6 @@ export async function getPolls({
image: true, image: true,
}, },
}, },
event: {
select: {
start: true,
duration: true,
},
},
participants: { participants: {
where: { where: {
deleted: false, deleted: false,
@ -95,7 +89,6 @@ export async function getPolls({
email: participant.email ?? undefined, email: participant.email ?? undefined,
image: participant.user?.image ?? undefined, image: participant.user?.image ?? undefined,
})), })),
event: poll.event ?? undefined,
}; };
}), }),
hasNextPage, hasNextPage,

View file

@ -1,99 +0,0 @@
import type { Prisma } from "@rallly/database";
import { prisma } from "@rallly/database";
import { unstable_cache } from "next/cache";
type PollFilters = {
userId: string;
limit?: number;
};
export const getRecentlyUpdatedPolls = async ({
userId,
limit = 3,
}: PollFilters) => {
// Build the where clause based on filters
const where: Prisma.PollWhereInput = {
userId,
deleted: false,
};
const data = await prisma.poll.findMany({
where,
select: {
id: true,
title: true,
status: true,
createdAt: true,
updatedAt: true,
event: {
select: {
start: true,
duration: true,
},
},
participants: {
where: {
deleted: false,
},
select: {
id: true,
name: true,
user: {
select: {
image: true,
},
},
},
orderBy: {
createdAt: "desc",
},
},
options: {
select: {
id: true,
startTime: true,
duration: true,
},
},
},
orderBy: {
updatedAt: "desc",
},
take: limit,
});
return data.map((poll) => {
const { options, ...rest } = poll;
const durations = new Set<number>();
for (const option of options) {
durations.add(option.duration);
}
return {
...rest,
participants: poll.participants.map((participant) => ({
id: participant.id,
name: participant.name,
image: participant.user?.image ?? undefined,
})),
dateOptions: {
first: options[0]?.startTime,
last: options[options.length - 1]?.startTime,
count: options.length,
duration:
durations.size === 1
? (durations.values().next().value as number)
: Array.from(durations),
},
event: poll.event ?? undefined,
};
});
};
export const getCachedRecentlyUpdatedPolls = unstable_cache(
getRecentlyUpdatedPolls,
undefined,
{
revalidate: 60 * 5,
tags: ["polls"],
},
);

View file

@ -31,11 +31,24 @@ export async function getScheduledEvents({
}) { }) {
const now = new Date(); const now = new Date();
const todayStart = dayjs().startOf("day").toDate();
const todayEnd = dayjs().endOf("day").toDate();
const where: Prisma.ScheduledEventWhereInput = { const where: Prisma.ScheduledEventWhereInput = {
userId, userId,
deletedAt: null, deletedAt: null,
...(status !== "past" && { start: { gte: now } }), ...(status === "upcoming" && {
...(status === "past" && { start: { lt: now } }), OR: [
{ allDay: false, start: { gte: now } },
{ allDay: true, start: { gte: todayStart, lte: todayEnd } },
],
}),
...(status === "past" && {
OR: [
{ allDay: false, start: { lt: now } },
{ allDay: true, start: { lt: todayStart } },
],
}),
...(search && { title: { contains: search, mode: "insensitive" } }), ...(search && { title: { contains: search, mode: "insensitive" } }),
status: mapStatus[status], status: mapStatus[status],
}; };
@ -76,10 +89,6 @@ export async function getScheduledEvents({
const events = rawEvents.map((event) => ({ const events = rawEvents.map((event) => ({
...event, ...event,
status:
event.status === "confirmed"
? ((event.start < now ? "past" : "upcoming") as Status)
: event.status,
invites: event.invites.map((invite) => ({ invites: event.invites.map((invite) => ({
id: invite.id, id: invite.id,
inviteeName: invite.inviteeName, inviteeName: invite.inviteeName,

View file

@ -1,8 +1,6 @@
import { ParticipantAvatarBar } from "@/components/participant-avatar-bar"; import { ParticipantAvatarBar } from "@/components/participant-avatar-bar";
import { StackedList } from "@/components/stacked-list"; import { StackedList } from "@/components/stacked-list";
import { Trans } from "@/components/trans"; import { Trans } from "@/components/trans";
import { ScheduledEventStatusBadge } from "@/features/scheduled-event/components/scheduled-event-status-badge";
import type { Status } from "@/features/scheduled-event/schema";
import { FormattedDateTime } from "@/features/timezone/client/formatted-date-time"; import { FormattedDateTime } from "@/features/timezone/client/formatted-date-time";
export const ScheduledEventList = StackedList; export const ScheduledEventList = StackedList;
@ -11,7 +9,6 @@ export function ScheduledEventListItem({
title, title,
start, start,
end, end,
status,
allDay, allDay,
invites, invites,
floating: isFloating, floating: isFloating,
@ -20,7 +17,6 @@ export function ScheduledEventListItem({
title: string; title: string;
start: Date; start: Date;
end: Date; end: Date;
status: Status;
allDay: boolean; allDay: boolean;
invites: { id: string; inviteeName: string; inviteeImage?: string }[]; invites: { id: string; inviteeName: string; inviteeImage?: string }[];
floating: boolean; floating: boolean;
@ -30,9 +26,6 @@ export function ScheduledEventListItem({
<div className="flex flex-1 flex-col gap-y-1 lg:flex-row-reverse lg:justify-end lg:gap-x-4"> <div className="flex flex-1 flex-col gap-y-1 lg:flex-row-reverse lg:justify-end lg:gap-x-4">
<div className="flex items-center gap-4 text-sm"> <div className="flex items-center gap-4 text-sm">
<div>{title}</div> <div>{title}</div>
<div>
<ScheduledEventStatusBadge status={status} />
</div>
</div> </div>
<div className="flex items-center whitespace-nowrap text-sm lg:min-w-40"> <div className="flex items-center whitespace-nowrap text-sm lg:min-w-40">
<div> <div>

View file

@ -7,7 +7,6 @@ import { mergeRouters, router } from "../trpc";
import { auth } from "./auth"; import { auth } from "./auth";
import { dashboard } from "./dashboard"; import { dashboard } from "./dashboard";
import { polls } from "./polls"; import { polls } from "./polls";
import { scheduledEvents } from "./scheduled-events";
import { user } from "./user"; import { user } from "./user";
dayjs.extend(toArray); // used for creating ics dayjs.extend(toArray); // used for creating ics
@ -16,7 +15,6 @@ dayjs.extend(utc);
export const appRouter = mergeRouters( export const appRouter = mergeRouters(
router({ router({
scheduledEvents,
auth, auth,
polls, polls,
user, user,

View file

@ -461,18 +461,27 @@ export const polls = router({
userId: true, userId: true,
guestId: true, guestId: true,
deleted: true, deleted: true,
event: {
select: {
start: true,
duration: true,
optionId: true,
},
},
watchers: { watchers: {
select: { select: {
userId: true, userId: true,
}, },
}, },
scheduledEvent: {
select: {
start: true,
end: true,
allDay: true,
invites: {
select: {
id: true,
inviteeName: true,
inviteeEmail: true,
inviteeTimeZone: true,
status: true,
},
},
},
},
}, },
where: { where: {
id: input.urlId, id: input.urlId,
@ -490,10 +499,33 @@ export const polls = router({
? userId === res.guestId ? userId === res.guestId
: userId === res.userId; : userId === res.userId;
const event = res.scheduledEvent
? {
start: res.scheduledEvent.start,
duration: res.scheduledEvent.allDay
? 0
: dayjs(res.scheduledEvent.end).diff(
dayjs(res.scheduledEvent.start),
"minute",
),
attendees: res.scheduledEvent.invites
.map((invite) => ({
name: invite.inviteeName,
email: invite.inviteeEmail,
status: invite.status,
}))
.filter((invite) => invite.status === "accepted"),
}
: null;
if (isOwner || res.adminUrlId === input.adminToken) { if (isOwner || res.adminUrlId === input.adminToken) {
return { ...res, inviteLink }; return {
...res,
inviteLink,
event,
};
} else { } else {
return { ...res, adminUrlId: "", inviteLink }; return { ...res, adminUrlId: "", inviteLink, event };
} }
}), }),
book: proProcedure book: proProcedure
@ -626,15 +658,6 @@ export const polls = router({
}, },
}, },
}, },
event: {
create: {
optionId: input.optionId,
start: eventStart.toDate(),
duration: option.duration,
title: poll.title,
userId: ctx.user.id,
},
},
}, },
}); });
@ -818,14 +841,6 @@ export const polls = router({
}, },
}); });
if (poll.eventId) {
await prisma.event.delete({
where: {
id: poll.eventId,
},
});
}
if (poll.scheduledEventId) { if (poll.scheduledEventId) {
await prisma.scheduledEvent.delete({ await prisma.scheduledEvent.delete({
where: { where: {

View file

@ -1,63 +0,0 @@
import { prisma } from "@rallly/database";
import dayjs from "dayjs";
import timezone from "dayjs/plugin/timezone";
import toArray from "dayjs/plugin/toArray";
import utc from "dayjs/plugin/utc";
import { z } from "zod";
import { privateProcedure, router } from "../trpc";
dayjs.extend(toArray);
dayjs.extend(timezone);
dayjs.extend(utc);
export const scheduledEvents = router({
list: privateProcedure
.input(
z.object({
period: z.enum(["upcoming", "past"]).default("upcoming"),
}),
)
.query(async ({ input, ctx }) => {
const events = await prisma.event.findMany({
select: {
id: true,
title: true,
start: true,
duration: true,
poll: {
select: {
timeZone: true,
participants: {
select: {
id: true,
name: true,
},
},
},
},
},
where: {
userId: ctx.user.id,
start:
input.period === "upcoming"
? { gte: new Date() }
: { lt: new Date() },
},
orderBy: [
{
start: "desc",
},
{
title: "asc",
},
],
});
return events.map(({ poll, ...event }) => ({
...event,
timeZone: poll?.timeZone || null,
participants: poll?.participants ?? [],
}));
}),
});

View file

@ -0,0 +1,14 @@
/*
Warnings:
- You are about to drop the `events` table. If the table is not empty, all the data it contains will be lost.
*/
-- DropForeignKey
ALTER TABLE "events" DROP CONSTRAINT "events_user_id_fkey";
-- DropForeignKey
ALTER TABLE "polls" DROP CONSTRAINT "polls_event_id_fkey";
-- DropTable
DROP TABLE "events";

View file

@ -1,23 +1,3 @@
/**
* Events are created when a user creates a new event
* @deprecated
*/
model Event {
id String @id @default(cuid())
userId String @map("user_id")
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
optionId String @map("option_id")
title String
start DateTime @db.Timestamp(0)
duration Int @default(0) @map("duration_minutes")
createdAt DateTime @default(now()) @map("created_at")
poll Poll?
@@index([userId], type: Hash)
@@map("events")
}
enum ScheduledEventStatus { enum ScheduledEventStatus {
confirmed confirmed
canceled canceled

View file

@ -39,7 +39,6 @@ model Poll {
requireParticipantEmail Boolean @default(false) @map("require_participant_email") requireParticipantEmail Boolean @default(false) @map("require_participant_email")
user User? @relation(fields: [userId], references: [id], onDelete: Cascade) user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
event Event? @relation(fields: [eventId], references: [id], onDelete: SetNull)
scheduledEvent ScheduledEvent? @relation(fields: [scheduledEventId], references: [id], onDelete: SetNull) scheduledEvent ScheduledEvent? @relation(fields: [scheduledEventId], references: [id], onDelete: SetNull)
options Option[] options Option[]
participants Participant[] participants Participant[]

View file

@ -53,7 +53,6 @@ model User {
comments Comment[] comments Comment[]
polls Poll[] polls Poll[]
watcher Watcher[] watcher Watcher[]
events Event[]
accounts Account[] accounts Account[]
participants Participant[] participants Participant[]
paymentMethods PaymentMethod[] paymentMethods PaymentMethod[]