diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 9ef1a7d..f4cdc35 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -7,6 +7,7 @@ import { Login, Settings, Entity, + SearchPage, } from "./pages"; import { SearchImageContextProvider } from "@contexts/SearchImageContext"; import { WithNotifications } from "@contexts/Notifications"; @@ -29,6 +30,7 @@ export const App = () => { + diff --git a/frontend/src/components/app-wrapper/dock.tsx b/frontend/src/components/app-wrapper/dock.tsx index ad0a3be..2e70b5a 100644 --- a/frontend/src/components/app-wrapper/dock.tsx +++ b/frontend/src/components/app-wrapper/dock.tsx @@ -8,7 +8,7 @@ export const Dock: Component = () => { - + diff --git a/frontend/src/contexts/SearchImageContext.tsx b/frontend/src/contexts/SearchImageContext.tsx index 26469d8..193a065 100644 --- a/frontend/src/contexts/SearchImageContext.tsx +++ b/frontend/src/contexts/SearchImageContext.tsx @@ -11,15 +11,10 @@ import { CategoryUnion, getUserImages, JustTheImageWhatAreTheseNames, + UserImage, } from "../network"; import { groupPropertiesWithImage } from "../utils/groupPropertiesWithImage"; -export type ImageWithRawData = Awaited< - ReturnType ->["ImageProperties"][number] & { - rawData: string[]; -}; - type TaggedCategory = Extract< CategoryUnion, { type: T } @@ -30,7 +25,7 @@ type CategoriesSpecificData = { }; export type SearchImageStore = { - images: Accessor; + images: Accessor; userImages: Accessor; @@ -44,51 +39,17 @@ export type SearchImageStore = { onRefetchImages: () => void; }; -// How wonderfully functional -const getAllValues = (object: object): Array => { - const loop = (acc: Array, next: object): Array => { - for (const [key, _value] of Object.entries(next)) { - if (key === "ID") { - continue; - } - - const value: unknown = _value; - switch (typeof value) { - case "object": - if (value != null) { - acc.push(...loop(acc, value)); - } - break; - case "string": - case "number": - case "boolean": - acc.push(value.toString()); - break; - default: - break; - } - } - - return acc; - }; - - return loop([], object); -}; - const SearchImageContext = createContext(); export const SearchImageContextProvider: Component = (props) => { const [data, { refetch }] = createResource(getUserImages); - const imageData = createMemo(() => { + const imageData = createMemo(() => { const d = data(); if (d == null) { return []; } - return d.ImageProperties.map((d) => ({ - ...d, - rawData: getAllValues(d), - })); + return d.ImageProperties; }); const processingImages = () => data()?.ProcessingImages ?? []; diff --git a/frontend/src/pages/index.ts b/frontend/src/pages/index.ts index 06db031..ce57c79 100644 --- a/frontend/src/pages/index.ts +++ b/frontend/src/pages/index.ts @@ -4,3 +4,4 @@ export * from "./image"; export * from "./settings"; export * from "./login"; export * from "./entity"; +export * from "./search"; diff --git a/frontend/src/pages/search/index.tsx b/frontend/src/pages/search/index.tsx new file mode 100644 index 0000000..d2879a1 --- /dev/null +++ b/frontend/src/pages/search/index.tsx @@ -0,0 +1,48 @@ +import { Component, createSignal } from "solid-js"; +import { Search } from "@kobalte/core/search"; +import { IconSearch } from "@tabler/icons-solidjs"; +import { useSearch } from "./search"; +import { UserImage } from "@network/index"; + +export const SearchPage: Component = () => { + const fuse = useSearch(); + + const [searchItems, setSearchItems] = createSignal([]); + + return ( + { + const items = fuse().search(e); + setSearchItems(items.map((i) => i.item.image)); + }} + itemComponent={(props) => ( + + + {JSON.stringify(props.item.rawValue)} + + + )} + > + + + + + + + + + + + + + + No result found + + + + ); +}; diff --git a/frontend/src/pages/search/search.ts b/frontend/src/pages/search/search.ts new file mode 100644 index 0000000..8e0a0cf --- /dev/null +++ b/frontend/src/pages/search/search.ts @@ -0,0 +1,47 @@ +import { useSearchImageContext } from "@contexts/SearchImageContext"; +import { UserImage } from "@network/index"; +import { createMemo } from "solid-js"; +import Fuse from "fuse.js"; + +const getSearchTerms = (image: UserImage): Array => { + switch (image.type) { + case "location": + return [ + image.data.Name, + image.data.Description, + image.data.Address, + image.data.CreatedAt, + ].filter((i) => i != null); + case "event": + return [ + image.data.Name, + image.data.Description, + image.data.CreatedAt, + ].filter((i) => i != null); + case "contact": + return [ + image.data.Name, + image.data.Description, + image.data.CreatedAt, + image.data.Email, + image.data.PhoneNumber, + ].filter((i) => i != null); + case "note": + return [ + image.data.Name, + image.data.Description, + image.data.CreatedAt, + image.data.Content, + ].filter((i) => i != null); + } +}; + +export const useSearch = () => { + const { images } = useSearchImageContext(); + + const searchTerms = createMemo(() => + images().map((i) => ({ image: i, searchTerms: getSearchTerms(i) })), + ); + + return () => new Fuse(searchTerms(), { keys: ["searchTerms"] }); +};