Skip to content

Commit 5db5fb8

Browse files
HK-180-Fixed Extra Resumes (#145)
1 parent f1e6b5c commit 5db5fb8

File tree

9 files changed

+736
-498
lines changed

9 files changed

+736
-498
lines changed

apps/web/src/actions/user-profile-mod.ts

Lines changed: 94 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,22 @@ import { z } from "zod";
55
import { db } from "db";
66
import { userCommonData, userHackerData } from "db/schema";
77
import { eq } from "db/drizzle";
8-
import { put } from "@vercel/blob";
8+
import { del } from "@vercel/blob";
99
import { decodeBase64AsFile } from "@/lib/utils/shared/files";
10-
import { returnValidationErrors } from "next-safe-action";
1110
import { revalidatePath } from "next/cache";
12-
import { getUser, getUserByTag } from "db/functions";
13-
import { RegistrationSettingsFormValidator } from "@/validators/shared/RegistrationSettingsForm";
11+
import { UNIQUE_KEY_CONSTRAINT_VIOLATION_CODE } from "@/lib/constants";
12+
import c from "config";
13+
import { DatabaseError } from "db/types";
14+
import {
15+
registrationSettingsFormValidator,
16+
modifyAccountSettingsSchema,
17+
profileSettingsSchema,
18+
} from "@/validators/settings";
19+
import { clerkClient, type User as ClerkUser } from "@clerk/nextjs/server";
20+
import { PAYLOAD_TOO_LARGE_CODE } from "@/lib/constants";
1421

1522
export const modifyRegistrationData = authenticatedAction
16-
.schema(RegistrationSettingsFormValidator)
23+
.schema(registrationSettingsFormValidator)
1724
.action(
1825
async ({
1926
parsedInput: {
@@ -37,12 +44,12 @@ export const modifyRegistrationData = authenticatedAction
3744
personalWebsite,
3845
phoneNumber,
3946
countryOfResidence,
47+
uploadedFile,
4048
},
4149
ctx: { userId },
4250
}) => {
43-
const user = await getUser(userId);
44-
if (!user) throw new Error("User not found");
4551
await Promise.all([
52+
// attempts to update both tables with Promise.all
4653
db
4754
.update(userCommonData)
4855
.set({
@@ -56,7 +63,7 @@ export const modifyRegistrationData = authenticatedAction
5663
phoneNumber,
5764
countryOfResidence,
5865
})
59-
.where(eq(userCommonData.clerkID, user.clerkID)),
66+
.where(eq(userCommonData.clerkID, userId)),
6067
db
6168
.update(userHackerData)
6269
.set({
@@ -71,9 +78,18 @@ export const modifyRegistrationData = authenticatedAction
7178
GitHub: github,
7279
LinkedIn: linkedin,
7380
PersonalWebsite: personalWebsite,
81+
resume: uploadedFile,
7482
})
75-
.where(eq(userHackerData.clerkID, user.clerkID)),
76-
]);
83+
.where(eq(userHackerData.clerkID, userId)),
84+
]).catch(async (err) => {
85+
console.log(
86+
`Error occured at modify registration data: ${err}`,
87+
);
88+
// If there's an error
89+
return {
90+
success: false,
91+
};
92+
});
7793
return {
7894
success: true,
7995
newAge: age,
@@ -96,99 +112,72 @@ export const modifyRegistrationData = authenticatedAction
96112
newPersonalWebsite: personalWebsite,
97113
newPhoneNumber: phoneNumber,
98114
newCountryOfResidence: countryOfResidence,
115+
newUploadedFile: uploadedFile,
99116
};
100117
},
101118
);
102119

103-
export const modifyResume = authenticatedAction
120+
export const deleteResume = authenticatedAction
104121
.schema(
105122
z.object({
106-
resume: z.string(),
123+
oldFileLink: z.string(),
107124
}),
108125
)
109-
.action(async ({ parsedInput: { resume }, ctx: { userId } }) => {
126+
.action(async ({ parsedInput: { oldFileLink } }) => {
127+
if (oldFileLink === c.noResumeProvidedURL) return null;
128+
await del(oldFileLink);
129+
});
130+
131+
export const modifyProfileData = authenticatedAction
132+
.schema(profileSettingsSchema)
133+
.action(async ({ parsedInput, ctx: { userId } }) => {
110134
await db
111-
.update(userHackerData)
112-
.set({ resume })
113-
.where(eq(userHackerData.clerkID, userId));
135+
.update(userCommonData)
136+
.set({
137+
...parsedInput,
138+
skills: parsedInput.skills.map((v) => v.toLowerCase()),
139+
})
140+
.where(eq(userCommonData.clerkID, userId));
114141
return {
115142
success: true,
116-
newResume: resume,
117143
};
118144
});
119145

120-
export const modifyProfileData = authenticatedAction
121-
.schema(
122-
z.object({
123-
pronouns: z.string(),
124-
bio: z.string(),
125-
skills: z.string().array(),
126-
discord: z.string(),
127-
}),
128-
)
129-
.action(
130-
async ({
131-
parsedInput: { bio, discord, pronouns, skills },
132-
ctx: { userId },
133-
}) => {
134-
const user = await getUser(userId);
135-
if (!user) {
136-
throw new Error("User not found");
137-
}
138-
await db
139-
.update(userCommonData)
140-
.set({ pronouns, bio, skills, discord })
141-
.where(eq(userCommonData.clerkID, user.clerkID));
142-
return {
143-
success: true,
144-
newPronouns: pronouns,
145-
newBio: bio,
146-
newSkills: skills,
147-
newDiscord: discord,
148-
};
149-
},
150-
);
151-
152-
// TODO: Fix after registration enhancements to allow for failure on conflict and return appropriate error message
153146
export const modifyAccountSettings = authenticatedAction
154-
.schema(
155-
z.object({
156-
firstName: z.string().min(1).max(50),
157-
lastName: z.string().min(1).max(50),
158-
hackerTag: z.string().min(1).max(50),
159-
hasSearchableProfile: z.boolean(),
160-
}),
161-
)
147+
.schema(modifyAccountSettingsSchema)
162148
.action(
163149
async ({
164150
parsedInput: {
165151
firstName,
166152
lastName,
167153
hackerTag,
168-
hasSearchableProfile,
154+
isSearchable: hasSearchableProfile,
169155
},
170156
ctx: { userId },
171157
}) => {
172-
const user = await getUser(userId);
173-
if (!user) throw new Error("User not found");
174-
let oldHackerTag = user.hackerTag; // change when hackertag is not PK on profileData table
175-
if (oldHackerTag != hackerTag)
176-
if (await getUserByTag(hackerTag))
177-
//if hackertag changed
178-
// copied from /api/registration/create
158+
try {
159+
await db
160+
.update(userCommonData)
161+
.set({
162+
firstName,
163+
lastName,
164+
hackerTag,
165+
isSearchable: hasSearchableProfile,
166+
})
167+
.where(eq(userCommonData.clerkID, userId));
168+
} catch (err) {
169+
console.log("modifyAccountSettings error is", err);
170+
if (
171+
err instanceof DatabaseError &&
172+
err.code === UNIQUE_KEY_CONSTRAINT_VIOLATION_CODE
173+
) {
179174
return {
180175
success: false,
181176
message: "hackertag_not_unique",
182177
};
183-
await db
184-
.update(userCommonData)
185-
.set({
186-
firstName,
187-
lastName,
188-
hackerTag,
189-
isSearchable: hasSearchableProfile,
190-
})
191-
.where(eq(userCommonData.clerkID, userId));
178+
}
179+
throw err;
180+
}
192181
return {
193182
success: true,
194183
newFirstName: firstName,
@@ -199,23 +188,43 @@ export const modifyAccountSettings = authenticatedAction
199188
},
200189
);
201190

191+
// come back and fix this tmr
202192
export const updateProfileImage = authenticatedAction
203193
.schema(z.object({ fileBase64: z.string(), fileName: z.string() }))
204194
.action(
205195
async ({ parsedInput: { fileBase64, fileName }, ctx: { userId } }) => {
206-
const image = await decodeBase64AsFile(fileBase64, fileName);
207-
const user = await db.query.userCommonData.findFirst({
208-
where: eq(userCommonData.clerkID, userId),
209-
});
210-
if (!user) throw new Error("User not found");
196+
const file = await decodeBase64AsFile(fileBase64, fileName);
197+
let clerkUser: ClerkUser;
198+
try {
199+
clerkUser = await clerkClient.users.updateUserProfileImage(
200+
userId,
201+
{
202+
file,
203+
},
204+
);
205+
} catch (err) {
206+
console.log(`Error updating Clerk profile image: ${err}`);
207+
if (
208+
typeof err === "object" &&
209+
err != null &&
210+
"status" in err &&
211+
err.status === PAYLOAD_TOO_LARGE_CODE
212+
) {
213+
return {
214+
success: false,
215+
message: "file_too_large",
216+
};
217+
}
218+
console.log(
219+
`Unknown Error updating Clerk profile image: ${err}`,
220+
);
221+
throw err;
222+
}
211223

212-
const blobUpload = await put(image.name, image, {
213-
access: "public",
214-
});
215224
await db
216225
.update(userCommonData)
217-
.set({ profilePhoto: blobUpload.url })
218-
.where(eq(userCommonData.clerkID, user.clerkID));
226+
.set({ profilePhoto: clerkUser.imageUrl })
227+
.where(eq(userCommonData.clerkID, userId));
219228
revalidatePath("/settings#profile");
220229
return { success: true };
221230
},

apps/web/src/app/settings/page.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ export default async function Page() {
1010
if (!userId) return redirect("/sign-in");
1111
const user = await getUser(userId);
1212
if (!user) return redirect("/sign-in");
13-
13+
const { email, ...userData } = user;
1414
return (
1515
<main>
1616
<Header tag="Account" />
17-
<AccountSettings user={user} />
17+
<AccountSettings user={userData} email={email} />
1818
<Header tag="Profile" />
19-
<ProfileSettings profile={user} />
19+
<ProfileSettings profile={userData} />
2020
<Header tag={"Registration"} />
2121
<RegistrationSettings />
2222
</main>

0 commit comments

Comments
 (0)