import { useEffect, useRef, useState } from 'react'; import { flushSync } from 'react-dom'; import { CopyButton } from '../../ui/CopyButton.js'; import { Drawer } from '../../ui/Drawer.js'; import { RailAction } from '../../ui/RailAction.js'; import { copyText } from '../../utils/clientControls.js'; import { instructionBlocks } from './instructionBlocks.js'; interface InstructionLinkStep { before?: string; link: [string, string]; after?: string; } interface InstructionCopyAction { id: string; label: string; text: string; } interface InstructionBlockData { id: string; label: string; title: string; summary: string; paragraphs?: string[]; steps?: Array; code?: string; multilineCode?: boolean; copies?: InstructionCopyAction[]; note?: string; } interface InstructionsFeatureOptions { isGateway: boolean; host: string; port: number; controlHost: string; } function InstructionStep({ step }: { step: string | InstructionLinkStep }) { if (typeof step === 'string') return step; return ( <> {step.before} {step.link[0]} {step.after} ); } function InstructionBlock({ block, open, onToggle, }: { block: InstructionBlockData; open: boolean; onToggle: () => void; }) { const [copyFeedback, setCopyFeedback] = useState>({}); const [copyAnnouncement, setCopyAnnouncement] = useState<{ id: string; message: string } | null>(null); const copyTimers = useRef(new Map>()); const copyAttempts = useRef(new Map()); useEffect(() => () => { for (const timer of copyTimers.current.values()) clearTimeout(timer); copyTimers.current.clear(); copyAttempts.current.clear(); }, []); async function copyInstruction(action: InstructionCopyAction) { const activeTimer = copyTimers.current.get(action.id); if (activeTimer) clearTimeout(activeTimer); const attempt = {}; copyAttempts.current.set(action.id, attempt); let feedback: { failed: boolean }; try { await copyText(action.text); feedback = { failed: false }; } catch { feedback = { failed: true }; } if (copyAttempts.current.get(action.id) !== attempt) return; const announcement = { id: action.id, message: feedback.failed ? `Не удалось скопировать ${action.label}` : `${action.label} скопировано`, }; const pendingTimer = copyTimers.current.get(action.id); if (pendingTimer) clearTimeout(pendingTimer); setCopyFeedback((current) => ({ ...current, [action.id]: feedback })); setCopyAnnouncement(announcement); copyTimers.current.set(action.id, setTimeout(() => { setCopyFeedback((current) => { const next = { ...current }; delete next[action.id]; return next; }); setCopyAnnouncement((current) => current?.id === action.id ? null : current); copyTimers.current.delete(action.id); copyAttempts.current.delete(action.id); }, 800)); } return (