# thinkrank/1.0.0/src/admin/components/content-brief/ExportOptions.js

ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console &amp; Local SEO, version 1.0.0. 402 lines.

- Page: https://pluginprobe.com/plugins/thinkrank/1.0.0/code/src/admin/components/content-brief/ExportOptions.js
- Raw: https://pluginprobe.com/plugins/thinkrank/1.0.0/raw/src/admin/components/content-brief/ExportOptions.js
- Modified: 2025-08-10T07:57:44+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/thinkrank/1.0.0/code/src/admin/components/content-brief/ExportOptions.js#L10-L20`.

```javascript
/**
 * Export Options Component
 *
 * Provides export functionality for generated content briefs
 *
 * @package ThinkRank
 * @since 1.0.0
 */

import { useState } from '@wordpress/element';
import { Button, Card, CardBody, SelectControl, Notice } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { download, copy } from '@wordpress/icons';
import apiFetch from '@wordpress/api-fetch';

const ExportOptions = ({ briefData }) => {
    const [exportFormat, setExportFormat] = useState('txt');
    const [isExporting, setIsExporting] = useState(false);
    const [exportError, setExportError] = useState(null);

    // Export format options
    const formatOptions = [
        { label: __('Plain Text (.txt)', 'thinkrank'), value: 'txt' },
        { label: __('PDF Document (.pdf)', 'thinkrank'), value: 'pdf' }
    ];

    /**
     * Copy brief to clipboard as formatted text
     */
    const copyToClipboard = () => {
        const formattedText = formatBriefAsText(briefData);

        // Try modern clipboard API first
        if (navigator.clipboard && navigator.clipboard.writeText) {
            navigator.clipboard.writeText(formattedText).then(() => {
                console.log('Brief copied to clipboard');
                // Show success message
                setExportError(null);
            }).catch((error) => {
                console.error('Failed to copy to clipboard:', error);
                fallbackCopyToClipboard(formattedText);
            });
        } else {
            // Fallback for older browsers
            fallbackCopyToClipboard(formattedText);
        }
    };

    /**
     * Fallback copy to clipboard method
     */
    const fallbackCopyToClipboard = (text) => {
        const textArea = document.createElement('textarea');
        textArea.value = text;
        textArea.style.position = 'fixed';
        textArea.style.left = '-999999px';
        textArea.style.top = '-999999px';
        document.body.appendChild(textArea);
        textArea.focus();
        textArea.select();

        try {
            const successful = document.execCommand('copy');
            if (successful) {
                console.log('Brief copied to clipboard (fallback)');
                setExportError(null);
            } else {
                setExportError(__('Failed to copy to clipboard', 'thinkrank'));
            }
        } catch (error) {
            console.error('Fallback copy failed:', error);
            setExportError(__('Copy to clipboard not supported in this browser', 'thinkrank'));
        } finally {
            document.body.removeChild(textArea);
        }
    };

    /**
     * Export brief in selected format
     */
    const exportBrief = async () => {
        setIsExporting(true);
        setExportError(null);

        try {
            const formattedText = formatBriefAsText(briefData);

            if (exportFormat === 'txt') {
                // Download as plain text
                downloadTextFile(formattedText, `content-brief-${briefData.id || 'generated'}.txt`);
            } else if (exportFormat === 'pdf') {
                // For PDF, we'll use the browser's print functionality
                // Create a new window with formatted content
                const printWindow = window.open('', '_blank');
                printWindow.document.write(`
                    <html>
                        <head>
                            <title>Content Brief</title>
                            <style>
                                body {
                                    font-family: Arial, sans-serif;
                                    margin: 40px;
                                    line-height: 1.6;
                                    color: #333;
                                }
                                h1 {
                                    color: #333;
                                    border-bottom: 2px solid #333;
                                    padding-bottom: 10px;
                                }
                                h2 {
                                    color: #666;
                                    margin-top: 30px;
                                    border-bottom: 1px solid #ccc;
                                    padding-bottom: 5px;
                                }
                                .section { margin-bottom: 20px; }
                                .outline-item { margin-left: 20px; }
                                pre {
                                    white-space: pre-wrap;
                                    font-family: Arial, sans-serif;
                                    font-size: 12px;
                                }
                                @media print {
                                    body { margin: 20px; }
                                    @page { margin: 1in; }
                                }
                            </style>
                        </head>
                        <body>
                            <pre>${formattedText.replace(/</g, '&lt;').replace(/>/g, '&gt;')}</pre>
                        </body>
                    </html>
                `);
                printWindow.document.close();
                printWindow.print();
            }
        } catch (error) {
            console.error('Export error:', error);
            setExportError(error.message || __('An error occurred during export', 'thinkrank'));
        } finally {
            setIsExporting(false);
        }
    };

    /**
     * Format brief data as plain text
     */
    const formatBriefAsText = (data) => {
        let text = '';

        // Debug: Log the data structure to see what's available
        console.log('Brief data for export:', data);

        // Header
        if (data.title && Array.isArray(data.title) && data.title[0]) {
            text += `Content Brief: "${data.title[0]}"\n`;
            text += '='.repeat(60) + '\n\n';
        } else if (data.title && typeof data.title === 'string') {
            text += `Content Brief: "${data.title}"\n`;
            text += '='.repeat(60) + '\n\n';
        }

        // Generation parameters
        if (data.generation_params) {
            const params = data.generation_params;
            text += 'BRIEF CONFIGURATION\n';
            text += `-`.repeat(30) + '\n';
            text += `Target Keywords: ${params.target_keywords?.join(', ') || 'N/A'}\n`;
            text += `Content Type: ${params.content_type || 'N/A'}\n`;
            text += `Target Audience: ${params.target_audience || 'N/A'}\n`;
            text += `Content Length: ${params.content_length || 'N/A'}\n`;
            text += `Tone: ${params.tone || 'N/A'}\n`;
            if (params.competitor_urls && params.competitor_urls.length > 0) {
                text += `Competitor URLs: ${params.competitor_urls.join(', ')}\n`;
            }
            if (params.additional_context) {
                text += `Additional Context: ${params.additional_context}\n`;
            }
            text += '\n';
        }

        // Title suggestions
        if (data.title && Array.isArray(data.title) && data.title.length > 1) {
            text += 'TITLE SUGGESTIONS\n';
            text += `-`.repeat(30) + '\n';
            data.title.forEach((title, index) => {
                text += `${index + 1}. ${title}\n`;
            });
            text += '\n';
        }

        // Meta description
        if (data.meta_description) {
            text += 'META DESCRIPTION\n';
            text += `-`.repeat(30) + '\n';
            text += `${data.meta_description}\n\n`;
        }

        // Content outline
        if (data.outline && Array.isArray(data.outline) && data.outline.length > 0) {
            text += 'CONTENT OUTLINE\n';
            text += `-`.repeat(30) + '\n';
            data.outline.forEach((item, index) => {
                const indent = '  '.repeat((item.level || 1) - 1);
                text += `${indent}${index + 1}. ${item.heading || item}`;
                if (item.word_count && item.word_count > 0) {
                    text += ` (${item.word_count} words)`;
                }
                text += '\n';

                if (item.key_points && Array.isArray(item.key_points) && item.key_points.length > 0) {
                    item.key_points.forEach((point) => {
                        text += `${indent}   • ${point}\n`;
                    });
                }

                if (item.keywords && Array.isArray(item.keywords) && item.keywords.length > 0) {
                    text += `${indent}   Keywords: ${item.keywords.join(', ')}\n`;
                }
                text += '\n';
            });
        }

        // SEO recommendations
        if (data.seo_recommendations) {
            text += 'SEO Recommendations:\n';
            text += `-`.repeat(20) + '\n';
            
            const seo = data.seo_recommendations;
            if (seo.related_keywords && seo.related_keywords.length > 0) {
                text += `Related Keywords: ${seo.related_keywords.join(', ')}\n`;
            }
            if (seo.internal_links && seo.internal_links.length > 0) {
                text += 'Internal Linking Opportunities:\n';
                seo.internal_links.forEach((link) => {
                    text += `  • ${link}\n`;
                });
            }
            text += '\n';
        }

        // Content gaps
        if (data.competitor_gaps && data.competitor_gaps.length > 0) {
            text += 'Content Gaps & Opportunities:\n';
            text += `-`.repeat(20) + '\n';
            data.competitor_gaps.forEach((gap) => {
                text += `• ${gap}\n`;
            });
            text += '\n';
        }

        // Call-to-actions
        if (data.call_to_actions && data.call_to_actions.length > 0) {
            text += 'Call-to-Action Suggestions:\n';
            text += `-`.repeat(20) + '\n';
            data.call_to_actions.forEach((cta, index) => {
                text += `${index + 1}. ${cta}\n`;
            });
            text += '\n';
        }

        // Raw AI response (if available)
        if (data.raw_response && data.raw_response.trim()) {
            text += 'FULL AI RESPONSE\n';
            text += `-`.repeat(30) + '\n';
            text += data.raw_response + '\n\n';
        }

        // Footer
        text += '='.repeat(60) + '\n';
        if (data.created_at) {
            text += `Generated on: ${data.created_at}\n`;
        }
        text += 'Powered by ThinkRank AI\n';
        text += 'https://thinkrank.ai\n';

        return text;
    };

    /**
     * Download text as file
     */
    const downloadTextFile = (content, filename) => {
        const blob = new Blob([content], { type: 'text/plain' });
        const url = URL.createObjectURL(blob);
        const link = document.createElement('a');
        link.href = url;
        link.download = filename;
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
        URL.revokeObjectURL(url);
    };

    /**
     * Create new post with brief content
     */
    const createPostFromBrief = () => {
        if (!briefData.outline || briefData.outline.length === 0) {
            setExportError(__('No outline available to create post', 'thinkrank'));
            return;
        }

        // Create basic post content from outline
        let postContent = '';
        
        briefData.outline.forEach((item) => {
            const headingTag = `h${item.level}`;
            postContent += `<${headingTag}>${item.heading}</${headingTag}>\n\n`;
            
            if (item.key_points && item.key_points.length > 0) {
                postContent += '<ul>\n';
                item.key_points.forEach((point) => {
                    postContent += `<li>${point}</li>\n`;
                });
                postContent += '</ul>\n\n';
            } else {
                postContent += `<p>[Write ${item.word_count || 200} words about ${item.heading}]</p>\n\n`;
            }
        });

        // Open new post editor with pre-filled content
        const newPostUrl = `${window.location.origin}/wp-admin/post-new.php`;
        const postData = {
            post_title: briefData.title?.[0] || 'New Post from Brief',
            content: postContent
        };

        // Store data in sessionStorage to be picked up by the editor
        sessionStorage.setItem('thinkrank_brief_data', JSON.stringify(postData));
        
        // Open new post editor
        window.open(newPostUrl, '_blank');
    };

    if (!briefData) {
        return null;
    }

    return (
        <Card>
            <CardBody>
                <h3>{__('📤 Export Options', 'thinkrank')}</h3>
                
                {exportError && (
                    <Notice status="error" isDismissible onRemove={() => setExportError(null)}>
                        {exportError}
                    </Notice>
                )}

                <div className="thinkrank-export-options">
                    <div className="export-format-selection">
                        <SelectControl
                            label={__('Export Format', 'thinkrank')}
                            value={exportFormat}
                            options={formatOptions}
                            onChange={setExportFormat}
                            __next40pxDefaultSize={true}
                            __nextHasNoMarginBottom={true}
                        />
                    </div>

                    <div className="export-actions">
                        <Button
                            isPrimary
                            onClick={exportBrief}
                            disabled={isExporting}
                            icon={download}
                        >
                            {isExporting ? __('Exporting...', 'thinkrank') : __('Download Brief', 'thinkrank')}
                        </Button>

                        <Button
                            isSecondary
                            onClick={copyToClipboard}
                            icon={copy}
                        >
                            {__('Copy to Clipboard', 'thinkrank')}
                        </Button>

                        <Button
                            isTertiary
                            onClick={createPostFromBrief}
                        >
                            {__('Create Post from Brief', 'thinkrank')}
                        </Button>
                    </div>
                </div>

                <div className="export-help">
                    <p className="description">
                        {__('Export your content brief for use in external tools or create a new WordPress post with the outline structure.', 'thinkrank')}
                    </p>
                </div>
            </CardBody>
        </Card>
    );
};

export default ExportOptions;

```
