diff --git a/frontend/src/ts/pages/friends.ts b/frontend/src/ts/pages/friends.ts index 3fc190e9dca8..eb1f30aafb4a 100644 --- a/frontend/src/ts/pages/friends.ts +++ b/frontend/src/ts/pages/friends.ts @@ -17,7 +17,7 @@ import { secondsToString } from "../utils/date-and-time"; import { PersonalBest } from "@monkeytype/schemas/shared"; import Format from "../utils/format"; import { getHtmlByUserFlags } from "../controllers/user-flag-controller"; -import { SortedTable } from "../utils/sorted-table"; +import { SortedTable, SortSchema } from "../utils/sorted-table"; import { getAvatarElement } from "../utils/discord-avatar"; import { formatTypingStatsRatio } from "../utils/misc"; import { getLanguageDisplayString } from "../utils/strings"; @@ -28,6 +28,7 @@ import * as AuthEvent from "../observables/auth-event"; import { Connection } from "@monkeytype/schemas/connections"; import { Friend, UserNameSchema } from "@monkeytype/schemas/users"; import * as Loader from "../elements/loader"; +import { LocalStorageWithSchema } from "../utils/local-storage-with-schema"; const pageElement = $(".page.pageFriends"); @@ -95,7 +96,7 @@ const addFriendModal = new SimpleModal({ const result = await addFriend(receiverName); if (result === true) { - return { status: 1, message: `Request send to ${receiverName}` }; + return { status: 1, message: `Request sent to ${receiverName}` }; } let status: -1 | 0 | 1 = -1; @@ -230,7 +231,11 @@ function updateFriends(): void { table: ".pageFriends .friends table", data: friendsList, buildRow: buildFriendRow, - initialSort: { property: "name", descending: false }, + persistence: new LocalStorageWithSchema({ + key: "friendsListSort", + schema: SortSchema, + fallback: { property: "name", descending: false }, + }), }); } else { friendsTable.setData(friendsList); diff --git a/frontend/src/ts/pages/profile.ts b/frontend/src/ts/pages/profile.ts index ce3dfa17e521..1de3ceea099a 100644 --- a/frontend/src/ts/pages/profile.ts +++ b/frontend/src/ts/pages/profile.ts @@ -251,7 +251,7 @@ $(".page.pageProfile").on("click", ".profile .addFriendButton", async () => { const result = await addFriend(friendName); if (result === true) { - Notifications.add(`Request send to ${friendName}`); + Notifications.add(`Request sent to ${friendName}`); $(".profile .details .addFriendButton").addClass("disabled"); } else { Notifications.add(result, -1); diff --git a/frontend/src/ts/utils/sorted-table.ts b/frontend/src/ts/utils/sorted-table.ts index 4124600f40a9..43b3afd7ec5f 100644 --- a/frontend/src/ts/utils/sorted-table.ts +++ b/frontend/src/ts/utils/sorted-table.ts @@ -1,34 +1,50 @@ -type Sort = { - property: string; - descending: boolean; +import { z } from "zod"; + +export const SortSchema = z.object({ + property: z.string(), + descending: z.boolean(), +}); +export type Sort = z.infer; + +type Persistence = { + get: () => Sort; + set: (sort: Sort) => boolean; }; type SortedTableOptions = { table: string; data?: T[]; buildRow: (entry: T) => HTMLTableRowElement; - initialSort?: Sort; -}; +} & ( + | { initialSort?: Sort; persistence?: never } + | { persistence?: Persistence; initialSort?: never } +); + export class SortedTable { - protected data: { source: T; element?: HTMLTableRowElement }[]; + protected data: { source: T; element?: HTMLTableRowElement }[] = []; private table: JQuery; private buildRow: (entry: T) => HTMLTableRowElement; private sort?: Sort; + private persistence?: Persistence; - constructor({ table, data, buildRow, initialSort }: SortedTableOptions) { - this.table = $(table); + constructor(options: SortedTableOptions) { + this.table = $(options.table); if (this.table === undefined) { - throw new Error(`No element found for ${table}`); + throw new Error(`No element found for ${options.table}`); } - this.buildRow = buildRow; - this.data = []; - if (data !== undefined) { - this.setData(data); + this.buildRow = options.buildRow; + + if (options.data !== undefined) { + this.setData(options.data); } - if (initialSort !== undefined) { - this.sort = initialSort; + if ("persistence" in options && options.persistence !== undefined) { + this.persistence = options.persistence; + this.sort = this.persistence.get(); + this.doSort(); + } else if ("initialSort" in options && options.initialSort !== undefined) { + this.sort = options.initialSort; this.doSort(); } @@ -43,13 +59,15 @@ export class SortedTable { target.dataset["sortDefaultDirection"] === "desc"; if (property === undefined) return; - if (this.sort === undefined || property !== this.sort.property) { - this.sort = { property, descending: defaultDirection }; + let updatedSort = this.sort; + + if (updatedSort === undefined || property !== updatedSort.property) { + updatedSort = { property, descending: defaultDirection }; } else { - this.sort.descending = !this.sort?.descending; + updatedSort.descending = !updatedSort?.descending; } + this.setSort(updatedSort); - this.doSort(); this.updateBody(); }; } @@ -57,6 +75,7 @@ export class SortedTable { public setSort(sort: Partial): void { this.sort = { ...this.sort, ...sort } as Sort; + this.persistence?.set(this.sort); this.doSort(); }