Skip to content

Commit 38f3fc2

Browse files
Leonabcd123fehmer
andauthored
refactor: Remove JQuery from account-settings (@Leonabcd123, @fehmer) (monkeytypegame#7219)
### Description Also modifies `swapElements` to accept `ElementWithUtils`. --------- Co-authored-by: Christian Fehmer <[email protected]> Co-authored-by: Christian Fehmer <[email protected]>
1 parent 331ca1a commit 38f3fc2

File tree

4 files changed

+90
-107
lines changed

4 files changed

+90
-107
lines changed

frontend/src/ts/elements/account-button.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -65,15 +65,11 @@ export function update(): void {
6565
accountButtonAndMenuEl
6666
.qs(".menu .items .goToProfile")
6767
?.setAttribute("href", `/profile/${name}`);
68-
void Misc.swapElements(
69-
loginButtonEl.native,
70-
accountButtonAndMenuEl.native,
71-
250,
72-
);
68+
void Misc.swapElements(loginButtonEl, accountButtonAndMenuEl, 250);
7369
} else {
7470
void Misc.swapElements(
75-
accountButtonAndMenuEl.native,
76-
loginButtonEl.native,
71+
accountButtonAndMenuEl,
72+
loginButtonEl,
7773
250,
7874
async () => {
7975
updateName("");

frontend/src/ts/elements/settings/theme-picker.ts

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import * as ActivePage from "../../states/active-page";
1313
import { CustomThemeColors, ThemeName } from "@monkeytype/schemas/configs";
1414
import { captureException } from "../../sentry";
1515
import { ThemesListSorted } from "../../constants/themes";
16+
import { qs } from "../../utils/dom";
1617

1718
function updateActiveButton(): void {
1819
let activeThemeName: string = Config.theme;
@@ -310,22 +311,14 @@ export function updateActiveTab(): void {
310311

311312
if (Config.customTheme) {
312313
void Misc.swapElements(
313-
document.querySelector(
314-
'.pageSettings [tabContent="preset"]',
315-
) as HTMLElement,
316-
document.querySelector(
317-
'.pageSettings [tabContent="custom"]',
318-
) as HTMLElement,
314+
qs('.pageSettings [tabContent="preset"]'),
315+
qs('.pageSettings [tabContent="custom"]'),
319316
250,
320317
);
321318
} else {
322319
void Misc.swapElements(
323-
document.querySelector(
324-
'.pageSettings [tabContent="custom"]',
325-
) as HTMLElement,
326-
document.querySelector(
327-
'.pageSettings [tabContent="preset"]',
328-
) as HTMLElement,
320+
qs('.pageSettings [tabContent="custom"]'),
321+
qs('.pageSettings [tabContent="preset"]'),
329322
250,
330323
);
331324
}

frontend/src/ts/pages/account-settings.ts

Lines changed: 68 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ import * as BlockedUserTable from "../elements/account-settings/blocked-user-tab
1212
import * as Notifications from "../elements/notifications";
1313
import { z } from "zod";
1414
import * as AuthEvent from "../observables/auth-event";
15-
import { qsr } from "../utils/dom";
15+
import { qs, qsr, onDocumentReady } from "../utils/dom";
1616

17-
const pageElement = $(".page.pageAccountSettings");
17+
const pageElement = qsr(".page.pageAccountSettings");
1818

1919
const StateSchema = z.object({
2020
tab: z.enum([
@@ -34,9 +34,9 @@ const state: State = {
3434
};
3535

3636
function updateAuthenticationSections(): void {
37-
pageElement.find(".section.passwordAuthSettings button").addClass("hidden");
38-
pageElement.find(".section.googleAuthSettings button").addClass("hidden");
39-
pageElement.find(".section.githubAuthSettings button").addClass("hidden");
37+
pageElement.qs(".section.passwordAuthSettings button")?.addClass("hidden");
38+
pageElement.qs(".section.googleAuthSettings button")?.addClass("hidden");
39+
pageElement.qs(".section.githubAuthSettings button")?.addClass("hidden");
4040

4141
const user = getAuthenticatedUser();
4242
if (user === null) return;
@@ -53,134 +53,128 @@ function updateAuthenticationSections(): void {
5353

5454
if (passwordProvider) {
5555
pageElement
56-
.find(".section.passwordAuthSettings #emailPasswordAuth")
57-
.removeClass("hidden");
56+
.qs(".section.passwordAuthSettings #emailPasswordAuth")
57+
?.removeClass("hidden");
5858
pageElement
59-
.find(".section.passwordAuthSettings #passPasswordAuth")
60-
.removeClass("hidden");
59+
.qs(".section.passwordAuthSettings #passPasswordAuth")
60+
?.removeClass("hidden");
6161
if (googleProvider || githubProvider) {
6262
pageElement
63-
.find(".section.passwordAuthSettings #removePasswordAuth")
64-
.removeClass("hidden");
63+
.qs(".section.passwordAuthSettings #removePasswordAuth")
64+
?.removeClass("hidden");
6565
}
6666
} else {
6767
pageElement
68-
.find(".section.passwordAuthSettings #addPasswordAuth")
69-
.removeClass("hidden");
68+
.qs(".section.passwordAuthSettings #addPasswordAuth")
69+
?.removeClass("hidden");
7070
}
7171

7272
if (googleProvider) {
7373
pageElement
74-
.find(".section.googleAuthSettings #removeGoogleAuth")
75-
.removeClass("hidden");
74+
.qs(".section.googleAuthSettings #removeGoogleAuth")
75+
?.removeClass("hidden");
7676
if (passwordProvider || githubProvider) {
7777
pageElement
78-
.find(".section.googleAuthSettings #removeGoogleAuth")
79-
.removeClass("disabled");
78+
.qs(".section.googleAuthSettings #removeGoogleAuth")
79+
?.removeClass("disabled");
8080
} else {
8181
pageElement
82-
.find(".section.googleAuthSettings #removeGoogleAuth")
83-
.addClass("disabled");
82+
.qs(".section.googleAuthSettings #removeGoogleAuth")
83+
?.addClass("disabled");
8484
}
8585
} else {
8686
pageElement
87-
.find(".section.googleAuthSettings #addGoogleAuth")
88-
.removeClass("hidden");
87+
.qs(".section.googleAuthSettings #addGoogleAuth")
88+
?.removeClass("hidden");
8989
}
9090
if (githubProvider) {
9191
pageElement
92-
.find(".section.githubAuthSettings #removeGithubAuth")
93-
.removeClass("hidden");
92+
.qs(".section.githubAuthSettings #removeGithubAuth")
93+
?.removeClass("hidden");
9494
if (passwordProvider || googleProvider) {
9595
pageElement
96-
.find(".section.githubAuthSettings #removeGithubAuth")
97-
.removeClass("disabled");
96+
.qs(".section.githubAuthSettings #removeGithubAuth")
97+
?.removeClass("disabled");
9898
} else {
9999
pageElement
100-
.find(".section.githubAuthSettings #removeGithubAuth")
101-
.addClass("disabled");
100+
.qs(".section.githubAuthSettings #removeGithubAuth")
101+
?.addClass("disabled");
102102
}
103103
} else {
104104
pageElement
105-
.find(".section.githubAuthSettings #addGithubAuth")
106-
.removeClass("hidden");
105+
.qs(".section.githubAuthSettings #addGithubAuth")
106+
?.removeClass("hidden");
107107
}
108108
}
109109

110110
function updateIntegrationSections(): void {
111111
//no code and no discord
112112
if (!isAuthenticated()) {
113-
pageElement.find(".section.discordIntegration").addClass("hidden");
113+
pageElement.qs(".section.discordIntegration")?.addClass("hidden");
114114
} else {
115115
if (!getSnapshot()) return;
116-
pageElement.find(".section.discordIntegration").removeClass("hidden");
116+
pageElement.qs(".section.discordIntegration")?.removeClass("hidden");
117117

118118
if (getSnapshot()?.discordId === undefined) {
119119
//show button
120120
pageElement
121-
.find(".section.discordIntegration .buttons")
122-
.removeClass("hidden");
123-
pageElement.find(".section.discordIntegration .info").addClass("hidden");
121+
.qs(".section.discordIntegration .buttons")
122+
?.removeClass("hidden");
123+
pageElement.qs(".section.discordIntegration .info")?.addClass("hidden");
124124
} else {
125125
pageElement
126-
.find(".section.discordIntegration .buttons")
127-
.addClass("hidden");
126+
.qs(".section.discordIntegration .buttons")
127+
?.addClass("hidden");
128128
pageElement
129-
.find(".section.discordIntegration .info")
130-
.removeClass("hidden");
129+
.qs(".section.discordIntegration .info")
130+
?.removeClass("hidden");
131131
}
132132
}
133133
}
134134

135135
function updateTabs(): void {
136136
void swapElements(
137-
pageElement.find(".tab.active")[0] as HTMLElement,
138-
pageElement.find(`.tab[data-tab="${state.tab}"]`)[0] as HTMLElement,
137+
pageElement.qs(".tab.active"),
138+
pageElement.qs(`.tab[data-tab="${state.tab}"]`),
139139
250,
140140
async () => {
141141
//
142142
},
143143
async () => {
144-
pageElement.find(".tab").removeClass("active");
145-
pageElement.find(`.tab[data-tab="${state.tab}"]`).addClass("active");
144+
pageElement.qs(".tab")?.removeClass("active");
145+
pageElement.qs(`.tab[data-tab="${state.tab}"]`)?.addClass("active");
146146
},
147147
);
148-
pageElement.find("button").removeClass("active");
149-
pageElement.find(`button[data-tab="${state.tab}"]`).addClass("active");
148+
pageElement.qs("button")?.removeClass("active");
149+
pageElement.qs(`button[data-tab="${state.tab}"]`)?.addClass("active");
150150
}
151151

152152
function updateAccountSections(): void {
153+
pageElement.qs(".section.optOutOfLeaderboards .optedOut")?.addClass("hidden");
153154
pageElement
154-
.find(".section.optOutOfLeaderboards .optedOut")
155-
.addClass("hidden");
155+
.qs(".section.optOutOfLeaderboards .buttons")
156+
?.removeClass("hidden");
157+
pageElement.qs(".section.setStreakHourOffset .info")?.addClass("hidden");
156158
pageElement
157-
.find(".section.optOutOfLeaderboards .buttons")
158-
.removeClass("hidden");
159-
pageElement.find(".section.setStreakHourOffset .info").addClass("hidden");
160-
pageElement
161-
.find(".section.setStreakHourOffset .buttons")
162-
.removeClass("hidden");
159+
.qs(".section.setStreakHourOffset .buttons")
160+
?.removeClass("hidden");
163161

164162
const snapshot = getSnapshot();
165163
if (snapshot?.lbOptOut === true) {
166164
pageElement
167-
.find(".section.optOutOfLeaderboards .optedOut")
168-
.removeClass("hidden");
165+
.qs(".section.optOutOfLeaderboards .optedOut")
166+
?.removeClass("hidden");
169167
pageElement
170-
.find(".section.optOutOfLeaderboards .buttons")
171-
.addClass("hidden");
168+
.qs(".section.optOutOfLeaderboards .buttons")
169+
?.addClass("hidden");
172170
}
173171
if (snapshot?.streakHourOffset !== undefined) {
174-
pageElement
175-
.find(".section.setStreakHourOffset .info")
176-
.removeClass("hidden");
172+
pageElement.qs(".section.setStreakHourOffset .info")?.removeClass("hidden");
177173
const sign = snapshot?.streakHourOffset > 0 ? "+" : "";
178174
pageElement
179-
.find(".section.setStreakHourOffset .info span")
180-
.text(sign + snapshot?.streakHourOffset);
181-
pageElement
182-
.find(".section.setStreakHourOffset .buttons")
183-
.addClass("hidden");
175+
.qs(".section.setStreakHourOffset .info span")
176+
?.setText(sign + snapshot?.streakHourOffset);
177+
pageElement.qs(".section.setStreakHourOffset .buttons")?.addClass("hidden");
184178
}
185179
}
186180

@@ -195,15 +189,17 @@ export function updateUI(): void {
195189
page.setUrlParams(state);
196190
}
197191

198-
$(".page.pageAccountSettings").on("click", ".tabs button", (event) => {
199-
state.tab = $(event.target).data("tab") as State["tab"];
192+
qs(".page.pageAccountSettings")?.onChild("click", ".tabs button", (event) => {
193+
state.tab = (event.target as HTMLElement).getAttribute(
194+
"data-tab",
195+
) as State["tab"];
200196
updateTabs();
201197
page.setUrlParams(state);
202198
});
203199

204-
$(
200+
qs(
205201
".page.pageAccountSettings .section.discordIntegration .getLinkAndGoToOauth",
206-
).on("click", () => {
202+
)?.on("click", () => {
207203
Loader.show();
208204
void Ape.users.getDiscordOAuth().then((response) => {
209205
if (response.status === 200) {
@@ -217,7 +213,7 @@ $(
217213
});
218214
});
219215

220-
$(".page.pageAccountSettings #setStreakHourOffset").on("click", () => {
216+
qs(".page.pageAccountSettings #setStreakHourOffset")?.on("click", () => {
221217
StreakHourOffsetModal.show();
222218
});
223219

@@ -230,7 +226,7 @@ AuthEvent.subscribe((event) => {
230226
export const page = new PageWithUrlParams({
231227
id: "accountSettings",
232228
display: "Account Settings",
233-
element: qsr(".page.pageAccountSettings"),
229+
element: pageElement,
234230
path: "/account-settings",
235231
urlParamsSchema: UrlParameterSchema,
236232
afterHide: async (): Promise<void> => {
@@ -241,11 +237,11 @@ export const page = new PageWithUrlParams({
241237
state.tab = options.urlParams.tab;
242238
}
243239
Skeleton.append("pageAccountSettings", "main");
244-
pageElement.find(`.tab[data-tab="${state.tab}"]`).addClass("active");
240+
pageElement.qs(`.tab[data-tab="${state.tab}"]`)?.addClass("active");
245241
updateUI();
246242
},
247243
});
248244

249-
$(() => {
245+
onDocumentReady(() => {
250246
Skeleton.save("pageAccountSettings");
251247
});

frontend/src/ts/utils/misc.ts

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { Result } from "@monkeytype/schemas/results";
77
import { RankAndCount } from "@monkeytype/schemas/users";
88
import { roundTo2 } from "@monkeytype/util/numbers";
99
import { animate, AnimationParams } from "animejs";
10+
import { ElementWithUtils } from "./dom";
1011

1112
export function whorf(speed: number, wordlen: number): number {
1213
return Math.min(
@@ -187,8 +188,8 @@ type LastIndex = {
187188
export const trailingComposeChars = /[\u02B0-\u02FF`´^¨~]+$|.*$/;
188189

189190
export async function swapElements(
190-
el1: HTMLElement,
191-
el2: HTMLElement,
191+
el1: ElementWithUtils | null,
192+
el2: ElementWithUtils | null,
192193
totalDuration: number,
193194
callback = async function (): Promise<void> {
194195
return Promise.resolve();
@@ -203,38 +204,35 @@ export async function swapElements(
203204

204205
totalDuration = applyReducedMotion(totalDuration);
205206
if (
206-
(el1.classList.contains("hidden") && !el2.classList.contains("hidden")) ||
207-
(!el1.classList.contains("hidden") && el2.classList.contains("hidden"))
207+
(el1.hasClass("hidden") && !el2.hasClass("hidden")) ||
208+
(!el1.hasClass("hidden") && el2.hasClass("hidden"))
208209
) {
209210
//one of them is hidden and the other is visible
210-
if (el1.classList.contains("hidden")) {
211+
if (el1.hasClass("hidden")) {
211212
await middleCallback();
212213
await callback();
213214
return false;
214215
}
215216

216-
el1.classList.remove("hidden");
217-
await promiseAnimate(el1, {
217+
el1.show();
218+
await el1.promiseAnimate({
218219
opacity: [1, 0],
219220
duration: totalDuration / 2,
220221
});
221-
el1.classList.add("hidden");
222+
el1.hide();
222223
await middleCallback();
223-
el2.classList.remove("hidden");
224-
await promiseAnimate(el2, {
224+
el2.show();
225+
await el2.promiseAnimate({
225226
opacity: [0, 1],
226227
duration: totalDuration / 2,
227228
});
228229
await callback();
229-
} else if (
230-
el1.classList.contains("hidden") &&
231-
el2.classList.contains("hidden")
232-
) {
230+
} else if (el1.hasClass("hidden") && el2.hasClass("hidden")) {
233231
//both are hidden, only fade in the second
234232
await middleCallback();
235233

236-
el2.classList.remove("hidden");
237-
await promiseAnimate(el2, {
234+
el2.show();
235+
await el2.promiseAnimate({
238236
opacity: [0, 1],
239237
duration: totalDuration / 2,
240238
});

0 commit comments

Comments
 (0)