-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(frontend): handle unthemed documents (#287)
* wip * feat(frontend): handle unthemed documents * rename * rename * fix(frontend): update layout * fix(frontend): review * fix: review * fix: review * fix: review
- Loading branch information
Lionel
authored
Feb 4, 2021
1 parent
4fa383b
commit 9ba8502
Showing
7 changed files
with
467 additions
and
4 deletions.
There are no files selected for viewing
56 changes: 56 additions & 0 deletions
56
targets/frontend/src/components/forms/ContentPicker/ThemePicker.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import PropTypes from "prop-types"; | ||
import React from "react"; | ||
import { Controller } from "react-hook-form"; | ||
import { Alert, Close, Text } from "theme-ui"; | ||
|
||
import { ThemeSearch } from "./ThemeSearch"; | ||
|
||
function ThemePicker({ ...props }) { | ||
return ( | ||
<Controller | ||
{...props} | ||
// eslint-disable-next-line no-unused-vars | ||
render={({ ref, ...renderProps }) => { | ||
if (renderProps.value) { | ||
return ( | ||
<Alert | ||
variant="highlight" | ||
sx={{ | ||
minWidth: 0, | ||
p: "xxsmall", | ||
paddingRight: "medium", | ||
position: "relative", | ||
}} | ||
> | ||
<Text | ||
sx={{ | ||
display: "block", | ||
overflow: "hidden", | ||
textOverflow: "ellipsis", | ||
whiteSpace: "nowrap", | ||
}} | ||
> | ||
{renderProps.value.title} | ||
</Text> | ||
<Close | ||
sx={{ position: "absolute", right: 0 }} | ||
onClick={() => { | ||
renderProps.onChange(""); | ||
}} | ||
/> | ||
</Alert> | ||
); | ||
} | ||
return <ThemeSearch {...renderProps} />; | ||
}} | ||
/> | ||
); | ||
} | ||
|
||
ThemePicker.propTypes = { | ||
disabled: PropTypes.bool, | ||
}; | ||
|
||
const MemoThemePicker = React.memo(ThemePicker); | ||
|
||
export { MemoThemePicker as ThemePicker }; |
169 changes: 169 additions & 0 deletions
169
targets/frontend/src/components/forms/ContentPicker/ThemeSearch.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
/** @jsxImportSource theme-ui */ | ||
|
||
import { SOURCES } from "@socialgouv/cdtn-sources"; | ||
import PropTypes from "prop-types"; | ||
import { useEffect, useState } from "react"; | ||
import Autosuggest from "react-autosuggest"; | ||
import { useDebouncedState } from "src/hooks/index"; | ||
import { Box, Input, Text } from "theme-ui"; | ||
import { useQuery } from "urql"; | ||
|
||
const sources = [SOURCES.THEMES]; | ||
|
||
const AUTOSUGGEST_MAX_RESULTS = 15; | ||
|
||
const searchThemesQuery = ` | ||
query searchThemes($sources: [String!]! = "", $search: String = "") { | ||
documents(where: { | ||
title: {_ilike: $search}, | ||
source: {_in: $sources}, | ||
}, limit: ${AUTOSUGGEST_MAX_RESULTS}) { | ||
source | ||
title | ||
cdtnId: cdtn_id | ||
themeDocuments: relation_a_aggregate(where: {type: {_eq: "theme-content"}}) {aggregate{count}} | ||
parentRelation: relation_b(where: {type: {_eq: "theme"}}) { | ||
document: a { | ||
title | ||
} | ||
} | ||
} | ||
} | ||
`; | ||
|
||
export function ThemeSearch({ onChange }) { | ||
const [suggestions, setSuggestions] = useState([]); | ||
const [inputSearchValue, setInputSearchValue] = useState(""); | ||
const [searchValue, , setDebouncedSearchValue] = useDebouncedState("", 500); | ||
|
||
const [results] = useQuery({ | ||
pause: searchValue.length < 3, | ||
query: searchThemesQuery, | ||
variables: { | ||
search: `%${searchValue}%`, | ||
sources, | ||
}, | ||
}); | ||
|
||
useEffect(() => { | ||
setSuggestions(results.data?.documents || []); | ||
}, [results.data]); | ||
|
||
const onSearchValueChange = (event, { newValue }) => { | ||
setInputSearchValue(newValue); | ||
}; | ||
|
||
const onSuggestionSelected = ( | ||
event, | ||
{ suggestion: { cdtnId, source, title = null, themeDocuments } } | ||
) => { | ||
const position = themeDocuments.aggregate.count; | ||
onChange({ cdtnId, position, source, title }); | ||
}; | ||
|
||
const onSuggestionsFetchRequested = async ({ value }) => { | ||
setDebouncedSearchValue(value); | ||
setInputSearchValue(value); | ||
}; | ||
|
||
const onSuggestionsClearRequested = () => { | ||
setSuggestions([]); | ||
}; | ||
|
||
const inputProps = { | ||
onChange: onSearchValueChange, | ||
placeholder: "Entrer le nom d'un thème et sélectionner le (ex: travail)", | ||
value: inputSearchValue, | ||
}; | ||
return ( | ||
<Autosuggest | ||
suggestions={suggestions} | ||
onSuggestionsFetchRequested={onSuggestionsFetchRequested} | ||
onSuggestionsClearRequested={onSuggestionsClearRequested} | ||
onSuggestionSelected={onSuggestionSelected} | ||
getSuggestionValue={getSuggestionValue} | ||
shouldRenderSuggestions={shouldRenderSuggestions} | ||
renderInputComponent={renderInputComponent} | ||
renderSuggestion={renderSuggestion} | ||
renderSuggestionsContainer={renderSuggestionsContainer} | ||
inputProps={inputProps} | ||
alwaysRenderSuggestions | ||
/> | ||
); | ||
} | ||
|
||
ThemeSearch.propTypes = { | ||
onChange: PropTypes.func.isRequired, | ||
}; | ||
|
||
const renderInputComponent = (inputProps) => ( | ||
<Input {...inputProps} sx={{ fontSize: "small", padding: "xxsmall" }} /> | ||
); | ||
|
||
function shouldRenderSuggestions(value) { | ||
return value.trim().length >= 2; | ||
} | ||
|
||
const getSuggestionValue = (content) => content.title; | ||
|
||
function renderSuggestion(content) { | ||
const parent = content.parentRelation[0]?.document?.title; | ||
const parentTitle = parent; | ||
return ( | ||
<Box sx={{ lineHeight: 1.2 }}> | ||
<Text sx={{ color: "muted", fontSize: "small", fontWeight: "300" }}> | ||
{parentTitle} | ||
</Text> | ||
<Text sx={{ display: "block" }}>{content.title}</Text> | ||
</Box> | ||
); | ||
} | ||
|
||
function renderSuggestionsContainer({ containerProps, children }) { | ||
return ( | ||
<Box | ||
{...containerProps} | ||
sx={{ | ||
position: "relative", | ||
}} | ||
> | ||
<Box | ||
sx={{ | ||
".react-autosuggest__suggestion--highlighted": { | ||
bg: "info", | ||
}, | ||
'[class*="container--open"] &': { | ||
border: "1px solid", | ||
borderColor: "neutral", | ||
borderRadius: "4px", | ||
boxShadow: "medium", | ||
left: 0, | ||
maxHeight: "300px", | ||
overflow: "scroll", | ||
position: "absolute", | ||
right: 0, | ||
top: "4px", | ||
}, | ||
bg: "white", | ||
li: { | ||
":nth-of-type(2n + 1):not(.react-autosuggest__suggestion--highlighted)": { | ||
bg: "highlight", | ||
}, | ||
cursor: "pointer", | ||
m: "0", | ||
p: "xxsmall", | ||
}, | ||
|
||
ul: { | ||
listStyleType: "none", | ||
m: "0", | ||
p: "0", | ||
}, | ||
zIndex: 1, | ||
}} | ||
> | ||
{children} | ||
</Box> | ||
</Box> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
import { SOURCES } from "@socialgouv/cdtn-sources"; | ||
import Link from "next/link"; | ||
import { RELATIONS } from "src/lib/relations"; | ||
import { Box, Card, Flex, Message, NavLink, Text } from "theme-ui"; | ||
import { useQuery } from "urql"; | ||
|
||
export const getUnthemedContentQuery = ` | ||
query getUnthemed($themeSources: [String!]!) { | ||
documents (where: { | ||
is_available: {_eq: true} | ||
is_published: {_eq: true} | ||
source: { | ||
_in: $themeSources | ||
} | ||
_and: [ | ||
{_not: { | ||
relation_b: {type: {_eq: "${RELATIONS.THEME_CONTENT}"} a :{source: {_eq: "${SOURCES.THEMES}"}} } | ||
}} | ||
{_not: {document: {_has_key: "split"}}} | ||
] | ||
}) { | ||
source | ||
slug | ||
title | ||
cdtnId: cdtn_id | ||
} | ||
} | ||
`; | ||
|
||
export const THEMABLE_CONTENT = [ | ||
SOURCES.CONTRIBUTIONS, | ||
SOURCES.EDITORIAL_CONTENT, | ||
SOURCES.EXTERNALS, | ||
SOURCES.LETTERS, | ||
SOURCES.SHEET_MT_PAGE, | ||
SOURCES.SHEET_SP, | ||
SOURCES.THEMATIC_FILES, | ||
SOURCES.TOOLS, | ||
]; | ||
|
||
export function UnThemedContent() { | ||
const [result] = useQuery({ | ||
query: getUnthemedContentQuery, | ||
variables: { | ||
themeSources: THEMABLE_CONTENT, | ||
}, | ||
}); | ||
|
||
const { data, fetching, error } = result; | ||
|
||
if (fetching) { | ||
return null; | ||
} | ||
if (error) { | ||
return ( | ||
<Message> | ||
<pre>{JSON.stringify(error, 2)}</pre> | ||
</Message> | ||
); | ||
} | ||
return ( | ||
<Link href="/unthemed" passHref> | ||
<NavLink> | ||
<Card> | ||
<Flex sx={{ justifyContent: "flex-end" }}> | ||
<Text | ||
color="secondary" | ||
sx={{ | ||
fontSize: "xxlarge", | ||
fontWeight: "600", | ||
}} | ||
> | ||
{data.documents.length} | ||
</Text> | ||
</Flex> | ||
<Box> | ||
<Text> Contenus non thémés</Text> | ||
</Box> | ||
</Card> | ||
</NavLink> | ||
</Link> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.