PluginProbe ʕ •ᴥ•ʔ
Everest Forms – Contact Form, Payment Form, Quiz, Survey & Custom Form Builder with AI / 3.5.2
Everest Forms – Contact Form, Payment Form, Quiz, Survey & Custom Form Builder with AI v3.5.2
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 / templates / components / PluginStatus.tsx
everest-forms / src / templates / components Last commit date
CreateFormCTA.tsx 2 weeks ago CreateWithAI.tsx 2 weeks ago Main.tsx 2 weeks ago PluginStatus.tsx 2 weeks ago Sidebar.tsx 2 weeks ago TemplateList.tsx 2 weeks ago TemplatesSkeleton.tsx 4 months ago
PluginStatus.tsx
245 lines
1 import React, { useEffect, useState } from "react";
2 import apiFetch from "@wordpress/api-fetch";
3 import {
4 Box,
5 Button,
6 Flex,
7 HStack,
8 Icon,
9 Spinner,
10 Text,
11 VStack,
12 useToast,
13 } from "@chakra-ui/react";
14 import { FiCheck, FiDownload, FiZap } from "react-icons/fi";
15 import { templatesScriptData } from "../utils/global";
16 import { __, sprintf } from '@wordpress/i18n';
17
18 interface PluginStatusProps {
19 requiredPlugins: { key: string; value: string }[];
20 onActivateAndContinue: () => void;
21 }
22
23 interface PluginStatusResponse {
24 success: boolean;
25 plugin_status: Record<string, string>;
26 message?: string;
27 }
28
29 const { restURL, security } = templatesScriptData;
30
31 const StatusBadge: React.FC<{ status: string | undefined }> = ({ status }) => {
32 if (!status) {
33 return <Spinner size="xs" color="#7545BB" thickness="2px" />;
34 }
35 if (status === 'active') {
36 return (
37 <HStack spacing="5px">
38 <Box w="6px" h="6px" borderRadius="full" bg="#22c55e" />
39 <Text fontSize="12px" fontWeight="500" color="#16a34a" margin="0">
40 {__('Active', 'everest-forms')}
41 </Text>
42 </HStack>
43 );
44 }
45 if (status === 'inactive') {
46 return (
47 <HStack spacing="5px">
48 <Box w="6px" h="6px" borderRadius="full" bg="#f59e0b" />
49 <Text fontSize="12px" fontWeight="500" color="#d97706" margin="0">
50 {__('Inactive', 'everest-forms')}
51 </Text>
52 </HStack>
53 );
54 }
55 if (status === 'not-installed') {
56 return (
57 <HStack spacing="5px">
58 <Box w="6px" h="6px" borderRadius="full" bg="#94a3b8" />
59 <Text fontSize="12px" fontWeight="500" color="#64748b" margin="0">
60 {__('Not installed', 'everest-forms')}
61 </Text>
62 </HStack>
63 );
64 }
65 if (status === 'error') {
66 return (
67 <HStack spacing="5px">
68 <Box w="6px" h="6px" borderRadius="full" bg="#ef4444" />
69 <Text fontSize="12px" fontWeight="500" color="#dc2626" margin="0">
70 {__('Error', 'everest-forms')}
71 </Text>
72 </HStack>
73 );
74 }
75 return null;
76 };
77
78 const PluginStatus: React.FC<PluginStatusProps> = ({
79 requiredPlugins,
80 onActivateAndContinue,
81 }) => {
82 const [pluginStatuses, setPluginStatuses] = useState<Record<string, string>>({});
83 const [loading, setLoading] = useState(false);
84 const [installInProgress, setInstallInProgress] = useState(false);
85 const [buttonState, setButtonState] = useState<'idle' | 'install' | 'activate' | 'continue'>('idle');
86 const toast = useToast();
87
88 useEffect(() => {
89 const fetchPluginStatus = async () => {
90 try {
91 const response = await apiFetch<PluginStatusResponse>({
92 path: `${restURL}everest-forms/v1/plugin/status`,
93 method: "GET",
94 headers: { "X-WP-Nonce": security },
95 });
96 if (response.success) {
97 setPluginStatuses(response.plugin_status);
98 deriveButtonState(response.plugin_status);
99 }
100 } catch {
101 toast({
102 title: __("Error", "everest-forms"),
103 description: __("Unable to check plugin status.", "everest-forms"),
104 status: "error", position: "bottom-right", duration: 5000, isClosable: true, variant: "subtle",
105 });
106 }
107 };
108 fetchPluginStatus();
109 }, []);
110
111 const deriveButtonState = (statuses: Record<string, string>) => {
112 const allActive = requiredPlugins.every(p => statuses[p.key] === 'active');
113 const anyNotInst = requiredPlugins.some(p => statuses[p.key] === 'not-installed');
114 const anyInactive = requiredPlugins.some(p => statuses[p.key] === 'inactive');
115
116 if (allActive) setButtonState('continue');
117 else if (anyNotInst) setButtonState('install');
118 else if (anyInactive) setButtonState('activate');
119 else setButtonState('continue');
120 };
121
122 const handleButtonClick = async () => {
123 if (buttonState === 'continue') {
124 onActivateAndContinue();
125 return;
126 }
127
128 setLoading(true);
129 setInstallInProgress(true);
130
131 let finalMessage = "";
132 for (const plugin of requiredPlugins) {
133 if (pluginStatuses[plugin.key] === 'active') continue;
134 try {
135 const response = (await apiFetch({
136 path: `${restURL}everest-forms/v1/plugin/activate`,
137 method: "POST",
138 body: JSON.stringify({
139 moduleData: [{ name: plugin.value, slug: plugin.key, type: "addon" }],
140 }),
141 headers: { "Content-Type": "application/json", "X-WP-Nonce": security },
142 })) as PluginStatusResponse;
143
144 if (response.success) {
145 setPluginStatuses(prev => ({ ...prev, [plugin.key]: 'active' }));
146 finalMessage = response.message || __("Plugin activated successfully.", "everest-forms");
147 } else {
148 setPluginStatuses(prev => ({ ...prev, [plugin.key]: 'error' }));
149 finalMessage = response.message || sprintf(__("Failed to activate: %s.", "everest-forms"), plugin.value);
150 }
151 } catch {
152 setPluginStatuses(prev => ({ ...prev, [plugin.key]: 'error' }));
153 finalMessage = sprintf(__("Unable to activate %s.", "everest-forms"), plugin.value);
154 }
155 }
156
157 setLoading(false);
158 setInstallInProgress(false);
159 setButtonState('continue');
160
161 toast({
162 title: __("Success", "everest-forms"),
163 description: finalMessage,
164 status: "success", position: "bottom-right", duration: 5000, isClosable: true, variant: "subtle",
165 });
166 };
167
168 const buttonConfig = {
169 install: { label: __('Install & Activate', 'everest-forms'), icon: FiDownload },
170 activate: { label: __('Activate', 'everest-forms'), icon: FiZap },
171 continue: { label: __('Continue', 'everest-forms'), icon: FiCheck },
172 idle: { label: __('Continue', 'everest-forms'), icon: FiCheck },
173 }[buttonState];
174
175 if (requiredPlugins.length === 0) return null;
176
177 return (
178 <VStack align="stretch" spacing="0">
179 {/* Addon rows */}
180 <VStack align="stretch" spacing="2px" mb="20px">
181 {requiredPlugins.map((plugin, i) => (
182 <Flex
183 key={plugin.key}
184 align="center"
185 justify="space-between"
186 px="14px"
187 py="12px"
188 bg={i % 2 === 0 ? '#fafafa' : 'white'}
189 border="1px solid #f1f5f9"
190 borderRadius={
191 i === 0
192 ? '10px 10px 0 0'
193 : i === requiredPlugins.length - 1
194 ? '0 0 10px 10px'
195 : '0'
196 }
197 borderTop={i > 0 ? 'none' : undefined}
198 >
199 <Text fontSize="14px" fontWeight="500" color="#374151" margin="0">
200 {plugin.value}
201 </Text>
202 <StatusBadge status={pluginStatuses[plugin.key]} />
203 </Flex>
204 ))}
205 </VStack>
206
207 {/* Action button */}
208 {buttonState !== 'idle' && (
209 <Box
210 as="button"
211 display="inline-flex"
212 alignItems="center"
213 justifyContent="center"
214 gap="8px"
215 alignSelf="flex-end"
216 h="40px"
217 px="20px"
218 borderRadius="8px"
219 bg={buttonState === 'continue' ? '#22c55e' : '#7545BB'}
220 color="white"
221 fontSize="14px"
222 fontWeight="500"
223 border="none"
224 cursor={loading || installInProgress ? 'not-allowed' : 'pointer'}
225 opacity={loading || installInProgress ? 0.75 : 1}
226 onClick={!loading && !installInProgress ? handleButtonClick : undefined}
227 transition="background 0.2s, opacity 0.2s"
228 _hover={{ bg: buttonState === 'continue' ? '#16a34a' : '#6a3daa' }}
229 >
230 {loading ? (
231 <Spinner size="xs" color="white" thickness="2px" />
232 ) : (
233 <Icon as={buttonConfig.icon} boxSize="4" />
234 )}
235 <Text margin="0" color="white">
236 {loading ? __('Processing…', 'everest-forms') : buttonConfig.label}
237 </Text>
238 </Box>
239 )}
240 </VStack>
241 );
242 };
243
244 export default PluginStatus;
245