Skip to content

Commit

Permalink
Merge branch 'dev' into I-made-cool-schedule
Browse files Browse the repository at this point in the history
  • Loading branch information
joshuasilva414 committed Oct 24, 2024
2 parents 6e0f5a9 + 3c7d9df commit c7a356e
Show file tree
Hide file tree
Showing 24 changed files with 1,859 additions and 251 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,6 @@ yarn-error.log*

# vscode
.vscode

#Jetbrians
.idea
22 changes: 17 additions & 5 deletions apps/web/src/actions/admin/scanner-admin-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { z } from "zod";
import { db, sql } from "db";
import { scans, userCommonData } from "db/schema";
import { eq, and } from "db/drizzle";

export const createScan = adminAction
.schema(
z.object({
Expand Down Expand Up @@ -65,12 +66,23 @@ export const getScan = adminAction
},
);

export const checkInUser = adminAction
.schema(z.string())
.action(async ({ parsedInput: user }) => {
// Schema will be moved over when rewrite of the other scanner happens
const checkInUserSchema = z.object({
userID: z.string(),
QRTimestamp: z
.number()
.positive()
.refine((timestamp) => {
return Date.now() - timestamp < 5 * 60 * 1000;
}, "QR Code has expired. Please tell user refresh the QR Code"),
});

export const checkInUserToHackathon = adminAction
.schema(checkInUserSchema)
.action(async ({ parsedInput: { userID } }) => {
// Set checkinTimestamp
return await db
await db
.update(userCommonData)
.set({ checkinTimestamp: sql`now()` })
.where(eq(userCommonData.clerkID, user));
.where(eq(userCommonData.clerkID, userID));
});
187 changes: 165 additions & 22 deletions apps/web/src/actions/user-profile-mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,54 +3,198 @@
import { authenticatedAction } from "@/lib/safe-action";
import { z } from "zod";
import { db } from "db";
import { userCommonData } from "db/schema";
import { userCommonData, userHackerData } from "db/schema";
import { eq } from "db/drizzle";
import { put } from "@vercel/blob";
import { decodeBase64AsFile } from "@/lib/utils/shared/files";
import { returnValidationErrors } from "next-safe-action";
import { revalidatePath } from "next/cache";
import { getUser } from "db/functions";
import { getUser, getUserByTag } from "db/functions";
import { RegistrationSettingsFormValidator } from "@/validators/shared/RegistrationSettingsForm";

// TODO: Add skill updating
export const modifyRegistrationData = authenticatedAction
.schema(RegistrationSettingsFormValidator)
.action(
async ({
parsedInput: {
age,
gender,
race,
ethnicity,
isEmailable,
university,
major,
levelOfStudy,
schoolID,
hackathonsAttended,
softwareBuildingExperience,
heardAboutEvent,
shirtSize,
dietaryRestrictions,
accommodationNote,
github,
linkedin,
personalWebsite,
phoneNumber,
countryOfResidence,
},
ctx: { userId },
}) => {
const user = await getUser(userId);
if (!user) throw new Error("User not found");
await Promise.all([
db
.update(userCommonData)
.set({
age,
gender,
race,
ethnicity,
shirtSize,
dietRestrictions: dietaryRestrictions,
accommodationNote,
phoneNumber,
countryOfResidence,
})
.where(eq(userCommonData.clerkID, user.clerkID)),
db
.update(userHackerData)
.set({
isEmailable,
university,
major,
levelOfStudy,
schoolID,
hackathonsAttended,
softwareExperience: softwareBuildingExperience,
heardFrom: heardAboutEvent,
GitHub: github,
LinkedIn: linkedin,
PersonalWebsite: personalWebsite,
})
.where(eq(userHackerData.clerkID, user.clerkID)),
]);
return {
success: true,
newAge: age,
newGender: gender,
newRace: race,
newEthnicity: ethnicity,
newWantsToReceiveMLHEmails: isEmailable,
newUniversity: university,
newMajor: major,
newLevelOfStudy: levelOfStudy,
newSchoolID: schoolID,
newHackathonsAttended: hackathonsAttended,
newSoftwareExperience: softwareBuildingExperience,
newHeardFrom: heardAboutEvent,
newShirtSize: shirtSize,
newDietaryRestrictions: dietaryRestrictions,
newAccommodationNote: accommodationNote,
newGitHub: github,
newLinkedIn: linkedin,
newPersonalWebsite: personalWebsite,
newPhoneNumber: phoneNumber,
newCountryOfResidence: countryOfResidence,
};
},
);

export const modifyResume = authenticatedAction
.schema(
z.object({
bio: z.string().max(500),
skills: z.string().max(100),
resume: z.string(),
}),
)
.action(async ({ parsedInput: { bio, skills }, ctx: { userId } }) => {
const user = await getUser(userId);
if (!user)
returnValidationErrors(z.null(), { _errors: ["User not found"] });

.action(async ({ parsedInput: { resume }, ctx: { userId } }) => {
await db
.update(userCommonData)
.set({ bio })
.where(eq(userCommonData.clerkID, user.clerkID));
return { success: true, newbio: bio };
.update(userHackerData)
.set({ resume })
.where(eq(userHackerData.clerkID, userId));
return {
success: true,
newResume: resume,
};
});

export const modifyProfileData = authenticatedAction
.schema(
z.object({
pronouns: z.string(),
bio: z.string(),
skills: z.string().array(),
discord: z.string(),
}),
)
.action(
async ({
parsedInput: { bio, discord, pronouns, skills },
ctx: { userId },
}) => {
const user = await getUser(userId);
if (!user) {
throw new Error("User not found");
}
await db
.update(userCommonData)
.set({ pronouns, bio, skills, discord })
.where(eq(userCommonData.clerkID, user.clerkID));
return {
success: true,
newPronouns: pronouns,
newBio: bio,
newSkills: skills,
newDiscord: discord,
};
},
);

// TODO: Fix after registration enhancements to allow for failure on conflict and return appropriate error message
export const modifyAccountSettings = authenticatedAction
.schema(
z.object({
firstName: z.string().min(1).max(50),
lastName: z.string().min(1).max(50),
hackerTag: z.string().min(1).max(50),
hasSearchableProfile: z.boolean(),
}),
)
.action(
async ({ parsedInput: { firstName, lastName }, ctx: { userId } }) => {
async ({
parsedInput: {
firstName,
lastName,
hackerTag,
hasSearchableProfile,
},
ctx: { userId },
}) => {
const user = await getUser(userId);
if (!user) throw new Error("User not found");

let oldHackerTag = user.hackerTag; // change when hackertag is not PK on profileData table
if (oldHackerTag != hackerTag)
if (await getUserByTag(hackerTag))
//if hackertag changed
// copied from /api/registration/create
return {
success: false,
message: "hackertag_not_unique",
};
await db
.update(userCommonData)
.set({ firstName, lastName })
.set({
firstName,
lastName,
hackerTag,
isSearchable: hasSearchableProfile,
})
.where(eq(userCommonData.clerkID, userId));
return {
success: true,
newFirstName: firstName,
newLastName: lastName,
newHackerTag: hackerTag,
newHasSearchableProfile: hasSearchableProfile,
};
},
);
Expand All @@ -60,11 +204,10 @@ export const updateProfileImage = authenticatedAction
.action(
async ({ parsedInput: { fileBase64, fileName }, ctx: { userId } }) => {
const image = await decodeBase64AsFile(fileBase64, fileName);
const user = await getUser(userId);
if (!user)
returnValidationErrors(z.null(), {
_errors: ["User not found"],
});
const user = await db.query.userCommonData.findFirst({
where: eq(userCommonData.clerkID, userId),
});
if (!user) throw new Error("User not found");

const blobUpload = await put(image.name, image, {
access: "public",
Expand Down
4 changes: 3 additions & 1 deletion apps/web/src/app/admin/check-in/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ export default async function Page({
);

const scanUser = await getUser(searchParams.user);
if (!scanUser)
console.log(scanUser);
if (!scanUser) {
return (
<div>
<CheckinScanner
Expand All @@ -30,6 +31,7 @@ export default async function Page({
/>
</div>
);
}

return (
<div>
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/app/dash/pass/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ function EventPass({ qrPayload, user, clerk, guild }: EventPassProps) {
<h1 className="mt-2 text-center text-4xl font-bold">
{user.firstName}
</h1>
<div className="flex w-full items-center justify-center space-x-5">
<div className="flex flex-col w-full items-center justify-center space-y-3 pt-2">
<h3 className="text-center font-mono text-sm">
@{user.hackerTag}
</h3>
Expand Down
15 changes: 0 additions & 15 deletions apps/web/src/app/settings/account/page.tsx

This file was deleted.

15 changes: 9 additions & 6 deletions apps/web/src/app/settings/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,15 @@ export default async function ({ children }: { children: ReactNode }) {
</div>
</div>
</div>
<div>
{/* <SettingsSection name="Settings" path="/settings" /> */}
<SettingsSection name="Account" path="/settings/account" />
<SettingsSection name="Profile" path="/settings/profile" />
</div>
<div className="col-span-4">{children}</div>
<aside className="sticky top-20 hidden h-screen md:block">
<SettingsSection name="Account" path="/settings#account" />
<SettingsSection name="Profile" path="/settings#profile" />
<SettingsSection
name="Registration"
path="/settings#registration"
/>
</aside>
<div className="col-span-4 mb-20 ml-5">{children}</div>
</div>
</>
);
Expand Down
33 changes: 31 additions & 2 deletions apps/web/src/app/settings/page.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,32 @@
export default function Page() {
return <span>howdy</span>;
import AccountSettings from "@/components/settings/AccountSettings";
import { auth } from "@clerk/nextjs";
import { redirect } from "next/navigation";
import ProfileSettings from "@/components/settings/ProfileSettings";
import RegistrationSettings from "@/components/settings/RegistrationSettings";
import { getUser } from "db/functions";

export default async function Page() {
const { userId } = auth();
if (!userId) return redirect("/sign-in");
const user = await getUser(userId);
if (!user) return redirect("/sign-in");

return (
<main>
<Header tag="Account" />
<AccountSettings user={user} />
<Header tag="Profile" />
<ProfileSettings profile={user} />
<Header tag={"Registration"} />
<RegistrationSettings />
</main>
);
}

function Header({ tag }: { tag: string }) {
return (
<h1 id={tag.toLowerCase()} className="mt-10 pb-5 text-4xl font-bold">
{tag}
</h1>
);
}
19 changes: 0 additions & 19 deletions apps/web/src/app/settings/profile/page.tsx

This file was deleted.

Loading

0 comments on commit c7a356e

Please sign in to comment.