1- import React from "react" ;
2- import { OverlayTrigger , Popover , Table } from "react-bootstrap" ;
1+ import React , { useState } from "react" ;
2+ import { Alert , OverlayTrigger , Popover , Table } from "react-bootstrap" ;
33import DeleteItemDialog from "../DeleteItemDialog" ;
44import { injectIntl } from "react-intl" ;
55import withI18n from "../../i18n/withI18n" ;
66import RecordRow from "./RecordRow" ;
77import PropTypes from "prop-types" ;
88import { processTypeaheadOptions } from "./TypeaheadAnswer" ;
9- import { IfGranted } from "react-authorization" ;
10- import { ROLE } from "../../constants/DefaultConstants" ;
9+ import { COLUMNS } from "../../constants/DefaultConstants" ;
1110import DateIntervalFilter from "./filter/DateIntervalFilter" ;
1211import PhaseFilter from "./filter/PhaseFilter" ;
1312import InstitutionFilter from "./filter/InstitutionFilter" ;
@@ -17,125 +16,142 @@ import { useI18n } from "../../hooks/useI18n";
1716import FilterIndicator from "../misc/FilterIndicator" ;
1817import { sanitizeArray } from "../../utils/Utils" ;
1918
20- class RecordTable extends React . Component {
21- static propTypes = {
22- intl : PropTypes . shape ( {
23- messages : PropTypes . object ,
24- formatMessage : PropTypes . func ,
25- locale : PropTypes . string ,
26- } ) ,
27- i18n : PropTypes . func ,
28- recordsLoaded : PropTypes . object . isRequired ,
29- formTemplate : PropTypes . string ,
30- formTemplatesLoaded : PropTypes . object . isRequired ,
31- handlers : PropTypes . object . isRequired ,
32- recordDeleted : PropTypes . object ,
33- disableDelete : PropTypes . bool ,
34- currentUser : PropTypes . object . isRequired ,
35- filterAndSort : PropTypes . object . isRequired ,
36- } ;
19+ const RecordTable = ( {
20+ intl,
21+ i18n,
22+ recordsLoaded,
23+ formTemplate,
24+ formTemplatesLoaded,
25+ handlers,
26+ disableDelete = false ,
27+ currentUser,
28+ filterAndSort,
29+ visibleColumns,
30+ } ) => {
31+ const [ selectedRecord , setSelectedRecord ] = useState ( null ) ;
3732
38- static defaultProps = {
39- disableDelete : false ,
33+ const onDelete = ( record ) => {
34+ setSelectedRecord ( record ) ;
4035 } ;
4136
42- constructor ( props ) {
43- super ( props ) ;
44- this . i18n = this . props . i18n ;
45- this . state = {
46- showDialog : false ,
47- } ;
48- }
49-
50- _onDelete = ( record ) => {
51- this . setState ( { selectedRecord : record } ) ;
37+ const onCancelDelete = ( ) => {
38+ setSelectedRecord ( null ) ;
5239 } ;
5340
54- _onCancelDelete = ( ) => {
55- this . setState ( { selectedRecord : null } ) ;
41+ const onSubmitDelete = ( ) => {
42+ handlers . onDelete ( selectedRecord ) ;
43+ setSelectedRecord ( null ) ;
5644 } ;
5745
58- _onSubmitDelete = ( ) => {
59- this . props . handlers . onDelete ( this . state . selectedRecord ) ;
60- this . setState ( { selectedRecord : null } ) ;
46+ const getDeleteLabel = ( ) => {
47+ return selectedRecord ? selectedRecord . localName : "" ;
6148 } ;
6249
63- render ( ) {
64- const filteredRecords = this . _getFormTemplateRecords ( ) ;
65- return (
66- < div >
67- < DeleteItemDialog
68- onClose = { this . _onCancelDelete }
69- onSubmit = { this . _onSubmitDelete }
70- show = { this . state . selectedRecord !== null }
71- item = { this . state . selectedRecord }
72- itemLabel = { this . _getDeleteLabel ( ) }
73- />
74- < Table size = "sm" responsive striped bordered hover >
75- { this . _renderHeader ( ) }
76- < tbody > { this . _renderRows ( filteredRecords ) } </ tbody >
77- </ Table >
78- </ div >
79- ) ;
80- }
81-
82- _getDeleteLabel ( ) {
83- return this . state . selectedRecord ? this . state . selectedRecord . localName : "" ;
84- }
50+ const getFormTemplateRecords = ( ) => {
51+ const records = sanitizeArray ( recordsLoaded . records ) ;
52+ if ( ! formTemplate ) {
53+ return records ;
54+ }
55+ return records . filter ( ( r ) => r . formTemplate === formTemplate ) ;
56+ } ;
8557
86- _renderHeader ( ) {
87- const { filters, sort, onChange } = this . props . filterAndSort ;
58+ const renderHeader = ( ) => {
59+ const { filters, sort, onChange } = filterAndSort ;
8860 return (
8961 < thead >
9062 < tr >
91- < IfGranted expected = { ROLE . READ_ALL_RECORDS } actual = { this . props . currentUser . roles } >
92- < th className = "col-1 content-center" > { this . i18n ( "records.id" ) } </ th >
93- </ IfGranted >
94- < th className = "col-2 content-center" > { this . i18n ( "records.local-name" ) } </ th >
95- < IfGranted expected = { ROLE . READ_ALL_RECORDS } actual = { this . props . currentUser . roles } >
63+ { visibleColumns . includes ( COLUMNS . ID ) && < th className = "col-1 content-center" > { i18n ( "records.id" ) } </ th > }
64+ { visibleColumns . includes ( COLUMNS . NAME ) && (
65+ < th className = "col-2 content-center" > { i18n ( "records.local-name" ) } </ th >
66+ ) }
67+ { visibleColumns . includes ( COLUMNS . AUTHOR ) && (
68+ < th className = "col-2 content-center" > { i18n ( "records.author" ) } </ th >
69+ ) }
70+ { visibleColumns . includes ( COLUMNS . INSTITUTION ) && (
9671 < FilterableInstitutionHeader filters = { filters } onFilterChange = { onChange } />
72+ ) }
73+ { visibleColumns . includes ( COLUMNS . TEMPLATE ) && (
9774 < FilterableTemplateHeader filters = { filters } onFilterChange = { onChange } />
98- </ IfGranted >
99- < FilterableLastModifiedHeader filters = { filters } sort = { sort } onFilterAndSortChange = { onChange } />
100- < FilterablePhaseHeader filters = { filters } onFilterChange = { onChange } />
101- < th className = "col-1 content-center" > { this . i18n ( "actions" ) } </ th >
75+ ) }
76+ { visibleColumns . includes ( COLUMNS . LAST_MODIFIED ) && (
77+ < FilterableLastModifiedHeader filters = { filters } sort = { sort } onFilterAndSortChange = { onChange } />
78+ ) }
79+ { visibleColumns . includes ( COLUMNS . STATUS ) && (
80+ < FilterablePhaseHeader filters = { filters } onFilterChange = { onChange } />
81+ ) }
82+ < th className = "col-1 content-center" > { i18n ( "actions" ) } </ th >
10283 </ tr >
10384 </ thead >
10485 ) ;
105- }
86+ } ;
10687
107- _renderRows ( filteredRecords ) {
108- const { formTemplatesLoaded, handlers, intl } = this . props ;
88+ const renderRows = ( filteredRecords ) => {
10989 const formTemplateOptions = formTemplatesLoaded . formTemplates
11090 ? processTypeaheadOptions ( formTemplatesLoaded . formTemplates , intl )
11191 : [ ] ;
112- let rows = [ ] ;
113- for ( let i = 0 , len = filteredRecords . length ; i < len ; i ++ ) {
114- rows . push (
115- < RecordRow
116- key = { filteredRecords [ i ] . key }
117- record = { filteredRecords [ i ] }
118- onEdit = { handlers . onEdit }
119- onDelete = { this . _onDelete }
120- formTemplateOptions = { formTemplateOptions }
121- currentUser = { this . props . currentUser }
122- disableDelete = { this . props . disableDelete }
123- /> ,
124- ) ;
125- }
126- return rows ;
127- }
12892
129- _getFormTemplateRecords ( ) {
130- const records = sanitizeArray ( this . props . recordsLoaded . records ) ,
131- formTemplate = this . props . formTemplate ;
93+ return filteredRecords . map ( ( record ) => (
94+ < RecordRow
95+ key = { record . key }
96+ record = { record }
97+ onEdit = { handlers . onEdit }
98+ onDelete = { onDelete }
99+ formTemplateOptions = { formTemplateOptions }
100+ currentUser = { currentUser }
101+ disableDelete = { disableDelete }
102+ visibleColumns = { visibleColumns }
103+ />
104+ ) ) ;
105+ } ;
106+
107+ const filteredRecords = getFormTemplateRecords ( ) ;
132108
133- if ( ! formTemplate ) {
134- return records ;
135- }
136- return records . filter ( ( r ) => r . formTemplate === formTemplate ) ;
137- }
138- }
109+ return (
110+ < div >
111+ < DeleteItemDialog
112+ onClose = { onCancelDelete }
113+ onSubmit = { onSubmitDelete }
114+ show = { selectedRecord !== null }
115+ item = { selectedRecord }
116+ itemLabel = { getDeleteLabel ( ) }
117+ />
118+ < Table className = "mb-0" size = "sm" responsive striped bordered hover >
119+ { renderHeader ( ) }
120+ { recordsLoaded . records && recordsLoaded . records . length > 0 ? (
121+ < tbody > { renderRows ( filteredRecords ) } </ tbody >
122+ ) : null }
123+ </ Table >
124+
125+ { ( ! recordsLoaded . records || recordsLoaded . records . length === 0 ) && (
126+ < Alert variant = "warning" className = "w-100" >
127+ { i18n ( "records.no-records" ) }
128+ </ Alert >
129+ ) }
130+ </ div >
131+ ) ;
132+ } ;
133+
134+ RecordTable . propTypes = {
135+ intl : PropTypes . shape ( {
136+ messages : PropTypes . object ,
137+ formatMessage : PropTypes . func ,
138+ locale : PropTypes . string ,
139+ } ) ,
140+ i18n : PropTypes . func ,
141+ recordsLoaded : PropTypes . object . isRequired ,
142+ formTemplate : PropTypes . string ,
143+ formTemplatesLoaded : PropTypes . object . isRequired ,
144+ handlers : PropTypes . object . isRequired ,
145+ recordDeleted : PropTypes . object ,
146+ disableDelete : PropTypes . bool ,
147+ currentUser : PropTypes . object . isRequired ,
148+ filterAndSort : PropTypes . object . isRequired ,
149+ visibleColumns : PropTypes . array ,
150+ } ;
151+
152+ RecordTable . defaultProps = {
153+ disableDelete : false ,
154+ } ;
139155
140156const FilterableInstitutionHeader = ( { filters, onFilterChange } ) => {
141157 const { i18n } = useI18n ( ) ;
@@ -158,7 +174,7 @@ const FilterableInstitutionHeader = ({ filters, onFilterChange }) => {
158174 title = { i18n ( "table.column.filterable" ) }
159175 >
160176 { i18n ( "institution.panel-title" ) }
161- < FilterIndicator filterValue = { filters . institution } />
177+ { sanitizeArray ( filters . institution ) . length > 0 && < FilterIndicator filterValue = { filters . institution } /> }
162178 </ th >
163179 </ OverlayTrigger >
164180 ) ;
@@ -239,7 +255,7 @@ const FilterablePhaseHeader = ({ filters, onFilterChange }) => {
239255 >
240256 < th id = "records-phase" className = "col-1 content-center cursor-pointer" title = { i18n ( "table.column.filterable" ) } >
241257 { i18n ( "records.completion-status" ) }
242- < FilterIndicator filterValue = { filters . phase } />
258+ { sanitizeArray ( filters . phase ) . length > 0 && < FilterIndicator filterValue = { filters . phase } /> }
243259 </ th >
244260 </ OverlayTrigger >
245261 ) ;
@@ -273,7 +289,7 @@ const FilterableTemplateHeader = ({ filters, onFilterChange }) => {
273289 >
274290 < th id = "records-template" className = "col-2 content-center cursor-pointer" title = { i18n ( "table.column.filterable" ) } >
275291 { i18n ( "records.form-template" ) }
276- < FilterIndicator filterValue = { filters . formTemplate } />
292+ { sanitizeArray ( filters . formTemplate ) . length > 0 && < FilterIndicator filterValue = { filters . formTemplate } /> }
277293 </ th >
278294 </ OverlayTrigger >
279295 ) ;
0 commit comments