From 0c40b9dbbc6746d5157b54bd5563be0eb5975f8c Mon Sep 17 00:00:00 2001
From: victor barbier <victor.barbier@recherche.gouv.fr>
Date: Mon, 9 Sep 2024 12:12:57 +0200
Subject: [PATCH] feat(client): rework

---
 .../src/components/results/debug/index.tsx    | 37 +++++++++
 .../components/results/highlights/index.tsx   | 81 +++++++------------
 .../client/src/components/results/index.tsx   | 21 +++--
 .../src/components/results/result/index.tsx   | 11 +--
 .../components/results/utils/highlights.tsx   | 38 +--------
 .../src/components/results/utils/url.tsx      |  2 +-
 project/client/src/styles/index.scss          |  9 +++
 project/client/src/types/data.ts              | 30 -------
 project/client/src/types/functions.ts         | 16 ----
 project/client/src/types/index.ts             | 43 ++++++++++
 10 files changed, 138 insertions(+), 150 deletions(-)
 create mode 100644 project/client/src/components/results/debug/index.tsx
 delete mode 100644 project/client/src/types/data.ts
 delete mode 100644 project/client/src/types/functions.ts
 create mode 100644 project/client/src/types/index.ts

diff --git a/project/client/src/components/results/debug/index.tsx b/project/client/src/components/results/debug/index.tsx
new file mode 100644
index 0000000..fd14de2
--- /dev/null
+++ b/project/client/src/components/results/debug/index.tsx
@@ -0,0 +1,37 @@
+import { Container, Badge, BadgeGroup, Accordion } from "@dataesr/dsfr-plus"
+import { MatchDebug } from "../../../types"
+
+type ResultsDebugArgs = {
+  resultsDebug: MatchDebug
+}
+export default function ResultsDebug({ resultsDebug }: ResultsDebugArgs) {
+  console.log("resultsDebug", resultsDebug)
+
+  if (!resultsDebug) return null
+
+  const criterionMatches = (criterion: string) => resultsDebug.criterion?.[criterion] ?? 0
+
+  return (
+    <Accordion className="fr-container fr-mt-3w" title="See more">
+      {resultsDebug.strategies.map((strategy, index) => (
+        <Container key={index} className="debug-item">
+          {strategy.equivalent_strategies.map((equivalent) => (
+            <BadgeGroup>
+              {equivalent.map((criterion) => {
+                const matches: number = criterionMatches(criterion)
+                return (
+                  <Badge color={matches ? "yellow-moutarde" : null}>{`${criterion}: ${matches} match${
+                    matches == 1 ? "" : "es"
+                  }`}</Badge>
+                )
+              })}
+            </BadgeGroup>
+          ))}
+          <Badge color={strategy.matches ? "success" : "error"}>{`${strategy.matches} ${
+            strategy.matches == 1 ? "possibility" : "possibilities"
+          }`}</Badge>
+        </Container>
+      ))}
+    </Accordion>
+  )
+}
diff --git a/project/client/src/components/results/highlights/index.tsx b/project/client/src/components/results/highlights/index.tsx
index 8a471f2..7b66133 100644
--- a/project/client/src/components/results/highlights/index.tsx
+++ b/project/client/src/components/results/highlights/index.tsx
@@ -1,65 +1,40 @@
 import { IntlMessageFormat } from "intl-messageformat"
-import { Container, Badge, Text, Row } from "@dataesr/dsfr-plus"
-import { CriterionHighlightsArgs, ResultHighlightsArgs, StrategyHighlightsArgs } from "../../../types/functions"
-import { getHighlightedText, getHighlightedQuery, strategyCriteria } from "../utils/highlights"
+import { Container, Badge, BadgeGroup } from "@dataesr/dsfr-plus"
+import { getHighlightedQuery } from "../utils/highlights"
 import useUrl from "../../../hooks/useUrl"
+import { MatchHighlight } from "../../../types"
 
-function CriterionHighlights({ criterion, criterionHighlights, setTitle }: CriterionHighlightsArgs) {
-  const { currentQuery } = useUrl()
+export type ResultHighlightsArgs = {
+  resultHighlights: MatchHighlight
+  setTitle: Function
+}
 
-  const highlightedData = criterionHighlights.map((criterionHighlight) => {
-    const highlightedText = getHighlightedText(criterionHighlight[0])
-    return {
-      highlightedCriterion: highlightedText.join(" "),
-      highlightedQuery: getHighlightedQuery(highlightedText, currentQuery),
-    }
-  })
+export default function ResultHighlights({ resultHighlights, setTitle }: ResultHighlightsArgs) {
+  const { currentQuery } = useUrl()
 
   const onEnter = (highlightedQuery: string) =>
-    setTitle(new IntlMessageFormat(highlightedQuery).format({ b: (chunks) => <strong>{chunks}</strong> }))
+    setTitle(
+      new IntlMessageFormat(highlightedQuery).format({
+        b: (chunks) => <strong key={JSON.stringify(chunks)}>{chunks}</strong>,
+      })
+    )
   const onLeave = () => setTitle(currentQuery)
 
   return (
-    <Row>
-      <Text>{`${criterion} (${highlightedData.length} match${highlightedData.length > 1 ? "es" : ""}):`}</Text>
-      {highlightedData.map((data, index) => (
-        <Text
-          key={index}
-          className="fr-ml-1w fr-mr-1w"
-          onMouseEnter={() => onEnter(data.highlightedQuery)}
-          onMouseLeave={() => onLeave()}
-        >
-          <strong>{data.highlightedCriterion}</strong>
-        </Text>
-      ))}
-    </Row>
-  )
-}
-
-function StrategyHighlights({ strategy, strategyHighlights, setTitle }: StrategyHighlightsArgs) {
-  const criteria = strategyCriteria(strategy)
-  const color = criteria.length === Object.keys(strategyHighlights).length ? "success" : "error"
-
-  return (
-    <Container>
-      <Badge color={color}>{`Strategy: ${criteria.join(", ")}`}</Badge>
-      {Object.entries(strategyHighlights).map(([criterion, criterionHighlights], index) => (
-        <CriterionHighlights
-          key={index}
-          criterion={criterion}
-          criterionHighlights={criterionHighlights}
-          setTitle={setTitle}
-        />
-      ))}
-    </Container>
-  )
-}
-
-export default function ResultHighlights({ resultHighlights, setTitle }: ResultHighlightsArgs) {
-  return (
-    <Container fluid className="fr-mt-4w">
-      {Object.entries(resultHighlights).map(([strategy, criteriaHighlights], index) => (
-        <StrategyHighlights key={index} strategy={strategy} strategyHighlights={criteriaHighlights} setTitle={setTitle} />
+    <Container fluid className="fr-mt-2w">
+      {Object.entries(resultHighlights.criterion).map(([criterion, highlights], groupIndex) => (
+        <BadgeGroup key={groupIndex}>
+          <Badge color="success">{criterion}</Badge>
+          {highlights.map((highlight, badgeIndex) => (
+            <Badge
+              key={badgeIndex}
+              onMouseEnter={() => onEnter(getHighlightedQuery(highlight, currentQuery))}
+              onMouseLeave={() => onLeave()}
+            >
+              {highlight?.join(" ")}
+            </Badge>
+          ))}
+        </BadgeGroup>
       ))}
     </Container>
   )
diff --git a/project/client/src/components/results/index.tsx b/project/client/src/components/results/index.tsx
index fdef0ba..3a8caa8 100644
--- a/project/client/src/components/results/index.tsx
+++ b/project/client/src/components/results/index.tsx
@@ -5,7 +5,8 @@ import useUrl from "../../hooks/useUrl"
 import Error from "../error"
 import Result from "./result"
 import Fetching from "../fetching"
-import { MatchIds } from "../../types/data"
+import { MatchIds } from "../../types"
+import ResultsDebug from "./debug"
 
 export default function Results() {
   const { currentQuery, currentMatcher, currentYear } = useUrl()
@@ -27,10 +28,14 @@ export default function Results() {
   const matchIds = data.results as MatchIds
   if (!matchIds.length)
     return (
-      <Container>
-        <Text size="lead">{currentTitle}</Text>
-        <Badge color="error">{`${currentMatcher} : no results`}</Badge>
-      </Container>
+      <>
+        <Container className="sticky card">
+          <Text size="lead">{currentTitle}</Text>
+        </Container>
+        <Container className="fr-mt-3w">
+          <Badge color="error">{`${currentMatcher} : 0 match`}</Badge>
+        </Container>
+      </>
     )
 
   return (
@@ -38,11 +43,15 @@ export default function Results() {
       <Container className="sticky card">
         <Text size="lead">{currentTitle}</Text>
       </Container>
-      <Container fluid className="fr-mt-5w">
+      <Container className="fr-mt-3w">
+        <Text size="md">{`${matchIds.length} match${matchIds.length > 1 ? "es" : ""}`}</Text>
+      </Container>
+      <Container fluid className="fr-mt-3w">
         {matchIds.map((id, index) => {
           return <Result key={index} resultData={data} resultId={id} setTitle={setTitle} />
         })}
       </Container>
+      <ResultsDebug resultsDebug={data?.debug} />
     </Container>
   )
 }
diff --git a/project/client/src/components/results/result/index.tsx b/project/client/src/components/results/result/index.tsx
index 94325f8..356f783 100644
--- a/project/client/src/components/results/result/index.tsx
+++ b/project/client/src/components/results/result/index.tsx
@@ -1,7 +1,6 @@
-import { Container, Badge, Row, BadgeGroup, Accordion } from "@dataesr/dsfr-plus"
-import { MatchId, MatchResults } from "../../../types/data"
+import { Container, Badge, Row, BadgeGroup } from "@dataesr/dsfr-plus"
+import { MatchId, MatchResults } from "../../../types"
 import useUrl from "../../../hooks/useUrl"
-import { getResultHighlights } from "../utils/highlights"
 import { getResultUrl } from "../utils/url"
 import ResultHighlights from "../highlights"
 
@@ -19,7 +18,7 @@ export default function Result({
   const { results: resultsIds, enriched_results: resultsEnriched, highlights: resultsHighlights } = resultData
   const resultIndex = resultsIds.findIndex((element) => element === resultId)
   const resultEnriched = resultsEnriched[resultIndex]
-  const resultHighlights = getResultHighlights(resultsHighlights, resultId)
+  const resultHighlights = resultsHighlights?.[resultId]
   const resultUrl = getResultUrl(resultId, currentMatcher)
 
   return (
@@ -42,9 +41,7 @@ export default function Result({
           {resultEnriched?.country?.length && <Badge color="pink-macaron">{resultEnriched.country[0]}</Badge>}
         </BadgeGroup>
       </Row>
-      <Accordion title="Highlights">
-        <ResultHighlights resultHighlights={resultHighlights} setTitle={setTitle} />
-      </Accordion>
+      <ResultHighlights resultHighlights={resultHighlights} setTitle={setTitle} />
     </Container>
   )
 }
diff --git a/project/client/src/components/results/utils/highlights.tsx b/project/client/src/components/results/utils/highlights.tsx
index 46c6358..8e61694 100644
--- a/project/client/src/components/results/utils/highlights.tsx
+++ b/project/client/src/components/results/utils/highlights.tsx
@@ -1,40 +1,4 @@
-import { MatchHighlights, MatchId, ResultHighlights, TextHighlight } from "../../../types/data"
-
-export const getResultHighlights = (resultsHighlights: MatchHighlights, id: MatchId) =>
-  Object.entries(resultsHighlights).reduce((acc: ResultHighlights, [strategy, strategyHighlights]) => {
-    Object.entries(strategyHighlights[id]).forEach(([criterion, criterionHiglights]) => {
-      if (strategy in acc) acc[strategy][criterion] = criterionHiglights
-      else acc[strategy] = { [criterion]: criterionHiglights }
-    })
-    return acc
-  }, {})
-
-export const strategyCriteria = (strategy: string) => strategy.split(";")
-
-const stringFindText = (str: string, text: string): Array<number> =>
-  [...str.matchAll(new RegExp(text, "gi"))].map((match) => match.index)
-
-export const getHighlightedText = (highlight: string): TextHighlight => {
-  const startTag = "<em>"
-  const endTag = "</em>"
-  const startTags = stringFindText(highlight, startTag)
-  const endTags = stringFindText(highlight, endTag)
-
-  let highlightedArray = []
-  let cursor = 0
-
-  for (let i = 0; i < startTags.length; i++) {
-    const startIndex = startTags[i]
-    const endIndex = endTags[i]
-
-    const highlighted = highlight.slice(startIndex + startTag.length, endIndex)
-    highlightedArray.push(highlighted)
-
-    cursor = endIndex + endTag.length
-  }
-
-  return highlightedArray
-}
+import { TextHighlight } from "../../../types"
 
 export function getHighlightedQuery(highlightedArray: TextHighlight, query: string) {
   let highlightedQuery = query
diff --git a/project/client/src/components/results/utils/url.tsx b/project/client/src/components/results/utils/url.tsx
index b73fcee..38f70fc 100644
--- a/project/client/src/components/results/utils/url.tsx
+++ b/project/client/src/components/results/utils/url.tsx
@@ -1,4 +1,4 @@
-import { MatchId } from "../../../types/data"
+import { MatchId } from "../../../types"
 
 export function getResultUrl(resultId: MatchId, currentMatcher: string) {
   if (currentMatcher === "ror") return `https://ror.org/${resultId}`
diff --git a/project/client/src/styles/index.scss b/project/client/src/styles/index.scss
index 3a18b74..280e747 100644
--- a/project/client/src/styles/index.scss
+++ b/project/client/src/styles/index.scss
@@ -14,3 +14,12 @@
   padding-top: 15px;
   padding-bottom: 1px;
 }
+
+.debug-item {
+  padding-bottom: 1rem !important
+}
+
+.debug-item:not(:first-child) {
+  border-top: 1px solid var(--border-default-grey);
+  padding-top: 1rem !important;
+}
\ No newline at end of file
diff --git a/project/client/src/types/data.ts b/project/client/src/types/data.ts
deleted file mode 100644
index 5ece45b..0000000
--- a/project/client/src/types/data.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-export type MatchId = string
-export type MatchIds = Array<MatchId>
-
-export type MatchEnrichedResult = {
-  id: MatchId
-  acronym: Array<string>
-  name: Array<string>
-  city: Array<string>
-  country: Array<string>
-}
-export type MatchEnrichedResults = Array<MatchEnrichedResult>
-
-export type CriterionHighlight = Array<string>
-export type CriterionHighlights = Array<CriterionHighlight>
-export type CriteriaHighlights = Record<string, CriterionHighlights>
-export type StrategyHighlights = Record<MatchId, CriteriaHighlights>
-
-export type ResultHighlights = Record<string, CriteriaHighlights>
-export type MatchHighlights = Record<string, StrategyHighlights>
-
-export type MatchResults = {
-  version: string
-  index_date: string
-  results: MatchIds
-  other_ids: MatchIds
-  enriched_results: MatchEnrichedResults
-  highlights: MatchHighlights
-}
-
-export type TextHighlight = Array<any>
diff --git a/project/client/src/types/functions.ts b/project/client/src/types/functions.ts
deleted file mode 100644
index e9cd79e..0000000
--- a/project/client/src/types/functions.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import { CriterionHighlights, CriteriaHighlights, ResultHighlights } from "./data"
-
-export type CriterionHighlightsArgs = {
-  criterion: string
-  criterionHighlights: CriterionHighlights
-  setTitle: Function
-}
-export type StrategyHighlightsArgs = {
-  strategy: string
-  strategyHighlights: CriteriaHighlights
-  setTitle: Function
-}
-export type ResultHighlightsArgs = {
-  resultHighlights: ResultHighlights
-  setTitle: Function
-}
diff --git a/project/client/src/types/index.ts b/project/client/src/types/index.ts
new file mode 100644
index 0000000..d101375
--- /dev/null
+++ b/project/client/src/types/index.ts
@@ -0,0 +1,43 @@
+export type MatchId = string
+export type MatchIds = Array<MatchId>
+
+export type MatchEnrichedResult = {
+  id: MatchId
+  name: Array<string>
+  acronym?: Array<string>
+  city?: Array<string>
+  country?: Array<string>
+}
+export type MatchEnrichedResults = Array<MatchEnrichedResult>
+
+export type CriteriaHighlight = Array<Array<string>>
+export type CriterionHighlight = Record<string, CriteriaHighlight>
+export type StrategyHighlight = Array<string>
+export type StrategiesHighlight = Array<StrategyHighlight>
+export type MatchHighlight = {
+  criterion: CriterionHighlight
+  strategies: StrategiesHighlight
+}
+export type MatchHighlights = Record<MatchId, MatchHighlight>
+
+export type CriterionDebug = Record<string, number>
+export type StrategiesDebug = {
+  equivalent_strategies: Array<Array<string>>
+  matches: number
+}
+export type MatchDebug = {
+  criterion: CriterionDebug
+  strategies: Array<StrategiesDebug>
+}
+
+export type MatchResults = {
+  version: string
+  index_date: string
+  results: MatchIds
+  other_ids: MatchIds
+  enriched_results: MatchEnrichedResults
+  highlights?: MatchHighlights
+  debug?: MatchDebug
+}
+
+export type TextHighlight = Array<any>