diff --git a/app/features/info/routes/support.tsx b/app/features/info/routes/support.tsx index 17807febd4..79ea1ca25d 100644 --- a/app/features/info/routes/support.tsx +++ b/app/features/info/routes/support.tsx @@ -48,6 +48,11 @@ const PERKS = [ name: "prioritySupport", extraInfo: true, }, + { + tier: 2, + name: "userShortLink", + extraInfo: true, + }, { tier: 2, name: "customizedColorsUser", diff --git a/app/features/user-page/UserRepository.server.ts b/app/features/user-page/UserRepository.server.ts index c0037c6056..01dce4d3aa 100644 --- a/app/features/user-page/UserRepository.server.ts +++ b/app/features/user-page/UserRepository.server.ts @@ -255,6 +255,14 @@ export async function findProfileByIdentifier( }; } +export function findByCustomUrl(customUrl: string) { + return db + .selectFrom("User") + .select(["User.id", "User.discordId", "User.customUrl", "User.patronTier"]) + .where("customUrl", "=", customUrl) + .executeTakeFirst(); +} + export function findBannedStatusByUserId(userId: number) { return db .selectFrom("User") diff --git a/app/features/user-page/routes/short.$customUrl.tsx b/app/features/user-page/routes/short.$customUrl.tsx new file mode 100644 index 0000000000..ac15d92857 --- /dev/null +++ b/app/features/user-page/routes/short.$customUrl.tsx @@ -0,0 +1,15 @@ +import type { LoaderFunction } from "@remix-run/node"; +import { redirect } from "react-router-dom"; +import * as UserRepository from "~/features/user-page/UserRepository.server"; +import { userPage } from "~/utils/urls"; +import { isAtLeastFiveDollarTierPatreon } from "~/utils/users"; + +export const loader: LoaderFunction = async ({ params }) => { + const user = await UserRepository.findByCustomUrl(params.customUrl!); + + if (!user || !isAtLeastFiveDollarTierPatreon(user)) { + return redirect("/"); + } + + return redirect(userPage(user)); +}; diff --git a/app/features/user-page/routes/u.$identifier.edit.tsx b/app/features/user-page/routes/u.$identifier.edit.tsx index f943e61d73..52ef6c4db8 100644 --- a/app/features/user-page/routes/u.$identifier.edit.tsx +++ b/app/features/user-page/routes/u.$identifier.edit.tsx @@ -321,6 +321,7 @@ function CustomUrlInput({ maxLength={USER.CUSTOM_URL_MAX_LENGTH} defaultValue={parentRouteData.user.customUrl ?? undefined} /> + {t("user:forms.info.customUrl")} ); } diff --git a/app/routes.ts b/app/routes.ts index 09f410d0e9..dc01956444 100644 --- a/app/routes.ts +++ b/app/routes.ts @@ -227,6 +227,8 @@ export default [ route("/org/:id", "features/api-public/routes/org.$id.ts"), ]), + route("/short/:customUrl", "features/user-page/routes/short.$customUrl.tsx"), + route("/theme", "features/theme/routes/theme.ts"), ...prefix("/auth", [ diff --git a/locales/en/common.json b/locales/en/common.json index 945f792023..cab9440d15 100644 --- a/locales/en/common.json +++ b/locales/en/common.json @@ -187,6 +187,8 @@ "support.perk.seePlusPercentage.extra": "Normally only failed suggests see their voting percentage. With this, you can always see your own percentage.", "support.perk.autoValidatePictures": "Auto validate uploaded pictures", "support.perk.autoValidatePictures.extra": "Any images you upload (e.g. team profile/banner picture) get automatically validated. Normally it needs a moderator's approval first. Note that this doesn't apply to images that were already submitted.", + "support.perk.userShortLink": "User page short link", + "support.perk.userShortLink.extra": "Instead of e.g. sendou.ink/u/sendou you can also use snd.ink/sendou when linking to your user profile.", "support.perk.customizedColorsUser": "Customize colors (user page)", "support.perk.customizedColorsTeam": "Customize colors (team page)", "support.perk.customizedColorsTeam.extra": "It is enough that one member of the team is a patron to get this perk.", diff --git a/locales/en/user.json b/locales/en/user.json index 41c24e407d..0199bf0d0b 100644 --- a/locales/en/user.json +++ b/locales/en/user.json @@ -40,6 +40,7 @@ "forms.errors.invalidCustomUrl.strangeCharacter": "Custom URL can't contain special characters", "forms.errors.invalidCustomUrl.duplicate": "Someone is already using this custom URL", "forms.errors.invalidSens": "Motion sens can't be set if R-stick sens isn't", + "forms.info.customUrl": "For patrons (Supporter & above) short link is available. E.g. instead of sendou.ink/u/sendou, snd.ink/sendou can be used.", "forms.info.favoriteBadge": "Your favorite badge is shown as big by default on your profile.", "forms.info.battlefy": "Battlefy account name is used for seeding and verification in some tournaments",