import React, { useState, useEffect, useRef } from 'react';
import Creator from './components/Creator';
import SupportModal from './components/SupportModal';
import TemplatesModal from './components/TemplatesModal';
const App = () => {
const [view, setView] = useState('list');
const [workflows, setWorkflows] = useState([]);
const [selectedWorkflow, setSelectedWorkflow] = useState(null);
const [loading, setLoading] = useState(true);
const [isSupportOpen, setIsSupportOpen] = useState(false);
const [isTemplatesModalOpen, setIsTemplatesModalOpen] = useState(false);
const [importStatus, setImportStatus] = useState(null); // { type: 'success'|'error', message: '' }
const importFileRef = useRef(null);
useEffect(() => {
fetchWorkflows();
}, []);
const fetchWorkflows = async () => {
setLoading(true);
try {
const response = await fetch(`${window.wpbotAutomator.apiUrl}/workflows`, {
headers: {
'X-WP-Nonce': window.wpbotAutomator.nonce,
},
});
const data = await response.json();
setWorkflows(data || []);
} catch (error) {
console.error('Error fetching workflows:', error);
} finally {
setLoading(false);
}
};
const handleCreateNew = () => {
setIsTemplatesModalOpen(true);
};
const handleTemplateSelect = (template) => {
setIsTemplatesModalOpen(false);
if (template) {
// Create a dummy workflow object from template
setSelectedWorkflow({
id: null,
name: template.name,
description: template.description,
workflow_data: template.workflow_data,
status: 'active'
});
} else {
setSelectedWorkflow(null);
}
setView('creator');
};
const handleEdit = (workflow) => {
setSelectedWorkflow(workflow);
setView('creator');
};
const handleDelete = async (e, id) => {
e.stopPropagation();
if (!window.confirm('Are you sure you want to delete this workflow?')) {
return;
}
try {
const response = await fetch(`${window.wpbotAutomator.apiUrl}/workflows/${id}`, {
method: 'DELETE',
headers: {
'X-WP-Nonce': window.wpbotAutomator.nonce,
},
});
const data = await response.json();
if (data.success) {
fetchWorkflows();
} else {
alert('Failed to delete workflow.');
}
} catch (error) {
console.error('Error deleting workflow:', error);
}
};
const handleToggleStatus = async (e, workflow) => {
e.stopPropagation();
const newStatus = workflow.status === 'active' ? 'inactive' : 'active';
try {
const response = await fetch(`${window.wpbotAutomator.apiUrl}/workflows/${workflow.id}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': window.wpbotAutomator.nonce,
},
body: JSON.stringify({
...workflow,
status: newStatus,
}),
});
const data = await response.json();
if (data.success) {
fetchWorkflows();
} else {
alert('Failed to update workflow status.');
}
} catch (error) {
console.error('Error updating workflow status:', error);
}
};
const handleBack = () => {
setView('list');
fetchWorkflows();
};
// ── Export helpers ────────────────────────────────────────────────────────
/**
* Trigger a JSON file download from a plain-object payload.
*/
const downloadJson = (data, filename) => {
const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
a.click();
URL.revokeObjectURL(url);
};
/**
* Export a single workflow by ID.
*/
const handleExportSingle = async (e, workflow) => {
e.stopPropagation();
try {
const response = await fetch(
`${window.wpbotAutomator.apiUrl}/workflows/export?id=${workflow.id}`,
{ headers: { 'X-WP-Nonce': window.wpbotAutomator.nonce } }
);
const data = await response.json();
const safeName = workflow.name.replace(/[^a-z0-9_-]/gi, '_').toLowerCase();
downloadJson(data, `wpbot-workflow-${safeName}.json`);
} catch (error) {
console.error('Error exporting workflow:', error);
alert('Failed to export workflow.');
}
};
/**
* Export all workflows.
*/
const handleExportAll = async () => {
try {
const response = await fetch(
`${window.wpbotAutomator.apiUrl}/workflows/export`,
{ headers: { 'X-WP-Nonce': window.wpbotAutomator.nonce } }
);
const data = await response.json();
downloadJson(data, 'wpbot-workflows-all.json');
} catch (error) {
console.error('Error exporting all workflows:', error);
alert('Failed to export workflows.');
}
};
// ── Import helpers ────────────────────────────────────────────────────────
const handleImportClick = () => {
setImportStatus(null);
importFileRef.current && importFileRef.current.click();
};
const handleImportFile = (e) => {
const file = e.target.files && e.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = async (evt) => {
let parsed;
try {
parsed = JSON.parse(evt.target.result);
} catch {
setImportStatus({ type: 'error', message: 'Invalid JSON file. Please select a valid export file.' });
return;
}
if (!parsed.workflows || !Array.isArray(parsed.workflows)) {
setImportStatus({ type: 'error', message: 'Invalid file format. Expected a "workflows" array.' });
return;
}
try {
const response = await fetch(`${window.wpbotAutomator.apiUrl}/workflows/import`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': window.wpbotAutomator.nonce,
},
body: JSON.stringify({ workflows: parsed.workflows }),
});
const data = await response.json();
if (data.success || data.imported > 0) {
const msg = `Successfully imported ${data.imported} workflow${data.imported !== 1 ? 's' : ''}.`
+ (data.errors && data.errors.length ? ` (${data.errors.length} skipped)` : '');
setImportStatus({ type: 'success', message: msg });
fetchWorkflows();
} else {
const errMsg = (data.errors && data.errors.join(' ')) || 'Import failed. No workflows were imported.';
setImportStatus({ type: 'error', message: errMsg });
}
} catch (error) {
console.error('Error importing workflows:', error);
setImportStatus({ type: 'error', message: 'Network error during import. Please try again.' });
}
};
reader.readAsText(file);
// Reset so the same file can be selected again
e.target.value = '';
};
if (view === 'creator') {
return
{workflow.description || 'No description'}