"use client"; import React, { useState, useEffect } from "react"; import { ChevronRight, Database, Settings, Activity, Search, ArrowLeft, Lock } from "lucide-react"; import Modal from "./ui/Modal"; export default function NodeConfigModal({ node, isOpen, onClose, onUpdateNode }) { const [step, setStep] = useState(1); const [search, setSearch] = useState(""); const [selectedAction, setSelectedAction] = useState(null); const [fieldValues, setFieldValues] = useState({}); const [fieldOptions, setFieldOptions] = useState({}); const [loadingOptions, setLoadingOptions] = useState({}); const [isTesting, setIsTesting] = useState(false); const [testResponse, setTestResponse] = useState(null); const [credentials, setCredentials] = useState([]); const [isLoadingCredentials, setIsLoadingCredentials] = useState(false); const [isAddingCredential, setIsAddingCredential] = useState(false); const [newCredential, setNewCredential] = useState({ name: "", data: {} }); const [isSavingCredential, setIsSavingCredential] = useState(false); useEffect(() => { if (isOpen) { setStep(1); setSearch(""); setTestResponse(null); if (node?.data?.actionId) { // Find action in metadata based on node.data.actionId let foundAction = null; if (node.appData?.categories) { node.appData.categories.forEach(cat => { const act = cat.actions.find(a => a.id === node.data.actionId); if (act) foundAction = act; }); } else if (node.appData?.actions) { foundAction = node.appData.actions.find(a => a.id === node.data.actionId); } setSelectedAction(foundAction); setFieldValues(node.data?.config || {}); } else { setSelectedAction(null); setFieldValues({}); } } }, [isOpen, node]); useEffect(() => { if (isOpen && node?.appData?.id) { const fetchCredentials = async () => { setIsLoadingCredentials(true); try { const response = await fetch(`${window.wpbotAutomator.apiUrl}/credentials?app_id=${node.appData.id}`, { headers: { 'X-WP-Nonce': window.wpbotAutomator.nonce }, }); const data = await response.json(); if (Array.isArray(data)) setCredentials(data); } catch (error) { console.error("Failed to fetch credentials:", error); } finally { setIsLoadingCredentials(false); } }; setIsAddingCredential(false); setNewCredential({ name: "", data: {} }); fetchCredentials(); } }, [isOpen, node?.appData?.id]); const handleSaveCredential = async () => { try { if (!newCredential.name) { alert("Validation Error: Please enter a typical Name for this credential."); return; } setIsSavingCredential(true); const payload = { name: newCredential.name, app_id: node.appData.id, data: newCredential.data }; const response = await fetch(`${window.wpbotAutomator.apiUrl}/credentials`, { method: "POST", headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': window.wpbotAutomator.nonce }, body: JSON.stringify(payload) }); const result = await response.json(); if (result.success) { setCredentials(prev => [...prev, result.credential]); if (selectedAction) { const credField = selectedAction.fields?.find(f => f.type === 'credential'); if (credField) handleFieldChange(credField.id, result.credential.id); } setIsAddingCredential(false); setNewCredential({ name: "", data: {} }); alert("Credential saved successfully!"); } else { alert("Failed to save credential on server: " + (result.message || JSON.stringify(result))); } } catch (error) { console.error("Error saving credential:", error); alert("Error saving credential. Check your browser console: " + error.message); } finally { setIsSavingCredential(false); } }; useEffect(() => { if (selectedAction?.fields) { selectedAction.fields.forEach(field => { if (field.type === 'select' && field.optionsUrl && !fieldOptions[field.id]) { fetchOptions(field); } }); } }, [selectedAction]); const fetchOptions = async (field) => { setLoadingOptions(prev => ({ ...prev, [field.id]: true })); try { const baseUrl = window.wpbotAutomator.apiUrl.replace(/\/$/, ''); const response = await fetch(`${baseUrl}${field.optionsUrl}`, { headers: { 'X-WP-Nonce': window.wpbotAutomator.nonce, }, }); const data = await response.json(); setFieldOptions(prev => ({ ...prev, [field.id]: Array.isArray(data) ? data : [] })); } catch (error) { console.error(`Error fetching options for ${field.id}:`, error); } finally { setLoadingOptions(prev => ({ ...prev, [field.id]: false })); } }; if (!node) return null; const handleSelectAction = (action) => { setSelectedAction(action); setStep(2); }; const handleSave = () => { onUpdateNode({ ...node, subtitle: selectedAction ? selectedAction.name : "Configure action", data: { ...node.data, actionId: selectedAction?.id, config: fieldValues } }); onClose(); }; const handleFieldChange = (fieldId, value) => { setFieldValues(prev => ({ ...prev, [fieldId]: value })); }; const handleTestRun = async () => { setIsTesting(true); setTestResponse(null); try { const response = await fetch(`${window.wpbotAutomator.apiUrl}/test-action`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-WP-Nonce': window.wpbotAutomator.nonce, }, body: JSON.stringify({ appId: node.appData.id, actionId: selectedAction.id, config: fieldValues, }), }); const data = await response.json(); setTestResponse(data); } catch (error) { console.error("Test Run error:", error); setTestResponse({ success: false, message: "Request failed. Check your connection or URL." }); } finally { setIsTesting(false); } }; const renderStep1 = () => { const categories = node.appData?.categories || (node.appData?.actions ? [{ id: "main", name: "Actions", actions: node.appData.actions }] : []); return (
{col.name}{col.required && *}
{col.type}
Use {'{token}'} to map values from the trigger.
Configure the details for this action
{selectedAction?.description}
Use this URL to send GET or POST requests to trigger this workflow.
Use this URL in your Facebook Developer App configuration.
Upgrade to Pro to unlock this field.
Next phase details
Specific options for this action will appear here in the final implementation.
{typeof testResponse.body === 'string' ? testResponse.body : JSON.stringify(testResponse.body, null, 2)}
{testResponse.message}
)}