PluginProbe ʕ •ᴥ•ʔ
Everest Forms – Contact Form, Payment Form, Quiz, Survey & Custom Form Builder with AI / 3.2.4
Everest Forms – Contact Form, Payment Form, Quiz, Survey & Custom Form Builder with AI v3.2.4
3.6.0 3.5.3 3.5.2 3.5.1 3.5.0 3.4.8 3.4.7 3.4.6 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.5.1 1.1.6 1.1.7 1.1.8 1.1.9 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.5.0 1.5.1 1.5.10 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.6.1 1.6.7 1.7.0 1.7.0.1 1.7.0.2 1.7.0.3 1.7.1 1.7.2 1.7.2.1 1.7.2.2 1.7.3 1.7.4 1.7.5 1.7.5.1 1.7.5.2 1.7.6 1.7.7 1.7.7.1 1.7.7.2 1.7.8 1.7.9 1.8.0 1.8.0.1 1.8.1 1.8.2 1.8.2.1 1.8.2.2 1.8.2.3 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 1.8.9 1.9.0 1.9.0.1 1.9.1 1.9.2 1.9.3 1.9.4 1.9.4.1 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0.0 2.0.0.1 2.0.1 2.0.2 2.0.3 2.0.3.1 2.0.4 2.0.4.1 2.0.5 2.0.6 2.0.7 2.0.8 2.0.8.1 2.0.9 3.0.0 3.0.0.1 3.0.1 3.0.2 3.0.3 3.0.3.1 3.0.4 3.0.4.1 3.0.4.2 3.0.5 3.0.5.1 3.0.5.2 3.0.6 3.0.6.1 3.0.7.1 3.0.8 3.0.8.1 3.0.9 3.0.9.1 3.0.9.2 3.0.9.3 3.0.9.4 3.0.9.5 3.1.0 3.1.1 3.1.2 3.2.0 3.2.1 3.2.2 3.2.3 3.2.4 3.2.5 3.2.6 3.3.0 3.4.0 3.4.1 3.4.2 3.4.2.1 3.4.3 3.4.4 3.4.5 trunk 1.0 1.0.1 1.0.2 1.0.3
everest-forms / src / dashboard / screens / Modules / Modules.js
everest-forms / src / dashboard / screens / Modules Last commit date
components 1 year ago Modules.js 1 year ago
Modules.js
427 lines
1 import React, { useContext, useEffect, useState, useCallback } from "react";
2 import {
3 Box,
4 Container,
5 Stack,
6 Select,
7 Tabs,
8 Tab,
9 TabList,
10 TabPanels,
11 TabPanel,
12 Button,
13 InputGroup,
14 InputLeftElement,
15 Input,
16 FormControl,
17 useToast,
18 Text
19 } from "@chakra-ui/react";
20 import { __ } from "@wordpress/i18n";
21 import {
22 getAllModules,
23 bulkActivateModules,
24 bulkDeactivateModules,
25 } from "./components/modules-api";
26 import ModuleBody from "./components/ModuleBody";
27 import AddonsSkeleton from "./../../skeleton/AddonsSkeleton/AddonsSkeleton";
28 import { Search } from "./../../components/Icon/Icon";
29 import dashboardReducer, {
30 actionTypes,
31 } from "./../../reducers/DashboardReducer";
32 import DashboardContext from "./../../context/DashboardContext";
33 import { debounce } from "lodash";
34
35 const Modules = () => {
36 const toast = useToast();
37 const [modules, setModules] = useState([]);
38 const [originalModules, setOriginalModules] = useState([]);
39 const [error, setError] = useState(null);
40 const [selectedModuleData, setSelectedModuleData] = useState("");
41 const [isSearching, setIsSearching] = useState(false);
42 const [tabIndex, setTabIndex] = useState(0);
43 const [isPerformingBulkAction, setIsPerformingBulkAction] = useState(false);
44 const [bulkAction, setBulkAction] = useState("");
45 const [modulesLoaded, setModulesLoaded] = useState(false);
46 const [{ allModules }, dispatch] = useContext(DashboardContext);
47 const [searchItem, setSearchItem] = useState('');
48 const [noItemFound, setNoItemFound] = useState(false);
49
50 const fetchModules = useCallback(() => {
51 getAllModules()
52 .then((data) => {
53 if (data.success) {
54 dispatch({
55 type: actionTypes.GET_ALL_MODULES,
56 allModules: data.modules_lists,
57 });
58
59 setOriginalModules(data.modules_lists);
60 filterModules(data.modules_lists);
61 setModulesLoaded(true);
62 }
63 })
64 .catch((error) => {
65 setError(error.message);
66 });
67 }, [dispatch, tabIndex]);
68
69 const filterModules = (modules) => {
70 let filteredModules = modules;
71
72 if (tabIndex === 1) {
73 filteredModules = modules.filter(module => module.type === "feature");
74 } else if (tabIndex === 2) {
75 filteredModules = modules.filter(module => module.type === "addon");
76 }
77
78 setModules(filteredModules);
79 setModulesLoaded(true);
80 };
81
82 useEffect(() => {
83 fetchModules();
84 }, [fetchModules]);
85
86 useEffect(() => {
87 if (error !== null) {
88 toast({
89 title: error,
90 status: "error",
91 duration: 3000,
92 });
93 }
94 }, [error]);
95
96 useEffect(() => {
97 filterModules(originalModules);
98 }, [tabIndex, originalModules]);
99
100 const handleBulkActions = () => {
101 setIsPerformingBulkAction(true);
102
103 const actionFunction = bulkAction === "activate" ? bulkActivateModules : bulkDeactivateModules;
104
105 actionFunction(selectedModuleData)
106 .then((data) => {
107 toast({
108 title: data.message,
109 status: data.success ? "success" : "error",
110 duration: 3000,
111 });
112 })
113 .catch((e) => {
114 toast({
115 title: e.message,
116 status: "error",
117 duration: 3000,
118 });
119 })
120 .finally(() => {
121 setIsPerformingBulkAction(false);
122 setSelectedModuleData({});
123 fetchModules();
124 });
125 };
126
127 const debounceSearch = debounce((val) => {
128 setIsSearching(true);
129
130 if (!val) {
131 filterModules(originalModules);
132 setIsSearching(false);
133 return;
134 }
135
136 let searchedData = [];
137
138 if (tabIndex === 1) {
139 searchedData = originalModules.filter(
140 (module) => module.type === "feature" && module.title.toLowerCase().includes(val.toLowerCase())
141 );
142 } else if (tabIndex === 2) {
143 searchedData = originalModules.filter(
144 (module) => module.type === "addon" && module.title.toLowerCase().includes(val.toLowerCase())
145 );
146 } else {
147 searchedData = originalModules.filter((module) => module.title.toLowerCase().includes(val.toLowerCase()));
148 }
149
150 if (searchedData.length > 0) {
151 setModules(searchedData);
152 setModulesLoaded(true);
153 setNoItemFound(false);
154 } else {
155 setModules([]);
156 setModulesLoaded(false);
157 setNoItemFound(true);
158 }
159
160 setIsSearching(false);
161 }, 800);
162
163 const handleSearchInputChange = (e) => {
164 const val = e.target.value;
165 setSearchItem(val);
166 debounceSearch(val);
167 };
168
169 const parseDate = (dateString) => {
170 const [day, month, year] = dateString.split("/").map(Number);
171 return new Date(year, month - 1, day);
172 };
173
174 const handleSorterChange = (sortType, data, setData) => {
175 switch (sortType) {
176 case "newest":
177 setData(
178 [...data].sort(
179 (firstAddonInContext, secondAddonInContext) =>
180 parseDate(secondAddonInContext.released_date) -
181 parseDate(firstAddonInContext.released_date)
182 )
183 );
184 break;
185 case "oldest":
186 setData(
187 [...data].sort(
188 (firstAddonInContext, secondAddonInContext) =>
189 parseDate(firstAddonInContext.released_date) -
190 parseDate(secondAddonInContext.released_date)
191 )
192 );
193 break;
194 case "asc":
195 setData(
196 [...data].sort(
197 (firstAddonInContext, secondAddonInContext) =>
198 firstAddonInContext.title.localeCompare(
199 secondAddonInContext.title
200 )
201 )
202 );
203 break;
204 case "desc":
205 setData(
206 [...data].sort(
207 (firstAddonInContext, secondAddonInContext) => secondAddonInContext.title.localeCompare(firstAddonInContext.title)
208 )
209 );
210 break;
211 default:
212 const sortedData = [...data].sort((firstAddonInContext, secondAddonInContext) => {
213 if ('popular_rank' in firstAddonInContext && 'popular_rank' in secondAddonInContext) {
214 return firstAddonInContext.popular_rank - secondAddonInContext.popular_rank;
215 } else if ('popular_rank' in firstAddonInContext) {
216 return -1;
217 } else if ('popular_rank' in secondAddonInContext) {
218 return 1;
219 } else {
220 return 0;
221 }
222 });
223 setData(sortedData);
224 }
225 };
226
227 return (
228 <Box top="var(--wp-admin--admin-bar--height, 0)" zIndex={1}>
229 <Container maxW="container.xl">
230 <Stack
231 direction="row"
232 minH="70px"
233 justify="space-between"
234 px="6"
235 >
236 <Stack direction="row" align="center" gap="5">
237 <Select
238 display="inline-flex"
239 alignItems="center"
240 size="md"
241 bg="#DFDFE0"
242 onChange={(e) => {
243 handleSorterChange(
244 e.target.value,
245 modules,
246 setModules
247 );
248 }}
249 border="1px solid #DFDFE0 !important"
250 borderRadius="4px !important"
251 icon=""
252 width="fit-content"
253 >
254 <option value="default">
255 {__("Popular", "everest-forms")}
256 </option>
257 <option value="newest">
258 {__("Newest", "everest-forms")}
259 </option>
260 <option value="oldest">
261 {__("Oldest", "everest-forms")}
262 </option>
263 <option value="asc">
264 {__("Ascending", "everest-forms")}
265 </option>
266 <option value="desc">
267 {__("Descending", "everest-forms")}
268 </option>
269 </Select>
270
271 <Tabs
272 index={tabIndex}
273 onChange={(index) => {
274 setTabIndex(index);
275 }}
276 >
277 <TabList>
278 <Tab
279 onClick={() => handleSearchInputChange({ target: { value: searchItem } })}
280 >
281 {__("All Modules", "everest-forms")}
282 </Tab>
283 <Tab
284 onClick={() => handleSearchInputChange({ target: { value: searchItem } })}
285 >
286 {__("Features", "everest-forms")}
287 </Tab>
288 <Tab
289 onClick={() => handleSearchInputChange({ target: { value: searchItem } })}
290 >
291 {__("Addons", "everest-forms")}
292 </Tab>
293 </TabList>
294 </Tabs>
295
296 <Box display="flex" gap="8px">
297 <Select
298 display="inline-flex"
299 alignItems="center"
300 size="md"
301 bg="#DFDFE0"
302 placeholder={__(
303 "Bulk Actions",
304 "everest-forms"
305 )}
306 onChange={(e) => setBulkAction(e.target.value)}
307 icon=""
308 width="fit-content"
309 border="1px solid #DFDFE0 !important"
310 borderRadius="4px !important"
311 >
312 <option value="activate">
313 {__("Activate", "everest-forms")}
314 </option>
315 <option value="deactivate">
316 {__("Deactivate", "everest-forms")}
317 </option>
318 </Select>
319
320 <Button
321 fontSize="14px"
322 variant="outline"
323 fontWeight="normal"
324 color="gray.600"
325 borderRadius="base"
326 border="1px solid #DFDFE0 !important"
327 textDecor="none !important"
328 padding="6px 12px"
329 onClick={handleBulkActions}
330 isLoading={isPerformingBulkAction}
331 >
332 {__("Apply", "everest-forms")}
333 </Button>
334 </Box>
335 </Stack>
336 <Stack direction="row" align="center" gap="7">
337 <FormControl>
338 <InputGroup>
339 <InputLeftElement
340 pointerEvents="none"
341 top="2px"
342 >
343 <Search h="5" w="5" color="gray.300" />
344 </InputLeftElement>
345 <Input
346 type="text"
347 placeholder={__(
348 "Search...",
349 "everest-forms"
350 )}
351 paddingLeft="32px !important"
352 value={searchItem} onChange={handleSearchInputChange}
353 />
354 </InputGroup>
355 </FormControl>
356 </Stack>
357 </Stack>
358 </Container>
359 <Container maxW="container.xl">
360 {
361 isSearching ? (
362 <AddonsSkeleton />
363 ) : (
364 noItemFound ? (
365 <Text
366 align="center"
367 fontSize="1.2rem"
368 bg="red"
369 color="white"
370 p={4}
371 m="5rem auto 0"
372 width="60%"
373 borderRadius="10px"
374 fontWeight="bold"
375 >
376 {(() => {
377 switch (tabIndex) {
378 case 1:
379 return __("Sorry, No features found", "everest-forms");
380 case 2:
381 return __("Sorry, No addons found", "everest-forms");
382 default:
383 return __("Sorry, No modules found", "everest-forms");
384 }
385 })()}
386 </Text>
387 ) : (
388 <Box>
389 <Tabs index={tabIndex}>
390 <TabPanels>
391 <TabPanel>
392 <ModuleBody
393 isPerformingBulkAction={isPerformingBulkAction}
394 filteredAddons={modules}
395 setSelectedModuleData={setSelectedModuleData}
396 selectedModuleData={selectedModuleData}
397 />
398 </TabPanel>
399 <TabPanel>
400 <ModuleBody
401 isPerformingBulkAction={isPerformingBulkAction}
402 filteredAddons={modules}
403 setSelectedModuleData={setSelectedModuleData}
404 selectedModuleData={selectedModuleData}
405 />
406 </TabPanel>
407 <TabPanel>
408 <ModuleBody
409 isPerformingBulkAction={isPerformingBulkAction}
410 filteredAddons={modules}
411 setSelectedModuleData={setSelectedModuleData}
412 selectedModuleData={selectedModuleData}
413 />
414 </TabPanel>
415 </TabPanels>
416 </Tabs>
417 </Box>
418 )
419 )
420 }
421 </Container>
422 </Box>
423 );
424 };
425
426 export default Modules;
427