From 1b57d94d9377637b9e302d89e7fad7f06af5d940 Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Wed, 7 Oct 2020 17:41:20 +0200 Subject: [PATCH 1/7] Use @reach/combobox instead of select2 --- app/assets/stylesheets/new_design/forms.scss | 23 ++ app/javascript/components/ComboSearch.js | 129 +++++++++++ .../components/shared/queryCache.js | 39 ++++ package.json | 3 + yarn.lock | 206 +++++++++++++++++- 5 files changed, 396 insertions(+), 4 deletions(-) create mode 100644 app/javascript/components/ComboSearch.js create mode 100644 app/javascript/components/shared/queryCache.js diff --git a/app/assets/stylesheets/new_design/forms.scss b/app/assets/stylesheets/new_design/forms.scss index 2caef5dcd..d01276865 100644 --- a/app/assets/stylesheets/new_design/forms.scss +++ b/app/assets/stylesheets/new_design/forms.scss @@ -290,6 +290,20 @@ } } + + [data-reach-combobox-input] { + padding: 16px; + width: 100%; + min-width: 50%; + max-width: 100%; + min-height: 62px; + margin-bottom: 40px; + } + + [data-reach-combobox-input]:focus { + border-color: $blue; + } + .select2 { min-width: 50%; } @@ -465,3 +479,12 @@ } } } + +[data-reach-combobox-option] { + font-size: 16px; +} + +[data-reach-combobox-option][aria-selected="true"] { + background: $light-blue !important; + color: $white; +} diff --git a/app/javascript/components/ComboSearch.js b/app/javascript/components/ComboSearch.js new file mode 100644 index 000000000..62a6aaa15 --- /dev/null +++ b/app/javascript/components/ComboSearch.js @@ -0,0 +1,129 @@ +import React, { useState, useMemo, useCallback, useRef } from 'react'; +import { useDebounce } from 'react-use'; +import { useQuery } from 'react-query'; +import PropTypes from 'prop-types'; +import { + Combobox, + ComboboxInput, + ComboboxPopover, + ComboboxList, + ComboboxOption +} from '@reach/combobox'; +import '@reach/combobox/styles.css'; + +function defaultTransformResults(_, results) { + return results; +} + +function ComboSearch({ + placeholder, + required, + hiddenFieldId, + onChange, + scope, + minimumInputLength, + transformResult, + allowInputValues = false, + transformResults = defaultTransformResults +}) { + const label = scope; + const hiddenField = useMemo( + () => document.querySelector(`input[data-uuid="${hiddenFieldId}"]`), + [hiddenFieldId] + ); + const initialValue = hiddenField && hiddenField.value; + const [searchTerm, setSearchTerm] = useState(''); + const [debouncedSearchTerm, setDebouncedSearchTerm] = useState(''); + const [value, setValue] = useState(initialValue); + const resultsMap = useRef({}); + const setExternalValue = useCallback((value) => { + if (hiddenField) { + hiddenField.setAttribute('value', value); + } + if (onChange) { + const result = resultsMap.current[value]; + onChange(value, result); + } + }); + + useDebounce( + () => { + setDebouncedSearchTerm(searchTerm); + }, + 300, + [searchTerm] + ); + + const handleOnChange = useCallback( + ({ target: { value } }) => { + setValue(value); + if (value.length >= minimumInputLength) { + setSearchTerm(value.trim()); + if (allowInputValues) { + setExternalValue(value); + } + } + }, + [minimumInputLength] + ); + + const handleOnSelect = useCallback((value) => { + setExternalValue(value); + setValue(value); + }); + + const { isSuccess, data } = useQuery([scope, debouncedSearchTerm], { + enabled: !!debouncedSearchTerm, + notifyOnStatusChange: false, + refetchOnMount: false + }); + const results = isSuccess ? transformResults(debouncedSearchTerm, data) : []; + + return ( + + + {isSuccess && ( + + {results.length > 0 ? ( + + {results.map((result) => { + const [key, str] = transformResult(result); + resultsMap.current[str] = result; + return ( + + ); + })} + + ) : ( + + Aucun résultat trouvé + + )} + + )} + + ); +} + +ComboSearch.propTypes = { + placeholder: PropTypes.string, + required: PropTypes.bool, + hiddenFieldId: PropTypes.string, + scope: PropTypes.string, + minimumInputLength: PropTypes.number, + transformResult: PropTypes.func, + transformResults: PropTypes.func, + allowInputValues: PropTypes.bool, + onChange: PropTypes.func +}; + +export default ComboSearch; diff --git a/app/javascript/components/shared/queryCache.js b/app/javascript/components/shared/queryCache.js new file mode 100644 index 000000000..501b6e45a --- /dev/null +++ b/app/javascript/components/shared/queryCache.js @@ -0,0 +1,39 @@ +import { QueryCache } from 'react-query'; +import { isNumeric } from '@utils'; + +const { api_geo_url, api_adresse_url } = gon.autocomplete || {}; + +export const queryCache = new QueryCache({ + defaultConfig: { + queries: { + queryFn: defaultQueryFn + } + } +}); + +function buildURL(scope, term) { + if (scope === 'adresse') { + return `${api_adresse_url}/search?q=${term}&limit=5`; + } else if (isNumeric(term)) { + const code = term.padStart(2, '0'); + return `${api_geo_url}/${scope}?code=${code}&limit=5`; + } + return `${api_geo_url}/${scope}?nom=${term}&limit=5`; +} + +function buildOptions() { + if (window.AbortController) { + const controller = new AbortController(); + const signal = controller.signal; + return [{ signal }, controller]; + } + return [{}, null]; +} + +async function defaultQueryFn(scope, term) { + const url = buildURL(scope, term); + const [options, controller] = buildOptions(); + const promise = fetch(url, options).then((response) => response.json()); + promise.cancel = () => controller && controller.abort(); + return promise; +} diff --git a/package.json b/package.json index 04e593dca..0d30aaa48 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "intersection-observer": "^0.10.0", "jquery": "^3.5.1", "mapbox-gl": "^1.11.1", + "match-sorter": "^4.2.1", "prop-types": "^15.7.2", "react": "^16.13.1", "react-dom": "^16.13.1", @@ -30,8 +31,10 @@ "react-loadable": "^5.5.0", "react-mapbox-gl": "^4.8.6", "react-mapbox-gl-draw": "^2.0.4", + "react-query": "^2.23.1", "react-scroll-to-component": "^1.0.2", "react-sortable-hoc": "^1.11.0", + "react-use": "^15.3.4", "react_ujs": "^2.6.1", "select2": "^4.0.13", "trix": "^1.2.3", diff --git a/yarn.lock b/yarn.lock index b7308502d..375deddcd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -898,6 +898,13 @@ core-js-pure "^3.0.0" regenerator-runtime "^0.13.4" +"@babel/runtime@^7.1.2", "@babel/runtime@^7.10.5", "@babel/runtime@^7.5.5": + version "7.11.2" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736" + integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/runtime@^7.2.0", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2": version "7.9.6" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.9.6.tgz#a9102eb5cadedf3f31d08a9ecf294af7827ea29f" @@ -1904,6 +1911,11 @@ "@types/istanbul-lib-coverage" "*" "@types/istanbul-lib-report" "*" +"@types/js-cookie@2.2.6": + version "2.2.6" + resolved "https://registry.yarnpkg.com/@types/js-cookie/-/js-cookie-2.2.6.tgz#f1a1cb35aff47bc5cfb05cb0c441ca91e914c26f" + integrity sha512-+oY0FDTO2GYKEV0YPvSshGq9t7YozVkgvXLty7zogQNuCxBhT9/3INX9Q7H1aRZ4SUDRXAKlJuA4EA5nTt7SNw== + "@types/json5@^0.0.29": version "0.0.29" resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" @@ -2146,6 +2158,11 @@ "@webassemblyjs/wast-parser" "1.9.0" "@xtuc/long" "4.2.2" +"@xobotyi/scrollbar-width@1.9.5": + version "1.9.5" + resolved "https://registry.yarnpkg.com/@xobotyi/scrollbar-width/-/scrollbar-width-1.9.5.tgz#80224a6919272f405b87913ca13b92929bdf3c4d" + integrity sha512-N8tkAACJx2ww8vFMneJmaAgmjAG1tnVBZJRLRcx061tmsLRZHSEZSLuGWnwPtunsSLvSqXQ2wfp7Mgqg1I+2dQ== + "@xtuc/ieee754@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" @@ -2913,6 +2930,11 @@ boolbase@^1.0.0, boolbase@~1.0.0: resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= +bowser@^1.7.3: + version "1.9.4" + resolved "https://registry.yarnpkg.com/bowser/-/bowser-1.9.4.tgz#890c58a2813a9d3243704334fa81b96a5c150c9a" + integrity sha512-9IdMmj2KjigRq6oWhmwv1W36pDuA4STQZ8q6YO9um+x07xgYNCD3Oou+WP/3L1HNz7iqythGet3/p4wvc8AAwQ== + boxen@^4.1.0, boxen@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/boxen/-/boxen-4.2.0.tgz#e411b62357d6d6d36587c8ac3d5d974daa070e64" @@ -4032,6 +4054,13 @@ copy-template-dir@^1.4.0: readdirp "^2.0.0" run-parallel "^1.1.4" +copy-to-clipboard@^3.2.0: + version "3.3.1" + resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.1.tgz#115aa1a9998ffab6196f93076ad6da3b913662ae" + integrity sha512-i13qo6kIHTTpCm8/Wup+0b1mVWETvu2kIMzKoK8FpkLkFxlt0znUAHcMzox+T8sPlqtZXq3CulEjQHsYiGFJUw== + dependencies: + toggle-selection "^1.0.6" + core-js-compat@^3.6.2: version "3.6.5" resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.6.5.tgz#2a51d9a4e25dfd6e690251aa81f99e3c05481f1c" @@ -4267,6 +4296,14 @@ css-has-pseudo@^0.10.0: postcss "^7.0.6" postcss-selector-parser "^5.0.0-rc.4" +css-in-js-utils@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/css-in-js-utils/-/css-in-js-utils-2.0.1.tgz#3b472b398787291b47cfe3e44fecfdd9e914ba99" + integrity sha512-PJF0SpJT+WdbVVt0AOYp9C8GnuruRlL/UFW7932nLWmFLQTaWEzTBQEx7/hn4BuV+WON75iAViSUJLiU3PKbpA== + dependencies: + hyphenate-style-name "^1.0.2" + isobject "^3.0.1" + css-loader@^3.4.2: version "3.5.3" resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-3.5.3.tgz#95ac16468e1adcd95c844729e0bb167639eb0bcf" @@ -4316,7 +4353,7 @@ css-tree@1.0.0-alpha.37: mdn-data "2.0.4" source-map "^0.6.1" -css-tree@1.0.0-alpha.39: +css-tree@1.0.0-alpha.39, css-tree@^1.0.0-alpha.28: version "1.0.0-alpha.39" resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.0.0-alpha.39.tgz#2bff3ffe1bb3f776cf7eefd91ee5cba77a149eeb" integrity sha512-7UvkEYgBAHRG9Nt980lYxjsTrCyHFN53ky3wVsDkiMdVqylqRt+Zc+jm5qw7/qyOvN2dHSYtX0e4MbCCExSvnA== @@ -4424,6 +4461,11 @@ csso@^4.0.2: dependencies: css-tree "1.0.0-alpha.39" +csstype@^2.5.5: + version "2.6.13" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.13.tgz#a6893015b90e84dd6e85d0e3b442a1e84f2dbe0f" + integrity sha512-ul26pfSQTZW8dcOnD2iiJssfXw0gdNVX9IJDH/X3K5DGPfj+fUYe3kB+swUY6BF3oZDxaID3AJt+9/ojSAE05A== + currently-unhandled@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" @@ -5124,7 +5166,7 @@ error-ex@^1.2.0, error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -error-stack-parser@^2.0.2, error-stack-parser@^2.0.3: +error-stack-parser@^2.0.2, error-stack-parser@^2.0.3, error-stack-parser@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-2.0.6.tgz#5a99a707bd7a4c58a797902d48d82803ede6aad8" integrity sha512-d51brTeqC+BHlwF0BhPtcYgF5nlzf9ZZ0ZIUQNZpc9ZB9qw5IJ2diTrBY9jlCJkTLITYPjmiX6OWCwH+fuyNgQ== @@ -5648,7 +5690,7 @@ fancy-log@^1.3.3: parse-node-version "^1.0.0" time-stamp "^1.0.0" -fast-deep-equal@^3.1.1: +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== @@ -5702,11 +5744,21 @@ fast-safe-stringify@^2.0.4, fast-safe-stringify@^2.0.7: resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz#124aa885899261f68aedb42a7c080de9da608743" integrity sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA== +fast-shallow-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fast-shallow-equal/-/fast-shallow-equal-1.0.0.tgz#d4dcaf6472440dcefa6f88b98e3251e27f25628b" + integrity sha512-HPtaa38cPgWvaCFmRNhlc6NG7pv6NUHqjPgVAkWGoB9mQMwYB27/K0CvOM5Czy+qpT3e8XJ6Q4aPAnzpNpzNaw== + fast-stringify@^1.1.0: version "1.1.2" resolved "https://registry.yarnpkg.com/fast-stringify/-/fast-stringify-1.1.2.tgz#f109b792d54343aec271b47882598d279402401d" integrity sha512-SfslXjiH8km0WnRiuPfpUKwlZjW5I878qsOm+2x8x3TgqmElOOLh1rgJFb+PolNdNRK3r8urEefqx0wt7vx1dA== +fastest-stable-stringify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/fastest-stable-stringify/-/fastest-stable-stringify-1.0.1.tgz#9122d406d4c9d98bea644a6b6853d5874b87b028" + integrity sha1-kSLUBtTJ2YvqZEpraFPVh0uHsCg= + fastq@^1.6.0: version "1.8.0" resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.8.0.tgz#550e1f9f59bbc65fe185cb6a9b4d95357107f481" @@ -6987,6 +7039,11 @@ hyperlinker@^1.0.0: resolved "https://registry.yarnpkg.com/hyperlinker/-/hyperlinker-1.0.0.tgz#23dc9e38a206b208ee49bc2d6c8ef47027df0c0e" integrity sha512-Ty8UblRWFEcfSuIaajM34LdPXIhbs1ajEX/BBPv24J+enSVaEVY63xQ6lTO9VRYS5LAoghIG0IDJ+p+IPzKUQQ== +hyphenate-style-name@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz#691879af8e220aea5750e8827db4ef62a54e361d" + integrity sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ== + iconv-lite@0.4.24, iconv-lite@^0.4.15, iconv-lite@^0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -7138,6 +7195,14 @@ ini@^1.3.2, ini@^1.3.4, ini@^1.3.5, ini@~1.3.0: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== +inline-style-prefixer@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/inline-style-prefixer/-/inline-style-prefixer-4.0.2.tgz#d390957d26f281255fe101da863158ac6eb60911" + integrity sha512-N8nVhwfYga9MiV9jWlwfdj1UDIaZlBFu4cJSJkIr7tZX7sHpHhGR5su1qdpW+7KPL8ISTvCIkcaFi/JdBknvPg== + dependencies: + bowser "^1.7.3" + css-in-js-utils "^2.0.0" + inquirer-autocomplete-prompt@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/inquirer-autocomplete-prompt/-/inquirer-autocomplete-prompt-1.1.0.tgz#e7745b49122e56b483659c91328a2c3fca33ffd6" @@ -7732,6 +7797,11 @@ js-base64@^2.1.8: resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.5.2.tgz#313b6274dda718f714d00b3330bbae6e38e90209" integrity sha512-Vg8czh0Q7sFBSUMWWArX/miJeBWYBPpdU/3M/DKSaekLMqrqVPaedp+5mZhie/r0lgrcaYBfwXatEew6gwgiQQ== +js-cookie@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8" + integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ== + js-string-escape@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef" @@ -8466,6 +8536,14 @@ marked@^0.3.6: resolved "https://registry.yarnpkg.com/marked/-/marked-0.3.19.tgz#5d47f709c4c9fc3c216b6d46127280f40b39d790" integrity sha512-ea2eGWOqNxPcXv8dyERdSr/6FmzvWwzjMxpfGB/sbMccXoct+xY+YukPD+QTUZwyvK7BZwcr4m21WBOW41pAkg== +match-sorter@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/match-sorter/-/match-sorter-4.2.1.tgz#575b4b3737185ba9518b67612b66877ea0b37358" + integrity sha512-s+3h9TiZU9U1pWhIERHf8/f4LmBN6IXaRgo2CI17+XGByGS1GvG5VvXK9pcGyCjGe3WM3mSYRC3ipGrd5UEVgw== + dependencies: + "@babel/runtime" "^7.10.5" + remove-accents "0.4.2" + maxstache-stream@^1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/maxstache-stream/-/maxstache-stream-1.0.4.tgz#9c7f5cab7e5fdd2d90da86143b4e9631ea328040" @@ -8884,6 +8962,20 @@ nan@^2.12.1, nan@^2.13.2: resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.1.tgz#d7be34dfa3105b91494c3147089315eff8874b01" integrity sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw== +nano-css@^5.2.1: + version "5.3.0" + resolved "https://registry.yarnpkg.com/nano-css/-/nano-css-5.3.0.tgz#9d3cd29788d48b6a07f52aa4aec7cf4da427b6b5" + integrity sha512-uM/9NGK9/E9/sTpbIZ/bQ9xOLOIHZwrrb/CRlbDHBU/GFS7Gshl24v/WJhwsVViWkpOXUmiZ66XO7fSB4Wd92Q== + dependencies: + css-tree "^1.0.0-alpha.28" + csstype "^2.5.5" + fastest-stable-stringify "^1.0.1" + inline-style-prefixer "^4.0.0" + rtl-css-js "^1.9.0" + sourcemap-codec "^1.4.1" + stacktrace-js "^2.0.0" + stylis "3.5.0" + nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" @@ -11103,6 +11195,13 @@ react-mapbox-gl@^4.8.6: deep-equal "1.0.1" supercluster "^7.0.0" +react-query@^2.23.1: + version "2.23.1" + resolved "https://registry.yarnpkg.com/react-query/-/react-query-2.23.1.tgz#7d676f56d3c6e96b4de4d0b178baf6bb6a0ec272" + integrity sha512-qIma0Kvr//LWgWFah7RcntvD4FurXXdQaQeIfqhCWKdhihhe3Xs5BHsljAP68jo719/+xhWxL3I96SvrU4gGHA== + dependencies: + "@babel/runtime" "^7.5.5" + react-scroll-to-component@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/react-scroll-to-component/-/react-scroll-to-component-1.0.2.tgz#f260dc936c62a53e772786d7832fe0884e195354" @@ -11119,6 +11218,31 @@ react-sortable-hoc@^1.11.0: invariant "^2.2.4" prop-types "^15.5.7" +react-universal-interface@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/react-universal-interface/-/react-universal-interface-0.6.2.tgz#5e8d438a01729a4dbbcbeeceb0b86be146fe2b3b" + integrity sha512-dg8yXdcQmvgR13RIlZbTRQOoUrDciFVoSBZILwjE2LFISxZZ8loVJKAkuzswl5js8BHda79bIb2b84ehU8IjXw== + +react-use@^15.3.4: + version "15.3.4" + resolved "https://registry.yarnpkg.com/react-use/-/react-use-15.3.4.tgz#f853d310bd71f75b38900a8caa3db93f6dc6e872" + integrity sha512-cHq1dELW6122oi1+xX7lwNyE/ugZs5L902BuO8eFJCfn2api1KeuPVG1M/GJouVARoUf54S2dYFMKo5nQXdTag== + dependencies: + "@types/js-cookie" "2.2.6" + "@xobotyi/scrollbar-width" "1.9.5" + copy-to-clipboard "^3.2.0" + fast-deep-equal "^3.1.3" + fast-shallow-equal "^1.0.0" + js-cookie "^2.2.1" + nano-css "^5.2.1" + react-universal-interface "^0.6.2" + resize-observer-polyfill "^1.5.1" + screenfull "^5.0.0" + set-harmonic-interval "^1.0.1" + throttle-debounce "^2.1.0" + ts-easing "^0.2.0" + tslib "^2.0.0" + react@^16.13.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react/-/react-16.13.1.tgz#2e818822f1a9743122c063d6410d85c1e3afe48e" @@ -11332,6 +11456,11 @@ regjsparser@^0.6.4: dependencies: jsesc "~0.5.0" +remove-accents@0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/remove-accents/-/remove-accents-0.4.2.tgz#0a43d3aaae1e80db919e07ae254b285d9e1c7bb5" + integrity sha1-CkPTqq4egNuRngeuJUsoXZ4ce7U= + remove-bom-buffer@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz#c2bf1e377520d324f623892e33c10cac2c252b53" @@ -11432,6 +11561,11 @@ requires-port@^1.0.0: resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= +resize-observer-polyfill@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464" + integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg== + resolve-cwd@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" @@ -11567,6 +11701,13 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^3.0.0" inherits "^2.0.1" +rtl-css-js@^1.9.0: + version "1.14.0" + resolved "https://registry.yarnpkg.com/rtl-css-js/-/rtl-css-js-1.14.0.tgz#daa4f192a92509e292a0519f4b255e6e3c076b7d" + integrity sha512-Dl5xDTeN3e7scU1cWX8c9b6/Nqz3u/HgR4gePc1kWXYiQWVQbKCEyK6+Hxve9LbcJ5EieHy1J9nJCN3grTtGwg== + dependencies: + "@babel/runtime" "^7.1.2" + run-async@^2.2.0, run-async@^2.4.0: version "2.4.1" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" @@ -11696,6 +11837,11 @@ schema-utils@^2.6.1, schema-utils@^2.6.5, schema-utils@^2.6.6: ajv "^6.12.0" ajv-keywords "^3.4.1" +screenfull@^5.0.0: + version "5.0.2" + resolved "https://registry.yarnpkg.com/screenfull/-/screenfull-5.0.2.tgz#b9acdcf1ec676a948674df5cd0ff66b902b0bed7" + integrity sha512-cCF2b+L/mnEiORLN5xSAz6H3t18i2oHh9BA8+CQlAh5DRw2+NFAGQJOSYbcGw8B2k04g/lVvFcfZ83b3ysH5UQ== + scroll-to@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/scroll-to/-/scroll-to-0.0.2.tgz#936d398a9133660a2492145c2c0081dfcb0728f3" @@ -11825,6 +11971,11 @@ set-blocking@^2.0.0, set-blocking@~2.0.0: resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= +set-harmonic-interval@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/set-harmonic-interval/-/set-harmonic-interval-1.0.1.tgz#e1773705539cdfb80ce1c3d99e7f298bb3995249" + integrity sha512-AhICkFV84tBP1aWqPwLZqFvAwqEoVA9kxNMniGEUvzOlm4vLmOFLiTT3UZ6bziJTy4bOVpzWGTfSCbmaayGx8g== + set-value@^2.0.0, set-value@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" @@ -12053,6 +12204,11 @@ source-map-url@^0.4.0: resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= +source-map@0.5.6: + version "0.5.6" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" + integrity sha1-dc449SvwczxafwwRjYEzSiu19BI= + source-map@^0.4.2: version "0.4.4" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" @@ -12070,6 +12226,11 @@ source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +sourcemap-codec@^1.4.1: + version "1.4.8" + resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" + integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== + spark-md5@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/spark-md5/-/spark-md5-3.0.1.tgz#83a0e255734f2ab4e5c466e5a2cfc9ba2aa2124d" @@ -12178,7 +12339,7 @@ stable@^0.1.8: resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== -stack-generator@^2.0.3: +stack-generator@^2.0.3, stack-generator@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/stack-generator/-/stack-generator-2.0.5.tgz#fb00e5b4ee97de603e0773ea78ce944d81596c36" integrity sha512-/t1ebrbHkrLrDuNMdeAcsvynWgoH/i4o8EGGfX7dEYDoTXOYVAkEpFdtshlvabzc6JlJ8Kf9YdFEoz7JkzGN9Q== @@ -12195,6 +12356,23 @@ stackframe@^1.1.1: resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.2.0.tgz#52429492d63c62eb989804c11552e3d22e779303" integrity sha512-GrdeshiRmS1YLMYgzF16olf2jJ/IzxXY9lhKOskuVziubpTYcYqyOwYeJKzQkwy7uN0fYSsbsC4RQaXf9LCrYA== +stacktrace-gps@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/stacktrace-gps/-/stacktrace-gps-3.0.4.tgz#7688dc2fc09ffb3a13165ebe0dbcaf41bcf0c69a" + integrity sha512-qIr8x41yZVSldqdqe6jciXEaSCKw1U8XTXpjDuy0ki/apyTn/r3w9hDAAQOhZdxvsC93H+WwwEu5cq5VemzYeg== + dependencies: + source-map "0.5.6" + stackframe "^1.1.1" + +stacktrace-js@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/stacktrace-js/-/stacktrace-js-2.0.2.tgz#4ca93ea9f494752d55709a081d400fdaebee897b" + integrity sha512-Je5vBeY4S1r/RnLydLl0TBTi3F2qdfWmYsGvtfZgEI+SCprPppaIhQf5nGcal4gI4cGpCV/duLcAzT1np6sQqg== + dependencies: + error-stack-parser "^2.0.6" + stack-generator "^2.0.5" + stacktrace-gps "^3.0.4" + static-extend@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" @@ -12490,6 +12668,11 @@ stylehacks@^4.0.0: postcss "^7.0.0" postcss-selector-parser "^3.0.0" +stylis@3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/stylis/-/stylis-3.5.0.tgz#016fa239663d77f868fef5b67cf201c4b7c701e1" + integrity sha512-pP7yXN6dwMzAR29Q0mBrabPCe0/mNO1MSr93bhay+hcZondvMMTpeGyd8nbhYJdyperNT2DRxONQuUGcJr5iPw== + supercluster@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/supercluster/-/supercluster-7.0.0.tgz#75d474fafb0a055db552ed7bd7bbda583f6ab321" @@ -12698,6 +12881,11 @@ text-table@^0.2.0: resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= +throttle-debounce@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/throttle-debounce/-/throttle-debounce-2.3.0.tgz#fd31865e66502071e411817e241465b3e9c372e2" + integrity sha512-H7oLPV0P7+jgvrk+6mwwwBDmxTaxnu9HMXmloNLXwnNO0ZxZ31Orah2n8lU1eMPvsaowP2CX+USCgyovXfdOFQ== + through2-filter@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/through2-filter/-/through2-filter-3.0.0.tgz#700e786df2367c2c88cd8aa5be4cf9c1e7831254" @@ -12862,6 +13050,11 @@ to-time@^1.0.2: dependencies: bignumber.js "^2.4.0" +toggle-selection@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/toggle-selection/-/toggle-selection-1.0.6.tgz#6e45b1263f2017fa0acc7d89d78b15b8bf77da32" + integrity sha1-bkWxJj8gF/oKzH2J14sVuL932jI= + toidentifier@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" @@ -12929,6 +13122,11 @@ tryer@^1.0.1: resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8" integrity sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA== +ts-easing@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/ts-easing/-/ts-easing-0.2.0.tgz#c8a8a35025105566588d87dbda05dd7fbfa5a4ec" + integrity sha512-Z86EW+fFFh/IFB1fqQ3/+7Zpf9t2ebOAxNI/V6Wo7r5gqiqtxmgTlQ1qbqQcjLKYeSHPTsEmvlJUDg/EuL0uHQ== + ts-pnp@^1.1.6: version "1.2.0" resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.2.0.tgz#a500ad084b0798f1c3071af391e65912c86bca92" From 2c7ee82d316be80f0c9bfacaeed59d6f317345fe Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Wed, 7 Oct 2020 17:41:51 +0200 Subject: [PATCH 2/7] Implement ComboRegionsSearch --- .../components/ComboRegionsSearch.js | 21 +++++++++++++++++++ app/javascript/loaders/ComboRegionsSearch.js | 3 +++ .../editable_champs/_regions.html.haml | 7 +++---- 3 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 app/javascript/components/ComboRegionsSearch.js create mode 100644 app/javascript/loaders/ComboRegionsSearch.js diff --git a/app/javascript/components/ComboRegionsSearch.js b/app/javascript/components/ComboRegionsSearch.js new file mode 100644 index 000000000..630ed5742 --- /dev/null +++ b/app/javascript/components/ComboRegionsSearch.js @@ -0,0 +1,21 @@ +import React from 'react'; +import { ReactQueryCacheProvider } from 'react-query'; + +import ComboSearch from './ComboSearch'; +import { queryCache } from './shared/queryCache'; + +function ComboRegionsSearch(params) { + return ( + + [code, nom]} + /> + + ); +} + +export default ComboRegionsSearch; diff --git a/app/javascript/loaders/ComboRegionsSearch.js b/app/javascript/loaders/ComboRegionsSearch.js new file mode 100644 index 000000000..4b281012d --- /dev/null +++ b/app/javascript/loaders/ComboRegionsSearch.js @@ -0,0 +1,3 @@ +import Loadable from '../components/Loadable'; + +export default Loadable(() => import('../components/ComboRegionsSearch')); diff --git a/app/views/shared/dossiers/editable_champs/_regions.html.haml b/app/views/shared/dossiers/editable_champs/_regions.html.haml index 4b16bea2d..6119f7a4e 100644 --- a/app/views/shared/dossiers/editable_champs/_regions.html.haml +++ b/app/views/shared/dossiers/editable_champs/_regions.html.haml @@ -1,4 +1,3 @@ -= form.select :value, [champ.value].compact, - { include_blank: true }, - required: champ.mandatory?, - class: 'select2 regions' +- hidden_field_id = SecureRandom.uuid += form.hidden_field :value, { data: { uuid: hidden_field_id } } += react_component("ComboRegionsSearch", mandatory: champ.mandatory?, hiddenFieldId: hidden_field_id) From 4217dcd94b38a8c177ea3495d1ed0fdbdba16b96 Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Wed, 7 Oct 2020 17:42:21 +0200 Subject: [PATCH 3/7] Implement ComboDepartementsSearch --- .../components/ComboDepartementsSearch.js | 32 +++++++++++++++++++ .../loaders/ComboDepartementsSearch.js | 3 ++ .../editable_champs/_departements.html.haml | 7 ++-- 3 files changed, 38 insertions(+), 4 deletions(-) create mode 100644 app/javascript/components/ComboDepartementsSearch.js create mode 100644 app/javascript/loaders/ComboDepartementsSearch.js diff --git a/app/javascript/components/ComboDepartementsSearch.js b/app/javascript/components/ComboDepartementsSearch.js new file mode 100644 index 000000000..5189dabbb --- /dev/null +++ b/app/javascript/components/ComboDepartementsSearch.js @@ -0,0 +1,32 @@ +import React, { useCallback } from 'react'; +import { ReactQueryCacheProvider } from 'react-query'; +import matchSorter from 'match-sorter'; + +import ComboSearch from './ComboSearch'; +import { queryCache } from './shared/queryCache'; + +const extraTerms = [{ code: '99', nom: 'Etranger' }]; + +function ComboDepartementsSearch(params) { + const transformResults = useCallback((term, results) => [ + ...results, + ...matchSorter(extraTerms, term, { + keys: ['nom', 'code'] + }) + ]); + + return ( + + [code, `${code} - ${nom}`]} + transformResults={transformResults} + /> + + ); +} + +export default ComboDepartementsSearch; diff --git a/app/javascript/loaders/ComboDepartementsSearch.js b/app/javascript/loaders/ComboDepartementsSearch.js new file mode 100644 index 000000000..d19d5570a --- /dev/null +++ b/app/javascript/loaders/ComboDepartementsSearch.js @@ -0,0 +1,3 @@ +import Loadable from '../components/Loadable'; + +export default Loadable(() => import('../components/ComboDepartementsSearch')); diff --git a/app/views/shared/dossiers/editable_champs/_departements.html.haml b/app/views/shared/dossiers/editable_champs/_departements.html.haml index 9d0171092..e7999af73 100644 --- a/app/views/shared/dossiers/editable_champs/_departements.html.haml +++ b/app/views/shared/dossiers/editable_champs/_departements.html.haml @@ -1,4 +1,3 @@ -= form.select :value, [champ.value].compact, - { include_blank: true }, - required: champ.mandatory?, - class: 'select2 departements' +- hidden_field_id = SecureRandom.uuid += form.hidden_field :value, { data: { uuid: hidden_field_id } } += react_component("ComboDepartementsSearch", mandatory: champ.mandatory?, hiddenFieldId: hidden_field_id) From b6c94a37587c3276d1264a1b45ade35e0271ed80 Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Wed, 7 Oct 2020 17:42:41 +0200 Subject: [PATCH 4/7] Implement ComboCommunesSearch --- .../components/ComboCommunesSearch.js | 24 +++++++++++++++++++ app/javascript/loaders/ComboCommunesSearch.js | 3 +++ .../editable_champs/_communes.html.haml | 7 +++--- 3 files changed, 30 insertions(+), 4 deletions(-) create mode 100644 app/javascript/components/ComboCommunesSearch.js create mode 100644 app/javascript/loaders/ComboCommunesSearch.js diff --git a/app/javascript/components/ComboCommunesSearch.js b/app/javascript/components/ComboCommunesSearch.js new file mode 100644 index 000000000..56d43ffee --- /dev/null +++ b/app/javascript/components/ComboCommunesSearch.js @@ -0,0 +1,24 @@ +import React from 'react'; +import { ReactQueryCacheProvider } from 'react-query'; + +import ComboSearch from './ComboSearch'; +import { queryCache } from './shared/queryCache'; + +function ComboCommunesSearch(params) { + return ( + + [ + code, + `${nom} (${codesPostaux[0]})` + ]} + /> + + ); +} + +export default ComboCommunesSearch; diff --git a/app/javascript/loaders/ComboCommunesSearch.js b/app/javascript/loaders/ComboCommunesSearch.js new file mode 100644 index 000000000..7689f27f7 --- /dev/null +++ b/app/javascript/loaders/ComboCommunesSearch.js @@ -0,0 +1,3 @@ +import Loadable from '../components/Loadable'; + +export default Loadable(() => import('../components/ComboCommunesSearch')); diff --git a/app/views/shared/dossiers/editable_champs/_communes.html.haml b/app/views/shared/dossiers/editable_champs/_communes.html.haml index 0087a725e..394aeb460 100644 --- a/app/views/shared/dossiers/editable_champs/_communes.html.haml +++ b/app/views/shared/dossiers/editable_champs/_communes.html.haml @@ -1,4 +1,3 @@ -= form.select :value, [champ.value].compact, - { include_blank: true }, - required: champ.mandatory?, - class: 'select2 communes' +- hidden_field_id = SecureRandom.uuid += form.hidden_field :value, { data: { uuid: hidden_field_id } } += react_component("ComboCommunesSearch", mandatory: champ.mandatory?, hiddenFieldId: hidden_field_id) From 8a2f079acb0dc920f408f9b2efef154649ded911 Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Wed, 7 Oct 2020 17:44:04 +0200 Subject: [PATCH 5/7] Implement ComboAdresseSearch --- app/assets/stylesheets/new_design/carte.scss | 4 + .../components/ComboAdresseSearch.js | 44 ++++++++++ .../components/MapEditor/SearchInput.js | 88 ------------------- app/javascript/components/MapEditor/index.js | 10 ++- app/javascript/loaders/ComboAdresseSearch.js | 3 + .../editable_champs/_address.html.haml | 7 +- 6 files changed, 60 insertions(+), 96 deletions(-) create mode 100644 app/javascript/components/ComboAdresseSearch.js delete mode 100644 app/javascript/components/MapEditor/SearchInput.js create mode 100644 app/javascript/loaders/ComboAdresseSearch.js diff --git a/app/assets/stylesheets/new_design/carte.scss b/app/assets/stylesheets/new_design/carte.scss index b23ec84e6..8728a4915 100644 --- a/app/assets/stylesheets/new_design/carte.scss +++ b/app/assets/stylesheets/new_design/carte.scss @@ -11,3 +11,7 @@ margin-top: 5px; } } + +.form [data-react-class='MapEditor'] [data-reach-combobox-input] { + margin-bottom: 0; +} diff --git a/app/javascript/components/ComboAdresseSearch.js b/app/javascript/components/ComboAdresseSearch.js new file mode 100644 index 000000000..a73ba8bf0 --- /dev/null +++ b/app/javascript/components/ComboAdresseSearch.js @@ -0,0 +1,44 @@ +import React, { useCallback } from 'react'; +import { ReactQueryCacheProvider } from 'react-query'; +import PropTypes from 'prop-types'; + +import ComboSearch from './ComboSearch'; +import { queryCache } from './shared/queryCache'; + +function ComboAdresseSearch({ + mandatory, + placeholder, + hiddenFieldId, + onChange, + transformResult = ({ properties: { label } }) => [label, label], + allowInputValues = true +}) { + const transformResults = useCallback((_, { features }) => features); + + return ( + + + + ); +} + +ComboAdresseSearch.propTypes = { + placeholder: PropTypes.string, + mandatory: PropTypes.bool, + hiddenFieldId: PropTypes.string, + transformResult: PropTypes.func, + allowInputValues: PropTypes.bool, + onChange: PropTypes.func +}; + +export default ComboAdresseSearch; diff --git a/app/javascript/components/MapEditor/SearchInput.js b/app/javascript/components/MapEditor/SearchInput.js deleted file mode 100644 index ae82126af..000000000 --- a/app/javascript/components/MapEditor/SearchInput.js +++ /dev/null @@ -1,88 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import { getJSON } from '@utils'; -import { - Combobox, - ComboboxInput, - ComboboxPopover, - ComboboxList, - ComboboxOption -} from '@reach/combobox'; -import '@reach/combobox/styles.css'; -import PropTypes from 'prop-types'; - -let cache = {}; -const useAddressSearch = (searchTerm) => { - const [addresses, setAddresses] = useState([]); - useEffect(() => { - if (searchTerm.trim() !== '') { - let isFresh = true; - fetchAddresses(searchTerm).then((addresses) => { - if (isFresh) setAddresses(addresses); - }); - return () => (isFresh = false); - } - }, [searchTerm]); - return addresses; -}; - -const fetchAddresses = (value) => { - if (cache[value]) { - return Promise.resolve(cache[value]); - } - const url = `https://api-adresse.data.gouv.fr/search/`; - return getJSON(url, { q: value, limit: 5 }, 'get').then((result) => { - if (result) { - cache[value] = result; - } - return result; - }); -}; - -const SearchInput = ({ getCoords }) => { - const [searchTerm, setSearchTerm] = useState(''); - const addresses = useAddressSearch(searchTerm); - const handleSearchTermChange = (event) => { - setSearchTerm(event.target.value); - }; - return ( - - - {addresses.features && ( - - {addresses.features.length > 0 ? ( - - {addresses.features.map((feature) => { - const str = `${feature.properties.name}, ${feature.properties.city}`; - return ( - getCoords(feature.geometry.coordinates)} - key={str} - value={str} - /> - ); - })} - - ) : ( - Aucun résultat - )} - - )} - - ); -}; - -SearchInput.propTypes = { - getCoords: PropTypes.func -}; - -export default SearchInput; diff --git a/app/javascript/components/MapEditor/index.js b/app/javascript/components/MapEditor/index.js index d3ab35a1c..4c6246a2f 100644 --- a/app/javascript/components/MapEditor/index.js +++ b/app/javascript/components/MapEditor/index.js @@ -9,7 +9,7 @@ import { getJSON, ajax, fire } from '@utils'; import { getMapStyle, SwitchMapStyle } from '../MapStyles'; -import SearchInput from './SearchInput'; +import ComboAdresseSearch from '../ComboAdresseSearch'; import { polygonCadastresFill, polygonCadastresLine, @@ -279,9 +279,11 @@ function MapEditor({ featureCollection, url, preview, options }) { marginBottom: '50px' }} > - { - setCoords(searchTerm); + { + setCoords(coordinates); setZoom([17]); }} /> diff --git a/app/javascript/loaders/ComboAdresseSearch.js b/app/javascript/loaders/ComboAdresseSearch.js new file mode 100644 index 000000000..d37c73f31 --- /dev/null +++ b/app/javascript/loaders/ComboAdresseSearch.js @@ -0,0 +1,3 @@ +import Loadable from '../components/Loadable'; + +export default Loadable(() => import('../components/ComboAdresseSearch')); diff --git a/app/views/shared/dossiers/editable_champs/_address.html.haml b/app/views/shared/dossiers/editable_champs/_address.html.haml index 95025fc33..4cc7f62a1 100644 --- a/app/views/shared/dossiers/editable_champs/_address.html.haml +++ b/app/views/shared/dossiers/editable_champs/_address.html.haml @@ -1,4 +1,3 @@ -= form.select :value, [champ.value].compact, - { include_blank: true }, - required: champ.mandatory?, - class: 'select2 adresse' +- hidden_field_id = SecureRandom.uuid += form.hidden_field :value, { data: { uuid: hidden_field_id } } += react_component("ComboAdresseSearch", mandatory: champ.mandatory?, hiddenFieldId: hidden_field_id) From 653270d02fbfa946a07891df2faaaa8628d77d00 Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Wed, 7 Oct 2020 17:44:21 +0200 Subject: [PATCH 6/7] Update specs --- app/controllers/api_geo_test_controller.rb | 2 +- spec/features/users/brouillon_spec.rb | 31 ++++++++++++---------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/app/controllers/api_geo_test_controller.rb b/app/controllers/api_geo_test_controller.rb index 9328dc830..d548823cb 100644 --- a/app/controllers/api_geo_test_controller.rb +++ b/app/controllers/api_geo_test_controller.rb @@ -8,6 +8,6 @@ class APIGeoTestController < ActionController::Base end def communes - render json: [{ nom: 'Ambléon' }] + render json: [{ nom: 'Ambléon', code: '01006', codesPostaux: ['01300'] }] end end diff --git a/spec/features/users/brouillon_spec.rb b/spec/features/users/brouillon_spec.rb index 7a3cfd055..f73d69475 100644 --- a/spec/features/users/brouillon_spec.rb +++ b/spec/features/users/brouillon_spec.rb @@ -5,7 +5,7 @@ feature 'The user' do let!(:procedure) { create(:procedure, :published, :for_individual, :with_all_champs_mandatory) } let(:user_dossier) { user.dossiers.first } - scenario 'fill a dossier', js: true, vcr: { cassette_name: 'api_geo_departements_regions_et_communes' } do + scenario 'fill a dossier', js: true do log_in(user, procedure) fill_individual @@ -30,13 +30,10 @@ feature 'The user' do select('AUSTRALIE', from: 'pays') select_champ_geo('regions', 'Ma', 'Martinique') - select('Martinique', from: 'regions') select_champ_geo('departements', 'Ai', '02 - Aisne') - select('02 - Aisne', from: 'departements') - select_champ_geo('communes', 'Am', 'Ambléon') - select('Ambléon', from: 'communes') + select_champ_geo('communes', 'Ambl', 'Ambléon (01300)') check('engagement') fill_in('dossier_link', with: '123') @@ -64,7 +61,7 @@ feature 'The user' do expect(champ_value_for('pays')).to eq('AUSTRALIE') expect(champ_value_for('regions')).to eq('Martinique') expect(champ_value_for('departements')).to eq('02 - Aisne') - expect(champ_value_for('communes')).to eq('Ambléon') + expect(champ_value_for('communes')).to eq('Ambléon (01300)') expect(champ_value_for('engagement')).to eq('on') expect(champ_value_for('dossier_link')).to eq('123') expect(champ_value_for('piece_justificative')).to be_nil # antivirus hasn't approved the file yet @@ -87,9 +84,9 @@ feature 'The user' do expect(page).to have_selected_value('simple_choice_drop_down_list_long', selected: 'bravo') expect(page).to have_selected_value('multiple_choice_drop_down_list_long', selected: ['alpha', 'charly']) expect(page).to have_selected_value('pays', selected: 'AUSTRALIE') - expect(page).to have_selected_value('regions', selected: 'Martinique') - expect(page).to have_selected_value('departements', selected: '02 - Aisne') - expect(page).to have_selected_value('communes', selected: 'Ambléon') + expect(page).to have_hidden_field('regions', with: 'Martinique') + expect(page).to have_hidden_field('departements', with: '02 - Aisne') + expect(page).to have_hidden_field('communes', with: 'Ambléon (01300)') expect(page).to have_checked_field('engagement') expect(page).to have_field('dossier_link', with: '123') expect(page).to have_text('file.pdf') @@ -321,6 +318,10 @@ feature 'The user' do e.sibling('.datetime').first('select')[:id][0..-4] end + def have_hidden_field(libelle, with:) + have_css("##{form_id_for(libelle)}[value=\"#{with}\"]") + end + def champ_value_for(libelle) champs = user_dossier.champs champs.find { |c| c.libelle == libelle }.value @@ -351,10 +352,12 @@ feature 'The user' do end def select_champ_geo(champ, fill_with, value) - find(".editable-champ-#{champ} .select2-container").click - id = find('.select2-container--open [role=listbox]')[:id] - find("[aria-controls=#{id}]").fill_in with: fill_with - expect(page).to have_content(value) - find('li', text: value).click + input = find("input[aria-label=#{champ}") + input.click + input.fill_in with: fill_with + selector = "li[data-option-value=\"#{value}\"]" + find(selector).click + expect(page).to have_css(selector) + expect(page).to have_hidden_field(champ, with: value) end end From 70bf9ea92f5e5565d78dfc02a733e0a4a60f964f Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Wed, 7 Oct 2020 17:44:44 +0200 Subject: [PATCH 7/7] remove unused select2 code --- app/javascript/new_design/select2.js | 95 ---------------------------- 1 file changed, 95 deletions(-) diff --git a/app/javascript/new_design/select2.js b/app/javascript/new_design/select2.js index e92aad0ce..e69e1c92e 100644 --- a/app/javascript/new_design/select2.js +++ b/app/javascript/new_design/select2.js @@ -1,8 +1,5 @@ import $ from 'jquery'; import 'select2'; -import { isNumeric } from '@utils'; - -const { api_geo_url, api_adresse_url } = gon.autocomplete || {}; const language = { errorLoading: function () { @@ -50,94 +47,6 @@ const baseOptions = { width: '100%' }; -const baseAjaxOptions = { - delay: 250, - timeout: 10 * 1000, // 10 sec - cache: true, - data({ term: nom }) { - return { - nom, - fields: 'nom,code' - }; - }, - processResults(data) { - return { - results: data.map(({ nom }) => ({ id: nom, text: nom })) - }; - } -}; - -const regionsOptions = { - ...baseOptions, - minimumInputLength: 2, - ajax: { url: `${api_geo_url}/regions`, ...baseAjaxOptions } -}; - -const communesOptions = { - ...baseOptions, - minimumInputLength: 2, - ajax: { url: `${api_geo_url}/communes`, ...baseAjaxOptions } -}; - -const etranger99 = { id: '99 - Étranger', text: '99 - Étranger' }; -const departementsOptions = { - ...baseOptions, - minimumInputLength: 1, - ajax: { - ...baseAjaxOptions, - url: `${api_geo_url}/departements`, - data({ term }) { - const data = { fields: 'nom,code' }; - - if (isNumeric(term)) { - data.code = term.trim().padStart(2, '0'); - } else { - data.nom = term; - } - - return data; - }, - processResults(data) { - return { - results: data - .map(({ nom, code }) => ({ - id: `${code} - ${nom}`, - text: `${code} - ${nom}` - })) - .concat([etranger99]) - }; - } - } -}; - -const adresseOptions = { - ...baseOptions, - minimumInputLength: 2, - ajax: { - ...baseAjaxOptions, - url: `${api_adresse_url}/search`, - data({ term: q }) { - return { - q, - limit: 5 - }; - }, - processResults(data) { - let r = data.features.map(({ properties: { label }, geometry }) => ({ - id: label, - text: label, - geometry - })); - // Allow the user to select an arbitrary address missing from the results, - // by adding the plain-text query to the list of results. - r.unshift({ id: data.query, text: data.query }); - return { - results: r - }; - } - } -}; - const templateOption = ({ text }) => $( `${text}` @@ -145,10 +54,6 @@ const templateOption = ({ text }) => addEventListener('ds:page:update', () => { $('select.select2').select2(baseOptions); - $('select.select2.departements').select2(departementsOptions); - $('select.select2.regions').select2(regionsOptions); - $('select.select2.communes').select2(communesOptions); - $('select.select2.adresse').select2(adresseOptions); $('.columns-form select.select2-limited').select2({ width: '300px',