-
Bastien DUMONT authoredBastien DUMONT authored
Consents.tsx 10.48 KiB
import React, {
useCallback,
useContext,
useEffect,
useMemo,
useState,
} from 'react'
import { AgGridReact } from 'ag-grid-react'
import 'ag-grid-community/dist/styles/ag-grid.css'
import 'ag-grid-community/dist/styles/ag-theme-alpine-dark.css'
import TablePagination from '@material-ui/core/TablePagination'
import {
ColDef,
ColGroupDef,
CsvExportParams,
GridApi,
GridReadyEvent,
RowNode,
RowSelectedEvent,
ValueFormatterParams,
} from 'ag-grid-community'
import styles from './consents.module.scss'
import './agGridOverrides.scss'
import './muiPaginationOverrides.scss'
import DowloadModal from './DowloadModal'
import { ConsentService } from '../../services/consent.service'
import { UserContextProps, UserContext } from '../../hooks/userContext'
import { IConsent } from '../../models/consent.model'
import { getAxiosXSRFHeader } from '../../axios.config'
import { DateTime } from 'luxon'
const Consents: React.FC = () => {
const [gridApi, setGridApi] = useState<GridApi | null>(null)
const [search, setSearch] = useState<string>('')
const [selectedNodes, setSelectedNodes] = useState<RowNode[]>([])
const [isShowingSelection, setIsShowingSelection] = useState<boolean>(false)
const [openDowloadModal, setOpenDowloadModal] = useState<boolean>(false)
const [consents, setConsents] = useState<IConsent[]>([])
const [page, setPage] = useState<number>(0)
const [rowsPerPage, setRowsPerPage] = useState<number>(50)
const [totalRows, setTotalRows] = useState<number>(50)
const { user }: Partial<UserContextProps> = useContext(UserContext)
const consentService = useMemo(() => {
return new ConsentService()
}, [])
const toggleOpenModal = useCallback(() => {
setOpenDowloadModal((prev) => !prev)
}, [])
const defaultColDef = useMemo(
() => ({
sortable: true,
resizable: true,
}),
[]
)
const dateFormatter = (data: ValueFormatterParams): string => {
return (data.value as DateTime).toLocaleString()
}
const [columnDefs] = useState<(ColDef | ColGroupDef)[] | null>([
{
field: 'ID',
hide: true,
},
{
field: 'pointID',
headerName: 'N° PDL',
initialWidth: 180,
filter: true,
checkboxSelection: true,
},
{
field: 'lastname',
headerName: 'Nom',
initialWidth: 180,
filter: true,
cellStyle: { textTransform: 'uppercase' },
},
{
field: 'firstname',
headerName: 'Prénom',
initialWidth: 180,
filter: true,
cellStyle: { textTransform: 'capitalize' },
},
{
field: 'address',
headerName: 'Adresse',
initialWidth: 300,
filter: true,
flex: 1,
},
{
field: 'postalCode',
headerName: 'CP',
initialWidth: 80,
filter: true,
},
{
field: 'city',
headerName: 'Ville',
},
{
field: 'safetyOnBoarding',
headerName: 'Secours',
initialWidth: 100,
},
{
field: 'startDate',
valueFormatter: dateFormatter,
headerName: 'Début du consentement',
initialWidth: 150,
filter: true,
sort: 'desc',
},
{
field: 'endDate',
valueFormatter: dateFormatter,
headerName: 'Fin du consentement',
initialWidth: 150,
filter: true,
},
])
const handleChangePage = useCallback(
(
_event: React.MouseEvent<HTMLButtonElement, MouseEvent> | null,
newPage: number
) => {
setPage(newPage)
},
[]
)
const handleChangeRowsPerPage = useCallback((event: any) => {
setRowsPerPage(event.target.value)
setPage(0)
}, [])
const checkSelectedNodes = useCallback(() => {
if (gridApi) {
const newNodes = gridApi.getRenderedNodes()
const idsToCheck: string[] = selectedNodes
.filter((node: RowNode) => node.isSelected)
.map((node: RowNode) => node.data.ID)
newNodes.forEach((node: RowNode) => {
if (idsToCheck.includes(node.data.ID))
node.setSelected(true, false, true)
})
}
}, [gridApi, selectedNodes])
const handleSearchChange = useCallback(
async (newSearch: string) => {
setSearch(newSearch)
if (user) {
let consentsData: IConsent[] | null = []
if (newSearch) {
consentsData = await consentService.searchConsent(
newSearch,
getAxiosXSRFHeader(user.xsrftoken)
)
} else {
const consentPagination = await consentService.getConsents(
rowsPerPage,
page,
getAxiosXSRFHeader(user.xsrftoken)
)
consentsData = consentPagination && consentPagination.rows
}
if (consentsData) {
setConsents(consentsData)
checkSelectedNodes()
}
}
},
[user, consentService, rowsPerPage, page, checkSelectedNodes]
)
const resetSelection = useCallback(() => {
if (gridApi) {
setIsShowingSelection(false)
gridApi.setRowData(consents)
gridApi.deselectAll()
setSelectedNodes([])
}
}, [gridApi, consents])
const onRowSelected = useCallback(
(event: RowSelectedEvent) => {
if (event.node.isSelected()) {
const index = selectedNodes.findIndex(
(node) => node.data.ID === event.node.data.ID
)
if (index === -1) {
setSelectedNodes((prev) => [...prev, event.node])
}
} else {
setSelectedNodes((prev) =>
prev.filter((node) => {
return node.data.ID != event.node.data.ID
})
)
}
},
[selectedNodes]
)
const continueSelection = useCallback(() => {
if (gridApi) {
setIsShowingSelection(false)
gridApi?.setRowData(consents)
const newNodes = gridApi.getRenderedNodes()
// We have to select nodes that have already been selected since we cannot pass a Node array to init AgGrid
const idsToCheck: string[] = selectedNodes
.filter((node: RowNode) => node.isSelected)
.map((node: RowNode) => node.data.ID)
newNodes.forEach((node: RowNode) => {
if (idsToCheck.includes(node.data.ID)) node.setSelected(true)
})
}
}, [gridApi, consents, selectedNodes])
const showCurrentSelection = useCallback(() => {
setIsShowingSelection(true)
const dataFromNode = selectedNodes.map((item: RowNode) => item.data)
selectedNodes && gridApi?.setRowData(dataFromNode)
gridApi?.selectAll()
}, [gridApi, selectedNodes])
const exportData = useCallback(() => {
//You can change default column separator
const params: CsvExportParams = {
columnSeparator: ',',
}
gridApi?.exportDataAsCsv(params)
setOpenDowloadModal(false)
resetSelection()
}, [gridApi, resetSelection])
const onGridReady = ({ api }: GridReadyEvent) => {
//Grid init method
setGridApi(api)
api.sizeColumnsToFit()
}
useEffect(() => {
function handleResize() {
gridApi?.sizeColumnsToFit()
}
handleResize()
window.addEventListener('resize', handleResize)
return () => {
window.removeEventListener('resize', handleResize)
}
}, [gridApi])
useEffect(() => {
async function getConsentsData() {
if (user) {
const consentsPaginationData = await consentService.getConsents(
rowsPerPage,
page,
getAxiosXSRFHeader(user.xsrftoken)
)
if (consentsPaginationData) {
setConsents(consentsPaginationData.rows)
checkSelectedNodes()
setTotalRows(consentsPaginationData.totalRows)
}
}
}
getConsentsData()
// /!\ Do not add checkSelected in dependencies or effect will trigger on each selection
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [user, consentService, rowsPerPage, page])
return (
<>
<div className="header">
<p className="title pagetitle">Gestion des consentements Enedis</p>
</div>
<div className={styles.content}>
<div className={styles.searchField}>
<div className={styles.inputGroup}>
<label htmlFor="search">Recherche</label>
<input
value={search}
name="search"
type="text"
placeholder="N°PDL, Nom, Prénom..."
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
handleSearchChange(e.target.value)
}
disabled={isShowingSelection}
autoComplete="off"
></input>
</div>
</div>
<div
className="ag-theme-alpine-dark"
style={{ width: '100%', height: '75vh' }}
>
<AgGridReact
onGridReady={onGridReady}
defaultColDef={defaultColDef}
rowHeight={35}
rowData={consents}
columnDefs={columnDefs}
animateRows={true}
rowSelection="multiple"
allowDragFromColumnsToolPanel={false}
onRowSelected={onRowSelected}
sortingOrder={['asc', 'desc']}
rowMultiSelectWithClick={true}
pagination={false}
suppressCellFocus={true}
></AgGridReact>
{search === '' && !isShowingSelection && (
<TablePagination
labelRowsPerPage="Consentements par page"
component="div"
count={totalRows}
page={page}
onPageChange={handleChangePage}
rowsPerPage={rowsPerPage}
onRowsPerPageChange={handleChangeRowsPerPage}
rowsPerPageOptions={[10, 25, 50, 100]}
/>
)}
</div>
{openDowloadModal && (
<DowloadModal
toggleOpenModal={toggleOpenModal}
exportData={exportData}
/>
)}
</div>
<div className={styles.footerButtons}>
<button
className="btnDelete"
onClick={isShowingSelection ? continueSelection : resetSelection}
disabled={
!isShowingSelection && selectedNodes && selectedNodes.length === 0
}
>
{isShowingSelection
? 'Continuer ma sélection'
: 'Tout déselectionner'}
</button>
<button
className={styles.btnSelection + ' btnValid'}
onClick={!isShowingSelection ? showCurrentSelection : toggleOpenModal}
disabled={selectedNodes && selectedNodes.length <= 0}
>
{!isShowingSelection ? 'Voir mes sélections' : 'Télécharger'}
<span>{selectedNodes?.length}</span>
</button>
</div>
</>
)
}
export default Consents