import React, { useState, useCallback } from 'react'; import { Button, Paper, Box, TextField } from "@mui/material"; import EditIcon from '@mui/icons-material/Edit'; import TextFieldsIcon from '@mui/icons-material/TextFields'; import DocumentScannerIcon from '@mui/icons-material/DocumentScanner'; import styled from "styled-components"; import { SimpleBox } from "../atoms/Box"; import Typography from "@mui/material/Typography"; import { useGlobalInfoStore } from "../../context/globalInfo"; import { useActionContext } from '../../context/browserActions'; import { useBrowserSteps, ListStep, TextStep, SelectorObject } from '../../context/browserSteps'; import { useSocketStore } from '../../context/socket'; import { ScreenshotSettings } from '../../shared/types'; import InputAdornment from '@mui/material/InputAdornment'; export const RightSidePanel = () => { const [textLabels, setTextLabels] = useState<{ [id: number]: string }>({}); const [errors, setErrors] = useState<{ [id: number]: string }>({}); const [confirmedTextSteps, setConfirmedTextSteps] = useState<{ [id: number]: boolean }>({}); const { lastAction, notify } = useGlobalInfoStore(); const { getText, startGetText, stopGetText, getScreenshot, startGetScreenshot, stopGetScreenshot, getList, startGetList, stopGetList } = useActionContext(); const { browserSteps, updateBrowserTextStepLabel, deleteBrowserStep, addScreenshotStep } = useBrowserSteps(); const { socket } = useSocketStore(); const handleTextLabelChange = (id: number, label: string) => { setTextLabels(prevLabels => ({ ...prevLabels, [id]: label })); if (!label.trim()) { setErrors(prevErrors => ({ ...prevErrors, [id]: 'Label cannot be empty' })); } else { setErrors(prevErrors => ({ ...prevErrors, [id]: '' })); } }; const handleTextStepConfirm = (id: number) => { const label = textLabels[id]?.trim(); if (label) { updateBrowserTextStepLabel(id, label); setConfirmedTextSteps(prev => ({ ...prev, [id]: true })); } else { setErrors(prevErrors => ({ ...prevErrors, [id]: 'Label cannot be empty' })); } }; const handleTextStepDiscard = (id: number) => { deleteBrowserStep(id); setTextLabels(prevLabels => { const { [id]: _, ...rest } = prevLabels; return rest; }); setErrors(prevErrors => { const { [id]: _, ...rest } = prevErrors; return rest; }); }; const getTextSettingsObject = useCallback(() => { const settings: Record = {}; browserSteps.forEach(step => { if (step.type === 'text' && step.label && step.selectorObj?.selector) { settings[step.label] = step.selectorObj; } }); return settings; }, [browserSteps]); const stopCaptureAndEmitGetTextSettings = useCallback(() => { const hasUnconfirmedTextSteps = browserSteps.some(step => step.type === 'text' && !confirmedTextSteps[step.id]); if (hasUnconfirmedTextSteps) { notify('error', 'Please confirm no labels are empty'); return; } stopGetText(); const settings = getTextSettingsObject(); const hasTextSteps = browserSteps.some(step => step.type === 'text'); if (hasTextSteps) { socket?.emit('action', { action: 'scrapeSchema', settings }); } }, [stopGetText, getTextSettingsObject, socket, browserSteps, confirmedTextSteps]); const getListSettingsObject = useCallback(() => { const settings: Record }> = {}; browserSteps.forEach(step => { if (step.type === 'list' && step.listSelector && Object.keys(step.fields).length > 0) { const fields: Record = {}; Object.entries(step.fields).forEach(([label, field]) => { if (field.selectorObj?.selector) { fields[label] = { selector: field.selectorObj.selector, tag: field.selectorObj.tag, attribute: field.selectorObj.attribute }; } }); settings[step.listSelector] = { listSelector: step.listSelector, fields: fields }; } }); return settings; }, [browserSteps]); const stopCaptureAndEmitGetListSettings = useCallback(() => { stopGetList(); const settings = getListSettingsObject(); if (settings) { socket?.emit('action', { action: 'scrapeList', settings }); } else { notify('error', 'Unable to create list settings. Make sure you have defined a field for the list.'); } }, [stopGetList, getListSettingsObject, socket, notify]); // const handleListFieldChange = (stepId: number, key: 'label' | 'data', value: string) => { // updateListStepField(stepId, key, value); // }; const captureScreenshot = (fullPage: boolean) => { const screenshotSettings: ScreenshotSettings = { fullPage, type: 'png', timeout: 30000, animations: 'allow', caret: 'hide', scale: 'device', }; socket?.emit('action', { action: 'screenshot', settings: screenshotSettings }); addScreenshotStep(fullPage); stopGetScreenshot(); }; return ( Last action: {` ${lastAction}`} {!getText && !getScreenshot && !getList && } {getList && <> } {!getText && !getScreenshot && !getList && } {getText && <> } {!getText && !getScreenshot && !getList && } {getScreenshot && ( )} {browserSteps.map(step => ( { step.type === 'text' && ( <> handleTextLabelChange(step.id, e.target.value)} fullWidth margin="normal" error={!!errors[step.id]} helperText={errors[step.id]} InputProps={{ readOnly: confirmedTextSteps[step.id], startAdornment: ( ) }} /> ) }} /> {!confirmedTextSteps[step.id] && ( )} )} {step.type === 'screenshot' && ( {`Take ${step.fullPage ? 'Fullpage' : 'Visible Part'} Screenshot`} )} {step.type === 'list' && ( <> List Selected Successfully {Object.entries(step.fields).map(([key, field]) => ( {}} fullWidth margin="normal" InputProps={{ startAdornment: ( ) }} /> ) }} /> ))} )} ))} ); };