import React, { useState, useEffect, useCallback } from 'react'; import { View, Text, TouchableOpacity, ScrollView, StyleSheet, Alert, ActivityIndicator, } from 'react-native'; import type { PluginComponentProps, CustomAction, DebuggerPlugin } from '../../core/types'; import { actionStore } from './actionStore'; const CustomActionsPanel: React.FC = ({ theme }) => { const [actions, setActions] = useState([]); const [runningAction, setRunningAction] = useState(null); const [lastResult, setLastResult] = useState<{ id: string; success: boolean; message?: string; } | null>(null); useEffect(() => { const unsub = actionStore.subscribe(setActions); return unsub; }, []); const handleRun = useCallback(async (action: CustomAction) => { const execute = async () => { setRunningAction(action.id); setLastResult(null); try { await action.handler(); setLastResult({ id: action.id, success: true, message: 'Completed' }); } catch (err) { setLastResult({ id: action.id, success: false, message: err instanceof Error ? err.message : 'Failed', }); } setRunningAction(null); }; if (action.destructive) { Alert.alert('⚠️ Confirm', `Run "${action.name}"? This action is marked as destructive.`, [ { text: 'Cancel', style: 'cancel' }, { text: 'Run', style: 'destructive', onPress: execute }, ]); } else { execute(); } }, []); const groups = React.useMemo(() => { const groupMap = new Map(); for (const action of actions) { const group = action.group || 'General'; const list = groupMap.get(group) || []; list.push(action); groupMap.set(group, list); } return groupMap; }, [actions]); if (actions.length === 0) { return ( 🎯 No Custom Actions Register actions:{'\n\n'} { 'registerAction({\n id: "clear-cache",\n name: "Clear Cache",\n icon: "🗑️",\n handler: () => clearCache(),\n})' } ); } return ( {/* Result Banner */} {lastResult && ( {lastResult.success ? '✅' : '❌'} {lastResult.message} )} {/* Action Groups */} {Array.from(groups.entries()).map(([groupName, groupActions]) => ( {groupName} {groupActions.map((action) => ( handleRun(action)} activeOpacity={0.7} disabled={!!runningAction} > {runningAction === action.id ? ( ) : ( <> {action.icon || '⚡'} {action.name} {action.description && ( {action.description} )} )} ))} ))} ); }; const styles = StyleSheet.create({ container: { flex: 1 }, emptyContainer: { flex: 1, alignItems: 'center', justifyContent: 'center', paddingHorizontal: 32, }, emptyIcon: { fontSize: 48, marginBottom: 16 }, emptyTitle: { fontSize: 16, fontWeight: '700', marginBottom: 8 }, emptyDesc: { fontSize: 13, textAlign: 'center', lineHeight: 20 }, resultBanner: { padding: 10, marginHorizontal: 12, marginVertical: 8, borderRadius: 8 }, resultText: { fontSize: 13, fontWeight: '600', textAlign: 'center' }, group: { paddingHorizontal: 12, marginBottom: 16 }, groupTitle: { fontSize: 11, fontWeight: '700', textTransform: 'uppercase', letterSpacing: 1, marginBottom: 8, marginTop: 12, }, grid: { flexDirection: 'row', flexWrap: 'wrap', gap: 8 }, actionCard: { width: '47%', padding: 16, borderRadius: 12, borderWidth: 1, alignItems: 'center', justifyContent: 'center', minHeight: 90, }, actionIcon: { fontSize: 24, marginBottom: 8 }, actionName: { fontSize: 13, fontWeight: '700', textAlign: 'center' }, actionDesc: { fontSize: 10, textAlign: 'center', marginTop: 4 }, }); export function createCustomActionsPlugin(): DebuggerPlugin { return { id: 'custom-actions', name: 'Actions', icon: '🎯', component: CustomActionsPanel, order: 110, }; }