PluginProbe ʕ •ᴥ•ʔ
Everest Forms – Contact Form, Payment Form, Quiz, Survey & Custom Form Builder with AI / 3.5.3
Everest Forms – Contact Form, Payment Form, Quiz, Survey & Custom Form Builder with AI v3.5.3
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 / SiteAssistant / SiteAssistant.tsx
everest-forms / src / dashboard / screens / SiteAssistant Last commit date
components 6 months ago SiteAssistant.tsx 2 months ago
SiteAssistant.tsx
1496 lines
1 /**
2 * External Dependencies
3 */
4 import {
5 Alert,
6 AlertIcon,
7 Box,
8 Button,
9 Collapse,
10 Container,
11 Divider,
12 Flex,
13 FormControl,
14 Grid,
15 Heading,
16 HStack,
17 Icon,
18 IconButton,
19 Image,
20 Input,
21 Link,
22 Spinner,
23 Stack,
24 Text,
25 useToast,
26 } from '@chakra-ui/react';
27 import {
28 useMutation,
29 useQueryClient,
30 UseQueryResult,
31 } from '@tanstack/react-query';
32 import apiFetch from '@wordpress/api-fetch';
33 import { __ } from '@wordpress/i18n';
34 import React, { useCallback, useEffect, useMemo, useState } from 'react';
35 import { BiChevronDown, BiChevronUp } from 'react-icons/bi';
36
37 /**
38 * Internal Dependencies
39 */
40 import {
41 Bulb,
42 DocsLines,
43 Headphones,
44 Star,
45 Team,
46 Video,
47 } from '../../components/Icon/Icon';
48 import applicationFormIcon from '../../images/icons/application-form.png';
49 import businessFormIcon from '../../images/icons/business-form.png';
50 import educationFormIcon from '../../images/icons/education-form.png';
51 import feedbackFormIcon from '../../images/icons/feedback-form.png';
52 import healthcareFormIcon from '../../images/icons/healthcare-form.png';
53 import informationFormIcon from '../../images/icons/infromation-form.png';
54 import SiteAssistantSkeleton from '../../skeleton/SiteAssistantSkeleton';
55 import {
56 docURL,
57 facebookGroup,
58 featureRequestURL,
59 submitReviewUrl,
60 ticketUrl,
61 } from '../../utils/constants';
62
63 interface SiteAssistantData {
64 skipped_steps: string[];
65 test_email_sent: boolean;
66 has_forms: boolean;
67 email_sent?: boolean;
68 last_form_email_status?: 'success' | 'failed' | '';
69 is_smtp_active?: boolean;
70 is_smart_smtp_installed?: boolean;
71 is_smart_smtp_active?: boolean;
72 }
73
74 interface ApiResponse {
75 success: boolean;
76 data: SiteAssistantData;
77 }
78
79 interface StepConfig {
80 id: string;
81 title: string;
82 isCompleted: (data: SiteAssistantData | undefined) => boolean;
83 }
84
85 interface Props {
86 siteAssistantQuery: UseQueryResult<any, any>;
87 }
88
89 const SmartSmtpIcon = () => (
90 <svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32" fill="none">
91 <path d="M10.3588 8.88574H28.2297V21.0705L10.3588 21.0705V8.88574Z" fill="url(#ss_g0)" stroke="url(#ss_g1)" strokeWidth="0.812315" />
92 <path d="M28.6358 21.4769L9.95259 8.47986V21.4769H28.6358Z" fill="url(#ss_g2)" />
93 <path d="M19.8124 15.1899L27.8234 8.48005L19.8124 3.30237L10.7648 8.48005L19.8124 15.1899Z" fill="url(#ss_g3)" stroke="url(#ss_g4)" strokeWidth="1.05601" />
94 <path d="M3.06884 16.2518L20.3557 16.2517L20.5126 27.9754H3.06884V16.2518Z" fill="url(#ss_g5)" stroke="url(#ss_g6)" strokeWidth="0.812315" />
95 <path d="M19.3879 16.1967H3.9625L11.3976 21.0705L19.3879 16.1967Z" fill="#0062CC" stroke="#0062CC" strokeWidth="0.812315" />
96 <path d="M27.896 9.03432L12.5214 23.2993L7.55934 19.2333L2.69446 15.8498L11.5771 20.6643L17.4664 16.6027L23.3557 12.5411L27.896 9.03432Z" fill="white" />
97 <defs>
98 <linearGradient id="ss_g0" x1="19.2942" y1="8.88574" x2="19.2942" y2="21.0705" gradientUnits="userSpaceOnUse"><stop offset="0.389" stopColor="#3395FF" /><stop offset="1" stopColor="#004A99" /></linearGradient>
99 <linearGradient id="ss_g1" x1="19.2942" y1="8.88574" x2="19.2942" y2="21.0705" gradientUnits="userSpaceOnUse"><stop stopColor="#3396FF" /><stop offset="1" stopColor="#004A99" /></linearGradient>
100 <linearGradient id="ss_g2" x1="9.95259" y1="8.47986" x2="19.6859" y2="20.3432" gradientUnits="userSpaceOnUse"><stop stopColor="#004A99" stopOpacity="0.76" /><stop offset="0.974" stopColor="#3395FF" /></linearGradient>
101 <linearGradient id="ss_g3" x1="19.2941" y1="1.16922" x2="19.2941" y2="14.9786" gradientUnits="userSpaceOnUse"><stop offset="0.404" stopColor="#3396FF" /><stop offset="0.759" stopColor="#004A99" /></linearGradient>
102 <linearGradient id="ss_g4" x1="19.2941" y1="1.16922" x2="19.2941" y2="14.9786" gradientUnits="userSpaceOnUse"><stop offset="0.4" stopColor="#3395FF" /><stop offset="0.76" stopColor="#004A99" /></linearGradient>
103 <linearGradient id="ss_g5" x1="11.5772" y1="15.7907" x2="11.5772" y2="27.9755" gradientUnits="userSpaceOnUse"><stop offset="0.344" stopColor="#3395FF" /><stop offset="0.939" stopColor="#004A99" /></linearGradient>
104 <linearGradient id="ss_g6" x1="11.5772" y1="15.7907" x2="11.5772" y2="27.9755" gradientUnits="userSpaceOnUse"><stop offset="0.364" stopColor="#3396FF" /><stop offset="1" stopColor="#004794" /></linearGradient>
105 </defs>
106 </svg>
107 );
108
109 const ExternalLinkIcon = () => (
110 <svg
111 xmlns="http://www.w3.org/2000/svg"
112 viewBox="0 0 14 14"
113 width="14"
114 height="14"
115 style={{ width: '14px', minWidth: '14px', height: '14px', display: 'inline-block', flex: '0 0 14px', marginRight: '6px', marginBottom: '-2px' }}
116 >
117 <path d="M1.167 11.083V4.667a1.75 1.75 0 0 1 1.75-1.75h3.5a.583.583 0 0 1 0 1.166h-3.5a.585.585 0 0 0-.584.584v6.416a.585.585 0 0 0 .584.584h6.416a.585.585 0 0 0 .584-.584v-3.5a.583.583 0 0 1 1.166 0v3.5a1.75 1.75 0 0 1-1.75 1.75H2.917a1.75 1.75 0 0 1-1.75-1.75M12.833 5.25a.583.583 0 1 1-1.166 0V3.157L6.247 8.58a.584.584 0 0 1-.826-.825l5.422-5.421H8.75a.583.583 0 1 1 0-1.166h3.5c.322 0 .583.26.583.583z" />
118 </svg>
119 );
120
121 const SendEmailIcon = () => (
122 <svg
123 xmlns="http://www.w3.org/2000/svg"
124 viewBox="0 0 14 14"
125 width="14"
126 height="14"
127 style={{ width: '14px', minWidth: '14px', height: '14px', display: 'inline-block', flex: '0 0 14px', marginRight: '6px' }}
128 >
129 <g clipPath="url(#send-clip)">
130 <path fill="currentColor" d="m12.613.584.122.019.12.035q.114.044.214.118l.094.081.08.094q.075.099.12.215l.034.119.019.122q.014.182-.048.353l.002.001-3.792 11.084a.876.876 0 0 1-1.581.162l-.059-.12-1.855-4.626-.055-.104a.6.6 0 0 0-.165-.165l-.104-.055-4.626-1.855a.875.875 0 0 1-.55-.834l.014-.133a.9.9 0 0 1 .156-.362L.84 4.63a.9.9 0 0 1 .335-.209L12.259.63v.002a.9.9 0 0 1 .354-.048M2.295 5.271l3.898 1.563a1.75 1.75 0 0 1 .899.81l.074.162 1.562 3.898 3.344-9.777z" />
131 <path fill="currentColor" d="M12.335.84a.584.584 0 0 1 .825.825L6.78 8.046a.584.584 0 0 1-.825-.825z" />
132 </g>
133 <defs>
134 <clipPath id="send-clip"><path d="M0 0h14v14H0z" /></clipPath>
135 </defs>
136 </svg>
137 );
138
139 const SiteAssistant: React.FC<Props> = ({ siteAssistantQuery }) => {
140 const dashboardData =
141 typeof _EVF_DASHBOARD_ !== 'undefined' ? _EVF_DASHBOARD_ : {};
142 const {
143 utmCampaign,
144 evfRestApiNonce,
145 restURL,
146 adminEmail,
147 adminURL,
148 isPro,
149 ajaxURL,
150 smartSmtpNonce,
151 } = dashboardData;
152
153 const toast = useToast();
154 const queryClient = useQueryClient();
155
156 const [open, setOpen] = useState<Record<string, boolean>>({});
157 const [testEmail, setTestEmail] = useState<string>(adminEmail || '');
158 const [isInstallingSmtp, setIsInstallingSmtp] = useState(false);
159 const [smtpLoadingPhase, setSmtpLoadingPhase] = useState<'installing' | 'activating' | null>(null);
160 const [smtpInstallError, setSmtpInstallError] = useState<string | null>(null);
161
162 const toggleOpen = useCallback((id: string) => {
163 setOpen((prev) => ({ ...prev, [id]: !prev[id] }));
164 }, []);
165
166 const handleConfigureRecaptcha = () => {
167 const settingsURL =
168 window._EVF_DASHBOARD_?.settingsURL ||
169 `${window.location.origin}/wp-admin/admin.php?page=evf-settings`;
170
171 window.open(`${settingsURL}&tab=recaptcha`, '_blank');
172 };
173
174 const handleOtherSpamFeatures = () => {
175 const settingsURL =
176 window._EVF_DASHBOARD_?.settingsURL ||
177 `${window.location.origin}/wp-admin/admin.php?page=evf-settings`;
178
179 window.open(`${settingsURL}&tab=recaptcha`, '_blank');
180 };
181
182 const { data: siteData, isLoading, error } = siteAssistantQuery;
183
184 const skipSpamProtectionMutation = useMutation({
185 mutationFn: async () => {
186 const response = await apiFetch({
187 path: `${restURL}everest-forms/v1/site-assistant/skip-setup`,
188 method: 'POST',
189 headers: {
190 'X-WP-Nonce': evfRestApiNonce,
191 },
192 data: {
193 step: 'spam_protection',
194 },
195 });
196 return response as ApiResponse;
197 },
198 onSuccess: (data) => {
199 queryClient.setQueryData(['siteAssistant'], data);
200 toast({
201 title: __('Success', 'everest-forms'),
202 description: __('Spam protection setup skipped.', 'everest-forms'),
203 status: 'success',
204 duration: 3000,
205 isClosable: true,
206 });
207 },
208 onError: (error: any) => {
209 console.error('Error skipping spam protection:', error);
210 toast({
211 title: __('Error', 'everest-forms'),
212 description:
213 error?.message ||
214 __('Failed to skip spam protection setup.', 'everest-forms'),
215 status: 'error',
216 duration: 3000,
217 isClosable: true,
218 });
219 },
220 });
221
222 const sendTestEmailMutation = useMutation({
223 mutationFn: async (email: string) => {
224 const response = await apiFetch({
225 path: `${restURL}everest-forms/v1/site-assistant/test-email`,
226 method: 'POST',
227 headers: {
228 'X-WP-Nonce': evfRestApiNonce,
229 },
230 data: {
231 email: email,
232 },
233 });
234 return response as ApiResponse;
235 },
236 onSuccess: (data) => {
237 queryClient.setQueryData(['siteAssistant'], (old: ApiResponse | undefined) => {
238 const prev = old?.data;
239 const incoming = data.data;
240 const merged: SiteAssistantData = {
241 ...prev,
242 ...incoming,
243 skipped_steps: incoming?.skipped_steps ?? prev?.skipped_steps ?? [],
244 test_email_sent:
245 incoming?.test_email_sent ?? prev?.test_email_sent ?? false,
246 has_forms: incoming?.has_forms ?? prev?.has_forms ?? false,
247 };
248 const next: ApiResponse = {
249 success: data.success ?? old?.success ?? true,
250 data: merged,
251 };
252 return next;
253 });
254 if (data?.data?.email_sent) {
255 toast({
256 title: __('Success', 'everest-forms'),
257 description: __(
258 "Test email sent successfully. Didn't receive it? Please check your Spam or Junk folder.",
259 'everest-forms',
260 ),
261 status: 'success',
262 duration: 3000,
263 isClosable: true,
264 });
265 } else {
266 toast({
267 title: __('Error', 'everest-forms'),
268 description: __(
269 'We could not send the test email. Please check your mail configuration.',
270 'everest-forms',
271 ),
272 status: 'error',
273 duration: 5000,
274 isClosable: true,
275 });
276 }
277 },
278 onError: (error: any) => {
279 console.error('Error sending test email:', error);
280 toast({
281 title: __('Error', 'everest-forms'),
282 description:
283 error?.message || __('Failed to send test email.', 'everest-forms'),
284 status: 'error',
285 duration: 3000,
286 isClosable: true,
287 });
288 },
289 });
290
291 const skipSendTestEmailMutation = useMutation({
292 mutationFn: async () => {
293 const response = await apiFetch({
294 path: `${restURL}everest-forms/v1/site-assistant/skip-setup`,
295 method: 'POST',
296 headers: {
297 'X-WP-Nonce': evfRestApiNonce,
298 },
299 data: {
300 step: 'send_test_email',
301 },
302 });
303 return response as ApiResponse;
304 },
305 onSuccess: (data) => {
306 queryClient.setQueryData(['siteAssistant'], data);
307 toast({
308 title: __('Success', 'everest-forms'),
309 description: __('Send test email step skipped.', 'everest-forms'),
310 status: 'success',
311 duration: 3000,
312 isClosable: true,
313 });
314 },
315 onError: (error: any) => {
316 console.error('Error skipping send test email:', error);
317 toast({
318 title: __('Error', 'everest-forms'),
319 description:
320 error?.message ||
321 __('Failed to skip send test email step.', 'everest-forms'),
322 status: 'error',
323 duration: 3000,
324 isClosable: true,
325 });
326 },
327 });
328
329 const assistantData = siteData?.data;
330 const mutationData = sendTestEmailMutation.data?.data;
331
332 const resolvedSmtpInstalled =
333 mutationData?.is_smart_smtp_installed ??
334 assistantData?.is_smart_smtp_installed;
335 const resolvedSmtpActive =
336 mutationData?.is_smtp_active ?? assistantData?.is_smtp_active;
337 const resolvedSmartSmtpPluginActive =
338 mutationData?.is_smart_smtp_active ?? assistantData?.is_smart_smtp_active;
339 const emailSentFromMutation = mutationData?.email_sent;
340 const testEmailSent =
341 emailSentFromMutation ?? assistantData?.test_email_sent ?? false;
342 const resolvedLastFormEmailStatus =
343 mutationData?.last_form_email_status ??
344 assistantData?.last_form_email_status ??
345 '';
346 const hasSuccessfulFormDelivery = resolvedLastFormEmailStatus === 'success';
347
348 // POST result is merged into the siteAssistant query cache. Mutation state can
349 // reset (remount, minified bundle timing) before the next paint, so do not rely
350 // on `sendTestEmailMutation.isSuccess` alone — `email_sent === false` on cached
351 // data matches the REST failure payload and the error toast branch.
352 const testEmailSendExplicitlyFailed =
353 (sendTestEmailMutation.isSuccess &&
354 mutationData != null &&
355 mutationData.email_sent !== true &&
356 mutationData.test_email_sent !== true) ||
357 assistantData?.email_sent === false;
358
359 const emailStatus: 'idle' | 'sent' | 'failed' = sendTestEmailMutation.isError
360 ? 'failed'
361 : testEmailSent || hasSuccessfulFormDelivery
362 ? 'sent'
363 : testEmailSendExplicitlyFailed
364 ? 'failed'
365 : resolvedLastFormEmailStatus === 'failed'
366 ? 'failed'
367 : 'idle';
368
369 const handleInstallSmtpPlugin = async () => {
370 const isInstallFlow = !resolvedSmtpInstalled;
371 setIsInstallingSmtp(true);
372 setSmtpLoadingPhase(isInstallFlow ? 'installing' : 'activating');
373 setSmtpInstallError(null);
374
375 let redirecting = false;
376 try {
377 const normalizedAdminUrl = (adminURL || '').endsWith('/')
378 ? (adminURL || '').slice(0, -1)
379 : adminURL || '';
380 const ajaxEndpoint = ajaxURL || `${normalizedAdminUrl}/admin-ajax.php`;
381 const formData = new FormData();
382 formData.append('action', 'everest_forms_install_and_activate_smart_smtp');
383 formData.append('security', smartSmtpNonce || '');
384 const response = await fetch(ajaxEndpoint, {
385 method: 'POST',
386 body: formData,
387 credentials: 'same-origin',
388 });
389 const result = await response.json();
390 if (result.success) {
391 // PHP installed+activated — switch to "Activating..." for the install flow
392 // and hold it for at least 800ms so the user can read it.
393 if (isInstallFlow) {
394 setSmtpLoadingPhase('activating');
395 await new Promise((r) => window.setTimeout(r, 800));
396 }
397 if (result.data?.redirection_url) {
398 // Redirect: skip cache updates — new page loads fresh data.
399 // Any setQueryData/invalidateQueries here triggers re-renders that
400 // flash the idle button state before the page unloads.
401 redirecting = true;
402 window.location.href = result.data.redirection_url;
403 } else {
404 // No redirect — update cache so UI reflects installed state.
405 queryClient.setQueryData(
406 ['siteAssistant'],
407 (old: ApiResponse | undefined) => {
408 const prev = old?.data;
409 return {
410 success: old?.success ?? true,
411 data: {
412 ...prev,
413 is_smart_smtp_installed: true,
414 is_smart_smtp_active: true,
415 skipped_steps: prev?.skipped_steps ?? [],
416 test_email_sent: prev?.test_email_sent ?? false,
417 has_forms: prev?.has_forms ?? false,
418 } as SiteAssistantData,
419 } as ApiResponse;
420 },
421 );
422 void queryClient.invalidateQueries({ queryKey: ['siteAssistant'] });
423 }
424 } else {
425 setSmtpInstallError(
426 result.data?.message ||
427 __('Installation failed. Please try manually.', 'everest-forms'),
428 );
429 }
430 } catch {
431 setSmtpInstallError(
432 __('Installation failed. Please try manually.', 'everest-forms'),
433 );
434 } finally {
435 if (!redirecting) {
436 setIsInstallingSmtp(false);
437 setSmtpLoadingPhase(null);
438 }
439 }
440 };
441
442 const handleSkipSpamProtection = () => {
443 skipSpamProtectionMutation.mutate();
444 };
445
446 const handleSendTestEmail = () => {
447 if (!testEmail || !testEmail.includes('@')) {
448 toast({
449 title: __('Invalid Email', 'everest-forms'),
450 description: __('Please enter a valid email address.', 'everest-forms'),
451 status: 'error',
452 duration: 3000,
453 isClosable: true,
454 });
455 return;
456 }
457 sendTestEmailMutation.mutate(testEmail);
458 };
459
460 const formCategories = [
461 {
462 name: __('Application Form', 'everest-forms'),
463 count: 15,
464 icon: applicationFormIcon,
465 slug: 'application',
466 },
467 {
468 name: __('Business Form', 'everest-forms'),
469 count: 2,
470 icon: businessFormIcon,
471 slug: 'bussiness',
472 },
473 {
474 name: __('Education Form', 'everest-forms'),
475 count: 2,
476 icon: educationFormIcon,
477 slug: 'education',
478 },
479 {
480 name: __('Information Form', 'everest-forms'),
481 count: 7,
482 icon: informationFormIcon,
483 slug: 'information',
484 },
485 {
486 name: __('Health Care Form', 'everest-forms'),
487 count: 1,
488 icon: healthcareFormIcon,
489 slug: 'healthcare',
490 },
491 {
492 name: __('Feedback Form', 'everest-forms'),
493 count: 8,
494 icon: feedbackFormIcon,
495 slug: 'feedback',
496 },
497 ];
498
499 const handleCreateNewForm = () => {
500 createBlankFormMutation.mutate(__('Untitled', 'everest-forms'));
501 };
502
503 const handleViewAllTemplates = () => {
504 const templatesURL = `${adminURL}admin.php?page=evf-builder&create-form=1`;
505 window.location.href = templatesURL;
506 };
507
508 const handleCategoryClick = (categorySlug: string) => {
509 const categoryURL = `${adminURL}admin.php?page=evf-builder&create-form=1&evf_template_category=${categorySlug}`;
510 window.location.href = categoryURL;
511 };
512
513 const skipCreateFormMutation = useMutation({
514 mutationFn: async () => {
515 const response = await apiFetch({
516 path: `${restURL}everest-forms/v1/site-assistant/skip-setup`,
517 method: 'POST',
518 headers: {
519 'X-WP-Nonce': evfRestApiNonce,
520 },
521 data: {
522 step: 'create_form',
523 },
524 });
525 return response as ApiResponse;
526 },
527 onSuccess: (data) => {
528 queryClient.setQueryData(['siteAssistant'], data);
529 toast({
530 title: __('Success', 'everest-forms'),
531 description: __('Form creation step skipped.', 'everest-forms'),
532 status: 'success',
533 duration: 3000,
534 isClosable: true,
535 });
536 },
537 onError: (error: any) => {
538 console.error('Error skipping create form:', error);
539 toast({
540 title: __('Error', 'everest-forms'),
541 description:
542 error?.message ||
543 __('Failed to skip create form step.', 'everest-forms'),
544 status: 'error',
545 duration: 3000,
546 isClosable: true,
547 });
548 },
549 });
550
551 const handleSkipCreateForm = () => {
552 skipCreateFormMutation.mutate();
553 };
554
555 const createBlankFormMutation = useMutation({
556 mutationFn: async (formName: string) => {
557 const response = await apiFetch({
558 path: `${restURL}everest-forms/v1/templates/create`,
559 method: 'POST',
560 body: JSON.stringify({
561 title: formName,
562 slug: 'blank_form',
563 }),
564 headers: {
565 'Content-Type': 'application/json',
566 'X-WP-Nonce': evfRestApiNonce,
567 },
568 });
569 return response as { success: boolean; data: { redirect: string } };
570 },
571 onSuccess: (response) => {
572 if (response.success && response.data) {
573 window.location.href = response.data.redirect;
574 }
575 },
576 onError: (error: any) => {
577 console.error('Error creating blank form:', error);
578 toast({
579 title: __('Error', 'everest-forms'),
580 description:
581 error?.message || __('Failed to create blank form.', 'everest-forms'),
582 status: 'error',
583 duration: 3000,
584 isClosable: true,
585 });
586 },
587 });
588
589 const renderCreateFormContent = () => (
590 <Stack
591 p="6"
592 gap="5"
593 bgColor="white"
594 borderRadius="base"
595 border="1px"
596 borderColor="gray.100"
597 overflow="hidden"
598 width="100%"
599 minWidth="0"
600 >
601 <HStack
602 justify={'space-between'}
603 cursor="pointer"
604 onClick={() => toggleOpen('createForm')}
605 >
606 <Heading as="h3" fontSize="19px" fontWeight="600" color="grey.500">
607 {__('Start Creating Forms', 'everest-forms')}
608 </Heading>
609 <IconButton
610 aria-label={'createForm'}
611 icon={
612 <Icon
613 as={open?.createForm ? BiChevronUp : BiChevronDown}
614 fontSize="2xl"
615 fill={open?.createForm ? 'primary.500' : 'black'}
616 />
617 }
618 cursor={'pointer'}
619 fontSize={'xl'}
620 size="sm"
621 boxShadow="none"
622 borderRadius="base"
623 variant={open?.createForm ? 'solid' : 'link'}
624 border="none"
625 bg={open?.createForm ? 'gray.100' : 'transparent'}
626 _hover={{
627 bg: open?.createForm ? 'gray.100' : 'inherit',
628 }}
629 pointerEvents="none"
630 />
631 </HStack>
632 <Collapse in={open?.createForm}>
633 <Stack gap={6}>
634 <Divider color={'gray.200'} />
635 <Text
636 fontSize="14px"
637 fontWeight="400"
638 color="grey.350"
639 lineHeight="19.3px"
640 >
641 {__(
642 'To get started quickly, you can create a new form from scratch or choose from the categories.',
643 'everest-forms',
644 )}
645 </Text>
646 <Button
647 width={'fit-content'}
648 colorScheme="primary"
649 onClick={handleCreateNewForm}
650 leftIcon={<Text fontSize="lg">+</Text>}
651 isLoading={createBlankFormMutation.isLoading}
652 loadingText={__('Creating...', 'everest-forms')}
653 >
654 {__('Create New Form', 'everest-forms')}
655 </Button>
656 <Box>
657 <HStack justify="space-between" mb={4}>
658 <Text
659 fontSize="12px"
660 fontWeight="600"
661 color="grey.300"
662 textTransform="uppercase"
663 letterSpacing="0.5px"
664 >
665 {__('CATEGORIES', 'everest-forms')}
666 </Text>
667 <Link
668 color="primary.500"
669 _hover={{
670 color: 'primary.600',
671 }}
672 textDecoration="underline"
673 onClick={handleViewAllTemplates}
674 cursor="pointer"
675 fontSize="sm"
676 >
677 {__('View All', 'everest-forms')}
678 </Link>
679 </HStack>
680 <Grid
681 templateColumns={{
682 base: '1fr',
683 md: 'repeat(2, 1fr)',
684 lg: 'repeat(3, 1fr)',
685 }}
686 gap={5}
687 >
688 {formCategories.map((category, index) => (
689 <Box
690 key={index}
691 px={4}
692 py={3}
693 border="1px"
694 borderColor="gray.200"
695 borderRadius="base"
696 _hover={{
697 borderColor: 'primary.500',
698 cursor: 'pointer',
699 }}
700 onClick={() => handleCategoryClick(category.slug)}
701 >
702 <HStack spacing={3}>
703 <Box p={3} bg={'primary.15'} rounded={'base'}>
704 <Image
705 src={category.icon}
706 alt={category.name}
707 boxSize="20px"
708 objectFit="contain"
709 />
710 </Box>
711 <Flex gap={1} direction={'column'}>
712 <Text
713 fontSize="14px"
714 fontWeight="600"
715 color="grey.400"
716 lineHeight="150%"
717 >
718 {category.name}
719 </Text>
720 <Text
721 fontSize="12px"
722 fontWeight="400"
723 color="grey.175"
724 lineHeight="150%"
725 textTransform="capitalize"
726 >
727 {category.count}{' '}
728 {category.count > 1
729 ? __('Templates', 'everest-forms')
730 : __('Template', 'everest-forms')}
731 </Text>
732 </Flex>
733 </HStack>
734 </Box>
735 ))}
736 </Grid>
737 </Box>
738 <Flex justify="flex-end">
739 <Link
740 fontSize="13px"
741 fontWeight="400"
742 color="grey.150"
743 letterSpacing="0.2px"
744 onClick={handleSkipCreateForm}
745 cursor="pointer"
746 opacity={skipCreateFormMutation.isLoading ? 0.6 : 1}
747 pointerEvents={skipCreateFormMutation.isLoading ? 'none' : 'auto'}
748 textDecor={'underline'}
749 >
750 {skipCreateFormMutation.isLoading
751 ? __('Skipping...', 'everest-forms')
752 : __('Skip Setup', 'everest-forms')}
753 </Link>
754 </Flex>
755 </Stack>
756 </Collapse>
757 </Stack>
758 );
759
760 const renderSendTestEmailContent = () => (
761 <Stack
762 p="6"
763 gap="5"
764 bgColor="white"
765 borderRadius="base"
766 border="1px"
767 borderColor="gray.100"
768 overflow="hidden"
769 width="100%"
770 minWidth="0"
771 borderTopWidth="2px"
772 borderTopColor="#7545BB"
773 borderStyle="solid"
774 >
775 <HStack
776 justify={'space-between'}
777 cursor="pointer"
778 onClick={() => toggleOpen('sendTestEmail')}
779 >
780 <HStack alignItems="center">
781 <Heading as="h3" fontSize="19px" fontWeight="600" color="grey.500">
782 {__('Send Test Email', 'everest-forms')}
783 <Box as="span" fontSize="inherit" fontWeight="inherit" color="inherit">
784 {' '}
785 <Box
786 as="span"
787 display="inline-flex"
788 alignItems="center"
789 justifyContent="center"
790 w="8px"
791 h="8px"
792 bg="7545BB"
793 borderRadius="full"
794 lineHeight="1"
795 verticalAlign="middle"
796 transform="translateY(-1px)"
797 >
798 </Box>
799 </Box>
800 </Heading>
801 </HStack>
802 <IconButton
803 aria-label={'sendTestEmail'}
804 icon={
805 <Icon
806 as={open?.sendTestEmail ? BiChevronUp : BiChevronDown}
807 fontSize="2xl"
808 fill={open?.sendTestEmail ? 'primary.500' : 'black'}
809 />
810 }
811 cursor={'pointer'}
812 fontSize={'xl'}
813 size="sm"
814 boxShadow="none"
815 borderRadius="base"
816 variant={open?.sendTestEmail ? 'solid' : 'link'}
817 border="none"
818 bg={open?.sendTestEmail ? 'gray.100' : 'transparent'}
819 _hover={{
820 bg: open?.sendTestEmail ? 'gray.100' : 'inherit',
821 }}
822 pointerEvents="none"
823 />
824 </HStack>
825 <Collapse in={open?.sendTestEmail}>
826 <Stack gap={5} minWidth="0" width="100%">
827 <Divider color={'gray.200'} />
828 {emailStatus === 'sent' && (
829 <Alert
830 status="success"
831 borderRadius="md"
832 border="1px"
833 borderColor="#389E2E !important"
834 borderStyle="solid"
835 fontSize="sm"
836 sx={{ backgroundColor: '#4CC74114 !important' }}
837 >
838 <AlertIcon />
839 <Text fontSize="sm" color="#389E2E!important">
840 {__(
841 'Test Email Sent Successfully - Your email delivery is working. Form notifications should reach your inbox reliably.',
842 'everest-forms',
843 )}
844 </Text>
845 </Alert>
846 )}
847 {emailStatus === 'failed' &&
848 (!resolvedSmartSmtpPluginActive || isInstallingSmtp) && (
849 <Box p={4} border="1px" borderColor="gray.200" borderRadius="md" bg="#007BFF0D">
850 <Flex justify="space-between" align="center" gap={4}>
851 <HStack align="flex-start" spacing={3} flex={1}>
852 <Box p={2} bg="primary.15" borderRadius="md" flexShrink={0} mt="1px" border="1px" borderColor="#EBEBEB">
853 <SmartSmtpIcon />
854 </Box>
855 <Box>
856 <Text fontSize="sm" fontWeight="600" color="grey.500">
857 {__('Having trouble sending emails?', 'everest-forms')}
858 </Text>
859 <HStack spacing={2} mb={1}>
860 <Text fontSize="xs" color="grey.350" lineHeight="1.5">
861 {__(
862 'SmartSMTP helps your website send emails more reliably.',
863 'everest-forms',
864 )}
865 </Text>
866 <Link href="https://wordpress.org/plugins/smart-smtp/" isExternal color="primary.500" fontSize="sm">
867 <ExternalLinkIcon />
868 </Link>
869 </HStack>
870 {smtpInstallError && (
871 <Text fontSize="xs" color="red.500" mt={1}>
872 {smtpInstallError}
873 </Text>
874 )}
875 </Box>
876 </HStack>
877 <Button
878 bgColor="#007BFF !important"
879 color="white"
880 size="sm"
881 onClick={handleInstallSmtpPlugin}
882 isDisabled={isInstallingSmtp}
883 leftIcon={isInstallingSmtp ? <Spinner size="xs" /> : undefined}
884 flexShrink={0}
885 >
886 {isInstallingSmtp
887 ? smtpLoadingPhase === 'activating'
888 ? __('Activating...', 'everest-forms')
889 : __('Installing...', 'everest-forms')
890 : resolvedSmtpInstalled
891 ? __('Activate SmartSMTP', 'everest-forms')
892 : __('Install & Activate SmartSMTP', 'everest-forms')}
893 </Button>
894 </Flex>
895 </Box>
896 )}
897 <HStack align="flex-start" gap={3}>
898 <Text
899 fontSize="14px"
900 fontWeight="400"
901 color="grey.350"
902 lineHeight="19.3px"
903 >
904 {__(
905 "Verify that your site can send emails. Enter your address and we'll send a quick test.",
906 'everest-forms',
907 )}
908 </Text>
909 </HStack>
910
911 <FormControl
912 width="100%"
913 maxWidth="100%"
914 sx={{ overflow: 'hidden' }}
915 padding="0px 1px"
916 >
917 <Box marginBottom="12px">
918 <Text
919 fontSize="14px"
920 fontWeight="600"
921 color="grey.500"
922 whiteSpace="nowrap"
923 flexShrink={0}
924 >
925 {__('Your Email Address', 'everest-forms')}
926 </Text>
927 </Box>
928 <Flex display="flex" gap={3} align="center" direction="row" width="100%">
929
930 <Input
931 placeholder={__(
932 'Enter the address where the test email should be delivered.',
933 'everest-forms',
934 )}
935 type="email"
936 bgColor="#ECECF033 !important"
937 value={testEmail}
938 onChange={(e) => setTestEmail(e.target.value)}
939 isDisabled={sendTestEmailMutation.isLoading}
940 onKeyDown={(e) => {
941 if (e.key === 'Enter') {
942 e.preventDefault();
943 handleSendTestEmail();
944 }
945 }}
946 sx={{
947 padding: '0 12px !important',
948 paddingRight: '12px !important',
949 boxSizing: 'border-box !important',
950 width: '100% !important',
951 maxWidth: '100% !important',
952 border: '1px solid #e1e1e1 !important',
953 fontSize: '14px !important',
954 '&:focus, &:focus-visible': {
955 outline: 'none !important',
956 boxShadow: 'none !important',
957 borderColor: '#e1e1e1 !important',
958 },
959 }}
960 outline="none"
961 outlineOffset="0"
962 _focus={{
963 boxShadow: 'none !important',
964 outline: 'none !important',
965 }}
966 _focusVisible={{
967 boxShadow: 'none !important',
968 outline: 'none !important',
969 }}
970 />
971 <Button
972 width={'fit-content'}
973 colorScheme="primary"
974 fontSize="13px" fontWeight="500"
975 onClick={handleSendTestEmail}
976 isLoading={sendTestEmailMutation.isLoading}
977 loadingText={__('Sending...', 'everest-forms')}
978 >
979 <SendEmailIcon />
980 {__('Send Test Email', 'everest-forms')}
981 </Button>
982 </Flex>
983 </FormControl>
984
985 <Flex justifyContent="flex-end">
986
987 <Link
988 fontSize="13px"
989 fontWeight="400"
990 color="grey.150"
991 letterSpacing="0.2px"
992 onClick={() => skipSendTestEmailMutation.mutate()}
993 cursor="pointer"
994 opacity={skipSendTestEmailMutation.isLoading ? 0.6 : 1}
995 pointerEvents={
996 skipSendTestEmailMutation.isLoading ? 'none' : 'auto'
997 }
998 textDecor={'underline'}
999 >
1000 {skipSendTestEmailMutation.isLoading
1001 ? __('Skipping...', 'everest-forms')
1002 : __('Skip Setup', 'everest-forms')}
1003 </Link>
1004 </Flex>
1005 </Stack>
1006 </Collapse>
1007 </Stack>
1008 );
1009
1010 useEffect(() => {
1011 if (adminEmail) {
1012 setTestEmail(adminEmail);
1013 }
1014 }, [adminEmail]);
1015
1016 const renderSpamProtectionContent = () => (
1017 <Stack
1018 p="6"
1019 gap="5"
1020 bgColor="white"
1021 borderRadius="base"
1022 border="1px"
1023 borderColor="gray.100"
1024 overflow="hidden"
1025 width="100%"
1026 minWidth="0"
1027 >
1028 <HStack
1029 justify={'space-between'}
1030 cursor="pointer"
1031 onClick={() => toggleOpen('spamProtection')}
1032 >
1033 <HStack alignItems="center">
1034 <Heading as="h3" fontSize="19px" fontWeight="600" color="grey.500">
1035 {__('Spam Protection', 'everest-forms')}
1036 </Heading>
1037 </HStack>
1038 <IconButton
1039 aria-label={'spamProtection'}
1040 icon={
1041 <Icon
1042 as={open?.spamProtection ? BiChevronUp : BiChevronDown}
1043 fontSize="2xl"
1044 fill={open?.spamProtection ? 'primary.500' : 'black'}
1045 />
1046 }
1047 cursor={'pointer'}
1048 fontSize={'xl'}
1049 size="sm"
1050 boxShadow="none"
1051 borderRadius="base"
1052 variant={open?.spamProtection ? 'solid' : 'link'}
1053 border="none"
1054 bg={open?.spamProtection ? 'gray.100' : 'transparent'}
1055 _hover={{
1056 bg: open?.spamProtection ? 'gray.100' : 'inherit',
1057 }}
1058 pointerEvents="none"
1059 />
1060 </HStack>
1061 <Collapse in={open?.spamProtection}>
1062 <Stack gap={5}>
1063 <Divider color={'gray.200'} />
1064 <Text
1065 fontSize="14px"
1066 fontWeight="400"
1067 color="grey.350"
1068 lineHeight="19.3px"
1069 >
1070 {__(
1071 'Set up protection against spam submissions. We recommend enabling reCaptcha v2.',
1072 'everest-forms',
1073 )}
1074 </Text>
1075 <Flex
1076 bg="#f9fafc"
1077 p="4"
1078 borderRadius="md"
1079 justify="space-between"
1080 align="center"
1081 >
1082 <Box>
1083 <Text fontSize={'15px'} fontWeight="bold" mb={1}>
1084 {__('reCaptcha v2', 'everest-forms')}
1085 </Text>
1086 <Text fontSize="14px" color="grey.600">
1087 {__('Enable Google reCaptcha protection', 'everest-forms')}
1088 </Text>
1089 </Box>
1090 <Link
1091 color="primary.500"
1092 textDecoration="underline"
1093 onClick={handleConfigureRecaptcha}
1094 cursor="pointer"
1095 >
1096 {__('Configure Settings', 'everest-forms')}
1097 </Link>
1098 </Flex>
1099 <HStack justifyContent="space-between" alignItems={'flex-end'}>
1100 <Text color="grey.600" fontSize="14px">
1101 {__(
1102 'You can also set up other spam protection features from ',
1103 'everest-forms',
1104 )}
1105 <Link
1106 color="primary.500"
1107 textDecoration="underline"
1108 onClick={handleOtherSpamFeatures}
1109 cursor="pointer"
1110 >
1111 {__('here', 'everest-forms')}
1112 </Link>
1113 .
1114 </Text>
1115 <Link
1116 fontSize="13px"
1117 fontWeight="400"
1118 color="grey.150"
1119 letterSpacing="0.2px"
1120 onClick={handleSkipSpamProtection}
1121 cursor="pointer"
1122 width="fit-content"
1123 opacity={skipSpamProtectionMutation.isLoading ? 0.6 : 1}
1124 pointerEvents={
1125 skipSpamProtectionMutation.isLoading ? 'none' : 'auto'
1126 }
1127 textDecor={'underline'}
1128 >
1129 {skipSpamProtectionMutation.isLoading
1130 ? __('Skipping...', 'everest-forms')
1131 : __('Skip Setup', 'everest-forms')}
1132 </Link>
1133 </HStack>
1134 </Stack>
1135 </Collapse>
1136 </Stack>
1137 );
1138
1139 const stepsConfig: StepConfig[] = useMemo(() => {
1140 const steps: StepConfig[] = [];
1141
1142 if (!siteData?.data?.has_forms) {
1143 steps.push({
1144 id: 'createForm',
1145 title: __('Start Creating Forms', 'everest-forms'),
1146 isCompleted: (data) =>
1147 !!data?.skipped_steps?.includes('create_form') || !!data?.has_forms,
1148 });
1149 }
1150
1151 steps.push(
1152 {
1153 id: 'sendTestEmail',
1154 title: __('Send Test Email', 'everest-forms'),
1155 isCompleted: (data) =>
1156 !!data?.test_email_sent ||
1157 !!data?.skipped_steps?.includes('send_test_email') ||
1158 data?.last_form_email_status === 'success',
1159 },
1160 {
1161 id: 'spamProtection',
1162 title: __('Spam Protection', 'everest-forms'),
1163 isCompleted: (data) =>
1164 !!data?.skipped_steps?.includes('spam_protection'),
1165 },
1166 );
1167
1168 return steps;
1169 }, [siteData?.data?.has_forms]);
1170
1171 const visibleSteps = useMemo(() => {
1172 return stepsConfig.filter((step) => !step.isCompleted(siteData?.data));
1173 }, [stepsConfig, siteData]);
1174
1175 const firstStepId = visibleSteps.length > 0 ? visibleSteps[0].id : null;
1176
1177 useEffect(() => {
1178 if (firstStepId && open[firstStepId] === undefined) {
1179 setOpen((prev) => ({ ...prev, [firstStepId]: true }));
1180 }
1181 }, [firstStepId]);
1182
1183 useEffect(() => {
1184 if (!isLoading && siteData && visibleSteps.length === 0) {
1185 let cleanURL = adminURL || '';
1186 if (cleanURL.endsWith('/')) cleanURL = cleanURL.slice(0, -1);
1187 if (cleanURL.endsWith('/admin.php')) cleanURL = cleanURL.slice(0, -10);
1188 const targetPage = isPro ? 'evf-analytics' : 'evf-entries';
1189 window.location.href = `${cleanURL}/admin.php?page=${targetPage}`;
1190 }
1191 }, [visibleSteps.length, isLoading, siteData]);
1192
1193 if (isLoading) {
1194 return <SiteAssistantSkeleton />;
1195 }
1196
1197 return (
1198 <Container maxW="full" py={10}>
1199 <Grid
1200 gridGap="5"
1201 gridTemplateColumns={{
1202 sm: '1fr',
1203 md: '2fr 2fr',
1204 lg: '3fr 2fr',
1205 xl: '3fr 1fr',
1206 }}
1207 >
1208 <Stack gap="6">
1209 {visibleSteps.map((step) => (
1210 <React.Fragment key={step.id}>
1211 {step.id === 'createForm' && renderCreateFormContent()}
1212 {step.id === 'sendTestEmail' && renderSendTestEmailContent()}
1213 {step.id === 'spamProtection' && renderSpamProtectionContent()}
1214 </React.Fragment>
1215 ))}
1216 </Stack>
1217
1218 <Stack gap="5">
1219 <Stack
1220 p="4"
1221 gap="3"
1222 bgColor="white"
1223 borderRadius="base"
1224 border="1px"
1225 borderColor="gray.100"
1226 >
1227 <HStack gap="2">
1228 <Icon as={Team} fontSize={'xl'} fill="primary.400" />
1229 <Heading
1230 as="h3"
1231 fontSize="16px"
1232 fontWeight="600"
1233 color="grey.400"
1234 lineHeight="150%"
1235 >
1236 {__('Everest Forms Community', 'everest-forms')}
1237 </Heading>
1238 </HStack>
1239 <Text
1240 fontSize="13px"
1241 fontWeight="400"
1242 color="grey.300"
1243 lineHeight="19.3px"
1244 mt="12px"
1245 >
1246 {__(
1247 'Join our exclusive group and connect with fellow Everest Forms members. Ask questions, contribute to discussions, and share feedback!',
1248 'everest-forms',
1249 )}
1250 </Text>
1251 <Link
1252 fontSize="13px"
1253 fontWeight="400"
1254 color="primary.400"
1255 letterSpacing="0.2px"
1256 textDecoration="underline"
1257 href={facebookGroup}
1258 isExternal
1259 mt="20px"
1260 >
1261 {__('Join our Facebook Group', 'everest-forms')}
1262 </Link>
1263 </Stack>
1264 <Stack
1265 p="4"
1266 gap="3"
1267 bgColor="white"
1268 borderRadius="base"
1269 border="1px"
1270 borderColor="gray.100"
1271 >
1272 <HStack gap="2">
1273 <Icon as={DocsLines} fontSize={'xl'} fill="primary.400" />
1274 <Heading
1275 as="h3"
1276 fontSize="16px"
1277 fontWeight="600"
1278 color="grey.400"
1279 lineHeight="150%"
1280 >
1281 {__('Getting Started', 'everest-forms')}
1282 </Heading>
1283 </HStack>
1284 <Text
1285 fontSize="13px"
1286 fontWeight="400"
1287 color="grey.300"
1288 lineHeight="19.3px"
1289 mt="12px"
1290 >
1291 {__(
1292 'Check our documentation for detailed information on Everest Forms features and how to use them.',
1293 'everest-forms',
1294 )}
1295 </Text>
1296 <Link
1297 fontSize="13px"
1298 fontWeight="400"
1299 color="primary.400"
1300 letterSpacing="0.2px"
1301 textDecoration="underline"
1302 href={docURL}
1303 isExternal
1304 mt="20px"
1305 >
1306 {__('View Documentation', 'everest-forms')}
1307 </Link>
1308 </Stack>
1309 <Stack
1310 p="4"
1311 gap="3"
1312 bgColor="white"
1313 borderRadius="base"
1314 border="1px"
1315 borderColor="gray.100"
1316 >
1317 <HStack gap="2">
1318 <Icon as={Headphones} fontSize={'xl'} fill="primary.400" />
1319 <Heading
1320 as="h3"
1321 fontSize="16px"
1322 fontWeight="600"
1323 color="grey.400"
1324 lineHeight="150%"
1325 >
1326 {__('Support', 'everest-forms')}
1327 </Heading>
1328 </HStack>
1329 <Text
1330 fontSize="13px"
1331 fontWeight="400"
1332 color="grey.300"
1333 lineHeight="19.3px"
1334 mt="12px"
1335 >
1336 {__(
1337 'Submit a ticket for encountered issues and get help from our support team instantly.',
1338 'everest-forms',
1339 )}
1340 </Text>
1341 <Link
1342 fontSize="13px"
1343 fontWeight="400"
1344 color="primary.400"
1345 letterSpacing="0.2px"
1346 textDecoration="underline"
1347 href={ticketUrl}
1348 isExternal
1349 mt="20px"
1350 >
1351 {__('Create a Ticket', 'everest-forms')}
1352 </Link>
1353 </Stack>
1354 <Stack
1355 p="4"
1356 gap="3"
1357 bgColor="white"
1358 borderRadius="base"
1359 border="1px"
1360 borderColor="gray.100"
1361 >
1362 <HStack gap="2">
1363 <Icon as={Bulb} fontSize={'xl'} fill="primary.400" />
1364 <Heading
1365 as="h3"
1366 fontSize="16px"
1367 fontWeight="600"
1368 color="grey.400"
1369 lineHeight="150%"
1370 >
1371 {__('Feature Request', 'everest-forms')}
1372 </Heading>
1373 </HStack>
1374 <Text
1375 fontSize="13px"
1376 fontWeight="400"
1377 color="grey.300"
1378 lineHeight="19.3px"
1379 mt="12px"
1380 >
1381 {__(
1382 "Don't find a feature you're looking for? Suggest any features you think would enhance our product.",
1383 'everest-forms',
1384 )}
1385 </Text>
1386 <Link
1387 fontSize="13px"
1388 fontWeight="400"
1389 color="primary.400"
1390 letterSpacing="0.2px"
1391 textDecoration="underline"
1392 href={featureRequestURL}
1393 isExternal
1394 mt="20px"
1395 >
1396 {__('Request a Feature', 'everest-forms')}
1397 </Link>
1398 </Stack>
1399 <Stack
1400 p="4"
1401 gap="3"
1402 bgColor="white"
1403 borderRadius="base"
1404 border="1px"
1405 borderColor="gray.100"
1406 >
1407 <HStack gap="2">
1408 <Icon as={Star} fontSize={'xl'} fill="primary.400" />
1409 <Heading
1410 as="h3"
1411 fontSize="16px"
1412 fontWeight="600"
1413 color="grey.400"
1414 lineHeight="150%"
1415 >
1416 {__('Submit a Review', 'everest-forms')}
1417 </Heading>
1418 </HStack>
1419 <Text
1420 fontSize="13px"
1421 fontWeight="400"
1422 color="grey.300"
1423 lineHeight="19.3px"
1424 mt="12px"
1425 >
1426 {__(
1427 "Please take a moment to give us a review. We appreciate honest feedback that'll help us improve our plugin.",
1428 'everest-forms',
1429 )}
1430 </Text>
1431 <Link
1432 fontSize="13px"
1433 fontWeight="400"
1434 color="primary.400"
1435 letterSpacing="0.2px"
1436 textDecoration="underline"
1437 href={submitReviewUrl}
1438 isExternal
1439 mt="20px"
1440 >
1441 {__('Submit a Review', 'everest-forms')}
1442 </Link>
1443 </Stack>
1444 <Stack
1445 p="4"
1446 gap="3"
1447 bgColor="white"
1448 borderRadius="base"
1449 border="1px"
1450 borderColor="gray.100"
1451 >
1452 <HStack gap="2">
1453 <Icon as={Video} fontSize={'xl'} fill="primary.400" />
1454 <Heading
1455 as="h3"
1456 fontSize="16px"
1457 fontWeight="600"
1458 color="grey.400"
1459 lineHeight="150%"
1460 >
1461 {__('Video Tutorials', 'everest-forms')}
1462 </Heading>
1463 </HStack>
1464 <Text
1465 fontSize="13px"
1466 fontWeight="400"
1467 color="grey.300"
1468 lineHeight="19.3px"
1469 mt="12px"
1470 >
1471 {__(
1472 "Watch our step-by-step video tutorials that'll help you get the best out of Everest Forms's features.",
1473 'everest-forms',
1474 )}
1475 </Text>
1476 <Link
1477 fontSize="13px"
1478 fontWeight="400"
1479 color="primary.400"
1480 letterSpacing="0.2px"
1481 textDecoration="underline"
1482 isExternal
1483 href="https://www.youtube.com/@everestforms"
1484 mt="20px"
1485 >
1486 {__('Watch Videos', 'everest-forms')}
1487 </Link>
1488 </Stack>
1489 </Stack>
1490 </Grid>
1491 </Container>
1492 );
1493 };
1494
1495 export default SiteAssistant;
1496