Добавлен модуль улучшения текста в NoteEditor с интеграцией нового модального окна. Реализована логика обработки ошибок и отображения улучшенного текста. Обновлены состояния для управления модальным окном и улучшением текста, что улучшает взаимодействие пользователя с заметками.

This commit is contained in:
Fovway 2025-11-07 16:29:00 +07:00
parent 74ae2ead31
commit cb40f032d2
2 changed files with 204 additions and 5 deletions

View File

@ -0,0 +1,162 @@
import React, { useState, useEffect } from "react";
import { Icon } from "@iconify/react";
interface ImproveTextModalProps {
isOpen: boolean;
onClose: () => void;
onApply: (improvedText: string) => void;
originalText: string;
improvedText: string;
isLoading?: boolean;
hasError?: boolean;
errorMessage?: string;
}
export const ImproveTextModal: React.FC<ImproveTextModalProps> = ({
isOpen,
onClose,
onApply,
originalText,
improvedText,
isLoading = false,
hasError = false,
errorMessage,
}) => {
const [localImprovedText, setLocalImprovedText] = useState(improvedText);
useEffect(() => {
if (isOpen) {
setLocalImprovedText(improvedText);
}
}, [isOpen, improvedText]);
const handleApply = () => {
if (!localImprovedText.trim()) {
return;
}
onApply(localImprovedText);
onClose();
};
useEffect(() => {
const handleEscape = (e: KeyboardEvent) => {
if (e.key === "Escape" && isOpen) {
onClose();
}
};
if (isOpen) {
document.addEventListener("keydown", handleEscape);
}
return () => document.removeEventListener("keydown", handleEscape);
}, [isOpen, onClose]);
if (!isOpen) return null;
return (
<div className="modal" style={{ display: "block" }} onClick={onClose}>
<div
className="modal-content"
style={{ maxWidth: "800px" }}
onClick={(e) => e.stopPropagation()}
>
<div className="modal-header">
<h3>Улучшенный текст</h3>
<span className="modal-close" onClick={onClose}>
&times;
</span>
</div>
<div className="modal-body" style={{ maxHeight: "70vh", overflowY: "auto" }}>
{isLoading ? (
<div style={{ textAlign: "center", padding: "40px 20px" }}>
<div className="loading-spinner" style={{ margin: "0 auto 20px" }}></div>
<p>Улучшаю текст через ИИ...</p>
</div>
) : hasError ? (
<div style={{ textAlign: "center", padding: "40px 20px" }}>
<Icon
icon="mdi:alert-circle"
style={{ fontSize: "48px", color: "#dc3545", marginBottom: "15px" }}
/>
<p style={{ color: "#dc3545", marginBottom: "10px", fontSize: "18px" }}>
Не удалось улучшить текст
</p>
<p style={{ fontSize: "14px", color: "#666" }}>
{errorMessage || "Произошла ошибка при улучшении текста. Проверьте настройки AI или попробуйте еще раз."}
</p>
</div>
) : (
<>
<div style={{ marginBottom: "20px" }}>
<h4 style={{ margin: "0 0 10px 0", fontSize: "16px", color: "#666" }}>
Оригинальный текст:
</h4>
<div
style={{
padding: "15px",
border: "1px solid var(--border-color)",
borderRadius: "8px",
backgroundColor: "var(--bg-secondary)",
maxHeight: "200px",
overflowY: "auto",
whiteSpace: "pre-wrap",
wordWrap: "break-word",
fontSize: "14px",
lineHeight: "1.6",
}}
>
{originalText || "(пусто)"}
</div>
</div>
<div>
<h4 style={{ margin: "0 0 10px 0", fontSize: "16px" }}>
Улучшенный текст:
</h4>
<textarea
value={localImprovedText}
onChange={(e) => setLocalImprovedText(e.target.value)}
style={{
width: "100%",
minHeight: "200px",
maxHeight: "400px",
padding: "15px",
border: "1px solid var(--border-color)",
borderRadius: "8px",
backgroundColor: "var(--bg-primary)",
color: "var(--text-primary)",
fontSize: "14px",
lineHeight: "1.6",
fontFamily: "inherit",
resize: "vertical",
whiteSpace: "pre-wrap",
wordWrap: "break-word",
overflowY: "auto",
}}
placeholder="Улучшенный текст появится здесь..."
/>
<p style={{ fontSize: "12px", color: "#666", marginTop: "8px" }}>
Вы можете отредактировать улучшенный текст перед применением
</p>
</div>
</>
)}
</div>
<div className="modal-footer">
<button
className="btn-primary"
onClick={handleApply}
disabled={isLoading || hasError || !localImprovedText.trim()}
>
Применить
</button>
<button className="btn-secondary" onClick={onClose} disabled={isLoading}>
Отмена
</button>
</div>
</div>
</div>
);
};

View File

@ -10,6 +10,7 @@ import { offlineNotesApi } from "../../api/offlineNotesApi";
import { aiApi } from "../../api/aiApi";
import { Icon } from "@iconify/react";
import { GenerateTagsModal } from "./GenerateTagsModal";
import { ImproveTextModal } from "./ImproveTextModal";
import { extractTags } from "../../utils/markdown";
interface NoteEditorProps {
@ -25,6 +26,10 @@ export const NoteEditor: React.FC<NoteEditorProps> = ({ onSave }) => {
const [suggestedTags, setSuggestedTags] = useState<string[]>([]);
const [isGeneratingTags, setIsGeneratingTags] = useState(false);
const [tagsGenerationError, setTagsGenerationError] = useState(false);
const [showImproveModal, setShowImproveModal] = useState(false);
const [improvedText, setImprovedText] = useState("");
const [improveError, setImproveError] = useState(false);
const [improveErrorMessage, setImproveErrorMessage] = useState<string>("");
const [showFloatingToolbar, setShowFloatingToolbar] = useState(false);
const [toolbarPosition, setToolbarPosition] = useState({ top: 0, left: 0 });
const [hasSelection, setHasSelection] = useState(false);
@ -89,18 +94,34 @@ export const NoteEditor: React.FC<NoteEditorProps> = ({ onSave }) => {
}
setIsAiLoading(true);
setImproveError(false);
setImproveErrorMessage("");
setImprovedText("");
setShowImproveModal(true);
try {
const improvedText = await aiApi.improveText(content);
setContent(improvedText);
showNotification("Текст улучшен!", "success");
} catch (error) {
const improved = await aiApi.improveText(content);
setImprovedText(improved);
setImproveError(false);
} catch (error: any) {
console.error("Ошибка улучшения текста:", error);
showNotification("Ошибка улучшения текста", "error");
setImproveError(true);
setImproveErrorMessage(
error.response?.data?.error || error.message || "Ошибка улучшения текста"
);
} finally {
setIsAiLoading(false);
}
};
const handleApplyImprovedText = (text: string) => {
setContent(text);
showNotification("Текст улучшен!", "success");
setShowImproveModal(false);
setImprovedText("");
setImproveError(false);
setImproveErrorMessage("");
};
const handleGenerateTags = async () => {
if (!content.trim()) {
showNotification("Введите текст для генерации тегов", "warning");
@ -1090,6 +1111,22 @@ export const NoteEditor: React.FC<NoteEditorProps> = ({ onSave }) => {
isLoading={isGeneratingTags}
hasError={tagsGenerationError}
/>
<ImproveTextModal
isOpen={showImproveModal}
onClose={() => {
setShowImproveModal(false);
setImprovedText("");
setImproveError(false);
setImproveErrorMessage("");
}}
onApply={handleApplyImprovedText}
originalText={content}
improvedText={improvedText}
isLoading={isAiLoading}
hasError={improveError}
errorMessage={improveErrorMessage}
/>
</div>
);
};