diff --git a/frontend/src/ts/commandline/lists/load-challenge.ts b/frontend/src/ts/commandline/lists/load-challenge.ts index f938047ff..09c893459 100644 --- a/frontend/src/ts/commandline/lists/load-challenge.ts +++ b/frontend/src/ts/commandline/lists/load-challenge.ts @@ -1,4 +1,4 @@ -import { navigate } from "../../observables/navigate-event"; +import { navigate } from "../../controllers/route-controller"; import * as ChallengeController from "../../controllers/challenge-controller"; import * as TestLogic from "../../test/test-logic"; import { capitalizeFirstLetterOfEachWord } from "../../utils/misc"; diff --git a/frontend/src/ts/commandline/lists/navigation.ts b/frontend/src/ts/commandline/lists/navigation.ts index cf6223b07..8f2e22369 100644 --- a/frontend/src/ts/commandline/lists/navigation.ts +++ b/frontend/src/ts/commandline/lists/navigation.ts @@ -1,4 +1,4 @@ -import { navigate } from "../../observables/navigate-event"; +import { navigate } from "../../controllers/route-controller"; import { toggleFullscreen } from "../../utils/misc"; const commands: MonkeyTypes.Command[] = [ diff --git a/frontend/src/ts/controllers/account-controller.ts b/frontend/src/ts/controllers/account-controller.ts index a56ae49b0..3e99f1429 100644 --- a/frontend/src/ts/controllers/account-controller.ts +++ b/frontend/src/ts/controllers/account-controller.ts @@ -43,9 +43,9 @@ import { hideFavoriteQuoteLength, showFavoriteQuoteLength, } from "../test/test-config"; -import { navigate } from "../observables/navigate-event"; import { update as updateTagsCommands } from "../commandline/lists/tags"; import * as ConnectionState from "../states/connection"; +import { navigate } from "./route-controller"; let signedOutThisSession = false; diff --git a/frontend/src/ts/controllers/input-controller.ts b/frontend/src/ts/controllers/input-controller.ts index 2fa9a3cc1..dca35f002 100644 --- a/frontend/src/ts/controllers/input-controller.ts +++ b/frontend/src/ts/controllers/input-controller.ts @@ -27,12 +27,12 @@ import * as TestInput from "../test/test-input"; import * as TestWords from "../test/test-words"; import * as Hangul from "hangul-js"; import * as CustomTextState from "../states/custom-text-name"; -import { navigate } from "../observables/navigate-event"; import * as FunboxList from "../test/funbox/funbox-list"; import * as Settings from "../pages/settings"; import * as KeymapEvent from "../observables/keymap-event"; import { IgnoredKeys } from "../constants/ignored-keys"; import { ModifierKeys } from "../constants/modifier-keys"; +import { navigate } from "./route-controller"; let dontInsertSpace = false; let correctShiftUsed = true; diff --git a/frontend/src/ts/controllers/page-controller.ts b/frontend/src/ts/controllers/page-controller.ts index 074d4293d..96c2dad42 100644 --- a/frontend/src/ts/controllers/page-controller.ts +++ b/frontend/src/ts/controllers/page-controller.ts @@ -10,14 +10,13 @@ import * as PageProfile from "../pages/profile"; import * as PageProfileSearch from "../pages/profile-search"; import * as Page404 from "../pages/404"; import * as PageTransition from "../states/page-transition"; -import type Page from "../pages/page"; import * as AdController from "../controllers/ad-controller"; import * as Focus from "../test/focus"; interface ChangeOptions { force?: boolean; params?: { [key: string]: string }; - data?: any; + data?: unknown; } export async function change( @@ -45,7 +44,7 @@ export async function change( console.log(`changing page ${pageName}`); } - const pages: Record = { + const pages = { loading: PageLoading.page, test: PageTest.page, settings: Settings.page, @@ -80,6 +79,7 @@ export async function change( previousPage?.afterHide(); await nextPage?.beforeShow({ params: options.params, + // @ts-expect-error data: options.data, }); } diff --git a/frontend/src/ts/controllers/profile-search-controller.ts b/frontend/src/ts/controllers/profile-search-controller.ts new file mode 100644 index 000000000..a21491b0b --- /dev/null +++ b/frontend/src/ts/controllers/profile-search-controller.ts @@ -0,0 +1,76 @@ +import { InputIndicator } from "../elements/input-indicator"; +import { sleep } from "../utils/misc"; +import Ape from "../ape"; +import { navigate } from "../controllers/route-controller"; +import * as Skeleton from "../popups/skeleton"; + +const searchIndicator = new InputIndicator( + $(".page.pageProfileSearch .search input"), + { + notFound: { + icon: "fa-user-slash", + level: -1, + }, + error: { + icon: "fa-times", + level: -1, + }, + checking: { + icon: "fa-circle-notch", + spinIcon: true, + level: 1, + }, + } +); + +function disableInputs(): void { + $(".page.pageProfileSearch .search .button").addClass("disabled"); + $(".page.pageProfileSearch .search input").attr("disabled", "disabled"); +} + +function enableInputs(): void { + $(".page.pageProfileSearch .search .button").removeClass("disabled"); + $(".page.pageProfileSearch .search input").removeAttr("disabled"); +} + +function areInputsDisabled(): boolean { + return ( + $(".page.pageProfileSearch .search input").attr("disabled") !== undefined + ); +} + +async function lookupProfile(): Promise { + searchIndicator.hide(); + const name = $(".page.pageProfileSearch .search input").val() as string; + if (name === "") return; + + searchIndicator.show("checking"); + disableInputs(); + + await sleep(500); + + const response = await Ape.users.getProfileByName(name); + enableInputs(); + if (response.status === 404) { + searchIndicator.show("notFound", "User not found"); + return; + } else if (response.status !== 200) { + searchIndicator.show("error", `Error: ${response.message}`); + return; + } + searchIndicator.hide(); + navigate(`/profile/${name}`, { + data: response.data, + }); +} + +$(".page.pageProfileSearch .search input").on("keyup", (e) => { + if (e.key === "Enter" && !areInputsDisabled()) lookupProfile(); +}); + +$(".page.pageProfileSearch .search .button").on("click", () => { + if (areInputsDisabled()) return; + lookupProfile(); +}); + +Skeleton.save("pageProfileSearch"); diff --git a/frontend/src/ts/controllers/route-controller.ts b/frontend/src/ts/controllers/route-controller.ts index d04a7e803..48157b643 100644 --- a/frontend/src/ts/controllers/route-controller.ts +++ b/frontend/src/ts/controllers/route-controller.ts @@ -2,7 +2,6 @@ import * as PageController from "./page-controller"; import * as Leaderboards from "../elements/leaderboards"; import * as TestUI from "../test/test-ui"; import * as PageTransition from "../states/page-transition"; -import * as NavigateEvent from "../observables/navigate-event"; import { Auth } from "../firebase"; //source: https://www.youtube.com/watch?v=OstALBk-jTc @@ -11,7 +10,7 @@ import { Auth } from "../firebase"; //this will be used in tribe interface NavigateOptions { empty?: boolean; - data?: any; + data?: unknown; } function pathToRegex(path: string): RegExp { @@ -84,11 +83,11 @@ const routes: Route[] = [ path: "/login", load: (): void => { if (!Auth) { - nav("/"); + navigate("/"); return; } if (Auth.currentUser) { - nav("/account"); + navigate("/account"); return; } PageController.change("login"); @@ -98,7 +97,7 @@ const routes: Route[] = [ path: "/account", load: (_params, options): void => { if (!Auth) { - nav("/"); + navigate("/"); return; } PageController.change("account", { @@ -126,7 +125,7 @@ const routes: Route[] = [ }, ]; -function nav( +export function navigate( url = window.location.pathname + window.location.search, options = {} as NavigateOptions ): void { @@ -173,19 +172,15 @@ document.addEventListener("DOMContentLoaded", () => { const target = e?.target as HTMLLinkElement; if (target.matches("[router-link]") && target?.href) { e.preventDefault(); - nav(target.href); + navigate(target.href); } }); }); $("#top .logo").on("click", () => { - nav("/"); + navigate("/"); }); $("#popups").on("click", "#leaderboards a.entryName", () => { Leaderboards.hide(); }); - -NavigateEvent.subscribe((url, options) => { - nav(url, options); -}); diff --git a/frontend/src/ts/elements/profile.ts b/frontend/src/ts/elements/profile.ts index 00d29d6a5..8db9e6a8e 100644 --- a/frontend/src/ts/elements/profile.ts +++ b/frontend/src/ts/elements/profile.ts @@ -10,7 +10,7 @@ import formatDistanceToNowStrict from "date-fns/formatDistanceToNowStrict"; type ProfileViewPaths = "profile" | "account"; -interface ProfileData extends MonkeyTypes.Snapshot { +export interface ProfileData extends MonkeyTypes.Snapshot { allTimeLbs: MonkeyTypes.LeaderboardMemory; uid: string; } diff --git a/frontend/src/ts/index.ts b/frontend/src/ts/index.ts index 59ed23e84..e56b5b3c0 100644 --- a/frontend/src/ts/index.ts +++ b/frontend/src/ts/index.ts @@ -40,6 +40,7 @@ import { egVideoListener } from "./popups/video-ad-popup"; import "./states/connection"; import "./test/tts"; import "./elements/fps-counter"; +import "./controllers/profile-search-controller"; type ExtendedGlobal = typeof globalThis & MonkeyTypes.Global; diff --git a/frontend/src/ts/observables/navigate-event.ts b/frontend/src/ts/observables/navigate-event.ts deleted file mode 100644 index e427b512a..000000000 --- a/frontend/src/ts/observables/navigate-event.ts +++ /dev/null @@ -1,23 +0,0 @@ -type SubscribeFunction = (url?: string, options?: NavigateOptions) => void; - -const subscribers: SubscribeFunction[] = []; - -export function subscribe(fn: SubscribeFunction): void { - subscribers.push(fn); -} - -interface NavigateOptions { - empty?: boolean; - data?: any; -} - -export function navigate(url?: string, options?: NavigateOptions): void { - subscribers.forEach((fn) => { - try { - fn(url, options); - } catch (e) { - console.error("Navigate event subscriber threw an error"); - console.error(e); - } - }); -} diff --git a/frontend/src/ts/pages/page.ts b/frontend/src/ts/pages/page.ts index 509e46c52..3bf97d552 100644 --- a/frontend/src/ts/pages/page.ts +++ b/frontend/src/ts/pages/page.ts @@ -1,15 +1,15 @@ -interface Options { +interface Options { params?: Record; - data?: any; + data?: T; } -export default class Page { +export default class Page { public name: MonkeyTypes.PageName; public element: JQuery; public pathname: string; public beforeHide: () => Promise; public afterHide: () => Promise; - public beforeShow: (options: Options) => Promise; + public beforeShow: (options: Options) => Promise; public afterShow: () => Promise; constructor( name: MonkeyTypes.PageName, @@ -17,7 +17,7 @@ export default class Page { pathname: string, beforeHide: () => Promise, afterHide: () => Promise, - beforeShow: (options: Options) => Promise, + beforeShow: (options: Options) => Promise, afterShow: () => Promise ) { this.name = name; diff --git a/frontend/src/ts/pages/profile-search.ts b/frontend/src/ts/pages/profile-search.ts index caf845b6b..71e3f2489 100644 --- a/frontend/src/ts/pages/profile-search.ts +++ b/frontend/src/ts/pages/profile-search.ts @@ -1,78 +1,6 @@ import Page from "./page"; -import { InputIndicator } from "../elements/input-indicator"; -import { sleep } from "../utils/misc"; -import Ape from "../ape"; -import { navigate } from "../observables/navigate-event"; import * as Skeleton from "../popups/skeleton"; -const searchIndicator = new InputIndicator( - $(".page.pageProfileSearch .search input"), - { - notFound: { - icon: "fa-user-slash", - level: -1, - }, - error: { - icon: "fa-times", - level: -1, - }, - checking: { - icon: "fa-circle-notch", - spinIcon: true, - level: 1, - }, - } -); - -function disableInputs(): void { - $(".page.pageProfileSearch .search .button").addClass("disabled"); - $(".page.pageProfileSearch .search input").attr("disabled", "disabled"); -} - -function enableInputs(): void { - $(".page.pageProfileSearch .search .button").removeClass("disabled"); - $(".page.pageProfileSearch .search input").removeAttr("disabled"); -} - -function areInputsDisabled(): boolean { - return ( - $(".page.pageProfileSearch .search input").attr("disabled") !== undefined - ); -} - -async function lookupProfile(): Promise { - searchIndicator.hide(); - const name = $(".page.pageProfileSearch .search input").val() as string; - if (name === "") return; - - searchIndicator.show("checking"); - disableInputs(); - - await sleep(500); - - const response = await Ape.users.getProfileByName(name); - enableInputs(); - if (response.status === 404) { - searchIndicator.show("notFound", "User not found"); - return; - } else if (response.status !== 200) { - searchIndicator.show("error", `Error: ${response.message}`); - return; - } - navigate(`/profile/${name}`, { - data: response.data, - }); -} - -$(".page.pageProfileSearch .search input").on("keyup", (e) => { - if (e.key === "Enter" && !areInputsDisabled()) lookupProfile(); -}); - -$(".page.pageProfileSearch .search .button").on("click", () => { - if (areInputsDisabled()) return; - lookupProfile(); -}); - export const page = new Page( "profileSearch", $(".page.pageProfileSearch"), @@ -86,11 +14,8 @@ export const page = new Page( async () => { Skeleton.append("pageProfileSearch", "middle"); $(".page.pageProfileSearch input").val(""); - searchIndicator.hide(); }, async () => { $(".page.pageProfileSearch input").focus(); } ); - -Skeleton.save("pageProfileSearch"); diff --git a/frontend/src/ts/pages/profile.ts b/frontend/src/ts/pages/profile.ts index 67aabdb36..abc1bc2be 100644 --- a/frontend/src/ts/pages/profile.ts +++ b/frontend/src/ts/pages/profile.ts @@ -151,7 +151,7 @@ function reset(): void { interface UpdateOptions { uidOrName?: string; - data?: any; + data?: undefined | Profile.ProfileData; } async function update(options: UpdateOptions): Promise { @@ -199,7 +199,7 @@ $(".page.pageProfile").on("click", ".profile .userReportButton", () => { UserReportPopup.show({ uid, name }); }); -export const page = new Page( +export const page = new Page( "profile", $(".page.pageProfile"), "/profile", @@ -220,7 +220,7 @@ export const page = new Page( reset(); update({ uidOrName, - data: options?.["data"], + data: options?.data, }); } else { $(".page.pageProfile .preloader").addClass("hidden");