import type { ReactNode } from 'react'; import { useCallback, useMemo, useState } from 'react'; import { getSikshyaApi } from '../api'; import { SIKSHYA_ENDPOINTS } from '../api/endpoints'; import { getErrorSummary } from '../api/errors'; import { NavIcon } from './NavIcon'; import { PlanUpgradeOverlay } from './PlanUpgradeOverlay'; import { PremiumGatedSurface } from './PremiumGatedSurface'; import { ButtonPrimary, LinkButtonPrimary } from './shared/buttons'; import { getLicensing, isFeatureEnabled } from '../lib/licensing'; import { appViewHref } from '../lib/appUrl'; import { useAddonEnabled } from '../hooks/useAddons'; import type { SettingsField, SettingsSection } from '../types/settingsSchema'; import type { SikshyaReactConfig } from '../types'; import { __, sprintf } from '../lib/i18n'; type Props = { config: SikshyaReactConfig; tabSchema: SettingsSection[]; renderField: (f: SettingsField) => React.ReactNode; }; function sectionIconName(raw?: string): string { const s = (raw || '').trim(); const fa = s.replace(/^fas\s+fa-/, '').replace(/^fa-/, ''); switch (fa) { case 'link': return 'tag'; case 'folder-open': case 'folder': return 'course'; case 'tags': return 'tag'; case 'route': return 'layers'; case 'cog': case 'cogs': return 'cog'; case 'info-circle': case 'question-circle': case 'bell': return 'helpCircle'; case 'shield-alt': case 'tools': return 'cog'; case 'envelope': case 'paper-plane': return 'mail'; case 'edit': return 'plusDocument'; default: return fa || 'cog'; } } function SectionShell(props: { title?: string; description?: string; icon?: string; children: ReactNode; className?: string; }) { const { title, description, icon, children, className = '' } = props; return (
{title ? (

{title}

{description ? (

{description}

) : null}
) : null} {children}
); } function EmailAddonDisabledOverlay({ config }: { config: SikshyaReactConfig }) { const href = appViewHref(config, 'addons'); return (

{__( 'Your plan includes professional email delivery. Enable the Professional email delivery & branded templates add-on to use SMTP and global HTML branding.', 'sikshya' )}

{__('Open Addons', 'sikshya')}
); } /** * Email → Delivery: addresses, SMTP, global HTML wrappers. Transactional copy lives under Email templates. */ export function EmailDeliverySettings(props: Props) { const { config, tabSchema, renderField } = props; const featureOn = isFeatureEnabled(config, 'email_advanced_customization'); const emailAdvancedAddon = useAddonEnabled('email_advanced_customization'); const advancedOk = featureOn && emailAdvancedAddon.enabled && !emailAdvancedAddon.loading; const lic = getLicensing(config); const addonsHref = useMemo(() => appViewHref(config, 'addons'), [config]); const [testTo, setTestTo] = useState(''); const [testBusy, setTestBusy] = useState(false); const [testFeedback, setTestFeedback] = useState<{ tone: 'ok' | 'err'; text: string } | null>(null); const sendTestEmail = useCallback(async () => { setTestBusy(true); setTestFeedback(null); try { const res = await getSikshyaApi().post<{ success?: boolean; message?: string }>( SIKSHYA_ENDPOINTS.pro.emailAdvancedTestDelivery, { to: testTo.trim() ? testTo.trim() : undefined } ); if (res.success) { setTestFeedback({ tone: 'ok', text: res.message || __('Test email sent.', 'sikshya') }); } else { setTestFeedback({ tone: 'err', text: res.message || __('Could not send test email.', 'sikshya') }); } } catch (e) { setTestFeedback({ tone: 'err', text: getErrorSummary(e) }); } finally { setTestBusy(false); } }, [testTo]); const byKey = new Map(); for (const sec of tabSchema) { const k = sec.section_key; if (k) { byKey.set(k, sec); } } const fieldsOf = (key: string) => byKey.get(key)?.fields ?? []; const smtpSection = byKey.get('email_smtp'); const brandingSection = byKey.get('email_html_branding'); const templatesHref = appViewHref(config, 'email-hub', { tab: 'templates' }); return (

{__( 'Delivery sets who sends mail and how. Which transactional emails actually go out is controlled per template on the Email templates screen (enable/disable and content). That includes drip unlock emails (Drip: lesson unlocked, Drip: course schedule unlocked) — turning a template off does not disable Content drip, only the email.', 'sikshya' )}

{__('Email templates', 'sikshya')}

{__( 'Welcome, enrollment, drip unlocks, completion, reminders — one list with per-template enable switches and editors.', 'sikshya' )}

{__('Open email templates', 'sikshya')}
{!advancedOk && !emailAdvancedAddon.loading ? (
{!featureOn ? ( <> {__('Growth or higher:', 'sikshya')}{' '} {lic?.isProActive ? ( sprintf( __( 'Your license is on %1$s. Custom SMTP and global HTML wrappers unlock on Growth or Scale — Starter includes core email only.', 'sikshya' ), lic.siteTierLabel || lic.siteTier || '' ) ) : ( __( 'Install Sikshya Pro and choose Growth or Scale to edit SMTP and branded HTML templates.', 'sikshya' ) )} ) : ( <> {__( 'Add-on: Turn on Professional email delivery & branded templates on the Addons screen to use SMTP and global HTML wrappers.', 'sikshya' )}{' '} {__('Addons', 'sikshya')} )}
) : null}
{fieldsOf('email_config').map(renderField)}
{fieldsOf('email_master_switches').length > 0 ? (
{fieldsOf('email_master_switches').map(renderField)}
) : null} {fieldsOf('email_certificate_delivery').length > 0 ? (
{fieldsOf('email_certificate_delivery').map(renderField)}
) : null} {/* min-h must accommodate the full PlanUpgradeOverlay card (~640px: * hero ~220px + value grid ~280px + footer CTAs ~120px + outer * PremiumGatedSurface padding ~32px). The overlay centers itself * with `items-center justify-center`, so a parent that's too short * would clip both top and bottom — leaving only the middle of the * upgrade card visible. */}

{smtpSection?.title || __('SMTP Settings (Optional)', 'sikshya')}

{smtpSection?.description ? (

{smtpSection.description}

) : null}
{fieldsOf('email_smtp').map(renderField)}
{advancedOk ? (

{__('Test delivery', 'sikshya')}

{__( 'Sends a short HTML message using your From / Reply-To settings, optional SMTP when enabled, and branded header and footer when configured.', 'sikshya' )}

void sendTestEmail()}> {testBusy ? __('Sending…', 'sikshya') : __('Send test email', 'sikshya')}
{testFeedback ? (

{testFeedback.text}

) : null}
) : null}
{!advancedOk && !emailAdvancedAddon.loading ? ( !featureOn ? ( ) : ( ) ) : null}
{/* Branding fields share the same `email_advanced_customization` * gate as the SMTP section above. The SMTP section already shows * the PlanUpgradeOverlay covering both feature areas — surfacing * a second identical overlay here was redundant chrome and made * the page feel heavier than it is. Just mute the fields with * opacity-65 to signal they're gated; the upgrade context is * already established by the overlay above + the page-level * "Growth or higher" banner near the top of this view. */}
{fieldsOf('email_html_branding').map(renderField)}
); }