PluginProbe ʕ •ᴥ•ʔ
GiveWP – Donation Plugin and Fundraising Platform / 2.23.2
GiveWP – Donation Plugin and Fundraising Platform v2.23.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 / ListTable / ListTable.tsx
give / src / Views / Components / ListTable Last commit date
hooks 4 years ago images 4 years ago BulkActionCheckbox.tsx 4 years ago BulkActionSelect.module.scss 4 years ago BulkActionSelect.tsx 4 years ago Filters.tsx 4 years ago FormSelect.module.scss 4 years ago FormSelect.tsx 4 years ago Input.module.scss 4 years ago Input.tsx 4 years ago ListTable.module.scss 4 years ago ListTable.tsx 4 years ago ListTablePage.module.scss 3 years ago ListTableRows.module.scss 3 years ago ListTableRows.tsx 4 years ago Pagination.module.scss 4 years ago Pagination.tsx 4 years ago README.MD 4 years ago RowAction.module.scss 4 years ago RowAction.tsx 4 years ago Select.module.scss 4 years ago Select.tsx 4 years ago TableCell.module.scss 4 years ago TableCell.tsx 4 years ago TestLabel.module.scss 4 years ago TestLabel.tsx 4 years ago TypeBadge.module.scss 4 years ago TypeBadge.tsx 4 years ago api.ts 4 years ago index.tsx 4 years ago
ListTable.tsx
241 lines
1 import {useEffect, useRef, useState} from 'react';
2 import {__, _n, sprintf} from '@wordpress/i18n';
3 import cx from 'classnames';
4
5 import styles from './ListTable.module.scss';
6 import ListTableRows from './ListTableRows';
7 import {Spinner} from '../index';
8 import {BulkActionCheckboxAll} from "@givewp/components/ListTable/BulkActionCheckbox";
9
10 export interface ListTableProps {
11 //required
12 columns: Array<ListTableColumn>;
13 title: string;
14 data: {items: Array<{}>};
15
16 //optional
17 pluralName?: string;
18 singleName?: string;
19 rowActions?: (({item, data, addRow, removeRow}) => JSX.Element)|JSX.Element|JSX.Element[]|Function|null;
20 parameters?: {};
21 error?: {}|Boolean;
22 isLoading?: Boolean;
23 align?: 'start'|'center'|'end';
24 }
25
26 export interface ListTableColumn {
27 //required
28 name: string;
29 text: string;
30
31 //optional
32 inlineSize?: string;
33 preset?: string;
34 heading?: boolean;
35 alignColumn?: 'start'|'center'|'end';
36 addClass?: string;
37 render?: ((item: {}) => JSX.Element)|JSX.Element|JSX.Element[]|null;
38 }
39
40 export const ListTable = ({
41 columns,
42 singleName = __('item', 'give'),
43 pluralName = __('items', 'give'),
44 title,
45 data,
46 rowActions = null,
47 parameters = {},
48 error = false,
49 isLoading = false,
50 align = 'start',
51 }: ListTableProps) => {
52 const [updateErrors, setUpdateErrors] = useState<{errors: Array<number>, successes: Array<number>}>({errors: [], successes: []});
53 const [errorOverlay, setErrorOverlay] = useState<string|boolean>(false);
54 const [initialLoad, setInitialLoad] = useState<boolean>(true);
55 const [loadingOverlay, setLoadingOverlay] = useState<string|boolean>(false);
56 const [overlayWidth, setOverlayWidth] = useState(0);
57 const tableRef = useRef<null|HTMLTableElement>();
58 const isEmpty = !error && data?.items.length === 0;
59
60 useEffect(() => {
61 initialLoad && data && setInitialLoad(false);
62 }, [data]);
63
64 useEffect(() => {
65 if (isLoading) {
66 // we need to set the overlay width in JS because tables only respect 'position: relative' in FireFox
67 if(tableRef.current){
68 setOverlayWidth(tableRef.current.getBoundingClientRect().width);
69 }
70 setLoadingOverlay(styles.appear);
71 }
72 if (!isLoading && loadingOverlay) {
73 setLoadingOverlay(styles.disappear);
74 const timeoutId = setTimeout(() => setLoadingOverlay(false), 100);
75 return () => clearTimeout(timeoutId);
76 }
77 }, [isLoading]);
78
79 useEffect(() => {
80 let timeoutId;
81 if (updateErrors.errors.length) {
82 setErrorOverlay(styles.appear);
83 timeoutId = setTimeout(
84 () =>
85 document.getElementById(styles.updateError).scrollIntoView?.({behavior: 'smooth', block: 'center'}),
86 100
87 );
88 } else if (errorOverlay) {
89 setErrorOverlay(styles.disappear);
90 timeoutId = setTimeout(() => setErrorOverlay(false), 100);
91 }
92 return () => clearTimeout(timeoutId);
93 }, [updateErrors.errors]);
94
95 const clearUpdateErrors = () => {
96 setUpdateErrors({errors: [], successes: []})
97 }
98
99 return (
100 <>
101
102 {( initialLoad && !error ) ? (
103 <div className={styles.initialLoad}>
104 <div
105 role="dialog"
106 aria-labelledby="giveListTableLoadingMessage"
107 className={cx(styles.tableGroup)}
108 >
109 <Spinner size={'large'} />
110 <h2 id="giveListTableLoadingMessage">
111 {sprintf(__('Loading %s', 'give'), pluralName)}
112 </h2>
113 </div>
114 </div>
115 ) : (
116 <div
117 role="group"
118 aria-labelledby="giveListTableCaption"
119 aria-describedby="giveListTableMessage"
120 className={styles.tableGroup}
121 tabIndex={0}
122 >
123 {loadingOverlay && (
124 <div className={cx(styles.overlay, loadingOverlay)} style={{width: overlayWidth && overlayWidth + 'px'}}>
125 <Spinner size={'medium'} />
126 </div>
127 )}
128 <table ref={tableRef} className={styles.table}>
129 <caption id="giveListTableCaption" className={styles.tableCaption}>
130 {title}
131 </caption>
132 <thead>
133 <tr>
134 <th
135 scope="col"
136 aria-sort="none"
137 className={cx(styles.tableColumnHeader, styles.selectAll)}
138 data-column='select'
139 >
140 <BulkActionCheckboxAll pluralName={pluralName} data={data}/>
141 </th>
142 <>
143 {columns.map(column =>
144 <th
145 scope="col"
146 aria-sort="none"
147 className={cx(styles.tableColumnHeader,
148 {
149 [styles[align]]: !column?.alignColumn,
150 [styles.center]: column?.alignColumn === 'center',
151 [styles.start]: column?.alignColumn === 'start',
152 }
153 )}
154 data-column={column.name}
155 key={column.name}
156 style={{inlineSize: (column?.inlineSize || '8rem')}}
157 >
158 {column.text}
159 </th>
160 )}
161 </>
162 </tr>
163 </thead>
164 <tbody className={styles.tableContent}>
165 <ListTableRows
166 columns={columns}
167 data={data}
168 isLoading={isLoading}
169 singleName={singleName}
170 rowActions={rowActions}
171 parameters={parameters}
172 setUpdateErrors={setUpdateErrors}
173 align={align}
174 />
175 </tbody>
176 </table>
177 {errorOverlay && (
178 <div className={cx(styles.overlay, errorOverlay)}>
179 <div
180 id={styles.updateError}
181 role="dialog"
182 aria-labelledby="giveListTableErrorMessage"
183 >
184 {Boolean(updateErrors.successes.length) && (
185 <span>
186 {updateErrors.successes.length + ' ' +
187 // translators:
188 // Like '1 item was updated successfully'
189 // or '3 items were updated successfully'
190 _n(
191 sprintf('%s was updated successfully.', singleName),
192 sprintf('%s were updated successfully.', pluralName),
193 updateErrors.successes.length,
194 'give'
195 )
196 }
197 </span>
198 )}
199 <span id="giveListTableErrorMessage">
200 {updateErrors.errors.length +
201 ' ' +
202 _n(
203 `${singleName} couldn't be updated.`,
204 `${pluralName} couldn't be updated.`,
205 updateErrors.errors.length,
206 'give'
207 )}
208 </span>
209 <button
210 type="button"
211 className={cx('dashicons dashicons-dismiss', styles.dismiss)}
212 onClick={clearUpdateErrors}
213 >
214 <span className="give-visually-hidden">{__('dismiss', 'give')}</span>
215 </button>
216 </div>
217 </div>
218 )}
219 <div id="giveListTableMessage">
220 {isEmpty && (
221 <div role='status' className={styles.statusMessage}>
222 {sprintf(__('No %s found.', 'give'), pluralName)}
223 </div>
224 )}
225 {error && (
226 <>
227 <div role='alert' className={styles.statusMessage}>
228 {sprintf(__('There was a problem retrieving the %s.', 'give'), pluralName)}
229 </div>
230 <div className={styles.statusMessage}>
231 <a href={window.location.href.toString()}>{__('Click here to reload the page.', 'give')}</a>
232 </div>
233 </>
234 )}
235 </div>
236 </div>
237 )}
238 </>
239 );
240 }
241