From 3ed43a145ceea6a88cfa1ff4f20284c03a4938bb Mon Sep 17 00:00:00 2001
From: Adam Antal <adam@reload.dk>
Date: Wed, 8 Jun 2022 16:59:21 +0200
Subject: [PATCH] Commit for Mikkel with a patch so that he can help me - will
 be deleted

---
 src/apps/search-header/search-header.tsx      |  83 +++++-
 .../autosuggest-text/autossugest-text.tsx     |  39 ++-
 .../autosuggest/autosuggest.dev.tsx           |  60 +++++
 src/components/autosuggest/autosuggest.tsx    |  74 ++++--
 src/components/autosuggest/suggest.graphql    |   1 -
 .../demo-suggest-dropdown/suggest.graphql     |  18 --
 src/components/search-bar/search-bar.dev.tsx  |  14 +-
 src/components/search-bar/search-bar.tsx      |  46 ++--
 .../dbc-gateway/generated/graphql.schema.json | 251 +++++++++++++++++-
 src/core/dbc-gateway/generated/graphql.tsx    |   3 +-
 10 files changed, 495 insertions(+), 94 deletions(-)
 delete mode 100644 src/components/demo-suggest-dropdown/suggest.graphql

diff --git a/src/apps/search-header/search-header.tsx b/src/apps/search-header/search-header.tsx
index c796967c51..175918fc08 100644
--- a/src/apps/search-header/search-header.tsx
+++ b/src/apps/search-header/search-header.tsx
@@ -1,5 +1,11 @@
-import React, { useState } from "react";
+import React, { useEffect, useState } from "react";
+import { useCombobox } from "downshift";
+import {
+  SuggestionsFromQueryStringQuery,
+  useSuggestionsFromQueryStringQuery
+} from "../../core/dbc-gateway/generated/graphql";
 import SearchBar from "../../components/search-bar/search-bar";
+import { Autosuggest } from "../../components/autosuggest/autosuggest";
 
 export interface SearchHeaderProps {
   searchHeaderUrl?: string;
@@ -7,6 +13,9 @@ export interface SearchHeaderProps {
   inputPlaceholder?: string;
 }
 
+export type SearchResultArray =
+  SuggestionsFromQueryStringQuery["suggest"]["result"];
+
 const SearchHeader: React.FC<SearchHeaderProps> = ({
   searchHeaderUrl = "/search",
   altText = "search icon",
@@ -14,14 +23,72 @@ const SearchHeader: React.FC<SearchHeaderProps> = ({
 }) => {
   const [q, setQ] = useState("");
 
+  // get all the data we need from our graphQL query
+  const {
+    data,
+    isLoading,
+    status
+  }: {
+    data: SuggestionsFromQueryStringQuery | undefined;
+    isLoading: boolean;
+    status: string;
+  } = useSuggestionsFromQueryStringQuery({ q });
+
+  const [allItems, setAllItems] = useState<object[]>([]);
+
+  const [inputItems, setInputItems] = useState<any[]>([]);
+
+  // once we have data, we set it into our useSate
+  useEffect(() => {
+    if (data) {
+      const arayOfResults = data.suggest.result;
+      setAllItems(arayOfResults);
+      setInputItems(arayOfResults);
+    }
+  }, [data]);
+
+  // here we get all the downshift properties for a combobox that we will need
+  const {
+    isOpen,
+    getMenuProps,
+    highlightedIndex,
+    getItemProps,
+    getInputProps,
+    getComboboxProps
+  } = useCombobox({
+    items: inputItems
+  });
+
   return (
-    <SearchBar
-      q={q}
-      setQuery={setQ}
-      searchHeaderUrl={searchHeaderUrl}
-      altText={altText}
-      inputPlaceholder={inputPlaceholder}
-    />
+    <div className="header__menu-second">
+      {/* eslint-disable react/jsx-props-no-spreading */}
+      {/* The downshift combobox works this way by design */}
+      <form
+        action={searchHeaderUrl}
+        className="header__menu-search"
+        {...getComboboxProps()}
+      >
+        {/* eslint-enable react/jsx-props-no-spreading */}
+        <SearchBar
+          q={q}
+          setQuery={setQ}
+          searchHeaderUrl={searchHeaderUrl}
+          altText={altText}
+          inputPlaceholder={inputPlaceholder}
+          getInputProps={getInputProps}
+        />
+        <Autosuggest
+          q={q}
+          data={allItems}
+          isLoading={isLoading}
+          status={status}
+          getMenuProps={getMenuProps}
+          highlightedIndex={highlightedIndex}
+          getItemProps={getItemProps}
+          isOpen={isOpen}
+        />
+      </form>
+    </div>
   );
 };
 
diff --git a/src/components/autosuggest-text/autossugest-text.tsx b/src/components/autosuggest-text/autossugest-text.tsx
index 499a5e2c4e..7428a073dd 100644
--- a/src/components/autosuggest-text/autossugest-text.tsx
+++ b/src/components/autosuggest-text/autossugest-text.tsx
@@ -4,22 +4,43 @@ import { SuggestionsFromQueryStringQuery } from "../../core/dbc-gateway/generate
 export interface AutosuggestTextProps {
   responseData: SuggestionsFromQueryStringQuery["suggest"]["result"];
   currentQ: string;
+  // TODO: find out what type this can be from downshifts official types
+  highlightedIndex: any;
+  getItemProps: any;
 }
 
 export const AutosuggestText: React.FC<AutosuggestTextProps> = ({
-  responseData
+  responseData,
+  highlightedIndex,
+  getItemProps
 }) => {
   return (
     <>
-      {responseData.map((item) => {
+      {responseData.map((item, index) => {
+        /* eslint-disable react/no-array-index-key */
+        // TODO: find a way to index the <li> without using index
         return (
-          <li className="autosuggest-text-container__item text-body-medium-regular">
-            {item.__typename === "Creator" ? `${item.name} (forfatter)` : null}
-            {item.__typename === "Subject" ? `${item.value} (emne)` : null}
-            {item.__typename === "Work"
-              ? `${item.title} (manifestation)`
-              : null}
-          </li>
+          <>
+            {/* eslint-disable react/jsx-props-no-spreading */}
+            <li
+              className="autosuggest-text-container__item text-body-medium-regular"
+              key={index}
+              style={
+                highlightedIndex === index ? { backgroundColor: "#bde4ff" } : {}
+              }
+              {...getItemProps({ item, index })}
+            >
+              {/* eslint-enable react/jsx-props-no-spreading */}
+              {/* eslint-enable react/no-array-index-key */}
+              {item.__typename === "Creator"
+                ? `${item.name} (forfatter)`
+                : null}
+              {item.__typename === "Subject" ? `${item.value} (emne)` : null}
+              {item.__typename === "Work"
+                ? `${item.title} (manifestation)`
+                : null}
+            </li>
+          </>
         );
       })}
     </>
diff --git a/src/components/autosuggest/autosuggest.dev.tsx b/src/components/autosuggest/autosuggest.dev.tsx
index 045907bc5d..fd8adf30b2 100644
--- a/src/components/autosuggest/autosuggest.dev.tsx
+++ b/src/components/autosuggest/autosuggest.dev.tsx
@@ -10,6 +10,66 @@ export default {
       name: "Query",
       defaultValue: "Adam",
       control: { type: "text" }
+    },
+    data: {
+      name: "Data",
+      defaultValue: {
+        suggest: {
+          result: [
+            {
+              __typename: "Creator",
+              name: "Adam August"
+            },
+            {
+              __typename: "Creator",
+              name: "Douglas Adams"
+            },
+            {
+              __typename: "Creator",
+              name: "Adam Neutzsky-Wulff"
+            },
+            {
+              __typename: "Creator",
+              name: "Andrew Adamson"
+            },
+            {
+              __typename: "Creator",
+              name: "Adam Wallensten"
+            },
+            {
+              __typename: "Creator",
+              name: "Adam Cooper"
+            },
+            {
+              __typename: "Creator",
+              name: "Adam Sandler"
+            },
+            {
+              __typename: "Creator",
+              name: "Adam McKay"
+            },
+            {
+              __typename: "Creator",
+              name: "Richard Adams"
+            },
+            {
+              __typename: "Creator",
+              name: "Adam Shankman"
+            }
+          ]
+        }
+      },
+      control: { type: "object" }
+    },
+    isLoading: {
+      name: "Is Loading",
+      defaultValue: false,
+      control: { type: "boolean" }
+    },
+    status: {
+      name: "Status of the transaction",
+      defaultValue: "success",
+      control: { type: "text" }
     }
   }
 } as ComponentMeta<typeof Autosuggest>;
diff --git a/src/components/autosuggest/autosuggest.tsx b/src/components/autosuggest/autosuggest.tsx
index 1c3a50380d..155ca3a62f 100644
--- a/src/components/autosuggest/autosuggest.tsx
+++ b/src/components/autosuggest/autosuggest.tsx
@@ -1,41 +1,65 @@
 import React from "react";
-import {
-  SuggestionsFromQueryStringQuery,
-  useSuggestionsFromQueryStringQuery
-} from "../../core/dbc-gateway/generated/graphql";
+import { SuggestionsFromQueryStringQuery } from "../../core/dbc-gateway/generated/graphql";
 import { AutosuggestText } from "../autosuggest-text/autossugest-text";
 
 export interface AutosuggestProps {
   q: string;
+  data: SuggestionsFromQueryStringQuery | undefined;
+  isLoading: boolean;
+  status: string;
+  // TODO: find out what type this can be from downshifts official types
+  getMenuProps: any;
+  highlightedIndex: any;
+  getItemProps: any;
+  isOpen: boolean;
 }
 
 export const Autosuggest: React.FC<AutosuggestProps> = ({
-  q = "placeholder"
+  q = "query",
+  data,
+  isLoading,
+  status,
+  getMenuProps,
+  highlightedIndex,
+  getItemProps,
+  isOpen
 }) => {
-  const {
-    data,
-    isLoading,
-    status
-  }: {
-    data: SuggestionsFromQueryStringQuery | undefined;
-    isLoading: boolean;
-    status: string;
-  } = useSuggestionsFromQueryStringQuery({ q });
+  // if (q.length < 3) {
+  //   return (
+  //     <ul className="autosuggest-text-container" style={{ display: "none" }} />
+  //   );
+  // }
 
-  if (isLoading) {
-    return <ul className="autosuggest-text-container">Loading</ul>;
-  }
-
-  // if the service cannot find any suggestions
-  if (data && data.suggest.result.length < 1) {
-    return <ul className="autosuggest-text-container">Ingen suggestions</ul>;
-  }
+  // if (isLoading) {
+  //   return <ul className="autosuggest-text-container">Loading</ul>;
+  // }
 
+  // // if the service cannot find any suggestions
+  // if (data && data.suggest.result.length < 1) {
+  //   return <ul className="autosuggest-text-container">Ingen suggestions</ul>;
+  // }
+  console.log(data);
   if (data && status === "success") {
     return (
-      <ul className="autosuggest-text-container">
-        <AutosuggestText responseData={data.suggest.result} currentQ={q} />
-      </ul>
+      <>
+        {/* eslint-disable react/jsx-props-no-spreading */}
+        {/* The downshift combobox works this way by design */}
+        <ul className="autosuggest-text-container" {...getMenuProps()}>
+          {/* eslint-enable react/jsx-props-no-spreading */}
+          {isOpen && isLoading ? (
+            <li>...Loading</li>
+          ) : (
+            isOpen && (
+              <AutosuggestText
+                responseData={data.suggest.result}
+                currentQ={q}
+                highlightedIndex={highlightedIndex}
+                getItemProps={getItemProps}
+              />
+            )
+          )}
+        </ul>
+      </>
     );
   }
 
diff --git a/src/components/autosuggest/suggest.graphql b/src/components/autosuggest/suggest.graphql
index 174769a5c3..e4a828b635 100644
--- a/src/components/autosuggest/suggest.graphql
+++ b/src/components/autosuggest/suggest.graphql
@@ -10,7 +10,6 @@ query suggestionsFromQueryString($q: String!) {
         name
       }
       ... on Work {
-        id
         title
       }
     }
diff --git a/src/components/demo-suggest-dropdown/suggest.graphql b/src/components/demo-suggest-dropdown/suggest.graphql
deleted file mode 100644
index 174769a5c3..0000000000
--- a/src/components/demo-suggest-dropdown/suggest.graphql
+++ /dev/null
@@ -1,18 +0,0 @@
-
-query suggestionsFromQueryString($q: String!) {
-  suggest(q: $q) {
-    result {
-      __typename
-      ... on Subject {
-        value
-      }
-      ... on Creator {
-        name
-      }
-      ... on Work {
-        id
-        title
-      }
-    }
-  }
-}
diff --git a/src/components/search-bar/search-bar.dev.tsx b/src/components/search-bar/search-bar.dev.tsx
index be1da324e6..6374253960 100644
--- a/src/components/search-bar/search-bar.dev.tsx
+++ b/src/components/search-bar/search-bar.dev.tsx
@@ -8,11 +8,6 @@ export default {
   title: "Components / Search Bar",
   component: SearchBar,
   argTypes: {
-    searchHeaderUrl: {
-      name: "Search header base URL",
-      defaultValue: "https://bibliotek.dk/search",
-      control: { type: "text" }
-    },
     altText: {
       name: "Alt text for search button image",
       defaultValue: "søgeikon",
@@ -35,7 +30,14 @@ export const Default: ComponentStory<typeof SearchBar> = (
   const [q, setQ] = useState("");
   return (
     <StoryHeader>
-      <SearchBar {...args} q={q} setQuery={setQ} />
+      <div className="header__menu-second">
+        <form
+          action="https://bibliotek.dk/search"
+          className="header__menu-search"
+        >
+          <SearchBar {...args} q={q} setQuery={setQ} />
+        </form>
+      </div>
     </StoryHeader>
   );
 };
diff --git a/src/components/search-bar/search-bar.tsx b/src/components/search-bar/search-bar.tsx
index 2242eae805..c53d52ec5a 100644
--- a/src/components/search-bar/search-bar.tsx
+++ b/src/components/search-bar/search-bar.tsx
@@ -1,5 +1,6 @@
 import * as React from "react";
 import searchIcon from "@danskernesdigitalebibliotek/dpl-design-system/build/icons/basic/icon-search.svg";
+import { GetInputPropsOptions } from "downshift";
 
 export interface SearchBarProps {
   q: string;
@@ -7,34 +8,39 @@ export interface SearchBarProps {
   searchHeaderUrl?: string;
   altText?: string;
   inputPlaceholder?: string;
+  // TODO: find out what type this can be from downshifts official types
+  getInputProps?: any;
 }
 
 const SearchBar: React.FC<SearchBarProps> = ({
   q,
   setQuery,
-  searchHeaderUrl = "/search",
   altText = "search icon",
-  inputPlaceholder = "Search here"
+  inputPlaceholder = "Search here",
+  getInputProps
 }) => {
   return (
-    <div className="header__menu-second">
-      <form action={searchHeaderUrl} className="header__menu-search">
-        <input
-          name="q"
-          className="header__menu-search-input text-body-medium-regular"
-          type="text"
-          placeholder={inputPlaceholder}
-          value={q}
-          onChange={(e) => setQuery(e.target.value)}
-        />
-        <input
-          type="image"
-          src={searchIcon}
-          alt={altText}
-          className="header__menu-search-icon"
-        />
-      </form>
-    </div>
+    <>
+      {/* eslint-disable react/jsx-props-no-spreading */}
+      {/* The downshift combobox works this way by design */}
+      <input
+        name="q"
+        className="header__menu-search-input text-body-medium-regular"
+        type="text"
+        autoComplete="off"
+        placeholder={inputPlaceholder}
+        value={q}
+        onChange={(e) => setQuery(e.target.value)}
+        {...getInputProps()}
+      />
+      {/* eslint-enable react/jsx-props-no-spreading */}
+      <input
+        type="image"
+        src={searchIcon}
+        alt={altText}
+        className="header__menu-search-icon"
+      />
+    </>
   );
 };
 
diff --git a/src/core/dbc-gateway/generated/graphql.schema.json b/src/core/dbc-gateway/generated/graphql.schema.json
index 6b2f7ec9cc..d11840b99b 100644
--- a/src/core/dbc-gateway/generated/graphql.schema.json
+++ b/src/core/dbc-gateway/generated/graphql.schema.json
@@ -7606,7 +7606,7 @@
         "interfaces": null,
         "enumValues": [
           {
-            "name": "FYSISK",
+            "name": "NOT_SPECIFIED",
             "description": null,
             "isDeprecated": false,
             "deprecationReason": null
@@ -7618,7 +7618,7 @@
             "deprecationReason": null
           },
           {
-            "name": "UKENDT",
+            "name": "PHYSICAL",
             "description": null,
             "isDeprecated": false,
             "deprecationReason": null
@@ -8487,6 +8487,191 @@
         "enumValues": null,
         "possibleTypes": null
       },
+      {
+        "kind": "OBJECT",
+        "name": "Draft_Facet",
+        "description": null,
+        "fields": [
+          {
+            "name": "facetCategory",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "String",
+                "ofType": null
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "values",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "LIST",
+                "name": null,
+                "ofType": {
+                  "kind": "NON_NULL",
+                  "name": null,
+                  "ofType": {
+                    "kind": "OBJECT",
+                    "name": "Draft_FacetTerm",
+                    "ofType": null
+                  }
+                }
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          }
+        ],
+        "inputFields": null,
+        "interfaces": [],
+        "enumValues": null,
+        "possibleTypes": null
+      },
+      {
+        "kind": "OBJECT",
+        "name": "Draft_FacetResponse",
+        "description": null,
+        "fields": [
+          {
+            "name": "categories",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "LIST",
+                "name": null,
+                "ofType": {
+                  "kind": "NON_NULL",
+                  "name": null,
+                  "ofType": {
+                    "kind": "OBJECT",
+                    "name": "Draft_Facet",
+                    "ofType": null
+                  }
+                }
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "popular",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "LIST",
+                "name": null,
+                "ofType": {
+                  "kind": "NON_NULL",
+                  "name": null,
+                  "ofType": {
+                    "kind": "OBJECT",
+                    "name": "Draft_FacetTerm",
+                    "ofType": null
+                  }
+                }
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          }
+        ],
+        "inputFields": null,
+        "interfaces": [],
+        "enumValues": null,
+        "possibleTypes": null
+      },
+      {
+        "kind": "OBJECT",
+        "name": "Draft_FacetTerm",
+        "description": null,
+        "fields": [
+          {
+            "name": "count",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "Int",
+                "ofType": null
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "facetCategory",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "String",
+                "ofType": null
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "popular",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "Boolean",
+                "ofType": null
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
+          {
+            "name": "term",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "SCALAR",
+                "name": "String",
+                "ofType": null
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          }
+        ],
+        "inputFields": null,
+        "interfaces": [],
+        "enumValues": null,
+        "possibleTypes": null
+      },
       {
         "kind": "OBJECT",
         "name": "Draft_FictionNonfiction",
@@ -11291,6 +11476,39 @@
             "isDeprecated": false,
             "deprecationReason": null
           },
+          {
+            "name": "search",
+            "description": "Search",
+            "args": [
+              {
+                "name": "q",
+                "description": null,
+                "type": {
+                  "kind": "NON_NULL",
+                  "name": null,
+                  "ofType": {
+                    "kind": "INPUT_OBJECT",
+                    "name": "SearchQuery",
+                    "ofType": null
+                  }
+                },
+                "defaultValue": null,
+                "isDeprecated": false,
+                "deprecationReason": null
+              }
+            ],
+            "type": {
+              "kind": "NON_NULL",
+              "name": null,
+              "ofType": {
+                "kind": "OBJECT",
+                "name": "Draft_SearchResponse",
+                "ofType": null
+              }
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          },
           {
             "name": "suggest",
             "description": null,
@@ -11872,6 +12090,29 @@
         ],
         "possibleTypes": null
       },
+      {
+        "kind": "OBJECT",
+        "name": "Draft_SearchResponse",
+        "description": null,
+        "fields": [
+          {
+            "name": "facets",
+            "description": null,
+            "args": [],
+            "type": {
+              "kind": "OBJECT",
+              "name": "Draft_FacetResponse",
+              "ofType": null
+            },
+            "isDeprecated": false,
+            "deprecationReason": null
+          }
+        ],
+        "inputFields": null,
+        "interfaces": [],
+        "enumValues": null,
+        "possibleTypes": null
+      },
       {
         "kind": "OBJECT",
         "name": "Draft_SeriesContainer",
@@ -11937,8 +12178,8 @@
         "description": null,
         "fields": [
           {
-            "name": "prefix",
-            "description": "A prefix to the shelfmark",
+            "name": "postfix",
+            "description": "A postfix to the shelfmark, eg. 99.4 Christensen, Inger. f. 1935",
             "args": [],
             "type": {
               "kind": "NON_NULL",
@@ -11954,7 +12195,7 @@
           },
           {
             "name": "shelfmark",
-            "description": "The actual shelfmark - e.g. information about on which shelf in the library this manifestation can be found",
+            "description": "The actual shelfmark - e.g. information about on which shelf in the library this manifestation can be found, e.g. 99.4",
             "args": [],
             "type": {
               "kind": "NON_NULL",
diff --git a/src/core/dbc-gateway/generated/graphql.tsx b/src/core/dbc-gateway/generated/graphql.tsx
index bb753538f3..d792ce1488 100644
--- a/src/core/dbc-gateway/generated/graphql.tsx
+++ b/src/core/dbc-gateway/generated/graphql.tsx
@@ -5922,7 +5922,7 @@ export type SuggestionsFromQueryStringQuery = {
     result: Array<
       | { __typename: "Creator"; name: string }
       | { __typename: "Subject"; value: string }
-      | { __typename: "Work"; id: string; title?: string | null }
+      | { __typename: "Work"; title?: string | null }
     >;
   };
 };
@@ -5939,7 +5939,6 @@ export const SuggestionsFromQueryStringDocument = `
         name
       }
       ... on Work {
-        id
         title
       }
     }