diff --git a/components/bal/commune-tab.js b/components/bal/commune-tab.js deleted file mode 100644 index af92be895..000000000 --- a/components/bal/commune-tab.js +++ /dev/null @@ -1,28 +0,0 @@ -import {useContext} from 'react' -import PropTypes from 'prop-types' -import {Pane} from 'evergreen-ui' - -import BalDataContext from '@/contexts/bal-data' - -import CertificationInfos from './certification-infos' -import HabilitationInfos from './habilitation-infos' - -function CommuneTab({commune}) { - const {baseLocale} = useContext(BalDataContext) - - return ( - - {baseLocale.status !== 'demo' && } - - - ) -} - -CommuneTab.propTypes = { - commune: PropTypes.shape({ - isCOM: PropTypes.bool.isRequired, - }).isRequired, -} - -export default CommuneTab - diff --git a/components/bal/commune-tab.tsx b/components/bal/commune-tab.tsx new file mode 100644 index 000000000..716765e1a --- /dev/null +++ b/components/bal/commune-tab.tsx @@ -0,0 +1,30 @@ +import React, {useContext} from 'react' +import {Pane} from 'evergreen-ui' + +import BalDataContext from '@/contexts/bal-data' +import TokenContext from '@/contexts/token' + +import CertificationInfos from './certification-infos' +import HabilitationInfos from './habilitation-infos' +import ReadOnlyInfos from './read-only-infos' +import {CommmuneType} from '@/types/commune' + +interface CommuneTabProps { + commune: CommmuneType; +} + +function CommuneTab({commune}: CommuneTabProps) { + const {baseLocale} = useContext(BalDataContext) + const {token} = useContext(TokenContext) + + return ( + + {!token && } + {token && baseLocale.status !== 'demo' && } + + + ) +} + +export default CommuneTab + diff --git a/components/bal/read-only-infos.tsx b/components/bal/read-only-infos.tsx new file mode 100644 index 000000000..a82426a28 --- /dev/null +++ b/components/bal/read-only-infos.tsx @@ -0,0 +1,42 @@ +import React, {useState} from 'react' +import {Pane, Alert, Text, Button} from 'evergreen-ui' +import RecoverBALAlert from '../bal-recovery/recover-bal-alert' + +function BALReadOnly() { + const [isDialogOpen, setIsDialogOpen] = useState(false) + + return ( + <> + { + setIsDialogOpen(false) + }} /> + + + + Vous ne pouvez pas modifier cette Base Adresse Locale car vous n’êtes pas authentifié comme administrateur. + + + Si vous êtes administrateur de cette Base Adresse Locale, vous pouvez récupérer vos accès en cliquant sur le bouton ci-dessous. + + + + + + ) +} + +export default BALReadOnly diff --git a/components/bal/toponymes-list.js b/components/bal/toponymes-list.tsx similarity index 71% rename from components/bal/toponymes-list.js rename to components/bal/toponymes-list.tsx index 671f080b9..9b5b7b53f 100644 --- a/components/bal/toponymes-list.js +++ b/components/bal/toponymes-list.tsx @@ -1,5 +1,4 @@ import {useContext, useMemo, useState} from 'react' -import PropTypes from 'prop-types' import {sortBy} from 'lodash' import {Table, Paragraph, Pane} from 'evergreen-ui' import {useRouter} from 'next/router' @@ -16,12 +15,23 @@ import TableRow from '@/components/table-row' import DeleteWarning from '@/components/delete-warning' import InfiniteScrollList from '@/components/infinite-scroll-list' import CommentsContent from '@/components/comments-content' +import RecoverBALAlert from '@/components/bal-recovery/recover-bal-alert' +import {ToponymeType} from '@/types/toponyme' -function ToponymesList({toponymes, onEnableEditing, onRemove, balId, addButton}) { +interface ToponymesListProps { + toponymes: ToponymeType[]; + onRemove: () => Promise; + onEnableEditing: (id: string) => void; + balId: string; + addButton: React.ReactNode; +} + +function ToponymesList({toponymes, onEnableEditing, onRemove, balId, addButton}: ToponymesListProps) { const {token} = useContext(TokenContext) const [toRemove, setToRemove] = useState(null) const [isDisabled, setIsDisabled] = useState(false) const {isEditing, reloadToponymes} = useContext(BalDataContext) + const [isRecoveryDialogOpen, setIsRecoveryDialogOpen] = useState(false) const router = useRouter() const handleRemove = async () => { @@ -33,8 +43,8 @@ function ToponymesList({toponymes, onEnableEditing, onRemove, balId, addButton}) setIsDisabled(false) } - const onSelect = id => { - router.push(`/bal/${balId}/toponymes/${id}`) + const onSelect = (id: string) => { + void router.push(`/bal/${balId}/toponymes/${id}`) } const [filtered, setFilter] = useFuse(toponymes, 200, { @@ -57,9 +67,14 @@ function ToponymesList({toponymes, onEnableEditing, onRemove, balId, addButton}) )} isDisabled={isDisabled} - onCancel={() => setToRemove(null)} + onCancel={() => { + setToRemove(null) + }} onConfirm={handleRemove} /> + { + setIsRecoveryDialogOpen(false) + }} /> - {toponyme => ( + {(toponyme: ToponymeType) => ( 0 ? : null, certification: toponyme.isAllCertified ? 'Toutes les adresses de ce toponyme sont certifiées par la commune' : null }} actions={{ - onSelect: () => onSelect(toponyme._id), - onEdit: () => onEnableEditing(toponyme._id), - onRemove: () => setToRemove(toponyme._id) + onSelect: () => { + onSelect(toponyme._id) + }, + onEdit: () => { + onEnableEditing(toponyme._id) + }, + onRemove: () => { + setToRemove(toponyme._id) + } + }} + onShowRecoveryDialog={() => { + setIsRecoveryDialogOpen(true) }} /> )} @@ -112,12 +137,4 @@ function ToponymesList({toponymes, onEnableEditing, onRemove, balId, addButton}) ) } -ToponymesList.propTypes = { - toponymes: PropTypes.array.isRequired, - onRemove: PropTypes.func, - onEnableEditing: PropTypes.func.isRequired, - balId: PropTypes.string.isRequired, - addButton: PropTypes.object -} - export default ToponymesList diff --git a/components/bal/voies-list.js b/components/bal/voies-list.tsx similarity index 71% rename from components/bal/voies-list.js rename to components/bal/voies-list.tsx index 046a56db9..c315b4be7 100644 --- a/components/bal/voies-list.js +++ b/components/bal/voies-list.tsx @@ -15,14 +15,26 @@ import useFuse from '@/hooks/fuse' import TableRow from '@/components/table-row' import CommentsContent from '@/components/comments-content' import DeleteWarning from '@/components/delete-warning' +import RecoverBALAlert from '@/components/bal-recovery/recover-bal-alert' import InfiniteScrollList from '../infinite-scroll-list' +import {VoieType} from '@/types/voie' -function VoiesList({voies, onEnableEditing, setToConvert, balId, onRemove, addButton}) { +interface VoiesListProps { + voies: VoieType[]; + onRemove: () => Promise; + onEnableEditing: (id: string) => void; + balId: string; + setToConvert: (id: string) => void; + addButton: React.ReactNode; +} + +function VoiesList({voies, onEnableEditing, setToConvert, balId, onRemove, addButton}: VoiesListProps) { const {token} = useContext(TokenContext) const [toRemove, setToRemove] = useState(null) const {isEditing, reloadVoies} = useContext(BalDataContext) const [isDisabled, setIsDisabled] = useState(false) + const [isRecoveryDialogOpen, setIsRecoveryDialogOpen] = useState(false) const router = useRouter() const handleRemove = async () => { @@ -34,8 +46,8 @@ function VoiesList({voies, onEnableEditing, setToConvert, balId, onRemove, addBu setIsDisabled(false) } - const onSelect = id => { - router.push(`/bal/${balId}/voies/${id}`) + const onSelect = (id: string) => { + void router.push(`/bal/${balId}/voies/${id}`) } const [filtered, setFilter] = useFuse(voies, 200, { @@ -57,10 +69,15 @@ function VoiesList({voies, onEnableEditing, setToConvert, balId, onRemove, addBu Êtes vous bien sûr de vouloir supprimer cette voie ainsi que tous ses numéros ? )} - onCancel={() => setToRemove(null)} + onCancel={() => { + setToRemove(null) + }} onConfirm={handleRemove} isDisabled={isDisabled} /> + { + setIsRecoveryDialogOpen(false) + }} /> - {voie => ( + {(voie: VoieType) => ( onSelect(voie._id), - onEdit: () => onEnableEditing(voie._id), - onRemove: () => setToRemove(voie._id), + onSelect: () => { + onSelect(voie._id) + }, + onEdit: () => { + onEnableEditing(voie._id) + }, + onRemove: () => { + setToRemove(voie._id) + }, extra: voie.nbNumeros === 0 ? { - callback: () => setToConvert(voie._id), + callback: () => { + setToConvert(voie._id) + }, icon: KeyTabIcon, - text: 'Convertir en toponyme', + text: 'Convertir en toponyme' } : null }} notifications={{ @@ -110,6 +136,9 @@ function VoiesList({voies, onEnableEditing, setToConvert, balId, onRemove, addBu comment: voie.commentedNumeros.length > 0 ? : null, warning: voie.nbNumeros === 0 ? 'Cette voie ne contient aucun numéro' : null }} + onShowRecoveryDialog={() => { + setIsRecoveryDialogOpen(true) + }} /> )} diff --git a/components/delete-warning.js b/components/delete-warning.tsx similarity index 62% rename from components/delete-warning.js rename to components/delete-warning.tsx index 56f73ff9e..d11c1616f 100644 --- a/components/delete-warning.js +++ b/components/delete-warning.tsx @@ -1,7 +1,14 @@ -import PropTypes from 'prop-types' import {Pane, Dialog} from 'evergreen-ui' -function DeleteWarning({isShown, content, onCancel, onConfirm, isDisabled}) { +interface DeleteWarningProps { + isShown: boolean; + content: React.ReactNode; + onCancel: () => void; + onConfirm: () => void; + isDisabled?: boolean; +} + +function DeleteWarning({isShown, content, onCancel, onConfirm, isDisabled}: DeleteWarningProps) { return ( - {token ? ( + {token && ( baseLocale.sync && isHabilitationValid ? ( ) ) - ) : ( - - - )} ) diff --git a/components/table-row/index.js b/components/table-row/index.tsx similarity index 59% rename from components/table-row/index.js rename to components/table-row/index.tsx index c0ad41e4b..352b3b71f 100644 --- a/components/table-row/index.js +++ b/components/table-row/index.tsx @@ -1,13 +1,36 @@ import React, {useCallback} from 'react' -import PropTypes from 'prop-types' -import {Table, Checkbox} from 'evergreen-ui' +import {Table, Checkbox, IconButton, LockIcon} from 'evergreen-ui' 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, nomAlt, complement, secondary, notifications, isSelected, isEditingEnabled, handleSelect, actions}) => { +interface TableRowProps { + label: string; + nomAlt?: string; + complement?: string; + secondary?: string; + handleSelect?: () => void; + isSelected?: boolean; + isEditing: boolean; + isAdmin: boolean; + notifications?: any; + actions?: { + onSelect: () => void; + onEdit: () => void; + onRemove: () => void; + extra?: { + callback: () => void; + icon: any; + text: string; + }; + }; + onShowRecoveryDialog?: () => void; +} + +function TableRow({label, nomAlt, complement, secondary, notifications, isSelected = false, isEditing, isAdmin, handleSelect, onShowRecoveryDialog, actions}: TableRowProps) { const {onSelect, onEdit} = actions + const isEditingEnabled = !isEditing && isAdmin const onClick = useCallback(e => { if (e.target.closest('[data-editable]') && isEditingEnabled) { @@ -49,33 +72,14 @@ const TableRow = React.memo(({label, nomAlt, complement, secondary, notification {isEditingEnabled && actions && ( )} + + {!isAdmin && ( + + + + )} ) -}) - -TableRow.propTypes = { - label: PropTypes.string.isRequired, - nomAlt: PropTypes.object, - complement: PropTypes.string, - secondary: PropTypes.string, - handleSelect: PropTypes.func, - isSelected: PropTypes.bool, - isEditingEnabled: PropTypes.bool, - notifications: PropTypes.object, - actions: PropTypes.shape({ - onSelect: PropTypes.func, - onEdit: PropTypes.func, - }).isRequired -} - -TableRow.defaultProps = { - complement: null, - nomAlt: null, - secondary: null, - notifications: null, - handleSelect: null, - isSelected: false, - isEditingEnabled: false } export default TableRow diff --git a/components/table-row/table-row-edit-shortcut.js b/components/table-row/table-row-edit-shortcut.tsx similarity index 70% rename from components/table-row/table-row-edit-shortcut.js rename to components/table-row/table-row-edit-shortcut.tsx index 88c7c0bb5..b005864c3 100644 --- a/components/table-row/table-row-edit-shortcut.js +++ b/components/table-row/table-row-edit-shortcut.tsx @@ -1,18 +1,30 @@ import React, {useState} from 'react' -import PropTypes from 'prop-types' import {Pane, Table, EditIcon, Text} from 'evergreen-ui' import LanguagePreview from '../bal/language-preview' -const TableRowEditShortcut = React.memo(({label, nomAlt, complement, colors, isEditingEnabled, isSelectable}) => { +interface TableRowEditShortcutProps { + label: string; + nomAlt?: any; + complement?: string; + colors?: any; + isEditingEnabled: boolean; + isSelectable: boolean; +} + +function TableRowEditShortcut({label, nomAlt, complement, colors = {}, isEditingEnabled, isSelectable}: TableRowEditShortcutProps) { const [hovered, setHovered] = useState(false) return ( setHovered(isSelectable)} - onMouseLeave={() => setHovered(false)} + onMouseEnter={() => { + setHovered(isSelectable) + }} + onMouseLeave={() => { + setHovered(false) + }} > ) -}) - -TableRowEditShortcut.propTypes = { - label: PropTypes.string.isRequired, - nomAlt: PropTypes.object, - complement: PropTypes.string, - colors: PropTypes.object, - isEditingEnabled: PropTypes.bool.isRequired, - isSelectable: PropTypes.bool.isRequired -} - -TableRowEditShortcut.defaultProps = { - complement: null, - nomAlt: null, - colors: {} } export default TableRowEditShortcut diff --git a/layouts/sidebar.tsx b/layouts/sidebar.tsx index d2feca080..bac436f11 100644 --- a/layouts/sidebar.tsx +++ b/layouts/sidebar.tsx @@ -2,6 +2,7 @@ import React, {useContext, useEffect} from 'react' import {Pane, Button, ChevronRightIcon, CrossIcon, ChevronLeftIcon, PaneProps} from 'evergreen-ui' import BalDataContext from '@/contexts/bal-data' +import useWindowSize from '@/hooks/useWindowSize' interface SidebarProps extends PaneProps { isHidden: boolean; @@ -13,7 +14,7 @@ interface SidebarProps extends PaneProps { function Sidebar({isHidden = false, size, onToggle, top, bottom = 0, ...props}: SidebarProps) { const {setEditingId, isEditing, setIsEditing} = useContext(BalDataContext) - + const {isMobile} = useWindowSize() const handleClick = () => { if (isEditing) { setEditingId(null) @@ -41,7 +42,7 @@ function Sidebar({isHidden = false, size, onToggle, top, bottom = 0, ...props}: bottom={bottom} zIndex={2} > - {innerWidth > 800 && ( + {!isMobile && (