From 28ca9662564d45bcd38778c051b7dcbaeef58587 Mon Sep 17 00:00:00 2001 From: Zen <99558412+zenpk@users.noreply.github.com> Date: Thu, 20 Apr 2023 04:50:07 +0800 Subject: [PATCH] Fixes #839: Allow user to select favorite badge (#1345) * temp save * temp save * temp save * tempsave * rollback * temp save * added combobox * finish combobox, discard * restore combobox * page load successfully * finish * rm excessive changes * fix prettier * fix prettier again --- app/db/models/badges/countsByUserId.sql | 4 +- app/db/models/users/queries.server.ts | 1 + app/db/models/users/updateProfile.sql | 3 +- app/db/seed/index.ts | 14 +++++++ app/db/types.ts | 1 + app/routes/u.$identifier.tsx | 1 + app/routes/u.$identifier/edit.tsx | 49 +++++++++++++++++++++++++ migrations/023-add-user-fav-badge.js | 5 +++ public/locales/en/user.json | 1 + public/locales/zh/user.json | 1 + 10 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 migrations/023-add-user-fav-badge.js diff --git a/app/db/models/badges/countsByUserId.sql b/app/db/models/badges/countsByUserId.sql index 9d6f1a518..1fa602c6c 100644 --- a/app/db/models/badges/countsByUserId.sql +++ b/app/db/models/badges/countsByUserId.sql @@ -11,4 +11,6 @@ where "BadgeOwner"."userId" = @userId group by "BadgeOwner"."badgeId", - "BadgeOwner"."userId" \ No newline at end of file + "BadgeOwner"."userId" +order by + "Badge"."id" = (select "favoriteBadgeId" from "User" where "id" = @userId) desc, "Badge"."id" asc diff --git a/app/db/models/users/queries.server.ts b/app/db/models/users/queries.server.ts index 0cce6001f..881a9b301 100644 --- a/app/db/models/users/queries.server.ts +++ b/app/db/models/users/queries.server.ts @@ -65,6 +65,7 @@ export const updateProfile = sql.transaction( | "stickSens" | "inGameName" | "css" + | "favoriteBadgeId" > & { weapons: MainWeaponId[] }) => { deleteUserWeaponsStm.run({ userId: rest.id }); for (const [i, weaponSplId] of weapons.entries()) { diff --git a/app/db/models/users/updateProfile.sql b/app/db/models/users/updateProfile.sql index 7ab8bae55..7d40dcbcd 100644 --- a/app/db/models/users/updateProfile.sql +++ b/app/db/models/users/updateProfile.sql @@ -7,6 +7,7 @@ set "stickSens" = @stickSens, "motionSens" = @motionSens, "inGameName" = @inGameName, - "css" = @css + "css" = @css, + "favoriteBadgeId" = @favoriteBadgeId where "id" = @id returning * diff --git a/app/db/seed/index.ts b/app/db/seed/index.ts index 865cc192d..ae2c02cde 100644 --- a/app/db/seed/index.ts +++ b/app/db/seed/index.ts @@ -68,6 +68,7 @@ const basicSeeds = [ realVideo, realVideoCast, xRankPlacements, + userFavBadges, ]; export function seed() { @@ -1176,3 +1177,16 @@ function xRankPlacements() { } })(); } + +function userFavBadges() { + // randomly choose Sendou's favorite badge + const badgeList = shuffle( + sql + .prepare(`select "badgeId" from "BadgeOwner" where "userId" = 1`) + .all() + .map((row) => row.badgeId) + ); + sql + .prepare(`update "User" set "favoriteBadgeId" = $id where "id" = 1`) + .run({ id: badgeList[0] }); +} diff --git a/app/db/types.ts b/app/db/types.ts index ea39bd264..8de3c3b8d 100644 --- a/app/db/types.ts +++ b/app/db/types.ts @@ -29,6 +29,7 @@ export interface User { /** Used to overwrite normal patron giving process and force give the patron status till this date */ patronTill: number | null; isVideoAdder: number; + favoriteBadgeId: number; } /** User table after joined with PlusTier table */ diff --git a/app/routes/u.$identifier.tsx b/app/routes/u.$identifier.tsx index 4bf0994b9..7b644a6b9 100644 --- a/app/routes/u.$identifier.tsx +++ b/app/routes/u.$identifier.tsx @@ -93,6 +93,7 @@ export const loader = ({ params }: LoaderArgs) => { country: user.country, css: canAddCustomizedColorsToUserProfile(user) ? user.css : undefined, badges: db.badges.countsByUserId(user.id), + favoriteBadgeId: user.favoriteBadgeId, results: db.calendarEvents.findResultsByUserId(user.id), buildsCount: db.builds.countByUserId(user.id), vods: findVods({ userId: user.id }), diff --git a/app/routes/u.$identifier/edit.tsx b/app/routes/u.$identifier/edit.tsx index d7ed54d71..4b6163ca9 100644 --- a/app/routes/u.$identifier/edit.tsx +++ b/app/routes/u.$identifier/edit.tsx @@ -122,6 +122,20 @@ const userEditActionSchema = z ) .max(USER.WEAPON_POOL_MAX_SIZE) ), + favoriteBadgeId: z.preprocess( + processMany(actualNumber, undefinedToNull), + z + .number() + .refine((val) => { + // unable to hook here + // return parentRouteData.badges + // .map((badge) => badge.id) + // .concat(0) + // .includes(val); + return val >= 0; + }) + .default(0) + ), }) .refine( (val) => { @@ -217,6 +231,7 @@ export default function UserEditPage() { + @@ -449,3 +464,37 @@ function BioTextarea({ initialValue }: { initialValue: User["bio"] }) { ); } + +function FavBadgeSelect({ + parentRouteData, +}: { + parentRouteData: UserPageLoaderData; +}) { + const { t } = useTranslation(["user"]); + + // user's current favorite badge is the initial value + const initialBadge = parentRouteData.badges.find( + (badge) => badge.id === parentRouteData.favoriteBadgeId + ); + + return ( +
+ + +
+ ); +} diff --git a/migrations/023-add-user-fav-badge.js b/migrations/023-add-user-fav-badge.js new file mode 100644 index 000000000..ffab64c1e --- /dev/null +++ b/migrations/023-add-user-fav-badge.js @@ -0,0 +1,5 @@ +module.exports.up = function (db) { + db.prepare( + /* sql */ `alter table "User" add "favoriteBadgeId" integer not null default 0` + ).run(); +}; diff --git a/public/locales/en/user.json b/public/locales/en/user.json index 0947f29a8..821abc649 100644 --- a/public/locales/en/user.json +++ b/public/locales/en/user.json @@ -11,6 +11,7 @@ "sens": "Sens", "weaponPool": "Weapon pool", "discordExplanation": "Username, profile picture, YouTube, Twitter and Twitch accounts come from your Discord account. See <1>FAQ for more information.", + "favoriteBadge": "Favorite Badge", "results.title": "Results", "results.placing": "Placing", diff --git a/public/locales/zh/user.json b/public/locales/zh/user.json index 04cff1782..4112a7d23 100644 --- a/public/locales/zh/user.json +++ b/public/locales/zh/user.json @@ -11,6 +11,7 @@ "sens": "感度", "weaponPool": "武器池", "discordExplanation": "用户名、头像、Youtube、Twitter和Twitch账号皆来自你的Discord账号。查看 <1>FAQ 以获得更多相关信息。", + "favoriteBadge": "最喜爱的徽章", "results.title": "成绩", "results.placing": "排名",