Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions apps/database/src/schema/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,28 @@ import {
// ── Enums ─────────────────────────────────────────────────

export const eventTagEnum = pgEnum("event_tag", [
"free food",
"career",
"free-food",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are renames of persisted PostgreSQL enum values, but I don't see a migration in this PR. Updating pgEnum here changes the TypeScript schema definition, but existing databases will still have the old enum values/data. Could we add a Drizzle migration that safely migrates the existing event_tag values (and existing event/user interest rows) to the new taxonomy before we start writing values like free-food and career-recruiting?

"career-recruiting",
"research",
"stem",
"academics",
"tech",
"entrepreneurship",
"politics",
"visual arts",
"performing arts",
"politics-policy",
"visual-arts",
"performing-arts",
"literature",
"culture",
"music",
"gaming",
"athletics",
"religion",
"sustainability",
"outdoors",
"wellness",
"community service",
"speaker event",
"social event",
"stem",
"outdoor-adventure",
"wellness-self-care",
"community-service",
"speaker-event",
"social-event",
]);

export const campusRegionEnum = pgEnum("campus_region", [
Expand Down
60 changes: 52 additions & 8 deletions apps/web/src/actions/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,53 @@ import {
import { revalidatePath } from "next/cache";
import { auth } from "~/auth";

// Derived from the DB schema so these can never drift from the pgEnum values
const LEGACY_INTEREST_TAG_ALIASES: Record<string, string> = {
career: "career-recruiting",
academic: "research",
academics: "academics",
tech: "tech",
political: "politics-policy",
politics: "politics-policy",
art: "visual-arts",
visual: "visual-arts",
performance: "performing-arts",
performing: "performing-arts",
cultural: "culture",
culture: "culture",
sports: "athletics",
athletic: "athletics",
religious: "religion",
religion: "religion",
outdoor: "outdoor-adventure",
outdoors: "outdoor-adventure",
wellness: "wellness-self-care",
speaker: "speaker-event",
social: "social-event",
"free food": "free-food",
"free-food": "free-food",
"community service": "community-service",
"community-service": "community-service",
"politics policy": "politics-policy",
"visual arts": "visual-arts",
"performing arts": "performing-arts",
"wellness self care": "wellness-self-care",
"speaker event": "speaker-event",
"social event": "social-event",
stem: "stem",
};

type InterestTag = (typeof eventTagEnum.enumValues)[number];
type CampusRegion = (typeof campusRegionEnum.enumValues)[number];

function normalizeInterestTag(tag: string): string {
const normalized = tag.trim().toLowerCase().replace(/\s+/g, "-");
return LEGACY_INTEREST_TAG_ALIASES[normalized] ?? LEGACY_INTEREST_TAG_ALIASES[tag] ?? normalized;
}

function dedupeInterests(values: string[]): string[] {
return [...new Set(values.map((value) => normalizeInterestTag(value)).filter(Boolean))];
}

export async function completeOnboarding(data: {
interests: string[];
classYear: string;
Expand All @@ -28,7 +71,6 @@ export async function completeOnboarding(data: {

const userId = session.user.id;

// Update user profile
await db
.update(users)
.set({
Expand All @@ -40,18 +82,17 @@ export async function completeOnboarding(data: {
})
.where(eq(users.id, userId));

// Insert interests
if (data.interests.length > 0) {
const normalizedInterests = dedupeInterests(data.interests);
await db.delete(userInterests).where(eq(userInterests.userId, userId));
await db.insert(userInterests).values(
data.interests.map((tag) => ({
normalizedInterests.map((tag) => ({
userId,
tag: tag as InterestTag,
})),
);
}

// Insert regions
if (data.regions.length > 0) {
await db.delete(userRegions).where(eq(userRegions.userId, userId));
await db.insert(userRegions).values(
Expand Down Expand Up @@ -129,6 +170,8 @@ export async function getUserProfile(): Promise<UserProfile> {
.from(userInterests)
.where(eq(userInterests.userId, user.id));

const normalizedInterests = dedupeInterests(interests.map(({ tag }) => tag));

const regions = await db
.select({ region: userRegions.region })
.from(userRegions)
Expand All @@ -143,7 +186,7 @@ export async function getUserProfile(): Promise<UserProfile> {
major: user.major,
avatarUrl: user.avatarUrl,
isOrgLeader: user.isOrgLeader,
interests: interests.map((i) => i.tag),
interests: normalizedInterests,
regions: regions.map((r) => r.region),
};
}
Expand All @@ -169,10 +212,11 @@ export async function updateProfile(data: {
.where(eq(users.id, userId));

if (data.interests) {
const normalizedInterests = dedupeInterests(data.interests);
await db.delete(userInterests).where(eq(userInterests.userId, userId));
if (data.interests.length > 0) {
if (normalizedInterests.length > 0) {
await db.insert(userInterests).values(
data.interests.map((tag) => ({
normalizedInterests.map((tag) => ({
userId,
tag: tag as InterestTag,
})),
Expand Down
Loading