From 5d276fcf2c592b3ca197b7051da2ffeff70828d0 Mon Sep 17 00:00:00 2001 From: Kalle <38327916+Sendouc@users.noreply.github.com> Date: Sat, 28 May 2022 10:49:44 +0300 Subject: [PATCH] Change comments data model a bit + adjust sorting --- .eslintrc.js | 1 + app/db/models/plusSuggestions.server.ts | 181 ++++++++++-------- app/permissions.ts | 11 +- app/routes/plus/suggestions.tsx | 77 ++++---- .../suggestions/comment.$tier.$userId.tsx | 14 +- 5 files changed, 152 insertions(+), 132 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index 8128016ad..f9d66af26 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -27,6 +27,7 @@ module.exports = { "@typescript-eslint/no-unsafe-call": 0, "@typescript-eslint/no-unsafe-argument": 0, "@typescript-eslint/no-non-null-assertion": 0, + "@typescript-eslint/no-explicit-any": 0, }, settings: { react: { diff --git a/app/db/models/plusSuggestions.server.ts b/app/db/models/plusSuggestions.server.ts index fbaffe458..b069d2571 100644 --- a/app/db/models/plusSuggestions.server.ts +++ b/app/db/models/plusSuggestions.server.ts @@ -32,95 +32,110 @@ export function create( createStm.run(args); } -const findStm = sql.prepare(` -WITH gs as ( - SELECT - "tier", - json_object( - 'info', - json_object( - 'id', - suggested."id", - 'discordId', - suggested."discordId", - 'discordName', - suggested."discordName", - 'discordDiscriminator', - suggested."discordDiscriminator", - 'discordAvatar', - suggested."discordAvatar" - ), - 'suggestions', - json_group_array( - json_object( - 'id', - "PlusSuggestion"."id", - 'author', - json_object( - 'id', - author."id", - 'discordId', - author."discordId", - 'discordName', - author."discordName", - 'discordDiscriminator', - author."discordDiscriminator" - ), - 'createdAt', - "createdAt", - 'text', - "text" - ) - ) - ) as users - FROM - "PlusSuggestion" - JOIN "User" AS author ON "PlusSuggestion"."authorId" = author."id" - JOIN "User" AS suggested ON "PlusSuggestion"."suggestedId" = suggested."id" - WHERE - "month" = $month - AND "year" = $year - AND "tier" >= $plusTier - GROUP BY - "suggestedId", - "tier" -) -SELECT - tier, - json_group_array(users) as users -from - gs -GROUP BY - "tier" +const findVisibleForUserStm = sql.prepare(` + SELECT + suggestion."id", + suggestion."createdAt", + suggestion."text", + suggestion."tier", + author."id" as "authorId", + author."discordId" as "authorDiscordId", + author."discordName" as "authorDiscordName", + author."discordDiscriminator" as "authorDiscordDiscriminator", + suggested."id" as "suggestedId", + suggested."discordId" as "suggestedDiscordId", + suggested."discordName" as "suggestedDiscordName", + suggested."discordDiscriminator" as "suggestedDiscordDiscriminator", + suggested."discordAvatar" as "suggestedDiscordAvatar" + FROM "PlusSuggestion" as suggestion + JOIN "User" AS author ON suggestion."authorId" = author."id" + JOIN "User" AS suggested ON suggestion."suggestedId" = suggested."id" + WHERE + "month" = $month + AND "year" = $year + AND "tier" >= $plusTier + ORDER BY + "createdAt" ASC `); -export type FindResult = { - tier: number; - users: { - info: Pick< +export interface FindVisibleForUserSuggestedUserInfo { + info: Pick< + User, + | "id" + | "discordId" + | "discordName" + | "discordDiscriminator" + | "discordAvatar" + >; + suggestions: (Pick & { + author: Pick< User, - | "id" - | "discordId" - | "discordName" - | "discordDiscriminator" - | "discordAvatar" + "id" | "discordId" | "discordName" | "discordDiscriminator" >; - suggestions: (Pick & { - author: Pick< - User, - "id" | "discordId" | "discordName" | "discordDiscriminator" - >; - })[]; - }[]; -}[]; + })[]; +} +export interface FindVisibleForUser { + [tier: string]: FindVisibleForUserSuggestedUserInfo[]; +} -export function find(args: MonthYear & Pick) { - if (!args.plusTier) return; +export function findVisibleForUser( + args: MonthYear & Pick +): FindVisibleForUser { + return sortNewestPlayersToBeSuggestedFirst( + mapFindVisibleForUserRowsToResult(findVisibleForUserStm.all(args)) + ); +} - return findStm.all(args).map((row) => ({ - ...row, - users: JSON.parse(row.users).map(JSON.parse), - })) as FindResult; +function mapFindVisibleForUserRowsToResult(rows: any[]): FindVisibleForUser { + return rows.reduce((result: FindVisibleForUser, row) => { + if (!result[row.tier]) result[row.tier] = []; + + const suggestionInfo = { + id: row.id, + createdAt: row.createdAt, + text: row.text, + author: { + id: row.authorId, + discordId: row.authorDiscordId, + discordName: row.authorDiscordName, + discordDiscriminator: row.authorDiscordDiscriminator, + }, + }; + + const existingSuggestion = result[row.tier].find( + (suggestion) => suggestion.info.id === row.suggestedId + ); + + if (existingSuggestion) { + existingSuggestion.suggestions.push(suggestionInfo); + } else { + result[row.tier].push({ + info: { + id: row.suggestedId, + discordId: row.suggestedDiscordId, + discordName: row.suggestedDiscordName, + discordDiscriminator: row.suggestedDiscriminator, + discordAvatar: row.suggestedDiscordAvatar, + }, + suggestions: [suggestionInfo], + }); + } + + return result; + }, {}); +} + +function sortNewestPlayersToBeSuggestedFirst( + suggestions: FindVisibleForUser +): FindVisibleForUser { + return Object.fromEntries( + Object.entries(suggestions).map(([tier, suggestions]) => [ + tier, + suggestions.sort( + (a, b) => b.suggestions[0].createdAt - a.suggestions[0].createdAt + ), + ]) + ); } const tiersSuggestedForStm = sql.prepare(` diff --git a/app/permissions.ts b/app/permissions.ts index 32471be5e..e24e4a0c4 100644 --- a/app/permissions.ts +++ b/app/permissions.ts @@ -4,7 +4,7 @@ import { allTruthy } from "./utils/arrays"; interface CanAddCommentToSuggestionFEArgs { user?: Pick; - suggestions: plusSuggestions.FindResult; + suggestions: plusSuggestions.FindVisibleForUser; suggested: { id: User["id"]; plusTier: NonNullable }; } export function canAddCommentToSuggestionFE( @@ -56,9 +56,8 @@ function alreadyCommentedByUser({ suggested, }: CanAddCommentToSuggestionFEArgs) { return Boolean( - suggestions - .find(({ tier }) => tier === suggested.plusTier) - ?.users.find((u) => u.info.id === suggested.id) + suggestions[suggested.plusTier] + ?.find((u) => u.info.id === suggested.id) ?.suggestions.some((s) => s.author.id === user?.id) ); } @@ -68,9 +67,7 @@ function playerAlreadySuggested({ suggested, }: Pick) { return Boolean( - suggestions - .find(({ tier }) => tier === suggested.plusTier) - ?.users.find((u) => u.info.id === suggested.id) + suggestions[suggested.plusTier]?.find((u) => u.info.id === suggested.id) ); } diff --git a/app/routes/plus/suggestions.tsx b/app/routes/plus/suggestions.tsx index 8c5aa479f..6d976d805 100644 --- a/app/routes/plus/suggestions.tsx +++ b/app/routes/plus/suggestions.tsx @@ -28,7 +28,6 @@ import { validate, } from "~/utils/remix"; import { discordFullName } from "~/utils/strings"; -import type { Unpacked } from "~/utils/types"; import { actualNumber } from "~/utils/zod"; export const links: LinksFunction = () => { @@ -53,13 +52,13 @@ export const action: ActionFunction = async ({ request }) => { }); const user = await requireUser(request); - const suggestions = db.plusSuggestions.find({ + const suggestions = db.plusSuggestions.findVisibleForUser({ ...upcomingVoting(new Date()), plusTier: user.plusTier, }); - const targetSuggestion = suggestions - ?.flatMap((s) => s.users) + const targetSuggestion = Object.values(suggestions) + ?.flat() .flatMap((u) => u.suggestions) .find((s) => s.id === data.suggestionId); @@ -72,7 +71,7 @@ export const action: ActionFunction = async ({ request }) => { }; export interface PlusSuggestionsLoaderData { - suggestions?: plusSuggestions.FindResult; + suggestions?: plusSuggestions.FindVisibleForUser; suggestedForTiers: number[]; } @@ -80,7 +79,7 @@ export const loader: LoaderFunction = async ({ request }) => { const user = await requireUser(request); return json({ - suggestions: db.plusSuggestions.find({ + suggestions: db.plusSuggestions.findVisibleForUser({ ...upcomingVoting(new Date()), plusTier: user.plusTier, }), @@ -94,16 +93,15 @@ export const loader: LoaderFunction = async ({ request }) => { export default function PlusSuggestionsPage() { const data = useLoaderData(); const [tierVisible, setTierVisible] = React.useState( - data.suggestions?.[0].tier ?? 0 + tierVisibleInitialState(data.suggestions) ); if (!data.suggestions) { return ; } - const visibleSuggestions = data.suggestions.find( - ({ tier }) => tier === tierVisible - ); + invariant(tierVisible); + const visibleSuggestions = data.suggestions[tierVisible]; invariant(visibleSuggestions); return ( @@ -113,28 +111,32 @@ export default function PlusSuggestionsPage() {
- {data.suggestions.map(({ tier, users }) => { - const id = String(tier); - return ( -
- - setTierVisible(tier)} - data-cy={`plus${tier}-radio`} - /> -
- ); - })} + {Object.entries(data.suggestions) + .sort((a, b) => Number(a[0]) - Number(b[0])) + .map(([tier, suggestions]) => { + const id = String(tier); + return ( +
+ + setTierVisible(tier)} + data-cy={`plus${tier}-radio`} + /> +
+ ); + })}
- {visibleSuggestions.users.map((u) => ( + {visibleSuggestions.map((u) => ( (); const user = useUser(); @@ -178,10 +187,8 @@ function SuggestedUser({ suggested, tier, }: { - suggested: Unpacked< - Unpacked>["users"] - >; - tier: number; + suggested: plusSuggestions.FindVisibleForUserSuggestedUserInfo; + tier: string; }) { const data = useLoaderData(); const user = useUser(); @@ -200,7 +207,7 @@ function SuggestedUser({ {canAddCommentToSuggestionFE({ user, suggestions: data.suggestions, - suggested: { id: suggested.info.id, plusTier: tier }, + suggested: { id: suggested.info.id, plusTier: Number(tier) }, }) ? ( // TODO: resetScroll={false} https://twitter.com/ryanflorence/status/1527775882797907969 { }); const user = await requireUser(request); - const suggestions = db.plusSuggestions.find({ + const suggestions = db.plusSuggestions.findVisibleForUser({ ...upcomingVoting(new Date()), plusTier: user.plusTier, }); @@ -65,19 +65,19 @@ export default function PlusCommentModalPage() { const data = matches.at(-2)!.data as PlusSuggestionsLoaderData; const targetUserId = Number(params.userId); - const tierSuggestedTo = Number(params.tier); - - const userBeingCommented = data.suggestions - ?.find(({ tier }) => tier === tierSuggestedTo) - ?.users.find((u) => u.info.id === targetUserId); + const tierSuggestedTo = String(params.tier); invariant(data.suggestions); + const userBeingCommented = data.suggestions[tierSuggestedTo]?.find( + (u) => u.info.id === targetUserId + ); + if ( !userBeingCommented || !canAddCommentToSuggestionFE({ user, suggestions: data.suggestions, - suggested: { id: targetUserId, plusTier: tierSuggestedTo }, + suggested: { id: targetUserId, plusTier: Number(tierSuggestedTo) }, }) ) { return ;