Skip to content

Commit

Permalink
feat: Initial frontend search proof of concept with Fuse.js (#3435)
Browse files Browse the repository at this point in the history
Co-authored-by: Ian Jones <[email protected]>
  • Loading branch information
DafyddLlyr and ianjon3s authored Jul 30, 2024
1 parent 3c7a772 commit c0990ca
Show file tree
Hide file tree
Showing 7 changed files with 364 additions and 117 deletions.
3 changes: 2 additions & 1 deletion editor.planx.uk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"@mui/material": "^5.15.10",
"@mui/utils": "^5.15.11",
"@opensystemslab/map": "^0.8.3",
"@opensystemslab/planx-core": "git+https://github.com/theopensystemslab/planx-core#dd24b0a",
"@opensystemslab/planx-core": "git+https://github.com/theopensystemslab/planx-core#0336fd4",
"@tiptap/core": "^2.4.0",
"@tiptap/extension-bold": "^2.0.3",
"@tiptap/extension-bubble-menu": "^2.1.13",
Expand Down Expand Up @@ -51,6 +51,7 @@
"dompurify": "^3.0.6",
"dotenv": "^16.4.5",
"formik": "^2.4.5",
"fuse.js": "^7.0.0",
"graphql": "^16.8.1",
"graphql-tag": "^2.12.6",
"immer": "^9.0.21",
Expand Down
51 changes: 29 additions & 22 deletions editor.planx.uk/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

53 changes: 53 additions & 0 deletions editor.planx.uk/src/hooks/useSearch.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import Fuse, { IFuseOptions } from "fuse.js";
import { useEffect, useMemo, useState } from "react";

interface UseSearchProps<T extends object> {
list: T[];
keys: string[];
}

export interface SearchResult<T extends object> {
item: T;
key: string;
matchIndices?: [number, number][];
}

export type SearchResults<T extends object> = SearchResult<T>[];

export const useSearch = <T extends object>({
list,
keys,
}: UseSearchProps<T>) => {
const [pattern, setPattern] = useState("");
const [results, setResults] = useState<SearchResults<T>>([]);

const fuseOptions: IFuseOptions<T> = useMemo(
() => ({
useExtendedSearch: true,
includeMatches: true,
minMatchCharLength: 3,
keys,
}),
[keys],
);

const fuse = useMemo(
() => new Fuse<T>(list, fuseOptions),
[list, fuseOptions],
);

useEffect(() => {
const fuseResults = fuse.search(pattern);
setResults(
fuseResults.map((result) => ({
item: result.item,
key: result.matches?.[0].key || "",
// We only display the first match
matchIndices:
(result.matches?.[0].indices as [number, number][]) || undefined,
})),
);
}, [pattern]);

return { results, search: setPattern };
};
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ import Hanger from "./Hanger";
import Question from "./Question";

const ExternalPortal: React.FC<any> = (props) => {
const copyNode = useStore((state) => state.copyNode);
const [copyNode, addExternalPortal] = useStore((state) => [
state.copyNode,
state.addExternalPortal,
]);
const [href, setHref] = useState("Loading...");

const { data, loading } = useQuery(
Expand All @@ -23,6 +26,7 @@ const ExternalPortal: React.FC<any> = (props) => {
flows_by_pk(id: $id) {
id
slug
name
team {
slug
}
Expand All @@ -31,8 +35,17 @@ const ExternalPortal: React.FC<any> = (props) => {
`,
{
variables: { id: props.data.flowId },
onCompleted: (data) =>
setHref([data.flows_by_pk.team.slug, data.flows_by_pk.slug].join("/")),
onCompleted: (data) => {
const href = [data.flows_by_pk.team.slug, data.flows_by_pk.slug].join(
"/",
);
setHref(href);
addExternalPortal({
id: props.data.flowId,
name: data.flows_by_pk.name,
href,
});
},
},
);

Expand Down
Loading

0 comments on commit c0990ca

Please sign in to comment.