import React, { useState, useEffect } from 'react'; import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router-dom'; import { ArrowLeft, Copy, Check, ChevronDown, ChevronRight, Zap, AlertCircle, Code, Calendar, Shield, Cpu, } from 'lucide-react'; // ============================================================================= // TYPES & CONSTANTS // ============================================================================= type CodeLanguage = 'python' | 'json'; interface LanguageConfig { label: string; icon: string; } const LANGUAGES: Record = { python: { label: 'Python', icon: 'py' }, json: { label: 'JSON', icon: '{}' }, }; // ============================================================================= // SYNTAX HIGHLIGHTING // ============================================================================= const highlightSyntax = (code: string, language: CodeLanguage): React.ReactNode => { const patterns: Record> = { json: [ { pattern: /"([^"\\]|\\.)*"(?=\s*:)/g, className: 'text-purple-400' }, { pattern: /"([^"\\]|\\.)*"(?!\s*:)/g, className: 'text-green-400' }, { pattern: /\b(true|false|null)\b/g, className: 'text-orange-400' }, { pattern: /\b(-?\d+\.?\d*)\b/g, className: 'text-cyan-400' }, ], python: [ { pattern: /#.*/g, className: 'text-gray-500 italic' }, { pattern: /\b(import|from|class|def|return|if|else|elif|for|while|try|except|with|as|None|True|False|self|async|await|in|and|or|not|is)\b/g, className: 'text-purple-400' }, { pattern: /('([^'\\]|\\.)*'|"([^"\\]|\\.)*"|f"([^"\\]|\\.)*"|f'([^'\\]|\\.)*')/g, className: 'text-green-400' }, { pattern: /\b(\d+\.?\d*)\b/g, className: 'text-cyan-400' }, { pattern: /@\w+/g, className: 'text-pink-400' }, ], }; const langPatterns = patterns[language] || []; if (langPatterns.length === 0) { return {code}; } const lines = code.split('\n'); return ( <> {lines.map((line, lineIndex) => { let result: Array<{ text: string; className?: string; start: number }> = [{ text: line, start: 0 }]; langPatterns.forEach(({ pattern, className }) => { const newResult: typeof result = []; result.forEach(segment => { if (segment.className) { newResult.push(segment); return; } const text = segment.text; const regex = new RegExp(pattern.source, pattern.flags); let lastIndex = 0; let match; while ((match = regex.exec(text)) !== null) { if (match.index > lastIndex) { newResult.push({ text: text.slice(lastIndex, match.index), start: segment.start + lastIndex }); } newResult.push({ text: match[0], className, start: segment.start + match.index }); lastIndex = match.index + match[0].length; if (match[0].length === 0) break; } if (lastIndex < text.length) { newResult.push({ text: text.slice(lastIndex), start: segment.start + lastIndex }); } }); result = newResult.length > 0 ? newResult : result; }); return ( {result.map((segment, i) => ( {segment.text} ))} {lineIndex < lines.length - 1 && '\n'} ); })} ); }; // ============================================================================= // CODE BLOCK COMPONENTS // ============================================================================= const CodeBlock: React.FC<{ code: string; language?: CodeLanguage; title?: string }> = ({ code, language = 'json', title }) => { const [copied, setCopied] = useState(false); const handleCopy = () => { navigator.clipboard.writeText(code); setCopied(true); setTimeout(() => setCopied(false), 2000); }; return (
{title && (
{title} {LANGUAGES[language]?.label || language}
)}
          {highlightSyntax(code, language)}
        
); }; // Removed TabbedCodeBlock - we only show Python examples since users write scripts in the UI // ============================================================================= // SIDEBAR NAVIGATION // ============================================================================= interface NavSection { titleKey: string; id: string; items?: { titleKey: string; id: string }[]; } const navSections: NavSection[] = [ { titleKey: 'Introduction', id: 'introduction' }, { titleKey: 'Quick Start', id: 'quick-start' }, { titleKey: 'How It Works', id: 'how-it-works' }, { titleKey: 'Available Plugins', id: 'plugins', items: [ { titleKey: 'Built-in Plugins', id: 'builtin-plugins' }, { titleKey: 'Custom Scripts', id: 'custom-scripts' }, { titleKey: 'Template Variables', id: 'template-variables' }, ], }, { titleKey: 'API Reference', id: 'api', items: [ { titleKey: 'API Methods', id: 'api-methods' }, { titleKey: 'Command Reference', id: 'command-reference' }, { titleKey: 'Schedule Types', id: 'schedule-types' }, { titleKey: 'Manage Tasks', id: 'manage-tasks' }, ], }, { titleKey: 'Examples', id: 'examples', items: [ { titleKey: 'Win Back Customers', id: 'example-reengagement' }, { titleKey: 'Booking Alerts', id: 'example-alerts' }, { titleKey: 'Weekly Reports', id: 'example-reports' }, ], }, { titleKey: 'Security', id: 'security', items: [ { titleKey: 'Safety Features', id: 'safety' }, { titleKey: 'Resource Limits', id: 'limits' }, ], }, { titleKey: 'Plugin Licensing', id: 'licensing' }, ]; const Sidebar: React.FC<{ activeSection: string; onSectionClick: (id: string) => void; }> = ({ activeSection, onSectionClick }) => { const [expandedSections, setExpandedSections] = useState(['plugins', 'api', 'examples', 'security']); const toggleSection = (id: string) => { setExpandedSections(prev => prev.includes(id) ? prev.filter(s => s !== id) : [...prev, id] ); }; return ( ); }; // ============================================================================= // API SECTION COMPONENT (Stripe-style split pane) // ============================================================================= interface ApiSectionProps { id: string; children: React.ReactNode; } const ApiSection: React.FC = ({ id, children }) => { return (
{children}
); }; const ApiContent: React.FC<{ children: React.ReactNode }> = ({ children }) => (
{children}
); const ApiExample: React.FC<{ children: React.ReactNode }> = ({ children }) => (
{children}
); // ============================================================================= // ATTRIBUTE TABLE // ============================================================================= interface Attribute { name: string; type: string; description: string; required?: boolean; } const AttributeTable: React.FC<{ attributes: Attribute[] }> = ({ attributes }) => (
{attributes.map(attr => (
{attr.name} {attr.type} {attr.required && ( required )}

{attr.description}

))}
); // ============================================================================= // MAIN COMPONENT // ============================================================================= const HelpPluginDocs: React.FC = () => { const { t } = useTranslation(); const navigate = useNavigate(); const [activeSection, setActiveSection] = useState('introduction'); const handleSectionClick = (id: string) => { setActiveSection(id); const element = document.getElementById(id); if (element) { element.scrollIntoView({ behavior: 'smooth', block: 'start' }); } }; // Track active section on scroll useEffect(() => { const handleScroll = () => { const sections = document.querySelectorAll('section[id]'); let current = 'introduction'; const headerHeight = 72; const threshold = headerHeight + 32; sections.forEach(section => { const rect = section.getBoundingClientRect(); if (rect.top <= threshold) { current = section.id; } }); setActiveSection(current); }; window.addEventListener('scroll', handleScroll); return () => window.removeEventListener('scroll', handleScroll); }, []); // ============================================================================= // CODE SNIPPETS // ============================================================================= const simplePluginExample = `# Get scheduled appointments appointments = api.get_appointments(status='SCHEDULED') # Count them count = len(appointments) # Log the result api.log(f'Found {count} scheduled appointments') # Return result result = {'total': count}`; const reengagementExample = `# Get customers who haven't booked in 60 days from datetime import datetime, timedelta cutoff = (datetime.now() - timedelta(days=60)).strftime('%Y-%m-%d') customers = api.get_customers(has_email=True, limit=50) # Send re-engagement emails sent = 0 for customer in customers[:30]: # Limit to 30 per run message = f'''Hi {customer['name']}, We miss you! It's been a while since your last visit. Get 20% off your next appointment with code: COMEBACK20 Hope to see you soon!''' success = api.send_email( to=customer['email'], subject='We Miss You! 20% Off', body=message ) if success: sent += 1 result = {'emails_sent': sent}`; const alertExample = `# Get appointments for next 7 days from datetime import datetime, timedelta today = datetime.now().strftime('%Y-%m-%d') next_week = (datetime.now() + timedelta(days=7)).strftime('%Y-%m-%d') upcoming = api.get_appointments( start_date=today, end_date=next_week, status='SCHEDULED' ) # Alert if bookings are low if len(upcoming) < 10: alert = f'''⚠️ LOW BOOKING ALERT Only {len(upcoming)} appointments for next 7 days. Recommendation: Run a promotion!''' api.send_email( to='manager@business.com', subject='⚠️ Low Bookings', body=alert ) result = {'alert_sent': True, 'count': len(upcoming)} else: result = {'alert_sent': False, 'count': len(upcoming)}`; return (
{/* Header */}

Automation Plugins

{/* Sidebar */} {/* Main Content */}
{/* Introduction */}

Automation Plugins

Automate your business with powerful plugins that run on schedules. Send emails, generate reports, and create custom workflows - all without writing complex code.

Key Features

  • Safe Scripting - Write Python-like code with if/else, loops, variables
  • Flexible Scheduling - Run daily, weekly, hourly, or on cron schedules
  • Resource Protected - Automatic limits prevent abuse
  • Pre-built Templates - Start with ready-made plugins

What You Can Automate

  • Send weekly summary reports to managers
  • Re-engage customers who haven't booked in 60 days
  • Alert when bookings are unusually low
  • Send birthday wishes with discount codes
  • Generate custom analytics and export data
  • Integrate with external services via webhooks
{/* Quick Start */}

Quick Start

Create your first automation in 3 simple steps:

  1. Write your script - Use simple Python code to access your data
  2. Set a schedule - Choose when and how often to run
  3. Activate & monitor - Your automation runs automatically

That's it! This script counts scheduled appointments and logs the result. It runs automatically on your schedule.

{/* How It Works */}

How It Works

Your scripts run in a secure sandbox with access to your business data through a simple API object.

Available API Methods

  • api.get_appointments() - Get your appointments
  • api.get_customers() - Get your customers
  • api.send_email() - Send emails
  • api.create_appointment() - Create appointments
  • api.log() - Debug logging

Execution Flow

  1. Script is validated for safety
  2. Loop guards injected to prevent infinite loops
  3. Executed with resource limits (30s timeout, 50 API calls)
  4. Results logged for audit trail
  5. Next run automatically scheduled
{/* Built-in Plugins */}

Built-in Plugins

Ready-to-use plugins for common business tasks. Just configure and activate.

How to Use Built-in Plugins

  1. 1. Navigate to Automation in your dashboard
  2. 2. Click "Create New Task"
  3. 3. Select a built-in plugin from the dropdown
  4. 4. Configure the plugin settings
  5. 5. Set your schedule and activate
{/* Custom Scripts */}

Custom Scripts

Write your own automation logic with Python. Access your data, write if/else logic, use loops, and create powerful custom workflows.

What You Can Use

  • ✓ if/else statements
  • ✓ for/while loops
  • ✓ Variables & lists
  • ✓ Dictionaries
  • ✓ String formatting
  • ✓ Math operations

What's Blocked

  • ✗ import statements
  • ✗ File system access
  • ✗ eval/exec
  • ✗ Network access*

*Except approved API calls via api.http_get()

{/* Template Variables */}

Template Variables

Make your plugins reusable and shareable with powerful template variables. The system supports four types of templates for maximum flexibility.

{/* 1. PROMPT Variables */}

1. User Input (PROMPT)

Prompt users for custom values during plugin installation. The system automatically generates a configuration form based on your template variables.

{'{{PROMPT:variable|description}}'} - Required field
{'{{PROMPT:variable|description|default}}'} - Optional field with default value

Example: {'{{PROMPT:manager_email|Manager email address}}'}

With default: {'{{PROMPT:discount|Discount code|SAVE20}}'}

{/* 2. CONTEXT Variables */}

2. Business Context (CONTEXT)

Automatically filled with business information from the system. No user input required!

✓ {'{{CONTEXT:business_name}}'} - Business name
✓ {'{{CONTEXT:owner_email}}'} - Owner email
✓ {'{{CONTEXT:owner_name}}'} - Owner full name
✓ {'{{CONTEXT:contact_email}}'} - Contact email
✓ {'{{CONTEXT:phone}}'} - Business phone

Benefit: Users don't need to manually enter data that's already in the system!

{/* 3. DATE Helpers */}

3. Date Helpers (DATE)

Pre-calculated dates without writing datetime code. All dates return YYYY-MM-DD format.

{'{{DATE:today}}'} or {'{{DATE:now}}'} - Current date
{'{{DATE:tomorrow}}'} - Tomorrow's date
{'{{DATE:yesterday}}'} - Yesterday's date
{'{{DATE:+7d}}'} - 7 days from now
{'{{DATE:-30d}}'} - 30 days ago
{'{{DATE:+2w}}'} - 2 weeks from now
{'{{DATE:monday}}'} - Next Monday
{'{{DATE:friday}}'} - Next Friday
{/* 4. Validation & Types */}

4. Automatic Validation

The system automatically detects field types and validates input:

Email: Variables with "email" in name/description are validated
Number: Variables with "count", "days", "hours", "limit" are numeric
URL: Variables with "url", "webhook", "endpoint" are validated
Textarea: Variables with "message", "body", "content" use multi-line input

Pro Tip: Combine all template types for maximum power! Use CONTEXT for business info, DATE for time logic, and PROMPT only when user input is truly needed.

{/* Visual Mockup of Configuration Form */}

Configure Plugin

Step 2 of 3
{/* Field 1: Required, no default */}

Number of days before a customer is considered inactive

{/* Field 2: Optional with default */}

Promotional discount code to offer

Default: SAVE20

{/* Field 3: Email type (auto-detected) */}

Email address for reports and notifications

Email validation enabled

{/* Field 4: Textarea (auto-detected) */}

Custom message to include in re-engagement emails