import React, { ReactElement, useEffect, useMemo, useRef, useState, } from 'react'; import Head from 'next/head'; import { mdiCheckCircleOutline, mdiDownloadBoxOutline, mdiFileDocumentOutline, mdiFileExportOutline, mdiFileSwapOutline, mdiHistory, mdiLinkVariant, } from '@mdi/js'; import BaseButton from '../components/BaseButton'; import BaseIcon from '../components/BaseIcon'; import CardBox from '../components/CardBox'; import SectionMain from '../components/SectionMain'; import SectionTitleLineWithButton from '../components/SectionTitleLineWithButton'; import LayoutAuthenticated from '../layouts/Authenticated'; import { getPageTitle } from '../config'; import { fetch as fetchArticles } from '../stores/articles/articlesSlice'; import { useAppDispatch, useAppSelector } from '../stores/hooks'; import { applyAffiliateReplacements, detectAffiliateLinks, type AffiliateReplacementGroup, type DetectedContentLink, } from '../helpers/affiliateLinks'; type SourceArticleRecord = { id?: string; title?: string | null; slug?: string | null; status?: string | null; excerpt?: string | null; content_html?: string | null; content_markdown?: string | null; source_url?: string | null; published_at?: string | null; createdAt?: string | null; updatedAt?: string | null; }; type Article = { id: string; title: string; status: string; source: string; readingTime: string; html: string; }; type ExportFormat = 'wordpress' | 'html' | 'markdown'; type ExportRecord = { id: string; articleTitle: string; format: ExportFormat; createdAt: string; replacements: number; fileName: string; preview: string; }; const sampleArticles: Article[] = [ { id: 'portable-power-stations', title: '7 Portable Power Station Uses for Weekend Travelers', status: 'Sample article', source: 'Fallback sample', readingTime: '5 min read', html: `
Weekend travelers are using compact power stations to keep phones, cameras, and small appliances running without hunting for outlets.
Our top recommendation is this portable power station because it balances capacity, size, and price.
For longer trips, add a folding solar charging panel to extend runtime while camping or tailgating.
`, }, { id: 'home-office-upgrades', title: 'Home Office Upgrades That Make Content Creators Faster', status: 'Sample article', source: 'Fallback sample', readingTime: '4 min read', html: `A focused creator desk can reduce editing friction and make every recording session feel easier.
Start with an adjustable LED desk light for consistent video quality.
Then upgrade voiceovers with a plug-and-play USB microphone that works with most recording apps.
`, }, ]; const formatLabels: Record${convertInlineMarkdownLinks(trimmedBlock).replace(
/\n/g,
'
',
)}
${escapeHtml(excerpt)}
` : '' }`; }; const normalizeArticleRecord = ( record: SourceArticleRecord, index: number, ): Article | null => { const html = getArticleHtml(record); const title = getStringValue(record.title) || `Article ${index + 1}`; if (!stripTags(html) && !title) return null; return { id: getStringValue(record.id) || getStringValue(record.slug) || `article-${index}`, title, status: formatStatusLabel(record.status), source: getSourceLabel(record.source_url), readingTime: estimateReadingTime(html), html, }; }; const slugify = (value: string) => value .toLowerCase() .replace(/[^a-z0-9]+/g, '-') .replace(/^-|-$/g, ''); const htmlAnchorPattern = /]*?\bhref\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+))[^>]*>([\s\S]*?)<\/a>/gi; const buildMarkdown = (html: string) => html .replace( htmlAnchorPattern, (_match, doubleQuoted, singleQuoted, bareUrl, label) => { const href = doubleQuoted || singleQuoted || bareUrl || ''; return `[${stripTags(label)}](${href})`; }, ) .replace(/(.*?)<\/p>/gis, '$1\n\n')
.replace(/
Buyer workflow
Choose a licensed article and the system automatically finds
common affiliate parameters like Amazon
Enter the buyer tag once; matching article links update
automatically.
Status
{selectedArticle.status}
Source
{selectedArticle.source}
No links were found in this article content.
Export a draft-ready file for WordPress or manual
publishing.
Saved locally for this first iteration.
A lightweight confirmation record for the buyer.
Article
{selectedExport.articleTitle}
Format
{formatLabels[selectedExport.format]}
Replacements
{selectedExport.replacements}
Created
{selectedExport.createdAt}
(\n)?/gi, '\n')
.replace(/<[^>]*>/g, '')
.replace(/\n{3,}/g, '\n\n')
.trim();
const buildWordPressXml = (
article: Article,
html: string,
) => `
Detect affiliate tags, personalize once, and export a ready
article.
tag
, ShareASale
u
, and generic
aff
{' '}
IDs.
Detected affiliate tags
Advanced fallback: replace a full affiliate URL
Preview & download
Export history
Export detail