modmapper-web/components/AddModDialog.tsx
Tyler Hallada 236b4c84ca SearchProvider singleton, fix lag with addAllAsync
Load modSearch data asynchronously and only rebuild the search if the page is refreshed. Fixes the lag when returning to the base sidebar page from a data page.
2022-08-27 17:01:16 -04:00

95 lines
3.0 KiB
TypeScript

import { createPortal } from "react-dom";
import React, { useCallback, useEffect, useState, useRef } from "react";
import { useDispatch } from "react-redux";
import useSWRImmutable from "swr/immutable";
import AddModData from "./AddModData";
import SearchBar from "./SearchBar";
import { jsonFetcher } from "../lib/api";
import { updateFetchedPlugin, PluginsByHashWithMods } from "../slices/plugins";
import styles from "../styles/AddModDialog.module.css";
import EscapeListener from "./EscapeListener";
type Props = {
counts: Record<number, [number, number, number]> | null;
};
const AddModDialog: React.FC<Props> = ({ counts }) => {
const [selectedMod, setSelectedMod] = useState<number | null>(null);
const [selectedPlugin, setSelectedPlugin] = useState<string | null>(null);
const [dialogShown, setDialogShown] = useState(false);
const searchInput = useRef<HTMLInputElement | null>(null);
const dispatch = useDispatch();
const { data, error } = useSWRImmutable(
selectedPlugin
? `https://plugins.modmapper.com/${selectedPlugin}.json`
: null,
(_) => jsonFetcher<PluginsByHashWithMods>(_)
);
const onAddModButtonClick = useCallback(async () => {
setSelectedMod(null);
setDialogShown(true);
requestAnimationFrame(() => {
if (searchInput.current) searchInput.current.focus();
});
}, [setSelectedMod, setDialogShown]);
return (
<>
<EscapeListener onEscape={() => setDialogShown(false)} />
<button onClick={onAddModButtonClick}>Add mod</button>
{typeof window !== "undefined" &&
createPortal(
<dialog open={dialogShown} className={styles.dialog}>
<h3>Add mod</h3>
<SearchBar
counts={counts}
sidebarOpen={false}
placeholder="Search mods…"
onSelectResult={(selectedItem) => {
if (selectedItem) {
setSelectedMod(selectedItem.id);
}
}}
inputRef={searchInput}
/>
{selectedMod && (
<AddModData
selectedMod={selectedMod}
selectedPlugin={selectedPlugin}
setSelectedPlugin={setSelectedPlugin}
counts={counts}
/>
)}
<menu>
<button
onClick={() => {
setSelectedMod(null);
setDialogShown(false);
if (searchInput.current) searchInput.current.value = "";
}}
>
Cancel
</button>
<button
onClick={() => {
if (data)
dispatch(updateFetchedPlugin({ ...data, enabled: true }));
setDialogShown(false);
}}
disabled={!selectedMod || !selectedPlugin || !data}
>
Add
</button>
</menu>
</dialog>,
document.body
)}
</>
);
};
export default AddModDialog;