PluginProbe ʕ •ᴥ•ʔ
GiveWP – Donation Plugin and Fundraising Platform / 2.12.2
GiveWP – Donation Plugin and Fundraising Platform v2.12.2
4.16.2 4.16.1 4.16.0 4.15.5 4.15.4 4.15.3 4.15.2 4.15.1 4.15.0 2.3.0 2.3.1 2.3.2 2.30.0 2.31.0 2.31.1 2.32.0 2.33.0 2.33.1 2.33.2 2.33.3 2.33.4 2.33.5 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.4.7 2.5.0 2.5.1 2.5.10 2.5.11 2.5.12 2.5.13 2.5.2 2.5.3 2.5.4 2.5.5 2.5.6 2.5.7 2.5.8 2.5.9 2.6.0 2.6.1 2.6.2 2.6.3 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.8.0 2.8.1 2.9.0 2.9.1 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.10.0 3.11.0 3.12.0 3.12.1 3.12.2 3.12.3 3.13.0 3.14.0 3.14.1 3.14.2 3.15.0 3.15.1 3.16.0 3.16.1 3.16.2 3.16.3 3.16.4 3.16.5 3.17.0 3.17.1 3.17.2 3.18.0 3.19.0 3.19.1 3.19.2 3.19.3 3.19.4 3.2.0 3.2.1 3.2.2 3.20.0 3.21.0 3.21.1 3.22.0 3.22.1 3.22.2 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.5.1 3.6.0 3.6.1 3.6.2 3.7.0 3.8.0 3.9.0 4.0.0 4.1.0 4.1.1 4.10.0 4.10.1 4.11.0 4.12.0 4.13.0 4.13.1 4.13.2 4.14.0 4.14.1 4.14.2 4.14.3 4.14.4 4.14.5 4.14.6 4.2.0 4.2.1 4.3.0 4.3.1 4.3.2 4.4.0 4.5.0 4.6.1 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 trunk 1.9.0 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.10.0 2.10.1 2.10.2 2.10.3 2.10.4 2.11.0 2.11.1 2.11.2 2.11.3 2.12.0 2.12.1 2.12.2 2.12.3 2.13.0 2.13.1 2.13.2 2.13.3 2.13.4 2.14.0 2.15.0 2.16.0 2.16.1 2.17.0 2.17.1 2.17.3 2.18.0 2.18.1 2.19.1 2.19.2 2.19.3 2.19.4 2.19.5 2.19.6 2.19.7 2.19.8 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.20.0 2.20.1 2.20.2 2.21.0 2.21.1 2.21.2 2.21.3 2.21.4 2.22.0 2.22.1 2.22.2 2.22.3 2.23.0 2.23.1 2.23.2 2.24.0 2.24.1 2.24.2 2.25.0 2.25.1 2.25.2 2.25.3 2.26.0 2.27.0 2.27.1 2.27.2 2.27.3 2.28.0 2.29.0 2.29.1 2.29.2
give / src / Views / Components / Table / index.js
give / src / Views / Components / Table Last commit date
index.js 5 years ago style.module.scss 5 years ago
index.js
181 lines
1 import { useState } from 'react';
2 import PropTypes from 'prop-types';
3 import classNames from 'classnames';
4 import { LoadingOverlay, Spinner } from '@givewp/components';
5
6 import styles from './style.module.scss';
7
8 const { __ } = wp.i18n;
9
10 const Table = ( { title, columns, data, columnFilters, stripped, isLoading, isSorting, ...rest } ) => {
11 const [ state, setState ] = useState( {} );
12 const [ cachedData, setCachedData ] = useState( [] );
13
14 Table.resetSortState = () => {
15 setState( {} );
16 };
17
18 // Clear cache if data is empty
19 if ( ! isLoading && ! data.length && cachedData.length ) {
20 setCachedData( [] );
21 } else if ( data.length && data !== cachedData ) {
22 // Cache data so we can show that under overlay while new data is fetching
23 setCachedData( data );
24 }
25
26 const visibleColumns = columns.filter( ( column ) => column.visible || column.visible === undefined );
27 const allowedColumns = visibleColumns.map( ( column ) => column.key );
28 // Get additional row columns added manually
29 const additionalColumns = visibleColumns
30 .filter( ( column ) => 'append' in column && column.append )
31 .map( ( column ) => {
32 return {
33 [ column.key ]: column.defaultValue ?? '',
34 };
35 } );
36
37 // Used when additional columns are added, but they not exist in the result row.
38 // So we have to sort result row to match columns order
39 const sortResults = ( order, object ) => {
40 const newObject = {};
41
42 order.forEach( ( key ) => {
43 newObject[ key ] = object[ key ];
44 } );
45 return newObject;
46 };
47
48 const handleItemSort = ( item ) => {
49 const direction = ( state[ item.label ] === 'desc' ) ? 'asc' : 'desc';
50
51 setState( { [ item.label ]: direction } );
52
53 return item.sortCallback( direction );
54 };
55
56 const getItemSortDirectionIcon = ( item ) => {
57 if ( ! state[ item.label ] ) {
58 return <span className={ classNames( 'dashicons dashicons-sort', styles.sortIcons, styles.sortIconUndefined ) } />;
59 }
60
61 const iconClasses = classNames(
62 'dashicons',
63 styles.sortIcons,
64 { 'dashicons-arrow-down': state[ item.label ] === 'desc' },
65 { 'dashicons-arrow-up': state[ item.label ] === 'asc' },
66 );
67
68 return <span className={ iconClasses } />;
69 };
70
71 const getHeaderRow = () => {
72 return visibleColumns.map( ( item, index ) => {
73 const columnStyles = ( item.styles ) ? { style: item.styles } : null;
74 return (
75 <div className={ styles.label } key={ index } { ...columnStyles }>
76 { item.label }
77 { item.sort && ( typeof item.sortCallback === 'function' ) && (
78 <span onClick={ () => handleItemSort( item ) }>
79 { getItemSortDirectionIcon( item ) }
80 </span>
81 ) }
82 { isLoading && isSorting && state[ item.label ] !== undefined && (
83 <Spinner size="tiny" style={ { marginLeft: 10 } } />
84 ) }
85 </div>
86 );
87 } );
88 };
89
90 const getRows = () => {
91 if ( ! isLoading && data.length === 0 ) {
92 return (
93 <div className={ styles.noData }>
94 { __( 'No data', 'give' ) }
95 </div>
96 );
97 }
98
99 if ( cachedData.length && isLoading ) {
100 data = cachedData;
101 }
102
103 return data.map( ( row, index ) => {
104 // Add additional row columns and sort the result row
105 const result = ( additionalColumns.length > 0 ) ? sortResults( allowedColumns, Object.assign( row, ...additionalColumns ) ) : row;
106 const RowItems = Object.entries( result )
107 // Display only provided columns
108 .filter( ( [ key ] ) => allowedColumns.includes( key ) )
109 .map( ( [ key, value ] ) => {
110 if ( columnFilters[ key ] && typeof columnFilters[ key ] === 'function' ) {
111 value = columnFilters[ key ]( value, data[ index ] );
112 }
113
114 const currentColumn = visibleColumns.find( ( column ) => column.key === key );
115 const columnStyles = ( currentColumn.styles ) ? { style: currentColumn.styles } : null;
116
117 return (
118 <div className={ styles.item } key={ key } { ...columnStyles }>
119 { value }
120 </div>
121 );
122 } );
123
124 const rowClasses = classNames(
125 'give-table-row',
126 { [ styles.rowStripped ]: stripped },
127 { [ styles.row ]: ! stripped },
128 );
129
130 return (
131 <div className={ rowClasses } key={ index }>
132 { RowItems }
133 </div>
134 );
135 } );
136 };
137
138 return (
139 <>
140 { isLoading && ! isSorting && (
141 <LoadingOverlay spinnerSize="small" />
142 ) }
143 { title && ( <div className={ styles.title }>
144 { title }
145 </div> ) }
146 <div className={ styles.table } { ...rest }>
147 <div className={ classNames( styles.header, { [ styles.headerStripped ]: stripped } ) }>
148 { getHeaderRow() }
149 </div>
150 { getRows() }
151 </div>
152 </>
153 );
154 };
155
156 Table.propTypes = {
157 // Table title
158 title: PropTypes.string,
159 // Columns to display
160 columns: PropTypes.array.isRequired,
161 // Table data rows
162 data: PropTypes.array.isRequired,
163 // Column filters
164 columnFilters: PropTypes.object,
165 // Stripped rows
166 stripped: PropTypes.bool,
167 // Show spinner if data is loading
168 isLoading: PropTypes.bool,
169 };
170
171 Table.defaultProps = {
172 title: null,
173 columns: [],
174 data: [],
175 columnFilters: {},
176 stripped: true,
177 isLoading: false,
178 };
179
180 export default Table;
181