PluginProbe ʕ •ᴥ•ʔ
GiveWP – Donation Plugin and Fundraising Platform / 2.22.3
GiveWP – Donation Plugin and Fundraising Platform v2.22.3
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 / index.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
index.tsx
235 lines
1 import {createContext, useRef, useState} from "react";
2 import {__} from "@wordpress/i18n";
3 import {A11yDialog} from "react-a11y-dialog";
4 import A11yDialogInstance from "a11y-dialog";
5
6 import {GiveIcon} from '@givewp/components';
7
8 import {ListTable, ListTableColumn} from './ListTable';
9 import Pagination from "./Pagination";
10 import {Filter, getInitialFilterState} from './Filters';
11 import useDebounce from "./hooks/useDebounce";
12 import {useResetPage} from "./hooks/useResetPage";
13 import ListTableApi from "./api";
14 import styles from './ListTablePage.module.scss';
15 import cx from "classnames";
16 import {BulkActionSelect} from "@givewp/components/ListTable/BulkActionSelect";
17
18 export interface ListTablePageProps {
19 //required
20 title: string;
21 columns: Array<ListTableColumn>;
22 apiSettings: {apiRoot, apiNonce};
23
24 //optional
25 bulkActions?: Array<BulkActionsConfig>|null;
26 pluralName?: string;
27 singleName?: string;
28 children?: JSX.Element|JSX.Element[]|null;
29 rowActions?: JSX.Element|JSX.Element[]|Function|null;
30 filterSettings?;
31 align?: 'start'|'center'|'end';
32 }
33
34 export interface FilterConfig {
35 // required
36 name: string;
37 type: 'select'|'formselect'|'search';
38
39 // optional
40 ariaLabel?: string;
41 inlineSize?: string;
42 text?: string;
43 options?: Array<{text:string, value:string}>
44 }
45
46 export interface BulkActionsConfig {
47 //required
48 label: string;
49 value: string|number;
50 action: (selected: Array<string|number>) => Promise<{errors: string|number, successes: string|number}>;
51 confirm: (selected: Array<string|number>, names?: Array<string>) => JSX.Element|JSX.Element[]|string;
52
53 //optional
54 isVisible?: (data, parameters) => Boolean;
55 type?: 'normal'|'warning'|'danger';
56 }
57
58 export const ShowConfirmModalContext = createContext((label, confirm, action, type=null) => {});
59 export const CheckboxContext = createContext(null);
60
61 export default function ListTablePage({
62 title,
63 columns,
64 apiSettings,
65 bulkActions = null,
66 filterSettings = [],
67 singleName = __('item', 'give'),
68 pluralName = __('items', 'give'),
69 rowActions = null,
70 children = null,
71 align = 'start',
72 }: ListTablePageProps) {
73 const [page, setPage] = useState<number>(1);
74 const [perPage, setPerPage] = useState<number>(30);
75 const [filters, setFilters] = useState(getInitialFilterState(filterSettings));
76 const [modalContent, setModalContent] = useState<{confirm, action, label, type?: 'normal'|'warning'|'danger'}>({
77 confirm: (selected)=>{},
78 action: (selected)=>{},
79 label: ''
80 });
81 const [selectedIds, setSelectedIds] = useState([]);
82 const [selectedNames, setSelectedNames] = useState([]);
83 const dialog = useRef() as {current: A11yDialogInstance};
84 const checkboxRefs = useRef([]);
85
86 const parameters = {
87 page,
88 perPage,
89 ...filters
90 };
91
92 const archiveApi = useRef(new ListTableApi(apiSettings)).current;
93
94 const {data, error, isValidating, mutate} = archiveApi.useListTable(parameters)
95
96 useResetPage(data, page, setPage, filters);
97
98 const handleFilterChange = (name, value) => {
99 setFilters(prevState => ({...prevState, [name]: value}));
100 }
101
102 const handleDebouncedFilterChange = useDebounce(handleFilterChange);
103
104 const showConfirmActionModal = (label, confirm, action, type:'normal'|'warning'|'danger'|null = null) => {
105 setModalContent({confirm, action, label, type});
106 dialog.current.show();
107 }
108
109 const openBulkActionModal = (event) => {
110 event.preventDefault();
111 const formData = new FormData(event.target);
112 const action = formData.get('giveListTableBulkActions');
113 const actionIndex = bulkActions.findIndex((config) => action == config.value);
114 if(actionIndex < 0) return;
115 const selected = [];
116 const names = [];
117 checkboxRefs.current.forEach((checkbox) => {
118 if(checkbox.checked){
119 selected.push(checkbox.dataset.id);
120 names.push(checkbox.dataset.name);
121 }
122 });
123 setSelectedIds(selected);
124 setSelectedNames(names);
125 if(selected.length){
126 setModalContent({...bulkActions[actionIndex]});
127 dialog.current.show();
128 }
129 }
130
131 const showPagination = () => (
132 <Pagination
133 currentPage={page}
134 totalPages={data ? data.totalPages : 1}
135 disabled={!data}
136 totalItems={data ? parseInt(data.totalItems) : -1}
137 setPage={setPage}
138 singleName={singleName}
139 pluralName={pluralName}
140 />
141 )
142
143 const PageActions = () => (
144 <div className={cx(styles.pageActions,
145 { [styles.alignEnd]: !bulkActions }
146 )}>
147 <BulkActionSelect parameters={parameters} data={data} bulkActions={bulkActions} showModal={openBulkActionModal}/>
148 {page && setPage && showPagination()}
149 </div>
150 );
151
152 return (
153 <>
154 <article className={styles.page}>
155 <header className={styles.pageHeader}>
156 <div className={styles.flexRow}>
157 <GiveIcon size={'1.875rem'}/>
158 <h1 className={styles.pageTitle}>{title}</h1>
159 </div>
160 {children &&
161 <div className={styles.flexRow}>
162 {children}
163 </div>
164 }
165 </header>
166 <section role='search' id={styles.searchContainer}>
167 {filterSettings.map(filter =>
168 <Filter
169 key={filter.name}
170 value={filters[filter.name]}
171 filter={filter}
172 onChange={handleFilterChange}
173 debouncedOnChange={handleDebouncedFilterChange}
174 />
175 )}
176 </section>
177 <div className={cx('wp-header-end', 'hidden')}/>
178 <div className={styles.pageContent}>
179 <PageActions/>
180 <CheckboxContext.Provider value={checkboxRefs}>
181 <ShowConfirmModalContext.Provider value={showConfirmActionModal}>
182 <ListTable
183 columns={columns}
184 singleName={singleName}
185 pluralName={pluralName}
186 title={title}
187 rowActions={rowActions}
188 parameters={parameters}
189 data={data}
190 error={error}
191 isLoading={isValidating}
192 align={align}
193 />
194 </ShowConfirmModalContext.Provider>
195 </CheckboxContext.Provider>
196 <PageActions/>
197 </div>
198 </article>
199 <A11yDialog
200 id='giveListTableModal'
201 dialogRef={instance => (dialog.current = instance)}
202 title={modalContent.label}
203 titleId={styles.modalTitle}
204 classNames={{
205 container: styles.container,
206 overlay: styles.overlay,
207 dialog: cx(styles.dialog, {
208 [styles.warning]: modalContent?.type === 'warning',
209 [styles.danger]: modalContent?.type === 'danger',
210 }),
211 closeButton: 'hidden',
212 }}
213 >
214 <div className={styles.modalContent}>
215 {modalContent?.confirm(selectedIds, selectedNames) || null}
216 </div>
217 <div className={styles.gutter}>
218 <button id={styles.cancel} onClick={(event) => dialog.current?.hide()}>
219 {__('Cancel', 'give')}
220 </button>
221 <button id={styles.confirm}
222 onClick={async (event) => {
223 dialog.current?.hide();
224 await modalContent.action(selectedIds);
225 await mutate();
226 }}
227 >
228 {__('Confirm', 'give')}
229 </button>
230 </div>
231 </A11yDialog>
232 </>
233 );
234 }
235