import React, { useState } from 'react' import { Smartphone, BookOpen, Zap, RotateCcw, Languages, BellRing, UserPlus, KeyRound, AlertCircle, Users, ShieldCheck, Activity, ShieldAlert, MessageSquare, FileCode, Settings, Search, X } from 'lucide-react' import { Switch } from './components/ui/switch' import { Tooltip, TooltipContent, TooltipTrigger, } from './components/ui/tooltip' import { toast } from "sonner" import type { DashboardData } from './types' import { SettingsLayout, SettingsHeader, SnapshotStat, FeatSection, FeatRow, SecondaryButton } from './components/ui/settings-ui'; // ─── Dashboard ──────────────────────────────────────────────────────────────── export default function Dashboard({ data: initialData }: { data: DashboardData }) { const [data, setData] = useState(initialData) const [searchQuery, setSearchQuery] = useState('') const [isSearchOpen, setIsSearchOpen] = useState(false) const searchRef = React.useRef(null) React.useEffect(() => { if (isSearchOpen && searchRef.current) { searchRef.current.focus(); } }, [isSearchOpen]); const [prevInitialData, setPrevInitialData] = useState(initialData); const [savingItems, setSavingItems] = useState>({}); if (initialData !== prevInitialData) { setPrevInitialData(initialData); setData(initialData); } const toggle = async (key: string) => { if (!data || savingItems[key]) return; const feat = data.features[key]; const isActuallyEnabled = Number(feat.enabled) === 1 || feat.enabled === true; const next = isActuallyEnabled ? 0 : 1; setSavingItems(prev => ({ ...prev, [key]: true })); // Optimistic UI update setData(prev => prev ? { ...prev, features: { ...prev.features, [key]: { ...feat, enabled: next } } } : prev); try { const res = await fetch(`${data.global.settingsRestUrl}${data.global.settingsRestUrl.includes('?') ? '&' : '?'}_=${Date.now()}`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': data.global.wpRestNonce }, body: JSON.stringify({ settings: { [feat.option]: next } }) }); const json = await res.json(); if (json.success) { toast.success(data.i18n.successTitle || 'Success', { description: data.i18n.success }); // Dispatch global refresh event with a small delay to allow transients to settle setTimeout(() => { window.dispatchEvent(new CustomEvent('wawp-refresh-data', { detail: { section: 'dashboard' } })); }, 150); // Notify sidebar about section visibility const sidebarMapping: Record = { 'wawp_otp_enabled': 'otp', 'wawp_campaigns_enabled': 'campaigns', 'wawp_abandoned_carts_enabled': 'abandonedCarts', 'wawp_chat_widget_enabled': 'chatWidget', 'wawp_notifications_enabled': 'notifications', 'wawp_system_info_enabled': 'systemInfo', 'wawp_countrycode_enabled': 'phoneField', 'wawp_google_recaptcha_enabled': 'recaptcha', 'wawp_passwordless_login_enabled': 'otpLogin', 'wawp_signup_enabled': 'signupOtp', 'wawp_checkout_otp_enabled': 'checkoutOtp', 'wawp_custom_pages_enabled': 'authPages', 'wawp_unified_log_enabled': 'activityHub', 'wawp_email_templates_enabled': 'emailTemplates' }; const sidebarKey = sidebarMapping[feat.option]; if (sidebarKey) { window.dispatchEvent(new CustomEvent('wawp-sections-updated', { detail: { [sidebarKey]: next === 1 } })); // If child OTP feature is enabled, ensure master OTP group is also shown in sidebar if (['otpLogin', 'signupOtp', 'checkoutOtp', 'customPages'].includes(sidebarKey) && next === 1) { window.dispatchEvent(new CustomEvent('wawp-sections-updated', { detail: { otp: true } })); } } } else { throw new Error(json.data || 'Action failed'); } } catch (err) { // Revert on error setData(prev => prev ? { ...prev, features: { ...prev.features, [key]: { ...feat, enabled: isActuallyEnabled ? 1 : 0 } } } : prev); toast.error(data.i18n.errorTitle || 'Error', { description: (err as Error).message }); } finally { setSavingItems(prev => ({ ...prev, [key]: false })); } }; const t = React.useCallback((key: string, fallback: string = ''): string => { const val = (data?.i18n as Record)?.[key]; return typeof val === 'string' ? val : fallback; }, [data.i18n]); const stats = data?.stats || { totalWpUsers: 0, usersWithPhone: 0, verified: 0, percentAdded: '0%', percentVerified: '0%' }; // Fallback if i18n is partially missing to prevent white page const pageTitle = "Dashboard" const pageSubtitle = "Manage your automated workflows, track delivery performance, and monitor system health in one centralized location."; if (!data) return null; const f = (key: string) => data?.features?.[key] || { enabled: false, allowed: false, option: '', error: undefined, pluginLink: undefined }; const isEnabled = (key: string) => { const feat = f(key); return Number(feat.enabled) === 1 || feat.enabled === true; }; const isAllowed = (_key: string) => true; const getError = (key: string) => f(key).error as string | undefined; const hasFeature = (key: string) => !!data.features[key as keyof typeof data.features]; const hasEngagement = (['chatWidget', 'notifications', 'abandonedCarts', 'campaigns', 'emailTemplates', 'multilang', 'subNotifs'] as (keyof typeof data.features)[]).some(k => !!data?.features?.[k]); const hasAuth = (['countryCode', 'otpLogin', 'signupOtp', 'checkoutOtp', 'customPages', 'recaptcha'] as (keyof typeof data.features)[]).some(k => !!data?.features?.[k]); const matchesSearch = (title: string = '', desc: string = '') => { if (!searchQuery) return true; const q = searchQuery.toLowerCase(); return title.toLowerCase().includes(q) || desc.toLowerCase().includes(q); }; return (
<> {/* WooCommerce Missing Global Notice */}
{isSearchOpen ? (
setSearchQuery(e.target.value)} onKeyDown={(e) => { if (e.key === 'Escape') { setSearchQuery(''); setIsSearchOpen(false); } }} />
) : ( setIsSearchOpen(true)} > )} window.open(data.urls.usersAdmin, '_blank')}> {t('viewAllUsers', 'View Users')}
{/* User Stats Snapshot */} {/* System Information Switch */}
{t('featSysInfoTitle', 'System Info')} {t('featSysInfoDesc', 'Monitor your server health and WordPress environment in real-time to ensure seamless performance for all automation tasks.')}
{isEnabled('systemInfo') && ( window.dispatchEvent(new CustomEvent('wawp-navigate', { detail: 'system_info' }))} > {t('btnSettings', 'Settings')} )} toggle('systemInfo')} />
{/* Feature Sections */} {hasEngagement && (matchesSearch(t('featChatTitle', ''), t('featChatDesc', '')) || matchesSearch("Dashboard", "Centralized command center") || matchesSearch(t('featAbandonTitle', ''), t('featAbandonDesc', '')) || matchesSearch(t('featCampaignTitle', ''), t('featCampaignDesc', '')) || matchesSearch(t('emailTemplates', ''), t('emailTemplatesDesc', '')) || matchesSearch(t('featMultiTitle', ''), t('featMultiDesc', '')) || matchesSearch(t('featSubTitle', ''), t('featSubDesc', ''))) && ( {hasFeature('chatWidget') && matchesSearch(t('featChatTitle', ''), t('featChatDesc', '')) && toggle('chatWidget')} docs="https://help.wawp.net/en_US/whatsapp-chat-button/" settingsUrl={data.urls.chatWidget} t={t as unknown as Record} />} {hasFeature('notifications') && matchesSearch(t('featNotifTitle', ''), t('featNotifDesc', '')) && toggle('notifications')} docs="https://help.wawp.net/en_US/automated-notifications/" settingsUrl={data.urls.notifications} t={t as unknown as Record} />} {hasFeature('abandonedCarts') && matchesSearch(t('featAbandonTitle', ''), t('featAbandonDesc', '')) && toggle('abandonedCarts')} docs="https://help.wawp.net/en_US/abandoned-carts/" settingsUrl={data.urls.abandonedCarts} pluginLink={data.wooStatus.installed ? data.urls.wooActivate : data.urls.wooInstall} t={t as unknown as Record} />} {hasFeature('campaigns') && matchesSearch(t('featCampaignTitle', ''), t('featCampaignDesc', '')) && toggle('campaigns')} docs="https://help.wawp.net/en_US/wawp-bulk-campaigns/" settingsUrl={data.urls.campaigns} t={t as unknown as Record} />} {hasFeature('multilang') && matchesSearch(t('featMultiTitle', ''), t('featMultiDesc', '')) && toggle('multilang')} docs="https://help.wawp.net/en_US/wawp-plugin-dashboard/" settingsUrl={data.urls.notifications} t={t as unknown as Record} />} {hasFeature('subNotifs') && matchesSearch(t('featSubTitle', ''), t('featSubDesc', '')) && toggle('subNotifs')} docs="https://help.wawp.net/en_US/wawp-plugin-dashboard/" settingsUrl={data.urls.notifications} pluginLink={f('subNotifs').pluginLink} t={t as unknown as Record} />} )} {hasAuth && (matchesSearch(t('featCountryTitle', ''), t('featCountryDesc', '')) || matchesSearch(t('featLoginTitle', ''), t('featLoginDesc', '')) || matchesSearch(t('featSignupTitle', ''), t('featSignupDesc', '')) || matchesSearch(t('featCheckoutTitle', ''), t('featCheckoutDesc', '')) || matchesSearch(t('featPagesTitle', ''), t('featPagesDesc', '')) || matchesSearch(t('featRecaptchaTitle', ''), t('featRecaptchaDesc', ''))) && ( {matchesSearch(t('featCountryTitle', ''), t('featCountryDesc', '')) && toggle('countryCode')} docs="https://help.wawp.net/en_US/advanced-country-code/" settingsUrl={data.urls.phoneField} t={t as unknown as Record} />} {matchesSearch(t('featLoginTitle', ''), t('featLoginDesc', '')) && toggle('otpLogin')} docs="https://help.wawp.net/en_US/passwordless-login/" settingsUrl={data.urls.otpLogin} t={t as unknown as Record} />} {matchesSearch(t('featSignupTitle', ''), t('featSignupDesc', '')) && toggle('signupOtp')} docs="https://help.wawp.net/en_US/registration-form-builder/" settingsUrl={data.urls.registration} t={t as unknown as Record} />} {matchesSearch(t('featCheckoutTitle', ''), t('featCheckoutDesc', '')) && toggle('checkoutOtp')} docs="https://help.wawp.net/en_US/checkout-verification/" settingsUrl={data.urls.checkout} pluginLink={data.wooStatus.installed ? data.urls.wooActivate : data.urls.wooInstall} t={t as unknown as Record} />} {matchesSearch(t('featPagesTitle', ''), t('featPagesDesc', '')) && toggle('customPages')} docs="https://help.wawp.net/en_US/authentication-pages/" settingsUrl={data.urls.pages} t={t as unknown as Record} />} {matchesSearch(t('featRecaptchaTitle', ''), t('featRecaptchaDesc', '')) && toggle('recaptcha')} docs="https://help.wawp.net/en_US/google-recaptcha/" settingsUrl={data.urls.recaptcha} t={t as unknown as Record} />} )}
) }