Добавлен модуль улучшения текста в NoteEditor с интеграцией нового модального окна. Реализована логика обработки ошибок и отображения улучшенного текста. Обновлены состояния для управления модальным окном и улучшением текста, что улучшает взаимодействие пользователя с заметками.
This commit is contained in:
parent
74ae2ead31
commit
cb40f032d2
162
src/components/notes/ImproveTextModal.tsx
Normal file
162
src/components/notes/ImproveTextModal.tsx
Normal 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}>
|
||||||
|
×
|
||||||
|
</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>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
@ -10,6 +10,7 @@ import { offlineNotesApi } from "../../api/offlineNotesApi";
|
|||||||
import { aiApi } from "../../api/aiApi";
|
import { aiApi } from "../../api/aiApi";
|
||||||
import { Icon } from "@iconify/react";
|
import { Icon } from "@iconify/react";
|
||||||
import { GenerateTagsModal } from "./GenerateTagsModal";
|
import { GenerateTagsModal } from "./GenerateTagsModal";
|
||||||
|
import { ImproveTextModal } from "./ImproveTextModal";
|
||||||
import { extractTags } from "../../utils/markdown";
|
import { extractTags } from "../../utils/markdown";
|
||||||
|
|
||||||
interface NoteEditorProps {
|
interface NoteEditorProps {
|
||||||
@ -25,6 +26,10 @@ export const NoteEditor: React.FC<NoteEditorProps> = ({ onSave }) => {
|
|||||||
const [suggestedTags, setSuggestedTags] = useState<string[]>([]);
|
const [suggestedTags, setSuggestedTags] = useState<string[]>([]);
|
||||||
const [isGeneratingTags, setIsGeneratingTags] = useState(false);
|
const [isGeneratingTags, setIsGeneratingTags] = useState(false);
|
||||||
const [tagsGenerationError, setTagsGenerationError] = 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 [showFloatingToolbar, setShowFloatingToolbar] = useState(false);
|
||||||
const [toolbarPosition, setToolbarPosition] = useState({ top: 0, left: 0 });
|
const [toolbarPosition, setToolbarPosition] = useState({ top: 0, left: 0 });
|
||||||
const [hasSelection, setHasSelection] = useState(false);
|
const [hasSelection, setHasSelection] = useState(false);
|
||||||
@ -89,18 +94,34 @@ export const NoteEditor: React.FC<NoteEditorProps> = ({ onSave }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setIsAiLoading(true);
|
setIsAiLoading(true);
|
||||||
|
setImproveError(false);
|
||||||
|
setImproveErrorMessage("");
|
||||||
|
setImprovedText("");
|
||||||
|
setShowImproveModal(true);
|
||||||
try {
|
try {
|
||||||
const improvedText = await aiApi.improveText(content);
|
const improved = await aiApi.improveText(content);
|
||||||
setContent(improvedText);
|
setImprovedText(improved);
|
||||||
showNotification("Текст улучшен!", "success");
|
setImproveError(false);
|
||||||
} catch (error) {
|
} catch (error: any) {
|
||||||
console.error("Ошибка улучшения текста:", error);
|
console.error("Ошибка улучшения текста:", error);
|
||||||
showNotification("Ошибка улучшения текста", "error");
|
setImproveError(true);
|
||||||
|
setImproveErrorMessage(
|
||||||
|
error.response?.data?.error || error.message || "Ошибка улучшения текста"
|
||||||
|
);
|
||||||
} finally {
|
} finally {
|
||||||
setIsAiLoading(false);
|
setIsAiLoading(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleApplyImprovedText = (text: string) => {
|
||||||
|
setContent(text);
|
||||||
|
showNotification("Текст улучшен!", "success");
|
||||||
|
setShowImproveModal(false);
|
||||||
|
setImprovedText("");
|
||||||
|
setImproveError(false);
|
||||||
|
setImproveErrorMessage("");
|
||||||
|
};
|
||||||
|
|
||||||
const handleGenerateTags = async () => {
|
const handleGenerateTags = async () => {
|
||||||
if (!content.trim()) {
|
if (!content.trim()) {
|
||||||
showNotification("Введите текст для генерации тегов", "warning");
|
showNotification("Введите текст для генерации тегов", "warning");
|
||||||
@ -1090,6 +1111,22 @@ export const NoteEditor: React.FC<NoteEditorProps> = ({ onSave }) => {
|
|||||||
isLoading={isGeneratingTags}
|
isLoading={isGeneratingTags}
|
||||||
hasError={tagsGenerationError}
|
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>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user