From 792c0e63a9f91170631aef5887a0a91cbb6c748f Mon Sep 17 00:00:00 2001 From: SleeplessOne1917 Date: Fri, 21 Jul 2023 20:22:16 -0400 Subject: [PATCH] Add loading screen for remote fetch and refactor loading ellipses --- .../components/common/loading-ellipses.tsx | 34 +++++++++++++++++ .../components/common/searchable-select.tsx | 37 +++++-------------- src/shared/components/remote-fetch.tsx | 20 +++++++++- 3 files changed, 63 insertions(+), 28 deletions(-) create mode 100644 src/shared/components/common/loading-ellipses.tsx diff --git a/src/shared/components/common/loading-ellipses.tsx b/src/shared/components/common/loading-ellipses.tsx new file mode 100644 index 00000000..ba96101f --- /dev/null +++ b/src/shared/components/common/loading-ellipses.tsx @@ -0,0 +1,34 @@ +import { Component } from "inferno"; + +interface LoadingEllipsesState { + ellipses: string; +} + +export class LoadingEllipses extends Component { + state: LoadingEllipsesState = { + ellipses: "...", + }; + #interval?: NodeJS.Timer; + + constructor(props: any, context: any) { + super(props, context); + } + + render() { + return this.state.ellipses; + } + + componentDidMount() { + this.#interval = setInterval(this.#updateEllipses, 1000); + } + + componentWillUnmount() { + clearInterval(this.#interval); + } + + #updateEllipses = () => { + this.setState(({ ellipses }) => ({ + ellipses: ellipses.length === 3 ? "" : ellipses + ".", + })); + }; +} diff --git a/src/shared/components/common/searchable-select.tsx b/src/shared/components/common/searchable-select.tsx index ef59a8c2..96d88a54 100644 --- a/src/shared/components/common/searchable-select.tsx +++ b/src/shared/components/common/searchable-select.tsx @@ -9,6 +9,7 @@ import { } from "inferno"; import { I18NextService } from "../../services"; import { Icon, Spinner } from "./icon"; +import { LoadingEllipses } from "./loading-ellipses"; interface SearchableSelectProps { id: string; @@ -22,7 +23,6 @@ interface SearchableSelectProps { interface SearchableSelectState { selectedIndex: number; searchText: string; - loadingEllipses: string; } function handleSearch(i: SearchableSelect, e: ChangeEvent) { @@ -70,12 +70,10 @@ export class SearchableSelect extends Component< > { searchInputRef: RefObject = createRef(); toggleButtonRef: RefObject = createRef(); - private loadingEllipsesInterval?: NodeJS.Timer = undefined; state: SearchableSelectState = { selectedIndex: 0, searchText: "", - loadingEllipses: "...", }; constructor(props: SearchableSelectProps, context: any) { @@ -99,7 +97,7 @@ export class SearchableSelect extends Component< render() { const { id, options, onSearch, loading } = this.props; - const { searchText, selectedIndex, loadingEllipses } = this.state; + const { searchText, selectedIndex } = this.state; return (
@@ -116,9 +114,14 @@ export class SearchableSelect extends Component< onClick={linkEvent(this, focusSearch)} ref={this.toggleButtonRef} > - {loading - ? `${I18NextService.i18n.t("loading")}${loadingEllipses}` - : options[selectedIndex].label} + {loading ? ( + <> + {I18NextService.i18n.t("loading")} + + + ) : ( + options[selectedIndex].label + )}
@@ -180,24 +183,4 @@ export class SearchableSelect extends Component< selectedIndex, }; } - - componentDidUpdate() { - const { loading } = this.props; - if (loading && !this.loadingEllipsesInterval) { - this.loadingEllipsesInterval = setInterval(() => { - this.setState(({ loadingEllipses }) => ({ - loadingEllipses: - loadingEllipses.length === 3 ? "" : loadingEllipses + ".", - })); - }, 750); - } else if (!loading && this.loadingEllipsesInterval) { - clearInterval(this.loadingEllipsesInterval); - } - } - - componentWillUnmount() { - if (this.loadingEllipsesInterval) { - clearInterval(this.loadingEllipsesInterval); - } - } } diff --git a/src/shared/components/remote-fetch.tsx b/src/shared/components/remote-fetch.tsx index 9583002a..3ff219cd 100644 --- a/src/shared/components/remote-fetch.tsx +++ b/src/shared/components/remote-fetch.tsx @@ -8,6 +8,8 @@ import { InitialFetchRequest } from "../interfaces"; import { FirstLoadService, HttpService, I18NextService } from "../services"; import { RequestState } from "../services/HttpService"; import { HtmlTags } from "./common/html-tags"; +import { Spinner } from "./common/icon"; +import { LoadingEllipses } from "./common/loading-ellipses"; interface RemoteFetchProps { uri?: string; @@ -90,7 +92,9 @@ export class RemoteFetch extends Component { } get content() { - const status: "success" | "loading" | "empty" = "success"; + const status = "loading" as "success" | "loading" | "empty"; + + const { uri } = getRemoteFetchQueryParams(); switch (status) { case "success": { @@ -103,6 +107,20 @@ export class RemoteFetch extends Component { ); } + + case "loading": { + return ( + <> +

+ Fetching {uri ? uriToQuery(uri) : "remote community"} + +

+
+ +
+ + ); + } } }