Skip to content

Commit

Permalink
fix: guest availability saving (#110)
Browse files Browse the repository at this point in the history
* fix: πŸ› correct type import

* feat: ✨ read time start and end from db

* fix: πŸ› remove guestForm from pageData, correct type

* feat: ✨ update data on mount

* feat: ✨ read meeting name from db

* fix: πŸ› correct guest availability saving

* fix: πŸ› resolve schema issues

* fix: πŸ› correct data fetching types

* chore: πŸ”§ remove default guest from store
  • Loading branch information
KevinWu098 authored May 31, 2024
1 parent d7919d5 commit fb1c5eb
Show file tree
Hide file tree
Showing 8 changed files with 117 additions and 18 deletions.
11 changes: 11 additions & 0 deletions src/lib/components/availability/LoginModal.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
isEditingAvailability,
isStateUnsaved,
guestSession,
availabilityDates,
} from "$lib/stores/availabilityStores";
import BrightnessAlert from "~icons/material-symbols/brightness-alert-outline-rounded";
import EmailIcon from "~icons/mdi/email";
Expand Down Expand Up @@ -85,6 +86,16 @@
authModal.close();
}
// encodes availabilityDates for formData
const availabilityDatesStrings = $availabilityDates.map((date) => JSON.stringify(date));
const availabilityDatesString = `[${availabilityDatesStrings.join(",")}]`;
formData.append("availabilityDates", availabilityDatesString);
await fetch("/api/availability/saveGuest", {
method: "POST",
body: formData,
});
$guestSession = {
guestName: guestData.data?.username,
meetingId: data.meetingId ?? "",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
let currentPage = 0;
console.log(currentPage, lastPage);
let currentPageAvailability: (ZotDate | null)[];
let selectionState: SelectionStateType | null = null;
Expand Down
7 changes: 6 additions & 1 deletion src/lib/db/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ export const membersInMeeting = pgTable(
{
memberId: text("member_id")
.notNull()
.references(() => users.id, { onDelete: "cascade" }),
.references(() => members.id, { onDelete: "cascade" }),
meetingId: uuid("meeting_id")
.notNull()
.references(() => meetings.id, { onDelete: "cascade" }),
Expand Down Expand Up @@ -257,3 +257,8 @@ export type MeetingInsertSchema = typeof meetings.$inferInsert;
export type MeetingSelectSchema = typeof meetings.$inferSelect;
export type MeetingDateInsertSchema = typeof meetingDates.$inferInsert;
export type MeetingDateSelectSchema = typeof meetingDates.$inferSelect;

export type AvailabilityMeetingDateJoinSchema = {
availabilities: typeof availabilities.$inferSelect;
meeting_dates: typeof meetingDates.$inferSelect;
};
12 changes: 6 additions & 6 deletions src/lib/utils/availability.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { PageData } from "../../routes/availability/[slug]/$types";

import { ZotDate } from "./ZotDate";

import type { AvailabilityInsertSchema } from "$lib/db/schema";
import type { AvailabilityMeetingDateJoinSchema } from "$lib/db/schema";
import type { GuestSession } from "$lib/types/availability";

export async function getGuestAvailability(guestSession: GuestSession) {
Expand All @@ -14,14 +14,14 @@ export async function getGuestAvailability(guestSession: GuestSession) {
},
});

const guestData: AvailabilityInsertSchema[] = await response.json();
const guestData: AvailabilityMeetingDateJoinSchema[] = await response.json();

return guestData?.map(
(availability) =>
new ZotDate(
new Date(availability.day),
new Date(availability.meeting_dates.date),
false,
Array.from(availability.availability_string).map((char) => char === "1"),
Array.from(availability.availabilities.availability_string).map((char) => char === "1"),
),
);
}
Expand All @@ -31,9 +31,9 @@ export const getUserAvailability = (data: PageData) => {
return data.availability?.map(
(availability) =>
new ZotDate(
new Date(availability.day),
new Date(availability.meeting_dates.date),
false,
Array.from(availability.availability_string).map((char) => char === "1"),
Array.from(availability.availabilities.availability_string).map((char) => char === "1"),
),
);
}
Expand Down
12 changes: 9 additions & 3 deletions src/routes/api/availability/+server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { and, eq } from "drizzle-orm";
import type { RequestHandler } from "./$types";

import { db } from "$lib/db/drizzle";
import { availabilities, guests } from "$lib/db/schema";
import { availabilities, guests, meetingDates } from "$lib/db/schema";

export const POST: RequestHandler = async ({ request }) => {
const data = await request.json();
Expand All @@ -25,11 +25,17 @@ export const POST: RequestHandler = async ({ request }) => {
const availability = await db
.select()
.from(availabilities)
.where(eq(availabilities.member_id, guest.id));
.innerJoin(meetingDates, eq(availabilities.meeting_day, meetingDates.id))
.where(
and(
eq(availabilities.member_id, guest.id),
eq(meetingDates.meeting_id, data.meetingId ?? ""),
),
);

if (availability.length == 0) {
return json([]);
}

return json(availability.sort((a, b) => (a.day < b.day ? -1 : 1)));
return json(availability.sort((a, b) => (a.meeting_dates.date > b.meeting_dates.date ? 1 : -1)));
};
76 changes: 76 additions & 0 deletions src/routes/api/availability/saveGuest/+server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { sql } from "drizzle-orm";

import { _getMeetingDates } from "../../../availability/[slug]/+page.server";

import { getExistingGuest, getExistingMeeting } from "$lib/db/databaseUtils.server";
import { db } from "$lib/db/drizzle";
import {
availabilities,
membersInMeeting,
type AvailabilityInsertSchema,
type MeetingDateSelectSchema,
} from "$lib/db/schema";
import type { ZotDate } from "$lib/utils/ZotDate";

export async function POST({ request }: { request: Request }) {
const formData = await request.formData();

const availabilityDates: ZotDate[] = JSON.parse(
(formData.get("availabilityDates") as string) ?? "[]",
);
const meetingId = (formData.get("meetingId") as string) ?? "";

let dbMeetingDates: MeetingDateSelectSchema[] = [];

try {
dbMeetingDates = await _getMeetingDates(meetingId);
} catch (e) {
console.log("Error getting meeting dates:", e);
}

if (!dbMeetingDates || dbMeetingDates.length === 0) return;

try {
const memberId = (
await getExistingGuest(
formData.get("username") as string,
await getExistingMeeting(meetingId),
)
).id;

const insertDates: AvailabilityInsertSchema[] = availabilityDates.map((date, index) => ({
day: new Date(date.day).toISOString(),
member_id: memberId,
meeting_day: dbMeetingDates[index].id as string, // Type-cast since id is guaranteed if a meetingDate exists
availability_string: date.availability.map((bool) => (bool ? "1" : "0")).join(""),
}));

await db.transaction(async (tx) => {
await Promise.all([
tx
.insert(availabilities)
.values(insertDates)
.onConflictDoUpdate({
target: [availabilities.member_id, availabilities.meeting_day],
set: {
// `excluded` refers to the row currently in conflict
availability_string: sql.raw(`excluded.availability_string`),
},
}),
tx
.insert(membersInMeeting)
.values({ memberId, meetingId, attending: "maybe" })
.onConflictDoNothing(),
]);
});

return new Response("Saved guest availability", {
status: 200,
});
} catch (e) {
console.log("Error saving availabilities:", e);
return new Response("Error saving availabilities", {
status: 500,
});
}
}
14 changes: 9 additions & 5 deletions src/routes/availability/[slug]/+page.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
meetingDates,
membersInMeeting,
type AvailabilityInsertSchema,
type AvailabilityMeetingDateJoinSchema,
type MeetingDateSelectSchema,
} from "$lib/db/schema";
import type { ZotDate } from "$lib/utils/ZotDate";
Expand All @@ -27,11 +28,14 @@ export const load: PageServerLoad = (async ({ locals, params }) => {
availability: user ? await getAvailability(user, params?.slug) : null,
meetingId: params?.slug as string | undefined,
meetingData: await getExistingMeeting(params?.slug),
defaultDates: (await getMeetingDates(params?.slug)) ?? [],
defaultDates: (await _getMeetingDates(params?.slug)) ?? [],
};
}) satisfies PageServerLoad;

const getAvailability = async (user: User, meetingId: string | undefined) => {
const getAvailability = async (
user: User,
meetingId: string | undefined,
): Promise<AvailabilityMeetingDateJoinSchema[]> => {
const availability = await db
.select()
.from(availabilities)
Expand All @@ -40,7 +44,7 @@ const getAvailability = async (user: User, meetingId: string | undefined) => {
and(eq(availabilities.member_id, user.id), eq(meetingDates.meeting_id, meetingId ?? "")),
);

return availability.map((item) => item.availabilities).sort((a, b) => (a.day < b.day ? -1 : 1));
return availability.sort((a, b) => (a.meeting_dates.date > b.meeting_dates.date ? 1 : -1));
};

export const actions: Actions = {
Expand All @@ -59,7 +63,7 @@ async function save({ request, locals }: { request: Request; locals: App.Locals
let dbMeetingDates: MeetingDateSelectSchema[] = [];

try {
dbMeetingDates = await getMeetingDates(meetingId);
dbMeetingDates = await _getMeetingDates(meetingId);
} catch (e) {
console.log("Error getting meeting dates:", e);
}
Expand Down Expand Up @@ -119,7 +123,7 @@ async function save({ request, locals }: { request: Request; locals: App.Locals
}
}

async function getMeetingDates(meetingId: string): Promise<MeetingDateSelectSchema[]> {
export async function _getMeetingDates(meetingId: string): Promise<MeetingDateSelectSchema[]> {
const dbMeeting = await getExistingMeeting(meetingId);
const dbMeetingDates = await db
.select()
Expand Down
2 changes: 0 additions & 2 deletions src/routes/summary/+page.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ export const load: PageServerLoad = async ({ cookies }) => {
.groupBy(meetings.id)
.where(eq(availabilities.member_id, user_id));

console.log(meetingList);

const scheduledMeetings = meetingList.filter((meeting) => meeting.scheduled === true);
const scheduled: ScheduledMeeting[] = scheduledMeetings.map((meeting) => {
const meetingDate = meeting.startDate?.toLocaleDateString();
Expand Down

0 comments on commit fb1c5eb

Please sign in to comment.