diff --git a/.gitignore b/.gitignore index bff419b1d..65c9ab7b6 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,8 @@ node_modules reports .next +available-flags.json + .env* !.env.sample diff --git a/README.md b/README.md index ce80b252f..778d30eae 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,11 @@ Installation des dépendances Node.js $ yarn ``` +## Drapeaux disponible pour les langues régionales +``` +$ yarn flags +``` + ## Développement Lancer le serveur de développement : diff --git a/components/accent-tool.js b/components/accent-tool.js index ff407cf2e..a63d93505 100644 --- a/components/accent-tool.js +++ b/components/accent-tool.js @@ -34,7 +34,7 @@ const ACCENTS = [ 'Œ' ] -function AccentTool({input, handleAccent, cursorPosition}) { +function AccentTool({input, handleAccent, cursorPosition, isDisabled}) { const handleClick = event => { const stringArray = input.split('') const {start, end} = cursorPosition @@ -61,7 +61,7 @@ function AccentTool({input, handleAccent, cursorPosition}) { )} > - + ) } @@ -69,7 +69,12 @@ function AccentTool({input, handleAccent, cursorPosition}) { AccentTool.propTypes = { input: PropTypes.string.isRequired, handleAccent: PropTypes.func.isRequired, - cursorPosition: PropTypes.objectOf(PropTypes.number).isRequired + cursorPosition: PropTypes.objectOf(PropTypes.number).isRequired, + isDisabled: PropTypes.bool +} + +AccentTool.defaultProps = { + isDisabled: false } export default AccentTool diff --git a/components/assisted-text-field.js b/components/assisted-text-field.js index 6ac9f3e36..d229bf140 100644 --- a/components/assisted-text-field.js +++ b/components/assisted-text-field.js @@ -6,7 +6,7 @@ import useFocus from '@/hooks/focus' import AccentTool from '@/components/accent-tool' -function AssistedTextField({label, placeholder, value, validationMessage, onChange, isFocus, isDisabled}) { +function AssistedTextField({label, placeholder, value, validationMessage, onChange, isFocus, isDisabled, isRequired}) { const [cursorPosition, setCursorPosition] = useState({start: 0, end: 0}) const [focusRef, ref] = useFocus() @@ -25,7 +25,7 @@ function AssistedTextField({label, placeholder, value, validationMessage, onChan - handleChangeAccent(e)} cursorPosition={cursorPosition} /> + handleChangeAccent(e)} cursorPosition={cursorPosition} isDisabled={isDisabled} /> ) @@ -53,7 +53,8 @@ AssistedTextField.defaultProps = { placeholder: '', isFocus: false, isDisabled: false, - validationMessage: null + validationMessage: null, + isRequired: true } AssistedTextField.propTypes = { @@ -63,7 +64,8 @@ AssistedTextField.propTypes = { validationMessage: PropTypes.string, onChange: PropTypes.func.isRequired, isFocus: PropTypes.bool, - isDisabled: PropTypes.bool + isDisabled: PropTypes.bool, + isRequired: PropTypes.bool } export default AssistedTextField diff --git a/components/bal/language-preview.js b/components/bal/language-preview.js new file mode 100644 index 000000000..861106040 --- /dev/null +++ b/components/bal/language-preview.js @@ -0,0 +1,49 @@ +import PropTypes from 'prop-types' +import Image from 'next/image' +import {Pane, UnorderedList, ListItem, Tooltip, Position, HelpIcon} from 'evergreen-ui' + +import availableFlags from '../../available-flags.json' + +function LanguagePreview({nomAlt}) { + const isFlagExist = availableFlags.includes(Object.keys(nomAlt)[0]) + + return ( + Object.keys(nomAlt).length > 1 ? ( + + + {Object.keys(nomAlt).map(language => ( + + {nomAlt[language]} + + ))} + + } + position={Position.BOTTOM_LEFT} + padding={0} + margin={0} + > + + Afficher les alternatives régionales + + + + ) : ( + + + {nomAlt[Object.keys(nomAlt)]} + + ) + ) +} + +LanguagePreview.propTypes = { + nomAlt: PropTypes.object.isRequired +} + +export default LanguagePreview diff --git a/components/bal/numero-editor.js b/components/bal/numero-editor.js index b64498faf..53e1d78fa 100644 --- a/components/bal/numero-editor.js +++ b/components/bal/numero-editor.js @@ -183,6 +183,7 @@ function NumeroEditor({initialVoieId, initialValue, commune, hasPreview, closeFo voieId={voieId} voies={voies} nomVoie={nomVoie} + initialNomAlt={initialValue?.nomAlt} mode={voieId ? 'selection' : 'creation'} validationMessage={getValidationMessage('nom')} handleVoie={setVoieId} @@ -289,6 +290,7 @@ NumeroEditor.propTypes = { PropTypes.object, // When "voie" comes from getNumerosToponyme() -> it's an Object with "nomVoie", needed to sort numeros by voie and display nomVoie PropTypes.string // When "voie" comes from getNumeros() -> it's a String (only the id of "voie" is return) ]).isRequired, + nomAlt: PropTypes.object, suffixe: PropTypes.string, parcelles: PropTypes.array, comment: PropTypes.string, diff --git a/components/bal/toponyme-editor.js b/components/bal/toponyme-editor.js index 22c6ac2d6..351f919f1 100644 --- a/components/bal/toponyme-editor.js +++ b/components/bal/toponyme-editor.js @@ -2,6 +2,7 @@ import {useState, useMemo, useContext, useCallback, useEffect} from 'react' import PropTypes from 'prop-types' import {difference} from 'lodash' import {Button} from 'evergreen-ui' +import router from 'next/router' import {addToponyme, editToponyme} from '@/lib/bal-api' @@ -20,12 +21,13 @@ import FormInput from '@/components/form-input' import PositionEditor from '@/components/bal/position-editor' import SelectParcelles from '@/components/bal/numero-editor/select-parcelles' import DisabledFormInput from '@/components/disabled-form-input' -import router from 'next/router' +import LanguesRegionalesForm from '@/components/langues-regionales-form' function ToponymeEditor({initialValue, commune, closeForm}) { const [isLoading, setIsLoading] = useState(false) const [nom, onNomChange, resetNom] = useInput(initialValue?.nom || '') const [getValidationMessage, setValidationMessages] = useValidationMessage(null) + const [nomAlt, setNomAlt] = useState(initialValue?.nomAlt) const {token} = useContext(TokenContext) const {baseLocale, setToponyme, reloadToponymes, refreshBALSync, reloadGeojson, reloadParcelles} = useContext(BalDataContext) @@ -40,6 +42,7 @@ function ToponymeEditor({initialValue, commune, closeForm}) { const body = { nom, + nomAlt: Object.keys(nomAlt).length > 0 ? nomAlt : null, positions: [], parcelles: selectedParcelles } @@ -84,7 +87,7 @@ function ToponymeEditor({initialValue, commune, closeForm}) { } catch { setIsLoading(false) } - }, [token, baseLocale._id, initialValue, nom, markers, selectedParcelles, setToponyme, closeForm, refreshBALSync, reloadToponymes, reloadParcelles, reloadGeojson, setValidationMessages]) + }, [token, baseLocale._id, initialValue, nom, nomAlt, markers, selectedParcelles, setToponyme, closeForm, refreshBALSync, reloadToponymes, reloadParcelles, reloadGeojson, setValidationMessages]) const onFormCancel = useCallback(e => { e.preventDefault() @@ -111,13 +114,15 @@ function ToponymeEditor({initialValue, commune, closeForm}) { + + @@ -158,6 +163,7 @@ ToponymeEditor.propTypes = { initialValue: PropTypes.shape({ _id: PropTypes.string.isRequired, nom: PropTypes.string.isRequired, + nomAlt: PropTypes.object, parcelles: PropTypes.array.isRequired, positions: PropTypes.array.isRequired }), diff --git a/components/bal/toponymes-list.js b/components/bal/toponymes-list.js index 7716eb7fe..f6437e2b5 100644 --- a/components/bal/toponymes-list.js +++ b/components/bal/toponymes-list.js @@ -50,6 +50,7 @@ function ToponymesList({toponymes, editedId, commune, onCancel, onSelect, onEnab 0 ? nomAlt : null, typeNumerotation: isMetric ? 'metrique' : 'numerique', trace: data ? data.geometry : null } @@ -63,7 +65,7 @@ function VoieEditor({initialValue, closeForm}) { } catch { setIsLoading(false) } - }, [baseLocale._id, initialValue, nom, isMetric, data, token, closeForm, setValidationMessages, setVoie, reloadVoies, reloadGeojson, refreshBALSync]) + }, [baseLocale._id, initialValue, nom, isMetric, data, token, nomAlt, closeForm, setValidationMessages, setVoie, reloadVoies, reloadGeojson, refreshBALSync]) const onFormCancel = useCallback(e => { e.preventDefault() @@ -92,27 +94,31 @@ function VoieEditor({initialValue, closeForm}) { return (
- - - - - - - {isMetric && ( - - )} + + + + + + + + + + {isMetric && ( + + )} + + + ) +} + +LanguesRegionalesForm.propTypes = { + initialValue: PropTypes.object, + handleLanguages: PropTypes.func.isRequired, +} + +export default LanguesRegionalesForm diff --git a/components/langues-regionales-form/language-field.js b/components/langues-regionales-form/language-field.js new file mode 100644 index 000000000..9b7fc152f --- /dev/null +++ b/components/langues-regionales-form/language-field.js @@ -0,0 +1,94 @@ +import {useCallback, useState, useMemo} from 'react' +import PropTypes from 'prop-types' +import {Pane, Button, SelectMenu, Tooltip, TrashIcon, PropertyIcon} from 'evergreen-ui' +import {capitalize} from 'lodash' + +import languesRegionales from '@ban-team/shared-data/langues-regionales.json' + +import AssistedTextField from '@/components/assisted-text-field' + +function LanguageField({initialValue, availableLanguages, onChange, onDelete}) { + const [codeISO, setCodeISO] = useState(initialValue?.code) + const [input, setInput] = useState(initialValue?.value || '') + + const languageLabel = useMemo(() => { + if (codeISO) { + return languesRegionales.find(language => language.code === codeISO)?.label + } + }, [codeISO]) + + const handleLanguageCode = codeISO => { + setCodeISO(codeISO) + onChange({code: codeISO, value: input}) + } + + const handleLanguageChange = useCallback(event => { + const {value} = event.target + + setInput(value) + onChange({code: codeISO, value}) + }, [codeISO, onChange]) + + return ( + + { + return {value: code, label: capitalize(label)} + }).sort((a, b) => a.label.localeCompare(b.label))} + selected={languageLabel} + onSelect={({value}) => handleLanguageCode(value)} + width='fit-content' + closeOnSelect + hasFilter={false} + > + + + + + + + + + + + + ) +} + +LanguageField.propTypes = { + initialValue: PropTypes.shape({ + code: PropTypes.oneOf(languesRegionales.map(({code}) => code)), + value: PropTypes.string + }).isRequired, + availableLanguages: PropTypes.array.isRequired, + onChange: PropTypes.func.isRequired, + onDelete: PropTypes.func.isRequired, +} + +export default LanguageField diff --git a/components/table-row/index.js b/components/table-row/index.js index dc5e58366..b3cf98c2a 100644 --- a/components/table-row/index.js +++ b/components/table-row/index.js @@ -6,7 +6,7 @@ import TableRowActions from '@/components/table-row/table-row-actions' import TableRowEditShortcut from '@/components/table-row/table-row-edit-shortcut' import TableRowNotifications from '@/components/table-row/table-row-notifications' -const TableRow = React.memo(({label, complement, secondary, notifications, isSelected, isEditingEnabled, handleSelect, actions}) => { +const TableRow = React.memo(({label, nomAlt, complement, secondary, notifications, isSelected, isEditingEnabled, handleSelect, actions}) => { const {onSelect, onEdit} = actions const onClick = useCallback(e => { @@ -30,6 +30,7 @@ const TableRow = React.memo(({label, complement, secondary, notifications, isSel { +import LanguagePreview from '../bal/language-preview' + +const TableRowEditShortcut = React.memo(({label, nomAlt, complement, isEditingEnabled, isSelectable}) => { const [hovered, setHovered] = useState(false) return ( @@ -18,7 +20,7 @@ const TableRowEditShortcut = React.memo(({label, complement, isEditingEnabled, i style={{cursor: isEditingEnabled ? 'text' : 'pointer'}} className='edit-cell' > - + {label} {complement && {` - ${complement}`}} {isEditingEnabled && ( @@ -26,6 +28,7 @@ const TableRowEditShortcut = React.memo(({label, complement, isEditingEnabled, i )} + {nomAlt && }