/
DnTyr
/
Password-Development
Обзор
Документация
Войти
/
DnTyr
/
Password-Development
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
frontend/src/components/Analyzer.js
201 строка
6 KB
DT
first_commit
03 июн 2026, 10:22
03 июн 2026, 10:22
357cb35
Код
Авторство
О чём код?
import { useAnalyzer } from "../hooks/useAnalyzer"; import PasswordInput from "./analyzer/PasswordInput"; import ResultBlock from "./analyzer/ResultBlock"; import React, { useState, useRef, useEffect, useCallback } from "react"; import { useTranslation } from "react-i18next"; import { toastSuccess, toastError } from "../utils/toast"; import { Copy, Loader2, Sparkles, TriangleAlert } from 'lucide-react'; function Analyzer({ resetSignal }) { const { t } = useTranslation(); const { password, setPassword, setIsGenerated, isGenerated, result, loading, cooldown, analyzePassword, isLeaked, isSafe, leakCount, isDeepLoading, deepCheckPassword, } = useAnalyzer(); useEffect(() => { if (resetSignal) { setIsGenerated(false); setPassword(""); } }, [resetSignal, setIsGenerated, setPassword]); const resultsRef = useRef(null); const scrollToResults = useCallback(() => { setTimeout(() => { if (resultsRef.current) { const elementRect = resultsRef.current.getBoundingClientRect(); const elementBottom = elementRect.bottom + window.pageYOffset; const scrollTarget = elementBottom - window.innerHeight + 55; window.scrollTo({ top: scrollTarget, behavior: "smooth", }); } }, 150); }, []); const handlePaste = async (e) => { if (e) { e.preventDefault(); e.stopPropagation(); } try { const text = await navigator.clipboard.readText(); if (text) { setPassword(text); setIsGenerated(false); toastSuccess(t("Скопировано из буфера обмена")); scrollToResults(); } } catch { toastError(t("Нет доступа к буферу обмена")); } }; const [showPasteTip, setShowPasteTip] = useState(false); return ( <div className="analyzer-container"> <div className="analyzer-header-wrapper"> <h2>{t("Анализ")}</h2> <div className="paste-btn-container"> <div className="paste-btn-wrapper"> {showPasteTip && ( <div className="custom-tooltip"> {t("Вставить пароль")} </div> )} <button type="button" className="paste-btn" onClick={handlePaste} onMouseEnter={() => setShowPasteTip(true)} onMouseLeave={() => setShowPasteTip(false)} > <Copy/> </button> </div> </div> </div> {/* INPUT */} <PasswordInput value={password} onChange={setPassword} onEnter={() => { analyzePassword(); scrollToResults(); }} onToggleVisibility={scrollToResults} isLeaked={isLeaked} isSafe={isSafe} leakCount={leakCount} /> {/* КНОПКА */} <button className="main-analyze-btn" onClick={() => { analyzePassword(); scrollToResults(); }} disabled={loading || cooldown} > {loading ? t("Загрузка...") : t("Проверить")} </button> {/* УТЕЧКИ */} {result && ( <div className="analyzer-footer"> {(leakCount === "found_locally" || (typeof leakCount === "number" && leakCount > 0)) && ( <div className="leak-warning"> <TriangleAlert className="leak-warning-icon" size={24} /> <span> {leakCount === "found_locally" ? t("Пароль найден в базе утечек!") : `${t("Найдено в утечках:")} ${leakCount} ${t("раз")}`} </span> </div> )} {leakCount === "clean" && ( <div className="leak-safe"> {t("Пароль в базе утечек не найден!")} </div> )} {leakCount === "error" && ( <div className="leak-error-hibp" role="alert"> <TriangleAlert className="leak-error-icon"/> <span>{t("Сервис проверки утечек временно недоступен.")}</span> </div> )} {password && (leakCount === 0 || leakCount === "error") && leakCount !== "found_locally" && ( <button className="btn-deep-check" onClick={deepCheckPassword} disabled={isDeepLoading} style={{ display: 'flex', alignItems: 'center', gap: '8px', justifyContent: 'center' }} > {isDeepLoading ? ( <> <Loader2 size={16} className="spin-animation" /> {t("Ищу в базах...")} </> ) : ( <> <Sparkles size={16} color="#ff8f62" /> {t("Сканировать базы утечек")} <Sparkles size={16} color="#ff8f62" /> </> )} </button> )} </div> )} {/* РЕЗУЛЬТАТ */} <div ref={resultsRef} className="analysis-results-wrapper" style={{ opacity: loading ? 0.6 : isGenerated ? 1 : 0.4, pointerEvents: isGenerated && !loading ? "auto" : "none", filter: isGenerated && !loading ? "none" : "grayscale(0.5)", transition: "all 0.3s ease", width: "100%", }} > {result && <ResultBlock result={result} />} </div> </div> ); } export default Analyzer;