Skip to content

Commit

Permalink
feat: ✨ save guest availability
Browse files Browse the repository at this point in the history
  • Loading branch information
KevinWu098 committed Apr 16, 2024
1 parent 0b7b2e7 commit 6e9af6b
Show file tree
Hide file tree
Showing 8 changed files with 157 additions and 42 deletions.
28 changes: 23 additions & 5 deletions src/lib/components/availability/LoginModal.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,16 @@
authModal.close();
}
const availabilitySaveForm: HTMLFormElement | null = document.getElementById(
"availabilitySaveForm",
) as HTMLFormElement;
if (availabilitySaveForm) {
availabilitySaveForm.submit();
}
$isEditingAvailability = false;
$isStateUnsaved = false;
// TODO: Update DB with data
}
},
});
Expand All @@ -51,10 +57,21 @@
authModal.close();
}
const availabilitySaveForm: HTMLFormElement | null = document?.getElementById(
"availabilitySaveForm",
) as HTMLFormElement;
if (availabilitySaveForm) {
if ("username" in availabilitySaveForm.elements) {
const username = availabilitySaveForm.elements.username as HTMLInputElement;
username.value = form.data.username;
}
availabilitySaveForm.submit();
}
$isEditingAvailability = false;
$isStateUnsaved = false;
// TODO: Update DB with guest data
}
},
});
Expand Down Expand Up @@ -145,7 +162,7 @@

<form
method="POST"
action="TODO"
action="/auth/guest"
use:guestEnhance
class="flex-center w-full grow flex-col items-center space-y-4 md:w-[250px]"
>
Expand All @@ -168,6 +185,7 @@
type="text"
class="grow appearance-none border-none focus:border-none focus:outline-none focus:ring-0"
placeholder="username"
name="username"
bind:value={$guestForm.username}
/>
</label>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
let currentPageAvailability: (ZotDate | null)[];
const getAvailability = () => {
export const getAvailability = () => {
return data.availability?.map(
(availability) =>
new ZotDate(
Expand Down
38 changes: 35 additions & 3 deletions src/lib/db/databaseUtils.server.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import { eq } from "drizzle-orm";
import { and, eq } from "drizzle-orm";
import type { SuperValidated } from "sveltekit-superforms";
import type { ZodObject, ZodString } from "zod";

import { db } from "./drizzle";
import { members, users } from "./schema";
import type { UserInsertSchema, MemberInsertSchema } from "./schema";
import { members, users, guests } from "./schema";
import type {
UserInsertSchema,
MemberInsertSchema,
MeetingSelectSchema,
GuestInsertSchema,
} from "./schema";

import type { AlertMessageType } from "$lib/types/auth";

Expand All @@ -30,6 +35,18 @@ export const checkIfEmailExists = async (email: string) => {
return queryResult.length > 0;
};

export const checkIfGuestUsernameExists = async (
username: string,
meeting: MeetingSelectSchema,
) => {
const result = await db
.select()
.from(guests)
.where(and(eq(guests.username, username), eq(guests.meeting_id, meeting.id)));

return result.length > 0;
};

export const insertNewMember = async (member: MemberInsertSchema) => {
return await db.insert(members).values(member);
};
Expand All @@ -38,6 +55,10 @@ export const insertNewUser = async (user: UserInsertSchema) => {
return await db.insert(users).values(user);
};

export const insertNewGuest = async (guest: GuestInsertSchema) => {
return await db.insert(guests).values(guest);
};

export const getAllUsers = async () => {
const queryResult = await db
.select({
Expand Down Expand Up @@ -65,3 +86,14 @@ export const getExistingUser = async (

return existingUser;
};

export const getExistingGuest = async (username: string, meeting: MeetingSelectSchema) => {
const [existingGuest] = await db
.select()
.from(guests)
.where(and(eq(guests.username, username), eq(guests.meeting_id, meeting.id)));

console.log("from db", existingGuest);

return existingGuest;
};
1 change: 1 addition & 0 deletions src/lib/db/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,7 @@ export const availabilitiesRelations = relations(availabilities, ({ one }) => ({

export type MemberInsertSchema = typeof members.$inferInsert;
export type UserInsertSchema = typeof users.$inferInsert;
export type GuestInsertSchema = typeof guests.$inferInsert;
export type AvailabilityInsertSchema = typeof availabilities.$inferInsert;
export type MeetingSelectSchema = typeof meetings.$inferSelect;
export type MeetingDateSelectSchema = typeof meetingDates.$inferSelect;
58 changes: 58 additions & 0 deletions src/routes/auth/guest/+page.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { fail } from "@sveltejs/kit";
import { generateId } from "lucia";
import { setError, superValidate } from "sveltekit-superforms/client";

import { _getMeeting } from "../../availability/+page.server";

import { guestSchema } from "$lib/config/zod-schemas";
import {
checkIfGuestUsernameExists,
insertNewGuest,
insertNewMember,
} from "$lib/db/databaseUtils.server";
import type { AlertMessageType } from "$lib/types/auth";

export const _guestSchema = guestSchema.pick({
username: true,
});

export const actions = {
default: createGuest,
};

async function createGuest({ request }: { request: Request }) {
const form = await superValidate<typeof _guestSchema, AlertMessageType>(request, _guestSchema);

if (!form.valid) {
return fail(400, { form });
}

try {
const isGuestUsernameAlreadyRegistered = await checkIfGuestUsernameExists(
form.data.username,
await _getMeeting(),
);

if (isGuestUsernameAlreadyRegistered === true) {
return setError(form, "username", "Guest username already exists");
}

const id = generateId(15);
await insertNewMember({ id: id });
await insertNewGuest({
username: form.data.username,
id: id,
meeting_id: "e3cf0163-e172-40c5-955a-ae9fa1090dc2", // TODO replace with actual meeting id
});
} catch (error) {
console.error(error);

return setError(
form,
"username",
`An error occurred while processing your request. Please try again. Error: ${error}`,
);
}

return { form };
}
2 changes: 0 additions & 2 deletions src/routes/auth/login/+page.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ async function login({ request, cookies }: { request: Request; cookies: Cookies
return fail(400, { form });
}

console.log();

const existingUser = await getExistingUser(form);

if (!existingUser) {
Expand Down
19 changes: 6 additions & 13 deletions src/routes/availability/+page.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { _loginSchema } from "../auth/login/+page.server";
import type { PageServerLoad } from "./$types";

import { guestSchema } from "$lib/config/zod-schemas";
import { getExistingGuest } from "$lib/db/databaseUtils.server";
import { db } from "$lib/db/drizzle";
import {
availabilities,
Expand Down Expand Up @@ -47,15 +48,6 @@ export const actions: Actions = {
async function saveAvailabilities({ request, locals }: { request: Request; locals: App.Locals }) {
const user: User | null = locals.user;

if (!user) {
return {
status: 403,
body: {
error: "Authentication required",
},
};
}

const formData = await request.formData();
const availabilityDates: ZotDate[] = JSON.parse(
(formData.get("availabilityDates") as string) ?? "",
Expand All @@ -77,7 +69,9 @@ async function saveAvailabilities({ request, locals }: { request: Request; local

const availability: AvailabilityInsertSchema = {
day: new Date(date.day).toISOString(),
member_id: user.id,
member_id:
user?.id ??
(await getExistingGuest(formData.get("username") as string, await _getMeeting())).id,
meeting_day: dbMeetingDates[i].id as string, // Type-cast since id is guaranteed if a meetingDate exists
availability_string: date.availability.toString(),
};
Expand All @@ -93,7 +87,6 @@ async function saveAvailabilities({ request, locals }: { request: Request; local
});
}

console.log("success!");
return {
status: 200,
body: {
Expand All @@ -112,15 +105,15 @@ async function saveAvailabilities({ request, locals }: { request: Request; local
}

// Used to access test meeting
async function getMeeting(): Promise<MeetingSelectSchema> {
export async function _getMeeting(): Promise<MeetingSelectSchema> {
const testMeeting = await db.select().from(meetings).where(eq(meetings.title, "default"));

return testMeeting[0];
}

// Used to access test meeting dates of test meeting
async function getMeetingDates(): Promise<MeetingDateSelectSchema[]> {
const testMeeting = await getMeeting();
const testMeeting = await _getMeeting();
const testMeetingDates = await db
.select()
.from(meetingDates)
Expand Down
51 changes: 33 additions & 18 deletions src/routes/availability/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@
import { GroupAvailability, PersonalAvailability } from "$lib/components/availability";
import {
availabilityDates,
generateSampleDates,
isEditingAvailability,
isStateUnsaved,
} from "$lib/stores/availabilityStores";
import { ZotDate } from "$lib/utils/ZotDate";
import { cn } from "$lib/utils/utils";
import CancelCircleOutline from "~icons/mdi/cancel-circle-outline";
import CheckboxMarkerdCircleOutlineIcon from "~icons/mdi/checkbox-marked-circle-outline";
Expand All @@ -16,29 +18,35 @@
let currentTab: number = 0;
// const handleSave = async () => {
// if (!data.user) {
// const authModal = document.getElementById("auth-modal") as HTMLDialogElement;
// if (authModal) {
// authModal.showModal();
// }
// } else {
// console.log("saving:", $availabilityDates);
const handleSave = async (cancel: () => void) => {
if (!data.user) {
const authModal = document.getElementById("auth-modal") as HTMLDialogElement;
if (authModal) {
authModal.showModal();
}
// console.log("saved");
// $isEditingAvailability = false;
// $isStateUnsaved = false;
// }
// };
cancel(); // Prevent the form action, handle with LoginModal instead
}
};
const handleCancel = () => {
// TODO: Repopulate prior state from DB
$availabilityDates = getAvailability() ?? generateSampleDates();
$isEditingAvailability = !$isEditingAvailability;
$isStateUnsaved = false;
};
export const getAvailability = () => {
return data.availability?.map(
(availability) =>
new ZotDate(
new Date(availability.day),
false,
JSON.parse("[" + availability.availability_string + "]"),
),
);
};
let innerWidth = 0;
$: mobileView = innerWidth < 768;
</script>
Expand All @@ -64,15 +72,22 @@
</button>

<form
use:enhance={() => {
return async ({ result }) => {
console.log(result);
use:enhance={({ cancel }) => {
handleSave(cancel);

return async ({ update }) => {
update();

$isEditingAvailability = false;
$isStateUnsaved = false;
};
}}
action="/availability?/saveAvailabilities"
method="POST"
id="availabilitySaveForm"
>
<input type="hidden" name="availabilityDates" value={JSON.stringify($availabilityDates)} />
<input type="hidden" name="username" value={data.user} />
<button
class={cn(
"flex-center btn btn-outline h-8 min-h-fit border-secondary px-2 uppercase text-secondary md:w-24 md:p-0",
Expand Down

0 comments on commit 6e9af6b

Please sign in to comment.